1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back! *
3 *----------------------------------------------------------*
4 * (c) 1995-2002 Artsoft Entertainment *
6 * Detmolder Strasse 189 *
9 * e-mail: info@artsoft.org *
10 *----------------------------------------------------------*
12 ***********************************************************/
14 #include "libgame/libgame.h"
24 /* select level set with EMC X11 graphics before activating EM GFX debugging */
25 #define DEBUG_EM_GFX 0
27 /* tool button identifiers */
28 #define TOOL_CTRL_ID_YES 0
29 #define TOOL_CTRL_ID_NO 1
30 #define TOOL_CTRL_ID_CONFIRM 2
31 #define TOOL_CTRL_ID_PLAYER_1 3
32 #define TOOL_CTRL_ID_PLAYER_2 4
33 #define TOOL_CTRL_ID_PLAYER_3 5
34 #define TOOL_CTRL_ID_PLAYER_4 6
36 #define NUM_TOOL_BUTTONS 7
38 /* forward declaration for internal use */
39 static void UnmapToolButtons();
40 static void HandleToolButtons(struct GadgetInfo *);
41 static int el_act_dir2crm(int, int, int);
42 static int el_act2crm(int, int);
44 static struct GadgetInfo *tool_gadget[NUM_TOOL_BUTTONS];
45 static int request_gadget_id = -1;
47 static char *print_if_not_empty(int element)
49 static char *s = NULL;
50 char *token_name = element_info[element].token_name;
55 s = checked_malloc(strlen(token_name) + 10 + 1);
57 if (element != EL_EMPTY)
58 sprintf(s, "%d\t['%s']", element, token_name);
60 sprintf(s, "%d", element);
65 void DumpTile(int x, int y)
70 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
77 printf("Field Info: SCREEN(%d, %d), LEVEL(%d, %d)\n", sx, sy, x, y);
80 if (!IN_LEV_FIELD(x, y))
82 printf("(not in level field)\n");
88 printf(" Feld: %d\t['%s']\n", Feld[x][y],
89 element_info[Feld[x][y]].token_name);
90 printf(" Back: %s\n", print_if_not_empty(Back[x][y]));
91 printf(" Store: %s\n", print_if_not_empty(Store[x][y]));
92 printf(" Store2: %s\n", print_if_not_empty(Store2[x][y]));
93 printf(" StorePlayer: %s\n", print_if_not_empty(StorePlayer[x][y]));
94 printf(" MovPos: %d\n", MovPos[x][y]);
95 printf(" MovDir: %d\n", MovDir[x][y]);
96 printf(" MovDelay: %d\n", MovDelay[x][y]);
97 printf(" ChangeDelay: %d\n", ChangeDelay[x][y]);
98 printf(" CustomValue: %d\n", CustomValue[x][y]);
99 printf(" GfxElement: %d\n", GfxElement[x][y]);
100 printf(" GfxAction: %d\n", GfxAction[x][y]);
101 printf(" GfxFrame: %d\n", GfxFrame[x][y]);
105 void SetDrawtoField(int mode)
107 if (mode == DRAW_BUFFERED && setup.soft_scrolling)
118 drawto_field = fieldbuffer;
120 else /* DRAW_DIRECT, DRAW_BACKBUFFER */
126 BX2 = SCR_FIELDX - 1;
127 BY2 = SCR_FIELDY - 1;
131 drawto_field = (mode == DRAW_DIRECT ? window : backbuffer);
135 void RedrawPlayfield(boolean force_redraw, int x, int y, int width, int height)
137 if (game_status == GAME_MODE_PLAYING &&
138 level.game_engine_type == GAME_ENGINE_TYPE_EM)
140 /* currently there is no partial redraw -- always redraw whole playfield */
142 RedrawPlayfield_EM(TRUE);
144 else if (game_status == GAME_MODE_PLAYING && !game.envelope_active)
150 width = gfx.sxsize + 2 * TILEX;
151 height = gfx.sysize + 2 * TILEY;
154 if (force_redraw || setup.direct_draw)
157 int x1 = (x - SX) / TILEX, y1 = (y - SY) / TILEY;
158 int x2 = (x - SX + width) / TILEX, y2 = (y - SY + height) / TILEY;
160 if (setup.direct_draw)
161 SetDrawtoField(DRAW_BACKBUFFER);
163 for (xx = BX1; xx <= BX2; xx++)
164 for (yy = BY1; yy <= BY2; yy++)
165 if (xx >= x1 && xx <= x2 && yy >= y1 && yy <= y2)
166 DrawScreenField(xx, yy);
169 if (setup.direct_draw)
170 SetDrawtoField(DRAW_DIRECT);
173 if (setup.soft_scrolling)
175 int fx = FX, fy = FY;
177 fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0);
178 fy += (ScreenMovDir & (MV_UP|MV_DOWN) ? ScreenGfxPos : 0);
180 BlitBitmap(fieldbuffer, backbuffer, fx,fy, SXSIZE,SYSIZE, SX,SY);
184 BlitBitmap(drawto, window, x, y, width, height, x, y);
190 DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
192 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
193 redraw_mask &= ~REDRAW_MAIN;
195 if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD)
196 redraw_mask |= REDRAW_FIELD;
198 if (redraw_mask & REDRAW_FIELD)
199 redraw_mask &= ~REDRAW_TILES;
201 if (redraw_mask == REDRAW_NONE)
204 if (global.fps_slowdown && game_status == GAME_MODE_PLAYING)
206 static boolean last_frame_skipped = FALSE;
207 boolean skip_even_when_not_scrolling = TRUE;
208 boolean just_scrolling = (ScreenMovDir != 0);
209 boolean verbose = FALSE;
211 if (global.fps_slowdown_factor > 1 &&
212 (FrameCounter % global.fps_slowdown_factor) &&
213 (just_scrolling || skip_even_when_not_scrolling))
215 redraw_mask &= ~REDRAW_MAIN;
217 last_frame_skipped = TRUE;
220 printf("FRAME SKIPPED\n");
224 if (last_frame_skipped)
225 redraw_mask |= REDRAW_FIELD;
227 last_frame_skipped = FALSE;
230 printf("frame not skipped\n");
234 /* synchronize X11 graphics at this point; if we would synchronize the
235 display immediately after the buffer switching (after the XFlush),
236 this could mean that we have to wait for the graphics to complete,
237 although we could go on doing calculations for the next frame */
241 if (redraw_mask & REDRAW_ALL)
243 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
245 redraw_mask = REDRAW_NONE;
248 if (redraw_mask & REDRAW_FIELD)
250 if (game_status != GAME_MODE_PLAYING ||
251 redraw_mask & REDRAW_FROM_BACKBUFFER)
253 BlitBitmap(backbuffer, window,
254 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
258 int fx = FX, fy = FY;
260 if (setup.soft_scrolling)
262 fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
263 fy += (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
266 if (setup.soft_scrolling ||
267 ABS(ScreenMovPos) + ScrollStepSize == TILEX ||
268 ABS(ScreenMovPos) == ScrollStepSize ||
269 redraw_tiles > REDRAWTILES_THRESHOLD)
271 BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
275 printf("redrawing all (ScreenGfxPos == %d) because %s\n",
277 (setup.soft_scrolling ?
278 "setup.soft_scrolling" :
279 ABS(ScreenGfxPos) + ScrollStepSize == TILEX ?
280 "ABS(ScreenGfxPos) + ScrollStepSize == TILEX" :
281 ABS(ScreenGfxPos) == ScrollStepSize ?
282 "ABS(ScreenGfxPos) == ScrollStepSize" :
283 "redraw_tiles > REDRAWTILES_THRESHOLD"));
289 redraw_mask &= ~REDRAW_MAIN;
292 if (redraw_mask & REDRAW_DOORS)
294 if (redraw_mask & REDRAW_DOOR_1)
295 BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
297 if (redraw_mask & REDRAW_DOOR_2)
298 BlitBitmap(backbuffer, window, VX, VY, VXSIZE, VYSIZE, VX, VY);
300 if (redraw_mask & REDRAW_DOOR_3)
301 BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
303 redraw_mask &= ~REDRAW_DOORS;
306 if (redraw_mask & REDRAW_MICROLEVEL)
308 BlitBitmap(backbuffer, window, SX, SY + 10 * TILEY, SXSIZE, 7 * TILEY,
309 SX, SY + 10 * TILEY);
311 redraw_mask &= ~REDRAW_MICROLEVEL;
314 if (redraw_mask & REDRAW_TILES)
316 for (x = 0; x < SCR_FIELDX; x++)
317 for (y = 0 ; y < SCR_FIELDY; y++)
318 if (redraw[redraw_x1 + x][redraw_y1 + y])
319 BlitBitmap(buffer, window,
320 FX + x * TILEX, FY + y * TILEY, TILEX, TILEY,
321 SX + x * TILEX, SY + y * TILEY);
324 if (redraw_mask & REDRAW_FPS) /* display frames per second */
329 sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
330 if (!global.fps_slowdown)
333 sprintf(text, "%.1f fps%s", global.frames_per_second, info1);
334 DrawTextExt(window, SX, SY, text, FONT_TEXT_2, BLIT_OPAQUE);
339 for (x = 0; x < MAX_BUF_XSIZE; x++)
340 for (y = 0; y < MAX_BUF_YSIZE; y++)
343 redraw_mask = REDRAW_NONE;
349 long fading_delay = 300;
351 if (setup.fading && (redraw_mask & REDRAW_FIELD))
358 ClearRectangle(window, REAL_SX,REAL_SY,FULL_SXSIZE,FULL_SYSIZE);
361 for (i = 0; i < 2 * FULL_SYSIZE; i++)
363 for (y = 0; y < FULL_SYSIZE; y++)
365 BlitBitmap(backbuffer, window,
366 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
374 for (i = 1; i < FULL_SYSIZE; i+=2)
375 BlitBitmap(backbuffer, window,
376 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
382 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, 0);
383 BlitBitmapMasked(backbuffer, window,
384 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
389 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, -1);
390 BlitBitmapMasked(backbuffer, window,
391 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
396 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, -1);
397 BlitBitmapMasked(backbuffer, window,
398 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
403 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, 0);
404 BlitBitmapMasked(backbuffer, window,
405 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
410 redraw_mask &= ~REDRAW_MAIN;
417 void FadeIn(int fade_delay)
426 FadeRectangle(NULL, 0, 0, WIN_XSIZE, WIN_YSIZE,
427 FADE_MODE_FADE_IN, fade_delay, 0);
429 redraw_mask = REDRAW_NONE;
432 void FadeOut(int fade_delay, int post_delay)
436 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
442 FadeRectangle(NULL, 0, 0, WIN_XSIZE, WIN_YSIZE,
443 FADE_MODE_FADE_OUT, fade_delay, post_delay);
445 redraw_mask = REDRAW_NONE;
448 void FadeCross(int fade_delay)
452 BlitBitmap(bitmap_db_title, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
458 FadeRectangle(bitmap_db_title, 0, 0, WIN_XSIZE, WIN_YSIZE,
459 FADE_MODE_CROSSFADE, fade_delay, 0);
461 redraw_mask = REDRAW_NONE;
464 void FadeInField(int fade_delay)
473 FadeRectangle(NULL, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
474 FADE_MODE_FADE_IN, fade_delay, 0);
476 redraw_mask &= ~REDRAW_FIELD;
479 void FadeOutField(int fade_delay, int post_delay)
483 ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
489 FadeRectangle(NULL, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
490 FADE_MODE_FADE_OUT, fade_delay, post_delay);
492 redraw_mask &= ~REDRAW_FIELD;
495 void FadeCrossField(int fade_delay)
499 BlitBitmap(bitmap_db_title, backbuffer, REAL_SX, REAL_SY,
500 FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
506 FadeRectangle(bitmap_db_title, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
507 FADE_MODE_CROSSFADE, fade_delay, 0);
509 redraw_mask &= ~REDRAW_FIELD;
512 void SetMainBackgroundImageIfDefined(int graphic)
514 if (graphic_info[graphic].bitmap)
515 SetMainBackgroundImage(graphic);
518 void SetMainBackgroundImage(int graphic)
520 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
521 graphic_info[graphic].bitmap ?
522 graphic_info[graphic].bitmap :
523 graphic_info[IMG_BACKGROUND].bitmap);
526 void SetDoorBackgroundImage(int graphic)
528 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
529 graphic_info[graphic].bitmap ?
530 graphic_info[graphic].bitmap :
531 graphic_info[IMG_BACKGROUND].bitmap);
534 void SetPanelBackground()
536 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, bitmap_db_panel,
537 DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, 0, 0);
539 SetDoorBackgroundBitmap(bitmap_db_panel);
542 void DrawBackground(int dst_x, int dst_y, int width, int height)
545 ClearRectangleOnBackground(drawto, dst_x, dst_y, width, height);
547 ClearRectangleOnBackground(backbuffer, dst_x, dst_y, width, height);
550 redraw_mask |= REDRAW_FIELD;
555 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
557 if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
559 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
560 SetDrawtoField(DRAW_BUFFERED);
563 SetDrawtoField(DRAW_BACKBUFFER);
565 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
567 ClearRectangle(window, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
568 SetDrawtoField(DRAW_DIRECT);
572 void MarkTileDirty(int x, int y)
574 int xx = redraw_x1 + x;
575 int yy = redraw_y1 + y;
580 redraw[xx][yy] = TRUE;
581 redraw_mask |= REDRAW_TILES;
584 void SetBorderElement()
588 BorderElement = EL_EMPTY;
590 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
592 for (x = 0; x < lev_fieldx; x++)
594 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
595 BorderElement = EL_STEELWALL;
597 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
603 void SetRandomAnimationValue(int x, int y)
605 gfx.anim_random_frame = GfxRandom[x][y];
608 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
610 /* animation synchronized with global frame counter, not move position */
611 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
612 sync_frame = FrameCounter;
615 if (graphic == element_info[EL_CUSTOM_START + 255].graphic[ACTION_DEFAULT] &&
621 printf("::: FOO!\n");
625 return getAnimationFrame(graphic_info[graphic].anim_frames,
626 graphic_info[graphic].anim_delay,
627 graphic_info[graphic].anim_mode,
628 graphic_info[graphic].anim_start_frame,
632 inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
633 int *x, int *y, boolean get_backside)
635 struct GraphicInfo *g = &graphic_info[graphic];
636 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
637 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
641 if (g->offset_y == 0) /* frames are ordered horizontally */
643 int max_width = g->anim_frames_per_line * g->width;
644 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
646 *x = pos % max_width;
647 *y = src_y % g->height + pos / max_width * g->height;
649 else if (g->offset_x == 0) /* frames are ordered vertically */
651 int max_height = g->anim_frames_per_line * g->height;
652 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
654 *x = src_x % g->width + pos / max_height * g->width;
655 *y = pos % max_height;
657 else /* frames are ordered diagonally */
659 *x = src_x + frame * g->offset_x;
660 *y = src_y + frame * g->offset_y;
664 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
666 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
669 void DrawGraphic(int x, int y, int graphic, int frame)
672 if (!IN_SCR_FIELD(x, y))
674 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
675 printf("DrawGraphic(): This should never happen!\n");
680 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
684 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
690 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
691 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
694 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
697 if (!IN_SCR_FIELD(x, y))
699 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
700 printf("DrawGraphicThruMask(): This should never happen!\n");
705 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
710 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
716 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
718 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
719 dst_x - src_x, dst_y - src_y);
720 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
723 void DrawMiniGraphic(int x, int y, int graphic)
725 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
726 MarkTileDirty(x / 2, y / 2);
729 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
731 struct GraphicInfo *g = &graphic_info[graphic];
733 int mini_starty = g->bitmap->height * 2 / 3;
736 *x = mini_startx + g->src_x / 2;
737 *y = mini_starty + g->src_y / 2;
740 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
745 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
746 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
749 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
750 int graphic, int frame,
751 int cut_mode, int mask_mode)
756 int width = TILEX, height = TILEY;
759 if (dx || dy) /* shifted graphic */
761 if (x < BX1) /* object enters playfield from the left */
768 else if (x > BX2) /* object enters playfield from the right */
774 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
780 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
782 else if (dx) /* general horizontal movement */
783 MarkTileDirty(x + SIGN(dx), y);
785 if (y < BY1) /* object enters playfield from the top */
787 if (cut_mode==CUT_BELOW) /* object completely above top border */
795 else if (y > BY2) /* object enters playfield from the bottom */
801 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
807 else if (dy > 0 && cut_mode == CUT_ABOVE)
809 if (y == BY2) /* object completely above bottom border */
815 MarkTileDirty(x, y + 1);
816 } /* object leaves playfield to the bottom */
817 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
819 else if (dy) /* general vertical movement */
820 MarkTileDirty(x, y + SIGN(dy));
824 if (!IN_SCR_FIELD(x, y))
826 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
827 printf("DrawGraphicShifted(): This should never happen!\n");
832 if (width > 0 && height > 0)
834 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
839 dst_x = FX + x * TILEX + dx;
840 dst_y = FY + y * TILEY + dy;
842 if (mask_mode == USE_MASKING)
844 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
845 dst_x - src_x, dst_y - src_y);
846 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
850 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
857 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
858 int graphic, int frame,
859 int cut_mode, int mask_mode)
864 int width = TILEX, height = TILEY;
867 int x2 = x + SIGN(dx);
868 int y2 = y + SIGN(dy);
869 int anim_frames = graphic_info[graphic].anim_frames;
870 int sync_frame = (dx ? ABS(dx) : ABS(dy)) * anim_frames / TILESIZE;
871 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
872 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
874 /* re-calculate animation frame for two-tile movement animation */
875 frame = getGraphicAnimationFrame(graphic, sync_frame);
877 /* check if movement start graphic inside screen area and should be drawn */
878 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
880 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
882 dst_x = FX + x1 * TILEX;
883 dst_y = FY + y1 * TILEY;
885 if (mask_mode == USE_MASKING)
887 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
888 dst_x - src_x, dst_y - src_y);
889 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
893 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
896 MarkTileDirty(x1, y1);
899 /* check if movement end graphic inside screen area and should be drawn */
900 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
902 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
904 dst_x = FX + x2 * TILEX;
905 dst_y = FY + y2 * TILEY;
907 if (mask_mode == USE_MASKING)
909 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
910 dst_x - src_x, dst_y - src_y);
911 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
915 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
918 MarkTileDirty(x2, y2);
922 static void DrawGraphicShifted(int x, int y, int dx, int dy,
923 int graphic, int frame,
924 int cut_mode, int mask_mode)
928 DrawGraphic(x, y, graphic, frame);
933 if (graphic_info[graphic].double_movement) /* EM style movement images */
934 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
936 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
939 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
940 int frame, int cut_mode)
942 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
945 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
946 int cut_mode, int mask_mode)
948 int lx = LEVELX(x), ly = LEVELY(y);
952 if (IN_LEV_FIELD(lx, ly))
954 SetRandomAnimationValue(lx, ly);
956 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
957 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
959 /* do not use double (EM style) movement graphic when not moving */
960 if (graphic_info[graphic].double_movement && !dx && !dy)
962 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
963 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
966 else /* border element */
968 graphic = el2img(element);
969 frame = getGraphicAnimationFrame(graphic, -1);
972 if (element == EL_EXPANDABLE_WALL)
974 boolean left_stopped = FALSE, right_stopped = FALSE;
976 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
978 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
979 right_stopped = TRUE;
981 if (left_stopped && right_stopped)
983 else if (left_stopped)
985 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
986 frame = graphic_info[graphic].anim_frames - 1;
988 else if (right_stopped)
990 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
991 frame = graphic_info[graphic].anim_frames - 1;
996 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
997 else if (mask_mode == USE_MASKING)
998 DrawGraphicThruMask(x, y, graphic, frame);
1000 DrawGraphic(x, y, graphic, frame);
1003 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1004 int cut_mode, int mask_mode)
1006 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1007 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1008 cut_mode, mask_mode);
1011 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1014 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1017 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1020 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1023 void DrawLevelElementThruMask(int x, int y, int element)
1025 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1028 void DrawLevelFieldThruMask(int x, int y)
1030 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1033 static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
1037 int sx = SCREENX(x), sy = SCREENY(y);
1039 int width, height, cx, cy, i;
1040 int crumbled_border_size = graphic_info[graphic].border_size;
1041 static int xy[4][2] =
1049 if (!IN_LEV_FIELD(x, y))
1052 element = TILE_GFX_ELEMENT(x, y);
1054 /* crumble field itself */
1055 if (GFX_CRUMBLED(element) && !IS_MOVING(x, y))
1057 if (!IN_SCR_FIELD(sx, sy))
1060 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1062 for (i = 0; i < 4; i++)
1064 int xx = x + xy[i][0];
1065 int yy = y + xy[i][1];
1067 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1070 /* check if neighbour field is of same type */
1071 if (GFX_CRUMBLED(element) && !IS_MOVING(xx, yy))
1074 if (i == 1 || i == 2)
1076 width = crumbled_border_size;
1078 cx = (i == 2 ? TILEX - crumbled_border_size : 0);
1084 height = crumbled_border_size;
1086 cy = (i == 3 ? TILEY - crumbled_border_size : 0);
1089 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1090 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1093 MarkTileDirty(sx, sy);
1095 else /* crumble neighbour fields */
1097 for (i = 0; i < 4; i++)
1099 int xx = x + xy[i][0];
1100 int yy = y + xy[i][1];
1101 int sxx = sx + xy[i][0];
1102 int syy = sy + xy[i][1];
1105 if (!IN_LEV_FIELD(xx, yy) ||
1106 !IN_SCR_FIELD(sxx, syy) ||
1111 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
1115 element = TILE_GFX_ELEMENT(xx, yy);
1117 if (!GFX_CRUMBLED(element))
1120 if (!IN_LEV_FIELD(xx, yy) ||
1121 !IN_SCR_FIELD(sxx, syy) ||
1122 !GFX_CRUMBLED(Feld[xx][yy]) ||
1128 graphic = el_act2crm(element, ACTION_DEFAULT);
1130 graphic = el_act2crm(Feld[xx][yy], ACTION_DEFAULT);
1132 crumbled_border_size = graphic_info[graphic].border_size;
1134 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1136 if (i == 1 || i == 2)
1138 width = crumbled_border_size;
1140 cx = (i == 1 ? TILEX - crumbled_border_size : 0);
1146 height = crumbled_border_size;
1148 cy = (i == 0 ? TILEY - crumbled_border_size : 0);
1151 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1152 width, height, FX + sxx * TILEX + cx, FY + syy * TILEY + cy);
1154 MarkTileDirty(sxx, syy);
1159 void DrawLevelFieldCrumbledSand(int x, int y)
1163 if (!IN_LEV_FIELD(x, y))
1167 /* !!! CHECK THIS !!! */
1170 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1171 GFX_CRUMBLED(GfxElement[x][y]))
1174 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1175 GfxElement[x][y] != EL_UNDEFINED &&
1176 GFX_CRUMBLED(GfxElement[x][y]))
1178 DrawLevelFieldCrumbledSandDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
1185 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
1187 graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
1190 DrawLevelFieldCrumbledSandExt(x, y, graphic, 0);
1193 void DrawLevelFieldCrumbledSandDigging(int x, int y, int direction,
1196 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1197 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1198 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1199 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1200 int sx = SCREENX(x), sy = SCREENY(y);
1202 DrawGraphic(sx, sy, graphic1, frame1);
1203 DrawLevelFieldCrumbledSandExt(x, y, graphic2, frame2);
1206 void DrawLevelFieldCrumbledSandNeighbours(int x, int y)
1208 int sx = SCREENX(x), sy = SCREENY(y);
1209 static int xy[4][2] =
1218 for (i = 0; i < 4; i++)
1220 int xx = x + xy[i][0];
1221 int yy = y + xy[i][1];
1222 int sxx = sx + xy[i][0];
1223 int syy = sy + xy[i][1];
1225 if (!IN_LEV_FIELD(xx, yy) ||
1226 !IN_SCR_FIELD(sxx, syy) ||
1227 !GFX_CRUMBLED(Feld[xx][yy]) ||
1231 DrawLevelField(xx, yy);
1235 static int getBorderElement(int x, int y)
1239 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1240 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1241 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1242 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1243 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1244 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1245 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1247 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1248 int steel_position = (x == -1 && y == -1 ? 0 :
1249 x == lev_fieldx && y == -1 ? 1 :
1250 x == -1 && y == lev_fieldy ? 2 :
1251 x == lev_fieldx && y == lev_fieldy ? 3 :
1252 x == -1 || x == lev_fieldx ? 4 :
1253 y == -1 || y == lev_fieldy ? 5 : 6);
1255 return border[steel_position][steel_type];
1258 void DrawScreenElement(int x, int y, int element)
1260 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1261 DrawLevelFieldCrumbledSand(LEVELX(x), LEVELY(y));
1264 void DrawLevelElement(int x, int y, int element)
1266 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1267 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1270 void DrawScreenField(int x, int y)
1272 int lx = LEVELX(x), ly = LEVELY(y);
1273 int element, content;
1275 if (!IN_LEV_FIELD(lx, ly))
1277 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1280 element = getBorderElement(lx, ly);
1282 DrawScreenElement(x, y, element);
1286 element = Feld[lx][ly];
1287 content = Store[lx][ly];
1289 if (IS_MOVING(lx, ly))
1291 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1292 boolean cut_mode = NO_CUTTING;
1294 if (element == EL_QUICKSAND_EMPTYING ||
1295 element == EL_MAGIC_WALL_EMPTYING ||
1296 element == EL_BD_MAGIC_WALL_EMPTYING ||
1297 element == EL_AMOEBA_DROPPING)
1298 cut_mode = CUT_ABOVE;
1299 else if (element == EL_QUICKSAND_FILLING ||
1300 element == EL_MAGIC_WALL_FILLING ||
1301 element == EL_BD_MAGIC_WALL_FILLING)
1302 cut_mode = CUT_BELOW;
1304 if (cut_mode == CUT_ABOVE)
1305 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1307 DrawScreenElement(x, y, EL_EMPTY);
1310 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1311 else if (cut_mode == NO_CUTTING)
1312 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1314 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1316 if (content == EL_ACID)
1318 int dir = MovDir[lx][ly];
1319 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
1320 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
1322 DrawLevelElementThruMask(newlx, newly, EL_ACID);
1325 else if (IS_BLOCKED(lx, ly))
1330 boolean cut_mode = NO_CUTTING;
1331 int element_old, content_old;
1333 Blocked2Moving(lx, ly, &oldx, &oldy);
1336 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1337 MovDir[oldx][oldy] == MV_RIGHT);
1339 element_old = Feld[oldx][oldy];
1340 content_old = Store[oldx][oldy];
1342 if (element_old == EL_QUICKSAND_EMPTYING ||
1343 element_old == EL_MAGIC_WALL_EMPTYING ||
1344 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1345 element_old == EL_AMOEBA_DROPPING)
1346 cut_mode = CUT_ABOVE;
1348 DrawScreenElement(x, y, EL_EMPTY);
1351 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1353 else if (cut_mode == NO_CUTTING)
1354 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1357 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1360 else if (IS_DRAWABLE(element))
1361 DrawScreenElement(x, y, element);
1363 DrawScreenElement(x, y, EL_EMPTY);
1366 void DrawLevelField(int x, int y)
1368 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1369 DrawScreenField(SCREENX(x), SCREENY(y));
1370 else if (IS_MOVING(x, y))
1374 Moving2Blocked(x, y, &newx, &newy);
1375 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1376 DrawScreenField(SCREENX(newx), SCREENY(newy));
1378 else if (IS_BLOCKED(x, y))
1382 Blocked2Moving(x, y, &oldx, &oldy);
1383 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1384 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1388 void DrawMiniElement(int x, int y, int element)
1392 graphic = el2edimg(element);
1393 DrawMiniGraphic(x, y, graphic);
1396 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1398 int x = sx + scroll_x, y = sy + scroll_y;
1400 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1401 DrawMiniElement(sx, sy, EL_EMPTY);
1402 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1403 DrawMiniElement(sx, sy, Feld[x][y]);
1405 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1408 void DrawEnvelopeBackground(int envelope_nr, int startx, int starty,
1409 int x, int y, int xsize, int ysize, int font_nr)
1411 int font_width = getFontWidth(font_nr);
1412 int font_height = getFontHeight(font_nr);
1413 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1416 int dst_x = SX + startx + x * font_width;
1417 int dst_y = SY + starty + y * font_height;
1418 int width = graphic_info[graphic].width;
1419 int height = graphic_info[graphic].height;
1420 int inner_width = MAX(width - 2 * font_width, font_width);
1421 int inner_height = MAX(height - 2 * font_height, font_height);
1422 int inner_sx = (width >= 3 * font_width ? font_width : 0);
1423 int inner_sy = (height >= 3 * font_height ? font_height : 0);
1424 boolean draw_masked = graphic_info[graphic].draw_masked;
1426 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1428 if (src_bitmap == NULL || width < font_width || height < font_height)
1430 ClearRectangle(drawto, dst_x, dst_y, font_width, font_height);
1434 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - font_width :
1435 inner_sx + (x - 1) * font_width % inner_width);
1436 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - font_height :
1437 inner_sy + (y - 1) * font_height % inner_height);
1441 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1442 dst_x - src_x, dst_y - src_y);
1443 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1447 BlitBitmap(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1451 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
1453 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1454 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1455 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
1456 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1457 boolean no_delay = (tape.warp_forward);
1458 unsigned long anim_delay = 0;
1459 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
1460 int anim_delay_value = (no_delay ? 0 : frame_delay_value);
1461 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
1462 int font_width = getFontWidth(font_nr);
1463 int font_height = getFontHeight(font_nr);
1464 int max_xsize = level.envelope[envelope_nr].xsize;
1465 int max_ysize = level.envelope[envelope_nr].ysize;
1466 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
1467 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
1468 int xend = max_xsize;
1469 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
1470 int xstep = (xstart < xend ? 1 : 0);
1471 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
1474 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
1476 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
1477 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
1478 int sx = (SXSIZE - xsize * font_width) / 2;
1479 int sy = (SYSIZE - ysize * font_height) / 2;
1482 SetDrawtoField(DRAW_BUFFERED);
1484 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
1486 SetDrawtoField(DRAW_BACKBUFFER);
1488 for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++)
1489 DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
1491 DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
1492 level.envelope[envelope_nr].text, font_nr, max_xsize,
1493 xsize - 2, ysize - 2, mask_mode);
1495 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
1498 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
1502 void ShowEnvelope(int envelope_nr)
1504 int element = EL_ENVELOPE_1 + envelope_nr;
1505 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1506 int sound_opening = element_info[element].sound[ACTION_OPENING];
1507 int sound_closing = element_info[element].sound[ACTION_CLOSING];
1508 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1509 boolean no_delay = (tape.warp_forward);
1510 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
1511 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
1512 int anim_mode = graphic_info[graphic].anim_mode;
1513 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
1514 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
1516 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
1518 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
1520 if (anim_mode == ANIM_DEFAULT)
1521 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
1523 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
1526 Delay(wait_delay_value);
1528 WaitForEventToContinue();
1530 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
1532 if (anim_mode != ANIM_NONE)
1533 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
1535 if (anim_mode == ANIM_DEFAULT)
1536 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
1538 game.envelope_active = FALSE;
1540 SetDrawtoField(DRAW_BUFFERED);
1542 redraw_mask |= REDRAW_FIELD;
1546 void getPreviewGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y,
1551 int width_mult, width_div;
1552 int height_mult, height_div;
1560 int offset_calc_pos = (tilesize < MICRO_TILESIZE || tilesize > TILESIZE ? 3 :
1561 5 - log_2(tilesize));
1562 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1563 int width_mult = offset_calc[offset_calc_pos].width_mult;
1564 int width_div = offset_calc[offset_calc_pos].width_div;
1565 int height_mult = offset_calc[offset_calc_pos].height_mult;
1566 int height_div = offset_calc[offset_calc_pos].height_div;
1567 int mini_startx = src_bitmap->width * width_mult / width_div;
1568 int mini_starty = src_bitmap->height * height_mult / height_div;
1569 int src_x = mini_startx + graphic_info[graphic].src_x * tilesize / TILESIZE;
1570 int src_y = mini_starty + graphic_info[graphic].src_y * tilesize / TILESIZE;
1572 *bitmap = src_bitmap;
1577 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
1581 int graphic = el2preimg(element);
1583 getPreviewGraphicSource(graphic, &src_bitmap, &src_x, &src_y, tilesize);
1584 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
1591 SetDrawBackgroundMask(REDRAW_NONE);
1594 for (x = BX1; x <= BX2; x++)
1595 for (y = BY1; y <= BY2; y++)
1596 DrawScreenField(x, y);
1598 redraw_mask |= REDRAW_FIELD;
1601 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1605 for (x = 0; x < size_x; x++)
1606 for (y = 0; y < size_y; y++)
1607 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1609 redraw_mask |= REDRAW_FIELD;
1612 static void DrawPreviewLevelExt(int from_x, int from_y)
1614 boolean show_level_border = (BorderElement != EL_EMPTY);
1615 int dst_x = preview.x;
1616 int dst_y = preview.y;
1617 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
1618 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
1619 int tile_size = preview.tile_size;
1620 int preview_width = preview.xsize * tile_size;
1621 int preview_height = preview.ysize * tile_size;
1622 int real_preview_xsize = MIN(level_xsize, preview.xsize);
1623 int real_preview_ysize = MIN(level_ysize, preview.ysize);
1626 DrawBackground(dst_x, dst_y, preview_width, preview_height);
1628 dst_x += (preview_width - real_preview_xsize * tile_size) / 2;
1629 dst_y += (preview_height - real_preview_ysize * tile_size) / 2;
1631 for (x = 0; x < real_preview_xsize; x++)
1633 for (y = 0; y < real_preview_ysize; y++)
1635 int lx = from_x + x + (show_level_border ? -1 : 0);
1636 int ly = from_y + y + (show_level_border ? -1 : 0);
1637 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
1638 getBorderElement(lx, ly));
1640 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
1641 element, tile_size);
1645 redraw_mask |= REDRAW_MICROLEVEL;
1648 #define MICROLABEL_EMPTY 0
1649 #define MICROLABEL_LEVEL_NAME 1
1650 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
1651 #define MICROLABEL_LEVEL_AUTHOR 3
1652 #define MICROLABEL_IMPORTED_FROM_HEAD 4
1653 #define MICROLABEL_IMPORTED_FROM 5
1654 #define MICROLABEL_IMPORTED_BY_HEAD 6
1655 #define MICROLABEL_IMPORTED_BY 7
1657 static void DrawPreviewLevelLabelExt(int mode)
1659 char label_text[MAX_OUTPUT_LINESIZE + 1];
1660 int max_len_label_text;
1661 int font_nr = FONT_TEXT_2;
1664 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
1665 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
1666 mode == MICROLABEL_IMPORTED_BY_HEAD)
1667 font_nr = FONT_TEXT_3;
1669 max_len_label_text = SXSIZE / getFontWidth(font_nr);
1671 for (i = 0; i < max_len_label_text; i++)
1672 label_text[i] = ' ';
1673 label_text[max_len_label_text] = '\0';
1675 if (strlen(label_text) > 0)
1677 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1678 int lypos = MICROLABEL2_YPOS;
1680 DrawText(lxpos, lypos, label_text, font_nr);
1684 (mode == MICROLABEL_LEVEL_NAME ? level.name :
1685 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
1686 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1687 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
1688 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
1689 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
1690 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
1691 max_len_label_text);
1692 label_text[max_len_label_text] = '\0';
1694 if (strlen(label_text) > 0)
1696 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1697 int lypos = MICROLABEL2_YPOS;
1699 DrawText(lxpos, lypos, label_text, font_nr);
1702 redraw_mask |= REDRAW_MICROLEVEL;
1705 void DrawPreviewLevel(boolean restart)
1707 static unsigned long scroll_delay = 0;
1708 static unsigned long label_delay = 0;
1709 static int from_x, from_y, scroll_direction;
1710 static int label_state, label_counter;
1711 unsigned long scroll_delay_value = preview.step_delay;
1712 boolean show_level_border = (BorderElement != EL_EMPTY);
1713 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
1714 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
1715 int last_game_status = game_status; /* save current game status */
1717 /* force PREVIEW font on preview level */
1718 game_status = GAME_MODE_PSEUDO_PREVIEW;
1722 from_x = from_y = 0;
1723 scroll_direction = MV_RIGHT;
1727 DrawPreviewLevelExt(from_x, from_y);
1728 DrawPreviewLevelLabelExt(label_state);
1730 /* initialize delay counters */
1731 DelayReached(&scroll_delay, 0);
1732 DelayReached(&label_delay, 0);
1734 if (leveldir_current->name)
1736 char label_text[MAX_OUTPUT_LINESIZE + 1];
1737 int font_nr = FONT_TEXT_1;
1738 int max_len_label_text = SXSIZE / getFontWidth(font_nr);
1741 strncpy(label_text, leveldir_current->name, max_len_label_text);
1742 label_text[max_len_label_text] = '\0';
1744 lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1745 lypos = SY + MICROLABEL1_YPOS;
1747 DrawText(lxpos, lypos, label_text, font_nr);
1750 game_status = last_game_status; /* restore current game status */
1755 /* scroll preview level, if needed */
1756 if ((level_xsize > preview.xsize || level_ysize > preview.ysize) &&
1757 DelayReached(&scroll_delay, scroll_delay_value))
1759 switch (scroll_direction)
1764 from_x -= preview.step_offset;
1765 from_x = (from_x < 0 ? 0 : from_x);
1768 scroll_direction = MV_UP;
1772 if (from_x < level_xsize - preview.xsize)
1774 from_x += preview.step_offset;
1775 from_x = (from_x > level_xsize - preview.xsize ?
1776 level_xsize - preview.xsize : from_x);
1779 scroll_direction = MV_DOWN;
1785 from_y -= preview.step_offset;
1786 from_y = (from_y < 0 ? 0 : from_y);
1789 scroll_direction = MV_RIGHT;
1793 if (from_y < level_ysize - preview.ysize)
1795 from_y += preview.step_offset;
1796 from_y = (from_y > level_ysize - preview.ysize ?
1797 level_ysize - preview.ysize : from_y);
1800 scroll_direction = MV_LEFT;
1807 DrawPreviewLevelExt(from_x, from_y);
1810 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
1811 /* redraw micro level label, if needed */
1812 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
1813 !strEqual(level.author, ANONYMOUS_NAME) &&
1814 !strEqual(level.author, leveldir_current->name) &&
1815 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
1817 int max_label_counter = 23;
1819 if (leveldir_current->imported_from != NULL &&
1820 strlen(leveldir_current->imported_from) > 0)
1821 max_label_counter += 14;
1822 if (leveldir_current->imported_by != NULL &&
1823 strlen(leveldir_current->imported_by) > 0)
1824 max_label_counter += 14;
1826 label_counter = (label_counter + 1) % max_label_counter;
1827 label_state = (label_counter >= 0 && label_counter <= 7 ?
1828 MICROLABEL_LEVEL_NAME :
1829 label_counter >= 9 && label_counter <= 12 ?
1830 MICROLABEL_LEVEL_AUTHOR_HEAD :
1831 label_counter >= 14 && label_counter <= 21 ?
1832 MICROLABEL_LEVEL_AUTHOR :
1833 label_counter >= 23 && label_counter <= 26 ?
1834 MICROLABEL_IMPORTED_FROM_HEAD :
1835 label_counter >= 28 && label_counter <= 35 ?
1836 MICROLABEL_IMPORTED_FROM :
1837 label_counter >= 37 && label_counter <= 40 ?
1838 MICROLABEL_IMPORTED_BY_HEAD :
1839 label_counter >= 42 && label_counter <= 49 ?
1840 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
1842 if (leveldir_current->imported_from == NULL &&
1843 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
1844 label_state == MICROLABEL_IMPORTED_FROM))
1845 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
1846 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
1848 DrawPreviewLevelLabelExt(label_state);
1851 game_status = last_game_status; /* restore current game status */
1854 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
1855 int graphic, int sync_frame, int mask_mode)
1857 int frame = getGraphicAnimationFrame(graphic, sync_frame);
1859 if (mask_mode == USE_MASKING)
1860 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
1862 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
1865 inline void DrawGraphicAnimation(int x, int y, int graphic)
1867 int lx = LEVELX(x), ly = LEVELY(y);
1869 if (!IN_SCR_FIELD(x, y))
1872 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
1873 graphic, GfxFrame[lx][ly], NO_MASKING);
1874 MarkTileDirty(x, y);
1877 void DrawLevelGraphicAnimation(int x, int y, int graphic)
1879 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
1882 void DrawLevelElementAnimation(int x, int y, int element)
1884 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
1886 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
1889 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
1891 int sx = SCREENX(x), sy = SCREENY(y);
1893 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
1896 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
1899 DrawGraphicAnimation(sx, sy, graphic);
1902 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
1903 DrawLevelFieldCrumbledSand(x, y);
1905 if (GFX_CRUMBLED(Feld[x][y]))
1906 DrawLevelFieldCrumbledSand(x, y);
1910 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
1912 int sx = SCREENX(x), sy = SCREENY(y);
1915 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
1918 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
1920 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
1923 DrawGraphicAnimation(sx, sy, graphic);
1925 if (GFX_CRUMBLED(element))
1926 DrawLevelFieldCrumbledSand(x, y);
1929 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
1931 if (player->use_murphy)
1933 /* this works only because currently only one player can be "murphy" ... */
1934 static int last_horizontal_dir = MV_LEFT;
1935 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
1937 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
1938 last_horizontal_dir = move_dir;
1940 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
1942 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
1944 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
1950 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
1953 static boolean equalGraphics(int graphic1, int graphic2)
1955 struct GraphicInfo *g1 = &graphic_info[graphic1];
1956 struct GraphicInfo *g2 = &graphic_info[graphic2];
1958 return (g1->bitmap == g2->bitmap &&
1959 g1->src_x == g2->src_x &&
1960 g1->src_y == g2->src_y &&
1961 g1->anim_frames == g2->anim_frames &&
1962 g1->anim_delay == g2->anim_delay &&
1963 g1->anim_mode == g2->anim_mode);
1966 void DrawAllPlayers()
1970 for (i = 0; i < MAX_PLAYERS; i++)
1971 if (stored_player[i].active)
1972 DrawPlayer(&stored_player[i]);
1975 void DrawPlayerField(int x, int y)
1977 if (!IS_PLAYER(x, y))
1980 DrawPlayer(PLAYERINFO(x, y));
1983 void DrawPlayer(struct PlayerInfo *player)
1985 int jx = player->jx;
1986 int jy = player->jy;
1987 int move_dir = player->MovDir;
1988 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
1989 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
1990 int last_jx = (player->is_moving ? jx - dx : jx);
1991 int last_jy = (player->is_moving ? jy - dy : jy);
1992 int next_jx = jx + dx;
1993 int next_jy = jy + dy;
1994 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
1995 boolean player_is_opaque = FALSE;
1996 int sx = SCREENX(jx), sy = SCREENY(jy);
1997 int sxx = 0, syy = 0;
1998 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
2000 int action = ACTION_DEFAULT;
2001 int last_player_graphic = getPlayerGraphic(player, move_dir);
2002 int last_player_frame = player->Frame;
2006 /* GfxElement[][] is set to the element the player is digging or collecting;
2007 remove also for off-screen player if the player is not moving anymore */
2008 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
2009 GfxElement[jx][jy] = EL_UNDEFINED;
2012 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
2016 if (!IN_LEV_FIELD(jx, jy))
2018 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
2019 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
2020 printf("DrawPlayerField(): This should never happen!\n");
2025 if (element == EL_EXPLOSION)
2028 action = (player->is_pushing ? ACTION_PUSHING :
2029 player->is_digging ? ACTION_DIGGING :
2030 player->is_collecting ? ACTION_COLLECTING :
2031 player->is_moving ? ACTION_MOVING :
2032 player->is_snapping ? ACTION_SNAPPING :
2033 player->is_dropping ? ACTION_DROPPING :
2034 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
2037 if (player->is_waiting)
2038 move_dir = player->dir_waiting;
2041 InitPlayerGfxAnimation(player, action, move_dir);
2043 /* ----------------------------------------------------------------------- */
2044 /* draw things in the field the player is leaving, if needed */
2045 /* ----------------------------------------------------------------------- */
2047 if (player->is_moving)
2049 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
2051 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
2053 if (last_element == EL_DYNAMITE_ACTIVE ||
2054 last_element == EL_EM_DYNAMITE_ACTIVE ||
2055 last_element == EL_SP_DISK_RED_ACTIVE)
2056 DrawDynamite(last_jx, last_jy);
2058 DrawLevelFieldThruMask(last_jx, last_jy);
2060 else if (last_element == EL_DYNAMITE_ACTIVE ||
2061 last_element == EL_EM_DYNAMITE_ACTIVE ||
2062 last_element == EL_SP_DISK_RED_ACTIVE)
2063 DrawDynamite(last_jx, last_jy);
2065 /* !!! this is not enough to prevent flickering of players which are
2066 moving next to each others without a free tile between them -- this
2067 can only be solved by drawing all players layer by layer (first the
2068 background, then the foreground etc.) !!! => TODO */
2069 else if (!IS_PLAYER(last_jx, last_jy))
2070 DrawLevelField(last_jx, last_jy);
2073 DrawLevelField(last_jx, last_jy);
2076 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
2077 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
2080 if (!IN_SCR_FIELD(sx, sy))
2083 if (setup.direct_draw)
2084 SetDrawtoField(DRAW_BUFFERED);
2086 /* ----------------------------------------------------------------------- */
2087 /* draw things behind the player, if needed */
2088 /* ----------------------------------------------------------------------- */
2091 DrawLevelElement(jx, jy, Back[jx][jy]);
2092 else if (IS_ACTIVE_BOMB(element))
2093 DrawLevelElement(jx, jy, EL_EMPTY);
2096 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
2098 int old_element = GfxElement[jx][jy];
2099 int old_graphic = el_act_dir2img(old_element, action, move_dir);
2100 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
2102 if (GFX_CRUMBLED(old_element))
2103 DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
2105 DrawGraphic(sx, sy, old_graphic, frame);
2107 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
2108 player_is_opaque = TRUE;
2112 GfxElement[jx][jy] = EL_UNDEFINED;
2114 /* make sure that pushed elements are drawn with correct frame rate */
2116 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2118 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
2119 GfxFrame[jx][jy] = player->StepFrame;
2121 if (player->is_pushing && player->is_moving)
2122 GfxFrame[jx][jy] = player->StepFrame;
2125 DrawLevelField(jx, jy);
2129 /* ----------------------------------------------------------------------- */
2130 /* draw player himself */
2131 /* ----------------------------------------------------------------------- */
2133 graphic = getPlayerGraphic(player, move_dir);
2135 /* in the case of changed player action or direction, prevent the current
2136 animation frame from being restarted for identical animations */
2137 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
2138 player->Frame = last_player_frame;
2140 frame = getGraphicAnimationFrame(graphic, player->Frame);
2144 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2145 sxx = player->GfxPos;
2147 syy = player->GfxPos;
2150 if (!setup.soft_scrolling && ScreenMovPos)
2153 if (player_is_opaque)
2154 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
2156 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2158 if (SHIELD_ON(player))
2160 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
2161 IMG_SHIELD_NORMAL_ACTIVE);
2162 int frame = getGraphicAnimationFrame(graphic, -1);
2164 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2167 /* ----------------------------------------------------------------------- */
2168 /* draw things the player is pushing, if needed */
2169 /* ----------------------------------------------------------------------- */
2172 printf("::: %d, %d [%d, %d] [%d]\n",
2173 player->is_pushing, player_is_moving, player->GfxAction,
2174 player->is_moving, player_is_moving);
2178 if (player->is_pushing && player->is_moving)
2180 int px = SCREENX(jx), py = SCREENY(jy);
2181 int pxx = (TILEX - ABS(sxx)) * dx;
2182 int pyy = (TILEY - ABS(syy)) * dy;
2183 int gfx_frame = GfxFrame[jx][jy];
2189 if (!IS_MOVING(jx, jy)) /* push movement already finished */
2191 element = Feld[next_jx][next_jy];
2192 gfx_frame = GfxFrame[next_jx][next_jy];
2195 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2198 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
2199 frame = getGraphicAnimationFrame(graphic, sync_frame);
2201 frame = getGraphicAnimationFrame(graphic, player->StepFrame);
2204 /* draw background element under pushed element (like the Sokoban field) */
2205 if (Back[next_jx][next_jy])
2206 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
2208 /* masked drawing is needed for EMC style (double) movement graphics */
2209 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
2213 /* ----------------------------------------------------------------------- */
2214 /* draw things in front of player (active dynamite or dynabombs) */
2215 /* ----------------------------------------------------------------------- */
2217 if (IS_ACTIVE_BOMB(element))
2219 graphic = el2img(element);
2220 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
2222 if (game.emulation == EMU_SUPAPLEX)
2223 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
2225 DrawGraphicThruMask(sx, sy, graphic, frame);
2228 if (player_is_moving && last_element == EL_EXPLOSION)
2230 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
2231 GfxElement[last_jx][last_jy] : EL_EMPTY);
2232 int graphic = el_act2img(element, ACTION_EXPLODING);
2233 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
2234 int phase = ExplodePhase[last_jx][last_jy] - 1;
2235 int frame = getGraphicAnimationFrame(graphic, phase - delay);
2238 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
2241 /* ----------------------------------------------------------------------- */
2242 /* draw elements the player is just walking/passing through/under */
2243 /* ----------------------------------------------------------------------- */
2245 if (player_is_moving)
2247 /* handle the field the player is leaving ... */
2248 if (IS_ACCESSIBLE_INSIDE(last_element))
2249 DrawLevelField(last_jx, last_jy);
2250 else if (IS_ACCESSIBLE_UNDER(last_element))
2251 DrawLevelFieldThruMask(last_jx, last_jy);
2254 /* do not redraw accessible elements if the player is just pushing them */
2255 if (!player_is_moving || !player->is_pushing)
2257 /* ... and the field the player is entering */
2258 if (IS_ACCESSIBLE_INSIDE(element))
2259 DrawLevelField(jx, jy);
2260 else if (IS_ACCESSIBLE_UNDER(element))
2261 DrawLevelFieldThruMask(jx, jy);
2264 if (setup.direct_draw)
2266 int dst_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
2267 int dst_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
2268 int x_size = TILEX * (1 + ABS(jx - last_jx));
2269 int y_size = TILEY * (1 + ABS(jy - last_jy));
2271 BlitBitmap(drawto_field, window,
2272 dst_x, dst_y, x_size, y_size, dst_x, dst_y);
2273 SetDrawtoField(DRAW_DIRECT);
2276 MarkTileDirty(sx, sy);
2279 /* ------------------------------------------------------------------------- */
2281 void WaitForEventToContinue()
2283 boolean still_wait = TRUE;
2285 /* simulate releasing mouse button over last gadget, if still pressed */
2287 HandleGadgets(-1, -1, 0);
2289 button_status = MB_RELEASED;
2301 case EVENT_BUTTONPRESS:
2302 case EVENT_KEYPRESS:
2306 case EVENT_KEYRELEASE:
2307 ClearPlayerAction();
2311 HandleOtherEvents(&event);
2315 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2322 /* don't eat all CPU time */
2327 #define MAX_REQUEST_LINES 13
2328 #define MAX_REQUEST_LINE_FONT1_LEN 7
2329 #define MAX_REQUEST_LINE_FONT2_LEN 10
2331 boolean Request(char *text, unsigned int req_state)
2333 int mx, my, ty, result = -1;
2334 unsigned int old_door_state;
2335 int last_game_status = game_status; /* save current game status */
2336 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
2337 int font_nr = FONT_TEXT_2;
2338 int max_word_len = 0;
2341 for (text_ptr = text; *text_ptr; text_ptr++)
2343 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
2345 if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
2347 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
2348 font_nr = FONT_LEVEL_NUMBER;
2354 if (game_status == GAME_MODE_PLAYING &&
2355 level.game_engine_type == GAME_ENGINE_TYPE_EM)
2356 BlitScreenToBitmap_EM(backbuffer);
2358 /* disable deactivated drawing when quick-loading level tape recording */
2359 if (tape.playing && tape.deactivate_display)
2360 TapeDeactivateDisplayOff(TRUE);
2362 SetMouseCursor(CURSOR_DEFAULT);
2364 #if defined(NETWORK_AVALIABLE)
2365 /* pause network game while waiting for request to answer */
2366 if (options.network &&
2367 game_status == GAME_MODE_PLAYING &&
2368 req_state & REQUEST_WAIT_FOR_INPUT)
2369 SendToServer_PausePlaying();
2372 old_door_state = GetDoorState();
2374 /* simulate releasing mouse button over last gadget, if still pressed */
2376 HandleGadgets(-1, -1, 0);
2380 if (old_door_state & DOOR_OPEN_1)
2382 CloseDoor(DOOR_CLOSE_1);
2384 /* save old door content */
2385 BlitBitmap(bitmap_db_door, bitmap_db_door,
2386 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2387 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
2391 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2394 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2396 /* clear door drawing field */
2397 DrawBackground(DX, DY, DXSIZE, DYSIZE);
2399 /* force DOOR font on preview level */
2400 game_status = GAME_MODE_PSEUDO_DOOR;
2402 /* write text for request */
2403 for (ty = 0; ty < MAX_REQUEST_LINES; ty++)
2405 char text_line[max_request_line_len + 1];
2411 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
2414 if (!tc || tc == ' ')
2425 strncpy(text_line, text, tl);
2428 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
2429 DY + 8 + ty * (getFontHeight(font_nr) + 2),
2430 text_line, font_nr);
2432 text += tl + (tc == ' ' ? 1 : 0);
2435 game_status = last_game_status; /* restore current game status */
2437 if (req_state & REQ_ASK)
2439 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2440 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2442 else if (req_state & REQ_CONFIRM)
2444 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2446 else if (req_state & REQ_PLAYER)
2448 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2449 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2450 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2451 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2454 /* copy request gadgets to door backbuffer */
2455 BlitBitmap(drawto, bitmap_db_door,
2456 DX, DY, DXSIZE, DYSIZE,
2457 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2459 OpenDoor(DOOR_OPEN_1);
2461 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
2463 if (game_status == GAME_MODE_PLAYING)
2465 SetPanelBackground();
2466 SetDrawBackgroundMask(REDRAW_DOOR_1);
2470 SetDrawBackgroundMask(REDRAW_FIELD);
2476 if (game_status != GAME_MODE_MAIN)
2479 button_status = MB_RELEASED;
2481 request_gadget_id = -1;
2483 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2495 case EVENT_BUTTONPRESS:
2496 case EVENT_BUTTONRELEASE:
2497 case EVENT_MOTIONNOTIFY:
2499 if (event.type == EVENT_MOTIONNOTIFY)
2501 if (!PointerInWindow(window))
2502 continue; /* window and pointer are on different screens */
2507 motion_status = TRUE;
2508 mx = ((MotionEvent *) &event)->x;
2509 my = ((MotionEvent *) &event)->y;
2513 motion_status = FALSE;
2514 mx = ((ButtonEvent *) &event)->x;
2515 my = ((ButtonEvent *) &event)->y;
2516 if (event.type == EVENT_BUTTONPRESS)
2517 button_status = ((ButtonEvent *) &event)->button;
2519 button_status = MB_RELEASED;
2522 /* this sets 'request_gadget_id' */
2523 HandleGadgets(mx, my, button_status);
2525 switch(request_gadget_id)
2527 case TOOL_CTRL_ID_YES:
2530 case TOOL_CTRL_ID_NO:
2533 case TOOL_CTRL_ID_CONFIRM:
2534 result = TRUE | FALSE;
2537 case TOOL_CTRL_ID_PLAYER_1:
2540 case TOOL_CTRL_ID_PLAYER_2:
2543 case TOOL_CTRL_ID_PLAYER_3:
2546 case TOOL_CTRL_ID_PLAYER_4:
2557 case EVENT_KEYPRESS:
2558 switch(GetEventKey((KeyEvent *)&event, TRUE))
2571 if (req_state & REQ_PLAYER)
2575 case EVENT_KEYRELEASE:
2576 ClearPlayerAction();
2580 HandleOtherEvents(&event);
2584 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2586 int joy = AnyJoystick();
2588 if (joy & JOY_BUTTON_1)
2590 else if (joy & JOY_BUTTON_2)
2596 /* don't eat all CPU time */
2600 if (game_status != GAME_MODE_MAIN)
2605 if (!(req_state & REQ_STAY_OPEN))
2607 CloseDoor(DOOR_CLOSE_1);
2609 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
2610 (req_state & REQ_REOPEN))
2611 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
2616 if (game_status == GAME_MODE_PLAYING)
2618 SetPanelBackground();
2619 SetDrawBackgroundMask(REDRAW_DOOR_1);
2623 SetDrawBackgroundMask(REDRAW_FIELD);
2626 #if defined(NETWORK_AVALIABLE)
2627 /* continue network game after request */
2628 if (options.network &&
2629 game_status == GAME_MODE_PLAYING &&
2630 req_state & REQUEST_WAIT_FOR_INPUT)
2631 SendToServer_ContinuePlaying();
2634 /* restore deactivated drawing when quick-loading level tape recording */
2635 if (tape.playing && tape.deactivate_display)
2636 TapeDeactivateDisplayOn();
2641 unsigned int OpenDoor(unsigned int door_state)
2643 if (door_state & DOOR_COPY_BACK)
2645 if (door_state & DOOR_OPEN_1)
2646 BlitBitmap(bitmap_db_door, bitmap_db_door,
2647 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2648 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2650 if (door_state & DOOR_OPEN_2)
2651 BlitBitmap(bitmap_db_door, bitmap_db_door,
2652 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
2653 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2655 door_state &= ~DOOR_COPY_BACK;
2658 return MoveDoor(door_state);
2661 unsigned int CloseDoor(unsigned int door_state)
2663 unsigned int old_door_state = GetDoorState();
2665 if (!(door_state & DOOR_NO_COPY_BACK))
2667 if (old_door_state & DOOR_OPEN_1)
2668 BlitBitmap(backbuffer, bitmap_db_door,
2669 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2671 if (old_door_state & DOOR_OPEN_2)
2672 BlitBitmap(backbuffer, bitmap_db_door,
2673 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2675 door_state &= ~DOOR_NO_COPY_BACK;
2678 return MoveDoor(door_state);
2681 unsigned int GetDoorState()
2683 return MoveDoor(DOOR_GET_STATE);
2686 unsigned int SetDoorState(unsigned int door_state)
2688 return MoveDoor(door_state | DOOR_SET_STATE);
2691 unsigned int MoveDoor(unsigned int door_state)
2693 static int door1 = DOOR_OPEN_1;
2694 static int door2 = DOOR_CLOSE_2;
2695 unsigned long door_delay = 0;
2696 unsigned long door_delay_value;
2699 if (door_1.width < 0 || door_1.width > DXSIZE)
2700 door_1.width = DXSIZE;
2701 if (door_1.height < 0 || door_1.height > DYSIZE)
2702 door_1.height = DYSIZE;
2703 if (door_2.width < 0 || door_2.width > VXSIZE)
2704 door_2.width = VXSIZE;
2705 if (door_2.height < 0 || door_2.height > VYSIZE)
2706 door_2.height = VYSIZE;
2708 if (door_state == DOOR_GET_STATE)
2709 return (door1 | door2);
2711 if (door_state & DOOR_SET_STATE)
2713 if (door_state & DOOR_ACTION_1)
2714 door1 = door_state & DOOR_ACTION_1;
2715 if (door_state & DOOR_ACTION_2)
2716 door2 = door_state & DOOR_ACTION_2;
2718 return (door1 | door2);
2721 if (!(door_state & DOOR_FORCE_REDRAW))
2723 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2724 door_state &= ~DOOR_OPEN_1;
2725 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2726 door_state &= ~DOOR_CLOSE_1;
2727 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2728 door_state &= ~DOOR_OPEN_2;
2729 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2730 door_state &= ~DOOR_CLOSE_2;
2733 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
2736 if (setup.quick_doors)
2738 stepsize = 20; /* must be choosen to always draw last frame */
2739 door_delay_value = 0;
2742 if (global.autoplay_leveldir)
2744 door_state |= DOOR_NO_DELAY;
2745 door_state &= ~DOOR_CLOSE_ALL;
2748 if (door_state & DOOR_ACTION)
2750 boolean handle_door_1 = (door_state & DOOR_ACTION_1);
2751 boolean handle_door_2 = (door_state & DOOR_ACTION_2);
2752 boolean door_1_done = (!handle_door_1);
2753 boolean door_2_done = (!handle_door_2);
2754 boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
2755 boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
2756 int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
2757 int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
2758 int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
2759 int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
2760 int door_size = (handle_door_1 ? door_size_1 : door_size_2);
2761 int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
2762 int door_skip = max_door_size - door_size;
2764 int end = door_size;
2766 int end = (door_state & DOOR_ACTION_1 && door_1.anim_mode & ANIM_VERTICAL ?
2770 int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
2772 int start = ((door_state & DOOR_NO_DELAY) ? end : offset_skip);
2776 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
2778 /* opening door sound has priority over simultaneously closing door */
2779 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2780 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2781 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2782 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2785 for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
2788 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2789 GC gc = bitmap->stored_clip_gc;
2791 if (door_state & DOOR_ACTION_1)
2793 int a = MIN(x * door_1.step_offset, end);
2794 int p = (door_state & DOOR_OPEN_1 ? end - a : a);
2795 int i = p + door_skip;
2797 if (door_1.anim_mode & ANIM_STATIC_PANEL)
2799 BlitBitmap(bitmap_db_door, drawto,
2800 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
2801 DXSIZE, DYSIZE, DX, DY);
2805 BlitBitmap(bitmap_db_door, drawto,
2806 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
2807 DXSIZE, DYSIZE - p / 2, DX, DY);
2809 ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
2812 if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
2814 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2815 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
2816 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
2817 int dst2_x = DX, dst2_y = DY;
2818 int width = i, height = DYSIZE;
2820 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2821 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2824 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2825 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2828 else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
2830 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2831 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
2832 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
2833 int dst2_x = DX, dst2_y = DY;
2834 int width = DXSIZE, height = i;
2836 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2837 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2840 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2841 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2844 else if (x <= DXSIZE) /* ANIM_DEFAULT */
2846 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
2848 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2849 BlitBitmapMasked(bitmap, drawto,
2850 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2851 DX + DXSIZE - i, DY + j);
2852 BlitBitmapMasked(bitmap, drawto,
2853 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2854 DX + DXSIZE - i, DY + 140 + j);
2855 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
2856 DY - (DOOR_GFX_PAGEY1 + j));
2857 BlitBitmapMasked(bitmap, drawto,
2858 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2860 BlitBitmapMasked(bitmap, drawto,
2861 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
2864 BlitBitmapMasked(bitmap, drawto,
2865 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2867 BlitBitmapMasked(bitmap, drawto,
2868 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2870 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2871 BlitBitmapMasked(bitmap, drawto,
2872 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2873 DX + DXSIZE - i, DY + 77 + j);
2874 BlitBitmapMasked(bitmap, drawto,
2875 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2876 DX + DXSIZE - i, DY + 203 + j);
2879 redraw_mask |= REDRAW_DOOR_1;
2880 door_1_done = (a == end);
2883 if (door_state & DOOR_ACTION_2)
2886 int a = MIN(x * door_2.step_offset, door_size);
2887 int p = (door_state & DOOR_OPEN_2 ? door_size - a : a);
2888 int i = p + door_skip;
2890 int a = MIN(x * door_2.step_offset, door_size_2);
2891 int p = (door_state & DOOR_OPEN_2 ? door_size_2 - a : a);
2892 int i = p + door_skip;
2895 if (door_2.anim_mode & ANIM_STATIC_PANEL)
2897 BlitBitmap(bitmap_db_door, drawto,
2898 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
2899 VXSIZE, VYSIZE, VX, VY);
2901 else if (x <= VYSIZE)
2903 BlitBitmap(bitmap_db_door, drawto,
2904 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
2905 VXSIZE, VYSIZE - p / 2, VX, VY);
2907 ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
2910 if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
2912 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
2913 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
2914 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
2915 int dst2_x = VX, dst2_y = VY;
2916 int width = i, height = VYSIZE;
2918 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2919 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2922 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2923 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2926 else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
2928 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
2929 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
2930 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
2931 int dst2_x = VX, dst2_y = VY;
2932 int width = VXSIZE, height = i;
2934 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2935 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2938 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2939 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2942 else if (x <= VXSIZE) /* ANIM_DEFAULT */
2944 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
2946 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2947 BlitBitmapMasked(bitmap, drawto,
2948 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
2949 VX + VXSIZE - i, VY + j);
2950 SetClipOrigin(bitmap, gc,
2951 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2952 BlitBitmapMasked(bitmap, drawto,
2953 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
2956 BlitBitmapMasked(bitmap, drawto,
2957 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2958 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
2959 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2960 BlitBitmapMasked(bitmap, drawto,
2961 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2963 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2966 redraw_mask |= REDRAW_DOOR_2;
2967 door_2_done = (a == VXSIZE);
2970 if (!(door_state & DOOR_NO_DELAY))
2974 if (game_status == GAME_MODE_MAIN)
2977 WaitUntilDelayReached(&door_delay, door_delay_value);
2982 if (door_state & DOOR_ACTION_1)
2983 door1 = door_state & DOOR_ACTION_1;
2984 if (door_state & DOOR_ACTION_2)
2985 door2 = door_state & DOOR_ACTION_2;
2987 return (door1 | door2);
2990 void DrawSpecialEditorDoor()
2992 /* draw bigger toolbox window */
2993 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
2994 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
2996 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2997 EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
3000 redraw_mask |= REDRAW_ALL;
3003 void UndrawSpecialEditorDoor()
3005 /* draw normal tape recorder window */
3006 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3007 EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
3010 redraw_mask |= REDRAW_ALL;
3014 /* ---------- new tool button stuff ---------------------------------------- */
3016 /* graphic position values for tool buttons */
3017 #define TOOL_BUTTON_YES_XPOS 2
3018 #define TOOL_BUTTON_YES_YPOS 250
3019 #define TOOL_BUTTON_YES_GFX_YPOS 0
3020 #define TOOL_BUTTON_YES_XSIZE 46
3021 #define TOOL_BUTTON_YES_YSIZE 28
3022 #define TOOL_BUTTON_NO_XPOS 52
3023 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
3024 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
3025 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
3026 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
3027 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
3028 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
3029 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
3030 #define TOOL_BUTTON_CONFIRM_XSIZE 96
3031 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
3032 #define TOOL_BUTTON_PLAYER_XSIZE 30
3033 #define TOOL_BUTTON_PLAYER_YSIZE 30
3034 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
3035 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
3036 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
3037 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
3038 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3039 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3040 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3041 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3042 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3043 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3044 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3045 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3046 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3047 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3048 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3049 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3050 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3051 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3052 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3053 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3062 } toolbutton_info[NUM_TOOL_BUTTONS] =
3065 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
3066 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
3067 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
3072 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
3073 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
3074 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
3079 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
3080 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
3081 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
3082 TOOL_CTRL_ID_CONFIRM,
3086 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3087 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
3088 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3089 TOOL_CTRL_ID_PLAYER_1,
3093 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3094 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
3095 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3096 TOOL_CTRL_ID_PLAYER_2,
3100 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3101 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
3102 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3103 TOOL_CTRL_ID_PLAYER_3,
3107 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3108 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
3109 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3110 TOOL_CTRL_ID_PLAYER_4,
3115 void CreateToolButtons()
3119 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3121 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3122 Bitmap *deco_bitmap = None;
3123 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
3124 struct GadgetInfo *gi;
3125 unsigned long event_mask;
3126 int gd_xoffset, gd_yoffset;
3127 int gd_x1, gd_x2, gd_y;
3130 event_mask = GD_EVENT_RELEASED;
3132 gd_xoffset = toolbutton_info[i].xpos;
3133 gd_yoffset = toolbutton_info[i].ypos;
3134 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
3135 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
3136 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
3138 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
3140 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
3142 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
3143 &deco_bitmap, &deco_x, &deco_y);
3144 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
3145 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
3148 gi = CreateGadget(GDI_CUSTOM_ID, id,
3149 GDI_INFO_TEXT, toolbutton_info[i].infotext,
3150 GDI_X, DX + toolbutton_info[i].x,
3151 GDI_Y, DY + toolbutton_info[i].y,
3152 GDI_WIDTH, toolbutton_info[i].width,
3153 GDI_HEIGHT, toolbutton_info[i].height,
3154 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
3155 GDI_STATE, GD_BUTTON_UNPRESSED,
3156 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
3157 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
3158 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
3159 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
3160 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
3161 GDI_DECORATION_SHIFTING, 1, 1,
3162 GDI_EVENT_MASK, event_mask,
3163 GDI_CALLBACK_ACTION, HandleToolButtons,
3167 Error(ERR_EXIT, "cannot create gadget");
3169 tool_gadget[id] = gi;
3173 void FreeToolButtons()
3177 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3178 FreeGadget(tool_gadget[i]);
3181 static void UnmapToolButtons()
3185 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3186 UnmapGadget(tool_gadget[i]);
3189 static void HandleToolButtons(struct GadgetInfo *gi)
3191 request_gadget_id = gi->custom_id;
3194 static struct Mapping_EM_to_RND_object
3197 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
3198 boolean is_backside; /* backside of moving element */
3204 em_object_mapping_list[] =
3207 Xblank, TRUE, FALSE,
3211 Yacid_splash_eB, FALSE, FALSE,
3212 EL_ACID_SPLASH_RIGHT, -1, -1
3215 Yacid_splash_wB, FALSE, FALSE,
3216 EL_ACID_SPLASH_LEFT, -1, -1
3219 #ifdef EM_ENGINE_BAD_ROLL
3221 Xstone_force_e, FALSE, FALSE,
3222 EL_ROCK, -1, MV_BIT_RIGHT
3225 Xstone_force_w, FALSE, FALSE,
3226 EL_ROCK, -1, MV_BIT_LEFT
3229 Xnut_force_e, FALSE, FALSE,
3230 EL_NUT, -1, MV_BIT_RIGHT
3233 Xnut_force_w, FALSE, FALSE,
3234 EL_NUT, -1, MV_BIT_LEFT
3237 Xspring_force_e, FALSE, FALSE,
3238 EL_SPRING, -1, MV_BIT_RIGHT
3241 Xspring_force_w, FALSE, FALSE,
3242 EL_SPRING, -1, MV_BIT_LEFT
3245 Xemerald_force_e, FALSE, FALSE,
3246 EL_EMERALD, -1, MV_BIT_RIGHT
3249 Xemerald_force_w, FALSE, FALSE,
3250 EL_EMERALD, -1, MV_BIT_LEFT
3253 Xdiamond_force_e, FALSE, FALSE,
3254 EL_DIAMOND, -1, MV_BIT_RIGHT
3257 Xdiamond_force_w, FALSE, FALSE,
3258 EL_DIAMOND, -1, MV_BIT_LEFT
3261 Xbomb_force_e, FALSE, FALSE,
3262 EL_BOMB, -1, MV_BIT_RIGHT
3265 Xbomb_force_w, FALSE, FALSE,
3266 EL_BOMB, -1, MV_BIT_LEFT
3268 #endif /* EM_ENGINE_BAD_ROLL */
3271 Xstone, TRUE, FALSE,
3275 Xstone_pause, FALSE, FALSE,
3279 Xstone_fall, FALSE, FALSE,
3283 Ystone_s, FALSE, FALSE,
3284 EL_ROCK, ACTION_FALLING, -1
3287 Ystone_sB, FALSE, TRUE,
3288 EL_ROCK, ACTION_FALLING, -1
3291 Ystone_e, FALSE, FALSE,
3292 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3295 Ystone_eB, FALSE, TRUE,
3296 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3299 Ystone_w, FALSE, FALSE,
3300 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3303 Ystone_wB, FALSE, TRUE,
3304 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3311 Xnut_pause, FALSE, FALSE,
3315 Xnut_fall, FALSE, FALSE,
3319 Ynut_s, FALSE, FALSE,
3320 EL_NUT, ACTION_FALLING, -1
3323 Ynut_sB, FALSE, TRUE,
3324 EL_NUT, ACTION_FALLING, -1
3327 Ynut_e, FALSE, FALSE,
3328 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3331 Ynut_eB, FALSE, TRUE,
3332 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3335 Ynut_w, FALSE, FALSE,
3336 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3339 Ynut_wB, FALSE, TRUE,
3340 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3343 Xbug_n, TRUE, FALSE,
3347 Xbug_e, TRUE, FALSE,
3348 EL_BUG_RIGHT, -1, -1
3351 Xbug_s, TRUE, FALSE,
3355 Xbug_w, TRUE, FALSE,
3359 Xbug_gon, FALSE, FALSE,
3363 Xbug_goe, FALSE, FALSE,
3364 EL_BUG_RIGHT, -1, -1
3367 Xbug_gos, FALSE, FALSE,
3371 Xbug_gow, FALSE, FALSE,
3375 Ybug_n, FALSE, FALSE,
3376 EL_BUG, ACTION_MOVING, MV_BIT_UP
3379 Ybug_nB, FALSE, TRUE,
3380 EL_BUG, ACTION_MOVING, MV_BIT_UP
3383 Ybug_e, FALSE, FALSE,
3384 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3387 Ybug_eB, FALSE, TRUE,
3388 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3391 Ybug_s, FALSE, FALSE,
3392 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3395 Ybug_sB, FALSE, TRUE,
3396 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3399 Ybug_w, FALSE, FALSE,
3400 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3403 Ybug_wB, FALSE, TRUE,
3404 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3407 Ybug_w_n, FALSE, FALSE,
3408 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3411 Ybug_n_e, FALSE, FALSE,
3412 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3415 Ybug_e_s, FALSE, FALSE,
3416 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3419 Ybug_s_w, FALSE, FALSE,
3420 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3423 Ybug_e_n, FALSE, FALSE,
3424 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3427 Ybug_s_e, FALSE, FALSE,
3428 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3431 Ybug_w_s, FALSE, FALSE,
3432 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3435 Ybug_n_w, FALSE, FALSE,
3436 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3439 Ybug_stone, FALSE, FALSE,
3440 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
3443 Ybug_spring, FALSE, FALSE,
3444 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
3447 Xtank_n, TRUE, FALSE,
3448 EL_SPACESHIP_UP, -1, -1
3451 Xtank_e, TRUE, FALSE,
3452 EL_SPACESHIP_RIGHT, -1, -1
3455 Xtank_s, TRUE, FALSE,
3456 EL_SPACESHIP_DOWN, -1, -1
3459 Xtank_w, TRUE, FALSE,
3460 EL_SPACESHIP_LEFT, -1, -1
3463 Xtank_gon, FALSE, FALSE,
3464 EL_SPACESHIP_UP, -1, -1
3467 Xtank_goe, FALSE, FALSE,
3468 EL_SPACESHIP_RIGHT, -1, -1
3471 Xtank_gos, FALSE, FALSE,
3472 EL_SPACESHIP_DOWN, -1, -1
3475 Xtank_gow, FALSE, FALSE,
3476 EL_SPACESHIP_LEFT, -1, -1
3479 Ytank_n, FALSE, FALSE,
3480 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3483 Ytank_nB, FALSE, TRUE,
3484 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3487 Ytank_e, FALSE, FALSE,
3488 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3491 Ytank_eB, FALSE, TRUE,
3492 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3495 Ytank_s, FALSE, FALSE,
3496 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3499 Ytank_sB, FALSE, TRUE,
3500 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3503 Ytank_w, FALSE, FALSE,
3504 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3507 Ytank_wB, FALSE, TRUE,
3508 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3511 Ytank_w_n, FALSE, FALSE,
3512 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3515 Ytank_n_e, FALSE, FALSE,
3516 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3519 Ytank_e_s, FALSE, FALSE,
3520 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3523 Ytank_s_w, FALSE, FALSE,
3524 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3527 Ytank_e_n, FALSE, FALSE,
3528 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3531 Ytank_s_e, FALSE, FALSE,
3532 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3535 Ytank_w_s, FALSE, FALSE,
3536 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3539 Ytank_n_w, FALSE, FALSE,
3540 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3543 Ytank_stone, FALSE, FALSE,
3544 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
3547 Ytank_spring, FALSE, FALSE,
3548 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
3551 Xandroid, TRUE, FALSE,
3552 EL_EMC_ANDROID, ACTION_ACTIVE, -1
3555 Xandroid_1_n, FALSE, FALSE,
3556 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3559 Xandroid_2_n, FALSE, FALSE,
3560 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3563 Xandroid_1_e, FALSE, FALSE,
3564 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3567 Xandroid_2_e, FALSE, FALSE,
3568 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3571 Xandroid_1_w, FALSE, FALSE,
3572 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3575 Xandroid_2_w, FALSE, FALSE,
3576 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3579 Xandroid_1_s, FALSE, FALSE,
3580 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3583 Xandroid_2_s, FALSE, FALSE,
3584 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3587 Yandroid_n, FALSE, FALSE,
3588 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3591 Yandroid_nB, FALSE, TRUE,
3592 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3595 Yandroid_ne, FALSE, FALSE,
3596 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
3599 Yandroid_neB, FALSE, TRUE,
3600 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
3603 Yandroid_e, FALSE, FALSE,
3604 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
3607 Yandroid_eB, FALSE, TRUE,
3608 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
3611 Yandroid_se, FALSE, FALSE,
3612 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
3615 Yandroid_seB, FALSE, TRUE,
3616 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
3619 Yandroid_s, FALSE, FALSE,
3620 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
3623 Yandroid_sB, FALSE, TRUE,
3624 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
3627 Yandroid_sw, FALSE, FALSE,
3628 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
3631 Yandroid_swB, FALSE, TRUE,
3632 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
3635 Yandroid_w, FALSE, FALSE,
3636 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
3639 Yandroid_wB, FALSE, TRUE,
3640 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
3643 Yandroid_nw, FALSE, FALSE,
3644 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
3647 Yandroid_nwB, FALSE, TRUE,
3648 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
3651 Xspring, TRUE, FALSE,
3655 Xspring_pause, FALSE, FALSE,
3659 Xspring_e, FALSE, FALSE,
3663 Xspring_w, FALSE, FALSE,
3667 Xspring_fall, FALSE, FALSE,
3671 Yspring_s, FALSE, FALSE,
3672 EL_SPRING, ACTION_FALLING, -1
3675 Yspring_sB, FALSE, TRUE,
3676 EL_SPRING, ACTION_FALLING, -1
3679 Yspring_e, FALSE, FALSE,
3680 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
3683 Yspring_eB, FALSE, TRUE,
3684 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
3687 Yspring_w, FALSE, FALSE,
3688 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
3691 Yspring_wB, FALSE, TRUE,
3692 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
3695 Yspring_kill_e, FALSE, FALSE,
3696 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
3699 Yspring_kill_eB, FALSE, TRUE,
3700 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
3703 Yspring_kill_w, FALSE, FALSE,
3704 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
3707 Yspring_kill_wB, FALSE, TRUE,
3708 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
3711 Xeater_n, TRUE, FALSE,
3712 EL_YAMYAM_UP, -1, -1
3715 Xeater_e, TRUE, FALSE,
3716 EL_YAMYAM_RIGHT, -1, -1
3719 Xeater_w, TRUE, FALSE,
3720 EL_YAMYAM_LEFT, -1, -1
3723 Xeater_s, TRUE, FALSE,
3724 EL_YAMYAM_DOWN, -1, -1
3727 Yeater_n, FALSE, FALSE,
3728 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
3731 Yeater_nB, FALSE, TRUE,
3732 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
3735 Yeater_e, FALSE, FALSE,
3736 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
3739 Yeater_eB, FALSE, TRUE,
3740 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
3743 Yeater_s, FALSE, FALSE,
3744 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
3747 Yeater_sB, FALSE, TRUE,
3748 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
3751 Yeater_w, FALSE, FALSE,
3752 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
3755 Yeater_wB, FALSE, TRUE,
3756 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
3759 Yeater_stone, FALSE, FALSE,
3760 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
3763 Yeater_spring, FALSE, FALSE,
3764 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
3767 Xalien, TRUE, FALSE,
3771 Xalien_pause, FALSE, FALSE,
3775 Yalien_n, FALSE, FALSE,
3776 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
3779 Yalien_nB, FALSE, TRUE,
3780 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
3783 Yalien_e, FALSE, FALSE,
3784 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
3787 Yalien_eB, FALSE, TRUE,
3788 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
3791 Yalien_s, FALSE, FALSE,
3792 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
3795 Yalien_sB, FALSE, TRUE,
3796 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
3799 Yalien_w, FALSE, FALSE,
3800 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
3803 Yalien_wB, FALSE, TRUE,
3804 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
3807 Yalien_stone, FALSE, FALSE,
3808 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
3811 Yalien_spring, FALSE, FALSE,
3812 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
3815 Xemerald, TRUE, FALSE,
3819 Xemerald_pause, FALSE, FALSE,
3823 Xemerald_fall, FALSE, FALSE,
3827 Xemerald_shine, FALSE, FALSE,
3828 EL_EMERALD, ACTION_TWINKLING, -1
3831 Yemerald_s, FALSE, FALSE,
3832 EL_EMERALD, ACTION_FALLING, -1
3835 Yemerald_sB, FALSE, TRUE,
3836 EL_EMERALD, ACTION_FALLING, -1
3839 Yemerald_e, FALSE, FALSE,
3840 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
3843 Yemerald_eB, FALSE, TRUE,
3844 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
3847 Yemerald_w, FALSE, FALSE,
3848 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
3851 Yemerald_wB, FALSE, TRUE,
3852 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
3855 Yemerald_eat, FALSE, FALSE,
3856 EL_EMERALD, ACTION_COLLECTING, -1
3859 Yemerald_stone, FALSE, FALSE,
3860 EL_NUT, ACTION_BREAKING, -1
3863 Xdiamond, TRUE, FALSE,
3867 Xdiamond_pause, FALSE, FALSE,
3871 Xdiamond_fall, FALSE, FALSE,
3875 Xdiamond_shine, FALSE, FALSE,
3876 EL_DIAMOND, ACTION_TWINKLING, -1
3879 Ydiamond_s, FALSE, FALSE,
3880 EL_DIAMOND, ACTION_FALLING, -1
3883 Ydiamond_sB, FALSE, TRUE,
3884 EL_DIAMOND, ACTION_FALLING, -1
3887 Ydiamond_e, FALSE, FALSE,
3888 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
3891 Ydiamond_eB, FALSE, TRUE,
3892 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
3895 Ydiamond_w, FALSE, FALSE,
3896 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
3899 Ydiamond_wB, FALSE, TRUE,
3900 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
3903 Ydiamond_eat, FALSE, FALSE,
3904 EL_DIAMOND, ACTION_COLLECTING, -1
3907 Ydiamond_stone, FALSE, FALSE,
3908 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
3911 Xdrip_fall, TRUE, FALSE,
3912 EL_AMOEBA_DROP, -1, -1
3915 Xdrip_stretch, FALSE, FALSE,
3916 EL_AMOEBA_DROP, ACTION_FALLING, -1
3919 Xdrip_stretchB, FALSE, TRUE,
3920 EL_AMOEBA_DROP, ACTION_FALLING, -1
3923 Xdrip_eat, FALSE, FALSE,
3924 EL_AMOEBA_DROP, ACTION_GROWING, -1
3927 Ydrip_s1, FALSE, FALSE,
3928 EL_AMOEBA_DROP, ACTION_FALLING, -1
3931 Ydrip_s1B, FALSE, TRUE,
3932 EL_AMOEBA_DROP, ACTION_FALLING, -1
3935 Ydrip_s2, FALSE, FALSE,
3936 EL_AMOEBA_DROP, ACTION_FALLING, -1
3939 Ydrip_s2B, FALSE, TRUE,
3940 EL_AMOEBA_DROP, ACTION_FALLING, -1
3947 Xbomb_pause, FALSE, FALSE,
3951 Xbomb_fall, FALSE, FALSE,
3955 Ybomb_s, FALSE, FALSE,
3956 EL_BOMB, ACTION_FALLING, -1
3959 Ybomb_sB, FALSE, TRUE,
3960 EL_BOMB, ACTION_FALLING, -1
3963 Ybomb_e, FALSE, FALSE,
3964 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
3967 Ybomb_eB, FALSE, TRUE,
3968 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
3971 Ybomb_w, FALSE, FALSE,
3972 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
3975 Ybomb_wB, FALSE, TRUE,
3976 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
3979 Ybomb_eat, FALSE, FALSE,
3980 EL_BOMB, ACTION_ACTIVATING, -1
3983 Xballoon, TRUE, FALSE,
3987 Yballoon_n, FALSE, FALSE,
3988 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
3991 Yballoon_nB, FALSE, TRUE,
3992 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
3995 Yballoon_e, FALSE, FALSE,
3996 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
3999 Yballoon_eB, FALSE, TRUE,
4000 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
4003 Yballoon_s, FALSE, FALSE,
4004 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
4007 Yballoon_sB, FALSE, TRUE,
4008 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
4011 Yballoon_w, FALSE, FALSE,
4012 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
4015 Yballoon_wB, FALSE, TRUE,
4016 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
4019 Xgrass, TRUE, FALSE,
4020 EL_EMC_GRASS, -1, -1
4023 Ygrass_nB, FALSE, FALSE,
4024 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
4027 Ygrass_eB, FALSE, FALSE,
4028 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
4031 Ygrass_sB, FALSE, FALSE,
4032 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
4035 Ygrass_wB, FALSE, FALSE,
4036 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
4043 Ydirt_nB, FALSE, FALSE,
4044 EL_SAND, ACTION_DIGGING, MV_BIT_UP
4047 Ydirt_eB, FALSE, FALSE,
4048 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
4051 Ydirt_sB, FALSE, FALSE,
4052 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
4055 Ydirt_wB, FALSE, FALSE,
4056 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
4059 Xacid_ne, TRUE, FALSE,
4060 EL_ACID_POOL_TOPRIGHT, -1, -1
4063 Xacid_se, TRUE, FALSE,
4064 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
4067 Xacid_s, TRUE, FALSE,
4068 EL_ACID_POOL_BOTTOM, -1, -1
4071 Xacid_sw, TRUE, FALSE,
4072 EL_ACID_POOL_BOTTOMLEFT, -1, -1
4075 Xacid_nw, TRUE, FALSE,
4076 EL_ACID_POOL_TOPLEFT, -1, -1
4079 Xacid_1, TRUE, FALSE,
4083 Xacid_2, FALSE, FALSE,
4087 Xacid_3, FALSE, FALSE,
4091 Xacid_4, FALSE, FALSE,
4095 Xacid_5, FALSE, FALSE,
4099 Xacid_6, FALSE, FALSE,
4103 Xacid_7, FALSE, FALSE,
4107 Xacid_8, FALSE, FALSE,
4111 Xball_1, TRUE, FALSE,
4112 EL_EMC_MAGIC_BALL, -1, -1
4115 Xball_1B, FALSE, FALSE,
4116 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4119 Xball_2, FALSE, FALSE,
4120 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4123 Xball_2B, FALSE, FALSE,
4124 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4127 Yball_eat, FALSE, FALSE,
4128 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
4131 Ykey_1_eat, FALSE, FALSE,
4132 EL_EM_KEY_1, ACTION_COLLECTING, -1
4135 Ykey_2_eat, FALSE, FALSE,
4136 EL_EM_KEY_2, ACTION_COLLECTING, -1
4139 Ykey_3_eat, FALSE, FALSE,
4140 EL_EM_KEY_3, ACTION_COLLECTING, -1
4143 Ykey_4_eat, FALSE, FALSE,
4144 EL_EM_KEY_4, ACTION_COLLECTING, -1
4147 Ykey_5_eat, FALSE, FALSE,
4148 EL_EMC_KEY_5, ACTION_COLLECTING, -1
4151 Ykey_6_eat, FALSE, FALSE,
4152 EL_EMC_KEY_6, ACTION_COLLECTING, -1
4155 Ykey_7_eat, FALSE, FALSE,
4156 EL_EMC_KEY_7, ACTION_COLLECTING, -1
4159 Ykey_8_eat, FALSE, FALSE,
4160 EL_EMC_KEY_8, ACTION_COLLECTING, -1
4163 Ylenses_eat, FALSE, FALSE,
4164 EL_EMC_LENSES, ACTION_COLLECTING, -1
4167 Ymagnify_eat, FALSE, FALSE,
4168 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
4171 Ygrass_eat, FALSE, FALSE,
4172 EL_EMC_GRASS, ACTION_SNAPPING, -1
4175 Ydirt_eat, FALSE, FALSE,
4176 EL_SAND, ACTION_SNAPPING, -1
4179 Xgrow_ns, TRUE, FALSE,
4180 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
4183 Ygrow_ns_eat, FALSE, FALSE,
4184 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
4187 Xgrow_ew, TRUE, FALSE,
4188 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
4191 Ygrow_ew_eat, FALSE, FALSE,
4192 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
4195 Xwonderwall, TRUE, FALSE,
4196 EL_MAGIC_WALL, -1, -1
4199 XwonderwallB, FALSE, FALSE,
4200 EL_MAGIC_WALL, ACTION_ACTIVE, -1
4203 Xamoeba_1, TRUE, FALSE,
4204 EL_AMOEBA_DRY, ACTION_OTHER, -1
4207 Xamoeba_2, FALSE, FALSE,
4208 EL_AMOEBA_DRY, ACTION_OTHER, -1
4211 Xamoeba_3, FALSE, FALSE,
4212 EL_AMOEBA_DRY, ACTION_OTHER, -1
4215 Xamoeba_4, FALSE, FALSE,
4216 EL_AMOEBA_DRY, ACTION_OTHER, -1
4219 Xamoeba_5, TRUE, FALSE,
4220 EL_AMOEBA_WET, ACTION_OTHER, -1
4223 Xamoeba_6, FALSE, FALSE,
4224 EL_AMOEBA_WET, ACTION_OTHER, -1
4227 Xamoeba_7, FALSE, FALSE,
4228 EL_AMOEBA_WET, ACTION_OTHER, -1
4231 Xamoeba_8, FALSE, FALSE,
4232 EL_AMOEBA_WET, ACTION_OTHER, -1
4235 Xdoor_1, TRUE, FALSE,
4236 EL_EM_GATE_1, -1, -1
4239 Xdoor_2, TRUE, FALSE,
4240 EL_EM_GATE_2, -1, -1
4243 Xdoor_3, TRUE, FALSE,
4244 EL_EM_GATE_3, -1, -1
4247 Xdoor_4, TRUE, FALSE,
4248 EL_EM_GATE_4, -1, -1
4251 Xdoor_5, TRUE, FALSE,
4252 EL_EMC_GATE_5, -1, -1
4255 Xdoor_6, TRUE, FALSE,
4256 EL_EMC_GATE_6, -1, -1
4259 Xdoor_7, TRUE, FALSE,
4260 EL_EMC_GATE_7, -1, -1
4263 Xdoor_8, TRUE, FALSE,
4264 EL_EMC_GATE_8, -1, -1
4267 Xkey_1, TRUE, FALSE,
4271 Xkey_2, TRUE, FALSE,
4275 Xkey_3, TRUE, FALSE,
4279 Xkey_4, TRUE, FALSE,
4283 Xkey_5, TRUE, FALSE,
4284 EL_EMC_KEY_5, -1, -1
4287 Xkey_6, TRUE, FALSE,
4288 EL_EMC_KEY_6, -1, -1
4291 Xkey_7, TRUE, FALSE,
4292 EL_EMC_KEY_7, -1, -1
4295 Xkey_8, TRUE, FALSE,
4296 EL_EMC_KEY_8, -1, -1
4299 Xwind_n, TRUE, FALSE,
4300 EL_BALLOON_SWITCH_UP, -1, -1
4303 Xwind_e, TRUE, FALSE,
4304 EL_BALLOON_SWITCH_RIGHT, -1, -1
4307 Xwind_s, TRUE, FALSE,
4308 EL_BALLOON_SWITCH_DOWN, -1, -1
4311 Xwind_w, TRUE, FALSE,
4312 EL_BALLOON_SWITCH_LEFT, -1, -1
4315 Xwind_nesw, TRUE, FALSE,
4316 EL_BALLOON_SWITCH_ANY, -1, -1
4319 Xwind_stop, TRUE, FALSE,
4320 EL_BALLOON_SWITCH_NONE, -1, -1
4324 EL_EXIT_CLOSED, -1, -1
4327 Xexit_1, TRUE, FALSE,
4328 EL_EXIT_OPEN, -1, -1
4331 Xexit_2, FALSE, FALSE,
4332 EL_EXIT_OPEN, -1, -1
4335 Xexit_3, FALSE, FALSE,
4336 EL_EXIT_OPEN, -1, -1
4339 Xdynamite, TRUE, FALSE,
4340 EL_EM_DYNAMITE, -1, -1
4343 Ydynamite_eat, FALSE, FALSE,
4344 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
4347 Xdynamite_1, TRUE, FALSE,
4348 EL_EM_DYNAMITE_ACTIVE, -1, -1
4351 Xdynamite_2, FALSE, FALSE,
4352 EL_EM_DYNAMITE_ACTIVE, -1, -1
4355 Xdynamite_3, FALSE, FALSE,
4356 EL_EM_DYNAMITE_ACTIVE, -1, -1
4359 Xdynamite_4, FALSE, FALSE,
4360 EL_EM_DYNAMITE_ACTIVE, -1, -1
4363 Xbumper, TRUE, FALSE,
4364 EL_EMC_SPRING_BUMPER, -1, -1
4367 XbumperB, FALSE, FALSE,
4368 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
4371 Xwheel, TRUE, FALSE,
4372 EL_ROBOT_WHEEL, -1, -1
4375 XwheelB, FALSE, FALSE,
4376 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
4379 Xswitch, TRUE, FALSE,
4380 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
4383 XswitchB, FALSE, FALSE,
4384 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
4388 EL_QUICKSAND_EMPTY, -1, -1
4391 Xsand_stone, TRUE, FALSE,
4392 EL_QUICKSAND_FULL, -1, -1
4395 Xsand_stonein_1, FALSE, TRUE,
4396 EL_ROCK, ACTION_FILLING, -1
4399 Xsand_stonein_2, FALSE, TRUE,
4400 EL_ROCK, ACTION_FILLING, -1
4403 Xsand_stonein_3, FALSE, TRUE,
4404 EL_ROCK, ACTION_FILLING, -1
4407 Xsand_stonein_4, FALSE, TRUE,
4408 EL_ROCK, ACTION_FILLING, -1
4411 Xsand_stonesand_1, FALSE, FALSE,
4412 EL_QUICKSAND_FULL, -1, -1
4415 Xsand_stonesand_2, FALSE, FALSE,
4416 EL_QUICKSAND_FULL, -1, -1
4419 Xsand_stonesand_3, FALSE, FALSE,
4420 EL_QUICKSAND_FULL, -1, -1
4423 Xsand_stonesand_4, FALSE, FALSE,
4424 EL_QUICKSAND_FULL, -1, -1
4427 Xsand_stoneout_1, FALSE, FALSE,
4428 EL_ROCK, ACTION_EMPTYING, -1
4431 Xsand_stoneout_2, FALSE, FALSE,
4432 EL_ROCK, ACTION_EMPTYING, -1
4435 Xsand_sandstone_1, FALSE, FALSE,
4436 EL_QUICKSAND_FULL, -1, -1
4439 Xsand_sandstone_2, FALSE, FALSE,
4440 EL_QUICKSAND_FULL, -1, -1
4443 Xsand_sandstone_3, FALSE, FALSE,
4444 EL_QUICKSAND_FULL, -1, -1
4447 Xsand_sandstone_4, FALSE, FALSE,
4448 EL_QUICKSAND_FULL, -1, -1
4451 Xplant, TRUE, FALSE,
4452 EL_EMC_PLANT, -1, -1
4455 Yplant, FALSE, FALSE,
4456 EL_EMC_PLANT, -1, -1
4459 Xlenses, TRUE, FALSE,
4460 EL_EMC_LENSES, -1, -1
4463 Xmagnify, TRUE, FALSE,
4464 EL_EMC_MAGNIFIER, -1, -1
4467 Xdripper, TRUE, FALSE,
4468 EL_EMC_DRIPPER, -1, -1
4471 XdripperB, FALSE, FALSE,
4472 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
4475 Xfake_blank, TRUE, FALSE,
4476 EL_INVISIBLE_WALL, -1, -1
4479 Xfake_blankB, FALSE, FALSE,
4480 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
4483 Xfake_grass, TRUE, FALSE,
4484 EL_EMC_FAKE_GRASS, -1, -1
4487 Xfake_grassB, FALSE, FALSE,
4488 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
4491 Xfake_door_1, TRUE, FALSE,
4492 EL_EM_GATE_1_GRAY, -1, -1
4495 Xfake_door_2, TRUE, FALSE,
4496 EL_EM_GATE_2_GRAY, -1, -1
4499 Xfake_door_3, TRUE, FALSE,
4500 EL_EM_GATE_3_GRAY, -1, -1
4503 Xfake_door_4, TRUE, FALSE,
4504 EL_EM_GATE_4_GRAY, -1, -1
4507 Xfake_door_5, TRUE, FALSE,
4508 EL_EMC_GATE_5_GRAY, -1, -1
4511 Xfake_door_6, TRUE, FALSE,
4512 EL_EMC_GATE_6_GRAY, -1, -1
4515 Xfake_door_7, TRUE, FALSE,
4516 EL_EMC_GATE_7_GRAY, -1, -1
4519 Xfake_door_8, TRUE, FALSE,
4520 EL_EMC_GATE_8_GRAY, -1, -1
4523 Xfake_acid_1, TRUE, FALSE,
4524 EL_EMC_FAKE_ACID, -1, -1
4527 Xfake_acid_2, FALSE, FALSE,
4528 EL_EMC_FAKE_ACID, -1, -1
4531 Xfake_acid_3, FALSE, FALSE,
4532 EL_EMC_FAKE_ACID, -1, -1
4535 Xfake_acid_4, FALSE, FALSE,
4536 EL_EMC_FAKE_ACID, -1, -1
4539 Xfake_acid_5, FALSE, FALSE,
4540 EL_EMC_FAKE_ACID, -1, -1
4543 Xfake_acid_6, FALSE, FALSE,
4544 EL_EMC_FAKE_ACID, -1, -1
4547 Xfake_acid_7, FALSE, FALSE,
4548 EL_EMC_FAKE_ACID, -1, -1
4551 Xfake_acid_8, FALSE, FALSE,
4552 EL_EMC_FAKE_ACID, -1, -1
4555 Xsteel_1, TRUE, FALSE,
4556 EL_STEELWALL, -1, -1
4559 Xsteel_2, TRUE, FALSE,
4560 EL_EMC_STEELWALL_2, -1, -1
4563 Xsteel_3, TRUE, FALSE,
4564 EL_EMC_STEELWALL_3, -1, -1
4567 Xsteel_4, TRUE, FALSE,
4568 EL_EMC_STEELWALL_4, -1, -1
4571 Xwall_1, TRUE, FALSE,
4575 Xwall_2, TRUE, FALSE,
4576 EL_EMC_WALL_14, -1, -1
4579 Xwall_3, TRUE, FALSE,
4580 EL_EMC_WALL_15, -1, -1
4583 Xwall_4, TRUE, FALSE,
4584 EL_EMC_WALL_16, -1, -1
4587 Xround_wall_1, TRUE, FALSE,
4588 EL_WALL_SLIPPERY, -1, -1
4591 Xround_wall_2, TRUE, FALSE,
4592 EL_EMC_WALL_SLIPPERY_2, -1, -1
4595 Xround_wall_3, TRUE, FALSE,
4596 EL_EMC_WALL_SLIPPERY_3, -1, -1
4599 Xround_wall_4, TRUE, FALSE,
4600 EL_EMC_WALL_SLIPPERY_4, -1, -1
4603 Xdecor_1, TRUE, FALSE,
4604 EL_EMC_WALL_8, -1, -1
4607 Xdecor_2, TRUE, FALSE,
4608 EL_EMC_WALL_6, -1, -1
4611 Xdecor_3, TRUE, FALSE,
4612 EL_EMC_WALL_4, -1, -1
4615 Xdecor_4, TRUE, FALSE,
4616 EL_EMC_WALL_7, -1, -1
4619 Xdecor_5, TRUE, FALSE,
4620 EL_EMC_WALL_5, -1, -1
4623 Xdecor_6, TRUE, FALSE,
4624 EL_EMC_WALL_9, -1, -1
4627 Xdecor_7, TRUE, FALSE,
4628 EL_EMC_WALL_10, -1, -1
4631 Xdecor_8, TRUE, FALSE,
4632 EL_EMC_WALL_1, -1, -1
4635 Xdecor_9, TRUE, FALSE,
4636 EL_EMC_WALL_2, -1, -1
4639 Xdecor_10, TRUE, FALSE,
4640 EL_EMC_WALL_3, -1, -1
4643 Xdecor_11, TRUE, FALSE,
4644 EL_EMC_WALL_11, -1, -1
4647 Xdecor_12, TRUE, FALSE,
4648 EL_EMC_WALL_12, -1, -1
4651 Xalpha_0, TRUE, FALSE,
4652 EL_CHAR('0'), -1, -1
4655 Xalpha_1, TRUE, FALSE,
4656 EL_CHAR('1'), -1, -1
4659 Xalpha_2, TRUE, FALSE,
4660 EL_CHAR('2'), -1, -1
4663 Xalpha_3, TRUE, FALSE,
4664 EL_CHAR('3'), -1, -1
4667 Xalpha_4, TRUE, FALSE,
4668 EL_CHAR('4'), -1, -1
4671 Xalpha_5, TRUE, FALSE,
4672 EL_CHAR('5'), -1, -1
4675 Xalpha_6, TRUE, FALSE,
4676 EL_CHAR('6'), -1, -1
4679 Xalpha_7, TRUE, FALSE,
4680 EL_CHAR('7'), -1, -1
4683 Xalpha_8, TRUE, FALSE,
4684 EL_CHAR('8'), -1, -1
4687 Xalpha_9, TRUE, FALSE,
4688 EL_CHAR('9'), -1, -1
4691 Xalpha_excla, TRUE, FALSE,
4692 EL_CHAR('!'), -1, -1
4695 Xalpha_quote, TRUE, FALSE,
4696 EL_CHAR('"'), -1, -1
4699 Xalpha_comma, TRUE, FALSE,
4700 EL_CHAR(','), -1, -1
4703 Xalpha_minus, TRUE, FALSE,
4704 EL_CHAR('-'), -1, -1
4707 Xalpha_perio, TRUE, FALSE,
4708 EL_CHAR('.'), -1, -1
4711 Xalpha_colon, TRUE, FALSE,
4712 EL_CHAR(':'), -1, -1
4715 Xalpha_quest, TRUE, FALSE,
4716 EL_CHAR('?'), -1, -1
4719 Xalpha_a, TRUE, FALSE,
4720 EL_CHAR('A'), -1, -1
4723 Xalpha_b, TRUE, FALSE,
4724 EL_CHAR('B'), -1, -1
4727 Xalpha_c, TRUE, FALSE,
4728 EL_CHAR('C'), -1, -1
4731 Xalpha_d, TRUE, FALSE,
4732 EL_CHAR('D'), -1, -1
4735 Xalpha_e, TRUE, FALSE,
4736 EL_CHAR('E'), -1, -1
4739 Xalpha_f, TRUE, FALSE,
4740 EL_CHAR('F'), -1, -1
4743 Xalpha_g, TRUE, FALSE,
4744 EL_CHAR('G'), -1, -1
4747 Xalpha_h, TRUE, FALSE,
4748 EL_CHAR('H'), -1, -1
4751 Xalpha_i, TRUE, FALSE,
4752 EL_CHAR('I'), -1, -1
4755 Xalpha_j, TRUE, FALSE,
4756 EL_CHAR('J'), -1, -1
4759 Xalpha_k, TRUE, FALSE,
4760 EL_CHAR('K'), -1, -1
4763 Xalpha_l, TRUE, FALSE,
4764 EL_CHAR('L'), -1, -1
4767 Xalpha_m, TRUE, FALSE,
4768 EL_CHAR('M'), -1, -1
4771 Xalpha_n, TRUE, FALSE,
4772 EL_CHAR('N'), -1, -1
4775 Xalpha_o, TRUE, FALSE,
4776 EL_CHAR('O'), -1, -1
4779 Xalpha_p, TRUE, FALSE,
4780 EL_CHAR('P'), -1, -1
4783 Xalpha_q, TRUE, FALSE,
4784 EL_CHAR('Q'), -1, -1
4787 Xalpha_r, TRUE, FALSE,
4788 EL_CHAR('R'), -1, -1
4791 Xalpha_s, TRUE, FALSE,
4792 EL_CHAR('S'), -1, -1
4795 Xalpha_t, TRUE, FALSE,
4796 EL_CHAR('T'), -1, -1
4799 Xalpha_u, TRUE, FALSE,
4800 EL_CHAR('U'), -1, -1
4803 Xalpha_v, TRUE, FALSE,
4804 EL_CHAR('V'), -1, -1
4807 Xalpha_w, TRUE, FALSE,
4808 EL_CHAR('W'), -1, -1
4811 Xalpha_x, TRUE, FALSE,
4812 EL_CHAR('X'), -1, -1
4815 Xalpha_y, TRUE, FALSE,
4816 EL_CHAR('Y'), -1, -1
4819 Xalpha_z, TRUE, FALSE,
4820 EL_CHAR('Z'), -1, -1
4823 Xalpha_arrow_e, TRUE, FALSE,
4824 EL_CHAR('>'), -1, -1
4827 Xalpha_arrow_w, TRUE, FALSE,
4828 EL_CHAR('<'), -1, -1
4831 Xalpha_copyr, TRUE, FALSE,
4832 EL_CHAR('©'), -1, -1
4836 Xboom_bug, FALSE, FALSE,
4837 EL_BUG, ACTION_EXPLODING, -1
4840 Xboom_bomb, FALSE, FALSE,
4841 EL_BOMB, ACTION_EXPLODING, -1
4844 Xboom_android, FALSE, FALSE,
4845 EL_EMC_ANDROID, ACTION_OTHER, -1
4848 Xboom_1, FALSE, FALSE,
4849 EL_DEFAULT, ACTION_EXPLODING, -1
4852 Xboom_2, FALSE, FALSE,
4853 EL_DEFAULT, ACTION_EXPLODING, -1
4856 Znormal, FALSE, FALSE,
4860 Zdynamite, FALSE, FALSE,
4864 Zplayer, FALSE, FALSE,
4868 ZBORDER, FALSE, FALSE,
4878 static struct Mapping_EM_to_RND_player
4887 em_player_mapping_list[] =
4891 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
4895 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
4899 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
4903 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
4907 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
4911 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
4915 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
4919 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
4923 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
4927 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
4931 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
4935 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
4939 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
4943 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
4947 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
4951 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
4955 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
4959 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
4963 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
4967 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
4971 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
4975 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
4979 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
4983 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
4987 EL_PLAYER_1, ACTION_DEFAULT, -1,
4991 EL_PLAYER_2, ACTION_DEFAULT, -1,
4995 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
4999 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
5003 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
5007 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
5011 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
5015 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
5019 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
5023 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
5027 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
5031 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
5035 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
5039 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
5043 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
5047 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
5051 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
5055 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
5059 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
5063 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
5067 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
5071 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
5075 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
5079 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
5083 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
5087 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
5091 EL_PLAYER_3, ACTION_DEFAULT, -1,
5095 EL_PLAYER_4, ACTION_DEFAULT, -1,
5104 int map_element_RND_to_EM(int element_rnd)
5106 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
5107 static boolean mapping_initialized = FALSE;
5109 if (!mapping_initialized)
5113 /* return "Xalpha_quest" for all undefined elements in mapping array */
5114 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
5115 mapping_RND_to_EM[i] = Xalpha_quest;
5117 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5118 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
5119 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
5120 em_object_mapping_list[i].element_em;
5122 mapping_initialized = TRUE;
5125 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
5126 return mapping_RND_to_EM[element_rnd];
5128 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
5133 int map_element_EM_to_RND(int element_em)
5135 static unsigned short mapping_EM_to_RND[TILE_MAX];
5136 static boolean mapping_initialized = FALSE;
5138 if (!mapping_initialized)
5142 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
5143 for (i = 0; i < TILE_MAX; i++)
5144 mapping_EM_to_RND[i] = EL_UNKNOWN;
5146 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5147 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
5148 em_object_mapping_list[i].element_rnd;
5150 mapping_initialized = TRUE;
5153 if (element_em >= 0 && element_em < TILE_MAX)
5154 return mapping_EM_to_RND[element_em];
5156 Error(ERR_WARN, "invalid EM level element %d", element_em);
5161 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
5163 struct LevelInfo_EM *level_em = level->native_em_level;
5164 struct LEVEL *lev = level_em->lev;
5167 for (i = 0; i < TILE_MAX; i++)
5168 lev->android_array[i] = Xblank;
5170 for (i = 0; i < level->num_android_clone_elements; i++)
5172 int element_rnd = level->android_clone_element[i];
5173 int element_em = map_element_RND_to_EM(element_rnd);
5175 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
5176 if (em_object_mapping_list[j].element_rnd == element_rnd)
5177 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
5181 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
5183 struct LevelInfo_EM *level_em = level->native_em_level;
5184 struct LEVEL *lev = level_em->lev;
5187 level->num_android_clone_elements = 0;
5189 for (i = 0; i < TILE_MAX; i++)
5191 int element_em = lev->android_array[i];
5193 boolean element_found = FALSE;
5195 if (element_em == Xblank)
5198 element_rnd = map_element_EM_to_RND(element_em);
5200 for (j = 0; j < level->num_android_clone_elements; j++)
5201 if (level->android_clone_element[j] == element_rnd)
5202 element_found = TRUE;
5206 level->android_clone_element[level->num_android_clone_elements++] =
5209 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
5214 if (level->num_android_clone_elements == 0)
5216 level->num_android_clone_elements = 1;
5217 level->android_clone_element[0] = EL_EMPTY;
5221 int map_direction_RND_to_EM(int direction)
5223 return (direction == MV_UP ? 0 :
5224 direction == MV_RIGHT ? 1 :
5225 direction == MV_DOWN ? 2 :
5226 direction == MV_LEFT ? 3 :
5230 int map_direction_EM_to_RND(int direction)
5232 return (direction == 0 ? MV_UP :
5233 direction == 1 ? MV_RIGHT :
5234 direction == 2 ? MV_DOWN :
5235 direction == 3 ? MV_LEFT :
5239 int get_next_element(int element)
5243 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
5244 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
5245 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
5246 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
5247 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
5248 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
5249 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
5251 default: return element;
5256 int el_act_dir2img(int element, int action, int direction)
5258 element = GFX_ELEMENT(element);
5260 if (direction == MV_NONE)
5261 return element_info[element].graphic[action];
5263 direction = MV_DIR_TO_BIT(direction);
5265 return element_info[element].direction_graphic[action][direction];
5268 int el_act_dir2img(int element, int action, int direction)
5270 element = GFX_ELEMENT(element);
5271 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5273 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5274 return element_info[element].direction_graphic[action][direction];
5279 static int el_act_dir2crm(int element, int action, int direction)
5281 element = GFX_ELEMENT(element);
5283 if (direction == MV_NONE)
5284 return element_info[element].crumbled[action];
5286 direction = MV_DIR_TO_BIT(direction);
5288 return element_info[element].direction_crumbled[action][direction];
5291 static int el_act_dir2crm(int element, int action, int direction)
5293 element = GFX_ELEMENT(element);
5294 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5296 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5297 return element_info[element].direction_crumbled[action][direction];
5301 int el_act2img(int element, int action)
5303 element = GFX_ELEMENT(element);
5305 return element_info[element].graphic[action];
5308 int el_act2crm(int element, int action)
5310 element = GFX_ELEMENT(element);
5312 return element_info[element].crumbled[action];
5315 int el_dir2img(int element, int direction)
5317 element = GFX_ELEMENT(element);
5319 return el_act_dir2img(element, ACTION_DEFAULT, direction);
5322 int el2baseimg(int element)
5324 return element_info[element].graphic[ACTION_DEFAULT];
5327 int el2img(int element)
5329 element = GFX_ELEMENT(element);
5331 return element_info[element].graphic[ACTION_DEFAULT];
5334 int el2edimg(int element)
5336 element = GFX_ELEMENT(element);
5338 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
5341 int el2preimg(int element)
5343 element = GFX_ELEMENT(element);
5345 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
5348 int font2baseimg(int font_nr)
5350 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
5354 void setCenteredPlayerNr_EM(int centered_player_nr)
5356 game.centered_player_nr = game.centered_player_nr_next = centered_player_nr;
5359 int getCenteredPlayerNr_EM()
5362 if (game.centered_player_nr_next >= 0 &&
5363 !native_em_level.ply[game.centered_player_nr_next]->alive)
5364 game.centered_player_nr_next = game.centered_player_nr;
5367 if (game.centered_player_nr != game.centered_player_nr_next)
5368 game.centered_player_nr = game.centered_player_nr_next;
5370 return game.centered_player_nr;
5373 void setSetCenteredPlayer_EM(boolean set_centered_player)
5375 game.set_centered_player = set_centered_player;
5378 boolean getSetCenteredPlayer_EM()
5380 return game.set_centered_player;
5384 int getNumActivePlayers_EM()
5386 int num_players = 0;
5392 for (i = 0; i < MAX_PLAYERS; i++)
5393 if (tape.player_participates[i])
5400 int getGameFrameDelay_EM(int native_em_game_frame_delay)
5402 int game_frame_delay_value;
5404 game_frame_delay_value =
5405 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
5406 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
5409 if (tape.playing && tape.warp_forward && !tape.pausing)
5410 game_frame_delay_value = 0;
5412 return game_frame_delay_value;
5416 unsigned int InitRND(long seed)
5418 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
5419 return InitEngineRND_EM(seed);
5421 return InitEngineRND(seed);
5424 void InitGraphicInfo_EM(void)
5426 struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
5427 struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
5431 int num_em_gfx_errors = 0;
5433 if (graphic_info_em_object[0][0].bitmap == NULL)
5435 /* EM graphics not yet initialized in em_open_all() */
5440 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
5443 /* always start with reliable default values */
5444 for (i = 0; i < TILE_MAX; i++)
5446 object_mapping[i].element_rnd = EL_UNKNOWN;
5447 object_mapping[i].is_backside = FALSE;
5448 object_mapping[i].action = ACTION_DEFAULT;
5449 object_mapping[i].direction = MV_NONE;
5452 /* always start with reliable default values */
5453 for (p = 0; p < MAX_PLAYERS; p++)
5455 for (i = 0; i < SPR_MAX; i++)
5457 player_mapping[p][i].element_rnd = EL_UNKNOWN;
5458 player_mapping[p][i].action = ACTION_DEFAULT;
5459 player_mapping[p][i].direction = MV_NONE;
5463 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5465 int e = em_object_mapping_list[i].element_em;
5467 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
5468 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
5470 if (em_object_mapping_list[i].action != -1)
5471 object_mapping[e].action = em_object_mapping_list[i].action;
5473 if (em_object_mapping_list[i].direction != -1)
5474 object_mapping[e].direction =
5475 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
5478 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
5480 int a = em_player_mapping_list[i].action_em;
5481 int p = em_player_mapping_list[i].player_nr;
5483 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
5485 if (em_player_mapping_list[i].action != -1)
5486 player_mapping[p][a].action = em_player_mapping_list[i].action;
5488 if (em_player_mapping_list[i].direction != -1)
5489 player_mapping[p][a].direction =
5490 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
5493 for (i = 0; i < TILE_MAX; i++)
5495 int element = object_mapping[i].element_rnd;
5496 int action = object_mapping[i].action;
5497 int direction = object_mapping[i].direction;
5498 boolean is_backside = object_mapping[i].is_backside;
5499 boolean action_removing = (action == ACTION_DIGGING ||
5500 action == ACTION_SNAPPING ||
5501 action == ACTION_COLLECTING);
5502 boolean action_exploding = ((action == ACTION_EXPLODING ||
5503 action == ACTION_SMASHED_BY_ROCK ||
5504 action == ACTION_SMASHED_BY_SPRING) &&
5505 element != EL_DIAMOND);
5506 boolean action_active = (action == ACTION_ACTIVE);
5507 boolean action_other = (action == ACTION_OTHER);
5509 for (j = 0; j < 8; j++)
5511 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
5512 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
5514 i == Xdrip_stretch ? element :
5515 i == Xdrip_stretchB ? element :
5516 i == Ydrip_s1 ? element :
5517 i == Ydrip_s1B ? element :
5518 i == Xball_1B ? element :
5519 i == Xball_2 ? element :
5520 i == Xball_2B ? element :
5521 i == Yball_eat ? element :
5522 i == Ykey_1_eat ? element :
5523 i == Ykey_2_eat ? element :
5524 i == Ykey_3_eat ? element :
5525 i == Ykey_4_eat ? element :
5526 i == Ykey_5_eat ? element :
5527 i == Ykey_6_eat ? element :
5528 i == Ykey_7_eat ? element :
5529 i == Ykey_8_eat ? element :
5530 i == Ylenses_eat ? element :
5531 i == Ymagnify_eat ? element :
5532 i == Ygrass_eat ? element :
5533 i == Ydirt_eat ? element :
5534 i == Yemerald_stone ? EL_EMERALD :
5535 i == Ydiamond_stone ? EL_ROCK :
5536 i == Xsand_stonein_1 ? element :
5537 i == Xsand_stonein_2 ? element :
5538 i == Xsand_stonein_3 ? element :
5539 i == Xsand_stonein_4 ? element :
5540 is_backside ? EL_EMPTY :
5541 action_removing ? EL_EMPTY :
5543 int effective_action = (j < 7 ? action :
5544 i == Xdrip_stretch ? action :
5545 i == Xdrip_stretchB ? action :
5546 i == Ydrip_s1 ? action :
5547 i == Ydrip_s1B ? action :
5548 i == Xball_1B ? action :
5549 i == Xball_2 ? action :
5550 i == Xball_2B ? action :
5551 i == Yball_eat ? action :
5552 i == Ykey_1_eat ? action :
5553 i == Ykey_2_eat ? action :
5554 i == Ykey_3_eat ? action :
5555 i == Ykey_4_eat ? action :
5556 i == Ykey_5_eat ? action :
5557 i == Ykey_6_eat ? action :
5558 i == Ykey_7_eat ? action :
5559 i == Ykey_8_eat ? action :
5560 i == Ylenses_eat ? action :
5561 i == Ymagnify_eat ? action :
5562 i == Ygrass_eat ? action :
5563 i == Ydirt_eat ? action :
5564 i == Xsand_stonein_1 ? action :
5565 i == Xsand_stonein_2 ? action :
5566 i == Xsand_stonein_3 ? action :
5567 i == Xsand_stonein_4 ? action :
5568 i == Xsand_stoneout_1 ? action :
5569 i == Xsand_stoneout_2 ? action :
5570 i == Xboom_android ? ACTION_EXPLODING :
5571 action_exploding ? ACTION_EXPLODING :
5572 action_active ? action :
5573 action_other ? action :
5575 int graphic = (el_act_dir2img(effective_element, effective_action,
5577 int crumbled = (el_act_dir2crm(effective_element, effective_action,
5579 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
5580 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
5581 boolean has_action_graphics = (graphic != base_graphic);
5582 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
5583 struct GraphicInfo *g = &graphic_info[graphic];
5584 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
5587 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
5588 boolean special_animation = (action != ACTION_DEFAULT &&
5589 g->anim_frames == 3 &&
5590 g->anim_delay == 2 &&
5591 g->anim_mode & ANIM_LINEAR);
5592 int sync_frame = (i == Xdrip_stretch ? 7 :
5593 i == Xdrip_stretchB ? 7 :
5594 i == Ydrip_s2 ? j + 8 :
5595 i == Ydrip_s2B ? j + 8 :
5604 i == Xfake_acid_1 ? 0 :
5605 i == Xfake_acid_2 ? 10 :
5606 i == Xfake_acid_3 ? 20 :
5607 i == Xfake_acid_4 ? 30 :
5608 i == Xfake_acid_5 ? 40 :
5609 i == Xfake_acid_6 ? 50 :
5610 i == Xfake_acid_7 ? 60 :
5611 i == Xfake_acid_8 ? 70 :
5613 i == Xball_2B ? j + 8 :
5614 i == Yball_eat ? j + 1 :
5615 i == Ykey_1_eat ? j + 1 :
5616 i == Ykey_2_eat ? j + 1 :
5617 i == Ykey_3_eat ? j + 1 :
5618 i == Ykey_4_eat ? j + 1 :
5619 i == Ykey_5_eat ? j + 1 :
5620 i == Ykey_6_eat ? j + 1 :
5621 i == Ykey_7_eat ? j + 1 :
5622 i == Ykey_8_eat ? j + 1 :
5623 i == Ylenses_eat ? j + 1 :
5624 i == Ymagnify_eat ? j + 1 :
5625 i == Ygrass_eat ? j + 1 :
5626 i == Ydirt_eat ? j + 1 :
5627 i == Xamoeba_1 ? 0 :
5628 i == Xamoeba_2 ? 1 :
5629 i == Xamoeba_3 ? 2 :
5630 i == Xamoeba_4 ? 3 :
5631 i == Xamoeba_5 ? 0 :
5632 i == Xamoeba_6 ? 1 :
5633 i == Xamoeba_7 ? 2 :
5634 i == Xamoeba_8 ? 3 :
5635 i == Xexit_2 ? j + 8 :
5636 i == Xexit_3 ? j + 16 :
5637 i == Xdynamite_1 ? 0 :
5638 i == Xdynamite_2 ? 8 :
5639 i == Xdynamite_3 ? 16 :
5640 i == Xdynamite_4 ? 24 :
5641 i == Xsand_stonein_1 ? j + 1 :
5642 i == Xsand_stonein_2 ? j + 9 :
5643 i == Xsand_stonein_3 ? j + 17 :
5644 i == Xsand_stonein_4 ? j + 25 :
5645 i == Xsand_stoneout_1 && j == 0 ? 0 :
5646 i == Xsand_stoneout_1 && j == 1 ? 0 :
5647 i == Xsand_stoneout_1 && j == 2 ? 1 :
5648 i == Xsand_stoneout_1 && j == 3 ? 2 :
5649 i == Xsand_stoneout_1 && j == 4 ? 2 :
5650 i == Xsand_stoneout_1 && j == 5 ? 3 :
5651 i == Xsand_stoneout_1 && j == 6 ? 4 :
5652 i == Xsand_stoneout_1 && j == 7 ? 4 :
5653 i == Xsand_stoneout_2 && j == 0 ? 5 :
5654 i == Xsand_stoneout_2 && j == 1 ? 6 :
5655 i == Xsand_stoneout_2 && j == 2 ? 7 :
5656 i == Xsand_stoneout_2 && j == 3 ? 8 :
5657 i == Xsand_stoneout_2 && j == 4 ? 9 :
5658 i == Xsand_stoneout_2 && j == 5 ? 11 :
5659 i == Xsand_stoneout_2 && j == 6 ? 13 :
5660 i == Xsand_stoneout_2 && j == 7 ? 15 :
5661 i == Xboom_bug && j == 1 ? 2 :
5662 i == Xboom_bug && j == 2 ? 2 :
5663 i == Xboom_bug && j == 3 ? 4 :
5664 i == Xboom_bug && j == 4 ? 4 :
5665 i == Xboom_bug && j == 5 ? 2 :
5666 i == Xboom_bug && j == 6 ? 2 :
5667 i == Xboom_bug && j == 7 ? 0 :
5668 i == Xboom_bomb && j == 1 ? 2 :
5669 i == Xboom_bomb && j == 2 ? 2 :
5670 i == Xboom_bomb && j == 3 ? 4 :
5671 i == Xboom_bomb && j == 4 ? 4 :
5672 i == Xboom_bomb && j == 5 ? 2 :
5673 i == Xboom_bomb && j == 6 ? 2 :
5674 i == Xboom_bomb && j == 7 ? 0 :
5675 i == Xboom_android && j == 7 ? 6 :
5676 i == Xboom_1 && j == 1 ? 2 :
5677 i == Xboom_1 && j == 2 ? 2 :
5678 i == Xboom_1 && j == 3 ? 4 :
5679 i == Xboom_1 && j == 4 ? 4 :
5680 i == Xboom_1 && j == 5 ? 6 :
5681 i == Xboom_1 && j == 6 ? 6 :
5682 i == Xboom_1 && j == 7 ? 8 :
5683 i == Xboom_2 && j == 0 ? 8 :
5684 i == Xboom_2 && j == 1 ? 8 :
5685 i == Xboom_2 && j == 2 ? 10 :
5686 i == Xboom_2 && j == 3 ? 10 :
5687 i == Xboom_2 && j == 4 ? 10 :
5688 i == Xboom_2 && j == 5 ? 12 :
5689 i == Xboom_2 && j == 6 ? 12 :
5690 i == Xboom_2 && j == 7 ? 12 :
5691 special_animation && j == 4 ? 3 :
5692 effective_action != action ? 0 :
5696 Bitmap *debug_bitmap = g_em->bitmap;
5697 int debug_src_x = g_em->src_x;
5698 int debug_src_y = g_em->src_y;
5701 int frame = getAnimationFrame(g->anim_frames,
5704 g->anim_start_frame,
5707 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
5708 g->double_movement && is_backside);
5710 g_em->bitmap = src_bitmap;
5711 g_em->src_x = src_x;
5712 g_em->src_y = src_y;
5713 g_em->src_offset_x = 0;
5714 g_em->src_offset_y = 0;
5715 g_em->dst_offset_x = 0;
5716 g_em->dst_offset_y = 0;
5717 g_em->width = TILEX;
5718 g_em->height = TILEY;
5720 g_em->crumbled_bitmap = NULL;
5721 g_em->crumbled_src_x = 0;
5722 g_em->crumbled_src_y = 0;
5723 g_em->crumbled_border_size = 0;
5725 g_em->has_crumbled_graphics = FALSE;
5726 g_em->preserve_background = FALSE;
5729 if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
5730 printf("::: empty crumbled: %d [%s], %d, %d\n",
5731 effective_element, element_info[effective_element].token_name,
5732 effective_action, direction);
5735 /* if element can be crumbled, but certain action graphics are just empty
5736 space (like snapping sand with the original R'n'D graphics), do not
5737 treat these empty space graphics as crumbled graphics in EMC engine */
5738 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
5740 getGraphicSource(crumbled, frame, &src_bitmap, &src_x, &src_y);
5742 g_em->has_crumbled_graphics = TRUE;
5743 g_em->crumbled_bitmap = src_bitmap;
5744 g_em->crumbled_src_x = src_x;
5745 g_em->crumbled_src_y = src_y;
5746 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
5750 if (element == EL_ROCK &&
5751 effective_action == ACTION_FILLING)
5752 printf("::: has_action_graphics == %d\n", has_action_graphics);
5755 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
5756 effective_action == ACTION_MOVING ||
5757 effective_action == ACTION_PUSHING ||
5758 effective_action == ACTION_EATING)) ||
5759 (!has_action_graphics && (effective_action == ACTION_FILLING ||
5760 effective_action == ACTION_EMPTYING)))
5763 (effective_action == ACTION_FALLING ||
5764 effective_action == ACTION_FILLING ||
5765 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
5766 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
5767 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
5768 int num_steps = (i == Ydrip_s1 ? 16 :
5769 i == Ydrip_s1B ? 16 :
5770 i == Ydrip_s2 ? 16 :
5771 i == Ydrip_s2B ? 16 :
5772 i == Xsand_stonein_1 ? 32 :
5773 i == Xsand_stonein_2 ? 32 :
5774 i == Xsand_stonein_3 ? 32 :
5775 i == Xsand_stonein_4 ? 32 :
5776 i == Xsand_stoneout_1 ? 16 :
5777 i == Xsand_stoneout_2 ? 16 : 8);
5778 int cx = ABS(dx) * (TILEX / num_steps);
5779 int cy = ABS(dy) * (TILEY / num_steps);
5780 int step_frame = (i == Ydrip_s2 ? j + 8 :
5781 i == Ydrip_s2B ? j + 8 :
5782 i == Xsand_stonein_2 ? j + 8 :
5783 i == Xsand_stonein_3 ? j + 16 :
5784 i == Xsand_stonein_4 ? j + 24 :
5785 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
5786 int step = (is_backside ? step_frame : num_steps - step_frame);
5788 if (is_backside) /* tile where movement starts */
5790 if (dx < 0 || dy < 0)
5792 g_em->src_offset_x = cx * step;
5793 g_em->src_offset_y = cy * step;
5797 g_em->dst_offset_x = cx * step;
5798 g_em->dst_offset_y = cy * step;
5801 else /* tile where movement ends */
5803 if (dx < 0 || dy < 0)
5805 g_em->dst_offset_x = cx * step;
5806 g_em->dst_offset_y = cy * step;
5810 g_em->src_offset_x = cx * step;
5811 g_em->src_offset_y = cy * step;
5815 g_em->width = TILEX - cx * step;
5816 g_em->height = TILEY - cy * step;
5820 /* create unique graphic identifier to decide if tile must be redrawn */
5821 /* bit 31 - 16 (16 bit): EM style graphic
5822 bit 15 - 12 ( 4 bit): EM style frame
5823 bit 11 - 6 ( 6 bit): graphic width
5824 bit 5 - 0 ( 6 bit): graphic height */
5825 g_em->unique_identifier =
5826 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
5828 /* create unique graphic identifier to decide if tile must be redrawn */
5829 /* bit 31 - 16 (16 bit): EM style element
5830 bit 15 - 12 ( 4 bit): EM style frame
5831 bit 11 - 6 ( 6 bit): graphic width
5832 bit 5 - 0 ( 6 bit): graphic height */
5833 g_em->unique_identifier =
5834 (i << 16) | (j << 12) | (g_em->width << 6) | g_em->height;
5838 if (effective_element == EL_ROCK)
5839 printf("::: EL_ROCK(%d, %d): %d, %d => %d\n",
5840 effective_action, j, graphic, frame, g_em->unique_identifier);
5846 /* skip check for EMC elements not contained in original EMC artwork */
5847 if (element == EL_EMC_FAKE_ACID)
5851 if (g_em->bitmap != debug_bitmap ||
5852 g_em->src_x != debug_src_x ||
5853 g_em->src_y != debug_src_y ||
5854 g_em->src_offset_x != 0 ||
5855 g_em->src_offset_y != 0 ||
5856 g_em->dst_offset_x != 0 ||
5857 g_em->dst_offset_y != 0 ||
5858 g_em->width != TILEX ||
5859 g_em->height != TILEY)
5861 static int last_i = -1;
5869 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
5870 i, element, element_info[element].token_name,
5871 element_action_info[effective_action].suffix, direction);
5873 if (element != effective_element)
5874 printf(" [%d ('%s')]",
5876 element_info[effective_element].token_name);
5880 if (g_em->bitmap != debug_bitmap)
5881 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
5882 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
5884 if (g_em->src_x != debug_src_x ||
5885 g_em->src_y != debug_src_y)
5886 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
5887 j, (is_backside ? 'B' : 'F'),
5888 g_em->src_x, g_em->src_y,
5889 g_em->src_x / 32, g_em->src_y / 32,
5890 debug_src_x, debug_src_y,
5891 debug_src_x / 32, debug_src_y / 32);
5893 if (g_em->src_offset_x != 0 ||
5894 g_em->src_offset_y != 0 ||
5895 g_em->dst_offset_x != 0 ||
5896 g_em->dst_offset_y != 0)
5897 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
5899 g_em->src_offset_x, g_em->src_offset_y,
5900 g_em->dst_offset_x, g_em->dst_offset_y);
5902 if (g_em->width != TILEX ||
5903 g_em->height != TILEY)
5904 printf(" %d (%d): size %d,%d should be %d,%d\n",
5906 g_em->width, g_em->height, TILEX, TILEY);
5908 num_em_gfx_errors++;
5915 for (i = 0; i < TILE_MAX; i++)
5917 for (j = 0; j < 8; j++)
5919 int element = object_mapping[i].element_rnd;
5920 int action = object_mapping[i].action;
5921 int direction = object_mapping[i].direction;
5922 boolean is_backside = object_mapping[i].is_backside;
5924 int graphic_action = el_act_dir2img(element, action, direction);
5925 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
5927 int graphic_action = element_info[element].graphic[action];
5928 int graphic_default = element_info[element].graphic[ACTION_DEFAULT];
5931 if ((action == ACTION_SMASHED_BY_ROCK ||
5932 action == ACTION_SMASHED_BY_SPRING ||
5933 action == ACTION_EATING) &&
5934 graphic_action == graphic_default)
5936 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
5937 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
5938 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
5939 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
5942 /* no separate animation for "smashed by rock" -- use rock instead */
5943 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
5944 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
5946 g_em->bitmap = g_xx->bitmap;
5947 g_em->src_x = g_xx->src_x;
5948 g_em->src_y = g_xx->src_y;
5949 g_em->src_offset_x = g_xx->src_offset_x;
5950 g_em->src_offset_y = g_xx->src_offset_y;
5951 g_em->dst_offset_x = g_xx->dst_offset_x;
5952 g_em->dst_offset_y = g_xx->dst_offset_y;
5953 g_em->width = g_xx->width;
5954 g_em->height = g_xx->height;
5956 g_em->unique_identifier = g_xx->unique_identifier;
5960 g_em->preserve_background = TRUE;
5965 for (p = 0; p < MAX_PLAYERS; p++)
5967 for (i = 0; i < SPR_MAX; i++)
5969 int element = player_mapping[p][i].element_rnd;
5970 int action = player_mapping[p][i].action;
5971 int direction = player_mapping[p][i].direction;
5973 for (j = 0; j < 8; j++)
5975 int effective_element = element;
5976 int effective_action = action;
5977 int graphic = (direction == MV_NONE ?
5978 el_act2img(effective_element, effective_action) :
5979 el_act_dir2img(effective_element, effective_action,
5981 struct GraphicInfo *g = &graphic_info[graphic];
5982 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
5988 Bitmap *debug_bitmap = g_em->bitmap;
5989 int debug_src_x = g_em->src_x;
5990 int debug_src_y = g_em->src_y;
5993 int frame = getAnimationFrame(g->anim_frames,
5996 g->anim_start_frame,
5999 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x,&src_y, FALSE);
6001 g_em->bitmap = src_bitmap;
6002 g_em->src_x = src_x;
6003 g_em->src_y = src_y;
6004 g_em->src_offset_x = 0;
6005 g_em->src_offset_y = 0;
6006 g_em->dst_offset_x = 0;
6007 g_em->dst_offset_y = 0;
6008 g_em->width = TILEX;
6009 g_em->height = TILEY;
6014 /* skip check for EMC elements not contained in original EMC artwork */
6015 if (element == EL_PLAYER_3 ||
6016 element == EL_PLAYER_4)
6020 if (g_em->bitmap != debug_bitmap ||
6021 g_em->src_x != debug_src_x ||
6022 g_em->src_y != debug_src_y)
6024 static int last_i = -1;
6032 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
6033 p, i, element, element_info[element].token_name,
6034 element_action_info[effective_action].suffix, direction);
6036 if (element != effective_element)
6037 printf(" [%d ('%s')]",
6039 element_info[effective_element].token_name);
6043 if (g_em->bitmap != debug_bitmap)
6044 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
6045 j, (int)(g_em->bitmap), (int)(debug_bitmap));
6047 if (g_em->src_x != debug_src_x ||
6048 g_em->src_y != debug_src_y)
6049 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
6051 g_em->src_x, g_em->src_y,
6052 g_em->src_x / 32, g_em->src_y / 32,
6053 debug_src_x, debug_src_y,
6054 debug_src_x / 32, debug_src_y / 32);
6056 num_em_gfx_errors++;
6066 printf("::: [%d errors found]\n", num_em_gfx_errors);
6072 void PlayMenuSound()
6074 int sound = menu.sound[game_status];
6076 if (sound == SND_UNDEFINED)
6079 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6080 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6083 if (IS_LOOP_SOUND(sound))
6084 PlaySoundLoop(sound);
6089 void PlayMenuSoundStereo(int sound, int stereo_position)
6091 if (sound == SND_UNDEFINED)
6094 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6095 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6098 if (IS_LOOP_SOUND(sound))
6099 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
6101 PlaySoundStereo(sound, stereo_position);
6104 void PlayMenuSoundIfLoop()
6106 int sound = menu.sound[game_status];
6108 if (sound == SND_UNDEFINED)
6111 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6112 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6115 if (IS_LOOP_SOUND(sound))
6116 PlaySoundLoop(sound);
6119 void PlayMenuMusic()
6121 int music = menu.music[game_status];
6123 if (music == MUS_UNDEFINED)
6129 void ToggleFullscreenIfNeeded()
6131 if (setup.fullscreen != video.fullscreen_enabled ||
6132 setup.fullscreen_mode != video.fullscreen_mode_current)
6134 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
6136 /* save backbuffer content which gets lost when toggling fullscreen mode */
6137 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6139 if (setup.fullscreen && video.fullscreen_enabled)
6141 /* keep fullscreen mode, but change screen mode */
6142 video.fullscreen_mode_current = setup.fullscreen_mode;
6143 video.fullscreen_enabled = FALSE;
6146 /* toggle fullscreen */
6147 ChangeVideoModeIfNeeded(setup.fullscreen);
6148 setup.fullscreen = video.fullscreen_enabled;
6150 /* restore backbuffer content from temporary backbuffer backup bitmap */
6151 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6153 FreeBitmap(tmp_backbuffer);
6155 redraw_mask = REDRAW_ALL;