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)
1736 int text_width = getTextWidth(label_text, font_nr);
1737 int lxpos = SX + menu.main.text.level_info_2.x - text_width / 2;
1738 int lypos = SY + menu.main.text.level_info_2.y;
1740 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1741 int lypos = MICROLABEL2_YPOS;
1744 DrawText(lxpos, lypos, label_text, font_nr);
1748 (mode == MICROLABEL_LEVEL_NAME ? level.name :
1749 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
1750 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1751 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
1752 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
1753 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
1754 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
1755 max_len_label_text);
1756 label_text[max_len_label_text] = '\0';
1758 if (strlen(label_text) > 0)
1761 int text_width = getTextWidth(label_text, font_nr);
1762 int lxpos = SX + menu.main.text.level_info_2.x - text_width / 2;
1763 int lypos = SY + menu.main.text.level_info_2.y;
1765 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1766 int lypos = MICROLABEL2_YPOS;
1769 DrawText(lxpos, lypos, label_text, font_nr);
1772 redraw_mask |= REDRAW_MICROLEVEL;
1775 void DrawPreviewLevel(boolean restart)
1777 static unsigned long scroll_delay = 0;
1778 static unsigned long label_delay = 0;
1779 static int from_x, from_y, scroll_direction;
1780 static int label_state, label_counter;
1781 unsigned long scroll_delay_value = preview.step_delay;
1782 boolean show_level_border = (BorderElement != EL_EMPTY);
1783 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
1784 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
1785 int last_game_status = game_status; /* save current game status */
1787 /* force PREVIEW font on preview level */
1788 game_status = GAME_MODE_PSEUDO_PREVIEW;
1792 from_x = preview.xoffset;
1793 from_y = preview.yoffset;
1794 scroll_direction = MV_RIGHT;
1798 DrawPreviewLevelExt(from_x, from_y);
1799 DrawPreviewLevelLabelExt(label_state);
1801 /* initialize delay counters */
1802 DelayReached(&scroll_delay, 0);
1803 DelayReached(&label_delay, 0);
1805 if (leveldir_current->name)
1807 char label_text[MAX_OUTPUT_LINESIZE + 1];
1808 int font_nr = FONT_TEXT_1;
1809 int max_len_label_text = SXSIZE / getFontWidth(font_nr);
1813 strncpy(label_text, leveldir_current->name, max_len_label_text);
1814 label_text[max_len_label_text] = '\0';
1817 text_width = getTextWidth(label_text, font_nr);
1818 lxpos = SX + menu.main.text.level_info_1.x - text_width / 2;
1819 lypos = SY + menu.main.text.level_info_1.y;
1821 lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1822 lypos = SY + MICROLABEL1_YPOS;
1825 DrawText(lxpos, lypos, label_text, font_nr);
1828 game_status = last_game_status; /* restore current game status */
1833 /* scroll preview level, if needed */
1834 if ((level_xsize > preview.xsize || level_ysize > preview.ysize) &&
1835 DelayReached(&scroll_delay, scroll_delay_value))
1837 switch (scroll_direction)
1842 from_x -= preview.step_offset;
1843 from_x = (from_x < 0 ? 0 : from_x);
1846 scroll_direction = MV_UP;
1850 if (from_x < level_xsize - preview.xsize)
1852 from_x += preview.step_offset;
1853 from_x = (from_x > level_xsize - preview.xsize ?
1854 level_xsize - preview.xsize : from_x);
1857 scroll_direction = MV_DOWN;
1863 from_y -= preview.step_offset;
1864 from_y = (from_y < 0 ? 0 : from_y);
1867 scroll_direction = MV_RIGHT;
1871 if (from_y < level_ysize - preview.ysize)
1873 from_y += preview.step_offset;
1874 from_y = (from_y > level_ysize - preview.ysize ?
1875 level_ysize - preview.ysize : from_y);
1878 scroll_direction = MV_LEFT;
1885 DrawPreviewLevelExt(from_x, from_y);
1888 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
1889 /* redraw micro level label, if needed */
1890 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
1891 !strEqual(level.author, ANONYMOUS_NAME) &&
1892 !strEqual(level.author, leveldir_current->name) &&
1893 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
1895 int max_label_counter = 23;
1897 if (leveldir_current->imported_from != NULL &&
1898 strlen(leveldir_current->imported_from) > 0)
1899 max_label_counter += 14;
1900 if (leveldir_current->imported_by != NULL &&
1901 strlen(leveldir_current->imported_by) > 0)
1902 max_label_counter += 14;
1904 label_counter = (label_counter + 1) % max_label_counter;
1905 label_state = (label_counter >= 0 && label_counter <= 7 ?
1906 MICROLABEL_LEVEL_NAME :
1907 label_counter >= 9 && label_counter <= 12 ?
1908 MICROLABEL_LEVEL_AUTHOR_HEAD :
1909 label_counter >= 14 && label_counter <= 21 ?
1910 MICROLABEL_LEVEL_AUTHOR :
1911 label_counter >= 23 && label_counter <= 26 ?
1912 MICROLABEL_IMPORTED_FROM_HEAD :
1913 label_counter >= 28 && label_counter <= 35 ?
1914 MICROLABEL_IMPORTED_FROM :
1915 label_counter >= 37 && label_counter <= 40 ?
1916 MICROLABEL_IMPORTED_BY_HEAD :
1917 label_counter >= 42 && label_counter <= 49 ?
1918 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
1920 if (leveldir_current->imported_from == NULL &&
1921 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
1922 label_state == MICROLABEL_IMPORTED_FROM))
1923 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
1924 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
1926 DrawPreviewLevelLabelExt(label_state);
1929 game_status = last_game_status; /* restore current game status */
1932 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
1933 int graphic, int sync_frame, int mask_mode)
1935 int frame = getGraphicAnimationFrame(graphic, sync_frame);
1937 if (mask_mode == USE_MASKING)
1938 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
1940 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
1943 inline void DrawGraphicAnimation(int x, int y, int graphic)
1945 int lx = LEVELX(x), ly = LEVELY(y);
1947 if (!IN_SCR_FIELD(x, y))
1950 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
1951 graphic, GfxFrame[lx][ly], NO_MASKING);
1952 MarkTileDirty(x, y);
1955 void DrawLevelGraphicAnimation(int x, int y, int graphic)
1957 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
1960 void DrawLevelElementAnimation(int x, int y, int element)
1962 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
1964 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
1967 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
1969 int sx = SCREENX(x), sy = SCREENY(y);
1971 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
1974 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
1977 DrawGraphicAnimation(sx, sy, graphic);
1980 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
1981 DrawLevelFieldCrumbledSand(x, y);
1983 if (GFX_CRUMBLED(Feld[x][y]))
1984 DrawLevelFieldCrumbledSand(x, y);
1988 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
1990 int sx = SCREENX(x), sy = SCREENY(y);
1993 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
1996 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
1998 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2001 DrawGraphicAnimation(sx, sy, graphic);
2003 if (GFX_CRUMBLED(element))
2004 DrawLevelFieldCrumbledSand(x, y);
2007 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
2009 if (player->use_murphy)
2011 /* this works only because currently only one player can be "murphy" ... */
2012 static int last_horizontal_dir = MV_LEFT;
2013 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
2015 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2016 last_horizontal_dir = move_dir;
2018 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
2020 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
2022 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
2028 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
2031 static boolean equalGraphics(int graphic1, int graphic2)
2033 struct GraphicInfo *g1 = &graphic_info[graphic1];
2034 struct GraphicInfo *g2 = &graphic_info[graphic2];
2036 return (g1->bitmap == g2->bitmap &&
2037 g1->src_x == g2->src_x &&
2038 g1->src_y == g2->src_y &&
2039 g1->anim_frames == g2->anim_frames &&
2040 g1->anim_delay == g2->anim_delay &&
2041 g1->anim_mode == g2->anim_mode);
2044 void DrawAllPlayers()
2048 for (i = 0; i < MAX_PLAYERS; i++)
2049 if (stored_player[i].active)
2050 DrawPlayer(&stored_player[i]);
2053 void DrawPlayerField(int x, int y)
2055 if (!IS_PLAYER(x, y))
2058 DrawPlayer(PLAYERINFO(x, y));
2061 void DrawPlayer(struct PlayerInfo *player)
2063 int jx = player->jx;
2064 int jy = player->jy;
2065 int move_dir = player->MovDir;
2066 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
2067 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
2068 int last_jx = (player->is_moving ? jx - dx : jx);
2069 int last_jy = (player->is_moving ? jy - dy : jy);
2070 int next_jx = jx + dx;
2071 int next_jy = jy + dy;
2072 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
2073 boolean player_is_opaque = FALSE;
2074 int sx = SCREENX(jx), sy = SCREENY(jy);
2075 int sxx = 0, syy = 0;
2076 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
2078 int action = ACTION_DEFAULT;
2079 int last_player_graphic = getPlayerGraphic(player, move_dir);
2080 int last_player_frame = player->Frame;
2083 /* GfxElement[][] is set to the element the player is digging or collecting;
2084 remove also for off-screen player if the player is not moving anymore */
2085 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
2086 GfxElement[jx][jy] = EL_UNDEFINED;
2088 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
2092 if (!IN_LEV_FIELD(jx, jy))
2094 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
2095 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
2096 printf("DrawPlayerField(): This should never happen!\n");
2101 if (element == EL_EXPLOSION)
2104 action = (player->is_pushing ? ACTION_PUSHING :
2105 player->is_digging ? ACTION_DIGGING :
2106 player->is_collecting ? ACTION_COLLECTING :
2107 player->is_moving ? ACTION_MOVING :
2108 player->is_snapping ? ACTION_SNAPPING :
2109 player->is_dropping ? ACTION_DROPPING :
2110 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
2112 if (player->is_waiting)
2113 move_dir = player->dir_waiting;
2115 InitPlayerGfxAnimation(player, action, move_dir);
2117 /* ----------------------------------------------------------------------- */
2118 /* draw things in the field the player is leaving, if needed */
2119 /* ----------------------------------------------------------------------- */
2121 if (player->is_moving)
2123 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
2125 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
2127 if (last_element == EL_DYNAMITE_ACTIVE ||
2128 last_element == EL_EM_DYNAMITE_ACTIVE ||
2129 last_element == EL_SP_DISK_RED_ACTIVE)
2130 DrawDynamite(last_jx, last_jy);
2132 DrawLevelFieldThruMask(last_jx, last_jy);
2134 else if (last_element == EL_DYNAMITE_ACTIVE ||
2135 last_element == EL_EM_DYNAMITE_ACTIVE ||
2136 last_element == EL_SP_DISK_RED_ACTIVE)
2137 DrawDynamite(last_jx, last_jy);
2139 /* !!! this is not enough to prevent flickering of players which are
2140 moving next to each others without a free tile between them -- this
2141 can only be solved by drawing all players layer by layer (first the
2142 background, then the foreground etc.) !!! => TODO */
2143 else if (!IS_PLAYER(last_jx, last_jy))
2144 DrawLevelField(last_jx, last_jy);
2147 DrawLevelField(last_jx, last_jy);
2150 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
2151 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
2154 if (!IN_SCR_FIELD(sx, sy))
2157 if (setup.direct_draw)
2158 SetDrawtoField(DRAW_BUFFERED);
2160 /* ----------------------------------------------------------------------- */
2161 /* draw things behind the player, if needed */
2162 /* ----------------------------------------------------------------------- */
2165 DrawLevelElement(jx, jy, Back[jx][jy]);
2166 else if (IS_ACTIVE_BOMB(element))
2167 DrawLevelElement(jx, jy, EL_EMPTY);
2170 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
2172 int old_element = GfxElement[jx][jy];
2173 int old_graphic = el_act_dir2img(old_element, action, move_dir);
2174 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
2176 if (GFX_CRUMBLED(old_element))
2177 DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
2179 DrawGraphic(sx, sy, old_graphic, frame);
2181 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
2182 player_is_opaque = TRUE;
2186 GfxElement[jx][jy] = EL_UNDEFINED;
2188 /* make sure that pushed elements are drawn with correct frame rate */
2190 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2192 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
2193 GfxFrame[jx][jy] = player->StepFrame;
2195 if (player->is_pushing && player->is_moving)
2196 GfxFrame[jx][jy] = player->StepFrame;
2199 DrawLevelField(jx, jy);
2203 /* ----------------------------------------------------------------------- */
2204 /* draw player himself */
2205 /* ----------------------------------------------------------------------- */
2207 graphic = getPlayerGraphic(player, move_dir);
2209 /* in the case of changed player action or direction, prevent the current
2210 animation frame from being restarted for identical animations */
2211 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
2212 player->Frame = last_player_frame;
2214 frame = getGraphicAnimationFrame(graphic, player->Frame);
2218 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2219 sxx = player->GfxPos;
2221 syy = player->GfxPos;
2224 if (!setup.soft_scrolling && ScreenMovPos)
2227 if (player_is_opaque)
2228 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
2230 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2232 if (SHIELD_ON(player))
2234 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
2235 IMG_SHIELD_NORMAL_ACTIVE);
2236 int frame = getGraphicAnimationFrame(graphic, -1);
2238 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2241 /* ----------------------------------------------------------------------- */
2242 /* draw things the player is pushing, if needed */
2243 /* ----------------------------------------------------------------------- */
2246 printf("::: %d, %d [%d, %d] [%d]\n",
2247 player->is_pushing, player_is_moving, player->GfxAction,
2248 player->is_moving, player_is_moving);
2252 if (player->is_pushing && player->is_moving)
2254 int px = SCREENX(jx), py = SCREENY(jy);
2255 int pxx = (TILEX - ABS(sxx)) * dx;
2256 int pyy = (TILEY - ABS(syy)) * dy;
2257 int gfx_frame = GfxFrame[jx][jy];
2263 if (!IS_MOVING(jx, jy)) /* push movement already finished */
2265 element = Feld[next_jx][next_jy];
2266 gfx_frame = GfxFrame[next_jx][next_jy];
2269 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2272 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
2273 frame = getGraphicAnimationFrame(graphic, sync_frame);
2275 frame = getGraphicAnimationFrame(graphic, player->StepFrame);
2278 /* draw background element under pushed element (like the Sokoban field) */
2279 if (Back[next_jx][next_jy])
2280 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
2282 /* masked drawing is needed for EMC style (double) movement graphics */
2283 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
2287 /* ----------------------------------------------------------------------- */
2288 /* draw things in front of player (active dynamite or dynabombs) */
2289 /* ----------------------------------------------------------------------- */
2291 if (IS_ACTIVE_BOMB(element))
2293 graphic = el2img(element);
2294 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
2296 if (game.emulation == EMU_SUPAPLEX)
2297 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
2299 DrawGraphicThruMask(sx, sy, graphic, frame);
2302 if (player_is_moving && last_element == EL_EXPLOSION)
2304 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
2305 GfxElement[last_jx][last_jy] : EL_EMPTY);
2306 int graphic = el_act2img(element, ACTION_EXPLODING);
2307 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
2308 int phase = ExplodePhase[last_jx][last_jy] - 1;
2309 int frame = getGraphicAnimationFrame(graphic, phase - delay);
2312 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
2315 /* ----------------------------------------------------------------------- */
2316 /* draw elements the player is just walking/passing through/under */
2317 /* ----------------------------------------------------------------------- */
2319 if (player_is_moving)
2321 /* handle the field the player is leaving ... */
2322 if (IS_ACCESSIBLE_INSIDE(last_element))
2323 DrawLevelField(last_jx, last_jy);
2324 else if (IS_ACCESSIBLE_UNDER(last_element))
2325 DrawLevelFieldThruMask(last_jx, last_jy);
2328 /* do not redraw accessible elements if the player is just pushing them */
2329 if (!player_is_moving || !player->is_pushing)
2331 /* ... and the field the player is entering */
2332 if (IS_ACCESSIBLE_INSIDE(element))
2333 DrawLevelField(jx, jy);
2334 else if (IS_ACCESSIBLE_UNDER(element))
2335 DrawLevelFieldThruMask(jx, jy);
2338 if (setup.direct_draw)
2340 int dst_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
2341 int dst_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
2342 int x_size = TILEX * (1 + ABS(jx - last_jx));
2343 int y_size = TILEY * (1 + ABS(jy - last_jy));
2345 BlitBitmap(drawto_field, window,
2346 dst_x, dst_y, x_size, y_size, dst_x, dst_y);
2347 SetDrawtoField(DRAW_DIRECT);
2350 MarkTileDirty(sx, sy);
2353 /* ------------------------------------------------------------------------- */
2355 void WaitForEventToContinue()
2357 boolean still_wait = TRUE;
2359 /* simulate releasing mouse button over last gadget, if still pressed */
2361 HandleGadgets(-1, -1, 0);
2363 button_status = MB_RELEASED;
2379 case EVENT_BUTTONPRESS:
2380 case EVENT_KEYPRESS:
2384 case EVENT_KEYRELEASE:
2385 ClearPlayerAction();
2389 HandleOtherEvents(&event);
2393 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2400 /* don't eat all CPU time */
2405 #define MAX_REQUEST_LINES 13
2406 #define MAX_REQUEST_LINE_FONT1_LEN 7
2407 #define MAX_REQUEST_LINE_FONT2_LEN 10
2409 boolean Request(char *text, unsigned int req_state)
2411 int mx, my, ty, result = -1;
2412 unsigned int old_door_state;
2413 int last_game_status = game_status; /* save current game status */
2414 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
2415 int font_nr = FONT_TEXT_2;
2416 int max_word_len = 0;
2419 for (text_ptr = text; *text_ptr; text_ptr++)
2421 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
2423 if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
2425 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
2426 font_nr = FONT_LEVEL_NUMBER;
2432 if (game_status == GAME_MODE_PLAYING &&
2433 level.game_engine_type == GAME_ENGINE_TYPE_EM)
2434 BlitScreenToBitmap_EM(backbuffer);
2436 /* disable deactivated drawing when quick-loading level tape recording */
2437 if (tape.playing && tape.deactivate_display)
2438 TapeDeactivateDisplayOff(TRUE);
2440 SetMouseCursor(CURSOR_DEFAULT);
2442 #if defined(NETWORK_AVALIABLE)
2443 /* pause network game while waiting for request to answer */
2444 if (options.network &&
2445 game_status == GAME_MODE_PLAYING &&
2446 req_state & REQUEST_WAIT_FOR_INPUT)
2447 SendToServer_PausePlaying();
2450 old_door_state = GetDoorState();
2452 /* simulate releasing mouse button over last gadget, if still pressed */
2454 HandleGadgets(-1, -1, 0);
2458 if (old_door_state & DOOR_OPEN_1)
2460 CloseDoor(DOOR_CLOSE_1);
2462 /* save old door content */
2463 BlitBitmap(bitmap_db_door, bitmap_db_door,
2464 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2465 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
2469 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2472 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2474 /* clear door drawing field */
2475 DrawBackground(DX, DY, DXSIZE, DYSIZE);
2477 /* force DOOR font on preview level */
2478 game_status = GAME_MODE_PSEUDO_DOOR;
2480 /* write text for request */
2481 for (ty = 0; ty < MAX_REQUEST_LINES; ty++)
2483 char text_line[max_request_line_len + 1];
2489 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
2492 if (!tc || tc == ' ')
2503 strncpy(text_line, text, tl);
2506 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
2507 DY + 8 + ty * (getFontHeight(font_nr) + 2),
2508 text_line, font_nr);
2510 text += tl + (tc == ' ' ? 1 : 0);
2513 game_status = last_game_status; /* restore current game status */
2515 if (req_state & REQ_ASK)
2517 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2518 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2520 else if (req_state & REQ_CONFIRM)
2522 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2524 else if (req_state & REQ_PLAYER)
2526 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2527 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2528 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2529 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2532 /* copy request gadgets to door backbuffer */
2533 BlitBitmap(drawto, bitmap_db_door,
2534 DX, DY, DXSIZE, DYSIZE,
2535 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2537 OpenDoor(DOOR_OPEN_1);
2539 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
2541 if (game_status == GAME_MODE_PLAYING)
2543 SetPanelBackground();
2544 SetDrawBackgroundMask(REDRAW_DOOR_1);
2548 SetDrawBackgroundMask(REDRAW_FIELD);
2554 if (game_status != GAME_MODE_MAIN)
2557 button_status = MB_RELEASED;
2559 request_gadget_id = -1;
2561 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2573 case EVENT_BUTTONPRESS:
2574 case EVENT_BUTTONRELEASE:
2575 case EVENT_MOTIONNOTIFY:
2577 if (event.type == EVENT_MOTIONNOTIFY)
2579 if (!PointerInWindow(window))
2580 continue; /* window and pointer are on different screens */
2585 motion_status = TRUE;
2586 mx = ((MotionEvent *) &event)->x;
2587 my = ((MotionEvent *) &event)->y;
2591 motion_status = FALSE;
2592 mx = ((ButtonEvent *) &event)->x;
2593 my = ((ButtonEvent *) &event)->y;
2594 if (event.type == EVENT_BUTTONPRESS)
2595 button_status = ((ButtonEvent *) &event)->button;
2597 button_status = MB_RELEASED;
2600 /* this sets 'request_gadget_id' */
2601 HandleGadgets(mx, my, button_status);
2603 switch(request_gadget_id)
2605 case TOOL_CTRL_ID_YES:
2608 case TOOL_CTRL_ID_NO:
2611 case TOOL_CTRL_ID_CONFIRM:
2612 result = TRUE | FALSE;
2615 case TOOL_CTRL_ID_PLAYER_1:
2618 case TOOL_CTRL_ID_PLAYER_2:
2621 case TOOL_CTRL_ID_PLAYER_3:
2624 case TOOL_CTRL_ID_PLAYER_4:
2635 case EVENT_KEYPRESS:
2636 switch(GetEventKey((KeyEvent *)&event, TRUE))
2649 if (req_state & REQ_PLAYER)
2653 case EVENT_KEYRELEASE:
2654 ClearPlayerAction();
2658 HandleOtherEvents(&event);
2662 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2664 int joy = AnyJoystick();
2666 if (joy & JOY_BUTTON_1)
2668 else if (joy & JOY_BUTTON_2)
2675 if (!PendingEvent()) /* delay only if no pending events */
2678 /* don't eat all CPU time */
2683 if (game_status != GAME_MODE_MAIN)
2688 if (!(req_state & REQ_STAY_OPEN))
2690 CloseDoor(DOOR_CLOSE_1);
2692 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
2693 (req_state & REQ_REOPEN))
2694 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
2699 if (game_status == GAME_MODE_PLAYING)
2701 SetPanelBackground();
2702 SetDrawBackgroundMask(REDRAW_DOOR_1);
2706 SetDrawBackgroundMask(REDRAW_FIELD);
2709 #if defined(NETWORK_AVALIABLE)
2710 /* continue network game after request */
2711 if (options.network &&
2712 game_status == GAME_MODE_PLAYING &&
2713 req_state & REQUEST_WAIT_FOR_INPUT)
2714 SendToServer_ContinuePlaying();
2717 /* restore deactivated drawing when quick-loading level tape recording */
2718 if (tape.playing && tape.deactivate_display)
2719 TapeDeactivateDisplayOn();
2724 unsigned int OpenDoor(unsigned int door_state)
2726 if (door_state & DOOR_COPY_BACK)
2728 if (door_state & DOOR_OPEN_1)
2729 BlitBitmap(bitmap_db_door, bitmap_db_door,
2730 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2731 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2733 if (door_state & DOOR_OPEN_2)
2734 BlitBitmap(bitmap_db_door, bitmap_db_door,
2735 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
2736 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2738 door_state &= ~DOOR_COPY_BACK;
2741 return MoveDoor(door_state);
2744 unsigned int CloseDoor(unsigned int door_state)
2746 unsigned int old_door_state = GetDoorState();
2748 if (!(door_state & DOOR_NO_COPY_BACK))
2750 if (old_door_state & DOOR_OPEN_1)
2751 BlitBitmap(backbuffer, bitmap_db_door,
2752 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2754 if (old_door_state & DOOR_OPEN_2)
2755 BlitBitmap(backbuffer, bitmap_db_door,
2756 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2758 door_state &= ~DOOR_NO_COPY_BACK;
2761 return MoveDoor(door_state);
2764 unsigned int GetDoorState()
2766 return MoveDoor(DOOR_GET_STATE);
2769 unsigned int SetDoorState(unsigned int door_state)
2771 return MoveDoor(door_state | DOOR_SET_STATE);
2774 unsigned int MoveDoor(unsigned int door_state)
2776 static int door1 = DOOR_OPEN_1;
2777 static int door2 = DOOR_CLOSE_2;
2778 unsigned long door_delay = 0;
2779 unsigned long door_delay_value;
2782 if (door_1.width < 0 || door_1.width > DXSIZE)
2783 door_1.width = DXSIZE;
2784 if (door_1.height < 0 || door_1.height > DYSIZE)
2785 door_1.height = DYSIZE;
2786 if (door_2.width < 0 || door_2.width > VXSIZE)
2787 door_2.width = VXSIZE;
2788 if (door_2.height < 0 || door_2.height > VYSIZE)
2789 door_2.height = VYSIZE;
2791 if (door_state == DOOR_GET_STATE)
2792 return (door1 | door2);
2794 if (door_state & DOOR_SET_STATE)
2796 if (door_state & DOOR_ACTION_1)
2797 door1 = door_state & DOOR_ACTION_1;
2798 if (door_state & DOOR_ACTION_2)
2799 door2 = door_state & DOOR_ACTION_2;
2801 return (door1 | door2);
2804 if (!(door_state & DOOR_FORCE_REDRAW))
2806 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2807 door_state &= ~DOOR_OPEN_1;
2808 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2809 door_state &= ~DOOR_CLOSE_1;
2810 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2811 door_state &= ~DOOR_OPEN_2;
2812 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2813 door_state &= ~DOOR_CLOSE_2;
2816 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
2819 if (setup.quick_doors)
2821 stepsize = 20; /* must be choosen to always draw last frame */
2822 door_delay_value = 0;
2825 if (global.autoplay_leveldir)
2827 door_state |= DOOR_NO_DELAY;
2828 door_state &= ~DOOR_CLOSE_ALL;
2831 if (door_state & DOOR_ACTION)
2833 boolean handle_door_1 = (door_state & DOOR_ACTION_1);
2834 boolean handle_door_2 = (door_state & DOOR_ACTION_2);
2835 boolean door_1_done = (!handle_door_1);
2836 boolean door_2_done = (!handle_door_2);
2837 boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
2838 boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
2839 int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
2840 int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
2841 int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
2842 int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
2843 int door_size = (handle_door_1 ? door_size_1 : door_size_2);
2844 int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
2845 int door_skip = max_door_size - door_size;
2846 int end = door_size;
2847 int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
2850 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
2852 /* opening door sound has priority over simultaneously closing door */
2853 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2854 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2855 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2856 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2859 for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
2862 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2863 GC gc = bitmap->stored_clip_gc;
2865 if (door_state & DOOR_ACTION_1)
2867 int a = MIN(x * door_1.step_offset, end);
2868 int p = (door_state & DOOR_OPEN_1 ? end - a : a);
2869 int i = p + door_skip;
2871 if (door_1.anim_mode & ANIM_STATIC_PANEL)
2873 BlitBitmap(bitmap_db_door, drawto,
2874 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
2875 DXSIZE, DYSIZE, DX, DY);
2879 BlitBitmap(bitmap_db_door, drawto,
2880 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
2881 DXSIZE, DYSIZE - p / 2, DX, DY);
2883 ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
2886 if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
2888 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2889 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
2890 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
2891 int dst2_x = DX, dst2_y = DY;
2892 int width = i, height = DYSIZE;
2894 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2895 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2898 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2899 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2902 else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
2904 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2905 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
2906 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
2907 int dst2_x = DX, dst2_y = DY;
2908 int width = DXSIZE, height = i;
2910 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2911 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2914 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2915 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2918 else if (x <= DXSIZE) /* ANIM_DEFAULT */
2920 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
2922 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2923 BlitBitmapMasked(bitmap, drawto,
2924 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2925 DX + DXSIZE - i, DY + j);
2926 BlitBitmapMasked(bitmap, drawto,
2927 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2928 DX + DXSIZE - i, DY + 140 + j);
2929 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
2930 DY - (DOOR_GFX_PAGEY1 + j));
2931 BlitBitmapMasked(bitmap, drawto,
2932 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2934 BlitBitmapMasked(bitmap, drawto,
2935 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
2938 BlitBitmapMasked(bitmap, drawto,
2939 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2941 BlitBitmapMasked(bitmap, drawto,
2942 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2944 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2945 BlitBitmapMasked(bitmap, drawto,
2946 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2947 DX + DXSIZE - i, DY + 77 + j);
2948 BlitBitmapMasked(bitmap, drawto,
2949 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2950 DX + DXSIZE - i, DY + 203 + j);
2953 redraw_mask |= REDRAW_DOOR_1;
2954 door_1_done = (a == end);
2957 if (door_state & DOOR_ACTION_2)
2959 int a = MIN(x * door_2.step_offset, door_size);
2960 int p = (door_state & DOOR_OPEN_2 ? door_size - a : a);
2961 int i = p + door_skip;
2963 if (door_2.anim_mode & ANIM_STATIC_PANEL)
2965 BlitBitmap(bitmap_db_door, drawto,
2966 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
2967 VXSIZE, VYSIZE, VX, VY);
2969 else if (x <= VYSIZE)
2971 BlitBitmap(bitmap_db_door, drawto,
2972 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
2973 VXSIZE, VYSIZE - p / 2, VX, VY);
2975 ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
2978 if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
2980 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
2981 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
2982 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
2983 int dst2_x = VX, dst2_y = VY;
2984 int width = i, height = VYSIZE;
2986 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2987 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2990 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2991 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2994 else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
2996 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
2997 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
2998 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
2999 int dst2_x = VX, dst2_y = VY;
3000 int width = VXSIZE, height = i;
3002 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3003 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3006 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3007 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3010 else if (x <= VXSIZE) /* ANIM_DEFAULT */
3012 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
3014 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3015 BlitBitmapMasked(bitmap, drawto,
3016 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
3017 VX + VXSIZE - i, VY + j);
3018 SetClipOrigin(bitmap, gc,
3019 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
3020 BlitBitmapMasked(bitmap, drawto,
3021 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
3024 BlitBitmapMasked(bitmap, drawto,
3025 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3026 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
3027 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3028 BlitBitmapMasked(bitmap, drawto,
3029 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3031 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
3034 redraw_mask |= REDRAW_DOOR_2;
3035 door_2_done = (a == VXSIZE);
3038 if (!(door_state & DOOR_NO_DELAY))
3042 if (game_status == GAME_MODE_MAIN)
3045 WaitUntilDelayReached(&door_delay, door_delay_value);
3050 if (door_state & DOOR_ACTION_1)
3051 door1 = door_state & DOOR_ACTION_1;
3052 if (door_state & DOOR_ACTION_2)
3053 door2 = door_state & DOOR_ACTION_2;
3055 return (door1 | door2);
3058 void DrawSpecialEditorDoor()
3060 /* draw bigger toolbox window */
3061 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
3062 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
3064 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3065 EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
3068 redraw_mask |= REDRAW_ALL;
3071 void UndrawSpecialEditorDoor()
3073 /* draw normal tape recorder window */
3074 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3075 EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
3078 redraw_mask |= REDRAW_ALL;
3082 /* ---------- new tool button stuff ---------------------------------------- */
3084 /* graphic position values for tool buttons */
3085 #define TOOL_BUTTON_YES_XPOS 2
3086 #define TOOL_BUTTON_YES_YPOS 250
3087 #define TOOL_BUTTON_YES_GFX_YPOS 0
3088 #define TOOL_BUTTON_YES_XSIZE 46
3089 #define TOOL_BUTTON_YES_YSIZE 28
3090 #define TOOL_BUTTON_NO_XPOS 52
3091 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
3092 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
3093 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
3094 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
3095 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
3096 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
3097 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
3098 #define TOOL_BUTTON_CONFIRM_XSIZE 96
3099 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
3100 #define TOOL_BUTTON_PLAYER_XSIZE 30
3101 #define TOOL_BUTTON_PLAYER_YSIZE 30
3102 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
3103 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
3104 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
3105 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
3106 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3107 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3108 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3109 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3110 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3111 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3112 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3113 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3114 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3115 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3116 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3117 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3118 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3119 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3120 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3121 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3130 } toolbutton_info[NUM_TOOL_BUTTONS] =
3133 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
3134 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
3135 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
3140 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
3141 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
3142 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
3147 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
3148 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
3149 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
3150 TOOL_CTRL_ID_CONFIRM,
3154 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3155 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
3156 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3157 TOOL_CTRL_ID_PLAYER_1,
3161 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3162 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
3163 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3164 TOOL_CTRL_ID_PLAYER_2,
3168 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3169 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
3170 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3171 TOOL_CTRL_ID_PLAYER_3,
3175 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3176 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
3177 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3178 TOOL_CTRL_ID_PLAYER_4,
3183 void CreateToolButtons()
3187 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3189 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3190 Bitmap *deco_bitmap = None;
3191 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
3192 struct GadgetInfo *gi;
3193 unsigned long event_mask;
3194 int gd_xoffset, gd_yoffset;
3195 int gd_x1, gd_x2, gd_y;
3198 event_mask = GD_EVENT_RELEASED;
3200 gd_xoffset = toolbutton_info[i].xpos;
3201 gd_yoffset = toolbutton_info[i].ypos;
3202 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
3203 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
3204 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
3206 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
3208 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
3210 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
3211 &deco_bitmap, &deco_x, &deco_y);
3212 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
3213 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
3216 gi = CreateGadget(GDI_CUSTOM_ID, id,
3217 GDI_INFO_TEXT, toolbutton_info[i].infotext,
3218 GDI_X, DX + toolbutton_info[i].x,
3219 GDI_Y, DY + toolbutton_info[i].y,
3220 GDI_WIDTH, toolbutton_info[i].width,
3221 GDI_HEIGHT, toolbutton_info[i].height,
3222 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
3223 GDI_STATE, GD_BUTTON_UNPRESSED,
3224 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
3225 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
3226 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
3227 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
3228 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
3229 GDI_DECORATION_SHIFTING, 1, 1,
3230 GDI_DIRECT_DRAW, FALSE,
3231 GDI_EVENT_MASK, event_mask,
3232 GDI_CALLBACK_ACTION, HandleToolButtons,
3236 Error(ERR_EXIT, "cannot create gadget");
3238 tool_gadget[id] = gi;
3242 void FreeToolButtons()
3246 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3247 FreeGadget(tool_gadget[i]);
3250 static void UnmapToolButtons()
3254 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3255 UnmapGadget(tool_gadget[i]);
3258 static void HandleToolButtons(struct GadgetInfo *gi)
3260 request_gadget_id = gi->custom_id;
3263 static struct Mapping_EM_to_RND_object
3266 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
3267 boolean is_backside; /* backside of moving element */
3273 em_object_mapping_list[] =
3276 Xblank, TRUE, FALSE,
3280 Yacid_splash_eB, FALSE, FALSE,
3281 EL_ACID_SPLASH_RIGHT, -1, -1
3284 Yacid_splash_wB, FALSE, FALSE,
3285 EL_ACID_SPLASH_LEFT, -1, -1
3288 #ifdef EM_ENGINE_BAD_ROLL
3290 Xstone_force_e, FALSE, FALSE,
3291 EL_ROCK, -1, MV_BIT_RIGHT
3294 Xstone_force_w, FALSE, FALSE,
3295 EL_ROCK, -1, MV_BIT_LEFT
3298 Xnut_force_e, FALSE, FALSE,
3299 EL_NUT, -1, MV_BIT_RIGHT
3302 Xnut_force_w, FALSE, FALSE,
3303 EL_NUT, -1, MV_BIT_LEFT
3306 Xspring_force_e, FALSE, FALSE,
3307 EL_SPRING, -1, MV_BIT_RIGHT
3310 Xspring_force_w, FALSE, FALSE,
3311 EL_SPRING, -1, MV_BIT_LEFT
3314 Xemerald_force_e, FALSE, FALSE,
3315 EL_EMERALD, -1, MV_BIT_RIGHT
3318 Xemerald_force_w, FALSE, FALSE,
3319 EL_EMERALD, -1, MV_BIT_LEFT
3322 Xdiamond_force_e, FALSE, FALSE,
3323 EL_DIAMOND, -1, MV_BIT_RIGHT
3326 Xdiamond_force_w, FALSE, FALSE,
3327 EL_DIAMOND, -1, MV_BIT_LEFT
3330 Xbomb_force_e, FALSE, FALSE,
3331 EL_BOMB, -1, MV_BIT_RIGHT
3334 Xbomb_force_w, FALSE, FALSE,
3335 EL_BOMB, -1, MV_BIT_LEFT
3337 #endif /* EM_ENGINE_BAD_ROLL */
3340 Xstone, TRUE, FALSE,
3344 Xstone_pause, FALSE, FALSE,
3348 Xstone_fall, FALSE, FALSE,
3352 Ystone_s, FALSE, FALSE,
3353 EL_ROCK, ACTION_FALLING, -1
3356 Ystone_sB, FALSE, TRUE,
3357 EL_ROCK, ACTION_FALLING, -1
3360 Ystone_e, FALSE, FALSE,
3361 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3364 Ystone_eB, FALSE, TRUE,
3365 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3368 Ystone_w, FALSE, FALSE,
3369 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3372 Ystone_wB, FALSE, TRUE,
3373 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3380 Xnut_pause, FALSE, FALSE,
3384 Xnut_fall, FALSE, FALSE,
3388 Ynut_s, FALSE, FALSE,
3389 EL_NUT, ACTION_FALLING, -1
3392 Ynut_sB, FALSE, TRUE,
3393 EL_NUT, ACTION_FALLING, -1
3396 Ynut_e, FALSE, FALSE,
3397 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3400 Ynut_eB, FALSE, TRUE,
3401 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3404 Ynut_w, FALSE, FALSE,
3405 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3408 Ynut_wB, FALSE, TRUE,
3409 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3412 Xbug_n, TRUE, FALSE,
3416 Xbug_e, TRUE, FALSE,
3417 EL_BUG_RIGHT, -1, -1
3420 Xbug_s, TRUE, FALSE,
3424 Xbug_w, TRUE, FALSE,
3428 Xbug_gon, FALSE, FALSE,
3432 Xbug_goe, FALSE, FALSE,
3433 EL_BUG_RIGHT, -1, -1
3436 Xbug_gos, FALSE, FALSE,
3440 Xbug_gow, FALSE, FALSE,
3444 Ybug_n, FALSE, FALSE,
3445 EL_BUG, ACTION_MOVING, MV_BIT_UP
3448 Ybug_nB, FALSE, TRUE,
3449 EL_BUG, ACTION_MOVING, MV_BIT_UP
3452 Ybug_e, FALSE, FALSE,
3453 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3456 Ybug_eB, FALSE, TRUE,
3457 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3460 Ybug_s, FALSE, FALSE,
3461 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3464 Ybug_sB, FALSE, TRUE,
3465 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3468 Ybug_w, FALSE, FALSE,
3469 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3472 Ybug_wB, FALSE, TRUE,
3473 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3476 Ybug_w_n, FALSE, FALSE,
3477 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3480 Ybug_n_e, FALSE, FALSE,
3481 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3484 Ybug_e_s, FALSE, FALSE,
3485 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3488 Ybug_s_w, FALSE, FALSE,
3489 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3492 Ybug_e_n, FALSE, FALSE,
3493 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3496 Ybug_s_e, FALSE, FALSE,
3497 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3500 Ybug_w_s, FALSE, FALSE,
3501 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3504 Ybug_n_w, FALSE, FALSE,
3505 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3508 Ybug_stone, FALSE, FALSE,
3509 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
3512 Ybug_spring, FALSE, FALSE,
3513 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
3516 Xtank_n, TRUE, FALSE,
3517 EL_SPACESHIP_UP, -1, -1
3520 Xtank_e, TRUE, FALSE,
3521 EL_SPACESHIP_RIGHT, -1, -1
3524 Xtank_s, TRUE, FALSE,
3525 EL_SPACESHIP_DOWN, -1, -1
3528 Xtank_w, TRUE, FALSE,
3529 EL_SPACESHIP_LEFT, -1, -1
3532 Xtank_gon, FALSE, FALSE,
3533 EL_SPACESHIP_UP, -1, -1
3536 Xtank_goe, FALSE, FALSE,
3537 EL_SPACESHIP_RIGHT, -1, -1
3540 Xtank_gos, FALSE, FALSE,
3541 EL_SPACESHIP_DOWN, -1, -1
3544 Xtank_gow, FALSE, FALSE,
3545 EL_SPACESHIP_LEFT, -1, -1
3548 Ytank_n, FALSE, FALSE,
3549 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3552 Ytank_nB, FALSE, TRUE,
3553 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3556 Ytank_e, FALSE, FALSE,
3557 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3560 Ytank_eB, FALSE, TRUE,
3561 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3564 Ytank_s, FALSE, FALSE,
3565 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3568 Ytank_sB, FALSE, TRUE,
3569 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3572 Ytank_w, FALSE, FALSE,
3573 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3576 Ytank_wB, FALSE, TRUE,
3577 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3580 Ytank_w_n, FALSE, FALSE,
3581 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3584 Ytank_n_e, FALSE, FALSE,
3585 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3588 Ytank_e_s, FALSE, FALSE,
3589 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3592 Ytank_s_w, FALSE, FALSE,
3593 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3596 Ytank_e_n, FALSE, FALSE,
3597 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3600 Ytank_s_e, FALSE, FALSE,
3601 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3604 Ytank_w_s, FALSE, FALSE,
3605 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3608 Ytank_n_w, FALSE, FALSE,
3609 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3612 Ytank_stone, FALSE, FALSE,
3613 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
3616 Ytank_spring, FALSE, FALSE,
3617 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
3620 Xandroid, TRUE, FALSE,
3621 EL_EMC_ANDROID, ACTION_ACTIVE, -1
3624 Xandroid_1_n, FALSE, FALSE,
3625 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3628 Xandroid_2_n, FALSE, FALSE,
3629 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3632 Xandroid_1_e, FALSE, FALSE,
3633 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3636 Xandroid_2_e, FALSE, FALSE,
3637 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3640 Xandroid_1_w, FALSE, FALSE,
3641 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3644 Xandroid_2_w, FALSE, FALSE,
3645 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3648 Xandroid_1_s, FALSE, FALSE,
3649 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3652 Xandroid_2_s, FALSE, FALSE,
3653 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3656 Yandroid_n, FALSE, FALSE,
3657 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3660 Yandroid_nB, FALSE, TRUE,
3661 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3664 Yandroid_ne, FALSE, FALSE,
3665 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
3668 Yandroid_neB, FALSE, TRUE,
3669 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
3672 Yandroid_e, FALSE, FALSE,
3673 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
3676 Yandroid_eB, FALSE, TRUE,
3677 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
3680 Yandroid_se, FALSE, FALSE,
3681 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
3684 Yandroid_seB, FALSE, TRUE,
3685 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
3688 Yandroid_s, FALSE, FALSE,
3689 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
3692 Yandroid_sB, FALSE, TRUE,
3693 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
3696 Yandroid_sw, FALSE, FALSE,
3697 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
3700 Yandroid_swB, FALSE, TRUE,
3701 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
3704 Yandroid_w, FALSE, FALSE,
3705 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
3708 Yandroid_wB, FALSE, TRUE,
3709 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
3712 Yandroid_nw, FALSE, FALSE,
3713 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
3716 Yandroid_nwB, FALSE, TRUE,
3717 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
3720 Xspring, TRUE, FALSE,
3724 Xspring_pause, FALSE, FALSE,
3728 Xspring_e, FALSE, FALSE,
3732 Xspring_w, FALSE, FALSE,
3736 Xspring_fall, FALSE, FALSE,
3740 Yspring_s, FALSE, FALSE,
3741 EL_SPRING, ACTION_FALLING, -1
3744 Yspring_sB, FALSE, TRUE,
3745 EL_SPRING, ACTION_FALLING, -1
3748 Yspring_e, FALSE, FALSE,
3749 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
3752 Yspring_eB, FALSE, TRUE,
3753 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
3756 Yspring_w, FALSE, FALSE,
3757 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
3760 Yspring_wB, FALSE, TRUE,
3761 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
3764 Yspring_kill_e, FALSE, FALSE,
3765 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
3768 Yspring_kill_eB, FALSE, TRUE,
3769 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
3772 Yspring_kill_w, FALSE, FALSE,
3773 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
3776 Yspring_kill_wB, FALSE, TRUE,
3777 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
3780 Xeater_n, TRUE, FALSE,
3781 EL_YAMYAM_UP, -1, -1
3784 Xeater_e, TRUE, FALSE,
3785 EL_YAMYAM_RIGHT, -1, -1
3788 Xeater_w, TRUE, FALSE,
3789 EL_YAMYAM_LEFT, -1, -1
3792 Xeater_s, TRUE, FALSE,
3793 EL_YAMYAM_DOWN, -1, -1
3796 Yeater_n, FALSE, FALSE,
3797 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
3800 Yeater_nB, FALSE, TRUE,
3801 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
3804 Yeater_e, FALSE, FALSE,
3805 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
3808 Yeater_eB, FALSE, TRUE,
3809 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
3812 Yeater_s, FALSE, FALSE,
3813 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
3816 Yeater_sB, FALSE, TRUE,
3817 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
3820 Yeater_w, FALSE, FALSE,
3821 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
3824 Yeater_wB, FALSE, TRUE,
3825 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
3828 Yeater_stone, FALSE, FALSE,
3829 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
3832 Yeater_spring, FALSE, FALSE,
3833 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
3836 Xalien, TRUE, FALSE,
3840 Xalien_pause, FALSE, FALSE,
3844 Yalien_n, FALSE, FALSE,
3845 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
3848 Yalien_nB, FALSE, TRUE,
3849 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
3852 Yalien_e, FALSE, FALSE,
3853 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
3856 Yalien_eB, FALSE, TRUE,
3857 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
3860 Yalien_s, FALSE, FALSE,
3861 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
3864 Yalien_sB, FALSE, TRUE,
3865 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
3868 Yalien_w, FALSE, FALSE,
3869 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
3872 Yalien_wB, FALSE, TRUE,
3873 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
3876 Yalien_stone, FALSE, FALSE,
3877 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
3880 Yalien_spring, FALSE, FALSE,
3881 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
3884 Xemerald, TRUE, FALSE,
3888 Xemerald_pause, FALSE, FALSE,
3892 Xemerald_fall, FALSE, FALSE,
3896 Xemerald_shine, FALSE, FALSE,
3897 EL_EMERALD, ACTION_TWINKLING, -1
3900 Yemerald_s, FALSE, FALSE,
3901 EL_EMERALD, ACTION_FALLING, -1
3904 Yemerald_sB, FALSE, TRUE,
3905 EL_EMERALD, ACTION_FALLING, -1
3908 Yemerald_e, FALSE, FALSE,
3909 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
3912 Yemerald_eB, FALSE, TRUE,
3913 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
3916 Yemerald_w, FALSE, FALSE,
3917 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
3920 Yemerald_wB, FALSE, TRUE,
3921 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
3924 Yemerald_eat, FALSE, FALSE,
3925 EL_EMERALD, ACTION_COLLECTING, -1
3928 Yemerald_stone, FALSE, FALSE,
3929 EL_NUT, ACTION_BREAKING, -1
3932 Xdiamond, TRUE, FALSE,
3936 Xdiamond_pause, FALSE, FALSE,
3940 Xdiamond_fall, FALSE, FALSE,
3944 Xdiamond_shine, FALSE, FALSE,
3945 EL_DIAMOND, ACTION_TWINKLING, -1
3948 Ydiamond_s, FALSE, FALSE,
3949 EL_DIAMOND, ACTION_FALLING, -1
3952 Ydiamond_sB, FALSE, TRUE,
3953 EL_DIAMOND, ACTION_FALLING, -1
3956 Ydiamond_e, FALSE, FALSE,
3957 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
3960 Ydiamond_eB, FALSE, TRUE,
3961 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
3964 Ydiamond_w, FALSE, FALSE,
3965 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
3968 Ydiamond_wB, FALSE, TRUE,
3969 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
3972 Ydiamond_eat, FALSE, FALSE,
3973 EL_DIAMOND, ACTION_COLLECTING, -1
3976 Ydiamond_stone, FALSE, FALSE,
3977 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
3980 Xdrip_fall, TRUE, FALSE,
3981 EL_AMOEBA_DROP, -1, -1
3984 Xdrip_stretch, FALSE, FALSE,
3985 EL_AMOEBA_DROP, ACTION_FALLING, -1
3988 Xdrip_stretchB, FALSE, TRUE,
3989 EL_AMOEBA_DROP, ACTION_FALLING, -1
3992 Xdrip_eat, FALSE, FALSE,
3993 EL_AMOEBA_DROP, ACTION_GROWING, -1
3996 Ydrip_s1, FALSE, FALSE,
3997 EL_AMOEBA_DROP, ACTION_FALLING, -1
4000 Ydrip_s1B, FALSE, TRUE,
4001 EL_AMOEBA_DROP, ACTION_FALLING, -1
4004 Ydrip_s2, FALSE, FALSE,
4005 EL_AMOEBA_DROP, ACTION_FALLING, -1
4008 Ydrip_s2B, FALSE, TRUE,
4009 EL_AMOEBA_DROP, ACTION_FALLING, -1
4016 Xbomb_pause, FALSE, FALSE,
4020 Xbomb_fall, FALSE, FALSE,
4024 Ybomb_s, FALSE, FALSE,
4025 EL_BOMB, ACTION_FALLING, -1
4028 Ybomb_sB, FALSE, TRUE,
4029 EL_BOMB, ACTION_FALLING, -1
4032 Ybomb_e, FALSE, FALSE,
4033 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
4036 Ybomb_eB, FALSE, TRUE,
4037 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
4040 Ybomb_w, FALSE, FALSE,
4041 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
4044 Ybomb_wB, FALSE, TRUE,
4045 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
4048 Ybomb_eat, FALSE, FALSE,
4049 EL_BOMB, ACTION_ACTIVATING, -1
4052 Xballoon, TRUE, FALSE,
4056 Yballoon_n, FALSE, FALSE,
4057 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
4060 Yballoon_nB, FALSE, TRUE,
4061 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
4064 Yballoon_e, FALSE, FALSE,
4065 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
4068 Yballoon_eB, FALSE, TRUE,
4069 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
4072 Yballoon_s, FALSE, FALSE,
4073 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
4076 Yballoon_sB, FALSE, TRUE,
4077 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
4080 Yballoon_w, FALSE, FALSE,
4081 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
4084 Yballoon_wB, FALSE, TRUE,
4085 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
4088 Xgrass, TRUE, FALSE,
4089 EL_EMC_GRASS, -1, -1
4092 Ygrass_nB, FALSE, FALSE,
4093 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
4096 Ygrass_eB, FALSE, FALSE,
4097 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
4100 Ygrass_sB, FALSE, FALSE,
4101 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
4104 Ygrass_wB, FALSE, FALSE,
4105 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
4112 Ydirt_nB, FALSE, FALSE,
4113 EL_SAND, ACTION_DIGGING, MV_BIT_UP
4116 Ydirt_eB, FALSE, FALSE,
4117 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
4120 Ydirt_sB, FALSE, FALSE,
4121 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
4124 Ydirt_wB, FALSE, FALSE,
4125 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
4128 Xacid_ne, TRUE, FALSE,
4129 EL_ACID_POOL_TOPRIGHT, -1, -1
4132 Xacid_se, TRUE, FALSE,
4133 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
4136 Xacid_s, TRUE, FALSE,
4137 EL_ACID_POOL_BOTTOM, -1, -1
4140 Xacid_sw, TRUE, FALSE,
4141 EL_ACID_POOL_BOTTOMLEFT, -1, -1
4144 Xacid_nw, TRUE, FALSE,
4145 EL_ACID_POOL_TOPLEFT, -1, -1
4148 Xacid_1, TRUE, FALSE,
4152 Xacid_2, FALSE, FALSE,
4156 Xacid_3, FALSE, FALSE,
4160 Xacid_4, FALSE, FALSE,
4164 Xacid_5, FALSE, FALSE,
4168 Xacid_6, FALSE, FALSE,
4172 Xacid_7, FALSE, FALSE,
4176 Xacid_8, FALSE, FALSE,
4180 Xball_1, TRUE, FALSE,
4181 EL_EMC_MAGIC_BALL, -1, -1
4184 Xball_1B, FALSE, FALSE,
4185 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4188 Xball_2, FALSE, FALSE,
4189 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4192 Xball_2B, FALSE, FALSE,
4193 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4196 Yball_eat, FALSE, FALSE,
4197 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
4200 Ykey_1_eat, FALSE, FALSE,
4201 EL_EM_KEY_1, ACTION_COLLECTING, -1
4204 Ykey_2_eat, FALSE, FALSE,
4205 EL_EM_KEY_2, ACTION_COLLECTING, -1
4208 Ykey_3_eat, FALSE, FALSE,
4209 EL_EM_KEY_3, ACTION_COLLECTING, -1
4212 Ykey_4_eat, FALSE, FALSE,
4213 EL_EM_KEY_4, ACTION_COLLECTING, -1
4216 Ykey_5_eat, FALSE, FALSE,
4217 EL_EMC_KEY_5, ACTION_COLLECTING, -1
4220 Ykey_6_eat, FALSE, FALSE,
4221 EL_EMC_KEY_6, ACTION_COLLECTING, -1
4224 Ykey_7_eat, FALSE, FALSE,
4225 EL_EMC_KEY_7, ACTION_COLLECTING, -1
4228 Ykey_8_eat, FALSE, FALSE,
4229 EL_EMC_KEY_8, ACTION_COLLECTING, -1
4232 Ylenses_eat, FALSE, FALSE,
4233 EL_EMC_LENSES, ACTION_COLLECTING, -1
4236 Ymagnify_eat, FALSE, FALSE,
4237 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
4240 Ygrass_eat, FALSE, FALSE,
4241 EL_EMC_GRASS, ACTION_SNAPPING, -1
4244 Ydirt_eat, FALSE, FALSE,
4245 EL_SAND, ACTION_SNAPPING, -1
4248 Xgrow_ns, TRUE, FALSE,
4249 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
4252 Ygrow_ns_eat, FALSE, FALSE,
4253 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
4256 Xgrow_ew, TRUE, FALSE,
4257 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
4260 Ygrow_ew_eat, FALSE, FALSE,
4261 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
4264 Xwonderwall, TRUE, FALSE,
4265 EL_MAGIC_WALL, -1, -1
4268 XwonderwallB, FALSE, FALSE,
4269 EL_MAGIC_WALL, ACTION_ACTIVE, -1
4272 Xamoeba_1, TRUE, FALSE,
4273 EL_AMOEBA_DRY, ACTION_OTHER, -1
4276 Xamoeba_2, FALSE, FALSE,
4277 EL_AMOEBA_DRY, ACTION_OTHER, -1
4280 Xamoeba_3, FALSE, FALSE,
4281 EL_AMOEBA_DRY, ACTION_OTHER, -1
4284 Xamoeba_4, FALSE, FALSE,
4285 EL_AMOEBA_DRY, ACTION_OTHER, -1
4288 Xamoeba_5, TRUE, FALSE,
4289 EL_AMOEBA_WET, ACTION_OTHER, -1
4292 Xamoeba_6, FALSE, FALSE,
4293 EL_AMOEBA_WET, ACTION_OTHER, -1
4296 Xamoeba_7, FALSE, FALSE,
4297 EL_AMOEBA_WET, ACTION_OTHER, -1
4300 Xamoeba_8, FALSE, FALSE,
4301 EL_AMOEBA_WET, ACTION_OTHER, -1
4304 Xdoor_1, TRUE, FALSE,
4305 EL_EM_GATE_1, -1, -1
4308 Xdoor_2, TRUE, FALSE,
4309 EL_EM_GATE_2, -1, -1
4312 Xdoor_3, TRUE, FALSE,
4313 EL_EM_GATE_3, -1, -1
4316 Xdoor_4, TRUE, FALSE,
4317 EL_EM_GATE_4, -1, -1
4320 Xdoor_5, TRUE, FALSE,
4321 EL_EMC_GATE_5, -1, -1
4324 Xdoor_6, TRUE, FALSE,
4325 EL_EMC_GATE_6, -1, -1
4328 Xdoor_7, TRUE, FALSE,
4329 EL_EMC_GATE_7, -1, -1
4332 Xdoor_8, TRUE, FALSE,
4333 EL_EMC_GATE_8, -1, -1
4336 Xkey_1, TRUE, FALSE,
4340 Xkey_2, TRUE, FALSE,
4344 Xkey_3, TRUE, FALSE,
4348 Xkey_4, TRUE, FALSE,
4352 Xkey_5, TRUE, FALSE,
4353 EL_EMC_KEY_5, -1, -1
4356 Xkey_6, TRUE, FALSE,
4357 EL_EMC_KEY_6, -1, -1
4360 Xkey_7, TRUE, FALSE,
4361 EL_EMC_KEY_7, -1, -1
4364 Xkey_8, TRUE, FALSE,
4365 EL_EMC_KEY_8, -1, -1
4368 Xwind_n, TRUE, FALSE,
4369 EL_BALLOON_SWITCH_UP, -1, -1
4372 Xwind_e, TRUE, FALSE,
4373 EL_BALLOON_SWITCH_RIGHT, -1, -1
4376 Xwind_s, TRUE, FALSE,
4377 EL_BALLOON_SWITCH_DOWN, -1, -1
4380 Xwind_w, TRUE, FALSE,
4381 EL_BALLOON_SWITCH_LEFT, -1, -1
4384 Xwind_nesw, TRUE, FALSE,
4385 EL_BALLOON_SWITCH_ANY, -1, -1
4388 Xwind_stop, TRUE, FALSE,
4389 EL_BALLOON_SWITCH_NONE, -1, -1
4393 EL_EXIT_CLOSED, -1, -1
4396 Xexit_1, TRUE, FALSE,
4397 EL_EXIT_OPEN, -1, -1
4400 Xexit_2, FALSE, FALSE,
4401 EL_EXIT_OPEN, -1, -1
4404 Xexit_3, FALSE, FALSE,
4405 EL_EXIT_OPEN, -1, -1
4408 Xdynamite, TRUE, FALSE,
4409 EL_EM_DYNAMITE, -1, -1
4412 Ydynamite_eat, FALSE, FALSE,
4413 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
4416 Xdynamite_1, TRUE, FALSE,
4417 EL_EM_DYNAMITE_ACTIVE, -1, -1
4420 Xdynamite_2, FALSE, FALSE,
4421 EL_EM_DYNAMITE_ACTIVE, -1, -1
4424 Xdynamite_3, FALSE, FALSE,
4425 EL_EM_DYNAMITE_ACTIVE, -1, -1
4428 Xdynamite_4, FALSE, FALSE,
4429 EL_EM_DYNAMITE_ACTIVE, -1, -1
4432 Xbumper, TRUE, FALSE,
4433 EL_EMC_SPRING_BUMPER, -1, -1
4436 XbumperB, FALSE, FALSE,
4437 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
4440 Xwheel, TRUE, FALSE,
4441 EL_ROBOT_WHEEL, -1, -1
4444 XwheelB, FALSE, FALSE,
4445 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
4448 Xswitch, TRUE, FALSE,
4449 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
4452 XswitchB, FALSE, FALSE,
4453 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
4457 EL_QUICKSAND_EMPTY, -1, -1
4460 Xsand_stone, TRUE, FALSE,
4461 EL_QUICKSAND_FULL, -1, -1
4464 Xsand_stonein_1, FALSE, TRUE,
4465 EL_ROCK, ACTION_FILLING, -1
4468 Xsand_stonein_2, FALSE, TRUE,
4469 EL_ROCK, ACTION_FILLING, -1
4472 Xsand_stonein_3, FALSE, TRUE,
4473 EL_ROCK, ACTION_FILLING, -1
4476 Xsand_stonein_4, FALSE, TRUE,
4477 EL_ROCK, ACTION_FILLING, -1
4480 Xsand_stonesand_1, FALSE, FALSE,
4481 EL_QUICKSAND_FULL, -1, -1
4484 Xsand_stonesand_2, FALSE, FALSE,
4485 EL_QUICKSAND_FULL, -1, -1
4488 Xsand_stonesand_3, FALSE, FALSE,
4489 EL_QUICKSAND_FULL, -1, -1
4492 Xsand_stonesand_4, FALSE, FALSE,
4493 EL_QUICKSAND_FULL, -1, -1
4496 Xsand_stoneout_1, FALSE, FALSE,
4497 EL_ROCK, ACTION_EMPTYING, -1
4500 Xsand_stoneout_2, FALSE, FALSE,
4501 EL_ROCK, ACTION_EMPTYING, -1
4504 Xsand_sandstone_1, FALSE, FALSE,
4505 EL_QUICKSAND_FULL, -1, -1
4508 Xsand_sandstone_2, FALSE, FALSE,
4509 EL_QUICKSAND_FULL, -1, -1
4512 Xsand_sandstone_3, FALSE, FALSE,
4513 EL_QUICKSAND_FULL, -1, -1
4516 Xsand_sandstone_4, FALSE, FALSE,
4517 EL_QUICKSAND_FULL, -1, -1
4520 Xplant, TRUE, FALSE,
4521 EL_EMC_PLANT, -1, -1
4524 Yplant, FALSE, FALSE,
4525 EL_EMC_PLANT, -1, -1
4528 Xlenses, TRUE, FALSE,
4529 EL_EMC_LENSES, -1, -1
4532 Xmagnify, TRUE, FALSE,
4533 EL_EMC_MAGNIFIER, -1, -1
4536 Xdripper, TRUE, FALSE,
4537 EL_EMC_DRIPPER, -1, -1
4540 XdripperB, FALSE, FALSE,
4541 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
4544 Xfake_blank, TRUE, FALSE,
4545 EL_INVISIBLE_WALL, -1, -1
4548 Xfake_blankB, FALSE, FALSE,
4549 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
4552 Xfake_grass, TRUE, FALSE,
4553 EL_EMC_FAKE_GRASS, -1, -1
4556 Xfake_grassB, FALSE, FALSE,
4557 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
4560 Xfake_door_1, TRUE, FALSE,
4561 EL_EM_GATE_1_GRAY, -1, -1
4564 Xfake_door_2, TRUE, FALSE,
4565 EL_EM_GATE_2_GRAY, -1, -1
4568 Xfake_door_3, TRUE, FALSE,
4569 EL_EM_GATE_3_GRAY, -1, -1
4572 Xfake_door_4, TRUE, FALSE,
4573 EL_EM_GATE_4_GRAY, -1, -1
4576 Xfake_door_5, TRUE, FALSE,
4577 EL_EMC_GATE_5_GRAY, -1, -1
4580 Xfake_door_6, TRUE, FALSE,
4581 EL_EMC_GATE_6_GRAY, -1, -1
4584 Xfake_door_7, TRUE, FALSE,
4585 EL_EMC_GATE_7_GRAY, -1, -1
4588 Xfake_door_8, TRUE, FALSE,
4589 EL_EMC_GATE_8_GRAY, -1, -1
4592 Xfake_acid_1, TRUE, FALSE,
4593 EL_EMC_FAKE_ACID, -1, -1
4596 Xfake_acid_2, FALSE, FALSE,
4597 EL_EMC_FAKE_ACID, -1, -1
4600 Xfake_acid_3, FALSE, FALSE,
4601 EL_EMC_FAKE_ACID, -1, -1
4604 Xfake_acid_4, FALSE, FALSE,
4605 EL_EMC_FAKE_ACID, -1, -1
4608 Xfake_acid_5, FALSE, FALSE,
4609 EL_EMC_FAKE_ACID, -1, -1
4612 Xfake_acid_6, FALSE, FALSE,
4613 EL_EMC_FAKE_ACID, -1, -1
4616 Xfake_acid_7, FALSE, FALSE,
4617 EL_EMC_FAKE_ACID, -1, -1
4620 Xfake_acid_8, FALSE, FALSE,
4621 EL_EMC_FAKE_ACID, -1, -1
4624 Xsteel_1, TRUE, FALSE,
4625 EL_STEELWALL, -1, -1
4628 Xsteel_2, TRUE, FALSE,
4629 EL_EMC_STEELWALL_2, -1, -1
4632 Xsteel_3, TRUE, FALSE,
4633 EL_EMC_STEELWALL_3, -1, -1
4636 Xsteel_4, TRUE, FALSE,
4637 EL_EMC_STEELWALL_4, -1, -1
4640 Xwall_1, TRUE, FALSE,
4644 Xwall_2, TRUE, FALSE,
4645 EL_EMC_WALL_14, -1, -1
4648 Xwall_3, TRUE, FALSE,
4649 EL_EMC_WALL_15, -1, -1
4652 Xwall_4, TRUE, FALSE,
4653 EL_EMC_WALL_16, -1, -1
4656 Xround_wall_1, TRUE, FALSE,
4657 EL_WALL_SLIPPERY, -1, -1
4660 Xround_wall_2, TRUE, FALSE,
4661 EL_EMC_WALL_SLIPPERY_2, -1, -1
4664 Xround_wall_3, TRUE, FALSE,
4665 EL_EMC_WALL_SLIPPERY_3, -1, -1
4668 Xround_wall_4, TRUE, FALSE,
4669 EL_EMC_WALL_SLIPPERY_4, -1, -1
4672 Xdecor_1, TRUE, FALSE,
4673 EL_EMC_WALL_8, -1, -1
4676 Xdecor_2, TRUE, FALSE,
4677 EL_EMC_WALL_6, -1, -1
4680 Xdecor_3, TRUE, FALSE,
4681 EL_EMC_WALL_4, -1, -1
4684 Xdecor_4, TRUE, FALSE,
4685 EL_EMC_WALL_7, -1, -1
4688 Xdecor_5, TRUE, FALSE,
4689 EL_EMC_WALL_5, -1, -1
4692 Xdecor_6, TRUE, FALSE,
4693 EL_EMC_WALL_9, -1, -1
4696 Xdecor_7, TRUE, FALSE,
4697 EL_EMC_WALL_10, -1, -1
4700 Xdecor_8, TRUE, FALSE,
4701 EL_EMC_WALL_1, -1, -1
4704 Xdecor_9, TRUE, FALSE,
4705 EL_EMC_WALL_2, -1, -1
4708 Xdecor_10, TRUE, FALSE,
4709 EL_EMC_WALL_3, -1, -1
4712 Xdecor_11, TRUE, FALSE,
4713 EL_EMC_WALL_11, -1, -1
4716 Xdecor_12, TRUE, FALSE,
4717 EL_EMC_WALL_12, -1, -1
4720 Xalpha_0, TRUE, FALSE,
4721 EL_CHAR('0'), -1, -1
4724 Xalpha_1, TRUE, FALSE,
4725 EL_CHAR('1'), -1, -1
4728 Xalpha_2, TRUE, FALSE,
4729 EL_CHAR('2'), -1, -1
4732 Xalpha_3, TRUE, FALSE,
4733 EL_CHAR('3'), -1, -1
4736 Xalpha_4, TRUE, FALSE,
4737 EL_CHAR('4'), -1, -1
4740 Xalpha_5, TRUE, FALSE,
4741 EL_CHAR('5'), -1, -1
4744 Xalpha_6, TRUE, FALSE,
4745 EL_CHAR('6'), -1, -1
4748 Xalpha_7, TRUE, FALSE,
4749 EL_CHAR('7'), -1, -1
4752 Xalpha_8, TRUE, FALSE,
4753 EL_CHAR('8'), -1, -1
4756 Xalpha_9, TRUE, FALSE,
4757 EL_CHAR('9'), -1, -1
4760 Xalpha_excla, TRUE, FALSE,
4761 EL_CHAR('!'), -1, -1
4764 Xalpha_quote, TRUE, FALSE,
4765 EL_CHAR('"'), -1, -1
4768 Xalpha_comma, TRUE, FALSE,
4769 EL_CHAR(','), -1, -1
4772 Xalpha_minus, TRUE, FALSE,
4773 EL_CHAR('-'), -1, -1
4776 Xalpha_perio, TRUE, FALSE,
4777 EL_CHAR('.'), -1, -1
4780 Xalpha_colon, TRUE, FALSE,
4781 EL_CHAR(':'), -1, -1
4784 Xalpha_quest, TRUE, FALSE,
4785 EL_CHAR('?'), -1, -1
4788 Xalpha_a, TRUE, FALSE,
4789 EL_CHAR('A'), -1, -1
4792 Xalpha_b, TRUE, FALSE,
4793 EL_CHAR('B'), -1, -1
4796 Xalpha_c, TRUE, FALSE,
4797 EL_CHAR('C'), -1, -1
4800 Xalpha_d, TRUE, FALSE,
4801 EL_CHAR('D'), -1, -1
4804 Xalpha_e, TRUE, FALSE,
4805 EL_CHAR('E'), -1, -1
4808 Xalpha_f, TRUE, FALSE,
4809 EL_CHAR('F'), -1, -1
4812 Xalpha_g, TRUE, FALSE,
4813 EL_CHAR('G'), -1, -1
4816 Xalpha_h, TRUE, FALSE,
4817 EL_CHAR('H'), -1, -1
4820 Xalpha_i, TRUE, FALSE,
4821 EL_CHAR('I'), -1, -1
4824 Xalpha_j, TRUE, FALSE,
4825 EL_CHAR('J'), -1, -1
4828 Xalpha_k, TRUE, FALSE,
4829 EL_CHAR('K'), -1, -1
4832 Xalpha_l, TRUE, FALSE,
4833 EL_CHAR('L'), -1, -1
4836 Xalpha_m, TRUE, FALSE,
4837 EL_CHAR('M'), -1, -1
4840 Xalpha_n, TRUE, FALSE,
4841 EL_CHAR('N'), -1, -1
4844 Xalpha_o, TRUE, FALSE,
4845 EL_CHAR('O'), -1, -1
4848 Xalpha_p, TRUE, FALSE,
4849 EL_CHAR('P'), -1, -1
4852 Xalpha_q, TRUE, FALSE,
4853 EL_CHAR('Q'), -1, -1
4856 Xalpha_r, TRUE, FALSE,
4857 EL_CHAR('R'), -1, -1
4860 Xalpha_s, TRUE, FALSE,
4861 EL_CHAR('S'), -1, -1
4864 Xalpha_t, TRUE, FALSE,
4865 EL_CHAR('T'), -1, -1
4868 Xalpha_u, TRUE, FALSE,
4869 EL_CHAR('U'), -1, -1
4872 Xalpha_v, TRUE, FALSE,
4873 EL_CHAR('V'), -1, -1
4876 Xalpha_w, TRUE, FALSE,
4877 EL_CHAR('W'), -1, -1
4880 Xalpha_x, TRUE, FALSE,
4881 EL_CHAR('X'), -1, -1
4884 Xalpha_y, TRUE, FALSE,
4885 EL_CHAR('Y'), -1, -1
4888 Xalpha_z, TRUE, FALSE,
4889 EL_CHAR('Z'), -1, -1
4892 Xalpha_arrow_e, TRUE, FALSE,
4893 EL_CHAR('>'), -1, -1
4896 Xalpha_arrow_w, TRUE, FALSE,
4897 EL_CHAR('<'), -1, -1
4900 Xalpha_copyr, TRUE, FALSE,
4901 EL_CHAR('©'), -1, -1
4905 Xboom_bug, FALSE, FALSE,
4906 EL_BUG, ACTION_EXPLODING, -1
4909 Xboom_bomb, FALSE, FALSE,
4910 EL_BOMB, ACTION_EXPLODING, -1
4913 Xboom_android, FALSE, FALSE,
4914 EL_EMC_ANDROID, ACTION_OTHER, -1
4917 Xboom_1, FALSE, FALSE,
4918 EL_DEFAULT, ACTION_EXPLODING, -1
4921 Xboom_2, FALSE, FALSE,
4922 EL_DEFAULT, ACTION_EXPLODING, -1
4925 Znormal, FALSE, FALSE,
4929 Zdynamite, FALSE, FALSE,
4933 Zplayer, FALSE, FALSE,
4937 ZBORDER, FALSE, FALSE,
4947 static struct Mapping_EM_to_RND_player
4956 em_player_mapping_list[] =
4960 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
4964 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
4968 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
4972 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
4976 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
4980 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
4984 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
4988 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
4992 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
4996 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
5000 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
5004 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
5008 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
5012 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
5016 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
5020 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
5024 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
5028 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
5032 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
5036 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
5040 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
5044 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
5048 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
5052 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
5056 EL_PLAYER_1, ACTION_DEFAULT, -1,
5060 EL_PLAYER_2, ACTION_DEFAULT, -1,
5064 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
5068 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
5072 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
5076 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
5080 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
5084 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
5088 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
5092 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
5096 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
5100 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
5104 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
5108 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
5112 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
5116 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
5120 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
5124 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
5128 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
5132 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
5136 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
5140 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
5144 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
5148 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
5152 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
5156 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
5160 EL_PLAYER_3, ACTION_DEFAULT, -1,
5164 EL_PLAYER_4, ACTION_DEFAULT, -1,
5173 int map_element_RND_to_EM(int element_rnd)
5175 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
5176 static boolean mapping_initialized = FALSE;
5178 if (!mapping_initialized)
5182 /* return "Xalpha_quest" for all undefined elements in mapping array */
5183 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
5184 mapping_RND_to_EM[i] = Xalpha_quest;
5186 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5187 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
5188 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
5189 em_object_mapping_list[i].element_em;
5191 mapping_initialized = TRUE;
5194 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
5195 return mapping_RND_to_EM[element_rnd];
5197 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
5202 int map_element_EM_to_RND(int element_em)
5204 static unsigned short mapping_EM_to_RND[TILE_MAX];
5205 static boolean mapping_initialized = FALSE;
5207 if (!mapping_initialized)
5211 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
5212 for (i = 0; i < TILE_MAX; i++)
5213 mapping_EM_to_RND[i] = EL_UNKNOWN;
5215 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5216 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
5217 em_object_mapping_list[i].element_rnd;
5219 mapping_initialized = TRUE;
5222 if (element_em >= 0 && element_em < TILE_MAX)
5223 return mapping_EM_to_RND[element_em];
5225 Error(ERR_WARN, "invalid EM level element %d", element_em);
5230 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
5232 struct LevelInfo_EM *level_em = level->native_em_level;
5233 struct LEVEL *lev = level_em->lev;
5236 for (i = 0; i < TILE_MAX; i++)
5237 lev->android_array[i] = Xblank;
5239 for (i = 0; i < level->num_android_clone_elements; i++)
5241 int element_rnd = level->android_clone_element[i];
5242 int element_em = map_element_RND_to_EM(element_rnd);
5244 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
5245 if (em_object_mapping_list[j].element_rnd == element_rnd)
5246 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
5250 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
5252 struct LevelInfo_EM *level_em = level->native_em_level;
5253 struct LEVEL *lev = level_em->lev;
5256 level->num_android_clone_elements = 0;
5258 for (i = 0; i < TILE_MAX; i++)
5260 int element_em = lev->android_array[i];
5262 boolean element_found = FALSE;
5264 if (element_em == Xblank)
5267 element_rnd = map_element_EM_to_RND(element_em);
5269 for (j = 0; j < level->num_android_clone_elements; j++)
5270 if (level->android_clone_element[j] == element_rnd)
5271 element_found = TRUE;
5275 level->android_clone_element[level->num_android_clone_elements++] =
5278 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
5283 if (level->num_android_clone_elements == 0)
5285 level->num_android_clone_elements = 1;
5286 level->android_clone_element[0] = EL_EMPTY;
5290 int map_direction_RND_to_EM(int direction)
5292 return (direction == MV_UP ? 0 :
5293 direction == MV_RIGHT ? 1 :
5294 direction == MV_DOWN ? 2 :
5295 direction == MV_LEFT ? 3 :
5299 int map_direction_EM_to_RND(int direction)
5301 return (direction == 0 ? MV_UP :
5302 direction == 1 ? MV_RIGHT :
5303 direction == 2 ? MV_DOWN :
5304 direction == 3 ? MV_LEFT :
5308 int get_next_element(int element)
5312 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
5313 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
5314 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
5315 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
5316 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
5317 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
5318 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
5320 default: return element;
5325 int el_act_dir2img(int element, int action, int direction)
5327 element = GFX_ELEMENT(element);
5329 if (direction == MV_NONE)
5330 return element_info[element].graphic[action];
5332 direction = MV_DIR_TO_BIT(direction);
5334 return element_info[element].direction_graphic[action][direction];
5337 int el_act_dir2img(int element, int action, int direction)
5339 element = GFX_ELEMENT(element);
5340 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5342 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5343 return element_info[element].direction_graphic[action][direction];
5348 static int el_act_dir2crm(int element, int action, int direction)
5350 element = GFX_ELEMENT(element);
5352 if (direction == MV_NONE)
5353 return element_info[element].crumbled[action];
5355 direction = MV_DIR_TO_BIT(direction);
5357 return element_info[element].direction_crumbled[action][direction];
5360 static int el_act_dir2crm(int element, int action, int direction)
5362 element = GFX_ELEMENT(element);
5363 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5365 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5366 return element_info[element].direction_crumbled[action][direction];
5370 int el_act2img(int element, int action)
5372 element = GFX_ELEMENT(element);
5374 return element_info[element].graphic[action];
5377 int el_act2crm(int element, int action)
5379 element = GFX_ELEMENT(element);
5381 return element_info[element].crumbled[action];
5384 int el_dir2img(int element, int direction)
5386 element = GFX_ELEMENT(element);
5388 return el_act_dir2img(element, ACTION_DEFAULT, direction);
5391 int el2baseimg(int element)
5393 return element_info[element].graphic[ACTION_DEFAULT];
5396 int el2img(int element)
5398 element = GFX_ELEMENT(element);
5400 return element_info[element].graphic[ACTION_DEFAULT];
5403 int el2edimg(int element)
5405 element = GFX_ELEMENT(element);
5407 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
5410 int el2preimg(int element)
5412 element = GFX_ELEMENT(element);
5414 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
5417 int font2baseimg(int font_nr)
5419 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
5422 int getNumActivePlayers_EM()
5424 int num_players = 0;
5430 for (i = 0; i < MAX_PLAYERS; i++)
5431 if (tape.player_participates[i])
5437 int getGameFrameDelay_EM(int native_em_game_frame_delay)
5439 int game_frame_delay_value;
5441 game_frame_delay_value =
5442 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
5443 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
5446 if (tape.playing && tape.warp_forward && !tape.pausing)
5447 game_frame_delay_value = 0;
5449 return game_frame_delay_value;
5452 unsigned int InitRND(long seed)
5454 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
5455 return InitEngineRandom_EM(seed);
5457 return InitEngineRandom_RND(seed);
5460 void InitGraphicInfo_EM(void)
5462 struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
5463 struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
5467 int num_em_gfx_errors = 0;
5469 if (graphic_info_em_object[0][0].bitmap == NULL)
5471 /* EM graphics not yet initialized in em_open_all() */
5476 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
5479 /* always start with reliable default values */
5480 for (i = 0; i < TILE_MAX; i++)
5482 object_mapping[i].element_rnd = EL_UNKNOWN;
5483 object_mapping[i].is_backside = FALSE;
5484 object_mapping[i].action = ACTION_DEFAULT;
5485 object_mapping[i].direction = MV_NONE;
5488 /* always start with reliable default values */
5489 for (p = 0; p < MAX_PLAYERS; p++)
5491 for (i = 0; i < SPR_MAX; i++)
5493 player_mapping[p][i].element_rnd = EL_UNKNOWN;
5494 player_mapping[p][i].action = ACTION_DEFAULT;
5495 player_mapping[p][i].direction = MV_NONE;
5499 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5501 int e = em_object_mapping_list[i].element_em;
5503 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
5504 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
5506 if (em_object_mapping_list[i].action != -1)
5507 object_mapping[e].action = em_object_mapping_list[i].action;
5509 if (em_object_mapping_list[i].direction != -1)
5510 object_mapping[e].direction =
5511 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
5514 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
5516 int a = em_player_mapping_list[i].action_em;
5517 int p = em_player_mapping_list[i].player_nr;
5519 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
5521 if (em_player_mapping_list[i].action != -1)
5522 player_mapping[p][a].action = em_player_mapping_list[i].action;
5524 if (em_player_mapping_list[i].direction != -1)
5525 player_mapping[p][a].direction =
5526 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
5529 for (i = 0; i < TILE_MAX; i++)
5531 int element = object_mapping[i].element_rnd;
5532 int action = object_mapping[i].action;
5533 int direction = object_mapping[i].direction;
5534 boolean is_backside = object_mapping[i].is_backside;
5535 boolean action_removing = (action == ACTION_DIGGING ||
5536 action == ACTION_SNAPPING ||
5537 action == ACTION_COLLECTING);
5538 boolean action_exploding = ((action == ACTION_EXPLODING ||
5539 action == ACTION_SMASHED_BY_ROCK ||
5540 action == ACTION_SMASHED_BY_SPRING) &&
5541 element != EL_DIAMOND);
5542 boolean action_active = (action == ACTION_ACTIVE);
5543 boolean action_other = (action == ACTION_OTHER);
5545 for (j = 0; j < 8; j++)
5547 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
5548 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
5550 i == Xdrip_stretch ? element :
5551 i == Xdrip_stretchB ? element :
5552 i == Ydrip_s1 ? element :
5553 i == Ydrip_s1B ? element :
5554 i == Xball_1B ? element :
5555 i == Xball_2 ? element :
5556 i == Xball_2B ? element :
5557 i == Yball_eat ? element :
5558 i == Ykey_1_eat ? element :
5559 i == Ykey_2_eat ? element :
5560 i == Ykey_3_eat ? element :
5561 i == Ykey_4_eat ? element :
5562 i == Ykey_5_eat ? element :
5563 i == Ykey_6_eat ? element :
5564 i == Ykey_7_eat ? element :
5565 i == Ykey_8_eat ? element :
5566 i == Ylenses_eat ? element :
5567 i == Ymagnify_eat ? element :
5568 i == Ygrass_eat ? element :
5569 i == Ydirt_eat ? element :
5570 i == Yemerald_stone ? EL_EMERALD :
5571 i == Ydiamond_stone ? EL_ROCK :
5572 i == Xsand_stonein_1 ? element :
5573 i == Xsand_stonein_2 ? element :
5574 i == Xsand_stonein_3 ? element :
5575 i == Xsand_stonein_4 ? element :
5576 is_backside ? EL_EMPTY :
5577 action_removing ? EL_EMPTY :
5579 int effective_action = (j < 7 ? action :
5580 i == Xdrip_stretch ? action :
5581 i == Xdrip_stretchB ? action :
5582 i == Ydrip_s1 ? action :
5583 i == Ydrip_s1B ? action :
5584 i == Xball_1B ? action :
5585 i == Xball_2 ? action :
5586 i == Xball_2B ? action :
5587 i == Yball_eat ? action :
5588 i == Ykey_1_eat ? action :
5589 i == Ykey_2_eat ? action :
5590 i == Ykey_3_eat ? action :
5591 i == Ykey_4_eat ? action :
5592 i == Ykey_5_eat ? action :
5593 i == Ykey_6_eat ? action :
5594 i == Ykey_7_eat ? action :
5595 i == Ykey_8_eat ? action :
5596 i == Ylenses_eat ? action :
5597 i == Ymagnify_eat ? action :
5598 i == Ygrass_eat ? action :
5599 i == Ydirt_eat ? action :
5600 i == Xsand_stonein_1 ? action :
5601 i == Xsand_stonein_2 ? action :
5602 i == Xsand_stonein_3 ? action :
5603 i == Xsand_stonein_4 ? action :
5604 i == Xsand_stoneout_1 ? action :
5605 i == Xsand_stoneout_2 ? action :
5606 i == Xboom_android ? ACTION_EXPLODING :
5607 action_exploding ? ACTION_EXPLODING :
5608 action_active ? action :
5609 action_other ? action :
5611 int graphic = (el_act_dir2img(effective_element, effective_action,
5613 int crumbled = (el_act_dir2crm(effective_element, effective_action,
5615 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
5616 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
5617 boolean has_action_graphics = (graphic != base_graphic);
5618 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
5619 struct GraphicInfo *g = &graphic_info[graphic];
5620 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
5623 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
5624 boolean special_animation = (action != ACTION_DEFAULT &&
5625 g->anim_frames == 3 &&
5626 g->anim_delay == 2 &&
5627 g->anim_mode & ANIM_LINEAR);
5628 int sync_frame = (i == Xdrip_stretch ? 7 :
5629 i == Xdrip_stretchB ? 7 :
5630 i == Ydrip_s2 ? j + 8 :
5631 i == Ydrip_s2B ? j + 8 :
5640 i == Xfake_acid_1 ? 0 :
5641 i == Xfake_acid_2 ? 10 :
5642 i == Xfake_acid_3 ? 20 :
5643 i == Xfake_acid_4 ? 30 :
5644 i == Xfake_acid_5 ? 40 :
5645 i == Xfake_acid_6 ? 50 :
5646 i == Xfake_acid_7 ? 60 :
5647 i == Xfake_acid_8 ? 70 :
5649 i == Xball_2B ? j + 8 :
5650 i == Yball_eat ? j + 1 :
5651 i == Ykey_1_eat ? j + 1 :
5652 i == Ykey_2_eat ? j + 1 :
5653 i == Ykey_3_eat ? j + 1 :
5654 i == Ykey_4_eat ? j + 1 :
5655 i == Ykey_5_eat ? j + 1 :
5656 i == Ykey_6_eat ? j + 1 :
5657 i == Ykey_7_eat ? j + 1 :
5658 i == Ykey_8_eat ? j + 1 :
5659 i == Ylenses_eat ? j + 1 :
5660 i == Ymagnify_eat ? j + 1 :
5661 i == Ygrass_eat ? j + 1 :
5662 i == Ydirt_eat ? j + 1 :
5663 i == Xamoeba_1 ? 0 :
5664 i == Xamoeba_2 ? 1 :
5665 i == Xamoeba_3 ? 2 :
5666 i == Xamoeba_4 ? 3 :
5667 i == Xamoeba_5 ? 0 :
5668 i == Xamoeba_6 ? 1 :
5669 i == Xamoeba_7 ? 2 :
5670 i == Xamoeba_8 ? 3 :
5671 i == Xexit_2 ? j + 8 :
5672 i == Xexit_3 ? j + 16 :
5673 i == Xdynamite_1 ? 0 :
5674 i == Xdynamite_2 ? 8 :
5675 i == Xdynamite_3 ? 16 :
5676 i == Xdynamite_4 ? 24 :
5677 i == Xsand_stonein_1 ? j + 1 :
5678 i == Xsand_stonein_2 ? j + 9 :
5679 i == Xsand_stonein_3 ? j + 17 :
5680 i == Xsand_stonein_4 ? j + 25 :
5681 i == Xsand_stoneout_1 && j == 0 ? 0 :
5682 i == Xsand_stoneout_1 && j == 1 ? 0 :
5683 i == Xsand_stoneout_1 && j == 2 ? 1 :
5684 i == Xsand_stoneout_1 && j == 3 ? 2 :
5685 i == Xsand_stoneout_1 && j == 4 ? 2 :
5686 i == Xsand_stoneout_1 && j == 5 ? 3 :
5687 i == Xsand_stoneout_1 && j == 6 ? 4 :
5688 i == Xsand_stoneout_1 && j == 7 ? 4 :
5689 i == Xsand_stoneout_2 && j == 0 ? 5 :
5690 i == Xsand_stoneout_2 && j == 1 ? 6 :
5691 i == Xsand_stoneout_2 && j == 2 ? 7 :
5692 i == Xsand_stoneout_2 && j == 3 ? 8 :
5693 i == Xsand_stoneout_2 && j == 4 ? 9 :
5694 i == Xsand_stoneout_2 && j == 5 ? 11 :
5695 i == Xsand_stoneout_2 && j == 6 ? 13 :
5696 i == Xsand_stoneout_2 && j == 7 ? 15 :
5697 i == Xboom_bug && j == 1 ? 2 :
5698 i == Xboom_bug && j == 2 ? 2 :
5699 i == Xboom_bug && j == 3 ? 4 :
5700 i == Xboom_bug && j == 4 ? 4 :
5701 i == Xboom_bug && j == 5 ? 2 :
5702 i == Xboom_bug && j == 6 ? 2 :
5703 i == Xboom_bug && j == 7 ? 0 :
5704 i == Xboom_bomb && j == 1 ? 2 :
5705 i == Xboom_bomb && j == 2 ? 2 :
5706 i == Xboom_bomb && j == 3 ? 4 :
5707 i == Xboom_bomb && j == 4 ? 4 :
5708 i == Xboom_bomb && j == 5 ? 2 :
5709 i == Xboom_bomb && j == 6 ? 2 :
5710 i == Xboom_bomb && j == 7 ? 0 :
5711 i == Xboom_android && j == 7 ? 6 :
5712 i == Xboom_1 && j == 1 ? 2 :
5713 i == Xboom_1 && j == 2 ? 2 :
5714 i == Xboom_1 && j == 3 ? 4 :
5715 i == Xboom_1 && j == 4 ? 4 :
5716 i == Xboom_1 && j == 5 ? 6 :
5717 i == Xboom_1 && j == 6 ? 6 :
5718 i == Xboom_1 && j == 7 ? 8 :
5719 i == Xboom_2 && j == 0 ? 8 :
5720 i == Xboom_2 && j == 1 ? 8 :
5721 i == Xboom_2 && j == 2 ? 10 :
5722 i == Xboom_2 && j == 3 ? 10 :
5723 i == Xboom_2 && j == 4 ? 10 :
5724 i == Xboom_2 && j == 5 ? 12 :
5725 i == Xboom_2 && j == 6 ? 12 :
5726 i == Xboom_2 && j == 7 ? 12 :
5727 special_animation && j == 4 ? 3 :
5728 effective_action != action ? 0 :
5732 Bitmap *debug_bitmap = g_em->bitmap;
5733 int debug_src_x = g_em->src_x;
5734 int debug_src_y = g_em->src_y;
5737 int frame = getAnimationFrame(g->anim_frames,
5740 g->anim_start_frame,
5743 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
5744 g->double_movement && is_backside);
5746 g_em->bitmap = src_bitmap;
5747 g_em->src_x = src_x;
5748 g_em->src_y = src_y;
5749 g_em->src_offset_x = 0;
5750 g_em->src_offset_y = 0;
5751 g_em->dst_offset_x = 0;
5752 g_em->dst_offset_y = 0;
5753 g_em->width = TILEX;
5754 g_em->height = TILEY;
5756 g_em->crumbled_bitmap = NULL;
5757 g_em->crumbled_src_x = 0;
5758 g_em->crumbled_src_y = 0;
5759 g_em->crumbled_border_size = 0;
5761 g_em->has_crumbled_graphics = FALSE;
5762 g_em->preserve_background = FALSE;
5765 if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
5766 printf("::: empty crumbled: %d [%s], %d, %d\n",
5767 effective_element, element_info[effective_element].token_name,
5768 effective_action, direction);
5771 /* if element can be crumbled, but certain action graphics are just empty
5772 space (like snapping sand with the original R'n'D graphics), do not
5773 treat these empty space graphics as crumbled graphics in EMC engine */
5774 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
5776 getGraphicSource(crumbled, frame, &src_bitmap, &src_x, &src_y);
5778 g_em->has_crumbled_graphics = TRUE;
5779 g_em->crumbled_bitmap = src_bitmap;
5780 g_em->crumbled_src_x = src_x;
5781 g_em->crumbled_src_y = src_y;
5782 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
5786 if (element == EL_ROCK &&
5787 effective_action == ACTION_FILLING)
5788 printf("::: has_action_graphics == %d\n", has_action_graphics);
5791 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
5792 effective_action == ACTION_MOVING ||
5793 effective_action == ACTION_PUSHING ||
5794 effective_action == ACTION_EATING)) ||
5795 (!has_action_graphics && (effective_action == ACTION_FILLING ||
5796 effective_action == ACTION_EMPTYING)))
5799 (effective_action == ACTION_FALLING ||
5800 effective_action == ACTION_FILLING ||
5801 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
5802 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
5803 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
5804 int num_steps = (i == Ydrip_s1 ? 16 :
5805 i == Ydrip_s1B ? 16 :
5806 i == Ydrip_s2 ? 16 :
5807 i == Ydrip_s2B ? 16 :
5808 i == Xsand_stonein_1 ? 32 :
5809 i == Xsand_stonein_2 ? 32 :
5810 i == Xsand_stonein_3 ? 32 :
5811 i == Xsand_stonein_4 ? 32 :
5812 i == Xsand_stoneout_1 ? 16 :
5813 i == Xsand_stoneout_2 ? 16 : 8);
5814 int cx = ABS(dx) * (TILEX / num_steps);
5815 int cy = ABS(dy) * (TILEY / num_steps);
5816 int step_frame = (i == Ydrip_s2 ? j + 8 :
5817 i == Ydrip_s2B ? j + 8 :
5818 i == Xsand_stonein_2 ? j + 8 :
5819 i == Xsand_stonein_3 ? j + 16 :
5820 i == Xsand_stonein_4 ? j + 24 :
5821 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
5822 int step = (is_backside ? step_frame : num_steps - step_frame);
5824 if (is_backside) /* tile where movement starts */
5826 if (dx < 0 || dy < 0)
5828 g_em->src_offset_x = cx * step;
5829 g_em->src_offset_y = cy * step;
5833 g_em->dst_offset_x = cx * step;
5834 g_em->dst_offset_y = cy * step;
5837 else /* tile where movement ends */
5839 if (dx < 0 || dy < 0)
5841 g_em->dst_offset_x = cx * step;
5842 g_em->dst_offset_y = cy * step;
5846 g_em->src_offset_x = cx * step;
5847 g_em->src_offset_y = cy * step;
5851 g_em->width = TILEX - cx * step;
5852 g_em->height = TILEY - cy * step;
5855 /* create unique graphic identifier to decide if tile must be redrawn */
5856 /* bit 31 - 16 (16 bit): EM style graphic
5857 bit 15 - 12 ( 4 bit): EM style frame
5858 bit 11 - 6 ( 6 bit): graphic width
5859 bit 5 - 0 ( 6 bit): graphic height */
5860 g_em->unique_identifier =
5861 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
5865 /* skip check for EMC elements not contained in original EMC artwork */
5866 if (element == EL_EMC_FAKE_ACID)
5869 if (g_em->bitmap != debug_bitmap ||
5870 g_em->src_x != debug_src_x ||
5871 g_em->src_y != debug_src_y ||
5872 g_em->src_offset_x != 0 ||
5873 g_em->src_offset_y != 0 ||
5874 g_em->dst_offset_x != 0 ||
5875 g_em->dst_offset_y != 0 ||
5876 g_em->width != TILEX ||
5877 g_em->height != TILEY)
5879 static int last_i = -1;
5887 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
5888 i, element, element_info[element].token_name,
5889 element_action_info[effective_action].suffix, direction);
5891 if (element != effective_element)
5892 printf(" [%d ('%s')]",
5894 element_info[effective_element].token_name);
5898 if (g_em->bitmap != debug_bitmap)
5899 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
5900 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
5902 if (g_em->src_x != debug_src_x ||
5903 g_em->src_y != debug_src_y)
5904 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
5905 j, (is_backside ? 'B' : 'F'),
5906 g_em->src_x, g_em->src_y,
5907 g_em->src_x / 32, g_em->src_y / 32,
5908 debug_src_x, debug_src_y,
5909 debug_src_x / 32, debug_src_y / 32);
5911 if (g_em->src_offset_x != 0 ||
5912 g_em->src_offset_y != 0 ||
5913 g_em->dst_offset_x != 0 ||
5914 g_em->dst_offset_y != 0)
5915 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
5917 g_em->src_offset_x, g_em->src_offset_y,
5918 g_em->dst_offset_x, g_em->dst_offset_y);
5920 if (g_em->width != TILEX ||
5921 g_em->height != TILEY)
5922 printf(" %d (%d): size %d,%d should be %d,%d\n",
5924 g_em->width, g_em->height, TILEX, TILEY);
5926 num_em_gfx_errors++;
5933 for (i = 0; i < TILE_MAX; i++)
5935 for (j = 0; j < 8; j++)
5937 int element = object_mapping[i].element_rnd;
5938 int action = object_mapping[i].action;
5939 int direction = object_mapping[i].direction;
5940 boolean is_backside = object_mapping[i].is_backside;
5941 int graphic_action = el_act_dir2img(element, action, direction);
5942 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
5944 if ((action == ACTION_SMASHED_BY_ROCK ||
5945 action == ACTION_SMASHED_BY_SPRING ||
5946 action == ACTION_EATING) &&
5947 graphic_action == graphic_default)
5949 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
5950 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
5951 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
5952 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
5955 /* no separate animation for "smashed by rock" -- use rock instead */
5956 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
5957 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
5959 g_em->bitmap = g_xx->bitmap;
5960 g_em->src_x = g_xx->src_x;
5961 g_em->src_y = g_xx->src_y;
5962 g_em->src_offset_x = g_xx->src_offset_x;
5963 g_em->src_offset_y = g_xx->src_offset_y;
5964 g_em->dst_offset_x = g_xx->dst_offset_x;
5965 g_em->dst_offset_y = g_xx->dst_offset_y;
5966 g_em->width = g_xx->width;
5967 g_em->height = g_xx->height;
5968 g_em->unique_identifier = g_xx->unique_identifier;
5971 g_em->preserve_background = TRUE;
5976 for (p = 0; p < MAX_PLAYERS; p++)
5978 for (i = 0; i < SPR_MAX; i++)
5980 int element = player_mapping[p][i].element_rnd;
5981 int action = player_mapping[p][i].action;
5982 int direction = player_mapping[p][i].direction;
5984 for (j = 0; j < 8; j++)
5986 int effective_element = element;
5987 int effective_action = action;
5988 int graphic = (direction == MV_NONE ?
5989 el_act2img(effective_element, effective_action) :
5990 el_act_dir2img(effective_element, effective_action,
5992 struct GraphicInfo *g = &graphic_info[graphic];
5993 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
5999 Bitmap *debug_bitmap = g_em->bitmap;
6000 int debug_src_x = g_em->src_x;
6001 int debug_src_y = g_em->src_y;
6004 int frame = getAnimationFrame(g->anim_frames,
6007 g->anim_start_frame,
6010 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x,&src_y, FALSE);
6012 g_em->bitmap = src_bitmap;
6013 g_em->src_x = src_x;
6014 g_em->src_y = src_y;
6015 g_em->src_offset_x = 0;
6016 g_em->src_offset_y = 0;
6017 g_em->dst_offset_x = 0;
6018 g_em->dst_offset_y = 0;
6019 g_em->width = TILEX;
6020 g_em->height = TILEY;
6024 /* skip check for EMC elements not contained in original EMC artwork */
6025 if (element == EL_PLAYER_3 ||
6026 element == EL_PLAYER_4)
6029 if (g_em->bitmap != debug_bitmap ||
6030 g_em->src_x != debug_src_x ||
6031 g_em->src_y != debug_src_y)
6033 static int last_i = -1;
6041 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
6042 p, i, element, element_info[element].token_name,
6043 element_action_info[effective_action].suffix, direction);
6045 if (element != effective_element)
6046 printf(" [%d ('%s')]",
6048 element_info[effective_element].token_name);
6052 if (g_em->bitmap != debug_bitmap)
6053 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
6054 j, (int)(g_em->bitmap), (int)(debug_bitmap));
6056 if (g_em->src_x != debug_src_x ||
6057 g_em->src_y != debug_src_y)
6058 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
6060 g_em->src_x, g_em->src_y,
6061 g_em->src_x / 32, g_em->src_y / 32,
6062 debug_src_x, debug_src_y,
6063 debug_src_x / 32, debug_src_y / 32);
6065 num_em_gfx_errors++;
6075 printf("::: [%d errors found]\n", num_em_gfx_errors);
6081 void PlayMenuSound()
6083 int sound = menu.sound[game_status];
6085 if (sound == SND_UNDEFINED)
6088 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6089 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6092 if (IS_LOOP_SOUND(sound))
6093 PlaySoundLoop(sound);
6098 void PlayMenuSoundStereo(int sound, int stereo_position)
6100 if (sound == SND_UNDEFINED)
6103 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6104 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6107 if (IS_LOOP_SOUND(sound))
6108 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
6110 PlaySoundStereo(sound, stereo_position);
6113 void PlayMenuSoundIfLoop()
6115 int sound = menu.sound[game_status];
6117 if (sound == SND_UNDEFINED)
6120 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6121 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6124 if (IS_LOOP_SOUND(sound))
6125 PlaySoundLoop(sound);
6128 void PlayMenuMusic()
6130 int music = menu.music[game_status];
6132 if (music == MUS_UNDEFINED)
6138 void ToggleFullscreenIfNeeded()
6140 boolean change_fullscreen = (setup.fullscreen !=
6141 video.fullscreen_enabled);
6142 boolean change_fullscreen_mode = (video.fullscreen_enabled &&
6143 !strEqual(setup.fullscreen_mode,
6144 video.fullscreen_mode_current));
6146 if (!video.fullscreen_available)
6150 if (change_fullscreen || change_fullscreen_mode)
6152 if (setup.fullscreen != video.fullscreen_enabled ||
6153 setup.fullscreen_mode != video.fullscreen_mode_current)
6156 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
6158 /* save backbuffer content which gets lost when toggling fullscreen mode */
6159 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6162 if (change_fullscreen_mode)
6164 if (setup.fullscreen && video.fullscreen_enabled)
6167 /* keep fullscreen, but change fullscreen mode (screen resolution) */
6169 /* (this is now set in sdl.c) */
6171 video.fullscreen_mode_current = setup.fullscreen_mode;
6173 video.fullscreen_enabled = FALSE; /* force new fullscreen mode */
6176 /* toggle fullscreen */
6177 ChangeVideoModeIfNeeded(setup.fullscreen);
6179 setup.fullscreen = video.fullscreen_enabled;
6181 /* restore backbuffer content from temporary backbuffer backup bitmap */
6182 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6184 FreeBitmap(tmp_backbuffer);
6187 /* update visible window/screen */
6188 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6190 redraw_mask = REDRAW_ALL;