1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back! *
3 *----------------------------------------------------------*
4 * (c) 1995-2006 Artsoft Entertainment *
6 * Detmolder Strasse 189 *
9 * e-mail: info@artsoft.org *
10 *----------------------------------------------------------*
12 ***********************************************************/
14 #include "libgame/libgame.h"
24 /* select level set with EMC X11 graphics before activating EM GFX debugging */
25 #define DEBUG_EM_GFX 0
27 /* tool button identifiers */
28 #define TOOL_CTRL_ID_YES 0
29 #define TOOL_CTRL_ID_NO 1
30 #define TOOL_CTRL_ID_CONFIRM 2
31 #define TOOL_CTRL_ID_PLAYER_1 3
32 #define TOOL_CTRL_ID_PLAYER_2 4
33 #define TOOL_CTRL_ID_PLAYER_3 5
34 #define TOOL_CTRL_ID_PLAYER_4 6
36 #define NUM_TOOL_BUTTONS 7
38 /* forward declaration for internal use */
39 static void UnmapToolButtons();
40 static void HandleToolButtons(struct GadgetInfo *);
41 static int el_act_dir2crm(int, int, int);
42 static int el_act2crm(int, int);
44 static struct GadgetInfo *tool_gadget[NUM_TOOL_BUTTONS];
45 static int request_gadget_id = -1;
47 static char *print_if_not_empty(int element)
49 static char *s = NULL;
50 char *token_name = element_info[element].token_name;
55 s = checked_malloc(strlen(token_name) + 10 + 1);
57 if (element != EL_EMPTY)
58 sprintf(s, "%d\t['%s']", element, token_name);
60 sprintf(s, "%d", element);
65 void DumpTile(int x, int y)
70 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
77 printf("Field Info: SCREEN(%d, %d), LEVEL(%d, %d)\n", sx, sy, x, y);
80 if (!IN_LEV_FIELD(x, y))
82 printf("(not in level field)\n");
88 printf(" Feld: %d\t['%s']\n", Feld[x][y],
89 element_info[Feld[x][y]].token_name);
90 printf(" Back: %s\n", print_if_not_empty(Back[x][y]));
91 printf(" Store: %s\n", print_if_not_empty(Store[x][y]));
92 printf(" Store2: %s\n", print_if_not_empty(Store2[x][y]));
93 printf(" StorePlayer: %s\n", print_if_not_empty(StorePlayer[x][y]));
94 printf(" MovPos: %d\n", MovPos[x][y]);
95 printf(" MovDir: %d\n", MovDir[x][y]);
96 printf(" MovDelay: %d\n", MovDelay[x][y]);
97 printf(" ChangeDelay: %d\n", ChangeDelay[x][y]);
98 printf(" CustomValue: %d\n", CustomValue[x][y]);
99 printf(" GfxElement: %d\n", GfxElement[x][y]);
100 printf(" GfxAction: %d\n", GfxAction[x][y]);
101 printf(" GfxFrame: %d\n", GfxFrame[x][y]);
105 void SetDrawtoField(int mode)
107 if (mode == DRAW_BUFFERED && setup.soft_scrolling)
118 drawto_field = fieldbuffer;
120 else /* DRAW_DIRECT, DRAW_BACKBUFFER */
126 BX2 = SCR_FIELDX - 1;
127 BY2 = SCR_FIELDY - 1;
131 drawto_field = (mode == DRAW_DIRECT ? window : backbuffer);
135 void RedrawPlayfield(boolean force_redraw, int x, int y, int width, int height)
137 if (game_status == GAME_MODE_PLAYING &&
138 level.game_engine_type == GAME_ENGINE_TYPE_EM)
140 /* currently there is no partial redraw -- always redraw whole playfield */
141 RedrawPlayfield_EM(TRUE);
143 /* blit playfield from scroll buffer to normal back buffer for fading in */
144 BlitScreenToBitmap_EM(backbuffer);
146 else if (game_status == GAME_MODE_PLAYING && !game.envelope_active)
152 width = gfx.sxsize + 2 * TILEX;
153 height = gfx.sysize + 2 * TILEY;
156 if (force_redraw || setup.direct_draw)
159 int x1 = (x - SX) / TILEX, y1 = (y - SY) / TILEY;
160 int x2 = (x - SX + width) / TILEX, y2 = (y - SY + height) / TILEY;
162 if (setup.direct_draw)
163 SetDrawtoField(DRAW_BACKBUFFER);
165 for (xx = BX1; xx <= BX2; xx++)
166 for (yy = BY1; yy <= BY2; yy++)
167 if (xx >= x1 && xx <= x2 && yy >= y1 && yy <= y2)
168 DrawScreenField(xx, yy);
171 if (setup.direct_draw)
172 SetDrawtoField(DRAW_DIRECT);
175 if (setup.soft_scrolling)
177 int fx = FX, fy = FY;
179 fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0);
180 fy += (ScreenMovDir & (MV_UP|MV_DOWN) ? ScreenGfxPos : 0);
182 BlitBitmap(fieldbuffer, backbuffer, fx,fy, SXSIZE,SYSIZE, SX,SY);
194 BlitBitmap(drawto, window, x, y, width, height, x, y);
197 void DrawMaskedBorder_Rect(int x, int y, int width, int height)
199 Bitmap *bitmap = graphic_info[IMG_GLOBAL_BORDER].bitmap;
201 SetClipOrigin(bitmap, bitmap->stored_clip_gc, 0, 0);
202 BlitBitmapMasked(bitmap, backbuffer, x, y, width, height, x, y);
205 void DrawMaskedBorder_FIELD()
207 if (game_status >= GAME_MODE_TITLE &&
208 game_status <= GAME_MODE_PLAYING &&
209 border.draw_masked[game_status])
210 DrawMaskedBorder_Rect(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
213 void DrawMaskedBorder_DOOR_1()
215 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
216 (game_status != GAME_MODE_EDITOR ||
217 border.draw_masked[GFX_SPECIAL_ARG_EDITOR]))
218 DrawMaskedBorder_Rect(DX, DY, DXSIZE, DYSIZE);
221 void DrawMaskedBorder_DOOR_2()
223 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
224 game_status != GAME_MODE_EDITOR)
225 DrawMaskedBorder_Rect(VX, VY, VXSIZE, VYSIZE);
228 void DrawMaskedBorder_DOOR_3()
230 /* currently not available */
233 void DrawMaskedBorder_ALL()
235 DrawMaskedBorder_FIELD();
236 DrawMaskedBorder_DOOR_1();
237 DrawMaskedBorder_DOOR_2();
238 DrawMaskedBorder_DOOR_3();
241 void DrawMaskedBorder(int redraw_mask)
243 if (redraw_mask & REDRAW_ALL)
244 DrawMaskedBorder_ALL();
247 if (redraw_mask & REDRAW_FIELD)
248 DrawMaskedBorder_FIELD();
249 if (redraw_mask & REDRAW_DOOR_1)
250 DrawMaskedBorder_DOOR_1();
251 if (redraw_mask & REDRAW_DOOR_2)
252 DrawMaskedBorder_DOOR_2();
253 if (redraw_mask & REDRAW_DOOR_3)
254 DrawMaskedBorder_DOOR_3();
261 DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
263 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
264 redraw_mask &= ~REDRAW_MAIN;
266 if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD)
267 redraw_mask |= REDRAW_FIELD;
269 if (redraw_mask & REDRAW_FIELD)
270 redraw_mask &= ~REDRAW_TILES;
272 if (redraw_mask == REDRAW_NONE)
275 if (redraw_mask & REDRAW_TILES &&
276 game_status == GAME_MODE_PLAYING &&
277 border.draw_masked[game_status])
278 redraw_mask |= REDRAW_FIELD;
280 if (global.fps_slowdown && game_status == GAME_MODE_PLAYING)
282 static boolean last_frame_skipped = FALSE;
283 boolean skip_even_when_not_scrolling = TRUE;
284 boolean just_scrolling = (ScreenMovDir != 0);
285 boolean verbose = FALSE;
287 if (global.fps_slowdown_factor > 1 &&
288 (FrameCounter % global.fps_slowdown_factor) &&
289 (just_scrolling || skip_even_when_not_scrolling))
291 redraw_mask &= ~REDRAW_MAIN;
293 last_frame_skipped = TRUE;
296 printf("FRAME SKIPPED\n");
300 if (last_frame_skipped)
301 redraw_mask |= REDRAW_FIELD;
303 last_frame_skipped = FALSE;
306 printf("frame not skipped\n");
310 /* synchronize X11 graphics at this point; if we would synchronize the
311 display immediately after the buffer switching (after the XFlush),
312 this could mean that we have to wait for the graphics to complete,
313 although we could go on doing calculations for the next frame */
318 DrawMaskedBorder(redraw_mask);
321 if (redraw_mask & REDRAW_ALL)
324 DrawMaskedBorder(REDRAW_ALL);
326 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
328 redraw_mask = REDRAW_NONE;
331 if (redraw_mask & REDRAW_FIELD)
333 if (game_status != GAME_MODE_PLAYING ||
334 redraw_mask & REDRAW_FROM_BACKBUFFER)
337 DrawMaskedBorder(REDRAW_FIELD);
339 BlitBitmap(backbuffer, window,
340 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
344 int fx = FX, fy = FY;
346 if (setup.soft_scrolling)
348 fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
349 fy += (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
352 if (setup.soft_scrolling ||
353 ABS(ScreenMovPos) + ScrollStepSize == TILEX ||
354 ABS(ScreenMovPos) == ScrollStepSize ||
355 redraw_tiles > REDRAWTILES_THRESHOLD)
358 if (border.draw_masked[GFX_SPECIAL_ARG_MAIN])
360 BlitBitmap(buffer, backbuffer, fx, fy, SXSIZE, SYSIZE, SX, SY);
362 DrawMaskedBorder(REDRAW_FIELD);
363 BlitBitmap(backbuffer, window,
364 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
368 BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
370 BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
375 printf("redrawing all (ScreenGfxPos == %d) because %s\n",
377 (setup.soft_scrolling ?
378 "setup.soft_scrolling" :
379 ABS(ScreenGfxPos) + ScrollStepSize == TILEX ?
380 "ABS(ScreenGfxPos) + ScrollStepSize == TILEX" :
381 ABS(ScreenGfxPos) == ScrollStepSize ?
382 "ABS(ScreenGfxPos) == ScrollStepSize" :
383 "redraw_tiles > REDRAWTILES_THRESHOLD"));
389 redraw_mask &= ~REDRAW_MAIN;
392 if (redraw_mask & REDRAW_DOORS)
394 if (redraw_mask & REDRAW_DOOR_1)
397 DrawMaskedBorder(REDRAW_DOOR_1);
399 BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
402 if (redraw_mask & REDRAW_DOOR_2)
405 DrawMaskedBorder(REDRAW_DOOR_2);
407 BlitBitmap(backbuffer, window, VX, VY, VXSIZE, VYSIZE, VX, VY);
410 if (redraw_mask & REDRAW_DOOR_3)
413 DrawMaskedBorder(REDRAW_DOOR_3);
415 BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
418 redraw_mask &= ~REDRAW_DOORS;
421 if (redraw_mask & REDRAW_MICROLEVEL)
423 BlitBitmap(backbuffer, window, SX, SY + 10 * TILEY, SXSIZE, 7 * TILEY,
424 SX, SY + 10 * TILEY);
426 redraw_mask &= ~REDRAW_MICROLEVEL;
429 if (redraw_mask & REDRAW_TILES)
431 for (x = 0; x < SCR_FIELDX; x++)
432 for (y = 0 ; y < SCR_FIELDY; y++)
433 if (redraw[redraw_x1 + x][redraw_y1 + y])
434 BlitBitmap(buffer, window,
435 FX + x * TILEX, FY + y * TILEY, TILEX, TILEY,
436 SX + x * TILEX, SY + y * TILEY);
439 if (redraw_mask & REDRAW_FPS) /* display frames per second */
444 sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
445 if (!global.fps_slowdown)
448 sprintf(text, "%.1f fps%s", global.frames_per_second, info1);
449 DrawTextExt(window, SX, SY, text, FONT_TEXT_2, BLIT_OPAQUE);
454 for (x = 0; x < MAX_BUF_XSIZE; x++)
455 for (y = 0; y < MAX_BUF_YSIZE; y++)
458 redraw_mask = REDRAW_NONE;
464 long fading_delay = 300;
466 if (setup.fading && (redraw_mask & REDRAW_FIELD))
473 ClearRectangle(window, REAL_SX,REAL_SY,FULL_SXSIZE,FULL_SYSIZE);
476 for (i = 0; i < 2 * FULL_SYSIZE; i++)
478 for (y = 0; y < FULL_SYSIZE; y++)
480 BlitBitmap(backbuffer, window,
481 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
489 for (i = 1; i < FULL_SYSIZE; i+=2)
490 BlitBitmap(backbuffer, window,
491 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
497 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, 0);
498 BlitBitmapMasked(backbuffer, window,
499 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
504 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, -1);
505 BlitBitmapMasked(backbuffer, window,
506 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
511 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, -1);
512 BlitBitmapMasked(backbuffer, window,
513 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
518 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, 0);
519 BlitBitmapMasked(backbuffer, window,
520 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
525 redraw_mask &= ~REDRAW_MAIN;
532 void FadeExt(int fade_mask, int fade_mode)
534 void (*draw_border_function)(void) = NULL;
535 Bitmap *bitmap = (fade_mode == FADE_MODE_CROSSFADE ? bitmap_db_cross : NULL);
536 int fade_delay = menu.fade_delay;
537 int post_delay = (fade_mode == FADE_MODE_FADE_OUT ? menu.post_delay : 0);
538 int x, y, width, height;
540 if (fade_mask & REDRAW_FIELD)
545 height = FULL_SYSIZE;
547 draw_border_function = DrawMaskedBorder_FIELD;
549 else /* REDRAW_ALL */
557 redraw_mask |= fade_mask;
559 if (!setup.fade_screens || fade_delay == 0)
561 if (fade_mode == FADE_MODE_FADE_OUT)
562 ClearRectangle(backbuffer, x, y, width, height);
569 FadeRectangle(bitmap, x, y, width, height, fade_mode, fade_delay, post_delay,
570 draw_border_function);
572 redraw_mask &= ~fade_mask;
575 void FadeIn(int fade_mask)
577 FadeExt(fade_mask, FADE_MODE_FADE_IN);
580 void FadeOut(int fade_mask)
582 FadeExt(fade_mask, FADE_MODE_FADE_OUT);
585 void FadeCross(int fade_mask)
587 FadeExt(fade_mask, FADE_MODE_CROSSFADE);
590 void FadeCrossSaveBackbuffer()
592 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
595 void SetMainBackgroundImageIfDefined(int graphic)
597 if (graphic_info[graphic].bitmap)
598 SetMainBackgroundImage(graphic);
601 void SetMainBackgroundImage(int graphic)
603 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
604 graphic_info[graphic].bitmap ?
605 graphic_info[graphic].bitmap :
606 graphic_info[IMG_BACKGROUND].bitmap);
609 void SetDoorBackgroundImage(int graphic)
611 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
612 graphic_info[graphic].bitmap ?
613 graphic_info[graphic].bitmap :
614 graphic_info[IMG_BACKGROUND].bitmap);
617 void SetPanelBackground()
619 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, bitmap_db_panel,
620 DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, 0, 0);
622 SetDoorBackgroundBitmap(bitmap_db_panel);
625 void DrawBackground(int dst_x, int dst_y, int width, int height)
628 ClearRectangleOnBackground(drawto, dst_x, dst_y, width, height);
630 ClearRectangleOnBackground(backbuffer, dst_x, dst_y, width, height);
633 redraw_mask |= REDRAW_FIELD;
638 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
640 if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
642 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
643 SetDrawtoField(DRAW_BUFFERED);
646 SetDrawtoField(DRAW_BACKBUFFER);
648 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
650 ClearRectangle(window, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
651 SetDrawtoField(DRAW_DIRECT);
655 void MarkTileDirty(int x, int y)
657 int xx = redraw_x1 + x;
658 int yy = redraw_y1 + y;
663 redraw[xx][yy] = TRUE;
664 redraw_mask |= REDRAW_TILES;
667 void SetBorderElement()
671 BorderElement = EL_EMPTY;
673 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
675 for (x = 0; x < lev_fieldx; x++)
677 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
678 BorderElement = EL_STEELWALL;
680 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
686 void SetRandomAnimationValue(int x, int y)
688 gfx.anim_random_frame = GfxRandom[x][y];
691 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
693 /* animation synchronized with global frame counter, not move position */
694 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
695 sync_frame = FrameCounter;
697 return getAnimationFrame(graphic_info[graphic].anim_frames,
698 graphic_info[graphic].anim_delay,
699 graphic_info[graphic].anim_mode,
700 graphic_info[graphic].anim_start_frame,
704 inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
705 int *x, int *y, boolean get_backside)
707 struct GraphicInfo *g = &graphic_info[graphic];
708 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
709 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
713 if (g->offset_y == 0) /* frames are ordered horizontally */
715 int max_width = g->anim_frames_per_line * g->width;
716 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
718 *x = pos % max_width;
719 *y = src_y % g->height + pos / max_width * g->height;
721 else if (g->offset_x == 0) /* frames are ordered vertically */
723 int max_height = g->anim_frames_per_line * g->height;
724 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
726 *x = src_x % g->width + pos / max_height * g->width;
727 *y = pos % max_height;
729 else /* frames are ordered diagonally */
731 *x = src_x + frame * g->offset_x;
732 *y = src_y + frame * g->offset_y;
736 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
738 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
741 void DrawGraphic(int x, int y, int graphic, int frame)
744 if (!IN_SCR_FIELD(x, y))
746 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
747 printf("DrawGraphic(): This should never happen!\n");
752 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
756 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
762 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
763 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
766 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
769 if (!IN_SCR_FIELD(x, y))
771 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
772 printf("DrawGraphicThruMask(): This should never happen!\n");
777 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
782 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
788 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
790 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
791 dst_x - src_x, dst_y - src_y);
792 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
795 void DrawMiniGraphic(int x, int y, int graphic)
797 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
798 MarkTileDirty(x / 2, y / 2);
801 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
803 struct GraphicInfo *g = &graphic_info[graphic];
805 int mini_starty = g->bitmap->height * 2 / 3;
808 *x = mini_startx + g->src_x / 2;
809 *y = mini_starty + g->src_y / 2;
812 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
817 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
818 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
821 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
822 int graphic, int frame,
823 int cut_mode, int mask_mode)
828 int width = TILEX, height = TILEY;
831 if (dx || dy) /* shifted graphic */
833 if (x < BX1) /* object enters playfield from the left */
840 else if (x > BX2) /* object enters playfield from the right */
846 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
852 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
854 else if (dx) /* general horizontal movement */
855 MarkTileDirty(x + SIGN(dx), y);
857 if (y < BY1) /* object enters playfield from the top */
859 if (cut_mode==CUT_BELOW) /* object completely above top border */
867 else if (y > BY2) /* object enters playfield from the bottom */
873 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
879 else if (dy > 0 && cut_mode == CUT_ABOVE)
881 if (y == BY2) /* object completely above bottom border */
887 MarkTileDirty(x, y + 1);
888 } /* object leaves playfield to the bottom */
889 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
891 else if (dy) /* general vertical movement */
892 MarkTileDirty(x, y + SIGN(dy));
896 if (!IN_SCR_FIELD(x, y))
898 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
899 printf("DrawGraphicShifted(): This should never happen!\n");
904 if (width > 0 && height > 0)
906 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
911 dst_x = FX + x * TILEX + dx;
912 dst_y = FY + y * TILEY + dy;
914 if (mask_mode == USE_MASKING)
916 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
917 dst_x - src_x, dst_y - src_y);
918 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
922 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
929 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
930 int graphic, int frame,
931 int cut_mode, int mask_mode)
936 int width = TILEX, height = TILEY;
939 int x2 = x + SIGN(dx);
940 int y2 = y + SIGN(dy);
941 int anim_frames = graphic_info[graphic].anim_frames;
942 int sync_frame = (dx ? ABS(dx) : ABS(dy)) * anim_frames / TILESIZE;
943 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
944 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
946 /* re-calculate animation frame for two-tile movement animation */
947 frame = getGraphicAnimationFrame(graphic, sync_frame);
949 /* check if movement start graphic inside screen area and should be drawn */
950 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
952 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
954 dst_x = FX + x1 * TILEX;
955 dst_y = FY + y1 * TILEY;
957 if (mask_mode == USE_MASKING)
959 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
960 dst_x - src_x, dst_y - src_y);
961 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
965 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
968 MarkTileDirty(x1, y1);
971 /* check if movement end graphic inside screen area and should be drawn */
972 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
974 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
976 dst_x = FX + x2 * TILEX;
977 dst_y = FY + y2 * TILEY;
979 if (mask_mode == USE_MASKING)
981 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
982 dst_x - src_x, dst_y - src_y);
983 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
987 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
990 MarkTileDirty(x2, y2);
994 static void DrawGraphicShifted(int x, int y, int dx, int dy,
995 int graphic, int frame,
996 int cut_mode, int mask_mode)
1000 DrawGraphic(x, y, graphic, frame);
1005 if (graphic_info[graphic].double_movement) /* EM style movement images */
1006 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1008 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1011 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1012 int frame, int cut_mode)
1014 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
1017 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1018 int cut_mode, int mask_mode)
1020 int lx = LEVELX(x), ly = LEVELY(y);
1024 if (IN_LEV_FIELD(lx, ly))
1026 SetRandomAnimationValue(lx, ly);
1028 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
1029 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1031 /* do not use double (EM style) movement graphic when not moving */
1032 if (graphic_info[graphic].double_movement && !dx && !dy)
1034 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
1035 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1038 else /* border element */
1040 graphic = el2img(element);
1041 frame = getGraphicAnimationFrame(graphic, -1);
1044 if (element == EL_EXPANDABLE_WALL)
1046 boolean left_stopped = FALSE, right_stopped = FALSE;
1048 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1049 left_stopped = TRUE;
1050 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1051 right_stopped = TRUE;
1053 if (left_stopped && right_stopped)
1055 else if (left_stopped)
1057 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1058 frame = graphic_info[graphic].anim_frames - 1;
1060 else if (right_stopped)
1062 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1063 frame = graphic_info[graphic].anim_frames - 1;
1068 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1069 else if (mask_mode == USE_MASKING)
1070 DrawGraphicThruMask(x, y, graphic, frame);
1072 DrawGraphic(x, y, graphic, frame);
1075 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1076 int cut_mode, int mask_mode)
1078 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1079 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1080 cut_mode, mask_mode);
1083 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1086 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1089 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1092 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1095 void DrawLevelElementThruMask(int x, int y, int element)
1097 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1100 void DrawLevelFieldThruMask(int x, int y)
1102 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1105 static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
1109 int sx = SCREENX(x), sy = SCREENY(y);
1111 int width, height, cx, cy, i;
1112 int crumbled_border_size = graphic_info[graphic].border_size;
1113 static int xy[4][2] =
1121 if (!IN_LEV_FIELD(x, y))
1124 element = TILE_GFX_ELEMENT(x, y);
1126 /* crumble field itself */
1127 if (GFX_CRUMBLED(element) && !IS_MOVING(x, y))
1129 if (!IN_SCR_FIELD(sx, sy))
1132 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1134 for (i = 0; i < 4; i++)
1136 int xx = x + xy[i][0];
1137 int yy = y + xy[i][1];
1139 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1142 /* check if neighbour field is of same type */
1143 if (GFX_CRUMBLED(element) && !IS_MOVING(xx, yy))
1146 if (i == 1 || i == 2)
1148 width = crumbled_border_size;
1150 cx = (i == 2 ? TILEX - crumbled_border_size : 0);
1156 height = crumbled_border_size;
1158 cy = (i == 3 ? TILEY - crumbled_border_size : 0);
1161 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1162 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1165 MarkTileDirty(sx, sy);
1167 else /* crumble neighbour fields */
1169 for (i = 0; i < 4; i++)
1171 int xx = x + xy[i][0];
1172 int yy = y + xy[i][1];
1173 int sxx = sx + xy[i][0];
1174 int syy = sy + xy[i][1];
1176 if (!IN_LEV_FIELD(xx, yy) ||
1177 !IN_SCR_FIELD(sxx, syy) ||
1181 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
1184 element = TILE_GFX_ELEMENT(xx, yy);
1186 if (!GFX_CRUMBLED(element))
1189 graphic = el_act2crm(element, ACTION_DEFAULT);
1190 crumbled_border_size = graphic_info[graphic].border_size;
1192 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1194 if (i == 1 || i == 2)
1196 width = crumbled_border_size;
1198 cx = (i == 1 ? TILEX - crumbled_border_size : 0);
1204 height = crumbled_border_size;
1206 cy = (i == 0 ? TILEY - crumbled_border_size : 0);
1209 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1210 width, height, FX + sxx * TILEX + cx, FY + syy * TILEY + cy);
1212 MarkTileDirty(sxx, syy);
1217 void DrawLevelFieldCrumbledSand(int x, int y)
1221 if (!IN_LEV_FIELD(x, y))
1225 /* !!! CHECK THIS !!! */
1228 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1229 GFX_CRUMBLED(GfxElement[x][y]))
1232 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1233 GfxElement[x][y] != EL_UNDEFINED &&
1234 GFX_CRUMBLED(GfxElement[x][y]))
1236 DrawLevelFieldCrumbledSandDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
1243 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
1245 graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
1248 DrawLevelFieldCrumbledSandExt(x, y, graphic, 0);
1251 void DrawLevelFieldCrumbledSandDigging(int x, int y, int direction,
1254 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1255 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1256 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1257 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1258 int sx = SCREENX(x), sy = SCREENY(y);
1260 DrawGraphic(sx, sy, graphic1, frame1);
1261 DrawLevelFieldCrumbledSandExt(x, y, graphic2, frame2);
1264 void DrawLevelFieldCrumbledSandNeighbours(int x, int y)
1266 int sx = SCREENX(x), sy = SCREENY(y);
1267 static int xy[4][2] =
1276 for (i = 0; i < 4; i++)
1278 int xx = x + xy[i][0];
1279 int yy = y + xy[i][1];
1280 int sxx = sx + xy[i][0];
1281 int syy = sy + xy[i][1];
1283 if (!IN_LEV_FIELD(xx, yy) ||
1284 !IN_SCR_FIELD(sxx, syy) ||
1285 !GFX_CRUMBLED(Feld[xx][yy]) ||
1289 DrawLevelField(xx, yy);
1293 static int getBorderElement(int x, int y)
1297 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1298 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1299 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1300 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1301 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1302 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1303 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1305 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1306 int steel_position = (x == -1 && y == -1 ? 0 :
1307 x == lev_fieldx && y == -1 ? 1 :
1308 x == -1 && y == lev_fieldy ? 2 :
1309 x == lev_fieldx && y == lev_fieldy ? 3 :
1310 x == -1 || x == lev_fieldx ? 4 :
1311 y == -1 || y == lev_fieldy ? 5 : 6);
1313 return border[steel_position][steel_type];
1316 void DrawScreenElement(int x, int y, int element)
1318 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1319 DrawLevelFieldCrumbledSand(LEVELX(x), LEVELY(y));
1322 void DrawLevelElement(int x, int y, int element)
1324 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1325 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1328 void DrawScreenField(int x, int y)
1330 int lx = LEVELX(x), ly = LEVELY(y);
1331 int element, content;
1333 if (!IN_LEV_FIELD(lx, ly))
1335 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1338 element = getBorderElement(lx, ly);
1340 DrawScreenElement(x, y, element);
1344 element = Feld[lx][ly];
1345 content = Store[lx][ly];
1347 if (IS_MOVING(lx, ly))
1349 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1350 boolean cut_mode = NO_CUTTING;
1352 if (element == EL_QUICKSAND_EMPTYING ||
1353 element == EL_MAGIC_WALL_EMPTYING ||
1354 element == EL_BD_MAGIC_WALL_EMPTYING ||
1355 element == EL_AMOEBA_DROPPING)
1356 cut_mode = CUT_ABOVE;
1357 else if (element == EL_QUICKSAND_FILLING ||
1358 element == EL_MAGIC_WALL_FILLING ||
1359 element == EL_BD_MAGIC_WALL_FILLING)
1360 cut_mode = CUT_BELOW;
1362 if (cut_mode == CUT_ABOVE)
1363 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1365 DrawScreenElement(x, y, EL_EMPTY);
1368 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1369 else if (cut_mode == NO_CUTTING)
1370 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1372 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1374 if (content == EL_ACID)
1376 int dir = MovDir[lx][ly];
1377 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
1378 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
1380 DrawLevelElementThruMask(newlx, newly, EL_ACID);
1383 else if (IS_BLOCKED(lx, ly))
1388 boolean cut_mode = NO_CUTTING;
1389 int element_old, content_old;
1391 Blocked2Moving(lx, ly, &oldx, &oldy);
1394 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1395 MovDir[oldx][oldy] == MV_RIGHT);
1397 element_old = Feld[oldx][oldy];
1398 content_old = Store[oldx][oldy];
1400 if (element_old == EL_QUICKSAND_EMPTYING ||
1401 element_old == EL_MAGIC_WALL_EMPTYING ||
1402 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1403 element_old == EL_AMOEBA_DROPPING)
1404 cut_mode = CUT_ABOVE;
1406 DrawScreenElement(x, y, EL_EMPTY);
1409 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1411 else if (cut_mode == NO_CUTTING)
1412 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1415 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1418 else if (IS_DRAWABLE(element))
1419 DrawScreenElement(x, y, element);
1421 DrawScreenElement(x, y, EL_EMPTY);
1424 void DrawLevelField(int x, int y)
1426 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1427 DrawScreenField(SCREENX(x), SCREENY(y));
1428 else if (IS_MOVING(x, y))
1432 Moving2Blocked(x, y, &newx, &newy);
1433 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1434 DrawScreenField(SCREENX(newx), SCREENY(newy));
1436 else if (IS_BLOCKED(x, y))
1440 Blocked2Moving(x, y, &oldx, &oldy);
1441 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1442 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1446 void DrawMiniElement(int x, int y, int element)
1450 graphic = el2edimg(element);
1451 DrawMiniGraphic(x, y, graphic);
1454 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1456 int x = sx + scroll_x, y = sy + scroll_y;
1458 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1459 DrawMiniElement(sx, sy, EL_EMPTY);
1460 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1461 DrawMiniElement(sx, sy, Feld[x][y]);
1463 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1466 void DrawEnvelopeBackground(int envelope_nr, int startx, int starty,
1467 int x, int y, int xsize, int ysize, int font_nr)
1469 int font_width = getFontWidth(font_nr);
1470 int font_height = getFontHeight(font_nr);
1471 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1474 int dst_x = SX + startx + x * font_width;
1475 int dst_y = SY + starty + y * font_height;
1476 int width = graphic_info[graphic].width;
1477 int height = graphic_info[graphic].height;
1478 int inner_width = MAX(width - 2 * font_width, font_width);
1479 int inner_height = MAX(height - 2 * font_height, font_height);
1480 int inner_sx = (width >= 3 * font_width ? font_width : 0);
1481 int inner_sy = (height >= 3 * font_height ? font_height : 0);
1482 boolean draw_masked = graphic_info[graphic].draw_masked;
1484 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1486 if (src_bitmap == NULL || width < font_width || height < font_height)
1488 ClearRectangle(drawto, dst_x, dst_y, font_width, font_height);
1492 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - font_width :
1493 inner_sx + (x - 1) * font_width % inner_width);
1494 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - font_height :
1495 inner_sy + (y - 1) * font_height % inner_height);
1499 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1500 dst_x - src_x, dst_y - src_y);
1501 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1505 BlitBitmap(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1509 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
1511 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1512 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1513 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
1514 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1515 boolean no_delay = (tape.warp_forward);
1516 unsigned long anim_delay = 0;
1517 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
1518 int anim_delay_value = (no_delay ? 0 : frame_delay_value);
1519 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
1520 int font_width = getFontWidth(font_nr);
1521 int font_height = getFontHeight(font_nr);
1522 int max_xsize = level.envelope[envelope_nr].xsize;
1523 int max_ysize = level.envelope[envelope_nr].ysize;
1524 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
1525 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
1526 int xend = max_xsize;
1527 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
1528 int xstep = (xstart < xend ? 1 : 0);
1529 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
1532 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
1534 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
1535 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
1536 int sx = (SXSIZE - xsize * font_width) / 2;
1537 int sy = (SYSIZE - ysize * font_height) / 2;
1540 SetDrawtoField(DRAW_BUFFERED);
1542 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
1544 SetDrawtoField(DRAW_BACKBUFFER);
1546 for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++)
1547 DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
1549 DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
1550 level.envelope[envelope_nr].text, font_nr, max_xsize,
1551 xsize - 2, ysize - 2, mask_mode);
1553 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
1556 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
1560 void ShowEnvelope(int envelope_nr)
1562 int element = EL_ENVELOPE_1 + envelope_nr;
1563 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1564 int sound_opening = element_info[element].sound[ACTION_OPENING];
1565 int sound_closing = element_info[element].sound[ACTION_CLOSING];
1566 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1567 boolean no_delay = (tape.warp_forward);
1568 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
1569 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
1570 int anim_mode = graphic_info[graphic].anim_mode;
1571 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
1572 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
1574 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
1576 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
1578 if (anim_mode == ANIM_DEFAULT)
1579 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
1581 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
1584 Delay(wait_delay_value);
1586 WaitForEventToContinue();
1588 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
1590 if (anim_mode != ANIM_NONE)
1591 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
1593 if (anim_mode == ANIM_DEFAULT)
1594 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
1596 game.envelope_active = FALSE;
1598 SetDrawtoField(DRAW_BUFFERED);
1600 redraw_mask |= REDRAW_FIELD;
1604 void getPreviewGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y,
1609 int width_mult, width_div;
1610 int height_mult, height_div;
1618 int offset_calc_pos = (tilesize < MICRO_TILESIZE || tilesize > TILESIZE ? 3 :
1619 5 - log_2(tilesize));
1620 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1621 int width_mult = offset_calc[offset_calc_pos].width_mult;
1622 int width_div = offset_calc[offset_calc_pos].width_div;
1623 int height_mult = offset_calc[offset_calc_pos].height_mult;
1624 int height_div = offset_calc[offset_calc_pos].height_div;
1625 int mini_startx = src_bitmap->width * width_mult / width_div;
1626 int mini_starty = src_bitmap->height * height_mult / height_div;
1627 int src_x = mini_startx + graphic_info[graphic].src_x * tilesize / TILESIZE;
1628 int src_y = mini_starty + graphic_info[graphic].src_y * tilesize / TILESIZE;
1630 *bitmap = src_bitmap;
1635 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
1639 int graphic = el2preimg(element);
1641 getPreviewGraphicSource(graphic, &src_bitmap, &src_x, &src_y, tilesize);
1642 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
1649 SetDrawBackgroundMask(REDRAW_NONE);
1652 for (x = BX1; x <= BX2; x++)
1653 for (y = BY1; y <= BY2; y++)
1654 DrawScreenField(x, y);
1656 redraw_mask |= REDRAW_FIELD;
1659 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1663 for (x = 0; x < size_x; x++)
1664 for (y = 0; y < size_y; y++)
1665 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1667 redraw_mask |= REDRAW_FIELD;
1670 static void DrawPreviewLevelExt(int from_x, int from_y)
1672 boolean show_level_border = (BorderElement != EL_EMPTY);
1673 int dst_x = preview.x;
1674 int dst_y = preview.y;
1675 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
1676 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
1677 int tile_size = preview.tile_size;
1678 int preview_width = preview.xsize * tile_size;
1679 int preview_height = preview.ysize * tile_size;
1680 int real_preview_xsize = MIN(level_xsize, preview.xsize);
1681 int real_preview_ysize = MIN(level_ysize, preview.ysize);
1684 DrawBackground(dst_x, dst_y, preview_width, preview_height);
1686 dst_x += (preview_width - real_preview_xsize * tile_size) / 2;
1687 dst_y += (preview_height - real_preview_ysize * tile_size) / 2;
1689 for (x = 0; x < real_preview_xsize; x++)
1691 for (y = 0; y < real_preview_ysize; y++)
1693 int lx = from_x + x + (show_level_border ? -1 : 0);
1694 int ly = from_y + y + (show_level_border ? -1 : 0);
1695 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
1696 getBorderElement(lx, ly));
1698 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
1699 element, tile_size);
1703 redraw_mask |= REDRAW_MICROLEVEL;
1706 #define MICROLABEL_EMPTY 0
1707 #define MICROLABEL_LEVEL_NAME 1
1708 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
1709 #define MICROLABEL_LEVEL_AUTHOR 3
1710 #define MICROLABEL_IMPORTED_FROM_HEAD 4
1711 #define MICROLABEL_IMPORTED_FROM 5
1712 #define MICROLABEL_IMPORTED_BY_HEAD 6
1713 #define MICROLABEL_IMPORTED_BY 7
1715 static void DrawPreviewLevelLabelExt(int mode)
1717 char label_text[MAX_OUTPUT_LINESIZE + 1];
1718 int max_len_label_text;
1719 int font_nr = FONT_TEXT_2;
1722 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
1723 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
1724 mode == MICROLABEL_IMPORTED_BY_HEAD)
1725 font_nr = FONT_TEXT_3;
1727 max_len_label_text = SXSIZE / getFontWidth(font_nr);
1729 for (i = 0; i < max_len_label_text; i++)
1730 label_text[i] = ' ';
1731 label_text[max_len_label_text] = '\0';
1733 if (strlen(label_text) > 0)
1735 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1736 int lypos = MICROLABEL2_YPOS;
1738 DrawText(lxpos, lypos, label_text, font_nr);
1742 (mode == MICROLABEL_LEVEL_NAME ? level.name :
1743 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
1744 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1745 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
1746 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
1747 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
1748 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
1749 max_len_label_text);
1750 label_text[max_len_label_text] = '\0';
1752 if (strlen(label_text) > 0)
1754 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1755 int lypos = MICROLABEL2_YPOS;
1757 DrawText(lxpos, lypos, label_text, font_nr);
1760 redraw_mask |= REDRAW_MICROLEVEL;
1763 void DrawPreviewLevel(boolean restart)
1765 static unsigned long scroll_delay = 0;
1766 static unsigned long label_delay = 0;
1767 static int from_x, from_y, scroll_direction;
1768 static int label_state, label_counter;
1769 unsigned long scroll_delay_value = preview.step_delay;
1770 boolean show_level_border = (BorderElement != EL_EMPTY);
1771 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
1772 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
1773 int last_game_status = game_status; /* save current game status */
1775 /* force PREVIEW font on preview level */
1776 game_status = GAME_MODE_PSEUDO_PREVIEW;
1780 from_x = preview.xoffset;
1781 from_y = preview.yoffset;
1782 scroll_direction = MV_RIGHT;
1786 DrawPreviewLevelExt(from_x, from_y);
1787 DrawPreviewLevelLabelExt(label_state);
1789 /* initialize delay counters */
1790 DelayReached(&scroll_delay, 0);
1791 DelayReached(&label_delay, 0);
1793 if (leveldir_current->name)
1795 char label_text[MAX_OUTPUT_LINESIZE + 1];
1796 int font_nr = FONT_TEXT_1;
1797 int max_len_label_text = SXSIZE / getFontWidth(font_nr);
1800 strncpy(label_text, leveldir_current->name, max_len_label_text);
1801 label_text[max_len_label_text] = '\0';
1803 lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1804 lypos = SY + MICROLABEL1_YPOS;
1806 DrawText(lxpos, lypos, label_text, font_nr);
1809 game_status = last_game_status; /* restore current game status */
1814 /* scroll preview level, if needed */
1815 if ((level_xsize > preview.xsize || level_ysize > preview.ysize) &&
1816 DelayReached(&scroll_delay, scroll_delay_value))
1818 switch (scroll_direction)
1823 from_x -= preview.step_offset;
1824 from_x = (from_x < 0 ? 0 : from_x);
1827 scroll_direction = MV_UP;
1831 if (from_x < level_xsize - preview.xsize)
1833 from_x += preview.step_offset;
1834 from_x = (from_x > level_xsize - preview.xsize ?
1835 level_xsize - preview.xsize : from_x);
1838 scroll_direction = MV_DOWN;
1844 from_y -= preview.step_offset;
1845 from_y = (from_y < 0 ? 0 : from_y);
1848 scroll_direction = MV_RIGHT;
1852 if (from_y < level_ysize - preview.ysize)
1854 from_y += preview.step_offset;
1855 from_y = (from_y > level_ysize - preview.ysize ?
1856 level_ysize - preview.ysize : from_y);
1859 scroll_direction = MV_LEFT;
1866 DrawPreviewLevelExt(from_x, from_y);
1869 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
1870 /* redraw micro level label, if needed */
1871 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
1872 !strEqual(level.author, ANONYMOUS_NAME) &&
1873 !strEqual(level.author, leveldir_current->name) &&
1874 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
1876 int max_label_counter = 23;
1878 if (leveldir_current->imported_from != NULL &&
1879 strlen(leveldir_current->imported_from) > 0)
1880 max_label_counter += 14;
1881 if (leveldir_current->imported_by != NULL &&
1882 strlen(leveldir_current->imported_by) > 0)
1883 max_label_counter += 14;
1885 label_counter = (label_counter + 1) % max_label_counter;
1886 label_state = (label_counter >= 0 && label_counter <= 7 ?
1887 MICROLABEL_LEVEL_NAME :
1888 label_counter >= 9 && label_counter <= 12 ?
1889 MICROLABEL_LEVEL_AUTHOR_HEAD :
1890 label_counter >= 14 && label_counter <= 21 ?
1891 MICROLABEL_LEVEL_AUTHOR :
1892 label_counter >= 23 && label_counter <= 26 ?
1893 MICROLABEL_IMPORTED_FROM_HEAD :
1894 label_counter >= 28 && label_counter <= 35 ?
1895 MICROLABEL_IMPORTED_FROM :
1896 label_counter >= 37 && label_counter <= 40 ?
1897 MICROLABEL_IMPORTED_BY_HEAD :
1898 label_counter >= 42 && label_counter <= 49 ?
1899 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
1901 if (leveldir_current->imported_from == NULL &&
1902 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
1903 label_state == MICROLABEL_IMPORTED_FROM))
1904 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
1905 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
1907 DrawPreviewLevelLabelExt(label_state);
1910 game_status = last_game_status; /* restore current game status */
1913 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
1914 int graphic, int sync_frame, int mask_mode)
1916 int frame = getGraphicAnimationFrame(graphic, sync_frame);
1918 if (mask_mode == USE_MASKING)
1919 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
1921 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
1924 inline void DrawGraphicAnimation(int x, int y, int graphic)
1926 int lx = LEVELX(x), ly = LEVELY(y);
1928 if (!IN_SCR_FIELD(x, y))
1931 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
1932 graphic, GfxFrame[lx][ly], NO_MASKING);
1933 MarkTileDirty(x, y);
1936 void DrawLevelGraphicAnimation(int x, int y, int graphic)
1938 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
1941 void DrawLevelElementAnimation(int x, int y, int element)
1943 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
1945 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
1948 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
1950 int sx = SCREENX(x), sy = SCREENY(y);
1952 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
1955 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
1958 DrawGraphicAnimation(sx, sy, graphic);
1961 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
1962 DrawLevelFieldCrumbledSand(x, y);
1964 if (GFX_CRUMBLED(Feld[x][y]))
1965 DrawLevelFieldCrumbledSand(x, y);
1969 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
1971 int sx = SCREENX(x), sy = SCREENY(y);
1974 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
1977 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
1979 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
1982 DrawGraphicAnimation(sx, sy, graphic);
1984 if (GFX_CRUMBLED(element))
1985 DrawLevelFieldCrumbledSand(x, y);
1988 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
1990 if (player->use_murphy)
1992 /* this works only because currently only one player can be "murphy" ... */
1993 static int last_horizontal_dir = MV_LEFT;
1994 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
1996 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
1997 last_horizontal_dir = move_dir;
1999 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
2001 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
2003 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
2009 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
2012 static boolean equalGraphics(int graphic1, int graphic2)
2014 struct GraphicInfo *g1 = &graphic_info[graphic1];
2015 struct GraphicInfo *g2 = &graphic_info[graphic2];
2017 return (g1->bitmap == g2->bitmap &&
2018 g1->src_x == g2->src_x &&
2019 g1->src_y == g2->src_y &&
2020 g1->anim_frames == g2->anim_frames &&
2021 g1->anim_delay == g2->anim_delay &&
2022 g1->anim_mode == g2->anim_mode);
2025 void DrawAllPlayers()
2029 for (i = 0; i < MAX_PLAYERS; i++)
2030 if (stored_player[i].active)
2031 DrawPlayer(&stored_player[i]);
2034 void DrawPlayerField(int x, int y)
2036 if (!IS_PLAYER(x, y))
2039 DrawPlayer(PLAYERINFO(x, y));
2042 void DrawPlayer(struct PlayerInfo *player)
2044 int jx = player->jx;
2045 int jy = player->jy;
2046 int move_dir = player->MovDir;
2047 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
2048 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
2049 int last_jx = (player->is_moving ? jx - dx : jx);
2050 int last_jy = (player->is_moving ? jy - dy : jy);
2051 int next_jx = jx + dx;
2052 int next_jy = jy + dy;
2053 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
2054 boolean player_is_opaque = FALSE;
2055 int sx = SCREENX(jx), sy = SCREENY(jy);
2056 int sxx = 0, syy = 0;
2057 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
2059 int action = ACTION_DEFAULT;
2060 int last_player_graphic = getPlayerGraphic(player, move_dir);
2061 int last_player_frame = player->Frame;
2064 /* GfxElement[][] is set to the element the player is digging or collecting;
2065 remove also for off-screen player if the player is not moving anymore */
2066 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
2067 GfxElement[jx][jy] = EL_UNDEFINED;
2069 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
2073 if (!IN_LEV_FIELD(jx, jy))
2075 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
2076 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
2077 printf("DrawPlayerField(): This should never happen!\n");
2082 if (element == EL_EXPLOSION)
2085 action = (player->is_pushing ? ACTION_PUSHING :
2086 player->is_digging ? ACTION_DIGGING :
2087 player->is_collecting ? ACTION_COLLECTING :
2088 player->is_moving ? ACTION_MOVING :
2089 player->is_snapping ? ACTION_SNAPPING :
2090 player->is_dropping ? ACTION_DROPPING :
2091 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
2093 if (player->is_waiting)
2094 move_dir = player->dir_waiting;
2096 InitPlayerGfxAnimation(player, action, move_dir);
2098 /* ----------------------------------------------------------------------- */
2099 /* draw things in the field the player is leaving, if needed */
2100 /* ----------------------------------------------------------------------- */
2102 if (player->is_moving)
2104 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
2106 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
2108 if (last_element == EL_DYNAMITE_ACTIVE ||
2109 last_element == EL_EM_DYNAMITE_ACTIVE ||
2110 last_element == EL_SP_DISK_RED_ACTIVE)
2111 DrawDynamite(last_jx, last_jy);
2113 DrawLevelFieldThruMask(last_jx, last_jy);
2115 else if (last_element == EL_DYNAMITE_ACTIVE ||
2116 last_element == EL_EM_DYNAMITE_ACTIVE ||
2117 last_element == EL_SP_DISK_RED_ACTIVE)
2118 DrawDynamite(last_jx, last_jy);
2120 /* !!! this is not enough to prevent flickering of players which are
2121 moving next to each others without a free tile between them -- this
2122 can only be solved by drawing all players layer by layer (first the
2123 background, then the foreground etc.) !!! => TODO */
2124 else if (!IS_PLAYER(last_jx, last_jy))
2125 DrawLevelField(last_jx, last_jy);
2128 DrawLevelField(last_jx, last_jy);
2131 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
2132 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
2135 if (!IN_SCR_FIELD(sx, sy))
2138 if (setup.direct_draw)
2139 SetDrawtoField(DRAW_BUFFERED);
2141 /* ----------------------------------------------------------------------- */
2142 /* draw things behind the player, if needed */
2143 /* ----------------------------------------------------------------------- */
2146 DrawLevelElement(jx, jy, Back[jx][jy]);
2147 else if (IS_ACTIVE_BOMB(element))
2148 DrawLevelElement(jx, jy, EL_EMPTY);
2151 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
2153 int old_element = GfxElement[jx][jy];
2154 int old_graphic = el_act_dir2img(old_element, action, move_dir);
2155 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
2157 if (GFX_CRUMBLED(old_element))
2158 DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
2160 DrawGraphic(sx, sy, old_graphic, frame);
2162 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
2163 player_is_opaque = TRUE;
2167 GfxElement[jx][jy] = EL_UNDEFINED;
2169 /* make sure that pushed elements are drawn with correct frame rate */
2171 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2173 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
2174 GfxFrame[jx][jy] = player->StepFrame;
2176 if (player->is_pushing && player->is_moving)
2177 GfxFrame[jx][jy] = player->StepFrame;
2180 DrawLevelField(jx, jy);
2184 /* ----------------------------------------------------------------------- */
2185 /* draw player himself */
2186 /* ----------------------------------------------------------------------- */
2188 graphic = getPlayerGraphic(player, move_dir);
2190 /* in the case of changed player action or direction, prevent the current
2191 animation frame from being restarted for identical animations */
2192 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
2193 player->Frame = last_player_frame;
2195 frame = getGraphicAnimationFrame(graphic, player->Frame);
2199 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2200 sxx = player->GfxPos;
2202 syy = player->GfxPos;
2205 if (!setup.soft_scrolling && ScreenMovPos)
2208 if (player_is_opaque)
2209 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
2211 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2213 if (SHIELD_ON(player))
2215 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
2216 IMG_SHIELD_NORMAL_ACTIVE);
2217 int frame = getGraphicAnimationFrame(graphic, -1);
2219 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2222 /* ----------------------------------------------------------------------- */
2223 /* draw things the player is pushing, if needed */
2224 /* ----------------------------------------------------------------------- */
2227 printf("::: %d, %d [%d, %d] [%d]\n",
2228 player->is_pushing, player_is_moving, player->GfxAction,
2229 player->is_moving, player_is_moving);
2233 if (player->is_pushing && player->is_moving)
2235 int px = SCREENX(jx), py = SCREENY(jy);
2236 int pxx = (TILEX - ABS(sxx)) * dx;
2237 int pyy = (TILEY - ABS(syy)) * dy;
2238 int gfx_frame = GfxFrame[jx][jy];
2244 if (!IS_MOVING(jx, jy)) /* push movement already finished */
2246 element = Feld[next_jx][next_jy];
2247 gfx_frame = GfxFrame[next_jx][next_jy];
2250 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2253 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
2254 frame = getGraphicAnimationFrame(graphic, sync_frame);
2256 frame = getGraphicAnimationFrame(graphic, player->StepFrame);
2259 /* draw background element under pushed element (like the Sokoban field) */
2260 if (Back[next_jx][next_jy])
2261 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
2263 /* masked drawing is needed for EMC style (double) movement graphics */
2264 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
2268 /* ----------------------------------------------------------------------- */
2269 /* draw things in front of player (active dynamite or dynabombs) */
2270 /* ----------------------------------------------------------------------- */
2272 if (IS_ACTIVE_BOMB(element))
2274 graphic = el2img(element);
2275 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
2277 if (game.emulation == EMU_SUPAPLEX)
2278 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
2280 DrawGraphicThruMask(sx, sy, graphic, frame);
2283 if (player_is_moving && last_element == EL_EXPLOSION)
2285 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
2286 GfxElement[last_jx][last_jy] : EL_EMPTY);
2287 int graphic = el_act2img(element, ACTION_EXPLODING);
2288 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
2289 int phase = ExplodePhase[last_jx][last_jy] - 1;
2290 int frame = getGraphicAnimationFrame(graphic, phase - delay);
2293 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
2296 /* ----------------------------------------------------------------------- */
2297 /* draw elements the player is just walking/passing through/under */
2298 /* ----------------------------------------------------------------------- */
2300 if (player_is_moving)
2302 /* handle the field the player is leaving ... */
2303 if (IS_ACCESSIBLE_INSIDE(last_element))
2304 DrawLevelField(last_jx, last_jy);
2305 else if (IS_ACCESSIBLE_UNDER(last_element))
2306 DrawLevelFieldThruMask(last_jx, last_jy);
2309 /* do not redraw accessible elements if the player is just pushing them */
2310 if (!player_is_moving || !player->is_pushing)
2312 /* ... and the field the player is entering */
2313 if (IS_ACCESSIBLE_INSIDE(element))
2314 DrawLevelField(jx, jy);
2315 else if (IS_ACCESSIBLE_UNDER(element))
2316 DrawLevelFieldThruMask(jx, jy);
2319 if (setup.direct_draw)
2321 int dst_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
2322 int dst_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
2323 int x_size = TILEX * (1 + ABS(jx - last_jx));
2324 int y_size = TILEY * (1 + ABS(jy - last_jy));
2326 BlitBitmap(drawto_field, window,
2327 dst_x, dst_y, x_size, y_size, dst_x, dst_y);
2328 SetDrawtoField(DRAW_DIRECT);
2331 MarkTileDirty(sx, sy);
2334 /* ------------------------------------------------------------------------- */
2336 void WaitForEventToContinue()
2338 boolean still_wait = TRUE;
2340 /* simulate releasing mouse button over last gadget, if still pressed */
2342 HandleGadgets(-1, -1, 0);
2344 button_status = MB_RELEASED;
2360 case EVENT_BUTTONPRESS:
2361 case EVENT_KEYPRESS:
2365 case EVENT_KEYRELEASE:
2366 ClearPlayerAction();
2370 HandleOtherEvents(&event);
2374 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2381 /* don't eat all CPU time */
2386 #define MAX_REQUEST_LINES 13
2387 #define MAX_REQUEST_LINE_FONT1_LEN 7
2388 #define MAX_REQUEST_LINE_FONT2_LEN 10
2390 boolean Request(char *text, unsigned int req_state)
2392 int mx, my, ty, result = -1;
2393 unsigned int old_door_state;
2394 int last_game_status = game_status; /* save current game status */
2395 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
2396 int font_nr = FONT_TEXT_2;
2397 int max_word_len = 0;
2400 for (text_ptr = text; *text_ptr; text_ptr++)
2402 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
2404 if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
2406 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
2407 font_nr = FONT_LEVEL_NUMBER;
2413 if (game_status == GAME_MODE_PLAYING &&
2414 level.game_engine_type == GAME_ENGINE_TYPE_EM)
2415 BlitScreenToBitmap_EM(backbuffer);
2417 /* disable deactivated drawing when quick-loading level tape recording */
2418 if (tape.playing && tape.deactivate_display)
2419 TapeDeactivateDisplayOff(TRUE);
2421 SetMouseCursor(CURSOR_DEFAULT);
2423 #if defined(NETWORK_AVALIABLE)
2424 /* pause network game while waiting for request to answer */
2425 if (options.network &&
2426 game_status == GAME_MODE_PLAYING &&
2427 req_state & REQUEST_WAIT_FOR_INPUT)
2428 SendToServer_PausePlaying();
2431 old_door_state = GetDoorState();
2433 /* simulate releasing mouse button over last gadget, if still pressed */
2435 HandleGadgets(-1, -1, 0);
2439 if (old_door_state & DOOR_OPEN_1)
2441 CloseDoor(DOOR_CLOSE_1);
2443 /* save old door content */
2444 BlitBitmap(bitmap_db_door, bitmap_db_door,
2445 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2446 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
2450 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2453 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2455 /* clear door drawing field */
2456 DrawBackground(DX, DY, DXSIZE, DYSIZE);
2458 /* force DOOR font on preview level */
2459 game_status = GAME_MODE_PSEUDO_DOOR;
2461 /* write text for request */
2462 for (ty = 0; ty < MAX_REQUEST_LINES; ty++)
2464 char text_line[max_request_line_len + 1];
2470 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
2473 if (!tc || tc == ' ')
2484 strncpy(text_line, text, tl);
2487 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
2488 DY + 8 + ty * (getFontHeight(font_nr) + 2),
2489 text_line, font_nr);
2491 text += tl + (tc == ' ' ? 1 : 0);
2494 game_status = last_game_status; /* restore current game status */
2496 if (req_state & REQ_ASK)
2498 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2499 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2501 else if (req_state & REQ_CONFIRM)
2503 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2505 else if (req_state & REQ_PLAYER)
2507 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2508 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2509 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2510 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2513 /* copy request gadgets to door backbuffer */
2514 BlitBitmap(drawto, bitmap_db_door,
2515 DX, DY, DXSIZE, DYSIZE,
2516 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2518 OpenDoor(DOOR_OPEN_1);
2520 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
2522 if (game_status == GAME_MODE_PLAYING)
2524 SetPanelBackground();
2525 SetDrawBackgroundMask(REDRAW_DOOR_1);
2529 SetDrawBackgroundMask(REDRAW_FIELD);
2535 if (game_status != GAME_MODE_MAIN)
2538 button_status = MB_RELEASED;
2540 request_gadget_id = -1;
2542 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2554 case EVENT_BUTTONPRESS:
2555 case EVENT_BUTTONRELEASE:
2556 case EVENT_MOTIONNOTIFY:
2558 if (event.type == EVENT_MOTIONNOTIFY)
2560 if (!PointerInWindow(window))
2561 continue; /* window and pointer are on different screens */
2566 motion_status = TRUE;
2567 mx = ((MotionEvent *) &event)->x;
2568 my = ((MotionEvent *) &event)->y;
2572 motion_status = FALSE;
2573 mx = ((ButtonEvent *) &event)->x;
2574 my = ((ButtonEvent *) &event)->y;
2575 if (event.type == EVENT_BUTTONPRESS)
2576 button_status = ((ButtonEvent *) &event)->button;
2578 button_status = MB_RELEASED;
2581 /* this sets 'request_gadget_id' */
2582 HandleGadgets(mx, my, button_status);
2584 switch(request_gadget_id)
2586 case TOOL_CTRL_ID_YES:
2589 case TOOL_CTRL_ID_NO:
2592 case TOOL_CTRL_ID_CONFIRM:
2593 result = TRUE | FALSE;
2596 case TOOL_CTRL_ID_PLAYER_1:
2599 case TOOL_CTRL_ID_PLAYER_2:
2602 case TOOL_CTRL_ID_PLAYER_3:
2605 case TOOL_CTRL_ID_PLAYER_4:
2616 case EVENT_KEYPRESS:
2617 switch(GetEventKey((KeyEvent *)&event, TRUE))
2630 if (req_state & REQ_PLAYER)
2634 case EVENT_KEYRELEASE:
2635 ClearPlayerAction();
2639 HandleOtherEvents(&event);
2643 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2645 int joy = AnyJoystick();
2647 if (joy & JOY_BUTTON_1)
2649 else if (joy & JOY_BUTTON_2)
2656 if (!PendingEvent()) /* delay only if no pending events */
2659 /* don't eat all CPU time */
2664 if (game_status != GAME_MODE_MAIN)
2669 if (!(req_state & REQ_STAY_OPEN))
2671 CloseDoor(DOOR_CLOSE_1);
2673 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
2674 (req_state & REQ_REOPEN))
2675 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
2680 if (game_status == GAME_MODE_PLAYING)
2682 SetPanelBackground();
2683 SetDrawBackgroundMask(REDRAW_DOOR_1);
2687 SetDrawBackgroundMask(REDRAW_FIELD);
2690 #if defined(NETWORK_AVALIABLE)
2691 /* continue network game after request */
2692 if (options.network &&
2693 game_status == GAME_MODE_PLAYING &&
2694 req_state & REQUEST_WAIT_FOR_INPUT)
2695 SendToServer_ContinuePlaying();
2698 /* restore deactivated drawing when quick-loading level tape recording */
2699 if (tape.playing && tape.deactivate_display)
2700 TapeDeactivateDisplayOn();
2705 unsigned int OpenDoor(unsigned int door_state)
2707 if (door_state & DOOR_COPY_BACK)
2709 if (door_state & DOOR_OPEN_1)
2710 BlitBitmap(bitmap_db_door, bitmap_db_door,
2711 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2712 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2714 if (door_state & DOOR_OPEN_2)
2715 BlitBitmap(bitmap_db_door, bitmap_db_door,
2716 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
2717 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2719 door_state &= ~DOOR_COPY_BACK;
2722 return MoveDoor(door_state);
2725 unsigned int CloseDoor(unsigned int door_state)
2727 unsigned int old_door_state = GetDoorState();
2729 if (!(door_state & DOOR_NO_COPY_BACK))
2731 if (old_door_state & DOOR_OPEN_1)
2732 BlitBitmap(backbuffer, bitmap_db_door,
2733 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2735 if (old_door_state & DOOR_OPEN_2)
2736 BlitBitmap(backbuffer, bitmap_db_door,
2737 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2739 door_state &= ~DOOR_NO_COPY_BACK;
2742 return MoveDoor(door_state);
2745 unsigned int GetDoorState()
2747 return MoveDoor(DOOR_GET_STATE);
2750 unsigned int SetDoorState(unsigned int door_state)
2752 return MoveDoor(door_state | DOOR_SET_STATE);
2755 unsigned int MoveDoor(unsigned int door_state)
2757 static int door1 = DOOR_OPEN_1;
2758 static int door2 = DOOR_CLOSE_2;
2759 unsigned long door_delay = 0;
2760 unsigned long door_delay_value;
2763 if (door_1.width < 0 || door_1.width > DXSIZE)
2764 door_1.width = DXSIZE;
2765 if (door_1.height < 0 || door_1.height > DYSIZE)
2766 door_1.height = DYSIZE;
2767 if (door_2.width < 0 || door_2.width > VXSIZE)
2768 door_2.width = VXSIZE;
2769 if (door_2.height < 0 || door_2.height > VYSIZE)
2770 door_2.height = VYSIZE;
2772 if (door_state == DOOR_GET_STATE)
2773 return (door1 | door2);
2775 if (door_state & DOOR_SET_STATE)
2777 if (door_state & DOOR_ACTION_1)
2778 door1 = door_state & DOOR_ACTION_1;
2779 if (door_state & DOOR_ACTION_2)
2780 door2 = door_state & DOOR_ACTION_2;
2782 return (door1 | door2);
2785 if (!(door_state & DOOR_FORCE_REDRAW))
2787 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2788 door_state &= ~DOOR_OPEN_1;
2789 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2790 door_state &= ~DOOR_CLOSE_1;
2791 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2792 door_state &= ~DOOR_OPEN_2;
2793 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2794 door_state &= ~DOOR_CLOSE_2;
2797 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
2800 if (setup.quick_doors)
2802 stepsize = 20; /* must be choosen to always draw last frame */
2803 door_delay_value = 0;
2806 if (global.autoplay_leveldir)
2808 door_state |= DOOR_NO_DELAY;
2809 door_state &= ~DOOR_CLOSE_ALL;
2812 if (door_state & DOOR_ACTION)
2814 boolean handle_door_1 = (door_state & DOOR_ACTION_1);
2815 boolean handle_door_2 = (door_state & DOOR_ACTION_2);
2816 boolean door_1_done = (!handle_door_1);
2817 boolean door_2_done = (!handle_door_2);
2818 boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
2819 boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
2820 int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
2821 int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
2822 int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
2823 int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
2824 int door_size = (handle_door_1 ? door_size_1 : door_size_2);
2825 int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
2826 int door_skip = max_door_size - door_size;
2827 int end = door_size;
2828 int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
2831 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
2833 /* opening door sound has priority over simultaneously closing door */
2834 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2835 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2836 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2837 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2840 for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
2843 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2844 GC gc = bitmap->stored_clip_gc;
2846 if (door_state & DOOR_ACTION_1)
2848 int a = MIN(x * door_1.step_offset, end);
2849 int p = (door_state & DOOR_OPEN_1 ? end - a : a);
2850 int i = p + door_skip;
2852 if (door_1.anim_mode & ANIM_STATIC_PANEL)
2854 BlitBitmap(bitmap_db_door, drawto,
2855 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
2856 DXSIZE, DYSIZE, DX, DY);
2860 BlitBitmap(bitmap_db_door, drawto,
2861 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
2862 DXSIZE, DYSIZE - p / 2, DX, DY);
2864 ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
2867 if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
2869 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2870 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
2871 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
2872 int dst2_x = DX, dst2_y = DY;
2873 int width = i, height = DYSIZE;
2875 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2876 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2879 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2880 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2883 else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
2885 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2886 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
2887 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
2888 int dst2_x = DX, dst2_y = DY;
2889 int width = DXSIZE, height = i;
2891 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2892 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2895 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2896 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2899 else if (x <= DXSIZE) /* ANIM_DEFAULT */
2901 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
2903 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2904 BlitBitmapMasked(bitmap, drawto,
2905 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2906 DX + DXSIZE - i, DY + j);
2907 BlitBitmapMasked(bitmap, drawto,
2908 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2909 DX + DXSIZE - i, DY + 140 + j);
2910 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
2911 DY - (DOOR_GFX_PAGEY1 + j));
2912 BlitBitmapMasked(bitmap, drawto,
2913 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2915 BlitBitmapMasked(bitmap, drawto,
2916 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
2919 BlitBitmapMasked(bitmap, drawto,
2920 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2922 BlitBitmapMasked(bitmap, drawto,
2923 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2925 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2926 BlitBitmapMasked(bitmap, drawto,
2927 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2928 DX + DXSIZE - i, DY + 77 + j);
2929 BlitBitmapMasked(bitmap, drawto,
2930 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2931 DX + DXSIZE - i, DY + 203 + j);
2934 redraw_mask |= REDRAW_DOOR_1;
2935 door_1_done = (a == end);
2938 if (door_state & DOOR_ACTION_2)
2940 int a = MIN(x * door_2.step_offset, door_size);
2941 int p = (door_state & DOOR_OPEN_2 ? door_size - a : a);
2942 int i = p + door_skip;
2944 if (door_2.anim_mode & ANIM_STATIC_PANEL)
2946 BlitBitmap(bitmap_db_door, drawto,
2947 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
2948 VXSIZE, VYSIZE, VX, VY);
2950 else if (x <= VYSIZE)
2952 BlitBitmap(bitmap_db_door, drawto,
2953 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
2954 VXSIZE, VYSIZE - p / 2, VX, VY);
2956 ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
2959 if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
2961 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
2962 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
2963 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
2964 int dst2_x = VX, dst2_y = VY;
2965 int width = i, height = VYSIZE;
2967 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2968 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2971 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2972 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2975 else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
2977 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
2978 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
2979 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
2980 int dst2_x = VX, dst2_y = VY;
2981 int width = VXSIZE, height = i;
2983 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2984 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2987 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2988 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2991 else if (x <= VXSIZE) /* ANIM_DEFAULT */
2993 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
2995 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2996 BlitBitmapMasked(bitmap, drawto,
2997 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
2998 VX + VXSIZE - i, VY + j);
2999 SetClipOrigin(bitmap, gc,
3000 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
3001 BlitBitmapMasked(bitmap, drawto,
3002 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
3005 BlitBitmapMasked(bitmap, drawto,
3006 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3007 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
3008 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3009 BlitBitmapMasked(bitmap, drawto,
3010 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3012 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
3015 redraw_mask |= REDRAW_DOOR_2;
3016 door_2_done = (a == VXSIZE);
3019 if (!(door_state & DOOR_NO_DELAY))
3023 if (game_status == GAME_MODE_MAIN)
3026 WaitUntilDelayReached(&door_delay, door_delay_value);
3031 if (door_state & DOOR_ACTION_1)
3032 door1 = door_state & DOOR_ACTION_1;
3033 if (door_state & DOOR_ACTION_2)
3034 door2 = door_state & DOOR_ACTION_2;
3036 return (door1 | door2);
3039 void DrawSpecialEditorDoor()
3041 /* draw bigger toolbox window */
3042 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
3043 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
3045 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3046 EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
3049 redraw_mask |= REDRAW_ALL;
3052 void UndrawSpecialEditorDoor()
3054 /* draw normal tape recorder window */
3055 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3056 EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
3059 redraw_mask |= REDRAW_ALL;
3063 /* ---------- new tool button stuff ---------------------------------------- */
3065 /* graphic position values for tool buttons */
3066 #define TOOL_BUTTON_YES_XPOS 2
3067 #define TOOL_BUTTON_YES_YPOS 250
3068 #define TOOL_BUTTON_YES_GFX_YPOS 0
3069 #define TOOL_BUTTON_YES_XSIZE 46
3070 #define TOOL_BUTTON_YES_YSIZE 28
3071 #define TOOL_BUTTON_NO_XPOS 52
3072 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
3073 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
3074 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
3075 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
3076 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
3077 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
3078 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
3079 #define TOOL_BUTTON_CONFIRM_XSIZE 96
3080 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
3081 #define TOOL_BUTTON_PLAYER_XSIZE 30
3082 #define TOOL_BUTTON_PLAYER_YSIZE 30
3083 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
3084 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
3085 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
3086 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
3087 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3088 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3089 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3090 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3091 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3092 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3093 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3094 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3095 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3096 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3097 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3098 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3099 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3100 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3101 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3102 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3111 } toolbutton_info[NUM_TOOL_BUTTONS] =
3114 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
3115 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
3116 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
3121 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
3122 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
3123 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
3128 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
3129 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
3130 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
3131 TOOL_CTRL_ID_CONFIRM,
3135 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3136 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
3137 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3138 TOOL_CTRL_ID_PLAYER_1,
3142 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3143 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
3144 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3145 TOOL_CTRL_ID_PLAYER_2,
3149 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3150 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
3151 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3152 TOOL_CTRL_ID_PLAYER_3,
3156 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3157 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
3158 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3159 TOOL_CTRL_ID_PLAYER_4,
3164 void CreateToolButtons()
3168 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3170 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3171 Bitmap *deco_bitmap = None;
3172 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
3173 struct GadgetInfo *gi;
3174 unsigned long event_mask;
3175 int gd_xoffset, gd_yoffset;
3176 int gd_x1, gd_x2, gd_y;
3179 event_mask = GD_EVENT_RELEASED;
3181 gd_xoffset = toolbutton_info[i].xpos;
3182 gd_yoffset = toolbutton_info[i].ypos;
3183 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
3184 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
3185 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
3187 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
3189 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
3191 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
3192 &deco_bitmap, &deco_x, &deco_y);
3193 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
3194 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
3197 gi = CreateGadget(GDI_CUSTOM_ID, id,
3198 GDI_INFO_TEXT, toolbutton_info[i].infotext,
3199 GDI_X, DX + toolbutton_info[i].x,
3200 GDI_Y, DY + toolbutton_info[i].y,
3201 GDI_WIDTH, toolbutton_info[i].width,
3202 GDI_HEIGHT, toolbutton_info[i].height,
3203 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
3204 GDI_STATE, GD_BUTTON_UNPRESSED,
3205 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
3206 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
3207 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
3208 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
3209 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
3210 GDI_DECORATION_SHIFTING, 1, 1,
3211 GDI_DIRECT_DRAW, FALSE,
3212 GDI_EVENT_MASK, event_mask,
3213 GDI_CALLBACK_ACTION, HandleToolButtons,
3217 Error(ERR_EXIT, "cannot create gadget");
3219 tool_gadget[id] = gi;
3223 void FreeToolButtons()
3227 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3228 FreeGadget(tool_gadget[i]);
3231 static void UnmapToolButtons()
3235 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3236 UnmapGadget(tool_gadget[i]);
3239 static void HandleToolButtons(struct GadgetInfo *gi)
3241 request_gadget_id = gi->custom_id;
3244 static struct Mapping_EM_to_RND_object
3247 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
3248 boolean is_backside; /* backside of moving element */
3254 em_object_mapping_list[] =
3257 Xblank, TRUE, FALSE,
3261 Yacid_splash_eB, FALSE, FALSE,
3262 EL_ACID_SPLASH_RIGHT, -1, -1
3265 Yacid_splash_wB, FALSE, FALSE,
3266 EL_ACID_SPLASH_LEFT, -1, -1
3269 #ifdef EM_ENGINE_BAD_ROLL
3271 Xstone_force_e, FALSE, FALSE,
3272 EL_ROCK, -1, MV_BIT_RIGHT
3275 Xstone_force_w, FALSE, FALSE,
3276 EL_ROCK, -1, MV_BIT_LEFT
3279 Xnut_force_e, FALSE, FALSE,
3280 EL_NUT, -1, MV_BIT_RIGHT
3283 Xnut_force_w, FALSE, FALSE,
3284 EL_NUT, -1, MV_BIT_LEFT
3287 Xspring_force_e, FALSE, FALSE,
3288 EL_SPRING, -1, MV_BIT_RIGHT
3291 Xspring_force_w, FALSE, FALSE,
3292 EL_SPRING, -1, MV_BIT_LEFT
3295 Xemerald_force_e, FALSE, FALSE,
3296 EL_EMERALD, -1, MV_BIT_RIGHT
3299 Xemerald_force_w, FALSE, FALSE,
3300 EL_EMERALD, -1, MV_BIT_LEFT
3303 Xdiamond_force_e, FALSE, FALSE,
3304 EL_DIAMOND, -1, MV_BIT_RIGHT
3307 Xdiamond_force_w, FALSE, FALSE,
3308 EL_DIAMOND, -1, MV_BIT_LEFT
3311 Xbomb_force_e, FALSE, FALSE,
3312 EL_BOMB, -1, MV_BIT_RIGHT
3315 Xbomb_force_w, FALSE, FALSE,
3316 EL_BOMB, -1, MV_BIT_LEFT
3318 #endif /* EM_ENGINE_BAD_ROLL */
3321 Xstone, TRUE, FALSE,
3325 Xstone_pause, FALSE, FALSE,
3329 Xstone_fall, FALSE, FALSE,
3333 Ystone_s, FALSE, FALSE,
3334 EL_ROCK, ACTION_FALLING, -1
3337 Ystone_sB, FALSE, TRUE,
3338 EL_ROCK, ACTION_FALLING, -1
3341 Ystone_e, FALSE, FALSE,
3342 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3345 Ystone_eB, FALSE, TRUE,
3346 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3349 Ystone_w, FALSE, FALSE,
3350 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3353 Ystone_wB, FALSE, TRUE,
3354 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3361 Xnut_pause, FALSE, FALSE,
3365 Xnut_fall, FALSE, FALSE,
3369 Ynut_s, FALSE, FALSE,
3370 EL_NUT, ACTION_FALLING, -1
3373 Ynut_sB, FALSE, TRUE,
3374 EL_NUT, ACTION_FALLING, -1
3377 Ynut_e, FALSE, FALSE,
3378 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3381 Ynut_eB, FALSE, TRUE,
3382 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3385 Ynut_w, FALSE, FALSE,
3386 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3389 Ynut_wB, FALSE, TRUE,
3390 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3393 Xbug_n, TRUE, FALSE,
3397 Xbug_e, TRUE, FALSE,
3398 EL_BUG_RIGHT, -1, -1
3401 Xbug_s, TRUE, FALSE,
3405 Xbug_w, TRUE, FALSE,
3409 Xbug_gon, FALSE, FALSE,
3413 Xbug_goe, FALSE, FALSE,
3414 EL_BUG_RIGHT, -1, -1
3417 Xbug_gos, FALSE, FALSE,
3421 Xbug_gow, FALSE, FALSE,
3425 Ybug_n, FALSE, FALSE,
3426 EL_BUG, ACTION_MOVING, MV_BIT_UP
3429 Ybug_nB, FALSE, TRUE,
3430 EL_BUG, ACTION_MOVING, MV_BIT_UP
3433 Ybug_e, FALSE, FALSE,
3434 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3437 Ybug_eB, FALSE, TRUE,
3438 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3441 Ybug_s, FALSE, FALSE,
3442 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3445 Ybug_sB, FALSE, TRUE,
3446 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3449 Ybug_w, FALSE, FALSE,
3450 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3453 Ybug_wB, FALSE, TRUE,
3454 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3457 Ybug_w_n, FALSE, FALSE,
3458 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3461 Ybug_n_e, FALSE, FALSE,
3462 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3465 Ybug_e_s, FALSE, FALSE,
3466 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3469 Ybug_s_w, FALSE, FALSE,
3470 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3473 Ybug_e_n, FALSE, FALSE,
3474 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3477 Ybug_s_e, FALSE, FALSE,
3478 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3481 Ybug_w_s, FALSE, FALSE,
3482 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3485 Ybug_n_w, FALSE, FALSE,
3486 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3489 Ybug_stone, FALSE, FALSE,
3490 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
3493 Ybug_spring, FALSE, FALSE,
3494 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
3497 Xtank_n, TRUE, FALSE,
3498 EL_SPACESHIP_UP, -1, -1
3501 Xtank_e, TRUE, FALSE,
3502 EL_SPACESHIP_RIGHT, -1, -1
3505 Xtank_s, TRUE, FALSE,
3506 EL_SPACESHIP_DOWN, -1, -1
3509 Xtank_w, TRUE, FALSE,
3510 EL_SPACESHIP_LEFT, -1, -1
3513 Xtank_gon, FALSE, FALSE,
3514 EL_SPACESHIP_UP, -1, -1
3517 Xtank_goe, FALSE, FALSE,
3518 EL_SPACESHIP_RIGHT, -1, -1
3521 Xtank_gos, FALSE, FALSE,
3522 EL_SPACESHIP_DOWN, -1, -1
3525 Xtank_gow, FALSE, FALSE,
3526 EL_SPACESHIP_LEFT, -1, -1
3529 Ytank_n, FALSE, FALSE,
3530 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3533 Ytank_nB, FALSE, TRUE,
3534 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3537 Ytank_e, FALSE, FALSE,
3538 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3541 Ytank_eB, FALSE, TRUE,
3542 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3545 Ytank_s, FALSE, FALSE,
3546 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3549 Ytank_sB, FALSE, TRUE,
3550 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3553 Ytank_w, FALSE, FALSE,
3554 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3557 Ytank_wB, FALSE, TRUE,
3558 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3561 Ytank_w_n, FALSE, FALSE,
3562 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3565 Ytank_n_e, FALSE, FALSE,
3566 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3569 Ytank_e_s, FALSE, FALSE,
3570 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3573 Ytank_s_w, FALSE, FALSE,
3574 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3577 Ytank_e_n, FALSE, FALSE,
3578 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3581 Ytank_s_e, FALSE, FALSE,
3582 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3585 Ytank_w_s, FALSE, FALSE,
3586 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3589 Ytank_n_w, FALSE, FALSE,
3590 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3593 Ytank_stone, FALSE, FALSE,
3594 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
3597 Ytank_spring, FALSE, FALSE,
3598 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
3601 Xandroid, TRUE, FALSE,
3602 EL_EMC_ANDROID, ACTION_ACTIVE, -1
3605 Xandroid_1_n, FALSE, FALSE,
3606 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3609 Xandroid_2_n, FALSE, FALSE,
3610 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3613 Xandroid_1_e, FALSE, FALSE,
3614 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3617 Xandroid_2_e, FALSE, FALSE,
3618 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3621 Xandroid_1_w, FALSE, FALSE,
3622 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3625 Xandroid_2_w, FALSE, FALSE,
3626 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3629 Xandroid_1_s, FALSE, FALSE,
3630 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3633 Xandroid_2_s, FALSE, FALSE,
3634 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3637 Yandroid_n, FALSE, FALSE,
3638 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3641 Yandroid_nB, FALSE, TRUE,
3642 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3645 Yandroid_ne, FALSE, FALSE,
3646 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
3649 Yandroid_neB, FALSE, TRUE,
3650 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
3653 Yandroid_e, FALSE, FALSE,
3654 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
3657 Yandroid_eB, FALSE, TRUE,
3658 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
3661 Yandroid_se, FALSE, FALSE,
3662 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
3665 Yandroid_seB, FALSE, TRUE,
3666 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
3669 Yandroid_s, FALSE, FALSE,
3670 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
3673 Yandroid_sB, FALSE, TRUE,
3674 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
3677 Yandroid_sw, FALSE, FALSE,
3678 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
3681 Yandroid_swB, FALSE, TRUE,
3682 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
3685 Yandroid_w, FALSE, FALSE,
3686 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
3689 Yandroid_wB, FALSE, TRUE,
3690 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
3693 Yandroid_nw, FALSE, FALSE,
3694 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
3697 Yandroid_nwB, FALSE, TRUE,
3698 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
3701 Xspring, TRUE, FALSE,
3705 Xspring_pause, FALSE, FALSE,
3709 Xspring_e, FALSE, FALSE,
3713 Xspring_w, FALSE, FALSE,
3717 Xspring_fall, FALSE, FALSE,
3721 Yspring_s, FALSE, FALSE,
3722 EL_SPRING, ACTION_FALLING, -1
3725 Yspring_sB, FALSE, TRUE,
3726 EL_SPRING, ACTION_FALLING, -1
3729 Yspring_e, FALSE, FALSE,
3730 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
3733 Yspring_eB, FALSE, TRUE,
3734 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
3737 Yspring_w, FALSE, FALSE,
3738 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
3741 Yspring_wB, FALSE, TRUE,
3742 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
3745 Yspring_kill_e, FALSE, FALSE,
3746 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
3749 Yspring_kill_eB, FALSE, TRUE,
3750 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
3753 Yspring_kill_w, FALSE, FALSE,
3754 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
3757 Yspring_kill_wB, FALSE, TRUE,
3758 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
3761 Xeater_n, TRUE, FALSE,
3762 EL_YAMYAM_UP, -1, -1
3765 Xeater_e, TRUE, FALSE,
3766 EL_YAMYAM_RIGHT, -1, -1
3769 Xeater_w, TRUE, FALSE,
3770 EL_YAMYAM_LEFT, -1, -1
3773 Xeater_s, TRUE, FALSE,
3774 EL_YAMYAM_DOWN, -1, -1
3777 Yeater_n, FALSE, FALSE,
3778 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
3781 Yeater_nB, FALSE, TRUE,
3782 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
3785 Yeater_e, FALSE, FALSE,
3786 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
3789 Yeater_eB, FALSE, TRUE,
3790 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
3793 Yeater_s, FALSE, FALSE,
3794 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
3797 Yeater_sB, FALSE, TRUE,
3798 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
3801 Yeater_w, FALSE, FALSE,
3802 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
3805 Yeater_wB, FALSE, TRUE,
3806 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
3809 Yeater_stone, FALSE, FALSE,
3810 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
3813 Yeater_spring, FALSE, FALSE,
3814 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
3817 Xalien, TRUE, FALSE,
3821 Xalien_pause, FALSE, FALSE,
3825 Yalien_n, FALSE, FALSE,
3826 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
3829 Yalien_nB, FALSE, TRUE,
3830 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
3833 Yalien_e, FALSE, FALSE,
3834 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
3837 Yalien_eB, FALSE, TRUE,
3838 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
3841 Yalien_s, FALSE, FALSE,
3842 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
3845 Yalien_sB, FALSE, TRUE,
3846 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
3849 Yalien_w, FALSE, FALSE,
3850 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
3853 Yalien_wB, FALSE, TRUE,
3854 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
3857 Yalien_stone, FALSE, FALSE,
3858 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
3861 Yalien_spring, FALSE, FALSE,
3862 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
3865 Xemerald, TRUE, FALSE,
3869 Xemerald_pause, FALSE, FALSE,
3873 Xemerald_fall, FALSE, FALSE,
3877 Xemerald_shine, FALSE, FALSE,
3878 EL_EMERALD, ACTION_TWINKLING, -1
3881 Yemerald_s, FALSE, FALSE,
3882 EL_EMERALD, ACTION_FALLING, -1
3885 Yemerald_sB, FALSE, TRUE,
3886 EL_EMERALD, ACTION_FALLING, -1
3889 Yemerald_e, FALSE, FALSE,
3890 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
3893 Yemerald_eB, FALSE, TRUE,
3894 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
3897 Yemerald_w, FALSE, FALSE,
3898 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
3901 Yemerald_wB, FALSE, TRUE,
3902 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
3905 Yemerald_eat, FALSE, FALSE,
3906 EL_EMERALD, ACTION_COLLECTING, -1
3909 Yemerald_stone, FALSE, FALSE,
3910 EL_NUT, ACTION_BREAKING, -1
3913 Xdiamond, TRUE, FALSE,
3917 Xdiamond_pause, FALSE, FALSE,
3921 Xdiamond_fall, FALSE, FALSE,
3925 Xdiamond_shine, FALSE, FALSE,
3926 EL_DIAMOND, ACTION_TWINKLING, -1
3929 Ydiamond_s, FALSE, FALSE,
3930 EL_DIAMOND, ACTION_FALLING, -1
3933 Ydiamond_sB, FALSE, TRUE,
3934 EL_DIAMOND, ACTION_FALLING, -1
3937 Ydiamond_e, FALSE, FALSE,
3938 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
3941 Ydiamond_eB, FALSE, TRUE,
3942 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
3945 Ydiamond_w, FALSE, FALSE,
3946 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
3949 Ydiamond_wB, FALSE, TRUE,
3950 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
3953 Ydiamond_eat, FALSE, FALSE,
3954 EL_DIAMOND, ACTION_COLLECTING, -1
3957 Ydiamond_stone, FALSE, FALSE,
3958 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
3961 Xdrip_fall, TRUE, FALSE,
3962 EL_AMOEBA_DROP, -1, -1
3965 Xdrip_stretch, FALSE, FALSE,
3966 EL_AMOEBA_DROP, ACTION_FALLING, -1
3969 Xdrip_stretchB, FALSE, TRUE,
3970 EL_AMOEBA_DROP, ACTION_FALLING, -1
3973 Xdrip_eat, FALSE, FALSE,
3974 EL_AMOEBA_DROP, ACTION_GROWING, -1
3977 Ydrip_s1, FALSE, FALSE,
3978 EL_AMOEBA_DROP, ACTION_FALLING, -1
3981 Ydrip_s1B, FALSE, TRUE,
3982 EL_AMOEBA_DROP, ACTION_FALLING, -1
3985 Ydrip_s2, FALSE, FALSE,
3986 EL_AMOEBA_DROP, ACTION_FALLING, -1
3989 Ydrip_s2B, FALSE, TRUE,
3990 EL_AMOEBA_DROP, ACTION_FALLING, -1
3997 Xbomb_pause, FALSE, FALSE,
4001 Xbomb_fall, FALSE, FALSE,
4005 Ybomb_s, FALSE, FALSE,
4006 EL_BOMB, ACTION_FALLING, -1
4009 Ybomb_sB, FALSE, TRUE,
4010 EL_BOMB, ACTION_FALLING, -1
4013 Ybomb_e, FALSE, FALSE,
4014 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
4017 Ybomb_eB, FALSE, TRUE,
4018 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
4021 Ybomb_w, FALSE, FALSE,
4022 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
4025 Ybomb_wB, FALSE, TRUE,
4026 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
4029 Ybomb_eat, FALSE, FALSE,
4030 EL_BOMB, ACTION_ACTIVATING, -1
4033 Xballoon, TRUE, FALSE,
4037 Yballoon_n, FALSE, FALSE,
4038 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
4041 Yballoon_nB, FALSE, TRUE,
4042 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
4045 Yballoon_e, FALSE, FALSE,
4046 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
4049 Yballoon_eB, FALSE, TRUE,
4050 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
4053 Yballoon_s, FALSE, FALSE,
4054 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
4057 Yballoon_sB, FALSE, TRUE,
4058 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
4061 Yballoon_w, FALSE, FALSE,
4062 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
4065 Yballoon_wB, FALSE, TRUE,
4066 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
4069 Xgrass, TRUE, FALSE,
4070 EL_EMC_GRASS, -1, -1
4073 Ygrass_nB, FALSE, FALSE,
4074 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
4077 Ygrass_eB, FALSE, FALSE,
4078 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
4081 Ygrass_sB, FALSE, FALSE,
4082 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
4085 Ygrass_wB, FALSE, FALSE,
4086 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
4093 Ydirt_nB, FALSE, FALSE,
4094 EL_SAND, ACTION_DIGGING, MV_BIT_UP
4097 Ydirt_eB, FALSE, FALSE,
4098 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
4101 Ydirt_sB, FALSE, FALSE,
4102 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
4105 Ydirt_wB, FALSE, FALSE,
4106 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
4109 Xacid_ne, TRUE, FALSE,
4110 EL_ACID_POOL_TOPRIGHT, -1, -1
4113 Xacid_se, TRUE, FALSE,
4114 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
4117 Xacid_s, TRUE, FALSE,
4118 EL_ACID_POOL_BOTTOM, -1, -1
4121 Xacid_sw, TRUE, FALSE,
4122 EL_ACID_POOL_BOTTOMLEFT, -1, -1
4125 Xacid_nw, TRUE, FALSE,
4126 EL_ACID_POOL_TOPLEFT, -1, -1
4129 Xacid_1, TRUE, FALSE,
4133 Xacid_2, FALSE, FALSE,
4137 Xacid_3, FALSE, FALSE,
4141 Xacid_4, FALSE, FALSE,
4145 Xacid_5, FALSE, FALSE,
4149 Xacid_6, FALSE, FALSE,
4153 Xacid_7, FALSE, FALSE,
4157 Xacid_8, FALSE, FALSE,
4161 Xball_1, TRUE, FALSE,
4162 EL_EMC_MAGIC_BALL, -1, -1
4165 Xball_1B, FALSE, FALSE,
4166 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4169 Xball_2, FALSE, FALSE,
4170 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4173 Xball_2B, FALSE, FALSE,
4174 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4177 Yball_eat, FALSE, FALSE,
4178 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
4181 Ykey_1_eat, FALSE, FALSE,
4182 EL_EM_KEY_1, ACTION_COLLECTING, -1
4185 Ykey_2_eat, FALSE, FALSE,
4186 EL_EM_KEY_2, ACTION_COLLECTING, -1
4189 Ykey_3_eat, FALSE, FALSE,
4190 EL_EM_KEY_3, ACTION_COLLECTING, -1
4193 Ykey_4_eat, FALSE, FALSE,
4194 EL_EM_KEY_4, ACTION_COLLECTING, -1
4197 Ykey_5_eat, FALSE, FALSE,
4198 EL_EMC_KEY_5, ACTION_COLLECTING, -1
4201 Ykey_6_eat, FALSE, FALSE,
4202 EL_EMC_KEY_6, ACTION_COLLECTING, -1
4205 Ykey_7_eat, FALSE, FALSE,
4206 EL_EMC_KEY_7, ACTION_COLLECTING, -1
4209 Ykey_8_eat, FALSE, FALSE,
4210 EL_EMC_KEY_8, ACTION_COLLECTING, -1
4213 Ylenses_eat, FALSE, FALSE,
4214 EL_EMC_LENSES, ACTION_COLLECTING, -1
4217 Ymagnify_eat, FALSE, FALSE,
4218 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
4221 Ygrass_eat, FALSE, FALSE,
4222 EL_EMC_GRASS, ACTION_SNAPPING, -1
4225 Ydirt_eat, FALSE, FALSE,
4226 EL_SAND, ACTION_SNAPPING, -1
4229 Xgrow_ns, TRUE, FALSE,
4230 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
4233 Ygrow_ns_eat, FALSE, FALSE,
4234 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
4237 Xgrow_ew, TRUE, FALSE,
4238 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
4241 Ygrow_ew_eat, FALSE, FALSE,
4242 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
4245 Xwonderwall, TRUE, FALSE,
4246 EL_MAGIC_WALL, -1, -1
4249 XwonderwallB, FALSE, FALSE,
4250 EL_MAGIC_WALL, ACTION_ACTIVE, -1
4253 Xamoeba_1, TRUE, FALSE,
4254 EL_AMOEBA_DRY, ACTION_OTHER, -1
4257 Xamoeba_2, FALSE, FALSE,
4258 EL_AMOEBA_DRY, ACTION_OTHER, -1
4261 Xamoeba_3, FALSE, FALSE,
4262 EL_AMOEBA_DRY, ACTION_OTHER, -1
4265 Xamoeba_4, FALSE, FALSE,
4266 EL_AMOEBA_DRY, ACTION_OTHER, -1
4269 Xamoeba_5, TRUE, FALSE,
4270 EL_AMOEBA_WET, ACTION_OTHER, -1
4273 Xamoeba_6, FALSE, FALSE,
4274 EL_AMOEBA_WET, ACTION_OTHER, -1
4277 Xamoeba_7, FALSE, FALSE,
4278 EL_AMOEBA_WET, ACTION_OTHER, -1
4281 Xamoeba_8, FALSE, FALSE,
4282 EL_AMOEBA_WET, ACTION_OTHER, -1
4285 Xdoor_1, TRUE, FALSE,
4286 EL_EM_GATE_1, -1, -1
4289 Xdoor_2, TRUE, FALSE,
4290 EL_EM_GATE_2, -1, -1
4293 Xdoor_3, TRUE, FALSE,
4294 EL_EM_GATE_3, -1, -1
4297 Xdoor_4, TRUE, FALSE,
4298 EL_EM_GATE_4, -1, -1
4301 Xdoor_5, TRUE, FALSE,
4302 EL_EMC_GATE_5, -1, -1
4305 Xdoor_6, TRUE, FALSE,
4306 EL_EMC_GATE_6, -1, -1
4309 Xdoor_7, TRUE, FALSE,
4310 EL_EMC_GATE_7, -1, -1
4313 Xdoor_8, TRUE, FALSE,
4314 EL_EMC_GATE_8, -1, -1
4317 Xkey_1, TRUE, FALSE,
4321 Xkey_2, TRUE, FALSE,
4325 Xkey_3, TRUE, FALSE,
4329 Xkey_4, TRUE, FALSE,
4333 Xkey_5, TRUE, FALSE,
4334 EL_EMC_KEY_5, -1, -1
4337 Xkey_6, TRUE, FALSE,
4338 EL_EMC_KEY_6, -1, -1
4341 Xkey_7, TRUE, FALSE,
4342 EL_EMC_KEY_7, -1, -1
4345 Xkey_8, TRUE, FALSE,
4346 EL_EMC_KEY_8, -1, -1
4349 Xwind_n, TRUE, FALSE,
4350 EL_BALLOON_SWITCH_UP, -1, -1
4353 Xwind_e, TRUE, FALSE,
4354 EL_BALLOON_SWITCH_RIGHT, -1, -1
4357 Xwind_s, TRUE, FALSE,
4358 EL_BALLOON_SWITCH_DOWN, -1, -1
4361 Xwind_w, TRUE, FALSE,
4362 EL_BALLOON_SWITCH_LEFT, -1, -1
4365 Xwind_nesw, TRUE, FALSE,
4366 EL_BALLOON_SWITCH_ANY, -1, -1
4369 Xwind_stop, TRUE, FALSE,
4370 EL_BALLOON_SWITCH_NONE, -1, -1
4374 EL_EXIT_CLOSED, -1, -1
4377 Xexit_1, TRUE, FALSE,
4378 EL_EXIT_OPEN, -1, -1
4381 Xexit_2, FALSE, FALSE,
4382 EL_EXIT_OPEN, -1, -1
4385 Xexit_3, FALSE, FALSE,
4386 EL_EXIT_OPEN, -1, -1
4389 Xdynamite, TRUE, FALSE,
4390 EL_EM_DYNAMITE, -1, -1
4393 Ydynamite_eat, FALSE, FALSE,
4394 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
4397 Xdynamite_1, TRUE, FALSE,
4398 EL_EM_DYNAMITE_ACTIVE, -1, -1
4401 Xdynamite_2, FALSE, FALSE,
4402 EL_EM_DYNAMITE_ACTIVE, -1, -1
4405 Xdynamite_3, FALSE, FALSE,
4406 EL_EM_DYNAMITE_ACTIVE, -1, -1
4409 Xdynamite_4, FALSE, FALSE,
4410 EL_EM_DYNAMITE_ACTIVE, -1, -1
4413 Xbumper, TRUE, FALSE,
4414 EL_EMC_SPRING_BUMPER, -1, -1
4417 XbumperB, FALSE, FALSE,
4418 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
4421 Xwheel, TRUE, FALSE,
4422 EL_ROBOT_WHEEL, -1, -1
4425 XwheelB, FALSE, FALSE,
4426 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
4429 Xswitch, TRUE, FALSE,
4430 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
4433 XswitchB, FALSE, FALSE,
4434 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
4438 EL_QUICKSAND_EMPTY, -1, -1
4441 Xsand_stone, TRUE, FALSE,
4442 EL_QUICKSAND_FULL, -1, -1
4445 Xsand_stonein_1, FALSE, TRUE,
4446 EL_ROCK, ACTION_FILLING, -1
4449 Xsand_stonein_2, FALSE, TRUE,
4450 EL_ROCK, ACTION_FILLING, -1
4453 Xsand_stonein_3, FALSE, TRUE,
4454 EL_ROCK, ACTION_FILLING, -1
4457 Xsand_stonein_4, FALSE, TRUE,
4458 EL_ROCK, ACTION_FILLING, -1
4461 Xsand_stonesand_1, FALSE, FALSE,
4462 EL_QUICKSAND_FULL, -1, -1
4465 Xsand_stonesand_2, FALSE, FALSE,
4466 EL_QUICKSAND_FULL, -1, -1
4469 Xsand_stonesand_3, FALSE, FALSE,
4470 EL_QUICKSAND_FULL, -1, -1
4473 Xsand_stonesand_4, FALSE, FALSE,
4474 EL_QUICKSAND_FULL, -1, -1
4477 Xsand_stoneout_1, FALSE, FALSE,
4478 EL_ROCK, ACTION_EMPTYING, -1
4481 Xsand_stoneout_2, FALSE, FALSE,
4482 EL_ROCK, ACTION_EMPTYING, -1
4485 Xsand_sandstone_1, FALSE, FALSE,
4486 EL_QUICKSAND_FULL, -1, -1
4489 Xsand_sandstone_2, FALSE, FALSE,
4490 EL_QUICKSAND_FULL, -1, -1
4493 Xsand_sandstone_3, FALSE, FALSE,
4494 EL_QUICKSAND_FULL, -1, -1
4497 Xsand_sandstone_4, FALSE, FALSE,
4498 EL_QUICKSAND_FULL, -1, -1
4501 Xplant, TRUE, FALSE,
4502 EL_EMC_PLANT, -1, -1
4505 Yplant, FALSE, FALSE,
4506 EL_EMC_PLANT, -1, -1
4509 Xlenses, TRUE, FALSE,
4510 EL_EMC_LENSES, -1, -1
4513 Xmagnify, TRUE, FALSE,
4514 EL_EMC_MAGNIFIER, -1, -1
4517 Xdripper, TRUE, FALSE,
4518 EL_EMC_DRIPPER, -1, -1
4521 XdripperB, FALSE, FALSE,
4522 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
4525 Xfake_blank, TRUE, FALSE,
4526 EL_INVISIBLE_WALL, -1, -1
4529 Xfake_blankB, FALSE, FALSE,
4530 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
4533 Xfake_grass, TRUE, FALSE,
4534 EL_EMC_FAKE_GRASS, -1, -1
4537 Xfake_grassB, FALSE, FALSE,
4538 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
4541 Xfake_door_1, TRUE, FALSE,
4542 EL_EM_GATE_1_GRAY, -1, -1
4545 Xfake_door_2, TRUE, FALSE,
4546 EL_EM_GATE_2_GRAY, -1, -1
4549 Xfake_door_3, TRUE, FALSE,
4550 EL_EM_GATE_3_GRAY, -1, -1
4553 Xfake_door_4, TRUE, FALSE,
4554 EL_EM_GATE_4_GRAY, -1, -1
4557 Xfake_door_5, TRUE, FALSE,
4558 EL_EMC_GATE_5_GRAY, -1, -1
4561 Xfake_door_6, TRUE, FALSE,
4562 EL_EMC_GATE_6_GRAY, -1, -1
4565 Xfake_door_7, TRUE, FALSE,
4566 EL_EMC_GATE_7_GRAY, -1, -1
4569 Xfake_door_8, TRUE, FALSE,
4570 EL_EMC_GATE_8_GRAY, -1, -1
4573 Xfake_acid_1, TRUE, FALSE,
4574 EL_EMC_FAKE_ACID, -1, -1
4577 Xfake_acid_2, FALSE, FALSE,
4578 EL_EMC_FAKE_ACID, -1, -1
4581 Xfake_acid_3, FALSE, FALSE,
4582 EL_EMC_FAKE_ACID, -1, -1
4585 Xfake_acid_4, FALSE, FALSE,
4586 EL_EMC_FAKE_ACID, -1, -1
4589 Xfake_acid_5, FALSE, FALSE,
4590 EL_EMC_FAKE_ACID, -1, -1
4593 Xfake_acid_6, FALSE, FALSE,
4594 EL_EMC_FAKE_ACID, -1, -1
4597 Xfake_acid_7, FALSE, FALSE,
4598 EL_EMC_FAKE_ACID, -1, -1
4601 Xfake_acid_8, FALSE, FALSE,
4602 EL_EMC_FAKE_ACID, -1, -1
4605 Xsteel_1, TRUE, FALSE,
4606 EL_STEELWALL, -1, -1
4609 Xsteel_2, TRUE, FALSE,
4610 EL_EMC_STEELWALL_2, -1, -1
4613 Xsteel_3, TRUE, FALSE,
4614 EL_EMC_STEELWALL_3, -1, -1
4617 Xsteel_4, TRUE, FALSE,
4618 EL_EMC_STEELWALL_4, -1, -1
4621 Xwall_1, TRUE, FALSE,
4625 Xwall_2, TRUE, FALSE,
4626 EL_EMC_WALL_14, -1, -1
4629 Xwall_3, TRUE, FALSE,
4630 EL_EMC_WALL_15, -1, -1
4633 Xwall_4, TRUE, FALSE,
4634 EL_EMC_WALL_16, -1, -1
4637 Xround_wall_1, TRUE, FALSE,
4638 EL_WALL_SLIPPERY, -1, -1
4641 Xround_wall_2, TRUE, FALSE,
4642 EL_EMC_WALL_SLIPPERY_2, -1, -1
4645 Xround_wall_3, TRUE, FALSE,
4646 EL_EMC_WALL_SLIPPERY_3, -1, -1
4649 Xround_wall_4, TRUE, FALSE,
4650 EL_EMC_WALL_SLIPPERY_4, -1, -1
4653 Xdecor_1, TRUE, FALSE,
4654 EL_EMC_WALL_8, -1, -1
4657 Xdecor_2, TRUE, FALSE,
4658 EL_EMC_WALL_6, -1, -1
4661 Xdecor_3, TRUE, FALSE,
4662 EL_EMC_WALL_4, -1, -1
4665 Xdecor_4, TRUE, FALSE,
4666 EL_EMC_WALL_7, -1, -1
4669 Xdecor_5, TRUE, FALSE,
4670 EL_EMC_WALL_5, -1, -1
4673 Xdecor_6, TRUE, FALSE,
4674 EL_EMC_WALL_9, -1, -1
4677 Xdecor_7, TRUE, FALSE,
4678 EL_EMC_WALL_10, -1, -1
4681 Xdecor_8, TRUE, FALSE,
4682 EL_EMC_WALL_1, -1, -1
4685 Xdecor_9, TRUE, FALSE,
4686 EL_EMC_WALL_2, -1, -1
4689 Xdecor_10, TRUE, FALSE,
4690 EL_EMC_WALL_3, -1, -1
4693 Xdecor_11, TRUE, FALSE,
4694 EL_EMC_WALL_11, -1, -1
4697 Xdecor_12, TRUE, FALSE,
4698 EL_EMC_WALL_12, -1, -1
4701 Xalpha_0, TRUE, FALSE,
4702 EL_CHAR('0'), -1, -1
4705 Xalpha_1, TRUE, FALSE,
4706 EL_CHAR('1'), -1, -1
4709 Xalpha_2, TRUE, FALSE,
4710 EL_CHAR('2'), -1, -1
4713 Xalpha_3, TRUE, FALSE,
4714 EL_CHAR('3'), -1, -1
4717 Xalpha_4, TRUE, FALSE,
4718 EL_CHAR('4'), -1, -1
4721 Xalpha_5, TRUE, FALSE,
4722 EL_CHAR('5'), -1, -1
4725 Xalpha_6, TRUE, FALSE,
4726 EL_CHAR('6'), -1, -1
4729 Xalpha_7, TRUE, FALSE,
4730 EL_CHAR('7'), -1, -1
4733 Xalpha_8, TRUE, FALSE,
4734 EL_CHAR('8'), -1, -1
4737 Xalpha_9, TRUE, FALSE,
4738 EL_CHAR('9'), -1, -1
4741 Xalpha_excla, TRUE, FALSE,
4742 EL_CHAR('!'), -1, -1
4745 Xalpha_quote, TRUE, FALSE,
4746 EL_CHAR('"'), -1, -1
4749 Xalpha_comma, TRUE, FALSE,
4750 EL_CHAR(','), -1, -1
4753 Xalpha_minus, TRUE, FALSE,
4754 EL_CHAR('-'), -1, -1
4757 Xalpha_perio, TRUE, FALSE,
4758 EL_CHAR('.'), -1, -1
4761 Xalpha_colon, TRUE, FALSE,
4762 EL_CHAR(':'), -1, -1
4765 Xalpha_quest, TRUE, FALSE,
4766 EL_CHAR('?'), -1, -1
4769 Xalpha_a, TRUE, FALSE,
4770 EL_CHAR('A'), -1, -1
4773 Xalpha_b, TRUE, FALSE,
4774 EL_CHAR('B'), -1, -1
4777 Xalpha_c, TRUE, FALSE,
4778 EL_CHAR('C'), -1, -1
4781 Xalpha_d, TRUE, FALSE,
4782 EL_CHAR('D'), -1, -1
4785 Xalpha_e, TRUE, FALSE,
4786 EL_CHAR('E'), -1, -1
4789 Xalpha_f, TRUE, FALSE,
4790 EL_CHAR('F'), -1, -1
4793 Xalpha_g, TRUE, FALSE,
4794 EL_CHAR('G'), -1, -1
4797 Xalpha_h, TRUE, FALSE,
4798 EL_CHAR('H'), -1, -1
4801 Xalpha_i, TRUE, FALSE,
4802 EL_CHAR('I'), -1, -1
4805 Xalpha_j, TRUE, FALSE,
4806 EL_CHAR('J'), -1, -1
4809 Xalpha_k, TRUE, FALSE,
4810 EL_CHAR('K'), -1, -1
4813 Xalpha_l, TRUE, FALSE,
4814 EL_CHAR('L'), -1, -1
4817 Xalpha_m, TRUE, FALSE,
4818 EL_CHAR('M'), -1, -1
4821 Xalpha_n, TRUE, FALSE,
4822 EL_CHAR('N'), -1, -1
4825 Xalpha_o, TRUE, FALSE,
4826 EL_CHAR('O'), -1, -1
4829 Xalpha_p, TRUE, FALSE,
4830 EL_CHAR('P'), -1, -1
4833 Xalpha_q, TRUE, FALSE,
4834 EL_CHAR('Q'), -1, -1
4837 Xalpha_r, TRUE, FALSE,
4838 EL_CHAR('R'), -1, -1
4841 Xalpha_s, TRUE, FALSE,
4842 EL_CHAR('S'), -1, -1
4845 Xalpha_t, TRUE, FALSE,
4846 EL_CHAR('T'), -1, -1
4849 Xalpha_u, TRUE, FALSE,
4850 EL_CHAR('U'), -1, -1
4853 Xalpha_v, TRUE, FALSE,
4854 EL_CHAR('V'), -1, -1
4857 Xalpha_w, TRUE, FALSE,
4858 EL_CHAR('W'), -1, -1
4861 Xalpha_x, TRUE, FALSE,
4862 EL_CHAR('X'), -1, -1
4865 Xalpha_y, TRUE, FALSE,
4866 EL_CHAR('Y'), -1, -1
4869 Xalpha_z, TRUE, FALSE,
4870 EL_CHAR('Z'), -1, -1
4873 Xalpha_arrow_e, TRUE, FALSE,
4874 EL_CHAR('>'), -1, -1
4877 Xalpha_arrow_w, TRUE, FALSE,
4878 EL_CHAR('<'), -1, -1
4881 Xalpha_copyr, TRUE, FALSE,
4882 EL_CHAR('©'), -1, -1
4886 Xboom_bug, FALSE, FALSE,
4887 EL_BUG, ACTION_EXPLODING, -1
4890 Xboom_bomb, FALSE, FALSE,
4891 EL_BOMB, ACTION_EXPLODING, -1
4894 Xboom_android, FALSE, FALSE,
4895 EL_EMC_ANDROID, ACTION_OTHER, -1
4898 Xboom_1, FALSE, FALSE,
4899 EL_DEFAULT, ACTION_EXPLODING, -1
4902 Xboom_2, FALSE, FALSE,
4903 EL_DEFAULT, ACTION_EXPLODING, -1
4906 Znormal, FALSE, FALSE,
4910 Zdynamite, FALSE, FALSE,
4914 Zplayer, FALSE, FALSE,
4918 ZBORDER, FALSE, FALSE,
4928 static struct Mapping_EM_to_RND_player
4937 em_player_mapping_list[] =
4941 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
4945 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
4949 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
4953 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
4957 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
4961 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
4965 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
4969 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
4973 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
4977 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
4981 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
4985 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
4989 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
4993 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
4997 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
5001 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
5005 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
5009 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
5013 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
5017 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
5021 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
5025 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
5029 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
5033 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
5037 EL_PLAYER_1, ACTION_DEFAULT, -1,
5041 EL_PLAYER_2, ACTION_DEFAULT, -1,
5045 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
5049 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
5053 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
5057 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
5061 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
5065 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
5069 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
5073 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
5077 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
5081 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
5085 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
5089 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
5093 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
5097 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
5101 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
5105 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
5109 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
5113 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
5117 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
5121 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
5125 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
5129 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
5133 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
5137 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
5141 EL_PLAYER_3, ACTION_DEFAULT, -1,
5145 EL_PLAYER_4, ACTION_DEFAULT, -1,
5154 int map_element_RND_to_EM(int element_rnd)
5156 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
5157 static boolean mapping_initialized = FALSE;
5159 if (!mapping_initialized)
5163 /* return "Xalpha_quest" for all undefined elements in mapping array */
5164 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
5165 mapping_RND_to_EM[i] = Xalpha_quest;
5167 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5168 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
5169 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
5170 em_object_mapping_list[i].element_em;
5172 mapping_initialized = TRUE;
5175 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
5176 return mapping_RND_to_EM[element_rnd];
5178 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
5183 int map_element_EM_to_RND(int element_em)
5185 static unsigned short mapping_EM_to_RND[TILE_MAX];
5186 static boolean mapping_initialized = FALSE;
5188 if (!mapping_initialized)
5192 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
5193 for (i = 0; i < TILE_MAX; i++)
5194 mapping_EM_to_RND[i] = EL_UNKNOWN;
5196 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5197 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
5198 em_object_mapping_list[i].element_rnd;
5200 mapping_initialized = TRUE;
5203 if (element_em >= 0 && element_em < TILE_MAX)
5204 return mapping_EM_to_RND[element_em];
5206 Error(ERR_WARN, "invalid EM level element %d", element_em);
5211 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
5213 struct LevelInfo_EM *level_em = level->native_em_level;
5214 struct LEVEL *lev = level_em->lev;
5217 for (i = 0; i < TILE_MAX; i++)
5218 lev->android_array[i] = Xblank;
5220 for (i = 0; i < level->num_android_clone_elements; i++)
5222 int element_rnd = level->android_clone_element[i];
5223 int element_em = map_element_RND_to_EM(element_rnd);
5225 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
5226 if (em_object_mapping_list[j].element_rnd == element_rnd)
5227 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
5231 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
5233 struct LevelInfo_EM *level_em = level->native_em_level;
5234 struct LEVEL *lev = level_em->lev;
5237 level->num_android_clone_elements = 0;
5239 for (i = 0; i < TILE_MAX; i++)
5241 int element_em = lev->android_array[i];
5243 boolean element_found = FALSE;
5245 if (element_em == Xblank)
5248 element_rnd = map_element_EM_to_RND(element_em);
5250 for (j = 0; j < level->num_android_clone_elements; j++)
5251 if (level->android_clone_element[j] == element_rnd)
5252 element_found = TRUE;
5256 level->android_clone_element[level->num_android_clone_elements++] =
5259 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
5264 if (level->num_android_clone_elements == 0)
5266 level->num_android_clone_elements = 1;
5267 level->android_clone_element[0] = EL_EMPTY;
5271 int map_direction_RND_to_EM(int direction)
5273 return (direction == MV_UP ? 0 :
5274 direction == MV_RIGHT ? 1 :
5275 direction == MV_DOWN ? 2 :
5276 direction == MV_LEFT ? 3 :
5280 int map_direction_EM_to_RND(int direction)
5282 return (direction == 0 ? MV_UP :
5283 direction == 1 ? MV_RIGHT :
5284 direction == 2 ? MV_DOWN :
5285 direction == 3 ? MV_LEFT :
5289 int get_next_element(int element)
5293 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
5294 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
5295 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
5296 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
5297 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
5298 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
5299 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
5301 default: return element;
5306 int el_act_dir2img(int element, int action, int direction)
5308 element = GFX_ELEMENT(element);
5310 if (direction == MV_NONE)
5311 return element_info[element].graphic[action];
5313 direction = MV_DIR_TO_BIT(direction);
5315 return element_info[element].direction_graphic[action][direction];
5318 int el_act_dir2img(int element, int action, int direction)
5320 element = GFX_ELEMENT(element);
5321 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5323 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5324 return element_info[element].direction_graphic[action][direction];
5329 static int el_act_dir2crm(int element, int action, int direction)
5331 element = GFX_ELEMENT(element);
5333 if (direction == MV_NONE)
5334 return element_info[element].crumbled[action];
5336 direction = MV_DIR_TO_BIT(direction);
5338 return element_info[element].direction_crumbled[action][direction];
5341 static int el_act_dir2crm(int element, int action, int direction)
5343 element = GFX_ELEMENT(element);
5344 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5346 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5347 return element_info[element].direction_crumbled[action][direction];
5351 int el_act2img(int element, int action)
5353 element = GFX_ELEMENT(element);
5355 return element_info[element].graphic[action];
5358 int el_act2crm(int element, int action)
5360 element = GFX_ELEMENT(element);
5362 return element_info[element].crumbled[action];
5365 int el_dir2img(int element, int direction)
5367 element = GFX_ELEMENT(element);
5369 return el_act_dir2img(element, ACTION_DEFAULT, direction);
5372 int el2baseimg(int element)
5374 return element_info[element].graphic[ACTION_DEFAULT];
5377 int el2img(int element)
5379 element = GFX_ELEMENT(element);
5381 return element_info[element].graphic[ACTION_DEFAULT];
5384 int el2edimg(int element)
5386 element = GFX_ELEMENT(element);
5388 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
5391 int el2preimg(int element)
5393 element = GFX_ELEMENT(element);
5395 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
5398 int font2baseimg(int font_nr)
5400 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
5403 int getNumActivePlayers_EM()
5405 int num_players = 0;
5411 for (i = 0; i < MAX_PLAYERS; i++)
5412 if (tape.player_participates[i])
5418 int getGameFrameDelay_EM(int native_em_game_frame_delay)
5420 int game_frame_delay_value;
5422 game_frame_delay_value =
5423 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
5424 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
5427 if (tape.playing && tape.warp_forward && !tape.pausing)
5428 game_frame_delay_value = 0;
5430 return game_frame_delay_value;
5433 unsigned int InitRND(long seed)
5435 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
5436 return InitEngineRandom_EM(seed);
5438 return InitEngineRandom_RND(seed);
5441 void InitGraphicInfo_EM(void)
5443 struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
5444 struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
5448 int num_em_gfx_errors = 0;
5450 if (graphic_info_em_object[0][0].bitmap == NULL)
5452 /* EM graphics not yet initialized in em_open_all() */
5457 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
5460 /* always start with reliable default values */
5461 for (i = 0; i < TILE_MAX; i++)
5463 object_mapping[i].element_rnd = EL_UNKNOWN;
5464 object_mapping[i].is_backside = FALSE;
5465 object_mapping[i].action = ACTION_DEFAULT;
5466 object_mapping[i].direction = MV_NONE;
5469 /* always start with reliable default values */
5470 for (p = 0; p < MAX_PLAYERS; p++)
5472 for (i = 0; i < SPR_MAX; i++)
5474 player_mapping[p][i].element_rnd = EL_UNKNOWN;
5475 player_mapping[p][i].action = ACTION_DEFAULT;
5476 player_mapping[p][i].direction = MV_NONE;
5480 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5482 int e = em_object_mapping_list[i].element_em;
5484 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
5485 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
5487 if (em_object_mapping_list[i].action != -1)
5488 object_mapping[e].action = em_object_mapping_list[i].action;
5490 if (em_object_mapping_list[i].direction != -1)
5491 object_mapping[e].direction =
5492 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
5495 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
5497 int a = em_player_mapping_list[i].action_em;
5498 int p = em_player_mapping_list[i].player_nr;
5500 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
5502 if (em_player_mapping_list[i].action != -1)
5503 player_mapping[p][a].action = em_player_mapping_list[i].action;
5505 if (em_player_mapping_list[i].direction != -1)
5506 player_mapping[p][a].direction =
5507 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
5510 for (i = 0; i < TILE_MAX; i++)
5512 int element = object_mapping[i].element_rnd;
5513 int action = object_mapping[i].action;
5514 int direction = object_mapping[i].direction;
5515 boolean is_backside = object_mapping[i].is_backside;
5516 boolean action_removing = (action == ACTION_DIGGING ||
5517 action == ACTION_SNAPPING ||
5518 action == ACTION_COLLECTING);
5519 boolean action_exploding = ((action == ACTION_EXPLODING ||
5520 action == ACTION_SMASHED_BY_ROCK ||
5521 action == ACTION_SMASHED_BY_SPRING) &&
5522 element != EL_DIAMOND);
5523 boolean action_active = (action == ACTION_ACTIVE);
5524 boolean action_other = (action == ACTION_OTHER);
5526 for (j = 0; j < 8; j++)
5528 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
5529 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
5531 i == Xdrip_stretch ? element :
5532 i == Xdrip_stretchB ? element :
5533 i == Ydrip_s1 ? element :
5534 i == Ydrip_s1B ? element :
5535 i == Xball_1B ? element :
5536 i == Xball_2 ? element :
5537 i == Xball_2B ? element :
5538 i == Yball_eat ? element :
5539 i == Ykey_1_eat ? element :
5540 i == Ykey_2_eat ? element :
5541 i == Ykey_3_eat ? element :
5542 i == Ykey_4_eat ? element :
5543 i == Ykey_5_eat ? element :
5544 i == Ykey_6_eat ? element :
5545 i == Ykey_7_eat ? element :
5546 i == Ykey_8_eat ? element :
5547 i == Ylenses_eat ? element :
5548 i == Ymagnify_eat ? element :
5549 i == Ygrass_eat ? element :
5550 i == Ydirt_eat ? element :
5551 i == Yemerald_stone ? EL_EMERALD :
5552 i == Ydiamond_stone ? EL_ROCK :
5553 i == Xsand_stonein_1 ? element :
5554 i == Xsand_stonein_2 ? element :
5555 i == Xsand_stonein_3 ? element :
5556 i == Xsand_stonein_4 ? element :
5557 is_backside ? EL_EMPTY :
5558 action_removing ? EL_EMPTY :
5560 int effective_action = (j < 7 ? action :
5561 i == Xdrip_stretch ? action :
5562 i == Xdrip_stretchB ? action :
5563 i == Ydrip_s1 ? action :
5564 i == Ydrip_s1B ? action :
5565 i == Xball_1B ? action :
5566 i == Xball_2 ? action :
5567 i == Xball_2B ? action :
5568 i == Yball_eat ? action :
5569 i == Ykey_1_eat ? action :
5570 i == Ykey_2_eat ? action :
5571 i == Ykey_3_eat ? action :
5572 i == Ykey_4_eat ? action :
5573 i == Ykey_5_eat ? action :
5574 i == Ykey_6_eat ? action :
5575 i == Ykey_7_eat ? action :
5576 i == Ykey_8_eat ? action :
5577 i == Ylenses_eat ? action :
5578 i == Ymagnify_eat ? action :
5579 i == Ygrass_eat ? action :
5580 i == Ydirt_eat ? action :
5581 i == Xsand_stonein_1 ? action :
5582 i == Xsand_stonein_2 ? action :
5583 i == Xsand_stonein_3 ? action :
5584 i == Xsand_stonein_4 ? action :
5585 i == Xsand_stoneout_1 ? action :
5586 i == Xsand_stoneout_2 ? action :
5587 i == Xboom_android ? ACTION_EXPLODING :
5588 action_exploding ? ACTION_EXPLODING :
5589 action_active ? action :
5590 action_other ? action :
5592 int graphic = (el_act_dir2img(effective_element, effective_action,
5594 int crumbled = (el_act_dir2crm(effective_element, effective_action,
5596 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
5597 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
5598 boolean has_action_graphics = (graphic != base_graphic);
5599 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
5600 struct GraphicInfo *g = &graphic_info[graphic];
5601 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
5604 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
5605 boolean special_animation = (action != ACTION_DEFAULT &&
5606 g->anim_frames == 3 &&
5607 g->anim_delay == 2 &&
5608 g->anim_mode & ANIM_LINEAR);
5609 int sync_frame = (i == Xdrip_stretch ? 7 :
5610 i == Xdrip_stretchB ? 7 :
5611 i == Ydrip_s2 ? j + 8 :
5612 i == Ydrip_s2B ? j + 8 :
5621 i == Xfake_acid_1 ? 0 :
5622 i == Xfake_acid_2 ? 10 :
5623 i == Xfake_acid_3 ? 20 :
5624 i == Xfake_acid_4 ? 30 :
5625 i == Xfake_acid_5 ? 40 :
5626 i == Xfake_acid_6 ? 50 :
5627 i == Xfake_acid_7 ? 60 :
5628 i == Xfake_acid_8 ? 70 :
5630 i == Xball_2B ? j + 8 :
5631 i == Yball_eat ? j + 1 :
5632 i == Ykey_1_eat ? j + 1 :
5633 i == Ykey_2_eat ? j + 1 :
5634 i == Ykey_3_eat ? j + 1 :
5635 i == Ykey_4_eat ? j + 1 :
5636 i == Ykey_5_eat ? j + 1 :
5637 i == Ykey_6_eat ? j + 1 :
5638 i == Ykey_7_eat ? j + 1 :
5639 i == Ykey_8_eat ? j + 1 :
5640 i == Ylenses_eat ? j + 1 :
5641 i == Ymagnify_eat ? j + 1 :
5642 i == Ygrass_eat ? j + 1 :
5643 i == Ydirt_eat ? j + 1 :
5644 i == Xamoeba_1 ? 0 :
5645 i == Xamoeba_2 ? 1 :
5646 i == Xamoeba_3 ? 2 :
5647 i == Xamoeba_4 ? 3 :
5648 i == Xamoeba_5 ? 0 :
5649 i == Xamoeba_6 ? 1 :
5650 i == Xamoeba_7 ? 2 :
5651 i == Xamoeba_8 ? 3 :
5652 i == Xexit_2 ? j + 8 :
5653 i == Xexit_3 ? j + 16 :
5654 i == Xdynamite_1 ? 0 :
5655 i == Xdynamite_2 ? 8 :
5656 i == Xdynamite_3 ? 16 :
5657 i == Xdynamite_4 ? 24 :
5658 i == Xsand_stonein_1 ? j + 1 :
5659 i == Xsand_stonein_2 ? j + 9 :
5660 i == Xsand_stonein_3 ? j + 17 :
5661 i == Xsand_stonein_4 ? j + 25 :
5662 i == Xsand_stoneout_1 && j == 0 ? 0 :
5663 i == Xsand_stoneout_1 && j == 1 ? 0 :
5664 i == Xsand_stoneout_1 && j == 2 ? 1 :
5665 i == Xsand_stoneout_1 && j == 3 ? 2 :
5666 i == Xsand_stoneout_1 && j == 4 ? 2 :
5667 i == Xsand_stoneout_1 && j == 5 ? 3 :
5668 i == Xsand_stoneout_1 && j == 6 ? 4 :
5669 i == Xsand_stoneout_1 && j == 7 ? 4 :
5670 i == Xsand_stoneout_2 && j == 0 ? 5 :
5671 i == Xsand_stoneout_2 && j == 1 ? 6 :
5672 i == Xsand_stoneout_2 && j == 2 ? 7 :
5673 i == Xsand_stoneout_2 && j == 3 ? 8 :
5674 i == Xsand_stoneout_2 && j == 4 ? 9 :
5675 i == Xsand_stoneout_2 && j == 5 ? 11 :
5676 i == Xsand_stoneout_2 && j == 6 ? 13 :
5677 i == Xsand_stoneout_2 && j == 7 ? 15 :
5678 i == Xboom_bug && j == 1 ? 2 :
5679 i == Xboom_bug && j == 2 ? 2 :
5680 i == Xboom_bug && j == 3 ? 4 :
5681 i == Xboom_bug && j == 4 ? 4 :
5682 i == Xboom_bug && j == 5 ? 2 :
5683 i == Xboom_bug && j == 6 ? 2 :
5684 i == Xboom_bug && j == 7 ? 0 :
5685 i == Xboom_bomb && j == 1 ? 2 :
5686 i == Xboom_bomb && j == 2 ? 2 :
5687 i == Xboom_bomb && j == 3 ? 4 :
5688 i == Xboom_bomb && j == 4 ? 4 :
5689 i == Xboom_bomb && j == 5 ? 2 :
5690 i == Xboom_bomb && j == 6 ? 2 :
5691 i == Xboom_bomb && j == 7 ? 0 :
5692 i == Xboom_android && j == 7 ? 6 :
5693 i == Xboom_1 && j == 1 ? 2 :
5694 i == Xboom_1 && j == 2 ? 2 :
5695 i == Xboom_1 && j == 3 ? 4 :
5696 i == Xboom_1 && j == 4 ? 4 :
5697 i == Xboom_1 && j == 5 ? 6 :
5698 i == Xboom_1 && j == 6 ? 6 :
5699 i == Xboom_1 && j == 7 ? 8 :
5700 i == Xboom_2 && j == 0 ? 8 :
5701 i == Xboom_2 && j == 1 ? 8 :
5702 i == Xboom_2 && j == 2 ? 10 :
5703 i == Xboom_2 && j == 3 ? 10 :
5704 i == Xboom_2 && j == 4 ? 10 :
5705 i == Xboom_2 && j == 5 ? 12 :
5706 i == Xboom_2 && j == 6 ? 12 :
5707 i == Xboom_2 && j == 7 ? 12 :
5708 special_animation && j == 4 ? 3 :
5709 effective_action != action ? 0 :
5713 Bitmap *debug_bitmap = g_em->bitmap;
5714 int debug_src_x = g_em->src_x;
5715 int debug_src_y = g_em->src_y;
5718 int frame = getAnimationFrame(g->anim_frames,
5721 g->anim_start_frame,
5724 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
5725 g->double_movement && is_backside);
5727 g_em->bitmap = src_bitmap;
5728 g_em->src_x = src_x;
5729 g_em->src_y = src_y;
5730 g_em->src_offset_x = 0;
5731 g_em->src_offset_y = 0;
5732 g_em->dst_offset_x = 0;
5733 g_em->dst_offset_y = 0;
5734 g_em->width = TILEX;
5735 g_em->height = TILEY;
5737 g_em->crumbled_bitmap = NULL;
5738 g_em->crumbled_src_x = 0;
5739 g_em->crumbled_src_y = 0;
5740 g_em->crumbled_border_size = 0;
5742 g_em->has_crumbled_graphics = FALSE;
5743 g_em->preserve_background = FALSE;
5746 if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
5747 printf("::: empty crumbled: %d [%s], %d, %d\n",
5748 effective_element, element_info[effective_element].token_name,
5749 effective_action, direction);
5752 /* if element can be crumbled, but certain action graphics are just empty
5753 space (like snapping sand with the original R'n'D graphics), do not
5754 treat these empty space graphics as crumbled graphics in EMC engine */
5755 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
5757 getGraphicSource(crumbled, frame, &src_bitmap, &src_x, &src_y);
5759 g_em->has_crumbled_graphics = TRUE;
5760 g_em->crumbled_bitmap = src_bitmap;
5761 g_em->crumbled_src_x = src_x;
5762 g_em->crumbled_src_y = src_y;
5763 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
5767 if (element == EL_ROCK &&
5768 effective_action == ACTION_FILLING)
5769 printf("::: has_action_graphics == %d\n", has_action_graphics);
5772 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
5773 effective_action == ACTION_MOVING ||
5774 effective_action == ACTION_PUSHING ||
5775 effective_action == ACTION_EATING)) ||
5776 (!has_action_graphics && (effective_action == ACTION_FILLING ||
5777 effective_action == ACTION_EMPTYING)))
5780 (effective_action == ACTION_FALLING ||
5781 effective_action == ACTION_FILLING ||
5782 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
5783 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
5784 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
5785 int num_steps = (i == Ydrip_s1 ? 16 :
5786 i == Ydrip_s1B ? 16 :
5787 i == Ydrip_s2 ? 16 :
5788 i == Ydrip_s2B ? 16 :
5789 i == Xsand_stonein_1 ? 32 :
5790 i == Xsand_stonein_2 ? 32 :
5791 i == Xsand_stonein_3 ? 32 :
5792 i == Xsand_stonein_4 ? 32 :
5793 i == Xsand_stoneout_1 ? 16 :
5794 i == Xsand_stoneout_2 ? 16 : 8);
5795 int cx = ABS(dx) * (TILEX / num_steps);
5796 int cy = ABS(dy) * (TILEY / num_steps);
5797 int step_frame = (i == Ydrip_s2 ? j + 8 :
5798 i == Ydrip_s2B ? j + 8 :
5799 i == Xsand_stonein_2 ? j + 8 :
5800 i == Xsand_stonein_3 ? j + 16 :
5801 i == Xsand_stonein_4 ? j + 24 :
5802 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
5803 int step = (is_backside ? step_frame : num_steps - step_frame);
5805 if (is_backside) /* tile where movement starts */
5807 if (dx < 0 || dy < 0)
5809 g_em->src_offset_x = cx * step;
5810 g_em->src_offset_y = cy * step;
5814 g_em->dst_offset_x = cx * step;
5815 g_em->dst_offset_y = cy * step;
5818 else /* tile where movement ends */
5820 if (dx < 0 || dy < 0)
5822 g_em->dst_offset_x = cx * step;
5823 g_em->dst_offset_y = cy * step;
5827 g_em->src_offset_x = cx * step;
5828 g_em->src_offset_y = cy * step;
5832 g_em->width = TILEX - cx * step;
5833 g_em->height = TILEY - cy * step;
5836 /* create unique graphic identifier to decide if tile must be redrawn */
5837 /* bit 31 - 16 (16 bit): EM style graphic
5838 bit 15 - 12 ( 4 bit): EM style frame
5839 bit 11 - 6 ( 6 bit): graphic width
5840 bit 5 - 0 ( 6 bit): graphic height */
5841 g_em->unique_identifier =
5842 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
5846 /* skip check for EMC elements not contained in original EMC artwork */
5847 if (element == EL_EMC_FAKE_ACID)
5850 if (g_em->bitmap != debug_bitmap ||
5851 g_em->src_x != debug_src_x ||
5852 g_em->src_y != debug_src_y ||
5853 g_em->src_offset_x != 0 ||
5854 g_em->src_offset_y != 0 ||
5855 g_em->dst_offset_x != 0 ||
5856 g_em->dst_offset_y != 0 ||
5857 g_em->width != TILEX ||
5858 g_em->height != TILEY)
5860 static int last_i = -1;
5868 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
5869 i, element, element_info[element].token_name,
5870 element_action_info[effective_action].suffix, direction);
5872 if (element != effective_element)
5873 printf(" [%d ('%s')]",
5875 element_info[effective_element].token_name);
5879 if (g_em->bitmap != debug_bitmap)
5880 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
5881 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
5883 if (g_em->src_x != debug_src_x ||
5884 g_em->src_y != debug_src_y)
5885 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
5886 j, (is_backside ? 'B' : 'F'),
5887 g_em->src_x, g_em->src_y,
5888 g_em->src_x / 32, g_em->src_y / 32,
5889 debug_src_x, debug_src_y,
5890 debug_src_x / 32, debug_src_y / 32);
5892 if (g_em->src_offset_x != 0 ||
5893 g_em->src_offset_y != 0 ||
5894 g_em->dst_offset_x != 0 ||
5895 g_em->dst_offset_y != 0)
5896 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
5898 g_em->src_offset_x, g_em->src_offset_y,
5899 g_em->dst_offset_x, g_em->dst_offset_y);
5901 if (g_em->width != TILEX ||
5902 g_em->height != TILEY)
5903 printf(" %d (%d): size %d,%d should be %d,%d\n",
5905 g_em->width, g_em->height, TILEX, TILEY);
5907 num_em_gfx_errors++;
5914 for (i = 0; i < TILE_MAX; i++)
5916 for (j = 0; j < 8; j++)
5918 int element = object_mapping[i].element_rnd;
5919 int action = object_mapping[i].action;
5920 int direction = object_mapping[i].direction;
5921 boolean is_backside = object_mapping[i].is_backside;
5922 int graphic_action = el_act_dir2img(element, action, direction);
5923 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
5925 if ((action == ACTION_SMASHED_BY_ROCK ||
5926 action == ACTION_SMASHED_BY_SPRING ||
5927 action == ACTION_EATING) &&
5928 graphic_action == graphic_default)
5930 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
5931 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
5932 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
5933 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
5936 /* no separate animation for "smashed by rock" -- use rock instead */
5937 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
5938 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
5940 g_em->bitmap = g_xx->bitmap;
5941 g_em->src_x = g_xx->src_x;
5942 g_em->src_y = g_xx->src_y;
5943 g_em->src_offset_x = g_xx->src_offset_x;
5944 g_em->src_offset_y = g_xx->src_offset_y;
5945 g_em->dst_offset_x = g_xx->dst_offset_x;
5946 g_em->dst_offset_y = g_xx->dst_offset_y;
5947 g_em->width = g_xx->width;
5948 g_em->height = g_xx->height;
5949 g_em->unique_identifier = g_xx->unique_identifier;
5952 g_em->preserve_background = TRUE;
5957 for (p = 0; p < MAX_PLAYERS; p++)
5959 for (i = 0; i < SPR_MAX; i++)
5961 int element = player_mapping[p][i].element_rnd;
5962 int action = player_mapping[p][i].action;
5963 int direction = player_mapping[p][i].direction;
5965 for (j = 0; j < 8; j++)
5967 int effective_element = element;
5968 int effective_action = action;
5969 int graphic = (direction == MV_NONE ?
5970 el_act2img(effective_element, effective_action) :
5971 el_act_dir2img(effective_element, effective_action,
5973 struct GraphicInfo *g = &graphic_info[graphic];
5974 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
5980 Bitmap *debug_bitmap = g_em->bitmap;
5981 int debug_src_x = g_em->src_x;
5982 int debug_src_y = g_em->src_y;
5985 int frame = getAnimationFrame(g->anim_frames,
5988 g->anim_start_frame,
5991 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x,&src_y, FALSE);
5993 g_em->bitmap = src_bitmap;
5994 g_em->src_x = src_x;
5995 g_em->src_y = src_y;
5996 g_em->src_offset_x = 0;
5997 g_em->src_offset_y = 0;
5998 g_em->dst_offset_x = 0;
5999 g_em->dst_offset_y = 0;
6000 g_em->width = TILEX;
6001 g_em->height = TILEY;
6005 /* skip check for EMC elements not contained in original EMC artwork */
6006 if (element == EL_PLAYER_3 ||
6007 element == EL_PLAYER_4)
6010 if (g_em->bitmap != debug_bitmap ||
6011 g_em->src_x != debug_src_x ||
6012 g_em->src_y != debug_src_y)
6014 static int last_i = -1;
6022 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
6023 p, i, element, element_info[element].token_name,
6024 element_action_info[effective_action].suffix, direction);
6026 if (element != effective_element)
6027 printf(" [%d ('%s')]",
6029 element_info[effective_element].token_name);
6033 if (g_em->bitmap != debug_bitmap)
6034 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
6035 j, (int)(g_em->bitmap), (int)(debug_bitmap));
6037 if (g_em->src_x != debug_src_x ||
6038 g_em->src_y != debug_src_y)
6039 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
6041 g_em->src_x, g_em->src_y,
6042 g_em->src_x / 32, g_em->src_y / 32,
6043 debug_src_x, debug_src_y,
6044 debug_src_x / 32, debug_src_y / 32);
6046 num_em_gfx_errors++;
6056 printf("::: [%d errors found]\n", num_em_gfx_errors);
6062 void PlayMenuSound()
6064 int sound = menu.sound[game_status];
6066 if (sound == SND_UNDEFINED)
6069 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6070 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6073 if (IS_LOOP_SOUND(sound))
6074 PlaySoundLoop(sound);
6079 void PlayMenuSoundStereo(int sound, int stereo_position)
6081 if (sound == SND_UNDEFINED)
6084 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6085 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6088 if (IS_LOOP_SOUND(sound))
6089 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
6091 PlaySoundStereo(sound, stereo_position);
6094 void PlayMenuSoundIfLoop()
6096 int sound = menu.sound[game_status];
6098 if (sound == SND_UNDEFINED)
6101 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6102 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6105 if (IS_LOOP_SOUND(sound))
6106 PlaySoundLoop(sound);
6109 void PlayMenuMusic()
6111 int music = menu.music[game_status];
6113 if (music == MUS_UNDEFINED)
6119 void ToggleFullscreenIfNeeded()
6121 boolean change_fullscreen = (setup.fullscreen !=
6122 video.fullscreen_enabled);
6123 boolean change_fullscreen_mode = (video.fullscreen_enabled &&
6124 !strEqual(setup.fullscreen_mode,
6125 video.fullscreen_mode_current));
6127 if (!video.fullscreen_available)
6131 if (change_fullscreen || change_fullscreen_mode)
6133 if (setup.fullscreen != video.fullscreen_enabled ||
6134 setup.fullscreen_mode != video.fullscreen_mode_current)
6137 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
6139 /* save backbuffer content which gets lost when toggling fullscreen mode */
6140 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6143 if (change_fullscreen_mode)
6145 if (setup.fullscreen && video.fullscreen_enabled)
6148 /* keep fullscreen, but change fullscreen mode (screen resolution) */
6150 /* (this is now set in sdl.c) */
6152 video.fullscreen_mode_current = setup.fullscreen_mode;
6154 video.fullscreen_enabled = FALSE; /* force new fullscreen mode */
6157 /* toggle fullscreen */
6158 ChangeVideoModeIfNeeded(setup.fullscreen);
6160 setup.fullscreen = video.fullscreen_enabled;
6162 /* restore backbuffer content from temporary backbuffer backup bitmap */
6163 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6165 FreeBitmap(tmp_backbuffer);
6168 /* update visible window/screen */
6169 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6171 redraw_mask = REDRAW_ALL;