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 x, y, width, height;
537 int fade_delay, post_delay;
539 if (fade_mask & REDRAW_FIELD)
544 height = FULL_SYSIZE;
546 fade_delay = menu.fade_delay;
547 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? menu.post_delay : 0);
549 draw_border_function = DrawMaskedBorder_FIELD;
551 else /* REDRAW_ALL */
558 fade_delay = title.fade_delay_final;
559 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? title.post_delay_final : 0);
562 redraw_mask |= fade_mask;
564 if (!setup.fade_screens || fade_delay == 0)
566 if (fade_mode == FADE_MODE_FADE_OUT)
567 ClearRectangle(backbuffer, x, y, width, height);
574 FadeRectangle(bitmap, x, y, width, height, fade_mode, fade_delay, post_delay,
575 draw_border_function);
577 redraw_mask &= ~fade_mask;
580 void FadeIn(int fade_mask)
582 FadeExt(fade_mask, FADE_MODE_FADE_IN);
585 void FadeOut(int fade_mask)
587 FadeExt(fade_mask, FADE_MODE_FADE_OUT);
590 void FadeCross(int fade_mask)
592 FadeExt(fade_mask, FADE_MODE_CROSSFADE);
595 void FadeCrossSaveBackbuffer()
597 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
600 void SetMainBackgroundImageIfDefined(int graphic)
602 if (graphic_info[graphic].bitmap)
603 SetMainBackgroundImage(graphic);
606 void SetMainBackgroundImage(int graphic)
608 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
609 graphic_info[graphic].bitmap ?
610 graphic_info[graphic].bitmap :
611 graphic_info[IMG_BACKGROUND].bitmap);
614 void SetDoorBackgroundImage(int graphic)
616 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
617 graphic_info[graphic].bitmap ?
618 graphic_info[graphic].bitmap :
619 graphic_info[IMG_BACKGROUND].bitmap);
622 void SetPanelBackground()
624 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, bitmap_db_panel,
625 DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, 0, 0);
627 SetDoorBackgroundBitmap(bitmap_db_panel);
630 void DrawBackground(int dst_x, int dst_y, int width, int height)
633 ClearRectangleOnBackground(drawto, dst_x, dst_y, width, height);
635 ClearRectangleOnBackground(backbuffer, dst_x, dst_y, width, height);
638 redraw_mask |= REDRAW_FIELD;
643 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
645 if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
647 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
648 SetDrawtoField(DRAW_BUFFERED);
651 SetDrawtoField(DRAW_BACKBUFFER);
653 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
655 ClearRectangle(window, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
656 SetDrawtoField(DRAW_DIRECT);
660 void MarkTileDirty(int x, int y)
662 int xx = redraw_x1 + x;
663 int yy = redraw_y1 + y;
668 redraw[xx][yy] = TRUE;
669 redraw_mask |= REDRAW_TILES;
672 void SetBorderElement()
676 BorderElement = EL_EMPTY;
678 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
680 for (x = 0; x < lev_fieldx; x++)
682 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
683 BorderElement = EL_STEELWALL;
685 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
691 void SetRandomAnimationValue(int x, int y)
693 gfx.anim_random_frame = GfxRandom[x][y];
696 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
698 /* animation synchronized with global frame counter, not move position */
699 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
700 sync_frame = FrameCounter;
702 return getAnimationFrame(graphic_info[graphic].anim_frames,
703 graphic_info[graphic].anim_delay,
704 graphic_info[graphic].anim_mode,
705 graphic_info[graphic].anim_start_frame,
709 inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
710 int *x, int *y, boolean get_backside)
712 struct GraphicInfo *g = &graphic_info[graphic];
713 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
714 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
718 if (g->offset_y == 0) /* frames are ordered horizontally */
720 int max_width = g->anim_frames_per_line * g->width;
721 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
723 *x = pos % max_width;
724 *y = src_y % g->height + pos / max_width * g->height;
726 else if (g->offset_x == 0) /* frames are ordered vertically */
728 int max_height = g->anim_frames_per_line * g->height;
729 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
731 *x = src_x % g->width + pos / max_height * g->width;
732 *y = pos % max_height;
734 else /* frames are ordered diagonally */
736 *x = src_x + frame * g->offset_x;
737 *y = src_y + frame * g->offset_y;
741 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
743 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
746 void DrawGraphic(int x, int y, int graphic, int frame)
749 if (!IN_SCR_FIELD(x, y))
751 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
752 printf("DrawGraphic(): This should never happen!\n");
757 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
761 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
767 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
768 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
771 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
774 if (!IN_SCR_FIELD(x, y))
776 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
777 printf("DrawGraphicThruMask(): This should never happen!\n");
782 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
787 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
793 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
795 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
796 dst_x - src_x, dst_y - src_y);
797 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
800 void DrawMiniGraphic(int x, int y, int graphic)
802 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
803 MarkTileDirty(x / 2, y / 2);
806 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
808 struct GraphicInfo *g = &graphic_info[graphic];
810 int mini_starty = g->bitmap->height * 2 / 3;
813 *x = mini_startx + g->src_x / 2;
814 *y = mini_starty + g->src_y / 2;
817 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
822 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
823 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
826 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
827 int graphic, int frame,
828 int cut_mode, int mask_mode)
833 int width = TILEX, height = TILEY;
836 if (dx || dy) /* shifted graphic */
838 if (x < BX1) /* object enters playfield from the left */
845 else if (x > BX2) /* object enters playfield from the right */
851 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
857 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
859 else if (dx) /* general horizontal movement */
860 MarkTileDirty(x + SIGN(dx), y);
862 if (y < BY1) /* object enters playfield from the top */
864 if (cut_mode==CUT_BELOW) /* object completely above top border */
872 else if (y > BY2) /* object enters playfield from the bottom */
878 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
884 else if (dy > 0 && cut_mode == CUT_ABOVE)
886 if (y == BY2) /* object completely above bottom border */
892 MarkTileDirty(x, y + 1);
893 } /* object leaves playfield to the bottom */
894 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
896 else if (dy) /* general vertical movement */
897 MarkTileDirty(x, y + SIGN(dy));
901 if (!IN_SCR_FIELD(x, y))
903 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
904 printf("DrawGraphicShifted(): This should never happen!\n");
909 if (width > 0 && height > 0)
911 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
916 dst_x = FX + x * TILEX + dx;
917 dst_y = FY + y * TILEY + dy;
919 if (mask_mode == USE_MASKING)
921 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
922 dst_x - src_x, dst_y - src_y);
923 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
927 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
934 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
935 int graphic, int frame,
936 int cut_mode, int mask_mode)
941 int width = TILEX, height = TILEY;
944 int x2 = x + SIGN(dx);
945 int y2 = y + SIGN(dy);
946 int anim_frames = graphic_info[graphic].anim_frames;
947 int sync_frame = (dx ? ABS(dx) : ABS(dy)) * anim_frames / TILESIZE;
948 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
949 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
951 /* re-calculate animation frame for two-tile movement animation */
952 frame = getGraphicAnimationFrame(graphic, sync_frame);
954 /* check if movement start graphic inside screen area and should be drawn */
955 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
957 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
959 dst_x = FX + x1 * TILEX;
960 dst_y = FY + y1 * TILEY;
962 if (mask_mode == USE_MASKING)
964 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
965 dst_x - src_x, dst_y - src_y);
966 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
970 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
973 MarkTileDirty(x1, y1);
976 /* check if movement end graphic inside screen area and should be drawn */
977 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
979 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
981 dst_x = FX + x2 * TILEX;
982 dst_y = FY + y2 * TILEY;
984 if (mask_mode == USE_MASKING)
986 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
987 dst_x - src_x, dst_y - src_y);
988 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
992 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
995 MarkTileDirty(x2, y2);
999 static void DrawGraphicShifted(int x, int y, int dx, int dy,
1000 int graphic, int frame,
1001 int cut_mode, int mask_mode)
1005 DrawGraphic(x, y, graphic, frame);
1010 if (graphic_info[graphic].double_movement) /* EM style movement images */
1011 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1013 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1016 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1017 int frame, int cut_mode)
1019 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
1022 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1023 int cut_mode, int mask_mode)
1025 int lx = LEVELX(x), ly = LEVELY(y);
1029 if (IN_LEV_FIELD(lx, ly))
1031 SetRandomAnimationValue(lx, ly);
1033 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
1034 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1036 /* do not use double (EM style) movement graphic when not moving */
1037 if (graphic_info[graphic].double_movement && !dx && !dy)
1039 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
1040 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1043 else /* border element */
1045 graphic = el2img(element);
1046 frame = getGraphicAnimationFrame(graphic, -1);
1049 if (element == EL_EXPANDABLE_WALL)
1051 boolean left_stopped = FALSE, right_stopped = FALSE;
1053 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1054 left_stopped = TRUE;
1055 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1056 right_stopped = TRUE;
1058 if (left_stopped && right_stopped)
1060 else if (left_stopped)
1062 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1063 frame = graphic_info[graphic].anim_frames - 1;
1065 else if (right_stopped)
1067 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1068 frame = graphic_info[graphic].anim_frames - 1;
1073 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1074 else if (mask_mode == USE_MASKING)
1075 DrawGraphicThruMask(x, y, graphic, frame);
1077 DrawGraphic(x, y, graphic, frame);
1080 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1081 int cut_mode, int mask_mode)
1083 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1084 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1085 cut_mode, mask_mode);
1088 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1091 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1094 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1097 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1100 void DrawLevelElementThruMask(int x, int y, int element)
1102 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1105 void DrawLevelFieldThruMask(int x, int y)
1107 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1110 static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
1114 int sx = SCREENX(x), sy = SCREENY(y);
1116 int width, height, cx, cy, i;
1117 int crumbled_border_size = graphic_info[graphic].border_size;
1118 static int xy[4][2] =
1126 if (!IN_LEV_FIELD(x, y))
1129 element = TILE_GFX_ELEMENT(x, y);
1131 /* crumble field itself */
1132 if (GFX_CRUMBLED(element) && !IS_MOVING(x, y))
1134 if (!IN_SCR_FIELD(sx, sy))
1137 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1139 for (i = 0; i < 4; i++)
1141 int xx = x + xy[i][0];
1142 int yy = y + xy[i][1];
1144 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1147 /* check if neighbour field is of same type */
1148 if (GFX_CRUMBLED(element) && !IS_MOVING(xx, yy))
1151 if (i == 1 || i == 2)
1153 width = crumbled_border_size;
1155 cx = (i == 2 ? TILEX - crumbled_border_size : 0);
1161 height = crumbled_border_size;
1163 cy = (i == 3 ? TILEY - crumbled_border_size : 0);
1166 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1167 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1170 MarkTileDirty(sx, sy);
1172 else /* crumble neighbour fields */
1174 for (i = 0; i < 4; i++)
1176 int xx = x + xy[i][0];
1177 int yy = y + xy[i][1];
1178 int sxx = sx + xy[i][0];
1179 int syy = sy + xy[i][1];
1181 if (!IN_LEV_FIELD(xx, yy) ||
1182 !IN_SCR_FIELD(sxx, syy) ||
1186 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
1189 element = TILE_GFX_ELEMENT(xx, yy);
1191 if (!GFX_CRUMBLED(element))
1194 graphic = el_act2crm(element, ACTION_DEFAULT);
1195 crumbled_border_size = graphic_info[graphic].border_size;
1197 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1199 if (i == 1 || i == 2)
1201 width = crumbled_border_size;
1203 cx = (i == 1 ? TILEX - crumbled_border_size : 0);
1209 height = crumbled_border_size;
1211 cy = (i == 0 ? TILEY - crumbled_border_size : 0);
1214 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1215 width, height, FX + sxx * TILEX + cx, FY + syy * TILEY + cy);
1217 MarkTileDirty(sxx, syy);
1222 void DrawLevelFieldCrumbledSand(int x, int y)
1226 if (!IN_LEV_FIELD(x, y))
1230 /* !!! CHECK THIS !!! */
1233 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1234 GFX_CRUMBLED(GfxElement[x][y]))
1237 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1238 GfxElement[x][y] != EL_UNDEFINED &&
1239 GFX_CRUMBLED(GfxElement[x][y]))
1241 DrawLevelFieldCrumbledSandDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
1248 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
1250 graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
1253 DrawLevelFieldCrumbledSandExt(x, y, graphic, 0);
1256 void DrawLevelFieldCrumbledSandDigging(int x, int y, int direction,
1259 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1260 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1261 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1262 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1263 int sx = SCREENX(x), sy = SCREENY(y);
1265 DrawGraphic(sx, sy, graphic1, frame1);
1266 DrawLevelFieldCrumbledSandExt(x, y, graphic2, frame2);
1269 void DrawLevelFieldCrumbledSandNeighbours(int x, int y)
1271 int sx = SCREENX(x), sy = SCREENY(y);
1272 static int xy[4][2] =
1281 for (i = 0; i < 4; i++)
1283 int xx = x + xy[i][0];
1284 int yy = y + xy[i][1];
1285 int sxx = sx + xy[i][0];
1286 int syy = sy + xy[i][1];
1288 if (!IN_LEV_FIELD(xx, yy) ||
1289 !IN_SCR_FIELD(sxx, syy) ||
1290 !GFX_CRUMBLED(Feld[xx][yy]) ||
1294 DrawLevelField(xx, yy);
1298 static int getBorderElement(int x, int y)
1302 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1303 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1304 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1305 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1306 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1307 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1308 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1310 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1311 int steel_position = (x == -1 && y == -1 ? 0 :
1312 x == lev_fieldx && y == -1 ? 1 :
1313 x == -1 && y == lev_fieldy ? 2 :
1314 x == lev_fieldx && y == lev_fieldy ? 3 :
1315 x == -1 || x == lev_fieldx ? 4 :
1316 y == -1 || y == lev_fieldy ? 5 : 6);
1318 return border[steel_position][steel_type];
1321 void DrawScreenElement(int x, int y, int element)
1323 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1324 DrawLevelFieldCrumbledSand(LEVELX(x), LEVELY(y));
1327 void DrawLevelElement(int x, int y, int element)
1329 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1330 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1333 void DrawScreenField(int x, int y)
1335 int lx = LEVELX(x), ly = LEVELY(y);
1336 int element, content;
1338 if (!IN_LEV_FIELD(lx, ly))
1340 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1343 element = getBorderElement(lx, ly);
1345 DrawScreenElement(x, y, element);
1349 element = Feld[lx][ly];
1350 content = Store[lx][ly];
1352 if (IS_MOVING(lx, ly))
1354 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1355 boolean cut_mode = NO_CUTTING;
1357 if (element == EL_QUICKSAND_EMPTYING ||
1358 element == EL_MAGIC_WALL_EMPTYING ||
1359 element == EL_BD_MAGIC_WALL_EMPTYING ||
1360 element == EL_AMOEBA_DROPPING)
1361 cut_mode = CUT_ABOVE;
1362 else if (element == EL_QUICKSAND_FILLING ||
1363 element == EL_MAGIC_WALL_FILLING ||
1364 element == EL_BD_MAGIC_WALL_FILLING)
1365 cut_mode = CUT_BELOW;
1367 if (cut_mode == CUT_ABOVE)
1368 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1370 DrawScreenElement(x, y, EL_EMPTY);
1373 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1374 else if (cut_mode == NO_CUTTING)
1375 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1377 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1379 if (content == EL_ACID)
1381 int dir = MovDir[lx][ly];
1382 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
1383 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
1385 DrawLevelElementThruMask(newlx, newly, EL_ACID);
1388 else if (IS_BLOCKED(lx, ly))
1393 boolean cut_mode = NO_CUTTING;
1394 int element_old, content_old;
1396 Blocked2Moving(lx, ly, &oldx, &oldy);
1399 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1400 MovDir[oldx][oldy] == MV_RIGHT);
1402 element_old = Feld[oldx][oldy];
1403 content_old = Store[oldx][oldy];
1405 if (element_old == EL_QUICKSAND_EMPTYING ||
1406 element_old == EL_MAGIC_WALL_EMPTYING ||
1407 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1408 element_old == EL_AMOEBA_DROPPING)
1409 cut_mode = CUT_ABOVE;
1411 DrawScreenElement(x, y, EL_EMPTY);
1414 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1416 else if (cut_mode == NO_CUTTING)
1417 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1420 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1423 else if (IS_DRAWABLE(element))
1424 DrawScreenElement(x, y, element);
1426 DrawScreenElement(x, y, EL_EMPTY);
1429 void DrawLevelField(int x, int y)
1431 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1432 DrawScreenField(SCREENX(x), SCREENY(y));
1433 else if (IS_MOVING(x, y))
1437 Moving2Blocked(x, y, &newx, &newy);
1438 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1439 DrawScreenField(SCREENX(newx), SCREENY(newy));
1441 else if (IS_BLOCKED(x, y))
1445 Blocked2Moving(x, y, &oldx, &oldy);
1446 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1447 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1451 void DrawMiniElement(int x, int y, int element)
1455 graphic = el2edimg(element);
1456 DrawMiniGraphic(x, y, graphic);
1459 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1461 int x = sx + scroll_x, y = sy + scroll_y;
1463 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1464 DrawMiniElement(sx, sy, EL_EMPTY);
1465 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1466 DrawMiniElement(sx, sy, Feld[x][y]);
1468 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1471 void DrawEnvelopeBackground(int envelope_nr, int startx, int starty,
1472 int x, int y, int xsize, int ysize, int font_nr)
1474 int font_width = getFontWidth(font_nr);
1475 int font_height = getFontHeight(font_nr);
1476 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1479 int dst_x = SX + startx + x * font_width;
1480 int dst_y = SY + starty + y * font_height;
1481 int width = graphic_info[graphic].width;
1482 int height = graphic_info[graphic].height;
1483 int inner_width = MAX(width - 2 * font_width, font_width);
1484 int inner_height = MAX(height - 2 * font_height, font_height);
1485 int inner_sx = (width >= 3 * font_width ? font_width : 0);
1486 int inner_sy = (height >= 3 * font_height ? font_height : 0);
1487 boolean draw_masked = graphic_info[graphic].draw_masked;
1489 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1491 if (src_bitmap == NULL || width < font_width || height < font_height)
1493 ClearRectangle(drawto, dst_x, dst_y, font_width, font_height);
1497 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - font_width :
1498 inner_sx + (x - 1) * font_width % inner_width);
1499 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - font_height :
1500 inner_sy + (y - 1) * font_height % inner_height);
1504 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1505 dst_x - src_x, dst_y - src_y);
1506 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1510 BlitBitmap(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1514 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
1516 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1517 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1518 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
1519 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1520 boolean no_delay = (tape.warp_forward);
1521 unsigned long anim_delay = 0;
1522 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
1523 int anim_delay_value = (no_delay ? 0 : frame_delay_value);
1524 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
1525 int font_width = getFontWidth(font_nr);
1526 int font_height = getFontHeight(font_nr);
1527 int max_xsize = level.envelope[envelope_nr].xsize;
1528 int max_ysize = level.envelope[envelope_nr].ysize;
1529 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
1530 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
1531 int xend = max_xsize;
1532 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
1533 int xstep = (xstart < xend ? 1 : 0);
1534 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
1537 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
1539 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
1540 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
1541 int sx = (SXSIZE - xsize * font_width) / 2;
1542 int sy = (SYSIZE - ysize * font_height) / 2;
1545 SetDrawtoField(DRAW_BUFFERED);
1547 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
1549 SetDrawtoField(DRAW_BACKBUFFER);
1551 for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++)
1552 DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
1554 DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
1555 level.envelope[envelope_nr].text, font_nr, max_xsize,
1556 xsize - 2, ysize - 2, mask_mode);
1558 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
1561 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
1565 void ShowEnvelope(int envelope_nr)
1567 int element = EL_ENVELOPE_1 + envelope_nr;
1568 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1569 int sound_opening = element_info[element].sound[ACTION_OPENING];
1570 int sound_closing = element_info[element].sound[ACTION_CLOSING];
1571 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1572 boolean no_delay = (tape.warp_forward);
1573 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
1574 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
1575 int anim_mode = graphic_info[graphic].anim_mode;
1576 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
1577 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
1579 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
1581 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
1583 if (anim_mode == ANIM_DEFAULT)
1584 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
1586 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
1589 Delay(wait_delay_value);
1591 WaitForEventToContinue();
1593 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
1595 if (anim_mode != ANIM_NONE)
1596 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
1598 if (anim_mode == ANIM_DEFAULT)
1599 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
1601 game.envelope_active = FALSE;
1603 SetDrawtoField(DRAW_BUFFERED);
1605 redraw_mask |= REDRAW_FIELD;
1609 void getPreviewGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y,
1614 int width_mult, width_div;
1615 int height_mult, height_div;
1623 int offset_calc_pos = (tilesize < MICRO_TILESIZE || tilesize > TILESIZE ? 3 :
1624 5 - log_2(tilesize));
1625 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1626 int width_mult = offset_calc[offset_calc_pos].width_mult;
1627 int width_div = offset_calc[offset_calc_pos].width_div;
1628 int height_mult = offset_calc[offset_calc_pos].height_mult;
1629 int height_div = offset_calc[offset_calc_pos].height_div;
1630 int mini_startx = src_bitmap->width * width_mult / width_div;
1631 int mini_starty = src_bitmap->height * height_mult / height_div;
1632 int src_x = mini_startx + graphic_info[graphic].src_x * tilesize / TILESIZE;
1633 int src_y = mini_starty + graphic_info[graphic].src_y * tilesize / TILESIZE;
1635 *bitmap = src_bitmap;
1640 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
1644 int graphic = el2preimg(element);
1646 getPreviewGraphicSource(graphic, &src_bitmap, &src_x, &src_y, tilesize);
1647 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
1654 SetDrawBackgroundMask(REDRAW_NONE);
1657 for (x = BX1; x <= BX2; x++)
1658 for (y = BY1; y <= BY2; y++)
1659 DrawScreenField(x, y);
1661 redraw_mask |= REDRAW_FIELD;
1664 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1668 for (x = 0; x < size_x; x++)
1669 for (y = 0; y < size_y; y++)
1670 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1672 redraw_mask |= REDRAW_FIELD;
1675 static void DrawPreviewLevelExt(int from_x, int from_y)
1677 boolean show_level_border = (BorderElement != EL_EMPTY);
1678 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
1679 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
1680 int tile_size = preview.tile_size;
1681 int preview_width = preview.xsize * tile_size;
1682 int preview_height = preview.ysize * tile_size;
1683 int real_preview_xsize = MIN(level_xsize, preview.xsize);
1684 int real_preview_ysize = MIN(level_ysize, preview.ysize);
1685 int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
1686 int dst_y = SY + preview.y;
1689 DrawBackground(dst_x, dst_y, preview_width, preview_height);
1691 dst_x += (preview_width - real_preview_xsize * tile_size) / 2;
1692 dst_y += (preview_height - real_preview_ysize * tile_size) / 2;
1694 for (x = 0; x < real_preview_xsize; x++)
1696 for (y = 0; y < real_preview_ysize; y++)
1698 int lx = from_x + x + (show_level_border ? -1 : 0);
1699 int ly = from_y + y + (show_level_border ? -1 : 0);
1700 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
1701 getBorderElement(lx, ly));
1703 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
1704 element, tile_size);
1708 redraw_mask |= REDRAW_MICROLEVEL;
1711 #define MICROLABEL_EMPTY 0
1712 #define MICROLABEL_LEVEL_NAME 1
1713 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
1714 #define MICROLABEL_LEVEL_AUTHOR 3
1715 #define MICROLABEL_IMPORTED_FROM_HEAD 4
1716 #define MICROLABEL_IMPORTED_FROM 5
1717 #define MICROLABEL_IMPORTED_BY_HEAD 6
1718 #define MICROLABEL_IMPORTED_BY 7
1720 static int getMaxTextLength(struct MenuPosInfo *pos, int font_nr)
1722 int max_text_width = SXSIZE;
1723 int font_width = getFontWidth(font_nr);
1725 if (pos->align == ALIGN_CENTER)
1726 max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
1727 else if (pos->align == ALIGN_RIGHT)
1728 max_text_width = pos->x;
1730 max_text_width = SXSIZE - pos->x;
1732 return max_text_width / font_width;
1735 static void DrawPreviewLevelLabelExt(int mode)
1737 struct MenuPosInfo *pos = &menu.main.text.level_info_2;
1738 char label_text[MAX_OUTPUT_LINESIZE + 1];
1739 int max_len_label_text;
1740 int font_nr = FONT_TEXT_2;
1743 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
1744 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
1745 mode == MICROLABEL_IMPORTED_BY_HEAD)
1746 font_nr = FONT_TEXT_3;
1749 max_len_label_text = getMaxTextLength(pos, font_nr);
1751 max_len_label_text = SXSIZE / getFontWidth(font_nr);
1754 for (i = 0; i < max_len_label_text; i++)
1755 label_text[i] = ' ';
1756 label_text[max_len_label_text] = '\0';
1758 if (strlen(label_text) > 0)
1761 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
1763 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1764 int lypos = MICROLABEL2_YPOS;
1766 DrawText(lxpos, lypos, label_text, font_nr);
1771 (mode == MICROLABEL_LEVEL_NAME ? level.name :
1772 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
1773 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1774 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
1775 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
1776 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
1777 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
1778 max_len_label_text);
1779 label_text[max_len_label_text] = '\0';
1781 if (strlen(label_text) > 0)
1784 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
1786 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1787 int lypos = MICROLABEL2_YPOS;
1789 DrawText(lxpos, lypos, label_text, font_nr);
1793 redraw_mask |= REDRAW_MICROLEVEL;
1796 void DrawPreviewLevel(boolean restart)
1798 static unsigned long scroll_delay = 0;
1799 static unsigned long label_delay = 0;
1800 static int from_x, from_y, scroll_direction;
1801 static int label_state, label_counter;
1802 unsigned long scroll_delay_value = preview.step_delay;
1803 boolean show_level_border = (BorderElement != EL_EMPTY);
1804 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
1805 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
1806 int last_game_status = game_status; /* save current game status */
1808 /* force PREVIEW font on preview level */
1809 game_status = GAME_MODE_PSEUDO_PREVIEW;
1816 if (preview.anim_mode == ANIM_CENTERED)
1818 if (level_xsize > preview.xsize)
1819 from_x = (level_xsize - preview.xsize) / 2;
1820 if (level_ysize > preview.ysize)
1821 from_y = (level_ysize - preview.ysize) / 2;
1824 from_x += preview.xoffset;
1825 from_y += preview.yoffset;
1827 scroll_direction = MV_RIGHT;
1831 DrawPreviewLevelExt(from_x, from_y);
1832 DrawPreviewLevelLabelExt(label_state);
1834 /* initialize delay counters */
1835 DelayReached(&scroll_delay, 0);
1836 DelayReached(&label_delay, 0);
1838 if (leveldir_current->name)
1840 struct MenuPosInfo *pos = &menu.main.text.level_info_1;
1841 char label_text[MAX_OUTPUT_LINESIZE + 1];
1842 int font_nr = FONT_TEXT_1;
1844 int max_len_label_text = getMaxTextLength(pos, font_nr);
1846 int max_len_label_text = SXSIZE / getFontWidth(font_nr);
1853 strncpy(label_text, leveldir_current->name, max_len_label_text);
1854 label_text[max_len_label_text] = '\0';
1857 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
1859 lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1860 lypos = SY + MICROLABEL1_YPOS;
1862 DrawText(lxpos, lypos, label_text, font_nr);
1866 game_status = last_game_status; /* restore current game status */
1871 /* scroll preview level, if needed */
1872 if (preview.anim_mode != ANIM_NONE &&
1873 (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
1874 DelayReached(&scroll_delay, scroll_delay_value))
1876 switch (scroll_direction)
1881 from_x -= preview.step_offset;
1882 from_x = (from_x < 0 ? 0 : from_x);
1885 scroll_direction = MV_UP;
1889 if (from_x < level_xsize - preview.xsize)
1891 from_x += preview.step_offset;
1892 from_x = (from_x > level_xsize - preview.xsize ?
1893 level_xsize - preview.xsize : from_x);
1896 scroll_direction = MV_DOWN;
1902 from_y -= preview.step_offset;
1903 from_y = (from_y < 0 ? 0 : from_y);
1906 scroll_direction = MV_RIGHT;
1910 if (from_y < level_ysize - preview.ysize)
1912 from_y += preview.step_offset;
1913 from_y = (from_y > level_ysize - preview.ysize ?
1914 level_ysize - preview.ysize : from_y);
1917 scroll_direction = MV_LEFT;
1924 DrawPreviewLevelExt(from_x, from_y);
1927 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
1928 /* redraw micro level label, if needed */
1929 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
1930 !strEqual(level.author, ANONYMOUS_NAME) &&
1931 !strEqual(level.author, leveldir_current->name) &&
1932 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
1934 int max_label_counter = 23;
1936 if (leveldir_current->imported_from != NULL &&
1937 strlen(leveldir_current->imported_from) > 0)
1938 max_label_counter += 14;
1939 if (leveldir_current->imported_by != NULL &&
1940 strlen(leveldir_current->imported_by) > 0)
1941 max_label_counter += 14;
1943 label_counter = (label_counter + 1) % max_label_counter;
1944 label_state = (label_counter >= 0 && label_counter <= 7 ?
1945 MICROLABEL_LEVEL_NAME :
1946 label_counter >= 9 && label_counter <= 12 ?
1947 MICROLABEL_LEVEL_AUTHOR_HEAD :
1948 label_counter >= 14 && label_counter <= 21 ?
1949 MICROLABEL_LEVEL_AUTHOR :
1950 label_counter >= 23 && label_counter <= 26 ?
1951 MICROLABEL_IMPORTED_FROM_HEAD :
1952 label_counter >= 28 && label_counter <= 35 ?
1953 MICROLABEL_IMPORTED_FROM :
1954 label_counter >= 37 && label_counter <= 40 ?
1955 MICROLABEL_IMPORTED_BY_HEAD :
1956 label_counter >= 42 && label_counter <= 49 ?
1957 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
1959 if (leveldir_current->imported_from == NULL &&
1960 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
1961 label_state == MICROLABEL_IMPORTED_FROM))
1962 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
1963 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
1965 DrawPreviewLevelLabelExt(label_state);
1968 game_status = last_game_status; /* restore current game status */
1971 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
1972 int graphic, int sync_frame, int mask_mode)
1974 int frame = getGraphicAnimationFrame(graphic, sync_frame);
1976 if (mask_mode == USE_MASKING)
1977 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
1979 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
1982 inline void DrawGraphicAnimation(int x, int y, int graphic)
1984 int lx = LEVELX(x), ly = LEVELY(y);
1986 if (!IN_SCR_FIELD(x, y))
1989 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
1990 graphic, GfxFrame[lx][ly], NO_MASKING);
1991 MarkTileDirty(x, y);
1994 void DrawLevelGraphicAnimation(int x, int y, int graphic)
1996 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
1999 void DrawLevelElementAnimation(int x, int y, int element)
2001 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2003 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2006 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
2008 int sx = SCREENX(x), sy = SCREENY(y);
2010 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2013 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2016 DrawGraphicAnimation(sx, sy, graphic);
2019 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
2020 DrawLevelFieldCrumbledSand(x, y);
2022 if (GFX_CRUMBLED(Feld[x][y]))
2023 DrawLevelFieldCrumbledSand(x, y);
2027 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
2029 int sx = SCREENX(x), sy = SCREENY(y);
2032 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2035 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2037 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2040 DrawGraphicAnimation(sx, sy, graphic);
2042 if (GFX_CRUMBLED(element))
2043 DrawLevelFieldCrumbledSand(x, y);
2046 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
2048 if (player->use_murphy)
2050 /* this works only because currently only one player can be "murphy" ... */
2051 static int last_horizontal_dir = MV_LEFT;
2052 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
2054 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2055 last_horizontal_dir = move_dir;
2057 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
2059 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
2061 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
2067 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
2070 static boolean equalGraphics(int graphic1, int graphic2)
2072 struct GraphicInfo *g1 = &graphic_info[graphic1];
2073 struct GraphicInfo *g2 = &graphic_info[graphic2];
2075 return (g1->bitmap == g2->bitmap &&
2076 g1->src_x == g2->src_x &&
2077 g1->src_y == g2->src_y &&
2078 g1->anim_frames == g2->anim_frames &&
2079 g1->anim_delay == g2->anim_delay &&
2080 g1->anim_mode == g2->anim_mode);
2083 void DrawAllPlayers()
2087 for (i = 0; i < MAX_PLAYERS; i++)
2088 if (stored_player[i].active)
2089 DrawPlayer(&stored_player[i]);
2092 void DrawPlayerField(int x, int y)
2094 if (!IS_PLAYER(x, y))
2097 DrawPlayer(PLAYERINFO(x, y));
2100 void DrawPlayer(struct PlayerInfo *player)
2102 int jx = player->jx;
2103 int jy = player->jy;
2104 int move_dir = player->MovDir;
2105 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
2106 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
2107 int last_jx = (player->is_moving ? jx - dx : jx);
2108 int last_jy = (player->is_moving ? jy - dy : jy);
2109 int next_jx = jx + dx;
2110 int next_jy = jy + dy;
2111 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
2112 boolean player_is_opaque = FALSE;
2113 int sx = SCREENX(jx), sy = SCREENY(jy);
2114 int sxx = 0, syy = 0;
2115 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
2117 int action = ACTION_DEFAULT;
2118 int last_player_graphic = getPlayerGraphic(player, move_dir);
2119 int last_player_frame = player->Frame;
2122 /* GfxElement[][] is set to the element the player is digging or collecting;
2123 remove also for off-screen player if the player is not moving anymore */
2124 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
2125 GfxElement[jx][jy] = EL_UNDEFINED;
2127 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
2131 if (!IN_LEV_FIELD(jx, jy))
2133 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
2134 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
2135 printf("DrawPlayerField(): This should never happen!\n");
2140 if (element == EL_EXPLOSION)
2143 action = (player->is_pushing ? ACTION_PUSHING :
2144 player->is_digging ? ACTION_DIGGING :
2145 player->is_collecting ? ACTION_COLLECTING :
2146 player->is_moving ? ACTION_MOVING :
2147 player->is_snapping ? ACTION_SNAPPING :
2148 player->is_dropping ? ACTION_DROPPING :
2149 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
2151 if (player->is_waiting)
2152 move_dir = player->dir_waiting;
2154 InitPlayerGfxAnimation(player, action, move_dir);
2156 /* ----------------------------------------------------------------------- */
2157 /* draw things in the field the player is leaving, if needed */
2158 /* ----------------------------------------------------------------------- */
2160 if (player->is_moving)
2162 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
2164 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
2166 if (last_element == EL_DYNAMITE_ACTIVE ||
2167 last_element == EL_EM_DYNAMITE_ACTIVE ||
2168 last_element == EL_SP_DISK_RED_ACTIVE)
2169 DrawDynamite(last_jx, last_jy);
2171 DrawLevelFieldThruMask(last_jx, last_jy);
2173 else if (last_element == EL_DYNAMITE_ACTIVE ||
2174 last_element == EL_EM_DYNAMITE_ACTIVE ||
2175 last_element == EL_SP_DISK_RED_ACTIVE)
2176 DrawDynamite(last_jx, last_jy);
2178 /* !!! this is not enough to prevent flickering of players which are
2179 moving next to each others without a free tile between them -- this
2180 can only be solved by drawing all players layer by layer (first the
2181 background, then the foreground etc.) !!! => TODO */
2182 else if (!IS_PLAYER(last_jx, last_jy))
2183 DrawLevelField(last_jx, last_jy);
2186 DrawLevelField(last_jx, last_jy);
2189 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
2190 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
2193 if (!IN_SCR_FIELD(sx, sy))
2196 if (setup.direct_draw)
2197 SetDrawtoField(DRAW_BUFFERED);
2199 /* ----------------------------------------------------------------------- */
2200 /* draw things behind the player, if needed */
2201 /* ----------------------------------------------------------------------- */
2204 DrawLevelElement(jx, jy, Back[jx][jy]);
2205 else if (IS_ACTIVE_BOMB(element))
2206 DrawLevelElement(jx, jy, EL_EMPTY);
2209 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
2211 int old_element = GfxElement[jx][jy];
2212 int old_graphic = el_act_dir2img(old_element, action, move_dir);
2213 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
2215 if (GFX_CRUMBLED(old_element))
2216 DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
2218 DrawGraphic(sx, sy, old_graphic, frame);
2220 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
2221 player_is_opaque = TRUE;
2225 GfxElement[jx][jy] = EL_UNDEFINED;
2227 /* make sure that pushed elements are drawn with correct frame rate */
2229 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2231 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
2232 GfxFrame[jx][jy] = player->StepFrame;
2234 if (player->is_pushing && player->is_moving)
2235 GfxFrame[jx][jy] = player->StepFrame;
2238 DrawLevelField(jx, jy);
2242 /* ----------------------------------------------------------------------- */
2243 /* draw player himself */
2244 /* ----------------------------------------------------------------------- */
2246 graphic = getPlayerGraphic(player, move_dir);
2248 /* in the case of changed player action or direction, prevent the current
2249 animation frame from being restarted for identical animations */
2250 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
2251 player->Frame = last_player_frame;
2253 frame = getGraphicAnimationFrame(graphic, player->Frame);
2257 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2258 sxx = player->GfxPos;
2260 syy = player->GfxPos;
2263 if (!setup.soft_scrolling && ScreenMovPos)
2266 if (player_is_opaque)
2267 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
2269 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2271 if (SHIELD_ON(player))
2273 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
2274 IMG_SHIELD_NORMAL_ACTIVE);
2275 int frame = getGraphicAnimationFrame(graphic, -1);
2277 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2280 /* ----------------------------------------------------------------------- */
2281 /* draw things the player is pushing, if needed */
2282 /* ----------------------------------------------------------------------- */
2285 printf("::: %d, %d [%d, %d] [%d]\n",
2286 player->is_pushing, player_is_moving, player->GfxAction,
2287 player->is_moving, player_is_moving);
2291 if (player->is_pushing && player->is_moving)
2293 int px = SCREENX(jx), py = SCREENY(jy);
2294 int pxx = (TILEX - ABS(sxx)) * dx;
2295 int pyy = (TILEY - ABS(syy)) * dy;
2296 int gfx_frame = GfxFrame[jx][jy];
2302 if (!IS_MOVING(jx, jy)) /* push movement already finished */
2304 element = Feld[next_jx][next_jy];
2305 gfx_frame = GfxFrame[next_jx][next_jy];
2308 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2311 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
2312 frame = getGraphicAnimationFrame(graphic, sync_frame);
2314 frame = getGraphicAnimationFrame(graphic, player->StepFrame);
2317 /* draw background element under pushed element (like the Sokoban field) */
2318 if (Back[next_jx][next_jy])
2319 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
2321 /* masked drawing is needed for EMC style (double) movement graphics */
2322 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
2326 /* ----------------------------------------------------------------------- */
2327 /* draw things in front of player (active dynamite or dynabombs) */
2328 /* ----------------------------------------------------------------------- */
2330 if (IS_ACTIVE_BOMB(element))
2332 graphic = el2img(element);
2333 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
2335 if (game.emulation == EMU_SUPAPLEX)
2336 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
2338 DrawGraphicThruMask(sx, sy, graphic, frame);
2341 if (player_is_moving && last_element == EL_EXPLOSION)
2343 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
2344 GfxElement[last_jx][last_jy] : EL_EMPTY);
2345 int graphic = el_act2img(element, ACTION_EXPLODING);
2346 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
2347 int phase = ExplodePhase[last_jx][last_jy] - 1;
2348 int frame = getGraphicAnimationFrame(graphic, phase - delay);
2351 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
2354 /* ----------------------------------------------------------------------- */
2355 /* draw elements the player is just walking/passing through/under */
2356 /* ----------------------------------------------------------------------- */
2358 if (player_is_moving)
2360 /* handle the field the player is leaving ... */
2361 if (IS_ACCESSIBLE_INSIDE(last_element))
2362 DrawLevelField(last_jx, last_jy);
2363 else if (IS_ACCESSIBLE_UNDER(last_element))
2364 DrawLevelFieldThruMask(last_jx, last_jy);
2367 /* do not redraw accessible elements if the player is just pushing them */
2368 if (!player_is_moving || !player->is_pushing)
2370 /* ... and the field the player is entering */
2371 if (IS_ACCESSIBLE_INSIDE(element))
2372 DrawLevelField(jx, jy);
2373 else if (IS_ACCESSIBLE_UNDER(element))
2374 DrawLevelFieldThruMask(jx, jy);
2377 if (setup.direct_draw)
2379 int dst_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
2380 int dst_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
2381 int x_size = TILEX * (1 + ABS(jx - last_jx));
2382 int y_size = TILEY * (1 + ABS(jy - last_jy));
2384 BlitBitmap(drawto_field, window,
2385 dst_x, dst_y, x_size, y_size, dst_x, dst_y);
2386 SetDrawtoField(DRAW_DIRECT);
2389 MarkTileDirty(sx, sy);
2392 /* ------------------------------------------------------------------------- */
2394 void WaitForEventToContinue()
2396 boolean still_wait = TRUE;
2398 /* simulate releasing mouse button over last gadget, if still pressed */
2400 HandleGadgets(-1, -1, 0);
2402 button_status = MB_RELEASED;
2418 case EVENT_BUTTONPRESS:
2419 case EVENT_KEYPRESS:
2423 case EVENT_KEYRELEASE:
2424 ClearPlayerAction();
2428 HandleOtherEvents(&event);
2432 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2439 /* don't eat all CPU time */
2444 #define MAX_REQUEST_LINES 13
2445 #define MAX_REQUEST_LINE_FONT1_LEN 7
2446 #define MAX_REQUEST_LINE_FONT2_LEN 10
2448 boolean Request(char *text, unsigned int req_state)
2450 int mx, my, ty, result = -1;
2451 unsigned int old_door_state;
2452 int last_game_status = game_status; /* save current game status */
2453 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
2454 int font_nr = FONT_TEXT_2;
2455 int max_word_len = 0;
2458 for (text_ptr = text; *text_ptr; text_ptr++)
2460 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
2462 if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
2464 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
2465 font_nr = FONT_LEVEL_NUMBER;
2471 if (game_status == GAME_MODE_PLAYING &&
2472 level.game_engine_type == GAME_ENGINE_TYPE_EM)
2473 BlitScreenToBitmap_EM(backbuffer);
2475 /* disable deactivated drawing when quick-loading level tape recording */
2476 if (tape.playing && tape.deactivate_display)
2477 TapeDeactivateDisplayOff(TRUE);
2479 SetMouseCursor(CURSOR_DEFAULT);
2481 #if defined(NETWORK_AVALIABLE)
2482 /* pause network game while waiting for request to answer */
2483 if (options.network &&
2484 game_status == GAME_MODE_PLAYING &&
2485 req_state & REQUEST_WAIT_FOR_INPUT)
2486 SendToServer_PausePlaying();
2489 old_door_state = GetDoorState();
2491 /* simulate releasing mouse button over last gadget, if still pressed */
2493 HandleGadgets(-1, -1, 0);
2497 if (old_door_state & DOOR_OPEN_1)
2499 CloseDoor(DOOR_CLOSE_1);
2501 /* save old door content */
2502 BlitBitmap(bitmap_db_door, bitmap_db_door,
2503 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2504 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
2508 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2511 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2513 /* clear door drawing field */
2514 DrawBackground(DX, DY, DXSIZE, DYSIZE);
2516 /* force DOOR font on preview level */
2517 game_status = GAME_MODE_PSEUDO_DOOR;
2519 /* write text for request */
2520 for (ty = 0; ty < MAX_REQUEST_LINES; ty++)
2522 char text_line[max_request_line_len + 1];
2528 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
2531 if (!tc || tc == ' ')
2542 strncpy(text_line, text, tl);
2545 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
2546 DY + 8 + ty * (getFontHeight(font_nr) + 2),
2547 text_line, font_nr);
2549 text += tl + (tc == ' ' ? 1 : 0);
2552 game_status = last_game_status; /* restore current game status */
2554 if (req_state & REQ_ASK)
2556 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2557 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2559 else if (req_state & REQ_CONFIRM)
2561 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2563 else if (req_state & REQ_PLAYER)
2565 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2566 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2567 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2568 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2571 /* copy request gadgets to door backbuffer */
2572 BlitBitmap(drawto, bitmap_db_door,
2573 DX, DY, DXSIZE, DYSIZE,
2574 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2576 OpenDoor(DOOR_OPEN_1);
2578 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
2580 if (game_status == GAME_MODE_PLAYING)
2582 SetPanelBackground();
2583 SetDrawBackgroundMask(REDRAW_DOOR_1);
2587 SetDrawBackgroundMask(REDRAW_FIELD);
2593 if (game_status != GAME_MODE_MAIN)
2596 button_status = MB_RELEASED;
2598 request_gadget_id = -1;
2600 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2612 case EVENT_BUTTONPRESS:
2613 case EVENT_BUTTONRELEASE:
2614 case EVENT_MOTIONNOTIFY:
2616 if (event.type == EVENT_MOTIONNOTIFY)
2618 if (!PointerInWindow(window))
2619 continue; /* window and pointer are on different screens */
2624 motion_status = TRUE;
2625 mx = ((MotionEvent *) &event)->x;
2626 my = ((MotionEvent *) &event)->y;
2630 motion_status = FALSE;
2631 mx = ((ButtonEvent *) &event)->x;
2632 my = ((ButtonEvent *) &event)->y;
2633 if (event.type == EVENT_BUTTONPRESS)
2634 button_status = ((ButtonEvent *) &event)->button;
2636 button_status = MB_RELEASED;
2639 /* this sets 'request_gadget_id' */
2640 HandleGadgets(mx, my, button_status);
2642 switch (request_gadget_id)
2644 case TOOL_CTRL_ID_YES:
2647 case TOOL_CTRL_ID_NO:
2650 case TOOL_CTRL_ID_CONFIRM:
2651 result = TRUE | FALSE;
2654 case TOOL_CTRL_ID_PLAYER_1:
2657 case TOOL_CTRL_ID_PLAYER_2:
2660 case TOOL_CTRL_ID_PLAYER_3:
2663 case TOOL_CTRL_ID_PLAYER_4:
2674 case EVENT_KEYPRESS:
2675 switch (GetEventKey((KeyEvent *)&event, TRUE))
2688 if (req_state & REQ_PLAYER)
2692 case EVENT_KEYRELEASE:
2693 ClearPlayerAction();
2697 HandleOtherEvents(&event);
2701 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2703 int joy = AnyJoystick();
2705 if (joy & JOY_BUTTON_1)
2707 else if (joy & JOY_BUTTON_2)
2714 if (!PendingEvent()) /* delay only if no pending events */
2717 /* don't eat all CPU time */
2722 if (game_status != GAME_MODE_MAIN)
2727 if (!(req_state & REQ_STAY_OPEN))
2729 CloseDoor(DOOR_CLOSE_1);
2731 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
2732 (req_state & REQ_REOPEN))
2733 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
2738 if (game_status == GAME_MODE_PLAYING)
2740 SetPanelBackground();
2741 SetDrawBackgroundMask(REDRAW_DOOR_1);
2745 SetDrawBackgroundMask(REDRAW_FIELD);
2748 #if defined(NETWORK_AVALIABLE)
2749 /* continue network game after request */
2750 if (options.network &&
2751 game_status == GAME_MODE_PLAYING &&
2752 req_state & REQUEST_WAIT_FOR_INPUT)
2753 SendToServer_ContinuePlaying();
2756 /* restore deactivated drawing when quick-loading level tape recording */
2757 if (tape.playing && tape.deactivate_display)
2758 TapeDeactivateDisplayOn();
2763 unsigned int OpenDoor(unsigned int door_state)
2765 if (door_state & DOOR_COPY_BACK)
2767 if (door_state & DOOR_OPEN_1)
2768 BlitBitmap(bitmap_db_door, bitmap_db_door,
2769 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2770 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2772 if (door_state & DOOR_OPEN_2)
2773 BlitBitmap(bitmap_db_door, bitmap_db_door,
2774 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
2775 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2777 door_state &= ~DOOR_COPY_BACK;
2780 return MoveDoor(door_state);
2783 unsigned int CloseDoor(unsigned int door_state)
2785 unsigned int old_door_state = GetDoorState();
2787 if (!(door_state & DOOR_NO_COPY_BACK))
2789 if (old_door_state & DOOR_OPEN_1)
2790 BlitBitmap(backbuffer, bitmap_db_door,
2791 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2793 if (old_door_state & DOOR_OPEN_2)
2794 BlitBitmap(backbuffer, bitmap_db_door,
2795 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2797 door_state &= ~DOOR_NO_COPY_BACK;
2800 return MoveDoor(door_state);
2803 unsigned int GetDoorState()
2805 return MoveDoor(DOOR_GET_STATE);
2808 unsigned int SetDoorState(unsigned int door_state)
2810 return MoveDoor(door_state | DOOR_SET_STATE);
2813 unsigned int MoveDoor(unsigned int door_state)
2815 static int door1 = DOOR_OPEN_1;
2816 static int door2 = DOOR_CLOSE_2;
2817 unsigned long door_delay = 0;
2818 unsigned long door_delay_value;
2821 if (door_1.width < 0 || door_1.width > DXSIZE)
2822 door_1.width = DXSIZE;
2823 if (door_1.height < 0 || door_1.height > DYSIZE)
2824 door_1.height = DYSIZE;
2825 if (door_2.width < 0 || door_2.width > VXSIZE)
2826 door_2.width = VXSIZE;
2827 if (door_2.height < 0 || door_2.height > VYSIZE)
2828 door_2.height = VYSIZE;
2830 if (door_state == DOOR_GET_STATE)
2831 return (door1 | door2);
2833 if (door_state & DOOR_SET_STATE)
2835 if (door_state & DOOR_ACTION_1)
2836 door1 = door_state & DOOR_ACTION_1;
2837 if (door_state & DOOR_ACTION_2)
2838 door2 = door_state & DOOR_ACTION_2;
2840 return (door1 | door2);
2843 if (!(door_state & DOOR_FORCE_REDRAW))
2845 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2846 door_state &= ~DOOR_OPEN_1;
2847 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2848 door_state &= ~DOOR_CLOSE_1;
2849 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2850 door_state &= ~DOOR_OPEN_2;
2851 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2852 door_state &= ~DOOR_CLOSE_2;
2855 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
2858 if (setup.quick_doors)
2860 stepsize = 20; /* must be choosen to always draw last frame */
2861 door_delay_value = 0;
2864 if (global.autoplay_leveldir)
2866 door_state |= DOOR_NO_DELAY;
2867 door_state &= ~DOOR_CLOSE_ALL;
2870 if (door_state & DOOR_ACTION)
2872 boolean handle_door_1 = (door_state & DOOR_ACTION_1);
2873 boolean handle_door_2 = (door_state & DOOR_ACTION_2);
2874 boolean door_1_done = (!handle_door_1);
2875 boolean door_2_done = (!handle_door_2);
2876 boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
2877 boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
2878 int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
2879 int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
2880 int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
2881 int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
2882 int door_size = (handle_door_1 ? door_size_1 : door_size_2);
2883 int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
2884 int door_skip = max_door_size - door_size;
2885 int end = door_size;
2886 int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
2889 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
2891 /* opening door sound has priority over simultaneously closing door */
2892 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2893 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2894 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2895 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2898 for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
2901 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2902 GC gc = bitmap->stored_clip_gc;
2904 if (door_state & DOOR_ACTION_1)
2906 int a = MIN(x * door_1.step_offset, end);
2907 int p = (door_state & DOOR_OPEN_1 ? end - a : a);
2908 int i = p + door_skip;
2910 if (door_1.anim_mode & ANIM_STATIC_PANEL)
2912 BlitBitmap(bitmap_db_door, drawto,
2913 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
2914 DXSIZE, DYSIZE, DX, DY);
2918 BlitBitmap(bitmap_db_door, drawto,
2919 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
2920 DXSIZE, DYSIZE - p / 2, DX, DY);
2922 ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
2925 if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
2927 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2928 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
2929 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
2930 int dst2_x = DX, dst2_y = DY;
2931 int width = i, height = DYSIZE;
2933 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2934 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2937 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2938 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2941 else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
2943 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2944 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
2945 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
2946 int dst2_x = DX, dst2_y = DY;
2947 int width = DXSIZE, height = i;
2949 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2950 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2953 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2954 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2957 else if (x <= DXSIZE) /* ANIM_DEFAULT */
2959 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
2961 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2962 BlitBitmapMasked(bitmap, drawto,
2963 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2964 DX + DXSIZE - i, DY + j);
2965 BlitBitmapMasked(bitmap, drawto,
2966 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2967 DX + DXSIZE - i, DY + 140 + j);
2968 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
2969 DY - (DOOR_GFX_PAGEY1 + j));
2970 BlitBitmapMasked(bitmap, drawto,
2971 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2973 BlitBitmapMasked(bitmap, drawto,
2974 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
2977 BlitBitmapMasked(bitmap, drawto,
2978 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2980 BlitBitmapMasked(bitmap, drawto,
2981 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2983 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2984 BlitBitmapMasked(bitmap, drawto,
2985 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2986 DX + DXSIZE - i, DY + 77 + j);
2987 BlitBitmapMasked(bitmap, drawto,
2988 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2989 DX + DXSIZE - i, DY + 203 + j);
2992 redraw_mask |= REDRAW_DOOR_1;
2993 door_1_done = (a == end);
2996 if (door_state & DOOR_ACTION_2)
2998 int a = MIN(x * door_2.step_offset, door_size);
2999 int p = (door_state & DOOR_OPEN_2 ? door_size - a : a);
3000 int i = p + door_skip;
3002 if (door_2.anim_mode & ANIM_STATIC_PANEL)
3004 BlitBitmap(bitmap_db_door, drawto,
3005 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
3006 VXSIZE, VYSIZE, VX, VY);
3008 else if (x <= VYSIZE)
3010 BlitBitmap(bitmap_db_door, drawto,
3011 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
3012 VXSIZE, VYSIZE - p / 2, VX, VY);
3014 ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
3017 if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
3019 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
3020 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
3021 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
3022 int dst2_x = VX, dst2_y = VY;
3023 int width = i, height = VYSIZE;
3025 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3026 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3029 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3030 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3033 else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
3035 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
3036 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
3037 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
3038 int dst2_x = VX, dst2_y = VY;
3039 int width = VXSIZE, height = i;
3041 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3042 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3045 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3046 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3049 else if (x <= VXSIZE) /* ANIM_DEFAULT */
3051 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
3053 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3054 BlitBitmapMasked(bitmap, drawto,
3055 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
3056 VX + VXSIZE - i, VY + j);
3057 SetClipOrigin(bitmap, gc,
3058 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
3059 BlitBitmapMasked(bitmap, drawto,
3060 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
3063 BlitBitmapMasked(bitmap, drawto,
3064 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3065 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
3066 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3067 BlitBitmapMasked(bitmap, drawto,
3068 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3070 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
3073 redraw_mask |= REDRAW_DOOR_2;
3074 door_2_done = (a == VXSIZE);
3077 if (!(door_state & DOOR_NO_DELAY))
3081 if (game_status == GAME_MODE_MAIN)
3084 WaitUntilDelayReached(&door_delay, door_delay_value);
3089 if (door_state & DOOR_ACTION_1)
3090 door1 = door_state & DOOR_ACTION_1;
3091 if (door_state & DOOR_ACTION_2)
3092 door2 = door_state & DOOR_ACTION_2;
3094 return (door1 | door2);
3097 void DrawSpecialEditorDoor()
3099 /* draw bigger toolbox window */
3100 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
3101 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
3103 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3104 EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
3107 redraw_mask |= REDRAW_ALL;
3110 void UndrawSpecialEditorDoor()
3112 /* draw normal tape recorder window */
3113 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3114 EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
3117 redraw_mask |= REDRAW_ALL;
3121 /* ---------- new tool button stuff ---------------------------------------- */
3123 /* graphic position values for tool buttons */
3124 #define TOOL_BUTTON_YES_XPOS 2
3125 #define TOOL_BUTTON_YES_YPOS 250
3126 #define TOOL_BUTTON_YES_GFX_YPOS 0
3127 #define TOOL_BUTTON_YES_XSIZE 46
3128 #define TOOL_BUTTON_YES_YSIZE 28
3129 #define TOOL_BUTTON_NO_XPOS 52
3130 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
3131 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
3132 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
3133 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
3134 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
3135 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
3136 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
3137 #define TOOL_BUTTON_CONFIRM_XSIZE 96
3138 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
3139 #define TOOL_BUTTON_PLAYER_XSIZE 30
3140 #define TOOL_BUTTON_PLAYER_YSIZE 30
3141 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
3142 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
3143 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
3144 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
3145 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3146 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3147 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3148 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3149 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3150 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3151 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3152 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3153 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3154 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3155 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3156 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3157 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3158 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3159 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3160 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3169 } toolbutton_info[NUM_TOOL_BUTTONS] =
3172 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
3173 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
3174 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
3179 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
3180 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
3181 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
3186 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
3187 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
3188 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
3189 TOOL_CTRL_ID_CONFIRM,
3193 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3194 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
3195 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3196 TOOL_CTRL_ID_PLAYER_1,
3200 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3201 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
3202 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3203 TOOL_CTRL_ID_PLAYER_2,
3207 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3208 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
3209 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3210 TOOL_CTRL_ID_PLAYER_3,
3214 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3215 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
3216 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3217 TOOL_CTRL_ID_PLAYER_4,
3222 void CreateToolButtons()
3226 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3228 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3229 Bitmap *deco_bitmap = None;
3230 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
3231 struct GadgetInfo *gi;
3232 unsigned long event_mask;
3233 int gd_xoffset, gd_yoffset;
3234 int gd_x1, gd_x2, gd_y;
3237 event_mask = GD_EVENT_RELEASED;
3239 gd_xoffset = toolbutton_info[i].xpos;
3240 gd_yoffset = toolbutton_info[i].ypos;
3241 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
3242 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
3243 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
3245 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
3247 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
3249 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
3250 &deco_bitmap, &deco_x, &deco_y);
3251 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
3252 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
3255 gi = CreateGadget(GDI_CUSTOM_ID, id,
3256 GDI_INFO_TEXT, toolbutton_info[i].infotext,
3257 GDI_X, DX + toolbutton_info[i].x,
3258 GDI_Y, DY + toolbutton_info[i].y,
3259 GDI_WIDTH, toolbutton_info[i].width,
3260 GDI_HEIGHT, toolbutton_info[i].height,
3261 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
3262 GDI_STATE, GD_BUTTON_UNPRESSED,
3263 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
3264 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
3265 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
3266 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
3267 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
3268 GDI_DECORATION_SHIFTING, 1, 1,
3269 GDI_DIRECT_DRAW, FALSE,
3270 GDI_EVENT_MASK, event_mask,
3271 GDI_CALLBACK_ACTION, HandleToolButtons,
3275 Error(ERR_EXIT, "cannot create gadget");
3277 tool_gadget[id] = gi;
3281 void FreeToolButtons()
3285 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3286 FreeGadget(tool_gadget[i]);
3289 static void UnmapToolButtons()
3293 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3294 UnmapGadget(tool_gadget[i]);
3297 static void HandleToolButtons(struct GadgetInfo *gi)
3299 request_gadget_id = gi->custom_id;
3302 static struct Mapping_EM_to_RND_object
3305 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
3306 boolean is_backside; /* backside of moving element */
3312 em_object_mapping_list[] =
3315 Xblank, TRUE, FALSE,
3319 Yacid_splash_eB, FALSE, FALSE,
3320 EL_ACID_SPLASH_RIGHT, -1, -1
3323 Yacid_splash_wB, FALSE, FALSE,
3324 EL_ACID_SPLASH_LEFT, -1, -1
3327 #ifdef EM_ENGINE_BAD_ROLL
3329 Xstone_force_e, FALSE, FALSE,
3330 EL_ROCK, -1, MV_BIT_RIGHT
3333 Xstone_force_w, FALSE, FALSE,
3334 EL_ROCK, -1, MV_BIT_LEFT
3337 Xnut_force_e, FALSE, FALSE,
3338 EL_NUT, -1, MV_BIT_RIGHT
3341 Xnut_force_w, FALSE, FALSE,
3342 EL_NUT, -1, MV_BIT_LEFT
3345 Xspring_force_e, FALSE, FALSE,
3346 EL_SPRING, -1, MV_BIT_RIGHT
3349 Xspring_force_w, FALSE, FALSE,
3350 EL_SPRING, -1, MV_BIT_LEFT
3353 Xemerald_force_e, FALSE, FALSE,
3354 EL_EMERALD, -1, MV_BIT_RIGHT
3357 Xemerald_force_w, FALSE, FALSE,
3358 EL_EMERALD, -1, MV_BIT_LEFT
3361 Xdiamond_force_e, FALSE, FALSE,
3362 EL_DIAMOND, -1, MV_BIT_RIGHT
3365 Xdiamond_force_w, FALSE, FALSE,
3366 EL_DIAMOND, -1, MV_BIT_LEFT
3369 Xbomb_force_e, FALSE, FALSE,
3370 EL_BOMB, -1, MV_BIT_RIGHT
3373 Xbomb_force_w, FALSE, FALSE,
3374 EL_BOMB, -1, MV_BIT_LEFT
3376 #endif /* EM_ENGINE_BAD_ROLL */
3379 Xstone, TRUE, FALSE,
3383 Xstone_pause, FALSE, FALSE,
3387 Xstone_fall, FALSE, FALSE,
3391 Ystone_s, FALSE, FALSE,
3392 EL_ROCK, ACTION_FALLING, -1
3395 Ystone_sB, FALSE, TRUE,
3396 EL_ROCK, ACTION_FALLING, -1
3399 Ystone_e, FALSE, FALSE,
3400 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3403 Ystone_eB, FALSE, TRUE,
3404 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3407 Ystone_w, FALSE, FALSE,
3408 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3411 Ystone_wB, FALSE, TRUE,
3412 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3419 Xnut_pause, FALSE, FALSE,
3423 Xnut_fall, FALSE, FALSE,
3427 Ynut_s, FALSE, FALSE,
3428 EL_NUT, ACTION_FALLING, -1
3431 Ynut_sB, FALSE, TRUE,
3432 EL_NUT, ACTION_FALLING, -1
3435 Ynut_e, FALSE, FALSE,
3436 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3439 Ynut_eB, FALSE, TRUE,
3440 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3443 Ynut_w, FALSE, FALSE,
3444 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3447 Ynut_wB, FALSE, TRUE,
3448 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3451 Xbug_n, TRUE, FALSE,
3455 Xbug_e, TRUE, FALSE,
3456 EL_BUG_RIGHT, -1, -1
3459 Xbug_s, TRUE, FALSE,
3463 Xbug_w, TRUE, FALSE,
3467 Xbug_gon, FALSE, FALSE,
3471 Xbug_goe, FALSE, FALSE,
3472 EL_BUG_RIGHT, -1, -1
3475 Xbug_gos, FALSE, FALSE,
3479 Xbug_gow, FALSE, FALSE,
3483 Ybug_n, FALSE, FALSE,
3484 EL_BUG, ACTION_MOVING, MV_BIT_UP
3487 Ybug_nB, FALSE, TRUE,
3488 EL_BUG, ACTION_MOVING, MV_BIT_UP
3491 Ybug_e, FALSE, FALSE,
3492 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3495 Ybug_eB, FALSE, TRUE,
3496 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3499 Ybug_s, FALSE, FALSE,
3500 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3503 Ybug_sB, FALSE, TRUE,
3504 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3507 Ybug_w, FALSE, FALSE,
3508 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3511 Ybug_wB, FALSE, TRUE,
3512 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3515 Ybug_w_n, FALSE, FALSE,
3516 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3519 Ybug_n_e, FALSE, FALSE,
3520 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3523 Ybug_e_s, FALSE, FALSE,
3524 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3527 Ybug_s_w, FALSE, FALSE,
3528 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3531 Ybug_e_n, FALSE, FALSE,
3532 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3535 Ybug_s_e, FALSE, FALSE,
3536 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3539 Ybug_w_s, FALSE, FALSE,
3540 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3543 Ybug_n_w, FALSE, FALSE,
3544 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3547 Ybug_stone, FALSE, FALSE,
3548 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
3551 Ybug_spring, FALSE, FALSE,
3552 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
3555 Xtank_n, TRUE, FALSE,
3556 EL_SPACESHIP_UP, -1, -1
3559 Xtank_e, TRUE, FALSE,
3560 EL_SPACESHIP_RIGHT, -1, -1
3563 Xtank_s, TRUE, FALSE,
3564 EL_SPACESHIP_DOWN, -1, -1
3567 Xtank_w, TRUE, FALSE,
3568 EL_SPACESHIP_LEFT, -1, -1
3571 Xtank_gon, FALSE, FALSE,
3572 EL_SPACESHIP_UP, -1, -1
3575 Xtank_goe, FALSE, FALSE,
3576 EL_SPACESHIP_RIGHT, -1, -1
3579 Xtank_gos, FALSE, FALSE,
3580 EL_SPACESHIP_DOWN, -1, -1
3583 Xtank_gow, FALSE, FALSE,
3584 EL_SPACESHIP_LEFT, -1, -1
3587 Ytank_n, FALSE, FALSE,
3588 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3591 Ytank_nB, FALSE, TRUE,
3592 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3595 Ytank_e, FALSE, FALSE,
3596 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3599 Ytank_eB, FALSE, TRUE,
3600 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3603 Ytank_s, FALSE, FALSE,
3604 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3607 Ytank_sB, FALSE, TRUE,
3608 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3611 Ytank_w, FALSE, FALSE,
3612 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3615 Ytank_wB, FALSE, TRUE,
3616 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3619 Ytank_w_n, FALSE, FALSE,
3620 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3623 Ytank_n_e, FALSE, FALSE,
3624 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3627 Ytank_e_s, FALSE, FALSE,
3628 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3631 Ytank_s_w, FALSE, FALSE,
3632 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3635 Ytank_e_n, FALSE, FALSE,
3636 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3639 Ytank_s_e, FALSE, FALSE,
3640 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3643 Ytank_w_s, FALSE, FALSE,
3644 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3647 Ytank_n_w, FALSE, FALSE,
3648 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3651 Ytank_stone, FALSE, FALSE,
3652 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
3655 Ytank_spring, FALSE, FALSE,
3656 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
3659 Xandroid, TRUE, FALSE,
3660 EL_EMC_ANDROID, ACTION_ACTIVE, -1
3663 Xandroid_1_n, FALSE, FALSE,
3664 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3667 Xandroid_2_n, FALSE, FALSE,
3668 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3671 Xandroid_1_e, FALSE, FALSE,
3672 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3675 Xandroid_2_e, FALSE, FALSE,
3676 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3679 Xandroid_1_w, FALSE, FALSE,
3680 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3683 Xandroid_2_w, FALSE, FALSE,
3684 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3687 Xandroid_1_s, FALSE, FALSE,
3688 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3691 Xandroid_2_s, FALSE, FALSE,
3692 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3695 Yandroid_n, FALSE, FALSE,
3696 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3699 Yandroid_nB, FALSE, TRUE,
3700 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3703 Yandroid_ne, FALSE, FALSE,
3704 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
3707 Yandroid_neB, FALSE, TRUE,
3708 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
3711 Yandroid_e, FALSE, FALSE,
3712 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
3715 Yandroid_eB, FALSE, TRUE,
3716 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
3719 Yandroid_se, FALSE, FALSE,
3720 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
3723 Yandroid_seB, FALSE, TRUE,
3724 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
3727 Yandroid_s, FALSE, FALSE,
3728 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
3731 Yandroid_sB, FALSE, TRUE,
3732 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
3735 Yandroid_sw, FALSE, FALSE,
3736 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
3739 Yandroid_swB, FALSE, TRUE,
3740 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
3743 Yandroid_w, FALSE, FALSE,
3744 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
3747 Yandroid_wB, FALSE, TRUE,
3748 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
3751 Yandroid_nw, FALSE, FALSE,
3752 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
3755 Yandroid_nwB, FALSE, TRUE,
3756 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
3759 Xspring, TRUE, FALSE,
3763 Xspring_pause, FALSE, FALSE,
3767 Xspring_e, FALSE, FALSE,
3771 Xspring_w, FALSE, FALSE,
3775 Xspring_fall, FALSE, FALSE,
3779 Yspring_s, FALSE, FALSE,
3780 EL_SPRING, ACTION_FALLING, -1
3783 Yspring_sB, FALSE, TRUE,
3784 EL_SPRING, ACTION_FALLING, -1
3787 Yspring_e, FALSE, FALSE,
3788 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
3791 Yspring_eB, FALSE, TRUE,
3792 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
3795 Yspring_w, FALSE, FALSE,
3796 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
3799 Yspring_wB, FALSE, TRUE,
3800 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
3803 Yspring_kill_e, FALSE, FALSE,
3804 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
3807 Yspring_kill_eB, FALSE, TRUE,
3808 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
3811 Yspring_kill_w, FALSE, FALSE,
3812 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
3815 Yspring_kill_wB, FALSE, TRUE,
3816 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
3819 Xeater_n, TRUE, FALSE,
3820 EL_YAMYAM_UP, -1, -1
3823 Xeater_e, TRUE, FALSE,
3824 EL_YAMYAM_RIGHT, -1, -1
3827 Xeater_w, TRUE, FALSE,
3828 EL_YAMYAM_LEFT, -1, -1
3831 Xeater_s, TRUE, FALSE,
3832 EL_YAMYAM_DOWN, -1, -1
3835 Yeater_n, FALSE, FALSE,
3836 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
3839 Yeater_nB, FALSE, TRUE,
3840 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
3843 Yeater_e, FALSE, FALSE,
3844 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
3847 Yeater_eB, FALSE, TRUE,
3848 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
3851 Yeater_s, FALSE, FALSE,
3852 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
3855 Yeater_sB, FALSE, TRUE,
3856 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
3859 Yeater_w, FALSE, FALSE,
3860 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
3863 Yeater_wB, FALSE, TRUE,
3864 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
3867 Yeater_stone, FALSE, FALSE,
3868 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
3871 Yeater_spring, FALSE, FALSE,
3872 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
3875 Xalien, TRUE, FALSE,
3879 Xalien_pause, FALSE, FALSE,
3883 Yalien_n, FALSE, FALSE,
3884 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
3887 Yalien_nB, FALSE, TRUE,
3888 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
3891 Yalien_e, FALSE, FALSE,
3892 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
3895 Yalien_eB, FALSE, TRUE,
3896 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
3899 Yalien_s, FALSE, FALSE,
3900 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
3903 Yalien_sB, FALSE, TRUE,
3904 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
3907 Yalien_w, FALSE, FALSE,
3908 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
3911 Yalien_wB, FALSE, TRUE,
3912 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
3915 Yalien_stone, FALSE, FALSE,
3916 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
3919 Yalien_spring, FALSE, FALSE,
3920 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
3923 Xemerald, TRUE, FALSE,
3927 Xemerald_pause, FALSE, FALSE,
3931 Xemerald_fall, FALSE, FALSE,
3935 Xemerald_shine, FALSE, FALSE,
3936 EL_EMERALD, ACTION_TWINKLING, -1
3939 Yemerald_s, FALSE, FALSE,
3940 EL_EMERALD, ACTION_FALLING, -1
3943 Yemerald_sB, FALSE, TRUE,
3944 EL_EMERALD, ACTION_FALLING, -1
3947 Yemerald_e, FALSE, FALSE,
3948 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
3951 Yemerald_eB, FALSE, TRUE,
3952 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
3955 Yemerald_w, FALSE, FALSE,
3956 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
3959 Yemerald_wB, FALSE, TRUE,
3960 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
3963 Yemerald_eat, FALSE, FALSE,
3964 EL_EMERALD, ACTION_COLLECTING, -1
3967 Yemerald_stone, FALSE, FALSE,
3968 EL_NUT, ACTION_BREAKING, -1
3971 Xdiamond, TRUE, FALSE,
3975 Xdiamond_pause, FALSE, FALSE,
3979 Xdiamond_fall, FALSE, FALSE,
3983 Xdiamond_shine, FALSE, FALSE,
3984 EL_DIAMOND, ACTION_TWINKLING, -1
3987 Ydiamond_s, FALSE, FALSE,
3988 EL_DIAMOND, ACTION_FALLING, -1
3991 Ydiamond_sB, FALSE, TRUE,
3992 EL_DIAMOND, ACTION_FALLING, -1
3995 Ydiamond_e, FALSE, FALSE,
3996 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
3999 Ydiamond_eB, FALSE, TRUE,
4000 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
4003 Ydiamond_w, FALSE, FALSE,
4004 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
4007 Ydiamond_wB, FALSE, TRUE,
4008 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
4011 Ydiamond_eat, FALSE, FALSE,
4012 EL_DIAMOND, ACTION_COLLECTING, -1
4015 Ydiamond_stone, FALSE, FALSE,
4016 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
4019 Xdrip_fall, TRUE, FALSE,
4020 EL_AMOEBA_DROP, -1, -1
4023 Xdrip_stretch, FALSE, FALSE,
4024 EL_AMOEBA_DROP, ACTION_FALLING, -1
4027 Xdrip_stretchB, FALSE, TRUE,
4028 EL_AMOEBA_DROP, ACTION_FALLING, -1
4031 Xdrip_eat, FALSE, FALSE,
4032 EL_AMOEBA_DROP, ACTION_GROWING, -1
4035 Ydrip_s1, FALSE, FALSE,
4036 EL_AMOEBA_DROP, ACTION_FALLING, -1
4039 Ydrip_s1B, FALSE, TRUE,
4040 EL_AMOEBA_DROP, ACTION_FALLING, -1
4043 Ydrip_s2, FALSE, FALSE,
4044 EL_AMOEBA_DROP, ACTION_FALLING, -1
4047 Ydrip_s2B, FALSE, TRUE,
4048 EL_AMOEBA_DROP, ACTION_FALLING, -1
4055 Xbomb_pause, FALSE, FALSE,
4059 Xbomb_fall, FALSE, FALSE,
4063 Ybomb_s, FALSE, FALSE,
4064 EL_BOMB, ACTION_FALLING, -1
4067 Ybomb_sB, FALSE, TRUE,
4068 EL_BOMB, ACTION_FALLING, -1
4071 Ybomb_e, FALSE, FALSE,
4072 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
4075 Ybomb_eB, FALSE, TRUE,
4076 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
4079 Ybomb_w, FALSE, FALSE,
4080 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
4083 Ybomb_wB, FALSE, TRUE,
4084 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
4087 Ybomb_eat, FALSE, FALSE,
4088 EL_BOMB, ACTION_ACTIVATING, -1
4091 Xballoon, TRUE, FALSE,
4095 Yballoon_n, FALSE, FALSE,
4096 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
4099 Yballoon_nB, FALSE, TRUE,
4100 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
4103 Yballoon_e, FALSE, FALSE,
4104 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
4107 Yballoon_eB, FALSE, TRUE,
4108 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
4111 Yballoon_s, FALSE, FALSE,
4112 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
4115 Yballoon_sB, FALSE, TRUE,
4116 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
4119 Yballoon_w, FALSE, FALSE,
4120 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
4123 Yballoon_wB, FALSE, TRUE,
4124 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
4127 Xgrass, TRUE, FALSE,
4128 EL_EMC_GRASS, -1, -1
4131 Ygrass_nB, FALSE, FALSE,
4132 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
4135 Ygrass_eB, FALSE, FALSE,
4136 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
4139 Ygrass_sB, FALSE, FALSE,
4140 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
4143 Ygrass_wB, FALSE, FALSE,
4144 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
4151 Ydirt_nB, FALSE, FALSE,
4152 EL_SAND, ACTION_DIGGING, MV_BIT_UP
4155 Ydirt_eB, FALSE, FALSE,
4156 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
4159 Ydirt_sB, FALSE, FALSE,
4160 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
4163 Ydirt_wB, FALSE, FALSE,
4164 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
4167 Xacid_ne, TRUE, FALSE,
4168 EL_ACID_POOL_TOPRIGHT, -1, -1
4171 Xacid_se, TRUE, FALSE,
4172 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
4175 Xacid_s, TRUE, FALSE,
4176 EL_ACID_POOL_BOTTOM, -1, -1
4179 Xacid_sw, TRUE, FALSE,
4180 EL_ACID_POOL_BOTTOMLEFT, -1, -1
4183 Xacid_nw, TRUE, FALSE,
4184 EL_ACID_POOL_TOPLEFT, -1, -1
4187 Xacid_1, TRUE, FALSE,
4191 Xacid_2, FALSE, FALSE,
4195 Xacid_3, FALSE, FALSE,
4199 Xacid_4, FALSE, FALSE,
4203 Xacid_5, FALSE, FALSE,
4207 Xacid_6, FALSE, FALSE,
4211 Xacid_7, FALSE, FALSE,
4215 Xacid_8, FALSE, FALSE,
4219 Xball_1, TRUE, FALSE,
4220 EL_EMC_MAGIC_BALL, -1, -1
4223 Xball_1B, FALSE, FALSE,
4224 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4227 Xball_2, FALSE, FALSE,
4228 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4231 Xball_2B, FALSE, FALSE,
4232 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4235 Yball_eat, FALSE, FALSE,
4236 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
4239 Ykey_1_eat, FALSE, FALSE,
4240 EL_EM_KEY_1, ACTION_COLLECTING, -1
4243 Ykey_2_eat, FALSE, FALSE,
4244 EL_EM_KEY_2, ACTION_COLLECTING, -1
4247 Ykey_3_eat, FALSE, FALSE,
4248 EL_EM_KEY_3, ACTION_COLLECTING, -1
4251 Ykey_4_eat, FALSE, FALSE,
4252 EL_EM_KEY_4, ACTION_COLLECTING, -1
4255 Ykey_5_eat, FALSE, FALSE,
4256 EL_EMC_KEY_5, ACTION_COLLECTING, -1
4259 Ykey_6_eat, FALSE, FALSE,
4260 EL_EMC_KEY_6, ACTION_COLLECTING, -1
4263 Ykey_7_eat, FALSE, FALSE,
4264 EL_EMC_KEY_7, ACTION_COLLECTING, -1
4267 Ykey_8_eat, FALSE, FALSE,
4268 EL_EMC_KEY_8, ACTION_COLLECTING, -1
4271 Ylenses_eat, FALSE, FALSE,
4272 EL_EMC_LENSES, ACTION_COLLECTING, -1
4275 Ymagnify_eat, FALSE, FALSE,
4276 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
4279 Ygrass_eat, FALSE, FALSE,
4280 EL_EMC_GRASS, ACTION_SNAPPING, -1
4283 Ydirt_eat, FALSE, FALSE,
4284 EL_SAND, ACTION_SNAPPING, -1
4287 Xgrow_ns, TRUE, FALSE,
4288 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
4291 Ygrow_ns_eat, FALSE, FALSE,
4292 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
4295 Xgrow_ew, TRUE, FALSE,
4296 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
4299 Ygrow_ew_eat, FALSE, FALSE,
4300 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
4303 Xwonderwall, TRUE, FALSE,
4304 EL_MAGIC_WALL, -1, -1
4307 XwonderwallB, FALSE, FALSE,
4308 EL_MAGIC_WALL, ACTION_ACTIVE, -1
4311 Xamoeba_1, TRUE, FALSE,
4312 EL_AMOEBA_DRY, ACTION_OTHER, -1
4315 Xamoeba_2, FALSE, FALSE,
4316 EL_AMOEBA_DRY, ACTION_OTHER, -1
4319 Xamoeba_3, FALSE, FALSE,
4320 EL_AMOEBA_DRY, ACTION_OTHER, -1
4323 Xamoeba_4, FALSE, FALSE,
4324 EL_AMOEBA_DRY, ACTION_OTHER, -1
4327 Xamoeba_5, TRUE, FALSE,
4328 EL_AMOEBA_WET, ACTION_OTHER, -1
4331 Xamoeba_6, FALSE, FALSE,
4332 EL_AMOEBA_WET, ACTION_OTHER, -1
4335 Xamoeba_7, FALSE, FALSE,
4336 EL_AMOEBA_WET, ACTION_OTHER, -1
4339 Xamoeba_8, FALSE, FALSE,
4340 EL_AMOEBA_WET, ACTION_OTHER, -1
4343 Xdoor_1, TRUE, FALSE,
4344 EL_EM_GATE_1, -1, -1
4347 Xdoor_2, TRUE, FALSE,
4348 EL_EM_GATE_2, -1, -1
4351 Xdoor_3, TRUE, FALSE,
4352 EL_EM_GATE_3, -1, -1
4355 Xdoor_4, TRUE, FALSE,
4356 EL_EM_GATE_4, -1, -1
4359 Xdoor_5, TRUE, FALSE,
4360 EL_EMC_GATE_5, -1, -1
4363 Xdoor_6, TRUE, FALSE,
4364 EL_EMC_GATE_6, -1, -1
4367 Xdoor_7, TRUE, FALSE,
4368 EL_EMC_GATE_7, -1, -1
4371 Xdoor_8, TRUE, FALSE,
4372 EL_EMC_GATE_8, -1, -1
4375 Xkey_1, TRUE, FALSE,
4379 Xkey_2, TRUE, FALSE,
4383 Xkey_3, TRUE, FALSE,
4387 Xkey_4, TRUE, FALSE,
4391 Xkey_5, TRUE, FALSE,
4392 EL_EMC_KEY_5, -1, -1
4395 Xkey_6, TRUE, FALSE,
4396 EL_EMC_KEY_6, -1, -1
4399 Xkey_7, TRUE, FALSE,
4400 EL_EMC_KEY_7, -1, -1
4403 Xkey_8, TRUE, FALSE,
4404 EL_EMC_KEY_8, -1, -1
4407 Xwind_n, TRUE, FALSE,
4408 EL_BALLOON_SWITCH_UP, -1, -1
4411 Xwind_e, TRUE, FALSE,
4412 EL_BALLOON_SWITCH_RIGHT, -1, -1
4415 Xwind_s, TRUE, FALSE,
4416 EL_BALLOON_SWITCH_DOWN, -1, -1
4419 Xwind_w, TRUE, FALSE,
4420 EL_BALLOON_SWITCH_LEFT, -1, -1
4423 Xwind_nesw, TRUE, FALSE,
4424 EL_BALLOON_SWITCH_ANY, -1, -1
4427 Xwind_stop, TRUE, FALSE,
4428 EL_BALLOON_SWITCH_NONE, -1, -1
4432 EL_EXIT_CLOSED, -1, -1
4435 Xexit_1, TRUE, FALSE,
4436 EL_EXIT_OPEN, -1, -1
4439 Xexit_2, FALSE, FALSE,
4440 EL_EXIT_OPEN, -1, -1
4443 Xexit_3, FALSE, FALSE,
4444 EL_EXIT_OPEN, -1, -1
4447 Xdynamite, TRUE, FALSE,
4448 EL_EM_DYNAMITE, -1, -1
4451 Ydynamite_eat, FALSE, FALSE,
4452 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
4455 Xdynamite_1, TRUE, FALSE,
4456 EL_EM_DYNAMITE_ACTIVE, -1, -1
4459 Xdynamite_2, FALSE, FALSE,
4460 EL_EM_DYNAMITE_ACTIVE, -1, -1
4463 Xdynamite_3, FALSE, FALSE,
4464 EL_EM_DYNAMITE_ACTIVE, -1, -1
4467 Xdynamite_4, FALSE, FALSE,
4468 EL_EM_DYNAMITE_ACTIVE, -1, -1
4471 Xbumper, TRUE, FALSE,
4472 EL_EMC_SPRING_BUMPER, -1, -1
4475 XbumperB, FALSE, FALSE,
4476 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
4479 Xwheel, TRUE, FALSE,
4480 EL_ROBOT_WHEEL, -1, -1
4483 XwheelB, FALSE, FALSE,
4484 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
4487 Xswitch, TRUE, FALSE,
4488 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
4491 XswitchB, FALSE, FALSE,
4492 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
4496 EL_QUICKSAND_EMPTY, -1, -1
4499 Xsand_stone, TRUE, FALSE,
4500 EL_QUICKSAND_FULL, -1, -1
4503 Xsand_stonein_1, FALSE, TRUE,
4504 EL_ROCK, ACTION_FILLING, -1
4507 Xsand_stonein_2, FALSE, TRUE,
4508 EL_ROCK, ACTION_FILLING, -1
4511 Xsand_stonein_3, FALSE, TRUE,
4512 EL_ROCK, ACTION_FILLING, -1
4515 Xsand_stonein_4, FALSE, TRUE,
4516 EL_ROCK, ACTION_FILLING, -1
4519 Xsand_stonesand_1, FALSE, FALSE,
4520 EL_QUICKSAND_FULL, -1, -1
4523 Xsand_stonesand_2, FALSE, FALSE,
4524 EL_QUICKSAND_FULL, -1, -1
4527 Xsand_stonesand_3, FALSE, FALSE,
4528 EL_QUICKSAND_FULL, -1, -1
4531 Xsand_stonesand_4, FALSE, FALSE,
4532 EL_QUICKSAND_FULL, -1, -1
4535 Xsand_stoneout_1, FALSE, FALSE,
4536 EL_ROCK, ACTION_EMPTYING, -1
4539 Xsand_stoneout_2, FALSE, FALSE,
4540 EL_ROCK, ACTION_EMPTYING, -1
4543 Xsand_sandstone_1, FALSE, FALSE,
4544 EL_QUICKSAND_FULL, -1, -1
4547 Xsand_sandstone_2, FALSE, FALSE,
4548 EL_QUICKSAND_FULL, -1, -1
4551 Xsand_sandstone_3, FALSE, FALSE,
4552 EL_QUICKSAND_FULL, -1, -1
4555 Xsand_sandstone_4, FALSE, FALSE,
4556 EL_QUICKSAND_FULL, -1, -1
4559 Xplant, TRUE, FALSE,
4560 EL_EMC_PLANT, -1, -1
4563 Yplant, FALSE, FALSE,
4564 EL_EMC_PLANT, -1, -1
4567 Xlenses, TRUE, FALSE,
4568 EL_EMC_LENSES, -1, -1
4571 Xmagnify, TRUE, FALSE,
4572 EL_EMC_MAGNIFIER, -1, -1
4575 Xdripper, TRUE, FALSE,
4576 EL_EMC_DRIPPER, -1, -1
4579 XdripperB, FALSE, FALSE,
4580 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
4583 Xfake_blank, TRUE, FALSE,
4584 EL_INVISIBLE_WALL, -1, -1
4587 Xfake_blankB, FALSE, FALSE,
4588 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
4591 Xfake_grass, TRUE, FALSE,
4592 EL_EMC_FAKE_GRASS, -1, -1
4595 Xfake_grassB, FALSE, FALSE,
4596 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
4599 Xfake_door_1, TRUE, FALSE,
4600 EL_EM_GATE_1_GRAY, -1, -1
4603 Xfake_door_2, TRUE, FALSE,
4604 EL_EM_GATE_2_GRAY, -1, -1
4607 Xfake_door_3, TRUE, FALSE,
4608 EL_EM_GATE_3_GRAY, -1, -1
4611 Xfake_door_4, TRUE, FALSE,
4612 EL_EM_GATE_4_GRAY, -1, -1
4615 Xfake_door_5, TRUE, FALSE,
4616 EL_EMC_GATE_5_GRAY, -1, -1
4619 Xfake_door_6, TRUE, FALSE,
4620 EL_EMC_GATE_6_GRAY, -1, -1
4623 Xfake_door_7, TRUE, FALSE,
4624 EL_EMC_GATE_7_GRAY, -1, -1
4627 Xfake_door_8, TRUE, FALSE,
4628 EL_EMC_GATE_8_GRAY, -1, -1
4631 Xfake_acid_1, TRUE, FALSE,
4632 EL_EMC_FAKE_ACID, -1, -1
4635 Xfake_acid_2, FALSE, FALSE,
4636 EL_EMC_FAKE_ACID, -1, -1
4639 Xfake_acid_3, FALSE, FALSE,
4640 EL_EMC_FAKE_ACID, -1, -1
4643 Xfake_acid_4, FALSE, FALSE,
4644 EL_EMC_FAKE_ACID, -1, -1
4647 Xfake_acid_5, FALSE, FALSE,
4648 EL_EMC_FAKE_ACID, -1, -1
4651 Xfake_acid_6, FALSE, FALSE,
4652 EL_EMC_FAKE_ACID, -1, -1
4655 Xfake_acid_7, FALSE, FALSE,
4656 EL_EMC_FAKE_ACID, -1, -1
4659 Xfake_acid_8, FALSE, FALSE,
4660 EL_EMC_FAKE_ACID, -1, -1
4663 Xsteel_1, TRUE, FALSE,
4664 EL_STEELWALL, -1, -1
4667 Xsteel_2, TRUE, FALSE,
4668 EL_EMC_STEELWALL_2, -1, -1
4671 Xsteel_3, TRUE, FALSE,
4672 EL_EMC_STEELWALL_3, -1, -1
4675 Xsteel_4, TRUE, FALSE,
4676 EL_EMC_STEELWALL_4, -1, -1
4679 Xwall_1, TRUE, FALSE,
4683 Xwall_2, TRUE, FALSE,
4684 EL_EMC_WALL_14, -1, -1
4687 Xwall_3, TRUE, FALSE,
4688 EL_EMC_WALL_15, -1, -1
4691 Xwall_4, TRUE, FALSE,
4692 EL_EMC_WALL_16, -1, -1
4695 Xround_wall_1, TRUE, FALSE,
4696 EL_WALL_SLIPPERY, -1, -1
4699 Xround_wall_2, TRUE, FALSE,
4700 EL_EMC_WALL_SLIPPERY_2, -1, -1
4703 Xround_wall_3, TRUE, FALSE,
4704 EL_EMC_WALL_SLIPPERY_3, -1, -1
4707 Xround_wall_4, TRUE, FALSE,
4708 EL_EMC_WALL_SLIPPERY_4, -1, -1
4711 Xdecor_1, TRUE, FALSE,
4712 EL_EMC_WALL_8, -1, -1
4715 Xdecor_2, TRUE, FALSE,
4716 EL_EMC_WALL_6, -1, -1
4719 Xdecor_3, TRUE, FALSE,
4720 EL_EMC_WALL_4, -1, -1
4723 Xdecor_4, TRUE, FALSE,
4724 EL_EMC_WALL_7, -1, -1
4727 Xdecor_5, TRUE, FALSE,
4728 EL_EMC_WALL_5, -1, -1
4731 Xdecor_6, TRUE, FALSE,
4732 EL_EMC_WALL_9, -1, -1
4735 Xdecor_7, TRUE, FALSE,
4736 EL_EMC_WALL_10, -1, -1
4739 Xdecor_8, TRUE, FALSE,
4740 EL_EMC_WALL_1, -1, -1
4743 Xdecor_9, TRUE, FALSE,
4744 EL_EMC_WALL_2, -1, -1
4747 Xdecor_10, TRUE, FALSE,
4748 EL_EMC_WALL_3, -1, -1
4751 Xdecor_11, TRUE, FALSE,
4752 EL_EMC_WALL_11, -1, -1
4755 Xdecor_12, TRUE, FALSE,
4756 EL_EMC_WALL_12, -1, -1
4759 Xalpha_0, TRUE, FALSE,
4760 EL_CHAR('0'), -1, -1
4763 Xalpha_1, TRUE, FALSE,
4764 EL_CHAR('1'), -1, -1
4767 Xalpha_2, TRUE, FALSE,
4768 EL_CHAR('2'), -1, -1
4771 Xalpha_3, TRUE, FALSE,
4772 EL_CHAR('3'), -1, -1
4775 Xalpha_4, TRUE, FALSE,
4776 EL_CHAR('4'), -1, -1
4779 Xalpha_5, TRUE, FALSE,
4780 EL_CHAR('5'), -1, -1
4783 Xalpha_6, TRUE, FALSE,
4784 EL_CHAR('6'), -1, -1
4787 Xalpha_7, TRUE, FALSE,
4788 EL_CHAR('7'), -1, -1
4791 Xalpha_8, TRUE, FALSE,
4792 EL_CHAR('8'), -1, -1
4795 Xalpha_9, TRUE, FALSE,
4796 EL_CHAR('9'), -1, -1
4799 Xalpha_excla, TRUE, FALSE,
4800 EL_CHAR('!'), -1, -1
4803 Xalpha_quote, TRUE, FALSE,
4804 EL_CHAR('"'), -1, -1
4807 Xalpha_comma, TRUE, FALSE,
4808 EL_CHAR(','), -1, -1
4811 Xalpha_minus, TRUE, FALSE,
4812 EL_CHAR('-'), -1, -1
4815 Xalpha_perio, TRUE, FALSE,
4816 EL_CHAR('.'), -1, -1
4819 Xalpha_colon, TRUE, FALSE,
4820 EL_CHAR(':'), -1, -1
4823 Xalpha_quest, TRUE, FALSE,
4824 EL_CHAR('?'), -1, -1
4827 Xalpha_a, TRUE, FALSE,
4828 EL_CHAR('A'), -1, -1
4831 Xalpha_b, TRUE, FALSE,
4832 EL_CHAR('B'), -1, -1
4835 Xalpha_c, TRUE, FALSE,
4836 EL_CHAR('C'), -1, -1
4839 Xalpha_d, TRUE, FALSE,
4840 EL_CHAR('D'), -1, -1
4843 Xalpha_e, TRUE, FALSE,
4844 EL_CHAR('E'), -1, -1
4847 Xalpha_f, TRUE, FALSE,
4848 EL_CHAR('F'), -1, -1
4851 Xalpha_g, TRUE, FALSE,
4852 EL_CHAR('G'), -1, -1
4855 Xalpha_h, TRUE, FALSE,
4856 EL_CHAR('H'), -1, -1
4859 Xalpha_i, TRUE, FALSE,
4860 EL_CHAR('I'), -1, -1
4863 Xalpha_j, TRUE, FALSE,
4864 EL_CHAR('J'), -1, -1
4867 Xalpha_k, TRUE, FALSE,
4868 EL_CHAR('K'), -1, -1
4871 Xalpha_l, TRUE, FALSE,
4872 EL_CHAR('L'), -1, -1
4875 Xalpha_m, TRUE, FALSE,
4876 EL_CHAR('M'), -1, -1
4879 Xalpha_n, TRUE, FALSE,
4880 EL_CHAR('N'), -1, -1
4883 Xalpha_o, TRUE, FALSE,
4884 EL_CHAR('O'), -1, -1
4887 Xalpha_p, TRUE, FALSE,
4888 EL_CHAR('P'), -1, -1
4891 Xalpha_q, TRUE, FALSE,
4892 EL_CHAR('Q'), -1, -1
4895 Xalpha_r, TRUE, FALSE,
4896 EL_CHAR('R'), -1, -1
4899 Xalpha_s, TRUE, FALSE,
4900 EL_CHAR('S'), -1, -1
4903 Xalpha_t, TRUE, FALSE,
4904 EL_CHAR('T'), -1, -1
4907 Xalpha_u, TRUE, FALSE,
4908 EL_CHAR('U'), -1, -1
4911 Xalpha_v, TRUE, FALSE,
4912 EL_CHAR('V'), -1, -1
4915 Xalpha_w, TRUE, FALSE,
4916 EL_CHAR('W'), -1, -1
4919 Xalpha_x, TRUE, FALSE,
4920 EL_CHAR('X'), -1, -1
4923 Xalpha_y, TRUE, FALSE,
4924 EL_CHAR('Y'), -1, -1
4927 Xalpha_z, TRUE, FALSE,
4928 EL_CHAR('Z'), -1, -1
4931 Xalpha_arrow_e, TRUE, FALSE,
4932 EL_CHAR('>'), -1, -1
4935 Xalpha_arrow_w, TRUE, FALSE,
4936 EL_CHAR('<'), -1, -1
4939 Xalpha_copyr, TRUE, FALSE,
4940 EL_CHAR('©'), -1, -1
4944 Xboom_bug, FALSE, FALSE,
4945 EL_BUG, ACTION_EXPLODING, -1
4948 Xboom_bomb, FALSE, FALSE,
4949 EL_BOMB, ACTION_EXPLODING, -1
4952 Xboom_android, FALSE, FALSE,
4953 EL_EMC_ANDROID, ACTION_OTHER, -1
4956 Xboom_1, FALSE, FALSE,
4957 EL_DEFAULT, ACTION_EXPLODING, -1
4960 Xboom_2, FALSE, FALSE,
4961 EL_DEFAULT, ACTION_EXPLODING, -1
4964 Znormal, FALSE, FALSE,
4968 Zdynamite, FALSE, FALSE,
4972 Zplayer, FALSE, FALSE,
4976 ZBORDER, FALSE, FALSE,
4986 static struct Mapping_EM_to_RND_player
4995 em_player_mapping_list[] =
4999 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
5003 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
5007 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
5011 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
5015 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
5019 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
5023 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
5027 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
5031 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
5035 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
5039 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
5043 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
5047 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
5051 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
5055 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
5059 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
5063 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
5067 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
5071 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
5075 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
5079 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
5083 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
5087 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
5091 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
5095 EL_PLAYER_1, ACTION_DEFAULT, -1,
5099 EL_PLAYER_2, ACTION_DEFAULT, -1,
5103 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
5107 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
5111 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
5115 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
5119 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
5123 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
5127 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
5131 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
5135 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
5139 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
5143 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
5147 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
5151 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
5155 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
5159 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
5163 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
5167 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
5171 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
5175 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
5179 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
5183 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
5187 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
5191 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
5195 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
5199 EL_PLAYER_3, ACTION_DEFAULT, -1,
5203 EL_PLAYER_4, ACTION_DEFAULT, -1,
5212 int map_element_RND_to_EM(int element_rnd)
5214 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
5215 static boolean mapping_initialized = FALSE;
5217 if (!mapping_initialized)
5221 /* return "Xalpha_quest" for all undefined elements in mapping array */
5222 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
5223 mapping_RND_to_EM[i] = Xalpha_quest;
5225 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5226 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
5227 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
5228 em_object_mapping_list[i].element_em;
5230 mapping_initialized = TRUE;
5233 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
5234 return mapping_RND_to_EM[element_rnd];
5236 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
5241 int map_element_EM_to_RND(int element_em)
5243 static unsigned short mapping_EM_to_RND[TILE_MAX];
5244 static boolean mapping_initialized = FALSE;
5246 if (!mapping_initialized)
5250 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
5251 for (i = 0; i < TILE_MAX; i++)
5252 mapping_EM_to_RND[i] = EL_UNKNOWN;
5254 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5255 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
5256 em_object_mapping_list[i].element_rnd;
5258 mapping_initialized = TRUE;
5261 if (element_em >= 0 && element_em < TILE_MAX)
5262 return mapping_EM_to_RND[element_em];
5264 Error(ERR_WARN, "invalid EM level element %d", element_em);
5269 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
5271 struct LevelInfo_EM *level_em = level->native_em_level;
5272 struct LEVEL *lev = level_em->lev;
5275 for (i = 0; i < TILE_MAX; i++)
5276 lev->android_array[i] = Xblank;
5278 for (i = 0; i < level->num_android_clone_elements; i++)
5280 int element_rnd = level->android_clone_element[i];
5281 int element_em = map_element_RND_to_EM(element_rnd);
5283 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
5284 if (em_object_mapping_list[j].element_rnd == element_rnd)
5285 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
5289 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
5291 struct LevelInfo_EM *level_em = level->native_em_level;
5292 struct LEVEL *lev = level_em->lev;
5295 level->num_android_clone_elements = 0;
5297 for (i = 0; i < TILE_MAX; i++)
5299 int element_em = lev->android_array[i];
5301 boolean element_found = FALSE;
5303 if (element_em == Xblank)
5306 element_rnd = map_element_EM_to_RND(element_em);
5308 for (j = 0; j < level->num_android_clone_elements; j++)
5309 if (level->android_clone_element[j] == element_rnd)
5310 element_found = TRUE;
5314 level->android_clone_element[level->num_android_clone_elements++] =
5317 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
5322 if (level->num_android_clone_elements == 0)
5324 level->num_android_clone_elements = 1;
5325 level->android_clone_element[0] = EL_EMPTY;
5329 int map_direction_RND_to_EM(int direction)
5331 return (direction == MV_UP ? 0 :
5332 direction == MV_RIGHT ? 1 :
5333 direction == MV_DOWN ? 2 :
5334 direction == MV_LEFT ? 3 :
5338 int map_direction_EM_to_RND(int direction)
5340 return (direction == 0 ? MV_UP :
5341 direction == 1 ? MV_RIGHT :
5342 direction == 2 ? MV_DOWN :
5343 direction == 3 ? MV_LEFT :
5347 int get_next_element(int element)
5351 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
5352 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
5353 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
5354 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
5355 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
5356 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
5357 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
5359 default: return element;
5364 int el_act_dir2img(int element, int action, int direction)
5366 element = GFX_ELEMENT(element);
5368 if (direction == MV_NONE)
5369 return element_info[element].graphic[action];
5371 direction = MV_DIR_TO_BIT(direction);
5373 return element_info[element].direction_graphic[action][direction];
5376 int el_act_dir2img(int element, int action, int direction)
5378 element = GFX_ELEMENT(element);
5379 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5381 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5382 return element_info[element].direction_graphic[action][direction];
5387 static int el_act_dir2crm(int element, int action, int direction)
5389 element = GFX_ELEMENT(element);
5391 if (direction == MV_NONE)
5392 return element_info[element].crumbled[action];
5394 direction = MV_DIR_TO_BIT(direction);
5396 return element_info[element].direction_crumbled[action][direction];
5399 static int el_act_dir2crm(int element, int action, int direction)
5401 element = GFX_ELEMENT(element);
5402 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5404 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5405 return element_info[element].direction_crumbled[action][direction];
5409 int el_act2img(int element, int action)
5411 element = GFX_ELEMENT(element);
5413 return element_info[element].graphic[action];
5416 int el_act2crm(int element, int action)
5418 element = GFX_ELEMENT(element);
5420 return element_info[element].crumbled[action];
5423 int el_dir2img(int element, int direction)
5425 element = GFX_ELEMENT(element);
5427 return el_act_dir2img(element, ACTION_DEFAULT, direction);
5430 int el2baseimg(int element)
5432 return element_info[element].graphic[ACTION_DEFAULT];
5435 int el2img(int element)
5437 element = GFX_ELEMENT(element);
5439 return element_info[element].graphic[ACTION_DEFAULT];
5442 int el2edimg(int element)
5444 element = GFX_ELEMENT(element);
5446 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
5449 int el2preimg(int element)
5451 element = GFX_ELEMENT(element);
5453 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
5456 int font2baseimg(int font_nr)
5458 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
5461 int getNumActivePlayers_EM()
5463 int num_players = 0;
5469 for (i = 0; i < MAX_PLAYERS; i++)
5470 if (tape.player_participates[i])
5476 int getGameFrameDelay_EM(int native_em_game_frame_delay)
5478 int game_frame_delay_value;
5480 game_frame_delay_value =
5481 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
5482 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
5485 if (tape.playing && tape.warp_forward && !tape.pausing)
5486 game_frame_delay_value = 0;
5488 return game_frame_delay_value;
5491 unsigned int InitRND(long seed)
5493 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
5494 return InitEngineRandom_EM(seed);
5496 return InitEngineRandom_RND(seed);
5499 void InitGraphicInfo_EM(void)
5501 struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
5502 struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
5506 int num_em_gfx_errors = 0;
5508 if (graphic_info_em_object[0][0].bitmap == NULL)
5510 /* EM graphics not yet initialized in em_open_all() */
5515 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
5518 /* always start with reliable default values */
5519 for (i = 0; i < TILE_MAX; i++)
5521 object_mapping[i].element_rnd = EL_UNKNOWN;
5522 object_mapping[i].is_backside = FALSE;
5523 object_mapping[i].action = ACTION_DEFAULT;
5524 object_mapping[i].direction = MV_NONE;
5527 /* always start with reliable default values */
5528 for (p = 0; p < MAX_PLAYERS; p++)
5530 for (i = 0; i < SPR_MAX; i++)
5532 player_mapping[p][i].element_rnd = EL_UNKNOWN;
5533 player_mapping[p][i].action = ACTION_DEFAULT;
5534 player_mapping[p][i].direction = MV_NONE;
5538 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5540 int e = em_object_mapping_list[i].element_em;
5542 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
5543 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
5545 if (em_object_mapping_list[i].action != -1)
5546 object_mapping[e].action = em_object_mapping_list[i].action;
5548 if (em_object_mapping_list[i].direction != -1)
5549 object_mapping[e].direction =
5550 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
5553 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
5555 int a = em_player_mapping_list[i].action_em;
5556 int p = em_player_mapping_list[i].player_nr;
5558 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
5560 if (em_player_mapping_list[i].action != -1)
5561 player_mapping[p][a].action = em_player_mapping_list[i].action;
5563 if (em_player_mapping_list[i].direction != -1)
5564 player_mapping[p][a].direction =
5565 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
5568 for (i = 0; i < TILE_MAX; i++)
5570 int element = object_mapping[i].element_rnd;
5571 int action = object_mapping[i].action;
5572 int direction = object_mapping[i].direction;
5573 boolean is_backside = object_mapping[i].is_backside;
5574 boolean action_removing = (action == ACTION_DIGGING ||
5575 action == ACTION_SNAPPING ||
5576 action == ACTION_COLLECTING);
5577 boolean action_exploding = ((action == ACTION_EXPLODING ||
5578 action == ACTION_SMASHED_BY_ROCK ||
5579 action == ACTION_SMASHED_BY_SPRING) &&
5580 element != EL_DIAMOND);
5581 boolean action_active = (action == ACTION_ACTIVE);
5582 boolean action_other = (action == ACTION_OTHER);
5584 for (j = 0; j < 8; j++)
5586 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
5587 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
5589 i == Xdrip_stretch ? element :
5590 i == Xdrip_stretchB ? element :
5591 i == Ydrip_s1 ? element :
5592 i == Ydrip_s1B ? element :
5593 i == Xball_1B ? element :
5594 i == Xball_2 ? element :
5595 i == Xball_2B ? element :
5596 i == Yball_eat ? element :
5597 i == Ykey_1_eat ? element :
5598 i == Ykey_2_eat ? element :
5599 i == Ykey_3_eat ? element :
5600 i == Ykey_4_eat ? element :
5601 i == Ykey_5_eat ? element :
5602 i == Ykey_6_eat ? element :
5603 i == Ykey_7_eat ? element :
5604 i == Ykey_8_eat ? element :
5605 i == Ylenses_eat ? element :
5606 i == Ymagnify_eat ? element :
5607 i == Ygrass_eat ? element :
5608 i == Ydirt_eat ? element :
5609 i == Yemerald_stone ? EL_EMERALD :
5610 i == Ydiamond_stone ? EL_ROCK :
5611 i == Xsand_stonein_1 ? element :
5612 i == Xsand_stonein_2 ? element :
5613 i == Xsand_stonein_3 ? element :
5614 i == Xsand_stonein_4 ? element :
5615 is_backside ? EL_EMPTY :
5616 action_removing ? EL_EMPTY :
5618 int effective_action = (j < 7 ? action :
5619 i == Xdrip_stretch ? action :
5620 i == Xdrip_stretchB ? action :
5621 i == Ydrip_s1 ? action :
5622 i == Ydrip_s1B ? action :
5623 i == Xball_1B ? action :
5624 i == Xball_2 ? action :
5625 i == Xball_2B ? action :
5626 i == Yball_eat ? action :
5627 i == Ykey_1_eat ? action :
5628 i == Ykey_2_eat ? action :
5629 i == Ykey_3_eat ? action :
5630 i == Ykey_4_eat ? action :
5631 i == Ykey_5_eat ? action :
5632 i == Ykey_6_eat ? action :
5633 i == Ykey_7_eat ? action :
5634 i == Ykey_8_eat ? action :
5635 i == Ylenses_eat ? action :
5636 i == Ymagnify_eat ? action :
5637 i == Ygrass_eat ? action :
5638 i == Ydirt_eat ? action :
5639 i == Xsand_stonein_1 ? action :
5640 i == Xsand_stonein_2 ? action :
5641 i == Xsand_stonein_3 ? action :
5642 i == Xsand_stonein_4 ? action :
5643 i == Xsand_stoneout_1 ? action :
5644 i == Xsand_stoneout_2 ? action :
5645 i == Xboom_android ? ACTION_EXPLODING :
5646 action_exploding ? ACTION_EXPLODING :
5647 action_active ? action :
5648 action_other ? action :
5650 int graphic = (el_act_dir2img(effective_element, effective_action,
5652 int crumbled = (el_act_dir2crm(effective_element, effective_action,
5654 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
5655 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
5656 boolean has_action_graphics = (graphic != base_graphic);
5657 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
5658 struct GraphicInfo *g = &graphic_info[graphic];
5659 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
5662 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
5663 boolean special_animation = (action != ACTION_DEFAULT &&
5664 g->anim_frames == 3 &&
5665 g->anim_delay == 2 &&
5666 g->anim_mode & ANIM_LINEAR);
5667 int sync_frame = (i == Xdrip_stretch ? 7 :
5668 i == Xdrip_stretchB ? 7 :
5669 i == Ydrip_s2 ? j + 8 :
5670 i == Ydrip_s2B ? j + 8 :
5679 i == Xfake_acid_1 ? 0 :
5680 i == Xfake_acid_2 ? 10 :
5681 i == Xfake_acid_3 ? 20 :
5682 i == Xfake_acid_4 ? 30 :
5683 i == Xfake_acid_5 ? 40 :
5684 i == Xfake_acid_6 ? 50 :
5685 i == Xfake_acid_7 ? 60 :
5686 i == Xfake_acid_8 ? 70 :
5688 i == Xball_2B ? j + 8 :
5689 i == Yball_eat ? j + 1 :
5690 i == Ykey_1_eat ? j + 1 :
5691 i == Ykey_2_eat ? j + 1 :
5692 i == Ykey_3_eat ? j + 1 :
5693 i == Ykey_4_eat ? j + 1 :
5694 i == Ykey_5_eat ? j + 1 :
5695 i == Ykey_6_eat ? j + 1 :
5696 i == Ykey_7_eat ? j + 1 :
5697 i == Ykey_8_eat ? j + 1 :
5698 i == Ylenses_eat ? j + 1 :
5699 i == Ymagnify_eat ? j + 1 :
5700 i == Ygrass_eat ? j + 1 :
5701 i == Ydirt_eat ? j + 1 :
5702 i == Xamoeba_1 ? 0 :
5703 i == Xamoeba_2 ? 1 :
5704 i == Xamoeba_3 ? 2 :
5705 i == Xamoeba_4 ? 3 :
5706 i == Xamoeba_5 ? 0 :
5707 i == Xamoeba_6 ? 1 :
5708 i == Xamoeba_7 ? 2 :
5709 i == Xamoeba_8 ? 3 :
5710 i == Xexit_2 ? j + 8 :
5711 i == Xexit_3 ? j + 16 :
5712 i == Xdynamite_1 ? 0 :
5713 i == Xdynamite_2 ? 8 :
5714 i == Xdynamite_3 ? 16 :
5715 i == Xdynamite_4 ? 24 :
5716 i == Xsand_stonein_1 ? j + 1 :
5717 i == Xsand_stonein_2 ? j + 9 :
5718 i == Xsand_stonein_3 ? j + 17 :
5719 i == Xsand_stonein_4 ? j + 25 :
5720 i == Xsand_stoneout_1 && j == 0 ? 0 :
5721 i == Xsand_stoneout_1 && j == 1 ? 0 :
5722 i == Xsand_stoneout_1 && j == 2 ? 1 :
5723 i == Xsand_stoneout_1 && j == 3 ? 2 :
5724 i == Xsand_stoneout_1 && j == 4 ? 2 :
5725 i == Xsand_stoneout_1 && j == 5 ? 3 :
5726 i == Xsand_stoneout_1 && j == 6 ? 4 :
5727 i == Xsand_stoneout_1 && j == 7 ? 4 :
5728 i == Xsand_stoneout_2 && j == 0 ? 5 :
5729 i == Xsand_stoneout_2 && j == 1 ? 6 :
5730 i == Xsand_stoneout_2 && j == 2 ? 7 :
5731 i == Xsand_stoneout_2 && j == 3 ? 8 :
5732 i == Xsand_stoneout_2 && j == 4 ? 9 :
5733 i == Xsand_stoneout_2 && j == 5 ? 11 :
5734 i == Xsand_stoneout_2 && j == 6 ? 13 :
5735 i == Xsand_stoneout_2 && j == 7 ? 15 :
5736 i == Xboom_bug && j == 1 ? 2 :
5737 i == Xboom_bug && j == 2 ? 2 :
5738 i == Xboom_bug && j == 3 ? 4 :
5739 i == Xboom_bug && j == 4 ? 4 :
5740 i == Xboom_bug && j == 5 ? 2 :
5741 i == Xboom_bug && j == 6 ? 2 :
5742 i == Xboom_bug && j == 7 ? 0 :
5743 i == Xboom_bomb && j == 1 ? 2 :
5744 i == Xboom_bomb && j == 2 ? 2 :
5745 i == Xboom_bomb && j == 3 ? 4 :
5746 i == Xboom_bomb && j == 4 ? 4 :
5747 i == Xboom_bomb && j == 5 ? 2 :
5748 i == Xboom_bomb && j == 6 ? 2 :
5749 i == Xboom_bomb && j == 7 ? 0 :
5750 i == Xboom_android && j == 7 ? 6 :
5751 i == Xboom_1 && j == 1 ? 2 :
5752 i == Xboom_1 && j == 2 ? 2 :
5753 i == Xboom_1 && j == 3 ? 4 :
5754 i == Xboom_1 && j == 4 ? 4 :
5755 i == Xboom_1 && j == 5 ? 6 :
5756 i == Xboom_1 && j == 6 ? 6 :
5757 i == Xboom_1 && j == 7 ? 8 :
5758 i == Xboom_2 && j == 0 ? 8 :
5759 i == Xboom_2 && j == 1 ? 8 :
5760 i == Xboom_2 && j == 2 ? 10 :
5761 i == Xboom_2 && j == 3 ? 10 :
5762 i == Xboom_2 && j == 4 ? 10 :
5763 i == Xboom_2 && j == 5 ? 12 :
5764 i == Xboom_2 && j == 6 ? 12 :
5765 i == Xboom_2 && j == 7 ? 12 :
5766 special_animation && j == 4 ? 3 :
5767 effective_action != action ? 0 :
5771 Bitmap *debug_bitmap = g_em->bitmap;
5772 int debug_src_x = g_em->src_x;
5773 int debug_src_y = g_em->src_y;
5776 int frame = getAnimationFrame(g->anim_frames,
5779 g->anim_start_frame,
5782 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
5783 g->double_movement && is_backside);
5785 g_em->bitmap = src_bitmap;
5786 g_em->src_x = src_x;
5787 g_em->src_y = src_y;
5788 g_em->src_offset_x = 0;
5789 g_em->src_offset_y = 0;
5790 g_em->dst_offset_x = 0;
5791 g_em->dst_offset_y = 0;
5792 g_em->width = TILEX;
5793 g_em->height = TILEY;
5795 g_em->crumbled_bitmap = NULL;
5796 g_em->crumbled_src_x = 0;
5797 g_em->crumbled_src_y = 0;
5798 g_em->crumbled_border_size = 0;
5800 g_em->has_crumbled_graphics = FALSE;
5801 g_em->preserve_background = FALSE;
5804 if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
5805 printf("::: empty crumbled: %d [%s], %d, %d\n",
5806 effective_element, element_info[effective_element].token_name,
5807 effective_action, direction);
5810 /* if element can be crumbled, but certain action graphics are just empty
5811 space (like snapping sand with the original R'n'D graphics), do not
5812 treat these empty space graphics as crumbled graphics in EMC engine */
5813 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
5815 getGraphicSource(crumbled, frame, &src_bitmap, &src_x, &src_y);
5817 g_em->has_crumbled_graphics = TRUE;
5818 g_em->crumbled_bitmap = src_bitmap;
5819 g_em->crumbled_src_x = src_x;
5820 g_em->crumbled_src_y = src_y;
5821 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
5825 if (element == EL_ROCK &&
5826 effective_action == ACTION_FILLING)
5827 printf("::: has_action_graphics == %d\n", has_action_graphics);
5830 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
5831 effective_action == ACTION_MOVING ||
5832 effective_action == ACTION_PUSHING ||
5833 effective_action == ACTION_EATING)) ||
5834 (!has_action_graphics && (effective_action == ACTION_FILLING ||
5835 effective_action == ACTION_EMPTYING)))
5838 (effective_action == ACTION_FALLING ||
5839 effective_action == ACTION_FILLING ||
5840 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
5841 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
5842 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
5843 int num_steps = (i == Ydrip_s1 ? 16 :
5844 i == Ydrip_s1B ? 16 :
5845 i == Ydrip_s2 ? 16 :
5846 i == Ydrip_s2B ? 16 :
5847 i == Xsand_stonein_1 ? 32 :
5848 i == Xsand_stonein_2 ? 32 :
5849 i == Xsand_stonein_3 ? 32 :
5850 i == Xsand_stonein_4 ? 32 :
5851 i == Xsand_stoneout_1 ? 16 :
5852 i == Xsand_stoneout_2 ? 16 : 8);
5853 int cx = ABS(dx) * (TILEX / num_steps);
5854 int cy = ABS(dy) * (TILEY / num_steps);
5855 int step_frame = (i == Ydrip_s2 ? j + 8 :
5856 i == Ydrip_s2B ? j + 8 :
5857 i == Xsand_stonein_2 ? j + 8 :
5858 i == Xsand_stonein_3 ? j + 16 :
5859 i == Xsand_stonein_4 ? j + 24 :
5860 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
5861 int step = (is_backside ? step_frame : num_steps - step_frame);
5863 if (is_backside) /* tile where movement starts */
5865 if (dx < 0 || dy < 0)
5867 g_em->src_offset_x = cx * step;
5868 g_em->src_offset_y = cy * step;
5872 g_em->dst_offset_x = cx * step;
5873 g_em->dst_offset_y = cy * step;
5876 else /* tile where movement ends */
5878 if (dx < 0 || dy < 0)
5880 g_em->dst_offset_x = cx * step;
5881 g_em->dst_offset_y = cy * step;
5885 g_em->src_offset_x = cx * step;
5886 g_em->src_offset_y = cy * step;
5890 g_em->width = TILEX - cx * step;
5891 g_em->height = TILEY - cy * step;
5894 /* create unique graphic identifier to decide if tile must be redrawn */
5895 /* bit 31 - 16 (16 bit): EM style graphic
5896 bit 15 - 12 ( 4 bit): EM style frame
5897 bit 11 - 6 ( 6 bit): graphic width
5898 bit 5 - 0 ( 6 bit): graphic height */
5899 g_em->unique_identifier =
5900 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
5904 /* skip check for EMC elements not contained in original EMC artwork */
5905 if (element == EL_EMC_FAKE_ACID)
5908 if (g_em->bitmap != debug_bitmap ||
5909 g_em->src_x != debug_src_x ||
5910 g_em->src_y != debug_src_y ||
5911 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 g_em->width != TILEX ||
5916 g_em->height != TILEY)
5918 static int last_i = -1;
5926 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
5927 i, element, element_info[element].token_name,
5928 element_action_info[effective_action].suffix, direction);
5930 if (element != effective_element)
5931 printf(" [%d ('%s')]",
5933 element_info[effective_element].token_name);
5937 if (g_em->bitmap != debug_bitmap)
5938 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
5939 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
5941 if (g_em->src_x != debug_src_x ||
5942 g_em->src_y != debug_src_y)
5943 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
5944 j, (is_backside ? 'B' : 'F'),
5945 g_em->src_x, g_em->src_y,
5946 g_em->src_x / 32, g_em->src_y / 32,
5947 debug_src_x, debug_src_y,
5948 debug_src_x / 32, debug_src_y / 32);
5950 if (g_em->src_offset_x != 0 ||
5951 g_em->src_offset_y != 0 ||
5952 g_em->dst_offset_x != 0 ||
5953 g_em->dst_offset_y != 0)
5954 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
5956 g_em->src_offset_x, g_em->src_offset_y,
5957 g_em->dst_offset_x, g_em->dst_offset_y);
5959 if (g_em->width != TILEX ||
5960 g_em->height != TILEY)
5961 printf(" %d (%d): size %d,%d should be %d,%d\n",
5963 g_em->width, g_em->height, TILEX, TILEY);
5965 num_em_gfx_errors++;
5972 for (i = 0; i < TILE_MAX; i++)
5974 for (j = 0; j < 8; j++)
5976 int element = object_mapping[i].element_rnd;
5977 int action = object_mapping[i].action;
5978 int direction = object_mapping[i].direction;
5979 boolean is_backside = object_mapping[i].is_backside;
5980 int graphic_action = el_act_dir2img(element, action, direction);
5981 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
5983 if ((action == ACTION_SMASHED_BY_ROCK ||
5984 action == ACTION_SMASHED_BY_SPRING ||
5985 action == ACTION_EATING) &&
5986 graphic_action == graphic_default)
5988 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
5989 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
5990 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
5991 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
5994 /* no separate animation for "smashed by rock" -- use rock instead */
5995 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
5996 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
5998 g_em->bitmap = g_xx->bitmap;
5999 g_em->src_x = g_xx->src_x;
6000 g_em->src_y = g_xx->src_y;
6001 g_em->src_offset_x = g_xx->src_offset_x;
6002 g_em->src_offset_y = g_xx->src_offset_y;
6003 g_em->dst_offset_x = g_xx->dst_offset_x;
6004 g_em->dst_offset_y = g_xx->dst_offset_y;
6005 g_em->width = g_xx->width;
6006 g_em->height = g_xx->height;
6007 g_em->unique_identifier = g_xx->unique_identifier;
6010 g_em->preserve_background = TRUE;
6015 for (p = 0; p < MAX_PLAYERS; p++)
6017 for (i = 0; i < SPR_MAX; i++)
6019 int element = player_mapping[p][i].element_rnd;
6020 int action = player_mapping[p][i].action;
6021 int direction = player_mapping[p][i].direction;
6023 for (j = 0; j < 8; j++)
6025 int effective_element = element;
6026 int effective_action = action;
6027 int graphic = (direction == MV_NONE ?
6028 el_act2img(effective_element, effective_action) :
6029 el_act_dir2img(effective_element, effective_action,
6031 struct GraphicInfo *g = &graphic_info[graphic];
6032 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
6038 Bitmap *debug_bitmap = g_em->bitmap;
6039 int debug_src_x = g_em->src_x;
6040 int debug_src_y = g_em->src_y;
6043 int frame = getAnimationFrame(g->anim_frames,
6046 g->anim_start_frame,
6049 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x,&src_y, FALSE);
6051 g_em->bitmap = src_bitmap;
6052 g_em->src_x = src_x;
6053 g_em->src_y = src_y;
6054 g_em->src_offset_x = 0;
6055 g_em->src_offset_y = 0;
6056 g_em->dst_offset_x = 0;
6057 g_em->dst_offset_y = 0;
6058 g_em->width = TILEX;
6059 g_em->height = TILEY;
6063 /* skip check for EMC elements not contained in original EMC artwork */
6064 if (element == EL_PLAYER_3 ||
6065 element == EL_PLAYER_4)
6068 if (g_em->bitmap != debug_bitmap ||
6069 g_em->src_x != debug_src_x ||
6070 g_em->src_y != debug_src_y)
6072 static int last_i = -1;
6080 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
6081 p, i, element, element_info[element].token_name,
6082 element_action_info[effective_action].suffix, direction);
6084 if (element != effective_element)
6085 printf(" [%d ('%s')]",
6087 element_info[effective_element].token_name);
6091 if (g_em->bitmap != debug_bitmap)
6092 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
6093 j, (int)(g_em->bitmap), (int)(debug_bitmap));
6095 if (g_em->src_x != debug_src_x ||
6096 g_em->src_y != debug_src_y)
6097 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
6099 g_em->src_x, g_em->src_y,
6100 g_em->src_x / 32, g_em->src_y / 32,
6101 debug_src_x, debug_src_y,
6102 debug_src_x / 32, debug_src_y / 32);
6104 num_em_gfx_errors++;
6114 printf("::: [%d errors found]\n", num_em_gfx_errors);
6120 void PlayMenuSound()
6122 int sound = menu.sound[game_status];
6124 if (sound == SND_UNDEFINED)
6127 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6128 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6131 if (IS_LOOP_SOUND(sound))
6132 PlaySoundLoop(sound);
6137 void PlayMenuSoundStereo(int sound, int stereo_position)
6139 if (sound == SND_UNDEFINED)
6142 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6143 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6146 if (IS_LOOP_SOUND(sound))
6147 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
6149 PlaySoundStereo(sound, stereo_position);
6152 void PlayMenuSoundIfLoop()
6154 int sound = menu.sound[game_status];
6156 if (sound == SND_UNDEFINED)
6159 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6160 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6163 if (IS_LOOP_SOUND(sound))
6164 PlaySoundLoop(sound);
6167 void PlayMenuMusic()
6169 int music = menu.music[game_status];
6171 if (music == MUS_UNDEFINED)
6177 void ToggleFullscreenIfNeeded()
6179 boolean change_fullscreen = (setup.fullscreen !=
6180 video.fullscreen_enabled);
6181 boolean change_fullscreen_mode = (video.fullscreen_enabled &&
6182 !strEqual(setup.fullscreen_mode,
6183 video.fullscreen_mode_current));
6185 if (!video.fullscreen_available)
6189 if (change_fullscreen || change_fullscreen_mode)
6191 if (setup.fullscreen != video.fullscreen_enabled ||
6192 setup.fullscreen_mode != video.fullscreen_mode_current)
6195 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
6197 /* save backbuffer content which gets lost when toggling fullscreen mode */
6198 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6201 if (change_fullscreen_mode)
6203 if (setup.fullscreen && video.fullscreen_enabled)
6206 /* keep fullscreen, but change fullscreen mode (screen resolution) */
6208 /* (this is now set in sdl.c) */
6210 video.fullscreen_mode_current = setup.fullscreen_mode;
6212 video.fullscreen_enabled = FALSE; /* force new fullscreen mode */
6215 /* toggle fullscreen */
6216 ChangeVideoModeIfNeeded(setup.fullscreen);
6218 setup.fullscreen = video.fullscreen_enabled;
6220 /* restore backbuffer content from temporary backbuffer backup bitmap */
6221 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6223 FreeBitmap(tmp_backbuffer);
6226 /* update visible window/screen */
6227 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6229 redraw_mask = REDRAW_ALL;