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 (global.fps_slowdown && game_status == GAME_MODE_PLAYING)
273 static boolean last_frame_skipped = FALSE;
274 boolean skip_even_when_not_scrolling = TRUE;
275 boolean just_scrolling = (ScreenMovDir != 0);
276 boolean verbose = FALSE;
278 if (global.fps_slowdown_factor > 1 &&
279 (FrameCounter % global.fps_slowdown_factor) &&
280 (just_scrolling || skip_even_when_not_scrolling))
282 redraw_mask &= ~REDRAW_MAIN;
284 last_frame_skipped = TRUE;
287 printf("FRAME SKIPPED\n");
291 if (last_frame_skipped)
292 redraw_mask |= REDRAW_FIELD;
294 last_frame_skipped = FALSE;
297 printf("frame not skipped\n");
301 /* synchronize X11 graphics at this point; if we would synchronize the
302 display immediately after the buffer switching (after the XFlush),
303 this could mean that we have to wait for the graphics to complete,
304 although we could go on doing calculations for the next frame */
308 if (redraw_mask & REDRAW_ALL)
310 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
312 redraw_mask = REDRAW_NONE;
315 if (redraw_mask & REDRAW_FIELD)
317 if (game_status != GAME_MODE_PLAYING ||
318 redraw_mask & REDRAW_FROM_BACKBUFFER)
320 DrawMaskedBorder(REDRAW_FIELD);
321 BlitBitmap(backbuffer, window,
322 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
326 int fx = FX, fy = FY;
328 if (setup.soft_scrolling)
330 fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
331 fy += (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
334 if (setup.soft_scrolling ||
335 ABS(ScreenMovPos) + ScrollStepSize == TILEX ||
336 ABS(ScreenMovPos) == ScrollStepSize ||
337 redraw_tiles > REDRAWTILES_THRESHOLD)
340 if (border.draw_masked[GFX_SPECIAL_ARG_MAIN])
342 BlitBitmap(buffer, backbuffer, fx, fy, SXSIZE, SYSIZE, SX, SY);
344 DrawMaskedBorder(REDRAW_FIELD);
345 BlitBitmap(backbuffer, window,
346 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
350 BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
352 BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
357 printf("redrawing all (ScreenGfxPos == %d) because %s\n",
359 (setup.soft_scrolling ?
360 "setup.soft_scrolling" :
361 ABS(ScreenGfxPos) + ScrollStepSize == TILEX ?
362 "ABS(ScreenGfxPos) + ScrollStepSize == TILEX" :
363 ABS(ScreenGfxPos) == ScrollStepSize ?
364 "ABS(ScreenGfxPos) == ScrollStepSize" :
365 "redraw_tiles > REDRAWTILES_THRESHOLD"));
371 redraw_mask &= ~REDRAW_MAIN;
374 if (redraw_mask & REDRAW_DOORS)
376 if (redraw_mask & REDRAW_DOOR_1)
378 DrawMaskedBorder(REDRAW_DOOR_1);
379 BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
382 if (redraw_mask & REDRAW_DOOR_2)
384 DrawMaskedBorder(REDRAW_DOOR_2);
385 BlitBitmap(backbuffer, window, VX, VY, VXSIZE, VYSIZE, VX, VY);
388 if (redraw_mask & REDRAW_DOOR_3)
390 DrawMaskedBorder(REDRAW_DOOR_3);
391 BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
394 redraw_mask &= ~REDRAW_DOORS;
397 if (redraw_mask & REDRAW_MICROLEVEL)
399 BlitBitmap(backbuffer, window, SX, SY + 10 * TILEY, SXSIZE, 7 * TILEY,
400 SX, SY + 10 * TILEY);
402 redraw_mask &= ~REDRAW_MICROLEVEL;
405 if (redraw_mask & REDRAW_TILES)
407 for (x = 0; x < SCR_FIELDX; x++)
408 for (y = 0 ; y < SCR_FIELDY; y++)
409 if (redraw[redraw_x1 + x][redraw_y1 + y])
410 BlitBitmap(buffer, window,
411 FX + x * TILEX, FY + y * TILEY, TILEX, TILEY,
412 SX + x * TILEX, SY + y * TILEY);
415 if (redraw_mask & REDRAW_FPS) /* display frames per second */
420 sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
421 if (!global.fps_slowdown)
424 sprintf(text, "%.1f fps%s", global.frames_per_second, info1);
425 DrawTextExt(window, SX, SY, text, FONT_TEXT_2, BLIT_OPAQUE);
430 for (x = 0; x < MAX_BUF_XSIZE; x++)
431 for (y = 0; y < MAX_BUF_YSIZE; y++)
434 redraw_mask = REDRAW_NONE;
440 long fading_delay = 300;
442 if (setup.fading && (redraw_mask & REDRAW_FIELD))
449 ClearRectangle(window, REAL_SX,REAL_SY,FULL_SXSIZE,FULL_SYSIZE);
452 for (i = 0; i < 2 * FULL_SYSIZE; i++)
454 for (y = 0; y < FULL_SYSIZE; y++)
456 BlitBitmap(backbuffer, window,
457 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
465 for (i = 1; i < FULL_SYSIZE; i+=2)
466 BlitBitmap(backbuffer, window,
467 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
473 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, 0);
474 BlitBitmapMasked(backbuffer, window,
475 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
480 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, -1);
481 BlitBitmapMasked(backbuffer, window,
482 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
487 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, -1);
488 BlitBitmapMasked(backbuffer, window,
489 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
494 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, 0);
495 BlitBitmapMasked(backbuffer, window,
496 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
501 redraw_mask &= ~REDRAW_MAIN;
508 void FadeExt(int fade_mask, int fade_mode)
510 void (*draw_border_function)(void) = NULL;
511 Bitmap *bitmap = (fade_mode == FADE_MODE_CROSSFADE ? bitmap_db_cross : NULL);
512 int fade_delay = menu.fade_delay;
513 int post_delay = (fade_mode == FADE_MODE_FADE_OUT ? menu.post_delay : 0);
514 int x, y, width, height;
516 if (fade_mask & REDRAW_FIELD)
521 height = FULL_SYSIZE;
523 draw_border_function = DrawMaskedBorder_FIELD;
525 else /* REDRAW_ALL */
533 redraw_mask |= fade_mask;
535 if (!setup.fade_screens || fade_delay == 0)
537 if (fade_mode == FADE_MODE_FADE_OUT)
538 ClearRectangle(backbuffer, x, y, width, height);
545 FadeRectangle(bitmap, x, y, width, height, fade_mode, fade_delay, post_delay,
546 draw_border_function);
548 redraw_mask &= ~fade_mask;
551 void FadeIn(int fade_mask)
553 FadeExt(fade_mask, FADE_MODE_FADE_IN);
556 void FadeOut(int fade_mask)
558 FadeExt(fade_mask, FADE_MODE_FADE_OUT);
561 void FadeCross(int fade_mask)
563 FadeExt(fade_mask, FADE_MODE_CROSSFADE);
566 void FadeCrossSaveBackbuffer()
568 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
571 void SetMainBackgroundImageIfDefined(int graphic)
573 if (graphic_info[graphic].bitmap)
574 SetMainBackgroundImage(graphic);
577 void SetMainBackgroundImage(int graphic)
579 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
580 graphic_info[graphic].bitmap ?
581 graphic_info[graphic].bitmap :
582 graphic_info[IMG_BACKGROUND].bitmap);
585 void SetDoorBackgroundImage(int graphic)
587 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
588 graphic_info[graphic].bitmap ?
589 graphic_info[graphic].bitmap :
590 graphic_info[IMG_BACKGROUND].bitmap);
593 void SetPanelBackground()
595 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, bitmap_db_panel,
596 DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, 0, 0);
598 SetDoorBackgroundBitmap(bitmap_db_panel);
601 void DrawBackground(int dst_x, int dst_y, int width, int height)
604 ClearRectangleOnBackground(drawto, dst_x, dst_y, width, height);
606 ClearRectangleOnBackground(backbuffer, dst_x, dst_y, width, height);
609 redraw_mask |= REDRAW_FIELD;
614 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
616 if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
618 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
619 SetDrawtoField(DRAW_BUFFERED);
622 SetDrawtoField(DRAW_BACKBUFFER);
624 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
626 ClearRectangle(window, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
627 SetDrawtoField(DRAW_DIRECT);
631 void MarkTileDirty(int x, int y)
633 int xx = redraw_x1 + x;
634 int yy = redraw_y1 + y;
639 redraw[xx][yy] = TRUE;
640 redraw_mask |= REDRAW_TILES;
643 void SetBorderElement()
647 BorderElement = EL_EMPTY;
649 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
651 for (x = 0; x < lev_fieldx; x++)
653 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
654 BorderElement = EL_STEELWALL;
656 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
662 void SetRandomAnimationValue(int x, int y)
664 gfx.anim_random_frame = GfxRandom[x][y];
667 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
669 /* animation synchronized with global frame counter, not move position */
670 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
671 sync_frame = FrameCounter;
673 return getAnimationFrame(graphic_info[graphic].anim_frames,
674 graphic_info[graphic].anim_delay,
675 graphic_info[graphic].anim_mode,
676 graphic_info[graphic].anim_start_frame,
680 inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
681 int *x, int *y, boolean get_backside)
683 struct GraphicInfo *g = &graphic_info[graphic];
684 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
685 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
689 if (g->offset_y == 0) /* frames are ordered horizontally */
691 int max_width = g->anim_frames_per_line * g->width;
692 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
694 *x = pos % max_width;
695 *y = src_y % g->height + pos / max_width * g->height;
697 else if (g->offset_x == 0) /* frames are ordered vertically */
699 int max_height = g->anim_frames_per_line * g->height;
700 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
702 *x = src_x % g->width + pos / max_height * g->width;
703 *y = pos % max_height;
705 else /* frames are ordered diagonally */
707 *x = src_x + frame * g->offset_x;
708 *y = src_y + frame * g->offset_y;
712 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
714 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
717 void DrawGraphic(int x, int y, int graphic, int frame)
720 if (!IN_SCR_FIELD(x, y))
722 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
723 printf("DrawGraphic(): This should never happen!\n");
728 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
732 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
738 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
739 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
742 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
745 if (!IN_SCR_FIELD(x, y))
747 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
748 printf("DrawGraphicThruMask(): This should never happen!\n");
753 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
758 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
764 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
766 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
767 dst_x - src_x, dst_y - src_y);
768 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
771 void DrawMiniGraphic(int x, int y, int graphic)
773 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
774 MarkTileDirty(x / 2, y / 2);
777 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
779 struct GraphicInfo *g = &graphic_info[graphic];
781 int mini_starty = g->bitmap->height * 2 / 3;
784 *x = mini_startx + g->src_x / 2;
785 *y = mini_starty + g->src_y / 2;
788 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
793 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
794 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
797 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
798 int graphic, int frame,
799 int cut_mode, int mask_mode)
804 int width = TILEX, height = TILEY;
807 if (dx || dy) /* shifted graphic */
809 if (x < BX1) /* object enters playfield from the left */
816 else if (x > BX2) /* object enters playfield from the right */
822 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
828 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
830 else if (dx) /* general horizontal movement */
831 MarkTileDirty(x + SIGN(dx), y);
833 if (y < BY1) /* object enters playfield from the top */
835 if (cut_mode==CUT_BELOW) /* object completely above top border */
843 else if (y > BY2) /* object enters playfield from the bottom */
849 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
855 else if (dy > 0 && cut_mode == CUT_ABOVE)
857 if (y == BY2) /* object completely above bottom border */
863 MarkTileDirty(x, y + 1);
864 } /* object leaves playfield to the bottom */
865 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
867 else if (dy) /* general vertical movement */
868 MarkTileDirty(x, y + SIGN(dy));
872 if (!IN_SCR_FIELD(x, y))
874 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
875 printf("DrawGraphicShifted(): This should never happen!\n");
880 if (width > 0 && height > 0)
882 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
887 dst_x = FX + x * TILEX + dx;
888 dst_y = FY + y * TILEY + dy;
890 if (mask_mode == USE_MASKING)
892 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
893 dst_x - src_x, dst_y - src_y);
894 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
898 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
905 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
906 int graphic, int frame,
907 int cut_mode, int mask_mode)
912 int width = TILEX, height = TILEY;
915 int x2 = x + SIGN(dx);
916 int y2 = y + SIGN(dy);
917 int anim_frames = graphic_info[graphic].anim_frames;
918 int sync_frame = (dx ? ABS(dx) : ABS(dy)) * anim_frames / TILESIZE;
919 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
920 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
922 /* re-calculate animation frame for two-tile movement animation */
923 frame = getGraphicAnimationFrame(graphic, sync_frame);
925 /* check if movement start graphic inside screen area and should be drawn */
926 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
928 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
930 dst_x = FX + x1 * TILEX;
931 dst_y = FY + y1 * TILEY;
933 if (mask_mode == USE_MASKING)
935 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
936 dst_x - src_x, dst_y - src_y);
937 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
941 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
944 MarkTileDirty(x1, y1);
947 /* check if movement end graphic inside screen area and should be drawn */
948 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
950 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
952 dst_x = FX + x2 * TILEX;
953 dst_y = FY + y2 * TILEY;
955 if (mask_mode == USE_MASKING)
957 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
958 dst_x - src_x, dst_y - src_y);
959 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
963 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
966 MarkTileDirty(x2, y2);
970 static void DrawGraphicShifted(int x, int y, int dx, int dy,
971 int graphic, int frame,
972 int cut_mode, int mask_mode)
976 DrawGraphic(x, y, graphic, frame);
981 if (graphic_info[graphic].double_movement) /* EM style movement images */
982 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
984 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
987 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
988 int frame, int cut_mode)
990 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
993 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
994 int cut_mode, int mask_mode)
996 int lx = LEVELX(x), ly = LEVELY(y);
1000 if (IN_LEV_FIELD(lx, ly))
1002 SetRandomAnimationValue(lx, ly);
1004 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
1005 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1007 /* do not use double (EM style) movement graphic when not moving */
1008 if (graphic_info[graphic].double_movement && !dx && !dy)
1010 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
1011 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1014 else /* border element */
1016 graphic = el2img(element);
1017 frame = getGraphicAnimationFrame(graphic, -1);
1020 if (element == EL_EXPANDABLE_WALL)
1022 boolean left_stopped = FALSE, right_stopped = FALSE;
1024 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1025 left_stopped = TRUE;
1026 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1027 right_stopped = TRUE;
1029 if (left_stopped && right_stopped)
1031 else if (left_stopped)
1033 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1034 frame = graphic_info[graphic].anim_frames - 1;
1036 else if (right_stopped)
1038 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1039 frame = graphic_info[graphic].anim_frames - 1;
1044 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1045 else if (mask_mode == USE_MASKING)
1046 DrawGraphicThruMask(x, y, graphic, frame);
1048 DrawGraphic(x, y, graphic, frame);
1051 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1052 int cut_mode, int mask_mode)
1054 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1055 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1056 cut_mode, mask_mode);
1059 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1062 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1065 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1068 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1071 void DrawLevelElementThruMask(int x, int y, int element)
1073 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1076 void DrawLevelFieldThruMask(int x, int y)
1078 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1081 static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
1085 int sx = SCREENX(x), sy = SCREENY(y);
1087 int width, height, cx, cy, i;
1088 int crumbled_border_size = graphic_info[graphic].border_size;
1089 static int xy[4][2] =
1097 if (!IN_LEV_FIELD(x, y))
1100 element = TILE_GFX_ELEMENT(x, y);
1102 /* crumble field itself */
1103 if (GFX_CRUMBLED(element) && !IS_MOVING(x, y))
1105 if (!IN_SCR_FIELD(sx, sy))
1108 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1110 for (i = 0; i < 4; i++)
1112 int xx = x + xy[i][0];
1113 int yy = y + xy[i][1];
1115 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1118 /* check if neighbour field is of same type */
1119 if (GFX_CRUMBLED(element) && !IS_MOVING(xx, yy))
1122 if (i == 1 || i == 2)
1124 width = crumbled_border_size;
1126 cx = (i == 2 ? TILEX - crumbled_border_size : 0);
1132 height = crumbled_border_size;
1134 cy = (i == 3 ? TILEY - crumbled_border_size : 0);
1137 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1138 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1141 MarkTileDirty(sx, sy);
1143 else /* crumble neighbour fields */
1145 for (i = 0; i < 4; i++)
1147 int xx = x + xy[i][0];
1148 int yy = y + xy[i][1];
1149 int sxx = sx + xy[i][0];
1150 int syy = sy + xy[i][1];
1152 if (!IN_LEV_FIELD(xx, yy) ||
1153 !IN_SCR_FIELD(sxx, syy) ||
1157 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
1160 element = TILE_GFX_ELEMENT(xx, yy);
1162 if (!GFX_CRUMBLED(element))
1165 graphic = el_act2crm(element, ACTION_DEFAULT);
1166 crumbled_border_size = graphic_info[graphic].border_size;
1168 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1170 if (i == 1 || i == 2)
1172 width = crumbled_border_size;
1174 cx = (i == 1 ? TILEX - crumbled_border_size : 0);
1180 height = crumbled_border_size;
1182 cy = (i == 0 ? TILEY - crumbled_border_size : 0);
1185 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1186 width, height, FX + sxx * TILEX + cx, FY + syy * TILEY + cy);
1188 MarkTileDirty(sxx, syy);
1193 void DrawLevelFieldCrumbledSand(int x, int y)
1197 if (!IN_LEV_FIELD(x, y))
1201 /* !!! CHECK THIS !!! */
1204 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1205 GFX_CRUMBLED(GfxElement[x][y]))
1208 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1209 GfxElement[x][y] != EL_UNDEFINED &&
1210 GFX_CRUMBLED(GfxElement[x][y]))
1212 DrawLevelFieldCrumbledSandDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
1219 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
1221 graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
1224 DrawLevelFieldCrumbledSandExt(x, y, graphic, 0);
1227 void DrawLevelFieldCrumbledSandDigging(int x, int y, int direction,
1230 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1231 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1232 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1233 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1234 int sx = SCREENX(x), sy = SCREENY(y);
1236 DrawGraphic(sx, sy, graphic1, frame1);
1237 DrawLevelFieldCrumbledSandExt(x, y, graphic2, frame2);
1240 void DrawLevelFieldCrumbledSandNeighbours(int x, int y)
1242 int sx = SCREENX(x), sy = SCREENY(y);
1243 static int xy[4][2] =
1252 for (i = 0; i < 4; i++)
1254 int xx = x + xy[i][0];
1255 int yy = y + xy[i][1];
1256 int sxx = sx + xy[i][0];
1257 int syy = sy + xy[i][1];
1259 if (!IN_LEV_FIELD(xx, yy) ||
1260 !IN_SCR_FIELD(sxx, syy) ||
1261 !GFX_CRUMBLED(Feld[xx][yy]) ||
1265 DrawLevelField(xx, yy);
1269 static int getBorderElement(int x, int y)
1273 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1274 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1275 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1276 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1277 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1278 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1279 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1281 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1282 int steel_position = (x == -1 && y == -1 ? 0 :
1283 x == lev_fieldx && y == -1 ? 1 :
1284 x == -1 && y == lev_fieldy ? 2 :
1285 x == lev_fieldx && y == lev_fieldy ? 3 :
1286 x == -1 || x == lev_fieldx ? 4 :
1287 y == -1 || y == lev_fieldy ? 5 : 6);
1289 return border[steel_position][steel_type];
1292 void DrawScreenElement(int x, int y, int element)
1294 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1295 DrawLevelFieldCrumbledSand(LEVELX(x), LEVELY(y));
1298 void DrawLevelElement(int x, int y, int element)
1300 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1301 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1304 void DrawScreenField(int x, int y)
1306 int lx = LEVELX(x), ly = LEVELY(y);
1307 int element, content;
1309 if (!IN_LEV_FIELD(lx, ly))
1311 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1314 element = getBorderElement(lx, ly);
1316 DrawScreenElement(x, y, element);
1320 element = Feld[lx][ly];
1321 content = Store[lx][ly];
1323 if (IS_MOVING(lx, ly))
1325 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1326 boolean cut_mode = NO_CUTTING;
1328 if (element == EL_QUICKSAND_EMPTYING ||
1329 element == EL_MAGIC_WALL_EMPTYING ||
1330 element == EL_BD_MAGIC_WALL_EMPTYING ||
1331 element == EL_AMOEBA_DROPPING)
1332 cut_mode = CUT_ABOVE;
1333 else if (element == EL_QUICKSAND_FILLING ||
1334 element == EL_MAGIC_WALL_FILLING ||
1335 element == EL_BD_MAGIC_WALL_FILLING)
1336 cut_mode = CUT_BELOW;
1338 if (cut_mode == CUT_ABOVE)
1339 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1341 DrawScreenElement(x, y, EL_EMPTY);
1344 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1345 else if (cut_mode == NO_CUTTING)
1346 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1348 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1350 if (content == EL_ACID)
1352 int dir = MovDir[lx][ly];
1353 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
1354 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
1356 DrawLevelElementThruMask(newlx, newly, EL_ACID);
1359 else if (IS_BLOCKED(lx, ly))
1364 boolean cut_mode = NO_CUTTING;
1365 int element_old, content_old;
1367 Blocked2Moving(lx, ly, &oldx, &oldy);
1370 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1371 MovDir[oldx][oldy] == MV_RIGHT);
1373 element_old = Feld[oldx][oldy];
1374 content_old = Store[oldx][oldy];
1376 if (element_old == EL_QUICKSAND_EMPTYING ||
1377 element_old == EL_MAGIC_WALL_EMPTYING ||
1378 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1379 element_old == EL_AMOEBA_DROPPING)
1380 cut_mode = CUT_ABOVE;
1382 DrawScreenElement(x, y, EL_EMPTY);
1385 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1387 else if (cut_mode == NO_CUTTING)
1388 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1391 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1394 else if (IS_DRAWABLE(element))
1395 DrawScreenElement(x, y, element);
1397 DrawScreenElement(x, y, EL_EMPTY);
1400 void DrawLevelField(int x, int y)
1402 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1403 DrawScreenField(SCREENX(x), SCREENY(y));
1404 else if (IS_MOVING(x, y))
1408 Moving2Blocked(x, y, &newx, &newy);
1409 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1410 DrawScreenField(SCREENX(newx), SCREENY(newy));
1412 else if (IS_BLOCKED(x, y))
1416 Blocked2Moving(x, y, &oldx, &oldy);
1417 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1418 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1422 void DrawMiniElement(int x, int y, int element)
1426 graphic = el2edimg(element);
1427 DrawMiniGraphic(x, y, graphic);
1430 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1432 int x = sx + scroll_x, y = sy + scroll_y;
1434 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1435 DrawMiniElement(sx, sy, EL_EMPTY);
1436 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1437 DrawMiniElement(sx, sy, Feld[x][y]);
1439 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1442 void DrawEnvelopeBackground(int envelope_nr, int startx, int starty,
1443 int x, int y, int xsize, int ysize, int font_nr)
1445 int font_width = getFontWidth(font_nr);
1446 int font_height = getFontHeight(font_nr);
1447 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1450 int dst_x = SX + startx + x * font_width;
1451 int dst_y = SY + starty + y * font_height;
1452 int width = graphic_info[graphic].width;
1453 int height = graphic_info[graphic].height;
1454 int inner_width = MAX(width - 2 * font_width, font_width);
1455 int inner_height = MAX(height - 2 * font_height, font_height);
1456 int inner_sx = (width >= 3 * font_width ? font_width : 0);
1457 int inner_sy = (height >= 3 * font_height ? font_height : 0);
1458 boolean draw_masked = graphic_info[graphic].draw_masked;
1460 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1462 if (src_bitmap == NULL || width < font_width || height < font_height)
1464 ClearRectangle(drawto, dst_x, dst_y, font_width, font_height);
1468 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - font_width :
1469 inner_sx + (x - 1) * font_width % inner_width);
1470 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - font_height :
1471 inner_sy + (y - 1) * font_height % inner_height);
1475 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1476 dst_x - src_x, dst_y - src_y);
1477 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1481 BlitBitmap(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1485 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
1487 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1488 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1489 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
1490 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1491 boolean no_delay = (tape.warp_forward);
1492 unsigned long anim_delay = 0;
1493 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
1494 int anim_delay_value = (no_delay ? 0 : frame_delay_value);
1495 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
1496 int font_width = getFontWidth(font_nr);
1497 int font_height = getFontHeight(font_nr);
1498 int max_xsize = level.envelope[envelope_nr].xsize;
1499 int max_ysize = level.envelope[envelope_nr].ysize;
1500 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
1501 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
1502 int xend = max_xsize;
1503 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
1504 int xstep = (xstart < xend ? 1 : 0);
1505 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
1508 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
1510 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
1511 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
1512 int sx = (SXSIZE - xsize * font_width) / 2;
1513 int sy = (SYSIZE - ysize * font_height) / 2;
1516 SetDrawtoField(DRAW_BUFFERED);
1518 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
1520 SetDrawtoField(DRAW_BACKBUFFER);
1522 for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++)
1523 DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
1525 DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
1526 level.envelope[envelope_nr].text, font_nr, max_xsize,
1527 xsize - 2, ysize - 2, mask_mode);
1529 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
1532 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
1536 void ShowEnvelope(int envelope_nr)
1538 int element = EL_ENVELOPE_1 + envelope_nr;
1539 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1540 int sound_opening = element_info[element].sound[ACTION_OPENING];
1541 int sound_closing = element_info[element].sound[ACTION_CLOSING];
1542 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1543 boolean no_delay = (tape.warp_forward);
1544 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
1545 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
1546 int anim_mode = graphic_info[graphic].anim_mode;
1547 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
1548 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
1550 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
1552 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
1554 if (anim_mode == ANIM_DEFAULT)
1555 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
1557 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
1560 Delay(wait_delay_value);
1562 WaitForEventToContinue();
1564 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
1566 if (anim_mode != ANIM_NONE)
1567 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
1569 if (anim_mode == ANIM_DEFAULT)
1570 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
1572 game.envelope_active = FALSE;
1574 SetDrawtoField(DRAW_BUFFERED);
1576 redraw_mask |= REDRAW_FIELD;
1580 void getPreviewGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y,
1585 int width_mult, width_div;
1586 int height_mult, height_div;
1594 int offset_calc_pos = (tilesize < MICRO_TILESIZE || tilesize > TILESIZE ? 3 :
1595 5 - log_2(tilesize));
1596 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1597 int width_mult = offset_calc[offset_calc_pos].width_mult;
1598 int width_div = offset_calc[offset_calc_pos].width_div;
1599 int height_mult = offset_calc[offset_calc_pos].height_mult;
1600 int height_div = offset_calc[offset_calc_pos].height_div;
1601 int mini_startx = src_bitmap->width * width_mult / width_div;
1602 int mini_starty = src_bitmap->height * height_mult / height_div;
1603 int src_x = mini_startx + graphic_info[graphic].src_x * tilesize / TILESIZE;
1604 int src_y = mini_starty + graphic_info[graphic].src_y * tilesize / TILESIZE;
1606 *bitmap = src_bitmap;
1611 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
1615 int graphic = el2preimg(element);
1617 getPreviewGraphicSource(graphic, &src_bitmap, &src_x, &src_y, tilesize);
1618 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
1625 SetDrawBackgroundMask(REDRAW_NONE);
1628 for (x = BX1; x <= BX2; x++)
1629 for (y = BY1; y <= BY2; y++)
1630 DrawScreenField(x, y);
1632 redraw_mask |= REDRAW_FIELD;
1635 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1639 for (x = 0; x < size_x; x++)
1640 for (y = 0; y < size_y; y++)
1641 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1643 redraw_mask |= REDRAW_FIELD;
1646 static void DrawPreviewLevelExt(int from_x, int from_y)
1648 boolean show_level_border = (BorderElement != EL_EMPTY);
1649 int dst_x = preview.x;
1650 int dst_y = preview.y;
1651 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
1652 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
1653 int tile_size = preview.tile_size;
1654 int preview_width = preview.xsize * tile_size;
1655 int preview_height = preview.ysize * tile_size;
1656 int real_preview_xsize = MIN(level_xsize, preview.xsize);
1657 int real_preview_ysize = MIN(level_ysize, preview.ysize);
1660 DrawBackground(dst_x, dst_y, preview_width, preview_height);
1662 dst_x += (preview_width - real_preview_xsize * tile_size) / 2;
1663 dst_y += (preview_height - real_preview_ysize * tile_size) / 2;
1665 for (x = 0; x < real_preview_xsize; x++)
1667 for (y = 0; y < real_preview_ysize; y++)
1669 int lx = from_x + x + (show_level_border ? -1 : 0);
1670 int ly = from_y + y + (show_level_border ? -1 : 0);
1671 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
1672 getBorderElement(lx, ly));
1674 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
1675 element, tile_size);
1679 redraw_mask |= REDRAW_MICROLEVEL;
1682 #define MICROLABEL_EMPTY 0
1683 #define MICROLABEL_LEVEL_NAME 1
1684 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
1685 #define MICROLABEL_LEVEL_AUTHOR 3
1686 #define MICROLABEL_IMPORTED_FROM_HEAD 4
1687 #define MICROLABEL_IMPORTED_FROM 5
1688 #define MICROLABEL_IMPORTED_BY_HEAD 6
1689 #define MICROLABEL_IMPORTED_BY 7
1691 static void DrawPreviewLevelLabelExt(int mode)
1693 char label_text[MAX_OUTPUT_LINESIZE + 1];
1694 int max_len_label_text;
1695 int font_nr = FONT_TEXT_2;
1698 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
1699 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
1700 mode == MICROLABEL_IMPORTED_BY_HEAD)
1701 font_nr = FONT_TEXT_3;
1703 max_len_label_text = SXSIZE / getFontWidth(font_nr);
1705 for (i = 0; i < max_len_label_text; i++)
1706 label_text[i] = ' ';
1707 label_text[max_len_label_text] = '\0';
1709 if (strlen(label_text) > 0)
1711 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1712 int lypos = MICROLABEL2_YPOS;
1714 DrawText(lxpos, lypos, label_text, font_nr);
1718 (mode == MICROLABEL_LEVEL_NAME ? level.name :
1719 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
1720 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1721 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
1722 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
1723 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
1724 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
1725 max_len_label_text);
1726 label_text[max_len_label_text] = '\0';
1728 if (strlen(label_text) > 0)
1730 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1731 int lypos = MICROLABEL2_YPOS;
1733 DrawText(lxpos, lypos, label_text, font_nr);
1736 redraw_mask |= REDRAW_MICROLEVEL;
1739 void DrawPreviewLevel(boolean restart)
1741 static unsigned long scroll_delay = 0;
1742 static unsigned long label_delay = 0;
1743 static int from_x, from_y, scroll_direction;
1744 static int label_state, label_counter;
1745 unsigned long scroll_delay_value = preview.step_delay;
1746 boolean show_level_border = (BorderElement != EL_EMPTY);
1747 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
1748 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
1749 int last_game_status = game_status; /* save current game status */
1751 /* force PREVIEW font on preview level */
1752 game_status = GAME_MODE_PSEUDO_PREVIEW;
1756 from_x = from_y = 0;
1757 scroll_direction = MV_RIGHT;
1761 DrawPreviewLevelExt(from_x, from_y);
1762 DrawPreviewLevelLabelExt(label_state);
1764 /* initialize delay counters */
1765 DelayReached(&scroll_delay, 0);
1766 DelayReached(&label_delay, 0);
1768 if (leveldir_current->name)
1770 char label_text[MAX_OUTPUT_LINESIZE + 1];
1771 int font_nr = FONT_TEXT_1;
1772 int max_len_label_text = SXSIZE / getFontWidth(font_nr);
1775 strncpy(label_text, leveldir_current->name, max_len_label_text);
1776 label_text[max_len_label_text] = '\0';
1778 lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1779 lypos = SY + MICROLABEL1_YPOS;
1781 DrawText(lxpos, lypos, label_text, font_nr);
1784 game_status = last_game_status; /* restore current game status */
1789 /* scroll preview level, if needed */
1790 if ((level_xsize > preview.xsize || level_ysize > preview.ysize) &&
1791 DelayReached(&scroll_delay, scroll_delay_value))
1793 switch (scroll_direction)
1798 from_x -= preview.step_offset;
1799 from_x = (from_x < 0 ? 0 : from_x);
1802 scroll_direction = MV_UP;
1806 if (from_x < level_xsize - preview.xsize)
1808 from_x += preview.step_offset;
1809 from_x = (from_x > level_xsize - preview.xsize ?
1810 level_xsize - preview.xsize : from_x);
1813 scroll_direction = MV_DOWN;
1819 from_y -= preview.step_offset;
1820 from_y = (from_y < 0 ? 0 : from_y);
1823 scroll_direction = MV_RIGHT;
1827 if (from_y < level_ysize - preview.ysize)
1829 from_y += preview.step_offset;
1830 from_y = (from_y > level_ysize - preview.ysize ?
1831 level_ysize - preview.ysize : from_y);
1834 scroll_direction = MV_LEFT;
1841 DrawPreviewLevelExt(from_x, from_y);
1844 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
1845 /* redraw micro level label, if needed */
1846 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
1847 !strEqual(level.author, ANONYMOUS_NAME) &&
1848 !strEqual(level.author, leveldir_current->name) &&
1849 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
1851 int max_label_counter = 23;
1853 if (leveldir_current->imported_from != NULL &&
1854 strlen(leveldir_current->imported_from) > 0)
1855 max_label_counter += 14;
1856 if (leveldir_current->imported_by != NULL &&
1857 strlen(leveldir_current->imported_by) > 0)
1858 max_label_counter += 14;
1860 label_counter = (label_counter + 1) % max_label_counter;
1861 label_state = (label_counter >= 0 && label_counter <= 7 ?
1862 MICROLABEL_LEVEL_NAME :
1863 label_counter >= 9 && label_counter <= 12 ?
1864 MICROLABEL_LEVEL_AUTHOR_HEAD :
1865 label_counter >= 14 && label_counter <= 21 ?
1866 MICROLABEL_LEVEL_AUTHOR :
1867 label_counter >= 23 && label_counter <= 26 ?
1868 MICROLABEL_IMPORTED_FROM_HEAD :
1869 label_counter >= 28 && label_counter <= 35 ?
1870 MICROLABEL_IMPORTED_FROM :
1871 label_counter >= 37 && label_counter <= 40 ?
1872 MICROLABEL_IMPORTED_BY_HEAD :
1873 label_counter >= 42 && label_counter <= 49 ?
1874 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
1876 if (leveldir_current->imported_from == NULL &&
1877 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
1878 label_state == MICROLABEL_IMPORTED_FROM))
1879 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
1880 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
1882 DrawPreviewLevelLabelExt(label_state);
1885 game_status = last_game_status; /* restore current game status */
1888 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
1889 int graphic, int sync_frame, int mask_mode)
1891 int frame = getGraphicAnimationFrame(graphic, sync_frame);
1893 if (mask_mode == USE_MASKING)
1894 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
1896 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
1899 inline void DrawGraphicAnimation(int x, int y, int graphic)
1901 int lx = LEVELX(x), ly = LEVELY(y);
1903 if (!IN_SCR_FIELD(x, y))
1906 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
1907 graphic, GfxFrame[lx][ly], NO_MASKING);
1908 MarkTileDirty(x, y);
1911 void DrawLevelGraphicAnimation(int x, int y, int graphic)
1913 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
1916 void DrawLevelElementAnimation(int x, int y, int element)
1918 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
1920 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
1923 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
1925 int sx = SCREENX(x), sy = SCREENY(y);
1927 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
1930 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
1933 DrawGraphicAnimation(sx, sy, graphic);
1936 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
1937 DrawLevelFieldCrumbledSand(x, y);
1939 if (GFX_CRUMBLED(Feld[x][y]))
1940 DrawLevelFieldCrumbledSand(x, y);
1944 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
1946 int sx = SCREENX(x), sy = SCREENY(y);
1949 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
1952 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
1954 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
1957 DrawGraphicAnimation(sx, sy, graphic);
1959 if (GFX_CRUMBLED(element))
1960 DrawLevelFieldCrumbledSand(x, y);
1963 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
1965 if (player->use_murphy)
1967 /* this works only because currently only one player can be "murphy" ... */
1968 static int last_horizontal_dir = MV_LEFT;
1969 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
1971 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
1972 last_horizontal_dir = move_dir;
1974 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
1976 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
1978 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
1984 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
1987 static boolean equalGraphics(int graphic1, int graphic2)
1989 struct GraphicInfo *g1 = &graphic_info[graphic1];
1990 struct GraphicInfo *g2 = &graphic_info[graphic2];
1992 return (g1->bitmap == g2->bitmap &&
1993 g1->src_x == g2->src_x &&
1994 g1->src_y == g2->src_y &&
1995 g1->anim_frames == g2->anim_frames &&
1996 g1->anim_delay == g2->anim_delay &&
1997 g1->anim_mode == g2->anim_mode);
2000 void DrawAllPlayers()
2004 for (i = 0; i < MAX_PLAYERS; i++)
2005 if (stored_player[i].active)
2006 DrawPlayer(&stored_player[i]);
2009 void DrawPlayerField(int x, int y)
2011 if (!IS_PLAYER(x, y))
2014 DrawPlayer(PLAYERINFO(x, y));
2017 void DrawPlayer(struct PlayerInfo *player)
2019 int jx = player->jx;
2020 int jy = player->jy;
2021 int move_dir = player->MovDir;
2022 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
2023 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
2024 int last_jx = (player->is_moving ? jx - dx : jx);
2025 int last_jy = (player->is_moving ? jy - dy : jy);
2026 int next_jx = jx + dx;
2027 int next_jy = jy + dy;
2028 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
2029 boolean player_is_opaque = FALSE;
2030 int sx = SCREENX(jx), sy = SCREENY(jy);
2031 int sxx = 0, syy = 0;
2032 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
2034 int action = ACTION_DEFAULT;
2035 int last_player_graphic = getPlayerGraphic(player, move_dir);
2036 int last_player_frame = player->Frame;
2039 /* GfxElement[][] is set to the element the player is digging or collecting;
2040 remove also for off-screen player if the player is not moving anymore */
2041 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
2042 GfxElement[jx][jy] = EL_UNDEFINED;
2044 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
2048 if (!IN_LEV_FIELD(jx, jy))
2050 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
2051 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
2052 printf("DrawPlayerField(): This should never happen!\n");
2057 if (element == EL_EXPLOSION)
2060 action = (player->is_pushing ? ACTION_PUSHING :
2061 player->is_digging ? ACTION_DIGGING :
2062 player->is_collecting ? ACTION_COLLECTING :
2063 player->is_moving ? ACTION_MOVING :
2064 player->is_snapping ? ACTION_SNAPPING :
2065 player->is_dropping ? ACTION_DROPPING :
2066 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
2068 if (player->is_waiting)
2069 move_dir = player->dir_waiting;
2071 InitPlayerGfxAnimation(player, action, move_dir);
2073 /* ----------------------------------------------------------------------- */
2074 /* draw things in the field the player is leaving, if needed */
2075 /* ----------------------------------------------------------------------- */
2077 if (player->is_moving)
2079 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
2081 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
2083 if (last_element == EL_DYNAMITE_ACTIVE ||
2084 last_element == EL_EM_DYNAMITE_ACTIVE ||
2085 last_element == EL_SP_DISK_RED_ACTIVE)
2086 DrawDynamite(last_jx, last_jy);
2088 DrawLevelFieldThruMask(last_jx, last_jy);
2090 else if (last_element == EL_DYNAMITE_ACTIVE ||
2091 last_element == EL_EM_DYNAMITE_ACTIVE ||
2092 last_element == EL_SP_DISK_RED_ACTIVE)
2093 DrawDynamite(last_jx, last_jy);
2095 /* !!! this is not enough to prevent flickering of players which are
2096 moving next to each others without a free tile between them -- this
2097 can only be solved by drawing all players layer by layer (first the
2098 background, then the foreground etc.) !!! => TODO */
2099 else if (!IS_PLAYER(last_jx, last_jy))
2100 DrawLevelField(last_jx, last_jy);
2103 DrawLevelField(last_jx, last_jy);
2106 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
2107 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
2110 if (!IN_SCR_FIELD(sx, sy))
2113 if (setup.direct_draw)
2114 SetDrawtoField(DRAW_BUFFERED);
2116 /* ----------------------------------------------------------------------- */
2117 /* draw things behind the player, if needed */
2118 /* ----------------------------------------------------------------------- */
2121 DrawLevelElement(jx, jy, Back[jx][jy]);
2122 else if (IS_ACTIVE_BOMB(element))
2123 DrawLevelElement(jx, jy, EL_EMPTY);
2126 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
2128 int old_element = GfxElement[jx][jy];
2129 int old_graphic = el_act_dir2img(old_element, action, move_dir);
2130 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
2132 if (GFX_CRUMBLED(old_element))
2133 DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
2135 DrawGraphic(sx, sy, old_graphic, frame);
2137 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
2138 player_is_opaque = TRUE;
2142 GfxElement[jx][jy] = EL_UNDEFINED;
2144 /* make sure that pushed elements are drawn with correct frame rate */
2146 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2148 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
2149 GfxFrame[jx][jy] = player->StepFrame;
2151 if (player->is_pushing && player->is_moving)
2152 GfxFrame[jx][jy] = player->StepFrame;
2155 DrawLevelField(jx, jy);
2159 /* ----------------------------------------------------------------------- */
2160 /* draw player himself */
2161 /* ----------------------------------------------------------------------- */
2163 graphic = getPlayerGraphic(player, move_dir);
2165 /* in the case of changed player action or direction, prevent the current
2166 animation frame from being restarted for identical animations */
2167 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
2168 player->Frame = last_player_frame;
2170 frame = getGraphicAnimationFrame(graphic, player->Frame);
2174 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2175 sxx = player->GfxPos;
2177 syy = player->GfxPos;
2180 if (!setup.soft_scrolling && ScreenMovPos)
2183 if (player_is_opaque)
2184 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
2186 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2188 if (SHIELD_ON(player))
2190 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
2191 IMG_SHIELD_NORMAL_ACTIVE);
2192 int frame = getGraphicAnimationFrame(graphic, -1);
2194 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2197 /* ----------------------------------------------------------------------- */
2198 /* draw things the player is pushing, if needed */
2199 /* ----------------------------------------------------------------------- */
2202 printf("::: %d, %d [%d, %d] [%d]\n",
2203 player->is_pushing, player_is_moving, player->GfxAction,
2204 player->is_moving, player_is_moving);
2208 if (player->is_pushing && player->is_moving)
2210 int px = SCREENX(jx), py = SCREENY(jy);
2211 int pxx = (TILEX - ABS(sxx)) * dx;
2212 int pyy = (TILEY - ABS(syy)) * dy;
2213 int gfx_frame = GfxFrame[jx][jy];
2219 if (!IS_MOVING(jx, jy)) /* push movement already finished */
2221 element = Feld[next_jx][next_jy];
2222 gfx_frame = GfxFrame[next_jx][next_jy];
2225 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2228 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
2229 frame = getGraphicAnimationFrame(graphic, sync_frame);
2231 frame = getGraphicAnimationFrame(graphic, player->StepFrame);
2234 /* draw background element under pushed element (like the Sokoban field) */
2235 if (Back[next_jx][next_jy])
2236 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
2238 /* masked drawing is needed for EMC style (double) movement graphics */
2239 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
2243 /* ----------------------------------------------------------------------- */
2244 /* draw things in front of player (active dynamite or dynabombs) */
2245 /* ----------------------------------------------------------------------- */
2247 if (IS_ACTIVE_BOMB(element))
2249 graphic = el2img(element);
2250 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
2252 if (game.emulation == EMU_SUPAPLEX)
2253 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
2255 DrawGraphicThruMask(sx, sy, graphic, frame);
2258 if (player_is_moving && last_element == EL_EXPLOSION)
2260 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
2261 GfxElement[last_jx][last_jy] : EL_EMPTY);
2262 int graphic = el_act2img(element, ACTION_EXPLODING);
2263 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
2264 int phase = ExplodePhase[last_jx][last_jy] - 1;
2265 int frame = getGraphicAnimationFrame(graphic, phase - delay);
2268 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
2271 /* ----------------------------------------------------------------------- */
2272 /* draw elements the player is just walking/passing through/under */
2273 /* ----------------------------------------------------------------------- */
2275 if (player_is_moving)
2277 /* handle the field the player is leaving ... */
2278 if (IS_ACCESSIBLE_INSIDE(last_element))
2279 DrawLevelField(last_jx, last_jy);
2280 else if (IS_ACCESSIBLE_UNDER(last_element))
2281 DrawLevelFieldThruMask(last_jx, last_jy);
2284 /* do not redraw accessible elements if the player is just pushing them */
2285 if (!player_is_moving || !player->is_pushing)
2287 /* ... and the field the player is entering */
2288 if (IS_ACCESSIBLE_INSIDE(element))
2289 DrawLevelField(jx, jy);
2290 else if (IS_ACCESSIBLE_UNDER(element))
2291 DrawLevelFieldThruMask(jx, jy);
2294 if (setup.direct_draw)
2296 int dst_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
2297 int dst_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
2298 int x_size = TILEX * (1 + ABS(jx - last_jx));
2299 int y_size = TILEY * (1 + ABS(jy - last_jy));
2301 BlitBitmap(drawto_field, window,
2302 dst_x, dst_y, x_size, y_size, dst_x, dst_y);
2303 SetDrawtoField(DRAW_DIRECT);
2306 MarkTileDirty(sx, sy);
2309 /* ------------------------------------------------------------------------- */
2311 void WaitForEventToContinue()
2313 boolean still_wait = TRUE;
2315 /* simulate releasing mouse button over last gadget, if still pressed */
2317 HandleGadgets(-1, -1, 0);
2319 button_status = MB_RELEASED;
2335 case EVENT_BUTTONPRESS:
2336 case EVENT_KEYPRESS:
2340 case EVENT_KEYRELEASE:
2341 ClearPlayerAction();
2345 HandleOtherEvents(&event);
2349 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2356 /* don't eat all CPU time */
2361 #define MAX_REQUEST_LINES 13
2362 #define MAX_REQUEST_LINE_FONT1_LEN 7
2363 #define MAX_REQUEST_LINE_FONT2_LEN 10
2365 boolean Request(char *text, unsigned int req_state)
2367 int mx, my, ty, result = -1;
2368 unsigned int old_door_state;
2369 int last_game_status = game_status; /* save current game status */
2370 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
2371 int font_nr = FONT_TEXT_2;
2372 int max_word_len = 0;
2375 for (text_ptr = text; *text_ptr; text_ptr++)
2377 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
2379 if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
2381 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
2382 font_nr = FONT_LEVEL_NUMBER;
2388 if (game_status == GAME_MODE_PLAYING &&
2389 level.game_engine_type == GAME_ENGINE_TYPE_EM)
2390 BlitScreenToBitmap_EM(backbuffer);
2392 /* disable deactivated drawing when quick-loading level tape recording */
2393 if (tape.playing && tape.deactivate_display)
2394 TapeDeactivateDisplayOff(TRUE);
2396 SetMouseCursor(CURSOR_DEFAULT);
2398 #if defined(NETWORK_AVALIABLE)
2399 /* pause network game while waiting for request to answer */
2400 if (options.network &&
2401 game_status == GAME_MODE_PLAYING &&
2402 req_state & REQUEST_WAIT_FOR_INPUT)
2403 SendToServer_PausePlaying();
2406 old_door_state = GetDoorState();
2408 /* simulate releasing mouse button over last gadget, if still pressed */
2410 HandleGadgets(-1, -1, 0);
2414 if (old_door_state & DOOR_OPEN_1)
2416 CloseDoor(DOOR_CLOSE_1);
2418 /* save old door content */
2419 BlitBitmap(bitmap_db_door, bitmap_db_door,
2420 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2421 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
2425 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2428 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2430 /* clear door drawing field */
2431 DrawBackground(DX, DY, DXSIZE, DYSIZE);
2433 /* force DOOR font on preview level */
2434 game_status = GAME_MODE_PSEUDO_DOOR;
2436 /* write text for request */
2437 for (ty = 0; ty < MAX_REQUEST_LINES; ty++)
2439 char text_line[max_request_line_len + 1];
2445 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
2448 if (!tc || tc == ' ')
2459 strncpy(text_line, text, tl);
2462 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
2463 DY + 8 + ty * (getFontHeight(font_nr) + 2),
2464 text_line, font_nr);
2466 text += tl + (tc == ' ' ? 1 : 0);
2469 game_status = last_game_status; /* restore current game status */
2471 if (req_state & REQ_ASK)
2473 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2474 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2476 else if (req_state & REQ_CONFIRM)
2478 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2480 else if (req_state & REQ_PLAYER)
2482 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2483 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2484 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2485 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2488 /* copy request gadgets to door backbuffer */
2489 BlitBitmap(drawto, bitmap_db_door,
2490 DX, DY, DXSIZE, DYSIZE,
2491 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2493 OpenDoor(DOOR_OPEN_1);
2495 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
2497 if (game_status == GAME_MODE_PLAYING)
2499 SetPanelBackground();
2500 SetDrawBackgroundMask(REDRAW_DOOR_1);
2504 SetDrawBackgroundMask(REDRAW_FIELD);
2510 if (game_status != GAME_MODE_MAIN)
2513 button_status = MB_RELEASED;
2515 request_gadget_id = -1;
2517 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2529 case EVENT_BUTTONPRESS:
2530 case EVENT_BUTTONRELEASE:
2531 case EVENT_MOTIONNOTIFY:
2533 if (event.type == EVENT_MOTIONNOTIFY)
2535 if (!PointerInWindow(window))
2536 continue; /* window and pointer are on different screens */
2541 motion_status = TRUE;
2542 mx = ((MotionEvent *) &event)->x;
2543 my = ((MotionEvent *) &event)->y;
2547 motion_status = FALSE;
2548 mx = ((ButtonEvent *) &event)->x;
2549 my = ((ButtonEvent *) &event)->y;
2550 if (event.type == EVENT_BUTTONPRESS)
2551 button_status = ((ButtonEvent *) &event)->button;
2553 button_status = MB_RELEASED;
2556 /* this sets 'request_gadget_id' */
2557 HandleGadgets(mx, my, button_status);
2559 switch(request_gadget_id)
2561 case TOOL_CTRL_ID_YES:
2564 case TOOL_CTRL_ID_NO:
2567 case TOOL_CTRL_ID_CONFIRM:
2568 result = TRUE | FALSE;
2571 case TOOL_CTRL_ID_PLAYER_1:
2574 case TOOL_CTRL_ID_PLAYER_2:
2577 case TOOL_CTRL_ID_PLAYER_3:
2580 case TOOL_CTRL_ID_PLAYER_4:
2591 case EVENT_KEYPRESS:
2592 switch(GetEventKey((KeyEvent *)&event, TRUE))
2605 if (req_state & REQ_PLAYER)
2609 case EVENT_KEYRELEASE:
2610 ClearPlayerAction();
2614 HandleOtherEvents(&event);
2618 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2620 int joy = AnyJoystick();
2622 if (joy & JOY_BUTTON_1)
2624 else if (joy & JOY_BUTTON_2)
2630 /* don't eat all CPU time */
2634 if (game_status != GAME_MODE_MAIN)
2639 if (!(req_state & REQ_STAY_OPEN))
2641 CloseDoor(DOOR_CLOSE_1);
2643 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
2644 (req_state & REQ_REOPEN))
2645 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
2650 if (game_status == GAME_MODE_PLAYING)
2652 SetPanelBackground();
2653 SetDrawBackgroundMask(REDRAW_DOOR_1);
2657 SetDrawBackgroundMask(REDRAW_FIELD);
2660 #if defined(NETWORK_AVALIABLE)
2661 /* continue network game after request */
2662 if (options.network &&
2663 game_status == GAME_MODE_PLAYING &&
2664 req_state & REQUEST_WAIT_FOR_INPUT)
2665 SendToServer_ContinuePlaying();
2668 /* restore deactivated drawing when quick-loading level tape recording */
2669 if (tape.playing && tape.deactivate_display)
2670 TapeDeactivateDisplayOn();
2675 unsigned int OpenDoor(unsigned int door_state)
2677 if (door_state & DOOR_COPY_BACK)
2679 if (door_state & DOOR_OPEN_1)
2680 BlitBitmap(bitmap_db_door, bitmap_db_door,
2681 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2682 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2684 if (door_state & DOOR_OPEN_2)
2685 BlitBitmap(bitmap_db_door, bitmap_db_door,
2686 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
2687 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2689 door_state &= ~DOOR_COPY_BACK;
2692 return MoveDoor(door_state);
2695 unsigned int CloseDoor(unsigned int door_state)
2697 unsigned int old_door_state = GetDoorState();
2699 if (!(door_state & DOOR_NO_COPY_BACK))
2701 if (old_door_state & DOOR_OPEN_1)
2702 BlitBitmap(backbuffer, bitmap_db_door,
2703 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2705 if (old_door_state & DOOR_OPEN_2)
2706 BlitBitmap(backbuffer, bitmap_db_door,
2707 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2709 door_state &= ~DOOR_NO_COPY_BACK;
2712 return MoveDoor(door_state);
2715 unsigned int GetDoorState()
2717 return MoveDoor(DOOR_GET_STATE);
2720 unsigned int SetDoorState(unsigned int door_state)
2722 return MoveDoor(door_state | DOOR_SET_STATE);
2725 unsigned int MoveDoor(unsigned int door_state)
2727 static int door1 = DOOR_OPEN_1;
2728 static int door2 = DOOR_CLOSE_2;
2729 unsigned long door_delay = 0;
2730 unsigned long door_delay_value;
2733 if (door_1.width < 0 || door_1.width > DXSIZE)
2734 door_1.width = DXSIZE;
2735 if (door_1.height < 0 || door_1.height > DYSIZE)
2736 door_1.height = DYSIZE;
2737 if (door_2.width < 0 || door_2.width > VXSIZE)
2738 door_2.width = VXSIZE;
2739 if (door_2.height < 0 || door_2.height > VYSIZE)
2740 door_2.height = VYSIZE;
2742 if (door_state == DOOR_GET_STATE)
2743 return (door1 | door2);
2745 if (door_state & DOOR_SET_STATE)
2747 if (door_state & DOOR_ACTION_1)
2748 door1 = door_state & DOOR_ACTION_1;
2749 if (door_state & DOOR_ACTION_2)
2750 door2 = door_state & DOOR_ACTION_2;
2752 return (door1 | door2);
2755 if (!(door_state & DOOR_FORCE_REDRAW))
2757 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2758 door_state &= ~DOOR_OPEN_1;
2759 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2760 door_state &= ~DOOR_CLOSE_1;
2761 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2762 door_state &= ~DOOR_OPEN_2;
2763 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2764 door_state &= ~DOOR_CLOSE_2;
2767 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
2770 if (setup.quick_doors)
2772 stepsize = 20; /* must be choosen to always draw last frame */
2773 door_delay_value = 0;
2776 if (global.autoplay_leveldir)
2778 door_state |= DOOR_NO_DELAY;
2779 door_state &= ~DOOR_CLOSE_ALL;
2782 if (door_state & DOOR_ACTION)
2784 boolean handle_door_1 = (door_state & DOOR_ACTION_1);
2785 boolean handle_door_2 = (door_state & DOOR_ACTION_2);
2786 boolean door_1_done = (!handle_door_1);
2787 boolean door_2_done = (!handle_door_2);
2788 boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
2789 boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
2790 int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
2791 int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
2792 int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
2793 int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
2794 int door_size = (handle_door_1 ? door_size_1 : door_size_2);
2795 int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
2796 int door_skip = max_door_size - door_size;
2797 int end = door_size;
2798 int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
2801 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
2803 /* opening door sound has priority over simultaneously closing door */
2804 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2805 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2806 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2807 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2810 for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
2813 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2814 GC gc = bitmap->stored_clip_gc;
2816 if (door_state & DOOR_ACTION_1)
2818 int a = MIN(x * door_1.step_offset, end);
2819 int p = (door_state & DOOR_OPEN_1 ? end - a : a);
2820 int i = p + door_skip;
2822 if (door_1.anim_mode & ANIM_STATIC_PANEL)
2824 BlitBitmap(bitmap_db_door, drawto,
2825 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
2826 DXSIZE, DYSIZE, DX, DY);
2830 BlitBitmap(bitmap_db_door, drawto,
2831 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
2832 DXSIZE, DYSIZE - p / 2, DX, DY);
2834 ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
2837 if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
2839 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2840 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
2841 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
2842 int dst2_x = DX, dst2_y = DY;
2843 int width = i, height = DYSIZE;
2845 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2846 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2849 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2850 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2853 else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
2855 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2856 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
2857 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
2858 int dst2_x = DX, dst2_y = DY;
2859 int width = DXSIZE, height = i;
2861 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2862 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2865 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2866 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2869 else if (x <= DXSIZE) /* ANIM_DEFAULT */
2871 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
2873 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2874 BlitBitmapMasked(bitmap, drawto,
2875 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2876 DX + DXSIZE - i, DY + j);
2877 BlitBitmapMasked(bitmap, drawto,
2878 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2879 DX + DXSIZE - i, DY + 140 + j);
2880 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
2881 DY - (DOOR_GFX_PAGEY1 + j));
2882 BlitBitmapMasked(bitmap, drawto,
2883 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2885 BlitBitmapMasked(bitmap, drawto,
2886 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
2889 BlitBitmapMasked(bitmap, drawto,
2890 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2892 BlitBitmapMasked(bitmap, drawto,
2893 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2895 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2896 BlitBitmapMasked(bitmap, drawto,
2897 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2898 DX + DXSIZE - i, DY + 77 + j);
2899 BlitBitmapMasked(bitmap, drawto,
2900 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2901 DX + DXSIZE - i, DY + 203 + j);
2904 redraw_mask |= REDRAW_DOOR_1;
2905 door_1_done = (a == end);
2908 if (door_state & DOOR_ACTION_2)
2910 int a = MIN(x * door_2.step_offset, door_size);
2911 int p = (door_state & DOOR_OPEN_2 ? door_size - a : a);
2912 int i = p + door_skip;
2914 if (door_2.anim_mode & ANIM_STATIC_PANEL)
2916 BlitBitmap(bitmap_db_door, drawto,
2917 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
2918 VXSIZE, VYSIZE, VX, VY);
2920 else if (x <= VYSIZE)
2922 BlitBitmap(bitmap_db_door, drawto,
2923 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
2924 VXSIZE, VYSIZE - p / 2, VX, VY);
2926 ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
2929 if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
2931 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
2932 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
2933 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
2934 int dst2_x = VX, dst2_y = VY;
2935 int width = i, height = VYSIZE;
2937 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2938 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2941 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2942 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2945 else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
2947 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
2948 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
2949 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
2950 int dst2_x = VX, dst2_y = VY;
2951 int width = VXSIZE, height = i;
2953 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2954 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2957 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2958 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2961 else if (x <= VXSIZE) /* ANIM_DEFAULT */
2963 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
2965 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2966 BlitBitmapMasked(bitmap, drawto,
2967 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
2968 VX + VXSIZE - i, VY + j);
2969 SetClipOrigin(bitmap, gc,
2970 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2971 BlitBitmapMasked(bitmap, drawto,
2972 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
2975 BlitBitmapMasked(bitmap, drawto,
2976 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2977 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
2978 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2979 BlitBitmapMasked(bitmap, drawto,
2980 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2982 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2985 redraw_mask |= REDRAW_DOOR_2;
2986 door_2_done = (a == VXSIZE);
2989 if (!(door_state & DOOR_NO_DELAY))
2993 if (game_status == GAME_MODE_MAIN)
2996 WaitUntilDelayReached(&door_delay, door_delay_value);
3001 if (door_state & DOOR_ACTION_1)
3002 door1 = door_state & DOOR_ACTION_1;
3003 if (door_state & DOOR_ACTION_2)
3004 door2 = door_state & DOOR_ACTION_2;
3006 return (door1 | door2);
3009 void DrawSpecialEditorDoor()
3011 /* draw bigger toolbox window */
3012 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
3013 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
3015 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3016 EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
3019 redraw_mask |= REDRAW_ALL;
3022 void UndrawSpecialEditorDoor()
3024 /* draw normal tape recorder window */
3025 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3026 EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
3029 redraw_mask |= REDRAW_ALL;
3033 /* ---------- new tool button stuff ---------------------------------------- */
3035 /* graphic position values for tool buttons */
3036 #define TOOL_BUTTON_YES_XPOS 2
3037 #define TOOL_BUTTON_YES_YPOS 250
3038 #define TOOL_BUTTON_YES_GFX_YPOS 0
3039 #define TOOL_BUTTON_YES_XSIZE 46
3040 #define TOOL_BUTTON_YES_YSIZE 28
3041 #define TOOL_BUTTON_NO_XPOS 52
3042 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
3043 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
3044 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
3045 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
3046 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
3047 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
3048 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
3049 #define TOOL_BUTTON_CONFIRM_XSIZE 96
3050 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
3051 #define TOOL_BUTTON_PLAYER_XSIZE 30
3052 #define TOOL_BUTTON_PLAYER_YSIZE 30
3053 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
3054 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
3055 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
3056 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
3057 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3058 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3059 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3060 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3061 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3062 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3063 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3064 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3065 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3066 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3067 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3068 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3069 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3070 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3071 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3072 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3081 } toolbutton_info[NUM_TOOL_BUTTONS] =
3084 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
3085 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
3086 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
3091 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
3092 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
3093 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
3098 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
3099 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
3100 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
3101 TOOL_CTRL_ID_CONFIRM,
3105 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3106 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
3107 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3108 TOOL_CTRL_ID_PLAYER_1,
3112 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3113 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
3114 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3115 TOOL_CTRL_ID_PLAYER_2,
3119 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3120 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
3121 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3122 TOOL_CTRL_ID_PLAYER_3,
3126 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3127 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
3128 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3129 TOOL_CTRL_ID_PLAYER_4,
3134 void CreateToolButtons()
3138 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3140 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3141 Bitmap *deco_bitmap = None;
3142 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
3143 struct GadgetInfo *gi;
3144 unsigned long event_mask;
3145 int gd_xoffset, gd_yoffset;
3146 int gd_x1, gd_x2, gd_y;
3149 event_mask = GD_EVENT_RELEASED;
3151 gd_xoffset = toolbutton_info[i].xpos;
3152 gd_yoffset = toolbutton_info[i].ypos;
3153 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
3154 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
3155 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
3157 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
3159 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
3161 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
3162 &deco_bitmap, &deco_x, &deco_y);
3163 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
3164 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
3167 gi = CreateGadget(GDI_CUSTOM_ID, id,
3168 GDI_INFO_TEXT, toolbutton_info[i].infotext,
3169 GDI_X, DX + toolbutton_info[i].x,
3170 GDI_Y, DY + toolbutton_info[i].y,
3171 GDI_WIDTH, toolbutton_info[i].width,
3172 GDI_HEIGHT, toolbutton_info[i].height,
3173 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
3174 GDI_STATE, GD_BUTTON_UNPRESSED,
3175 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
3176 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
3177 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
3178 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
3179 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
3180 GDI_DECORATION_SHIFTING, 1, 1,
3181 GDI_DIRECT_DRAW, FALSE,
3182 GDI_EVENT_MASK, event_mask,
3183 GDI_CALLBACK_ACTION, HandleToolButtons,
3187 Error(ERR_EXIT, "cannot create gadget");
3189 tool_gadget[id] = gi;
3193 void FreeToolButtons()
3197 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3198 FreeGadget(tool_gadget[i]);
3201 static void UnmapToolButtons()
3205 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3206 UnmapGadget(tool_gadget[i]);
3209 static void HandleToolButtons(struct GadgetInfo *gi)
3211 request_gadget_id = gi->custom_id;
3214 static struct Mapping_EM_to_RND_object
3217 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
3218 boolean is_backside; /* backside of moving element */
3224 em_object_mapping_list[] =
3227 Xblank, TRUE, FALSE,
3231 Yacid_splash_eB, FALSE, FALSE,
3232 EL_ACID_SPLASH_RIGHT, -1, -1
3235 Yacid_splash_wB, FALSE, FALSE,
3236 EL_ACID_SPLASH_LEFT, -1, -1
3239 #ifdef EM_ENGINE_BAD_ROLL
3241 Xstone_force_e, FALSE, FALSE,
3242 EL_ROCK, -1, MV_BIT_RIGHT
3245 Xstone_force_w, FALSE, FALSE,
3246 EL_ROCK, -1, MV_BIT_LEFT
3249 Xnut_force_e, FALSE, FALSE,
3250 EL_NUT, -1, MV_BIT_RIGHT
3253 Xnut_force_w, FALSE, FALSE,
3254 EL_NUT, -1, MV_BIT_LEFT
3257 Xspring_force_e, FALSE, FALSE,
3258 EL_SPRING, -1, MV_BIT_RIGHT
3261 Xspring_force_w, FALSE, FALSE,
3262 EL_SPRING, -1, MV_BIT_LEFT
3265 Xemerald_force_e, FALSE, FALSE,
3266 EL_EMERALD, -1, MV_BIT_RIGHT
3269 Xemerald_force_w, FALSE, FALSE,
3270 EL_EMERALD, -1, MV_BIT_LEFT
3273 Xdiamond_force_e, FALSE, FALSE,
3274 EL_DIAMOND, -1, MV_BIT_RIGHT
3277 Xdiamond_force_w, FALSE, FALSE,
3278 EL_DIAMOND, -1, MV_BIT_LEFT
3281 Xbomb_force_e, FALSE, FALSE,
3282 EL_BOMB, -1, MV_BIT_RIGHT
3285 Xbomb_force_w, FALSE, FALSE,
3286 EL_BOMB, -1, MV_BIT_LEFT
3288 #endif /* EM_ENGINE_BAD_ROLL */
3291 Xstone, TRUE, FALSE,
3295 Xstone_pause, FALSE, FALSE,
3299 Xstone_fall, FALSE, FALSE,
3303 Ystone_s, FALSE, FALSE,
3304 EL_ROCK, ACTION_FALLING, -1
3307 Ystone_sB, FALSE, TRUE,
3308 EL_ROCK, ACTION_FALLING, -1
3311 Ystone_e, FALSE, FALSE,
3312 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3315 Ystone_eB, FALSE, TRUE,
3316 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3319 Ystone_w, FALSE, FALSE,
3320 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3323 Ystone_wB, FALSE, TRUE,
3324 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3331 Xnut_pause, FALSE, FALSE,
3335 Xnut_fall, FALSE, FALSE,
3339 Ynut_s, FALSE, FALSE,
3340 EL_NUT, ACTION_FALLING, -1
3343 Ynut_sB, FALSE, TRUE,
3344 EL_NUT, ACTION_FALLING, -1
3347 Ynut_e, FALSE, FALSE,
3348 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3351 Ynut_eB, FALSE, TRUE,
3352 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3355 Ynut_w, FALSE, FALSE,
3356 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3359 Ynut_wB, FALSE, TRUE,
3360 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3363 Xbug_n, TRUE, FALSE,
3367 Xbug_e, TRUE, FALSE,
3368 EL_BUG_RIGHT, -1, -1
3371 Xbug_s, TRUE, FALSE,
3375 Xbug_w, TRUE, FALSE,
3379 Xbug_gon, FALSE, FALSE,
3383 Xbug_goe, FALSE, FALSE,
3384 EL_BUG_RIGHT, -1, -1
3387 Xbug_gos, FALSE, FALSE,
3391 Xbug_gow, FALSE, FALSE,
3395 Ybug_n, FALSE, FALSE,
3396 EL_BUG, ACTION_MOVING, MV_BIT_UP
3399 Ybug_nB, FALSE, TRUE,
3400 EL_BUG, ACTION_MOVING, MV_BIT_UP
3403 Ybug_e, FALSE, FALSE,
3404 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3407 Ybug_eB, FALSE, TRUE,
3408 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3411 Ybug_s, FALSE, FALSE,
3412 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3415 Ybug_sB, FALSE, TRUE,
3416 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3419 Ybug_w, FALSE, FALSE,
3420 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3423 Ybug_wB, FALSE, TRUE,
3424 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3427 Ybug_w_n, FALSE, FALSE,
3428 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3431 Ybug_n_e, FALSE, FALSE,
3432 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3435 Ybug_e_s, FALSE, FALSE,
3436 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3439 Ybug_s_w, FALSE, FALSE,
3440 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3443 Ybug_e_n, FALSE, FALSE,
3444 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3447 Ybug_s_e, FALSE, FALSE,
3448 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3451 Ybug_w_s, FALSE, FALSE,
3452 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3455 Ybug_n_w, FALSE, FALSE,
3456 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3459 Ybug_stone, FALSE, FALSE,
3460 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
3463 Ybug_spring, FALSE, FALSE,
3464 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
3467 Xtank_n, TRUE, FALSE,
3468 EL_SPACESHIP_UP, -1, -1
3471 Xtank_e, TRUE, FALSE,
3472 EL_SPACESHIP_RIGHT, -1, -1
3475 Xtank_s, TRUE, FALSE,
3476 EL_SPACESHIP_DOWN, -1, -1
3479 Xtank_w, TRUE, FALSE,
3480 EL_SPACESHIP_LEFT, -1, -1
3483 Xtank_gon, FALSE, FALSE,
3484 EL_SPACESHIP_UP, -1, -1
3487 Xtank_goe, FALSE, FALSE,
3488 EL_SPACESHIP_RIGHT, -1, -1
3491 Xtank_gos, FALSE, FALSE,
3492 EL_SPACESHIP_DOWN, -1, -1
3495 Xtank_gow, FALSE, FALSE,
3496 EL_SPACESHIP_LEFT, -1, -1
3499 Ytank_n, FALSE, FALSE,
3500 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3503 Ytank_nB, FALSE, TRUE,
3504 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3507 Ytank_e, FALSE, FALSE,
3508 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3511 Ytank_eB, FALSE, TRUE,
3512 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3515 Ytank_s, FALSE, FALSE,
3516 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3519 Ytank_sB, FALSE, TRUE,
3520 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3523 Ytank_w, FALSE, FALSE,
3524 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3527 Ytank_wB, FALSE, TRUE,
3528 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3531 Ytank_w_n, FALSE, FALSE,
3532 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3535 Ytank_n_e, FALSE, FALSE,
3536 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3539 Ytank_e_s, FALSE, FALSE,
3540 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3543 Ytank_s_w, FALSE, FALSE,
3544 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3547 Ytank_e_n, FALSE, FALSE,
3548 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3551 Ytank_s_e, FALSE, FALSE,
3552 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3555 Ytank_w_s, FALSE, FALSE,
3556 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3559 Ytank_n_w, FALSE, FALSE,
3560 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3563 Ytank_stone, FALSE, FALSE,
3564 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
3567 Ytank_spring, FALSE, FALSE,
3568 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
3571 Xandroid, TRUE, FALSE,
3572 EL_EMC_ANDROID, ACTION_ACTIVE, -1
3575 Xandroid_1_n, FALSE, FALSE,
3576 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3579 Xandroid_2_n, FALSE, FALSE,
3580 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3583 Xandroid_1_e, FALSE, FALSE,
3584 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3587 Xandroid_2_e, FALSE, FALSE,
3588 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3591 Xandroid_1_w, FALSE, FALSE,
3592 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3595 Xandroid_2_w, FALSE, FALSE,
3596 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3599 Xandroid_1_s, FALSE, FALSE,
3600 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3603 Xandroid_2_s, FALSE, FALSE,
3604 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3607 Yandroid_n, FALSE, FALSE,
3608 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3611 Yandroid_nB, FALSE, TRUE,
3612 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3615 Yandroid_ne, FALSE, FALSE,
3616 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
3619 Yandroid_neB, FALSE, TRUE,
3620 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
3623 Yandroid_e, FALSE, FALSE,
3624 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
3627 Yandroid_eB, FALSE, TRUE,
3628 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
3631 Yandroid_se, FALSE, FALSE,
3632 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
3635 Yandroid_seB, FALSE, TRUE,
3636 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
3639 Yandroid_s, FALSE, FALSE,
3640 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
3643 Yandroid_sB, FALSE, TRUE,
3644 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
3647 Yandroid_sw, FALSE, FALSE,
3648 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
3651 Yandroid_swB, FALSE, TRUE,
3652 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
3655 Yandroid_w, FALSE, FALSE,
3656 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
3659 Yandroid_wB, FALSE, TRUE,
3660 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
3663 Yandroid_nw, FALSE, FALSE,
3664 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
3667 Yandroid_nwB, FALSE, TRUE,
3668 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
3671 Xspring, TRUE, FALSE,
3675 Xspring_pause, FALSE, FALSE,
3679 Xspring_e, FALSE, FALSE,
3683 Xspring_w, FALSE, FALSE,
3687 Xspring_fall, FALSE, FALSE,
3691 Yspring_s, FALSE, FALSE,
3692 EL_SPRING, ACTION_FALLING, -1
3695 Yspring_sB, FALSE, TRUE,
3696 EL_SPRING, ACTION_FALLING, -1
3699 Yspring_e, FALSE, FALSE,
3700 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
3703 Yspring_eB, FALSE, TRUE,
3704 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
3707 Yspring_w, FALSE, FALSE,
3708 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
3711 Yspring_wB, FALSE, TRUE,
3712 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
3715 Yspring_kill_e, FALSE, FALSE,
3716 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
3719 Yspring_kill_eB, FALSE, TRUE,
3720 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
3723 Yspring_kill_w, FALSE, FALSE,
3724 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
3727 Yspring_kill_wB, FALSE, TRUE,
3728 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
3731 Xeater_n, TRUE, FALSE,
3732 EL_YAMYAM_UP, -1, -1
3735 Xeater_e, TRUE, FALSE,
3736 EL_YAMYAM_RIGHT, -1, -1
3739 Xeater_w, TRUE, FALSE,
3740 EL_YAMYAM_LEFT, -1, -1
3743 Xeater_s, TRUE, FALSE,
3744 EL_YAMYAM_DOWN, -1, -1
3747 Yeater_n, FALSE, FALSE,
3748 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
3751 Yeater_nB, FALSE, TRUE,
3752 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
3755 Yeater_e, FALSE, FALSE,
3756 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
3759 Yeater_eB, FALSE, TRUE,
3760 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
3763 Yeater_s, FALSE, FALSE,
3764 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
3767 Yeater_sB, FALSE, TRUE,
3768 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
3771 Yeater_w, FALSE, FALSE,
3772 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
3775 Yeater_wB, FALSE, TRUE,
3776 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
3779 Yeater_stone, FALSE, FALSE,
3780 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
3783 Yeater_spring, FALSE, FALSE,
3784 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
3787 Xalien, TRUE, FALSE,
3791 Xalien_pause, FALSE, FALSE,
3795 Yalien_n, FALSE, FALSE,
3796 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
3799 Yalien_nB, FALSE, TRUE,
3800 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
3803 Yalien_e, FALSE, FALSE,
3804 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
3807 Yalien_eB, FALSE, TRUE,
3808 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
3811 Yalien_s, FALSE, FALSE,
3812 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
3815 Yalien_sB, FALSE, TRUE,
3816 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
3819 Yalien_w, FALSE, FALSE,
3820 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
3823 Yalien_wB, FALSE, TRUE,
3824 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
3827 Yalien_stone, FALSE, FALSE,
3828 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
3831 Yalien_spring, FALSE, FALSE,
3832 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
3835 Xemerald, TRUE, FALSE,
3839 Xemerald_pause, FALSE, FALSE,
3843 Xemerald_fall, FALSE, FALSE,
3847 Xemerald_shine, FALSE, FALSE,
3848 EL_EMERALD, ACTION_TWINKLING, -1
3851 Yemerald_s, FALSE, FALSE,
3852 EL_EMERALD, ACTION_FALLING, -1
3855 Yemerald_sB, FALSE, TRUE,
3856 EL_EMERALD, ACTION_FALLING, -1
3859 Yemerald_e, FALSE, FALSE,
3860 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
3863 Yemerald_eB, FALSE, TRUE,
3864 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
3867 Yemerald_w, FALSE, FALSE,
3868 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
3871 Yemerald_wB, FALSE, TRUE,
3872 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
3875 Yemerald_eat, FALSE, FALSE,
3876 EL_EMERALD, ACTION_COLLECTING, -1
3879 Yemerald_stone, FALSE, FALSE,
3880 EL_NUT, ACTION_BREAKING, -1
3883 Xdiamond, TRUE, FALSE,
3887 Xdiamond_pause, FALSE, FALSE,
3891 Xdiamond_fall, FALSE, FALSE,
3895 Xdiamond_shine, FALSE, FALSE,
3896 EL_DIAMOND, ACTION_TWINKLING, -1
3899 Ydiamond_s, FALSE, FALSE,
3900 EL_DIAMOND, ACTION_FALLING, -1
3903 Ydiamond_sB, FALSE, TRUE,
3904 EL_DIAMOND, ACTION_FALLING, -1
3907 Ydiamond_e, FALSE, FALSE,
3908 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
3911 Ydiamond_eB, FALSE, TRUE,
3912 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
3915 Ydiamond_w, FALSE, FALSE,
3916 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
3919 Ydiamond_wB, FALSE, TRUE,
3920 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
3923 Ydiamond_eat, FALSE, FALSE,
3924 EL_DIAMOND, ACTION_COLLECTING, -1
3927 Ydiamond_stone, FALSE, FALSE,
3928 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
3931 Xdrip_fall, TRUE, FALSE,
3932 EL_AMOEBA_DROP, -1, -1
3935 Xdrip_stretch, FALSE, FALSE,
3936 EL_AMOEBA_DROP, ACTION_FALLING, -1
3939 Xdrip_stretchB, FALSE, TRUE,
3940 EL_AMOEBA_DROP, ACTION_FALLING, -1
3943 Xdrip_eat, FALSE, FALSE,
3944 EL_AMOEBA_DROP, ACTION_GROWING, -1
3947 Ydrip_s1, FALSE, FALSE,
3948 EL_AMOEBA_DROP, ACTION_FALLING, -1
3951 Ydrip_s1B, FALSE, TRUE,
3952 EL_AMOEBA_DROP, ACTION_FALLING, -1
3955 Ydrip_s2, FALSE, FALSE,
3956 EL_AMOEBA_DROP, ACTION_FALLING, -1
3959 Ydrip_s2B, FALSE, TRUE,
3960 EL_AMOEBA_DROP, ACTION_FALLING, -1
3967 Xbomb_pause, FALSE, FALSE,
3971 Xbomb_fall, FALSE, FALSE,
3975 Ybomb_s, FALSE, FALSE,
3976 EL_BOMB, ACTION_FALLING, -1
3979 Ybomb_sB, FALSE, TRUE,
3980 EL_BOMB, ACTION_FALLING, -1
3983 Ybomb_e, FALSE, FALSE,
3984 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
3987 Ybomb_eB, FALSE, TRUE,
3988 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
3991 Ybomb_w, FALSE, FALSE,
3992 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
3995 Ybomb_wB, FALSE, TRUE,
3996 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
3999 Ybomb_eat, FALSE, FALSE,
4000 EL_BOMB, ACTION_ACTIVATING, -1
4003 Xballoon, TRUE, FALSE,
4007 Yballoon_n, FALSE, FALSE,
4008 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
4011 Yballoon_nB, FALSE, TRUE,
4012 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
4015 Yballoon_e, FALSE, FALSE,
4016 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
4019 Yballoon_eB, FALSE, TRUE,
4020 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
4023 Yballoon_s, FALSE, FALSE,
4024 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
4027 Yballoon_sB, FALSE, TRUE,
4028 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
4031 Yballoon_w, FALSE, FALSE,
4032 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
4035 Yballoon_wB, FALSE, TRUE,
4036 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
4039 Xgrass, TRUE, FALSE,
4040 EL_EMC_GRASS, -1, -1
4043 Ygrass_nB, FALSE, FALSE,
4044 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
4047 Ygrass_eB, FALSE, FALSE,
4048 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
4051 Ygrass_sB, FALSE, FALSE,
4052 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
4055 Ygrass_wB, FALSE, FALSE,
4056 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
4063 Ydirt_nB, FALSE, FALSE,
4064 EL_SAND, ACTION_DIGGING, MV_BIT_UP
4067 Ydirt_eB, FALSE, FALSE,
4068 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
4071 Ydirt_sB, FALSE, FALSE,
4072 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
4075 Ydirt_wB, FALSE, FALSE,
4076 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
4079 Xacid_ne, TRUE, FALSE,
4080 EL_ACID_POOL_TOPRIGHT, -1, -1
4083 Xacid_se, TRUE, FALSE,
4084 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
4087 Xacid_s, TRUE, FALSE,
4088 EL_ACID_POOL_BOTTOM, -1, -1
4091 Xacid_sw, TRUE, FALSE,
4092 EL_ACID_POOL_BOTTOMLEFT, -1, -1
4095 Xacid_nw, TRUE, FALSE,
4096 EL_ACID_POOL_TOPLEFT, -1, -1
4099 Xacid_1, TRUE, FALSE,
4103 Xacid_2, FALSE, FALSE,
4107 Xacid_3, FALSE, FALSE,
4111 Xacid_4, FALSE, FALSE,
4115 Xacid_5, FALSE, FALSE,
4119 Xacid_6, FALSE, FALSE,
4123 Xacid_7, FALSE, FALSE,
4127 Xacid_8, FALSE, FALSE,
4131 Xball_1, TRUE, FALSE,
4132 EL_EMC_MAGIC_BALL, -1, -1
4135 Xball_1B, FALSE, FALSE,
4136 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4139 Xball_2, FALSE, FALSE,
4140 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4143 Xball_2B, FALSE, FALSE,
4144 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4147 Yball_eat, FALSE, FALSE,
4148 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
4151 Ykey_1_eat, FALSE, FALSE,
4152 EL_EM_KEY_1, ACTION_COLLECTING, -1
4155 Ykey_2_eat, FALSE, FALSE,
4156 EL_EM_KEY_2, ACTION_COLLECTING, -1
4159 Ykey_3_eat, FALSE, FALSE,
4160 EL_EM_KEY_3, ACTION_COLLECTING, -1
4163 Ykey_4_eat, FALSE, FALSE,
4164 EL_EM_KEY_4, ACTION_COLLECTING, -1
4167 Ykey_5_eat, FALSE, FALSE,
4168 EL_EMC_KEY_5, ACTION_COLLECTING, -1
4171 Ykey_6_eat, FALSE, FALSE,
4172 EL_EMC_KEY_6, ACTION_COLLECTING, -1
4175 Ykey_7_eat, FALSE, FALSE,
4176 EL_EMC_KEY_7, ACTION_COLLECTING, -1
4179 Ykey_8_eat, FALSE, FALSE,
4180 EL_EMC_KEY_8, ACTION_COLLECTING, -1
4183 Ylenses_eat, FALSE, FALSE,
4184 EL_EMC_LENSES, ACTION_COLLECTING, -1
4187 Ymagnify_eat, FALSE, FALSE,
4188 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
4191 Ygrass_eat, FALSE, FALSE,
4192 EL_EMC_GRASS, ACTION_SNAPPING, -1
4195 Ydirt_eat, FALSE, FALSE,
4196 EL_SAND, ACTION_SNAPPING, -1
4199 Xgrow_ns, TRUE, FALSE,
4200 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
4203 Ygrow_ns_eat, FALSE, FALSE,
4204 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
4207 Xgrow_ew, TRUE, FALSE,
4208 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
4211 Ygrow_ew_eat, FALSE, FALSE,
4212 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
4215 Xwonderwall, TRUE, FALSE,
4216 EL_MAGIC_WALL, -1, -1
4219 XwonderwallB, FALSE, FALSE,
4220 EL_MAGIC_WALL, ACTION_ACTIVE, -1
4223 Xamoeba_1, TRUE, FALSE,
4224 EL_AMOEBA_DRY, ACTION_OTHER, -1
4227 Xamoeba_2, FALSE, FALSE,
4228 EL_AMOEBA_DRY, ACTION_OTHER, -1
4231 Xamoeba_3, FALSE, FALSE,
4232 EL_AMOEBA_DRY, ACTION_OTHER, -1
4235 Xamoeba_4, FALSE, FALSE,
4236 EL_AMOEBA_DRY, ACTION_OTHER, -1
4239 Xamoeba_5, TRUE, FALSE,
4240 EL_AMOEBA_WET, ACTION_OTHER, -1
4243 Xamoeba_6, FALSE, FALSE,
4244 EL_AMOEBA_WET, ACTION_OTHER, -1
4247 Xamoeba_7, FALSE, FALSE,
4248 EL_AMOEBA_WET, ACTION_OTHER, -1
4251 Xamoeba_8, FALSE, FALSE,
4252 EL_AMOEBA_WET, ACTION_OTHER, -1
4255 Xdoor_1, TRUE, FALSE,
4256 EL_EM_GATE_1, -1, -1
4259 Xdoor_2, TRUE, FALSE,
4260 EL_EM_GATE_2, -1, -1
4263 Xdoor_3, TRUE, FALSE,
4264 EL_EM_GATE_3, -1, -1
4267 Xdoor_4, TRUE, FALSE,
4268 EL_EM_GATE_4, -1, -1
4271 Xdoor_5, TRUE, FALSE,
4272 EL_EMC_GATE_5, -1, -1
4275 Xdoor_6, TRUE, FALSE,
4276 EL_EMC_GATE_6, -1, -1
4279 Xdoor_7, TRUE, FALSE,
4280 EL_EMC_GATE_7, -1, -1
4283 Xdoor_8, TRUE, FALSE,
4284 EL_EMC_GATE_8, -1, -1
4287 Xkey_1, TRUE, FALSE,
4291 Xkey_2, TRUE, FALSE,
4295 Xkey_3, TRUE, FALSE,
4299 Xkey_4, TRUE, FALSE,
4303 Xkey_5, TRUE, FALSE,
4304 EL_EMC_KEY_5, -1, -1
4307 Xkey_6, TRUE, FALSE,
4308 EL_EMC_KEY_6, -1, -1
4311 Xkey_7, TRUE, FALSE,
4312 EL_EMC_KEY_7, -1, -1
4315 Xkey_8, TRUE, FALSE,
4316 EL_EMC_KEY_8, -1, -1
4319 Xwind_n, TRUE, FALSE,
4320 EL_BALLOON_SWITCH_UP, -1, -1
4323 Xwind_e, TRUE, FALSE,
4324 EL_BALLOON_SWITCH_RIGHT, -1, -1
4327 Xwind_s, TRUE, FALSE,
4328 EL_BALLOON_SWITCH_DOWN, -1, -1
4331 Xwind_w, TRUE, FALSE,
4332 EL_BALLOON_SWITCH_LEFT, -1, -1
4335 Xwind_nesw, TRUE, FALSE,
4336 EL_BALLOON_SWITCH_ANY, -1, -1
4339 Xwind_stop, TRUE, FALSE,
4340 EL_BALLOON_SWITCH_NONE, -1, -1
4344 EL_EXIT_CLOSED, -1, -1
4347 Xexit_1, TRUE, FALSE,
4348 EL_EXIT_OPEN, -1, -1
4351 Xexit_2, FALSE, FALSE,
4352 EL_EXIT_OPEN, -1, -1
4355 Xexit_3, FALSE, FALSE,
4356 EL_EXIT_OPEN, -1, -1
4359 Xdynamite, TRUE, FALSE,
4360 EL_EM_DYNAMITE, -1, -1
4363 Ydynamite_eat, FALSE, FALSE,
4364 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
4367 Xdynamite_1, TRUE, FALSE,
4368 EL_EM_DYNAMITE_ACTIVE, -1, -1
4371 Xdynamite_2, FALSE, FALSE,
4372 EL_EM_DYNAMITE_ACTIVE, -1, -1
4375 Xdynamite_3, FALSE, FALSE,
4376 EL_EM_DYNAMITE_ACTIVE, -1, -1
4379 Xdynamite_4, FALSE, FALSE,
4380 EL_EM_DYNAMITE_ACTIVE, -1, -1
4383 Xbumper, TRUE, FALSE,
4384 EL_EMC_SPRING_BUMPER, -1, -1
4387 XbumperB, FALSE, FALSE,
4388 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
4391 Xwheel, TRUE, FALSE,
4392 EL_ROBOT_WHEEL, -1, -1
4395 XwheelB, FALSE, FALSE,
4396 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
4399 Xswitch, TRUE, FALSE,
4400 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
4403 XswitchB, FALSE, FALSE,
4404 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
4408 EL_QUICKSAND_EMPTY, -1, -1
4411 Xsand_stone, TRUE, FALSE,
4412 EL_QUICKSAND_FULL, -1, -1
4415 Xsand_stonein_1, FALSE, TRUE,
4416 EL_ROCK, ACTION_FILLING, -1
4419 Xsand_stonein_2, FALSE, TRUE,
4420 EL_ROCK, ACTION_FILLING, -1
4423 Xsand_stonein_3, FALSE, TRUE,
4424 EL_ROCK, ACTION_FILLING, -1
4427 Xsand_stonein_4, FALSE, TRUE,
4428 EL_ROCK, ACTION_FILLING, -1
4431 Xsand_stonesand_1, FALSE, FALSE,
4432 EL_QUICKSAND_FULL, -1, -1
4435 Xsand_stonesand_2, FALSE, FALSE,
4436 EL_QUICKSAND_FULL, -1, -1
4439 Xsand_stonesand_3, FALSE, FALSE,
4440 EL_QUICKSAND_FULL, -1, -1
4443 Xsand_stonesand_4, FALSE, FALSE,
4444 EL_QUICKSAND_FULL, -1, -1
4447 Xsand_stoneout_1, FALSE, FALSE,
4448 EL_ROCK, ACTION_EMPTYING, -1
4451 Xsand_stoneout_2, FALSE, FALSE,
4452 EL_ROCK, ACTION_EMPTYING, -1
4455 Xsand_sandstone_1, FALSE, FALSE,
4456 EL_QUICKSAND_FULL, -1, -1
4459 Xsand_sandstone_2, FALSE, FALSE,
4460 EL_QUICKSAND_FULL, -1, -1
4463 Xsand_sandstone_3, FALSE, FALSE,
4464 EL_QUICKSAND_FULL, -1, -1
4467 Xsand_sandstone_4, FALSE, FALSE,
4468 EL_QUICKSAND_FULL, -1, -1
4471 Xplant, TRUE, FALSE,
4472 EL_EMC_PLANT, -1, -1
4475 Yplant, FALSE, FALSE,
4476 EL_EMC_PLANT, -1, -1
4479 Xlenses, TRUE, FALSE,
4480 EL_EMC_LENSES, -1, -1
4483 Xmagnify, TRUE, FALSE,
4484 EL_EMC_MAGNIFIER, -1, -1
4487 Xdripper, TRUE, FALSE,
4488 EL_EMC_DRIPPER, -1, -1
4491 XdripperB, FALSE, FALSE,
4492 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
4495 Xfake_blank, TRUE, FALSE,
4496 EL_INVISIBLE_WALL, -1, -1
4499 Xfake_blankB, FALSE, FALSE,
4500 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
4503 Xfake_grass, TRUE, FALSE,
4504 EL_EMC_FAKE_GRASS, -1, -1
4507 Xfake_grassB, FALSE, FALSE,
4508 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
4511 Xfake_door_1, TRUE, FALSE,
4512 EL_EM_GATE_1_GRAY, -1, -1
4515 Xfake_door_2, TRUE, FALSE,
4516 EL_EM_GATE_2_GRAY, -1, -1
4519 Xfake_door_3, TRUE, FALSE,
4520 EL_EM_GATE_3_GRAY, -1, -1
4523 Xfake_door_4, TRUE, FALSE,
4524 EL_EM_GATE_4_GRAY, -1, -1
4527 Xfake_door_5, TRUE, FALSE,
4528 EL_EMC_GATE_5_GRAY, -1, -1
4531 Xfake_door_6, TRUE, FALSE,
4532 EL_EMC_GATE_6_GRAY, -1, -1
4535 Xfake_door_7, TRUE, FALSE,
4536 EL_EMC_GATE_7_GRAY, -1, -1
4539 Xfake_door_8, TRUE, FALSE,
4540 EL_EMC_GATE_8_GRAY, -1, -1
4543 Xfake_acid_1, TRUE, FALSE,
4544 EL_EMC_FAKE_ACID, -1, -1
4547 Xfake_acid_2, FALSE, FALSE,
4548 EL_EMC_FAKE_ACID, -1, -1
4551 Xfake_acid_3, FALSE, FALSE,
4552 EL_EMC_FAKE_ACID, -1, -1
4555 Xfake_acid_4, FALSE, FALSE,
4556 EL_EMC_FAKE_ACID, -1, -1
4559 Xfake_acid_5, FALSE, FALSE,
4560 EL_EMC_FAKE_ACID, -1, -1
4563 Xfake_acid_6, FALSE, FALSE,
4564 EL_EMC_FAKE_ACID, -1, -1
4567 Xfake_acid_7, FALSE, FALSE,
4568 EL_EMC_FAKE_ACID, -1, -1
4571 Xfake_acid_8, FALSE, FALSE,
4572 EL_EMC_FAKE_ACID, -1, -1
4575 Xsteel_1, TRUE, FALSE,
4576 EL_STEELWALL, -1, -1
4579 Xsteel_2, TRUE, FALSE,
4580 EL_EMC_STEELWALL_2, -1, -1
4583 Xsteel_3, TRUE, FALSE,
4584 EL_EMC_STEELWALL_3, -1, -1
4587 Xsteel_4, TRUE, FALSE,
4588 EL_EMC_STEELWALL_4, -1, -1
4591 Xwall_1, TRUE, FALSE,
4595 Xwall_2, TRUE, FALSE,
4596 EL_EMC_WALL_14, -1, -1
4599 Xwall_3, TRUE, FALSE,
4600 EL_EMC_WALL_15, -1, -1
4603 Xwall_4, TRUE, FALSE,
4604 EL_EMC_WALL_16, -1, -1
4607 Xround_wall_1, TRUE, FALSE,
4608 EL_WALL_SLIPPERY, -1, -1
4611 Xround_wall_2, TRUE, FALSE,
4612 EL_EMC_WALL_SLIPPERY_2, -1, -1
4615 Xround_wall_3, TRUE, FALSE,
4616 EL_EMC_WALL_SLIPPERY_3, -1, -1
4619 Xround_wall_4, TRUE, FALSE,
4620 EL_EMC_WALL_SLIPPERY_4, -1, -1
4623 Xdecor_1, TRUE, FALSE,
4624 EL_EMC_WALL_8, -1, -1
4627 Xdecor_2, TRUE, FALSE,
4628 EL_EMC_WALL_6, -1, -1
4631 Xdecor_3, TRUE, FALSE,
4632 EL_EMC_WALL_4, -1, -1
4635 Xdecor_4, TRUE, FALSE,
4636 EL_EMC_WALL_7, -1, -1
4639 Xdecor_5, TRUE, FALSE,
4640 EL_EMC_WALL_5, -1, -1
4643 Xdecor_6, TRUE, FALSE,
4644 EL_EMC_WALL_9, -1, -1
4647 Xdecor_7, TRUE, FALSE,
4648 EL_EMC_WALL_10, -1, -1
4651 Xdecor_8, TRUE, FALSE,
4652 EL_EMC_WALL_1, -1, -1
4655 Xdecor_9, TRUE, FALSE,
4656 EL_EMC_WALL_2, -1, -1
4659 Xdecor_10, TRUE, FALSE,
4660 EL_EMC_WALL_3, -1, -1
4663 Xdecor_11, TRUE, FALSE,
4664 EL_EMC_WALL_11, -1, -1
4667 Xdecor_12, TRUE, FALSE,
4668 EL_EMC_WALL_12, -1, -1
4671 Xalpha_0, TRUE, FALSE,
4672 EL_CHAR('0'), -1, -1
4675 Xalpha_1, TRUE, FALSE,
4676 EL_CHAR('1'), -1, -1
4679 Xalpha_2, TRUE, FALSE,
4680 EL_CHAR('2'), -1, -1
4683 Xalpha_3, TRUE, FALSE,
4684 EL_CHAR('3'), -1, -1
4687 Xalpha_4, TRUE, FALSE,
4688 EL_CHAR('4'), -1, -1
4691 Xalpha_5, TRUE, FALSE,
4692 EL_CHAR('5'), -1, -1
4695 Xalpha_6, TRUE, FALSE,
4696 EL_CHAR('6'), -1, -1
4699 Xalpha_7, TRUE, FALSE,
4700 EL_CHAR('7'), -1, -1
4703 Xalpha_8, TRUE, FALSE,
4704 EL_CHAR('8'), -1, -1
4707 Xalpha_9, TRUE, FALSE,
4708 EL_CHAR('9'), -1, -1
4711 Xalpha_excla, TRUE, FALSE,
4712 EL_CHAR('!'), -1, -1
4715 Xalpha_quote, TRUE, FALSE,
4716 EL_CHAR('"'), -1, -1
4719 Xalpha_comma, TRUE, FALSE,
4720 EL_CHAR(','), -1, -1
4723 Xalpha_minus, TRUE, FALSE,
4724 EL_CHAR('-'), -1, -1
4727 Xalpha_perio, TRUE, FALSE,
4728 EL_CHAR('.'), -1, -1
4731 Xalpha_colon, TRUE, FALSE,
4732 EL_CHAR(':'), -1, -1
4735 Xalpha_quest, TRUE, FALSE,
4736 EL_CHAR('?'), -1, -1
4739 Xalpha_a, TRUE, FALSE,
4740 EL_CHAR('A'), -1, -1
4743 Xalpha_b, TRUE, FALSE,
4744 EL_CHAR('B'), -1, -1
4747 Xalpha_c, TRUE, FALSE,
4748 EL_CHAR('C'), -1, -1
4751 Xalpha_d, TRUE, FALSE,
4752 EL_CHAR('D'), -1, -1
4755 Xalpha_e, TRUE, FALSE,
4756 EL_CHAR('E'), -1, -1
4759 Xalpha_f, TRUE, FALSE,
4760 EL_CHAR('F'), -1, -1
4763 Xalpha_g, TRUE, FALSE,
4764 EL_CHAR('G'), -1, -1
4767 Xalpha_h, TRUE, FALSE,
4768 EL_CHAR('H'), -1, -1
4771 Xalpha_i, TRUE, FALSE,
4772 EL_CHAR('I'), -1, -1
4775 Xalpha_j, TRUE, FALSE,
4776 EL_CHAR('J'), -1, -1
4779 Xalpha_k, TRUE, FALSE,
4780 EL_CHAR('K'), -1, -1
4783 Xalpha_l, TRUE, FALSE,
4784 EL_CHAR('L'), -1, -1
4787 Xalpha_m, TRUE, FALSE,
4788 EL_CHAR('M'), -1, -1
4791 Xalpha_n, TRUE, FALSE,
4792 EL_CHAR('N'), -1, -1
4795 Xalpha_o, TRUE, FALSE,
4796 EL_CHAR('O'), -1, -1
4799 Xalpha_p, TRUE, FALSE,
4800 EL_CHAR('P'), -1, -1
4803 Xalpha_q, TRUE, FALSE,
4804 EL_CHAR('Q'), -1, -1
4807 Xalpha_r, TRUE, FALSE,
4808 EL_CHAR('R'), -1, -1
4811 Xalpha_s, TRUE, FALSE,
4812 EL_CHAR('S'), -1, -1
4815 Xalpha_t, TRUE, FALSE,
4816 EL_CHAR('T'), -1, -1
4819 Xalpha_u, TRUE, FALSE,
4820 EL_CHAR('U'), -1, -1
4823 Xalpha_v, TRUE, FALSE,
4824 EL_CHAR('V'), -1, -1
4827 Xalpha_w, TRUE, FALSE,
4828 EL_CHAR('W'), -1, -1
4831 Xalpha_x, TRUE, FALSE,
4832 EL_CHAR('X'), -1, -1
4835 Xalpha_y, TRUE, FALSE,
4836 EL_CHAR('Y'), -1, -1
4839 Xalpha_z, TRUE, FALSE,
4840 EL_CHAR('Z'), -1, -1
4843 Xalpha_arrow_e, TRUE, FALSE,
4844 EL_CHAR('>'), -1, -1
4847 Xalpha_arrow_w, TRUE, FALSE,
4848 EL_CHAR('<'), -1, -1
4851 Xalpha_copyr, TRUE, FALSE,
4852 EL_CHAR('©'), -1, -1
4856 Xboom_bug, FALSE, FALSE,
4857 EL_BUG, ACTION_EXPLODING, -1
4860 Xboom_bomb, FALSE, FALSE,
4861 EL_BOMB, ACTION_EXPLODING, -1
4864 Xboom_android, FALSE, FALSE,
4865 EL_EMC_ANDROID, ACTION_OTHER, -1
4868 Xboom_1, FALSE, FALSE,
4869 EL_DEFAULT, ACTION_EXPLODING, -1
4872 Xboom_2, FALSE, FALSE,
4873 EL_DEFAULT, ACTION_EXPLODING, -1
4876 Znormal, FALSE, FALSE,
4880 Zdynamite, FALSE, FALSE,
4884 Zplayer, FALSE, FALSE,
4888 ZBORDER, FALSE, FALSE,
4898 static struct Mapping_EM_to_RND_player
4907 em_player_mapping_list[] =
4911 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
4915 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
4919 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
4923 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
4927 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
4931 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
4935 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
4939 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
4943 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
4947 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
4951 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
4955 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
4959 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
4963 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
4967 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
4971 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
4975 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
4979 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
4983 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
4987 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
4991 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
4995 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
4999 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
5003 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
5007 EL_PLAYER_1, ACTION_DEFAULT, -1,
5011 EL_PLAYER_2, ACTION_DEFAULT, -1,
5015 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
5019 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
5023 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
5027 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
5031 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
5035 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
5039 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
5043 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
5047 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
5051 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
5055 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
5059 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
5063 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
5067 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
5071 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
5075 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
5079 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
5083 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
5087 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
5091 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
5095 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
5099 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
5103 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
5107 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
5111 EL_PLAYER_3, ACTION_DEFAULT, -1,
5115 EL_PLAYER_4, ACTION_DEFAULT, -1,
5124 int map_element_RND_to_EM(int element_rnd)
5126 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
5127 static boolean mapping_initialized = FALSE;
5129 if (!mapping_initialized)
5133 /* return "Xalpha_quest" for all undefined elements in mapping array */
5134 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
5135 mapping_RND_to_EM[i] = Xalpha_quest;
5137 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5138 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
5139 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
5140 em_object_mapping_list[i].element_em;
5142 mapping_initialized = TRUE;
5145 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
5146 return mapping_RND_to_EM[element_rnd];
5148 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
5153 int map_element_EM_to_RND(int element_em)
5155 static unsigned short mapping_EM_to_RND[TILE_MAX];
5156 static boolean mapping_initialized = FALSE;
5158 if (!mapping_initialized)
5162 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
5163 for (i = 0; i < TILE_MAX; i++)
5164 mapping_EM_to_RND[i] = EL_UNKNOWN;
5166 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5167 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
5168 em_object_mapping_list[i].element_rnd;
5170 mapping_initialized = TRUE;
5173 if (element_em >= 0 && element_em < TILE_MAX)
5174 return mapping_EM_to_RND[element_em];
5176 Error(ERR_WARN, "invalid EM level element %d", element_em);
5181 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
5183 struct LevelInfo_EM *level_em = level->native_em_level;
5184 struct LEVEL *lev = level_em->lev;
5187 for (i = 0; i < TILE_MAX; i++)
5188 lev->android_array[i] = Xblank;
5190 for (i = 0; i < level->num_android_clone_elements; i++)
5192 int element_rnd = level->android_clone_element[i];
5193 int element_em = map_element_RND_to_EM(element_rnd);
5195 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
5196 if (em_object_mapping_list[j].element_rnd == element_rnd)
5197 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
5201 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
5203 struct LevelInfo_EM *level_em = level->native_em_level;
5204 struct LEVEL *lev = level_em->lev;
5207 level->num_android_clone_elements = 0;
5209 for (i = 0; i < TILE_MAX; i++)
5211 int element_em = lev->android_array[i];
5213 boolean element_found = FALSE;
5215 if (element_em == Xblank)
5218 element_rnd = map_element_EM_to_RND(element_em);
5220 for (j = 0; j < level->num_android_clone_elements; j++)
5221 if (level->android_clone_element[j] == element_rnd)
5222 element_found = TRUE;
5226 level->android_clone_element[level->num_android_clone_elements++] =
5229 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
5234 if (level->num_android_clone_elements == 0)
5236 level->num_android_clone_elements = 1;
5237 level->android_clone_element[0] = EL_EMPTY;
5241 int map_direction_RND_to_EM(int direction)
5243 return (direction == MV_UP ? 0 :
5244 direction == MV_RIGHT ? 1 :
5245 direction == MV_DOWN ? 2 :
5246 direction == MV_LEFT ? 3 :
5250 int map_direction_EM_to_RND(int direction)
5252 return (direction == 0 ? MV_UP :
5253 direction == 1 ? MV_RIGHT :
5254 direction == 2 ? MV_DOWN :
5255 direction == 3 ? MV_LEFT :
5259 int get_next_element(int element)
5263 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
5264 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
5265 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
5266 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
5267 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
5268 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
5269 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
5271 default: return element;
5276 int el_act_dir2img(int element, int action, int direction)
5278 element = GFX_ELEMENT(element);
5280 if (direction == MV_NONE)
5281 return element_info[element].graphic[action];
5283 direction = MV_DIR_TO_BIT(direction);
5285 return element_info[element].direction_graphic[action][direction];
5288 int el_act_dir2img(int element, int action, int direction)
5290 element = GFX_ELEMENT(element);
5291 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5293 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5294 return element_info[element].direction_graphic[action][direction];
5299 static int el_act_dir2crm(int element, int action, int direction)
5301 element = GFX_ELEMENT(element);
5303 if (direction == MV_NONE)
5304 return element_info[element].crumbled[action];
5306 direction = MV_DIR_TO_BIT(direction);
5308 return element_info[element].direction_crumbled[action][direction];
5311 static int el_act_dir2crm(int element, int action, int direction)
5313 element = GFX_ELEMENT(element);
5314 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5316 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5317 return element_info[element].direction_crumbled[action][direction];
5321 int el_act2img(int element, int action)
5323 element = GFX_ELEMENT(element);
5325 return element_info[element].graphic[action];
5328 int el_act2crm(int element, int action)
5330 element = GFX_ELEMENT(element);
5332 return element_info[element].crumbled[action];
5335 int el_dir2img(int element, int direction)
5337 element = GFX_ELEMENT(element);
5339 return el_act_dir2img(element, ACTION_DEFAULT, direction);
5342 int el2baseimg(int element)
5344 return element_info[element].graphic[ACTION_DEFAULT];
5347 int el2img(int element)
5349 element = GFX_ELEMENT(element);
5351 return element_info[element].graphic[ACTION_DEFAULT];
5354 int el2edimg(int element)
5356 element = GFX_ELEMENT(element);
5358 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
5361 int el2preimg(int element)
5363 element = GFX_ELEMENT(element);
5365 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
5368 int font2baseimg(int font_nr)
5370 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
5373 int getNumActivePlayers_EM()
5375 int num_players = 0;
5381 for (i = 0; i < MAX_PLAYERS; i++)
5382 if (tape.player_participates[i])
5388 int getGameFrameDelay_EM(int native_em_game_frame_delay)
5390 int game_frame_delay_value;
5392 game_frame_delay_value =
5393 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
5394 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
5397 if (tape.playing && tape.warp_forward && !tape.pausing)
5398 game_frame_delay_value = 0;
5400 return game_frame_delay_value;
5403 unsigned int InitRND(long seed)
5405 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
5406 return InitEngineRandom_EM(seed);
5408 return InitEngineRandom_RND(seed);
5411 void InitGraphicInfo_EM(void)
5413 struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
5414 struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
5418 int num_em_gfx_errors = 0;
5420 if (graphic_info_em_object[0][0].bitmap == NULL)
5422 /* EM graphics not yet initialized in em_open_all() */
5427 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
5430 /* always start with reliable default values */
5431 for (i = 0; i < TILE_MAX; i++)
5433 object_mapping[i].element_rnd = EL_UNKNOWN;
5434 object_mapping[i].is_backside = FALSE;
5435 object_mapping[i].action = ACTION_DEFAULT;
5436 object_mapping[i].direction = MV_NONE;
5439 /* always start with reliable default values */
5440 for (p = 0; p < MAX_PLAYERS; p++)
5442 for (i = 0; i < SPR_MAX; i++)
5444 player_mapping[p][i].element_rnd = EL_UNKNOWN;
5445 player_mapping[p][i].action = ACTION_DEFAULT;
5446 player_mapping[p][i].direction = MV_NONE;
5450 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5452 int e = em_object_mapping_list[i].element_em;
5454 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
5455 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
5457 if (em_object_mapping_list[i].action != -1)
5458 object_mapping[e].action = em_object_mapping_list[i].action;
5460 if (em_object_mapping_list[i].direction != -1)
5461 object_mapping[e].direction =
5462 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
5465 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
5467 int a = em_player_mapping_list[i].action_em;
5468 int p = em_player_mapping_list[i].player_nr;
5470 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
5472 if (em_player_mapping_list[i].action != -1)
5473 player_mapping[p][a].action = em_player_mapping_list[i].action;
5475 if (em_player_mapping_list[i].direction != -1)
5476 player_mapping[p][a].direction =
5477 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
5480 for (i = 0; i < TILE_MAX; i++)
5482 int element = object_mapping[i].element_rnd;
5483 int action = object_mapping[i].action;
5484 int direction = object_mapping[i].direction;
5485 boolean is_backside = object_mapping[i].is_backside;
5486 boolean action_removing = (action == ACTION_DIGGING ||
5487 action == ACTION_SNAPPING ||
5488 action == ACTION_COLLECTING);
5489 boolean action_exploding = ((action == ACTION_EXPLODING ||
5490 action == ACTION_SMASHED_BY_ROCK ||
5491 action == ACTION_SMASHED_BY_SPRING) &&
5492 element != EL_DIAMOND);
5493 boolean action_active = (action == ACTION_ACTIVE);
5494 boolean action_other = (action == ACTION_OTHER);
5496 for (j = 0; j < 8; j++)
5498 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
5499 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
5501 i == Xdrip_stretch ? element :
5502 i == Xdrip_stretchB ? element :
5503 i == Ydrip_s1 ? element :
5504 i == Ydrip_s1B ? element :
5505 i == Xball_1B ? element :
5506 i == Xball_2 ? element :
5507 i == Xball_2B ? element :
5508 i == Yball_eat ? element :
5509 i == Ykey_1_eat ? element :
5510 i == Ykey_2_eat ? element :
5511 i == Ykey_3_eat ? element :
5512 i == Ykey_4_eat ? element :
5513 i == Ykey_5_eat ? element :
5514 i == Ykey_6_eat ? element :
5515 i == Ykey_7_eat ? element :
5516 i == Ykey_8_eat ? element :
5517 i == Ylenses_eat ? element :
5518 i == Ymagnify_eat ? element :
5519 i == Ygrass_eat ? element :
5520 i == Ydirt_eat ? element :
5521 i == Yemerald_stone ? EL_EMERALD :
5522 i == Ydiamond_stone ? EL_ROCK :
5523 i == Xsand_stonein_1 ? element :
5524 i == Xsand_stonein_2 ? element :
5525 i == Xsand_stonein_3 ? element :
5526 i == Xsand_stonein_4 ? element :
5527 is_backside ? EL_EMPTY :
5528 action_removing ? EL_EMPTY :
5530 int effective_action = (j < 7 ? action :
5531 i == Xdrip_stretch ? action :
5532 i == Xdrip_stretchB ? action :
5533 i == Ydrip_s1 ? action :
5534 i == Ydrip_s1B ? action :
5535 i == Xball_1B ? action :
5536 i == Xball_2 ? action :
5537 i == Xball_2B ? action :
5538 i == Yball_eat ? action :
5539 i == Ykey_1_eat ? action :
5540 i == Ykey_2_eat ? action :
5541 i == Ykey_3_eat ? action :
5542 i == Ykey_4_eat ? action :
5543 i == Ykey_5_eat ? action :
5544 i == Ykey_6_eat ? action :
5545 i == Ykey_7_eat ? action :
5546 i == Ykey_8_eat ? action :
5547 i == Ylenses_eat ? action :
5548 i == Ymagnify_eat ? action :
5549 i == Ygrass_eat ? action :
5550 i == Ydirt_eat ? action :
5551 i == Xsand_stonein_1 ? action :
5552 i == Xsand_stonein_2 ? action :
5553 i == Xsand_stonein_3 ? action :
5554 i == Xsand_stonein_4 ? action :
5555 i == Xsand_stoneout_1 ? action :
5556 i == Xsand_stoneout_2 ? action :
5557 i == Xboom_android ? ACTION_EXPLODING :
5558 action_exploding ? ACTION_EXPLODING :
5559 action_active ? action :
5560 action_other ? action :
5562 int graphic = (el_act_dir2img(effective_element, effective_action,
5564 int crumbled = (el_act_dir2crm(effective_element, effective_action,
5566 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
5567 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
5568 boolean has_action_graphics = (graphic != base_graphic);
5569 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
5570 struct GraphicInfo *g = &graphic_info[graphic];
5571 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
5574 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
5575 boolean special_animation = (action != ACTION_DEFAULT &&
5576 g->anim_frames == 3 &&
5577 g->anim_delay == 2 &&
5578 g->anim_mode & ANIM_LINEAR);
5579 int sync_frame = (i == Xdrip_stretch ? 7 :
5580 i == Xdrip_stretchB ? 7 :
5581 i == Ydrip_s2 ? j + 8 :
5582 i == Ydrip_s2B ? j + 8 :
5591 i == Xfake_acid_1 ? 0 :
5592 i == Xfake_acid_2 ? 10 :
5593 i == Xfake_acid_3 ? 20 :
5594 i == Xfake_acid_4 ? 30 :
5595 i == Xfake_acid_5 ? 40 :
5596 i == Xfake_acid_6 ? 50 :
5597 i == Xfake_acid_7 ? 60 :
5598 i == Xfake_acid_8 ? 70 :
5600 i == Xball_2B ? j + 8 :
5601 i == Yball_eat ? j + 1 :
5602 i == Ykey_1_eat ? j + 1 :
5603 i == Ykey_2_eat ? j + 1 :
5604 i == Ykey_3_eat ? j + 1 :
5605 i == Ykey_4_eat ? j + 1 :
5606 i == Ykey_5_eat ? j + 1 :
5607 i == Ykey_6_eat ? j + 1 :
5608 i == Ykey_7_eat ? j + 1 :
5609 i == Ykey_8_eat ? j + 1 :
5610 i == Ylenses_eat ? j + 1 :
5611 i == Ymagnify_eat ? j + 1 :
5612 i == Ygrass_eat ? j + 1 :
5613 i == Ydirt_eat ? j + 1 :
5614 i == Xamoeba_1 ? 0 :
5615 i == Xamoeba_2 ? 1 :
5616 i == Xamoeba_3 ? 2 :
5617 i == Xamoeba_4 ? 3 :
5618 i == Xamoeba_5 ? 0 :
5619 i == Xamoeba_6 ? 1 :
5620 i == Xamoeba_7 ? 2 :
5621 i == Xamoeba_8 ? 3 :
5622 i == Xexit_2 ? j + 8 :
5623 i == Xexit_3 ? j + 16 :
5624 i == Xdynamite_1 ? 0 :
5625 i == Xdynamite_2 ? 8 :
5626 i == Xdynamite_3 ? 16 :
5627 i == Xdynamite_4 ? 24 :
5628 i == Xsand_stonein_1 ? j + 1 :
5629 i == Xsand_stonein_2 ? j + 9 :
5630 i == Xsand_stonein_3 ? j + 17 :
5631 i == Xsand_stonein_4 ? j + 25 :
5632 i == Xsand_stoneout_1 && j == 0 ? 0 :
5633 i == Xsand_stoneout_1 && j == 1 ? 0 :
5634 i == Xsand_stoneout_1 && j == 2 ? 1 :
5635 i == Xsand_stoneout_1 && j == 3 ? 2 :
5636 i == Xsand_stoneout_1 && j == 4 ? 2 :
5637 i == Xsand_stoneout_1 && j == 5 ? 3 :
5638 i == Xsand_stoneout_1 && j == 6 ? 4 :
5639 i == Xsand_stoneout_1 && j == 7 ? 4 :
5640 i == Xsand_stoneout_2 && j == 0 ? 5 :
5641 i == Xsand_stoneout_2 && j == 1 ? 6 :
5642 i == Xsand_stoneout_2 && j == 2 ? 7 :
5643 i == Xsand_stoneout_2 && j == 3 ? 8 :
5644 i == Xsand_stoneout_2 && j == 4 ? 9 :
5645 i == Xsand_stoneout_2 && j == 5 ? 11 :
5646 i == Xsand_stoneout_2 && j == 6 ? 13 :
5647 i == Xsand_stoneout_2 && j == 7 ? 15 :
5648 i == Xboom_bug && j == 1 ? 2 :
5649 i == Xboom_bug && j == 2 ? 2 :
5650 i == Xboom_bug && j == 3 ? 4 :
5651 i == Xboom_bug && j == 4 ? 4 :
5652 i == Xboom_bug && j == 5 ? 2 :
5653 i == Xboom_bug && j == 6 ? 2 :
5654 i == Xboom_bug && j == 7 ? 0 :
5655 i == Xboom_bomb && j == 1 ? 2 :
5656 i == Xboom_bomb && j == 2 ? 2 :
5657 i == Xboom_bomb && j == 3 ? 4 :
5658 i == Xboom_bomb && j == 4 ? 4 :
5659 i == Xboom_bomb && j == 5 ? 2 :
5660 i == Xboom_bomb && j == 6 ? 2 :
5661 i == Xboom_bomb && j == 7 ? 0 :
5662 i == Xboom_android && j == 7 ? 6 :
5663 i == Xboom_1 && j == 1 ? 2 :
5664 i == Xboom_1 && j == 2 ? 2 :
5665 i == Xboom_1 && j == 3 ? 4 :
5666 i == Xboom_1 && j == 4 ? 4 :
5667 i == Xboom_1 && j == 5 ? 6 :
5668 i == Xboom_1 && j == 6 ? 6 :
5669 i == Xboom_1 && j == 7 ? 8 :
5670 i == Xboom_2 && j == 0 ? 8 :
5671 i == Xboom_2 && j == 1 ? 8 :
5672 i == Xboom_2 && j == 2 ? 10 :
5673 i == Xboom_2 && j == 3 ? 10 :
5674 i == Xboom_2 && j == 4 ? 10 :
5675 i == Xboom_2 && j == 5 ? 12 :
5676 i == Xboom_2 && j == 6 ? 12 :
5677 i == Xboom_2 && j == 7 ? 12 :
5678 special_animation && j == 4 ? 3 :
5679 effective_action != action ? 0 :
5683 Bitmap *debug_bitmap = g_em->bitmap;
5684 int debug_src_x = g_em->src_x;
5685 int debug_src_y = g_em->src_y;
5688 int frame = getAnimationFrame(g->anim_frames,
5691 g->anim_start_frame,
5694 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
5695 g->double_movement && is_backside);
5697 g_em->bitmap = src_bitmap;
5698 g_em->src_x = src_x;
5699 g_em->src_y = src_y;
5700 g_em->src_offset_x = 0;
5701 g_em->src_offset_y = 0;
5702 g_em->dst_offset_x = 0;
5703 g_em->dst_offset_y = 0;
5704 g_em->width = TILEX;
5705 g_em->height = TILEY;
5707 g_em->crumbled_bitmap = NULL;
5708 g_em->crumbled_src_x = 0;
5709 g_em->crumbled_src_y = 0;
5710 g_em->crumbled_border_size = 0;
5712 g_em->has_crumbled_graphics = FALSE;
5713 g_em->preserve_background = FALSE;
5716 if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
5717 printf("::: empty crumbled: %d [%s], %d, %d\n",
5718 effective_element, element_info[effective_element].token_name,
5719 effective_action, direction);
5722 /* if element can be crumbled, but certain action graphics are just empty
5723 space (like snapping sand with the original R'n'D graphics), do not
5724 treat these empty space graphics as crumbled graphics in EMC engine */
5725 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
5727 getGraphicSource(crumbled, frame, &src_bitmap, &src_x, &src_y);
5729 g_em->has_crumbled_graphics = TRUE;
5730 g_em->crumbled_bitmap = src_bitmap;
5731 g_em->crumbled_src_x = src_x;
5732 g_em->crumbled_src_y = src_y;
5733 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
5737 if (element == EL_ROCK &&
5738 effective_action == ACTION_FILLING)
5739 printf("::: has_action_graphics == %d\n", has_action_graphics);
5742 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
5743 effective_action == ACTION_MOVING ||
5744 effective_action == ACTION_PUSHING ||
5745 effective_action == ACTION_EATING)) ||
5746 (!has_action_graphics && (effective_action == ACTION_FILLING ||
5747 effective_action == ACTION_EMPTYING)))
5750 (effective_action == ACTION_FALLING ||
5751 effective_action == ACTION_FILLING ||
5752 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
5753 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
5754 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
5755 int num_steps = (i == Ydrip_s1 ? 16 :
5756 i == Ydrip_s1B ? 16 :
5757 i == Ydrip_s2 ? 16 :
5758 i == Ydrip_s2B ? 16 :
5759 i == Xsand_stonein_1 ? 32 :
5760 i == Xsand_stonein_2 ? 32 :
5761 i == Xsand_stonein_3 ? 32 :
5762 i == Xsand_stonein_4 ? 32 :
5763 i == Xsand_stoneout_1 ? 16 :
5764 i == Xsand_stoneout_2 ? 16 : 8);
5765 int cx = ABS(dx) * (TILEX / num_steps);
5766 int cy = ABS(dy) * (TILEY / num_steps);
5767 int step_frame = (i == Ydrip_s2 ? j + 8 :
5768 i == Ydrip_s2B ? j + 8 :
5769 i == Xsand_stonein_2 ? j + 8 :
5770 i == Xsand_stonein_3 ? j + 16 :
5771 i == Xsand_stonein_4 ? j + 24 :
5772 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
5773 int step = (is_backside ? step_frame : num_steps - step_frame);
5775 if (is_backside) /* tile where movement starts */
5777 if (dx < 0 || dy < 0)
5779 g_em->src_offset_x = cx * step;
5780 g_em->src_offset_y = cy * step;
5784 g_em->dst_offset_x = cx * step;
5785 g_em->dst_offset_y = cy * step;
5788 else /* tile where movement ends */
5790 if (dx < 0 || dy < 0)
5792 g_em->dst_offset_x = cx * step;
5793 g_em->dst_offset_y = cy * step;
5797 g_em->src_offset_x = cx * step;
5798 g_em->src_offset_y = cy * step;
5802 g_em->width = TILEX - cx * step;
5803 g_em->height = TILEY - cy * step;
5806 /* create unique graphic identifier to decide if tile must be redrawn */
5807 /* bit 31 - 16 (16 bit): EM style graphic
5808 bit 15 - 12 ( 4 bit): EM style frame
5809 bit 11 - 6 ( 6 bit): graphic width
5810 bit 5 - 0 ( 6 bit): graphic height */
5811 g_em->unique_identifier =
5812 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
5816 /* skip check for EMC elements not contained in original EMC artwork */
5817 if (element == EL_EMC_FAKE_ACID)
5820 if (g_em->bitmap != debug_bitmap ||
5821 g_em->src_x != debug_src_x ||
5822 g_em->src_y != debug_src_y ||
5823 g_em->src_offset_x != 0 ||
5824 g_em->src_offset_y != 0 ||
5825 g_em->dst_offset_x != 0 ||
5826 g_em->dst_offset_y != 0 ||
5827 g_em->width != TILEX ||
5828 g_em->height != TILEY)
5830 static int last_i = -1;
5838 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
5839 i, element, element_info[element].token_name,
5840 element_action_info[effective_action].suffix, direction);
5842 if (element != effective_element)
5843 printf(" [%d ('%s')]",
5845 element_info[effective_element].token_name);
5849 if (g_em->bitmap != debug_bitmap)
5850 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
5851 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
5853 if (g_em->src_x != debug_src_x ||
5854 g_em->src_y != debug_src_y)
5855 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
5856 j, (is_backside ? 'B' : 'F'),
5857 g_em->src_x, g_em->src_y,
5858 g_em->src_x / 32, g_em->src_y / 32,
5859 debug_src_x, debug_src_y,
5860 debug_src_x / 32, debug_src_y / 32);
5862 if (g_em->src_offset_x != 0 ||
5863 g_em->src_offset_y != 0 ||
5864 g_em->dst_offset_x != 0 ||
5865 g_em->dst_offset_y != 0)
5866 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
5868 g_em->src_offset_x, g_em->src_offset_y,
5869 g_em->dst_offset_x, g_em->dst_offset_y);
5871 if (g_em->width != TILEX ||
5872 g_em->height != TILEY)
5873 printf(" %d (%d): size %d,%d should be %d,%d\n",
5875 g_em->width, g_em->height, TILEX, TILEY);
5877 num_em_gfx_errors++;
5884 for (i = 0; i < TILE_MAX; i++)
5886 for (j = 0; j < 8; j++)
5888 int element = object_mapping[i].element_rnd;
5889 int action = object_mapping[i].action;
5890 int direction = object_mapping[i].direction;
5891 boolean is_backside = object_mapping[i].is_backside;
5892 int graphic_action = el_act_dir2img(element, action, direction);
5893 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
5895 if ((action == ACTION_SMASHED_BY_ROCK ||
5896 action == ACTION_SMASHED_BY_SPRING ||
5897 action == ACTION_EATING) &&
5898 graphic_action == graphic_default)
5900 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
5901 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
5902 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
5903 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
5906 /* no separate animation for "smashed by rock" -- use rock instead */
5907 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
5908 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
5910 g_em->bitmap = g_xx->bitmap;
5911 g_em->src_x = g_xx->src_x;
5912 g_em->src_y = g_xx->src_y;
5913 g_em->src_offset_x = g_xx->src_offset_x;
5914 g_em->src_offset_y = g_xx->src_offset_y;
5915 g_em->dst_offset_x = g_xx->dst_offset_x;
5916 g_em->dst_offset_y = g_xx->dst_offset_y;
5917 g_em->width = g_xx->width;
5918 g_em->height = g_xx->height;
5919 g_em->unique_identifier = g_xx->unique_identifier;
5922 g_em->preserve_background = TRUE;
5927 for (p = 0; p < MAX_PLAYERS; p++)
5929 for (i = 0; i < SPR_MAX; i++)
5931 int element = player_mapping[p][i].element_rnd;
5932 int action = player_mapping[p][i].action;
5933 int direction = player_mapping[p][i].direction;
5935 for (j = 0; j < 8; j++)
5937 int effective_element = element;
5938 int effective_action = action;
5939 int graphic = (direction == MV_NONE ?
5940 el_act2img(effective_element, effective_action) :
5941 el_act_dir2img(effective_element, effective_action,
5943 struct GraphicInfo *g = &graphic_info[graphic];
5944 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
5950 Bitmap *debug_bitmap = g_em->bitmap;
5951 int debug_src_x = g_em->src_x;
5952 int debug_src_y = g_em->src_y;
5955 int frame = getAnimationFrame(g->anim_frames,
5958 g->anim_start_frame,
5961 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x,&src_y, FALSE);
5963 g_em->bitmap = src_bitmap;
5964 g_em->src_x = src_x;
5965 g_em->src_y = src_y;
5966 g_em->src_offset_x = 0;
5967 g_em->src_offset_y = 0;
5968 g_em->dst_offset_x = 0;
5969 g_em->dst_offset_y = 0;
5970 g_em->width = TILEX;
5971 g_em->height = TILEY;
5975 /* skip check for EMC elements not contained in original EMC artwork */
5976 if (element == EL_PLAYER_3 ||
5977 element == EL_PLAYER_4)
5980 if (g_em->bitmap != debug_bitmap ||
5981 g_em->src_x != debug_src_x ||
5982 g_em->src_y != debug_src_y)
5984 static int last_i = -1;
5992 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
5993 p, i, element, element_info[element].token_name,
5994 element_action_info[effective_action].suffix, direction);
5996 if (element != effective_element)
5997 printf(" [%d ('%s')]",
5999 element_info[effective_element].token_name);
6003 if (g_em->bitmap != debug_bitmap)
6004 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
6005 j, (int)(g_em->bitmap), (int)(debug_bitmap));
6007 if (g_em->src_x != debug_src_x ||
6008 g_em->src_y != debug_src_y)
6009 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
6011 g_em->src_x, g_em->src_y,
6012 g_em->src_x / 32, g_em->src_y / 32,
6013 debug_src_x, debug_src_y,
6014 debug_src_x / 32, debug_src_y / 32);
6016 num_em_gfx_errors++;
6026 printf("::: [%d errors found]\n", num_em_gfx_errors);
6032 void PlayMenuSound()
6034 int sound = menu.sound[game_status];
6036 if (sound == SND_UNDEFINED)
6039 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6040 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6043 if (IS_LOOP_SOUND(sound))
6044 PlaySoundLoop(sound);
6049 void PlayMenuSoundStereo(int sound, int stereo_position)
6051 if (sound == SND_UNDEFINED)
6054 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6055 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6058 if (IS_LOOP_SOUND(sound))
6059 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
6061 PlaySoundStereo(sound, stereo_position);
6064 void PlayMenuSoundIfLoop()
6066 int sound = menu.sound[game_status];
6068 if (sound == SND_UNDEFINED)
6071 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6072 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6075 if (IS_LOOP_SOUND(sound))
6076 PlaySoundLoop(sound);
6079 void PlayMenuMusic()
6081 int music = menu.music[game_status];
6083 if (music == MUS_UNDEFINED)
6089 void ToggleFullscreenIfNeeded()
6091 boolean change_fullscreen = (setup.fullscreen !=
6092 video.fullscreen_enabled);
6093 boolean change_fullscreen_mode = (video.fullscreen_enabled &&
6094 !strEqual(setup.fullscreen_mode,
6095 video.fullscreen_mode_current));
6097 if (!video.fullscreen_available)
6101 if (change_fullscreen || change_fullscreen_mode)
6103 if (setup.fullscreen != video.fullscreen_enabled ||
6104 setup.fullscreen_mode != video.fullscreen_mode_current)
6107 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
6109 /* save backbuffer content which gets lost when toggling fullscreen mode */
6110 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6113 if (change_fullscreen_mode)
6115 if (setup.fullscreen && video.fullscreen_enabled)
6118 /* keep fullscreen, but change fullscreen mode (screen resolution) */
6120 /* (this is now set in sdl.c) */
6122 video.fullscreen_mode_current = setup.fullscreen_mode;
6124 video.fullscreen_enabled = FALSE; /* force new fullscreen mode */
6127 /* toggle fullscreen */
6128 ChangeVideoModeIfNeeded(setup.fullscreen);
6130 setup.fullscreen = video.fullscreen_enabled;
6132 /* restore backbuffer content from temporary backbuffer backup bitmap */
6133 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6135 FreeBitmap(tmp_backbuffer);
6138 /* update visible window/screen */
6139 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6141 redraw_mask = REDRAW_ALL;