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_MODE_PLAYING])
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 if (game_status != GAME_MODE_PLAYING ||
319 redraw_mask & REDRAW_FROM_BACKBUFFER ||
320 buffer == backbuffer)
321 DrawMaskedBorder(redraw_mask);
324 if (redraw_mask & REDRAW_ALL)
327 DrawMaskedBorder(REDRAW_ALL);
329 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
331 redraw_mask = REDRAW_NONE;
334 if (redraw_mask & REDRAW_FIELD)
336 if (game_status != GAME_MODE_PLAYING ||
337 redraw_mask & REDRAW_FROM_BACKBUFFER)
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)
357 if (border.draw_masked[GAME_MODE_PLAYING])
359 if (buffer != backbuffer)
361 BlitBitmap(buffer, backbuffer, fx, fy, SXSIZE, SYSIZE, SX, SY);
362 DrawMaskedBorder(REDRAW_FIELD);
365 BlitBitmap(backbuffer, window,
366 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
371 BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
376 printf("redrawing all (ScreenGfxPos == %d) because %s\n",
378 (setup.soft_scrolling ?
379 "setup.soft_scrolling" :
380 ABS(ScreenGfxPos) + ScrollStepSize == TILEX ?
381 "ABS(ScreenGfxPos) + ScrollStepSize == TILEX" :
382 ABS(ScreenGfxPos) == ScrollStepSize ?
383 "ABS(ScreenGfxPos) == ScrollStepSize" :
384 "redraw_tiles > REDRAWTILES_THRESHOLD"));
390 redraw_mask &= ~REDRAW_MAIN;
393 if (redraw_mask & REDRAW_DOORS)
395 if (redraw_mask & REDRAW_DOOR_1)
396 BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
398 if (redraw_mask & REDRAW_DOOR_2)
399 BlitBitmap(backbuffer, window, VX, VY, VXSIZE, VYSIZE, VX, VY);
401 if (redraw_mask & REDRAW_DOOR_3)
402 BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
404 redraw_mask &= ~REDRAW_DOORS;
407 if (redraw_mask & REDRAW_MICROLEVEL)
409 BlitBitmap(backbuffer, window, SX, SY + 10 * TILEY, SXSIZE, 7 * TILEY,
410 SX, SY + 10 * TILEY);
412 redraw_mask &= ~REDRAW_MICROLEVEL;
415 if (redraw_mask & REDRAW_TILES)
417 for (x = 0; x < SCR_FIELDX; x++)
418 for (y = 0 ; y < SCR_FIELDY; y++)
419 if (redraw[redraw_x1 + x][redraw_y1 + y])
420 BlitBitmap(buffer, window,
421 FX + x * TILEX, FY + y * TILEY, TILEX, TILEY,
422 SX + x * TILEX, SY + y * TILEY);
425 if (redraw_mask & REDRAW_FPS) /* display frames per second */
430 sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
431 if (!global.fps_slowdown)
434 sprintf(text, "%.1f fps%s", global.frames_per_second, info1);
435 DrawTextExt(window, SX, SY, text, FONT_TEXT_2, BLIT_OPAQUE);
440 for (x = 0; x < MAX_BUF_XSIZE; x++)
441 for (y = 0; y < MAX_BUF_YSIZE; y++)
444 redraw_mask = REDRAW_NONE;
450 long fading_delay = 300;
452 if (setup.fading && (redraw_mask & REDRAW_FIELD))
459 ClearRectangle(window, REAL_SX,REAL_SY,FULL_SXSIZE,FULL_SYSIZE);
462 for (i = 0; i < 2 * FULL_SYSIZE; i++)
464 for (y = 0; y < FULL_SYSIZE; y++)
466 BlitBitmap(backbuffer, window,
467 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
475 for (i = 1; i < FULL_SYSIZE; i+=2)
476 BlitBitmap(backbuffer, window,
477 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
483 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, 0);
484 BlitBitmapMasked(backbuffer, window,
485 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
490 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, -1);
491 BlitBitmapMasked(backbuffer, window,
492 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
497 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, -1);
498 BlitBitmapMasked(backbuffer, window,
499 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
504 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, 0);
505 BlitBitmapMasked(backbuffer, window,
506 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
511 redraw_mask &= ~REDRAW_MAIN;
518 void FadeExt(int fade_mask, int fade_mode)
520 void (*draw_border_function)(void) = NULL;
521 Bitmap *bitmap = (fade_mode == FADE_MODE_CROSSFADE ? bitmap_db_cross : NULL);
522 int x, y, width, height;
523 int fade_delay, post_delay;
525 if (fade_mask & REDRAW_FIELD)
530 height = FULL_SYSIZE;
532 fade_delay = menu.fade_delay;
533 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? menu.post_delay : 0);
535 draw_border_function = DrawMaskedBorder_FIELD;
537 else /* REDRAW_ALL */
544 fade_delay = title.fade_delay_final;
545 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? title.post_delay_final : 0);
548 redraw_mask |= fade_mask;
550 if (!setup.fade_screens || fade_delay == 0)
552 if (fade_mode == FADE_MODE_FADE_OUT)
553 ClearRectangle(backbuffer, x, y, width, height);
560 FadeRectangle(bitmap, x, y, width, height, fade_mode, fade_delay, post_delay,
561 draw_border_function);
563 redraw_mask &= ~fade_mask;
566 void FadeIn(int fade_mask)
568 FadeExt(fade_mask, FADE_MODE_FADE_IN);
571 void FadeOut(int fade_mask)
573 FadeExt(fade_mask, FADE_MODE_FADE_OUT);
576 void FadeCross(int fade_mask)
578 FadeExt(fade_mask, FADE_MODE_CROSSFADE);
581 void FadeCrossSaveBackbuffer()
583 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
586 void SetMainBackgroundImageIfDefined(int graphic)
588 if (graphic_info[graphic].bitmap)
589 SetMainBackgroundImage(graphic);
592 void SetMainBackgroundImage(int graphic)
594 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
595 graphic_info[graphic].bitmap ?
596 graphic_info[graphic].bitmap :
597 graphic_info[IMG_BACKGROUND].bitmap);
600 void SetDoorBackgroundImage(int graphic)
602 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
603 graphic_info[graphic].bitmap ?
604 graphic_info[graphic].bitmap :
605 graphic_info[IMG_BACKGROUND].bitmap);
608 void SetPanelBackground()
610 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, bitmap_db_panel,
611 DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, 0, 0);
613 SetDoorBackgroundBitmap(bitmap_db_panel);
616 void DrawBackground(int x, int y, int width, int height)
618 /* !!! "drawto" might still point to playfield buffer here (see below) !!! */
619 /* (when entering hall of fame after playing) */
621 ClearRectangleOnBackground(drawto, x, y, width, height);
623 ClearRectangleOnBackground(backbuffer, x, y, width, height);
626 redraw_mask |= REDRAW_FIELD;
629 void DrawBackgroundForFont(int x, int y, int width, int height, int font_nr)
631 struct FontBitmapInfo *font = getFontBitmapInfo(font_nr);
633 if (font->bitmap == NULL)
636 DrawBackground(x, y, width, height);
639 void DrawBackgroundForGraphic(int x, int y, int width, int height, int graphic)
641 struct GraphicInfo *g = &graphic_info[graphic];
643 if (g->bitmap == NULL)
646 DrawBackground(x, y, width, height);
651 /* !!! "drawto" might still point to playfield buffer here (see above) !!! */
652 /* (when entering hall of fame after playing) */
653 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
655 /* !!! maybe this should be done before clearing the background !!! */
656 if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
658 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
659 SetDrawtoField(DRAW_BUFFERED);
662 SetDrawtoField(DRAW_BACKBUFFER);
664 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
666 ClearRectangle(window, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
667 SetDrawtoField(DRAW_DIRECT);
671 void MarkTileDirty(int x, int y)
673 int xx = redraw_x1 + x;
674 int yy = redraw_y1 + y;
679 redraw[xx][yy] = TRUE;
680 redraw_mask |= REDRAW_TILES;
683 void SetBorderElement()
687 BorderElement = EL_EMPTY;
689 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
691 for (x = 0; x < lev_fieldx; x++)
693 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
694 BorderElement = EL_STEELWALL;
696 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
702 void SetRandomAnimationValue(int x, int y)
704 gfx.anim_random_frame = GfxRandom[x][y];
707 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
709 /* animation synchronized with global frame counter, not move position */
710 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
711 sync_frame = FrameCounter;
713 return getAnimationFrame(graphic_info[graphic].anim_frames,
714 graphic_info[graphic].anim_delay,
715 graphic_info[graphic].anim_mode,
716 graphic_info[graphic].anim_start_frame,
720 inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
721 int *x, int *y, boolean get_backside)
723 struct GraphicInfo *g = &graphic_info[graphic];
724 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
725 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
729 if (g->offset_y == 0) /* frames are ordered horizontally */
731 int max_width = g->anim_frames_per_line * g->width;
732 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
734 *x = pos % max_width;
735 *y = src_y % g->height + pos / max_width * g->height;
737 else if (g->offset_x == 0) /* frames are ordered vertically */
739 int max_height = g->anim_frames_per_line * g->height;
740 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
742 *x = src_x % g->width + pos / max_height * g->width;
743 *y = pos % max_height;
745 else /* frames are ordered diagonally */
747 *x = src_x + frame * g->offset_x;
748 *y = src_y + frame * g->offset_y;
752 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
754 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
757 void DrawGraphic(int x, int y, int graphic, int frame)
760 if (!IN_SCR_FIELD(x, y))
762 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
763 printf("DrawGraphic(): This should never happen!\n");
768 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
772 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
778 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
779 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
782 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
785 if (!IN_SCR_FIELD(x, y))
787 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
788 printf("DrawGraphicThruMask(): This should never happen!\n");
793 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
798 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
804 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
806 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
807 dst_x - src_x, dst_y - src_y);
808 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
811 void DrawMiniGraphic(int x, int y, int graphic)
813 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
814 MarkTileDirty(x / 2, y / 2);
817 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
819 struct GraphicInfo *g = &graphic_info[graphic];
821 int mini_starty = g->bitmap->height * 2 / 3;
824 *x = mini_startx + g->src_x / 2;
825 *y = mini_starty + g->src_y / 2;
828 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
833 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
834 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
837 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
838 int graphic, int frame,
839 int cut_mode, int mask_mode)
844 int width = TILEX, height = TILEY;
847 if (dx || dy) /* shifted graphic */
849 if (x < BX1) /* object enters playfield from the left */
856 else if (x > BX2) /* object enters playfield from the right */
862 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
868 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
870 else if (dx) /* general horizontal movement */
871 MarkTileDirty(x + SIGN(dx), y);
873 if (y < BY1) /* object enters playfield from the top */
875 if (cut_mode==CUT_BELOW) /* object completely above top border */
883 else if (y > BY2) /* object enters playfield from the bottom */
889 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
895 else if (dy > 0 && cut_mode == CUT_ABOVE)
897 if (y == BY2) /* object completely above bottom border */
903 MarkTileDirty(x, y + 1);
904 } /* object leaves playfield to the bottom */
905 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
907 else if (dy) /* general vertical movement */
908 MarkTileDirty(x, y + SIGN(dy));
912 if (!IN_SCR_FIELD(x, y))
914 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
915 printf("DrawGraphicShifted(): This should never happen!\n");
920 if (width > 0 && height > 0)
922 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
927 dst_x = FX + x * TILEX + dx;
928 dst_y = FY + y * TILEY + dy;
930 if (mask_mode == USE_MASKING)
932 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
933 dst_x - src_x, dst_y - src_y);
934 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
938 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
945 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
946 int graphic, int frame,
947 int cut_mode, int mask_mode)
952 int width = TILEX, height = TILEY;
955 int x2 = x + SIGN(dx);
956 int y2 = y + SIGN(dy);
957 int anim_frames = graphic_info[graphic].anim_frames;
958 int sync_frame = (dx ? ABS(dx) : ABS(dy)) * anim_frames / TILESIZE;
959 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
960 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
962 /* re-calculate animation frame for two-tile movement animation */
963 frame = getGraphicAnimationFrame(graphic, sync_frame);
965 /* check if movement start graphic inside screen area and should be drawn */
966 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
968 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
970 dst_x = FX + x1 * TILEX;
971 dst_y = FY + y1 * TILEY;
973 if (mask_mode == USE_MASKING)
975 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
976 dst_x - src_x, dst_y - src_y);
977 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
981 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
984 MarkTileDirty(x1, y1);
987 /* check if movement end graphic inside screen area and should be drawn */
988 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
990 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
992 dst_x = FX + x2 * TILEX;
993 dst_y = FY + y2 * TILEY;
995 if (mask_mode == USE_MASKING)
997 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
998 dst_x - src_x, dst_y - src_y);
999 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1003 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1006 MarkTileDirty(x2, y2);
1010 static void DrawGraphicShifted(int x, int y, int dx, int dy,
1011 int graphic, int frame,
1012 int cut_mode, int mask_mode)
1016 DrawGraphic(x, y, graphic, frame);
1021 if (graphic_info[graphic].double_movement) /* EM style movement images */
1022 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1024 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1027 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1028 int frame, int cut_mode)
1030 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
1033 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1034 int cut_mode, int mask_mode)
1036 int lx = LEVELX(x), ly = LEVELY(y);
1040 if (IN_LEV_FIELD(lx, ly))
1042 SetRandomAnimationValue(lx, ly);
1044 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
1045 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1047 /* do not use double (EM style) movement graphic when not moving */
1048 if (graphic_info[graphic].double_movement && !dx && !dy)
1050 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
1051 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1054 else /* border element */
1056 graphic = el2img(element);
1057 frame = getGraphicAnimationFrame(graphic, -1);
1060 if (element == EL_EXPANDABLE_WALL)
1062 boolean left_stopped = FALSE, right_stopped = FALSE;
1064 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1065 left_stopped = TRUE;
1066 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1067 right_stopped = TRUE;
1069 if (left_stopped && right_stopped)
1071 else if (left_stopped)
1073 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1074 frame = graphic_info[graphic].anim_frames - 1;
1076 else if (right_stopped)
1078 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1079 frame = graphic_info[graphic].anim_frames - 1;
1084 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1085 else if (mask_mode == USE_MASKING)
1086 DrawGraphicThruMask(x, y, graphic, frame);
1088 DrawGraphic(x, y, graphic, frame);
1091 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1092 int cut_mode, int mask_mode)
1094 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1095 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1096 cut_mode, mask_mode);
1099 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1102 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1105 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1108 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1111 void DrawLevelElementThruMask(int x, int y, int element)
1113 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1116 void DrawLevelFieldThruMask(int x, int y)
1118 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1121 static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
1125 int sx = SCREENX(x), sy = SCREENY(y);
1127 int width, height, cx, cy, i;
1128 int crumbled_border_size = graphic_info[graphic].border_size;
1129 static int xy[4][2] =
1137 if (!IN_LEV_FIELD(x, y))
1140 element = TILE_GFX_ELEMENT(x, y);
1142 /* crumble field itself */
1143 if (GFX_CRUMBLED(element) && !IS_MOVING(x, y))
1145 if (!IN_SCR_FIELD(sx, sy))
1148 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1150 for (i = 0; i < 4; i++)
1152 int xx = x + xy[i][0];
1153 int yy = y + xy[i][1];
1155 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1158 /* check if neighbour field is of same type */
1159 if (GFX_CRUMBLED(element) && !IS_MOVING(xx, yy))
1162 if (i == 1 || i == 2)
1164 width = crumbled_border_size;
1166 cx = (i == 2 ? TILEX - crumbled_border_size : 0);
1172 height = crumbled_border_size;
1174 cy = (i == 3 ? TILEY - crumbled_border_size : 0);
1177 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1178 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1181 MarkTileDirty(sx, sy);
1183 else /* crumble neighbour fields */
1185 for (i = 0; i < 4; i++)
1187 int xx = x + xy[i][0];
1188 int yy = y + xy[i][1];
1189 int sxx = sx + xy[i][0];
1190 int syy = sy + xy[i][1];
1192 if (!IN_LEV_FIELD(xx, yy) ||
1193 !IN_SCR_FIELD(sxx, syy) ||
1197 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
1200 element = TILE_GFX_ELEMENT(xx, yy);
1202 if (!GFX_CRUMBLED(element))
1205 graphic = el_act2crm(element, ACTION_DEFAULT);
1206 crumbled_border_size = graphic_info[graphic].border_size;
1208 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1210 if (i == 1 || i == 2)
1212 width = crumbled_border_size;
1214 cx = (i == 1 ? TILEX - crumbled_border_size : 0);
1220 height = crumbled_border_size;
1222 cy = (i == 0 ? TILEY - crumbled_border_size : 0);
1225 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1226 width, height, FX + sxx * TILEX + cx, FY + syy * TILEY + cy);
1228 MarkTileDirty(sxx, syy);
1233 void DrawLevelFieldCrumbledSand(int x, int y)
1237 if (!IN_LEV_FIELD(x, y))
1241 /* !!! CHECK THIS !!! */
1244 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1245 GFX_CRUMBLED(GfxElement[x][y]))
1248 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1249 GfxElement[x][y] != EL_UNDEFINED &&
1250 GFX_CRUMBLED(GfxElement[x][y]))
1252 DrawLevelFieldCrumbledSandDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
1259 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
1261 graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
1264 DrawLevelFieldCrumbledSandExt(x, y, graphic, 0);
1267 void DrawLevelFieldCrumbledSandDigging(int x, int y, int direction,
1270 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1271 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1272 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1273 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1274 int sx = SCREENX(x), sy = SCREENY(y);
1276 DrawGraphic(sx, sy, graphic1, frame1);
1277 DrawLevelFieldCrumbledSandExt(x, y, graphic2, frame2);
1280 void DrawLevelFieldCrumbledSandNeighbours(int x, int y)
1282 int sx = SCREENX(x), sy = SCREENY(y);
1283 static int xy[4][2] =
1292 for (i = 0; i < 4; i++)
1294 int xx = x + xy[i][0];
1295 int yy = y + xy[i][1];
1296 int sxx = sx + xy[i][0];
1297 int syy = sy + xy[i][1];
1299 if (!IN_LEV_FIELD(xx, yy) ||
1300 !IN_SCR_FIELD(sxx, syy) ||
1301 !GFX_CRUMBLED(Feld[xx][yy]) ||
1305 DrawLevelField(xx, yy);
1309 static int getBorderElement(int x, int y)
1313 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1314 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1315 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1316 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1317 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1318 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1319 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1321 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1322 int steel_position = (x == -1 && y == -1 ? 0 :
1323 x == lev_fieldx && y == -1 ? 1 :
1324 x == -1 && y == lev_fieldy ? 2 :
1325 x == lev_fieldx && y == lev_fieldy ? 3 :
1326 x == -1 || x == lev_fieldx ? 4 :
1327 y == -1 || y == lev_fieldy ? 5 : 6);
1329 return border[steel_position][steel_type];
1332 void DrawScreenElement(int x, int y, int element)
1334 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1335 DrawLevelFieldCrumbledSand(LEVELX(x), LEVELY(y));
1338 void DrawLevelElement(int x, int y, int element)
1340 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1341 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1344 void DrawScreenField(int x, int y)
1346 int lx = LEVELX(x), ly = LEVELY(y);
1347 int element, content;
1349 if (!IN_LEV_FIELD(lx, ly))
1351 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1354 element = getBorderElement(lx, ly);
1356 DrawScreenElement(x, y, element);
1360 element = Feld[lx][ly];
1361 content = Store[lx][ly];
1363 if (IS_MOVING(lx, ly))
1365 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1366 boolean cut_mode = NO_CUTTING;
1368 if (element == EL_QUICKSAND_EMPTYING ||
1369 element == EL_MAGIC_WALL_EMPTYING ||
1370 element == EL_BD_MAGIC_WALL_EMPTYING ||
1371 element == EL_AMOEBA_DROPPING)
1372 cut_mode = CUT_ABOVE;
1373 else if (element == EL_QUICKSAND_FILLING ||
1374 element == EL_MAGIC_WALL_FILLING ||
1375 element == EL_BD_MAGIC_WALL_FILLING)
1376 cut_mode = CUT_BELOW;
1378 if (cut_mode == CUT_ABOVE)
1379 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1381 DrawScreenElement(x, y, EL_EMPTY);
1384 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1385 else if (cut_mode == NO_CUTTING)
1386 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1388 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1390 if (content == EL_ACID)
1392 int dir = MovDir[lx][ly];
1393 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
1394 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
1396 DrawLevelElementThruMask(newlx, newly, EL_ACID);
1399 else if (IS_BLOCKED(lx, ly))
1404 boolean cut_mode = NO_CUTTING;
1405 int element_old, content_old;
1407 Blocked2Moving(lx, ly, &oldx, &oldy);
1410 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1411 MovDir[oldx][oldy] == MV_RIGHT);
1413 element_old = Feld[oldx][oldy];
1414 content_old = Store[oldx][oldy];
1416 if (element_old == EL_QUICKSAND_EMPTYING ||
1417 element_old == EL_MAGIC_WALL_EMPTYING ||
1418 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1419 element_old == EL_AMOEBA_DROPPING)
1420 cut_mode = CUT_ABOVE;
1422 DrawScreenElement(x, y, EL_EMPTY);
1425 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1427 else if (cut_mode == NO_CUTTING)
1428 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1431 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1434 else if (IS_DRAWABLE(element))
1435 DrawScreenElement(x, y, element);
1437 DrawScreenElement(x, y, EL_EMPTY);
1440 void DrawLevelField(int x, int y)
1442 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1443 DrawScreenField(SCREENX(x), SCREENY(y));
1444 else if (IS_MOVING(x, y))
1448 Moving2Blocked(x, y, &newx, &newy);
1449 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1450 DrawScreenField(SCREENX(newx), SCREENY(newy));
1452 else if (IS_BLOCKED(x, y))
1456 Blocked2Moving(x, y, &oldx, &oldy);
1457 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1458 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1462 void DrawMiniElement(int x, int y, int element)
1466 graphic = el2edimg(element);
1467 DrawMiniGraphic(x, y, graphic);
1470 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1472 int x = sx + scroll_x, y = sy + scroll_y;
1474 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1475 DrawMiniElement(sx, sy, EL_EMPTY);
1476 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1477 DrawMiniElement(sx, sy, Feld[x][y]);
1479 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1482 void DrawEnvelopeBackground(int envelope_nr, int startx, int starty,
1483 int x, int y, int xsize, int ysize, int font_nr)
1485 int font_width = getFontWidth(font_nr);
1486 int font_height = getFontHeight(font_nr);
1487 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1490 int dst_x = SX + startx + x * font_width;
1491 int dst_y = SY + starty + y * font_height;
1492 int width = graphic_info[graphic].width;
1493 int height = graphic_info[graphic].height;
1494 int inner_width = MAX(width - 2 * font_width, font_width);
1495 int inner_height = MAX(height - 2 * font_height, font_height);
1496 int inner_sx = (width >= 3 * font_width ? font_width : 0);
1497 int inner_sy = (height >= 3 * font_height ? font_height : 0);
1498 boolean draw_masked = graphic_info[graphic].draw_masked;
1500 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1502 if (src_bitmap == NULL || width < font_width || height < font_height)
1504 ClearRectangle(drawto, dst_x, dst_y, font_width, font_height);
1508 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - font_width :
1509 inner_sx + (x - 1) * font_width % inner_width);
1510 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - font_height :
1511 inner_sy + (y - 1) * font_height % inner_height);
1515 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1516 dst_x - src_x, dst_y - src_y);
1517 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1521 BlitBitmap(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1525 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
1527 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1528 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1529 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
1530 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1531 boolean no_delay = (tape.warp_forward);
1532 unsigned long anim_delay = 0;
1533 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
1534 int anim_delay_value = (no_delay ? 0 : frame_delay_value);
1535 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
1536 int font_width = getFontWidth(font_nr);
1537 int font_height = getFontHeight(font_nr);
1538 int max_xsize = level.envelope[envelope_nr].xsize;
1539 int max_ysize = level.envelope[envelope_nr].ysize;
1540 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
1541 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
1542 int xend = max_xsize;
1543 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
1544 int xstep = (xstart < xend ? 1 : 0);
1545 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
1548 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
1550 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
1551 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
1552 int sx = (SXSIZE - xsize * font_width) / 2;
1553 int sy = (SYSIZE - ysize * font_height) / 2;
1556 SetDrawtoField(DRAW_BUFFERED);
1558 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
1560 SetDrawtoField(DRAW_BACKBUFFER);
1562 for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++)
1563 DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
1565 DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
1566 level.envelope[envelope_nr].text, font_nr, max_xsize,
1567 xsize - 2, ysize - 2, mask_mode);
1569 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
1572 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
1576 void ShowEnvelope(int envelope_nr)
1578 int element = EL_ENVELOPE_1 + envelope_nr;
1579 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1580 int sound_opening = element_info[element].sound[ACTION_OPENING];
1581 int sound_closing = element_info[element].sound[ACTION_CLOSING];
1582 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1583 boolean no_delay = (tape.warp_forward);
1584 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
1585 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
1586 int anim_mode = graphic_info[graphic].anim_mode;
1587 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
1588 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
1590 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
1592 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
1594 if (anim_mode == ANIM_DEFAULT)
1595 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
1597 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
1600 Delay(wait_delay_value);
1602 WaitForEventToContinue();
1604 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
1606 if (anim_mode != ANIM_NONE)
1607 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
1609 if (anim_mode == ANIM_DEFAULT)
1610 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
1612 game.envelope_active = FALSE;
1614 SetDrawtoField(DRAW_BUFFERED);
1616 redraw_mask |= REDRAW_FIELD;
1620 void getPreviewGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y,
1625 int width_mult, width_div;
1626 int height_mult, height_div;
1634 int offset_calc_pos = (tilesize < MICRO_TILESIZE || tilesize > TILESIZE ? 3 :
1635 5 - log_2(tilesize));
1636 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1637 int width_mult = offset_calc[offset_calc_pos].width_mult;
1638 int width_div = offset_calc[offset_calc_pos].width_div;
1639 int height_mult = offset_calc[offset_calc_pos].height_mult;
1640 int height_div = offset_calc[offset_calc_pos].height_div;
1641 int mini_startx = src_bitmap->width * width_mult / width_div;
1642 int mini_starty = src_bitmap->height * height_mult / height_div;
1643 int src_x = mini_startx + graphic_info[graphic].src_x * tilesize / TILESIZE;
1644 int src_y = mini_starty + graphic_info[graphic].src_y * tilesize / TILESIZE;
1646 *bitmap = src_bitmap;
1651 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
1655 int graphic = el2preimg(element);
1657 getPreviewGraphicSource(graphic, &src_bitmap, &src_x, &src_y, tilesize);
1658 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
1665 SetDrawBackgroundMask(REDRAW_NONE);
1668 for (x = BX1; x <= BX2; x++)
1669 for (y = BY1; y <= BY2; y++)
1670 DrawScreenField(x, y);
1672 redraw_mask |= REDRAW_FIELD;
1675 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1679 for (x = 0; x < size_x; x++)
1680 for (y = 0; y < size_y; y++)
1681 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1683 redraw_mask |= REDRAW_FIELD;
1686 static void DrawPreviewLevelExt(int from_x, int from_y)
1688 boolean show_level_border = (BorderElement != EL_EMPTY);
1689 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
1690 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
1691 int tile_size = preview.tile_size;
1692 int preview_width = preview.xsize * tile_size;
1693 int preview_height = preview.ysize * tile_size;
1694 int real_preview_xsize = MIN(level_xsize, preview.xsize);
1695 int real_preview_ysize = MIN(level_ysize, preview.ysize);
1696 int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
1697 int dst_y = SY + preview.y;
1700 DrawBackground(dst_x, dst_y, preview_width, preview_height);
1702 dst_x += (preview_width - real_preview_xsize * tile_size) / 2;
1703 dst_y += (preview_height - real_preview_ysize * tile_size) / 2;
1705 for (x = 0; x < real_preview_xsize; x++)
1707 for (y = 0; y < real_preview_ysize; y++)
1709 int lx = from_x + x + (show_level_border ? -1 : 0);
1710 int ly = from_y + y + (show_level_border ? -1 : 0);
1711 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
1712 getBorderElement(lx, ly));
1714 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
1715 element, tile_size);
1719 redraw_mask |= REDRAW_MICROLEVEL;
1722 #define MICROLABEL_EMPTY 0
1723 #define MICROLABEL_LEVEL_NAME 1
1724 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
1725 #define MICROLABEL_LEVEL_AUTHOR 3
1726 #define MICROLABEL_IMPORTED_FROM_HEAD 4
1727 #define MICROLABEL_IMPORTED_FROM 5
1728 #define MICROLABEL_IMPORTED_BY_HEAD 6
1729 #define MICROLABEL_IMPORTED_BY 7
1731 static int getMaxTextLength(struct MenuPosInfo *pos, int font_nr)
1733 int max_text_width = SXSIZE;
1734 int font_width = getFontWidth(font_nr);
1736 if (pos->align == ALIGN_CENTER)
1737 max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
1738 else if (pos->align == ALIGN_RIGHT)
1739 max_text_width = pos->x;
1741 max_text_width = SXSIZE - pos->x;
1743 return max_text_width / font_width;
1746 static void DrawPreviewLevelLabelExt(int mode)
1748 struct MenuPosInfo *pos = &menu.main.text.level_info_2;
1749 char label_text[MAX_OUTPUT_LINESIZE + 1];
1750 int max_len_label_text;
1751 int font_nr = FONT_TEXT_2;
1754 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
1755 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
1756 mode == MICROLABEL_IMPORTED_BY_HEAD)
1757 font_nr = FONT_TEXT_3;
1760 max_len_label_text = getMaxTextLength(pos, font_nr);
1762 max_len_label_text = SXSIZE / getFontWidth(font_nr);
1765 for (i = 0; i < max_len_label_text; i++)
1766 label_text[i] = ' ';
1767 label_text[max_len_label_text] = '\0';
1769 if (strlen(label_text) > 0)
1772 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
1774 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1775 int lypos = MICROLABEL2_YPOS;
1777 DrawText(lxpos, lypos, label_text, font_nr);
1782 (mode == MICROLABEL_LEVEL_NAME ? level.name :
1783 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
1784 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1785 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
1786 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
1787 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
1788 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
1789 max_len_label_text);
1790 label_text[max_len_label_text] = '\0';
1792 if (strlen(label_text) > 0)
1795 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
1797 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1798 int lypos = MICROLABEL2_YPOS;
1800 DrawText(lxpos, lypos, label_text, font_nr);
1804 redraw_mask |= REDRAW_MICROLEVEL;
1807 void DrawPreviewLevel(boolean restart)
1809 static unsigned long scroll_delay = 0;
1810 static unsigned long label_delay = 0;
1811 static int from_x, from_y, scroll_direction;
1812 static int label_state, label_counter;
1813 unsigned long scroll_delay_value = preview.step_delay;
1814 boolean show_level_border = (BorderElement != EL_EMPTY);
1815 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
1816 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
1817 int last_game_status = game_status; /* save current game status */
1819 /* force PREVIEW font on preview level */
1820 game_status = GAME_MODE_PSEUDO_PREVIEW;
1827 if (preview.anim_mode == ANIM_CENTERED)
1829 if (level_xsize > preview.xsize)
1830 from_x = (level_xsize - preview.xsize) / 2;
1831 if (level_ysize > preview.ysize)
1832 from_y = (level_ysize - preview.ysize) / 2;
1835 from_x += preview.xoffset;
1836 from_y += preview.yoffset;
1838 scroll_direction = MV_RIGHT;
1842 DrawPreviewLevelExt(from_x, from_y);
1843 DrawPreviewLevelLabelExt(label_state);
1845 /* initialize delay counters */
1846 DelayReached(&scroll_delay, 0);
1847 DelayReached(&label_delay, 0);
1849 if (leveldir_current->name)
1851 struct MenuPosInfo *pos = &menu.main.text.level_info_1;
1852 char label_text[MAX_OUTPUT_LINESIZE + 1];
1853 int font_nr = FONT_TEXT_1;
1855 int max_len_label_text = getMaxTextLength(pos, font_nr);
1857 int max_len_label_text = SXSIZE / getFontWidth(font_nr);
1864 strncpy(label_text, leveldir_current->name, max_len_label_text);
1865 label_text[max_len_label_text] = '\0';
1868 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
1870 lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1871 lypos = SY + MICROLABEL1_YPOS;
1873 DrawText(lxpos, lypos, label_text, font_nr);
1877 game_status = last_game_status; /* restore current game status */
1882 /* scroll preview level, if needed */
1883 if (preview.anim_mode != ANIM_NONE &&
1884 (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
1885 DelayReached(&scroll_delay, scroll_delay_value))
1887 switch (scroll_direction)
1892 from_x -= preview.step_offset;
1893 from_x = (from_x < 0 ? 0 : from_x);
1896 scroll_direction = MV_UP;
1900 if (from_x < level_xsize - preview.xsize)
1902 from_x += preview.step_offset;
1903 from_x = (from_x > level_xsize - preview.xsize ?
1904 level_xsize - preview.xsize : from_x);
1907 scroll_direction = MV_DOWN;
1913 from_y -= preview.step_offset;
1914 from_y = (from_y < 0 ? 0 : from_y);
1917 scroll_direction = MV_RIGHT;
1921 if (from_y < level_ysize - preview.ysize)
1923 from_y += preview.step_offset;
1924 from_y = (from_y > level_ysize - preview.ysize ?
1925 level_ysize - preview.ysize : from_y);
1928 scroll_direction = MV_LEFT;
1935 DrawPreviewLevelExt(from_x, from_y);
1938 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
1939 /* redraw micro level label, if needed */
1940 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
1941 !strEqual(level.author, ANONYMOUS_NAME) &&
1942 !strEqual(level.author, leveldir_current->name) &&
1943 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
1945 int max_label_counter = 23;
1947 if (leveldir_current->imported_from != NULL &&
1948 strlen(leveldir_current->imported_from) > 0)
1949 max_label_counter += 14;
1950 if (leveldir_current->imported_by != NULL &&
1951 strlen(leveldir_current->imported_by) > 0)
1952 max_label_counter += 14;
1954 label_counter = (label_counter + 1) % max_label_counter;
1955 label_state = (label_counter >= 0 && label_counter <= 7 ?
1956 MICROLABEL_LEVEL_NAME :
1957 label_counter >= 9 && label_counter <= 12 ?
1958 MICROLABEL_LEVEL_AUTHOR_HEAD :
1959 label_counter >= 14 && label_counter <= 21 ?
1960 MICROLABEL_LEVEL_AUTHOR :
1961 label_counter >= 23 && label_counter <= 26 ?
1962 MICROLABEL_IMPORTED_FROM_HEAD :
1963 label_counter >= 28 && label_counter <= 35 ?
1964 MICROLABEL_IMPORTED_FROM :
1965 label_counter >= 37 && label_counter <= 40 ?
1966 MICROLABEL_IMPORTED_BY_HEAD :
1967 label_counter >= 42 && label_counter <= 49 ?
1968 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
1970 if (leveldir_current->imported_from == NULL &&
1971 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
1972 label_state == MICROLABEL_IMPORTED_FROM))
1973 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
1974 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
1976 DrawPreviewLevelLabelExt(label_state);
1979 game_status = last_game_status; /* restore current game status */
1982 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
1983 int graphic, int sync_frame, int mask_mode)
1985 int frame = getGraphicAnimationFrame(graphic, sync_frame);
1987 if (mask_mode == USE_MASKING)
1988 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
1990 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
1993 inline void DrawGraphicAnimation(int x, int y, int graphic)
1995 int lx = LEVELX(x), ly = LEVELY(y);
1997 if (!IN_SCR_FIELD(x, y))
2000 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
2001 graphic, GfxFrame[lx][ly], NO_MASKING);
2002 MarkTileDirty(x, y);
2005 void DrawLevelGraphicAnimation(int x, int y, int graphic)
2007 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2010 void DrawLevelElementAnimation(int x, int y, int element)
2012 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2014 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2017 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
2019 int sx = SCREENX(x), sy = SCREENY(y);
2021 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2024 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2027 DrawGraphicAnimation(sx, sy, graphic);
2030 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
2031 DrawLevelFieldCrumbledSand(x, y);
2033 if (GFX_CRUMBLED(Feld[x][y]))
2034 DrawLevelFieldCrumbledSand(x, y);
2038 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
2040 int sx = SCREENX(x), sy = SCREENY(y);
2043 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2046 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2048 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2051 DrawGraphicAnimation(sx, sy, graphic);
2053 if (GFX_CRUMBLED(element))
2054 DrawLevelFieldCrumbledSand(x, y);
2057 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
2059 if (player->use_murphy)
2061 /* this works only because currently only one player can be "murphy" ... */
2062 static int last_horizontal_dir = MV_LEFT;
2063 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
2065 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2066 last_horizontal_dir = move_dir;
2068 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
2070 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
2072 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
2078 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
2081 static boolean equalGraphics(int graphic1, int graphic2)
2083 struct GraphicInfo *g1 = &graphic_info[graphic1];
2084 struct GraphicInfo *g2 = &graphic_info[graphic2];
2086 return (g1->bitmap == g2->bitmap &&
2087 g1->src_x == g2->src_x &&
2088 g1->src_y == g2->src_y &&
2089 g1->anim_frames == g2->anim_frames &&
2090 g1->anim_delay == g2->anim_delay &&
2091 g1->anim_mode == g2->anim_mode);
2094 void DrawAllPlayers()
2098 for (i = 0; i < MAX_PLAYERS; i++)
2099 if (stored_player[i].active)
2100 DrawPlayer(&stored_player[i]);
2103 void DrawPlayerField(int x, int y)
2105 if (!IS_PLAYER(x, y))
2108 DrawPlayer(PLAYERINFO(x, y));
2111 void DrawPlayer(struct PlayerInfo *player)
2113 int jx = player->jx;
2114 int jy = player->jy;
2115 int move_dir = player->MovDir;
2116 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
2117 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
2118 int last_jx = (player->is_moving ? jx - dx : jx);
2119 int last_jy = (player->is_moving ? jy - dy : jy);
2120 int next_jx = jx + dx;
2121 int next_jy = jy + dy;
2122 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
2123 boolean player_is_opaque = FALSE;
2124 int sx = SCREENX(jx), sy = SCREENY(jy);
2125 int sxx = 0, syy = 0;
2126 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
2128 int action = ACTION_DEFAULT;
2129 int last_player_graphic = getPlayerGraphic(player, move_dir);
2130 int last_player_frame = player->Frame;
2133 /* GfxElement[][] is set to the element the player is digging or collecting;
2134 remove also for off-screen player if the player is not moving anymore */
2135 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
2136 GfxElement[jx][jy] = EL_UNDEFINED;
2138 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
2142 if (!IN_LEV_FIELD(jx, jy))
2144 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
2145 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
2146 printf("DrawPlayerField(): This should never happen!\n");
2151 if (element == EL_EXPLOSION)
2154 action = (player->is_pushing ? ACTION_PUSHING :
2155 player->is_digging ? ACTION_DIGGING :
2156 player->is_collecting ? ACTION_COLLECTING :
2157 player->is_moving ? ACTION_MOVING :
2158 player->is_snapping ? ACTION_SNAPPING :
2159 player->is_dropping ? ACTION_DROPPING :
2160 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
2162 if (player->is_waiting)
2163 move_dir = player->dir_waiting;
2165 InitPlayerGfxAnimation(player, action, move_dir);
2167 /* ----------------------------------------------------------------------- */
2168 /* draw things in the field the player is leaving, if needed */
2169 /* ----------------------------------------------------------------------- */
2171 if (player->is_moving)
2173 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
2175 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
2177 if (last_element == EL_DYNAMITE_ACTIVE ||
2178 last_element == EL_EM_DYNAMITE_ACTIVE ||
2179 last_element == EL_SP_DISK_RED_ACTIVE)
2180 DrawDynamite(last_jx, last_jy);
2182 DrawLevelFieldThruMask(last_jx, last_jy);
2184 else if (last_element == EL_DYNAMITE_ACTIVE ||
2185 last_element == EL_EM_DYNAMITE_ACTIVE ||
2186 last_element == EL_SP_DISK_RED_ACTIVE)
2187 DrawDynamite(last_jx, last_jy);
2189 /* !!! this is not enough to prevent flickering of players which are
2190 moving next to each others without a free tile between them -- this
2191 can only be solved by drawing all players layer by layer (first the
2192 background, then the foreground etc.) !!! => TODO */
2193 else if (!IS_PLAYER(last_jx, last_jy))
2194 DrawLevelField(last_jx, last_jy);
2197 DrawLevelField(last_jx, last_jy);
2200 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
2201 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
2204 if (!IN_SCR_FIELD(sx, sy))
2207 if (setup.direct_draw)
2208 SetDrawtoField(DRAW_BUFFERED);
2210 /* ----------------------------------------------------------------------- */
2211 /* draw things behind the player, if needed */
2212 /* ----------------------------------------------------------------------- */
2215 DrawLevelElement(jx, jy, Back[jx][jy]);
2216 else if (IS_ACTIVE_BOMB(element))
2217 DrawLevelElement(jx, jy, EL_EMPTY);
2220 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
2222 int old_element = GfxElement[jx][jy];
2223 int old_graphic = el_act_dir2img(old_element, action, move_dir);
2224 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
2226 if (GFX_CRUMBLED(old_element))
2227 DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
2229 DrawGraphic(sx, sy, old_graphic, frame);
2231 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
2232 player_is_opaque = TRUE;
2236 GfxElement[jx][jy] = EL_UNDEFINED;
2238 /* make sure that pushed elements are drawn with correct frame rate */
2240 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2242 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
2243 GfxFrame[jx][jy] = player->StepFrame;
2245 if (player->is_pushing && player->is_moving)
2246 GfxFrame[jx][jy] = player->StepFrame;
2249 DrawLevelField(jx, jy);
2253 /* ----------------------------------------------------------------------- */
2254 /* draw player himself */
2255 /* ----------------------------------------------------------------------- */
2257 graphic = getPlayerGraphic(player, move_dir);
2259 /* in the case of changed player action or direction, prevent the current
2260 animation frame from being restarted for identical animations */
2261 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
2262 player->Frame = last_player_frame;
2264 frame = getGraphicAnimationFrame(graphic, player->Frame);
2268 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2269 sxx = player->GfxPos;
2271 syy = player->GfxPos;
2274 if (!setup.soft_scrolling && ScreenMovPos)
2277 if (player_is_opaque)
2278 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
2280 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2282 if (SHIELD_ON(player))
2284 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
2285 IMG_SHIELD_NORMAL_ACTIVE);
2286 int frame = getGraphicAnimationFrame(graphic, -1);
2288 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2291 /* ----------------------------------------------------------------------- */
2292 /* draw things the player is pushing, if needed */
2293 /* ----------------------------------------------------------------------- */
2296 printf("::: %d, %d [%d, %d] [%d]\n",
2297 player->is_pushing, player_is_moving, player->GfxAction,
2298 player->is_moving, player_is_moving);
2302 if (player->is_pushing && player->is_moving)
2304 int px = SCREENX(jx), py = SCREENY(jy);
2305 int pxx = (TILEX - ABS(sxx)) * dx;
2306 int pyy = (TILEY - ABS(syy)) * dy;
2307 int gfx_frame = GfxFrame[jx][jy];
2313 if (!IS_MOVING(jx, jy)) /* push movement already finished */
2315 element = Feld[next_jx][next_jy];
2316 gfx_frame = GfxFrame[next_jx][next_jy];
2319 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2322 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
2323 frame = getGraphicAnimationFrame(graphic, sync_frame);
2325 frame = getGraphicAnimationFrame(graphic, player->StepFrame);
2328 /* draw background element under pushed element (like the Sokoban field) */
2329 if (Back[next_jx][next_jy])
2330 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
2332 /* masked drawing is needed for EMC style (double) movement graphics */
2333 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
2337 /* ----------------------------------------------------------------------- */
2338 /* draw things in front of player (active dynamite or dynabombs) */
2339 /* ----------------------------------------------------------------------- */
2341 if (IS_ACTIVE_BOMB(element))
2343 graphic = el2img(element);
2344 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
2346 if (game.emulation == EMU_SUPAPLEX)
2347 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
2349 DrawGraphicThruMask(sx, sy, graphic, frame);
2352 if (player_is_moving && last_element == EL_EXPLOSION)
2354 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
2355 GfxElement[last_jx][last_jy] : EL_EMPTY);
2356 int graphic = el_act2img(element, ACTION_EXPLODING);
2357 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
2358 int phase = ExplodePhase[last_jx][last_jy] - 1;
2359 int frame = getGraphicAnimationFrame(graphic, phase - delay);
2362 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
2365 /* ----------------------------------------------------------------------- */
2366 /* draw elements the player is just walking/passing through/under */
2367 /* ----------------------------------------------------------------------- */
2369 if (player_is_moving)
2371 /* handle the field the player is leaving ... */
2372 if (IS_ACCESSIBLE_INSIDE(last_element))
2373 DrawLevelField(last_jx, last_jy);
2374 else if (IS_ACCESSIBLE_UNDER(last_element))
2375 DrawLevelFieldThruMask(last_jx, last_jy);
2378 /* do not redraw accessible elements if the player is just pushing them */
2379 if (!player_is_moving || !player->is_pushing)
2381 /* ... and the field the player is entering */
2382 if (IS_ACCESSIBLE_INSIDE(element))
2383 DrawLevelField(jx, jy);
2384 else if (IS_ACCESSIBLE_UNDER(element))
2385 DrawLevelFieldThruMask(jx, jy);
2388 if (setup.direct_draw)
2390 int dst_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
2391 int dst_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
2392 int x_size = TILEX * (1 + ABS(jx - last_jx));
2393 int y_size = TILEY * (1 + ABS(jy - last_jy));
2395 BlitBitmap(drawto_field, window,
2396 dst_x, dst_y, x_size, y_size, dst_x, dst_y);
2397 SetDrawtoField(DRAW_DIRECT);
2400 MarkTileDirty(sx, sy);
2403 /* ------------------------------------------------------------------------- */
2405 void WaitForEventToContinue()
2407 boolean still_wait = TRUE;
2409 /* simulate releasing mouse button over last gadget, if still pressed */
2411 HandleGadgets(-1, -1, 0);
2413 button_status = MB_RELEASED;
2429 case EVENT_BUTTONPRESS:
2430 case EVENT_KEYPRESS:
2434 case EVENT_KEYRELEASE:
2435 ClearPlayerAction();
2439 HandleOtherEvents(&event);
2443 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2450 /* don't eat all CPU time */
2455 #define MAX_REQUEST_LINES 13
2456 #define MAX_REQUEST_LINE_FONT1_LEN 7
2457 #define MAX_REQUEST_LINE_FONT2_LEN 10
2459 boolean Request(char *text, unsigned int req_state)
2461 int mx, my, ty, result = -1;
2462 unsigned int old_door_state;
2463 int last_game_status = game_status; /* save current game status */
2464 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
2465 int font_nr = FONT_TEXT_2;
2466 int max_word_len = 0;
2469 for (text_ptr = text; *text_ptr; text_ptr++)
2471 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
2473 if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
2475 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
2476 font_nr = FONT_LEVEL_NUMBER;
2482 if (game_status == GAME_MODE_PLAYING &&
2483 level.game_engine_type == GAME_ENGINE_TYPE_EM)
2484 BlitScreenToBitmap_EM(backbuffer);
2486 /* disable deactivated drawing when quick-loading level tape recording */
2487 if (tape.playing && tape.deactivate_display)
2488 TapeDeactivateDisplayOff(TRUE);
2490 SetMouseCursor(CURSOR_DEFAULT);
2492 #if defined(NETWORK_AVALIABLE)
2493 /* pause network game while waiting for request to answer */
2494 if (options.network &&
2495 game_status == GAME_MODE_PLAYING &&
2496 req_state & REQUEST_WAIT_FOR_INPUT)
2497 SendToServer_PausePlaying();
2500 old_door_state = GetDoorState();
2502 /* simulate releasing mouse button over last gadget, if still pressed */
2504 HandleGadgets(-1, -1, 0);
2508 if (old_door_state & DOOR_OPEN_1)
2510 CloseDoor(DOOR_CLOSE_1);
2512 /* save old door content */
2513 BlitBitmap(bitmap_db_door, bitmap_db_door,
2514 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2515 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
2519 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2522 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2524 /* clear door drawing field */
2525 DrawBackground(DX, DY, DXSIZE, DYSIZE);
2527 /* force DOOR font on preview level */
2528 game_status = GAME_MODE_PSEUDO_DOOR;
2530 /* write text for request */
2531 for (ty = 0; ty < MAX_REQUEST_LINES; ty++)
2533 char text_line[max_request_line_len + 1];
2539 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
2542 if (!tc || tc == ' ')
2553 strncpy(text_line, text, tl);
2556 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
2557 DY + 8 + ty * (getFontHeight(font_nr) + 2),
2558 text_line, font_nr);
2560 text += tl + (tc == ' ' ? 1 : 0);
2563 game_status = last_game_status; /* restore current game status */
2565 if (req_state & REQ_ASK)
2567 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2568 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2570 else if (req_state & REQ_CONFIRM)
2572 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2574 else if (req_state & REQ_PLAYER)
2576 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2577 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2578 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2579 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2582 /* copy request gadgets to door backbuffer */
2583 BlitBitmap(drawto, bitmap_db_door,
2584 DX, DY, DXSIZE, DYSIZE,
2585 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2587 OpenDoor(DOOR_OPEN_1);
2589 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
2591 if (game_status == GAME_MODE_PLAYING)
2593 SetPanelBackground();
2594 SetDrawBackgroundMask(REDRAW_DOOR_1);
2598 SetDrawBackgroundMask(REDRAW_FIELD);
2604 if (game_status != GAME_MODE_MAIN)
2607 button_status = MB_RELEASED;
2609 request_gadget_id = -1;
2611 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2623 case EVENT_BUTTONPRESS:
2624 case EVENT_BUTTONRELEASE:
2625 case EVENT_MOTIONNOTIFY:
2627 if (event.type == EVENT_MOTIONNOTIFY)
2629 if (!PointerInWindow(window))
2630 continue; /* window and pointer are on different screens */
2635 motion_status = TRUE;
2636 mx = ((MotionEvent *) &event)->x;
2637 my = ((MotionEvent *) &event)->y;
2641 motion_status = FALSE;
2642 mx = ((ButtonEvent *) &event)->x;
2643 my = ((ButtonEvent *) &event)->y;
2644 if (event.type == EVENT_BUTTONPRESS)
2645 button_status = ((ButtonEvent *) &event)->button;
2647 button_status = MB_RELEASED;
2650 /* this sets 'request_gadget_id' */
2651 HandleGadgets(mx, my, button_status);
2653 switch (request_gadget_id)
2655 case TOOL_CTRL_ID_YES:
2658 case TOOL_CTRL_ID_NO:
2661 case TOOL_CTRL_ID_CONFIRM:
2662 result = TRUE | FALSE;
2665 case TOOL_CTRL_ID_PLAYER_1:
2668 case TOOL_CTRL_ID_PLAYER_2:
2671 case TOOL_CTRL_ID_PLAYER_3:
2674 case TOOL_CTRL_ID_PLAYER_4:
2685 case EVENT_KEYPRESS:
2686 switch (GetEventKey((KeyEvent *)&event, TRUE))
2699 if (req_state & REQ_PLAYER)
2703 case EVENT_KEYRELEASE:
2704 ClearPlayerAction();
2708 HandleOtherEvents(&event);
2712 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2714 int joy = AnyJoystick();
2716 if (joy & JOY_BUTTON_1)
2718 else if (joy & JOY_BUTTON_2)
2725 if (!PendingEvent()) /* delay only if no pending events */
2728 /* don't eat all CPU time */
2733 if (game_status != GAME_MODE_MAIN)
2738 if (!(req_state & REQ_STAY_OPEN))
2740 CloseDoor(DOOR_CLOSE_1);
2742 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
2743 (req_state & REQ_REOPEN))
2744 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
2749 if (game_status == GAME_MODE_PLAYING)
2751 SetPanelBackground();
2752 SetDrawBackgroundMask(REDRAW_DOOR_1);
2756 SetDrawBackgroundMask(REDRAW_FIELD);
2759 #if defined(NETWORK_AVALIABLE)
2760 /* continue network game after request */
2761 if (options.network &&
2762 game_status == GAME_MODE_PLAYING &&
2763 req_state & REQUEST_WAIT_FOR_INPUT)
2764 SendToServer_ContinuePlaying();
2767 /* restore deactivated drawing when quick-loading level tape recording */
2768 if (tape.playing && tape.deactivate_display)
2769 TapeDeactivateDisplayOn();
2774 unsigned int OpenDoor(unsigned int door_state)
2776 if (door_state & DOOR_COPY_BACK)
2778 if (door_state & DOOR_OPEN_1)
2779 BlitBitmap(bitmap_db_door, bitmap_db_door,
2780 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2781 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2783 if (door_state & DOOR_OPEN_2)
2784 BlitBitmap(bitmap_db_door, bitmap_db_door,
2785 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
2786 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2788 door_state &= ~DOOR_COPY_BACK;
2791 return MoveDoor(door_state);
2794 unsigned int CloseDoor(unsigned int door_state)
2796 unsigned int old_door_state = GetDoorState();
2798 if (!(door_state & DOOR_NO_COPY_BACK))
2800 if (old_door_state & DOOR_OPEN_1)
2801 BlitBitmap(backbuffer, bitmap_db_door,
2802 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2804 if (old_door_state & DOOR_OPEN_2)
2805 BlitBitmap(backbuffer, bitmap_db_door,
2806 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2808 door_state &= ~DOOR_NO_COPY_BACK;
2811 return MoveDoor(door_state);
2814 unsigned int GetDoorState()
2816 return MoveDoor(DOOR_GET_STATE);
2819 unsigned int SetDoorState(unsigned int door_state)
2821 return MoveDoor(door_state | DOOR_SET_STATE);
2824 unsigned int MoveDoor(unsigned int door_state)
2826 static int door1 = DOOR_OPEN_1;
2827 static int door2 = DOOR_CLOSE_2;
2828 unsigned long door_delay = 0;
2829 unsigned long door_delay_value;
2832 if (door_1.width < 0 || door_1.width > DXSIZE)
2833 door_1.width = DXSIZE;
2834 if (door_1.height < 0 || door_1.height > DYSIZE)
2835 door_1.height = DYSIZE;
2836 if (door_2.width < 0 || door_2.width > VXSIZE)
2837 door_2.width = VXSIZE;
2838 if (door_2.height < 0 || door_2.height > VYSIZE)
2839 door_2.height = VYSIZE;
2841 if (door_state == DOOR_GET_STATE)
2842 return (door1 | door2);
2844 if (door_state & DOOR_SET_STATE)
2846 if (door_state & DOOR_ACTION_1)
2847 door1 = door_state & DOOR_ACTION_1;
2848 if (door_state & DOOR_ACTION_2)
2849 door2 = door_state & DOOR_ACTION_2;
2851 return (door1 | door2);
2854 if (!(door_state & DOOR_FORCE_REDRAW))
2856 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2857 door_state &= ~DOOR_OPEN_1;
2858 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2859 door_state &= ~DOOR_CLOSE_1;
2860 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2861 door_state &= ~DOOR_OPEN_2;
2862 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2863 door_state &= ~DOOR_CLOSE_2;
2866 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
2869 if (setup.quick_doors)
2871 stepsize = 20; /* must be choosen to always draw last frame */
2872 door_delay_value = 0;
2875 if (global.autoplay_leveldir)
2877 door_state |= DOOR_NO_DELAY;
2878 door_state &= ~DOOR_CLOSE_ALL;
2881 if (door_state & DOOR_ACTION)
2883 boolean handle_door_1 = (door_state & DOOR_ACTION_1);
2884 boolean handle_door_2 = (door_state & DOOR_ACTION_2);
2885 boolean door_1_done = (!handle_door_1);
2886 boolean door_2_done = (!handle_door_2);
2887 boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
2888 boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
2889 int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
2890 int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
2891 int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
2892 int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
2893 int door_size = (handle_door_1 ? door_size_1 : door_size_2);
2894 int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
2895 int door_skip = max_door_size - door_size;
2896 int end = door_size;
2897 int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
2900 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
2902 /* opening door sound has priority over simultaneously closing door */
2903 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2904 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2905 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2906 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2909 for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
2912 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2913 GC gc = bitmap->stored_clip_gc;
2915 if (door_state & DOOR_ACTION_1)
2917 int a = MIN(x * door_1.step_offset, end);
2918 int p = (door_state & DOOR_OPEN_1 ? end - a : a);
2919 int i = p + door_skip;
2921 if (door_1.anim_mode & ANIM_STATIC_PANEL)
2923 BlitBitmap(bitmap_db_door, drawto,
2924 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
2925 DXSIZE, DYSIZE, DX, DY);
2929 BlitBitmap(bitmap_db_door, drawto,
2930 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
2931 DXSIZE, DYSIZE - p / 2, DX, DY);
2933 ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
2936 if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
2938 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2939 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
2940 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
2941 int dst2_x = DX, dst2_y = DY;
2942 int width = i, height = DYSIZE;
2944 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2945 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2948 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2949 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2952 else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
2954 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2955 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
2956 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
2957 int dst2_x = DX, dst2_y = DY;
2958 int width = DXSIZE, height = i;
2960 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2961 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2964 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2965 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2968 else if (x <= DXSIZE) /* ANIM_DEFAULT */
2970 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
2972 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2973 BlitBitmapMasked(bitmap, drawto,
2974 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2975 DX + DXSIZE - i, DY + j);
2976 BlitBitmapMasked(bitmap, drawto,
2977 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2978 DX + DXSIZE - i, DY + 140 + j);
2979 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
2980 DY - (DOOR_GFX_PAGEY1 + j));
2981 BlitBitmapMasked(bitmap, drawto,
2982 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2984 BlitBitmapMasked(bitmap, drawto,
2985 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
2988 BlitBitmapMasked(bitmap, drawto,
2989 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2991 BlitBitmapMasked(bitmap, drawto,
2992 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2994 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2995 BlitBitmapMasked(bitmap, drawto,
2996 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2997 DX + DXSIZE - i, DY + 77 + j);
2998 BlitBitmapMasked(bitmap, drawto,
2999 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
3000 DX + DXSIZE - i, DY + 203 + j);
3003 redraw_mask |= REDRAW_DOOR_1;
3004 door_1_done = (a == end);
3007 if (door_state & DOOR_ACTION_2)
3009 int a = MIN(x * door_2.step_offset, door_size);
3010 int p = (door_state & DOOR_OPEN_2 ? door_size - a : a);
3011 int i = p + door_skip;
3013 if (door_2.anim_mode & ANIM_STATIC_PANEL)
3015 BlitBitmap(bitmap_db_door, drawto,
3016 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
3017 VXSIZE, VYSIZE, VX, VY);
3019 else if (x <= VYSIZE)
3021 BlitBitmap(bitmap_db_door, drawto,
3022 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
3023 VXSIZE, VYSIZE - p / 2, VX, VY);
3025 ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
3028 if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
3030 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
3031 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
3032 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
3033 int dst2_x = VX, dst2_y = VY;
3034 int width = i, height = VYSIZE;
3036 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3037 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3040 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3041 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3044 else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
3046 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
3047 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
3048 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
3049 int dst2_x = VX, dst2_y = VY;
3050 int width = VXSIZE, height = i;
3052 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3053 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3056 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3057 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3060 else if (x <= VXSIZE) /* ANIM_DEFAULT */
3062 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
3064 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3065 BlitBitmapMasked(bitmap, drawto,
3066 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
3067 VX + VXSIZE - i, VY + j);
3068 SetClipOrigin(bitmap, gc,
3069 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
3070 BlitBitmapMasked(bitmap, drawto,
3071 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
3074 BlitBitmapMasked(bitmap, drawto,
3075 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3076 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
3077 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3078 BlitBitmapMasked(bitmap, drawto,
3079 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3081 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
3084 redraw_mask |= REDRAW_DOOR_2;
3085 door_2_done = (a == VXSIZE);
3088 if (!(door_state & DOOR_NO_DELAY))
3092 if (game_status == GAME_MODE_MAIN)
3095 WaitUntilDelayReached(&door_delay, door_delay_value);
3100 if (door_state & DOOR_ACTION_1)
3101 door1 = door_state & DOOR_ACTION_1;
3102 if (door_state & DOOR_ACTION_2)
3103 door2 = door_state & DOOR_ACTION_2;
3105 return (door1 | door2);
3108 void DrawSpecialEditorDoor()
3110 /* draw bigger toolbox window */
3111 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
3112 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
3114 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3115 EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
3118 redraw_mask |= REDRAW_ALL;
3121 void UndrawSpecialEditorDoor()
3123 /* draw normal tape recorder window */
3124 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3125 EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
3128 redraw_mask |= REDRAW_ALL;
3132 /* ---------- new tool button stuff ---------------------------------------- */
3134 /* graphic position values for tool buttons */
3135 #define TOOL_BUTTON_YES_XPOS 2
3136 #define TOOL_BUTTON_YES_YPOS 250
3137 #define TOOL_BUTTON_YES_GFX_YPOS 0
3138 #define TOOL_BUTTON_YES_XSIZE 46
3139 #define TOOL_BUTTON_YES_YSIZE 28
3140 #define TOOL_BUTTON_NO_XPOS 52
3141 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
3142 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
3143 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
3144 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
3145 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
3146 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
3147 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
3148 #define TOOL_BUTTON_CONFIRM_XSIZE 96
3149 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
3150 #define TOOL_BUTTON_PLAYER_XSIZE 30
3151 #define TOOL_BUTTON_PLAYER_YSIZE 30
3152 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
3153 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
3154 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
3155 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
3156 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3157 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3158 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3159 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3160 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3161 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3162 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3163 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3164 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3165 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3166 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3167 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3168 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3169 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3170 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3171 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3180 } toolbutton_info[NUM_TOOL_BUTTONS] =
3183 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
3184 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
3185 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
3190 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
3191 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
3192 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
3197 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
3198 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
3199 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
3200 TOOL_CTRL_ID_CONFIRM,
3204 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3205 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
3206 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3207 TOOL_CTRL_ID_PLAYER_1,
3211 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3212 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
3213 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3214 TOOL_CTRL_ID_PLAYER_2,
3218 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3219 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
3220 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3221 TOOL_CTRL_ID_PLAYER_3,
3225 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3226 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
3227 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3228 TOOL_CTRL_ID_PLAYER_4,
3233 void CreateToolButtons()
3237 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3239 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3240 Bitmap *deco_bitmap = None;
3241 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
3242 struct GadgetInfo *gi;
3243 unsigned long event_mask;
3244 int gd_xoffset, gd_yoffset;
3245 int gd_x1, gd_x2, gd_y;
3248 event_mask = GD_EVENT_RELEASED;
3250 gd_xoffset = toolbutton_info[i].xpos;
3251 gd_yoffset = toolbutton_info[i].ypos;
3252 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
3253 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
3254 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
3256 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
3258 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
3260 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
3261 &deco_bitmap, &deco_x, &deco_y);
3262 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
3263 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
3266 gi = CreateGadget(GDI_CUSTOM_ID, id,
3267 GDI_INFO_TEXT, toolbutton_info[i].infotext,
3268 GDI_X, DX + toolbutton_info[i].x,
3269 GDI_Y, DY + toolbutton_info[i].y,
3270 GDI_WIDTH, toolbutton_info[i].width,
3271 GDI_HEIGHT, toolbutton_info[i].height,
3272 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
3273 GDI_STATE, GD_BUTTON_UNPRESSED,
3274 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
3275 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
3276 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
3277 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
3278 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
3279 GDI_DECORATION_SHIFTING, 1, 1,
3280 GDI_DIRECT_DRAW, FALSE,
3281 GDI_EVENT_MASK, event_mask,
3282 GDI_CALLBACK_ACTION, HandleToolButtons,
3286 Error(ERR_EXIT, "cannot create gadget");
3288 tool_gadget[id] = gi;
3292 void FreeToolButtons()
3296 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3297 FreeGadget(tool_gadget[i]);
3300 static void UnmapToolButtons()
3304 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3305 UnmapGadget(tool_gadget[i]);
3308 static void HandleToolButtons(struct GadgetInfo *gi)
3310 request_gadget_id = gi->custom_id;
3313 static struct Mapping_EM_to_RND_object
3316 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
3317 boolean is_backside; /* backside of moving element */
3323 em_object_mapping_list[] =
3326 Xblank, TRUE, FALSE,
3330 Yacid_splash_eB, FALSE, FALSE,
3331 EL_ACID_SPLASH_RIGHT, -1, -1
3334 Yacid_splash_wB, FALSE, FALSE,
3335 EL_ACID_SPLASH_LEFT, -1, -1
3338 #ifdef EM_ENGINE_BAD_ROLL
3340 Xstone_force_e, FALSE, FALSE,
3341 EL_ROCK, -1, MV_BIT_RIGHT
3344 Xstone_force_w, FALSE, FALSE,
3345 EL_ROCK, -1, MV_BIT_LEFT
3348 Xnut_force_e, FALSE, FALSE,
3349 EL_NUT, -1, MV_BIT_RIGHT
3352 Xnut_force_w, FALSE, FALSE,
3353 EL_NUT, -1, MV_BIT_LEFT
3356 Xspring_force_e, FALSE, FALSE,
3357 EL_SPRING, -1, MV_BIT_RIGHT
3360 Xspring_force_w, FALSE, FALSE,
3361 EL_SPRING, -1, MV_BIT_LEFT
3364 Xemerald_force_e, FALSE, FALSE,
3365 EL_EMERALD, -1, MV_BIT_RIGHT
3368 Xemerald_force_w, FALSE, FALSE,
3369 EL_EMERALD, -1, MV_BIT_LEFT
3372 Xdiamond_force_e, FALSE, FALSE,
3373 EL_DIAMOND, -1, MV_BIT_RIGHT
3376 Xdiamond_force_w, FALSE, FALSE,
3377 EL_DIAMOND, -1, MV_BIT_LEFT
3380 Xbomb_force_e, FALSE, FALSE,
3381 EL_BOMB, -1, MV_BIT_RIGHT
3384 Xbomb_force_w, FALSE, FALSE,
3385 EL_BOMB, -1, MV_BIT_LEFT
3387 #endif /* EM_ENGINE_BAD_ROLL */
3390 Xstone, TRUE, FALSE,
3394 Xstone_pause, FALSE, FALSE,
3398 Xstone_fall, FALSE, FALSE,
3402 Ystone_s, FALSE, FALSE,
3403 EL_ROCK, ACTION_FALLING, -1
3406 Ystone_sB, FALSE, TRUE,
3407 EL_ROCK, ACTION_FALLING, -1
3410 Ystone_e, FALSE, FALSE,
3411 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3414 Ystone_eB, FALSE, TRUE,
3415 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3418 Ystone_w, FALSE, FALSE,
3419 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3422 Ystone_wB, FALSE, TRUE,
3423 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3430 Xnut_pause, FALSE, FALSE,
3434 Xnut_fall, FALSE, FALSE,
3438 Ynut_s, FALSE, FALSE,
3439 EL_NUT, ACTION_FALLING, -1
3442 Ynut_sB, FALSE, TRUE,
3443 EL_NUT, ACTION_FALLING, -1
3446 Ynut_e, FALSE, FALSE,
3447 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3450 Ynut_eB, FALSE, TRUE,
3451 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3454 Ynut_w, FALSE, FALSE,
3455 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3458 Ynut_wB, FALSE, TRUE,
3459 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3462 Xbug_n, TRUE, FALSE,
3466 Xbug_e, TRUE, FALSE,
3467 EL_BUG_RIGHT, -1, -1
3470 Xbug_s, TRUE, FALSE,
3474 Xbug_w, TRUE, FALSE,
3478 Xbug_gon, FALSE, FALSE,
3482 Xbug_goe, FALSE, FALSE,
3483 EL_BUG_RIGHT, -1, -1
3486 Xbug_gos, FALSE, FALSE,
3490 Xbug_gow, FALSE, FALSE,
3494 Ybug_n, FALSE, FALSE,
3495 EL_BUG, ACTION_MOVING, MV_BIT_UP
3498 Ybug_nB, FALSE, TRUE,
3499 EL_BUG, ACTION_MOVING, MV_BIT_UP
3502 Ybug_e, FALSE, FALSE,
3503 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3506 Ybug_eB, FALSE, TRUE,
3507 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3510 Ybug_s, FALSE, FALSE,
3511 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3514 Ybug_sB, FALSE, TRUE,
3515 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3518 Ybug_w, FALSE, FALSE,
3519 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3522 Ybug_wB, FALSE, TRUE,
3523 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3526 Ybug_w_n, FALSE, FALSE,
3527 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3530 Ybug_n_e, FALSE, FALSE,
3531 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3534 Ybug_e_s, FALSE, FALSE,
3535 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3538 Ybug_s_w, FALSE, FALSE,
3539 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3542 Ybug_e_n, FALSE, FALSE,
3543 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3546 Ybug_s_e, FALSE, FALSE,
3547 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3550 Ybug_w_s, FALSE, FALSE,
3551 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3554 Ybug_n_w, FALSE, FALSE,
3555 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3558 Ybug_stone, FALSE, FALSE,
3559 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
3562 Ybug_spring, FALSE, FALSE,
3563 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
3566 Xtank_n, TRUE, FALSE,
3567 EL_SPACESHIP_UP, -1, -1
3570 Xtank_e, TRUE, FALSE,
3571 EL_SPACESHIP_RIGHT, -1, -1
3574 Xtank_s, TRUE, FALSE,
3575 EL_SPACESHIP_DOWN, -1, -1
3578 Xtank_w, TRUE, FALSE,
3579 EL_SPACESHIP_LEFT, -1, -1
3582 Xtank_gon, FALSE, FALSE,
3583 EL_SPACESHIP_UP, -1, -1
3586 Xtank_goe, FALSE, FALSE,
3587 EL_SPACESHIP_RIGHT, -1, -1
3590 Xtank_gos, FALSE, FALSE,
3591 EL_SPACESHIP_DOWN, -1, -1
3594 Xtank_gow, FALSE, FALSE,
3595 EL_SPACESHIP_LEFT, -1, -1
3598 Ytank_n, FALSE, FALSE,
3599 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3602 Ytank_nB, FALSE, TRUE,
3603 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3606 Ytank_e, FALSE, FALSE,
3607 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3610 Ytank_eB, FALSE, TRUE,
3611 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3614 Ytank_s, FALSE, FALSE,
3615 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3618 Ytank_sB, FALSE, TRUE,
3619 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3622 Ytank_w, FALSE, FALSE,
3623 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3626 Ytank_wB, FALSE, TRUE,
3627 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3630 Ytank_w_n, FALSE, FALSE,
3631 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3634 Ytank_n_e, FALSE, FALSE,
3635 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3638 Ytank_e_s, FALSE, FALSE,
3639 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3642 Ytank_s_w, FALSE, FALSE,
3643 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3646 Ytank_e_n, FALSE, FALSE,
3647 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3650 Ytank_s_e, FALSE, FALSE,
3651 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3654 Ytank_w_s, FALSE, FALSE,
3655 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3658 Ytank_n_w, FALSE, FALSE,
3659 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3662 Ytank_stone, FALSE, FALSE,
3663 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
3666 Ytank_spring, FALSE, FALSE,
3667 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
3670 Xandroid, TRUE, FALSE,
3671 EL_EMC_ANDROID, ACTION_ACTIVE, -1
3674 Xandroid_1_n, FALSE, FALSE,
3675 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3678 Xandroid_2_n, FALSE, FALSE,
3679 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3682 Xandroid_1_e, FALSE, FALSE,
3683 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3686 Xandroid_2_e, FALSE, FALSE,
3687 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3690 Xandroid_1_w, FALSE, FALSE,
3691 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3694 Xandroid_2_w, FALSE, FALSE,
3695 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3698 Xandroid_1_s, FALSE, FALSE,
3699 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3702 Xandroid_2_s, FALSE, FALSE,
3703 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3706 Yandroid_n, FALSE, FALSE,
3707 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3710 Yandroid_nB, FALSE, TRUE,
3711 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3714 Yandroid_ne, FALSE, FALSE,
3715 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
3718 Yandroid_neB, FALSE, TRUE,
3719 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
3722 Yandroid_e, FALSE, FALSE,
3723 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
3726 Yandroid_eB, FALSE, TRUE,
3727 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
3730 Yandroid_se, FALSE, FALSE,
3731 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
3734 Yandroid_seB, FALSE, TRUE,
3735 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
3738 Yandroid_s, FALSE, FALSE,
3739 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
3742 Yandroid_sB, FALSE, TRUE,
3743 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
3746 Yandroid_sw, FALSE, FALSE,
3747 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
3750 Yandroid_swB, FALSE, TRUE,
3751 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
3754 Yandroid_w, FALSE, FALSE,
3755 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
3758 Yandroid_wB, FALSE, TRUE,
3759 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
3762 Yandroid_nw, FALSE, FALSE,
3763 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
3766 Yandroid_nwB, FALSE, TRUE,
3767 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
3770 Xspring, TRUE, FALSE,
3774 Xspring_pause, FALSE, FALSE,
3778 Xspring_e, FALSE, FALSE,
3782 Xspring_w, FALSE, FALSE,
3786 Xspring_fall, FALSE, FALSE,
3790 Yspring_s, FALSE, FALSE,
3791 EL_SPRING, ACTION_FALLING, -1
3794 Yspring_sB, FALSE, TRUE,
3795 EL_SPRING, ACTION_FALLING, -1
3798 Yspring_e, FALSE, FALSE,
3799 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
3802 Yspring_eB, FALSE, TRUE,
3803 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
3806 Yspring_w, FALSE, FALSE,
3807 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
3810 Yspring_wB, FALSE, TRUE,
3811 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
3814 Yspring_kill_e, FALSE, FALSE,
3815 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
3818 Yspring_kill_eB, FALSE, TRUE,
3819 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
3822 Yspring_kill_w, FALSE, FALSE,
3823 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
3826 Yspring_kill_wB, FALSE, TRUE,
3827 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
3830 Xeater_n, TRUE, FALSE,
3831 EL_YAMYAM_UP, -1, -1
3834 Xeater_e, TRUE, FALSE,
3835 EL_YAMYAM_RIGHT, -1, -1
3838 Xeater_w, TRUE, FALSE,
3839 EL_YAMYAM_LEFT, -1, -1
3842 Xeater_s, TRUE, FALSE,
3843 EL_YAMYAM_DOWN, -1, -1
3846 Yeater_n, FALSE, FALSE,
3847 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
3850 Yeater_nB, FALSE, TRUE,
3851 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
3854 Yeater_e, FALSE, FALSE,
3855 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
3858 Yeater_eB, FALSE, TRUE,
3859 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
3862 Yeater_s, FALSE, FALSE,
3863 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
3866 Yeater_sB, FALSE, TRUE,
3867 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
3870 Yeater_w, FALSE, FALSE,
3871 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
3874 Yeater_wB, FALSE, TRUE,
3875 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
3878 Yeater_stone, FALSE, FALSE,
3879 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
3882 Yeater_spring, FALSE, FALSE,
3883 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
3886 Xalien, TRUE, FALSE,
3890 Xalien_pause, FALSE, FALSE,
3894 Yalien_n, FALSE, FALSE,
3895 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
3898 Yalien_nB, FALSE, TRUE,
3899 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
3902 Yalien_e, FALSE, FALSE,
3903 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
3906 Yalien_eB, FALSE, TRUE,
3907 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
3910 Yalien_s, FALSE, FALSE,
3911 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
3914 Yalien_sB, FALSE, TRUE,
3915 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
3918 Yalien_w, FALSE, FALSE,
3919 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
3922 Yalien_wB, FALSE, TRUE,
3923 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
3926 Yalien_stone, FALSE, FALSE,
3927 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
3930 Yalien_spring, FALSE, FALSE,
3931 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
3934 Xemerald, TRUE, FALSE,
3938 Xemerald_pause, FALSE, FALSE,
3942 Xemerald_fall, FALSE, FALSE,
3946 Xemerald_shine, FALSE, FALSE,
3947 EL_EMERALD, ACTION_TWINKLING, -1
3950 Yemerald_s, FALSE, FALSE,
3951 EL_EMERALD, ACTION_FALLING, -1
3954 Yemerald_sB, FALSE, TRUE,
3955 EL_EMERALD, ACTION_FALLING, -1
3958 Yemerald_e, FALSE, FALSE,
3959 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
3962 Yemerald_eB, FALSE, TRUE,
3963 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
3966 Yemerald_w, FALSE, FALSE,
3967 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
3970 Yemerald_wB, FALSE, TRUE,
3971 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
3974 Yemerald_eat, FALSE, FALSE,
3975 EL_EMERALD, ACTION_COLLECTING, -1
3978 Yemerald_stone, FALSE, FALSE,
3979 EL_NUT, ACTION_BREAKING, -1
3982 Xdiamond, TRUE, FALSE,
3986 Xdiamond_pause, FALSE, FALSE,
3990 Xdiamond_fall, FALSE, FALSE,
3994 Xdiamond_shine, FALSE, FALSE,
3995 EL_DIAMOND, ACTION_TWINKLING, -1
3998 Ydiamond_s, FALSE, FALSE,
3999 EL_DIAMOND, ACTION_FALLING, -1
4002 Ydiamond_sB, FALSE, TRUE,
4003 EL_DIAMOND, ACTION_FALLING, -1
4006 Ydiamond_e, FALSE, FALSE,
4007 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
4010 Ydiamond_eB, FALSE, TRUE,
4011 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
4014 Ydiamond_w, FALSE, FALSE,
4015 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
4018 Ydiamond_wB, FALSE, TRUE,
4019 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
4022 Ydiamond_eat, FALSE, FALSE,
4023 EL_DIAMOND, ACTION_COLLECTING, -1
4026 Ydiamond_stone, FALSE, FALSE,
4027 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
4030 Xdrip_fall, TRUE, FALSE,
4031 EL_AMOEBA_DROP, -1, -1
4034 Xdrip_stretch, FALSE, FALSE,
4035 EL_AMOEBA_DROP, ACTION_FALLING, -1
4038 Xdrip_stretchB, FALSE, TRUE,
4039 EL_AMOEBA_DROP, ACTION_FALLING, -1
4042 Xdrip_eat, FALSE, FALSE,
4043 EL_AMOEBA_DROP, ACTION_GROWING, -1
4046 Ydrip_s1, FALSE, FALSE,
4047 EL_AMOEBA_DROP, ACTION_FALLING, -1
4050 Ydrip_s1B, FALSE, TRUE,
4051 EL_AMOEBA_DROP, ACTION_FALLING, -1
4054 Ydrip_s2, FALSE, FALSE,
4055 EL_AMOEBA_DROP, ACTION_FALLING, -1
4058 Ydrip_s2B, FALSE, TRUE,
4059 EL_AMOEBA_DROP, ACTION_FALLING, -1
4066 Xbomb_pause, FALSE, FALSE,
4070 Xbomb_fall, FALSE, FALSE,
4074 Ybomb_s, FALSE, FALSE,
4075 EL_BOMB, ACTION_FALLING, -1
4078 Ybomb_sB, FALSE, TRUE,
4079 EL_BOMB, ACTION_FALLING, -1
4082 Ybomb_e, FALSE, FALSE,
4083 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
4086 Ybomb_eB, FALSE, TRUE,
4087 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
4090 Ybomb_w, FALSE, FALSE,
4091 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
4094 Ybomb_wB, FALSE, TRUE,
4095 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
4098 Ybomb_eat, FALSE, FALSE,
4099 EL_BOMB, ACTION_ACTIVATING, -1
4102 Xballoon, TRUE, FALSE,
4106 Yballoon_n, FALSE, FALSE,
4107 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
4110 Yballoon_nB, FALSE, TRUE,
4111 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
4114 Yballoon_e, FALSE, FALSE,
4115 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
4118 Yballoon_eB, FALSE, TRUE,
4119 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
4122 Yballoon_s, FALSE, FALSE,
4123 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
4126 Yballoon_sB, FALSE, TRUE,
4127 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
4130 Yballoon_w, FALSE, FALSE,
4131 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
4134 Yballoon_wB, FALSE, TRUE,
4135 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
4138 Xgrass, TRUE, FALSE,
4139 EL_EMC_GRASS, -1, -1
4142 Ygrass_nB, FALSE, FALSE,
4143 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
4146 Ygrass_eB, FALSE, FALSE,
4147 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
4150 Ygrass_sB, FALSE, FALSE,
4151 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
4154 Ygrass_wB, FALSE, FALSE,
4155 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
4162 Ydirt_nB, FALSE, FALSE,
4163 EL_SAND, ACTION_DIGGING, MV_BIT_UP
4166 Ydirt_eB, FALSE, FALSE,
4167 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
4170 Ydirt_sB, FALSE, FALSE,
4171 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
4174 Ydirt_wB, FALSE, FALSE,
4175 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
4178 Xacid_ne, TRUE, FALSE,
4179 EL_ACID_POOL_TOPRIGHT, -1, -1
4182 Xacid_se, TRUE, FALSE,
4183 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
4186 Xacid_s, TRUE, FALSE,
4187 EL_ACID_POOL_BOTTOM, -1, -1
4190 Xacid_sw, TRUE, FALSE,
4191 EL_ACID_POOL_BOTTOMLEFT, -1, -1
4194 Xacid_nw, TRUE, FALSE,
4195 EL_ACID_POOL_TOPLEFT, -1, -1
4198 Xacid_1, TRUE, FALSE,
4202 Xacid_2, FALSE, FALSE,
4206 Xacid_3, FALSE, FALSE,
4210 Xacid_4, FALSE, FALSE,
4214 Xacid_5, FALSE, FALSE,
4218 Xacid_6, FALSE, FALSE,
4222 Xacid_7, FALSE, FALSE,
4226 Xacid_8, FALSE, FALSE,
4230 Xball_1, TRUE, FALSE,
4231 EL_EMC_MAGIC_BALL, -1, -1
4234 Xball_1B, FALSE, FALSE,
4235 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4238 Xball_2, FALSE, FALSE,
4239 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4242 Xball_2B, FALSE, FALSE,
4243 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4246 Yball_eat, FALSE, FALSE,
4247 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
4250 Ykey_1_eat, FALSE, FALSE,
4251 EL_EM_KEY_1, ACTION_COLLECTING, -1
4254 Ykey_2_eat, FALSE, FALSE,
4255 EL_EM_KEY_2, ACTION_COLLECTING, -1
4258 Ykey_3_eat, FALSE, FALSE,
4259 EL_EM_KEY_3, ACTION_COLLECTING, -1
4262 Ykey_4_eat, FALSE, FALSE,
4263 EL_EM_KEY_4, ACTION_COLLECTING, -1
4266 Ykey_5_eat, FALSE, FALSE,
4267 EL_EMC_KEY_5, ACTION_COLLECTING, -1
4270 Ykey_6_eat, FALSE, FALSE,
4271 EL_EMC_KEY_6, ACTION_COLLECTING, -1
4274 Ykey_7_eat, FALSE, FALSE,
4275 EL_EMC_KEY_7, ACTION_COLLECTING, -1
4278 Ykey_8_eat, FALSE, FALSE,
4279 EL_EMC_KEY_8, ACTION_COLLECTING, -1
4282 Ylenses_eat, FALSE, FALSE,
4283 EL_EMC_LENSES, ACTION_COLLECTING, -1
4286 Ymagnify_eat, FALSE, FALSE,
4287 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
4290 Ygrass_eat, FALSE, FALSE,
4291 EL_EMC_GRASS, ACTION_SNAPPING, -1
4294 Ydirt_eat, FALSE, FALSE,
4295 EL_SAND, ACTION_SNAPPING, -1
4298 Xgrow_ns, TRUE, FALSE,
4299 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
4302 Ygrow_ns_eat, FALSE, FALSE,
4303 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
4306 Xgrow_ew, TRUE, FALSE,
4307 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
4310 Ygrow_ew_eat, FALSE, FALSE,
4311 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
4314 Xwonderwall, TRUE, FALSE,
4315 EL_MAGIC_WALL, -1, -1
4318 XwonderwallB, FALSE, FALSE,
4319 EL_MAGIC_WALL, ACTION_ACTIVE, -1
4322 Xamoeba_1, TRUE, FALSE,
4323 EL_AMOEBA_DRY, ACTION_OTHER, -1
4326 Xamoeba_2, FALSE, FALSE,
4327 EL_AMOEBA_DRY, ACTION_OTHER, -1
4330 Xamoeba_3, FALSE, FALSE,
4331 EL_AMOEBA_DRY, ACTION_OTHER, -1
4334 Xamoeba_4, FALSE, FALSE,
4335 EL_AMOEBA_DRY, ACTION_OTHER, -1
4338 Xamoeba_5, TRUE, FALSE,
4339 EL_AMOEBA_WET, ACTION_OTHER, -1
4342 Xamoeba_6, FALSE, FALSE,
4343 EL_AMOEBA_WET, ACTION_OTHER, -1
4346 Xamoeba_7, FALSE, FALSE,
4347 EL_AMOEBA_WET, ACTION_OTHER, -1
4350 Xamoeba_8, FALSE, FALSE,
4351 EL_AMOEBA_WET, ACTION_OTHER, -1
4354 Xdoor_1, TRUE, FALSE,
4355 EL_EM_GATE_1, -1, -1
4358 Xdoor_2, TRUE, FALSE,
4359 EL_EM_GATE_2, -1, -1
4362 Xdoor_3, TRUE, FALSE,
4363 EL_EM_GATE_3, -1, -1
4366 Xdoor_4, TRUE, FALSE,
4367 EL_EM_GATE_4, -1, -1
4370 Xdoor_5, TRUE, FALSE,
4371 EL_EMC_GATE_5, -1, -1
4374 Xdoor_6, TRUE, FALSE,
4375 EL_EMC_GATE_6, -1, -1
4378 Xdoor_7, TRUE, FALSE,
4379 EL_EMC_GATE_7, -1, -1
4382 Xdoor_8, TRUE, FALSE,
4383 EL_EMC_GATE_8, -1, -1
4386 Xkey_1, TRUE, FALSE,
4390 Xkey_2, TRUE, FALSE,
4394 Xkey_3, TRUE, FALSE,
4398 Xkey_4, TRUE, FALSE,
4402 Xkey_5, TRUE, FALSE,
4403 EL_EMC_KEY_5, -1, -1
4406 Xkey_6, TRUE, FALSE,
4407 EL_EMC_KEY_6, -1, -1
4410 Xkey_7, TRUE, FALSE,
4411 EL_EMC_KEY_7, -1, -1
4414 Xkey_8, TRUE, FALSE,
4415 EL_EMC_KEY_8, -1, -1
4418 Xwind_n, TRUE, FALSE,
4419 EL_BALLOON_SWITCH_UP, -1, -1
4422 Xwind_e, TRUE, FALSE,
4423 EL_BALLOON_SWITCH_RIGHT, -1, -1
4426 Xwind_s, TRUE, FALSE,
4427 EL_BALLOON_SWITCH_DOWN, -1, -1
4430 Xwind_w, TRUE, FALSE,
4431 EL_BALLOON_SWITCH_LEFT, -1, -1
4434 Xwind_nesw, TRUE, FALSE,
4435 EL_BALLOON_SWITCH_ANY, -1, -1
4438 Xwind_stop, TRUE, FALSE,
4439 EL_BALLOON_SWITCH_NONE, -1, -1
4443 EL_EXIT_CLOSED, -1, -1
4446 Xexit_1, TRUE, FALSE,
4447 EL_EXIT_OPEN, -1, -1
4450 Xexit_2, FALSE, FALSE,
4451 EL_EXIT_OPEN, -1, -1
4454 Xexit_3, FALSE, FALSE,
4455 EL_EXIT_OPEN, -1, -1
4458 Xdynamite, TRUE, FALSE,
4459 EL_EM_DYNAMITE, -1, -1
4462 Ydynamite_eat, FALSE, FALSE,
4463 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
4466 Xdynamite_1, TRUE, FALSE,
4467 EL_EM_DYNAMITE_ACTIVE, -1, -1
4470 Xdynamite_2, FALSE, FALSE,
4471 EL_EM_DYNAMITE_ACTIVE, -1, -1
4474 Xdynamite_3, FALSE, FALSE,
4475 EL_EM_DYNAMITE_ACTIVE, -1, -1
4478 Xdynamite_4, FALSE, FALSE,
4479 EL_EM_DYNAMITE_ACTIVE, -1, -1
4482 Xbumper, TRUE, FALSE,
4483 EL_EMC_SPRING_BUMPER, -1, -1
4486 XbumperB, FALSE, FALSE,
4487 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
4490 Xwheel, TRUE, FALSE,
4491 EL_ROBOT_WHEEL, -1, -1
4494 XwheelB, FALSE, FALSE,
4495 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
4498 Xswitch, TRUE, FALSE,
4499 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
4502 XswitchB, FALSE, FALSE,
4503 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
4507 EL_QUICKSAND_EMPTY, -1, -1
4510 Xsand_stone, TRUE, FALSE,
4511 EL_QUICKSAND_FULL, -1, -1
4514 Xsand_stonein_1, FALSE, TRUE,
4515 EL_ROCK, ACTION_FILLING, -1
4518 Xsand_stonein_2, FALSE, TRUE,
4519 EL_ROCK, ACTION_FILLING, -1
4522 Xsand_stonein_3, FALSE, TRUE,
4523 EL_ROCK, ACTION_FILLING, -1
4526 Xsand_stonein_4, FALSE, TRUE,
4527 EL_ROCK, ACTION_FILLING, -1
4530 Xsand_stonesand_1, FALSE, FALSE,
4531 EL_QUICKSAND_FULL, -1, -1
4534 Xsand_stonesand_2, FALSE, FALSE,
4535 EL_QUICKSAND_FULL, -1, -1
4538 Xsand_stonesand_3, FALSE, FALSE,
4539 EL_QUICKSAND_FULL, -1, -1
4542 Xsand_stonesand_4, FALSE, FALSE,
4543 EL_QUICKSAND_FULL, -1, -1
4546 Xsand_stoneout_1, FALSE, FALSE,
4547 EL_ROCK, ACTION_EMPTYING, -1
4550 Xsand_stoneout_2, FALSE, FALSE,
4551 EL_ROCK, ACTION_EMPTYING, -1
4554 Xsand_sandstone_1, FALSE, FALSE,
4555 EL_QUICKSAND_FULL, -1, -1
4558 Xsand_sandstone_2, FALSE, FALSE,
4559 EL_QUICKSAND_FULL, -1, -1
4562 Xsand_sandstone_3, FALSE, FALSE,
4563 EL_QUICKSAND_FULL, -1, -1
4566 Xsand_sandstone_4, FALSE, FALSE,
4567 EL_QUICKSAND_FULL, -1, -1
4570 Xplant, TRUE, FALSE,
4571 EL_EMC_PLANT, -1, -1
4574 Yplant, FALSE, FALSE,
4575 EL_EMC_PLANT, -1, -1
4578 Xlenses, TRUE, FALSE,
4579 EL_EMC_LENSES, -1, -1
4582 Xmagnify, TRUE, FALSE,
4583 EL_EMC_MAGNIFIER, -1, -1
4586 Xdripper, TRUE, FALSE,
4587 EL_EMC_DRIPPER, -1, -1
4590 XdripperB, FALSE, FALSE,
4591 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
4594 Xfake_blank, TRUE, FALSE,
4595 EL_INVISIBLE_WALL, -1, -1
4598 Xfake_blankB, FALSE, FALSE,
4599 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
4602 Xfake_grass, TRUE, FALSE,
4603 EL_EMC_FAKE_GRASS, -1, -1
4606 Xfake_grassB, FALSE, FALSE,
4607 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
4610 Xfake_door_1, TRUE, FALSE,
4611 EL_EM_GATE_1_GRAY, -1, -1
4614 Xfake_door_2, TRUE, FALSE,
4615 EL_EM_GATE_2_GRAY, -1, -1
4618 Xfake_door_3, TRUE, FALSE,
4619 EL_EM_GATE_3_GRAY, -1, -1
4622 Xfake_door_4, TRUE, FALSE,
4623 EL_EM_GATE_4_GRAY, -1, -1
4626 Xfake_door_5, TRUE, FALSE,
4627 EL_EMC_GATE_5_GRAY, -1, -1
4630 Xfake_door_6, TRUE, FALSE,
4631 EL_EMC_GATE_6_GRAY, -1, -1
4634 Xfake_door_7, TRUE, FALSE,
4635 EL_EMC_GATE_7_GRAY, -1, -1
4638 Xfake_door_8, TRUE, FALSE,
4639 EL_EMC_GATE_8_GRAY, -1, -1
4642 Xfake_acid_1, TRUE, FALSE,
4643 EL_EMC_FAKE_ACID, -1, -1
4646 Xfake_acid_2, FALSE, FALSE,
4647 EL_EMC_FAKE_ACID, -1, -1
4650 Xfake_acid_3, FALSE, FALSE,
4651 EL_EMC_FAKE_ACID, -1, -1
4654 Xfake_acid_4, FALSE, FALSE,
4655 EL_EMC_FAKE_ACID, -1, -1
4658 Xfake_acid_5, FALSE, FALSE,
4659 EL_EMC_FAKE_ACID, -1, -1
4662 Xfake_acid_6, FALSE, FALSE,
4663 EL_EMC_FAKE_ACID, -1, -1
4666 Xfake_acid_7, FALSE, FALSE,
4667 EL_EMC_FAKE_ACID, -1, -1
4670 Xfake_acid_8, FALSE, FALSE,
4671 EL_EMC_FAKE_ACID, -1, -1
4674 Xsteel_1, TRUE, FALSE,
4675 EL_STEELWALL, -1, -1
4678 Xsteel_2, TRUE, FALSE,
4679 EL_EMC_STEELWALL_2, -1, -1
4682 Xsteel_3, TRUE, FALSE,
4683 EL_EMC_STEELWALL_3, -1, -1
4686 Xsteel_4, TRUE, FALSE,
4687 EL_EMC_STEELWALL_4, -1, -1
4690 Xwall_1, TRUE, FALSE,
4694 Xwall_2, TRUE, FALSE,
4695 EL_EMC_WALL_14, -1, -1
4698 Xwall_3, TRUE, FALSE,
4699 EL_EMC_WALL_15, -1, -1
4702 Xwall_4, TRUE, FALSE,
4703 EL_EMC_WALL_16, -1, -1
4706 Xround_wall_1, TRUE, FALSE,
4707 EL_WALL_SLIPPERY, -1, -1
4710 Xround_wall_2, TRUE, FALSE,
4711 EL_EMC_WALL_SLIPPERY_2, -1, -1
4714 Xround_wall_3, TRUE, FALSE,
4715 EL_EMC_WALL_SLIPPERY_3, -1, -1
4718 Xround_wall_4, TRUE, FALSE,
4719 EL_EMC_WALL_SLIPPERY_4, -1, -1
4722 Xdecor_1, TRUE, FALSE,
4723 EL_EMC_WALL_8, -1, -1
4726 Xdecor_2, TRUE, FALSE,
4727 EL_EMC_WALL_6, -1, -1
4730 Xdecor_3, TRUE, FALSE,
4731 EL_EMC_WALL_4, -1, -1
4734 Xdecor_4, TRUE, FALSE,
4735 EL_EMC_WALL_7, -1, -1
4738 Xdecor_5, TRUE, FALSE,
4739 EL_EMC_WALL_5, -1, -1
4742 Xdecor_6, TRUE, FALSE,
4743 EL_EMC_WALL_9, -1, -1
4746 Xdecor_7, TRUE, FALSE,
4747 EL_EMC_WALL_10, -1, -1
4750 Xdecor_8, TRUE, FALSE,
4751 EL_EMC_WALL_1, -1, -1
4754 Xdecor_9, TRUE, FALSE,
4755 EL_EMC_WALL_2, -1, -1
4758 Xdecor_10, TRUE, FALSE,
4759 EL_EMC_WALL_3, -1, -1
4762 Xdecor_11, TRUE, FALSE,
4763 EL_EMC_WALL_11, -1, -1
4766 Xdecor_12, TRUE, FALSE,
4767 EL_EMC_WALL_12, -1, -1
4770 Xalpha_0, TRUE, FALSE,
4771 EL_CHAR('0'), -1, -1
4774 Xalpha_1, TRUE, FALSE,
4775 EL_CHAR('1'), -1, -1
4778 Xalpha_2, TRUE, FALSE,
4779 EL_CHAR('2'), -1, -1
4782 Xalpha_3, TRUE, FALSE,
4783 EL_CHAR('3'), -1, -1
4786 Xalpha_4, TRUE, FALSE,
4787 EL_CHAR('4'), -1, -1
4790 Xalpha_5, TRUE, FALSE,
4791 EL_CHAR('5'), -1, -1
4794 Xalpha_6, TRUE, FALSE,
4795 EL_CHAR('6'), -1, -1
4798 Xalpha_7, TRUE, FALSE,
4799 EL_CHAR('7'), -1, -1
4802 Xalpha_8, TRUE, FALSE,
4803 EL_CHAR('8'), -1, -1
4806 Xalpha_9, TRUE, FALSE,
4807 EL_CHAR('9'), -1, -1
4810 Xalpha_excla, TRUE, FALSE,
4811 EL_CHAR('!'), -1, -1
4814 Xalpha_quote, TRUE, FALSE,
4815 EL_CHAR('"'), -1, -1
4818 Xalpha_comma, TRUE, FALSE,
4819 EL_CHAR(','), -1, -1
4822 Xalpha_minus, TRUE, FALSE,
4823 EL_CHAR('-'), -1, -1
4826 Xalpha_perio, TRUE, FALSE,
4827 EL_CHAR('.'), -1, -1
4830 Xalpha_colon, TRUE, FALSE,
4831 EL_CHAR(':'), -1, -1
4834 Xalpha_quest, TRUE, FALSE,
4835 EL_CHAR('?'), -1, -1
4838 Xalpha_a, TRUE, FALSE,
4839 EL_CHAR('A'), -1, -1
4842 Xalpha_b, TRUE, FALSE,
4843 EL_CHAR('B'), -1, -1
4846 Xalpha_c, TRUE, FALSE,
4847 EL_CHAR('C'), -1, -1
4850 Xalpha_d, TRUE, FALSE,
4851 EL_CHAR('D'), -1, -1
4854 Xalpha_e, TRUE, FALSE,
4855 EL_CHAR('E'), -1, -1
4858 Xalpha_f, TRUE, FALSE,
4859 EL_CHAR('F'), -1, -1
4862 Xalpha_g, TRUE, FALSE,
4863 EL_CHAR('G'), -1, -1
4866 Xalpha_h, TRUE, FALSE,
4867 EL_CHAR('H'), -1, -1
4870 Xalpha_i, TRUE, FALSE,
4871 EL_CHAR('I'), -1, -1
4874 Xalpha_j, TRUE, FALSE,
4875 EL_CHAR('J'), -1, -1
4878 Xalpha_k, TRUE, FALSE,
4879 EL_CHAR('K'), -1, -1
4882 Xalpha_l, TRUE, FALSE,
4883 EL_CHAR('L'), -1, -1
4886 Xalpha_m, TRUE, FALSE,
4887 EL_CHAR('M'), -1, -1
4890 Xalpha_n, TRUE, FALSE,
4891 EL_CHAR('N'), -1, -1
4894 Xalpha_o, TRUE, FALSE,
4895 EL_CHAR('O'), -1, -1
4898 Xalpha_p, TRUE, FALSE,
4899 EL_CHAR('P'), -1, -1
4902 Xalpha_q, TRUE, FALSE,
4903 EL_CHAR('Q'), -1, -1
4906 Xalpha_r, TRUE, FALSE,
4907 EL_CHAR('R'), -1, -1
4910 Xalpha_s, TRUE, FALSE,
4911 EL_CHAR('S'), -1, -1
4914 Xalpha_t, TRUE, FALSE,
4915 EL_CHAR('T'), -1, -1
4918 Xalpha_u, TRUE, FALSE,
4919 EL_CHAR('U'), -1, -1
4922 Xalpha_v, TRUE, FALSE,
4923 EL_CHAR('V'), -1, -1
4926 Xalpha_w, TRUE, FALSE,
4927 EL_CHAR('W'), -1, -1
4930 Xalpha_x, TRUE, FALSE,
4931 EL_CHAR('X'), -1, -1
4934 Xalpha_y, TRUE, FALSE,
4935 EL_CHAR('Y'), -1, -1
4938 Xalpha_z, TRUE, FALSE,
4939 EL_CHAR('Z'), -1, -1
4942 Xalpha_arrow_e, TRUE, FALSE,
4943 EL_CHAR('>'), -1, -1
4946 Xalpha_arrow_w, TRUE, FALSE,
4947 EL_CHAR('<'), -1, -1
4950 Xalpha_copyr, TRUE, FALSE,
4951 EL_CHAR('©'), -1, -1
4955 Xboom_bug, FALSE, FALSE,
4956 EL_BUG, ACTION_EXPLODING, -1
4959 Xboom_bomb, FALSE, FALSE,
4960 EL_BOMB, ACTION_EXPLODING, -1
4963 Xboom_android, FALSE, FALSE,
4964 EL_EMC_ANDROID, ACTION_OTHER, -1
4967 Xboom_1, FALSE, FALSE,
4968 EL_DEFAULT, ACTION_EXPLODING, -1
4971 Xboom_2, FALSE, FALSE,
4972 EL_DEFAULT, ACTION_EXPLODING, -1
4975 Znormal, FALSE, FALSE,
4979 Zdynamite, FALSE, FALSE,
4983 Zplayer, FALSE, FALSE,
4987 ZBORDER, FALSE, FALSE,
4997 static struct Mapping_EM_to_RND_player
5006 em_player_mapping_list[] =
5010 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
5014 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
5018 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
5022 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
5026 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
5030 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
5034 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
5038 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
5042 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
5046 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
5050 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
5054 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
5058 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
5062 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
5066 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
5070 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
5074 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
5078 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
5082 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
5086 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
5090 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
5094 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
5098 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
5102 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
5106 EL_PLAYER_1, ACTION_DEFAULT, -1,
5110 EL_PLAYER_2, ACTION_DEFAULT, -1,
5114 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
5118 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
5122 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
5126 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
5130 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
5134 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
5138 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
5142 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
5146 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
5150 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
5154 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
5158 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
5162 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
5166 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
5170 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
5174 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
5178 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
5182 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
5186 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
5190 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
5194 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
5198 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
5202 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
5206 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
5210 EL_PLAYER_3, ACTION_DEFAULT, -1,
5214 EL_PLAYER_4, ACTION_DEFAULT, -1,
5223 int map_element_RND_to_EM(int element_rnd)
5225 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
5226 static boolean mapping_initialized = FALSE;
5228 if (!mapping_initialized)
5232 /* return "Xalpha_quest" for all undefined elements in mapping array */
5233 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
5234 mapping_RND_to_EM[i] = Xalpha_quest;
5236 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5237 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
5238 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
5239 em_object_mapping_list[i].element_em;
5241 mapping_initialized = TRUE;
5244 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
5245 return mapping_RND_to_EM[element_rnd];
5247 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
5252 int map_element_EM_to_RND(int element_em)
5254 static unsigned short mapping_EM_to_RND[TILE_MAX];
5255 static boolean mapping_initialized = FALSE;
5257 if (!mapping_initialized)
5261 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
5262 for (i = 0; i < TILE_MAX; i++)
5263 mapping_EM_to_RND[i] = EL_UNKNOWN;
5265 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5266 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
5267 em_object_mapping_list[i].element_rnd;
5269 mapping_initialized = TRUE;
5272 if (element_em >= 0 && element_em < TILE_MAX)
5273 return mapping_EM_to_RND[element_em];
5275 Error(ERR_WARN, "invalid EM level element %d", element_em);
5280 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
5282 struct LevelInfo_EM *level_em = level->native_em_level;
5283 struct LEVEL *lev = level_em->lev;
5286 for (i = 0; i < TILE_MAX; i++)
5287 lev->android_array[i] = Xblank;
5289 for (i = 0; i < level->num_android_clone_elements; i++)
5291 int element_rnd = level->android_clone_element[i];
5292 int element_em = map_element_RND_to_EM(element_rnd);
5294 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
5295 if (em_object_mapping_list[j].element_rnd == element_rnd)
5296 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
5300 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
5302 struct LevelInfo_EM *level_em = level->native_em_level;
5303 struct LEVEL *lev = level_em->lev;
5306 level->num_android_clone_elements = 0;
5308 for (i = 0; i < TILE_MAX; i++)
5310 int element_em = lev->android_array[i];
5312 boolean element_found = FALSE;
5314 if (element_em == Xblank)
5317 element_rnd = map_element_EM_to_RND(element_em);
5319 for (j = 0; j < level->num_android_clone_elements; j++)
5320 if (level->android_clone_element[j] == element_rnd)
5321 element_found = TRUE;
5325 level->android_clone_element[level->num_android_clone_elements++] =
5328 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
5333 if (level->num_android_clone_elements == 0)
5335 level->num_android_clone_elements = 1;
5336 level->android_clone_element[0] = EL_EMPTY;
5340 int map_direction_RND_to_EM(int direction)
5342 return (direction == MV_UP ? 0 :
5343 direction == MV_RIGHT ? 1 :
5344 direction == MV_DOWN ? 2 :
5345 direction == MV_LEFT ? 3 :
5349 int map_direction_EM_to_RND(int direction)
5351 return (direction == 0 ? MV_UP :
5352 direction == 1 ? MV_RIGHT :
5353 direction == 2 ? MV_DOWN :
5354 direction == 3 ? MV_LEFT :
5358 int get_next_element(int element)
5362 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
5363 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
5364 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
5365 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
5366 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
5367 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
5368 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
5370 default: return element;
5375 int el_act_dir2img(int element, int action, int direction)
5377 element = GFX_ELEMENT(element);
5379 if (direction == MV_NONE)
5380 return element_info[element].graphic[action];
5382 direction = MV_DIR_TO_BIT(direction);
5384 return element_info[element].direction_graphic[action][direction];
5387 int el_act_dir2img(int element, int action, int direction)
5389 element = GFX_ELEMENT(element);
5390 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5392 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5393 return element_info[element].direction_graphic[action][direction];
5398 static int el_act_dir2crm(int element, int action, int direction)
5400 element = GFX_ELEMENT(element);
5402 if (direction == MV_NONE)
5403 return element_info[element].crumbled[action];
5405 direction = MV_DIR_TO_BIT(direction);
5407 return element_info[element].direction_crumbled[action][direction];
5410 static int el_act_dir2crm(int element, int action, int direction)
5412 element = GFX_ELEMENT(element);
5413 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5415 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5416 return element_info[element].direction_crumbled[action][direction];
5420 int el_act2img(int element, int action)
5422 element = GFX_ELEMENT(element);
5424 return element_info[element].graphic[action];
5427 int el_act2crm(int element, int action)
5429 element = GFX_ELEMENT(element);
5431 return element_info[element].crumbled[action];
5434 int el_dir2img(int element, int direction)
5436 element = GFX_ELEMENT(element);
5438 return el_act_dir2img(element, ACTION_DEFAULT, direction);
5441 int el2baseimg(int element)
5443 return element_info[element].graphic[ACTION_DEFAULT];
5446 int el2img(int element)
5448 element = GFX_ELEMENT(element);
5450 return element_info[element].graphic[ACTION_DEFAULT];
5453 int el2edimg(int element)
5455 element = GFX_ELEMENT(element);
5457 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
5460 int el2preimg(int element)
5462 element = GFX_ELEMENT(element);
5464 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
5467 int font2baseimg(int font_nr)
5469 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
5472 int getNumActivePlayers_EM()
5474 int num_players = 0;
5480 for (i = 0; i < MAX_PLAYERS; i++)
5481 if (tape.player_participates[i])
5487 int getGameFrameDelay_EM(int native_em_game_frame_delay)
5489 int game_frame_delay_value;
5491 game_frame_delay_value =
5492 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
5493 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
5496 if (tape.playing && tape.warp_forward && !tape.pausing)
5497 game_frame_delay_value = 0;
5499 return game_frame_delay_value;
5502 unsigned int InitRND(long seed)
5504 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
5505 return InitEngineRandom_EM(seed);
5507 return InitEngineRandom_RND(seed);
5510 void InitGraphicInfo_EM(void)
5512 struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
5513 struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
5517 int num_em_gfx_errors = 0;
5519 if (graphic_info_em_object[0][0].bitmap == NULL)
5521 /* EM graphics not yet initialized in em_open_all() */
5526 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
5529 /* always start with reliable default values */
5530 for (i = 0; i < TILE_MAX; i++)
5532 object_mapping[i].element_rnd = EL_UNKNOWN;
5533 object_mapping[i].is_backside = FALSE;
5534 object_mapping[i].action = ACTION_DEFAULT;
5535 object_mapping[i].direction = MV_NONE;
5538 /* always start with reliable default values */
5539 for (p = 0; p < MAX_PLAYERS; p++)
5541 for (i = 0; i < SPR_MAX; i++)
5543 player_mapping[p][i].element_rnd = EL_UNKNOWN;
5544 player_mapping[p][i].action = ACTION_DEFAULT;
5545 player_mapping[p][i].direction = MV_NONE;
5549 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5551 int e = em_object_mapping_list[i].element_em;
5553 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
5554 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
5556 if (em_object_mapping_list[i].action != -1)
5557 object_mapping[e].action = em_object_mapping_list[i].action;
5559 if (em_object_mapping_list[i].direction != -1)
5560 object_mapping[e].direction =
5561 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
5564 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
5566 int a = em_player_mapping_list[i].action_em;
5567 int p = em_player_mapping_list[i].player_nr;
5569 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
5571 if (em_player_mapping_list[i].action != -1)
5572 player_mapping[p][a].action = em_player_mapping_list[i].action;
5574 if (em_player_mapping_list[i].direction != -1)
5575 player_mapping[p][a].direction =
5576 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
5579 for (i = 0; i < TILE_MAX; i++)
5581 int element = object_mapping[i].element_rnd;
5582 int action = object_mapping[i].action;
5583 int direction = object_mapping[i].direction;
5584 boolean is_backside = object_mapping[i].is_backside;
5585 boolean action_removing = (action == ACTION_DIGGING ||
5586 action == ACTION_SNAPPING ||
5587 action == ACTION_COLLECTING);
5588 boolean action_exploding = ((action == ACTION_EXPLODING ||
5589 action == ACTION_SMASHED_BY_ROCK ||
5590 action == ACTION_SMASHED_BY_SPRING) &&
5591 element != EL_DIAMOND);
5592 boolean action_active = (action == ACTION_ACTIVE);
5593 boolean action_other = (action == ACTION_OTHER);
5595 for (j = 0; j < 8; j++)
5597 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
5598 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
5600 i == Xdrip_stretch ? element :
5601 i == Xdrip_stretchB ? element :
5602 i == Ydrip_s1 ? element :
5603 i == Ydrip_s1B ? element :
5604 i == Xball_1B ? element :
5605 i == Xball_2 ? element :
5606 i == Xball_2B ? element :
5607 i == Yball_eat ? element :
5608 i == Ykey_1_eat ? element :
5609 i == Ykey_2_eat ? element :
5610 i == Ykey_3_eat ? element :
5611 i == Ykey_4_eat ? element :
5612 i == Ykey_5_eat ? element :
5613 i == Ykey_6_eat ? element :
5614 i == Ykey_7_eat ? element :
5615 i == Ykey_8_eat ? element :
5616 i == Ylenses_eat ? element :
5617 i == Ymagnify_eat ? element :
5618 i == Ygrass_eat ? element :
5619 i == Ydirt_eat ? element :
5620 i == Yemerald_stone ? EL_EMERALD :
5621 i == Ydiamond_stone ? EL_ROCK :
5622 i == Xsand_stonein_1 ? element :
5623 i == Xsand_stonein_2 ? element :
5624 i == Xsand_stonein_3 ? element :
5625 i == Xsand_stonein_4 ? element :
5626 is_backside ? EL_EMPTY :
5627 action_removing ? EL_EMPTY :
5629 int effective_action = (j < 7 ? action :
5630 i == Xdrip_stretch ? action :
5631 i == Xdrip_stretchB ? action :
5632 i == Ydrip_s1 ? action :
5633 i == Ydrip_s1B ? action :
5634 i == Xball_1B ? action :
5635 i == Xball_2 ? action :
5636 i == Xball_2B ? action :
5637 i == Yball_eat ? action :
5638 i == Ykey_1_eat ? action :
5639 i == Ykey_2_eat ? action :
5640 i == Ykey_3_eat ? action :
5641 i == Ykey_4_eat ? action :
5642 i == Ykey_5_eat ? action :
5643 i == Ykey_6_eat ? action :
5644 i == Ykey_7_eat ? action :
5645 i == Ykey_8_eat ? action :
5646 i == Ylenses_eat ? action :
5647 i == Ymagnify_eat ? action :
5648 i == Ygrass_eat ? action :
5649 i == Ydirt_eat ? action :
5650 i == Xsand_stonein_1 ? action :
5651 i == Xsand_stonein_2 ? action :
5652 i == Xsand_stonein_3 ? action :
5653 i == Xsand_stonein_4 ? action :
5654 i == Xsand_stoneout_1 ? action :
5655 i == Xsand_stoneout_2 ? action :
5656 i == Xboom_android ? ACTION_EXPLODING :
5657 action_exploding ? ACTION_EXPLODING :
5658 action_active ? action :
5659 action_other ? action :
5661 int graphic = (el_act_dir2img(effective_element, effective_action,
5663 int crumbled = (el_act_dir2crm(effective_element, effective_action,
5665 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
5666 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
5667 boolean has_action_graphics = (graphic != base_graphic);
5668 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
5669 struct GraphicInfo *g = &graphic_info[graphic];
5670 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
5673 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
5674 boolean special_animation = (action != ACTION_DEFAULT &&
5675 g->anim_frames == 3 &&
5676 g->anim_delay == 2 &&
5677 g->anim_mode & ANIM_LINEAR);
5678 int sync_frame = (i == Xdrip_stretch ? 7 :
5679 i == Xdrip_stretchB ? 7 :
5680 i == Ydrip_s2 ? j + 8 :
5681 i == Ydrip_s2B ? j + 8 :
5690 i == Xfake_acid_1 ? 0 :
5691 i == Xfake_acid_2 ? 10 :
5692 i == Xfake_acid_3 ? 20 :
5693 i == Xfake_acid_4 ? 30 :
5694 i == Xfake_acid_5 ? 40 :
5695 i == Xfake_acid_6 ? 50 :
5696 i == Xfake_acid_7 ? 60 :
5697 i == Xfake_acid_8 ? 70 :
5699 i == Xball_2B ? j + 8 :
5700 i == Yball_eat ? j + 1 :
5701 i == Ykey_1_eat ? j + 1 :
5702 i == Ykey_2_eat ? j + 1 :
5703 i == Ykey_3_eat ? j + 1 :
5704 i == Ykey_4_eat ? j + 1 :
5705 i == Ykey_5_eat ? j + 1 :
5706 i == Ykey_6_eat ? j + 1 :
5707 i == Ykey_7_eat ? j + 1 :
5708 i == Ykey_8_eat ? j + 1 :
5709 i == Ylenses_eat ? j + 1 :
5710 i == Ymagnify_eat ? j + 1 :
5711 i == Ygrass_eat ? j + 1 :
5712 i == Ydirt_eat ? j + 1 :
5713 i == Xamoeba_1 ? 0 :
5714 i == Xamoeba_2 ? 1 :
5715 i == Xamoeba_3 ? 2 :
5716 i == Xamoeba_4 ? 3 :
5717 i == Xamoeba_5 ? 0 :
5718 i == Xamoeba_6 ? 1 :
5719 i == Xamoeba_7 ? 2 :
5720 i == Xamoeba_8 ? 3 :
5721 i == Xexit_2 ? j + 8 :
5722 i == Xexit_3 ? j + 16 :
5723 i == Xdynamite_1 ? 0 :
5724 i == Xdynamite_2 ? 8 :
5725 i == Xdynamite_3 ? 16 :
5726 i == Xdynamite_4 ? 24 :
5727 i == Xsand_stonein_1 ? j + 1 :
5728 i == Xsand_stonein_2 ? j + 9 :
5729 i == Xsand_stonein_3 ? j + 17 :
5730 i == Xsand_stonein_4 ? j + 25 :
5731 i == Xsand_stoneout_1 && j == 0 ? 0 :
5732 i == Xsand_stoneout_1 && j == 1 ? 0 :
5733 i == Xsand_stoneout_1 && j == 2 ? 1 :
5734 i == Xsand_stoneout_1 && j == 3 ? 2 :
5735 i == Xsand_stoneout_1 && j == 4 ? 2 :
5736 i == Xsand_stoneout_1 && j == 5 ? 3 :
5737 i == Xsand_stoneout_1 && j == 6 ? 4 :
5738 i == Xsand_stoneout_1 && j == 7 ? 4 :
5739 i == Xsand_stoneout_2 && j == 0 ? 5 :
5740 i == Xsand_stoneout_2 && j == 1 ? 6 :
5741 i == Xsand_stoneout_2 && j == 2 ? 7 :
5742 i == Xsand_stoneout_2 && j == 3 ? 8 :
5743 i == Xsand_stoneout_2 && j == 4 ? 9 :
5744 i == Xsand_stoneout_2 && j == 5 ? 11 :
5745 i == Xsand_stoneout_2 && j == 6 ? 13 :
5746 i == Xsand_stoneout_2 && j == 7 ? 15 :
5747 i == Xboom_bug && j == 1 ? 2 :
5748 i == Xboom_bug && j == 2 ? 2 :
5749 i == Xboom_bug && j == 3 ? 4 :
5750 i == Xboom_bug && j == 4 ? 4 :
5751 i == Xboom_bug && j == 5 ? 2 :
5752 i == Xboom_bug && j == 6 ? 2 :
5753 i == Xboom_bug && j == 7 ? 0 :
5754 i == Xboom_bomb && j == 1 ? 2 :
5755 i == Xboom_bomb && j == 2 ? 2 :
5756 i == Xboom_bomb && j == 3 ? 4 :
5757 i == Xboom_bomb && j == 4 ? 4 :
5758 i == Xboom_bomb && j == 5 ? 2 :
5759 i == Xboom_bomb && j == 6 ? 2 :
5760 i == Xboom_bomb && j == 7 ? 0 :
5761 i == Xboom_android && j == 7 ? 6 :
5762 i == Xboom_1 && j == 1 ? 2 :
5763 i == Xboom_1 && j == 2 ? 2 :
5764 i == Xboom_1 && j == 3 ? 4 :
5765 i == Xboom_1 && j == 4 ? 4 :
5766 i == Xboom_1 && j == 5 ? 6 :
5767 i == Xboom_1 && j == 6 ? 6 :
5768 i == Xboom_1 && j == 7 ? 8 :
5769 i == Xboom_2 && j == 0 ? 8 :
5770 i == Xboom_2 && j == 1 ? 8 :
5771 i == Xboom_2 && j == 2 ? 10 :
5772 i == Xboom_2 && j == 3 ? 10 :
5773 i == Xboom_2 && j == 4 ? 10 :
5774 i == Xboom_2 && j == 5 ? 12 :
5775 i == Xboom_2 && j == 6 ? 12 :
5776 i == Xboom_2 && j == 7 ? 12 :
5777 special_animation && j == 4 ? 3 :
5778 effective_action != action ? 0 :
5782 Bitmap *debug_bitmap = g_em->bitmap;
5783 int debug_src_x = g_em->src_x;
5784 int debug_src_y = g_em->src_y;
5787 int frame = getAnimationFrame(g->anim_frames,
5790 g->anim_start_frame,
5793 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
5794 g->double_movement && is_backside);
5796 g_em->bitmap = src_bitmap;
5797 g_em->src_x = src_x;
5798 g_em->src_y = src_y;
5799 g_em->src_offset_x = 0;
5800 g_em->src_offset_y = 0;
5801 g_em->dst_offset_x = 0;
5802 g_em->dst_offset_y = 0;
5803 g_em->width = TILEX;
5804 g_em->height = TILEY;
5806 g_em->crumbled_bitmap = NULL;
5807 g_em->crumbled_src_x = 0;
5808 g_em->crumbled_src_y = 0;
5809 g_em->crumbled_border_size = 0;
5811 g_em->has_crumbled_graphics = FALSE;
5812 g_em->preserve_background = FALSE;
5815 if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
5816 printf("::: empty crumbled: %d [%s], %d, %d\n",
5817 effective_element, element_info[effective_element].token_name,
5818 effective_action, direction);
5821 /* if element can be crumbled, but certain action graphics are just empty
5822 space (like snapping sand with the original R'n'D graphics), do not
5823 treat these empty space graphics as crumbled graphics in EMC engine */
5824 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
5826 getGraphicSource(crumbled, frame, &src_bitmap, &src_x, &src_y);
5828 g_em->has_crumbled_graphics = TRUE;
5829 g_em->crumbled_bitmap = src_bitmap;
5830 g_em->crumbled_src_x = src_x;
5831 g_em->crumbled_src_y = src_y;
5832 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
5836 if (element == EL_ROCK &&
5837 effective_action == ACTION_FILLING)
5838 printf("::: has_action_graphics == %d\n", has_action_graphics);
5841 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
5842 effective_action == ACTION_MOVING ||
5843 effective_action == ACTION_PUSHING ||
5844 effective_action == ACTION_EATING)) ||
5845 (!has_action_graphics && (effective_action == ACTION_FILLING ||
5846 effective_action == ACTION_EMPTYING)))
5849 (effective_action == ACTION_FALLING ||
5850 effective_action == ACTION_FILLING ||
5851 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
5852 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
5853 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
5854 int num_steps = (i == Ydrip_s1 ? 16 :
5855 i == Ydrip_s1B ? 16 :
5856 i == Ydrip_s2 ? 16 :
5857 i == Ydrip_s2B ? 16 :
5858 i == Xsand_stonein_1 ? 32 :
5859 i == Xsand_stonein_2 ? 32 :
5860 i == Xsand_stonein_3 ? 32 :
5861 i == Xsand_stonein_4 ? 32 :
5862 i == Xsand_stoneout_1 ? 16 :
5863 i == Xsand_stoneout_2 ? 16 : 8);
5864 int cx = ABS(dx) * (TILEX / num_steps);
5865 int cy = ABS(dy) * (TILEY / num_steps);
5866 int step_frame = (i == Ydrip_s2 ? j + 8 :
5867 i == Ydrip_s2B ? j + 8 :
5868 i == Xsand_stonein_2 ? j + 8 :
5869 i == Xsand_stonein_3 ? j + 16 :
5870 i == Xsand_stonein_4 ? j + 24 :
5871 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
5872 int step = (is_backside ? step_frame : num_steps - step_frame);
5874 if (is_backside) /* tile where movement starts */
5876 if (dx < 0 || dy < 0)
5878 g_em->src_offset_x = cx * step;
5879 g_em->src_offset_y = cy * step;
5883 g_em->dst_offset_x = cx * step;
5884 g_em->dst_offset_y = cy * step;
5887 else /* tile where movement ends */
5889 if (dx < 0 || dy < 0)
5891 g_em->dst_offset_x = cx * step;
5892 g_em->dst_offset_y = cy * step;
5896 g_em->src_offset_x = cx * step;
5897 g_em->src_offset_y = cy * step;
5901 g_em->width = TILEX - cx * step;
5902 g_em->height = TILEY - cy * step;
5905 /* create unique graphic identifier to decide if tile must be redrawn */
5906 /* bit 31 - 16 (16 bit): EM style graphic
5907 bit 15 - 12 ( 4 bit): EM style frame
5908 bit 11 - 6 ( 6 bit): graphic width
5909 bit 5 - 0 ( 6 bit): graphic height */
5910 g_em->unique_identifier =
5911 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
5915 /* skip check for EMC elements not contained in original EMC artwork */
5916 if (element == EL_EMC_FAKE_ACID)
5919 if (g_em->bitmap != debug_bitmap ||
5920 g_em->src_x != debug_src_x ||
5921 g_em->src_y != debug_src_y ||
5922 g_em->src_offset_x != 0 ||
5923 g_em->src_offset_y != 0 ||
5924 g_em->dst_offset_x != 0 ||
5925 g_em->dst_offset_y != 0 ||
5926 g_em->width != TILEX ||
5927 g_em->height != TILEY)
5929 static int last_i = -1;
5937 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
5938 i, element, element_info[element].token_name,
5939 element_action_info[effective_action].suffix, direction);
5941 if (element != effective_element)
5942 printf(" [%d ('%s')]",
5944 element_info[effective_element].token_name);
5948 if (g_em->bitmap != debug_bitmap)
5949 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
5950 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
5952 if (g_em->src_x != debug_src_x ||
5953 g_em->src_y != debug_src_y)
5954 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
5955 j, (is_backside ? 'B' : 'F'),
5956 g_em->src_x, g_em->src_y,
5957 g_em->src_x / 32, g_em->src_y / 32,
5958 debug_src_x, debug_src_y,
5959 debug_src_x / 32, debug_src_y / 32);
5961 if (g_em->src_offset_x != 0 ||
5962 g_em->src_offset_y != 0 ||
5963 g_em->dst_offset_x != 0 ||
5964 g_em->dst_offset_y != 0)
5965 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
5967 g_em->src_offset_x, g_em->src_offset_y,
5968 g_em->dst_offset_x, g_em->dst_offset_y);
5970 if (g_em->width != TILEX ||
5971 g_em->height != TILEY)
5972 printf(" %d (%d): size %d,%d should be %d,%d\n",
5974 g_em->width, g_em->height, TILEX, TILEY);
5976 num_em_gfx_errors++;
5983 for (i = 0; i < TILE_MAX; i++)
5985 for (j = 0; j < 8; j++)
5987 int element = object_mapping[i].element_rnd;
5988 int action = object_mapping[i].action;
5989 int direction = object_mapping[i].direction;
5990 boolean is_backside = object_mapping[i].is_backside;
5991 int graphic_action = el_act_dir2img(element, action, direction);
5992 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
5994 if ((action == ACTION_SMASHED_BY_ROCK ||
5995 action == ACTION_SMASHED_BY_SPRING ||
5996 action == ACTION_EATING) &&
5997 graphic_action == graphic_default)
5999 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
6000 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
6001 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
6002 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
6005 /* no separate animation for "smashed by rock" -- use rock instead */
6006 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
6007 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
6009 g_em->bitmap = g_xx->bitmap;
6010 g_em->src_x = g_xx->src_x;
6011 g_em->src_y = g_xx->src_y;
6012 g_em->src_offset_x = g_xx->src_offset_x;
6013 g_em->src_offset_y = g_xx->src_offset_y;
6014 g_em->dst_offset_x = g_xx->dst_offset_x;
6015 g_em->dst_offset_y = g_xx->dst_offset_y;
6016 g_em->width = g_xx->width;
6017 g_em->height = g_xx->height;
6018 g_em->unique_identifier = g_xx->unique_identifier;
6021 g_em->preserve_background = TRUE;
6026 for (p = 0; p < MAX_PLAYERS; p++)
6028 for (i = 0; i < SPR_MAX; i++)
6030 int element = player_mapping[p][i].element_rnd;
6031 int action = player_mapping[p][i].action;
6032 int direction = player_mapping[p][i].direction;
6034 for (j = 0; j < 8; j++)
6036 int effective_element = element;
6037 int effective_action = action;
6038 int graphic = (direction == MV_NONE ?
6039 el_act2img(effective_element, effective_action) :
6040 el_act_dir2img(effective_element, effective_action,
6042 struct GraphicInfo *g = &graphic_info[graphic];
6043 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
6049 Bitmap *debug_bitmap = g_em->bitmap;
6050 int debug_src_x = g_em->src_x;
6051 int debug_src_y = g_em->src_y;
6054 int frame = getAnimationFrame(g->anim_frames,
6057 g->anim_start_frame,
6060 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x,&src_y, FALSE);
6062 g_em->bitmap = src_bitmap;
6063 g_em->src_x = src_x;
6064 g_em->src_y = src_y;
6065 g_em->src_offset_x = 0;
6066 g_em->src_offset_y = 0;
6067 g_em->dst_offset_x = 0;
6068 g_em->dst_offset_y = 0;
6069 g_em->width = TILEX;
6070 g_em->height = TILEY;
6074 /* skip check for EMC elements not contained in original EMC artwork */
6075 if (element == EL_PLAYER_3 ||
6076 element == EL_PLAYER_4)
6079 if (g_em->bitmap != debug_bitmap ||
6080 g_em->src_x != debug_src_x ||
6081 g_em->src_y != debug_src_y)
6083 static int last_i = -1;
6091 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
6092 p, i, element, element_info[element].token_name,
6093 element_action_info[effective_action].suffix, direction);
6095 if (element != effective_element)
6096 printf(" [%d ('%s')]",
6098 element_info[effective_element].token_name);
6102 if (g_em->bitmap != debug_bitmap)
6103 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
6104 j, (int)(g_em->bitmap), (int)(debug_bitmap));
6106 if (g_em->src_x != debug_src_x ||
6107 g_em->src_y != debug_src_y)
6108 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
6110 g_em->src_x, g_em->src_y,
6111 g_em->src_x / 32, g_em->src_y / 32,
6112 debug_src_x, debug_src_y,
6113 debug_src_x / 32, debug_src_y / 32);
6115 num_em_gfx_errors++;
6125 printf("::: [%d errors found]\n", num_em_gfx_errors);
6131 void PlayMenuSound()
6133 int sound = menu.sound[game_status];
6135 if (sound == SND_UNDEFINED)
6138 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6139 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6142 if (IS_LOOP_SOUND(sound))
6143 PlaySoundLoop(sound);
6148 void PlayMenuSoundStereo(int sound, int stereo_position)
6150 if (sound == SND_UNDEFINED)
6153 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6154 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6157 if (IS_LOOP_SOUND(sound))
6158 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
6160 PlaySoundStereo(sound, stereo_position);
6163 void PlayMenuSoundIfLoop()
6165 int sound = menu.sound[game_status];
6167 if (sound == SND_UNDEFINED)
6170 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6171 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6174 if (IS_LOOP_SOUND(sound))
6175 PlaySoundLoop(sound);
6178 void PlayMenuMusic()
6180 int music = menu.music[game_status];
6182 if (music == MUS_UNDEFINED)
6188 void ToggleFullscreenIfNeeded()
6190 boolean change_fullscreen = (setup.fullscreen !=
6191 video.fullscreen_enabled);
6192 boolean change_fullscreen_mode = (video.fullscreen_enabled &&
6193 !strEqual(setup.fullscreen_mode,
6194 video.fullscreen_mode_current));
6196 if (!video.fullscreen_available)
6200 if (change_fullscreen || change_fullscreen_mode)
6202 if (setup.fullscreen != video.fullscreen_enabled ||
6203 setup.fullscreen_mode != video.fullscreen_mode_current)
6206 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
6208 /* save backbuffer content which gets lost when toggling fullscreen mode */
6209 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6212 if (change_fullscreen_mode)
6214 if (setup.fullscreen && video.fullscreen_enabled)
6217 /* keep fullscreen, but change fullscreen mode (screen resolution) */
6219 /* (this is now set in sdl.c) */
6221 video.fullscreen_mode_current = setup.fullscreen_mode;
6223 video.fullscreen_enabled = FALSE; /* force new fullscreen mode */
6226 /* toggle fullscreen */
6227 ChangeVideoModeIfNeeded(setup.fullscreen);
6229 setup.fullscreen = video.fullscreen_enabled;
6231 /* restore backbuffer content from temporary backbuffer backup bitmap */
6232 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6234 FreeBitmap(tmp_backbuffer);
6237 /* update visible window/screen */
6238 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6240 redraw_mask = REDRAW_ALL;