1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back! *
3 *----------------------------------------------------------*
4 * (c) 1995-2006 Artsoft Entertainment *
6 * Detmolder Strasse 189 *
9 * e-mail: info@artsoft.org *
10 *----------------------------------------------------------*
12 ***********************************************************/
14 #include "libgame/libgame.h"
24 /* select level set with EMC X11 graphics before activating EM GFX debugging */
25 #define DEBUG_EM_GFX 0
27 /* tool button identifiers */
28 #define TOOL_CTRL_ID_YES 0
29 #define TOOL_CTRL_ID_NO 1
30 #define TOOL_CTRL_ID_CONFIRM 2
31 #define TOOL_CTRL_ID_PLAYER_1 3
32 #define TOOL_CTRL_ID_PLAYER_2 4
33 #define TOOL_CTRL_ID_PLAYER_3 5
34 #define TOOL_CTRL_ID_PLAYER_4 6
36 #define NUM_TOOL_BUTTONS 7
38 /* forward declaration for internal use */
39 static void UnmapToolButtons();
40 static void HandleToolButtons(struct GadgetInfo *);
41 static int el_act_dir2crm(int, int, int);
42 static int el_act2crm(int, int);
44 static struct GadgetInfo *tool_gadget[NUM_TOOL_BUTTONS];
45 static int request_gadget_id = -1;
47 static char *print_if_not_empty(int element)
49 static char *s = NULL;
50 char *token_name = element_info[element].token_name;
55 s = checked_malloc(strlen(token_name) + 10 + 1);
57 if (element != EL_EMPTY)
58 sprintf(s, "%d\t['%s']", element, token_name);
60 sprintf(s, "%d", element);
65 void DumpTile(int x, int y)
70 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
77 printf("Field Info: SCREEN(%d, %d), LEVEL(%d, %d)\n", sx, sy, x, y);
80 if (!IN_LEV_FIELD(x, y))
82 printf("(not in level field)\n");
88 printf(" Feld: %d\t['%s']\n", Feld[x][y],
89 element_info[Feld[x][y]].token_name);
90 printf(" Back: %s\n", print_if_not_empty(Back[x][y]));
91 printf(" Store: %s\n", print_if_not_empty(Store[x][y]));
92 printf(" Store2: %s\n", print_if_not_empty(Store2[x][y]));
93 printf(" StorePlayer: %s\n", print_if_not_empty(StorePlayer[x][y]));
94 printf(" MovPos: %d\n", MovPos[x][y]);
95 printf(" MovDir: %d\n", MovDir[x][y]);
96 printf(" MovDelay: %d\n", MovDelay[x][y]);
97 printf(" ChangeDelay: %d\n", ChangeDelay[x][y]);
98 printf(" CustomValue: %d\n", CustomValue[x][y]);
99 printf(" GfxElement: %d\n", GfxElement[x][y]);
100 printf(" GfxAction: %d\n", GfxAction[x][y]);
101 printf(" GfxFrame: %d\n", GfxFrame[x][y]);
105 void SetDrawtoField(int mode)
107 if (mode == DRAW_BUFFERED && setup.soft_scrolling)
118 drawto_field = fieldbuffer;
120 else /* DRAW_DIRECT, DRAW_BACKBUFFER */
126 BX2 = SCR_FIELDX - 1;
127 BY2 = SCR_FIELDY - 1;
131 drawto_field = (mode == DRAW_DIRECT ? window : backbuffer);
135 void RedrawPlayfield(boolean force_redraw, int x, int y, int width, int height)
137 if (game_status == GAME_MODE_PLAYING &&
138 level.game_engine_type == GAME_ENGINE_TYPE_EM)
140 /* currently there is no partial redraw -- always redraw whole playfield */
141 RedrawPlayfield_EM(TRUE);
143 /* blit playfield from scroll buffer to normal back buffer for fading in */
144 BlitScreenToBitmap_EM(backbuffer);
146 else if (game_status == GAME_MODE_PLAYING && !game.envelope_active)
152 width = gfx.sxsize + 2 * TILEX;
153 height = gfx.sysize + 2 * TILEY;
156 if (force_redraw || setup.direct_draw)
159 int x1 = (x - SX) / TILEX, y1 = (y - SY) / TILEY;
160 int x2 = (x - SX + width) / TILEX, y2 = (y - SY + height) / TILEY;
162 if (setup.direct_draw)
163 SetDrawtoField(DRAW_BACKBUFFER);
165 for (xx = BX1; xx <= BX2; xx++)
166 for (yy = BY1; yy <= BY2; yy++)
167 if (xx >= x1 && xx <= x2 && yy >= y1 && yy <= y2)
168 DrawScreenField(xx, yy);
171 if (setup.direct_draw)
172 SetDrawtoField(DRAW_DIRECT);
175 if (setup.soft_scrolling)
177 int fx = FX, fy = FY;
179 fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0);
180 fy += (ScreenMovDir & (MV_UP|MV_DOWN) ? ScreenGfxPos : 0);
182 BlitBitmap(fieldbuffer, backbuffer, fx,fy, SXSIZE,SYSIZE, SX,SY);
194 BlitBitmap(drawto, window, x, y, width, height, x, y);
197 void DrawMaskedBorder_FIELD()
199 if (game_status >= GAME_MODE_TITLE &&
200 game_status <= GAME_MODE_PLAYING &&
201 border.draw_masked[game_status])
202 BlitBitmapMasked(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
203 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
207 void DrawMaskedBorder_DOOR_1()
209 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
210 (game_status != GAME_MODE_EDITOR ||
211 border.draw_masked[GFX_SPECIAL_ARG_EDITOR]))
212 BlitBitmapMasked(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
213 DX, DY, DXSIZE, DYSIZE, DX, DY);
216 void DrawMaskedBorder_DOOR_2()
218 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
219 game_status != GAME_MODE_EDITOR)
220 BlitBitmapMasked(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
221 VX, VY, VXSIZE, VYSIZE, VX, VY);
224 void DrawMaskedBorder_DOOR_3()
226 /* currently not available */
229 void DrawMaskedBorder_ALL()
231 DrawMaskedBorder_FIELD();
232 DrawMaskedBorder_DOOR_1();
233 DrawMaskedBorder_DOOR_2();
234 DrawMaskedBorder_DOOR_3();
237 void DrawMaskedBorder(int redraw_mask)
239 if (redraw_mask & REDRAW_ALL)
240 DrawMaskedBorder_ALL();
243 if (redraw_mask & REDRAW_FIELD)
244 DrawMaskedBorder_FIELD();
245 if (redraw_mask & REDRAW_DOOR_1)
246 DrawMaskedBorder_DOOR_1();
247 if (redraw_mask & REDRAW_DOOR_2)
248 DrawMaskedBorder_DOOR_2();
249 if (redraw_mask & REDRAW_DOOR_3)
250 DrawMaskedBorder_DOOR_3();
257 DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
259 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
260 redraw_mask &= ~REDRAW_MAIN;
262 if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD)
263 redraw_mask |= REDRAW_FIELD;
265 if (redraw_mask & REDRAW_FIELD)
266 redraw_mask &= ~REDRAW_TILES;
268 if (redraw_mask == REDRAW_NONE)
271 if (redraw_mask & REDRAW_TILES &&
272 game_status == GAME_MODE_PLAYING &&
273 border.draw_masked[game_status])
274 redraw_mask |= REDRAW_FIELD;
276 if (global.fps_slowdown && game_status == GAME_MODE_PLAYING)
278 static boolean last_frame_skipped = FALSE;
279 boolean skip_even_when_not_scrolling = TRUE;
280 boolean just_scrolling = (ScreenMovDir != 0);
281 boolean verbose = FALSE;
283 if (global.fps_slowdown_factor > 1 &&
284 (FrameCounter % global.fps_slowdown_factor) &&
285 (just_scrolling || skip_even_when_not_scrolling))
287 redraw_mask &= ~REDRAW_MAIN;
289 last_frame_skipped = TRUE;
292 printf("FRAME SKIPPED\n");
296 if (last_frame_skipped)
297 redraw_mask |= REDRAW_FIELD;
299 last_frame_skipped = FALSE;
302 printf("frame not skipped\n");
306 /* synchronize X11 graphics at this point; if we would synchronize the
307 display immediately after the buffer switching (after the XFlush),
308 this could mean that we have to wait for the graphics to complete,
309 although we could go on doing calculations for the next frame */
314 DrawMaskedBorder(redraw_mask);
317 if (redraw_mask & REDRAW_ALL)
320 DrawMaskedBorder(REDRAW_ALL);
322 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
324 redraw_mask = REDRAW_NONE;
327 if (redraw_mask & REDRAW_FIELD)
329 if (game_status != GAME_MODE_PLAYING ||
330 redraw_mask & REDRAW_FROM_BACKBUFFER)
333 DrawMaskedBorder(REDRAW_FIELD);
335 BlitBitmap(backbuffer, window,
336 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
340 int fx = FX, fy = FY;
342 if (setup.soft_scrolling)
344 fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
345 fy += (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
348 if (setup.soft_scrolling ||
349 ABS(ScreenMovPos) + ScrollStepSize == TILEX ||
350 ABS(ScreenMovPos) == ScrollStepSize ||
351 redraw_tiles > REDRAWTILES_THRESHOLD)
354 if (border.draw_masked[GFX_SPECIAL_ARG_MAIN])
356 BlitBitmap(buffer, backbuffer, fx, fy, SXSIZE, SYSIZE, SX, SY);
358 DrawMaskedBorder(REDRAW_FIELD);
359 BlitBitmap(backbuffer, window,
360 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
364 BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
366 BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
371 printf("redrawing all (ScreenGfxPos == %d) because %s\n",
373 (setup.soft_scrolling ?
374 "setup.soft_scrolling" :
375 ABS(ScreenGfxPos) + ScrollStepSize == TILEX ?
376 "ABS(ScreenGfxPos) + ScrollStepSize == TILEX" :
377 ABS(ScreenGfxPos) == ScrollStepSize ?
378 "ABS(ScreenGfxPos) == ScrollStepSize" :
379 "redraw_tiles > REDRAWTILES_THRESHOLD"));
385 redraw_mask &= ~REDRAW_MAIN;
388 if (redraw_mask & REDRAW_DOORS)
390 if (redraw_mask & REDRAW_DOOR_1)
393 DrawMaskedBorder(REDRAW_DOOR_1);
395 BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
398 if (redraw_mask & REDRAW_DOOR_2)
401 DrawMaskedBorder(REDRAW_DOOR_2);
403 BlitBitmap(backbuffer, window, VX, VY, VXSIZE, VYSIZE, VX, VY);
406 if (redraw_mask & REDRAW_DOOR_3)
409 DrawMaskedBorder(REDRAW_DOOR_3);
411 BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
414 redraw_mask &= ~REDRAW_DOORS;
417 if (redraw_mask & REDRAW_MICROLEVEL)
419 BlitBitmap(backbuffer, window, SX, SY + 10 * TILEY, SXSIZE, 7 * TILEY,
420 SX, SY + 10 * TILEY);
422 redraw_mask &= ~REDRAW_MICROLEVEL;
425 if (redraw_mask & REDRAW_TILES)
427 for (x = 0; x < SCR_FIELDX; x++)
428 for (y = 0 ; y < SCR_FIELDY; y++)
429 if (redraw[redraw_x1 + x][redraw_y1 + y])
430 BlitBitmap(buffer, window,
431 FX + x * TILEX, FY + y * TILEY, TILEX, TILEY,
432 SX + x * TILEX, SY + y * TILEY);
435 if (redraw_mask & REDRAW_FPS) /* display frames per second */
440 sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
441 if (!global.fps_slowdown)
444 sprintf(text, "%.1f fps%s", global.frames_per_second, info1);
445 DrawTextExt(window, SX, SY, text, FONT_TEXT_2, BLIT_OPAQUE);
450 for (x = 0; x < MAX_BUF_XSIZE; x++)
451 for (y = 0; y < MAX_BUF_YSIZE; y++)
454 redraw_mask = REDRAW_NONE;
460 long fading_delay = 300;
462 if (setup.fading && (redraw_mask & REDRAW_FIELD))
469 ClearRectangle(window, REAL_SX,REAL_SY,FULL_SXSIZE,FULL_SYSIZE);
472 for (i = 0; i < 2 * FULL_SYSIZE; i++)
474 for (y = 0; y < FULL_SYSIZE; y++)
476 BlitBitmap(backbuffer, window,
477 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
485 for (i = 1; i < FULL_SYSIZE; i+=2)
486 BlitBitmap(backbuffer, window,
487 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
493 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, 0);
494 BlitBitmapMasked(backbuffer, window,
495 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
500 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, -1);
501 BlitBitmapMasked(backbuffer, window,
502 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
507 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, -1);
508 BlitBitmapMasked(backbuffer, window,
509 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
514 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, 0);
515 BlitBitmapMasked(backbuffer, window,
516 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
521 redraw_mask &= ~REDRAW_MAIN;
528 void FadeExt(int fade_mask, int fade_mode)
530 void (*draw_border_function)(void) = NULL;
531 Bitmap *bitmap = (fade_mode == FADE_MODE_CROSSFADE ? bitmap_db_cross : NULL);
532 int fade_delay = menu.fade_delay;
533 int post_delay = (fade_mode == FADE_MODE_FADE_OUT ? menu.post_delay : 0);
534 int x, y, width, height;
536 if (fade_mask & REDRAW_FIELD)
541 height = FULL_SYSIZE;
543 draw_border_function = DrawMaskedBorder_FIELD;
545 else /* REDRAW_ALL */
553 redraw_mask |= fade_mask;
555 if (!setup.fade_screens || fade_delay == 0)
557 if (fade_mode == FADE_MODE_FADE_OUT)
558 ClearRectangle(backbuffer, x, y, width, height);
565 FadeRectangle(bitmap, x, y, width, height, fade_mode, fade_delay, post_delay,
566 draw_border_function);
568 redraw_mask &= ~fade_mask;
571 void FadeIn(int fade_mask)
573 FadeExt(fade_mask, FADE_MODE_FADE_IN);
576 void FadeOut(int fade_mask)
578 FadeExt(fade_mask, FADE_MODE_FADE_OUT);
581 void FadeCross(int fade_mask)
583 FadeExt(fade_mask, FADE_MODE_CROSSFADE);
586 void FadeCrossSaveBackbuffer()
588 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
591 void SetMainBackgroundImageIfDefined(int graphic)
593 if (graphic_info[graphic].bitmap)
594 SetMainBackgroundImage(graphic);
597 void SetMainBackgroundImage(int graphic)
599 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
600 graphic_info[graphic].bitmap ?
601 graphic_info[graphic].bitmap :
602 graphic_info[IMG_BACKGROUND].bitmap);
605 void SetDoorBackgroundImage(int graphic)
607 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
608 graphic_info[graphic].bitmap ?
609 graphic_info[graphic].bitmap :
610 graphic_info[IMG_BACKGROUND].bitmap);
613 void SetPanelBackground()
615 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, bitmap_db_panel,
616 DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, 0, 0);
618 SetDoorBackgroundBitmap(bitmap_db_panel);
621 void DrawBackground(int dst_x, int dst_y, int width, int height)
624 ClearRectangleOnBackground(drawto, dst_x, dst_y, width, height);
626 ClearRectangleOnBackground(backbuffer, dst_x, dst_y, width, height);
629 redraw_mask |= REDRAW_FIELD;
634 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
636 if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
638 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
639 SetDrawtoField(DRAW_BUFFERED);
642 SetDrawtoField(DRAW_BACKBUFFER);
644 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
646 ClearRectangle(window, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
647 SetDrawtoField(DRAW_DIRECT);
651 void MarkTileDirty(int x, int y)
653 int xx = redraw_x1 + x;
654 int yy = redraw_y1 + y;
659 redraw[xx][yy] = TRUE;
660 redraw_mask |= REDRAW_TILES;
663 void SetBorderElement()
667 BorderElement = EL_EMPTY;
669 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
671 for (x = 0; x < lev_fieldx; x++)
673 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
674 BorderElement = EL_STEELWALL;
676 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
682 void SetRandomAnimationValue(int x, int y)
684 gfx.anim_random_frame = GfxRandom[x][y];
687 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
689 /* animation synchronized with global frame counter, not move position */
690 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
691 sync_frame = FrameCounter;
693 return getAnimationFrame(graphic_info[graphic].anim_frames,
694 graphic_info[graphic].anim_delay,
695 graphic_info[graphic].anim_mode,
696 graphic_info[graphic].anim_start_frame,
700 inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
701 int *x, int *y, boolean get_backside)
703 struct GraphicInfo *g = &graphic_info[graphic];
704 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
705 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
709 if (g->offset_y == 0) /* frames are ordered horizontally */
711 int max_width = g->anim_frames_per_line * g->width;
712 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
714 *x = pos % max_width;
715 *y = src_y % g->height + pos / max_width * g->height;
717 else if (g->offset_x == 0) /* frames are ordered vertically */
719 int max_height = g->anim_frames_per_line * g->height;
720 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
722 *x = src_x % g->width + pos / max_height * g->width;
723 *y = pos % max_height;
725 else /* frames are ordered diagonally */
727 *x = src_x + frame * g->offset_x;
728 *y = src_y + frame * g->offset_y;
732 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
734 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
737 void DrawGraphic(int x, int y, int graphic, int frame)
740 if (!IN_SCR_FIELD(x, y))
742 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
743 printf("DrawGraphic(): This should never happen!\n");
748 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
752 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
758 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
759 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
762 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
765 if (!IN_SCR_FIELD(x, y))
767 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
768 printf("DrawGraphicThruMask(): This should never happen!\n");
773 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
778 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
784 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
786 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
787 dst_x - src_x, dst_y - src_y);
788 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
791 void DrawMiniGraphic(int x, int y, int graphic)
793 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
794 MarkTileDirty(x / 2, y / 2);
797 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
799 struct GraphicInfo *g = &graphic_info[graphic];
801 int mini_starty = g->bitmap->height * 2 / 3;
804 *x = mini_startx + g->src_x / 2;
805 *y = mini_starty + g->src_y / 2;
808 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
813 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
814 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
817 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
818 int graphic, int frame,
819 int cut_mode, int mask_mode)
824 int width = TILEX, height = TILEY;
827 if (dx || dy) /* shifted graphic */
829 if (x < BX1) /* object enters playfield from the left */
836 else if (x > BX2) /* object enters playfield from the right */
842 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
848 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
850 else if (dx) /* general horizontal movement */
851 MarkTileDirty(x + SIGN(dx), y);
853 if (y < BY1) /* object enters playfield from the top */
855 if (cut_mode==CUT_BELOW) /* object completely above top border */
863 else if (y > BY2) /* object enters playfield from the bottom */
869 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
875 else if (dy > 0 && cut_mode == CUT_ABOVE)
877 if (y == BY2) /* object completely above bottom border */
883 MarkTileDirty(x, y + 1);
884 } /* object leaves playfield to the bottom */
885 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
887 else if (dy) /* general vertical movement */
888 MarkTileDirty(x, y + SIGN(dy));
892 if (!IN_SCR_FIELD(x, y))
894 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
895 printf("DrawGraphicShifted(): This should never happen!\n");
900 if (width > 0 && height > 0)
902 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
907 dst_x = FX + x * TILEX + dx;
908 dst_y = FY + y * TILEY + dy;
910 if (mask_mode == USE_MASKING)
912 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
913 dst_x - src_x, dst_y - src_y);
914 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
918 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
925 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
926 int graphic, int frame,
927 int cut_mode, int mask_mode)
932 int width = TILEX, height = TILEY;
935 int x2 = x + SIGN(dx);
936 int y2 = y + SIGN(dy);
937 int anim_frames = graphic_info[graphic].anim_frames;
938 int sync_frame = (dx ? ABS(dx) : ABS(dy)) * anim_frames / TILESIZE;
939 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
940 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
942 /* re-calculate animation frame for two-tile movement animation */
943 frame = getGraphicAnimationFrame(graphic, sync_frame);
945 /* check if movement start graphic inside screen area and should be drawn */
946 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
948 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
950 dst_x = FX + x1 * TILEX;
951 dst_y = FY + y1 * TILEY;
953 if (mask_mode == USE_MASKING)
955 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
956 dst_x - src_x, dst_y - src_y);
957 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
961 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
964 MarkTileDirty(x1, y1);
967 /* check if movement end graphic inside screen area and should be drawn */
968 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
970 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
972 dst_x = FX + x2 * TILEX;
973 dst_y = FY + y2 * TILEY;
975 if (mask_mode == USE_MASKING)
977 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
978 dst_x - src_x, dst_y - src_y);
979 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
983 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
986 MarkTileDirty(x2, y2);
990 static void DrawGraphicShifted(int x, int y, int dx, int dy,
991 int graphic, int frame,
992 int cut_mode, int mask_mode)
996 DrawGraphic(x, y, graphic, frame);
1001 if (graphic_info[graphic].double_movement) /* EM style movement images */
1002 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1004 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1007 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1008 int frame, int cut_mode)
1010 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
1013 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1014 int cut_mode, int mask_mode)
1016 int lx = LEVELX(x), ly = LEVELY(y);
1020 if (IN_LEV_FIELD(lx, ly))
1022 SetRandomAnimationValue(lx, ly);
1024 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
1025 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1027 /* do not use double (EM style) movement graphic when not moving */
1028 if (graphic_info[graphic].double_movement && !dx && !dy)
1030 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
1031 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1034 else /* border element */
1036 graphic = el2img(element);
1037 frame = getGraphicAnimationFrame(graphic, -1);
1040 if (element == EL_EXPANDABLE_WALL)
1042 boolean left_stopped = FALSE, right_stopped = FALSE;
1044 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1045 left_stopped = TRUE;
1046 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1047 right_stopped = TRUE;
1049 if (left_stopped && right_stopped)
1051 else if (left_stopped)
1053 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1054 frame = graphic_info[graphic].anim_frames - 1;
1056 else if (right_stopped)
1058 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1059 frame = graphic_info[graphic].anim_frames - 1;
1064 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1065 else if (mask_mode == USE_MASKING)
1066 DrawGraphicThruMask(x, y, graphic, frame);
1068 DrawGraphic(x, y, graphic, frame);
1071 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1072 int cut_mode, int mask_mode)
1074 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1075 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1076 cut_mode, mask_mode);
1079 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1082 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1085 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1088 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1091 void DrawLevelElementThruMask(int x, int y, int element)
1093 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1096 void DrawLevelFieldThruMask(int x, int y)
1098 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1101 static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
1105 int sx = SCREENX(x), sy = SCREENY(y);
1107 int width, height, cx, cy, i;
1108 int crumbled_border_size = graphic_info[graphic].border_size;
1109 static int xy[4][2] =
1117 if (!IN_LEV_FIELD(x, y))
1120 element = TILE_GFX_ELEMENT(x, y);
1122 /* crumble field itself */
1123 if (GFX_CRUMBLED(element) && !IS_MOVING(x, y))
1125 if (!IN_SCR_FIELD(sx, sy))
1128 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1130 for (i = 0; i < 4; i++)
1132 int xx = x + xy[i][0];
1133 int yy = y + xy[i][1];
1135 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1138 /* check if neighbour field is of same type */
1139 if (GFX_CRUMBLED(element) && !IS_MOVING(xx, yy))
1142 if (i == 1 || i == 2)
1144 width = crumbled_border_size;
1146 cx = (i == 2 ? TILEX - crumbled_border_size : 0);
1152 height = crumbled_border_size;
1154 cy = (i == 3 ? TILEY - crumbled_border_size : 0);
1157 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1158 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1161 MarkTileDirty(sx, sy);
1163 else /* crumble neighbour fields */
1165 for (i = 0; i < 4; i++)
1167 int xx = x + xy[i][0];
1168 int yy = y + xy[i][1];
1169 int sxx = sx + xy[i][0];
1170 int syy = sy + xy[i][1];
1172 if (!IN_LEV_FIELD(xx, yy) ||
1173 !IN_SCR_FIELD(sxx, syy) ||
1177 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
1180 element = TILE_GFX_ELEMENT(xx, yy);
1182 if (!GFX_CRUMBLED(element))
1185 graphic = el_act2crm(element, ACTION_DEFAULT);
1186 crumbled_border_size = graphic_info[graphic].border_size;
1188 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1190 if (i == 1 || i == 2)
1192 width = crumbled_border_size;
1194 cx = (i == 1 ? TILEX - crumbled_border_size : 0);
1200 height = crumbled_border_size;
1202 cy = (i == 0 ? TILEY - crumbled_border_size : 0);
1205 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1206 width, height, FX + sxx * TILEX + cx, FY + syy * TILEY + cy);
1208 MarkTileDirty(sxx, syy);
1213 void DrawLevelFieldCrumbledSand(int x, int y)
1217 if (!IN_LEV_FIELD(x, y))
1221 /* !!! CHECK THIS !!! */
1224 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1225 GFX_CRUMBLED(GfxElement[x][y]))
1228 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1229 GfxElement[x][y] != EL_UNDEFINED &&
1230 GFX_CRUMBLED(GfxElement[x][y]))
1232 DrawLevelFieldCrumbledSandDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
1239 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
1241 graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
1244 DrawLevelFieldCrumbledSandExt(x, y, graphic, 0);
1247 void DrawLevelFieldCrumbledSandDigging(int x, int y, int direction,
1250 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1251 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1252 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1253 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1254 int sx = SCREENX(x), sy = SCREENY(y);
1256 DrawGraphic(sx, sy, graphic1, frame1);
1257 DrawLevelFieldCrumbledSandExt(x, y, graphic2, frame2);
1260 void DrawLevelFieldCrumbledSandNeighbours(int x, int y)
1262 int sx = SCREENX(x), sy = SCREENY(y);
1263 static int xy[4][2] =
1272 for (i = 0; i < 4; i++)
1274 int xx = x + xy[i][0];
1275 int yy = y + xy[i][1];
1276 int sxx = sx + xy[i][0];
1277 int syy = sy + xy[i][1];
1279 if (!IN_LEV_FIELD(xx, yy) ||
1280 !IN_SCR_FIELD(sxx, syy) ||
1281 !GFX_CRUMBLED(Feld[xx][yy]) ||
1285 DrawLevelField(xx, yy);
1289 static int getBorderElement(int x, int y)
1293 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1294 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1295 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1296 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1297 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1298 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1299 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1301 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1302 int steel_position = (x == -1 && y == -1 ? 0 :
1303 x == lev_fieldx && y == -1 ? 1 :
1304 x == -1 && y == lev_fieldy ? 2 :
1305 x == lev_fieldx && y == lev_fieldy ? 3 :
1306 x == -1 || x == lev_fieldx ? 4 :
1307 y == -1 || y == lev_fieldy ? 5 : 6);
1309 return border[steel_position][steel_type];
1312 void DrawScreenElement(int x, int y, int element)
1314 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1315 DrawLevelFieldCrumbledSand(LEVELX(x), LEVELY(y));
1318 void DrawLevelElement(int x, int y, int element)
1320 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1321 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1324 void DrawScreenField(int x, int y)
1326 int lx = LEVELX(x), ly = LEVELY(y);
1327 int element, content;
1329 if (!IN_LEV_FIELD(lx, ly))
1331 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1334 element = getBorderElement(lx, ly);
1336 DrawScreenElement(x, y, element);
1340 element = Feld[lx][ly];
1341 content = Store[lx][ly];
1343 if (IS_MOVING(lx, ly))
1345 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1346 boolean cut_mode = NO_CUTTING;
1348 if (element == EL_QUICKSAND_EMPTYING ||
1349 element == EL_MAGIC_WALL_EMPTYING ||
1350 element == EL_BD_MAGIC_WALL_EMPTYING ||
1351 element == EL_AMOEBA_DROPPING)
1352 cut_mode = CUT_ABOVE;
1353 else if (element == EL_QUICKSAND_FILLING ||
1354 element == EL_MAGIC_WALL_FILLING ||
1355 element == EL_BD_MAGIC_WALL_FILLING)
1356 cut_mode = CUT_BELOW;
1358 if (cut_mode == CUT_ABOVE)
1359 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1361 DrawScreenElement(x, y, EL_EMPTY);
1364 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1365 else if (cut_mode == NO_CUTTING)
1366 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1368 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1370 if (content == EL_ACID)
1372 int dir = MovDir[lx][ly];
1373 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
1374 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
1376 DrawLevelElementThruMask(newlx, newly, EL_ACID);
1379 else if (IS_BLOCKED(lx, ly))
1384 boolean cut_mode = NO_CUTTING;
1385 int element_old, content_old;
1387 Blocked2Moving(lx, ly, &oldx, &oldy);
1390 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1391 MovDir[oldx][oldy] == MV_RIGHT);
1393 element_old = Feld[oldx][oldy];
1394 content_old = Store[oldx][oldy];
1396 if (element_old == EL_QUICKSAND_EMPTYING ||
1397 element_old == EL_MAGIC_WALL_EMPTYING ||
1398 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1399 element_old == EL_AMOEBA_DROPPING)
1400 cut_mode = CUT_ABOVE;
1402 DrawScreenElement(x, y, EL_EMPTY);
1405 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1407 else if (cut_mode == NO_CUTTING)
1408 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1411 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1414 else if (IS_DRAWABLE(element))
1415 DrawScreenElement(x, y, element);
1417 DrawScreenElement(x, y, EL_EMPTY);
1420 void DrawLevelField(int x, int y)
1422 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1423 DrawScreenField(SCREENX(x), SCREENY(y));
1424 else if (IS_MOVING(x, y))
1428 Moving2Blocked(x, y, &newx, &newy);
1429 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1430 DrawScreenField(SCREENX(newx), SCREENY(newy));
1432 else if (IS_BLOCKED(x, y))
1436 Blocked2Moving(x, y, &oldx, &oldy);
1437 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1438 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1442 void DrawMiniElement(int x, int y, int element)
1446 graphic = el2edimg(element);
1447 DrawMiniGraphic(x, y, graphic);
1450 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1452 int x = sx + scroll_x, y = sy + scroll_y;
1454 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1455 DrawMiniElement(sx, sy, EL_EMPTY);
1456 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1457 DrawMiniElement(sx, sy, Feld[x][y]);
1459 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1462 void DrawEnvelopeBackground(int envelope_nr, int startx, int starty,
1463 int x, int y, int xsize, int ysize, int font_nr)
1465 int font_width = getFontWidth(font_nr);
1466 int font_height = getFontHeight(font_nr);
1467 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1470 int dst_x = SX + startx + x * font_width;
1471 int dst_y = SY + starty + y * font_height;
1472 int width = graphic_info[graphic].width;
1473 int height = graphic_info[graphic].height;
1474 int inner_width = MAX(width - 2 * font_width, font_width);
1475 int inner_height = MAX(height - 2 * font_height, font_height);
1476 int inner_sx = (width >= 3 * font_width ? font_width : 0);
1477 int inner_sy = (height >= 3 * font_height ? font_height : 0);
1478 boolean draw_masked = graphic_info[graphic].draw_masked;
1480 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1482 if (src_bitmap == NULL || width < font_width || height < font_height)
1484 ClearRectangle(drawto, dst_x, dst_y, font_width, font_height);
1488 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - font_width :
1489 inner_sx + (x - 1) * font_width % inner_width);
1490 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - font_height :
1491 inner_sy + (y - 1) * font_height % inner_height);
1495 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1496 dst_x - src_x, dst_y - src_y);
1497 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1501 BlitBitmap(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1505 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
1507 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1508 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1509 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
1510 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1511 boolean no_delay = (tape.warp_forward);
1512 unsigned long anim_delay = 0;
1513 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
1514 int anim_delay_value = (no_delay ? 0 : frame_delay_value);
1515 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
1516 int font_width = getFontWidth(font_nr);
1517 int font_height = getFontHeight(font_nr);
1518 int max_xsize = level.envelope[envelope_nr].xsize;
1519 int max_ysize = level.envelope[envelope_nr].ysize;
1520 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
1521 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
1522 int xend = max_xsize;
1523 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
1524 int xstep = (xstart < xend ? 1 : 0);
1525 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
1528 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
1530 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
1531 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
1532 int sx = (SXSIZE - xsize * font_width) / 2;
1533 int sy = (SYSIZE - ysize * font_height) / 2;
1536 SetDrawtoField(DRAW_BUFFERED);
1538 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
1540 SetDrawtoField(DRAW_BACKBUFFER);
1542 for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++)
1543 DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
1545 DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
1546 level.envelope[envelope_nr].text, font_nr, max_xsize,
1547 xsize - 2, ysize - 2, mask_mode);
1549 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
1552 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
1556 void ShowEnvelope(int envelope_nr)
1558 int element = EL_ENVELOPE_1 + envelope_nr;
1559 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1560 int sound_opening = element_info[element].sound[ACTION_OPENING];
1561 int sound_closing = element_info[element].sound[ACTION_CLOSING];
1562 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1563 boolean no_delay = (tape.warp_forward);
1564 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
1565 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
1566 int anim_mode = graphic_info[graphic].anim_mode;
1567 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
1568 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
1570 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
1572 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
1574 if (anim_mode == ANIM_DEFAULT)
1575 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
1577 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
1580 Delay(wait_delay_value);
1582 WaitForEventToContinue();
1584 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
1586 if (anim_mode != ANIM_NONE)
1587 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
1589 if (anim_mode == ANIM_DEFAULT)
1590 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
1592 game.envelope_active = FALSE;
1594 SetDrawtoField(DRAW_BUFFERED);
1596 redraw_mask |= REDRAW_FIELD;
1600 void getPreviewGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y,
1605 int width_mult, width_div;
1606 int height_mult, height_div;
1614 int offset_calc_pos = (tilesize < MICRO_TILESIZE || tilesize > TILESIZE ? 3 :
1615 5 - log_2(tilesize));
1616 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1617 int width_mult = offset_calc[offset_calc_pos].width_mult;
1618 int width_div = offset_calc[offset_calc_pos].width_div;
1619 int height_mult = offset_calc[offset_calc_pos].height_mult;
1620 int height_div = offset_calc[offset_calc_pos].height_div;
1621 int mini_startx = src_bitmap->width * width_mult / width_div;
1622 int mini_starty = src_bitmap->height * height_mult / height_div;
1623 int src_x = mini_startx + graphic_info[graphic].src_x * tilesize / TILESIZE;
1624 int src_y = mini_starty + graphic_info[graphic].src_y * tilesize / TILESIZE;
1626 *bitmap = src_bitmap;
1631 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
1635 int graphic = el2preimg(element);
1637 getPreviewGraphicSource(graphic, &src_bitmap, &src_x, &src_y, tilesize);
1638 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
1645 SetDrawBackgroundMask(REDRAW_NONE);
1648 for (x = BX1; x <= BX2; x++)
1649 for (y = BY1; y <= BY2; y++)
1650 DrawScreenField(x, y);
1652 redraw_mask |= REDRAW_FIELD;
1655 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1659 for (x = 0; x < size_x; x++)
1660 for (y = 0; y < size_y; y++)
1661 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1663 redraw_mask |= REDRAW_FIELD;
1666 static void DrawPreviewLevelExt(int from_x, int from_y)
1668 boolean show_level_border = (BorderElement != EL_EMPTY);
1669 int dst_x = preview.x;
1670 int dst_y = preview.y;
1671 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
1672 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
1673 int tile_size = preview.tile_size;
1674 int preview_width = preview.xsize * tile_size;
1675 int preview_height = preview.ysize * tile_size;
1676 int real_preview_xsize = MIN(level_xsize, preview.xsize);
1677 int real_preview_ysize = MIN(level_ysize, preview.ysize);
1680 DrawBackground(dst_x, dst_y, preview_width, preview_height);
1682 dst_x += (preview_width - real_preview_xsize * tile_size) / 2;
1683 dst_y += (preview_height - real_preview_ysize * tile_size) / 2;
1685 for (x = 0; x < real_preview_xsize; x++)
1687 for (y = 0; y < real_preview_ysize; y++)
1689 int lx = from_x + x + (show_level_border ? -1 : 0);
1690 int ly = from_y + y + (show_level_border ? -1 : 0);
1691 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
1692 getBorderElement(lx, ly));
1694 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
1695 element, tile_size);
1699 redraw_mask |= REDRAW_MICROLEVEL;
1702 #define MICROLABEL_EMPTY 0
1703 #define MICROLABEL_LEVEL_NAME 1
1704 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
1705 #define MICROLABEL_LEVEL_AUTHOR 3
1706 #define MICROLABEL_IMPORTED_FROM_HEAD 4
1707 #define MICROLABEL_IMPORTED_FROM 5
1708 #define MICROLABEL_IMPORTED_BY_HEAD 6
1709 #define MICROLABEL_IMPORTED_BY 7
1711 static void DrawPreviewLevelLabelExt(int mode)
1713 char label_text[MAX_OUTPUT_LINESIZE + 1];
1714 int max_len_label_text;
1715 int font_nr = FONT_TEXT_2;
1718 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
1719 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
1720 mode == MICROLABEL_IMPORTED_BY_HEAD)
1721 font_nr = FONT_TEXT_3;
1723 max_len_label_text = SXSIZE / getFontWidth(font_nr);
1725 for (i = 0; i < max_len_label_text; i++)
1726 label_text[i] = ' ';
1727 label_text[max_len_label_text] = '\0';
1729 if (strlen(label_text) > 0)
1731 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1732 int lypos = MICROLABEL2_YPOS;
1734 DrawText(lxpos, lypos, label_text, font_nr);
1738 (mode == MICROLABEL_LEVEL_NAME ? level.name :
1739 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
1740 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1741 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
1742 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
1743 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
1744 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
1745 max_len_label_text);
1746 label_text[max_len_label_text] = '\0';
1748 if (strlen(label_text) > 0)
1750 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1751 int lypos = MICROLABEL2_YPOS;
1753 DrawText(lxpos, lypos, label_text, font_nr);
1756 redraw_mask |= REDRAW_MICROLEVEL;
1759 void DrawPreviewLevel(boolean restart)
1761 static unsigned long scroll_delay = 0;
1762 static unsigned long label_delay = 0;
1763 static int from_x, from_y, scroll_direction;
1764 static int label_state, label_counter;
1765 unsigned long scroll_delay_value = preview.step_delay;
1766 boolean show_level_border = (BorderElement != EL_EMPTY);
1767 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
1768 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
1769 int last_game_status = game_status; /* save current game status */
1771 /* force PREVIEW font on preview level */
1772 game_status = GAME_MODE_PSEUDO_PREVIEW;
1776 from_x = from_y = 0;
1777 scroll_direction = MV_RIGHT;
1781 DrawPreviewLevelExt(from_x, from_y);
1782 DrawPreviewLevelLabelExt(label_state);
1784 /* initialize delay counters */
1785 DelayReached(&scroll_delay, 0);
1786 DelayReached(&label_delay, 0);
1788 if (leveldir_current->name)
1790 char label_text[MAX_OUTPUT_LINESIZE + 1];
1791 int font_nr = FONT_TEXT_1;
1792 int max_len_label_text = SXSIZE / getFontWidth(font_nr);
1795 strncpy(label_text, leveldir_current->name, max_len_label_text);
1796 label_text[max_len_label_text] = '\0';
1798 lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1799 lypos = SY + MICROLABEL1_YPOS;
1801 DrawText(lxpos, lypos, label_text, font_nr);
1804 game_status = last_game_status; /* restore current game status */
1809 /* scroll preview level, if needed */
1810 if ((level_xsize > preview.xsize || level_ysize > preview.ysize) &&
1811 DelayReached(&scroll_delay, scroll_delay_value))
1813 switch (scroll_direction)
1818 from_x -= preview.step_offset;
1819 from_x = (from_x < 0 ? 0 : from_x);
1822 scroll_direction = MV_UP;
1826 if (from_x < level_xsize - preview.xsize)
1828 from_x += preview.step_offset;
1829 from_x = (from_x > level_xsize - preview.xsize ?
1830 level_xsize - preview.xsize : from_x);
1833 scroll_direction = MV_DOWN;
1839 from_y -= preview.step_offset;
1840 from_y = (from_y < 0 ? 0 : from_y);
1843 scroll_direction = MV_RIGHT;
1847 if (from_y < level_ysize - preview.ysize)
1849 from_y += preview.step_offset;
1850 from_y = (from_y > level_ysize - preview.ysize ?
1851 level_ysize - preview.ysize : from_y);
1854 scroll_direction = MV_LEFT;
1861 DrawPreviewLevelExt(from_x, from_y);
1864 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
1865 /* redraw micro level label, if needed */
1866 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
1867 !strEqual(level.author, ANONYMOUS_NAME) &&
1868 !strEqual(level.author, leveldir_current->name) &&
1869 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
1871 int max_label_counter = 23;
1873 if (leveldir_current->imported_from != NULL &&
1874 strlen(leveldir_current->imported_from) > 0)
1875 max_label_counter += 14;
1876 if (leveldir_current->imported_by != NULL &&
1877 strlen(leveldir_current->imported_by) > 0)
1878 max_label_counter += 14;
1880 label_counter = (label_counter + 1) % max_label_counter;
1881 label_state = (label_counter >= 0 && label_counter <= 7 ?
1882 MICROLABEL_LEVEL_NAME :
1883 label_counter >= 9 && label_counter <= 12 ?
1884 MICROLABEL_LEVEL_AUTHOR_HEAD :
1885 label_counter >= 14 && label_counter <= 21 ?
1886 MICROLABEL_LEVEL_AUTHOR :
1887 label_counter >= 23 && label_counter <= 26 ?
1888 MICROLABEL_IMPORTED_FROM_HEAD :
1889 label_counter >= 28 && label_counter <= 35 ?
1890 MICROLABEL_IMPORTED_FROM :
1891 label_counter >= 37 && label_counter <= 40 ?
1892 MICROLABEL_IMPORTED_BY_HEAD :
1893 label_counter >= 42 && label_counter <= 49 ?
1894 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
1896 if (leveldir_current->imported_from == NULL &&
1897 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
1898 label_state == MICROLABEL_IMPORTED_FROM))
1899 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
1900 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
1902 DrawPreviewLevelLabelExt(label_state);
1905 game_status = last_game_status; /* restore current game status */
1908 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
1909 int graphic, int sync_frame, int mask_mode)
1911 int frame = getGraphicAnimationFrame(graphic, sync_frame);
1913 if (mask_mode == USE_MASKING)
1914 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
1916 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
1919 inline void DrawGraphicAnimation(int x, int y, int graphic)
1921 int lx = LEVELX(x), ly = LEVELY(y);
1923 if (!IN_SCR_FIELD(x, y))
1926 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
1927 graphic, GfxFrame[lx][ly], NO_MASKING);
1928 MarkTileDirty(x, y);
1931 void DrawLevelGraphicAnimation(int x, int y, int graphic)
1933 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
1936 void DrawLevelElementAnimation(int x, int y, int element)
1938 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
1940 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
1943 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
1945 int sx = SCREENX(x), sy = SCREENY(y);
1947 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
1950 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
1953 DrawGraphicAnimation(sx, sy, graphic);
1956 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
1957 DrawLevelFieldCrumbledSand(x, y);
1959 if (GFX_CRUMBLED(Feld[x][y]))
1960 DrawLevelFieldCrumbledSand(x, y);
1964 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
1966 int sx = SCREENX(x), sy = SCREENY(y);
1969 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
1972 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
1974 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
1977 DrawGraphicAnimation(sx, sy, graphic);
1979 if (GFX_CRUMBLED(element))
1980 DrawLevelFieldCrumbledSand(x, y);
1983 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
1985 if (player->use_murphy)
1987 /* this works only because currently only one player can be "murphy" ... */
1988 static int last_horizontal_dir = MV_LEFT;
1989 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
1991 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
1992 last_horizontal_dir = move_dir;
1994 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
1996 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
1998 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
2004 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
2007 static boolean equalGraphics(int graphic1, int graphic2)
2009 struct GraphicInfo *g1 = &graphic_info[graphic1];
2010 struct GraphicInfo *g2 = &graphic_info[graphic2];
2012 return (g1->bitmap == g2->bitmap &&
2013 g1->src_x == g2->src_x &&
2014 g1->src_y == g2->src_y &&
2015 g1->anim_frames == g2->anim_frames &&
2016 g1->anim_delay == g2->anim_delay &&
2017 g1->anim_mode == g2->anim_mode);
2020 void DrawAllPlayers()
2024 for (i = 0; i < MAX_PLAYERS; i++)
2025 if (stored_player[i].active)
2026 DrawPlayer(&stored_player[i]);
2029 void DrawPlayerField(int x, int y)
2031 if (!IS_PLAYER(x, y))
2034 DrawPlayer(PLAYERINFO(x, y));
2037 void DrawPlayer(struct PlayerInfo *player)
2039 int jx = player->jx;
2040 int jy = player->jy;
2041 int move_dir = player->MovDir;
2042 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
2043 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
2044 int last_jx = (player->is_moving ? jx - dx : jx);
2045 int last_jy = (player->is_moving ? jy - dy : jy);
2046 int next_jx = jx + dx;
2047 int next_jy = jy + dy;
2048 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
2049 boolean player_is_opaque = FALSE;
2050 int sx = SCREENX(jx), sy = SCREENY(jy);
2051 int sxx = 0, syy = 0;
2052 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
2054 int action = ACTION_DEFAULT;
2055 int last_player_graphic = getPlayerGraphic(player, move_dir);
2056 int last_player_frame = player->Frame;
2059 /* GfxElement[][] is set to the element the player is digging or collecting;
2060 remove also for off-screen player if the player is not moving anymore */
2061 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
2062 GfxElement[jx][jy] = EL_UNDEFINED;
2064 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
2068 if (!IN_LEV_FIELD(jx, jy))
2070 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
2071 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
2072 printf("DrawPlayerField(): This should never happen!\n");
2077 if (element == EL_EXPLOSION)
2080 action = (player->is_pushing ? ACTION_PUSHING :
2081 player->is_digging ? ACTION_DIGGING :
2082 player->is_collecting ? ACTION_COLLECTING :
2083 player->is_moving ? ACTION_MOVING :
2084 player->is_snapping ? ACTION_SNAPPING :
2085 player->is_dropping ? ACTION_DROPPING :
2086 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
2088 if (player->is_waiting)
2089 move_dir = player->dir_waiting;
2091 InitPlayerGfxAnimation(player, action, move_dir);
2093 /* ----------------------------------------------------------------------- */
2094 /* draw things in the field the player is leaving, if needed */
2095 /* ----------------------------------------------------------------------- */
2097 if (player->is_moving)
2099 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
2101 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
2103 if (last_element == EL_DYNAMITE_ACTIVE ||
2104 last_element == EL_EM_DYNAMITE_ACTIVE ||
2105 last_element == EL_SP_DISK_RED_ACTIVE)
2106 DrawDynamite(last_jx, last_jy);
2108 DrawLevelFieldThruMask(last_jx, last_jy);
2110 else if (last_element == EL_DYNAMITE_ACTIVE ||
2111 last_element == EL_EM_DYNAMITE_ACTIVE ||
2112 last_element == EL_SP_DISK_RED_ACTIVE)
2113 DrawDynamite(last_jx, last_jy);
2115 /* !!! this is not enough to prevent flickering of players which are
2116 moving next to each others without a free tile between them -- this
2117 can only be solved by drawing all players layer by layer (first the
2118 background, then the foreground etc.) !!! => TODO */
2119 else if (!IS_PLAYER(last_jx, last_jy))
2120 DrawLevelField(last_jx, last_jy);
2123 DrawLevelField(last_jx, last_jy);
2126 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
2127 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
2130 if (!IN_SCR_FIELD(sx, sy))
2133 if (setup.direct_draw)
2134 SetDrawtoField(DRAW_BUFFERED);
2136 /* ----------------------------------------------------------------------- */
2137 /* draw things behind the player, if needed */
2138 /* ----------------------------------------------------------------------- */
2141 DrawLevelElement(jx, jy, Back[jx][jy]);
2142 else if (IS_ACTIVE_BOMB(element))
2143 DrawLevelElement(jx, jy, EL_EMPTY);
2146 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
2148 int old_element = GfxElement[jx][jy];
2149 int old_graphic = el_act_dir2img(old_element, action, move_dir);
2150 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
2152 if (GFX_CRUMBLED(old_element))
2153 DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
2155 DrawGraphic(sx, sy, old_graphic, frame);
2157 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
2158 player_is_opaque = TRUE;
2162 GfxElement[jx][jy] = EL_UNDEFINED;
2164 /* make sure that pushed elements are drawn with correct frame rate */
2166 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2168 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
2169 GfxFrame[jx][jy] = player->StepFrame;
2171 if (player->is_pushing && player->is_moving)
2172 GfxFrame[jx][jy] = player->StepFrame;
2175 DrawLevelField(jx, jy);
2179 /* ----------------------------------------------------------------------- */
2180 /* draw player himself */
2181 /* ----------------------------------------------------------------------- */
2183 graphic = getPlayerGraphic(player, move_dir);
2185 /* in the case of changed player action or direction, prevent the current
2186 animation frame from being restarted for identical animations */
2187 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
2188 player->Frame = last_player_frame;
2190 frame = getGraphicAnimationFrame(graphic, player->Frame);
2194 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2195 sxx = player->GfxPos;
2197 syy = player->GfxPos;
2200 if (!setup.soft_scrolling && ScreenMovPos)
2203 if (player_is_opaque)
2204 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
2206 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2208 if (SHIELD_ON(player))
2210 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
2211 IMG_SHIELD_NORMAL_ACTIVE);
2212 int frame = getGraphicAnimationFrame(graphic, -1);
2214 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2217 /* ----------------------------------------------------------------------- */
2218 /* draw things the player is pushing, if needed */
2219 /* ----------------------------------------------------------------------- */
2222 printf("::: %d, %d [%d, %d] [%d]\n",
2223 player->is_pushing, player_is_moving, player->GfxAction,
2224 player->is_moving, player_is_moving);
2228 if (player->is_pushing && player->is_moving)
2230 int px = SCREENX(jx), py = SCREENY(jy);
2231 int pxx = (TILEX - ABS(sxx)) * dx;
2232 int pyy = (TILEY - ABS(syy)) * dy;
2233 int gfx_frame = GfxFrame[jx][jy];
2239 if (!IS_MOVING(jx, jy)) /* push movement already finished */
2241 element = Feld[next_jx][next_jy];
2242 gfx_frame = GfxFrame[next_jx][next_jy];
2245 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2248 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
2249 frame = getGraphicAnimationFrame(graphic, sync_frame);
2251 frame = getGraphicAnimationFrame(graphic, player->StepFrame);
2254 /* draw background element under pushed element (like the Sokoban field) */
2255 if (Back[next_jx][next_jy])
2256 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
2258 /* masked drawing is needed for EMC style (double) movement graphics */
2259 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
2263 /* ----------------------------------------------------------------------- */
2264 /* draw things in front of player (active dynamite or dynabombs) */
2265 /* ----------------------------------------------------------------------- */
2267 if (IS_ACTIVE_BOMB(element))
2269 graphic = el2img(element);
2270 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
2272 if (game.emulation == EMU_SUPAPLEX)
2273 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
2275 DrawGraphicThruMask(sx, sy, graphic, frame);
2278 if (player_is_moving && last_element == EL_EXPLOSION)
2280 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
2281 GfxElement[last_jx][last_jy] : EL_EMPTY);
2282 int graphic = el_act2img(element, ACTION_EXPLODING);
2283 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
2284 int phase = ExplodePhase[last_jx][last_jy] - 1;
2285 int frame = getGraphicAnimationFrame(graphic, phase - delay);
2288 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
2291 /* ----------------------------------------------------------------------- */
2292 /* draw elements the player is just walking/passing through/under */
2293 /* ----------------------------------------------------------------------- */
2295 if (player_is_moving)
2297 /* handle the field the player is leaving ... */
2298 if (IS_ACCESSIBLE_INSIDE(last_element))
2299 DrawLevelField(last_jx, last_jy);
2300 else if (IS_ACCESSIBLE_UNDER(last_element))
2301 DrawLevelFieldThruMask(last_jx, last_jy);
2304 /* do not redraw accessible elements if the player is just pushing them */
2305 if (!player_is_moving || !player->is_pushing)
2307 /* ... and the field the player is entering */
2308 if (IS_ACCESSIBLE_INSIDE(element))
2309 DrawLevelField(jx, jy);
2310 else if (IS_ACCESSIBLE_UNDER(element))
2311 DrawLevelFieldThruMask(jx, jy);
2314 if (setup.direct_draw)
2316 int dst_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
2317 int dst_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
2318 int x_size = TILEX * (1 + ABS(jx - last_jx));
2319 int y_size = TILEY * (1 + ABS(jy - last_jy));
2321 BlitBitmap(drawto_field, window,
2322 dst_x, dst_y, x_size, y_size, dst_x, dst_y);
2323 SetDrawtoField(DRAW_DIRECT);
2326 MarkTileDirty(sx, sy);
2329 /* ------------------------------------------------------------------------- */
2331 void WaitForEventToContinue()
2333 boolean still_wait = TRUE;
2335 /* simulate releasing mouse button over last gadget, if still pressed */
2337 HandleGadgets(-1, -1, 0);
2339 button_status = MB_RELEASED;
2355 case EVENT_BUTTONPRESS:
2356 case EVENT_KEYPRESS:
2360 case EVENT_KEYRELEASE:
2361 ClearPlayerAction();
2365 HandleOtherEvents(&event);
2369 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2376 /* don't eat all CPU time */
2381 #define MAX_REQUEST_LINES 13
2382 #define MAX_REQUEST_LINE_FONT1_LEN 7
2383 #define MAX_REQUEST_LINE_FONT2_LEN 10
2385 boolean Request(char *text, unsigned int req_state)
2387 int mx, my, ty, result = -1;
2388 unsigned int old_door_state;
2389 int last_game_status = game_status; /* save current game status */
2390 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
2391 int font_nr = FONT_TEXT_2;
2392 int max_word_len = 0;
2395 for (text_ptr = text; *text_ptr; text_ptr++)
2397 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
2399 if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
2401 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
2402 font_nr = FONT_LEVEL_NUMBER;
2408 if (game_status == GAME_MODE_PLAYING &&
2409 level.game_engine_type == GAME_ENGINE_TYPE_EM)
2410 BlitScreenToBitmap_EM(backbuffer);
2412 /* disable deactivated drawing when quick-loading level tape recording */
2413 if (tape.playing && tape.deactivate_display)
2414 TapeDeactivateDisplayOff(TRUE);
2416 SetMouseCursor(CURSOR_DEFAULT);
2418 #if defined(NETWORK_AVALIABLE)
2419 /* pause network game while waiting for request to answer */
2420 if (options.network &&
2421 game_status == GAME_MODE_PLAYING &&
2422 req_state & REQUEST_WAIT_FOR_INPUT)
2423 SendToServer_PausePlaying();
2426 old_door_state = GetDoorState();
2428 /* simulate releasing mouse button over last gadget, if still pressed */
2430 HandleGadgets(-1, -1, 0);
2434 if (old_door_state & DOOR_OPEN_1)
2436 CloseDoor(DOOR_CLOSE_1);
2438 /* save old door content */
2439 BlitBitmap(bitmap_db_door, bitmap_db_door,
2440 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2441 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
2445 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2448 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2450 /* clear door drawing field */
2451 DrawBackground(DX, DY, DXSIZE, DYSIZE);
2453 /* force DOOR font on preview level */
2454 game_status = GAME_MODE_PSEUDO_DOOR;
2456 /* write text for request */
2457 for (ty = 0; ty < MAX_REQUEST_LINES; ty++)
2459 char text_line[max_request_line_len + 1];
2465 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
2468 if (!tc || tc == ' ')
2479 strncpy(text_line, text, tl);
2482 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
2483 DY + 8 + ty * (getFontHeight(font_nr) + 2),
2484 text_line, font_nr);
2486 text += tl + (tc == ' ' ? 1 : 0);
2489 game_status = last_game_status; /* restore current game status */
2491 if (req_state & REQ_ASK)
2493 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2494 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2496 else if (req_state & REQ_CONFIRM)
2498 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2500 else if (req_state & REQ_PLAYER)
2502 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2503 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2504 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2505 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2508 /* copy request gadgets to door backbuffer */
2509 BlitBitmap(drawto, bitmap_db_door,
2510 DX, DY, DXSIZE, DYSIZE,
2511 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2513 OpenDoor(DOOR_OPEN_1);
2515 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
2517 if (game_status == GAME_MODE_PLAYING)
2519 SetPanelBackground();
2520 SetDrawBackgroundMask(REDRAW_DOOR_1);
2524 SetDrawBackgroundMask(REDRAW_FIELD);
2530 if (game_status != GAME_MODE_MAIN)
2533 button_status = MB_RELEASED;
2535 request_gadget_id = -1;
2537 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2549 case EVENT_BUTTONPRESS:
2550 case EVENT_BUTTONRELEASE:
2551 case EVENT_MOTIONNOTIFY:
2553 if (event.type == EVENT_MOTIONNOTIFY)
2555 if (!PointerInWindow(window))
2556 continue; /* window and pointer are on different screens */
2561 motion_status = TRUE;
2562 mx = ((MotionEvent *) &event)->x;
2563 my = ((MotionEvent *) &event)->y;
2567 motion_status = FALSE;
2568 mx = ((ButtonEvent *) &event)->x;
2569 my = ((ButtonEvent *) &event)->y;
2570 if (event.type == EVENT_BUTTONPRESS)
2571 button_status = ((ButtonEvent *) &event)->button;
2573 button_status = MB_RELEASED;
2576 /* this sets 'request_gadget_id' */
2577 HandleGadgets(mx, my, button_status);
2579 switch(request_gadget_id)
2581 case TOOL_CTRL_ID_YES:
2584 case TOOL_CTRL_ID_NO:
2587 case TOOL_CTRL_ID_CONFIRM:
2588 result = TRUE | FALSE;
2591 case TOOL_CTRL_ID_PLAYER_1:
2594 case TOOL_CTRL_ID_PLAYER_2:
2597 case TOOL_CTRL_ID_PLAYER_3:
2600 case TOOL_CTRL_ID_PLAYER_4:
2611 case EVENT_KEYPRESS:
2612 switch(GetEventKey((KeyEvent *)&event, TRUE))
2625 if (req_state & REQ_PLAYER)
2629 case EVENT_KEYRELEASE:
2630 ClearPlayerAction();
2634 HandleOtherEvents(&event);
2638 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2640 int joy = AnyJoystick();
2642 if (joy & JOY_BUTTON_1)
2644 else if (joy & JOY_BUTTON_2)
2651 if (!PendingEvent()) /* delay only if no pending events */
2654 /* don't eat all CPU time */
2659 if (game_status != GAME_MODE_MAIN)
2664 if (!(req_state & REQ_STAY_OPEN))
2666 CloseDoor(DOOR_CLOSE_1);
2668 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
2669 (req_state & REQ_REOPEN))
2670 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
2675 if (game_status == GAME_MODE_PLAYING)
2677 SetPanelBackground();
2678 SetDrawBackgroundMask(REDRAW_DOOR_1);
2682 SetDrawBackgroundMask(REDRAW_FIELD);
2685 #if defined(NETWORK_AVALIABLE)
2686 /* continue network game after request */
2687 if (options.network &&
2688 game_status == GAME_MODE_PLAYING &&
2689 req_state & REQUEST_WAIT_FOR_INPUT)
2690 SendToServer_ContinuePlaying();
2693 /* restore deactivated drawing when quick-loading level tape recording */
2694 if (tape.playing && tape.deactivate_display)
2695 TapeDeactivateDisplayOn();
2700 unsigned int OpenDoor(unsigned int door_state)
2702 if (door_state & DOOR_COPY_BACK)
2704 if (door_state & DOOR_OPEN_1)
2705 BlitBitmap(bitmap_db_door, bitmap_db_door,
2706 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2707 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2709 if (door_state & DOOR_OPEN_2)
2710 BlitBitmap(bitmap_db_door, bitmap_db_door,
2711 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
2712 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2714 door_state &= ~DOOR_COPY_BACK;
2717 return MoveDoor(door_state);
2720 unsigned int CloseDoor(unsigned int door_state)
2722 unsigned int old_door_state = GetDoorState();
2724 if (!(door_state & DOOR_NO_COPY_BACK))
2726 if (old_door_state & DOOR_OPEN_1)
2727 BlitBitmap(backbuffer, bitmap_db_door,
2728 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2730 if (old_door_state & DOOR_OPEN_2)
2731 BlitBitmap(backbuffer, bitmap_db_door,
2732 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2734 door_state &= ~DOOR_NO_COPY_BACK;
2737 return MoveDoor(door_state);
2740 unsigned int GetDoorState()
2742 return MoveDoor(DOOR_GET_STATE);
2745 unsigned int SetDoorState(unsigned int door_state)
2747 return MoveDoor(door_state | DOOR_SET_STATE);
2750 unsigned int MoveDoor(unsigned int door_state)
2752 static int door1 = DOOR_OPEN_1;
2753 static int door2 = DOOR_CLOSE_2;
2754 unsigned long door_delay = 0;
2755 unsigned long door_delay_value;
2758 if (door_1.width < 0 || door_1.width > DXSIZE)
2759 door_1.width = DXSIZE;
2760 if (door_1.height < 0 || door_1.height > DYSIZE)
2761 door_1.height = DYSIZE;
2762 if (door_2.width < 0 || door_2.width > VXSIZE)
2763 door_2.width = VXSIZE;
2764 if (door_2.height < 0 || door_2.height > VYSIZE)
2765 door_2.height = VYSIZE;
2767 if (door_state == DOOR_GET_STATE)
2768 return (door1 | door2);
2770 if (door_state & DOOR_SET_STATE)
2772 if (door_state & DOOR_ACTION_1)
2773 door1 = door_state & DOOR_ACTION_1;
2774 if (door_state & DOOR_ACTION_2)
2775 door2 = door_state & DOOR_ACTION_2;
2777 return (door1 | door2);
2780 if (!(door_state & DOOR_FORCE_REDRAW))
2782 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2783 door_state &= ~DOOR_OPEN_1;
2784 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2785 door_state &= ~DOOR_CLOSE_1;
2786 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2787 door_state &= ~DOOR_OPEN_2;
2788 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2789 door_state &= ~DOOR_CLOSE_2;
2792 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
2795 if (setup.quick_doors)
2797 stepsize = 20; /* must be choosen to always draw last frame */
2798 door_delay_value = 0;
2801 if (global.autoplay_leveldir)
2803 door_state |= DOOR_NO_DELAY;
2804 door_state &= ~DOOR_CLOSE_ALL;
2807 if (door_state & DOOR_ACTION)
2809 boolean handle_door_1 = (door_state & DOOR_ACTION_1);
2810 boolean handle_door_2 = (door_state & DOOR_ACTION_2);
2811 boolean door_1_done = (!handle_door_1);
2812 boolean door_2_done = (!handle_door_2);
2813 boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
2814 boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
2815 int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
2816 int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
2817 int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
2818 int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
2819 int door_size = (handle_door_1 ? door_size_1 : door_size_2);
2820 int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
2821 int door_skip = max_door_size - door_size;
2822 int end = door_size;
2823 int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
2826 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
2828 /* opening door sound has priority over simultaneously closing door */
2829 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2830 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2831 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2832 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2835 for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
2838 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2839 GC gc = bitmap->stored_clip_gc;
2841 if (door_state & DOOR_ACTION_1)
2843 int a = MIN(x * door_1.step_offset, end);
2844 int p = (door_state & DOOR_OPEN_1 ? end - a : a);
2845 int i = p + door_skip;
2847 if (door_1.anim_mode & ANIM_STATIC_PANEL)
2849 BlitBitmap(bitmap_db_door, drawto,
2850 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
2851 DXSIZE, DYSIZE, DX, DY);
2855 BlitBitmap(bitmap_db_door, drawto,
2856 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
2857 DXSIZE, DYSIZE - p / 2, DX, DY);
2859 ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
2862 if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
2864 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2865 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
2866 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
2867 int dst2_x = DX, dst2_y = DY;
2868 int width = i, height = DYSIZE;
2870 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2871 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2874 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2875 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2878 else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
2880 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2881 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
2882 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
2883 int dst2_x = DX, dst2_y = DY;
2884 int width = DXSIZE, height = i;
2886 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2887 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2890 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2891 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2894 else if (x <= DXSIZE) /* ANIM_DEFAULT */
2896 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
2898 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2899 BlitBitmapMasked(bitmap, drawto,
2900 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2901 DX + DXSIZE - i, DY + j);
2902 BlitBitmapMasked(bitmap, drawto,
2903 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2904 DX + DXSIZE - i, DY + 140 + j);
2905 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
2906 DY - (DOOR_GFX_PAGEY1 + j));
2907 BlitBitmapMasked(bitmap, drawto,
2908 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2910 BlitBitmapMasked(bitmap, drawto,
2911 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
2914 BlitBitmapMasked(bitmap, drawto,
2915 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2917 BlitBitmapMasked(bitmap, drawto,
2918 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2920 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2921 BlitBitmapMasked(bitmap, drawto,
2922 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2923 DX + DXSIZE - i, DY + 77 + j);
2924 BlitBitmapMasked(bitmap, drawto,
2925 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2926 DX + DXSIZE - i, DY + 203 + j);
2929 redraw_mask |= REDRAW_DOOR_1;
2930 door_1_done = (a == end);
2933 if (door_state & DOOR_ACTION_2)
2935 int a = MIN(x * door_2.step_offset, door_size);
2936 int p = (door_state & DOOR_OPEN_2 ? door_size - a : a);
2937 int i = p + door_skip;
2939 if (door_2.anim_mode & ANIM_STATIC_PANEL)
2941 BlitBitmap(bitmap_db_door, drawto,
2942 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
2943 VXSIZE, VYSIZE, VX, VY);
2945 else if (x <= VYSIZE)
2947 BlitBitmap(bitmap_db_door, drawto,
2948 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
2949 VXSIZE, VYSIZE - p / 2, VX, VY);
2951 ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
2954 if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
2956 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
2957 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
2958 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
2959 int dst2_x = VX, dst2_y = VY;
2960 int width = i, height = VYSIZE;
2962 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2963 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2966 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2967 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2970 else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
2972 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
2973 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
2974 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
2975 int dst2_x = VX, dst2_y = VY;
2976 int width = VXSIZE, height = i;
2978 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2979 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2982 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2983 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2986 else if (x <= VXSIZE) /* ANIM_DEFAULT */
2988 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
2990 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2991 BlitBitmapMasked(bitmap, drawto,
2992 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
2993 VX + VXSIZE - i, VY + j);
2994 SetClipOrigin(bitmap, gc,
2995 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2996 BlitBitmapMasked(bitmap, drawto,
2997 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
3000 BlitBitmapMasked(bitmap, drawto,
3001 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3002 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
3003 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3004 BlitBitmapMasked(bitmap, drawto,
3005 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3007 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
3010 redraw_mask |= REDRAW_DOOR_2;
3011 door_2_done = (a == VXSIZE);
3014 if (!(door_state & DOOR_NO_DELAY))
3018 if (game_status == GAME_MODE_MAIN)
3021 WaitUntilDelayReached(&door_delay, door_delay_value);
3026 if (door_state & DOOR_ACTION_1)
3027 door1 = door_state & DOOR_ACTION_1;
3028 if (door_state & DOOR_ACTION_2)
3029 door2 = door_state & DOOR_ACTION_2;
3031 return (door1 | door2);
3034 void DrawSpecialEditorDoor()
3036 /* draw bigger toolbox window */
3037 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
3038 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
3040 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3041 EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
3044 redraw_mask |= REDRAW_ALL;
3047 void UndrawSpecialEditorDoor()
3049 /* draw normal tape recorder window */
3050 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3051 EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
3054 redraw_mask |= REDRAW_ALL;
3058 /* ---------- new tool button stuff ---------------------------------------- */
3060 /* graphic position values for tool buttons */
3061 #define TOOL_BUTTON_YES_XPOS 2
3062 #define TOOL_BUTTON_YES_YPOS 250
3063 #define TOOL_BUTTON_YES_GFX_YPOS 0
3064 #define TOOL_BUTTON_YES_XSIZE 46
3065 #define TOOL_BUTTON_YES_YSIZE 28
3066 #define TOOL_BUTTON_NO_XPOS 52
3067 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
3068 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
3069 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
3070 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
3071 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
3072 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
3073 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
3074 #define TOOL_BUTTON_CONFIRM_XSIZE 96
3075 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
3076 #define TOOL_BUTTON_PLAYER_XSIZE 30
3077 #define TOOL_BUTTON_PLAYER_YSIZE 30
3078 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
3079 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
3080 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
3081 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
3082 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3083 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3084 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3085 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3086 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3087 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3088 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3089 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3090 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3091 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3092 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3093 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3094 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3095 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3096 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3097 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3106 } toolbutton_info[NUM_TOOL_BUTTONS] =
3109 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
3110 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
3111 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
3116 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
3117 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
3118 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
3123 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
3124 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
3125 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
3126 TOOL_CTRL_ID_CONFIRM,
3130 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3131 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
3132 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3133 TOOL_CTRL_ID_PLAYER_1,
3137 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3138 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
3139 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3140 TOOL_CTRL_ID_PLAYER_2,
3144 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3145 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
3146 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3147 TOOL_CTRL_ID_PLAYER_3,
3151 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3152 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
3153 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3154 TOOL_CTRL_ID_PLAYER_4,
3159 void CreateToolButtons()
3163 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3165 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3166 Bitmap *deco_bitmap = None;
3167 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
3168 struct GadgetInfo *gi;
3169 unsigned long event_mask;
3170 int gd_xoffset, gd_yoffset;
3171 int gd_x1, gd_x2, gd_y;
3174 event_mask = GD_EVENT_RELEASED;
3176 gd_xoffset = toolbutton_info[i].xpos;
3177 gd_yoffset = toolbutton_info[i].ypos;
3178 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
3179 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
3180 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
3182 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
3184 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
3186 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
3187 &deco_bitmap, &deco_x, &deco_y);
3188 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
3189 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
3192 gi = CreateGadget(GDI_CUSTOM_ID, id,
3193 GDI_INFO_TEXT, toolbutton_info[i].infotext,
3194 GDI_X, DX + toolbutton_info[i].x,
3195 GDI_Y, DY + toolbutton_info[i].y,
3196 GDI_WIDTH, toolbutton_info[i].width,
3197 GDI_HEIGHT, toolbutton_info[i].height,
3198 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
3199 GDI_STATE, GD_BUTTON_UNPRESSED,
3200 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
3201 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
3202 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
3203 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
3204 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
3205 GDI_DECORATION_SHIFTING, 1, 1,
3206 GDI_DIRECT_DRAW, FALSE,
3207 GDI_EVENT_MASK, event_mask,
3208 GDI_CALLBACK_ACTION, HandleToolButtons,
3212 Error(ERR_EXIT, "cannot create gadget");
3214 tool_gadget[id] = gi;
3218 void FreeToolButtons()
3222 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3223 FreeGadget(tool_gadget[i]);
3226 static void UnmapToolButtons()
3230 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3231 UnmapGadget(tool_gadget[i]);
3234 static void HandleToolButtons(struct GadgetInfo *gi)
3236 request_gadget_id = gi->custom_id;
3239 static struct Mapping_EM_to_RND_object
3242 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
3243 boolean is_backside; /* backside of moving element */
3249 em_object_mapping_list[] =
3252 Xblank, TRUE, FALSE,
3256 Yacid_splash_eB, FALSE, FALSE,
3257 EL_ACID_SPLASH_RIGHT, -1, -1
3260 Yacid_splash_wB, FALSE, FALSE,
3261 EL_ACID_SPLASH_LEFT, -1, -1
3264 #ifdef EM_ENGINE_BAD_ROLL
3266 Xstone_force_e, FALSE, FALSE,
3267 EL_ROCK, -1, MV_BIT_RIGHT
3270 Xstone_force_w, FALSE, FALSE,
3271 EL_ROCK, -1, MV_BIT_LEFT
3274 Xnut_force_e, FALSE, FALSE,
3275 EL_NUT, -1, MV_BIT_RIGHT
3278 Xnut_force_w, FALSE, FALSE,
3279 EL_NUT, -1, MV_BIT_LEFT
3282 Xspring_force_e, FALSE, FALSE,
3283 EL_SPRING, -1, MV_BIT_RIGHT
3286 Xspring_force_w, FALSE, FALSE,
3287 EL_SPRING, -1, MV_BIT_LEFT
3290 Xemerald_force_e, FALSE, FALSE,
3291 EL_EMERALD, -1, MV_BIT_RIGHT
3294 Xemerald_force_w, FALSE, FALSE,
3295 EL_EMERALD, -1, MV_BIT_LEFT
3298 Xdiamond_force_e, FALSE, FALSE,
3299 EL_DIAMOND, -1, MV_BIT_RIGHT
3302 Xdiamond_force_w, FALSE, FALSE,
3303 EL_DIAMOND, -1, MV_BIT_LEFT
3306 Xbomb_force_e, FALSE, FALSE,
3307 EL_BOMB, -1, MV_BIT_RIGHT
3310 Xbomb_force_w, FALSE, FALSE,
3311 EL_BOMB, -1, MV_BIT_LEFT
3313 #endif /* EM_ENGINE_BAD_ROLL */
3316 Xstone, TRUE, FALSE,
3320 Xstone_pause, FALSE, FALSE,
3324 Xstone_fall, FALSE, FALSE,
3328 Ystone_s, FALSE, FALSE,
3329 EL_ROCK, ACTION_FALLING, -1
3332 Ystone_sB, FALSE, TRUE,
3333 EL_ROCK, ACTION_FALLING, -1
3336 Ystone_e, FALSE, FALSE,
3337 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3340 Ystone_eB, FALSE, TRUE,
3341 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3344 Ystone_w, FALSE, FALSE,
3345 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3348 Ystone_wB, FALSE, TRUE,
3349 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3356 Xnut_pause, FALSE, FALSE,
3360 Xnut_fall, FALSE, FALSE,
3364 Ynut_s, FALSE, FALSE,
3365 EL_NUT, ACTION_FALLING, -1
3368 Ynut_sB, FALSE, TRUE,
3369 EL_NUT, ACTION_FALLING, -1
3372 Ynut_e, FALSE, FALSE,
3373 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3376 Ynut_eB, FALSE, TRUE,
3377 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3380 Ynut_w, FALSE, FALSE,
3381 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3384 Ynut_wB, FALSE, TRUE,
3385 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3388 Xbug_n, TRUE, FALSE,
3392 Xbug_e, TRUE, FALSE,
3393 EL_BUG_RIGHT, -1, -1
3396 Xbug_s, TRUE, FALSE,
3400 Xbug_w, TRUE, FALSE,
3404 Xbug_gon, FALSE, FALSE,
3408 Xbug_goe, FALSE, FALSE,
3409 EL_BUG_RIGHT, -1, -1
3412 Xbug_gos, FALSE, FALSE,
3416 Xbug_gow, FALSE, FALSE,
3420 Ybug_n, FALSE, FALSE,
3421 EL_BUG, ACTION_MOVING, MV_BIT_UP
3424 Ybug_nB, FALSE, TRUE,
3425 EL_BUG, ACTION_MOVING, MV_BIT_UP
3428 Ybug_e, FALSE, FALSE,
3429 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3432 Ybug_eB, FALSE, TRUE,
3433 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3436 Ybug_s, FALSE, FALSE,
3437 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3440 Ybug_sB, FALSE, TRUE,
3441 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3444 Ybug_w, FALSE, FALSE,
3445 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3448 Ybug_wB, FALSE, TRUE,
3449 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3452 Ybug_w_n, FALSE, FALSE,
3453 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3456 Ybug_n_e, FALSE, FALSE,
3457 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3460 Ybug_e_s, FALSE, FALSE,
3461 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3464 Ybug_s_w, FALSE, FALSE,
3465 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3468 Ybug_e_n, FALSE, FALSE,
3469 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3472 Ybug_s_e, FALSE, FALSE,
3473 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3476 Ybug_w_s, FALSE, FALSE,
3477 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3480 Ybug_n_w, FALSE, FALSE,
3481 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3484 Ybug_stone, FALSE, FALSE,
3485 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
3488 Ybug_spring, FALSE, FALSE,
3489 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
3492 Xtank_n, TRUE, FALSE,
3493 EL_SPACESHIP_UP, -1, -1
3496 Xtank_e, TRUE, FALSE,
3497 EL_SPACESHIP_RIGHT, -1, -1
3500 Xtank_s, TRUE, FALSE,
3501 EL_SPACESHIP_DOWN, -1, -1
3504 Xtank_w, TRUE, FALSE,
3505 EL_SPACESHIP_LEFT, -1, -1
3508 Xtank_gon, FALSE, FALSE,
3509 EL_SPACESHIP_UP, -1, -1
3512 Xtank_goe, FALSE, FALSE,
3513 EL_SPACESHIP_RIGHT, -1, -1
3516 Xtank_gos, FALSE, FALSE,
3517 EL_SPACESHIP_DOWN, -1, -1
3520 Xtank_gow, FALSE, FALSE,
3521 EL_SPACESHIP_LEFT, -1, -1
3524 Ytank_n, FALSE, FALSE,
3525 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3528 Ytank_nB, FALSE, TRUE,
3529 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3532 Ytank_e, FALSE, FALSE,
3533 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3536 Ytank_eB, FALSE, TRUE,
3537 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3540 Ytank_s, FALSE, FALSE,
3541 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3544 Ytank_sB, FALSE, TRUE,
3545 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3548 Ytank_w, FALSE, FALSE,
3549 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3552 Ytank_wB, FALSE, TRUE,
3553 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3556 Ytank_w_n, FALSE, FALSE,
3557 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3560 Ytank_n_e, FALSE, FALSE,
3561 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3564 Ytank_e_s, FALSE, FALSE,
3565 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3568 Ytank_s_w, FALSE, FALSE,
3569 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3572 Ytank_e_n, FALSE, FALSE,
3573 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3576 Ytank_s_e, FALSE, FALSE,
3577 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3580 Ytank_w_s, FALSE, FALSE,
3581 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3584 Ytank_n_w, FALSE, FALSE,
3585 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3588 Ytank_stone, FALSE, FALSE,
3589 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
3592 Ytank_spring, FALSE, FALSE,
3593 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
3596 Xandroid, TRUE, FALSE,
3597 EL_EMC_ANDROID, ACTION_ACTIVE, -1
3600 Xandroid_1_n, FALSE, FALSE,
3601 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3604 Xandroid_2_n, FALSE, FALSE,
3605 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3608 Xandroid_1_e, FALSE, FALSE,
3609 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3612 Xandroid_2_e, FALSE, FALSE,
3613 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3616 Xandroid_1_w, FALSE, FALSE,
3617 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3620 Xandroid_2_w, FALSE, FALSE,
3621 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3624 Xandroid_1_s, FALSE, FALSE,
3625 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3628 Xandroid_2_s, FALSE, FALSE,
3629 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3632 Yandroid_n, FALSE, FALSE,
3633 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3636 Yandroid_nB, FALSE, TRUE,
3637 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3640 Yandroid_ne, FALSE, FALSE,
3641 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
3644 Yandroid_neB, FALSE, TRUE,
3645 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
3648 Yandroid_e, FALSE, FALSE,
3649 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
3652 Yandroid_eB, FALSE, TRUE,
3653 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
3656 Yandroid_se, FALSE, FALSE,
3657 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
3660 Yandroid_seB, FALSE, TRUE,
3661 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
3664 Yandroid_s, FALSE, FALSE,
3665 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
3668 Yandroid_sB, FALSE, TRUE,
3669 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
3672 Yandroid_sw, FALSE, FALSE,
3673 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
3676 Yandroid_swB, FALSE, TRUE,
3677 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
3680 Yandroid_w, FALSE, FALSE,
3681 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
3684 Yandroid_wB, FALSE, TRUE,
3685 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
3688 Yandroid_nw, FALSE, FALSE,
3689 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
3692 Yandroid_nwB, FALSE, TRUE,
3693 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
3696 Xspring, TRUE, FALSE,
3700 Xspring_pause, FALSE, FALSE,
3704 Xspring_e, FALSE, FALSE,
3708 Xspring_w, FALSE, FALSE,
3712 Xspring_fall, FALSE, FALSE,
3716 Yspring_s, FALSE, FALSE,
3717 EL_SPRING, ACTION_FALLING, -1
3720 Yspring_sB, FALSE, TRUE,
3721 EL_SPRING, ACTION_FALLING, -1
3724 Yspring_e, FALSE, FALSE,
3725 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
3728 Yspring_eB, FALSE, TRUE,
3729 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
3732 Yspring_w, FALSE, FALSE,
3733 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
3736 Yspring_wB, FALSE, TRUE,
3737 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
3740 Yspring_kill_e, FALSE, FALSE,
3741 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
3744 Yspring_kill_eB, FALSE, TRUE,
3745 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
3748 Yspring_kill_w, FALSE, FALSE,
3749 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
3752 Yspring_kill_wB, FALSE, TRUE,
3753 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
3756 Xeater_n, TRUE, FALSE,
3757 EL_YAMYAM_UP, -1, -1
3760 Xeater_e, TRUE, FALSE,
3761 EL_YAMYAM_RIGHT, -1, -1
3764 Xeater_w, TRUE, FALSE,
3765 EL_YAMYAM_LEFT, -1, -1
3768 Xeater_s, TRUE, FALSE,
3769 EL_YAMYAM_DOWN, -1, -1
3772 Yeater_n, FALSE, FALSE,
3773 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
3776 Yeater_nB, FALSE, TRUE,
3777 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
3780 Yeater_e, FALSE, FALSE,
3781 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
3784 Yeater_eB, FALSE, TRUE,
3785 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
3788 Yeater_s, FALSE, FALSE,
3789 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
3792 Yeater_sB, FALSE, TRUE,
3793 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
3796 Yeater_w, FALSE, FALSE,
3797 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
3800 Yeater_wB, FALSE, TRUE,
3801 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
3804 Yeater_stone, FALSE, FALSE,
3805 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
3808 Yeater_spring, FALSE, FALSE,
3809 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
3812 Xalien, TRUE, FALSE,
3816 Xalien_pause, FALSE, FALSE,
3820 Yalien_n, FALSE, FALSE,
3821 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
3824 Yalien_nB, FALSE, TRUE,
3825 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
3828 Yalien_e, FALSE, FALSE,
3829 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
3832 Yalien_eB, FALSE, TRUE,
3833 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
3836 Yalien_s, FALSE, FALSE,
3837 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
3840 Yalien_sB, FALSE, TRUE,
3841 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
3844 Yalien_w, FALSE, FALSE,
3845 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
3848 Yalien_wB, FALSE, TRUE,
3849 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
3852 Yalien_stone, FALSE, FALSE,
3853 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
3856 Yalien_spring, FALSE, FALSE,
3857 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
3860 Xemerald, TRUE, FALSE,
3864 Xemerald_pause, FALSE, FALSE,
3868 Xemerald_fall, FALSE, FALSE,
3872 Xemerald_shine, FALSE, FALSE,
3873 EL_EMERALD, ACTION_TWINKLING, -1
3876 Yemerald_s, FALSE, FALSE,
3877 EL_EMERALD, ACTION_FALLING, -1
3880 Yemerald_sB, FALSE, TRUE,
3881 EL_EMERALD, ACTION_FALLING, -1
3884 Yemerald_e, FALSE, FALSE,
3885 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
3888 Yemerald_eB, FALSE, TRUE,
3889 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
3892 Yemerald_w, FALSE, FALSE,
3893 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
3896 Yemerald_wB, FALSE, TRUE,
3897 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
3900 Yemerald_eat, FALSE, FALSE,
3901 EL_EMERALD, ACTION_COLLECTING, -1
3904 Yemerald_stone, FALSE, FALSE,
3905 EL_NUT, ACTION_BREAKING, -1
3908 Xdiamond, TRUE, FALSE,
3912 Xdiamond_pause, FALSE, FALSE,
3916 Xdiamond_fall, FALSE, FALSE,
3920 Xdiamond_shine, FALSE, FALSE,
3921 EL_DIAMOND, ACTION_TWINKLING, -1
3924 Ydiamond_s, FALSE, FALSE,
3925 EL_DIAMOND, ACTION_FALLING, -1
3928 Ydiamond_sB, FALSE, TRUE,
3929 EL_DIAMOND, ACTION_FALLING, -1
3932 Ydiamond_e, FALSE, FALSE,
3933 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
3936 Ydiamond_eB, FALSE, TRUE,
3937 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
3940 Ydiamond_w, FALSE, FALSE,
3941 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
3944 Ydiamond_wB, FALSE, TRUE,
3945 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
3948 Ydiamond_eat, FALSE, FALSE,
3949 EL_DIAMOND, ACTION_COLLECTING, -1
3952 Ydiamond_stone, FALSE, FALSE,
3953 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
3956 Xdrip_fall, TRUE, FALSE,
3957 EL_AMOEBA_DROP, -1, -1
3960 Xdrip_stretch, FALSE, FALSE,
3961 EL_AMOEBA_DROP, ACTION_FALLING, -1
3964 Xdrip_stretchB, FALSE, TRUE,
3965 EL_AMOEBA_DROP, ACTION_FALLING, -1
3968 Xdrip_eat, FALSE, FALSE,
3969 EL_AMOEBA_DROP, ACTION_GROWING, -1
3972 Ydrip_s1, FALSE, FALSE,
3973 EL_AMOEBA_DROP, ACTION_FALLING, -1
3976 Ydrip_s1B, FALSE, TRUE,
3977 EL_AMOEBA_DROP, ACTION_FALLING, -1
3980 Ydrip_s2, FALSE, FALSE,
3981 EL_AMOEBA_DROP, ACTION_FALLING, -1
3984 Ydrip_s2B, FALSE, TRUE,
3985 EL_AMOEBA_DROP, ACTION_FALLING, -1
3992 Xbomb_pause, FALSE, FALSE,
3996 Xbomb_fall, FALSE, FALSE,
4000 Ybomb_s, FALSE, FALSE,
4001 EL_BOMB, ACTION_FALLING, -1
4004 Ybomb_sB, FALSE, TRUE,
4005 EL_BOMB, ACTION_FALLING, -1
4008 Ybomb_e, FALSE, FALSE,
4009 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
4012 Ybomb_eB, FALSE, TRUE,
4013 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
4016 Ybomb_w, FALSE, FALSE,
4017 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
4020 Ybomb_wB, FALSE, TRUE,
4021 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
4024 Ybomb_eat, FALSE, FALSE,
4025 EL_BOMB, ACTION_ACTIVATING, -1
4028 Xballoon, TRUE, FALSE,
4032 Yballoon_n, FALSE, FALSE,
4033 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
4036 Yballoon_nB, FALSE, TRUE,
4037 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
4040 Yballoon_e, FALSE, FALSE,
4041 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
4044 Yballoon_eB, FALSE, TRUE,
4045 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
4048 Yballoon_s, FALSE, FALSE,
4049 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
4052 Yballoon_sB, FALSE, TRUE,
4053 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
4056 Yballoon_w, FALSE, FALSE,
4057 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
4060 Yballoon_wB, FALSE, TRUE,
4061 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
4064 Xgrass, TRUE, FALSE,
4065 EL_EMC_GRASS, -1, -1
4068 Ygrass_nB, FALSE, FALSE,
4069 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
4072 Ygrass_eB, FALSE, FALSE,
4073 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
4076 Ygrass_sB, FALSE, FALSE,
4077 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
4080 Ygrass_wB, FALSE, FALSE,
4081 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
4088 Ydirt_nB, FALSE, FALSE,
4089 EL_SAND, ACTION_DIGGING, MV_BIT_UP
4092 Ydirt_eB, FALSE, FALSE,
4093 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
4096 Ydirt_sB, FALSE, FALSE,
4097 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
4100 Ydirt_wB, FALSE, FALSE,
4101 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
4104 Xacid_ne, TRUE, FALSE,
4105 EL_ACID_POOL_TOPRIGHT, -1, -1
4108 Xacid_se, TRUE, FALSE,
4109 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
4112 Xacid_s, TRUE, FALSE,
4113 EL_ACID_POOL_BOTTOM, -1, -1
4116 Xacid_sw, TRUE, FALSE,
4117 EL_ACID_POOL_BOTTOMLEFT, -1, -1
4120 Xacid_nw, TRUE, FALSE,
4121 EL_ACID_POOL_TOPLEFT, -1, -1
4124 Xacid_1, TRUE, FALSE,
4128 Xacid_2, FALSE, FALSE,
4132 Xacid_3, FALSE, FALSE,
4136 Xacid_4, FALSE, FALSE,
4140 Xacid_5, FALSE, FALSE,
4144 Xacid_6, FALSE, FALSE,
4148 Xacid_7, FALSE, FALSE,
4152 Xacid_8, FALSE, FALSE,
4156 Xball_1, TRUE, FALSE,
4157 EL_EMC_MAGIC_BALL, -1, -1
4160 Xball_1B, FALSE, FALSE,
4161 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4164 Xball_2, FALSE, FALSE,
4165 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4168 Xball_2B, FALSE, FALSE,
4169 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4172 Yball_eat, FALSE, FALSE,
4173 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
4176 Ykey_1_eat, FALSE, FALSE,
4177 EL_EM_KEY_1, ACTION_COLLECTING, -1
4180 Ykey_2_eat, FALSE, FALSE,
4181 EL_EM_KEY_2, ACTION_COLLECTING, -1
4184 Ykey_3_eat, FALSE, FALSE,
4185 EL_EM_KEY_3, ACTION_COLLECTING, -1
4188 Ykey_4_eat, FALSE, FALSE,
4189 EL_EM_KEY_4, ACTION_COLLECTING, -1
4192 Ykey_5_eat, FALSE, FALSE,
4193 EL_EMC_KEY_5, ACTION_COLLECTING, -1
4196 Ykey_6_eat, FALSE, FALSE,
4197 EL_EMC_KEY_6, ACTION_COLLECTING, -1
4200 Ykey_7_eat, FALSE, FALSE,
4201 EL_EMC_KEY_7, ACTION_COLLECTING, -1
4204 Ykey_8_eat, FALSE, FALSE,
4205 EL_EMC_KEY_8, ACTION_COLLECTING, -1
4208 Ylenses_eat, FALSE, FALSE,
4209 EL_EMC_LENSES, ACTION_COLLECTING, -1
4212 Ymagnify_eat, FALSE, FALSE,
4213 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
4216 Ygrass_eat, FALSE, FALSE,
4217 EL_EMC_GRASS, ACTION_SNAPPING, -1
4220 Ydirt_eat, FALSE, FALSE,
4221 EL_SAND, ACTION_SNAPPING, -1
4224 Xgrow_ns, TRUE, FALSE,
4225 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
4228 Ygrow_ns_eat, FALSE, FALSE,
4229 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
4232 Xgrow_ew, TRUE, FALSE,
4233 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
4236 Ygrow_ew_eat, FALSE, FALSE,
4237 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
4240 Xwonderwall, TRUE, FALSE,
4241 EL_MAGIC_WALL, -1, -1
4244 XwonderwallB, FALSE, FALSE,
4245 EL_MAGIC_WALL, ACTION_ACTIVE, -1
4248 Xamoeba_1, TRUE, FALSE,
4249 EL_AMOEBA_DRY, ACTION_OTHER, -1
4252 Xamoeba_2, FALSE, FALSE,
4253 EL_AMOEBA_DRY, ACTION_OTHER, -1
4256 Xamoeba_3, FALSE, FALSE,
4257 EL_AMOEBA_DRY, ACTION_OTHER, -1
4260 Xamoeba_4, FALSE, FALSE,
4261 EL_AMOEBA_DRY, ACTION_OTHER, -1
4264 Xamoeba_5, TRUE, FALSE,
4265 EL_AMOEBA_WET, ACTION_OTHER, -1
4268 Xamoeba_6, FALSE, FALSE,
4269 EL_AMOEBA_WET, ACTION_OTHER, -1
4272 Xamoeba_7, FALSE, FALSE,
4273 EL_AMOEBA_WET, ACTION_OTHER, -1
4276 Xamoeba_8, FALSE, FALSE,
4277 EL_AMOEBA_WET, ACTION_OTHER, -1
4280 Xdoor_1, TRUE, FALSE,
4281 EL_EM_GATE_1, -1, -1
4284 Xdoor_2, TRUE, FALSE,
4285 EL_EM_GATE_2, -1, -1
4288 Xdoor_3, TRUE, FALSE,
4289 EL_EM_GATE_3, -1, -1
4292 Xdoor_4, TRUE, FALSE,
4293 EL_EM_GATE_4, -1, -1
4296 Xdoor_5, TRUE, FALSE,
4297 EL_EMC_GATE_5, -1, -1
4300 Xdoor_6, TRUE, FALSE,
4301 EL_EMC_GATE_6, -1, -1
4304 Xdoor_7, TRUE, FALSE,
4305 EL_EMC_GATE_7, -1, -1
4308 Xdoor_8, TRUE, FALSE,
4309 EL_EMC_GATE_8, -1, -1
4312 Xkey_1, TRUE, FALSE,
4316 Xkey_2, TRUE, FALSE,
4320 Xkey_3, TRUE, FALSE,
4324 Xkey_4, TRUE, FALSE,
4328 Xkey_5, TRUE, FALSE,
4329 EL_EMC_KEY_5, -1, -1
4332 Xkey_6, TRUE, FALSE,
4333 EL_EMC_KEY_6, -1, -1
4336 Xkey_7, TRUE, FALSE,
4337 EL_EMC_KEY_7, -1, -1
4340 Xkey_8, TRUE, FALSE,
4341 EL_EMC_KEY_8, -1, -1
4344 Xwind_n, TRUE, FALSE,
4345 EL_BALLOON_SWITCH_UP, -1, -1
4348 Xwind_e, TRUE, FALSE,
4349 EL_BALLOON_SWITCH_RIGHT, -1, -1
4352 Xwind_s, TRUE, FALSE,
4353 EL_BALLOON_SWITCH_DOWN, -1, -1
4356 Xwind_w, TRUE, FALSE,
4357 EL_BALLOON_SWITCH_LEFT, -1, -1
4360 Xwind_nesw, TRUE, FALSE,
4361 EL_BALLOON_SWITCH_ANY, -1, -1
4364 Xwind_stop, TRUE, FALSE,
4365 EL_BALLOON_SWITCH_NONE, -1, -1
4369 EL_EXIT_CLOSED, -1, -1
4372 Xexit_1, TRUE, FALSE,
4373 EL_EXIT_OPEN, -1, -1
4376 Xexit_2, FALSE, FALSE,
4377 EL_EXIT_OPEN, -1, -1
4380 Xexit_3, FALSE, FALSE,
4381 EL_EXIT_OPEN, -1, -1
4384 Xdynamite, TRUE, FALSE,
4385 EL_EM_DYNAMITE, -1, -1
4388 Ydynamite_eat, FALSE, FALSE,
4389 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
4392 Xdynamite_1, TRUE, FALSE,
4393 EL_EM_DYNAMITE_ACTIVE, -1, -1
4396 Xdynamite_2, FALSE, FALSE,
4397 EL_EM_DYNAMITE_ACTIVE, -1, -1
4400 Xdynamite_3, FALSE, FALSE,
4401 EL_EM_DYNAMITE_ACTIVE, -1, -1
4404 Xdynamite_4, FALSE, FALSE,
4405 EL_EM_DYNAMITE_ACTIVE, -1, -1
4408 Xbumper, TRUE, FALSE,
4409 EL_EMC_SPRING_BUMPER, -1, -1
4412 XbumperB, FALSE, FALSE,
4413 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
4416 Xwheel, TRUE, FALSE,
4417 EL_ROBOT_WHEEL, -1, -1
4420 XwheelB, FALSE, FALSE,
4421 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
4424 Xswitch, TRUE, FALSE,
4425 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
4428 XswitchB, FALSE, FALSE,
4429 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
4433 EL_QUICKSAND_EMPTY, -1, -1
4436 Xsand_stone, TRUE, FALSE,
4437 EL_QUICKSAND_FULL, -1, -1
4440 Xsand_stonein_1, FALSE, TRUE,
4441 EL_ROCK, ACTION_FILLING, -1
4444 Xsand_stonein_2, FALSE, TRUE,
4445 EL_ROCK, ACTION_FILLING, -1
4448 Xsand_stonein_3, FALSE, TRUE,
4449 EL_ROCK, ACTION_FILLING, -1
4452 Xsand_stonein_4, FALSE, TRUE,
4453 EL_ROCK, ACTION_FILLING, -1
4456 Xsand_stonesand_1, FALSE, FALSE,
4457 EL_QUICKSAND_FULL, -1, -1
4460 Xsand_stonesand_2, FALSE, FALSE,
4461 EL_QUICKSAND_FULL, -1, -1
4464 Xsand_stonesand_3, FALSE, FALSE,
4465 EL_QUICKSAND_FULL, -1, -1
4468 Xsand_stonesand_4, FALSE, FALSE,
4469 EL_QUICKSAND_FULL, -1, -1
4472 Xsand_stoneout_1, FALSE, FALSE,
4473 EL_ROCK, ACTION_EMPTYING, -1
4476 Xsand_stoneout_2, FALSE, FALSE,
4477 EL_ROCK, ACTION_EMPTYING, -1
4480 Xsand_sandstone_1, FALSE, FALSE,
4481 EL_QUICKSAND_FULL, -1, -1
4484 Xsand_sandstone_2, FALSE, FALSE,
4485 EL_QUICKSAND_FULL, -1, -1
4488 Xsand_sandstone_3, FALSE, FALSE,
4489 EL_QUICKSAND_FULL, -1, -1
4492 Xsand_sandstone_4, FALSE, FALSE,
4493 EL_QUICKSAND_FULL, -1, -1
4496 Xplant, TRUE, FALSE,
4497 EL_EMC_PLANT, -1, -1
4500 Yplant, FALSE, FALSE,
4501 EL_EMC_PLANT, -1, -1
4504 Xlenses, TRUE, FALSE,
4505 EL_EMC_LENSES, -1, -1
4508 Xmagnify, TRUE, FALSE,
4509 EL_EMC_MAGNIFIER, -1, -1
4512 Xdripper, TRUE, FALSE,
4513 EL_EMC_DRIPPER, -1, -1
4516 XdripperB, FALSE, FALSE,
4517 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
4520 Xfake_blank, TRUE, FALSE,
4521 EL_INVISIBLE_WALL, -1, -1
4524 Xfake_blankB, FALSE, FALSE,
4525 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
4528 Xfake_grass, TRUE, FALSE,
4529 EL_EMC_FAKE_GRASS, -1, -1
4532 Xfake_grassB, FALSE, FALSE,
4533 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
4536 Xfake_door_1, TRUE, FALSE,
4537 EL_EM_GATE_1_GRAY, -1, -1
4540 Xfake_door_2, TRUE, FALSE,
4541 EL_EM_GATE_2_GRAY, -1, -1
4544 Xfake_door_3, TRUE, FALSE,
4545 EL_EM_GATE_3_GRAY, -1, -1
4548 Xfake_door_4, TRUE, FALSE,
4549 EL_EM_GATE_4_GRAY, -1, -1
4552 Xfake_door_5, TRUE, FALSE,
4553 EL_EMC_GATE_5_GRAY, -1, -1
4556 Xfake_door_6, TRUE, FALSE,
4557 EL_EMC_GATE_6_GRAY, -1, -1
4560 Xfake_door_7, TRUE, FALSE,
4561 EL_EMC_GATE_7_GRAY, -1, -1
4564 Xfake_door_8, TRUE, FALSE,
4565 EL_EMC_GATE_8_GRAY, -1, -1
4568 Xfake_acid_1, TRUE, FALSE,
4569 EL_EMC_FAKE_ACID, -1, -1
4572 Xfake_acid_2, FALSE, FALSE,
4573 EL_EMC_FAKE_ACID, -1, -1
4576 Xfake_acid_3, FALSE, FALSE,
4577 EL_EMC_FAKE_ACID, -1, -1
4580 Xfake_acid_4, FALSE, FALSE,
4581 EL_EMC_FAKE_ACID, -1, -1
4584 Xfake_acid_5, FALSE, FALSE,
4585 EL_EMC_FAKE_ACID, -1, -1
4588 Xfake_acid_6, FALSE, FALSE,
4589 EL_EMC_FAKE_ACID, -1, -1
4592 Xfake_acid_7, FALSE, FALSE,
4593 EL_EMC_FAKE_ACID, -1, -1
4596 Xfake_acid_8, FALSE, FALSE,
4597 EL_EMC_FAKE_ACID, -1, -1
4600 Xsteel_1, TRUE, FALSE,
4601 EL_STEELWALL, -1, -1
4604 Xsteel_2, TRUE, FALSE,
4605 EL_EMC_STEELWALL_2, -1, -1
4608 Xsteel_3, TRUE, FALSE,
4609 EL_EMC_STEELWALL_3, -1, -1
4612 Xsteel_4, TRUE, FALSE,
4613 EL_EMC_STEELWALL_4, -1, -1
4616 Xwall_1, TRUE, FALSE,
4620 Xwall_2, TRUE, FALSE,
4621 EL_EMC_WALL_14, -1, -1
4624 Xwall_3, TRUE, FALSE,
4625 EL_EMC_WALL_15, -1, -1
4628 Xwall_4, TRUE, FALSE,
4629 EL_EMC_WALL_16, -1, -1
4632 Xround_wall_1, TRUE, FALSE,
4633 EL_WALL_SLIPPERY, -1, -1
4636 Xround_wall_2, TRUE, FALSE,
4637 EL_EMC_WALL_SLIPPERY_2, -1, -1
4640 Xround_wall_3, TRUE, FALSE,
4641 EL_EMC_WALL_SLIPPERY_3, -1, -1
4644 Xround_wall_4, TRUE, FALSE,
4645 EL_EMC_WALL_SLIPPERY_4, -1, -1
4648 Xdecor_1, TRUE, FALSE,
4649 EL_EMC_WALL_8, -1, -1
4652 Xdecor_2, TRUE, FALSE,
4653 EL_EMC_WALL_6, -1, -1
4656 Xdecor_3, TRUE, FALSE,
4657 EL_EMC_WALL_4, -1, -1
4660 Xdecor_4, TRUE, FALSE,
4661 EL_EMC_WALL_7, -1, -1
4664 Xdecor_5, TRUE, FALSE,
4665 EL_EMC_WALL_5, -1, -1
4668 Xdecor_6, TRUE, FALSE,
4669 EL_EMC_WALL_9, -1, -1
4672 Xdecor_7, TRUE, FALSE,
4673 EL_EMC_WALL_10, -1, -1
4676 Xdecor_8, TRUE, FALSE,
4677 EL_EMC_WALL_1, -1, -1
4680 Xdecor_9, TRUE, FALSE,
4681 EL_EMC_WALL_2, -1, -1
4684 Xdecor_10, TRUE, FALSE,
4685 EL_EMC_WALL_3, -1, -1
4688 Xdecor_11, TRUE, FALSE,
4689 EL_EMC_WALL_11, -1, -1
4692 Xdecor_12, TRUE, FALSE,
4693 EL_EMC_WALL_12, -1, -1
4696 Xalpha_0, TRUE, FALSE,
4697 EL_CHAR('0'), -1, -1
4700 Xalpha_1, TRUE, FALSE,
4701 EL_CHAR('1'), -1, -1
4704 Xalpha_2, TRUE, FALSE,
4705 EL_CHAR('2'), -1, -1
4708 Xalpha_3, TRUE, FALSE,
4709 EL_CHAR('3'), -1, -1
4712 Xalpha_4, TRUE, FALSE,
4713 EL_CHAR('4'), -1, -1
4716 Xalpha_5, TRUE, FALSE,
4717 EL_CHAR('5'), -1, -1
4720 Xalpha_6, TRUE, FALSE,
4721 EL_CHAR('6'), -1, -1
4724 Xalpha_7, TRUE, FALSE,
4725 EL_CHAR('7'), -1, -1
4728 Xalpha_8, TRUE, FALSE,
4729 EL_CHAR('8'), -1, -1
4732 Xalpha_9, TRUE, FALSE,
4733 EL_CHAR('9'), -1, -1
4736 Xalpha_excla, TRUE, FALSE,
4737 EL_CHAR('!'), -1, -1
4740 Xalpha_quote, TRUE, FALSE,
4741 EL_CHAR('"'), -1, -1
4744 Xalpha_comma, TRUE, FALSE,
4745 EL_CHAR(','), -1, -1
4748 Xalpha_minus, TRUE, FALSE,
4749 EL_CHAR('-'), -1, -1
4752 Xalpha_perio, TRUE, FALSE,
4753 EL_CHAR('.'), -1, -1
4756 Xalpha_colon, TRUE, FALSE,
4757 EL_CHAR(':'), -1, -1
4760 Xalpha_quest, TRUE, FALSE,
4761 EL_CHAR('?'), -1, -1
4764 Xalpha_a, TRUE, FALSE,
4765 EL_CHAR('A'), -1, -1
4768 Xalpha_b, TRUE, FALSE,
4769 EL_CHAR('B'), -1, -1
4772 Xalpha_c, TRUE, FALSE,
4773 EL_CHAR('C'), -1, -1
4776 Xalpha_d, TRUE, FALSE,
4777 EL_CHAR('D'), -1, -1
4780 Xalpha_e, TRUE, FALSE,
4781 EL_CHAR('E'), -1, -1
4784 Xalpha_f, TRUE, FALSE,
4785 EL_CHAR('F'), -1, -1
4788 Xalpha_g, TRUE, FALSE,
4789 EL_CHAR('G'), -1, -1
4792 Xalpha_h, TRUE, FALSE,
4793 EL_CHAR('H'), -1, -1
4796 Xalpha_i, TRUE, FALSE,
4797 EL_CHAR('I'), -1, -1
4800 Xalpha_j, TRUE, FALSE,
4801 EL_CHAR('J'), -1, -1
4804 Xalpha_k, TRUE, FALSE,
4805 EL_CHAR('K'), -1, -1
4808 Xalpha_l, TRUE, FALSE,
4809 EL_CHAR('L'), -1, -1
4812 Xalpha_m, TRUE, FALSE,
4813 EL_CHAR('M'), -1, -1
4816 Xalpha_n, TRUE, FALSE,
4817 EL_CHAR('N'), -1, -1
4820 Xalpha_o, TRUE, FALSE,
4821 EL_CHAR('O'), -1, -1
4824 Xalpha_p, TRUE, FALSE,
4825 EL_CHAR('P'), -1, -1
4828 Xalpha_q, TRUE, FALSE,
4829 EL_CHAR('Q'), -1, -1
4832 Xalpha_r, TRUE, FALSE,
4833 EL_CHAR('R'), -1, -1
4836 Xalpha_s, TRUE, FALSE,
4837 EL_CHAR('S'), -1, -1
4840 Xalpha_t, TRUE, FALSE,
4841 EL_CHAR('T'), -1, -1
4844 Xalpha_u, TRUE, FALSE,
4845 EL_CHAR('U'), -1, -1
4848 Xalpha_v, TRUE, FALSE,
4849 EL_CHAR('V'), -1, -1
4852 Xalpha_w, TRUE, FALSE,
4853 EL_CHAR('W'), -1, -1
4856 Xalpha_x, TRUE, FALSE,
4857 EL_CHAR('X'), -1, -1
4860 Xalpha_y, TRUE, FALSE,
4861 EL_CHAR('Y'), -1, -1
4864 Xalpha_z, TRUE, FALSE,
4865 EL_CHAR('Z'), -1, -1
4868 Xalpha_arrow_e, TRUE, FALSE,
4869 EL_CHAR('>'), -1, -1
4872 Xalpha_arrow_w, TRUE, FALSE,
4873 EL_CHAR('<'), -1, -1
4876 Xalpha_copyr, TRUE, FALSE,
4877 EL_CHAR('©'), -1, -1
4881 Xboom_bug, FALSE, FALSE,
4882 EL_BUG, ACTION_EXPLODING, -1
4885 Xboom_bomb, FALSE, FALSE,
4886 EL_BOMB, ACTION_EXPLODING, -1
4889 Xboom_android, FALSE, FALSE,
4890 EL_EMC_ANDROID, ACTION_OTHER, -1
4893 Xboom_1, FALSE, FALSE,
4894 EL_DEFAULT, ACTION_EXPLODING, -1
4897 Xboom_2, FALSE, FALSE,
4898 EL_DEFAULT, ACTION_EXPLODING, -1
4901 Znormal, FALSE, FALSE,
4905 Zdynamite, FALSE, FALSE,
4909 Zplayer, FALSE, FALSE,
4913 ZBORDER, FALSE, FALSE,
4923 static struct Mapping_EM_to_RND_player
4932 em_player_mapping_list[] =
4936 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
4940 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
4944 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
4948 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
4952 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
4956 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
4960 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
4964 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
4968 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
4972 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
4976 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
4980 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
4984 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
4988 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
4992 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
4996 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
5000 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
5004 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
5008 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
5012 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
5016 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
5020 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
5024 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
5028 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
5032 EL_PLAYER_1, ACTION_DEFAULT, -1,
5036 EL_PLAYER_2, ACTION_DEFAULT, -1,
5040 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
5044 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
5048 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
5052 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
5056 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
5060 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
5064 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
5068 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
5072 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
5076 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
5080 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
5084 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
5088 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
5092 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
5096 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
5100 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
5104 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
5108 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
5112 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
5116 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
5120 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
5124 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
5128 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
5132 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
5136 EL_PLAYER_3, ACTION_DEFAULT, -1,
5140 EL_PLAYER_4, ACTION_DEFAULT, -1,
5149 int map_element_RND_to_EM(int element_rnd)
5151 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
5152 static boolean mapping_initialized = FALSE;
5154 if (!mapping_initialized)
5158 /* return "Xalpha_quest" for all undefined elements in mapping array */
5159 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
5160 mapping_RND_to_EM[i] = Xalpha_quest;
5162 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5163 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
5164 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
5165 em_object_mapping_list[i].element_em;
5167 mapping_initialized = TRUE;
5170 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
5171 return mapping_RND_to_EM[element_rnd];
5173 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
5178 int map_element_EM_to_RND(int element_em)
5180 static unsigned short mapping_EM_to_RND[TILE_MAX];
5181 static boolean mapping_initialized = FALSE;
5183 if (!mapping_initialized)
5187 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
5188 for (i = 0; i < TILE_MAX; i++)
5189 mapping_EM_to_RND[i] = EL_UNKNOWN;
5191 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5192 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
5193 em_object_mapping_list[i].element_rnd;
5195 mapping_initialized = TRUE;
5198 if (element_em >= 0 && element_em < TILE_MAX)
5199 return mapping_EM_to_RND[element_em];
5201 Error(ERR_WARN, "invalid EM level element %d", element_em);
5206 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
5208 struct LevelInfo_EM *level_em = level->native_em_level;
5209 struct LEVEL *lev = level_em->lev;
5212 for (i = 0; i < TILE_MAX; i++)
5213 lev->android_array[i] = Xblank;
5215 for (i = 0; i < level->num_android_clone_elements; i++)
5217 int element_rnd = level->android_clone_element[i];
5218 int element_em = map_element_RND_to_EM(element_rnd);
5220 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
5221 if (em_object_mapping_list[j].element_rnd == element_rnd)
5222 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
5226 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
5228 struct LevelInfo_EM *level_em = level->native_em_level;
5229 struct LEVEL *lev = level_em->lev;
5232 level->num_android_clone_elements = 0;
5234 for (i = 0; i < TILE_MAX; i++)
5236 int element_em = lev->android_array[i];
5238 boolean element_found = FALSE;
5240 if (element_em == Xblank)
5243 element_rnd = map_element_EM_to_RND(element_em);
5245 for (j = 0; j < level->num_android_clone_elements; j++)
5246 if (level->android_clone_element[j] == element_rnd)
5247 element_found = TRUE;
5251 level->android_clone_element[level->num_android_clone_elements++] =
5254 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
5259 if (level->num_android_clone_elements == 0)
5261 level->num_android_clone_elements = 1;
5262 level->android_clone_element[0] = EL_EMPTY;
5266 int map_direction_RND_to_EM(int direction)
5268 return (direction == MV_UP ? 0 :
5269 direction == MV_RIGHT ? 1 :
5270 direction == MV_DOWN ? 2 :
5271 direction == MV_LEFT ? 3 :
5275 int map_direction_EM_to_RND(int direction)
5277 return (direction == 0 ? MV_UP :
5278 direction == 1 ? MV_RIGHT :
5279 direction == 2 ? MV_DOWN :
5280 direction == 3 ? MV_LEFT :
5284 int get_next_element(int element)
5288 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
5289 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
5290 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
5291 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
5292 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
5293 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
5294 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
5296 default: return element;
5301 int el_act_dir2img(int element, int action, int direction)
5303 element = GFX_ELEMENT(element);
5305 if (direction == MV_NONE)
5306 return element_info[element].graphic[action];
5308 direction = MV_DIR_TO_BIT(direction);
5310 return element_info[element].direction_graphic[action][direction];
5313 int el_act_dir2img(int element, int action, int direction)
5315 element = GFX_ELEMENT(element);
5316 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5318 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5319 return element_info[element].direction_graphic[action][direction];
5324 static int el_act_dir2crm(int element, int action, int direction)
5326 element = GFX_ELEMENT(element);
5328 if (direction == MV_NONE)
5329 return element_info[element].crumbled[action];
5331 direction = MV_DIR_TO_BIT(direction);
5333 return element_info[element].direction_crumbled[action][direction];
5336 static int el_act_dir2crm(int element, int action, int direction)
5338 element = GFX_ELEMENT(element);
5339 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5341 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5342 return element_info[element].direction_crumbled[action][direction];
5346 int el_act2img(int element, int action)
5348 element = GFX_ELEMENT(element);
5350 return element_info[element].graphic[action];
5353 int el_act2crm(int element, int action)
5355 element = GFX_ELEMENT(element);
5357 return element_info[element].crumbled[action];
5360 int el_dir2img(int element, int direction)
5362 element = GFX_ELEMENT(element);
5364 return el_act_dir2img(element, ACTION_DEFAULT, direction);
5367 int el2baseimg(int element)
5369 return element_info[element].graphic[ACTION_DEFAULT];
5372 int el2img(int element)
5374 element = GFX_ELEMENT(element);
5376 return element_info[element].graphic[ACTION_DEFAULT];
5379 int el2edimg(int element)
5381 element = GFX_ELEMENT(element);
5383 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
5386 int el2preimg(int element)
5388 element = GFX_ELEMENT(element);
5390 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
5393 int font2baseimg(int font_nr)
5395 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
5398 int getNumActivePlayers_EM()
5400 int num_players = 0;
5406 for (i = 0; i < MAX_PLAYERS; i++)
5407 if (tape.player_participates[i])
5413 int getGameFrameDelay_EM(int native_em_game_frame_delay)
5415 int game_frame_delay_value;
5417 game_frame_delay_value =
5418 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
5419 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
5422 if (tape.playing && tape.warp_forward && !tape.pausing)
5423 game_frame_delay_value = 0;
5425 return game_frame_delay_value;
5428 unsigned int InitRND(long seed)
5430 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
5431 return InitEngineRandom_EM(seed);
5433 return InitEngineRandom_RND(seed);
5436 void InitGraphicInfo_EM(void)
5438 struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
5439 struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
5443 int num_em_gfx_errors = 0;
5445 if (graphic_info_em_object[0][0].bitmap == NULL)
5447 /* EM graphics not yet initialized in em_open_all() */
5452 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
5455 /* always start with reliable default values */
5456 for (i = 0; i < TILE_MAX; i++)
5458 object_mapping[i].element_rnd = EL_UNKNOWN;
5459 object_mapping[i].is_backside = FALSE;
5460 object_mapping[i].action = ACTION_DEFAULT;
5461 object_mapping[i].direction = MV_NONE;
5464 /* always start with reliable default values */
5465 for (p = 0; p < MAX_PLAYERS; p++)
5467 for (i = 0; i < SPR_MAX; i++)
5469 player_mapping[p][i].element_rnd = EL_UNKNOWN;
5470 player_mapping[p][i].action = ACTION_DEFAULT;
5471 player_mapping[p][i].direction = MV_NONE;
5475 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5477 int e = em_object_mapping_list[i].element_em;
5479 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
5480 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
5482 if (em_object_mapping_list[i].action != -1)
5483 object_mapping[e].action = em_object_mapping_list[i].action;
5485 if (em_object_mapping_list[i].direction != -1)
5486 object_mapping[e].direction =
5487 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
5490 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
5492 int a = em_player_mapping_list[i].action_em;
5493 int p = em_player_mapping_list[i].player_nr;
5495 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
5497 if (em_player_mapping_list[i].action != -1)
5498 player_mapping[p][a].action = em_player_mapping_list[i].action;
5500 if (em_player_mapping_list[i].direction != -1)
5501 player_mapping[p][a].direction =
5502 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
5505 for (i = 0; i < TILE_MAX; i++)
5507 int element = object_mapping[i].element_rnd;
5508 int action = object_mapping[i].action;
5509 int direction = object_mapping[i].direction;
5510 boolean is_backside = object_mapping[i].is_backside;
5511 boolean action_removing = (action == ACTION_DIGGING ||
5512 action == ACTION_SNAPPING ||
5513 action == ACTION_COLLECTING);
5514 boolean action_exploding = ((action == ACTION_EXPLODING ||
5515 action == ACTION_SMASHED_BY_ROCK ||
5516 action == ACTION_SMASHED_BY_SPRING) &&
5517 element != EL_DIAMOND);
5518 boolean action_active = (action == ACTION_ACTIVE);
5519 boolean action_other = (action == ACTION_OTHER);
5521 for (j = 0; j < 8; j++)
5523 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
5524 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
5526 i == Xdrip_stretch ? element :
5527 i == Xdrip_stretchB ? element :
5528 i == Ydrip_s1 ? element :
5529 i == Ydrip_s1B ? element :
5530 i == Xball_1B ? element :
5531 i == Xball_2 ? element :
5532 i == Xball_2B ? element :
5533 i == Yball_eat ? element :
5534 i == Ykey_1_eat ? element :
5535 i == Ykey_2_eat ? element :
5536 i == Ykey_3_eat ? element :
5537 i == Ykey_4_eat ? element :
5538 i == Ykey_5_eat ? element :
5539 i == Ykey_6_eat ? element :
5540 i == Ykey_7_eat ? element :
5541 i == Ykey_8_eat ? element :
5542 i == Ylenses_eat ? element :
5543 i == Ymagnify_eat ? element :
5544 i == Ygrass_eat ? element :
5545 i == Ydirt_eat ? element :
5546 i == Yemerald_stone ? EL_EMERALD :
5547 i == Ydiamond_stone ? EL_ROCK :
5548 i == Xsand_stonein_1 ? element :
5549 i == Xsand_stonein_2 ? element :
5550 i == Xsand_stonein_3 ? element :
5551 i == Xsand_stonein_4 ? element :
5552 is_backside ? EL_EMPTY :
5553 action_removing ? EL_EMPTY :
5555 int effective_action = (j < 7 ? action :
5556 i == Xdrip_stretch ? action :
5557 i == Xdrip_stretchB ? action :
5558 i == Ydrip_s1 ? action :
5559 i == Ydrip_s1B ? action :
5560 i == Xball_1B ? action :
5561 i == Xball_2 ? action :
5562 i == Xball_2B ? action :
5563 i == Yball_eat ? action :
5564 i == Ykey_1_eat ? action :
5565 i == Ykey_2_eat ? action :
5566 i == Ykey_3_eat ? action :
5567 i == Ykey_4_eat ? action :
5568 i == Ykey_5_eat ? action :
5569 i == Ykey_6_eat ? action :
5570 i == Ykey_7_eat ? action :
5571 i == Ykey_8_eat ? action :
5572 i == Ylenses_eat ? action :
5573 i == Ymagnify_eat ? action :
5574 i == Ygrass_eat ? action :
5575 i == Ydirt_eat ? action :
5576 i == Xsand_stonein_1 ? action :
5577 i == Xsand_stonein_2 ? action :
5578 i == Xsand_stonein_3 ? action :
5579 i == Xsand_stonein_4 ? action :
5580 i == Xsand_stoneout_1 ? action :
5581 i == Xsand_stoneout_2 ? action :
5582 i == Xboom_android ? ACTION_EXPLODING :
5583 action_exploding ? ACTION_EXPLODING :
5584 action_active ? action :
5585 action_other ? action :
5587 int graphic = (el_act_dir2img(effective_element, effective_action,
5589 int crumbled = (el_act_dir2crm(effective_element, effective_action,
5591 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
5592 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
5593 boolean has_action_graphics = (graphic != base_graphic);
5594 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
5595 struct GraphicInfo *g = &graphic_info[graphic];
5596 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
5599 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
5600 boolean special_animation = (action != ACTION_DEFAULT &&
5601 g->anim_frames == 3 &&
5602 g->anim_delay == 2 &&
5603 g->anim_mode & ANIM_LINEAR);
5604 int sync_frame = (i == Xdrip_stretch ? 7 :
5605 i == Xdrip_stretchB ? 7 :
5606 i == Ydrip_s2 ? j + 8 :
5607 i == Ydrip_s2B ? j + 8 :
5616 i == Xfake_acid_1 ? 0 :
5617 i == Xfake_acid_2 ? 10 :
5618 i == Xfake_acid_3 ? 20 :
5619 i == Xfake_acid_4 ? 30 :
5620 i == Xfake_acid_5 ? 40 :
5621 i == Xfake_acid_6 ? 50 :
5622 i == Xfake_acid_7 ? 60 :
5623 i == Xfake_acid_8 ? 70 :
5625 i == Xball_2B ? j + 8 :
5626 i == Yball_eat ? j + 1 :
5627 i == Ykey_1_eat ? j + 1 :
5628 i == Ykey_2_eat ? j + 1 :
5629 i == Ykey_3_eat ? j + 1 :
5630 i == Ykey_4_eat ? j + 1 :
5631 i == Ykey_5_eat ? j + 1 :
5632 i == Ykey_6_eat ? j + 1 :
5633 i == Ykey_7_eat ? j + 1 :
5634 i == Ykey_8_eat ? j + 1 :
5635 i == Ylenses_eat ? j + 1 :
5636 i == Ymagnify_eat ? j + 1 :
5637 i == Ygrass_eat ? j + 1 :
5638 i == Ydirt_eat ? j + 1 :
5639 i == Xamoeba_1 ? 0 :
5640 i == Xamoeba_2 ? 1 :
5641 i == Xamoeba_3 ? 2 :
5642 i == Xamoeba_4 ? 3 :
5643 i == Xamoeba_5 ? 0 :
5644 i == Xamoeba_6 ? 1 :
5645 i == Xamoeba_7 ? 2 :
5646 i == Xamoeba_8 ? 3 :
5647 i == Xexit_2 ? j + 8 :
5648 i == Xexit_3 ? j + 16 :
5649 i == Xdynamite_1 ? 0 :
5650 i == Xdynamite_2 ? 8 :
5651 i == Xdynamite_3 ? 16 :
5652 i == Xdynamite_4 ? 24 :
5653 i == Xsand_stonein_1 ? j + 1 :
5654 i == Xsand_stonein_2 ? j + 9 :
5655 i == Xsand_stonein_3 ? j + 17 :
5656 i == Xsand_stonein_4 ? j + 25 :
5657 i == Xsand_stoneout_1 && j == 0 ? 0 :
5658 i == Xsand_stoneout_1 && j == 1 ? 0 :
5659 i == Xsand_stoneout_1 && j == 2 ? 1 :
5660 i == Xsand_stoneout_1 && j == 3 ? 2 :
5661 i == Xsand_stoneout_1 && j == 4 ? 2 :
5662 i == Xsand_stoneout_1 && j == 5 ? 3 :
5663 i == Xsand_stoneout_1 && j == 6 ? 4 :
5664 i == Xsand_stoneout_1 && j == 7 ? 4 :
5665 i == Xsand_stoneout_2 && j == 0 ? 5 :
5666 i == Xsand_stoneout_2 && j == 1 ? 6 :
5667 i == Xsand_stoneout_2 && j == 2 ? 7 :
5668 i == Xsand_stoneout_2 && j == 3 ? 8 :
5669 i == Xsand_stoneout_2 && j == 4 ? 9 :
5670 i == Xsand_stoneout_2 && j == 5 ? 11 :
5671 i == Xsand_stoneout_2 && j == 6 ? 13 :
5672 i == Xsand_stoneout_2 && j == 7 ? 15 :
5673 i == Xboom_bug && j == 1 ? 2 :
5674 i == Xboom_bug && j == 2 ? 2 :
5675 i == Xboom_bug && j == 3 ? 4 :
5676 i == Xboom_bug && j == 4 ? 4 :
5677 i == Xboom_bug && j == 5 ? 2 :
5678 i == Xboom_bug && j == 6 ? 2 :
5679 i == Xboom_bug && j == 7 ? 0 :
5680 i == Xboom_bomb && j == 1 ? 2 :
5681 i == Xboom_bomb && j == 2 ? 2 :
5682 i == Xboom_bomb && j == 3 ? 4 :
5683 i == Xboom_bomb && j == 4 ? 4 :
5684 i == Xboom_bomb && j == 5 ? 2 :
5685 i == Xboom_bomb && j == 6 ? 2 :
5686 i == Xboom_bomb && j == 7 ? 0 :
5687 i == Xboom_android && j == 7 ? 6 :
5688 i == Xboom_1 && j == 1 ? 2 :
5689 i == Xboom_1 && j == 2 ? 2 :
5690 i == Xboom_1 && j == 3 ? 4 :
5691 i == Xboom_1 && j == 4 ? 4 :
5692 i == Xboom_1 && j == 5 ? 6 :
5693 i == Xboom_1 && j == 6 ? 6 :
5694 i == Xboom_1 && j == 7 ? 8 :
5695 i == Xboom_2 && j == 0 ? 8 :
5696 i == Xboom_2 && j == 1 ? 8 :
5697 i == Xboom_2 && j == 2 ? 10 :
5698 i == Xboom_2 && j == 3 ? 10 :
5699 i == Xboom_2 && j == 4 ? 10 :
5700 i == Xboom_2 && j == 5 ? 12 :
5701 i == Xboom_2 && j == 6 ? 12 :
5702 i == Xboom_2 && j == 7 ? 12 :
5703 special_animation && j == 4 ? 3 :
5704 effective_action != action ? 0 :
5708 Bitmap *debug_bitmap = g_em->bitmap;
5709 int debug_src_x = g_em->src_x;
5710 int debug_src_y = g_em->src_y;
5713 int frame = getAnimationFrame(g->anim_frames,
5716 g->anim_start_frame,
5719 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
5720 g->double_movement && is_backside);
5722 g_em->bitmap = src_bitmap;
5723 g_em->src_x = src_x;
5724 g_em->src_y = src_y;
5725 g_em->src_offset_x = 0;
5726 g_em->src_offset_y = 0;
5727 g_em->dst_offset_x = 0;
5728 g_em->dst_offset_y = 0;
5729 g_em->width = TILEX;
5730 g_em->height = TILEY;
5732 g_em->crumbled_bitmap = NULL;
5733 g_em->crumbled_src_x = 0;
5734 g_em->crumbled_src_y = 0;
5735 g_em->crumbled_border_size = 0;
5737 g_em->has_crumbled_graphics = FALSE;
5738 g_em->preserve_background = FALSE;
5741 if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
5742 printf("::: empty crumbled: %d [%s], %d, %d\n",
5743 effective_element, element_info[effective_element].token_name,
5744 effective_action, direction);
5747 /* if element can be crumbled, but certain action graphics are just empty
5748 space (like snapping sand with the original R'n'D graphics), do not
5749 treat these empty space graphics as crumbled graphics in EMC engine */
5750 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
5752 getGraphicSource(crumbled, frame, &src_bitmap, &src_x, &src_y);
5754 g_em->has_crumbled_graphics = TRUE;
5755 g_em->crumbled_bitmap = src_bitmap;
5756 g_em->crumbled_src_x = src_x;
5757 g_em->crumbled_src_y = src_y;
5758 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
5762 if (element == EL_ROCK &&
5763 effective_action == ACTION_FILLING)
5764 printf("::: has_action_graphics == %d\n", has_action_graphics);
5767 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
5768 effective_action == ACTION_MOVING ||
5769 effective_action == ACTION_PUSHING ||
5770 effective_action == ACTION_EATING)) ||
5771 (!has_action_graphics && (effective_action == ACTION_FILLING ||
5772 effective_action == ACTION_EMPTYING)))
5775 (effective_action == ACTION_FALLING ||
5776 effective_action == ACTION_FILLING ||
5777 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
5778 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
5779 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
5780 int num_steps = (i == Ydrip_s1 ? 16 :
5781 i == Ydrip_s1B ? 16 :
5782 i == Ydrip_s2 ? 16 :
5783 i == Ydrip_s2B ? 16 :
5784 i == Xsand_stonein_1 ? 32 :
5785 i == Xsand_stonein_2 ? 32 :
5786 i == Xsand_stonein_3 ? 32 :
5787 i == Xsand_stonein_4 ? 32 :
5788 i == Xsand_stoneout_1 ? 16 :
5789 i == Xsand_stoneout_2 ? 16 : 8);
5790 int cx = ABS(dx) * (TILEX / num_steps);
5791 int cy = ABS(dy) * (TILEY / num_steps);
5792 int step_frame = (i == Ydrip_s2 ? j + 8 :
5793 i == Ydrip_s2B ? j + 8 :
5794 i == Xsand_stonein_2 ? j + 8 :
5795 i == Xsand_stonein_3 ? j + 16 :
5796 i == Xsand_stonein_4 ? j + 24 :
5797 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
5798 int step = (is_backside ? step_frame : num_steps - step_frame);
5800 if (is_backside) /* tile where movement starts */
5802 if (dx < 0 || dy < 0)
5804 g_em->src_offset_x = cx * step;
5805 g_em->src_offset_y = cy * step;
5809 g_em->dst_offset_x = cx * step;
5810 g_em->dst_offset_y = cy * step;
5813 else /* tile where movement ends */
5815 if (dx < 0 || dy < 0)
5817 g_em->dst_offset_x = cx * step;
5818 g_em->dst_offset_y = cy * step;
5822 g_em->src_offset_x = cx * step;
5823 g_em->src_offset_y = cy * step;
5827 g_em->width = TILEX - cx * step;
5828 g_em->height = TILEY - cy * step;
5831 /* create unique graphic identifier to decide if tile must be redrawn */
5832 /* bit 31 - 16 (16 bit): EM style graphic
5833 bit 15 - 12 ( 4 bit): EM style frame
5834 bit 11 - 6 ( 6 bit): graphic width
5835 bit 5 - 0 ( 6 bit): graphic height */
5836 g_em->unique_identifier =
5837 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
5841 /* skip check for EMC elements not contained in original EMC artwork */
5842 if (element == EL_EMC_FAKE_ACID)
5845 if (g_em->bitmap != debug_bitmap ||
5846 g_em->src_x != debug_src_x ||
5847 g_em->src_y != debug_src_y ||
5848 g_em->src_offset_x != 0 ||
5849 g_em->src_offset_y != 0 ||
5850 g_em->dst_offset_x != 0 ||
5851 g_em->dst_offset_y != 0 ||
5852 g_em->width != TILEX ||
5853 g_em->height != TILEY)
5855 static int last_i = -1;
5863 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
5864 i, element, element_info[element].token_name,
5865 element_action_info[effective_action].suffix, direction);
5867 if (element != effective_element)
5868 printf(" [%d ('%s')]",
5870 element_info[effective_element].token_name);
5874 if (g_em->bitmap != debug_bitmap)
5875 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
5876 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
5878 if (g_em->src_x != debug_src_x ||
5879 g_em->src_y != debug_src_y)
5880 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
5881 j, (is_backside ? 'B' : 'F'),
5882 g_em->src_x, g_em->src_y,
5883 g_em->src_x / 32, g_em->src_y / 32,
5884 debug_src_x, debug_src_y,
5885 debug_src_x / 32, debug_src_y / 32);
5887 if (g_em->src_offset_x != 0 ||
5888 g_em->src_offset_y != 0 ||
5889 g_em->dst_offset_x != 0 ||
5890 g_em->dst_offset_y != 0)
5891 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
5893 g_em->src_offset_x, g_em->src_offset_y,
5894 g_em->dst_offset_x, g_em->dst_offset_y);
5896 if (g_em->width != TILEX ||
5897 g_em->height != TILEY)
5898 printf(" %d (%d): size %d,%d should be %d,%d\n",
5900 g_em->width, g_em->height, TILEX, TILEY);
5902 num_em_gfx_errors++;
5909 for (i = 0; i < TILE_MAX; i++)
5911 for (j = 0; j < 8; j++)
5913 int element = object_mapping[i].element_rnd;
5914 int action = object_mapping[i].action;
5915 int direction = object_mapping[i].direction;
5916 boolean is_backside = object_mapping[i].is_backside;
5917 int graphic_action = el_act_dir2img(element, action, direction);
5918 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
5920 if ((action == ACTION_SMASHED_BY_ROCK ||
5921 action == ACTION_SMASHED_BY_SPRING ||
5922 action == ACTION_EATING) &&
5923 graphic_action == graphic_default)
5925 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
5926 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
5927 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
5928 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
5931 /* no separate animation for "smashed by rock" -- use rock instead */
5932 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
5933 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
5935 g_em->bitmap = g_xx->bitmap;
5936 g_em->src_x = g_xx->src_x;
5937 g_em->src_y = g_xx->src_y;
5938 g_em->src_offset_x = g_xx->src_offset_x;
5939 g_em->src_offset_y = g_xx->src_offset_y;
5940 g_em->dst_offset_x = g_xx->dst_offset_x;
5941 g_em->dst_offset_y = g_xx->dst_offset_y;
5942 g_em->width = g_xx->width;
5943 g_em->height = g_xx->height;
5944 g_em->unique_identifier = g_xx->unique_identifier;
5947 g_em->preserve_background = TRUE;
5952 for (p = 0; p < MAX_PLAYERS; p++)
5954 for (i = 0; i < SPR_MAX; i++)
5956 int element = player_mapping[p][i].element_rnd;
5957 int action = player_mapping[p][i].action;
5958 int direction = player_mapping[p][i].direction;
5960 for (j = 0; j < 8; j++)
5962 int effective_element = element;
5963 int effective_action = action;
5964 int graphic = (direction == MV_NONE ?
5965 el_act2img(effective_element, effective_action) :
5966 el_act_dir2img(effective_element, effective_action,
5968 struct GraphicInfo *g = &graphic_info[graphic];
5969 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
5975 Bitmap *debug_bitmap = g_em->bitmap;
5976 int debug_src_x = g_em->src_x;
5977 int debug_src_y = g_em->src_y;
5980 int frame = getAnimationFrame(g->anim_frames,
5983 g->anim_start_frame,
5986 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x,&src_y, FALSE);
5988 g_em->bitmap = src_bitmap;
5989 g_em->src_x = src_x;
5990 g_em->src_y = src_y;
5991 g_em->src_offset_x = 0;
5992 g_em->src_offset_y = 0;
5993 g_em->dst_offset_x = 0;
5994 g_em->dst_offset_y = 0;
5995 g_em->width = TILEX;
5996 g_em->height = TILEY;
6000 /* skip check for EMC elements not contained in original EMC artwork */
6001 if (element == EL_PLAYER_3 ||
6002 element == EL_PLAYER_4)
6005 if (g_em->bitmap != debug_bitmap ||
6006 g_em->src_x != debug_src_x ||
6007 g_em->src_y != debug_src_y)
6009 static int last_i = -1;
6017 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
6018 p, i, element, element_info[element].token_name,
6019 element_action_info[effective_action].suffix, direction);
6021 if (element != effective_element)
6022 printf(" [%d ('%s')]",
6024 element_info[effective_element].token_name);
6028 if (g_em->bitmap != debug_bitmap)
6029 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
6030 j, (int)(g_em->bitmap), (int)(debug_bitmap));
6032 if (g_em->src_x != debug_src_x ||
6033 g_em->src_y != debug_src_y)
6034 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
6036 g_em->src_x, g_em->src_y,
6037 g_em->src_x / 32, g_em->src_y / 32,
6038 debug_src_x, debug_src_y,
6039 debug_src_x / 32, debug_src_y / 32);
6041 num_em_gfx_errors++;
6051 printf("::: [%d errors found]\n", num_em_gfx_errors);
6057 void PlayMenuSound()
6059 int sound = menu.sound[game_status];
6061 if (sound == SND_UNDEFINED)
6064 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6065 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6068 if (IS_LOOP_SOUND(sound))
6069 PlaySoundLoop(sound);
6074 void PlayMenuSoundStereo(int sound, int stereo_position)
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 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
6086 PlaySoundStereo(sound, stereo_position);
6089 void PlayMenuSoundIfLoop()
6091 int sound = menu.sound[game_status];
6093 if (sound == SND_UNDEFINED)
6096 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6097 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6100 if (IS_LOOP_SOUND(sound))
6101 PlaySoundLoop(sound);
6104 void PlayMenuMusic()
6106 int music = menu.music[game_status];
6108 if (music == MUS_UNDEFINED)
6114 void ToggleFullscreenIfNeeded()
6116 boolean change_fullscreen = (setup.fullscreen !=
6117 video.fullscreen_enabled);
6118 boolean change_fullscreen_mode = (video.fullscreen_enabled &&
6119 !strEqual(setup.fullscreen_mode,
6120 video.fullscreen_mode_current));
6122 if (!video.fullscreen_available)
6126 if (change_fullscreen || change_fullscreen_mode)
6128 if (setup.fullscreen != video.fullscreen_enabled ||
6129 setup.fullscreen_mode != video.fullscreen_mode_current)
6132 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
6134 /* save backbuffer content which gets lost when toggling fullscreen mode */
6135 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6138 if (change_fullscreen_mode)
6140 if (setup.fullscreen && video.fullscreen_enabled)
6143 /* keep fullscreen, but change fullscreen mode (screen resolution) */
6145 /* (this is now set in sdl.c) */
6147 video.fullscreen_mode_current = setup.fullscreen_mode;
6149 video.fullscreen_enabled = FALSE; /* force new fullscreen mode */
6152 /* toggle fullscreen */
6153 ChangeVideoModeIfNeeded(setup.fullscreen);
6155 setup.fullscreen = video.fullscreen_enabled;
6157 /* restore backbuffer content from temporary backbuffer backup bitmap */
6158 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6160 FreeBitmap(tmp_backbuffer);
6163 /* update visible window/screen */
6164 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6166 redraw_mask = REDRAW_ALL;