1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back! *
3 *----------------------------------------------------------*
4 * (c) 1995-2006 Artsoft Entertainment *
6 * Detmolder Strasse 189 *
9 * e-mail: info@artsoft.org *
10 *----------------------------------------------------------*
12 ***********************************************************/
14 #include "libgame/libgame.h"
24 /* select level set with EMC X11 graphics before activating EM GFX debugging */
25 #define DEBUG_EM_GFX 0
27 /* tool button identifiers */
28 #define TOOL_CTRL_ID_YES 0
29 #define TOOL_CTRL_ID_NO 1
30 #define TOOL_CTRL_ID_CONFIRM 2
31 #define TOOL_CTRL_ID_PLAYER_1 3
32 #define TOOL_CTRL_ID_PLAYER_2 4
33 #define TOOL_CTRL_ID_PLAYER_3 5
34 #define TOOL_CTRL_ID_PLAYER_4 6
36 #define NUM_TOOL_BUTTONS 7
38 /* forward declaration for internal use */
39 static void UnmapToolButtons();
40 static void HandleToolButtons(struct GadgetInfo *);
41 static int el_act_dir2crm(int, int, int);
42 static int el_act2crm(int, int);
44 static struct GadgetInfo *tool_gadget[NUM_TOOL_BUTTONS];
45 static int request_gadget_id = -1;
47 static char *print_if_not_empty(int element)
49 static char *s = NULL;
50 char *token_name = element_info[element].token_name;
55 s = checked_malloc(strlen(token_name) + 10 + 1);
57 if (element != EL_EMPTY)
58 sprintf(s, "%d\t['%s']", element, token_name);
60 sprintf(s, "%d", element);
65 void DumpTile(int x, int y)
70 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
77 printf("Field Info: SCREEN(%d, %d), LEVEL(%d, %d)\n", sx, sy, x, y);
80 if (!IN_LEV_FIELD(x, y))
82 printf("(not in level field)\n");
88 printf(" Feld: %d\t['%s']\n", Feld[x][y],
89 element_info[Feld[x][y]].token_name);
90 printf(" Back: %s\n", print_if_not_empty(Back[x][y]));
91 printf(" Store: %s\n", print_if_not_empty(Store[x][y]));
92 printf(" Store2: %s\n", print_if_not_empty(Store2[x][y]));
93 printf(" StorePlayer: %s\n", print_if_not_empty(StorePlayer[x][y]));
94 printf(" MovPos: %d\n", MovPos[x][y]);
95 printf(" MovDir: %d\n", MovDir[x][y]);
96 printf(" MovDelay: %d\n", MovDelay[x][y]);
97 printf(" ChangeDelay: %d\n", ChangeDelay[x][y]);
98 printf(" CustomValue: %d\n", CustomValue[x][y]);
99 printf(" GfxElement: %d\n", GfxElement[x][y]);
100 printf(" GfxAction: %d\n", GfxAction[x][y]);
101 printf(" GfxFrame: %d\n", GfxFrame[x][y]);
105 void SetDrawtoField(int mode)
107 if (mode == DRAW_BUFFERED && setup.soft_scrolling)
118 drawto_field = fieldbuffer;
120 else /* DRAW_DIRECT, DRAW_BACKBUFFER */
126 BX2 = SCR_FIELDX - 1;
127 BY2 = SCR_FIELDY - 1;
131 drawto_field = (mode == DRAW_DIRECT ? window : backbuffer);
135 void RedrawPlayfield(boolean force_redraw, int x, int y, int width, int height)
137 if (game_status == GAME_MODE_PLAYING &&
138 level.game_engine_type == GAME_ENGINE_TYPE_EM)
140 /* currently there is no partial redraw -- always redraw whole playfield */
141 RedrawPlayfield_EM(TRUE);
143 /* blit playfield from scroll buffer to normal back buffer for fading in */
144 BlitScreenToBitmap_EM(backbuffer);
146 else if (game_status == GAME_MODE_PLAYING && !game.envelope_active)
152 width = gfx.sxsize + 2 * TILEX;
153 height = gfx.sysize + 2 * TILEY;
156 if (force_redraw || setup.direct_draw)
159 int x1 = (x - SX) / TILEX, y1 = (y - SY) / TILEY;
160 int x2 = (x - SX + width) / TILEX, y2 = (y - SY + height) / TILEY;
162 if (setup.direct_draw)
163 SetDrawtoField(DRAW_BACKBUFFER);
165 for (xx = BX1; xx <= BX2; xx++)
166 for (yy = BY1; yy <= BY2; yy++)
167 if (xx >= x1 && xx <= x2 && yy >= y1 && yy <= y2)
168 DrawScreenField(xx, yy);
171 if (setup.direct_draw)
172 SetDrawtoField(DRAW_DIRECT);
175 if (setup.soft_scrolling)
177 int fx = FX, fy = FY;
179 fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0);
180 fy += (ScreenMovDir & (MV_UP|MV_DOWN) ? ScreenGfxPos : 0);
182 BlitBitmap(fieldbuffer, backbuffer, fx,fy, SXSIZE,SYSIZE, SX,SY);
194 BlitBitmap(drawto, window, x, y, width, height, x, y);
197 void DrawMaskedBorder_Rect(int x, int y, int width, int height)
199 Bitmap *bitmap = graphic_info[IMG_GLOBAL_BORDER].bitmap;
201 SetClipOrigin(bitmap, bitmap->stored_clip_gc, 0, 0);
202 BlitBitmapMasked(bitmap, backbuffer, x, y, width, height, x, y);
205 void DrawMaskedBorder_FIELD()
207 if (game_status >= GAME_MODE_TITLE &&
208 game_status <= GAME_MODE_PLAYING &&
209 border.draw_masked[game_status])
210 DrawMaskedBorder_Rect(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
213 void DrawMaskedBorder_DOOR_1()
215 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
216 (game_status != GAME_MODE_EDITOR ||
217 border.draw_masked[GFX_SPECIAL_ARG_EDITOR]))
218 DrawMaskedBorder_Rect(DX, DY, DXSIZE, DYSIZE);
221 void DrawMaskedBorder_DOOR_2()
223 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
224 game_status != GAME_MODE_EDITOR)
225 DrawMaskedBorder_Rect(VX, VY, VXSIZE, VYSIZE);
228 void DrawMaskedBorder_DOOR_3()
230 /* currently not available */
233 void DrawMaskedBorder_ALL()
235 DrawMaskedBorder_FIELD();
236 DrawMaskedBorder_DOOR_1();
237 DrawMaskedBorder_DOOR_2();
238 DrawMaskedBorder_DOOR_3();
241 void DrawMaskedBorder(int redraw_mask)
243 if (redraw_mask & REDRAW_ALL)
244 DrawMaskedBorder_ALL();
247 if (redraw_mask & REDRAW_FIELD)
248 DrawMaskedBorder_FIELD();
249 if (redraw_mask & REDRAW_DOOR_1)
250 DrawMaskedBorder_DOOR_1();
251 if (redraw_mask & REDRAW_DOOR_2)
252 DrawMaskedBorder_DOOR_2();
253 if (redraw_mask & REDRAW_DOOR_3)
254 DrawMaskedBorder_DOOR_3();
261 DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
263 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
264 redraw_mask &= ~REDRAW_MAIN;
266 if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD)
267 redraw_mask |= REDRAW_FIELD;
269 if (redraw_mask & REDRAW_FIELD)
270 redraw_mask &= ~REDRAW_TILES;
272 if (redraw_mask == REDRAW_NONE)
275 if (redraw_mask & REDRAW_TILES &&
276 game_status == GAME_MODE_PLAYING &&
277 border.draw_masked[game_status])
278 redraw_mask |= REDRAW_FIELD;
280 if (global.fps_slowdown && game_status == GAME_MODE_PLAYING)
282 static boolean last_frame_skipped = FALSE;
283 boolean skip_even_when_not_scrolling = TRUE;
284 boolean just_scrolling = (ScreenMovDir != 0);
285 boolean verbose = FALSE;
287 if (global.fps_slowdown_factor > 1 &&
288 (FrameCounter % global.fps_slowdown_factor) &&
289 (just_scrolling || skip_even_when_not_scrolling))
291 redraw_mask &= ~REDRAW_MAIN;
293 last_frame_skipped = TRUE;
296 printf("FRAME SKIPPED\n");
300 if (last_frame_skipped)
301 redraw_mask |= REDRAW_FIELD;
303 last_frame_skipped = FALSE;
306 printf("frame not skipped\n");
310 /* synchronize X11 graphics at this point; if we would synchronize the
311 display immediately after the buffer switching (after the XFlush),
312 this could mean that we have to wait for the graphics to complete,
313 although we could go on doing calculations for the next frame */
318 DrawMaskedBorder(redraw_mask);
321 if (redraw_mask & REDRAW_ALL)
324 DrawMaskedBorder(REDRAW_ALL);
326 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
328 redraw_mask = REDRAW_NONE;
331 if (redraw_mask & REDRAW_FIELD)
333 if (game_status != GAME_MODE_PLAYING ||
334 redraw_mask & REDRAW_FROM_BACKBUFFER)
337 DrawMaskedBorder(REDRAW_FIELD);
339 BlitBitmap(backbuffer, window,
340 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
344 int fx = FX, fy = FY;
346 if (setup.soft_scrolling)
348 fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
349 fy += (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
352 if (setup.soft_scrolling ||
353 ABS(ScreenMovPos) + ScrollStepSize == TILEX ||
354 ABS(ScreenMovPos) == ScrollStepSize ||
355 redraw_tiles > REDRAWTILES_THRESHOLD)
358 if (border.draw_masked[GFX_SPECIAL_ARG_MAIN])
360 BlitBitmap(buffer, backbuffer, fx, fy, SXSIZE, SYSIZE, SX, SY);
362 DrawMaskedBorder(REDRAW_FIELD);
363 BlitBitmap(backbuffer, window,
364 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
368 BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
370 BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
375 printf("redrawing all (ScreenGfxPos == %d) because %s\n",
377 (setup.soft_scrolling ?
378 "setup.soft_scrolling" :
379 ABS(ScreenGfxPos) + ScrollStepSize == TILEX ?
380 "ABS(ScreenGfxPos) + ScrollStepSize == TILEX" :
381 ABS(ScreenGfxPos) == ScrollStepSize ?
382 "ABS(ScreenGfxPos) == ScrollStepSize" :
383 "redraw_tiles > REDRAWTILES_THRESHOLD"));
389 redraw_mask &= ~REDRAW_MAIN;
392 if (redraw_mask & REDRAW_DOORS)
394 if (redraw_mask & REDRAW_DOOR_1)
397 DrawMaskedBorder(REDRAW_DOOR_1);
399 BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
402 if (redraw_mask & REDRAW_DOOR_2)
405 DrawMaskedBorder(REDRAW_DOOR_2);
407 BlitBitmap(backbuffer, window, VX, VY, VXSIZE, VYSIZE, VX, VY);
410 if (redraw_mask & REDRAW_DOOR_3)
413 DrawMaskedBorder(REDRAW_DOOR_3);
415 BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
418 redraw_mask &= ~REDRAW_DOORS;
421 if (redraw_mask & REDRAW_MICROLEVEL)
423 BlitBitmap(backbuffer, window, SX, SY + 10 * TILEY, SXSIZE, 7 * TILEY,
424 SX, SY + 10 * TILEY);
426 redraw_mask &= ~REDRAW_MICROLEVEL;
429 if (redraw_mask & REDRAW_TILES)
431 for (x = 0; x < SCR_FIELDX; x++)
432 for (y = 0 ; y < SCR_FIELDY; y++)
433 if (redraw[redraw_x1 + x][redraw_y1 + y])
434 BlitBitmap(buffer, window,
435 FX + x * TILEX, FY + y * TILEY, TILEX, TILEY,
436 SX + x * TILEX, SY + y * TILEY);
439 if (redraw_mask & REDRAW_FPS) /* display frames per second */
444 sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
445 if (!global.fps_slowdown)
448 sprintf(text, "%.1f fps%s", global.frames_per_second, info1);
449 DrawTextExt(window, SX, SY, text, FONT_TEXT_2, BLIT_OPAQUE);
454 for (x = 0; x < MAX_BUF_XSIZE; x++)
455 for (y = 0; y < MAX_BUF_YSIZE; y++)
458 redraw_mask = REDRAW_NONE;
464 long fading_delay = 300;
466 if (setup.fading && (redraw_mask & REDRAW_FIELD))
473 ClearRectangle(window, REAL_SX,REAL_SY,FULL_SXSIZE,FULL_SYSIZE);
476 for (i = 0; i < 2 * FULL_SYSIZE; i++)
478 for (y = 0; y < FULL_SYSIZE; y++)
480 BlitBitmap(backbuffer, window,
481 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
489 for (i = 1; i < FULL_SYSIZE; i+=2)
490 BlitBitmap(backbuffer, window,
491 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
497 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, 0);
498 BlitBitmapMasked(backbuffer, window,
499 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
504 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, -1);
505 BlitBitmapMasked(backbuffer, window,
506 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
511 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, -1);
512 BlitBitmapMasked(backbuffer, window,
513 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
518 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, 0);
519 BlitBitmapMasked(backbuffer, window,
520 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
525 redraw_mask &= ~REDRAW_MAIN;
532 void FadeExt(int fade_mask, int fade_mode)
534 void (*draw_border_function)(void) = NULL;
535 Bitmap *bitmap = (fade_mode == FADE_MODE_CROSSFADE ? bitmap_db_cross : NULL);
536 int fade_delay = menu.fade_delay;
537 int post_delay = (fade_mode == FADE_MODE_FADE_OUT ? menu.post_delay : 0);
538 int x, y, width, height;
540 if (fade_mask & REDRAW_FIELD)
545 height = FULL_SYSIZE;
547 draw_border_function = DrawMaskedBorder_FIELD;
549 else /* REDRAW_ALL */
557 redraw_mask |= fade_mask;
559 if (!setup.fade_screens || fade_delay == 0)
561 if (fade_mode == FADE_MODE_FADE_OUT)
562 ClearRectangle(backbuffer, x, y, width, height);
569 FadeRectangle(bitmap, x, y, width, height, fade_mode, fade_delay, post_delay,
570 draw_border_function);
572 redraw_mask &= ~fade_mask;
575 void FadeIn(int fade_mask)
577 FadeExt(fade_mask, FADE_MODE_FADE_IN);
580 void FadeOut(int fade_mask)
582 FadeExt(fade_mask, FADE_MODE_FADE_OUT);
585 void FadeCross(int fade_mask)
587 FadeExt(fade_mask, FADE_MODE_CROSSFADE);
590 void FadeCrossSaveBackbuffer()
592 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
595 void SetMainBackgroundImageIfDefined(int graphic)
597 if (graphic_info[graphic].bitmap)
598 SetMainBackgroundImage(graphic);
601 void SetMainBackgroundImage(int graphic)
603 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
604 graphic_info[graphic].bitmap ?
605 graphic_info[graphic].bitmap :
606 graphic_info[IMG_BACKGROUND].bitmap);
609 void SetDoorBackgroundImage(int graphic)
611 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
612 graphic_info[graphic].bitmap ?
613 graphic_info[graphic].bitmap :
614 graphic_info[IMG_BACKGROUND].bitmap);
617 void SetPanelBackground()
619 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, bitmap_db_panel,
620 DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, 0, 0);
622 SetDoorBackgroundBitmap(bitmap_db_panel);
625 void DrawBackground(int dst_x, int dst_y, int width, int height)
628 ClearRectangleOnBackground(drawto, dst_x, dst_y, width, height);
630 ClearRectangleOnBackground(backbuffer, dst_x, dst_y, width, height);
633 redraw_mask |= REDRAW_FIELD;
638 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
640 if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
642 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
643 SetDrawtoField(DRAW_BUFFERED);
646 SetDrawtoField(DRAW_BACKBUFFER);
648 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
650 ClearRectangle(window, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
651 SetDrawtoField(DRAW_DIRECT);
655 void MarkTileDirty(int x, int y)
657 int xx = redraw_x1 + x;
658 int yy = redraw_y1 + y;
663 redraw[xx][yy] = TRUE;
664 redraw_mask |= REDRAW_TILES;
667 void SetBorderElement()
671 BorderElement = EL_EMPTY;
673 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
675 for (x = 0; x < lev_fieldx; x++)
677 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
678 BorderElement = EL_STEELWALL;
680 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
686 void SetRandomAnimationValue(int x, int y)
688 gfx.anim_random_frame = GfxRandom[x][y];
691 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
693 /* animation synchronized with global frame counter, not move position */
694 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
695 sync_frame = FrameCounter;
697 return getAnimationFrame(graphic_info[graphic].anim_frames,
698 graphic_info[graphic].anim_delay,
699 graphic_info[graphic].anim_mode,
700 graphic_info[graphic].anim_start_frame,
704 inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
705 int *x, int *y, boolean get_backside)
707 struct GraphicInfo *g = &graphic_info[graphic];
708 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
709 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
713 if (g->offset_y == 0) /* frames are ordered horizontally */
715 int max_width = g->anim_frames_per_line * g->width;
716 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
718 *x = pos % max_width;
719 *y = src_y % g->height + pos / max_width * g->height;
721 else if (g->offset_x == 0) /* frames are ordered vertically */
723 int max_height = g->anim_frames_per_line * g->height;
724 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
726 *x = src_x % g->width + pos / max_height * g->width;
727 *y = pos % max_height;
729 else /* frames are ordered diagonally */
731 *x = src_x + frame * g->offset_x;
732 *y = src_y + frame * g->offset_y;
736 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
738 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
741 void DrawGraphic(int x, int y, int graphic, int frame)
744 if (!IN_SCR_FIELD(x, y))
746 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
747 printf("DrawGraphic(): This should never happen!\n");
752 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
756 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
762 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
763 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
766 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
769 if (!IN_SCR_FIELD(x, y))
771 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
772 printf("DrawGraphicThruMask(): This should never happen!\n");
777 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
782 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
788 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
790 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
791 dst_x - src_x, dst_y - src_y);
792 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
795 void DrawMiniGraphic(int x, int y, int graphic)
797 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
798 MarkTileDirty(x / 2, y / 2);
801 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
803 struct GraphicInfo *g = &graphic_info[graphic];
805 int mini_starty = g->bitmap->height * 2 / 3;
808 *x = mini_startx + g->src_x / 2;
809 *y = mini_starty + g->src_y / 2;
812 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
817 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
818 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
821 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
822 int graphic, int frame,
823 int cut_mode, int mask_mode)
828 int width = TILEX, height = TILEY;
831 if (dx || dy) /* shifted graphic */
833 if (x < BX1) /* object enters playfield from the left */
840 else if (x > BX2) /* object enters playfield from the right */
846 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
852 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
854 else if (dx) /* general horizontal movement */
855 MarkTileDirty(x + SIGN(dx), y);
857 if (y < BY1) /* object enters playfield from the top */
859 if (cut_mode==CUT_BELOW) /* object completely above top border */
867 else if (y > BY2) /* object enters playfield from the bottom */
873 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
879 else if (dy > 0 && cut_mode == CUT_ABOVE)
881 if (y == BY2) /* object completely above bottom border */
887 MarkTileDirty(x, y + 1);
888 } /* object leaves playfield to the bottom */
889 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
891 else if (dy) /* general vertical movement */
892 MarkTileDirty(x, y + SIGN(dy));
896 if (!IN_SCR_FIELD(x, y))
898 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
899 printf("DrawGraphicShifted(): This should never happen!\n");
904 if (width > 0 && height > 0)
906 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
911 dst_x = FX + x * TILEX + dx;
912 dst_y = FY + y * TILEY + dy;
914 if (mask_mode == USE_MASKING)
916 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
917 dst_x - src_x, dst_y - src_y);
918 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
922 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
929 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
930 int graphic, int frame,
931 int cut_mode, int mask_mode)
936 int width = TILEX, height = TILEY;
939 int x2 = x + SIGN(dx);
940 int y2 = y + SIGN(dy);
941 int anim_frames = graphic_info[graphic].anim_frames;
942 int sync_frame = (dx ? ABS(dx) : ABS(dy)) * anim_frames / TILESIZE;
943 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
944 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
946 /* re-calculate animation frame for two-tile movement animation */
947 frame = getGraphicAnimationFrame(graphic, sync_frame);
949 /* check if movement start graphic inside screen area and should be drawn */
950 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
952 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
954 dst_x = FX + x1 * TILEX;
955 dst_y = FY + y1 * TILEY;
957 if (mask_mode == USE_MASKING)
959 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
960 dst_x - src_x, dst_y - src_y);
961 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
965 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
968 MarkTileDirty(x1, y1);
971 /* check if movement end graphic inside screen area and should be drawn */
972 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
974 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
976 dst_x = FX + x2 * TILEX;
977 dst_y = FY + y2 * TILEY;
979 if (mask_mode == USE_MASKING)
981 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
982 dst_x - src_x, dst_y - src_y);
983 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
987 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
990 MarkTileDirty(x2, y2);
994 static void DrawGraphicShifted(int x, int y, int dx, int dy,
995 int graphic, int frame,
996 int cut_mode, int mask_mode)
1000 DrawGraphic(x, y, graphic, frame);
1005 if (graphic_info[graphic].double_movement) /* EM style movement images */
1006 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1008 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1011 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1012 int frame, int cut_mode)
1014 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
1017 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1018 int cut_mode, int mask_mode)
1020 int lx = LEVELX(x), ly = LEVELY(y);
1024 if (IN_LEV_FIELD(lx, ly))
1026 SetRandomAnimationValue(lx, ly);
1028 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
1029 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1031 /* do not use double (EM style) movement graphic when not moving */
1032 if (graphic_info[graphic].double_movement && !dx && !dy)
1034 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
1035 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1038 else /* border element */
1040 graphic = el2img(element);
1041 frame = getGraphicAnimationFrame(graphic, -1);
1044 if (element == EL_EXPANDABLE_WALL)
1046 boolean left_stopped = FALSE, right_stopped = FALSE;
1048 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1049 left_stopped = TRUE;
1050 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1051 right_stopped = TRUE;
1053 if (left_stopped && right_stopped)
1055 else if (left_stopped)
1057 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1058 frame = graphic_info[graphic].anim_frames - 1;
1060 else if (right_stopped)
1062 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1063 frame = graphic_info[graphic].anim_frames - 1;
1068 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1069 else if (mask_mode == USE_MASKING)
1070 DrawGraphicThruMask(x, y, graphic, frame);
1072 DrawGraphic(x, y, graphic, frame);
1075 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1076 int cut_mode, int mask_mode)
1078 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1079 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1080 cut_mode, mask_mode);
1083 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1086 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1089 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1092 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1095 void DrawLevelElementThruMask(int x, int y, int element)
1097 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1100 void DrawLevelFieldThruMask(int x, int y)
1102 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1105 static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
1109 int sx = SCREENX(x), sy = SCREENY(y);
1111 int width, height, cx, cy, i;
1112 int crumbled_border_size = graphic_info[graphic].border_size;
1113 static int xy[4][2] =
1121 if (!IN_LEV_FIELD(x, y))
1124 element = TILE_GFX_ELEMENT(x, y);
1126 /* crumble field itself */
1127 if (GFX_CRUMBLED(element) && !IS_MOVING(x, y))
1129 if (!IN_SCR_FIELD(sx, sy))
1132 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1134 for (i = 0; i < 4; i++)
1136 int xx = x + xy[i][0];
1137 int yy = y + xy[i][1];
1139 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1142 /* check if neighbour field is of same type */
1143 if (GFX_CRUMBLED(element) && !IS_MOVING(xx, yy))
1146 if (i == 1 || i == 2)
1148 width = crumbled_border_size;
1150 cx = (i == 2 ? TILEX - crumbled_border_size : 0);
1156 height = crumbled_border_size;
1158 cy = (i == 3 ? TILEY - crumbled_border_size : 0);
1161 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1162 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1165 MarkTileDirty(sx, sy);
1167 else /* crumble neighbour fields */
1169 for (i = 0; i < 4; i++)
1171 int xx = x + xy[i][0];
1172 int yy = y + xy[i][1];
1173 int sxx = sx + xy[i][0];
1174 int syy = sy + xy[i][1];
1176 if (!IN_LEV_FIELD(xx, yy) ||
1177 !IN_SCR_FIELD(sxx, syy) ||
1181 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
1184 element = TILE_GFX_ELEMENT(xx, yy);
1186 if (!GFX_CRUMBLED(element))
1189 graphic = el_act2crm(element, ACTION_DEFAULT);
1190 crumbled_border_size = graphic_info[graphic].border_size;
1192 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1194 if (i == 1 || i == 2)
1196 width = crumbled_border_size;
1198 cx = (i == 1 ? TILEX - crumbled_border_size : 0);
1204 height = crumbled_border_size;
1206 cy = (i == 0 ? TILEY - crumbled_border_size : 0);
1209 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1210 width, height, FX + sxx * TILEX + cx, FY + syy * TILEY + cy);
1212 MarkTileDirty(sxx, syy);
1217 void DrawLevelFieldCrumbledSand(int x, int y)
1221 if (!IN_LEV_FIELD(x, y))
1225 /* !!! CHECK THIS !!! */
1228 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1229 GFX_CRUMBLED(GfxElement[x][y]))
1232 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1233 GfxElement[x][y] != EL_UNDEFINED &&
1234 GFX_CRUMBLED(GfxElement[x][y]))
1236 DrawLevelFieldCrumbledSandDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
1243 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
1245 graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
1248 DrawLevelFieldCrumbledSandExt(x, y, graphic, 0);
1251 void DrawLevelFieldCrumbledSandDigging(int x, int y, int direction,
1254 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1255 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1256 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1257 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1258 int sx = SCREENX(x), sy = SCREENY(y);
1260 DrawGraphic(sx, sy, graphic1, frame1);
1261 DrawLevelFieldCrumbledSandExt(x, y, graphic2, frame2);
1264 void DrawLevelFieldCrumbledSandNeighbours(int x, int y)
1266 int sx = SCREENX(x), sy = SCREENY(y);
1267 static int xy[4][2] =
1276 for (i = 0; i < 4; i++)
1278 int xx = x + xy[i][0];
1279 int yy = y + xy[i][1];
1280 int sxx = sx + xy[i][0];
1281 int syy = sy + xy[i][1];
1283 if (!IN_LEV_FIELD(xx, yy) ||
1284 !IN_SCR_FIELD(sxx, syy) ||
1285 !GFX_CRUMBLED(Feld[xx][yy]) ||
1289 DrawLevelField(xx, yy);
1293 static int getBorderElement(int x, int y)
1297 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1298 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1299 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1300 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1301 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1302 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1303 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1305 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1306 int steel_position = (x == -1 && y == -1 ? 0 :
1307 x == lev_fieldx && y == -1 ? 1 :
1308 x == -1 && y == lev_fieldy ? 2 :
1309 x == lev_fieldx && y == lev_fieldy ? 3 :
1310 x == -1 || x == lev_fieldx ? 4 :
1311 y == -1 || y == lev_fieldy ? 5 : 6);
1313 return border[steel_position][steel_type];
1316 void DrawScreenElement(int x, int y, int element)
1318 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1319 DrawLevelFieldCrumbledSand(LEVELX(x), LEVELY(y));
1322 void DrawLevelElement(int x, int y, int element)
1324 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1325 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1328 void DrawScreenField(int x, int y)
1330 int lx = LEVELX(x), ly = LEVELY(y);
1331 int element, content;
1333 if (!IN_LEV_FIELD(lx, ly))
1335 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1338 element = getBorderElement(lx, ly);
1340 DrawScreenElement(x, y, element);
1344 element = Feld[lx][ly];
1345 content = Store[lx][ly];
1347 if (IS_MOVING(lx, ly))
1349 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1350 boolean cut_mode = NO_CUTTING;
1352 if (element == EL_QUICKSAND_EMPTYING ||
1353 element == EL_MAGIC_WALL_EMPTYING ||
1354 element == EL_BD_MAGIC_WALL_EMPTYING ||
1355 element == EL_AMOEBA_DROPPING)
1356 cut_mode = CUT_ABOVE;
1357 else if (element == EL_QUICKSAND_FILLING ||
1358 element == EL_MAGIC_WALL_FILLING ||
1359 element == EL_BD_MAGIC_WALL_FILLING)
1360 cut_mode = CUT_BELOW;
1362 if (cut_mode == CUT_ABOVE)
1363 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1365 DrawScreenElement(x, y, EL_EMPTY);
1368 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1369 else if (cut_mode == NO_CUTTING)
1370 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1372 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1374 if (content == EL_ACID)
1376 int dir = MovDir[lx][ly];
1377 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
1378 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
1380 DrawLevelElementThruMask(newlx, newly, EL_ACID);
1383 else if (IS_BLOCKED(lx, ly))
1388 boolean cut_mode = NO_CUTTING;
1389 int element_old, content_old;
1391 Blocked2Moving(lx, ly, &oldx, &oldy);
1394 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1395 MovDir[oldx][oldy] == MV_RIGHT);
1397 element_old = Feld[oldx][oldy];
1398 content_old = Store[oldx][oldy];
1400 if (element_old == EL_QUICKSAND_EMPTYING ||
1401 element_old == EL_MAGIC_WALL_EMPTYING ||
1402 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1403 element_old == EL_AMOEBA_DROPPING)
1404 cut_mode = CUT_ABOVE;
1406 DrawScreenElement(x, y, EL_EMPTY);
1409 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1411 else if (cut_mode == NO_CUTTING)
1412 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1415 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1418 else if (IS_DRAWABLE(element))
1419 DrawScreenElement(x, y, element);
1421 DrawScreenElement(x, y, EL_EMPTY);
1424 void DrawLevelField(int x, int y)
1426 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1427 DrawScreenField(SCREENX(x), SCREENY(y));
1428 else if (IS_MOVING(x, y))
1432 Moving2Blocked(x, y, &newx, &newy);
1433 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1434 DrawScreenField(SCREENX(newx), SCREENY(newy));
1436 else if (IS_BLOCKED(x, y))
1440 Blocked2Moving(x, y, &oldx, &oldy);
1441 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1442 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1446 void DrawMiniElement(int x, int y, int element)
1450 graphic = el2edimg(element);
1451 DrawMiniGraphic(x, y, graphic);
1454 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1456 int x = sx + scroll_x, y = sy + scroll_y;
1458 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1459 DrawMiniElement(sx, sy, EL_EMPTY);
1460 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1461 DrawMiniElement(sx, sy, Feld[x][y]);
1463 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1466 void DrawEnvelopeBackground(int envelope_nr, int startx, int starty,
1467 int x, int y, int xsize, int ysize, int font_nr)
1469 int font_width = getFontWidth(font_nr);
1470 int font_height = getFontHeight(font_nr);
1471 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1474 int dst_x = SX + startx + x * font_width;
1475 int dst_y = SY + starty + y * font_height;
1476 int width = graphic_info[graphic].width;
1477 int height = graphic_info[graphic].height;
1478 int inner_width = MAX(width - 2 * font_width, font_width);
1479 int inner_height = MAX(height - 2 * font_height, font_height);
1480 int inner_sx = (width >= 3 * font_width ? font_width : 0);
1481 int inner_sy = (height >= 3 * font_height ? font_height : 0);
1482 boolean draw_masked = graphic_info[graphic].draw_masked;
1484 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1486 if (src_bitmap == NULL || width < font_width || height < font_height)
1488 ClearRectangle(drawto, dst_x, dst_y, font_width, font_height);
1492 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - font_width :
1493 inner_sx + (x - 1) * font_width % inner_width);
1494 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - font_height :
1495 inner_sy + (y - 1) * font_height % inner_height);
1499 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1500 dst_x - src_x, dst_y - src_y);
1501 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1505 BlitBitmap(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1509 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
1511 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1512 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1513 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
1514 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1515 boolean no_delay = (tape.warp_forward);
1516 unsigned long anim_delay = 0;
1517 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
1518 int anim_delay_value = (no_delay ? 0 : frame_delay_value);
1519 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
1520 int font_width = getFontWidth(font_nr);
1521 int font_height = getFontHeight(font_nr);
1522 int max_xsize = level.envelope[envelope_nr].xsize;
1523 int max_ysize = level.envelope[envelope_nr].ysize;
1524 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
1525 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
1526 int xend = max_xsize;
1527 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
1528 int xstep = (xstart < xend ? 1 : 0);
1529 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
1532 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
1534 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
1535 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
1536 int sx = (SXSIZE - xsize * font_width) / 2;
1537 int sy = (SYSIZE - ysize * font_height) / 2;
1540 SetDrawtoField(DRAW_BUFFERED);
1542 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
1544 SetDrawtoField(DRAW_BACKBUFFER);
1546 for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++)
1547 DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
1549 DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
1550 level.envelope[envelope_nr].text, font_nr, max_xsize,
1551 xsize - 2, ysize - 2, mask_mode);
1553 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
1556 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
1560 void ShowEnvelope(int envelope_nr)
1562 int element = EL_ENVELOPE_1 + envelope_nr;
1563 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1564 int sound_opening = element_info[element].sound[ACTION_OPENING];
1565 int sound_closing = element_info[element].sound[ACTION_CLOSING];
1566 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1567 boolean no_delay = (tape.warp_forward);
1568 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
1569 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
1570 int anim_mode = graphic_info[graphic].anim_mode;
1571 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
1572 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
1574 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
1576 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
1578 if (anim_mode == ANIM_DEFAULT)
1579 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
1581 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
1584 Delay(wait_delay_value);
1586 WaitForEventToContinue();
1588 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
1590 if (anim_mode != ANIM_NONE)
1591 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
1593 if (anim_mode == ANIM_DEFAULT)
1594 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
1596 game.envelope_active = FALSE;
1598 SetDrawtoField(DRAW_BUFFERED);
1600 redraw_mask |= REDRAW_FIELD;
1604 void getPreviewGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y,
1609 int width_mult, width_div;
1610 int height_mult, height_div;
1618 int offset_calc_pos = (tilesize < MICRO_TILESIZE || tilesize > TILESIZE ? 3 :
1619 5 - log_2(tilesize));
1620 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1621 int width_mult = offset_calc[offset_calc_pos].width_mult;
1622 int width_div = offset_calc[offset_calc_pos].width_div;
1623 int height_mult = offset_calc[offset_calc_pos].height_mult;
1624 int height_div = offset_calc[offset_calc_pos].height_div;
1625 int mini_startx = src_bitmap->width * width_mult / width_div;
1626 int mini_starty = src_bitmap->height * height_mult / height_div;
1627 int src_x = mini_startx + graphic_info[graphic].src_x * tilesize / TILESIZE;
1628 int src_y = mini_starty + graphic_info[graphic].src_y * tilesize / TILESIZE;
1630 *bitmap = src_bitmap;
1635 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
1639 int graphic = el2preimg(element);
1641 getPreviewGraphicSource(graphic, &src_bitmap, &src_x, &src_y, tilesize);
1642 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
1649 SetDrawBackgroundMask(REDRAW_NONE);
1652 for (x = BX1; x <= BX2; x++)
1653 for (y = BY1; y <= BY2; y++)
1654 DrawScreenField(x, y);
1656 redraw_mask |= REDRAW_FIELD;
1659 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1663 for (x = 0; x < size_x; x++)
1664 for (y = 0; y < size_y; y++)
1665 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1667 redraw_mask |= REDRAW_FIELD;
1670 static void DrawPreviewLevelExt(int from_x, int from_y)
1672 boolean show_level_border = (BorderElement != EL_EMPTY);
1673 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
1674 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
1675 int tile_size = preview.tile_size;
1676 int preview_width = preview.xsize * tile_size;
1677 int preview_height = preview.ysize * tile_size;
1678 int real_preview_xsize = MIN(level_xsize, preview.xsize);
1679 int real_preview_ysize = MIN(level_ysize, preview.ysize);
1680 int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
1681 int dst_y = SY + preview.y;
1684 DrawBackground(dst_x, dst_y, preview_width, preview_height);
1686 dst_x += (preview_width - real_preview_xsize * tile_size) / 2;
1687 dst_y += (preview_height - real_preview_ysize * tile_size) / 2;
1689 for (x = 0; x < real_preview_xsize; x++)
1691 for (y = 0; y < real_preview_ysize; y++)
1693 int lx = from_x + x + (show_level_border ? -1 : 0);
1694 int ly = from_y + y + (show_level_border ? -1 : 0);
1695 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
1696 getBorderElement(lx, ly));
1698 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
1699 element, tile_size);
1703 redraw_mask |= REDRAW_MICROLEVEL;
1706 #define MICROLABEL_EMPTY 0
1707 #define MICROLABEL_LEVEL_NAME 1
1708 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
1709 #define MICROLABEL_LEVEL_AUTHOR 3
1710 #define MICROLABEL_IMPORTED_FROM_HEAD 4
1711 #define MICROLABEL_IMPORTED_FROM 5
1712 #define MICROLABEL_IMPORTED_BY_HEAD 6
1713 #define MICROLABEL_IMPORTED_BY 7
1715 static int getMaxTextLength(struct MenuPosInfo *pos, int font_nr)
1717 int max_text_width = SXSIZE;
1718 int font_width = getFontWidth(font_nr);
1720 if (pos->align == ALIGN_CENTER)
1721 max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
1722 else if (pos->align == ALIGN_RIGHT)
1723 max_text_width = pos->x;
1725 max_text_width = SXSIZE - pos->x;
1727 return max_text_width / font_width;
1730 static void DrawPreviewLevelLabelExt(int mode)
1732 struct MenuPosInfo *pos = &menu.main.text.level_info_2;
1733 char label_text[MAX_OUTPUT_LINESIZE + 1];
1734 int max_len_label_text;
1735 int font_nr = FONT_TEXT_2;
1738 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
1739 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
1740 mode == MICROLABEL_IMPORTED_BY_HEAD)
1741 font_nr = FONT_TEXT_3;
1744 max_len_label_text = getMaxTextLength(pos, font_nr);
1746 max_len_label_text = SXSIZE / getFontWidth(font_nr);
1749 for (i = 0; i < max_len_label_text; i++)
1750 label_text[i] = ' ';
1751 label_text[max_len_label_text] = '\0';
1753 if (strlen(label_text) > 0)
1756 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
1758 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1759 int lypos = MICROLABEL2_YPOS;
1761 DrawText(lxpos, lypos, label_text, font_nr);
1766 (mode == MICROLABEL_LEVEL_NAME ? level.name :
1767 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
1768 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1769 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
1770 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
1771 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
1772 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
1773 max_len_label_text);
1774 label_text[max_len_label_text] = '\0';
1776 if (strlen(label_text) > 0)
1779 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
1781 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1782 int lypos = MICROLABEL2_YPOS;
1784 DrawText(lxpos, lypos, label_text, font_nr);
1788 redraw_mask |= REDRAW_MICROLEVEL;
1791 void DrawPreviewLevel(boolean restart)
1793 static unsigned long scroll_delay = 0;
1794 static unsigned long label_delay = 0;
1795 static int from_x, from_y, scroll_direction;
1796 static int label_state, label_counter;
1797 unsigned long scroll_delay_value = preview.step_delay;
1798 boolean show_level_border = (BorderElement != EL_EMPTY);
1799 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
1800 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
1801 int last_game_status = game_status; /* save current game status */
1803 /* force PREVIEW font on preview level */
1804 game_status = GAME_MODE_PSEUDO_PREVIEW;
1811 if (preview.anim_mode == ANIM_CENTERED)
1813 if (level_xsize > preview.xsize)
1814 from_x = (level_xsize - preview.xsize) / 2;
1815 if (level_ysize > preview.ysize)
1816 from_y = (level_ysize - preview.ysize) / 2;
1819 from_x += preview.xoffset;
1820 from_y += preview.yoffset;
1822 scroll_direction = MV_RIGHT;
1826 DrawPreviewLevelExt(from_x, from_y);
1827 DrawPreviewLevelLabelExt(label_state);
1829 /* initialize delay counters */
1830 DelayReached(&scroll_delay, 0);
1831 DelayReached(&label_delay, 0);
1833 if (leveldir_current->name)
1835 struct MenuPosInfo *pos = &menu.main.text.level_info_1;
1836 char label_text[MAX_OUTPUT_LINESIZE + 1];
1837 int font_nr = FONT_TEXT_1;
1839 int max_len_label_text = getMaxTextLength(pos, font_nr);
1841 int max_len_label_text = SXSIZE / getFontWidth(font_nr);
1848 strncpy(label_text, leveldir_current->name, max_len_label_text);
1849 label_text[max_len_label_text] = '\0';
1852 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
1854 lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1855 lypos = SY + MICROLABEL1_YPOS;
1857 DrawText(lxpos, lypos, label_text, font_nr);
1861 game_status = last_game_status; /* restore current game status */
1866 /* scroll preview level, if needed */
1867 if (preview.anim_mode != ANIM_NONE &&
1868 (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
1869 DelayReached(&scroll_delay, scroll_delay_value))
1871 switch (scroll_direction)
1876 from_x -= preview.step_offset;
1877 from_x = (from_x < 0 ? 0 : from_x);
1880 scroll_direction = MV_UP;
1884 if (from_x < level_xsize - preview.xsize)
1886 from_x += preview.step_offset;
1887 from_x = (from_x > level_xsize - preview.xsize ?
1888 level_xsize - preview.xsize : from_x);
1891 scroll_direction = MV_DOWN;
1897 from_y -= preview.step_offset;
1898 from_y = (from_y < 0 ? 0 : from_y);
1901 scroll_direction = MV_RIGHT;
1905 if (from_y < level_ysize - preview.ysize)
1907 from_y += preview.step_offset;
1908 from_y = (from_y > level_ysize - preview.ysize ?
1909 level_ysize - preview.ysize : from_y);
1912 scroll_direction = MV_LEFT;
1919 DrawPreviewLevelExt(from_x, from_y);
1922 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
1923 /* redraw micro level label, if needed */
1924 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
1925 !strEqual(level.author, ANONYMOUS_NAME) &&
1926 !strEqual(level.author, leveldir_current->name) &&
1927 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
1929 int max_label_counter = 23;
1931 if (leveldir_current->imported_from != NULL &&
1932 strlen(leveldir_current->imported_from) > 0)
1933 max_label_counter += 14;
1934 if (leveldir_current->imported_by != NULL &&
1935 strlen(leveldir_current->imported_by) > 0)
1936 max_label_counter += 14;
1938 label_counter = (label_counter + 1) % max_label_counter;
1939 label_state = (label_counter >= 0 && label_counter <= 7 ?
1940 MICROLABEL_LEVEL_NAME :
1941 label_counter >= 9 && label_counter <= 12 ?
1942 MICROLABEL_LEVEL_AUTHOR_HEAD :
1943 label_counter >= 14 && label_counter <= 21 ?
1944 MICROLABEL_LEVEL_AUTHOR :
1945 label_counter >= 23 && label_counter <= 26 ?
1946 MICROLABEL_IMPORTED_FROM_HEAD :
1947 label_counter >= 28 && label_counter <= 35 ?
1948 MICROLABEL_IMPORTED_FROM :
1949 label_counter >= 37 && label_counter <= 40 ?
1950 MICROLABEL_IMPORTED_BY_HEAD :
1951 label_counter >= 42 && label_counter <= 49 ?
1952 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
1954 if (leveldir_current->imported_from == NULL &&
1955 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
1956 label_state == MICROLABEL_IMPORTED_FROM))
1957 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
1958 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
1960 DrawPreviewLevelLabelExt(label_state);
1963 game_status = last_game_status; /* restore current game status */
1966 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
1967 int graphic, int sync_frame, int mask_mode)
1969 int frame = getGraphicAnimationFrame(graphic, sync_frame);
1971 if (mask_mode == USE_MASKING)
1972 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
1974 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
1977 inline void DrawGraphicAnimation(int x, int y, int graphic)
1979 int lx = LEVELX(x), ly = LEVELY(y);
1981 if (!IN_SCR_FIELD(x, y))
1984 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
1985 graphic, GfxFrame[lx][ly], NO_MASKING);
1986 MarkTileDirty(x, y);
1989 void DrawLevelGraphicAnimation(int x, int y, int graphic)
1991 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
1994 void DrawLevelElementAnimation(int x, int y, int element)
1996 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
1998 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2001 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
2003 int sx = SCREENX(x), sy = SCREENY(y);
2005 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2008 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2011 DrawGraphicAnimation(sx, sy, graphic);
2014 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
2015 DrawLevelFieldCrumbledSand(x, y);
2017 if (GFX_CRUMBLED(Feld[x][y]))
2018 DrawLevelFieldCrumbledSand(x, y);
2022 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
2024 int sx = SCREENX(x), sy = SCREENY(y);
2027 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2030 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2032 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2035 DrawGraphicAnimation(sx, sy, graphic);
2037 if (GFX_CRUMBLED(element))
2038 DrawLevelFieldCrumbledSand(x, y);
2041 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
2043 if (player->use_murphy)
2045 /* this works only because currently only one player can be "murphy" ... */
2046 static int last_horizontal_dir = MV_LEFT;
2047 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
2049 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2050 last_horizontal_dir = move_dir;
2052 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
2054 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
2056 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
2062 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
2065 static boolean equalGraphics(int graphic1, int graphic2)
2067 struct GraphicInfo *g1 = &graphic_info[graphic1];
2068 struct GraphicInfo *g2 = &graphic_info[graphic2];
2070 return (g1->bitmap == g2->bitmap &&
2071 g1->src_x == g2->src_x &&
2072 g1->src_y == g2->src_y &&
2073 g1->anim_frames == g2->anim_frames &&
2074 g1->anim_delay == g2->anim_delay &&
2075 g1->anim_mode == g2->anim_mode);
2078 void DrawAllPlayers()
2082 for (i = 0; i < MAX_PLAYERS; i++)
2083 if (stored_player[i].active)
2084 DrawPlayer(&stored_player[i]);
2087 void DrawPlayerField(int x, int y)
2089 if (!IS_PLAYER(x, y))
2092 DrawPlayer(PLAYERINFO(x, y));
2095 void DrawPlayer(struct PlayerInfo *player)
2097 int jx = player->jx;
2098 int jy = player->jy;
2099 int move_dir = player->MovDir;
2100 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
2101 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
2102 int last_jx = (player->is_moving ? jx - dx : jx);
2103 int last_jy = (player->is_moving ? jy - dy : jy);
2104 int next_jx = jx + dx;
2105 int next_jy = jy + dy;
2106 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
2107 boolean player_is_opaque = FALSE;
2108 int sx = SCREENX(jx), sy = SCREENY(jy);
2109 int sxx = 0, syy = 0;
2110 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
2112 int action = ACTION_DEFAULT;
2113 int last_player_graphic = getPlayerGraphic(player, move_dir);
2114 int last_player_frame = player->Frame;
2117 /* GfxElement[][] is set to the element the player is digging or collecting;
2118 remove also for off-screen player if the player is not moving anymore */
2119 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
2120 GfxElement[jx][jy] = EL_UNDEFINED;
2122 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
2126 if (!IN_LEV_FIELD(jx, jy))
2128 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
2129 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
2130 printf("DrawPlayerField(): This should never happen!\n");
2135 if (element == EL_EXPLOSION)
2138 action = (player->is_pushing ? ACTION_PUSHING :
2139 player->is_digging ? ACTION_DIGGING :
2140 player->is_collecting ? ACTION_COLLECTING :
2141 player->is_moving ? ACTION_MOVING :
2142 player->is_snapping ? ACTION_SNAPPING :
2143 player->is_dropping ? ACTION_DROPPING :
2144 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
2146 if (player->is_waiting)
2147 move_dir = player->dir_waiting;
2149 InitPlayerGfxAnimation(player, action, move_dir);
2151 /* ----------------------------------------------------------------------- */
2152 /* draw things in the field the player is leaving, if needed */
2153 /* ----------------------------------------------------------------------- */
2155 if (player->is_moving)
2157 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
2159 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
2161 if (last_element == EL_DYNAMITE_ACTIVE ||
2162 last_element == EL_EM_DYNAMITE_ACTIVE ||
2163 last_element == EL_SP_DISK_RED_ACTIVE)
2164 DrawDynamite(last_jx, last_jy);
2166 DrawLevelFieldThruMask(last_jx, last_jy);
2168 else if (last_element == EL_DYNAMITE_ACTIVE ||
2169 last_element == EL_EM_DYNAMITE_ACTIVE ||
2170 last_element == EL_SP_DISK_RED_ACTIVE)
2171 DrawDynamite(last_jx, last_jy);
2173 /* !!! this is not enough to prevent flickering of players which are
2174 moving next to each others without a free tile between them -- this
2175 can only be solved by drawing all players layer by layer (first the
2176 background, then the foreground etc.) !!! => TODO */
2177 else if (!IS_PLAYER(last_jx, last_jy))
2178 DrawLevelField(last_jx, last_jy);
2181 DrawLevelField(last_jx, last_jy);
2184 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
2185 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
2188 if (!IN_SCR_FIELD(sx, sy))
2191 if (setup.direct_draw)
2192 SetDrawtoField(DRAW_BUFFERED);
2194 /* ----------------------------------------------------------------------- */
2195 /* draw things behind the player, if needed */
2196 /* ----------------------------------------------------------------------- */
2199 DrawLevelElement(jx, jy, Back[jx][jy]);
2200 else if (IS_ACTIVE_BOMB(element))
2201 DrawLevelElement(jx, jy, EL_EMPTY);
2204 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
2206 int old_element = GfxElement[jx][jy];
2207 int old_graphic = el_act_dir2img(old_element, action, move_dir);
2208 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
2210 if (GFX_CRUMBLED(old_element))
2211 DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
2213 DrawGraphic(sx, sy, old_graphic, frame);
2215 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
2216 player_is_opaque = TRUE;
2220 GfxElement[jx][jy] = EL_UNDEFINED;
2222 /* make sure that pushed elements are drawn with correct frame rate */
2224 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2226 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
2227 GfxFrame[jx][jy] = player->StepFrame;
2229 if (player->is_pushing && player->is_moving)
2230 GfxFrame[jx][jy] = player->StepFrame;
2233 DrawLevelField(jx, jy);
2237 /* ----------------------------------------------------------------------- */
2238 /* draw player himself */
2239 /* ----------------------------------------------------------------------- */
2241 graphic = getPlayerGraphic(player, move_dir);
2243 /* in the case of changed player action or direction, prevent the current
2244 animation frame from being restarted for identical animations */
2245 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
2246 player->Frame = last_player_frame;
2248 frame = getGraphicAnimationFrame(graphic, player->Frame);
2252 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2253 sxx = player->GfxPos;
2255 syy = player->GfxPos;
2258 if (!setup.soft_scrolling && ScreenMovPos)
2261 if (player_is_opaque)
2262 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
2264 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2266 if (SHIELD_ON(player))
2268 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
2269 IMG_SHIELD_NORMAL_ACTIVE);
2270 int frame = getGraphicAnimationFrame(graphic, -1);
2272 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2275 /* ----------------------------------------------------------------------- */
2276 /* draw things the player is pushing, if needed */
2277 /* ----------------------------------------------------------------------- */
2280 printf("::: %d, %d [%d, %d] [%d]\n",
2281 player->is_pushing, player_is_moving, player->GfxAction,
2282 player->is_moving, player_is_moving);
2286 if (player->is_pushing && player->is_moving)
2288 int px = SCREENX(jx), py = SCREENY(jy);
2289 int pxx = (TILEX - ABS(sxx)) * dx;
2290 int pyy = (TILEY - ABS(syy)) * dy;
2291 int gfx_frame = GfxFrame[jx][jy];
2297 if (!IS_MOVING(jx, jy)) /* push movement already finished */
2299 element = Feld[next_jx][next_jy];
2300 gfx_frame = GfxFrame[next_jx][next_jy];
2303 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2306 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
2307 frame = getGraphicAnimationFrame(graphic, sync_frame);
2309 frame = getGraphicAnimationFrame(graphic, player->StepFrame);
2312 /* draw background element under pushed element (like the Sokoban field) */
2313 if (Back[next_jx][next_jy])
2314 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
2316 /* masked drawing is needed for EMC style (double) movement graphics */
2317 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
2321 /* ----------------------------------------------------------------------- */
2322 /* draw things in front of player (active dynamite or dynabombs) */
2323 /* ----------------------------------------------------------------------- */
2325 if (IS_ACTIVE_BOMB(element))
2327 graphic = el2img(element);
2328 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
2330 if (game.emulation == EMU_SUPAPLEX)
2331 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
2333 DrawGraphicThruMask(sx, sy, graphic, frame);
2336 if (player_is_moving && last_element == EL_EXPLOSION)
2338 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
2339 GfxElement[last_jx][last_jy] : EL_EMPTY);
2340 int graphic = el_act2img(element, ACTION_EXPLODING);
2341 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
2342 int phase = ExplodePhase[last_jx][last_jy] - 1;
2343 int frame = getGraphicAnimationFrame(graphic, phase - delay);
2346 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
2349 /* ----------------------------------------------------------------------- */
2350 /* draw elements the player is just walking/passing through/under */
2351 /* ----------------------------------------------------------------------- */
2353 if (player_is_moving)
2355 /* handle the field the player is leaving ... */
2356 if (IS_ACCESSIBLE_INSIDE(last_element))
2357 DrawLevelField(last_jx, last_jy);
2358 else if (IS_ACCESSIBLE_UNDER(last_element))
2359 DrawLevelFieldThruMask(last_jx, last_jy);
2362 /* do not redraw accessible elements if the player is just pushing them */
2363 if (!player_is_moving || !player->is_pushing)
2365 /* ... and the field the player is entering */
2366 if (IS_ACCESSIBLE_INSIDE(element))
2367 DrawLevelField(jx, jy);
2368 else if (IS_ACCESSIBLE_UNDER(element))
2369 DrawLevelFieldThruMask(jx, jy);
2372 if (setup.direct_draw)
2374 int dst_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
2375 int dst_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
2376 int x_size = TILEX * (1 + ABS(jx - last_jx));
2377 int y_size = TILEY * (1 + ABS(jy - last_jy));
2379 BlitBitmap(drawto_field, window,
2380 dst_x, dst_y, x_size, y_size, dst_x, dst_y);
2381 SetDrawtoField(DRAW_DIRECT);
2384 MarkTileDirty(sx, sy);
2387 /* ------------------------------------------------------------------------- */
2389 void WaitForEventToContinue()
2391 boolean still_wait = TRUE;
2393 /* simulate releasing mouse button over last gadget, if still pressed */
2395 HandleGadgets(-1, -1, 0);
2397 button_status = MB_RELEASED;
2413 case EVENT_BUTTONPRESS:
2414 case EVENT_KEYPRESS:
2418 case EVENT_KEYRELEASE:
2419 ClearPlayerAction();
2423 HandleOtherEvents(&event);
2427 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2434 /* don't eat all CPU time */
2439 #define MAX_REQUEST_LINES 13
2440 #define MAX_REQUEST_LINE_FONT1_LEN 7
2441 #define MAX_REQUEST_LINE_FONT2_LEN 10
2443 boolean Request(char *text, unsigned int req_state)
2445 int mx, my, ty, result = -1;
2446 unsigned int old_door_state;
2447 int last_game_status = game_status; /* save current game status */
2448 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
2449 int font_nr = FONT_TEXT_2;
2450 int max_word_len = 0;
2453 for (text_ptr = text; *text_ptr; text_ptr++)
2455 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
2457 if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
2459 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
2460 font_nr = FONT_LEVEL_NUMBER;
2466 if (game_status == GAME_MODE_PLAYING &&
2467 level.game_engine_type == GAME_ENGINE_TYPE_EM)
2468 BlitScreenToBitmap_EM(backbuffer);
2470 /* disable deactivated drawing when quick-loading level tape recording */
2471 if (tape.playing && tape.deactivate_display)
2472 TapeDeactivateDisplayOff(TRUE);
2474 SetMouseCursor(CURSOR_DEFAULT);
2476 #if defined(NETWORK_AVALIABLE)
2477 /* pause network game while waiting for request to answer */
2478 if (options.network &&
2479 game_status == GAME_MODE_PLAYING &&
2480 req_state & REQUEST_WAIT_FOR_INPUT)
2481 SendToServer_PausePlaying();
2484 old_door_state = GetDoorState();
2486 /* simulate releasing mouse button over last gadget, if still pressed */
2488 HandleGadgets(-1, -1, 0);
2492 if (old_door_state & DOOR_OPEN_1)
2494 CloseDoor(DOOR_CLOSE_1);
2496 /* save old door content */
2497 BlitBitmap(bitmap_db_door, bitmap_db_door,
2498 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2499 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
2503 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2506 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2508 /* clear door drawing field */
2509 DrawBackground(DX, DY, DXSIZE, DYSIZE);
2511 /* force DOOR font on preview level */
2512 game_status = GAME_MODE_PSEUDO_DOOR;
2514 /* write text for request */
2515 for (ty = 0; ty < MAX_REQUEST_LINES; ty++)
2517 char text_line[max_request_line_len + 1];
2523 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
2526 if (!tc || tc == ' ')
2537 strncpy(text_line, text, tl);
2540 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
2541 DY + 8 + ty * (getFontHeight(font_nr) + 2),
2542 text_line, font_nr);
2544 text += tl + (tc == ' ' ? 1 : 0);
2547 game_status = last_game_status; /* restore current game status */
2549 if (req_state & REQ_ASK)
2551 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2552 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2554 else if (req_state & REQ_CONFIRM)
2556 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2558 else if (req_state & REQ_PLAYER)
2560 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2561 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2562 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2563 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2566 /* copy request gadgets to door backbuffer */
2567 BlitBitmap(drawto, bitmap_db_door,
2568 DX, DY, DXSIZE, DYSIZE,
2569 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2571 OpenDoor(DOOR_OPEN_1);
2573 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
2575 if (game_status == GAME_MODE_PLAYING)
2577 SetPanelBackground();
2578 SetDrawBackgroundMask(REDRAW_DOOR_1);
2582 SetDrawBackgroundMask(REDRAW_FIELD);
2588 if (game_status != GAME_MODE_MAIN)
2591 button_status = MB_RELEASED;
2593 request_gadget_id = -1;
2595 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2607 case EVENT_BUTTONPRESS:
2608 case EVENT_BUTTONRELEASE:
2609 case EVENT_MOTIONNOTIFY:
2611 if (event.type == EVENT_MOTIONNOTIFY)
2613 if (!PointerInWindow(window))
2614 continue; /* window and pointer are on different screens */
2619 motion_status = TRUE;
2620 mx = ((MotionEvent *) &event)->x;
2621 my = ((MotionEvent *) &event)->y;
2625 motion_status = FALSE;
2626 mx = ((ButtonEvent *) &event)->x;
2627 my = ((ButtonEvent *) &event)->y;
2628 if (event.type == EVENT_BUTTONPRESS)
2629 button_status = ((ButtonEvent *) &event)->button;
2631 button_status = MB_RELEASED;
2634 /* this sets 'request_gadget_id' */
2635 HandleGadgets(mx, my, button_status);
2637 switch(request_gadget_id)
2639 case TOOL_CTRL_ID_YES:
2642 case TOOL_CTRL_ID_NO:
2645 case TOOL_CTRL_ID_CONFIRM:
2646 result = TRUE | FALSE;
2649 case TOOL_CTRL_ID_PLAYER_1:
2652 case TOOL_CTRL_ID_PLAYER_2:
2655 case TOOL_CTRL_ID_PLAYER_3:
2658 case TOOL_CTRL_ID_PLAYER_4:
2669 case EVENT_KEYPRESS:
2670 switch(GetEventKey((KeyEvent *)&event, TRUE))
2683 if (req_state & REQ_PLAYER)
2687 case EVENT_KEYRELEASE:
2688 ClearPlayerAction();
2692 HandleOtherEvents(&event);
2696 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2698 int joy = AnyJoystick();
2700 if (joy & JOY_BUTTON_1)
2702 else if (joy & JOY_BUTTON_2)
2709 if (!PendingEvent()) /* delay only if no pending events */
2712 /* don't eat all CPU time */
2717 if (game_status != GAME_MODE_MAIN)
2722 if (!(req_state & REQ_STAY_OPEN))
2724 CloseDoor(DOOR_CLOSE_1);
2726 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
2727 (req_state & REQ_REOPEN))
2728 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
2733 if (game_status == GAME_MODE_PLAYING)
2735 SetPanelBackground();
2736 SetDrawBackgroundMask(REDRAW_DOOR_1);
2740 SetDrawBackgroundMask(REDRAW_FIELD);
2743 #if defined(NETWORK_AVALIABLE)
2744 /* continue network game after request */
2745 if (options.network &&
2746 game_status == GAME_MODE_PLAYING &&
2747 req_state & REQUEST_WAIT_FOR_INPUT)
2748 SendToServer_ContinuePlaying();
2751 /* restore deactivated drawing when quick-loading level tape recording */
2752 if (tape.playing && tape.deactivate_display)
2753 TapeDeactivateDisplayOn();
2758 unsigned int OpenDoor(unsigned int door_state)
2760 if (door_state & DOOR_COPY_BACK)
2762 if (door_state & DOOR_OPEN_1)
2763 BlitBitmap(bitmap_db_door, bitmap_db_door,
2764 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2765 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2767 if (door_state & DOOR_OPEN_2)
2768 BlitBitmap(bitmap_db_door, bitmap_db_door,
2769 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
2770 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2772 door_state &= ~DOOR_COPY_BACK;
2775 return MoveDoor(door_state);
2778 unsigned int CloseDoor(unsigned int door_state)
2780 unsigned int old_door_state = GetDoorState();
2782 if (!(door_state & DOOR_NO_COPY_BACK))
2784 if (old_door_state & DOOR_OPEN_1)
2785 BlitBitmap(backbuffer, bitmap_db_door,
2786 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2788 if (old_door_state & DOOR_OPEN_2)
2789 BlitBitmap(backbuffer, bitmap_db_door,
2790 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2792 door_state &= ~DOOR_NO_COPY_BACK;
2795 return MoveDoor(door_state);
2798 unsigned int GetDoorState()
2800 return MoveDoor(DOOR_GET_STATE);
2803 unsigned int SetDoorState(unsigned int door_state)
2805 return MoveDoor(door_state | DOOR_SET_STATE);
2808 unsigned int MoveDoor(unsigned int door_state)
2810 static int door1 = DOOR_OPEN_1;
2811 static int door2 = DOOR_CLOSE_2;
2812 unsigned long door_delay = 0;
2813 unsigned long door_delay_value;
2816 if (door_1.width < 0 || door_1.width > DXSIZE)
2817 door_1.width = DXSIZE;
2818 if (door_1.height < 0 || door_1.height > DYSIZE)
2819 door_1.height = DYSIZE;
2820 if (door_2.width < 0 || door_2.width > VXSIZE)
2821 door_2.width = VXSIZE;
2822 if (door_2.height < 0 || door_2.height > VYSIZE)
2823 door_2.height = VYSIZE;
2825 if (door_state == DOOR_GET_STATE)
2826 return (door1 | door2);
2828 if (door_state & DOOR_SET_STATE)
2830 if (door_state & DOOR_ACTION_1)
2831 door1 = door_state & DOOR_ACTION_1;
2832 if (door_state & DOOR_ACTION_2)
2833 door2 = door_state & DOOR_ACTION_2;
2835 return (door1 | door2);
2838 if (!(door_state & DOOR_FORCE_REDRAW))
2840 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2841 door_state &= ~DOOR_OPEN_1;
2842 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2843 door_state &= ~DOOR_CLOSE_1;
2844 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2845 door_state &= ~DOOR_OPEN_2;
2846 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2847 door_state &= ~DOOR_CLOSE_2;
2850 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
2853 if (setup.quick_doors)
2855 stepsize = 20; /* must be choosen to always draw last frame */
2856 door_delay_value = 0;
2859 if (global.autoplay_leveldir)
2861 door_state |= DOOR_NO_DELAY;
2862 door_state &= ~DOOR_CLOSE_ALL;
2865 if (door_state & DOOR_ACTION)
2867 boolean handle_door_1 = (door_state & DOOR_ACTION_1);
2868 boolean handle_door_2 = (door_state & DOOR_ACTION_2);
2869 boolean door_1_done = (!handle_door_1);
2870 boolean door_2_done = (!handle_door_2);
2871 boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
2872 boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
2873 int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
2874 int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
2875 int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
2876 int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
2877 int door_size = (handle_door_1 ? door_size_1 : door_size_2);
2878 int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
2879 int door_skip = max_door_size - door_size;
2880 int end = door_size;
2881 int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
2884 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
2886 /* opening door sound has priority over simultaneously closing door */
2887 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2888 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2889 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2890 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2893 for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
2896 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2897 GC gc = bitmap->stored_clip_gc;
2899 if (door_state & DOOR_ACTION_1)
2901 int a = MIN(x * door_1.step_offset, end);
2902 int p = (door_state & DOOR_OPEN_1 ? end - a : a);
2903 int i = p + door_skip;
2905 if (door_1.anim_mode & ANIM_STATIC_PANEL)
2907 BlitBitmap(bitmap_db_door, drawto,
2908 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
2909 DXSIZE, DYSIZE, DX, DY);
2913 BlitBitmap(bitmap_db_door, drawto,
2914 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
2915 DXSIZE, DYSIZE - p / 2, DX, DY);
2917 ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
2920 if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
2922 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2923 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
2924 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
2925 int dst2_x = DX, dst2_y = DY;
2926 int width = i, height = DYSIZE;
2928 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2929 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2932 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2933 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2936 else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
2938 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2939 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
2940 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
2941 int dst2_x = DX, dst2_y = DY;
2942 int width = DXSIZE, height = i;
2944 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2945 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2948 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2949 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2952 else if (x <= DXSIZE) /* ANIM_DEFAULT */
2954 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
2956 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2957 BlitBitmapMasked(bitmap, drawto,
2958 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2959 DX + DXSIZE - i, DY + j);
2960 BlitBitmapMasked(bitmap, drawto,
2961 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2962 DX + DXSIZE - i, DY + 140 + j);
2963 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
2964 DY - (DOOR_GFX_PAGEY1 + j));
2965 BlitBitmapMasked(bitmap, drawto,
2966 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2968 BlitBitmapMasked(bitmap, drawto,
2969 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
2972 BlitBitmapMasked(bitmap, drawto,
2973 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2975 BlitBitmapMasked(bitmap, drawto,
2976 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2978 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2979 BlitBitmapMasked(bitmap, drawto,
2980 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2981 DX + DXSIZE - i, DY + 77 + j);
2982 BlitBitmapMasked(bitmap, drawto,
2983 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2984 DX + DXSIZE - i, DY + 203 + j);
2987 redraw_mask |= REDRAW_DOOR_1;
2988 door_1_done = (a == end);
2991 if (door_state & DOOR_ACTION_2)
2993 int a = MIN(x * door_2.step_offset, door_size);
2994 int p = (door_state & DOOR_OPEN_2 ? door_size - a : a);
2995 int i = p + door_skip;
2997 if (door_2.anim_mode & ANIM_STATIC_PANEL)
2999 BlitBitmap(bitmap_db_door, drawto,
3000 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
3001 VXSIZE, VYSIZE, VX, VY);
3003 else if (x <= VYSIZE)
3005 BlitBitmap(bitmap_db_door, drawto,
3006 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
3007 VXSIZE, VYSIZE - p / 2, VX, VY);
3009 ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
3012 if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
3014 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
3015 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
3016 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
3017 int dst2_x = VX, dst2_y = VY;
3018 int width = i, height = VYSIZE;
3020 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3021 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3024 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3025 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3028 else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
3030 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
3031 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
3032 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
3033 int dst2_x = VX, dst2_y = VY;
3034 int width = VXSIZE, height = i;
3036 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3037 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3040 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3041 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3044 else if (x <= VXSIZE) /* ANIM_DEFAULT */
3046 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
3048 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3049 BlitBitmapMasked(bitmap, drawto,
3050 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
3051 VX + VXSIZE - i, VY + j);
3052 SetClipOrigin(bitmap, gc,
3053 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
3054 BlitBitmapMasked(bitmap, drawto,
3055 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
3058 BlitBitmapMasked(bitmap, drawto,
3059 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3060 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
3061 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3062 BlitBitmapMasked(bitmap, drawto,
3063 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3065 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
3068 redraw_mask |= REDRAW_DOOR_2;
3069 door_2_done = (a == VXSIZE);
3072 if (!(door_state & DOOR_NO_DELAY))
3076 if (game_status == GAME_MODE_MAIN)
3079 WaitUntilDelayReached(&door_delay, door_delay_value);
3084 if (door_state & DOOR_ACTION_1)
3085 door1 = door_state & DOOR_ACTION_1;
3086 if (door_state & DOOR_ACTION_2)
3087 door2 = door_state & DOOR_ACTION_2;
3089 return (door1 | door2);
3092 void DrawSpecialEditorDoor()
3094 /* draw bigger toolbox window */
3095 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
3096 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
3098 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3099 EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
3102 redraw_mask |= REDRAW_ALL;
3105 void UndrawSpecialEditorDoor()
3107 /* draw normal tape recorder window */
3108 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3109 EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
3112 redraw_mask |= REDRAW_ALL;
3116 /* ---------- new tool button stuff ---------------------------------------- */
3118 /* graphic position values for tool buttons */
3119 #define TOOL_BUTTON_YES_XPOS 2
3120 #define TOOL_BUTTON_YES_YPOS 250
3121 #define TOOL_BUTTON_YES_GFX_YPOS 0
3122 #define TOOL_BUTTON_YES_XSIZE 46
3123 #define TOOL_BUTTON_YES_YSIZE 28
3124 #define TOOL_BUTTON_NO_XPOS 52
3125 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
3126 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
3127 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
3128 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
3129 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
3130 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
3131 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
3132 #define TOOL_BUTTON_CONFIRM_XSIZE 96
3133 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
3134 #define TOOL_BUTTON_PLAYER_XSIZE 30
3135 #define TOOL_BUTTON_PLAYER_YSIZE 30
3136 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
3137 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
3138 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
3139 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
3140 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3141 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3142 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3143 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3144 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3145 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3146 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3147 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3148 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3149 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3150 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3151 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3152 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3153 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3154 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3155 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3164 } toolbutton_info[NUM_TOOL_BUTTONS] =
3167 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
3168 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
3169 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
3174 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
3175 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
3176 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
3181 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
3182 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
3183 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
3184 TOOL_CTRL_ID_CONFIRM,
3188 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3189 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
3190 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3191 TOOL_CTRL_ID_PLAYER_1,
3195 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3196 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
3197 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3198 TOOL_CTRL_ID_PLAYER_2,
3202 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3203 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
3204 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3205 TOOL_CTRL_ID_PLAYER_3,
3209 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3210 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
3211 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3212 TOOL_CTRL_ID_PLAYER_4,
3217 void CreateToolButtons()
3221 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3223 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3224 Bitmap *deco_bitmap = None;
3225 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
3226 struct GadgetInfo *gi;
3227 unsigned long event_mask;
3228 int gd_xoffset, gd_yoffset;
3229 int gd_x1, gd_x2, gd_y;
3232 event_mask = GD_EVENT_RELEASED;
3234 gd_xoffset = toolbutton_info[i].xpos;
3235 gd_yoffset = toolbutton_info[i].ypos;
3236 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
3237 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
3238 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
3240 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
3242 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
3244 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
3245 &deco_bitmap, &deco_x, &deco_y);
3246 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
3247 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
3250 gi = CreateGadget(GDI_CUSTOM_ID, id,
3251 GDI_INFO_TEXT, toolbutton_info[i].infotext,
3252 GDI_X, DX + toolbutton_info[i].x,
3253 GDI_Y, DY + toolbutton_info[i].y,
3254 GDI_WIDTH, toolbutton_info[i].width,
3255 GDI_HEIGHT, toolbutton_info[i].height,
3256 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
3257 GDI_STATE, GD_BUTTON_UNPRESSED,
3258 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
3259 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
3260 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
3261 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
3262 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
3263 GDI_DECORATION_SHIFTING, 1, 1,
3264 GDI_DIRECT_DRAW, FALSE,
3265 GDI_EVENT_MASK, event_mask,
3266 GDI_CALLBACK_ACTION, HandleToolButtons,
3270 Error(ERR_EXIT, "cannot create gadget");
3272 tool_gadget[id] = gi;
3276 void FreeToolButtons()
3280 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3281 FreeGadget(tool_gadget[i]);
3284 static void UnmapToolButtons()
3288 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3289 UnmapGadget(tool_gadget[i]);
3292 static void HandleToolButtons(struct GadgetInfo *gi)
3294 request_gadget_id = gi->custom_id;
3297 static struct Mapping_EM_to_RND_object
3300 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
3301 boolean is_backside; /* backside of moving element */
3307 em_object_mapping_list[] =
3310 Xblank, TRUE, FALSE,
3314 Yacid_splash_eB, FALSE, FALSE,
3315 EL_ACID_SPLASH_RIGHT, -1, -1
3318 Yacid_splash_wB, FALSE, FALSE,
3319 EL_ACID_SPLASH_LEFT, -1, -1
3322 #ifdef EM_ENGINE_BAD_ROLL
3324 Xstone_force_e, FALSE, FALSE,
3325 EL_ROCK, -1, MV_BIT_RIGHT
3328 Xstone_force_w, FALSE, FALSE,
3329 EL_ROCK, -1, MV_BIT_LEFT
3332 Xnut_force_e, FALSE, FALSE,
3333 EL_NUT, -1, MV_BIT_RIGHT
3336 Xnut_force_w, FALSE, FALSE,
3337 EL_NUT, -1, MV_BIT_LEFT
3340 Xspring_force_e, FALSE, FALSE,
3341 EL_SPRING, -1, MV_BIT_RIGHT
3344 Xspring_force_w, FALSE, FALSE,
3345 EL_SPRING, -1, MV_BIT_LEFT
3348 Xemerald_force_e, FALSE, FALSE,
3349 EL_EMERALD, -1, MV_BIT_RIGHT
3352 Xemerald_force_w, FALSE, FALSE,
3353 EL_EMERALD, -1, MV_BIT_LEFT
3356 Xdiamond_force_e, FALSE, FALSE,
3357 EL_DIAMOND, -1, MV_BIT_RIGHT
3360 Xdiamond_force_w, FALSE, FALSE,
3361 EL_DIAMOND, -1, MV_BIT_LEFT
3364 Xbomb_force_e, FALSE, FALSE,
3365 EL_BOMB, -1, MV_BIT_RIGHT
3368 Xbomb_force_w, FALSE, FALSE,
3369 EL_BOMB, -1, MV_BIT_LEFT
3371 #endif /* EM_ENGINE_BAD_ROLL */
3374 Xstone, TRUE, FALSE,
3378 Xstone_pause, FALSE, FALSE,
3382 Xstone_fall, FALSE, FALSE,
3386 Ystone_s, FALSE, FALSE,
3387 EL_ROCK, ACTION_FALLING, -1
3390 Ystone_sB, FALSE, TRUE,
3391 EL_ROCK, ACTION_FALLING, -1
3394 Ystone_e, FALSE, FALSE,
3395 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3398 Ystone_eB, FALSE, TRUE,
3399 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3402 Ystone_w, FALSE, FALSE,
3403 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3406 Ystone_wB, FALSE, TRUE,
3407 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3414 Xnut_pause, FALSE, FALSE,
3418 Xnut_fall, FALSE, FALSE,
3422 Ynut_s, FALSE, FALSE,
3423 EL_NUT, ACTION_FALLING, -1
3426 Ynut_sB, FALSE, TRUE,
3427 EL_NUT, ACTION_FALLING, -1
3430 Ynut_e, FALSE, FALSE,
3431 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3434 Ynut_eB, FALSE, TRUE,
3435 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3438 Ynut_w, FALSE, FALSE,
3439 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3442 Ynut_wB, FALSE, TRUE,
3443 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3446 Xbug_n, TRUE, FALSE,
3450 Xbug_e, TRUE, FALSE,
3451 EL_BUG_RIGHT, -1, -1
3454 Xbug_s, TRUE, FALSE,
3458 Xbug_w, TRUE, FALSE,
3462 Xbug_gon, FALSE, FALSE,
3466 Xbug_goe, FALSE, FALSE,
3467 EL_BUG_RIGHT, -1, -1
3470 Xbug_gos, FALSE, FALSE,
3474 Xbug_gow, FALSE, FALSE,
3478 Ybug_n, FALSE, FALSE,
3479 EL_BUG, ACTION_MOVING, MV_BIT_UP
3482 Ybug_nB, FALSE, TRUE,
3483 EL_BUG, ACTION_MOVING, MV_BIT_UP
3486 Ybug_e, FALSE, FALSE,
3487 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3490 Ybug_eB, FALSE, TRUE,
3491 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3494 Ybug_s, FALSE, FALSE,
3495 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3498 Ybug_sB, FALSE, TRUE,
3499 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3502 Ybug_w, FALSE, FALSE,
3503 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3506 Ybug_wB, FALSE, TRUE,
3507 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3510 Ybug_w_n, FALSE, FALSE,
3511 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3514 Ybug_n_e, FALSE, FALSE,
3515 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3518 Ybug_e_s, FALSE, FALSE,
3519 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3522 Ybug_s_w, FALSE, FALSE,
3523 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3526 Ybug_e_n, FALSE, FALSE,
3527 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3530 Ybug_s_e, FALSE, FALSE,
3531 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3534 Ybug_w_s, FALSE, FALSE,
3535 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3538 Ybug_n_w, FALSE, FALSE,
3539 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3542 Ybug_stone, FALSE, FALSE,
3543 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
3546 Ybug_spring, FALSE, FALSE,
3547 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
3550 Xtank_n, TRUE, FALSE,
3551 EL_SPACESHIP_UP, -1, -1
3554 Xtank_e, TRUE, FALSE,
3555 EL_SPACESHIP_RIGHT, -1, -1
3558 Xtank_s, TRUE, FALSE,
3559 EL_SPACESHIP_DOWN, -1, -1
3562 Xtank_w, TRUE, FALSE,
3563 EL_SPACESHIP_LEFT, -1, -1
3566 Xtank_gon, FALSE, FALSE,
3567 EL_SPACESHIP_UP, -1, -1
3570 Xtank_goe, FALSE, FALSE,
3571 EL_SPACESHIP_RIGHT, -1, -1
3574 Xtank_gos, FALSE, FALSE,
3575 EL_SPACESHIP_DOWN, -1, -1
3578 Xtank_gow, FALSE, FALSE,
3579 EL_SPACESHIP_LEFT, -1, -1
3582 Ytank_n, FALSE, FALSE,
3583 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3586 Ytank_nB, FALSE, TRUE,
3587 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3590 Ytank_e, FALSE, FALSE,
3591 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3594 Ytank_eB, FALSE, TRUE,
3595 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3598 Ytank_s, FALSE, FALSE,
3599 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3602 Ytank_sB, FALSE, TRUE,
3603 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3606 Ytank_w, FALSE, FALSE,
3607 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3610 Ytank_wB, FALSE, TRUE,
3611 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3614 Ytank_w_n, FALSE, FALSE,
3615 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3618 Ytank_n_e, FALSE, FALSE,
3619 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3622 Ytank_e_s, FALSE, FALSE,
3623 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3626 Ytank_s_w, FALSE, FALSE,
3627 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3630 Ytank_e_n, FALSE, FALSE,
3631 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3634 Ytank_s_e, FALSE, FALSE,
3635 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3638 Ytank_w_s, FALSE, FALSE,
3639 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3642 Ytank_n_w, FALSE, FALSE,
3643 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3646 Ytank_stone, FALSE, FALSE,
3647 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
3650 Ytank_spring, FALSE, FALSE,
3651 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
3654 Xandroid, TRUE, FALSE,
3655 EL_EMC_ANDROID, ACTION_ACTIVE, -1
3658 Xandroid_1_n, FALSE, FALSE,
3659 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3662 Xandroid_2_n, FALSE, FALSE,
3663 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3666 Xandroid_1_e, FALSE, FALSE,
3667 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3670 Xandroid_2_e, FALSE, FALSE,
3671 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3674 Xandroid_1_w, FALSE, FALSE,
3675 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3678 Xandroid_2_w, FALSE, FALSE,
3679 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3682 Xandroid_1_s, FALSE, FALSE,
3683 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3686 Xandroid_2_s, FALSE, FALSE,
3687 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3690 Yandroid_n, FALSE, FALSE,
3691 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3694 Yandroid_nB, FALSE, TRUE,
3695 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3698 Yandroid_ne, FALSE, FALSE,
3699 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
3702 Yandroid_neB, FALSE, TRUE,
3703 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
3706 Yandroid_e, FALSE, FALSE,
3707 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
3710 Yandroid_eB, FALSE, TRUE,
3711 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
3714 Yandroid_se, FALSE, FALSE,
3715 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
3718 Yandroid_seB, FALSE, TRUE,
3719 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
3722 Yandroid_s, FALSE, FALSE,
3723 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
3726 Yandroid_sB, FALSE, TRUE,
3727 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
3730 Yandroid_sw, FALSE, FALSE,
3731 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
3734 Yandroid_swB, FALSE, TRUE,
3735 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
3738 Yandroid_w, FALSE, FALSE,
3739 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
3742 Yandroid_wB, FALSE, TRUE,
3743 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
3746 Yandroid_nw, FALSE, FALSE,
3747 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
3750 Yandroid_nwB, FALSE, TRUE,
3751 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
3754 Xspring, TRUE, FALSE,
3758 Xspring_pause, FALSE, FALSE,
3762 Xspring_e, FALSE, FALSE,
3766 Xspring_w, FALSE, FALSE,
3770 Xspring_fall, FALSE, FALSE,
3774 Yspring_s, FALSE, FALSE,
3775 EL_SPRING, ACTION_FALLING, -1
3778 Yspring_sB, FALSE, TRUE,
3779 EL_SPRING, ACTION_FALLING, -1
3782 Yspring_e, FALSE, FALSE,
3783 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
3786 Yspring_eB, FALSE, TRUE,
3787 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
3790 Yspring_w, FALSE, FALSE,
3791 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
3794 Yspring_wB, FALSE, TRUE,
3795 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
3798 Yspring_kill_e, FALSE, FALSE,
3799 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
3802 Yspring_kill_eB, FALSE, TRUE,
3803 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
3806 Yspring_kill_w, FALSE, FALSE,
3807 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
3810 Yspring_kill_wB, FALSE, TRUE,
3811 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
3814 Xeater_n, TRUE, FALSE,
3815 EL_YAMYAM_UP, -1, -1
3818 Xeater_e, TRUE, FALSE,
3819 EL_YAMYAM_RIGHT, -1, -1
3822 Xeater_w, TRUE, FALSE,
3823 EL_YAMYAM_LEFT, -1, -1
3826 Xeater_s, TRUE, FALSE,
3827 EL_YAMYAM_DOWN, -1, -1
3830 Yeater_n, FALSE, FALSE,
3831 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
3834 Yeater_nB, FALSE, TRUE,
3835 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
3838 Yeater_e, FALSE, FALSE,
3839 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
3842 Yeater_eB, FALSE, TRUE,
3843 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
3846 Yeater_s, FALSE, FALSE,
3847 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
3850 Yeater_sB, FALSE, TRUE,
3851 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
3854 Yeater_w, FALSE, FALSE,
3855 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
3858 Yeater_wB, FALSE, TRUE,
3859 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
3862 Yeater_stone, FALSE, FALSE,
3863 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
3866 Yeater_spring, FALSE, FALSE,
3867 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
3870 Xalien, TRUE, FALSE,
3874 Xalien_pause, FALSE, FALSE,
3878 Yalien_n, FALSE, FALSE,
3879 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
3882 Yalien_nB, FALSE, TRUE,
3883 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
3886 Yalien_e, FALSE, FALSE,
3887 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
3890 Yalien_eB, FALSE, TRUE,
3891 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
3894 Yalien_s, FALSE, FALSE,
3895 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
3898 Yalien_sB, FALSE, TRUE,
3899 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
3902 Yalien_w, FALSE, FALSE,
3903 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
3906 Yalien_wB, FALSE, TRUE,
3907 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
3910 Yalien_stone, FALSE, FALSE,
3911 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
3914 Yalien_spring, FALSE, FALSE,
3915 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
3918 Xemerald, TRUE, FALSE,
3922 Xemerald_pause, FALSE, FALSE,
3926 Xemerald_fall, FALSE, FALSE,
3930 Xemerald_shine, FALSE, FALSE,
3931 EL_EMERALD, ACTION_TWINKLING, -1
3934 Yemerald_s, FALSE, FALSE,
3935 EL_EMERALD, ACTION_FALLING, -1
3938 Yemerald_sB, FALSE, TRUE,
3939 EL_EMERALD, ACTION_FALLING, -1
3942 Yemerald_e, FALSE, FALSE,
3943 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
3946 Yemerald_eB, FALSE, TRUE,
3947 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
3950 Yemerald_w, FALSE, FALSE,
3951 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
3954 Yemerald_wB, FALSE, TRUE,
3955 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
3958 Yemerald_eat, FALSE, FALSE,
3959 EL_EMERALD, ACTION_COLLECTING, -1
3962 Yemerald_stone, FALSE, FALSE,
3963 EL_NUT, ACTION_BREAKING, -1
3966 Xdiamond, TRUE, FALSE,
3970 Xdiamond_pause, FALSE, FALSE,
3974 Xdiamond_fall, FALSE, FALSE,
3978 Xdiamond_shine, FALSE, FALSE,
3979 EL_DIAMOND, ACTION_TWINKLING, -1
3982 Ydiamond_s, FALSE, FALSE,
3983 EL_DIAMOND, ACTION_FALLING, -1
3986 Ydiamond_sB, FALSE, TRUE,
3987 EL_DIAMOND, ACTION_FALLING, -1
3990 Ydiamond_e, FALSE, FALSE,
3991 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
3994 Ydiamond_eB, FALSE, TRUE,
3995 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
3998 Ydiamond_w, FALSE, FALSE,
3999 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
4002 Ydiamond_wB, FALSE, TRUE,
4003 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
4006 Ydiamond_eat, FALSE, FALSE,
4007 EL_DIAMOND, ACTION_COLLECTING, -1
4010 Ydiamond_stone, FALSE, FALSE,
4011 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
4014 Xdrip_fall, TRUE, FALSE,
4015 EL_AMOEBA_DROP, -1, -1
4018 Xdrip_stretch, FALSE, FALSE,
4019 EL_AMOEBA_DROP, ACTION_FALLING, -1
4022 Xdrip_stretchB, FALSE, TRUE,
4023 EL_AMOEBA_DROP, ACTION_FALLING, -1
4026 Xdrip_eat, FALSE, FALSE,
4027 EL_AMOEBA_DROP, ACTION_GROWING, -1
4030 Ydrip_s1, FALSE, FALSE,
4031 EL_AMOEBA_DROP, ACTION_FALLING, -1
4034 Ydrip_s1B, FALSE, TRUE,
4035 EL_AMOEBA_DROP, ACTION_FALLING, -1
4038 Ydrip_s2, FALSE, FALSE,
4039 EL_AMOEBA_DROP, ACTION_FALLING, -1
4042 Ydrip_s2B, FALSE, TRUE,
4043 EL_AMOEBA_DROP, ACTION_FALLING, -1
4050 Xbomb_pause, FALSE, FALSE,
4054 Xbomb_fall, FALSE, FALSE,
4058 Ybomb_s, FALSE, FALSE,
4059 EL_BOMB, ACTION_FALLING, -1
4062 Ybomb_sB, FALSE, TRUE,
4063 EL_BOMB, ACTION_FALLING, -1
4066 Ybomb_e, FALSE, FALSE,
4067 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
4070 Ybomb_eB, FALSE, TRUE,
4071 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
4074 Ybomb_w, FALSE, FALSE,
4075 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
4078 Ybomb_wB, FALSE, TRUE,
4079 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
4082 Ybomb_eat, FALSE, FALSE,
4083 EL_BOMB, ACTION_ACTIVATING, -1
4086 Xballoon, TRUE, FALSE,
4090 Yballoon_n, FALSE, FALSE,
4091 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
4094 Yballoon_nB, FALSE, TRUE,
4095 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
4098 Yballoon_e, FALSE, FALSE,
4099 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
4102 Yballoon_eB, FALSE, TRUE,
4103 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
4106 Yballoon_s, FALSE, FALSE,
4107 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
4110 Yballoon_sB, FALSE, TRUE,
4111 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
4114 Yballoon_w, FALSE, FALSE,
4115 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
4118 Yballoon_wB, FALSE, TRUE,
4119 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
4122 Xgrass, TRUE, FALSE,
4123 EL_EMC_GRASS, -1, -1
4126 Ygrass_nB, FALSE, FALSE,
4127 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
4130 Ygrass_eB, FALSE, FALSE,
4131 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
4134 Ygrass_sB, FALSE, FALSE,
4135 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
4138 Ygrass_wB, FALSE, FALSE,
4139 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
4146 Ydirt_nB, FALSE, FALSE,
4147 EL_SAND, ACTION_DIGGING, MV_BIT_UP
4150 Ydirt_eB, FALSE, FALSE,
4151 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
4154 Ydirt_sB, FALSE, FALSE,
4155 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
4158 Ydirt_wB, FALSE, FALSE,
4159 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
4162 Xacid_ne, TRUE, FALSE,
4163 EL_ACID_POOL_TOPRIGHT, -1, -1
4166 Xacid_se, TRUE, FALSE,
4167 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
4170 Xacid_s, TRUE, FALSE,
4171 EL_ACID_POOL_BOTTOM, -1, -1
4174 Xacid_sw, TRUE, FALSE,
4175 EL_ACID_POOL_BOTTOMLEFT, -1, -1
4178 Xacid_nw, TRUE, FALSE,
4179 EL_ACID_POOL_TOPLEFT, -1, -1
4182 Xacid_1, TRUE, FALSE,
4186 Xacid_2, FALSE, FALSE,
4190 Xacid_3, FALSE, FALSE,
4194 Xacid_4, FALSE, FALSE,
4198 Xacid_5, FALSE, FALSE,
4202 Xacid_6, FALSE, FALSE,
4206 Xacid_7, FALSE, FALSE,
4210 Xacid_8, FALSE, FALSE,
4214 Xball_1, TRUE, FALSE,
4215 EL_EMC_MAGIC_BALL, -1, -1
4218 Xball_1B, FALSE, FALSE,
4219 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4222 Xball_2, FALSE, FALSE,
4223 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4226 Xball_2B, FALSE, FALSE,
4227 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4230 Yball_eat, FALSE, FALSE,
4231 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
4234 Ykey_1_eat, FALSE, FALSE,
4235 EL_EM_KEY_1, ACTION_COLLECTING, -1
4238 Ykey_2_eat, FALSE, FALSE,
4239 EL_EM_KEY_2, ACTION_COLLECTING, -1
4242 Ykey_3_eat, FALSE, FALSE,
4243 EL_EM_KEY_3, ACTION_COLLECTING, -1
4246 Ykey_4_eat, FALSE, FALSE,
4247 EL_EM_KEY_4, ACTION_COLLECTING, -1
4250 Ykey_5_eat, FALSE, FALSE,
4251 EL_EMC_KEY_5, ACTION_COLLECTING, -1
4254 Ykey_6_eat, FALSE, FALSE,
4255 EL_EMC_KEY_6, ACTION_COLLECTING, -1
4258 Ykey_7_eat, FALSE, FALSE,
4259 EL_EMC_KEY_7, ACTION_COLLECTING, -1
4262 Ykey_8_eat, FALSE, FALSE,
4263 EL_EMC_KEY_8, ACTION_COLLECTING, -1
4266 Ylenses_eat, FALSE, FALSE,
4267 EL_EMC_LENSES, ACTION_COLLECTING, -1
4270 Ymagnify_eat, FALSE, FALSE,
4271 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
4274 Ygrass_eat, FALSE, FALSE,
4275 EL_EMC_GRASS, ACTION_SNAPPING, -1
4278 Ydirt_eat, FALSE, FALSE,
4279 EL_SAND, ACTION_SNAPPING, -1
4282 Xgrow_ns, TRUE, FALSE,
4283 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
4286 Ygrow_ns_eat, FALSE, FALSE,
4287 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
4290 Xgrow_ew, TRUE, FALSE,
4291 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
4294 Ygrow_ew_eat, FALSE, FALSE,
4295 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
4298 Xwonderwall, TRUE, FALSE,
4299 EL_MAGIC_WALL, -1, -1
4302 XwonderwallB, FALSE, FALSE,
4303 EL_MAGIC_WALL, ACTION_ACTIVE, -1
4306 Xamoeba_1, TRUE, FALSE,
4307 EL_AMOEBA_DRY, ACTION_OTHER, -1
4310 Xamoeba_2, FALSE, FALSE,
4311 EL_AMOEBA_DRY, ACTION_OTHER, -1
4314 Xamoeba_3, FALSE, FALSE,
4315 EL_AMOEBA_DRY, ACTION_OTHER, -1
4318 Xamoeba_4, FALSE, FALSE,
4319 EL_AMOEBA_DRY, ACTION_OTHER, -1
4322 Xamoeba_5, TRUE, FALSE,
4323 EL_AMOEBA_WET, ACTION_OTHER, -1
4326 Xamoeba_6, FALSE, FALSE,
4327 EL_AMOEBA_WET, ACTION_OTHER, -1
4330 Xamoeba_7, FALSE, FALSE,
4331 EL_AMOEBA_WET, ACTION_OTHER, -1
4334 Xamoeba_8, FALSE, FALSE,
4335 EL_AMOEBA_WET, ACTION_OTHER, -1
4338 Xdoor_1, TRUE, FALSE,
4339 EL_EM_GATE_1, -1, -1
4342 Xdoor_2, TRUE, FALSE,
4343 EL_EM_GATE_2, -1, -1
4346 Xdoor_3, TRUE, FALSE,
4347 EL_EM_GATE_3, -1, -1
4350 Xdoor_4, TRUE, FALSE,
4351 EL_EM_GATE_4, -1, -1
4354 Xdoor_5, TRUE, FALSE,
4355 EL_EMC_GATE_5, -1, -1
4358 Xdoor_6, TRUE, FALSE,
4359 EL_EMC_GATE_6, -1, -1
4362 Xdoor_7, TRUE, FALSE,
4363 EL_EMC_GATE_7, -1, -1
4366 Xdoor_8, TRUE, FALSE,
4367 EL_EMC_GATE_8, -1, -1
4370 Xkey_1, TRUE, FALSE,
4374 Xkey_2, TRUE, FALSE,
4378 Xkey_3, TRUE, FALSE,
4382 Xkey_4, TRUE, FALSE,
4386 Xkey_5, TRUE, FALSE,
4387 EL_EMC_KEY_5, -1, -1
4390 Xkey_6, TRUE, FALSE,
4391 EL_EMC_KEY_6, -1, -1
4394 Xkey_7, TRUE, FALSE,
4395 EL_EMC_KEY_7, -1, -1
4398 Xkey_8, TRUE, FALSE,
4399 EL_EMC_KEY_8, -1, -1
4402 Xwind_n, TRUE, FALSE,
4403 EL_BALLOON_SWITCH_UP, -1, -1
4406 Xwind_e, TRUE, FALSE,
4407 EL_BALLOON_SWITCH_RIGHT, -1, -1
4410 Xwind_s, TRUE, FALSE,
4411 EL_BALLOON_SWITCH_DOWN, -1, -1
4414 Xwind_w, TRUE, FALSE,
4415 EL_BALLOON_SWITCH_LEFT, -1, -1
4418 Xwind_nesw, TRUE, FALSE,
4419 EL_BALLOON_SWITCH_ANY, -1, -1
4422 Xwind_stop, TRUE, FALSE,
4423 EL_BALLOON_SWITCH_NONE, -1, -1
4427 EL_EXIT_CLOSED, -1, -1
4430 Xexit_1, TRUE, FALSE,
4431 EL_EXIT_OPEN, -1, -1
4434 Xexit_2, FALSE, FALSE,
4435 EL_EXIT_OPEN, -1, -1
4438 Xexit_3, FALSE, FALSE,
4439 EL_EXIT_OPEN, -1, -1
4442 Xdynamite, TRUE, FALSE,
4443 EL_EM_DYNAMITE, -1, -1
4446 Ydynamite_eat, FALSE, FALSE,
4447 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
4450 Xdynamite_1, TRUE, FALSE,
4451 EL_EM_DYNAMITE_ACTIVE, -1, -1
4454 Xdynamite_2, FALSE, FALSE,
4455 EL_EM_DYNAMITE_ACTIVE, -1, -1
4458 Xdynamite_3, FALSE, FALSE,
4459 EL_EM_DYNAMITE_ACTIVE, -1, -1
4462 Xdynamite_4, FALSE, FALSE,
4463 EL_EM_DYNAMITE_ACTIVE, -1, -1
4466 Xbumper, TRUE, FALSE,
4467 EL_EMC_SPRING_BUMPER, -1, -1
4470 XbumperB, FALSE, FALSE,
4471 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
4474 Xwheel, TRUE, FALSE,
4475 EL_ROBOT_WHEEL, -1, -1
4478 XwheelB, FALSE, FALSE,
4479 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
4482 Xswitch, TRUE, FALSE,
4483 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
4486 XswitchB, FALSE, FALSE,
4487 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
4491 EL_QUICKSAND_EMPTY, -1, -1
4494 Xsand_stone, TRUE, FALSE,
4495 EL_QUICKSAND_FULL, -1, -1
4498 Xsand_stonein_1, FALSE, TRUE,
4499 EL_ROCK, ACTION_FILLING, -1
4502 Xsand_stonein_2, FALSE, TRUE,
4503 EL_ROCK, ACTION_FILLING, -1
4506 Xsand_stonein_3, FALSE, TRUE,
4507 EL_ROCK, ACTION_FILLING, -1
4510 Xsand_stonein_4, FALSE, TRUE,
4511 EL_ROCK, ACTION_FILLING, -1
4514 Xsand_stonesand_1, FALSE, FALSE,
4515 EL_QUICKSAND_FULL, -1, -1
4518 Xsand_stonesand_2, FALSE, FALSE,
4519 EL_QUICKSAND_FULL, -1, -1
4522 Xsand_stonesand_3, FALSE, FALSE,
4523 EL_QUICKSAND_FULL, -1, -1
4526 Xsand_stonesand_4, FALSE, FALSE,
4527 EL_QUICKSAND_FULL, -1, -1
4530 Xsand_stoneout_1, FALSE, FALSE,
4531 EL_ROCK, ACTION_EMPTYING, -1
4534 Xsand_stoneout_2, FALSE, FALSE,
4535 EL_ROCK, ACTION_EMPTYING, -1
4538 Xsand_sandstone_1, FALSE, FALSE,
4539 EL_QUICKSAND_FULL, -1, -1
4542 Xsand_sandstone_2, FALSE, FALSE,
4543 EL_QUICKSAND_FULL, -1, -1
4546 Xsand_sandstone_3, FALSE, FALSE,
4547 EL_QUICKSAND_FULL, -1, -1
4550 Xsand_sandstone_4, FALSE, FALSE,
4551 EL_QUICKSAND_FULL, -1, -1
4554 Xplant, TRUE, FALSE,
4555 EL_EMC_PLANT, -1, -1
4558 Yplant, FALSE, FALSE,
4559 EL_EMC_PLANT, -1, -1
4562 Xlenses, TRUE, FALSE,
4563 EL_EMC_LENSES, -1, -1
4566 Xmagnify, TRUE, FALSE,
4567 EL_EMC_MAGNIFIER, -1, -1
4570 Xdripper, TRUE, FALSE,
4571 EL_EMC_DRIPPER, -1, -1
4574 XdripperB, FALSE, FALSE,
4575 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
4578 Xfake_blank, TRUE, FALSE,
4579 EL_INVISIBLE_WALL, -1, -1
4582 Xfake_blankB, FALSE, FALSE,
4583 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
4586 Xfake_grass, TRUE, FALSE,
4587 EL_EMC_FAKE_GRASS, -1, -1
4590 Xfake_grassB, FALSE, FALSE,
4591 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
4594 Xfake_door_1, TRUE, FALSE,
4595 EL_EM_GATE_1_GRAY, -1, -1
4598 Xfake_door_2, TRUE, FALSE,
4599 EL_EM_GATE_2_GRAY, -1, -1
4602 Xfake_door_3, TRUE, FALSE,
4603 EL_EM_GATE_3_GRAY, -1, -1
4606 Xfake_door_4, TRUE, FALSE,
4607 EL_EM_GATE_4_GRAY, -1, -1
4610 Xfake_door_5, TRUE, FALSE,
4611 EL_EMC_GATE_5_GRAY, -1, -1
4614 Xfake_door_6, TRUE, FALSE,
4615 EL_EMC_GATE_6_GRAY, -1, -1
4618 Xfake_door_7, TRUE, FALSE,
4619 EL_EMC_GATE_7_GRAY, -1, -1
4622 Xfake_door_8, TRUE, FALSE,
4623 EL_EMC_GATE_8_GRAY, -1, -1
4626 Xfake_acid_1, TRUE, FALSE,
4627 EL_EMC_FAKE_ACID, -1, -1
4630 Xfake_acid_2, FALSE, FALSE,
4631 EL_EMC_FAKE_ACID, -1, -1
4634 Xfake_acid_3, FALSE, FALSE,
4635 EL_EMC_FAKE_ACID, -1, -1
4638 Xfake_acid_4, FALSE, FALSE,
4639 EL_EMC_FAKE_ACID, -1, -1
4642 Xfake_acid_5, FALSE, FALSE,
4643 EL_EMC_FAKE_ACID, -1, -1
4646 Xfake_acid_6, FALSE, FALSE,
4647 EL_EMC_FAKE_ACID, -1, -1
4650 Xfake_acid_7, FALSE, FALSE,
4651 EL_EMC_FAKE_ACID, -1, -1
4654 Xfake_acid_8, FALSE, FALSE,
4655 EL_EMC_FAKE_ACID, -1, -1
4658 Xsteel_1, TRUE, FALSE,
4659 EL_STEELWALL, -1, -1
4662 Xsteel_2, TRUE, FALSE,
4663 EL_EMC_STEELWALL_2, -1, -1
4666 Xsteel_3, TRUE, FALSE,
4667 EL_EMC_STEELWALL_3, -1, -1
4670 Xsteel_4, TRUE, FALSE,
4671 EL_EMC_STEELWALL_4, -1, -1
4674 Xwall_1, TRUE, FALSE,
4678 Xwall_2, TRUE, FALSE,
4679 EL_EMC_WALL_14, -1, -1
4682 Xwall_3, TRUE, FALSE,
4683 EL_EMC_WALL_15, -1, -1
4686 Xwall_4, TRUE, FALSE,
4687 EL_EMC_WALL_16, -1, -1
4690 Xround_wall_1, TRUE, FALSE,
4691 EL_WALL_SLIPPERY, -1, -1
4694 Xround_wall_2, TRUE, FALSE,
4695 EL_EMC_WALL_SLIPPERY_2, -1, -1
4698 Xround_wall_3, TRUE, FALSE,
4699 EL_EMC_WALL_SLIPPERY_3, -1, -1
4702 Xround_wall_4, TRUE, FALSE,
4703 EL_EMC_WALL_SLIPPERY_4, -1, -1
4706 Xdecor_1, TRUE, FALSE,
4707 EL_EMC_WALL_8, -1, -1
4710 Xdecor_2, TRUE, FALSE,
4711 EL_EMC_WALL_6, -1, -1
4714 Xdecor_3, TRUE, FALSE,
4715 EL_EMC_WALL_4, -1, -1
4718 Xdecor_4, TRUE, FALSE,
4719 EL_EMC_WALL_7, -1, -1
4722 Xdecor_5, TRUE, FALSE,
4723 EL_EMC_WALL_5, -1, -1
4726 Xdecor_6, TRUE, FALSE,
4727 EL_EMC_WALL_9, -1, -1
4730 Xdecor_7, TRUE, FALSE,
4731 EL_EMC_WALL_10, -1, -1
4734 Xdecor_8, TRUE, FALSE,
4735 EL_EMC_WALL_1, -1, -1
4738 Xdecor_9, TRUE, FALSE,
4739 EL_EMC_WALL_2, -1, -1
4742 Xdecor_10, TRUE, FALSE,
4743 EL_EMC_WALL_3, -1, -1
4746 Xdecor_11, TRUE, FALSE,
4747 EL_EMC_WALL_11, -1, -1
4750 Xdecor_12, TRUE, FALSE,
4751 EL_EMC_WALL_12, -1, -1
4754 Xalpha_0, TRUE, FALSE,
4755 EL_CHAR('0'), -1, -1
4758 Xalpha_1, TRUE, FALSE,
4759 EL_CHAR('1'), -1, -1
4762 Xalpha_2, TRUE, FALSE,
4763 EL_CHAR('2'), -1, -1
4766 Xalpha_3, TRUE, FALSE,
4767 EL_CHAR('3'), -1, -1
4770 Xalpha_4, TRUE, FALSE,
4771 EL_CHAR('4'), -1, -1
4774 Xalpha_5, TRUE, FALSE,
4775 EL_CHAR('5'), -1, -1
4778 Xalpha_6, TRUE, FALSE,
4779 EL_CHAR('6'), -1, -1
4782 Xalpha_7, TRUE, FALSE,
4783 EL_CHAR('7'), -1, -1
4786 Xalpha_8, TRUE, FALSE,
4787 EL_CHAR('8'), -1, -1
4790 Xalpha_9, TRUE, FALSE,
4791 EL_CHAR('9'), -1, -1
4794 Xalpha_excla, TRUE, FALSE,
4795 EL_CHAR('!'), -1, -1
4798 Xalpha_quote, TRUE, FALSE,
4799 EL_CHAR('"'), -1, -1
4802 Xalpha_comma, TRUE, FALSE,
4803 EL_CHAR(','), -1, -1
4806 Xalpha_minus, TRUE, FALSE,
4807 EL_CHAR('-'), -1, -1
4810 Xalpha_perio, TRUE, FALSE,
4811 EL_CHAR('.'), -1, -1
4814 Xalpha_colon, TRUE, FALSE,
4815 EL_CHAR(':'), -1, -1
4818 Xalpha_quest, TRUE, FALSE,
4819 EL_CHAR('?'), -1, -1
4822 Xalpha_a, TRUE, FALSE,
4823 EL_CHAR('A'), -1, -1
4826 Xalpha_b, TRUE, FALSE,
4827 EL_CHAR('B'), -1, -1
4830 Xalpha_c, TRUE, FALSE,
4831 EL_CHAR('C'), -1, -1
4834 Xalpha_d, TRUE, FALSE,
4835 EL_CHAR('D'), -1, -1
4838 Xalpha_e, TRUE, FALSE,
4839 EL_CHAR('E'), -1, -1
4842 Xalpha_f, TRUE, FALSE,
4843 EL_CHAR('F'), -1, -1
4846 Xalpha_g, TRUE, FALSE,
4847 EL_CHAR('G'), -1, -1
4850 Xalpha_h, TRUE, FALSE,
4851 EL_CHAR('H'), -1, -1
4854 Xalpha_i, TRUE, FALSE,
4855 EL_CHAR('I'), -1, -1
4858 Xalpha_j, TRUE, FALSE,
4859 EL_CHAR('J'), -1, -1
4862 Xalpha_k, TRUE, FALSE,
4863 EL_CHAR('K'), -1, -1
4866 Xalpha_l, TRUE, FALSE,
4867 EL_CHAR('L'), -1, -1
4870 Xalpha_m, TRUE, FALSE,
4871 EL_CHAR('M'), -1, -1
4874 Xalpha_n, TRUE, FALSE,
4875 EL_CHAR('N'), -1, -1
4878 Xalpha_o, TRUE, FALSE,
4879 EL_CHAR('O'), -1, -1
4882 Xalpha_p, TRUE, FALSE,
4883 EL_CHAR('P'), -1, -1
4886 Xalpha_q, TRUE, FALSE,
4887 EL_CHAR('Q'), -1, -1
4890 Xalpha_r, TRUE, FALSE,
4891 EL_CHAR('R'), -1, -1
4894 Xalpha_s, TRUE, FALSE,
4895 EL_CHAR('S'), -1, -1
4898 Xalpha_t, TRUE, FALSE,
4899 EL_CHAR('T'), -1, -1
4902 Xalpha_u, TRUE, FALSE,
4903 EL_CHAR('U'), -1, -1
4906 Xalpha_v, TRUE, FALSE,
4907 EL_CHAR('V'), -1, -1
4910 Xalpha_w, TRUE, FALSE,
4911 EL_CHAR('W'), -1, -1
4914 Xalpha_x, TRUE, FALSE,
4915 EL_CHAR('X'), -1, -1
4918 Xalpha_y, TRUE, FALSE,
4919 EL_CHAR('Y'), -1, -1
4922 Xalpha_z, TRUE, FALSE,
4923 EL_CHAR('Z'), -1, -1
4926 Xalpha_arrow_e, TRUE, FALSE,
4927 EL_CHAR('>'), -1, -1
4930 Xalpha_arrow_w, TRUE, FALSE,
4931 EL_CHAR('<'), -1, -1
4934 Xalpha_copyr, TRUE, FALSE,
4935 EL_CHAR('©'), -1, -1
4939 Xboom_bug, FALSE, FALSE,
4940 EL_BUG, ACTION_EXPLODING, -1
4943 Xboom_bomb, FALSE, FALSE,
4944 EL_BOMB, ACTION_EXPLODING, -1
4947 Xboom_android, FALSE, FALSE,
4948 EL_EMC_ANDROID, ACTION_OTHER, -1
4951 Xboom_1, FALSE, FALSE,
4952 EL_DEFAULT, ACTION_EXPLODING, -1
4955 Xboom_2, FALSE, FALSE,
4956 EL_DEFAULT, ACTION_EXPLODING, -1
4959 Znormal, FALSE, FALSE,
4963 Zdynamite, FALSE, FALSE,
4967 Zplayer, FALSE, FALSE,
4971 ZBORDER, FALSE, FALSE,
4981 static struct Mapping_EM_to_RND_player
4990 em_player_mapping_list[] =
4994 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
4998 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
5002 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
5006 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
5010 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
5014 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
5018 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
5022 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
5026 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
5030 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
5034 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
5038 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
5042 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
5046 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
5050 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
5054 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
5058 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
5062 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
5066 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
5070 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
5074 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
5078 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
5082 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
5086 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
5090 EL_PLAYER_1, ACTION_DEFAULT, -1,
5094 EL_PLAYER_2, ACTION_DEFAULT, -1,
5098 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
5102 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
5106 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
5110 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
5114 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
5118 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
5122 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
5126 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
5130 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
5134 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
5138 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
5142 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
5146 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
5150 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
5154 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
5158 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
5162 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
5166 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
5170 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
5174 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
5178 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
5182 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
5186 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
5190 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
5194 EL_PLAYER_3, ACTION_DEFAULT, -1,
5198 EL_PLAYER_4, ACTION_DEFAULT, -1,
5207 int map_element_RND_to_EM(int element_rnd)
5209 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
5210 static boolean mapping_initialized = FALSE;
5212 if (!mapping_initialized)
5216 /* return "Xalpha_quest" for all undefined elements in mapping array */
5217 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
5218 mapping_RND_to_EM[i] = Xalpha_quest;
5220 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5221 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
5222 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
5223 em_object_mapping_list[i].element_em;
5225 mapping_initialized = TRUE;
5228 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
5229 return mapping_RND_to_EM[element_rnd];
5231 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
5236 int map_element_EM_to_RND(int element_em)
5238 static unsigned short mapping_EM_to_RND[TILE_MAX];
5239 static boolean mapping_initialized = FALSE;
5241 if (!mapping_initialized)
5245 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
5246 for (i = 0; i < TILE_MAX; i++)
5247 mapping_EM_to_RND[i] = EL_UNKNOWN;
5249 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5250 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
5251 em_object_mapping_list[i].element_rnd;
5253 mapping_initialized = TRUE;
5256 if (element_em >= 0 && element_em < TILE_MAX)
5257 return mapping_EM_to_RND[element_em];
5259 Error(ERR_WARN, "invalid EM level element %d", element_em);
5264 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
5266 struct LevelInfo_EM *level_em = level->native_em_level;
5267 struct LEVEL *lev = level_em->lev;
5270 for (i = 0; i < TILE_MAX; i++)
5271 lev->android_array[i] = Xblank;
5273 for (i = 0; i < level->num_android_clone_elements; i++)
5275 int element_rnd = level->android_clone_element[i];
5276 int element_em = map_element_RND_to_EM(element_rnd);
5278 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
5279 if (em_object_mapping_list[j].element_rnd == element_rnd)
5280 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
5284 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
5286 struct LevelInfo_EM *level_em = level->native_em_level;
5287 struct LEVEL *lev = level_em->lev;
5290 level->num_android_clone_elements = 0;
5292 for (i = 0; i < TILE_MAX; i++)
5294 int element_em = lev->android_array[i];
5296 boolean element_found = FALSE;
5298 if (element_em == Xblank)
5301 element_rnd = map_element_EM_to_RND(element_em);
5303 for (j = 0; j < level->num_android_clone_elements; j++)
5304 if (level->android_clone_element[j] == element_rnd)
5305 element_found = TRUE;
5309 level->android_clone_element[level->num_android_clone_elements++] =
5312 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
5317 if (level->num_android_clone_elements == 0)
5319 level->num_android_clone_elements = 1;
5320 level->android_clone_element[0] = EL_EMPTY;
5324 int map_direction_RND_to_EM(int direction)
5326 return (direction == MV_UP ? 0 :
5327 direction == MV_RIGHT ? 1 :
5328 direction == MV_DOWN ? 2 :
5329 direction == MV_LEFT ? 3 :
5333 int map_direction_EM_to_RND(int direction)
5335 return (direction == 0 ? MV_UP :
5336 direction == 1 ? MV_RIGHT :
5337 direction == 2 ? MV_DOWN :
5338 direction == 3 ? MV_LEFT :
5342 int get_next_element(int element)
5346 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
5347 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
5348 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
5349 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
5350 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
5351 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
5352 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
5354 default: return element;
5359 int el_act_dir2img(int element, int action, int direction)
5361 element = GFX_ELEMENT(element);
5363 if (direction == MV_NONE)
5364 return element_info[element].graphic[action];
5366 direction = MV_DIR_TO_BIT(direction);
5368 return element_info[element].direction_graphic[action][direction];
5371 int el_act_dir2img(int element, int action, int direction)
5373 element = GFX_ELEMENT(element);
5374 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5376 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5377 return element_info[element].direction_graphic[action][direction];
5382 static int el_act_dir2crm(int element, int action, int direction)
5384 element = GFX_ELEMENT(element);
5386 if (direction == MV_NONE)
5387 return element_info[element].crumbled[action];
5389 direction = MV_DIR_TO_BIT(direction);
5391 return element_info[element].direction_crumbled[action][direction];
5394 static int el_act_dir2crm(int element, int action, int direction)
5396 element = GFX_ELEMENT(element);
5397 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5399 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5400 return element_info[element].direction_crumbled[action][direction];
5404 int el_act2img(int element, int action)
5406 element = GFX_ELEMENT(element);
5408 return element_info[element].graphic[action];
5411 int el_act2crm(int element, int action)
5413 element = GFX_ELEMENT(element);
5415 return element_info[element].crumbled[action];
5418 int el_dir2img(int element, int direction)
5420 element = GFX_ELEMENT(element);
5422 return el_act_dir2img(element, ACTION_DEFAULT, direction);
5425 int el2baseimg(int element)
5427 return element_info[element].graphic[ACTION_DEFAULT];
5430 int el2img(int element)
5432 element = GFX_ELEMENT(element);
5434 return element_info[element].graphic[ACTION_DEFAULT];
5437 int el2edimg(int element)
5439 element = GFX_ELEMENT(element);
5441 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
5444 int el2preimg(int element)
5446 element = GFX_ELEMENT(element);
5448 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
5451 int font2baseimg(int font_nr)
5453 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
5456 int getNumActivePlayers_EM()
5458 int num_players = 0;
5464 for (i = 0; i < MAX_PLAYERS; i++)
5465 if (tape.player_participates[i])
5471 int getGameFrameDelay_EM(int native_em_game_frame_delay)
5473 int game_frame_delay_value;
5475 game_frame_delay_value =
5476 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
5477 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
5480 if (tape.playing && tape.warp_forward && !tape.pausing)
5481 game_frame_delay_value = 0;
5483 return game_frame_delay_value;
5486 unsigned int InitRND(long seed)
5488 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
5489 return InitEngineRandom_EM(seed);
5491 return InitEngineRandom_RND(seed);
5494 void InitGraphicInfo_EM(void)
5496 struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
5497 struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
5501 int num_em_gfx_errors = 0;
5503 if (graphic_info_em_object[0][0].bitmap == NULL)
5505 /* EM graphics not yet initialized in em_open_all() */
5510 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
5513 /* always start with reliable default values */
5514 for (i = 0; i < TILE_MAX; i++)
5516 object_mapping[i].element_rnd = EL_UNKNOWN;
5517 object_mapping[i].is_backside = FALSE;
5518 object_mapping[i].action = ACTION_DEFAULT;
5519 object_mapping[i].direction = MV_NONE;
5522 /* always start with reliable default values */
5523 for (p = 0; p < MAX_PLAYERS; p++)
5525 for (i = 0; i < SPR_MAX; i++)
5527 player_mapping[p][i].element_rnd = EL_UNKNOWN;
5528 player_mapping[p][i].action = ACTION_DEFAULT;
5529 player_mapping[p][i].direction = MV_NONE;
5533 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5535 int e = em_object_mapping_list[i].element_em;
5537 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
5538 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
5540 if (em_object_mapping_list[i].action != -1)
5541 object_mapping[e].action = em_object_mapping_list[i].action;
5543 if (em_object_mapping_list[i].direction != -1)
5544 object_mapping[e].direction =
5545 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
5548 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
5550 int a = em_player_mapping_list[i].action_em;
5551 int p = em_player_mapping_list[i].player_nr;
5553 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
5555 if (em_player_mapping_list[i].action != -1)
5556 player_mapping[p][a].action = em_player_mapping_list[i].action;
5558 if (em_player_mapping_list[i].direction != -1)
5559 player_mapping[p][a].direction =
5560 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
5563 for (i = 0; i < TILE_MAX; i++)
5565 int element = object_mapping[i].element_rnd;
5566 int action = object_mapping[i].action;
5567 int direction = object_mapping[i].direction;
5568 boolean is_backside = object_mapping[i].is_backside;
5569 boolean action_removing = (action == ACTION_DIGGING ||
5570 action == ACTION_SNAPPING ||
5571 action == ACTION_COLLECTING);
5572 boolean action_exploding = ((action == ACTION_EXPLODING ||
5573 action == ACTION_SMASHED_BY_ROCK ||
5574 action == ACTION_SMASHED_BY_SPRING) &&
5575 element != EL_DIAMOND);
5576 boolean action_active = (action == ACTION_ACTIVE);
5577 boolean action_other = (action == ACTION_OTHER);
5579 for (j = 0; j < 8; j++)
5581 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
5582 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
5584 i == Xdrip_stretch ? element :
5585 i == Xdrip_stretchB ? element :
5586 i == Ydrip_s1 ? element :
5587 i == Ydrip_s1B ? element :
5588 i == Xball_1B ? element :
5589 i == Xball_2 ? element :
5590 i == Xball_2B ? element :
5591 i == Yball_eat ? element :
5592 i == Ykey_1_eat ? element :
5593 i == Ykey_2_eat ? element :
5594 i == Ykey_3_eat ? element :
5595 i == Ykey_4_eat ? element :
5596 i == Ykey_5_eat ? element :
5597 i == Ykey_6_eat ? element :
5598 i == Ykey_7_eat ? element :
5599 i == Ykey_8_eat ? element :
5600 i == Ylenses_eat ? element :
5601 i == Ymagnify_eat ? element :
5602 i == Ygrass_eat ? element :
5603 i == Ydirt_eat ? element :
5604 i == Yemerald_stone ? EL_EMERALD :
5605 i == Ydiamond_stone ? EL_ROCK :
5606 i == Xsand_stonein_1 ? element :
5607 i == Xsand_stonein_2 ? element :
5608 i == Xsand_stonein_3 ? element :
5609 i == Xsand_stonein_4 ? element :
5610 is_backside ? EL_EMPTY :
5611 action_removing ? EL_EMPTY :
5613 int effective_action = (j < 7 ? action :
5614 i == Xdrip_stretch ? action :
5615 i == Xdrip_stretchB ? action :
5616 i == Ydrip_s1 ? action :
5617 i == Ydrip_s1B ? action :
5618 i == Xball_1B ? action :
5619 i == Xball_2 ? action :
5620 i == Xball_2B ? action :
5621 i == Yball_eat ? action :
5622 i == Ykey_1_eat ? action :
5623 i == Ykey_2_eat ? action :
5624 i == Ykey_3_eat ? action :
5625 i == Ykey_4_eat ? action :
5626 i == Ykey_5_eat ? action :
5627 i == Ykey_6_eat ? action :
5628 i == Ykey_7_eat ? action :
5629 i == Ykey_8_eat ? action :
5630 i == Ylenses_eat ? action :
5631 i == Ymagnify_eat ? action :
5632 i == Ygrass_eat ? action :
5633 i == Ydirt_eat ? action :
5634 i == Xsand_stonein_1 ? action :
5635 i == Xsand_stonein_2 ? action :
5636 i == Xsand_stonein_3 ? action :
5637 i == Xsand_stonein_4 ? action :
5638 i == Xsand_stoneout_1 ? action :
5639 i == Xsand_stoneout_2 ? action :
5640 i == Xboom_android ? ACTION_EXPLODING :
5641 action_exploding ? ACTION_EXPLODING :
5642 action_active ? action :
5643 action_other ? action :
5645 int graphic = (el_act_dir2img(effective_element, effective_action,
5647 int crumbled = (el_act_dir2crm(effective_element, effective_action,
5649 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
5650 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
5651 boolean has_action_graphics = (graphic != base_graphic);
5652 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
5653 struct GraphicInfo *g = &graphic_info[graphic];
5654 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
5657 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
5658 boolean special_animation = (action != ACTION_DEFAULT &&
5659 g->anim_frames == 3 &&
5660 g->anim_delay == 2 &&
5661 g->anim_mode & ANIM_LINEAR);
5662 int sync_frame = (i == Xdrip_stretch ? 7 :
5663 i == Xdrip_stretchB ? 7 :
5664 i == Ydrip_s2 ? j + 8 :
5665 i == Ydrip_s2B ? j + 8 :
5674 i == Xfake_acid_1 ? 0 :
5675 i == Xfake_acid_2 ? 10 :
5676 i == Xfake_acid_3 ? 20 :
5677 i == Xfake_acid_4 ? 30 :
5678 i == Xfake_acid_5 ? 40 :
5679 i == Xfake_acid_6 ? 50 :
5680 i == Xfake_acid_7 ? 60 :
5681 i == Xfake_acid_8 ? 70 :
5683 i == Xball_2B ? j + 8 :
5684 i == Yball_eat ? j + 1 :
5685 i == Ykey_1_eat ? j + 1 :
5686 i == Ykey_2_eat ? j + 1 :
5687 i == Ykey_3_eat ? j + 1 :
5688 i == Ykey_4_eat ? j + 1 :
5689 i == Ykey_5_eat ? j + 1 :
5690 i == Ykey_6_eat ? j + 1 :
5691 i == Ykey_7_eat ? j + 1 :
5692 i == Ykey_8_eat ? j + 1 :
5693 i == Ylenses_eat ? j + 1 :
5694 i == Ymagnify_eat ? j + 1 :
5695 i == Ygrass_eat ? j + 1 :
5696 i == Ydirt_eat ? j + 1 :
5697 i == Xamoeba_1 ? 0 :
5698 i == Xamoeba_2 ? 1 :
5699 i == Xamoeba_3 ? 2 :
5700 i == Xamoeba_4 ? 3 :
5701 i == Xamoeba_5 ? 0 :
5702 i == Xamoeba_6 ? 1 :
5703 i == Xamoeba_7 ? 2 :
5704 i == Xamoeba_8 ? 3 :
5705 i == Xexit_2 ? j + 8 :
5706 i == Xexit_3 ? j + 16 :
5707 i == Xdynamite_1 ? 0 :
5708 i == Xdynamite_2 ? 8 :
5709 i == Xdynamite_3 ? 16 :
5710 i == Xdynamite_4 ? 24 :
5711 i == Xsand_stonein_1 ? j + 1 :
5712 i == Xsand_stonein_2 ? j + 9 :
5713 i == Xsand_stonein_3 ? j + 17 :
5714 i == Xsand_stonein_4 ? j + 25 :
5715 i == Xsand_stoneout_1 && j == 0 ? 0 :
5716 i == Xsand_stoneout_1 && j == 1 ? 0 :
5717 i == Xsand_stoneout_1 && j == 2 ? 1 :
5718 i == Xsand_stoneout_1 && j == 3 ? 2 :
5719 i == Xsand_stoneout_1 && j == 4 ? 2 :
5720 i == Xsand_stoneout_1 && j == 5 ? 3 :
5721 i == Xsand_stoneout_1 && j == 6 ? 4 :
5722 i == Xsand_stoneout_1 && j == 7 ? 4 :
5723 i == Xsand_stoneout_2 && j == 0 ? 5 :
5724 i == Xsand_stoneout_2 && j == 1 ? 6 :
5725 i == Xsand_stoneout_2 && j == 2 ? 7 :
5726 i == Xsand_stoneout_2 && j == 3 ? 8 :
5727 i == Xsand_stoneout_2 && j == 4 ? 9 :
5728 i == Xsand_stoneout_2 && j == 5 ? 11 :
5729 i == Xsand_stoneout_2 && j == 6 ? 13 :
5730 i == Xsand_stoneout_2 && j == 7 ? 15 :
5731 i == Xboom_bug && j == 1 ? 2 :
5732 i == Xboom_bug && j == 2 ? 2 :
5733 i == Xboom_bug && j == 3 ? 4 :
5734 i == Xboom_bug && j == 4 ? 4 :
5735 i == Xboom_bug && j == 5 ? 2 :
5736 i == Xboom_bug && j == 6 ? 2 :
5737 i == Xboom_bug && j == 7 ? 0 :
5738 i == Xboom_bomb && j == 1 ? 2 :
5739 i == Xboom_bomb && j == 2 ? 2 :
5740 i == Xboom_bomb && j == 3 ? 4 :
5741 i == Xboom_bomb && j == 4 ? 4 :
5742 i == Xboom_bomb && j == 5 ? 2 :
5743 i == Xboom_bomb && j == 6 ? 2 :
5744 i == Xboom_bomb && j == 7 ? 0 :
5745 i == Xboom_android && j == 7 ? 6 :
5746 i == Xboom_1 && j == 1 ? 2 :
5747 i == Xboom_1 && j == 2 ? 2 :
5748 i == Xboom_1 && j == 3 ? 4 :
5749 i == Xboom_1 && j == 4 ? 4 :
5750 i == Xboom_1 && j == 5 ? 6 :
5751 i == Xboom_1 && j == 6 ? 6 :
5752 i == Xboom_1 && j == 7 ? 8 :
5753 i == Xboom_2 && j == 0 ? 8 :
5754 i == Xboom_2 && j == 1 ? 8 :
5755 i == Xboom_2 && j == 2 ? 10 :
5756 i == Xboom_2 && j == 3 ? 10 :
5757 i == Xboom_2 && j == 4 ? 10 :
5758 i == Xboom_2 && j == 5 ? 12 :
5759 i == Xboom_2 && j == 6 ? 12 :
5760 i == Xboom_2 && j == 7 ? 12 :
5761 special_animation && j == 4 ? 3 :
5762 effective_action != action ? 0 :
5766 Bitmap *debug_bitmap = g_em->bitmap;
5767 int debug_src_x = g_em->src_x;
5768 int debug_src_y = g_em->src_y;
5771 int frame = getAnimationFrame(g->anim_frames,
5774 g->anim_start_frame,
5777 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
5778 g->double_movement && is_backside);
5780 g_em->bitmap = src_bitmap;
5781 g_em->src_x = src_x;
5782 g_em->src_y = src_y;
5783 g_em->src_offset_x = 0;
5784 g_em->src_offset_y = 0;
5785 g_em->dst_offset_x = 0;
5786 g_em->dst_offset_y = 0;
5787 g_em->width = TILEX;
5788 g_em->height = TILEY;
5790 g_em->crumbled_bitmap = NULL;
5791 g_em->crumbled_src_x = 0;
5792 g_em->crumbled_src_y = 0;
5793 g_em->crumbled_border_size = 0;
5795 g_em->has_crumbled_graphics = FALSE;
5796 g_em->preserve_background = FALSE;
5799 if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
5800 printf("::: empty crumbled: %d [%s], %d, %d\n",
5801 effective_element, element_info[effective_element].token_name,
5802 effective_action, direction);
5805 /* if element can be crumbled, but certain action graphics are just empty
5806 space (like snapping sand with the original R'n'D graphics), do not
5807 treat these empty space graphics as crumbled graphics in EMC engine */
5808 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
5810 getGraphicSource(crumbled, frame, &src_bitmap, &src_x, &src_y);
5812 g_em->has_crumbled_graphics = TRUE;
5813 g_em->crumbled_bitmap = src_bitmap;
5814 g_em->crumbled_src_x = src_x;
5815 g_em->crumbled_src_y = src_y;
5816 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
5820 if (element == EL_ROCK &&
5821 effective_action == ACTION_FILLING)
5822 printf("::: has_action_graphics == %d\n", has_action_graphics);
5825 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
5826 effective_action == ACTION_MOVING ||
5827 effective_action == ACTION_PUSHING ||
5828 effective_action == ACTION_EATING)) ||
5829 (!has_action_graphics && (effective_action == ACTION_FILLING ||
5830 effective_action == ACTION_EMPTYING)))
5833 (effective_action == ACTION_FALLING ||
5834 effective_action == ACTION_FILLING ||
5835 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
5836 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
5837 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
5838 int num_steps = (i == Ydrip_s1 ? 16 :
5839 i == Ydrip_s1B ? 16 :
5840 i == Ydrip_s2 ? 16 :
5841 i == Ydrip_s2B ? 16 :
5842 i == Xsand_stonein_1 ? 32 :
5843 i == Xsand_stonein_2 ? 32 :
5844 i == Xsand_stonein_3 ? 32 :
5845 i == Xsand_stonein_4 ? 32 :
5846 i == Xsand_stoneout_1 ? 16 :
5847 i == Xsand_stoneout_2 ? 16 : 8);
5848 int cx = ABS(dx) * (TILEX / num_steps);
5849 int cy = ABS(dy) * (TILEY / num_steps);
5850 int step_frame = (i == Ydrip_s2 ? j + 8 :
5851 i == Ydrip_s2B ? j + 8 :
5852 i == Xsand_stonein_2 ? j + 8 :
5853 i == Xsand_stonein_3 ? j + 16 :
5854 i == Xsand_stonein_4 ? j + 24 :
5855 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
5856 int step = (is_backside ? step_frame : num_steps - step_frame);
5858 if (is_backside) /* tile where movement starts */
5860 if (dx < 0 || dy < 0)
5862 g_em->src_offset_x = cx * step;
5863 g_em->src_offset_y = cy * step;
5867 g_em->dst_offset_x = cx * step;
5868 g_em->dst_offset_y = cy * step;
5871 else /* tile where movement ends */
5873 if (dx < 0 || dy < 0)
5875 g_em->dst_offset_x = cx * step;
5876 g_em->dst_offset_y = cy * step;
5880 g_em->src_offset_x = cx * step;
5881 g_em->src_offset_y = cy * step;
5885 g_em->width = TILEX - cx * step;
5886 g_em->height = TILEY - cy * step;
5889 /* create unique graphic identifier to decide if tile must be redrawn */
5890 /* bit 31 - 16 (16 bit): EM style graphic
5891 bit 15 - 12 ( 4 bit): EM style frame
5892 bit 11 - 6 ( 6 bit): graphic width
5893 bit 5 - 0 ( 6 bit): graphic height */
5894 g_em->unique_identifier =
5895 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
5899 /* skip check for EMC elements not contained in original EMC artwork */
5900 if (element == EL_EMC_FAKE_ACID)
5903 if (g_em->bitmap != debug_bitmap ||
5904 g_em->src_x != debug_src_x ||
5905 g_em->src_y != debug_src_y ||
5906 g_em->src_offset_x != 0 ||
5907 g_em->src_offset_y != 0 ||
5908 g_em->dst_offset_x != 0 ||
5909 g_em->dst_offset_y != 0 ||
5910 g_em->width != TILEX ||
5911 g_em->height != TILEY)
5913 static int last_i = -1;
5921 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
5922 i, element, element_info[element].token_name,
5923 element_action_info[effective_action].suffix, direction);
5925 if (element != effective_element)
5926 printf(" [%d ('%s')]",
5928 element_info[effective_element].token_name);
5932 if (g_em->bitmap != debug_bitmap)
5933 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
5934 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
5936 if (g_em->src_x != debug_src_x ||
5937 g_em->src_y != debug_src_y)
5938 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
5939 j, (is_backside ? 'B' : 'F'),
5940 g_em->src_x, g_em->src_y,
5941 g_em->src_x / 32, g_em->src_y / 32,
5942 debug_src_x, debug_src_y,
5943 debug_src_x / 32, debug_src_y / 32);
5945 if (g_em->src_offset_x != 0 ||
5946 g_em->src_offset_y != 0 ||
5947 g_em->dst_offset_x != 0 ||
5948 g_em->dst_offset_y != 0)
5949 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
5951 g_em->src_offset_x, g_em->src_offset_y,
5952 g_em->dst_offset_x, g_em->dst_offset_y);
5954 if (g_em->width != TILEX ||
5955 g_em->height != TILEY)
5956 printf(" %d (%d): size %d,%d should be %d,%d\n",
5958 g_em->width, g_em->height, TILEX, TILEY);
5960 num_em_gfx_errors++;
5967 for (i = 0; i < TILE_MAX; i++)
5969 for (j = 0; j < 8; j++)
5971 int element = object_mapping[i].element_rnd;
5972 int action = object_mapping[i].action;
5973 int direction = object_mapping[i].direction;
5974 boolean is_backside = object_mapping[i].is_backside;
5975 int graphic_action = el_act_dir2img(element, action, direction);
5976 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
5978 if ((action == ACTION_SMASHED_BY_ROCK ||
5979 action == ACTION_SMASHED_BY_SPRING ||
5980 action == ACTION_EATING) &&
5981 graphic_action == graphic_default)
5983 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
5984 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
5985 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
5986 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
5989 /* no separate animation for "smashed by rock" -- use rock instead */
5990 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
5991 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
5993 g_em->bitmap = g_xx->bitmap;
5994 g_em->src_x = g_xx->src_x;
5995 g_em->src_y = g_xx->src_y;
5996 g_em->src_offset_x = g_xx->src_offset_x;
5997 g_em->src_offset_y = g_xx->src_offset_y;
5998 g_em->dst_offset_x = g_xx->dst_offset_x;
5999 g_em->dst_offset_y = g_xx->dst_offset_y;
6000 g_em->width = g_xx->width;
6001 g_em->height = g_xx->height;
6002 g_em->unique_identifier = g_xx->unique_identifier;
6005 g_em->preserve_background = TRUE;
6010 for (p = 0; p < MAX_PLAYERS; p++)
6012 for (i = 0; i < SPR_MAX; i++)
6014 int element = player_mapping[p][i].element_rnd;
6015 int action = player_mapping[p][i].action;
6016 int direction = player_mapping[p][i].direction;
6018 for (j = 0; j < 8; j++)
6020 int effective_element = element;
6021 int effective_action = action;
6022 int graphic = (direction == MV_NONE ?
6023 el_act2img(effective_element, effective_action) :
6024 el_act_dir2img(effective_element, effective_action,
6026 struct GraphicInfo *g = &graphic_info[graphic];
6027 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
6033 Bitmap *debug_bitmap = g_em->bitmap;
6034 int debug_src_x = g_em->src_x;
6035 int debug_src_y = g_em->src_y;
6038 int frame = getAnimationFrame(g->anim_frames,
6041 g->anim_start_frame,
6044 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x,&src_y, FALSE);
6046 g_em->bitmap = src_bitmap;
6047 g_em->src_x = src_x;
6048 g_em->src_y = src_y;
6049 g_em->src_offset_x = 0;
6050 g_em->src_offset_y = 0;
6051 g_em->dst_offset_x = 0;
6052 g_em->dst_offset_y = 0;
6053 g_em->width = TILEX;
6054 g_em->height = TILEY;
6058 /* skip check for EMC elements not contained in original EMC artwork */
6059 if (element == EL_PLAYER_3 ||
6060 element == EL_PLAYER_4)
6063 if (g_em->bitmap != debug_bitmap ||
6064 g_em->src_x != debug_src_x ||
6065 g_em->src_y != debug_src_y)
6067 static int last_i = -1;
6075 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
6076 p, i, element, element_info[element].token_name,
6077 element_action_info[effective_action].suffix, direction);
6079 if (element != effective_element)
6080 printf(" [%d ('%s')]",
6082 element_info[effective_element].token_name);
6086 if (g_em->bitmap != debug_bitmap)
6087 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
6088 j, (int)(g_em->bitmap), (int)(debug_bitmap));
6090 if (g_em->src_x != debug_src_x ||
6091 g_em->src_y != debug_src_y)
6092 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
6094 g_em->src_x, g_em->src_y,
6095 g_em->src_x / 32, g_em->src_y / 32,
6096 debug_src_x, debug_src_y,
6097 debug_src_x / 32, debug_src_y / 32);
6099 num_em_gfx_errors++;
6109 printf("::: [%d errors found]\n", num_em_gfx_errors);
6115 void PlayMenuSound()
6117 int sound = menu.sound[game_status];
6119 if (sound == SND_UNDEFINED)
6122 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6123 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6126 if (IS_LOOP_SOUND(sound))
6127 PlaySoundLoop(sound);
6132 void PlayMenuSoundStereo(int sound, int stereo_position)
6134 if (sound == SND_UNDEFINED)
6137 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6138 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6141 if (IS_LOOP_SOUND(sound))
6142 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
6144 PlaySoundStereo(sound, stereo_position);
6147 void PlayMenuSoundIfLoop()
6149 int sound = menu.sound[game_status];
6151 if (sound == SND_UNDEFINED)
6154 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6155 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6158 if (IS_LOOP_SOUND(sound))
6159 PlaySoundLoop(sound);
6162 void PlayMenuMusic()
6164 int music = menu.music[game_status];
6166 if (music == MUS_UNDEFINED)
6172 void ToggleFullscreenIfNeeded()
6174 boolean change_fullscreen = (setup.fullscreen !=
6175 video.fullscreen_enabled);
6176 boolean change_fullscreen_mode = (video.fullscreen_enabled &&
6177 !strEqual(setup.fullscreen_mode,
6178 video.fullscreen_mode_current));
6180 if (!video.fullscreen_available)
6184 if (change_fullscreen || change_fullscreen_mode)
6186 if (setup.fullscreen != video.fullscreen_enabled ||
6187 setup.fullscreen_mode != video.fullscreen_mode_current)
6190 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
6192 /* save backbuffer content which gets lost when toggling fullscreen mode */
6193 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6196 if (change_fullscreen_mode)
6198 if (setup.fullscreen && video.fullscreen_enabled)
6201 /* keep fullscreen, but change fullscreen mode (screen resolution) */
6203 /* (this is now set in sdl.c) */
6205 video.fullscreen_mode_current = setup.fullscreen_mode;
6207 video.fullscreen_enabled = FALSE; /* force new fullscreen mode */
6210 /* toggle fullscreen */
6211 ChangeVideoModeIfNeeded(setup.fullscreen);
6213 setup.fullscreen = video.fullscreen_enabled;
6215 /* restore backbuffer content from temporary backbuffer backup bitmap */
6216 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6218 FreeBitmap(tmp_backbuffer);
6221 /* update visible window/screen */
6222 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6224 redraw_mask = REDRAW_ALL;