1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back! *
3 *----------------------------------------------------------*
4 * (c) 1995-2006 Artsoft Entertainment *
6 * Detmolder Strasse 189 *
9 * e-mail: info@artsoft.org *
10 *----------------------------------------------------------*
12 ***********************************************************/
14 #include "libgame/libgame.h"
24 /* select level set with EMC X11 graphics before activating EM GFX debugging */
25 #define DEBUG_EM_GFX 0
27 /* tool button identifiers */
28 #define TOOL_CTRL_ID_YES 0
29 #define TOOL_CTRL_ID_NO 1
30 #define TOOL_CTRL_ID_CONFIRM 2
31 #define TOOL_CTRL_ID_PLAYER_1 3
32 #define TOOL_CTRL_ID_PLAYER_2 4
33 #define TOOL_CTRL_ID_PLAYER_3 5
34 #define TOOL_CTRL_ID_PLAYER_4 6
36 #define NUM_TOOL_BUTTONS 7
38 /* forward declaration for internal use */
39 static void UnmapToolButtons();
40 static void HandleToolButtons(struct GadgetInfo *);
41 static int el_act_dir2crm(int, int, int);
42 static int el_act2crm(int, int);
44 static struct GadgetInfo *tool_gadget[NUM_TOOL_BUTTONS];
45 static int request_gadget_id = -1;
47 static char *print_if_not_empty(int element)
49 static char *s = NULL;
50 char *token_name = element_info[element].token_name;
55 s = checked_malloc(strlen(token_name) + 10 + 1);
57 if (element != EL_EMPTY)
58 sprintf(s, "%d\t['%s']", element, token_name);
60 sprintf(s, "%d", element);
65 void DumpTile(int x, int y)
70 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
77 printf("Field Info: SCREEN(%d, %d), LEVEL(%d, %d)\n", sx, sy, x, y);
80 if (!IN_LEV_FIELD(x, y))
82 printf("(not in level field)\n");
88 printf(" Feld: %d\t['%s']\n", Feld[x][y],
89 element_info[Feld[x][y]].token_name);
90 printf(" Back: %s\n", print_if_not_empty(Back[x][y]));
91 printf(" Store: %s\n", print_if_not_empty(Store[x][y]));
92 printf(" Store2: %s\n", print_if_not_empty(Store2[x][y]));
93 printf(" StorePlayer: %s\n", print_if_not_empty(StorePlayer[x][y]));
94 printf(" MovPos: %d\n", MovPos[x][y]);
95 printf(" MovDir: %d\n", MovDir[x][y]);
96 printf(" MovDelay: %d\n", MovDelay[x][y]);
97 printf(" ChangeDelay: %d\n", ChangeDelay[x][y]);
98 printf(" CustomValue: %d\n", CustomValue[x][y]);
99 printf(" GfxElement: %d\n", GfxElement[x][y]);
100 printf(" GfxAction: %d\n", GfxAction[x][y]);
101 printf(" GfxFrame: %d\n", GfxFrame[x][y]);
105 void SetDrawtoField(int mode)
107 if (mode == DRAW_BUFFERED && setup.soft_scrolling)
118 drawto_field = fieldbuffer;
120 else /* DRAW_DIRECT, DRAW_BACKBUFFER */
126 BX2 = SCR_FIELDX - 1;
127 BY2 = SCR_FIELDY - 1;
131 drawto_field = (mode == DRAW_DIRECT ? window : backbuffer);
135 void RedrawPlayfield(boolean force_redraw, int x, int y, int width, int height)
137 if (game_status == GAME_MODE_PLAYING &&
138 level.game_engine_type == GAME_ENGINE_TYPE_EM)
140 /* currently there is no partial redraw -- always redraw whole playfield */
141 RedrawPlayfield_EM(TRUE);
143 /* blit playfield from scroll buffer to normal back buffer for fading in */
144 BlitScreenToBitmap_EM(backbuffer);
146 else if (game_status == GAME_MODE_PLAYING && !game.envelope_active)
152 width = gfx.sxsize + 2 * TILEX;
153 height = gfx.sysize + 2 * TILEY;
156 if (force_redraw || setup.direct_draw)
159 int x1 = (x - SX) / TILEX, y1 = (y - SY) / TILEY;
160 int x2 = (x - SX + width) / TILEX, y2 = (y - SY + height) / TILEY;
162 if (setup.direct_draw)
163 SetDrawtoField(DRAW_BACKBUFFER);
165 for (xx = BX1; xx <= BX2; xx++)
166 for (yy = BY1; yy <= BY2; yy++)
167 if (xx >= x1 && xx <= x2 && yy >= y1 && yy <= y2)
168 DrawScreenField(xx, yy);
171 if (setup.direct_draw)
172 SetDrawtoField(DRAW_DIRECT);
175 if (setup.soft_scrolling)
177 int fx = FX, fy = FY;
179 fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0);
180 fy += (ScreenMovDir & (MV_UP|MV_DOWN) ? ScreenGfxPos : 0);
182 BlitBitmap(fieldbuffer, backbuffer, fx,fy, SXSIZE,SYSIZE, SX,SY);
194 BlitBitmap(drawto, window, x, y, width, height, x, y);
197 void DrawMaskedBorder_Rect(int x, int y, int width, int height)
199 Bitmap *bitmap = graphic_info[IMG_GLOBAL_BORDER].bitmap;
201 SetClipOrigin(bitmap, bitmap->stored_clip_gc, 0, 0);
202 BlitBitmapMasked(bitmap, backbuffer, x, y, width, height, x, y);
205 void DrawMaskedBorder_FIELD()
207 if (game_status >= GAME_MODE_TITLE &&
208 game_status <= GAME_MODE_PLAYING &&
209 border.draw_masked[game_status])
210 DrawMaskedBorder_Rect(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
213 void DrawMaskedBorder_DOOR_1()
215 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
216 (game_status != GAME_MODE_EDITOR ||
217 border.draw_masked[GFX_SPECIAL_ARG_EDITOR]))
218 DrawMaskedBorder_Rect(DX, DY, DXSIZE, DYSIZE);
221 void DrawMaskedBorder_DOOR_2()
223 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
224 game_status != GAME_MODE_EDITOR)
225 DrawMaskedBorder_Rect(VX, VY, VXSIZE, VYSIZE);
228 void DrawMaskedBorder_DOOR_3()
230 /* currently not available */
233 void DrawMaskedBorder_ALL()
235 DrawMaskedBorder_FIELD();
236 DrawMaskedBorder_DOOR_1();
237 DrawMaskedBorder_DOOR_2();
238 DrawMaskedBorder_DOOR_3();
241 void DrawMaskedBorder(int redraw_mask)
243 if (redraw_mask & REDRAW_ALL)
244 DrawMaskedBorder_ALL();
247 if (redraw_mask & REDRAW_FIELD)
248 DrawMaskedBorder_FIELD();
249 if (redraw_mask & REDRAW_DOOR_1)
250 DrawMaskedBorder_DOOR_1();
251 if (redraw_mask & REDRAW_DOOR_2)
252 DrawMaskedBorder_DOOR_2();
253 if (redraw_mask & REDRAW_DOOR_3)
254 DrawMaskedBorder_DOOR_3();
261 DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
263 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
264 redraw_mask &= ~REDRAW_MAIN;
266 if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD)
267 redraw_mask |= REDRAW_FIELD;
269 if (redraw_mask & REDRAW_FIELD)
270 redraw_mask &= ~REDRAW_TILES;
272 if (redraw_mask == REDRAW_NONE)
275 if (redraw_mask & REDRAW_TILES &&
276 game_status == GAME_MODE_PLAYING &&
277 border.draw_masked[game_status])
278 redraw_mask |= REDRAW_FIELD;
280 if (global.fps_slowdown && game_status == GAME_MODE_PLAYING)
282 static boolean last_frame_skipped = FALSE;
283 boolean skip_even_when_not_scrolling = TRUE;
284 boolean just_scrolling = (ScreenMovDir != 0);
285 boolean verbose = FALSE;
287 if (global.fps_slowdown_factor > 1 &&
288 (FrameCounter % global.fps_slowdown_factor) &&
289 (just_scrolling || skip_even_when_not_scrolling))
291 redraw_mask &= ~REDRAW_MAIN;
293 last_frame_skipped = TRUE;
296 printf("FRAME SKIPPED\n");
300 if (last_frame_skipped)
301 redraw_mask |= REDRAW_FIELD;
303 last_frame_skipped = FALSE;
306 printf("frame not skipped\n");
310 /* synchronize X11 graphics at this point; if we would synchronize the
311 display immediately after the buffer switching (after the XFlush),
312 this could mean that we have to wait for the graphics to complete,
313 although we could go on doing calculations for the next frame */
318 DrawMaskedBorder(redraw_mask);
321 if (redraw_mask & REDRAW_ALL)
324 DrawMaskedBorder(REDRAW_ALL);
326 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
328 redraw_mask = REDRAW_NONE;
331 if (redraw_mask & REDRAW_FIELD)
333 if (game_status != GAME_MODE_PLAYING ||
334 redraw_mask & REDRAW_FROM_BACKBUFFER)
337 DrawMaskedBorder(REDRAW_FIELD);
339 BlitBitmap(backbuffer, window,
340 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
344 int fx = FX, fy = FY;
346 if (setup.soft_scrolling)
348 fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
349 fy += (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
352 if (setup.soft_scrolling ||
353 ABS(ScreenMovPos) + ScrollStepSize == TILEX ||
354 ABS(ScreenMovPos) == ScrollStepSize ||
355 redraw_tiles > REDRAWTILES_THRESHOLD)
358 if (border.draw_masked[GFX_SPECIAL_ARG_MAIN])
360 BlitBitmap(buffer, backbuffer, fx, fy, SXSIZE, SYSIZE, SX, SY);
362 DrawMaskedBorder(REDRAW_FIELD);
363 BlitBitmap(backbuffer, window,
364 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
368 BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
370 BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
375 printf("redrawing all (ScreenGfxPos == %d) because %s\n",
377 (setup.soft_scrolling ?
378 "setup.soft_scrolling" :
379 ABS(ScreenGfxPos) + ScrollStepSize == TILEX ?
380 "ABS(ScreenGfxPos) + ScrollStepSize == TILEX" :
381 ABS(ScreenGfxPos) == ScrollStepSize ?
382 "ABS(ScreenGfxPos) == ScrollStepSize" :
383 "redraw_tiles > REDRAWTILES_THRESHOLD"));
389 redraw_mask &= ~REDRAW_MAIN;
392 if (redraw_mask & REDRAW_DOORS)
394 if (redraw_mask & REDRAW_DOOR_1)
397 DrawMaskedBorder(REDRAW_DOOR_1);
399 BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
402 if (redraw_mask & REDRAW_DOOR_2)
405 DrawMaskedBorder(REDRAW_DOOR_2);
407 BlitBitmap(backbuffer, window, VX, VY, VXSIZE, VYSIZE, VX, VY);
410 if (redraw_mask & REDRAW_DOOR_3)
413 DrawMaskedBorder(REDRAW_DOOR_3);
415 BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
418 redraw_mask &= ~REDRAW_DOORS;
421 if (redraw_mask & REDRAW_MICROLEVEL)
423 BlitBitmap(backbuffer, window, SX, SY + 10 * TILEY, SXSIZE, 7 * TILEY,
424 SX, SY + 10 * TILEY);
426 redraw_mask &= ~REDRAW_MICROLEVEL;
429 if (redraw_mask & REDRAW_TILES)
431 for (x = 0; x < SCR_FIELDX; x++)
432 for (y = 0 ; y < SCR_FIELDY; y++)
433 if (redraw[redraw_x1 + x][redraw_y1 + y])
434 BlitBitmap(buffer, window,
435 FX + x * TILEX, FY + y * TILEY, TILEX, TILEY,
436 SX + x * TILEX, SY + y * TILEY);
439 if (redraw_mask & REDRAW_FPS) /* display frames per second */
444 sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
445 if (!global.fps_slowdown)
448 sprintf(text, "%.1f fps%s", global.frames_per_second, info1);
449 DrawTextExt(window, SX, SY, text, FONT_TEXT_2, BLIT_OPAQUE);
454 for (x = 0; x < MAX_BUF_XSIZE; x++)
455 for (y = 0; y < MAX_BUF_YSIZE; y++)
458 redraw_mask = REDRAW_NONE;
464 long fading_delay = 300;
466 if (setup.fading && (redraw_mask & REDRAW_FIELD))
473 ClearRectangle(window, REAL_SX,REAL_SY,FULL_SXSIZE,FULL_SYSIZE);
476 for (i = 0; i < 2 * FULL_SYSIZE; i++)
478 for (y = 0; y < FULL_SYSIZE; y++)
480 BlitBitmap(backbuffer, window,
481 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
489 for (i = 1; i < FULL_SYSIZE; i+=2)
490 BlitBitmap(backbuffer, window,
491 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
497 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, 0);
498 BlitBitmapMasked(backbuffer, window,
499 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
504 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, -1);
505 BlitBitmapMasked(backbuffer, window,
506 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
511 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, -1);
512 BlitBitmapMasked(backbuffer, window,
513 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
518 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, 0);
519 BlitBitmapMasked(backbuffer, window,
520 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
525 redraw_mask &= ~REDRAW_MAIN;
532 void FadeExt(int fade_mask, int fade_mode)
534 void (*draw_border_function)(void) = NULL;
535 Bitmap *bitmap = (fade_mode == FADE_MODE_CROSSFADE ? bitmap_db_cross : NULL);
536 int x, y, width, height;
537 int fade_delay, post_delay;
539 if (fade_mask & REDRAW_FIELD)
544 height = FULL_SYSIZE;
546 fade_delay = menu.fade_delay;
547 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? menu.post_delay : 0);
549 draw_border_function = DrawMaskedBorder_FIELD;
551 else /* REDRAW_ALL */
558 fade_delay = title.fade_delay_final;
559 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? title.post_delay_final : 0);
562 redraw_mask |= fade_mask;
564 if (!setup.fade_screens || fade_delay == 0)
566 if (fade_mode == FADE_MODE_FADE_OUT)
567 ClearRectangle(backbuffer, x, y, width, height);
574 FadeRectangle(bitmap, x, y, width, height, fade_mode, fade_delay, post_delay,
575 draw_border_function);
577 redraw_mask &= ~fade_mask;
580 void FadeIn(int fade_mask)
582 FadeExt(fade_mask, FADE_MODE_FADE_IN);
585 void FadeOut(int fade_mask)
587 FadeExt(fade_mask, FADE_MODE_FADE_OUT);
590 void FadeCross(int fade_mask)
592 FadeExt(fade_mask, FADE_MODE_CROSSFADE);
595 void FadeCrossSaveBackbuffer()
597 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
600 void SetMainBackgroundImageIfDefined(int graphic)
602 if (graphic_info[graphic].bitmap)
603 SetMainBackgroundImage(graphic);
606 void SetMainBackgroundImage(int graphic)
608 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
609 graphic_info[graphic].bitmap ?
610 graphic_info[graphic].bitmap :
611 graphic_info[IMG_BACKGROUND].bitmap);
614 void SetDoorBackgroundImage(int graphic)
616 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
617 graphic_info[graphic].bitmap ?
618 graphic_info[graphic].bitmap :
619 graphic_info[IMG_BACKGROUND].bitmap);
622 void SetPanelBackground()
624 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, bitmap_db_panel,
625 DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, 0, 0);
627 SetDoorBackgroundBitmap(bitmap_db_panel);
630 void DrawBackground(int dst_x, int dst_y, int width, int height)
632 /* !!! "drawto" might still point to playfield buffer here (see below) !!! */
633 /* (when entering hall of fame after playing) */
635 ClearRectangleOnBackground(drawto, dst_x, dst_y, width, height);
637 ClearRectangleOnBackground(backbuffer, dst_x, dst_y, width, height);
640 redraw_mask |= REDRAW_FIELD;
645 /* !!! "drawto" might still point to playfield buffer here (see above) !!! */
646 /* (when entering hall of fame after playing) */
647 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
649 /* !!! maybe this should be done before clearing the background !!! */
650 if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
652 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
653 SetDrawtoField(DRAW_BUFFERED);
656 SetDrawtoField(DRAW_BACKBUFFER);
658 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
660 ClearRectangle(window, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
661 SetDrawtoField(DRAW_DIRECT);
665 void MarkTileDirty(int x, int y)
667 int xx = redraw_x1 + x;
668 int yy = redraw_y1 + y;
673 redraw[xx][yy] = TRUE;
674 redraw_mask |= REDRAW_TILES;
677 void SetBorderElement()
681 BorderElement = EL_EMPTY;
683 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
685 for (x = 0; x < lev_fieldx; x++)
687 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
688 BorderElement = EL_STEELWALL;
690 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
696 void SetRandomAnimationValue(int x, int y)
698 gfx.anim_random_frame = GfxRandom[x][y];
701 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
703 /* animation synchronized with global frame counter, not move position */
704 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
705 sync_frame = FrameCounter;
707 return getAnimationFrame(graphic_info[graphic].anim_frames,
708 graphic_info[graphic].anim_delay,
709 graphic_info[graphic].anim_mode,
710 graphic_info[graphic].anim_start_frame,
714 inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
715 int *x, int *y, boolean get_backside)
717 struct GraphicInfo *g = &graphic_info[graphic];
718 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
719 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
723 if (g->offset_y == 0) /* frames are ordered horizontally */
725 int max_width = g->anim_frames_per_line * g->width;
726 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
728 *x = pos % max_width;
729 *y = src_y % g->height + pos / max_width * g->height;
731 else if (g->offset_x == 0) /* frames are ordered vertically */
733 int max_height = g->anim_frames_per_line * g->height;
734 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
736 *x = src_x % g->width + pos / max_height * g->width;
737 *y = pos % max_height;
739 else /* frames are ordered diagonally */
741 *x = src_x + frame * g->offset_x;
742 *y = src_y + frame * g->offset_y;
746 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
748 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
751 void DrawGraphic(int x, int y, int graphic, int frame)
754 if (!IN_SCR_FIELD(x, y))
756 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
757 printf("DrawGraphic(): This should never happen!\n");
762 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
766 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
772 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
773 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
776 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
779 if (!IN_SCR_FIELD(x, y))
781 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
782 printf("DrawGraphicThruMask(): This should never happen!\n");
787 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
792 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
798 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
800 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
801 dst_x - src_x, dst_y - src_y);
802 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
805 void DrawMiniGraphic(int x, int y, int graphic)
807 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
808 MarkTileDirty(x / 2, y / 2);
811 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
813 struct GraphicInfo *g = &graphic_info[graphic];
815 int mini_starty = g->bitmap->height * 2 / 3;
818 *x = mini_startx + g->src_x / 2;
819 *y = mini_starty + g->src_y / 2;
822 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
827 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
828 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
831 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
832 int graphic, int frame,
833 int cut_mode, int mask_mode)
838 int width = TILEX, height = TILEY;
841 if (dx || dy) /* shifted graphic */
843 if (x < BX1) /* object enters playfield from the left */
850 else if (x > BX2) /* object enters playfield from the right */
856 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
862 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
864 else if (dx) /* general horizontal movement */
865 MarkTileDirty(x + SIGN(dx), y);
867 if (y < BY1) /* object enters playfield from the top */
869 if (cut_mode==CUT_BELOW) /* object completely above top border */
877 else if (y > BY2) /* object enters playfield from the bottom */
883 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
889 else if (dy > 0 && cut_mode == CUT_ABOVE)
891 if (y == BY2) /* object completely above bottom border */
897 MarkTileDirty(x, y + 1);
898 } /* object leaves playfield to the bottom */
899 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
901 else if (dy) /* general vertical movement */
902 MarkTileDirty(x, y + SIGN(dy));
906 if (!IN_SCR_FIELD(x, y))
908 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
909 printf("DrawGraphicShifted(): This should never happen!\n");
914 if (width > 0 && height > 0)
916 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
921 dst_x = FX + x * TILEX + dx;
922 dst_y = FY + y * TILEY + dy;
924 if (mask_mode == USE_MASKING)
926 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
927 dst_x - src_x, dst_y - src_y);
928 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
932 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
939 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
940 int graphic, int frame,
941 int cut_mode, int mask_mode)
946 int width = TILEX, height = TILEY;
949 int x2 = x + SIGN(dx);
950 int y2 = y + SIGN(dy);
951 int anim_frames = graphic_info[graphic].anim_frames;
952 int sync_frame = (dx ? ABS(dx) : ABS(dy)) * anim_frames / TILESIZE;
953 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
954 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
956 /* re-calculate animation frame for two-tile movement animation */
957 frame = getGraphicAnimationFrame(graphic, sync_frame);
959 /* check if movement start graphic inside screen area and should be drawn */
960 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
962 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
964 dst_x = FX + x1 * TILEX;
965 dst_y = FY + y1 * TILEY;
967 if (mask_mode == USE_MASKING)
969 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
970 dst_x - src_x, dst_y - src_y);
971 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
975 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
978 MarkTileDirty(x1, y1);
981 /* check if movement end graphic inside screen area and should be drawn */
982 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
984 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
986 dst_x = FX + x2 * TILEX;
987 dst_y = FY + y2 * TILEY;
989 if (mask_mode == USE_MASKING)
991 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
992 dst_x - src_x, dst_y - src_y);
993 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
997 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1000 MarkTileDirty(x2, y2);
1004 static void DrawGraphicShifted(int x, int y, int dx, int dy,
1005 int graphic, int frame,
1006 int cut_mode, int mask_mode)
1010 DrawGraphic(x, y, graphic, frame);
1015 if (graphic_info[graphic].double_movement) /* EM style movement images */
1016 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1018 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1021 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1022 int frame, int cut_mode)
1024 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
1027 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1028 int cut_mode, int mask_mode)
1030 int lx = LEVELX(x), ly = LEVELY(y);
1034 if (IN_LEV_FIELD(lx, ly))
1036 SetRandomAnimationValue(lx, ly);
1038 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
1039 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1041 /* do not use double (EM style) movement graphic when not moving */
1042 if (graphic_info[graphic].double_movement && !dx && !dy)
1044 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
1045 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1048 else /* border element */
1050 graphic = el2img(element);
1051 frame = getGraphicAnimationFrame(graphic, -1);
1054 if (element == EL_EXPANDABLE_WALL)
1056 boolean left_stopped = FALSE, right_stopped = FALSE;
1058 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1059 left_stopped = TRUE;
1060 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1061 right_stopped = TRUE;
1063 if (left_stopped && right_stopped)
1065 else if (left_stopped)
1067 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1068 frame = graphic_info[graphic].anim_frames - 1;
1070 else if (right_stopped)
1072 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1073 frame = graphic_info[graphic].anim_frames - 1;
1078 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1079 else if (mask_mode == USE_MASKING)
1080 DrawGraphicThruMask(x, y, graphic, frame);
1082 DrawGraphic(x, y, graphic, frame);
1085 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1086 int cut_mode, int mask_mode)
1088 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1089 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1090 cut_mode, mask_mode);
1093 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1096 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1099 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1102 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1105 void DrawLevelElementThruMask(int x, int y, int element)
1107 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1110 void DrawLevelFieldThruMask(int x, int y)
1112 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1115 static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
1119 int sx = SCREENX(x), sy = SCREENY(y);
1121 int width, height, cx, cy, i;
1122 int crumbled_border_size = graphic_info[graphic].border_size;
1123 static int xy[4][2] =
1131 if (!IN_LEV_FIELD(x, y))
1134 element = TILE_GFX_ELEMENT(x, y);
1136 /* crumble field itself */
1137 if (GFX_CRUMBLED(element) && !IS_MOVING(x, y))
1139 if (!IN_SCR_FIELD(sx, sy))
1142 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1144 for (i = 0; i < 4; i++)
1146 int xx = x + xy[i][0];
1147 int yy = y + xy[i][1];
1149 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1152 /* check if neighbour field is of same type */
1153 if (GFX_CRUMBLED(element) && !IS_MOVING(xx, yy))
1156 if (i == 1 || i == 2)
1158 width = crumbled_border_size;
1160 cx = (i == 2 ? TILEX - crumbled_border_size : 0);
1166 height = crumbled_border_size;
1168 cy = (i == 3 ? TILEY - crumbled_border_size : 0);
1171 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1172 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1175 MarkTileDirty(sx, sy);
1177 else /* crumble neighbour fields */
1179 for (i = 0; i < 4; i++)
1181 int xx = x + xy[i][0];
1182 int yy = y + xy[i][1];
1183 int sxx = sx + xy[i][0];
1184 int syy = sy + xy[i][1];
1186 if (!IN_LEV_FIELD(xx, yy) ||
1187 !IN_SCR_FIELD(sxx, syy) ||
1191 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
1194 element = TILE_GFX_ELEMENT(xx, yy);
1196 if (!GFX_CRUMBLED(element))
1199 graphic = el_act2crm(element, ACTION_DEFAULT);
1200 crumbled_border_size = graphic_info[graphic].border_size;
1202 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1204 if (i == 1 || i == 2)
1206 width = crumbled_border_size;
1208 cx = (i == 1 ? TILEX - crumbled_border_size : 0);
1214 height = crumbled_border_size;
1216 cy = (i == 0 ? TILEY - crumbled_border_size : 0);
1219 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1220 width, height, FX + sxx * TILEX + cx, FY + syy * TILEY + cy);
1222 MarkTileDirty(sxx, syy);
1227 void DrawLevelFieldCrumbledSand(int x, int y)
1231 if (!IN_LEV_FIELD(x, y))
1235 /* !!! CHECK THIS !!! */
1238 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1239 GFX_CRUMBLED(GfxElement[x][y]))
1242 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1243 GfxElement[x][y] != EL_UNDEFINED &&
1244 GFX_CRUMBLED(GfxElement[x][y]))
1246 DrawLevelFieldCrumbledSandDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
1253 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
1255 graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
1258 DrawLevelFieldCrumbledSandExt(x, y, graphic, 0);
1261 void DrawLevelFieldCrumbledSandDigging(int x, int y, int direction,
1264 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1265 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1266 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1267 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1268 int sx = SCREENX(x), sy = SCREENY(y);
1270 DrawGraphic(sx, sy, graphic1, frame1);
1271 DrawLevelFieldCrumbledSandExt(x, y, graphic2, frame2);
1274 void DrawLevelFieldCrumbledSandNeighbours(int x, int y)
1276 int sx = SCREENX(x), sy = SCREENY(y);
1277 static int xy[4][2] =
1286 for (i = 0; i < 4; i++)
1288 int xx = x + xy[i][0];
1289 int yy = y + xy[i][1];
1290 int sxx = sx + xy[i][0];
1291 int syy = sy + xy[i][1];
1293 if (!IN_LEV_FIELD(xx, yy) ||
1294 !IN_SCR_FIELD(sxx, syy) ||
1295 !GFX_CRUMBLED(Feld[xx][yy]) ||
1299 DrawLevelField(xx, yy);
1303 static int getBorderElement(int x, int y)
1307 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1308 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1309 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1310 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1311 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1312 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1313 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1315 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1316 int steel_position = (x == -1 && y == -1 ? 0 :
1317 x == lev_fieldx && y == -1 ? 1 :
1318 x == -1 && y == lev_fieldy ? 2 :
1319 x == lev_fieldx && y == lev_fieldy ? 3 :
1320 x == -1 || x == lev_fieldx ? 4 :
1321 y == -1 || y == lev_fieldy ? 5 : 6);
1323 return border[steel_position][steel_type];
1326 void DrawScreenElement(int x, int y, int element)
1328 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1329 DrawLevelFieldCrumbledSand(LEVELX(x), LEVELY(y));
1332 void DrawLevelElement(int x, int y, int element)
1334 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1335 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1338 void DrawScreenField(int x, int y)
1340 int lx = LEVELX(x), ly = LEVELY(y);
1341 int element, content;
1343 if (!IN_LEV_FIELD(lx, ly))
1345 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1348 element = getBorderElement(lx, ly);
1350 DrawScreenElement(x, y, element);
1354 element = Feld[lx][ly];
1355 content = Store[lx][ly];
1357 if (IS_MOVING(lx, ly))
1359 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1360 boolean cut_mode = NO_CUTTING;
1362 if (element == EL_QUICKSAND_EMPTYING ||
1363 element == EL_MAGIC_WALL_EMPTYING ||
1364 element == EL_BD_MAGIC_WALL_EMPTYING ||
1365 element == EL_AMOEBA_DROPPING)
1366 cut_mode = CUT_ABOVE;
1367 else if (element == EL_QUICKSAND_FILLING ||
1368 element == EL_MAGIC_WALL_FILLING ||
1369 element == EL_BD_MAGIC_WALL_FILLING)
1370 cut_mode = CUT_BELOW;
1372 if (cut_mode == CUT_ABOVE)
1373 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1375 DrawScreenElement(x, y, EL_EMPTY);
1378 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1379 else if (cut_mode == NO_CUTTING)
1380 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1382 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1384 if (content == EL_ACID)
1386 int dir = MovDir[lx][ly];
1387 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
1388 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
1390 DrawLevelElementThruMask(newlx, newly, EL_ACID);
1393 else if (IS_BLOCKED(lx, ly))
1398 boolean cut_mode = NO_CUTTING;
1399 int element_old, content_old;
1401 Blocked2Moving(lx, ly, &oldx, &oldy);
1404 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1405 MovDir[oldx][oldy] == MV_RIGHT);
1407 element_old = Feld[oldx][oldy];
1408 content_old = Store[oldx][oldy];
1410 if (element_old == EL_QUICKSAND_EMPTYING ||
1411 element_old == EL_MAGIC_WALL_EMPTYING ||
1412 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1413 element_old == EL_AMOEBA_DROPPING)
1414 cut_mode = CUT_ABOVE;
1416 DrawScreenElement(x, y, EL_EMPTY);
1419 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1421 else if (cut_mode == NO_CUTTING)
1422 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1425 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1428 else if (IS_DRAWABLE(element))
1429 DrawScreenElement(x, y, element);
1431 DrawScreenElement(x, y, EL_EMPTY);
1434 void DrawLevelField(int x, int y)
1436 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1437 DrawScreenField(SCREENX(x), SCREENY(y));
1438 else if (IS_MOVING(x, y))
1442 Moving2Blocked(x, y, &newx, &newy);
1443 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1444 DrawScreenField(SCREENX(newx), SCREENY(newy));
1446 else if (IS_BLOCKED(x, y))
1450 Blocked2Moving(x, y, &oldx, &oldy);
1451 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1452 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1456 void DrawMiniElement(int x, int y, int element)
1460 graphic = el2edimg(element);
1461 DrawMiniGraphic(x, y, graphic);
1464 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1466 int x = sx + scroll_x, y = sy + scroll_y;
1468 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1469 DrawMiniElement(sx, sy, EL_EMPTY);
1470 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1471 DrawMiniElement(sx, sy, Feld[x][y]);
1473 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1476 void DrawEnvelopeBackground(int envelope_nr, int startx, int starty,
1477 int x, int y, int xsize, int ysize, int font_nr)
1479 int font_width = getFontWidth(font_nr);
1480 int font_height = getFontHeight(font_nr);
1481 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1484 int dst_x = SX + startx + x * font_width;
1485 int dst_y = SY + starty + y * font_height;
1486 int width = graphic_info[graphic].width;
1487 int height = graphic_info[graphic].height;
1488 int inner_width = MAX(width - 2 * font_width, font_width);
1489 int inner_height = MAX(height - 2 * font_height, font_height);
1490 int inner_sx = (width >= 3 * font_width ? font_width : 0);
1491 int inner_sy = (height >= 3 * font_height ? font_height : 0);
1492 boolean draw_masked = graphic_info[graphic].draw_masked;
1494 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1496 if (src_bitmap == NULL || width < font_width || height < font_height)
1498 ClearRectangle(drawto, dst_x, dst_y, font_width, font_height);
1502 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - font_width :
1503 inner_sx + (x - 1) * font_width % inner_width);
1504 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - font_height :
1505 inner_sy + (y - 1) * font_height % inner_height);
1509 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1510 dst_x - src_x, dst_y - src_y);
1511 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1515 BlitBitmap(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1519 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
1521 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1522 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1523 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
1524 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1525 boolean no_delay = (tape.warp_forward);
1526 unsigned long anim_delay = 0;
1527 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
1528 int anim_delay_value = (no_delay ? 0 : frame_delay_value);
1529 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
1530 int font_width = getFontWidth(font_nr);
1531 int font_height = getFontHeight(font_nr);
1532 int max_xsize = level.envelope[envelope_nr].xsize;
1533 int max_ysize = level.envelope[envelope_nr].ysize;
1534 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
1535 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
1536 int xend = max_xsize;
1537 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
1538 int xstep = (xstart < xend ? 1 : 0);
1539 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
1542 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
1544 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
1545 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
1546 int sx = (SXSIZE - xsize * font_width) / 2;
1547 int sy = (SYSIZE - ysize * font_height) / 2;
1550 SetDrawtoField(DRAW_BUFFERED);
1552 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
1554 SetDrawtoField(DRAW_BACKBUFFER);
1556 for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++)
1557 DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
1559 DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
1560 level.envelope[envelope_nr].text, font_nr, max_xsize,
1561 xsize - 2, ysize - 2, mask_mode);
1563 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
1566 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
1570 void ShowEnvelope(int envelope_nr)
1572 int element = EL_ENVELOPE_1 + envelope_nr;
1573 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1574 int sound_opening = element_info[element].sound[ACTION_OPENING];
1575 int sound_closing = element_info[element].sound[ACTION_CLOSING];
1576 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1577 boolean no_delay = (tape.warp_forward);
1578 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
1579 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
1580 int anim_mode = graphic_info[graphic].anim_mode;
1581 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
1582 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
1584 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
1586 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
1588 if (anim_mode == ANIM_DEFAULT)
1589 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
1591 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
1594 Delay(wait_delay_value);
1596 WaitForEventToContinue();
1598 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
1600 if (anim_mode != ANIM_NONE)
1601 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
1603 if (anim_mode == ANIM_DEFAULT)
1604 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
1606 game.envelope_active = FALSE;
1608 SetDrawtoField(DRAW_BUFFERED);
1610 redraw_mask |= REDRAW_FIELD;
1614 void getPreviewGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y,
1619 int width_mult, width_div;
1620 int height_mult, height_div;
1628 int offset_calc_pos = (tilesize < MICRO_TILESIZE || tilesize > TILESIZE ? 3 :
1629 5 - log_2(tilesize));
1630 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1631 int width_mult = offset_calc[offset_calc_pos].width_mult;
1632 int width_div = offset_calc[offset_calc_pos].width_div;
1633 int height_mult = offset_calc[offset_calc_pos].height_mult;
1634 int height_div = offset_calc[offset_calc_pos].height_div;
1635 int mini_startx = src_bitmap->width * width_mult / width_div;
1636 int mini_starty = src_bitmap->height * height_mult / height_div;
1637 int src_x = mini_startx + graphic_info[graphic].src_x * tilesize / TILESIZE;
1638 int src_y = mini_starty + graphic_info[graphic].src_y * tilesize / TILESIZE;
1640 *bitmap = src_bitmap;
1645 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
1649 int graphic = el2preimg(element);
1651 getPreviewGraphicSource(graphic, &src_bitmap, &src_x, &src_y, tilesize);
1652 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
1659 SetDrawBackgroundMask(REDRAW_NONE);
1662 for (x = BX1; x <= BX2; x++)
1663 for (y = BY1; y <= BY2; y++)
1664 DrawScreenField(x, y);
1666 redraw_mask |= REDRAW_FIELD;
1669 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1673 for (x = 0; x < size_x; x++)
1674 for (y = 0; y < size_y; y++)
1675 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1677 redraw_mask |= REDRAW_FIELD;
1680 static void DrawPreviewLevelExt(int from_x, int from_y)
1682 boolean show_level_border = (BorderElement != EL_EMPTY);
1683 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
1684 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
1685 int tile_size = preview.tile_size;
1686 int preview_width = preview.xsize * tile_size;
1687 int preview_height = preview.ysize * tile_size;
1688 int real_preview_xsize = MIN(level_xsize, preview.xsize);
1689 int real_preview_ysize = MIN(level_ysize, preview.ysize);
1690 int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
1691 int dst_y = SY + preview.y;
1694 DrawBackground(dst_x, dst_y, preview_width, preview_height);
1696 dst_x += (preview_width - real_preview_xsize * tile_size) / 2;
1697 dst_y += (preview_height - real_preview_ysize * tile_size) / 2;
1699 for (x = 0; x < real_preview_xsize; x++)
1701 for (y = 0; y < real_preview_ysize; y++)
1703 int lx = from_x + x + (show_level_border ? -1 : 0);
1704 int ly = from_y + y + (show_level_border ? -1 : 0);
1705 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
1706 getBorderElement(lx, ly));
1708 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
1709 element, tile_size);
1713 redraw_mask |= REDRAW_MICROLEVEL;
1716 #define MICROLABEL_EMPTY 0
1717 #define MICROLABEL_LEVEL_NAME 1
1718 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
1719 #define MICROLABEL_LEVEL_AUTHOR 3
1720 #define MICROLABEL_IMPORTED_FROM_HEAD 4
1721 #define MICROLABEL_IMPORTED_FROM 5
1722 #define MICROLABEL_IMPORTED_BY_HEAD 6
1723 #define MICROLABEL_IMPORTED_BY 7
1725 static int getMaxTextLength(struct MenuPosInfo *pos, int font_nr)
1727 int max_text_width = SXSIZE;
1728 int font_width = getFontWidth(font_nr);
1730 if (pos->align == ALIGN_CENTER)
1731 max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
1732 else if (pos->align == ALIGN_RIGHT)
1733 max_text_width = pos->x;
1735 max_text_width = SXSIZE - pos->x;
1737 return max_text_width / font_width;
1740 static void DrawPreviewLevelLabelExt(int mode)
1742 struct MenuPosInfo *pos = &menu.main.text.level_info_2;
1743 char label_text[MAX_OUTPUT_LINESIZE + 1];
1744 int max_len_label_text;
1745 int font_nr = FONT_TEXT_2;
1748 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
1749 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
1750 mode == MICROLABEL_IMPORTED_BY_HEAD)
1751 font_nr = FONT_TEXT_3;
1754 max_len_label_text = getMaxTextLength(pos, font_nr);
1756 max_len_label_text = SXSIZE / getFontWidth(font_nr);
1759 for (i = 0; i < max_len_label_text; i++)
1760 label_text[i] = ' ';
1761 label_text[max_len_label_text] = '\0';
1763 if (strlen(label_text) > 0)
1766 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
1768 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1769 int lypos = MICROLABEL2_YPOS;
1771 DrawText(lxpos, lypos, label_text, font_nr);
1776 (mode == MICROLABEL_LEVEL_NAME ? level.name :
1777 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
1778 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1779 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
1780 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
1781 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
1782 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
1783 max_len_label_text);
1784 label_text[max_len_label_text] = '\0';
1786 if (strlen(label_text) > 0)
1789 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
1791 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1792 int lypos = MICROLABEL2_YPOS;
1794 DrawText(lxpos, lypos, label_text, font_nr);
1798 redraw_mask |= REDRAW_MICROLEVEL;
1801 void DrawPreviewLevel(boolean restart)
1803 static unsigned long scroll_delay = 0;
1804 static unsigned long label_delay = 0;
1805 static int from_x, from_y, scroll_direction;
1806 static int label_state, label_counter;
1807 unsigned long scroll_delay_value = preview.step_delay;
1808 boolean show_level_border = (BorderElement != EL_EMPTY);
1809 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
1810 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
1811 int last_game_status = game_status; /* save current game status */
1813 /* force PREVIEW font on preview level */
1814 game_status = GAME_MODE_PSEUDO_PREVIEW;
1821 if (preview.anim_mode == ANIM_CENTERED)
1823 if (level_xsize > preview.xsize)
1824 from_x = (level_xsize - preview.xsize) / 2;
1825 if (level_ysize > preview.ysize)
1826 from_y = (level_ysize - preview.ysize) / 2;
1829 from_x += preview.xoffset;
1830 from_y += preview.yoffset;
1832 scroll_direction = MV_RIGHT;
1836 DrawPreviewLevelExt(from_x, from_y);
1837 DrawPreviewLevelLabelExt(label_state);
1839 /* initialize delay counters */
1840 DelayReached(&scroll_delay, 0);
1841 DelayReached(&label_delay, 0);
1843 if (leveldir_current->name)
1845 struct MenuPosInfo *pos = &menu.main.text.level_info_1;
1846 char label_text[MAX_OUTPUT_LINESIZE + 1];
1847 int font_nr = FONT_TEXT_1;
1849 int max_len_label_text = getMaxTextLength(pos, font_nr);
1851 int max_len_label_text = SXSIZE / getFontWidth(font_nr);
1858 strncpy(label_text, leveldir_current->name, max_len_label_text);
1859 label_text[max_len_label_text] = '\0';
1862 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
1864 lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1865 lypos = SY + MICROLABEL1_YPOS;
1867 DrawText(lxpos, lypos, label_text, font_nr);
1871 game_status = last_game_status; /* restore current game status */
1876 /* scroll preview level, if needed */
1877 if (preview.anim_mode != ANIM_NONE &&
1878 (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
1879 DelayReached(&scroll_delay, scroll_delay_value))
1881 switch (scroll_direction)
1886 from_x -= preview.step_offset;
1887 from_x = (from_x < 0 ? 0 : from_x);
1890 scroll_direction = MV_UP;
1894 if (from_x < level_xsize - preview.xsize)
1896 from_x += preview.step_offset;
1897 from_x = (from_x > level_xsize - preview.xsize ?
1898 level_xsize - preview.xsize : from_x);
1901 scroll_direction = MV_DOWN;
1907 from_y -= preview.step_offset;
1908 from_y = (from_y < 0 ? 0 : from_y);
1911 scroll_direction = MV_RIGHT;
1915 if (from_y < level_ysize - preview.ysize)
1917 from_y += preview.step_offset;
1918 from_y = (from_y > level_ysize - preview.ysize ?
1919 level_ysize - preview.ysize : from_y);
1922 scroll_direction = MV_LEFT;
1929 DrawPreviewLevelExt(from_x, from_y);
1932 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
1933 /* redraw micro level label, if needed */
1934 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
1935 !strEqual(level.author, ANONYMOUS_NAME) &&
1936 !strEqual(level.author, leveldir_current->name) &&
1937 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
1939 int max_label_counter = 23;
1941 if (leveldir_current->imported_from != NULL &&
1942 strlen(leveldir_current->imported_from) > 0)
1943 max_label_counter += 14;
1944 if (leveldir_current->imported_by != NULL &&
1945 strlen(leveldir_current->imported_by) > 0)
1946 max_label_counter += 14;
1948 label_counter = (label_counter + 1) % max_label_counter;
1949 label_state = (label_counter >= 0 && label_counter <= 7 ?
1950 MICROLABEL_LEVEL_NAME :
1951 label_counter >= 9 && label_counter <= 12 ?
1952 MICROLABEL_LEVEL_AUTHOR_HEAD :
1953 label_counter >= 14 && label_counter <= 21 ?
1954 MICROLABEL_LEVEL_AUTHOR :
1955 label_counter >= 23 && label_counter <= 26 ?
1956 MICROLABEL_IMPORTED_FROM_HEAD :
1957 label_counter >= 28 && label_counter <= 35 ?
1958 MICROLABEL_IMPORTED_FROM :
1959 label_counter >= 37 && label_counter <= 40 ?
1960 MICROLABEL_IMPORTED_BY_HEAD :
1961 label_counter >= 42 && label_counter <= 49 ?
1962 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
1964 if (leveldir_current->imported_from == NULL &&
1965 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
1966 label_state == MICROLABEL_IMPORTED_FROM))
1967 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
1968 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
1970 DrawPreviewLevelLabelExt(label_state);
1973 game_status = last_game_status; /* restore current game status */
1976 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
1977 int graphic, int sync_frame, int mask_mode)
1979 int frame = getGraphicAnimationFrame(graphic, sync_frame);
1981 if (mask_mode == USE_MASKING)
1982 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
1984 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
1987 inline void DrawGraphicAnimation(int x, int y, int graphic)
1989 int lx = LEVELX(x), ly = LEVELY(y);
1991 if (!IN_SCR_FIELD(x, y))
1994 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
1995 graphic, GfxFrame[lx][ly], NO_MASKING);
1996 MarkTileDirty(x, y);
1999 void DrawLevelGraphicAnimation(int x, int y, int graphic)
2001 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2004 void DrawLevelElementAnimation(int x, int y, int element)
2006 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2008 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2011 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
2013 int sx = SCREENX(x), sy = SCREENY(y);
2015 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2018 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2021 DrawGraphicAnimation(sx, sy, graphic);
2024 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
2025 DrawLevelFieldCrumbledSand(x, y);
2027 if (GFX_CRUMBLED(Feld[x][y]))
2028 DrawLevelFieldCrumbledSand(x, y);
2032 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
2034 int sx = SCREENX(x), sy = SCREENY(y);
2037 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2040 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2042 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2045 DrawGraphicAnimation(sx, sy, graphic);
2047 if (GFX_CRUMBLED(element))
2048 DrawLevelFieldCrumbledSand(x, y);
2051 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
2053 if (player->use_murphy)
2055 /* this works only because currently only one player can be "murphy" ... */
2056 static int last_horizontal_dir = MV_LEFT;
2057 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
2059 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2060 last_horizontal_dir = move_dir;
2062 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
2064 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
2066 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
2072 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
2075 static boolean equalGraphics(int graphic1, int graphic2)
2077 struct GraphicInfo *g1 = &graphic_info[graphic1];
2078 struct GraphicInfo *g2 = &graphic_info[graphic2];
2080 return (g1->bitmap == g2->bitmap &&
2081 g1->src_x == g2->src_x &&
2082 g1->src_y == g2->src_y &&
2083 g1->anim_frames == g2->anim_frames &&
2084 g1->anim_delay == g2->anim_delay &&
2085 g1->anim_mode == g2->anim_mode);
2088 void DrawAllPlayers()
2092 for (i = 0; i < MAX_PLAYERS; i++)
2093 if (stored_player[i].active)
2094 DrawPlayer(&stored_player[i]);
2097 void DrawPlayerField(int x, int y)
2099 if (!IS_PLAYER(x, y))
2102 DrawPlayer(PLAYERINFO(x, y));
2105 void DrawPlayer(struct PlayerInfo *player)
2107 int jx = player->jx;
2108 int jy = player->jy;
2109 int move_dir = player->MovDir;
2110 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
2111 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
2112 int last_jx = (player->is_moving ? jx - dx : jx);
2113 int last_jy = (player->is_moving ? jy - dy : jy);
2114 int next_jx = jx + dx;
2115 int next_jy = jy + dy;
2116 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
2117 boolean player_is_opaque = FALSE;
2118 int sx = SCREENX(jx), sy = SCREENY(jy);
2119 int sxx = 0, syy = 0;
2120 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
2122 int action = ACTION_DEFAULT;
2123 int last_player_graphic = getPlayerGraphic(player, move_dir);
2124 int last_player_frame = player->Frame;
2127 /* GfxElement[][] is set to the element the player is digging or collecting;
2128 remove also for off-screen player if the player is not moving anymore */
2129 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
2130 GfxElement[jx][jy] = EL_UNDEFINED;
2132 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
2136 if (!IN_LEV_FIELD(jx, jy))
2138 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
2139 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
2140 printf("DrawPlayerField(): This should never happen!\n");
2145 if (element == EL_EXPLOSION)
2148 action = (player->is_pushing ? ACTION_PUSHING :
2149 player->is_digging ? ACTION_DIGGING :
2150 player->is_collecting ? ACTION_COLLECTING :
2151 player->is_moving ? ACTION_MOVING :
2152 player->is_snapping ? ACTION_SNAPPING :
2153 player->is_dropping ? ACTION_DROPPING :
2154 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
2156 if (player->is_waiting)
2157 move_dir = player->dir_waiting;
2159 InitPlayerGfxAnimation(player, action, move_dir);
2161 /* ----------------------------------------------------------------------- */
2162 /* draw things in the field the player is leaving, if needed */
2163 /* ----------------------------------------------------------------------- */
2165 if (player->is_moving)
2167 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
2169 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
2171 if (last_element == EL_DYNAMITE_ACTIVE ||
2172 last_element == EL_EM_DYNAMITE_ACTIVE ||
2173 last_element == EL_SP_DISK_RED_ACTIVE)
2174 DrawDynamite(last_jx, last_jy);
2176 DrawLevelFieldThruMask(last_jx, last_jy);
2178 else if (last_element == EL_DYNAMITE_ACTIVE ||
2179 last_element == EL_EM_DYNAMITE_ACTIVE ||
2180 last_element == EL_SP_DISK_RED_ACTIVE)
2181 DrawDynamite(last_jx, last_jy);
2183 /* !!! this is not enough to prevent flickering of players which are
2184 moving next to each others without a free tile between them -- this
2185 can only be solved by drawing all players layer by layer (first the
2186 background, then the foreground etc.) !!! => TODO */
2187 else if (!IS_PLAYER(last_jx, last_jy))
2188 DrawLevelField(last_jx, last_jy);
2191 DrawLevelField(last_jx, last_jy);
2194 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
2195 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
2198 if (!IN_SCR_FIELD(sx, sy))
2201 if (setup.direct_draw)
2202 SetDrawtoField(DRAW_BUFFERED);
2204 /* ----------------------------------------------------------------------- */
2205 /* draw things behind the player, if needed */
2206 /* ----------------------------------------------------------------------- */
2209 DrawLevelElement(jx, jy, Back[jx][jy]);
2210 else if (IS_ACTIVE_BOMB(element))
2211 DrawLevelElement(jx, jy, EL_EMPTY);
2214 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
2216 int old_element = GfxElement[jx][jy];
2217 int old_graphic = el_act_dir2img(old_element, action, move_dir);
2218 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
2220 if (GFX_CRUMBLED(old_element))
2221 DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
2223 DrawGraphic(sx, sy, old_graphic, frame);
2225 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
2226 player_is_opaque = TRUE;
2230 GfxElement[jx][jy] = EL_UNDEFINED;
2232 /* make sure that pushed elements are drawn with correct frame rate */
2234 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2236 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
2237 GfxFrame[jx][jy] = player->StepFrame;
2239 if (player->is_pushing && player->is_moving)
2240 GfxFrame[jx][jy] = player->StepFrame;
2243 DrawLevelField(jx, jy);
2247 /* ----------------------------------------------------------------------- */
2248 /* draw player himself */
2249 /* ----------------------------------------------------------------------- */
2251 graphic = getPlayerGraphic(player, move_dir);
2253 /* in the case of changed player action or direction, prevent the current
2254 animation frame from being restarted for identical animations */
2255 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
2256 player->Frame = last_player_frame;
2258 frame = getGraphicAnimationFrame(graphic, player->Frame);
2262 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2263 sxx = player->GfxPos;
2265 syy = player->GfxPos;
2268 if (!setup.soft_scrolling && ScreenMovPos)
2271 if (player_is_opaque)
2272 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
2274 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2276 if (SHIELD_ON(player))
2278 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
2279 IMG_SHIELD_NORMAL_ACTIVE);
2280 int frame = getGraphicAnimationFrame(graphic, -1);
2282 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2285 /* ----------------------------------------------------------------------- */
2286 /* draw things the player is pushing, if needed */
2287 /* ----------------------------------------------------------------------- */
2290 printf("::: %d, %d [%d, %d] [%d]\n",
2291 player->is_pushing, player_is_moving, player->GfxAction,
2292 player->is_moving, player_is_moving);
2296 if (player->is_pushing && player->is_moving)
2298 int px = SCREENX(jx), py = SCREENY(jy);
2299 int pxx = (TILEX - ABS(sxx)) * dx;
2300 int pyy = (TILEY - ABS(syy)) * dy;
2301 int gfx_frame = GfxFrame[jx][jy];
2307 if (!IS_MOVING(jx, jy)) /* push movement already finished */
2309 element = Feld[next_jx][next_jy];
2310 gfx_frame = GfxFrame[next_jx][next_jy];
2313 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2316 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
2317 frame = getGraphicAnimationFrame(graphic, sync_frame);
2319 frame = getGraphicAnimationFrame(graphic, player->StepFrame);
2322 /* draw background element under pushed element (like the Sokoban field) */
2323 if (Back[next_jx][next_jy])
2324 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
2326 /* masked drawing is needed for EMC style (double) movement graphics */
2327 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
2331 /* ----------------------------------------------------------------------- */
2332 /* draw things in front of player (active dynamite or dynabombs) */
2333 /* ----------------------------------------------------------------------- */
2335 if (IS_ACTIVE_BOMB(element))
2337 graphic = el2img(element);
2338 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
2340 if (game.emulation == EMU_SUPAPLEX)
2341 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
2343 DrawGraphicThruMask(sx, sy, graphic, frame);
2346 if (player_is_moving && last_element == EL_EXPLOSION)
2348 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
2349 GfxElement[last_jx][last_jy] : EL_EMPTY);
2350 int graphic = el_act2img(element, ACTION_EXPLODING);
2351 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
2352 int phase = ExplodePhase[last_jx][last_jy] - 1;
2353 int frame = getGraphicAnimationFrame(graphic, phase - delay);
2356 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
2359 /* ----------------------------------------------------------------------- */
2360 /* draw elements the player is just walking/passing through/under */
2361 /* ----------------------------------------------------------------------- */
2363 if (player_is_moving)
2365 /* handle the field the player is leaving ... */
2366 if (IS_ACCESSIBLE_INSIDE(last_element))
2367 DrawLevelField(last_jx, last_jy);
2368 else if (IS_ACCESSIBLE_UNDER(last_element))
2369 DrawLevelFieldThruMask(last_jx, last_jy);
2372 /* do not redraw accessible elements if the player is just pushing them */
2373 if (!player_is_moving || !player->is_pushing)
2375 /* ... and the field the player is entering */
2376 if (IS_ACCESSIBLE_INSIDE(element))
2377 DrawLevelField(jx, jy);
2378 else if (IS_ACCESSIBLE_UNDER(element))
2379 DrawLevelFieldThruMask(jx, jy);
2382 if (setup.direct_draw)
2384 int dst_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
2385 int dst_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
2386 int x_size = TILEX * (1 + ABS(jx - last_jx));
2387 int y_size = TILEY * (1 + ABS(jy - last_jy));
2389 BlitBitmap(drawto_field, window,
2390 dst_x, dst_y, x_size, y_size, dst_x, dst_y);
2391 SetDrawtoField(DRAW_DIRECT);
2394 MarkTileDirty(sx, sy);
2397 /* ------------------------------------------------------------------------- */
2399 void WaitForEventToContinue()
2401 boolean still_wait = TRUE;
2403 /* simulate releasing mouse button over last gadget, if still pressed */
2405 HandleGadgets(-1, -1, 0);
2407 button_status = MB_RELEASED;
2423 case EVENT_BUTTONPRESS:
2424 case EVENT_KEYPRESS:
2428 case EVENT_KEYRELEASE:
2429 ClearPlayerAction();
2433 HandleOtherEvents(&event);
2437 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2444 /* don't eat all CPU time */
2449 #define MAX_REQUEST_LINES 13
2450 #define MAX_REQUEST_LINE_FONT1_LEN 7
2451 #define MAX_REQUEST_LINE_FONT2_LEN 10
2453 boolean Request(char *text, unsigned int req_state)
2455 int mx, my, ty, result = -1;
2456 unsigned int old_door_state;
2457 int last_game_status = game_status; /* save current game status */
2458 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
2459 int font_nr = FONT_TEXT_2;
2460 int max_word_len = 0;
2463 for (text_ptr = text; *text_ptr; text_ptr++)
2465 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
2467 if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
2469 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
2470 font_nr = FONT_LEVEL_NUMBER;
2476 if (game_status == GAME_MODE_PLAYING &&
2477 level.game_engine_type == GAME_ENGINE_TYPE_EM)
2478 BlitScreenToBitmap_EM(backbuffer);
2480 /* disable deactivated drawing when quick-loading level tape recording */
2481 if (tape.playing && tape.deactivate_display)
2482 TapeDeactivateDisplayOff(TRUE);
2484 SetMouseCursor(CURSOR_DEFAULT);
2486 #if defined(NETWORK_AVALIABLE)
2487 /* pause network game while waiting for request to answer */
2488 if (options.network &&
2489 game_status == GAME_MODE_PLAYING &&
2490 req_state & REQUEST_WAIT_FOR_INPUT)
2491 SendToServer_PausePlaying();
2494 old_door_state = GetDoorState();
2496 /* simulate releasing mouse button over last gadget, if still pressed */
2498 HandleGadgets(-1, -1, 0);
2502 if (old_door_state & DOOR_OPEN_1)
2504 CloseDoor(DOOR_CLOSE_1);
2506 /* save old door content */
2507 BlitBitmap(bitmap_db_door, bitmap_db_door,
2508 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2509 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
2513 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2516 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2518 /* clear door drawing field */
2519 DrawBackground(DX, DY, DXSIZE, DYSIZE);
2521 /* force DOOR font on preview level */
2522 game_status = GAME_MODE_PSEUDO_DOOR;
2524 /* write text for request */
2525 for (ty = 0; ty < MAX_REQUEST_LINES; ty++)
2527 char text_line[max_request_line_len + 1];
2533 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
2536 if (!tc || tc == ' ')
2547 strncpy(text_line, text, tl);
2550 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
2551 DY + 8 + ty * (getFontHeight(font_nr) + 2),
2552 text_line, font_nr);
2554 text += tl + (tc == ' ' ? 1 : 0);
2557 game_status = last_game_status; /* restore current game status */
2559 if (req_state & REQ_ASK)
2561 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2562 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2564 else if (req_state & REQ_CONFIRM)
2566 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2568 else if (req_state & REQ_PLAYER)
2570 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2571 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2572 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2573 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2576 /* copy request gadgets to door backbuffer */
2577 BlitBitmap(drawto, bitmap_db_door,
2578 DX, DY, DXSIZE, DYSIZE,
2579 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2581 OpenDoor(DOOR_OPEN_1);
2583 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
2585 if (game_status == GAME_MODE_PLAYING)
2587 SetPanelBackground();
2588 SetDrawBackgroundMask(REDRAW_DOOR_1);
2592 SetDrawBackgroundMask(REDRAW_FIELD);
2598 if (game_status != GAME_MODE_MAIN)
2601 button_status = MB_RELEASED;
2603 request_gadget_id = -1;
2605 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2617 case EVENT_BUTTONPRESS:
2618 case EVENT_BUTTONRELEASE:
2619 case EVENT_MOTIONNOTIFY:
2621 if (event.type == EVENT_MOTIONNOTIFY)
2623 if (!PointerInWindow(window))
2624 continue; /* window and pointer are on different screens */
2629 motion_status = TRUE;
2630 mx = ((MotionEvent *) &event)->x;
2631 my = ((MotionEvent *) &event)->y;
2635 motion_status = FALSE;
2636 mx = ((ButtonEvent *) &event)->x;
2637 my = ((ButtonEvent *) &event)->y;
2638 if (event.type == EVENT_BUTTONPRESS)
2639 button_status = ((ButtonEvent *) &event)->button;
2641 button_status = MB_RELEASED;
2644 /* this sets 'request_gadget_id' */
2645 HandleGadgets(mx, my, button_status);
2647 switch (request_gadget_id)
2649 case TOOL_CTRL_ID_YES:
2652 case TOOL_CTRL_ID_NO:
2655 case TOOL_CTRL_ID_CONFIRM:
2656 result = TRUE | FALSE;
2659 case TOOL_CTRL_ID_PLAYER_1:
2662 case TOOL_CTRL_ID_PLAYER_2:
2665 case TOOL_CTRL_ID_PLAYER_3:
2668 case TOOL_CTRL_ID_PLAYER_4:
2679 case EVENT_KEYPRESS:
2680 switch (GetEventKey((KeyEvent *)&event, TRUE))
2693 if (req_state & REQ_PLAYER)
2697 case EVENT_KEYRELEASE:
2698 ClearPlayerAction();
2702 HandleOtherEvents(&event);
2706 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2708 int joy = AnyJoystick();
2710 if (joy & JOY_BUTTON_1)
2712 else if (joy & JOY_BUTTON_2)
2719 if (!PendingEvent()) /* delay only if no pending events */
2722 /* don't eat all CPU time */
2727 if (game_status != GAME_MODE_MAIN)
2732 if (!(req_state & REQ_STAY_OPEN))
2734 CloseDoor(DOOR_CLOSE_1);
2736 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
2737 (req_state & REQ_REOPEN))
2738 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
2743 if (game_status == GAME_MODE_PLAYING)
2745 SetPanelBackground();
2746 SetDrawBackgroundMask(REDRAW_DOOR_1);
2750 SetDrawBackgroundMask(REDRAW_FIELD);
2753 #if defined(NETWORK_AVALIABLE)
2754 /* continue network game after request */
2755 if (options.network &&
2756 game_status == GAME_MODE_PLAYING &&
2757 req_state & REQUEST_WAIT_FOR_INPUT)
2758 SendToServer_ContinuePlaying();
2761 /* restore deactivated drawing when quick-loading level tape recording */
2762 if (tape.playing && tape.deactivate_display)
2763 TapeDeactivateDisplayOn();
2768 unsigned int OpenDoor(unsigned int door_state)
2770 if (door_state & DOOR_COPY_BACK)
2772 if (door_state & DOOR_OPEN_1)
2773 BlitBitmap(bitmap_db_door, bitmap_db_door,
2774 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2775 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2777 if (door_state & DOOR_OPEN_2)
2778 BlitBitmap(bitmap_db_door, bitmap_db_door,
2779 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
2780 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2782 door_state &= ~DOOR_COPY_BACK;
2785 return MoveDoor(door_state);
2788 unsigned int CloseDoor(unsigned int door_state)
2790 unsigned int old_door_state = GetDoorState();
2792 if (!(door_state & DOOR_NO_COPY_BACK))
2794 if (old_door_state & DOOR_OPEN_1)
2795 BlitBitmap(backbuffer, bitmap_db_door,
2796 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2798 if (old_door_state & DOOR_OPEN_2)
2799 BlitBitmap(backbuffer, bitmap_db_door,
2800 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2802 door_state &= ~DOOR_NO_COPY_BACK;
2805 return MoveDoor(door_state);
2808 unsigned int GetDoorState()
2810 return MoveDoor(DOOR_GET_STATE);
2813 unsigned int SetDoorState(unsigned int door_state)
2815 return MoveDoor(door_state | DOOR_SET_STATE);
2818 unsigned int MoveDoor(unsigned int door_state)
2820 static int door1 = DOOR_OPEN_1;
2821 static int door2 = DOOR_CLOSE_2;
2822 unsigned long door_delay = 0;
2823 unsigned long door_delay_value;
2826 if (door_1.width < 0 || door_1.width > DXSIZE)
2827 door_1.width = DXSIZE;
2828 if (door_1.height < 0 || door_1.height > DYSIZE)
2829 door_1.height = DYSIZE;
2830 if (door_2.width < 0 || door_2.width > VXSIZE)
2831 door_2.width = VXSIZE;
2832 if (door_2.height < 0 || door_2.height > VYSIZE)
2833 door_2.height = VYSIZE;
2835 if (door_state == DOOR_GET_STATE)
2836 return (door1 | door2);
2838 if (door_state & DOOR_SET_STATE)
2840 if (door_state & DOOR_ACTION_1)
2841 door1 = door_state & DOOR_ACTION_1;
2842 if (door_state & DOOR_ACTION_2)
2843 door2 = door_state & DOOR_ACTION_2;
2845 return (door1 | door2);
2848 if (!(door_state & DOOR_FORCE_REDRAW))
2850 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2851 door_state &= ~DOOR_OPEN_1;
2852 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2853 door_state &= ~DOOR_CLOSE_1;
2854 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2855 door_state &= ~DOOR_OPEN_2;
2856 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2857 door_state &= ~DOOR_CLOSE_2;
2860 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
2863 if (setup.quick_doors)
2865 stepsize = 20; /* must be choosen to always draw last frame */
2866 door_delay_value = 0;
2869 if (global.autoplay_leveldir)
2871 door_state |= DOOR_NO_DELAY;
2872 door_state &= ~DOOR_CLOSE_ALL;
2875 if (door_state & DOOR_ACTION)
2877 boolean handle_door_1 = (door_state & DOOR_ACTION_1);
2878 boolean handle_door_2 = (door_state & DOOR_ACTION_2);
2879 boolean door_1_done = (!handle_door_1);
2880 boolean door_2_done = (!handle_door_2);
2881 boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
2882 boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
2883 int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
2884 int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
2885 int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
2886 int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
2887 int door_size = (handle_door_1 ? door_size_1 : door_size_2);
2888 int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
2889 int door_skip = max_door_size - door_size;
2890 int end = door_size;
2891 int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
2894 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
2896 /* opening door sound has priority over simultaneously closing door */
2897 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2898 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2899 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2900 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2903 for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
2906 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2907 GC gc = bitmap->stored_clip_gc;
2909 if (door_state & DOOR_ACTION_1)
2911 int a = MIN(x * door_1.step_offset, end);
2912 int p = (door_state & DOOR_OPEN_1 ? end - a : a);
2913 int i = p + door_skip;
2915 if (door_1.anim_mode & ANIM_STATIC_PANEL)
2917 BlitBitmap(bitmap_db_door, drawto,
2918 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
2919 DXSIZE, DYSIZE, DX, DY);
2923 BlitBitmap(bitmap_db_door, drawto,
2924 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
2925 DXSIZE, DYSIZE - p / 2, DX, DY);
2927 ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
2930 if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
2932 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2933 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
2934 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
2935 int dst2_x = DX, dst2_y = DY;
2936 int width = i, height = DYSIZE;
2938 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2939 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2942 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2943 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2946 else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
2948 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2949 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
2950 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
2951 int dst2_x = DX, dst2_y = DY;
2952 int width = DXSIZE, height = i;
2954 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2955 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2958 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2959 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2962 else if (x <= DXSIZE) /* ANIM_DEFAULT */
2964 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
2966 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2967 BlitBitmapMasked(bitmap, drawto,
2968 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2969 DX + DXSIZE - i, DY + j);
2970 BlitBitmapMasked(bitmap, drawto,
2971 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2972 DX + DXSIZE - i, DY + 140 + j);
2973 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
2974 DY - (DOOR_GFX_PAGEY1 + j));
2975 BlitBitmapMasked(bitmap, drawto,
2976 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2978 BlitBitmapMasked(bitmap, drawto,
2979 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
2982 BlitBitmapMasked(bitmap, drawto,
2983 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2985 BlitBitmapMasked(bitmap, drawto,
2986 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2988 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2989 BlitBitmapMasked(bitmap, drawto,
2990 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2991 DX + DXSIZE - i, DY + 77 + j);
2992 BlitBitmapMasked(bitmap, drawto,
2993 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2994 DX + DXSIZE - i, DY + 203 + j);
2997 redraw_mask |= REDRAW_DOOR_1;
2998 door_1_done = (a == end);
3001 if (door_state & DOOR_ACTION_2)
3003 int a = MIN(x * door_2.step_offset, door_size);
3004 int p = (door_state & DOOR_OPEN_2 ? door_size - a : a);
3005 int i = p + door_skip;
3007 if (door_2.anim_mode & ANIM_STATIC_PANEL)
3009 BlitBitmap(bitmap_db_door, drawto,
3010 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
3011 VXSIZE, VYSIZE, VX, VY);
3013 else if (x <= VYSIZE)
3015 BlitBitmap(bitmap_db_door, drawto,
3016 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
3017 VXSIZE, VYSIZE - p / 2, VX, VY);
3019 ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
3022 if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
3024 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
3025 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
3026 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
3027 int dst2_x = VX, dst2_y = VY;
3028 int width = i, height = VYSIZE;
3030 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3031 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3034 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3035 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3038 else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
3040 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
3041 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
3042 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
3043 int dst2_x = VX, dst2_y = VY;
3044 int width = VXSIZE, height = i;
3046 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3047 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3050 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3051 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3054 else if (x <= VXSIZE) /* ANIM_DEFAULT */
3056 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
3058 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3059 BlitBitmapMasked(bitmap, drawto,
3060 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
3061 VX + VXSIZE - i, VY + j);
3062 SetClipOrigin(bitmap, gc,
3063 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
3064 BlitBitmapMasked(bitmap, drawto,
3065 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
3068 BlitBitmapMasked(bitmap, drawto,
3069 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3070 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
3071 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3072 BlitBitmapMasked(bitmap, drawto,
3073 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3075 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
3078 redraw_mask |= REDRAW_DOOR_2;
3079 door_2_done = (a == VXSIZE);
3082 if (!(door_state & DOOR_NO_DELAY))
3086 if (game_status == GAME_MODE_MAIN)
3089 WaitUntilDelayReached(&door_delay, door_delay_value);
3094 if (door_state & DOOR_ACTION_1)
3095 door1 = door_state & DOOR_ACTION_1;
3096 if (door_state & DOOR_ACTION_2)
3097 door2 = door_state & DOOR_ACTION_2;
3099 return (door1 | door2);
3102 void DrawSpecialEditorDoor()
3104 /* draw bigger toolbox window */
3105 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
3106 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
3108 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3109 EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
3112 redraw_mask |= REDRAW_ALL;
3115 void UndrawSpecialEditorDoor()
3117 /* draw normal tape recorder window */
3118 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3119 EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
3122 redraw_mask |= REDRAW_ALL;
3126 /* ---------- new tool button stuff ---------------------------------------- */
3128 /* graphic position values for tool buttons */
3129 #define TOOL_BUTTON_YES_XPOS 2
3130 #define TOOL_BUTTON_YES_YPOS 250
3131 #define TOOL_BUTTON_YES_GFX_YPOS 0
3132 #define TOOL_BUTTON_YES_XSIZE 46
3133 #define TOOL_BUTTON_YES_YSIZE 28
3134 #define TOOL_BUTTON_NO_XPOS 52
3135 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
3136 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
3137 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
3138 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
3139 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
3140 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
3141 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
3142 #define TOOL_BUTTON_CONFIRM_XSIZE 96
3143 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
3144 #define TOOL_BUTTON_PLAYER_XSIZE 30
3145 #define TOOL_BUTTON_PLAYER_YSIZE 30
3146 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
3147 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
3148 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
3149 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
3150 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3151 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3152 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3153 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3154 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3155 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3156 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3157 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3158 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3159 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3160 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3161 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3162 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3163 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3164 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3165 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3174 } toolbutton_info[NUM_TOOL_BUTTONS] =
3177 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
3178 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
3179 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
3184 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
3185 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
3186 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
3191 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
3192 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
3193 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
3194 TOOL_CTRL_ID_CONFIRM,
3198 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3199 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
3200 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3201 TOOL_CTRL_ID_PLAYER_1,
3205 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3206 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
3207 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3208 TOOL_CTRL_ID_PLAYER_2,
3212 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3213 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
3214 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3215 TOOL_CTRL_ID_PLAYER_3,
3219 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3220 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
3221 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3222 TOOL_CTRL_ID_PLAYER_4,
3227 void CreateToolButtons()
3231 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3233 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3234 Bitmap *deco_bitmap = None;
3235 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
3236 struct GadgetInfo *gi;
3237 unsigned long event_mask;
3238 int gd_xoffset, gd_yoffset;
3239 int gd_x1, gd_x2, gd_y;
3242 event_mask = GD_EVENT_RELEASED;
3244 gd_xoffset = toolbutton_info[i].xpos;
3245 gd_yoffset = toolbutton_info[i].ypos;
3246 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
3247 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
3248 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
3250 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
3252 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
3254 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
3255 &deco_bitmap, &deco_x, &deco_y);
3256 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
3257 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
3260 gi = CreateGadget(GDI_CUSTOM_ID, id,
3261 GDI_INFO_TEXT, toolbutton_info[i].infotext,
3262 GDI_X, DX + toolbutton_info[i].x,
3263 GDI_Y, DY + toolbutton_info[i].y,
3264 GDI_WIDTH, toolbutton_info[i].width,
3265 GDI_HEIGHT, toolbutton_info[i].height,
3266 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
3267 GDI_STATE, GD_BUTTON_UNPRESSED,
3268 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
3269 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
3270 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
3271 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
3272 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
3273 GDI_DECORATION_SHIFTING, 1, 1,
3274 GDI_DIRECT_DRAW, FALSE,
3275 GDI_EVENT_MASK, event_mask,
3276 GDI_CALLBACK_ACTION, HandleToolButtons,
3280 Error(ERR_EXIT, "cannot create gadget");
3282 tool_gadget[id] = gi;
3286 void FreeToolButtons()
3290 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3291 FreeGadget(tool_gadget[i]);
3294 static void UnmapToolButtons()
3298 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3299 UnmapGadget(tool_gadget[i]);
3302 static void HandleToolButtons(struct GadgetInfo *gi)
3304 request_gadget_id = gi->custom_id;
3307 static struct Mapping_EM_to_RND_object
3310 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
3311 boolean is_backside; /* backside of moving element */
3317 em_object_mapping_list[] =
3320 Xblank, TRUE, FALSE,
3324 Yacid_splash_eB, FALSE, FALSE,
3325 EL_ACID_SPLASH_RIGHT, -1, -1
3328 Yacid_splash_wB, FALSE, FALSE,
3329 EL_ACID_SPLASH_LEFT, -1, -1
3332 #ifdef EM_ENGINE_BAD_ROLL
3334 Xstone_force_e, FALSE, FALSE,
3335 EL_ROCK, -1, MV_BIT_RIGHT
3338 Xstone_force_w, FALSE, FALSE,
3339 EL_ROCK, -1, MV_BIT_LEFT
3342 Xnut_force_e, FALSE, FALSE,
3343 EL_NUT, -1, MV_BIT_RIGHT
3346 Xnut_force_w, FALSE, FALSE,
3347 EL_NUT, -1, MV_BIT_LEFT
3350 Xspring_force_e, FALSE, FALSE,
3351 EL_SPRING, -1, MV_BIT_RIGHT
3354 Xspring_force_w, FALSE, FALSE,
3355 EL_SPRING, -1, MV_BIT_LEFT
3358 Xemerald_force_e, FALSE, FALSE,
3359 EL_EMERALD, -1, MV_BIT_RIGHT
3362 Xemerald_force_w, FALSE, FALSE,
3363 EL_EMERALD, -1, MV_BIT_LEFT
3366 Xdiamond_force_e, FALSE, FALSE,
3367 EL_DIAMOND, -1, MV_BIT_RIGHT
3370 Xdiamond_force_w, FALSE, FALSE,
3371 EL_DIAMOND, -1, MV_BIT_LEFT
3374 Xbomb_force_e, FALSE, FALSE,
3375 EL_BOMB, -1, MV_BIT_RIGHT
3378 Xbomb_force_w, FALSE, FALSE,
3379 EL_BOMB, -1, MV_BIT_LEFT
3381 #endif /* EM_ENGINE_BAD_ROLL */
3384 Xstone, TRUE, FALSE,
3388 Xstone_pause, FALSE, FALSE,
3392 Xstone_fall, FALSE, FALSE,
3396 Ystone_s, FALSE, FALSE,
3397 EL_ROCK, ACTION_FALLING, -1
3400 Ystone_sB, FALSE, TRUE,
3401 EL_ROCK, ACTION_FALLING, -1
3404 Ystone_e, FALSE, FALSE,
3405 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3408 Ystone_eB, FALSE, TRUE,
3409 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3412 Ystone_w, FALSE, FALSE,
3413 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3416 Ystone_wB, FALSE, TRUE,
3417 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3424 Xnut_pause, FALSE, FALSE,
3428 Xnut_fall, FALSE, FALSE,
3432 Ynut_s, FALSE, FALSE,
3433 EL_NUT, ACTION_FALLING, -1
3436 Ynut_sB, FALSE, TRUE,
3437 EL_NUT, ACTION_FALLING, -1
3440 Ynut_e, FALSE, FALSE,
3441 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3444 Ynut_eB, FALSE, TRUE,
3445 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3448 Ynut_w, FALSE, FALSE,
3449 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3452 Ynut_wB, FALSE, TRUE,
3453 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3456 Xbug_n, TRUE, FALSE,
3460 Xbug_e, TRUE, FALSE,
3461 EL_BUG_RIGHT, -1, -1
3464 Xbug_s, TRUE, FALSE,
3468 Xbug_w, TRUE, FALSE,
3472 Xbug_gon, FALSE, FALSE,
3476 Xbug_goe, FALSE, FALSE,
3477 EL_BUG_RIGHT, -1, -1
3480 Xbug_gos, FALSE, FALSE,
3484 Xbug_gow, FALSE, FALSE,
3488 Ybug_n, FALSE, FALSE,
3489 EL_BUG, ACTION_MOVING, MV_BIT_UP
3492 Ybug_nB, FALSE, TRUE,
3493 EL_BUG, ACTION_MOVING, MV_BIT_UP
3496 Ybug_e, FALSE, FALSE,
3497 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3500 Ybug_eB, FALSE, TRUE,
3501 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3504 Ybug_s, FALSE, FALSE,
3505 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3508 Ybug_sB, FALSE, TRUE,
3509 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3512 Ybug_w, FALSE, FALSE,
3513 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3516 Ybug_wB, FALSE, TRUE,
3517 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3520 Ybug_w_n, FALSE, FALSE,
3521 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3524 Ybug_n_e, FALSE, FALSE,
3525 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3528 Ybug_e_s, FALSE, FALSE,
3529 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3532 Ybug_s_w, FALSE, FALSE,
3533 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3536 Ybug_e_n, FALSE, FALSE,
3537 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3540 Ybug_s_e, FALSE, FALSE,
3541 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3544 Ybug_w_s, FALSE, FALSE,
3545 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3548 Ybug_n_w, FALSE, FALSE,
3549 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3552 Ybug_stone, FALSE, FALSE,
3553 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
3556 Ybug_spring, FALSE, FALSE,
3557 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
3560 Xtank_n, TRUE, FALSE,
3561 EL_SPACESHIP_UP, -1, -1
3564 Xtank_e, TRUE, FALSE,
3565 EL_SPACESHIP_RIGHT, -1, -1
3568 Xtank_s, TRUE, FALSE,
3569 EL_SPACESHIP_DOWN, -1, -1
3572 Xtank_w, TRUE, FALSE,
3573 EL_SPACESHIP_LEFT, -1, -1
3576 Xtank_gon, FALSE, FALSE,
3577 EL_SPACESHIP_UP, -1, -1
3580 Xtank_goe, FALSE, FALSE,
3581 EL_SPACESHIP_RIGHT, -1, -1
3584 Xtank_gos, FALSE, FALSE,
3585 EL_SPACESHIP_DOWN, -1, -1
3588 Xtank_gow, FALSE, FALSE,
3589 EL_SPACESHIP_LEFT, -1, -1
3592 Ytank_n, FALSE, FALSE,
3593 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3596 Ytank_nB, FALSE, TRUE,
3597 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3600 Ytank_e, FALSE, FALSE,
3601 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3604 Ytank_eB, FALSE, TRUE,
3605 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3608 Ytank_s, FALSE, FALSE,
3609 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3612 Ytank_sB, FALSE, TRUE,
3613 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3616 Ytank_w, FALSE, FALSE,
3617 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3620 Ytank_wB, FALSE, TRUE,
3621 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3624 Ytank_w_n, FALSE, FALSE,
3625 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3628 Ytank_n_e, FALSE, FALSE,
3629 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3632 Ytank_e_s, FALSE, FALSE,
3633 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3636 Ytank_s_w, FALSE, FALSE,
3637 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3640 Ytank_e_n, FALSE, FALSE,
3641 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3644 Ytank_s_e, FALSE, FALSE,
3645 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3648 Ytank_w_s, FALSE, FALSE,
3649 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3652 Ytank_n_w, FALSE, FALSE,
3653 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3656 Ytank_stone, FALSE, FALSE,
3657 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
3660 Ytank_spring, FALSE, FALSE,
3661 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
3664 Xandroid, TRUE, FALSE,
3665 EL_EMC_ANDROID, ACTION_ACTIVE, -1
3668 Xandroid_1_n, FALSE, FALSE,
3669 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3672 Xandroid_2_n, FALSE, FALSE,
3673 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3676 Xandroid_1_e, FALSE, FALSE,
3677 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3680 Xandroid_2_e, FALSE, FALSE,
3681 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3684 Xandroid_1_w, FALSE, FALSE,
3685 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3688 Xandroid_2_w, FALSE, FALSE,
3689 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3692 Xandroid_1_s, FALSE, FALSE,
3693 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3696 Xandroid_2_s, FALSE, FALSE,
3697 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3700 Yandroid_n, FALSE, FALSE,
3701 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3704 Yandroid_nB, FALSE, TRUE,
3705 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3708 Yandroid_ne, FALSE, FALSE,
3709 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
3712 Yandroid_neB, FALSE, TRUE,
3713 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
3716 Yandroid_e, FALSE, FALSE,
3717 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
3720 Yandroid_eB, FALSE, TRUE,
3721 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
3724 Yandroid_se, FALSE, FALSE,
3725 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
3728 Yandroid_seB, FALSE, TRUE,
3729 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
3732 Yandroid_s, FALSE, FALSE,
3733 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
3736 Yandroid_sB, FALSE, TRUE,
3737 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
3740 Yandroid_sw, FALSE, FALSE,
3741 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
3744 Yandroid_swB, FALSE, TRUE,
3745 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
3748 Yandroid_w, FALSE, FALSE,
3749 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
3752 Yandroid_wB, FALSE, TRUE,
3753 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
3756 Yandroid_nw, FALSE, FALSE,
3757 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
3760 Yandroid_nwB, FALSE, TRUE,
3761 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
3764 Xspring, TRUE, FALSE,
3768 Xspring_pause, FALSE, FALSE,
3772 Xspring_e, FALSE, FALSE,
3776 Xspring_w, FALSE, FALSE,
3780 Xspring_fall, FALSE, FALSE,
3784 Yspring_s, FALSE, FALSE,
3785 EL_SPRING, ACTION_FALLING, -1
3788 Yspring_sB, FALSE, TRUE,
3789 EL_SPRING, ACTION_FALLING, -1
3792 Yspring_e, FALSE, FALSE,
3793 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
3796 Yspring_eB, FALSE, TRUE,
3797 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
3800 Yspring_w, FALSE, FALSE,
3801 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
3804 Yspring_wB, FALSE, TRUE,
3805 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
3808 Yspring_kill_e, FALSE, FALSE,
3809 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
3812 Yspring_kill_eB, FALSE, TRUE,
3813 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
3816 Yspring_kill_w, FALSE, FALSE,
3817 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
3820 Yspring_kill_wB, FALSE, TRUE,
3821 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
3824 Xeater_n, TRUE, FALSE,
3825 EL_YAMYAM_UP, -1, -1
3828 Xeater_e, TRUE, FALSE,
3829 EL_YAMYAM_RIGHT, -1, -1
3832 Xeater_w, TRUE, FALSE,
3833 EL_YAMYAM_LEFT, -1, -1
3836 Xeater_s, TRUE, FALSE,
3837 EL_YAMYAM_DOWN, -1, -1
3840 Yeater_n, FALSE, FALSE,
3841 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
3844 Yeater_nB, FALSE, TRUE,
3845 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
3848 Yeater_e, FALSE, FALSE,
3849 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
3852 Yeater_eB, FALSE, TRUE,
3853 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
3856 Yeater_s, FALSE, FALSE,
3857 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
3860 Yeater_sB, FALSE, TRUE,
3861 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
3864 Yeater_w, FALSE, FALSE,
3865 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
3868 Yeater_wB, FALSE, TRUE,
3869 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
3872 Yeater_stone, FALSE, FALSE,
3873 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
3876 Yeater_spring, FALSE, FALSE,
3877 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
3880 Xalien, TRUE, FALSE,
3884 Xalien_pause, FALSE, FALSE,
3888 Yalien_n, FALSE, FALSE,
3889 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
3892 Yalien_nB, FALSE, TRUE,
3893 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
3896 Yalien_e, FALSE, FALSE,
3897 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
3900 Yalien_eB, FALSE, TRUE,
3901 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
3904 Yalien_s, FALSE, FALSE,
3905 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
3908 Yalien_sB, FALSE, TRUE,
3909 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
3912 Yalien_w, FALSE, FALSE,
3913 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
3916 Yalien_wB, FALSE, TRUE,
3917 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
3920 Yalien_stone, FALSE, FALSE,
3921 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
3924 Yalien_spring, FALSE, FALSE,
3925 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
3928 Xemerald, TRUE, FALSE,
3932 Xemerald_pause, FALSE, FALSE,
3936 Xemerald_fall, FALSE, FALSE,
3940 Xemerald_shine, FALSE, FALSE,
3941 EL_EMERALD, ACTION_TWINKLING, -1
3944 Yemerald_s, FALSE, FALSE,
3945 EL_EMERALD, ACTION_FALLING, -1
3948 Yemerald_sB, FALSE, TRUE,
3949 EL_EMERALD, ACTION_FALLING, -1
3952 Yemerald_e, FALSE, FALSE,
3953 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
3956 Yemerald_eB, FALSE, TRUE,
3957 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
3960 Yemerald_w, FALSE, FALSE,
3961 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
3964 Yemerald_wB, FALSE, TRUE,
3965 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
3968 Yemerald_eat, FALSE, FALSE,
3969 EL_EMERALD, ACTION_COLLECTING, -1
3972 Yemerald_stone, FALSE, FALSE,
3973 EL_NUT, ACTION_BREAKING, -1
3976 Xdiamond, TRUE, FALSE,
3980 Xdiamond_pause, FALSE, FALSE,
3984 Xdiamond_fall, FALSE, FALSE,
3988 Xdiamond_shine, FALSE, FALSE,
3989 EL_DIAMOND, ACTION_TWINKLING, -1
3992 Ydiamond_s, FALSE, FALSE,
3993 EL_DIAMOND, ACTION_FALLING, -1
3996 Ydiamond_sB, FALSE, TRUE,
3997 EL_DIAMOND, ACTION_FALLING, -1
4000 Ydiamond_e, FALSE, FALSE,
4001 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
4004 Ydiamond_eB, FALSE, TRUE,
4005 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
4008 Ydiamond_w, FALSE, FALSE,
4009 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
4012 Ydiamond_wB, FALSE, TRUE,
4013 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
4016 Ydiamond_eat, FALSE, FALSE,
4017 EL_DIAMOND, ACTION_COLLECTING, -1
4020 Ydiamond_stone, FALSE, FALSE,
4021 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
4024 Xdrip_fall, TRUE, FALSE,
4025 EL_AMOEBA_DROP, -1, -1
4028 Xdrip_stretch, FALSE, FALSE,
4029 EL_AMOEBA_DROP, ACTION_FALLING, -1
4032 Xdrip_stretchB, FALSE, TRUE,
4033 EL_AMOEBA_DROP, ACTION_FALLING, -1
4036 Xdrip_eat, FALSE, FALSE,
4037 EL_AMOEBA_DROP, ACTION_GROWING, -1
4040 Ydrip_s1, FALSE, FALSE,
4041 EL_AMOEBA_DROP, ACTION_FALLING, -1
4044 Ydrip_s1B, FALSE, TRUE,
4045 EL_AMOEBA_DROP, ACTION_FALLING, -1
4048 Ydrip_s2, FALSE, FALSE,
4049 EL_AMOEBA_DROP, ACTION_FALLING, -1
4052 Ydrip_s2B, FALSE, TRUE,
4053 EL_AMOEBA_DROP, ACTION_FALLING, -1
4060 Xbomb_pause, FALSE, FALSE,
4064 Xbomb_fall, FALSE, FALSE,
4068 Ybomb_s, FALSE, FALSE,
4069 EL_BOMB, ACTION_FALLING, -1
4072 Ybomb_sB, FALSE, TRUE,
4073 EL_BOMB, ACTION_FALLING, -1
4076 Ybomb_e, FALSE, FALSE,
4077 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
4080 Ybomb_eB, FALSE, TRUE,
4081 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
4084 Ybomb_w, FALSE, FALSE,
4085 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
4088 Ybomb_wB, FALSE, TRUE,
4089 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
4092 Ybomb_eat, FALSE, FALSE,
4093 EL_BOMB, ACTION_ACTIVATING, -1
4096 Xballoon, TRUE, FALSE,
4100 Yballoon_n, FALSE, FALSE,
4101 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
4104 Yballoon_nB, FALSE, TRUE,
4105 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
4108 Yballoon_e, FALSE, FALSE,
4109 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
4112 Yballoon_eB, FALSE, TRUE,
4113 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
4116 Yballoon_s, FALSE, FALSE,
4117 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
4120 Yballoon_sB, FALSE, TRUE,
4121 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
4124 Yballoon_w, FALSE, FALSE,
4125 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
4128 Yballoon_wB, FALSE, TRUE,
4129 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
4132 Xgrass, TRUE, FALSE,
4133 EL_EMC_GRASS, -1, -1
4136 Ygrass_nB, FALSE, FALSE,
4137 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
4140 Ygrass_eB, FALSE, FALSE,
4141 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
4144 Ygrass_sB, FALSE, FALSE,
4145 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
4148 Ygrass_wB, FALSE, FALSE,
4149 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
4156 Ydirt_nB, FALSE, FALSE,
4157 EL_SAND, ACTION_DIGGING, MV_BIT_UP
4160 Ydirt_eB, FALSE, FALSE,
4161 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
4164 Ydirt_sB, FALSE, FALSE,
4165 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
4168 Ydirt_wB, FALSE, FALSE,
4169 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
4172 Xacid_ne, TRUE, FALSE,
4173 EL_ACID_POOL_TOPRIGHT, -1, -1
4176 Xacid_se, TRUE, FALSE,
4177 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
4180 Xacid_s, TRUE, FALSE,
4181 EL_ACID_POOL_BOTTOM, -1, -1
4184 Xacid_sw, TRUE, FALSE,
4185 EL_ACID_POOL_BOTTOMLEFT, -1, -1
4188 Xacid_nw, TRUE, FALSE,
4189 EL_ACID_POOL_TOPLEFT, -1, -1
4192 Xacid_1, TRUE, FALSE,
4196 Xacid_2, FALSE, FALSE,
4200 Xacid_3, FALSE, FALSE,
4204 Xacid_4, FALSE, FALSE,
4208 Xacid_5, FALSE, FALSE,
4212 Xacid_6, FALSE, FALSE,
4216 Xacid_7, FALSE, FALSE,
4220 Xacid_8, FALSE, FALSE,
4224 Xball_1, TRUE, FALSE,
4225 EL_EMC_MAGIC_BALL, -1, -1
4228 Xball_1B, FALSE, FALSE,
4229 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4232 Xball_2, FALSE, FALSE,
4233 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4236 Xball_2B, FALSE, FALSE,
4237 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4240 Yball_eat, FALSE, FALSE,
4241 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
4244 Ykey_1_eat, FALSE, FALSE,
4245 EL_EM_KEY_1, ACTION_COLLECTING, -1
4248 Ykey_2_eat, FALSE, FALSE,
4249 EL_EM_KEY_2, ACTION_COLLECTING, -1
4252 Ykey_3_eat, FALSE, FALSE,
4253 EL_EM_KEY_3, ACTION_COLLECTING, -1
4256 Ykey_4_eat, FALSE, FALSE,
4257 EL_EM_KEY_4, ACTION_COLLECTING, -1
4260 Ykey_5_eat, FALSE, FALSE,
4261 EL_EMC_KEY_5, ACTION_COLLECTING, -1
4264 Ykey_6_eat, FALSE, FALSE,
4265 EL_EMC_KEY_6, ACTION_COLLECTING, -1
4268 Ykey_7_eat, FALSE, FALSE,
4269 EL_EMC_KEY_7, ACTION_COLLECTING, -1
4272 Ykey_8_eat, FALSE, FALSE,
4273 EL_EMC_KEY_8, ACTION_COLLECTING, -1
4276 Ylenses_eat, FALSE, FALSE,
4277 EL_EMC_LENSES, ACTION_COLLECTING, -1
4280 Ymagnify_eat, FALSE, FALSE,
4281 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
4284 Ygrass_eat, FALSE, FALSE,
4285 EL_EMC_GRASS, ACTION_SNAPPING, -1
4288 Ydirt_eat, FALSE, FALSE,
4289 EL_SAND, ACTION_SNAPPING, -1
4292 Xgrow_ns, TRUE, FALSE,
4293 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
4296 Ygrow_ns_eat, FALSE, FALSE,
4297 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
4300 Xgrow_ew, TRUE, FALSE,
4301 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
4304 Ygrow_ew_eat, FALSE, FALSE,
4305 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
4308 Xwonderwall, TRUE, FALSE,
4309 EL_MAGIC_WALL, -1, -1
4312 XwonderwallB, FALSE, FALSE,
4313 EL_MAGIC_WALL, ACTION_ACTIVE, -1
4316 Xamoeba_1, TRUE, FALSE,
4317 EL_AMOEBA_DRY, ACTION_OTHER, -1
4320 Xamoeba_2, FALSE, FALSE,
4321 EL_AMOEBA_DRY, ACTION_OTHER, -1
4324 Xamoeba_3, FALSE, FALSE,
4325 EL_AMOEBA_DRY, ACTION_OTHER, -1
4328 Xamoeba_4, FALSE, FALSE,
4329 EL_AMOEBA_DRY, ACTION_OTHER, -1
4332 Xamoeba_5, TRUE, FALSE,
4333 EL_AMOEBA_WET, ACTION_OTHER, -1
4336 Xamoeba_6, FALSE, FALSE,
4337 EL_AMOEBA_WET, ACTION_OTHER, -1
4340 Xamoeba_7, FALSE, FALSE,
4341 EL_AMOEBA_WET, ACTION_OTHER, -1
4344 Xamoeba_8, FALSE, FALSE,
4345 EL_AMOEBA_WET, ACTION_OTHER, -1
4348 Xdoor_1, TRUE, FALSE,
4349 EL_EM_GATE_1, -1, -1
4352 Xdoor_2, TRUE, FALSE,
4353 EL_EM_GATE_2, -1, -1
4356 Xdoor_3, TRUE, FALSE,
4357 EL_EM_GATE_3, -1, -1
4360 Xdoor_4, TRUE, FALSE,
4361 EL_EM_GATE_4, -1, -1
4364 Xdoor_5, TRUE, FALSE,
4365 EL_EMC_GATE_5, -1, -1
4368 Xdoor_6, TRUE, FALSE,
4369 EL_EMC_GATE_6, -1, -1
4372 Xdoor_7, TRUE, FALSE,
4373 EL_EMC_GATE_7, -1, -1
4376 Xdoor_8, TRUE, FALSE,
4377 EL_EMC_GATE_8, -1, -1
4380 Xkey_1, TRUE, FALSE,
4384 Xkey_2, TRUE, FALSE,
4388 Xkey_3, TRUE, FALSE,
4392 Xkey_4, TRUE, FALSE,
4396 Xkey_5, TRUE, FALSE,
4397 EL_EMC_KEY_5, -1, -1
4400 Xkey_6, TRUE, FALSE,
4401 EL_EMC_KEY_6, -1, -1
4404 Xkey_7, TRUE, FALSE,
4405 EL_EMC_KEY_7, -1, -1
4408 Xkey_8, TRUE, FALSE,
4409 EL_EMC_KEY_8, -1, -1
4412 Xwind_n, TRUE, FALSE,
4413 EL_BALLOON_SWITCH_UP, -1, -1
4416 Xwind_e, TRUE, FALSE,
4417 EL_BALLOON_SWITCH_RIGHT, -1, -1
4420 Xwind_s, TRUE, FALSE,
4421 EL_BALLOON_SWITCH_DOWN, -1, -1
4424 Xwind_w, TRUE, FALSE,
4425 EL_BALLOON_SWITCH_LEFT, -1, -1
4428 Xwind_nesw, TRUE, FALSE,
4429 EL_BALLOON_SWITCH_ANY, -1, -1
4432 Xwind_stop, TRUE, FALSE,
4433 EL_BALLOON_SWITCH_NONE, -1, -1
4437 EL_EXIT_CLOSED, -1, -1
4440 Xexit_1, TRUE, FALSE,
4441 EL_EXIT_OPEN, -1, -1
4444 Xexit_2, FALSE, FALSE,
4445 EL_EXIT_OPEN, -1, -1
4448 Xexit_3, FALSE, FALSE,
4449 EL_EXIT_OPEN, -1, -1
4452 Xdynamite, TRUE, FALSE,
4453 EL_EM_DYNAMITE, -1, -1
4456 Ydynamite_eat, FALSE, FALSE,
4457 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
4460 Xdynamite_1, TRUE, FALSE,
4461 EL_EM_DYNAMITE_ACTIVE, -1, -1
4464 Xdynamite_2, FALSE, FALSE,
4465 EL_EM_DYNAMITE_ACTIVE, -1, -1
4468 Xdynamite_3, FALSE, FALSE,
4469 EL_EM_DYNAMITE_ACTIVE, -1, -1
4472 Xdynamite_4, FALSE, FALSE,
4473 EL_EM_DYNAMITE_ACTIVE, -1, -1
4476 Xbumper, TRUE, FALSE,
4477 EL_EMC_SPRING_BUMPER, -1, -1
4480 XbumperB, FALSE, FALSE,
4481 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
4484 Xwheel, TRUE, FALSE,
4485 EL_ROBOT_WHEEL, -1, -1
4488 XwheelB, FALSE, FALSE,
4489 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
4492 Xswitch, TRUE, FALSE,
4493 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
4496 XswitchB, FALSE, FALSE,
4497 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
4501 EL_QUICKSAND_EMPTY, -1, -1
4504 Xsand_stone, TRUE, FALSE,
4505 EL_QUICKSAND_FULL, -1, -1
4508 Xsand_stonein_1, FALSE, TRUE,
4509 EL_ROCK, ACTION_FILLING, -1
4512 Xsand_stonein_2, FALSE, TRUE,
4513 EL_ROCK, ACTION_FILLING, -1
4516 Xsand_stonein_3, FALSE, TRUE,
4517 EL_ROCK, ACTION_FILLING, -1
4520 Xsand_stonein_4, FALSE, TRUE,
4521 EL_ROCK, ACTION_FILLING, -1
4524 Xsand_stonesand_1, FALSE, FALSE,
4525 EL_QUICKSAND_FULL, -1, -1
4528 Xsand_stonesand_2, FALSE, FALSE,
4529 EL_QUICKSAND_FULL, -1, -1
4532 Xsand_stonesand_3, FALSE, FALSE,
4533 EL_QUICKSAND_FULL, -1, -1
4536 Xsand_stonesand_4, FALSE, FALSE,
4537 EL_QUICKSAND_FULL, -1, -1
4540 Xsand_stoneout_1, FALSE, FALSE,
4541 EL_ROCK, ACTION_EMPTYING, -1
4544 Xsand_stoneout_2, FALSE, FALSE,
4545 EL_ROCK, ACTION_EMPTYING, -1
4548 Xsand_sandstone_1, FALSE, FALSE,
4549 EL_QUICKSAND_FULL, -1, -1
4552 Xsand_sandstone_2, FALSE, FALSE,
4553 EL_QUICKSAND_FULL, -1, -1
4556 Xsand_sandstone_3, FALSE, FALSE,
4557 EL_QUICKSAND_FULL, -1, -1
4560 Xsand_sandstone_4, FALSE, FALSE,
4561 EL_QUICKSAND_FULL, -1, -1
4564 Xplant, TRUE, FALSE,
4565 EL_EMC_PLANT, -1, -1
4568 Yplant, FALSE, FALSE,
4569 EL_EMC_PLANT, -1, -1
4572 Xlenses, TRUE, FALSE,
4573 EL_EMC_LENSES, -1, -1
4576 Xmagnify, TRUE, FALSE,
4577 EL_EMC_MAGNIFIER, -1, -1
4580 Xdripper, TRUE, FALSE,
4581 EL_EMC_DRIPPER, -1, -1
4584 XdripperB, FALSE, FALSE,
4585 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
4588 Xfake_blank, TRUE, FALSE,
4589 EL_INVISIBLE_WALL, -1, -1
4592 Xfake_blankB, FALSE, FALSE,
4593 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
4596 Xfake_grass, TRUE, FALSE,
4597 EL_EMC_FAKE_GRASS, -1, -1
4600 Xfake_grassB, FALSE, FALSE,
4601 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
4604 Xfake_door_1, TRUE, FALSE,
4605 EL_EM_GATE_1_GRAY, -1, -1
4608 Xfake_door_2, TRUE, FALSE,
4609 EL_EM_GATE_2_GRAY, -1, -1
4612 Xfake_door_3, TRUE, FALSE,
4613 EL_EM_GATE_3_GRAY, -1, -1
4616 Xfake_door_4, TRUE, FALSE,
4617 EL_EM_GATE_4_GRAY, -1, -1
4620 Xfake_door_5, TRUE, FALSE,
4621 EL_EMC_GATE_5_GRAY, -1, -1
4624 Xfake_door_6, TRUE, FALSE,
4625 EL_EMC_GATE_6_GRAY, -1, -1
4628 Xfake_door_7, TRUE, FALSE,
4629 EL_EMC_GATE_7_GRAY, -1, -1
4632 Xfake_door_8, TRUE, FALSE,
4633 EL_EMC_GATE_8_GRAY, -1, -1
4636 Xfake_acid_1, TRUE, FALSE,
4637 EL_EMC_FAKE_ACID, -1, -1
4640 Xfake_acid_2, FALSE, FALSE,
4641 EL_EMC_FAKE_ACID, -1, -1
4644 Xfake_acid_3, FALSE, FALSE,
4645 EL_EMC_FAKE_ACID, -1, -1
4648 Xfake_acid_4, FALSE, FALSE,
4649 EL_EMC_FAKE_ACID, -1, -1
4652 Xfake_acid_5, FALSE, FALSE,
4653 EL_EMC_FAKE_ACID, -1, -1
4656 Xfake_acid_6, FALSE, FALSE,
4657 EL_EMC_FAKE_ACID, -1, -1
4660 Xfake_acid_7, FALSE, FALSE,
4661 EL_EMC_FAKE_ACID, -1, -1
4664 Xfake_acid_8, FALSE, FALSE,
4665 EL_EMC_FAKE_ACID, -1, -1
4668 Xsteel_1, TRUE, FALSE,
4669 EL_STEELWALL, -1, -1
4672 Xsteel_2, TRUE, FALSE,
4673 EL_EMC_STEELWALL_2, -1, -1
4676 Xsteel_3, TRUE, FALSE,
4677 EL_EMC_STEELWALL_3, -1, -1
4680 Xsteel_4, TRUE, FALSE,
4681 EL_EMC_STEELWALL_4, -1, -1
4684 Xwall_1, TRUE, FALSE,
4688 Xwall_2, TRUE, FALSE,
4689 EL_EMC_WALL_14, -1, -1
4692 Xwall_3, TRUE, FALSE,
4693 EL_EMC_WALL_15, -1, -1
4696 Xwall_4, TRUE, FALSE,
4697 EL_EMC_WALL_16, -1, -1
4700 Xround_wall_1, TRUE, FALSE,
4701 EL_WALL_SLIPPERY, -1, -1
4704 Xround_wall_2, TRUE, FALSE,
4705 EL_EMC_WALL_SLIPPERY_2, -1, -1
4708 Xround_wall_3, TRUE, FALSE,
4709 EL_EMC_WALL_SLIPPERY_3, -1, -1
4712 Xround_wall_4, TRUE, FALSE,
4713 EL_EMC_WALL_SLIPPERY_4, -1, -1
4716 Xdecor_1, TRUE, FALSE,
4717 EL_EMC_WALL_8, -1, -1
4720 Xdecor_2, TRUE, FALSE,
4721 EL_EMC_WALL_6, -1, -1
4724 Xdecor_3, TRUE, FALSE,
4725 EL_EMC_WALL_4, -1, -1
4728 Xdecor_4, TRUE, FALSE,
4729 EL_EMC_WALL_7, -1, -1
4732 Xdecor_5, TRUE, FALSE,
4733 EL_EMC_WALL_5, -1, -1
4736 Xdecor_6, TRUE, FALSE,
4737 EL_EMC_WALL_9, -1, -1
4740 Xdecor_7, TRUE, FALSE,
4741 EL_EMC_WALL_10, -1, -1
4744 Xdecor_8, TRUE, FALSE,
4745 EL_EMC_WALL_1, -1, -1
4748 Xdecor_9, TRUE, FALSE,
4749 EL_EMC_WALL_2, -1, -1
4752 Xdecor_10, TRUE, FALSE,
4753 EL_EMC_WALL_3, -1, -1
4756 Xdecor_11, TRUE, FALSE,
4757 EL_EMC_WALL_11, -1, -1
4760 Xdecor_12, TRUE, FALSE,
4761 EL_EMC_WALL_12, -1, -1
4764 Xalpha_0, TRUE, FALSE,
4765 EL_CHAR('0'), -1, -1
4768 Xalpha_1, TRUE, FALSE,
4769 EL_CHAR('1'), -1, -1
4772 Xalpha_2, TRUE, FALSE,
4773 EL_CHAR('2'), -1, -1
4776 Xalpha_3, TRUE, FALSE,
4777 EL_CHAR('3'), -1, -1
4780 Xalpha_4, TRUE, FALSE,
4781 EL_CHAR('4'), -1, -1
4784 Xalpha_5, TRUE, FALSE,
4785 EL_CHAR('5'), -1, -1
4788 Xalpha_6, TRUE, FALSE,
4789 EL_CHAR('6'), -1, -1
4792 Xalpha_7, TRUE, FALSE,
4793 EL_CHAR('7'), -1, -1
4796 Xalpha_8, TRUE, FALSE,
4797 EL_CHAR('8'), -1, -1
4800 Xalpha_9, TRUE, FALSE,
4801 EL_CHAR('9'), -1, -1
4804 Xalpha_excla, TRUE, FALSE,
4805 EL_CHAR('!'), -1, -1
4808 Xalpha_quote, TRUE, FALSE,
4809 EL_CHAR('"'), -1, -1
4812 Xalpha_comma, TRUE, FALSE,
4813 EL_CHAR(','), -1, -1
4816 Xalpha_minus, TRUE, FALSE,
4817 EL_CHAR('-'), -1, -1
4820 Xalpha_perio, TRUE, FALSE,
4821 EL_CHAR('.'), -1, -1
4824 Xalpha_colon, TRUE, FALSE,
4825 EL_CHAR(':'), -1, -1
4828 Xalpha_quest, TRUE, FALSE,
4829 EL_CHAR('?'), -1, -1
4832 Xalpha_a, TRUE, FALSE,
4833 EL_CHAR('A'), -1, -1
4836 Xalpha_b, TRUE, FALSE,
4837 EL_CHAR('B'), -1, -1
4840 Xalpha_c, TRUE, FALSE,
4841 EL_CHAR('C'), -1, -1
4844 Xalpha_d, TRUE, FALSE,
4845 EL_CHAR('D'), -1, -1
4848 Xalpha_e, TRUE, FALSE,
4849 EL_CHAR('E'), -1, -1
4852 Xalpha_f, TRUE, FALSE,
4853 EL_CHAR('F'), -1, -1
4856 Xalpha_g, TRUE, FALSE,
4857 EL_CHAR('G'), -1, -1
4860 Xalpha_h, TRUE, FALSE,
4861 EL_CHAR('H'), -1, -1
4864 Xalpha_i, TRUE, FALSE,
4865 EL_CHAR('I'), -1, -1
4868 Xalpha_j, TRUE, FALSE,
4869 EL_CHAR('J'), -1, -1
4872 Xalpha_k, TRUE, FALSE,
4873 EL_CHAR('K'), -1, -1
4876 Xalpha_l, TRUE, FALSE,
4877 EL_CHAR('L'), -1, -1
4880 Xalpha_m, TRUE, FALSE,
4881 EL_CHAR('M'), -1, -1
4884 Xalpha_n, TRUE, FALSE,
4885 EL_CHAR('N'), -1, -1
4888 Xalpha_o, TRUE, FALSE,
4889 EL_CHAR('O'), -1, -1
4892 Xalpha_p, TRUE, FALSE,
4893 EL_CHAR('P'), -1, -1
4896 Xalpha_q, TRUE, FALSE,
4897 EL_CHAR('Q'), -1, -1
4900 Xalpha_r, TRUE, FALSE,
4901 EL_CHAR('R'), -1, -1
4904 Xalpha_s, TRUE, FALSE,
4905 EL_CHAR('S'), -1, -1
4908 Xalpha_t, TRUE, FALSE,
4909 EL_CHAR('T'), -1, -1
4912 Xalpha_u, TRUE, FALSE,
4913 EL_CHAR('U'), -1, -1
4916 Xalpha_v, TRUE, FALSE,
4917 EL_CHAR('V'), -1, -1
4920 Xalpha_w, TRUE, FALSE,
4921 EL_CHAR('W'), -1, -1
4924 Xalpha_x, TRUE, FALSE,
4925 EL_CHAR('X'), -1, -1
4928 Xalpha_y, TRUE, FALSE,
4929 EL_CHAR('Y'), -1, -1
4932 Xalpha_z, TRUE, FALSE,
4933 EL_CHAR('Z'), -1, -1
4936 Xalpha_arrow_e, TRUE, FALSE,
4937 EL_CHAR('>'), -1, -1
4940 Xalpha_arrow_w, TRUE, FALSE,
4941 EL_CHAR('<'), -1, -1
4944 Xalpha_copyr, TRUE, FALSE,
4945 EL_CHAR('©'), -1, -1
4949 Xboom_bug, FALSE, FALSE,
4950 EL_BUG, ACTION_EXPLODING, -1
4953 Xboom_bomb, FALSE, FALSE,
4954 EL_BOMB, ACTION_EXPLODING, -1
4957 Xboom_android, FALSE, FALSE,
4958 EL_EMC_ANDROID, ACTION_OTHER, -1
4961 Xboom_1, FALSE, FALSE,
4962 EL_DEFAULT, ACTION_EXPLODING, -1
4965 Xboom_2, FALSE, FALSE,
4966 EL_DEFAULT, ACTION_EXPLODING, -1
4969 Znormal, FALSE, FALSE,
4973 Zdynamite, FALSE, FALSE,
4977 Zplayer, FALSE, FALSE,
4981 ZBORDER, FALSE, FALSE,
4991 static struct Mapping_EM_to_RND_player
5000 em_player_mapping_list[] =
5004 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
5008 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
5012 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
5016 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
5020 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
5024 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
5028 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
5032 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
5036 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
5040 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
5044 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
5048 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
5052 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
5056 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
5060 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
5064 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
5068 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
5072 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
5076 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
5080 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
5084 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
5088 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
5092 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
5096 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
5100 EL_PLAYER_1, ACTION_DEFAULT, -1,
5104 EL_PLAYER_2, ACTION_DEFAULT, -1,
5108 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
5112 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
5116 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
5120 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
5124 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
5128 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
5132 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
5136 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
5140 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
5144 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
5148 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
5152 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
5156 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
5160 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
5164 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
5168 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
5172 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
5176 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
5180 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
5184 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
5188 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
5192 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
5196 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
5200 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
5204 EL_PLAYER_3, ACTION_DEFAULT, -1,
5208 EL_PLAYER_4, ACTION_DEFAULT, -1,
5217 int map_element_RND_to_EM(int element_rnd)
5219 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
5220 static boolean mapping_initialized = FALSE;
5222 if (!mapping_initialized)
5226 /* return "Xalpha_quest" for all undefined elements in mapping array */
5227 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
5228 mapping_RND_to_EM[i] = Xalpha_quest;
5230 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5231 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
5232 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
5233 em_object_mapping_list[i].element_em;
5235 mapping_initialized = TRUE;
5238 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
5239 return mapping_RND_to_EM[element_rnd];
5241 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
5246 int map_element_EM_to_RND(int element_em)
5248 static unsigned short mapping_EM_to_RND[TILE_MAX];
5249 static boolean mapping_initialized = FALSE;
5251 if (!mapping_initialized)
5255 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
5256 for (i = 0; i < TILE_MAX; i++)
5257 mapping_EM_to_RND[i] = EL_UNKNOWN;
5259 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5260 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
5261 em_object_mapping_list[i].element_rnd;
5263 mapping_initialized = TRUE;
5266 if (element_em >= 0 && element_em < TILE_MAX)
5267 return mapping_EM_to_RND[element_em];
5269 Error(ERR_WARN, "invalid EM level element %d", element_em);
5274 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
5276 struct LevelInfo_EM *level_em = level->native_em_level;
5277 struct LEVEL *lev = level_em->lev;
5280 for (i = 0; i < TILE_MAX; i++)
5281 lev->android_array[i] = Xblank;
5283 for (i = 0; i < level->num_android_clone_elements; i++)
5285 int element_rnd = level->android_clone_element[i];
5286 int element_em = map_element_RND_to_EM(element_rnd);
5288 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
5289 if (em_object_mapping_list[j].element_rnd == element_rnd)
5290 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
5294 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
5296 struct LevelInfo_EM *level_em = level->native_em_level;
5297 struct LEVEL *lev = level_em->lev;
5300 level->num_android_clone_elements = 0;
5302 for (i = 0; i < TILE_MAX; i++)
5304 int element_em = lev->android_array[i];
5306 boolean element_found = FALSE;
5308 if (element_em == Xblank)
5311 element_rnd = map_element_EM_to_RND(element_em);
5313 for (j = 0; j < level->num_android_clone_elements; j++)
5314 if (level->android_clone_element[j] == element_rnd)
5315 element_found = TRUE;
5319 level->android_clone_element[level->num_android_clone_elements++] =
5322 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
5327 if (level->num_android_clone_elements == 0)
5329 level->num_android_clone_elements = 1;
5330 level->android_clone_element[0] = EL_EMPTY;
5334 int map_direction_RND_to_EM(int direction)
5336 return (direction == MV_UP ? 0 :
5337 direction == MV_RIGHT ? 1 :
5338 direction == MV_DOWN ? 2 :
5339 direction == MV_LEFT ? 3 :
5343 int map_direction_EM_to_RND(int direction)
5345 return (direction == 0 ? MV_UP :
5346 direction == 1 ? MV_RIGHT :
5347 direction == 2 ? MV_DOWN :
5348 direction == 3 ? MV_LEFT :
5352 int get_next_element(int element)
5356 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
5357 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
5358 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
5359 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
5360 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
5361 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
5362 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
5364 default: return element;
5369 int el_act_dir2img(int element, int action, int direction)
5371 element = GFX_ELEMENT(element);
5373 if (direction == MV_NONE)
5374 return element_info[element].graphic[action];
5376 direction = MV_DIR_TO_BIT(direction);
5378 return element_info[element].direction_graphic[action][direction];
5381 int el_act_dir2img(int element, int action, int direction)
5383 element = GFX_ELEMENT(element);
5384 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5386 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5387 return element_info[element].direction_graphic[action][direction];
5392 static int el_act_dir2crm(int element, int action, int direction)
5394 element = GFX_ELEMENT(element);
5396 if (direction == MV_NONE)
5397 return element_info[element].crumbled[action];
5399 direction = MV_DIR_TO_BIT(direction);
5401 return element_info[element].direction_crumbled[action][direction];
5404 static int el_act_dir2crm(int element, int action, int direction)
5406 element = GFX_ELEMENT(element);
5407 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5409 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5410 return element_info[element].direction_crumbled[action][direction];
5414 int el_act2img(int element, int action)
5416 element = GFX_ELEMENT(element);
5418 return element_info[element].graphic[action];
5421 int el_act2crm(int element, int action)
5423 element = GFX_ELEMENT(element);
5425 return element_info[element].crumbled[action];
5428 int el_dir2img(int element, int direction)
5430 element = GFX_ELEMENT(element);
5432 return el_act_dir2img(element, ACTION_DEFAULT, direction);
5435 int el2baseimg(int element)
5437 return element_info[element].graphic[ACTION_DEFAULT];
5440 int el2img(int element)
5442 element = GFX_ELEMENT(element);
5444 return element_info[element].graphic[ACTION_DEFAULT];
5447 int el2edimg(int element)
5449 element = GFX_ELEMENT(element);
5451 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
5454 int el2preimg(int element)
5456 element = GFX_ELEMENT(element);
5458 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
5461 int font2baseimg(int font_nr)
5463 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
5466 int getNumActivePlayers_EM()
5468 int num_players = 0;
5474 for (i = 0; i < MAX_PLAYERS; i++)
5475 if (tape.player_participates[i])
5481 int getGameFrameDelay_EM(int native_em_game_frame_delay)
5483 int game_frame_delay_value;
5485 game_frame_delay_value =
5486 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
5487 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
5490 if (tape.playing && tape.warp_forward && !tape.pausing)
5491 game_frame_delay_value = 0;
5493 return game_frame_delay_value;
5496 unsigned int InitRND(long seed)
5498 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
5499 return InitEngineRandom_EM(seed);
5501 return InitEngineRandom_RND(seed);
5504 void InitGraphicInfo_EM(void)
5506 struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
5507 struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
5511 int num_em_gfx_errors = 0;
5513 if (graphic_info_em_object[0][0].bitmap == NULL)
5515 /* EM graphics not yet initialized in em_open_all() */
5520 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
5523 /* always start with reliable default values */
5524 for (i = 0; i < TILE_MAX; i++)
5526 object_mapping[i].element_rnd = EL_UNKNOWN;
5527 object_mapping[i].is_backside = FALSE;
5528 object_mapping[i].action = ACTION_DEFAULT;
5529 object_mapping[i].direction = MV_NONE;
5532 /* always start with reliable default values */
5533 for (p = 0; p < MAX_PLAYERS; p++)
5535 for (i = 0; i < SPR_MAX; i++)
5537 player_mapping[p][i].element_rnd = EL_UNKNOWN;
5538 player_mapping[p][i].action = ACTION_DEFAULT;
5539 player_mapping[p][i].direction = MV_NONE;
5543 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5545 int e = em_object_mapping_list[i].element_em;
5547 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
5548 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
5550 if (em_object_mapping_list[i].action != -1)
5551 object_mapping[e].action = em_object_mapping_list[i].action;
5553 if (em_object_mapping_list[i].direction != -1)
5554 object_mapping[e].direction =
5555 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
5558 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
5560 int a = em_player_mapping_list[i].action_em;
5561 int p = em_player_mapping_list[i].player_nr;
5563 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
5565 if (em_player_mapping_list[i].action != -1)
5566 player_mapping[p][a].action = em_player_mapping_list[i].action;
5568 if (em_player_mapping_list[i].direction != -1)
5569 player_mapping[p][a].direction =
5570 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
5573 for (i = 0; i < TILE_MAX; i++)
5575 int element = object_mapping[i].element_rnd;
5576 int action = object_mapping[i].action;
5577 int direction = object_mapping[i].direction;
5578 boolean is_backside = object_mapping[i].is_backside;
5579 boolean action_removing = (action == ACTION_DIGGING ||
5580 action == ACTION_SNAPPING ||
5581 action == ACTION_COLLECTING);
5582 boolean action_exploding = ((action == ACTION_EXPLODING ||
5583 action == ACTION_SMASHED_BY_ROCK ||
5584 action == ACTION_SMASHED_BY_SPRING) &&
5585 element != EL_DIAMOND);
5586 boolean action_active = (action == ACTION_ACTIVE);
5587 boolean action_other = (action == ACTION_OTHER);
5589 for (j = 0; j < 8; j++)
5591 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
5592 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
5594 i == Xdrip_stretch ? element :
5595 i == Xdrip_stretchB ? element :
5596 i == Ydrip_s1 ? element :
5597 i == Ydrip_s1B ? element :
5598 i == Xball_1B ? element :
5599 i == Xball_2 ? element :
5600 i == Xball_2B ? element :
5601 i == Yball_eat ? element :
5602 i == Ykey_1_eat ? element :
5603 i == Ykey_2_eat ? element :
5604 i == Ykey_3_eat ? element :
5605 i == Ykey_4_eat ? element :
5606 i == Ykey_5_eat ? element :
5607 i == Ykey_6_eat ? element :
5608 i == Ykey_7_eat ? element :
5609 i == Ykey_8_eat ? element :
5610 i == Ylenses_eat ? element :
5611 i == Ymagnify_eat ? element :
5612 i == Ygrass_eat ? element :
5613 i == Ydirt_eat ? element :
5614 i == Yemerald_stone ? EL_EMERALD :
5615 i == Ydiamond_stone ? EL_ROCK :
5616 i == Xsand_stonein_1 ? element :
5617 i == Xsand_stonein_2 ? element :
5618 i == Xsand_stonein_3 ? element :
5619 i == Xsand_stonein_4 ? element :
5620 is_backside ? EL_EMPTY :
5621 action_removing ? EL_EMPTY :
5623 int effective_action = (j < 7 ? action :
5624 i == Xdrip_stretch ? action :
5625 i == Xdrip_stretchB ? action :
5626 i == Ydrip_s1 ? action :
5627 i == Ydrip_s1B ? action :
5628 i == Xball_1B ? action :
5629 i == Xball_2 ? action :
5630 i == Xball_2B ? action :
5631 i == Yball_eat ? action :
5632 i == Ykey_1_eat ? action :
5633 i == Ykey_2_eat ? action :
5634 i == Ykey_3_eat ? action :
5635 i == Ykey_4_eat ? action :
5636 i == Ykey_5_eat ? action :
5637 i == Ykey_6_eat ? action :
5638 i == Ykey_7_eat ? action :
5639 i == Ykey_8_eat ? action :
5640 i == Ylenses_eat ? action :
5641 i == Ymagnify_eat ? action :
5642 i == Ygrass_eat ? action :
5643 i == Ydirt_eat ? action :
5644 i == Xsand_stonein_1 ? action :
5645 i == Xsand_stonein_2 ? action :
5646 i == Xsand_stonein_3 ? action :
5647 i == Xsand_stonein_4 ? action :
5648 i == Xsand_stoneout_1 ? action :
5649 i == Xsand_stoneout_2 ? action :
5650 i == Xboom_android ? ACTION_EXPLODING :
5651 action_exploding ? ACTION_EXPLODING :
5652 action_active ? action :
5653 action_other ? action :
5655 int graphic = (el_act_dir2img(effective_element, effective_action,
5657 int crumbled = (el_act_dir2crm(effective_element, effective_action,
5659 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
5660 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
5661 boolean has_action_graphics = (graphic != base_graphic);
5662 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
5663 struct GraphicInfo *g = &graphic_info[graphic];
5664 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
5667 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
5668 boolean special_animation = (action != ACTION_DEFAULT &&
5669 g->anim_frames == 3 &&
5670 g->anim_delay == 2 &&
5671 g->anim_mode & ANIM_LINEAR);
5672 int sync_frame = (i == Xdrip_stretch ? 7 :
5673 i == Xdrip_stretchB ? 7 :
5674 i == Ydrip_s2 ? j + 8 :
5675 i == Ydrip_s2B ? j + 8 :
5684 i == Xfake_acid_1 ? 0 :
5685 i == Xfake_acid_2 ? 10 :
5686 i == Xfake_acid_3 ? 20 :
5687 i == Xfake_acid_4 ? 30 :
5688 i == Xfake_acid_5 ? 40 :
5689 i == Xfake_acid_6 ? 50 :
5690 i == Xfake_acid_7 ? 60 :
5691 i == Xfake_acid_8 ? 70 :
5693 i == Xball_2B ? j + 8 :
5694 i == Yball_eat ? j + 1 :
5695 i == Ykey_1_eat ? j + 1 :
5696 i == Ykey_2_eat ? j + 1 :
5697 i == Ykey_3_eat ? j + 1 :
5698 i == Ykey_4_eat ? j + 1 :
5699 i == Ykey_5_eat ? j + 1 :
5700 i == Ykey_6_eat ? j + 1 :
5701 i == Ykey_7_eat ? j + 1 :
5702 i == Ykey_8_eat ? j + 1 :
5703 i == Ylenses_eat ? j + 1 :
5704 i == Ymagnify_eat ? j + 1 :
5705 i == Ygrass_eat ? j + 1 :
5706 i == Ydirt_eat ? j + 1 :
5707 i == Xamoeba_1 ? 0 :
5708 i == Xamoeba_2 ? 1 :
5709 i == Xamoeba_3 ? 2 :
5710 i == Xamoeba_4 ? 3 :
5711 i == Xamoeba_5 ? 0 :
5712 i == Xamoeba_6 ? 1 :
5713 i == Xamoeba_7 ? 2 :
5714 i == Xamoeba_8 ? 3 :
5715 i == Xexit_2 ? j + 8 :
5716 i == Xexit_3 ? j + 16 :
5717 i == Xdynamite_1 ? 0 :
5718 i == Xdynamite_2 ? 8 :
5719 i == Xdynamite_3 ? 16 :
5720 i == Xdynamite_4 ? 24 :
5721 i == Xsand_stonein_1 ? j + 1 :
5722 i == Xsand_stonein_2 ? j + 9 :
5723 i == Xsand_stonein_3 ? j + 17 :
5724 i == Xsand_stonein_4 ? j + 25 :
5725 i == Xsand_stoneout_1 && j == 0 ? 0 :
5726 i == Xsand_stoneout_1 && j == 1 ? 0 :
5727 i == Xsand_stoneout_1 && j == 2 ? 1 :
5728 i == Xsand_stoneout_1 && j == 3 ? 2 :
5729 i == Xsand_stoneout_1 && j == 4 ? 2 :
5730 i == Xsand_stoneout_1 && j == 5 ? 3 :
5731 i == Xsand_stoneout_1 && j == 6 ? 4 :
5732 i == Xsand_stoneout_1 && j == 7 ? 4 :
5733 i == Xsand_stoneout_2 && j == 0 ? 5 :
5734 i == Xsand_stoneout_2 && j == 1 ? 6 :
5735 i == Xsand_stoneout_2 && j == 2 ? 7 :
5736 i == Xsand_stoneout_2 && j == 3 ? 8 :
5737 i == Xsand_stoneout_2 && j == 4 ? 9 :
5738 i == Xsand_stoneout_2 && j == 5 ? 11 :
5739 i == Xsand_stoneout_2 && j == 6 ? 13 :
5740 i == Xsand_stoneout_2 && j == 7 ? 15 :
5741 i == Xboom_bug && j == 1 ? 2 :
5742 i == Xboom_bug && j == 2 ? 2 :
5743 i == Xboom_bug && j == 3 ? 4 :
5744 i == Xboom_bug && j == 4 ? 4 :
5745 i == Xboom_bug && j == 5 ? 2 :
5746 i == Xboom_bug && j == 6 ? 2 :
5747 i == Xboom_bug && j == 7 ? 0 :
5748 i == Xboom_bomb && j == 1 ? 2 :
5749 i == Xboom_bomb && j == 2 ? 2 :
5750 i == Xboom_bomb && j == 3 ? 4 :
5751 i == Xboom_bomb && j == 4 ? 4 :
5752 i == Xboom_bomb && j == 5 ? 2 :
5753 i == Xboom_bomb && j == 6 ? 2 :
5754 i == Xboom_bomb && j == 7 ? 0 :
5755 i == Xboom_android && j == 7 ? 6 :
5756 i == Xboom_1 && j == 1 ? 2 :
5757 i == Xboom_1 && j == 2 ? 2 :
5758 i == Xboom_1 && j == 3 ? 4 :
5759 i == Xboom_1 && j == 4 ? 4 :
5760 i == Xboom_1 && j == 5 ? 6 :
5761 i == Xboom_1 && j == 6 ? 6 :
5762 i == Xboom_1 && j == 7 ? 8 :
5763 i == Xboom_2 && j == 0 ? 8 :
5764 i == Xboom_2 && j == 1 ? 8 :
5765 i == Xboom_2 && j == 2 ? 10 :
5766 i == Xboom_2 && j == 3 ? 10 :
5767 i == Xboom_2 && j == 4 ? 10 :
5768 i == Xboom_2 && j == 5 ? 12 :
5769 i == Xboom_2 && j == 6 ? 12 :
5770 i == Xboom_2 && j == 7 ? 12 :
5771 special_animation && j == 4 ? 3 :
5772 effective_action != action ? 0 :
5776 Bitmap *debug_bitmap = g_em->bitmap;
5777 int debug_src_x = g_em->src_x;
5778 int debug_src_y = g_em->src_y;
5781 int frame = getAnimationFrame(g->anim_frames,
5784 g->anim_start_frame,
5787 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
5788 g->double_movement && is_backside);
5790 g_em->bitmap = src_bitmap;
5791 g_em->src_x = src_x;
5792 g_em->src_y = src_y;
5793 g_em->src_offset_x = 0;
5794 g_em->src_offset_y = 0;
5795 g_em->dst_offset_x = 0;
5796 g_em->dst_offset_y = 0;
5797 g_em->width = TILEX;
5798 g_em->height = TILEY;
5800 g_em->crumbled_bitmap = NULL;
5801 g_em->crumbled_src_x = 0;
5802 g_em->crumbled_src_y = 0;
5803 g_em->crumbled_border_size = 0;
5805 g_em->has_crumbled_graphics = FALSE;
5806 g_em->preserve_background = FALSE;
5809 if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
5810 printf("::: empty crumbled: %d [%s], %d, %d\n",
5811 effective_element, element_info[effective_element].token_name,
5812 effective_action, direction);
5815 /* if element can be crumbled, but certain action graphics are just empty
5816 space (like snapping sand with the original R'n'D graphics), do not
5817 treat these empty space graphics as crumbled graphics in EMC engine */
5818 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
5820 getGraphicSource(crumbled, frame, &src_bitmap, &src_x, &src_y);
5822 g_em->has_crumbled_graphics = TRUE;
5823 g_em->crumbled_bitmap = src_bitmap;
5824 g_em->crumbled_src_x = src_x;
5825 g_em->crumbled_src_y = src_y;
5826 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
5830 if (element == EL_ROCK &&
5831 effective_action == ACTION_FILLING)
5832 printf("::: has_action_graphics == %d\n", has_action_graphics);
5835 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
5836 effective_action == ACTION_MOVING ||
5837 effective_action == ACTION_PUSHING ||
5838 effective_action == ACTION_EATING)) ||
5839 (!has_action_graphics && (effective_action == ACTION_FILLING ||
5840 effective_action == ACTION_EMPTYING)))
5843 (effective_action == ACTION_FALLING ||
5844 effective_action == ACTION_FILLING ||
5845 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
5846 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
5847 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
5848 int num_steps = (i == Ydrip_s1 ? 16 :
5849 i == Ydrip_s1B ? 16 :
5850 i == Ydrip_s2 ? 16 :
5851 i == Ydrip_s2B ? 16 :
5852 i == Xsand_stonein_1 ? 32 :
5853 i == Xsand_stonein_2 ? 32 :
5854 i == Xsand_stonein_3 ? 32 :
5855 i == Xsand_stonein_4 ? 32 :
5856 i == Xsand_stoneout_1 ? 16 :
5857 i == Xsand_stoneout_2 ? 16 : 8);
5858 int cx = ABS(dx) * (TILEX / num_steps);
5859 int cy = ABS(dy) * (TILEY / num_steps);
5860 int step_frame = (i == Ydrip_s2 ? j + 8 :
5861 i == Ydrip_s2B ? j + 8 :
5862 i == Xsand_stonein_2 ? j + 8 :
5863 i == Xsand_stonein_3 ? j + 16 :
5864 i == Xsand_stonein_4 ? j + 24 :
5865 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
5866 int step = (is_backside ? step_frame : num_steps - step_frame);
5868 if (is_backside) /* tile where movement starts */
5870 if (dx < 0 || dy < 0)
5872 g_em->src_offset_x = cx * step;
5873 g_em->src_offset_y = cy * step;
5877 g_em->dst_offset_x = cx * step;
5878 g_em->dst_offset_y = cy * step;
5881 else /* tile where movement ends */
5883 if (dx < 0 || dy < 0)
5885 g_em->dst_offset_x = cx * step;
5886 g_em->dst_offset_y = cy * step;
5890 g_em->src_offset_x = cx * step;
5891 g_em->src_offset_y = cy * step;
5895 g_em->width = TILEX - cx * step;
5896 g_em->height = TILEY - cy * step;
5899 /* create unique graphic identifier to decide if tile must be redrawn */
5900 /* bit 31 - 16 (16 bit): EM style graphic
5901 bit 15 - 12 ( 4 bit): EM style frame
5902 bit 11 - 6 ( 6 bit): graphic width
5903 bit 5 - 0 ( 6 bit): graphic height */
5904 g_em->unique_identifier =
5905 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
5909 /* skip check for EMC elements not contained in original EMC artwork */
5910 if (element == EL_EMC_FAKE_ACID)
5913 if (g_em->bitmap != debug_bitmap ||
5914 g_em->src_x != debug_src_x ||
5915 g_em->src_y != debug_src_y ||
5916 g_em->src_offset_x != 0 ||
5917 g_em->src_offset_y != 0 ||
5918 g_em->dst_offset_x != 0 ||
5919 g_em->dst_offset_y != 0 ||
5920 g_em->width != TILEX ||
5921 g_em->height != TILEY)
5923 static int last_i = -1;
5931 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
5932 i, element, element_info[element].token_name,
5933 element_action_info[effective_action].suffix, direction);
5935 if (element != effective_element)
5936 printf(" [%d ('%s')]",
5938 element_info[effective_element].token_name);
5942 if (g_em->bitmap != debug_bitmap)
5943 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
5944 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
5946 if (g_em->src_x != debug_src_x ||
5947 g_em->src_y != debug_src_y)
5948 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
5949 j, (is_backside ? 'B' : 'F'),
5950 g_em->src_x, g_em->src_y,
5951 g_em->src_x / 32, g_em->src_y / 32,
5952 debug_src_x, debug_src_y,
5953 debug_src_x / 32, debug_src_y / 32);
5955 if (g_em->src_offset_x != 0 ||
5956 g_em->src_offset_y != 0 ||
5957 g_em->dst_offset_x != 0 ||
5958 g_em->dst_offset_y != 0)
5959 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
5961 g_em->src_offset_x, g_em->src_offset_y,
5962 g_em->dst_offset_x, g_em->dst_offset_y);
5964 if (g_em->width != TILEX ||
5965 g_em->height != TILEY)
5966 printf(" %d (%d): size %d,%d should be %d,%d\n",
5968 g_em->width, g_em->height, TILEX, TILEY);
5970 num_em_gfx_errors++;
5977 for (i = 0; i < TILE_MAX; i++)
5979 for (j = 0; j < 8; j++)
5981 int element = object_mapping[i].element_rnd;
5982 int action = object_mapping[i].action;
5983 int direction = object_mapping[i].direction;
5984 boolean is_backside = object_mapping[i].is_backside;
5985 int graphic_action = el_act_dir2img(element, action, direction);
5986 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
5988 if ((action == ACTION_SMASHED_BY_ROCK ||
5989 action == ACTION_SMASHED_BY_SPRING ||
5990 action == ACTION_EATING) &&
5991 graphic_action == graphic_default)
5993 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
5994 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
5995 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
5996 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
5999 /* no separate animation for "smashed by rock" -- use rock instead */
6000 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
6001 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
6003 g_em->bitmap = g_xx->bitmap;
6004 g_em->src_x = g_xx->src_x;
6005 g_em->src_y = g_xx->src_y;
6006 g_em->src_offset_x = g_xx->src_offset_x;
6007 g_em->src_offset_y = g_xx->src_offset_y;
6008 g_em->dst_offset_x = g_xx->dst_offset_x;
6009 g_em->dst_offset_y = g_xx->dst_offset_y;
6010 g_em->width = g_xx->width;
6011 g_em->height = g_xx->height;
6012 g_em->unique_identifier = g_xx->unique_identifier;
6015 g_em->preserve_background = TRUE;
6020 for (p = 0; p < MAX_PLAYERS; p++)
6022 for (i = 0; i < SPR_MAX; i++)
6024 int element = player_mapping[p][i].element_rnd;
6025 int action = player_mapping[p][i].action;
6026 int direction = player_mapping[p][i].direction;
6028 for (j = 0; j < 8; j++)
6030 int effective_element = element;
6031 int effective_action = action;
6032 int graphic = (direction == MV_NONE ?
6033 el_act2img(effective_element, effective_action) :
6034 el_act_dir2img(effective_element, effective_action,
6036 struct GraphicInfo *g = &graphic_info[graphic];
6037 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
6043 Bitmap *debug_bitmap = g_em->bitmap;
6044 int debug_src_x = g_em->src_x;
6045 int debug_src_y = g_em->src_y;
6048 int frame = getAnimationFrame(g->anim_frames,
6051 g->anim_start_frame,
6054 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x,&src_y, FALSE);
6056 g_em->bitmap = src_bitmap;
6057 g_em->src_x = src_x;
6058 g_em->src_y = src_y;
6059 g_em->src_offset_x = 0;
6060 g_em->src_offset_y = 0;
6061 g_em->dst_offset_x = 0;
6062 g_em->dst_offset_y = 0;
6063 g_em->width = TILEX;
6064 g_em->height = TILEY;
6068 /* skip check for EMC elements not contained in original EMC artwork */
6069 if (element == EL_PLAYER_3 ||
6070 element == EL_PLAYER_4)
6073 if (g_em->bitmap != debug_bitmap ||
6074 g_em->src_x != debug_src_x ||
6075 g_em->src_y != debug_src_y)
6077 static int last_i = -1;
6085 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
6086 p, i, element, element_info[element].token_name,
6087 element_action_info[effective_action].suffix, direction);
6089 if (element != effective_element)
6090 printf(" [%d ('%s')]",
6092 element_info[effective_element].token_name);
6096 if (g_em->bitmap != debug_bitmap)
6097 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
6098 j, (int)(g_em->bitmap), (int)(debug_bitmap));
6100 if (g_em->src_x != debug_src_x ||
6101 g_em->src_y != debug_src_y)
6102 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
6104 g_em->src_x, g_em->src_y,
6105 g_em->src_x / 32, g_em->src_y / 32,
6106 debug_src_x, debug_src_y,
6107 debug_src_x / 32, debug_src_y / 32);
6109 num_em_gfx_errors++;
6119 printf("::: [%d errors found]\n", num_em_gfx_errors);
6125 void PlayMenuSound()
6127 int sound = menu.sound[game_status];
6129 if (sound == SND_UNDEFINED)
6132 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6133 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6136 if (IS_LOOP_SOUND(sound))
6137 PlaySoundLoop(sound);
6142 void PlayMenuSoundStereo(int sound, int stereo_position)
6144 if (sound == SND_UNDEFINED)
6147 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6148 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6151 if (IS_LOOP_SOUND(sound))
6152 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
6154 PlaySoundStereo(sound, stereo_position);
6157 void PlayMenuSoundIfLoop()
6159 int sound = menu.sound[game_status];
6161 if (sound == SND_UNDEFINED)
6164 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6165 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6168 if (IS_LOOP_SOUND(sound))
6169 PlaySoundLoop(sound);
6172 void PlayMenuMusic()
6174 int music = menu.music[game_status];
6176 if (music == MUS_UNDEFINED)
6182 void ToggleFullscreenIfNeeded()
6184 boolean change_fullscreen = (setup.fullscreen !=
6185 video.fullscreen_enabled);
6186 boolean change_fullscreen_mode = (video.fullscreen_enabled &&
6187 !strEqual(setup.fullscreen_mode,
6188 video.fullscreen_mode_current));
6190 if (!video.fullscreen_available)
6194 if (change_fullscreen || change_fullscreen_mode)
6196 if (setup.fullscreen != video.fullscreen_enabled ||
6197 setup.fullscreen_mode != video.fullscreen_mode_current)
6200 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
6202 /* save backbuffer content which gets lost when toggling fullscreen mode */
6203 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6206 if (change_fullscreen_mode)
6208 if (setup.fullscreen && video.fullscreen_enabled)
6211 /* keep fullscreen, but change fullscreen mode (screen resolution) */
6213 /* (this is now set in sdl.c) */
6215 video.fullscreen_mode_current = setup.fullscreen_mode;
6217 video.fullscreen_enabled = FALSE; /* force new fullscreen mode */
6220 /* toggle fullscreen */
6221 ChangeVideoModeIfNeeded(setup.fullscreen);
6223 setup.fullscreen = video.fullscreen_enabled;
6225 /* restore backbuffer content from temporary backbuffer backup bitmap */
6226 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6228 FreeBitmap(tmp_backbuffer);
6231 /* update visible window/screen */
6232 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6234 redraw_mask = REDRAW_ALL;