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"
26 /* select level set with EMC X11 graphics before activating EM GFX debugging */
27 #define DEBUG_EM_GFX 0
29 /* tool button identifiers */
30 #define TOOL_CTRL_ID_YES 0
31 #define TOOL_CTRL_ID_NO 1
32 #define TOOL_CTRL_ID_CONFIRM 2
33 #define TOOL_CTRL_ID_PLAYER_1 3
34 #define TOOL_CTRL_ID_PLAYER_2 4
35 #define TOOL_CTRL_ID_PLAYER_3 5
36 #define TOOL_CTRL_ID_PLAYER_4 6
38 #define NUM_TOOL_BUTTONS 7
40 /* forward declaration for internal use */
41 static void UnmapToolButtons();
42 static void HandleToolButtons(struct GadgetInfo *);
43 static int el_act_dir2crm(int, int, int);
44 static int el_act2crm(int, int);
46 static struct GadgetInfo *tool_gadget[NUM_TOOL_BUTTONS];
47 static int request_gadget_id = -1;
49 static char *print_if_not_empty(int element)
51 static char *s = NULL;
52 char *token_name = element_info[element].token_name;
57 s = checked_malloc(strlen(token_name) + 10 + 1);
59 if (element != EL_EMPTY)
60 sprintf(s, "%d\t['%s']", element, token_name);
62 sprintf(s, "%d", element);
67 void DumpTile(int x, int y)
72 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
79 printf("Field Info: SCREEN(%d, %d), LEVEL(%d, %d)\n", sx, sy, x, y);
82 if (!IN_LEV_FIELD(x, y))
84 printf("(not in level field)\n");
90 printf(" Feld: %d\t['%s']\n", Feld[x][y],
91 element_info[Feld[x][y]].token_name);
92 printf(" Back: %s\n", print_if_not_empty(Back[x][y]));
93 printf(" Store: %s\n", print_if_not_empty(Store[x][y]));
94 printf(" Store2: %s\n", print_if_not_empty(Store2[x][y]));
95 printf(" StorePlayer: %s\n", print_if_not_empty(StorePlayer[x][y]));
96 printf(" MovPos: %d\n", MovPos[x][y]);
97 printf(" MovDir: %d\n", MovDir[x][y]);
98 printf(" MovDelay: %d\n", MovDelay[x][y]);
99 printf(" ChangeDelay: %d\n", ChangeDelay[x][y]);
100 printf(" CustomValue: %d\n", CustomValue[x][y]);
101 printf(" GfxElement: %d\n", GfxElement[x][y]);
102 printf(" GfxAction: %d\n", GfxAction[x][y]);
103 printf(" GfxFrame: %d\n", GfxFrame[x][y]);
107 void SetDrawtoField(int mode)
109 if (mode == DRAW_BUFFERED && setup.soft_scrolling)
120 drawto_field = fieldbuffer;
122 else /* DRAW_BACKBUFFER */
128 BX2 = SCR_FIELDX - 1;
129 BY2 = SCR_FIELDY - 1;
133 drawto_field = backbuffer;
137 void RedrawPlayfield(boolean force_redraw, int x, int y, int width, int height)
139 if (game_status == GAME_MODE_PLAYING &&
140 level.game_engine_type == GAME_ENGINE_TYPE_EM)
142 /* currently there is no partial redraw -- always redraw whole playfield */
143 RedrawPlayfield_EM(TRUE);
145 /* blit playfield from scroll buffer to normal back buffer for fading in */
146 BlitScreenToBitmap_EM(backbuffer);
148 else if (game_status == GAME_MODE_PLAYING &&
149 level.game_engine_type == GAME_ENGINE_TYPE_SP)
151 /* currently there is no partial redraw -- always redraw whole playfield */
152 RedrawPlayfield_SP(TRUE);
154 /* blit playfield from scroll buffer to normal back buffer for fading in */
155 BlitScreenToBitmap_SP(backbuffer);
157 else if (game_status == GAME_MODE_PLAYING &&
158 !game.envelope_active)
164 width = gfx.sxsize + 2 * TILEX;
165 height = gfx.sysize + 2 * TILEY;
171 int x1 = (x - SX) / TILEX, y1 = (y - SY) / TILEY;
172 int x2 = (x - SX + width) / TILEX, y2 = (y - SY + height) / TILEY;
174 for (xx = BX1; xx <= BX2; xx++)
175 for (yy = BY1; yy <= BY2; yy++)
176 if (xx >= x1 && xx <= x2 && yy >= y1 && yy <= y2)
177 DrawScreenField(xx, yy);
181 if (setup.soft_scrolling)
183 int fx = FX, fy = FY;
185 fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0);
186 fy += (ScreenMovDir & (MV_UP|MV_DOWN) ? ScreenGfxPos : 0);
188 BlitBitmap(fieldbuffer, backbuffer, fx,fy, SXSIZE,SYSIZE, SX,SY);
200 BlitBitmap(drawto, window, x, y, width, height, x, y);
203 void DrawMaskedBorder_Rect(int x, int y, int width, int height)
205 Bitmap *bitmap = graphic_info[IMG_GLOBAL_BORDER].bitmap;
207 SetClipOrigin(bitmap, bitmap->stored_clip_gc, 0, 0);
208 BlitBitmapMasked(bitmap, backbuffer, x, y, width, height, x, y);
211 void DrawMaskedBorder_FIELD()
213 if (global.border_status >= GAME_MODE_TITLE &&
214 global.border_status <= GAME_MODE_PLAYING &&
215 border.draw_masked[global.border_status])
216 DrawMaskedBorder_Rect(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
219 void DrawMaskedBorder_DOOR_1()
221 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
222 (global.border_status != GAME_MODE_EDITOR ||
223 border.draw_masked[GFX_SPECIAL_ARG_EDITOR]))
224 DrawMaskedBorder_Rect(DX, DY, DXSIZE, DYSIZE);
227 void DrawMaskedBorder_DOOR_2()
229 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
230 global.border_status != GAME_MODE_EDITOR)
231 DrawMaskedBorder_Rect(VX, VY, VXSIZE, VYSIZE);
234 void DrawMaskedBorder_DOOR_3()
236 /* currently not available */
239 void DrawMaskedBorder_ALL()
241 DrawMaskedBorder_FIELD();
242 DrawMaskedBorder_DOOR_1();
243 DrawMaskedBorder_DOOR_2();
244 DrawMaskedBorder_DOOR_3();
247 void DrawMaskedBorder(int redraw_mask)
249 /* never draw masked screen borders on borderless screens */
250 if (effectiveGameStatus() == GAME_MODE_LOADING ||
251 effectiveGameStatus() == GAME_MODE_TITLE)
254 if (redraw_mask & REDRAW_ALL)
255 DrawMaskedBorder_ALL();
258 if (redraw_mask & REDRAW_FIELD)
259 DrawMaskedBorder_FIELD();
260 if (redraw_mask & REDRAW_DOOR_1)
261 DrawMaskedBorder_DOOR_1();
262 if (redraw_mask & REDRAW_DOOR_2)
263 DrawMaskedBorder_DOOR_2();
264 if (redraw_mask & REDRAW_DOOR_3)
265 DrawMaskedBorder_DOOR_3();
272 DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
275 printf("::: TILES TO REFRESH: %d\n", redraw_tiles);
276 for (x = 0; x < SCR_FIELDX; x++)
277 for (y = 0 ; y < SCR_FIELDY; y++)
278 if (redraw[redraw_x1 + x][redraw_y1 + y])
279 printf("::: - %d, %d [%s]\n",
280 LEVELX(x), LEVELY(y),
281 EL_NAME(Feld[LEVELX(x)][LEVELY(y)]));
284 if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD)
285 redraw_mask |= REDRAW_FIELD;
287 if (redraw_mask & REDRAW_FIELD)
288 redraw_mask &= ~REDRAW_TILES;
290 if (redraw_mask == REDRAW_NONE)
293 if (redraw_mask & REDRAW_TILES &&
294 game_status == GAME_MODE_PLAYING &&
295 border.draw_masked[GAME_MODE_PLAYING])
296 redraw_mask |= REDRAW_FIELD;
298 if (global.fps_slowdown && game_status == GAME_MODE_PLAYING)
300 static boolean last_frame_skipped = FALSE;
301 boolean skip_even_when_not_scrolling = TRUE;
302 boolean just_scrolling = (ScreenMovDir != 0);
303 boolean verbose = FALSE;
305 if (global.fps_slowdown_factor > 1 &&
306 (FrameCounter % global.fps_slowdown_factor) &&
307 (just_scrolling || skip_even_when_not_scrolling))
309 redraw_mask &= ~REDRAW_MAIN;
311 last_frame_skipped = TRUE;
314 printf("FRAME SKIPPED\n");
318 if (last_frame_skipped)
319 redraw_mask |= REDRAW_FIELD;
321 last_frame_skipped = FALSE;
324 printf("frame not skipped\n");
328 /* synchronize X11 graphics at this point; if we would synchronize the
329 display immediately after the buffer switching (after the XFlush),
330 this could mean that we have to wait for the graphics to complete,
331 although we could go on doing calculations for the next frame */
335 /* prevent drawing masked border to backbuffer when using playfield buffer */
336 if (game_status != GAME_MODE_PLAYING ||
337 redraw_mask & REDRAW_FROM_BACKBUFFER ||
338 buffer == backbuffer)
339 DrawMaskedBorder(redraw_mask);
341 DrawMaskedBorder(redraw_mask & REDRAW_DOORS);
343 if (redraw_mask & REDRAW_ALL)
345 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
347 redraw_mask = REDRAW_NONE;
350 if (redraw_mask & REDRAW_FIELD)
353 printf("::: REDRAW_FIELD\n");
356 if (game_status != GAME_MODE_PLAYING ||
357 redraw_mask & REDRAW_FROM_BACKBUFFER)
359 BlitBitmap(backbuffer, window,
360 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
364 int fx = FX, fy = FY;
366 if (setup.soft_scrolling)
368 fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
369 fy += (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
372 if (setup.soft_scrolling ||
373 ABS(ScreenMovPos) + ScrollStepSize == TILEX ||
374 ABS(ScreenMovPos) == ScrollStepSize ||
375 redraw_tiles > REDRAWTILES_THRESHOLD)
377 if (border.draw_masked[GAME_MODE_PLAYING])
379 if (buffer != backbuffer)
381 /* copy playfield buffer to backbuffer to add masked border */
382 BlitBitmap(buffer, backbuffer, fx, fy, SXSIZE, SYSIZE, SX, SY);
383 DrawMaskedBorder(REDRAW_FIELD);
386 BlitBitmap(backbuffer, window,
387 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
392 BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
397 printf("redrawing all (ScreenGfxPos == %d) because %s\n",
399 (setup.soft_scrolling ?
400 "setup.soft_scrolling" :
401 ABS(ScreenGfxPos) + ScrollStepSize == TILEX ?
402 "ABS(ScreenGfxPos) + ScrollStepSize == TILEX" :
403 ABS(ScreenGfxPos) == ScrollStepSize ?
404 "ABS(ScreenGfxPos) == ScrollStepSize" :
405 "redraw_tiles > REDRAWTILES_THRESHOLD"));
411 redraw_mask &= ~REDRAW_MAIN;
414 if (redraw_mask & REDRAW_DOORS)
416 if (redraw_mask & REDRAW_DOOR_1)
417 BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
419 if (redraw_mask & REDRAW_DOOR_2)
420 BlitBitmap(backbuffer, window, VX, VY, VXSIZE, VYSIZE, VX, VY);
422 if (redraw_mask & REDRAW_DOOR_3)
423 BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
425 redraw_mask &= ~REDRAW_DOORS;
428 if (redraw_mask & REDRAW_MICROLEVEL)
430 BlitBitmap(backbuffer, window, SX, SY + 10 * TILEY, SXSIZE, 7 * TILEY,
431 SX, SY + 10 * TILEY);
433 redraw_mask &= ~REDRAW_MICROLEVEL;
436 if (redraw_mask & REDRAW_TILES)
439 printf("::: REDRAW_TILES\n");
442 for (x = 0; x < SCR_FIELDX; x++)
443 for (y = 0 ; y < SCR_FIELDY; y++)
444 if (redraw[redraw_x1 + x][redraw_y1 + y])
445 BlitBitmap(buffer, window,
446 FX + x * TILEX, FY + y * TILEY, TILEX, TILEY,
447 SX + x * TILEX, SY + y * TILEY);
450 if (redraw_mask & REDRAW_FPS) /* display frames per second */
455 sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
456 if (!global.fps_slowdown)
459 sprintf(text, "%04.1f fps%s", global.frames_per_second, info1);
461 DrawTextExt(window, SX + SXSIZE + SX, 0, text, FONT_TEXT_2, BLIT_OPAQUE);
463 DrawTextExt(window, SX, SY, text, FONT_TEXT_2, BLIT_OPAQUE);
469 for (x = 0; x < MAX_BUF_XSIZE; x++)
470 for (y = 0; y < MAX_BUF_YSIZE; y++)
473 redraw_mask = REDRAW_NONE;
476 static void FadeCrossSaveBackbuffer()
478 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
481 static void FadeExt(int fade_mask, int fade_mode, int fade_type)
483 static int fade_type_skip = FADE_TYPE_NONE;
484 void (*draw_border_function)(void) = NULL;
485 Bitmap *bitmap = (fade_mode & FADE_TYPE_TRANSFORM ? bitmap_db_cross : NULL);
486 int x, y, width, height;
487 int fade_delay, post_delay;
489 if (fade_type == FADE_TYPE_FADE_OUT)
491 if (fade_type_skip != FADE_TYPE_NONE)
494 printf("::: skipping %d ... [%d] (X)\n", fade_mode, fade_type_skip);
497 /* skip all fade operations until specified fade operation */
498 if (fade_type & fade_type_skip)
499 fade_type_skip = FADE_TYPE_NONE;
504 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
506 FadeCrossSaveBackbuffer();
512 redraw_mask |= fade_mask;
514 if (fade_type == FADE_TYPE_SKIP)
517 printf("::: will skip %d ... [%d]\n", fade_mode, fade_type_skip);
520 fade_type_skip = fade_mode;
526 printf("::: !!! FADING %d ... [%d] [%d]\n", fade_mode, fade_type,
531 fade_delay = fading.fade_delay;
532 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
535 if (fade_type_skip != FADE_TYPE_NONE)
538 printf("::: skipping %d ... [%d]\n", fade_mode, fade_type_skip);
541 /* skip all fade operations until specified fade operation */
542 if (fade_type & fade_type_skip)
543 fade_type_skip = FADE_TYPE_NONE;
553 if (global.autoplay_leveldir)
555 // fading.fade_mode = FADE_MODE_NONE;
562 if (fading.fade_mode == FADE_MODE_NONE)
570 /* !!! what about fade_mask == REDRAW_FIELD | REDRAW_ALL ??? !!! */
573 printf("::: NOW FADING %d ... [%d]\n", fade_mode, fade_type);
577 if (fade_mask == REDRAW_NONE)
578 fade_mask = REDRAW_FIELD;
581 // if (fade_mask & REDRAW_FIELD)
582 if (fade_mask == REDRAW_FIELD)
587 height = FULL_SYSIZE;
590 fade_delay = fading.fade_delay;
591 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
594 if (border.draw_masked_when_fading)
595 draw_border_function = DrawMaskedBorder_FIELD; /* update when fading */
597 DrawMaskedBorder_FIELD(); /* draw once */
599 else /* REDRAW_ALL */
607 fade_delay = fading.fade_delay;
608 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
613 if (!setup.fade_screens ||
615 fading.fade_mode == FADE_MODE_NONE)
617 if (!setup.fade_screens || fade_delay == 0)
620 if (fade_mode == FADE_MODE_FADE_OUT)
624 if (fade_mode == FADE_MODE_FADE_OUT &&
625 fading.fade_mode != FADE_MODE_NONE)
626 ClearRectangle(backbuffer, x, y, width, height);
630 BlitBitmap(backbuffer, window, x, y, width, height, x, y);
631 redraw_mask = REDRAW_NONE;
639 FadeRectangle(bitmap, x, y, width, height, fade_mode, fade_delay, post_delay,
640 draw_border_function);
642 redraw_mask &= ~fade_mask;
645 void FadeIn(int fade_mask)
647 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
648 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_IN);
650 FadeExt(fade_mask, FADE_MODE_FADE_IN, FADE_TYPE_FADE_IN);
653 void FadeOut(int fade_mask)
655 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
656 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_OUT);
658 FadeExt(fade_mask, FADE_MODE_FADE_OUT, FADE_TYPE_FADE_OUT);
660 global.border_status = game_status;
663 static void FadeSetLeaveNext(struct TitleFadingInfo fading_leave, boolean set)
665 static struct TitleFadingInfo fading_leave_stored;
668 fading_leave_stored = fading_leave;
670 fading = fading_leave_stored;
673 void FadeSetEnterMenu()
675 fading = menu.enter_menu;
678 printf("::: storing enter_menu\n");
681 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
684 void FadeSetLeaveMenu()
686 fading = menu.leave_menu;
689 printf("::: storing leave_menu\n");
692 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
695 void FadeSetEnterScreen()
697 fading = menu.enter_screen[game_status];
700 printf("::: storing leave_screen[%d]\n", game_status);
703 FadeSetLeaveNext(menu.leave_screen[game_status], TRUE); /* store */
706 void FadeSetNextScreen()
708 fading = menu.next_screen;
711 printf("::: storing next_screen\n");
714 // (do not overwrite fade mode set by FadeSetEnterScreen)
715 // FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
718 void FadeSetLeaveScreen()
721 printf("::: recalling last stored value\n");
724 FadeSetLeaveNext(menu.leave_screen[game_status], FALSE); /* recall */
727 void FadeSetFromType(int type)
729 if (type & TYPE_ENTER_SCREEN)
730 FadeSetEnterScreen();
731 else if (type & TYPE_ENTER)
733 else if (type & TYPE_LEAVE)
737 void FadeSetDisabled()
739 static struct TitleFadingInfo fading_none = { FADE_MODE_NONE, -1, -1, -1 };
741 fading = fading_none;
744 void FadeSkipNextFadeIn()
746 FadeExt(0, FADE_MODE_SKIP_FADE_IN, FADE_TYPE_SKIP);
749 void FadeSkipNextFadeOut()
751 FadeExt(0, FADE_MODE_SKIP_FADE_OUT, FADE_TYPE_SKIP);
754 void SetWindowBackgroundImageIfDefined(int graphic)
756 if (graphic_info[graphic].bitmap)
757 SetWindowBackgroundBitmap(graphic_info[graphic].bitmap);
760 void SetMainBackgroundImageIfDefined(int graphic)
762 if (graphic_info[graphic].bitmap)
763 SetMainBackgroundBitmap(graphic_info[graphic].bitmap);
766 void SetDoorBackgroundImageIfDefined(int graphic)
768 if (graphic_info[graphic].bitmap)
769 SetDoorBackgroundBitmap(graphic_info[graphic].bitmap);
772 void SetWindowBackgroundImage(int graphic)
774 SetWindowBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
775 graphic_info[graphic].bitmap ?
776 graphic_info[graphic].bitmap :
777 graphic_info[IMG_BACKGROUND].bitmap);
780 void SetMainBackgroundImage(int graphic)
782 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
783 graphic_info[graphic].bitmap ?
784 graphic_info[graphic].bitmap :
785 graphic_info[IMG_BACKGROUND].bitmap);
788 void SetDoorBackgroundImage(int graphic)
790 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
791 graphic_info[graphic].bitmap ?
792 graphic_info[graphic].bitmap :
793 graphic_info[IMG_BACKGROUND].bitmap);
796 void SetPanelBackground()
799 struct GraphicInfo *gfx = &graphic_info[IMG_BACKGROUND_PANEL];
802 BlitBitmapTiled(gfx->bitmap, bitmap_db_panel, gfx->src_x, gfx->src_y,
803 gfx->width, gfx->height, 0, 0, DXSIZE, DYSIZE);
805 /* (ClearRectangle() only needed if panel bitmap is smaller than panel) */
806 ClearRectangle(bitmap_db_panel, DX, DY, DXSIZE, DYSIZE);
807 BlitBitmap(gfx->bitmap, bitmap_db_panel, gfx->src_x, gfx->src_y,
808 MIN(gfx->width, DXSIZE), MIN(gfx->height, DYSIZE), 0, 0);
811 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, bitmap_db_panel,
812 DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, 0, 0);
815 SetDoorBackgroundBitmap(bitmap_db_panel);
818 void DrawBackground(int x, int y, int width, int height)
820 /* !!! "drawto" might still point to playfield buffer here (see below) !!! */
821 /* (when entering hall of fame after playing) */
823 ClearRectangleOnBackground(drawto, x, y, width, height);
825 ClearRectangleOnBackground(backbuffer, x, y, width, height);
828 redraw_mask |= REDRAW_FIELD;
831 void DrawBackgroundForFont(int x, int y, int width, int height, int font_nr)
833 struct FontBitmapInfo *font = getFontBitmapInfo(font_nr);
835 if (font->bitmap == NULL)
838 DrawBackground(x, y, width, height);
841 void DrawBackgroundForGraphic(int x, int y, int width, int height, int graphic)
843 struct GraphicInfo *g = &graphic_info[graphic];
845 if (g->bitmap == NULL)
848 DrawBackground(x, y, width, height);
853 /* !!! "drawto" might still point to playfield buffer here (see above) !!! */
854 /* (when entering hall of fame after playing) */
855 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
857 /* !!! maybe this should be done before clearing the background !!! */
858 if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
860 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
861 SetDrawtoField(DRAW_BUFFERED);
864 SetDrawtoField(DRAW_BACKBUFFER);
867 void MarkTileDirty(int x, int y)
869 int xx = redraw_x1 + x;
870 int yy = redraw_y1 + y;
875 redraw[xx][yy] = TRUE;
876 redraw_mask |= REDRAW_TILES;
879 void SetBorderElement()
883 BorderElement = EL_EMPTY;
885 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
887 for (x = 0; x < lev_fieldx; x++)
889 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
890 BorderElement = EL_STEELWALL;
892 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
898 void FloodFillLevel(int from_x, int from_y, int fill_element,
899 short field[MAX_LEV_FIELDX][MAX_LEV_FIELDY],
900 int max_fieldx, int max_fieldy)
904 static int check[4][2] = { { -1, 0 }, { 0, -1 }, { 1, 0 }, { 0, 1 } };
905 static int safety = 0;
907 /* check if starting field still has the desired content */
908 if (field[from_x][from_y] == fill_element)
913 if (safety > max_fieldx * max_fieldy)
914 Error(ERR_EXIT, "Something went wrong in 'FloodFill()'. Please debug.");
916 old_element = field[from_x][from_y];
917 field[from_x][from_y] = fill_element;
919 for (i = 0; i < 4; i++)
921 x = from_x + check[i][0];
922 y = from_y + check[i][1];
924 if (IN_FIELD(x, y, max_fieldx, max_fieldy) && field[x][y] == old_element)
925 FloodFillLevel(x, y, fill_element, field, max_fieldx, max_fieldy);
931 void SetRandomAnimationValue(int x, int y)
933 gfx.anim_random_frame = GfxRandom[x][y];
936 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
938 /* animation synchronized with global frame counter, not move position */
939 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
940 sync_frame = FrameCounter;
942 return getAnimationFrame(graphic_info[graphic].anim_frames,
943 graphic_info[graphic].anim_delay,
944 graphic_info[graphic].anim_mode,
945 graphic_info[graphic].anim_start_frame,
949 void getSizedGraphicSource(int graphic, int frame, int tilesize_raw,
950 Bitmap **bitmap, int *x, int *y)
954 int width_mult, width_div;
955 int height_mult, height_div;
959 { 15, 16, 2, 3 }, /* 1 x 1 */
960 { 7, 8, 2, 3 }, /* 2 x 2 */
961 { 3, 4, 2, 3 }, /* 4 x 4 */
962 { 1, 2, 2, 3 }, /* 8 x 8 */
963 { 0, 1, 2, 3 }, /* 16 x 16 */
964 { 0, 1, 0, 1 }, /* 32 x 32 */
966 struct GraphicInfo *g = &graphic_info[graphic];
967 Bitmap *src_bitmap = g->bitmap;
968 int tilesize = MIN(MAX(1, tilesize_raw), TILESIZE);
969 int offset_calc_pos = log_2(tilesize);
970 int width_mult = offset_calc[offset_calc_pos].width_mult;
971 int width_div = offset_calc[offset_calc_pos].width_div;
972 int height_mult = offset_calc[offset_calc_pos].height_mult;
973 int height_div = offset_calc[offset_calc_pos].height_div;
974 int startx = src_bitmap->width * width_mult / width_div;
975 int starty = src_bitmap->height * height_mult / height_div;
976 int src_x = g->src_x * tilesize / TILESIZE;
977 int src_y = g->src_y * tilesize / TILESIZE;
978 int width = g->width * tilesize / TILESIZE;
979 int height = g->height * tilesize / TILESIZE;
980 int offset_x = g->offset_x * tilesize / TILESIZE;
981 int offset_y = g->offset_y * tilesize / TILESIZE;
983 if (g->offset_y == 0) /* frames are ordered horizontally */
985 int max_width = g->anim_frames_per_line * width;
986 int pos = (src_y / height) * max_width + src_x + frame * offset_x;
988 src_x = pos % max_width;
989 src_y = src_y % height + pos / max_width * height;
991 else if (g->offset_x == 0) /* frames are ordered vertically */
993 int max_height = g->anim_frames_per_line * height;
994 int pos = (src_x / width) * max_height + src_y + frame * offset_y;
996 src_x = src_x % width + pos / max_height * width;
997 src_y = pos % max_height;
999 else /* frames are ordered diagonally */
1001 src_x = src_x + frame * offset_x;
1002 src_y = src_y + frame * offset_y;
1005 *bitmap = src_bitmap;
1006 *x = startx + src_x;
1007 *y = starty + src_y;
1010 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1013 getSizedGraphicSource(graphic, 0, MINI_TILESIZE, bitmap, x, y);
1015 struct GraphicInfo *g = &graphic_info[graphic];
1016 int mini_startx = 0;
1017 int mini_starty = g->bitmap->height * 2 / 3;
1019 *bitmap = g->bitmap;
1020 *x = mini_startx + g->src_x / 2;
1021 *y = mini_starty + g->src_y / 2;
1025 inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1026 int *x, int *y, boolean get_backside)
1028 struct GraphicInfo *g = &graphic_info[graphic];
1029 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
1030 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
1032 *bitmap = g->bitmap;
1034 if (g->offset_y == 0) /* frames are ordered horizontally */
1036 int max_width = g->anim_frames_per_line * g->width;
1037 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
1039 *x = pos % max_width;
1040 *y = src_y % g->height + pos / max_width * g->height;
1042 else if (g->offset_x == 0) /* frames are ordered vertically */
1044 int max_height = g->anim_frames_per_line * g->height;
1045 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
1047 *x = src_x % g->width + pos / max_height * g->width;
1048 *y = pos % max_height;
1050 else /* frames are ordered diagonally */
1052 *x = src_x + frame * g->offset_x;
1053 *y = src_y + frame * g->offset_y;
1057 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
1059 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
1062 void DrawGraphic(int x, int y, int graphic, int frame)
1065 if (!IN_SCR_FIELD(x, y))
1067 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1068 printf("DrawGraphic(): This should never happen!\n");
1073 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
1074 MarkTileDirty(x, y);
1077 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1083 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1084 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
1087 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
1090 if (!IN_SCR_FIELD(x, y))
1092 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1093 printf("DrawGraphicThruMask(): This should never happen!\n");
1098 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
1100 MarkTileDirty(x, y);
1103 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
1109 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1111 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1112 dst_x - src_x, dst_y - src_y);
1113 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
1116 void DrawSizedGraphic(int x, int y, int graphic, int frame, int tilesize)
1118 DrawSizedGraphicExt(drawto, SX + x * tilesize, SY + y * tilesize, graphic,
1120 MarkTileDirty(x / tilesize, y / tilesize);
1123 void DrawSizedGraphicExt(DrawBuffer *d, int x, int y, int graphic, int frame,
1129 getSizedGraphicSource(graphic, frame, tilesize, &src_bitmap, &src_x, &src_y);
1130 BlitBitmap(src_bitmap, d, src_x, src_y, tilesize, tilesize, x, y);
1133 void DrawMiniGraphic(int x, int y, int graphic)
1135 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
1136 MarkTileDirty(x / 2, y / 2);
1139 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
1144 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1145 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
1148 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
1149 int graphic, int frame,
1150 int cut_mode, int mask_mode)
1155 int width = TILEX, height = TILEY;
1158 if (dx || dy) /* shifted graphic */
1160 if (x < BX1) /* object enters playfield from the left */
1167 else if (x > BX2) /* object enters playfield from the right */
1173 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
1179 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
1181 else if (dx) /* general horizontal movement */
1182 MarkTileDirty(x + SIGN(dx), y);
1184 if (y < BY1) /* object enters playfield from the top */
1186 if (cut_mode==CUT_BELOW) /* object completely above top border */
1194 else if (y > BY2) /* object enters playfield from the bottom */
1200 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
1206 else if (dy > 0 && cut_mode == CUT_ABOVE)
1208 if (y == BY2) /* object completely above bottom border */
1214 MarkTileDirty(x, y + 1);
1215 } /* object leaves playfield to the bottom */
1216 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1218 else if (dy) /* general vertical movement */
1219 MarkTileDirty(x, y + SIGN(dy));
1223 if (!IN_SCR_FIELD(x, y))
1225 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1226 printf("DrawGraphicShifted(): This should never happen!\n");
1231 if (width > 0 && height > 0)
1233 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1238 dst_x = FX + x * TILEX + dx;
1239 dst_y = FY + y * TILEY + dy;
1241 if (mask_mode == USE_MASKING)
1243 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1244 dst_x - src_x, dst_y - src_y);
1245 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1249 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1252 MarkTileDirty(x, y);
1256 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
1257 int graphic, int frame,
1258 int cut_mode, int mask_mode)
1263 int width = TILEX, height = TILEY;
1266 int x2 = x + SIGN(dx);
1267 int y2 = y + SIGN(dy);
1269 /* !!! DOES NOT WORK FOR SLOW MOVEMENT !!! */
1270 int sync_frame = GfxFrame[LEVELX(x)][LEVELY(y)];
1272 /* movement with two-tile animations must be sync'ed with movement position,
1273 not with current GfxFrame (which can be higher when using slow movement) */
1274 int anim_pos = (dx ? ABS(dx) : ABS(dy));
1275 int anim_frames = graphic_info[graphic].anim_frames;
1277 /* (we also need anim_delay here for movement animations with less frames) */
1278 int anim_delay = graphic_info[graphic].anim_delay;
1279 int sync_frame = anim_pos * anim_frames * anim_delay / TILESIZE;
1281 int sync_frame = anim_pos * anim_frames / TILESIZE;
1284 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
1285 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
1287 /* re-calculate animation frame for two-tile movement animation */
1288 frame = getGraphicAnimationFrame(graphic, sync_frame);
1292 printf("::: %d, %d, %d => %d [%d]\n",
1293 anim_pos, anim_frames, anim_delay, sync_frame, graphic);
1295 printf("::: %d, %d => %d\n",
1296 anim_pos, anim_frames, sync_frame);
1301 printf("::: %d [%d, %d] [%d] [%d]\n", frame, sync_frame, dy,
1302 GfxFrame[LEVELX(x)][LEVELY(y)], mask_mode);
1305 /* check if movement start graphic inside screen area and should be drawn */
1306 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
1308 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
1310 dst_x = FX + x1 * TILEX;
1311 dst_y = FY + y1 * TILEY;
1313 if (mask_mode == USE_MASKING)
1315 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1316 dst_x - src_x, dst_y - src_y);
1317 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1321 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1324 MarkTileDirty(x1, y1);
1327 /* check if movement end graphic inside screen area and should be drawn */
1328 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
1330 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
1332 dst_x = FX + x2 * TILEX;
1333 dst_y = FY + y2 * TILEY;
1335 if (mask_mode == USE_MASKING)
1337 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1338 dst_x - src_x, dst_y - src_y);
1339 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1343 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1346 MarkTileDirty(x2, y2);
1350 static void DrawGraphicShifted(int x, int y, int dx, int dy,
1351 int graphic, int frame,
1352 int cut_mode, int mask_mode)
1356 DrawGraphic(x, y, graphic, frame);
1361 if (graphic_info[graphic].double_movement) /* EM style movement images */
1362 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1364 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1367 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1368 int frame, int cut_mode)
1370 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
1373 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1374 int cut_mode, int mask_mode)
1376 int lx = LEVELX(x), ly = LEVELY(y);
1380 if (IN_LEV_FIELD(lx, ly))
1382 SetRandomAnimationValue(lx, ly);
1384 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
1385 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1387 /* do not use double (EM style) movement graphic when not moving */
1388 if (graphic_info[graphic].double_movement && !dx && !dy)
1390 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
1391 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1394 else /* border element */
1396 graphic = el2img(element);
1397 frame = getGraphicAnimationFrame(graphic, -1);
1400 if (element == EL_EXPANDABLE_WALL)
1402 boolean left_stopped = FALSE, right_stopped = FALSE;
1404 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1405 left_stopped = TRUE;
1406 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1407 right_stopped = TRUE;
1409 if (left_stopped && right_stopped)
1411 else if (left_stopped)
1413 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1414 frame = graphic_info[graphic].anim_frames - 1;
1416 else if (right_stopped)
1418 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1419 frame = graphic_info[graphic].anim_frames - 1;
1424 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1425 else if (mask_mode == USE_MASKING)
1426 DrawGraphicThruMask(x, y, graphic, frame);
1428 DrawGraphic(x, y, graphic, frame);
1431 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1432 int cut_mode, int mask_mode)
1434 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1435 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1436 cut_mode, mask_mode);
1439 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1442 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1445 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1448 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1451 void DrawLevelElementThruMask(int x, int y, int element)
1453 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1456 void DrawLevelFieldThruMask(int x, int y)
1458 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1461 /* !!! implementation of quicksand is totally broken !!! */
1462 #define IS_CRUMBLED_TILE(x, y, e) \
1463 (GFX_CRUMBLED(e) && (!IN_LEV_FIELD(x, y) || \
1464 !IS_MOVING(x, y) || \
1465 (e) == EL_QUICKSAND_EMPTYING || \
1466 (e) == EL_QUICKSAND_FAST_EMPTYING))
1468 static void DrawLevelFieldCrumbledInnerCorners(int x, int y, int dx, int dy,
1473 int width, height, cx, cy;
1474 int sx = SCREENX(x), sy = SCREENY(y);
1475 int crumbled_border_size = graphic_info[graphic].border_size;
1478 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1480 for (i = 1; i < 4; i++)
1482 int dxx = (i & 1 ? dx : 0);
1483 int dyy = (i & 2 ? dy : 0);
1486 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1489 /* check if neighbour field is of same crumble type */
1490 boolean same = (IS_CRUMBLED_TILE(xx, yy, element) &&
1491 graphic_info[graphic].class ==
1492 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class);
1494 /* return if check prevents inner corner */
1495 if (same == (dxx == dx && dyy == dy))
1499 /* if we reach this point, we have an inner corner */
1501 getGraphicSource(graphic, 1, &src_bitmap, &src_x, &src_y);
1503 width = crumbled_border_size;
1504 height = crumbled_border_size;
1505 cx = (dx > 0 ? TILEX - crumbled_border_size : 0);
1506 cy = (dy > 0 ? TILEY - crumbled_border_size : 0);
1508 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1509 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1512 static void DrawLevelFieldCrumbledBorders(int x, int y, int graphic, int frame,
1517 int width, height, bx, by, cx, cy;
1518 int sx = SCREENX(x), sy = SCREENY(y);
1519 int crumbled_border_size = graphic_info[graphic].border_size;
1522 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1524 /* draw simple, sloppy, non-corner-accurate crumbled border */
1527 width = (dir == 1 || dir == 2 ? crumbled_border_size : TILEX);
1528 height = (dir == 0 || dir == 3 ? crumbled_border_size : TILEY);
1529 cx = (dir == 2 ? TILEX - crumbled_border_size : 0);
1530 cy = (dir == 3 ? TILEY - crumbled_border_size : 0);
1532 if (dir == 1 || dir == 2) /* left or right crumbled border */
1534 width = crumbled_border_size;
1536 cx = (dir == 2 ? TILEX - crumbled_border_size : 0);
1539 else /* top or bottom crumbled border */
1542 height = crumbled_border_size;
1544 cy = (dir == 3 ? TILEY - crumbled_border_size : 0);
1548 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1549 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1551 /* (remaining middle border part must be at least as big as corner part) */
1552 if (!(graphic_info[graphic].style & STYLE_ACCURATE_BORDERS) ||
1553 crumbled_border_size >= TILESIZE / 3)
1556 /* correct corners of crumbled border, if needed */
1559 for (i = -1; i <= 1; i+=2)
1561 int xx = x + (dir == 0 || dir == 3 ? i : 0);
1562 int yy = y + (dir == 1 || dir == 2 ? i : 0);
1563 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1566 /* check if neighbour field is of same crumble type */
1567 if (IS_CRUMBLED_TILE(xx, yy, element) &&
1568 graphic_info[graphic].class ==
1569 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1571 /* no crumbled corner, but continued crumbled border */
1573 int c1 = (dir == 2 || dir == 3 ? TILESIZE - crumbled_border_size : 0);
1574 int c2 = (i == 1 ? TILESIZE - crumbled_border_size : 0);
1575 int b1 = (i == 1 ? crumbled_border_size :
1576 TILESIZE - 2 * crumbled_border_size);
1578 width = crumbled_border_size;
1579 height = crumbled_border_size;
1581 if (dir == 1 || dir == 2)
1596 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
1597 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1601 if (dir == 1 || dir == 2) /* left or right crumbled border */
1603 for (i = -1; i <= 1; i+=2)
1607 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1610 /* check if neighbour field is of same crumble type */
1611 if (IS_CRUMBLED_TILE(xx, yy, element) &&
1612 graphic_info[graphic].class ==
1613 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1615 /* no crumbled corner, but continued crumbled border */
1617 width = crumbled_border_size;
1618 height = crumbled_border_size;
1619 cx = (dir == 2 ? TILEX - crumbled_border_size : 0);
1620 cy = (i == 1 ? TILEY - crumbled_border_size : 0);
1622 by = (i == 1 ? crumbled_border_size :
1623 TILEY - 2 * crumbled_border_size);
1625 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
1626 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1630 else /* top or bottom crumbled border */
1632 for (i = -1; i <= 1; i+=2)
1636 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1639 /* check if neighbour field is of same crumble type */
1640 if (IS_CRUMBLED_TILE(xx, yy, element) &&
1641 graphic_info[graphic].class ==
1642 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1644 /* no crumbled corner, but continued crumbled border */
1646 width = crumbled_border_size;
1647 height = crumbled_border_size;
1648 cx = (i == 1 ? TILEX - crumbled_border_size : 0);
1649 cy = (dir == 3 ? TILEY - crumbled_border_size : 0);
1650 bx = (i == 1 ? crumbled_border_size :
1651 TILEX - 2 * crumbled_border_size);
1654 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
1655 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1662 static void DrawLevelFieldCrumbledExt(int x, int y, int graphic, int frame)
1664 int sx = SCREENX(x), sy = SCREENY(y);
1667 static int xy[4][2] =
1675 if (!IN_LEV_FIELD(x, y))
1678 element = TILE_GFX_ELEMENT(x, y);
1680 /* crumble field itself */
1681 if (IS_CRUMBLED_TILE(x, y, element))
1683 if (!IN_SCR_FIELD(sx, sy))
1686 for (i = 0; i < 4; i++)
1688 int xx = x + xy[i][0];
1689 int yy = y + xy[i][1];
1691 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1694 /* check if neighbour field is of same crumble type */
1696 if (IS_CRUMBLED_TILE(xx, yy, element) &&
1697 graphic_info[graphic].class ==
1698 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1701 if (IS_CRUMBLED_TILE(xx, yy, element))
1705 DrawLevelFieldCrumbledBorders(x, y, graphic, frame, i);
1708 if ((graphic_info[graphic].style & STYLE_INNER_CORNERS) &&
1709 graphic_info[graphic].anim_frames == 2)
1711 for (i = 0; i < 4; i++)
1713 int dx = (i & 1 ? +1 : -1);
1714 int dy = (i & 2 ? +1 : -1);
1716 DrawLevelFieldCrumbledInnerCorners(x, y, dx, dy, graphic);
1720 MarkTileDirty(sx, sy);
1722 else /* center field not crumbled -- crumble neighbour fields */
1724 for (i = 0; i < 4; i++)
1726 int xx = x + xy[i][0];
1727 int yy = y + xy[i][1];
1728 int sxx = sx + xy[i][0];
1729 int syy = sy + xy[i][1];
1731 if (!IN_LEV_FIELD(xx, yy) ||
1732 !IN_SCR_FIELD(sxx, syy))
1735 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
1738 element = TILE_GFX_ELEMENT(xx, yy);
1740 if (!IS_CRUMBLED_TILE(xx, yy, element))
1743 graphic = el_act2crm(element, ACTION_DEFAULT);
1745 DrawLevelFieldCrumbledBorders(xx, yy, graphic, 0, 3 - i);
1747 MarkTileDirty(sxx, syy);
1752 void DrawLevelFieldCrumbled(int x, int y)
1756 if (!IN_LEV_FIELD(x, y))
1760 /* !!! CHECK THIS !!! */
1763 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1764 GFX_CRUMBLED(GfxElement[x][y]))
1767 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1768 GfxElement[x][y] != EL_UNDEFINED &&
1769 GFX_CRUMBLED(GfxElement[x][y]))
1771 DrawLevelFieldCrumbledDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
1778 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
1780 graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
1783 DrawLevelFieldCrumbledExt(x, y, graphic, 0);
1786 void DrawLevelFieldCrumbledDigging(int x, int y, int direction,
1789 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1790 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1791 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1792 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1793 int sx = SCREENX(x), sy = SCREENY(y);
1795 DrawGraphic(sx, sy, graphic1, frame1);
1796 DrawLevelFieldCrumbledExt(x, y, graphic2, frame2);
1799 void DrawLevelFieldCrumbledNeighbours(int x, int y)
1801 int sx = SCREENX(x), sy = SCREENY(y);
1802 static int xy[4][2] =
1811 for (i = 0; i < 4; i++)
1813 int xx = x + xy[i][0];
1814 int yy = y + xy[i][1];
1815 int sxx = sx + xy[i][0];
1816 int syy = sy + xy[i][1];
1818 if (!IN_LEV_FIELD(xx, yy) ||
1819 !IN_SCR_FIELD(sxx, syy) ||
1820 !GFX_CRUMBLED(Feld[xx][yy]) ||
1824 DrawLevelField(xx, yy);
1828 static int getBorderElement(int x, int y)
1832 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1833 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1834 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1835 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1836 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1837 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1838 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1840 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1841 int steel_position = (x == -1 && y == -1 ? 0 :
1842 x == lev_fieldx && y == -1 ? 1 :
1843 x == -1 && y == lev_fieldy ? 2 :
1844 x == lev_fieldx && y == lev_fieldy ? 3 :
1845 x == -1 || x == lev_fieldx ? 4 :
1846 y == -1 || y == lev_fieldy ? 5 : 6);
1848 return border[steel_position][steel_type];
1851 void DrawScreenElement(int x, int y, int element)
1853 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1854 DrawLevelFieldCrumbled(LEVELX(x), LEVELY(y));
1857 void DrawLevelElement(int x, int y, int element)
1859 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1860 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1863 void DrawScreenField(int x, int y)
1865 int lx = LEVELX(x), ly = LEVELY(y);
1866 int element, content;
1868 if (!IN_LEV_FIELD(lx, ly))
1870 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1873 element = getBorderElement(lx, ly);
1875 DrawScreenElement(x, y, element);
1880 element = Feld[lx][ly];
1881 content = Store[lx][ly];
1883 if (IS_MOVING(lx, ly))
1885 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1886 boolean cut_mode = NO_CUTTING;
1888 if (element == EL_QUICKSAND_EMPTYING ||
1889 element == EL_QUICKSAND_FAST_EMPTYING ||
1890 element == EL_MAGIC_WALL_EMPTYING ||
1891 element == EL_BD_MAGIC_WALL_EMPTYING ||
1892 element == EL_DC_MAGIC_WALL_EMPTYING ||
1893 element == EL_AMOEBA_DROPPING)
1894 cut_mode = CUT_ABOVE;
1895 else if (element == EL_QUICKSAND_FILLING ||
1896 element == EL_QUICKSAND_FAST_FILLING ||
1897 element == EL_MAGIC_WALL_FILLING ||
1898 element == EL_BD_MAGIC_WALL_FILLING ||
1899 element == EL_DC_MAGIC_WALL_FILLING)
1900 cut_mode = CUT_BELOW;
1903 if (lx == 9 && ly == 1)
1904 printf("::: %s [%d] [%d, %d] [%d]\n",
1905 EL_NAME(TILE_GFX_ELEMENT(lx, ly)),
1906 el_act2crm(TILE_GFX_ELEMENT(lx, ly), ACTION_DEFAULT),
1907 element_info[EL_QUICKSAND_EMPTYING].graphic[ACTION_DEFAULT],
1908 element_info[EL_QUICKSAND_EMPTYING].crumbled[ACTION_DEFAULT],
1909 GFX_CRUMBLED(TILE_GFX_ELEMENT(lx, ly)));
1912 if (cut_mode == CUT_ABOVE)
1914 DrawScreenElement(x, y, element);
1916 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1919 DrawScreenElement(x, y, EL_EMPTY);
1922 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1923 else if (cut_mode == NO_CUTTING)
1924 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1927 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1930 if (cut_mode == CUT_BELOW &&
1931 IN_LEV_FIELD(lx, ly + 1) && IN_SCR_FIELD(x, y + 1))
1932 DrawLevelElement(lx, ly + 1, element);
1936 if (content == EL_ACID)
1938 int dir = MovDir[lx][ly];
1939 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
1940 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
1942 DrawLevelElementThruMask(newlx, newly, EL_ACID);
1945 else if (IS_BLOCKED(lx, ly))
1950 boolean cut_mode = NO_CUTTING;
1951 int element_old, content_old;
1953 Blocked2Moving(lx, ly, &oldx, &oldy);
1956 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1957 MovDir[oldx][oldy] == MV_RIGHT);
1959 element_old = Feld[oldx][oldy];
1960 content_old = Store[oldx][oldy];
1962 if (element_old == EL_QUICKSAND_EMPTYING ||
1963 element_old == EL_QUICKSAND_FAST_EMPTYING ||
1964 element_old == EL_MAGIC_WALL_EMPTYING ||
1965 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1966 element_old == EL_DC_MAGIC_WALL_EMPTYING ||
1967 element_old == EL_AMOEBA_DROPPING)
1968 cut_mode = CUT_ABOVE;
1970 DrawScreenElement(x, y, EL_EMPTY);
1973 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1975 else if (cut_mode == NO_CUTTING)
1976 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1979 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1982 else if (IS_DRAWABLE(element))
1983 DrawScreenElement(x, y, element);
1985 DrawScreenElement(x, y, EL_EMPTY);
1988 void DrawLevelField(int x, int y)
1990 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1991 DrawScreenField(SCREENX(x), SCREENY(y));
1992 else if (IS_MOVING(x, y))
1996 Moving2Blocked(x, y, &newx, &newy);
1997 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1998 DrawScreenField(SCREENX(newx), SCREENY(newy));
2000 else if (IS_BLOCKED(x, y))
2004 Blocked2Moving(x, y, &oldx, &oldy);
2005 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
2006 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
2010 void DrawMiniElement(int x, int y, int element)
2014 graphic = el2edimg(element);
2015 DrawMiniGraphic(x, y, graphic);
2018 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
2020 int x = sx + scroll_x, y = sy + scroll_y;
2022 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
2023 DrawMiniElement(sx, sy, EL_EMPTY);
2024 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
2025 DrawMiniElement(sx, sy, Feld[x][y]);
2027 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
2030 void DrawEnvelopeBackground(int envelope_nr, int startx, int starty,
2031 int x, int y, int xsize, int ysize, int font_nr)
2033 int font_width = getFontWidth(font_nr);
2034 int font_height = getFontHeight(font_nr);
2035 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2038 int dst_x = SX + startx + x * font_width;
2039 int dst_y = SY + starty + y * font_height;
2040 int width = graphic_info[graphic].width;
2041 int height = graphic_info[graphic].height;
2042 int inner_width = MAX(width - 2 * font_width, font_width);
2043 int inner_height = MAX(height - 2 * font_height, font_height);
2044 int inner_sx = (width >= 3 * font_width ? font_width : 0);
2045 int inner_sy = (height >= 3 * font_height ? font_height : 0);
2046 boolean draw_masked = graphic_info[graphic].draw_masked;
2048 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
2050 if (src_bitmap == NULL || width < font_width || height < font_height)
2052 ClearRectangle(drawto, dst_x, dst_y, font_width, font_height);
2056 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - font_width :
2057 inner_sx + (x - 1) * font_width % inner_width);
2058 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - font_height :
2059 inner_sy + (y - 1) * font_height % inner_height);
2063 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
2064 dst_x - src_x, dst_y - src_y);
2065 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, font_width, font_height,
2069 BlitBitmap(src_bitmap, drawto, src_x, src_y, font_width, font_height,
2073 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
2075 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2076 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2077 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2078 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2079 boolean no_delay = (tape.warp_forward);
2080 unsigned long anim_delay = 0;
2081 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
2082 int anim_delay_value = (no_delay ? 0 : frame_delay_value);
2083 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
2084 int font_width = getFontWidth(font_nr);
2085 int font_height = getFontHeight(font_nr);
2086 int max_xsize = level.envelope[envelope_nr].xsize;
2087 int max_ysize = level.envelope[envelope_nr].ysize;
2088 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
2089 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
2090 int xend = max_xsize;
2091 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
2092 int xstep = (xstart < xend ? 1 : 0);
2093 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2096 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
2098 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2099 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2100 int sx = (SXSIZE - xsize * font_width) / 2;
2101 int sy = (SYSIZE - ysize * font_height) / 2;
2104 SetDrawtoField(DRAW_BUFFERED);
2106 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
2108 SetDrawtoField(DRAW_BACKBUFFER);
2110 for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++)
2111 DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
2114 DrawTextBuffer(SX + sx + font_width, SY + sy + font_height,
2115 level.envelope[envelope_nr].text, font_nr, max_xsize,
2116 xsize - 2, ysize - 2, 0, mask_mode,
2117 level.envelope[envelope_nr].autowrap,
2118 level.envelope[envelope_nr].centered, FALSE);
2120 DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
2121 level.envelope[envelope_nr].text, font_nr, max_xsize,
2122 xsize - 2, ysize - 2, mask_mode);
2125 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2128 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
2132 void AnimateEnvelopeDoor(char *text, int anim_mode, int action)
2135 int envelope_nr = 0;
2137 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2138 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2139 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2140 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2141 boolean no_delay = (tape.warp_forward);
2142 unsigned long anim_delay = 0;
2143 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
2144 int anim_delay_value = (no_delay ? 0 : frame_delay_value);
2146 int max_word_len = maxWordLengthInString(text);
2147 int font_nr = (max_word_len > 7 ? FONT_TEXT_1 : FONT_TEXT_2);
2149 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
2151 int font_width = getFontWidth(font_nr);
2152 int font_height = getFontHeight(font_nr);
2156 int max_xsize = DXSIZE / font_width;
2157 int max_ysize = DYSIZE / font_height;
2159 int max_xsize = 7; /* tools.c: MAX_REQUEST_LINE_FONT1_LEN == 7 */
2160 int max_ysize = 13; /* tools.c: MAX_REQUEST_LINES == 13 */
2164 int max_xsize = level.envelope[envelope_nr].xsize;
2165 int max_ysize = level.envelope[envelope_nr].ysize;
2167 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
2168 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
2169 int xend = max_xsize;
2170 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
2171 int xstep = (xstart < xend ? 1 : 0);
2172 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2177 char *text_copy = getStringCopy(text);
2180 font_nr = FONT_TEXT_2;
2182 if (maxWordLengthInString(text) > 7) /* MAX_REQUEST_LINE_FONT1_LEN == 7 */
2184 max_xsize = 10; /* tools.c: MAX_REQUEST_LINE_FONT2_LEN == 10 */
2185 font_nr = FONT_TEXT_1;
2188 int max_word_len = 0;
2190 char *text_copy = getStringCopy(text);
2192 font_nr = FONT_TEXT_2;
2194 for (text_ptr = text; *text_ptr; text_ptr++)
2196 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
2198 if (max_word_len > 7) /* tools.c: MAX_REQUEST_LINE_FONT1_LEN == 7 */
2200 max_xsize = 10; /* tools.c: MAX_REQUEST_LINE_FONT2_LEN == 10 */
2201 font_nr = FONT_TEXT_1;
2210 for (text_ptr = text_copy; *text_ptr; text_ptr++)
2211 if (*text_ptr == ' ')
2216 dDX = SX + (SXSIZE - DXSIZE) / 2 - DX;
2217 dDY = SY + (SYSIZE - DYSIZE) / 2 - DY;
2219 dDX = SX + SXSIZE / 2 - max_xsize * font_width / 2 - DX;
2220 dDY = SY + SYSIZE / 2 - max_ysize * font_height / 2 - DY;
2223 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
2225 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2226 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2227 int sx = (SXSIZE - xsize * font_width) / 2;
2228 int sy = (SYSIZE - ysize * font_height) / 2;
2232 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2234 SetDrawtoField(DRAW_BUFFERED);
2236 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
2238 SetDrawtoField(DRAW_BACKBUFFER);
2241 for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++)
2242 DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
2247 DrawTextBuffer(SX + sx + font_width, SY + sy + font_height + 8,
2248 text_copy, font_nr, max_xsize,
2249 xsize - 2, ysize - 2, 2, mask_mode,
2250 FALSE, TRUE, FALSE);
2252 DrawTextBuffer(SX + sx + font_width, SY + sy + font_height,
2253 level.envelope[envelope_nr].text, font_nr, max_xsize,
2254 xsize - 2, ysize - 2, 0, mask_mode,
2255 level.envelope[envelope_nr].autowrap,
2256 level.envelope[envelope_nr].centered, FALSE);
2260 DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
2261 level.envelope[envelope_nr].text, font_nr, max_xsize,
2262 xsize - 2, ysize - 2, mask_mode);
2265 /* copy request gadgets to door backbuffer */
2267 if ((ysize - 2) > 13)
2268 BlitBitmap(bitmap_db_door, drawto,
2269 DOOR_GFX_PAGEX1 + (DXSIZE - (xsize - 2) * font_width) / 2,
2270 DOOR_GFX_PAGEY1 + 13 * font_height,
2271 (xsize - 2) * font_width,
2272 (ysize - 2 - 13) * font_height,
2273 SX + sx + font_width,
2274 SY + sy + font_height * (1 + 13));
2276 if ((ysize - 2) > 13)
2277 BlitBitmap(bitmap_db_door, drawto,
2278 DOOR_GFX_PAGEX1 + (DXSIZE - (xsize - 2) * font_width) / 2,
2279 DOOR_GFX_PAGEY1 + 13 * font_height,
2280 (xsize - 2) * font_width,
2281 (ysize - 2 - 13) * font_height,
2282 SX + sx + font_width,
2283 SY + sy + font_height * (1 + 13));
2287 redraw_mask = REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2288 // redraw_mask |= REDRAW_ALL | REDRAW_FROM_BACKBUFFER;
2290 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2300 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
2308 void ShowEnvelope(int envelope_nr)
2310 int element = EL_ENVELOPE_1 + envelope_nr;
2311 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2312 int sound_opening = element_info[element].sound[ACTION_OPENING];
2313 int sound_closing = element_info[element].sound[ACTION_CLOSING];
2314 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2315 boolean no_delay = (tape.warp_forward);
2316 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
2317 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
2318 int anim_mode = graphic_info[graphic].anim_mode;
2319 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2320 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2322 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
2324 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2326 if (anim_mode == ANIM_DEFAULT)
2327 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
2329 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
2332 Delay(wait_delay_value);
2334 WaitForEventToContinue();
2336 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2338 if (anim_mode != ANIM_NONE)
2339 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
2341 if (anim_mode == ANIM_DEFAULT)
2342 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
2344 game.envelope_active = FALSE;
2346 SetDrawtoField(DRAW_BUFFERED);
2348 redraw_mask |= REDRAW_FIELD;
2352 void ShowEnvelopeDoor(char *text, int action)
2355 int last_game_status = game_status; /* save current game status */
2356 // int last_draw_background_mask = gfx.draw_background_mask;
2357 int envelope_nr = 0;
2359 int element = EL_ENVELOPE_1 + envelope_nr;
2360 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2361 int sound_opening = element_info[element].sound[ACTION_OPENING];
2362 int sound_closing = element_info[element].sound[ACTION_CLOSING];
2364 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2365 boolean no_delay = (tape.warp_forward);
2366 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
2367 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
2369 int anim_mode = graphic_info[graphic].anim_mode;
2370 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2371 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2374 if (game_status == GAME_MODE_PLAYING)
2376 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
2377 BlitScreenToBitmap_EM(backbuffer);
2378 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
2379 BlitScreenToBitmap_SP(backbuffer);
2382 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
2386 SetDrawtoField(DRAW_BACKBUFFER);
2388 // SetDrawBackgroundMask(REDRAW_NONE);
2390 if (action == ACTION_OPENING)
2392 BlitBitmap(backbuffer, bitmap_db_store, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2394 if (game_status != GAME_MODE_MAIN)
2398 /* force DOOR font inside door area */
2399 game_status = GAME_MODE_PSEUDO_DOOR;
2402 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
2404 if (action == ACTION_OPENING)
2406 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2408 if (anim_mode == ANIM_DEFAULT)
2409 AnimateEnvelopeDoor(text, ANIM_DEFAULT, ACTION_OPENING);
2411 AnimateEnvelopeDoor(text, main_anim_mode, ACTION_OPENING);
2415 Delay(wait_delay_value);
2417 WaitForEventToContinue();
2422 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2424 if (anim_mode != ANIM_NONE)
2425 AnimateEnvelopeDoor(text, main_anim_mode, ACTION_CLOSING);
2427 if (anim_mode == ANIM_DEFAULT)
2428 AnimateEnvelopeDoor(text, ANIM_DEFAULT, ACTION_CLOSING);
2431 game.envelope_active = FALSE;
2434 game_status = last_game_status; /* restore current game status */
2436 if (action == ACTION_CLOSING)
2438 if (game_status != GAME_MODE_MAIN)
2441 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2444 SetDrawtoField(DRAW_BUFFERED);
2447 // SetDrawBackgroundMask(last_draw_background_mask);
2450 redraw_mask = REDRAW_FIELD;
2451 // redraw_mask |= REDRAW_ALL;
2453 redraw_mask |= REDRAW_FIELD;
2457 if (game_status == GAME_MODE_MAIN)
2462 if (game_status == GAME_MODE_PLAYING &&
2463 level.game_engine_type == GAME_ENGINE_TYPE_RND)
2464 SetDrawtoField(DRAW_BUFFERED);
2470 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
2474 int graphic = el2preimg(element);
2476 getSizedGraphicSource(graphic, 0, tilesize, &src_bitmap, &src_x, &src_y);
2477 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
2485 SetMainBackgroundImage(IMG_BACKGROUND_PLAYING);
2486 SetDrawBackgroundMask(REDRAW_FIELD);
2488 SetDrawBackgroundMask(REDRAW_NONE);
2493 for (x = BX1; x <= BX2; x++)
2494 for (y = BY1; y <= BY2; y++)
2495 DrawScreenField(x, y);
2497 redraw_mask |= REDRAW_FIELD;
2500 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
2504 for (x = 0; x < size_x; x++)
2505 for (y = 0; y < size_y; y++)
2506 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
2508 redraw_mask |= REDRAW_FIELD;
2511 static void DrawPreviewLevelExt(int from_x, int from_y)
2513 boolean show_level_border = (BorderElement != EL_EMPTY);
2514 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2515 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2516 int tile_size = preview.tile_size;
2517 int preview_width = preview.xsize * tile_size;
2518 int preview_height = preview.ysize * tile_size;
2519 int real_preview_xsize = MIN(level_xsize, preview.xsize);
2520 int real_preview_ysize = MIN(level_ysize, preview.ysize);
2521 int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
2522 int dst_y = SY + ALIGNED_YPOS(preview.y, preview_height, preview.valign);
2525 DrawBackground(dst_x, dst_y, preview_width, preview_height);
2527 dst_x += (preview_width - real_preview_xsize * tile_size) / 2;
2528 dst_y += (preview_height - real_preview_ysize * tile_size) / 2;
2530 for (x = 0; x < real_preview_xsize; x++)
2532 for (y = 0; y < real_preview_ysize; y++)
2534 int lx = from_x + x + (show_level_border ? -1 : 0);
2535 int ly = from_y + y + (show_level_border ? -1 : 0);
2536 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
2537 getBorderElement(lx, ly));
2539 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
2540 element, tile_size);
2544 redraw_mask |= REDRAW_MICROLEVEL;
2547 #define MICROLABEL_EMPTY 0
2548 #define MICROLABEL_LEVEL_NAME 1
2549 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
2550 #define MICROLABEL_LEVEL_AUTHOR 3
2551 #define MICROLABEL_IMPORTED_FROM_HEAD 4
2552 #define MICROLABEL_IMPORTED_FROM 5
2553 #define MICROLABEL_IMPORTED_BY_HEAD 6
2554 #define MICROLABEL_IMPORTED_BY 7
2556 static int getMaxTextLength(struct TextPosInfo *pos, int font_nr)
2558 int max_text_width = SXSIZE;
2559 int font_width = getFontWidth(font_nr);
2561 if (pos->align == ALIGN_CENTER)
2562 max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
2563 else if (pos->align == ALIGN_RIGHT)
2564 max_text_width = pos->x;
2566 max_text_width = SXSIZE - pos->x;
2568 return max_text_width / font_width;
2571 static void DrawPreviewLevelLabelExt(int mode)
2573 struct TextPosInfo *pos = &menu.main.text.level_info_2;
2574 char label_text[MAX_OUTPUT_LINESIZE + 1];
2575 int max_len_label_text;
2577 int font_nr = pos->font;
2580 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
2581 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
2582 mode == MICROLABEL_IMPORTED_BY_HEAD)
2583 font_nr = pos->font_alt;
2585 int font_nr = FONT_TEXT_2;
2588 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
2589 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
2590 mode == MICROLABEL_IMPORTED_BY_HEAD)
2591 font_nr = FONT_TEXT_3;
2595 max_len_label_text = getMaxTextLength(pos, font_nr);
2597 max_len_label_text = SXSIZE / getFontWidth(font_nr);
2601 if (pos->size != -1)
2602 max_len_label_text = pos->size;
2605 for (i = 0; i < max_len_label_text; i++)
2606 label_text[i] = ' ';
2607 label_text[max_len_label_text] = '\0';
2609 if (strlen(label_text) > 0)
2612 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2614 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
2615 int lypos = MICROLABEL2_YPOS;
2617 DrawText(lxpos, lypos, label_text, font_nr);
2622 (mode == MICROLABEL_LEVEL_NAME ? level.name :
2623 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
2624 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
2625 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
2626 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
2627 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
2628 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
2629 max_len_label_text);
2630 label_text[max_len_label_text] = '\0';
2632 if (strlen(label_text) > 0)
2635 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2637 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
2638 int lypos = MICROLABEL2_YPOS;
2640 DrawText(lxpos, lypos, label_text, font_nr);
2644 redraw_mask |= REDRAW_MICROLEVEL;
2647 void DrawPreviewLevel(boolean restart)
2649 static unsigned long scroll_delay = 0;
2650 static unsigned long label_delay = 0;
2651 static int from_x, from_y, scroll_direction;
2652 static int label_state, label_counter;
2653 unsigned long scroll_delay_value = preview.step_delay;
2654 boolean show_level_border = (BorderElement != EL_EMPTY);
2655 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2656 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2657 int last_game_status = game_status; /* save current game status */
2660 /* force PREVIEW font on preview level */
2661 game_status = GAME_MODE_PSEUDO_PREVIEW;
2669 if (preview.anim_mode == ANIM_CENTERED)
2671 if (level_xsize > preview.xsize)
2672 from_x = (level_xsize - preview.xsize) / 2;
2673 if (level_ysize > preview.ysize)
2674 from_y = (level_ysize - preview.ysize) / 2;
2677 from_x += preview.xoffset;
2678 from_y += preview.yoffset;
2680 scroll_direction = MV_RIGHT;
2684 DrawPreviewLevelExt(from_x, from_y);
2685 DrawPreviewLevelLabelExt(label_state);
2687 /* initialize delay counters */
2688 DelayReached(&scroll_delay, 0);
2689 DelayReached(&label_delay, 0);
2691 if (leveldir_current->name)
2693 struct TextPosInfo *pos = &menu.main.text.level_info_1;
2694 char label_text[MAX_OUTPUT_LINESIZE + 1];
2696 int font_nr = pos->font;
2698 int font_nr = FONT_TEXT_1;
2701 int max_len_label_text = getMaxTextLength(pos, font_nr);
2703 int max_len_label_text = SXSIZE / getFontWidth(font_nr);
2711 if (pos->size != -1)
2712 max_len_label_text = pos->size;
2715 strncpy(label_text, leveldir_current->name, max_len_label_text);
2716 label_text[max_len_label_text] = '\0';
2719 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2721 lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
2722 lypos = SY + MICROLABEL1_YPOS;
2724 DrawText(lxpos, lypos, label_text, font_nr);
2728 game_status = last_game_status; /* restore current game status */
2733 /* scroll preview level, if needed */
2734 if (preview.anim_mode != ANIM_NONE &&
2735 (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
2736 DelayReached(&scroll_delay, scroll_delay_value))
2738 switch (scroll_direction)
2743 from_x -= preview.step_offset;
2744 from_x = (from_x < 0 ? 0 : from_x);
2747 scroll_direction = MV_UP;
2751 if (from_x < level_xsize - preview.xsize)
2753 from_x += preview.step_offset;
2754 from_x = (from_x > level_xsize - preview.xsize ?
2755 level_xsize - preview.xsize : from_x);
2758 scroll_direction = MV_DOWN;
2764 from_y -= preview.step_offset;
2765 from_y = (from_y < 0 ? 0 : from_y);
2768 scroll_direction = MV_RIGHT;
2772 if (from_y < level_ysize - preview.ysize)
2774 from_y += preview.step_offset;
2775 from_y = (from_y > level_ysize - preview.ysize ?
2776 level_ysize - preview.ysize : from_y);
2779 scroll_direction = MV_LEFT;
2786 DrawPreviewLevelExt(from_x, from_y);
2789 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
2790 /* redraw micro level label, if needed */
2791 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
2792 !strEqual(level.author, ANONYMOUS_NAME) &&
2793 !strEqual(level.author, leveldir_current->name) &&
2794 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
2796 int max_label_counter = 23;
2798 if (leveldir_current->imported_from != NULL &&
2799 strlen(leveldir_current->imported_from) > 0)
2800 max_label_counter += 14;
2801 if (leveldir_current->imported_by != NULL &&
2802 strlen(leveldir_current->imported_by) > 0)
2803 max_label_counter += 14;
2805 label_counter = (label_counter + 1) % max_label_counter;
2806 label_state = (label_counter >= 0 && label_counter <= 7 ?
2807 MICROLABEL_LEVEL_NAME :
2808 label_counter >= 9 && label_counter <= 12 ?
2809 MICROLABEL_LEVEL_AUTHOR_HEAD :
2810 label_counter >= 14 && label_counter <= 21 ?
2811 MICROLABEL_LEVEL_AUTHOR :
2812 label_counter >= 23 && label_counter <= 26 ?
2813 MICROLABEL_IMPORTED_FROM_HEAD :
2814 label_counter >= 28 && label_counter <= 35 ?
2815 MICROLABEL_IMPORTED_FROM :
2816 label_counter >= 37 && label_counter <= 40 ?
2817 MICROLABEL_IMPORTED_BY_HEAD :
2818 label_counter >= 42 && label_counter <= 49 ?
2819 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
2821 if (leveldir_current->imported_from == NULL &&
2822 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
2823 label_state == MICROLABEL_IMPORTED_FROM))
2824 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
2825 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
2827 DrawPreviewLevelLabelExt(label_state);
2830 game_status = last_game_status; /* restore current game status */
2833 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
2834 int graphic, int sync_frame, int mask_mode)
2836 int frame = getGraphicAnimationFrame(graphic, sync_frame);
2838 if (mask_mode == USE_MASKING)
2839 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
2841 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
2844 inline void DrawGraphicAnimation(int x, int y, int graphic)
2846 int lx = LEVELX(x), ly = LEVELY(y);
2848 if (!IN_SCR_FIELD(x, y))
2851 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
2852 graphic, GfxFrame[lx][ly], NO_MASKING);
2853 MarkTileDirty(x, y);
2856 void DrawLevelGraphicAnimation(int x, int y, int graphic)
2858 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2861 void DrawLevelElementAnimation(int x, int y, int element)
2863 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2865 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2868 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
2870 int sx = SCREENX(x), sy = SCREENY(y);
2872 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2875 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2878 DrawGraphicAnimation(sx, sy, graphic);
2881 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
2882 DrawLevelFieldCrumbled(x, y);
2884 if (GFX_CRUMBLED(Feld[x][y]))
2885 DrawLevelFieldCrumbled(x, y);
2889 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
2891 int sx = SCREENX(x), sy = SCREENY(y);
2894 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2897 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2899 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2902 DrawGraphicAnimation(sx, sy, graphic);
2904 if (GFX_CRUMBLED(element))
2905 DrawLevelFieldCrumbled(x, y);
2908 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
2910 if (player->use_murphy)
2912 /* this works only because currently only one player can be "murphy" ... */
2913 static int last_horizontal_dir = MV_LEFT;
2914 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
2916 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2917 last_horizontal_dir = move_dir;
2919 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
2921 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
2923 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
2929 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
2932 static boolean equalGraphics(int graphic1, int graphic2)
2934 struct GraphicInfo *g1 = &graphic_info[graphic1];
2935 struct GraphicInfo *g2 = &graphic_info[graphic2];
2937 return (g1->bitmap == g2->bitmap &&
2938 g1->src_x == g2->src_x &&
2939 g1->src_y == g2->src_y &&
2940 g1->anim_frames == g2->anim_frames &&
2941 g1->anim_delay == g2->anim_delay &&
2942 g1->anim_mode == g2->anim_mode);
2945 void DrawAllPlayers()
2949 for (i = 0; i < MAX_PLAYERS; i++)
2950 if (stored_player[i].active)
2951 DrawPlayer(&stored_player[i]);
2954 void DrawPlayerField(int x, int y)
2956 if (!IS_PLAYER(x, y))
2959 DrawPlayer(PLAYERINFO(x, y));
2962 #define DRAW_PLAYER_OVER_PUSHED_ELEMENT 1
2964 void DrawPlayer(struct PlayerInfo *player)
2966 int jx = player->jx;
2967 int jy = player->jy;
2968 int move_dir = player->MovDir;
2969 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
2970 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
2971 int last_jx = (player->is_moving ? jx - dx : jx);
2972 int last_jy = (player->is_moving ? jy - dy : jy);
2973 int next_jx = jx + dx;
2974 int next_jy = jy + dy;
2975 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
2976 boolean player_is_opaque = FALSE;
2977 int sx = SCREENX(jx), sy = SCREENY(jy);
2978 int sxx = 0, syy = 0;
2979 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
2981 int action = ACTION_DEFAULT;
2982 int last_player_graphic = getPlayerGraphic(player, move_dir);
2983 int last_player_frame = player->Frame;
2986 /* GfxElement[][] is set to the element the player is digging or collecting;
2987 remove also for off-screen player if the player is not moving anymore */
2988 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
2989 GfxElement[jx][jy] = EL_UNDEFINED;
2991 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
2995 if (!IN_LEV_FIELD(jx, jy))
2997 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
2998 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
2999 printf("DrawPlayerField(): This should never happen!\n");
3004 if (element == EL_EXPLOSION)
3007 action = (player->is_pushing ? ACTION_PUSHING :
3008 player->is_digging ? ACTION_DIGGING :
3009 player->is_collecting ? ACTION_COLLECTING :
3010 player->is_moving ? ACTION_MOVING :
3011 player->is_snapping ? ACTION_SNAPPING :
3012 player->is_dropping ? ACTION_DROPPING :
3013 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
3015 if (player->is_waiting)
3016 move_dir = player->dir_waiting;
3018 InitPlayerGfxAnimation(player, action, move_dir);
3020 /* ----------------------------------------------------------------------- */
3021 /* draw things in the field the player is leaving, if needed */
3022 /* ----------------------------------------------------------------------- */
3024 if (player->is_moving)
3026 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
3028 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
3030 if (last_element == EL_DYNAMITE_ACTIVE ||
3031 last_element == EL_EM_DYNAMITE_ACTIVE ||
3032 last_element == EL_SP_DISK_RED_ACTIVE)
3033 DrawDynamite(last_jx, last_jy);
3035 DrawLevelFieldThruMask(last_jx, last_jy);
3037 else if (last_element == EL_DYNAMITE_ACTIVE ||
3038 last_element == EL_EM_DYNAMITE_ACTIVE ||
3039 last_element == EL_SP_DISK_RED_ACTIVE)
3040 DrawDynamite(last_jx, last_jy);
3042 /* !!! this is not enough to prevent flickering of players which are
3043 moving next to each others without a free tile between them -- this
3044 can only be solved by drawing all players layer by layer (first the
3045 background, then the foreground etc.) !!! => TODO */
3046 else if (!IS_PLAYER(last_jx, last_jy))
3047 DrawLevelField(last_jx, last_jy);
3050 DrawLevelField(last_jx, last_jy);
3053 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
3054 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
3057 if (!IN_SCR_FIELD(sx, sy))
3060 /* ----------------------------------------------------------------------- */
3061 /* draw things behind the player, if needed */
3062 /* ----------------------------------------------------------------------- */
3065 DrawLevelElement(jx, jy, Back[jx][jy]);
3066 else if (IS_ACTIVE_BOMB(element))
3067 DrawLevelElement(jx, jy, EL_EMPTY);
3070 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
3072 int old_element = GfxElement[jx][jy];
3073 int old_graphic = el_act_dir2img(old_element, action, move_dir);
3074 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
3076 if (GFX_CRUMBLED(old_element))
3077 DrawLevelFieldCrumbledDigging(jx, jy, move_dir, player->StepFrame);
3079 DrawGraphic(sx, sy, old_graphic, frame);
3081 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
3082 player_is_opaque = TRUE;
3086 GfxElement[jx][jy] = EL_UNDEFINED;
3088 /* make sure that pushed elements are drawn with correct frame rate */
3090 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
3092 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
3093 GfxFrame[jx][jy] = player->StepFrame;
3095 if (player->is_pushing && player->is_moving)
3096 GfxFrame[jx][jy] = player->StepFrame;
3099 DrawLevelField(jx, jy);
3103 #if !DRAW_PLAYER_OVER_PUSHED_ELEMENT
3104 /* ----------------------------------------------------------------------- */
3105 /* draw player himself */
3106 /* ----------------------------------------------------------------------- */
3108 graphic = getPlayerGraphic(player, move_dir);
3110 /* in the case of changed player action or direction, prevent the current
3111 animation frame from being restarted for identical animations */
3112 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
3113 player->Frame = last_player_frame;
3115 frame = getGraphicAnimationFrame(graphic, player->Frame);
3119 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3120 sxx = player->GfxPos;
3122 syy = player->GfxPos;
3125 if (!setup.soft_scrolling && ScreenMovPos)
3128 if (player_is_opaque)
3129 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
3131 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3133 if (SHIELD_ON(player))
3135 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
3136 IMG_SHIELD_NORMAL_ACTIVE);
3137 int frame = getGraphicAnimationFrame(graphic, -1);
3139 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3143 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
3146 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3147 sxx = player->GfxPos;
3149 syy = player->GfxPos;
3153 /* ----------------------------------------------------------------------- */
3154 /* draw things the player is pushing, if needed */
3155 /* ----------------------------------------------------------------------- */
3158 printf("::: %d, %d [%d, %d] [%d]\n",
3159 player->is_pushing, player_is_moving, player->GfxAction,
3160 player->is_moving, player_is_moving);
3164 if (player->is_pushing && player->is_moving)
3166 int px = SCREENX(jx), py = SCREENY(jy);
3167 int pxx = (TILEX - ABS(sxx)) * dx;
3168 int pyy = (TILEY - ABS(syy)) * dy;
3169 int gfx_frame = GfxFrame[jx][jy];
3175 if (!IS_MOVING(jx, jy)) /* push movement already finished */
3177 element = Feld[next_jx][next_jy];
3178 gfx_frame = GfxFrame[next_jx][next_jy];
3181 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
3184 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
3185 frame = getGraphicAnimationFrame(graphic, sync_frame);
3187 frame = getGraphicAnimationFrame(graphic, player->StepFrame);
3190 /* draw background element under pushed element (like the Sokoban field) */
3192 if (game.use_masked_pushing && IS_MOVING(jx, jy))
3194 /* this allows transparent pushing animation over non-black background */
3197 DrawLevelElement(jx, jy, Back[jx][jy]);
3199 DrawLevelElement(jx, jy, EL_EMPTY);
3201 if (Back[next_jx][next_jy])
3202 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3204 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
3206 else if (Back[next_jx][next_jy])
3207 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3209 if (Back[next_jx][next_jy])
3210 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3214 printf("::: %d, %d, %d, %d [%d] [%d, %d, %d] [%d] [%d, %d] [%d, %d]\n",
3215 jx, px, player->GfxPos, player->StepFrame,
3220 GfxFrame[jx][jy], GfxFrame[next_jx][next_jy]);
3224 /* do not draw (EM style) pushing animation when pushing is finished */
3225 /* (two-tile animations usually do not contain start and end frame) */
3226 if (graphic_info[graphic].double_movement && !IS_MOVING(jx, jy))
3227 DrawLevelElement(next_jx, next_jy, Feld[next_jx][next_jy]);
3229 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3231 /* masked drawing is needed for EMC style (double) movement graphics */
3232 /* !!! (ONLY WHEN DRAWING PUSHED ELEMENT OVER THE PLAYER) !!! */
3233 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3238 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
3239 /* ----------------------------------------------------------------------- */
3240 /* draw player himself */
3241 /* ----------------------------------------------------------------------- */
3243 graphic = getPlayerGraphic(player, move_dir);
3245 /* in the case of changed player action or direction, prevent the current
3246 animation frame from being restarted for identical animations */
3247 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
3248 player->Frame = last_player_frame;
3250 frame = getGraphicAnimationFrame(graphic, player->Frame);
3254 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3255 sxx = player->GfxPos;
3257 syy = player->GfxPos;
3260 if (!setup.soft_scrolling && ScreenMovPos)
3263 if (player_is_opaque)
3264 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
3266 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3268 if (SHIELD_ON(player))
3270 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
3271 IMG_SHIELD_NORMAL_ACTIVE);
3272 int frame = getGraphicAnimationFrame(graphic, -1);
3274 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3278 /* ----------------------------------------------------------------------- */
3279 /* draw things in front of player (active dynamite or dynabombs) */
3280 /* ----------------------------------------------------------------------- */
3282 if (IS_ACTIVE_BOMB(element))
3284 graphic = el2img(element);
3285 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
3287 if (game.emulation == EMU_SUPAPLEX)
3288 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
3290 DrawGraphicThruMask(sx, sy, graphic, frame);
3293 if (player_is_moving && last_element == EL_EXPLOSION)
3295 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
3296 GfxElement[last_jx][last_jy] : EL_EMPTY);
3297 int graphic = el_act2img(element, ACTION_EXPLODING);
3298 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
3299 int phase = ExplodePhase[last_jx][last_jy] - 1;
3300 int frame = getGraphicAnimationFrame(graphic, phase - delay);
3303 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
3306 /* ----------------------------------------------------------------------- */
3307 /* draw elements the player is just walking/passing through/under */
3308 /* ----------------------------------------------------------------------- */
3310 if (player_is_moving)
3312 /* handle the field the player is leaving ... */
3313 if (IS_ACCESSIBLE_INSIDE(last_element))
3314 DrawLevelField(last_jx, last_jy);
3315 else if (IS_ACCESSIBLE_UNDER(last_element))
3316 DrawLevelFieldThruMask(last_jx, last_jy);
3319 /* do not redraw accessible elements if the player is just pushing them */
3320 if (!player_is_moving || !player->is_pushing)
3322 /* ... and the field the player is entering */
3323 if (IS_ACCESSIBLE_INSIDE(element))
3324 DrawLevelField(jx, jy);
3325 else if (IS_ACCESSIBLE_UNDER(element))
3326 DrawLevelFieldThruMask(jx, jy);
3329 MarkTileDirty(sx, sy);
3332 /* ------------------------------------------------------------------------- */
3334 void WaitForEventToContinue()
3336 boolean still_wait = TRUE;
3338 /* simulate releasing mouse button over last gadget, if still pressed */
3340 HandleGadgets(-1, -1, 0);
3342 button_status = MB_RELEASED;
3358 case EVENT_BUTTONPRESS:
3359 case EVENT_KEYPRESS:
3363 case EVENT_KEYRELEASE:
3364 ClearPlayerAction();
3368 HandleOtherEvents(&event);
3372 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3379 /* don't eat all CPU time */
3384 #define MAX_REQUEST_LINES 13
3385 #define MAX_REQUEST_LINE_FONT1_LEN 7
3386 #define MAX_REQUEST_LINE_FONT2_LEN 10
3388 boolean Request(char *text, unsigned int req_state)
3390 int mx, my, ty, result = -1;
3391 unsigned int old_door_state;
3392 int last_game_status = game_status; /* save current game status */
3393 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
3394 int font_nr = FONT_TEXT_2;
3395 boolean use_envelope_request = TRUE * 0;
3397 int max_word_len = 0;
3403 if (maxWordLengthInString(text) > MAX_REQUEST_LINE_FONT1_LEN)
3405 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
3406 font_nr = FONT_TEXT_1;
3409 for (text_ptr = text; *text_ptr; text_ptr++)
3411 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
3413 if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
3415 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
3417 font_nr = FONT_TEXT_1;
3419 font_nr = FONT_LEVEL_NUMBER;
3427 if (game_status == GAME_MODE_PLAYING)
3429 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
3430 BlitScreenToBitmap_EM(backbuffer);
3431 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
3432 BlitScreenToBitmap_SP(backbuffer);
3435 /* disable deactivated drawing when quick-loading level tape recording */
3436 if (tape.playing && tape.deactivate_display)
3437 TapeDeactivateDisplayOff(TRUE);
3439 SetMouseCursor(CURSOR_DEFAULT);
3441 #if defined(NETWORK_AVALIABLE)
3442 /* pause network game while waiting for request to answer */
3443 if (options.network &&
3444 game_status == GAME_MODE_PLAYING &&
3445 req_state & REQUEST_WAIT_FOR_INPUT)
3446 SendToServer_PausePlaying();
3449 old_door_state = GetDoorState();
3451 /* simulate releasing mouse button over last gadget, if still pressed */
3453 HandleGadgets(-1, -1, 0);
3458 if (old_door_state & DOOR_OPEN_1 && !use_envelope_request)
3460 if (old_door_state & DOOR_OPEN_1)
3463 CloseDoor(DOOR_CLOSE_1);
3465 /* save old door content */
3466 BlitBitmap(bitmap_db_door, bitmap_db_door,
3467 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
3468 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
3472 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
3475 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3477 /* clear door drawing field */
3478 DrawBackground(DX, DY, DXSIZE, DYSIZE);
3480 /* force DOOR font inside door area */
3481 game_status = GAME_MODE_PSEUDO_DOOR;
3483 /* write text for request */
3484 for (text_ptr = text, ty = 0; ty < MAX_REQUEST_LINES; ty++)
3486 char text_line[max_request_line_len + 1];
3492 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
3494 tc = *(text_ptr + tx);
3495 if (!tc || tc == ' ')
3506 strncpy(text_line, text_ptr, tl);
3509 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
3510 DY + 8 + ty * (getFontHeight(font_nr) + 2),
3511 text_line, font_nr);
3513 text_ptr += tl + (tc == ' ' ? 1 : 0);
3516 game_status = last_game_status; /* restore current game status */
3519 if (use_envelope_request)
3523 CreateToolButtons();
3527 if (req_state & REQ_ASK)
3529 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
3530 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
3532 else if (req_state & REQ_CONFIRM)
3534 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
3536 else if (req_state & REQ_PLAYER)
3538 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
3539 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
3540 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
3541 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
3544 /* copy request gadgets to door backbuffer */
3545 BlitBitmap(drawto, bitmap_db_door,
3546 DX, DY, DXSIZE, DYSIZE,
3547 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
3550 if (use_envelope_request)
3552 ShowEnvelopeDoor(text, ACTION_OPENING);
3554 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3556 if ((req_state & REQ_ASK && (i == TOOL_CTRL_ID_YES ||
3557 i == TOOL_CTRL_ID_NO)) ||
3558 (req_state & REQ_CONFIRM && i == TOOL_CTRL_ID_CONFIRM) ||
3559 (req_state & REQ_PLAYER && (i == TOOL_CTRL_ID_PLAYER_1 &&
3560 i == TOOL_CTRL_ID_PLAYER_2 &&
3561 i == TOOL_CTRL_ID_PLAYER_3 &&
3562 i == TOOL_CTRL_ID_PLAYER_4)))
3564 int x = tool_gadget[i]->x + dDX;
3565 int y = tool_gadget[i]->y + dDY;
3567 ModifyGadget(tool_gadget[i], GDI_X, x, GDI_Y, y, GDI_END);
3574 if (!use_envelope_request)
3575 OpenDoor(DOOR_OPEN_1);
3577 OpenDoor(DOOR_OPEN_1);
3580 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
3582 if (game_status == GAME_MODE_PLAYING)
3584 SetPanelBackground();
3585 SetDrawBackgroundMask(REDRAW_DOOR_1);
3589 SetDrawBackgroundMask(REDRAW_FIELD);
3596 if (game_status != GAME_MODE_MAIN && !use_envelope_request)
3599 if (game_status != GAME_MODE_MAIN)
3603 button_status = MB_RELEASED;
3605 request_gadget_id = -1;
3607 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3619 case EVENT_BUTTONPRESS:
3620 case EVENT_BUTTONRELEASE:
3621 case EVENT_MOTIONNOTIFY:
3623 if (event.type == EVENT_MOTIONNOTIFY)
3625 if (!PointerInWindow(window))
3626 continue; /* window and pointer are on different screens */
3631 motion_status = TRUE;
3632 mx = ((MotionEvent *) &event)->x;
3633 my = ((MotionEvent *) &event)->y;
3637 motion_status = FALSE;
3638 mx = ((ButtonEvent *) &event)->x;
3639 my = ((ButtonEvent *) &event)->y;
3640 if (event.type == EVENT_BUTTONPRESS)
3641 button_status = ((ButtonEvent *) &event)->button;
3643 button_status = MB_RELEASED;
3646 /* this sets 'request_gadget_id' */
3647 HandleGadgets(mx, my, button_status);
3649 switch (request_gadget_id)
3651 case TOOL_CTRL_ID_YES:
3654 case TOOL_CTRL_ID_NO:
3657 case TOOL_CTRL_ID_CONFIRM:
3658 result = TRUE | FALSE;
3661 case TOOL_CTRL_ID_PLAYER_1:
3664 case TOOL_CTRL_ID_PLAYER_2:
3667 case TOOL_CTRL_ID_PLAYER_3:
3670 case TOOL_CTRL_ID_PLAYER_4:
3681 case EVENT_KEYPRESS:
3682 switch (GetEventKey((KeyEvent *)&event, TRUE))
3685 if (req_state & REQ_CONFIRM)
3701 if (req_state & REQ_PLAYER)
3705 case EVENT_KEYRELEASE:
3706 ClearPlayerAction();
3710 HandleOtherEvents(&event);
3714 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3716 int joy = AnyJoystick();
3718 if (joy & JOY_BUTTON_1)
3720 else if (joy & JOY_BUTTON_2)
3726 if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd)
3728 HandleGameActions();
3734 if (!PendingEvent()) /* delay only if no pending events */
3745 if (!PendingEvent()) /* delay only if no pending events */
3748 /* don't eat all CPU time */
3755 if (game_status != GAME_MODE_MAIN)
3761 if (use_envelope_request)
3762 ShowEnvelopeDoor(text, ACTION_CLOSING);
3766 if (!(req_state & REQ_STAY_OPEN) && !use_envelope_request)
3768 if (!(req_state & REQ_STAY_OPEN))
3771 CloseDoor(DOOR_CLOSE_1);
3773 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
3774 (req_state & REQ_REOPEN))
3775 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
3780 if (game_status == GAME_MODE_PLAYING)
3782 SetPanelBackground();
3783 SetDrawBackgroundMask(REDRAW_DOOR_1);
3787 SetDrawBackgroundMask(REDRAW_FIELD);
3790 #if defined(NETWORK_AVALIABLE)
3791 /* continue network game after request */
3792 if (options.network &&
3793 game_status == GAME_MODE_PLAYING &&
3794 req_state & REQUEST_WAIT_FOR_INPUT)
3795 SendToServer_ContinuePlaying();
3798 /* restore deactivated drawing when quick-loading level tape recording */
3799 if (tape.playing && tape.deactivate_display)
3800 TapeDeactivateDisplayOn();
3805 unsigned int OpenDoor(unsigned int door_state)
3807 if (door_state & DOOR_COPY_BACK)
3809 if (door_state & DOOR_OPEN_1)
3810 BlitBitmap(bitmap_db_door, bitmap_db_door,
3811 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
3812 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
3814 if (door_state & DOOR_OPEN_2)
3815 BlitBitmap(bitmap_db_door, bitmap_db_door,
3816 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
3817 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
3819 door_state &= ~DOOR_COPY_BACK;
3822 return MoveDoor(door_state);
3825 unsigned int CloseDoor(unsigned int door_state)
3827 unsigned int old_door_state = GetDoorState();
3829 if (!(door_state & DOOR_NO_COPY_BACK))
3831 if (old_door_state & DOOR_OPEN_1)
3832 BlitBitmap(backbuffer, bitmap_db_door,
3833 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
3835 if (old_door_state & DOOR_OPEN_2)
3836 BlitBitmap(backbuffer, bitmap_db_door,
3837 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
3839 door_state &= ~DOOR_NO_COPY_BACK;
3842 return MoveDoor(door_state);
3845 unsigned int GetDoorState()
3847 return MoveDoor(DOOR_GET_STATE);
3850 unsigned int SetDoorState(unsigned int door_state)
3852 return MoveDoor(door_state | DOOR_SET_STATE);
3855 unsigned int MoveDoor(unsigned int door_state)
3857 static int door1 = DOOR_OPEN_1;
3858 static int door2 = DOOR_CLOSE_2;
3859 unsigned long door_delay = 0;
3860 unsigned long door_delay_value;
3863 if (door_1.width < 0 || door_1.width > DXSIZE)
3864 door_1.width = DXSIZE;
3865 if (door_1.height < 0 || door_1.height > DYSIZE)
3866 door_1.height = DYSIZE;
3867 if (door_2.width < 0 || door_2.width > VXSIZE)
3868 door_2.width = VXSIZE;
3869 if (door_2.height < 0 || door_2.height > VYSIZE)
3870 door_2.height = VYSIZE;
3872 if (door_state == DOOR_GET_STATE)
3873 return (door1 | door2);
3875 if (door_state & DOOR_SET_STATE)
3877 if (door_state & DOOR_ACTION_1)
3878 door1 = door_state & DOOR_ACTION_1;
3879 if (door_state & DOOR_ACTION_2)
3880 door2 = door_state & DOOR_ACTION_2;
3882 return (door1 | door2);
3885 if (!(door_state & DOOR_FORCE_REDRAW))
3887 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
3888 door_state &= ~DOOR_OPEN_1;
3889 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
3890 door_state &= ~DOOR_CLOSE_1;
3891 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
3892 door_state &= ~DOOR_OPEN_2;
3893 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
3894 door_state &= ~DOOR_CLOSE_2;
3897 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
3900 if (setup.quick_doors)
3902 stepsize = 20; /* must be chosen to always draw last frame */
3903 door_delay_value = 0;
3906 if (global.autoplay_leveldir)
3908 door_state |= DOOR_NO_DELAY;
3909 door_state &= ~DOOR_CLOSE_ALL;
3913 if (game_status == GAME_MODE_EDITOR)
3914 door_state |= DOOR_NO_DELAY;
3917 if (door_state & DOOR_ACTION)
3919 boolean handle_door_1 = (door_state & DOOR_ACTION_1);
3920 boolean handle_door_2 = (door_state & DOOR_ACTION_2);
3921 boolean door_1_done = (!handle_door_1);
3922 boolean door_2_done = (!handle_door_2);
3923 boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
3924 boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
3925 int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
3926 int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
3927 int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
3928 int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
3929 int door_size = (handle_door_1 ? door_size_1 : door_size_2);
3930 int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
3931 int door_skip = max_door_size - door_size;
3932 int end = door_size;
3933 int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
3936 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
3938 /* opening door sound has priority over simultaneously closing door */
3939 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
3940 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
3941 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
3942 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
3945 for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
3948 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3949 GC gc = bitmap->stored_clip_gc;
3951 if (door_state & DOOR_ACTION_1)
3953 int a = MIN(x * door_1.step_offset, end);
3954 int p = (door_state & DOOR_OPEN_1 ? end - a : a);
3955 int i = p + door_skip;
3957 if (door_1.anim_mode & ANIM_STATIC_PANEL)
3959 BlitBitmap(bitmap_db_door, drawto,
3960 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
3961 DXSIZE, DYSIZE, DX, DY);
3965 BlitBitmap(bitmap_db_door, drawto,
3966 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
3967 DXSIZE, DYSIZE - p / 2, DX, DY);
3969 ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
3972 if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
3974 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
3975 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
3976 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
3977 int dst2_x = DX, dst2_y = DY;
3978 int width = i, height = DYSIZE;
3980 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3981 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3984 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3985 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3988 else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
3990 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
3991 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
3992 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
3993 int dst2_x = DX, dst2_y = DY;
3994 int width = DXSIZE, height = i;
3996 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3997 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
4000 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
4001 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
4004 else if (x <= DXSIZE) /* ANIM_DEFAULT */
4006 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
4008 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
4009 BlitBitmapMasked(bitmap, drawto,
4010 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
4011 DX + DXSIZE - i, DY + j);
4012 BlitBitmapMasked(bitmap, drawto,
4013 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
4014 DX + DXSIZE - i, DY + 140 + j);
4015 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
4016 DY - (DOOR_GFX_PAGEY1 + j));
4017 BlitBitmapMasked(bitmap, drawto,
4018 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
4020 BlitBitmapMasked(bitmap, drawto,
4021 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
4024 BlitBitmapMasked(bitmap, drawto,
4025 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
4027 BlitBitmapMasked(bitmap, drawto,
4028 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
4030 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
4031 BlitBitmapMasked(bitmap, drawto,
4032 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
4033 DX + DXSIZE - i, DY + 77 + j);
4034 BlitBitmapMasked(bitmap, drawto,
4035 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
4036 DX + DXSIZE - i, DY + 203 + j);
4039 redraw_mask |= REDRAW_DOOR_1;
4040 door_1_done = (a == end);
4043 if (door_state & DOOR_ACTION_2)
4045 int a = MIN(x * door_2.step_offset, door_size);
4046 int p = (door_state & DOOR_OPEN_2 ? door_size - a : a);
4047 int i = p + door_skip;
4049 if (door_2.anim_mode & ANIM_STATIC_PANEL)
4051 BlitBitmap(bitmap_db_door, drawto,
4052 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
4053 VXSIZE, VYSIZE, VX, VY);
4055 else if (x <= VYSIZE)
4057 BlitBitmap(bitmap_db_door, drawto,
4058 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
4059 VXSIZE, VYSIZE - p / 2, VX, VY);
4061 ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
4064 if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
4066 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
4067 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
4068 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
4069 int dst2_x = VX, dst2_y = VY;
4070 int width = i, height = VYSIZE;
4072 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
4073 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
4076 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
4077 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
4080 else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
4082 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
4083 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
4084 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
4085 int dst2_x = VX, dst2_y = VY;
4086 int width = VXSIZE, height = i;
4088 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
4089 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
4092 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
4093 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
4096 else if (x <= VXSIZE) /* ANIM_DEFAULT */
4098 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
4100 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
4101 BlitBitmapMasked(bitmap, drawto,
4102 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
4103 VX + VXSIZE - i, VY + j);
4104 SetClipOrigin(bitmap, gc,
4105 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
4106 BlitBitmapMasked(bitmap, drawto,
4107 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
4110 BlitBitmapMasked(bitmap, drawto,
4111 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
4112 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
4113 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
4114 BlitBitmapMasked(bitmap, drawto,
4115 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
4117 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
4120 redraw_mask |= REDRAW_DOOR_2;
4121 door_2_done = (a == VXSIZE);
4124 if (!(door_state & DOOR_NO_DELAY))
4128 if (game_status == GAME_MODE_MAIN)
4131 WaitUntilDelayReached(&door_delay, door_delay_value);
4136 if (door_state & DOOR_ACTION_1)
4137 door1 = door_state & DOOR_ACTION_1;
4138 if (door_state & DOOR_ACTION_2)
4139 door2 = door_state & DOOR_ACTION_2;
4141 return (door1 | door2);
4144 void DrawSpecialEditorDoor()
4146 /* draw bigger toolbox window */
4147 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
4148 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
4150 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
4151 EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
4154 redraw_mask |= REDRAW_ALL;
4157 void UndrawSpecialEditorDoor()
4159 /* draw normal tape recorder window */
4160 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
4161 EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
4164 redraw_mask |= REDRAW_ALL;
4168 /* ---------- new tool button stuff ---------------------------------------- */
4170 /* graphic position values for tool buttons */
4171 #define TOOL_BUTTON_YES_XPOS 2
4172 #define TOOL_BUTTON_YES_YPOS 250
4173 #define TOOL_BUTTON_YES_GFX_YPOS 0
4174 #define TOOL_BUTTON_YES_XSIZE 46
4175 #define TOOL_BUTTON_YES_YSIZE 28
4176 #define TOOL_BUTTON_NO_XPOS 52
4177 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
4178 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
4179 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
4180 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
4181 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
4182 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
4183 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
4184 #define TOOL_BUTTON_CONFIRM_XSIZE 96
4185 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
4186 #define TOOL_BUTTON_PLAYER_XSIZE 30
4187 #define TOOL_BUTTON_PLAYER_YSIZE 30
4188 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
4189 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
4190 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
4191 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
4192 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
4193 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
4194 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
4195 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
4196 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
4197 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
4198 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
4199 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
4200 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
4201 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
4202 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
4203 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
4204 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
4205 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
4206 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
4207 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
4216 } toolbutton_info[NUM_TOOL_BUTTONS] =
4219 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
4220 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
4221 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
4226 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
4227 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
4228 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
4233 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
4234 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
4235 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
4236 TOOL_CTRL_ID_CONFIRM,
4240 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
4241 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
4242 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
4243 TOOL_CTRL_ID_PLAYER_1,
4247 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
4248 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
4249 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
4250 TOOL_CTRL_ID_PLAYER_2,
4254 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
4255 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
4256 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
4257 TOOL_CTRL_ID_PLAYER_3,
4261 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
4262 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
4263 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
4264 TOOL_CTRL_ID_PLAYER_4,
4269 void CreateToolButtons()
4273 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4275 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
4276 Bitmap *deco_bitmap = None;
4277 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
4278 struct GadgetInfo *gi;
4279 unsigned long event_mask;
4280 int gd_xoffset, gd_yoffset;
4281 int gd_x1, gd_x2, gd_y;
4284 event_mask = GD_EVENT_RELEASED;
4286 gd_xoffset = toolbutton_info[i].xpos;
4287 gd_yoffset = toolbutton_info[i].ypos;
4288 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
4289 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
4290 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
4292 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
4294 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
4296 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
4297 &deco_bitmap, &deco_x, &deco_y);
4298 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
4299 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
4302 gi = CreateGadget(GDI_CUSTOM_ID, id,
4303 GDI_INFO_TEXT, toolbutton_info[i].infotext,
4304 GDI_X, DX + toolbutton_info[i].x,
4305 GDI_Y, DY + toolbutton_info[i].y,
4306 GDI_WIDTH, toolbutton_info[i].width,
4307 GDI_HEIGHT, toolbutton_info[i].height,
4308 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
4309 GDI_STATE, GD_BUTTON_UNPRESSED,
4310 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
4311 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
4312 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
4313 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
4314 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
4315 GDI_DECORATION_SHIFTING, 1, 1,
4316 GDI_DIRECT_DRAW, FALSE,
4317 GDI_EVENT_MASK, event_mask,
4318 GDI_CALLBACK_ACTION, HandleToolButtons,
4322 Error(ERR_EXIT, "cannot create gadget");
4324 tool_gadget[id] = gi;
4328 void FreeToolButtons()
4332 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4333 FreeGadget(tool_gadget[i]);
4336 static void UnmapToolButtons()
4340 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4341 UnmapGadget(tool_gadget[i]);
4344 static void HandleToolButtons(struct GadgetInfo *gi)
4346 request_gadget_id = gi->custom_id;
4349 static struct Mapping_EM_to_RND_object
4352 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
4353 boolean is_backside; /* backside of moving element */
4359 em_object_mapping_list[] =
4362 Xblank, TRUE, FALSE,
4366 Yacid_splash_eB, FALSE, FALSE,
4367 EL_ACID_SPLASH_RIGHT, -1, -1
4370 Yacid_splash_wB, FALSE, FALSE,
4371 EL_ACID_SPLASH_LEFT, -1, -1
4374 #ifdef EM_ENGINE_BAD_ROLL
4376 Xstone_force_e, FALSE, FALSE,
4377 EL_ROCK, -1, MV_BIT_RIGHT
4380 Xstone_force_w, FALSE, FALSE,
4381 EL_ROCK, -1, MV_BIT_LEFT
4384 Xnut_force_e, FALSE, FALSE,
4385 EL_NUT, -1, MV_BIT_RIGHT
4388 Xnut_force_w, FALSE, FALSE,
4389 EL_NUT, -1, MV_BIT_LEFT
4392 Xspring_force_e, FALSE, FALSE,
4393 EL_SPRING, -1, MV_BIT_RIGHT
4396 Xspring_force_w, FALSE, FALSE,
4397 EL_SPRING, -1, MV_BIT_LEFT
4400 Xemerald_force_e, FALSE, FALSE,
4401 EL_EMERALD, -1, MV_BIT_RIGHT
4404 Xemerald_force_w, FALSE, FALSE,
4405 EL_EMERALD, -1, MV_BIT_LEFT
4408 Xdiamond_force_e, FALSE, FALSE,
4409 EL_DIAMOND, -1, MV_BIT_RIGHT
4412 Xdiamond_force_w, FALSE, FALSE,
4413 EL_DIAMOND, -1, MV_BIT_LEFT
4416 Xbomb_force_e, FALSE, FALSE,
4417 EL_BOMB, -1, MV_BIT_RIGHT
4420 Xbomb_force_w, FALSE, FALSE,
4421 EL_BOMB, -1, MV_BIT_LEFT
4423 #endif /* EM_ENGINE_BAD_ROLL */
4426 Xstone, TRUE, FALSE,
4430 Xstone_pause, FALSE, FALSE,
4434 Xstone_fall, FALSE, FALSE,
4438 Ystone_s, FALSE, FALSE,
4439 EL_ROCK, ACTION_FALLING, -1
4442 Ystone_sB, FALSE, TRUE,
4443 EL_ROCK, ACTION_FALLING, -1
4446 Ystone_e, FALSE, FALSE,
4447 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
4450 Ystone_eB, FALSE, TRUE,
4451 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
4454 Ystone_w, FALSE, FALSE,
4455 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
4458 Ystone_wB, FALSE, TRUE,
4459 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
4466 Xnut_pause, FALSE, FALSE,
4470 Xnut_fall, FALSE, FALSE,
4474 Ynut_s, FALSE, FALSE,
4475 EL_NUT, ACTION_FALLING, -1
4478 Ynut_sB, FALSE, TRUE,
4479 EL_NUT, ACTION_FALLING, -1
4482 Ynut_e, FALSE, FALSE,
4483 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
4486 Ynut_eB, FALSE, TRUE,
4487 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
4490 Ynut_w, FALSE, FALSE,
4491 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
4494 Ynut_wB, FALSE, TRUE,
4495 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
4498 Xbug_n, TRUE, FALSE,
4502 Xbug_e, TRUE, FALSE,
4503 EL_BUG_RIGHT, -1, -1
4506 Xbug_s, TRUE, FALSE,
4510 Xbug_w, TRUE, FALSE,
4514 Xbug_gon, FALSE, FALSE,
4518 Xbug_goe, FALSE, FALSE,
4519 EL_BUG_RIGHT, -1, -1
4522 Xbug_gos, FALSE, FALSE,
4526 Xbug_gow, FALSE, FALSE,
4530 Ybug_n, FALSE, FALSE,
4531 EL_BUG, ACTION_MOVING, MV_BIT_UP
4534 Ybug_nB, FALSE, TRUE,
4535 EL_BUG, ACTION_MOVING, MV_BIT_UP
4538 Ybug_e, FALSE, FALSE,
4539 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
4542 Ybug_eB, FALSE, TRUE,
4543 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
4546 Ybug_s, FALSE, FALSE,
4547 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
4550 Ybug_sB, FALSE, TRUE,
4551 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
4554 Ybug_w, FALSE, FALSE,
4555 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
4558 Ybug_wB, FALSE, TRUE,
4559 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
4562 Ybug_w_n, FALSE, FALSE,
4563 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
4566 Ybug_n_e, FALSE, FALSE,
4567 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
4570 Ybug_e_s, FALSE, FALSE,
4571 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
4574 Ybug_s_w, FALSE, FALSE,
4575 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
4578 Ybug_e_n, FALSE, FALSE,
4579 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
4582 Ybug_s_e, FALSE, FALSE,
4583 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
4586 Ybug_w_s, FALSE, FALSE,
4587 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
4590 Ybug_n_w, FALSE, FALSE,
4591 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
4594 Ybug_stone, FALSE, FALSE,
4595 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
4598 Ybug_spring, FALSE, FALSE,
4599 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
4602 Xtank_n, TRUE, FALSE,
4603 EL_SPACESHIP_UP, -1, -1
4606 Xtank_e, TRUE, FALSE,
4607 EL_SPACESHIP_RIGHT, -1, -1
4610 Xtank_s, TRUE, FALSE,
4611 EL_SPACESHIP_DOWN, -1, -1
4614 Xtank_w, TRUE, FALSE,
4615 EL_SPACESHIP_LEFT, -1, -1
4618 Xtank_gon, FALSE, FALSE,
4619 EL_SPACESHIP_UP, -1, -1
4622 Xtank_goe, FALSE, FALSE,
4623 EL_SPACESHIP_RIGHT, -1, -1
4626 Xtank_gos, FALSE, FALSE,
4627 EL_SPACESHIP_DOWN, -1, -1
4630 Xtank_gow, FALSE, FALSE,
4631 EL_SPACESHIP_LEFT, -1, -1
4634 Ytank_n, FALSE, FALSE,
4635 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
4638 Ytank_nB, FALSE, TRUE,
4639 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
4642 Ytank_e, FALSE, FALSE,
4643 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
4646 Ytank_eB, FALSE, TRUE,
4647 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
4650 Ytank_s, FALSE, FALSE,
4651 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
4654 Ytank_sB, FALSE, TRUE,
4655 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
4658 Ytank_w, FALSE, FALSE,
4659 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
4662 Ytank_wB, FALSE, TRUE,
4663 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
4666 Ytank_w_n, FALSE, FALSE,
4667 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
4670 Ytank_n_e, FALSE, FALSE,
4671 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
4674 Ytank_e_s, FALSE, FALSE,
4675 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
4678 Ytank_s_w, FALSE, FALSE,
4679 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
4682 Ytank_e_n, FALSE, FALSE,
4683 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
4686 Ytank_s_e, FALSE, FALSE,
4687 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
4690 Ytank_w_s, FALSE, FALSE,
4691 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
4694 Ytank_n_w, FALSE, FALSE,
4695 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
4698 Ytank_stone, FALSE, FALSE,
4699 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
4702 Ytank_spring, FALSE, FALSE,
4703 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
4706 Xandroid, TRUE, FALSE,
4707 EL_EMC_ANDROID, ACTION_ACTIVE, -1
4710 Xandroid_1_n, FALSE, FALSE,
4711 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
4714 Xandroid_2_n, FALSE, FALSE,
4715 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
4718 Xandroid_1_e, FALSE, FALSE,
4719 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
4722 Xandroid_2_e, FALSE, FALSE,
4723 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
4726 Xandroid_1_w, FALSE, FALSE,
4727 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
4730 Xandroid_2_w, FALSE, FALSE,
4731 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
4734 Xandroid_1_s, FALSE, FALSE,
4735 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
4738 Xandroid_2_s, FALSE, FALSE,
4739 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
4742 Yandroid_n, FALSE, FALSE,
4743 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
4746 Yandroid_nB, FALSE, TRUE,
4747 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
4750 Yandroid_ne, FALSE, FALSE,
4751 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
4754 Yandroid_neB, FALSE, TRUE,
4755 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
4758 Yandroid_e, FALSE, FALSE,
4759 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
4762 Yandroid_eB, FALSE, TRUE,
4763 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
4766 Yandroid_se, FALSE, FALSE,
4767 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
4770 Yandroid_seB, FALSE, TRUE,
4771 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
4774 Yandroid_s, FALSE, FALSE,
4775 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
4778 Yandroid_sB, FALSE, TRUE,
4779 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
4782 Yandroid_sw, FALSE, FALSE,
4783 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
4786 Yandroid_swB, FALSE, TRUE,
4787 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
4790 Yandroid_w, FALSE, FALSE,
4791 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
4794 Yandroid_wB, FALSE, TRUE,
4795 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
4798 Yandroid_nw, FALSE, FALSE,
4799 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
4802 Yandroid_nwB, FALSE, TRUE,
4803 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
4806 Xspring, TRUE, FALSE,
4810 Xspring_pause, FALSE, FALSE,
4814 Xspring_e, FALSE, FALSE,
4818 Xspring_w, FALSE, FALSE,
4822 Xspring_fall, FALSE, FALSE,
4826 Yspring_s, FALSE, FALSE,
4827 EL_SPRING, ACTION_FALLING, -1
4830 Yspring_sB, FALSE, TRUE,
4831 EL_SPRING, ACTION_FALLING, -1
4834 Yspring_e, FALSE, FALSE,
4835 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
4838 Yspring_eB, FALSE, TRUE,
4839 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
4842 Yspring_w, FALSE, FALSE,
4843 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
4846 Yspring_wB, FALSE, TRUE,
4847 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
4850 Yspring_kill_e, FALSE, FALSE,
4851 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
4854 Yspring_kill_eB, FALSE, TRUE,
4855 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
4858 Yspring_kill_w, FALSE, FALSE,
4859 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
4862 Yspring_kill_wB, FALSE, TRUE,
4863 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
4866 Xeater_n, TRUE, FALSE,
4867 EL_YAMYAM_UP, -1, -1
4870 Xeater_e, TRUE, FALSE,
4871 EL_YAMYAM_RIGHT, -1, -1
4874 Xeater_w, TRUE, FALSE,
4875 EL_YAMYAM_LEFT, -1, -1
4878 Xeater_s, TRUE, FALSE,
4879 EL_YAMYAM_DOWN, -1, -1
4882 Yeater_n, FALSE, FALSE,
4883 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
4886 Yeater_nB, FALSE, TRUE,
4887 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
4890 Yeater_e, FALSE, FALSE,
4891 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
4894 Yeater_eB, FALSE, TRUE,
4895 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
4898 Yeater_s, FALSE, FALSE,
4899 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
4902 Yeater_sB, FALSE, TRUE,
4903 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
4906 Yeater_w, FALSE, FALSE,
4907 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
4910 Yeater_wB, FALSE, TRUE,
4911 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
4914 Yeater_stone, FALSE, FALSE,
4915 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
4918 Yeater_spring, FALSE, FALSE,
4919 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
4922 Xalien, TRUE, FALSE,
4926 Xalien_pause, FALSE, FALSE,
4930 Yalien_n, FALSE, FALSE,
4931 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
4934 Yalien_nB, FALSE, TRUE,
4935 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
4938 Yalien_e, FALSE, FALSE,
4939 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
4942 Yalien_eB, FALSE, TRUE,
4943 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
4946 Yalien_s, FALSE, FALSE,
4947 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
4950 Yalien_sB, FALSE, TRUE,
4951 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
4954 Yalien_w, FALSE, FALSE,
4955 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
4958 Yalien_wB, FALSE, TRUE,
4959 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
4962 Yalien_stone, FALSE, FALSE,
4963 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
4966 Yalien_spring, FALSE, FALSE,
4967 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
4970 Xemerald, TRUE, FALSE,
4974 Xemerald_pause, FALSE, FALSE,
4978 Xemerald_fall, FALSE, FALSE,
4982 Xemerald_shine, FALSE, FALSE,
4983 EL_EMERALD, ACTION_TWINKLING, -1
4986 Yemerald_s, FALSE, FALSE,
4987 EL_EMERALD, ACTION_FALLING, -1
4990 Yemerald_sB, FALSE, TRUE,
4991 EL_EMERALD, ACTION_FALLING, -1
4994 Yemerald_e, FALSE, FALSE,
4995 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
4998 Yemerald_eB, FALSE, TRUE,
4999 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
5002 Yemerald_w, FALSE, FALSE,
5003 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
5006 Yemerald_wB, FALSE, TRUE,
5007 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
5010 Yemerald_eat, FALSE, FALSE,
5011 EL_EMERALD, ACTION_COLLECTING, -1
5014 Yemerald_stone, FALSE, FALSE,
5015 EL_NUT, ACTION_BREAKING, -1
5018 Xdiamond, TRUE, FALSE,
5022 Xdiamond_pause, FALSE, FALSE,
5026 Xdiamond_fall, FALSE, FALSE,
5030 Xdiamond_shine, FALSE, FALSE,
5031 EL_DIAMOND, ACTION_TWINKLING, -1
5034 Ydiamond_s, FALSE, FALSE,
5035 EL_DIAMOND, ACTION_FALLING, -1
5038 Ydiamond_sB, FALSE, TRUE,
5039 EL_DIAMOND, ACTION_FALLING, -1
5042 Ydiamond_e, FALSE, FALSE,
5043 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
5046 Ydiamond_eB, FALSE, TRUE,
5047 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
5050 Ydiamond_w, FALSE, FALSE,
5051 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
5054 Ydiamond_wB, FALSE, TRUE,
5055 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
5058 Ydiamond_eat, FALSE, FALSE,
5059 EL_DIAMOND, ACTION_COLLECTING, -1
5062 Ydiamond_stone, FALSE, FALSE,
5063 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
5066 Xdrip_fall, TRUE, FALSE,
5067 EL_AMOEBA_DROP, -1, -1
5070 Xdrip_stretch, FALSE, FALSE,
5071 EL_AMOEBA_DROP, ACTION_FALLING, -1
5074 Xdrip_stretchB, FALSE, TRUE,
5075 EL_AMOEBA_DROP, ACTION_FALLING, -1
5078 Xdrip_eat, FALSE, FALSE,
5079 EL_AMOEBA_DROP, ACTION_GROWING, -1
5082 Ydrip_s1, FALSE, FALSE,
5083 EL_AMOEBA_DROP, ACTION_FALLING, -1
5086 Ydrip_s1B, FALSE, TRUE,
5087 EL_AMOEBA_DROP, ACTION_FALLING, -1
5090 Ydrip_s2, FALSE, FALSE,
5091 EL_AMOEBA_DROP, ACTION_FALLING, -1
5094 Ydrip_s2B, FALSE, TRUE,
5095 EL_AMOEBA_DROP, ACTION_FALLING, -1
5102 Xbomb_pause, FALSE, FALSE,
5106 Xbomb_fall, FALSE, FALSE,
5110 Ybomb_s, FALSE, FALSE,
5111 EL_BOMB, ACTION_FALLING, -1
5114 Ybomb_sB, FALSE, TRUE,
5115 EL_BOMB, ACTION_FALLING, -1
5118 Ybomb_e, FALSE, FALSE,
5119 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
5122 Ybomb_eB, FALSE, TRUE,
5123 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
5126 Ybomb_w, FALSE, FALSE,
5127 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
5130 Ybomb_wB, FALSE, TRUE,
5131 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
5134 Ybomb_eat, FALSE, FALSE,
5135 EL_BOMB, ACTION_ACTIVATING, -1
5138 Xballoon, TRUE, FALSE,
5142 Yballoon_n, FALSE, FALSE,
5143 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
5146 Yballoon_nB, FALSE, TRUE,
5147 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
5150 Yballoon_e, FALSE, FALSE,
5151 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
5154 Yballoon_eB, FALSE, TRUE,
5155 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
5158 Yballoon_s, FALSE, FALSE,
5159 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
5162 Yballoon_sB, FALSE, TRUE,
5163 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
5166 Yballoon_w, FALSE, FALSE,
5167 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
5170 Yballoon_wB, FALSE, TRUE,
5171 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
5174 Xgrass, TRUE, FALSE,
5175 EL_EMC_GRASS, -1, -1
5178 Ygrass_nB, FALSE, FALSE,
5179 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
5182 Ygrass_eB, FALSE, FALSE,
5183 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
5186 Ygrass_sB, FALSE, FALSE,
5187 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
5190 Ygrass_wB, FALSE, FALSE,
5191 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
5198 Ydirt_nB, FALSE, FALSE,
5199 EL_SAND, ACTION_DIGGING, MV_BIT_UP
5202 Ydirt_eB, FALSE, FALSE,
5203 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
5206 Ydirt_sB, FALSE, FALSE,
5207 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
5210 Ydirt_wB, FALSE, FALSE,
5211 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
5214 Xacid_ne, TRUE, FALSE,
5215 EL_ACID_POOL_TOPRIGHT, -1, -1
5218 Xacid_se, TRUE, FALSE,
5219 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
5222 Xacid_s, TRUE, FALSE,
5223 EL_ACID_POOL_BOTTOM, -1, -1
5226 Xacid_sw, TRUE, FALSE,
5227 EL_ACID_POOL_BOTTOMLEFT, -1, -1
5230 Xacid_nw, TRUE, FALSE,
5231 EL_ACID_POOL_TOPLEFT, -1, -1
5234 Xacid_1, TRUE, FALSE,
5238 Xacid_2, FALSE, FALSE,
5242 Xacid_3, FALSE, FALSE,
5246 Xacid_4, FALSE, FALSE,
5250 Xacid_5, FALSE, FALSE,
5254 Xacid_6, FALSE, FALSE,
5258 Xacid_7, FALSE, FALSE,
5262 Xacid_8, FALSE, FALSE,
5266 Xball_1, TRUE, FALSE,
5267 EL_EMC_MAGIC_BALL, -1, -1
5270 Xball_1B, FALSE, FALSE,
5271 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5274 Xball_2, FALSE, FALSE,
5275 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5278 Xball_2B, FALSE, FALSE,
5279 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5282 Yball_eat, FALSE, FALSE,
5283 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
5286 Ykey_1_eat, FALSE, FALSE,
5287 EL_EM_KEY_1, ACTION_COLLECTING, -1
5290 Ykey_2_eat, FALSE, FALSE,
5291 EL_EM_KEY_2, ACTION_COLLECTING, -1
5294 Ykey_3_eat, FALSE, FALSE,
5295 EL_EM_KEY_3, ACTION_COLLECTING, -1
5298 Ykey_4_eat, FALSE, FALSE,
5299 EL_EM_KEY_4, ACTION_COLLECTING, -1
5302 Ykey_5_eat, FALSE, FALSE,
5303 EL_EMC_KEY_5, ACTION_COLLECTING, -1
5306 Ykey_6_eat, FALSE, FALSE,
5307 EL_EMC_KEY_6, ACTION_COLLECTING, -1
5310 Ykey_7_eat, FALSE, FALSE,
5311 EL_EMC_KEY_7, ACTION_COLLECTING, -1
5314 Ykey_8_eat, FALSE, FALSE,
5315 EL_EMC_KEY_8, ACTION_COLLECTING, -1
5318 Ylenses_eat, FALSE, FALSE,
5319 EL_EMC_LENSES, ACTION_COLLECTING, -1
5322 Ymagnify_eat, FALSE, FALSE,
5323 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
5326 Ygrass_eat, FALSE, FALSE,
5327 EL_EMC_GRASS, ACTION_SNAPPING, -1
5330 Ydirt_eat, FALSE, FALSE,
5331 EL_SAND, ACTION_SNAPPING, -1
5334 Xgrow_ns, TRUE, FALSE,
5335 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
5338 Ygrow_ns_eat, FALSE, FALSE,
5339 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
5342 Xgrow_ew, TRUE, FALSE,
5343 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
5346 Ygrow_ew_eat, FALSE, FALSE,
5347 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
5350 Xwonderwall, TRUE, FALSE,
5351 EL_MAGIC_WALL, -1, -1
5354 XwonderwallB, FALSE, FALSE,
5355 EL_MAGIC_WALL, ACTION_ACTIVE, -1
5358 Xamoeba_1, TRUE, FALSE,
5359 EL_AMOEBA_DRY, ACTION_OTHER, -1
5362 Xamoeba_2, FALSE, FALSE,
5363 EL_AMOEBA_DRY, ACTION_OTHER, -1
5366 Xamoeba_3, FALSE, FALSE,
5367 EL_AMOEBA_DRY, ACTION_OTHER, -1
5370 Xamoeba_4, FALSE, FALSE,
5371 EL_AMOEBA_DRY, ACTION_OTHER, -1
5374 Xamoeba_5, TRUE, FALSE,
5375 EL_AMOEBA_WET, ACTION_OTHER, -1
5378 Xamoeba_6, FALSE, FALSE,
5379 EL_AMOEBA_WET, ACTION_OTHER, -1
5382 Xamoeba_7, FALSE, FALSE,
5383 EL_AMOEBA_WET, ACTION_OTHER, -1
5386 Xamoeba_8, FALSE, FALSE,
5387 EL_AMOEBA_WET, ACTION_OTHER, -1
5390 Xdoor_1, TRUE, FALSE,
5391 EL_EM_GATE_1, -1, -1
5394 Xdoor_2, TRUE, FALSE,
5395 EL_EM_GATE_2, -1, -1
5398 Xdoor_3, TRUE, FALSE,
5399 EL_EM_GATE_3, -1, -1
5402 Xdoor_4, TRUE, FALSE,
5403 EL_EM_GATE_4, -1, -1
5406 Xdoor_5, TRUE, FALSE,
5407 EL_EMC_GATE_5, -1, -1
5410 Xdoor_6, TRUE, FALSE,
5411 EL_EMC_GATE_6, -1, -1
5414 Xdoor_7, TRUE, FALSE,
5415 EL_EMC_GATE_7, -1, -1
5418 Xdoor_8, TRUE, FALSE,
5419 EL_EMC_GATE_8, -1, -1
5422 Xkey_1, TRUE, FALSE,
5426 Xkey_2, TRUE, FALSE,
5430 Xkey_3, TRUE, FALSE,
5434 Xkey_4, TRUE, FALSE,
5438 Xkey_5, TRUE, FALSE,
5439 EL_EMC_KEY_5, -1, -1
5442 Xkey_6, TRUE, FALSE,
5443 EL_EMC_KEY_6, -1, -1
5446 Xkey_7, TRUE, FALSE,
5447 EL_EMC_KEY_7, -1, -1
5450 Xkey_8, TRUE, FALSE,
5451 EL_EMC_KEY_8, -1, -1
5454 Xwind_n, TRUE, FALSE,
5455 EL_BALLOON_SWITCH_UP, -1, -1
5458 Xwind_e, TRUE, FALSE,
5459 EL_BALLOON_SWITCH_RIGHT, -1, -1
5462 Xwind_s, TRUE, FALSE,
5463 EL_BALLOON_SWITCH_DOWN, -1, -1
5466 Xwind_w, TRUE, FALSE,
5467 EL_BALLOON_SWITCH_LEFT, -1, -1
5470 Xwind_nesw, TRUE, FALSE,
5471 EL_BALLOON_SWITCH_ANY, -1, -1
5474 Xwind_stop, TRUE, FALSE,
5475 EL_BALLOON_SWITCH_NONE, -1, -1
5479 EL_EM_EXIT_CLOSED, -1, -1
5482 Xexit_1, TRUE, FALSE,
5483 EL_EM_EXIT_OPEN, -1, -1
5486 Xexit_2, FALSE, FALSE,
5487 EL_EM_EXIT_OPEN, -1, -1
5490 Xexit_3, FALSE, FALSE,
5491 EL_EM_EXIT_OPEN, -1, -1
5494 Xdynamite, TRUE, FALSE,
5495 EL_EM_DYNAMITE, -1, -1
5498 Ydynamite_eat, FALSE, FALSE,
5499 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
5502 Xdynamite_1, TRUE, FALSE,
5503 EL_EM_DYNAMITE_ACTIVE, -1, -1
5506 Xdynamite_2, FALSE, FALSE,
5507 EL_EM_DYNAMITE_ACTIVE, -1, -1
5510 Xdynamite_3, FALSE, FALSE,
5511 EL_EM_DYNAMITE_ACTIVE, -1, -1
5514 Xdynamite_4, FALSE, FALSE,
5515 EL_EM_DYNAMITE_ACTIVE, -1, -1
5518 Xbumper, TRUE, FALSE,
5519 EL_EMC_SPRING_BUMPER, -1, -1
5522 XbumperB, FALSE, FALSE,
5523 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
5526 Xwheel, TRUE, FALSE,
5527 EL_ROBOT_WHEEL, -1, -1
5530 XwheelB, FALSE, FALSE,
5531 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
5534 Xswitch, TRUE, FALSE,
5535 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
5538 XswitchB, FALSE, FALSE,
5539 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
5543 EL_QUICKSAND_EMPTY, -1, -1
5546 Xsand_stone, TRUE, FALSE,
5547 EL_QUICKSAND_FULL, -1, -1
5550 Xsand_stonein_1, FALSE, TRUE,
5551 EL_ROCK, ACTION_FILLING, -1
5554 Xsand_stonein_2, FALSE, TRUE,
5555 EL_ROCK, ACTION_FILLING, -1
5558 Xsand_stonein_3, FALSE, TRUE,
5559 EL_ROCK, ACTION_FILLING, -1
5562 Xsand_stonein_4, FALSE, TRUE,
5563 EL_ROCK, ACTION_FILLING, -1
5567 Xsand_stonesand_1, FALSE, FALSE,
5568 EL_QUICKSAND_EMPTYING, -1, -1
5571 Xsand_stonesand_2, FALSE, FALSE,
5572 EL_QUICKSAND_EMPTYING, -1, -1
5575 Xsand_stonesand_3, FALSE, FALSE,
5576 EL_QUICKSAND_EMPTYING, -1, -1
5579 Xsand_stonesand_4, FALSE, FALSE,
5580 EL_QUICKSAND_EMPTYING, -1, -1
5583 Xsand_stonesand_quickout_1, FALSE, FALSE,
5584 EL_QUICKSAND_EMPTYING, -1, -1
5587 Xsand_stonesand_quickout_2, FALSE, FALSE,
5588 EL_QUICKSAND_EMPTYING, -1, -1
5592 Xsand_stonesand_1, FALSE, FALSE,
5593 EL_QUICKSAND_FULL, -1, -1
5596 Xsand_stonesand_2, FALSE, FALSE,
5597 EL_QUICKSAND_FULL, -1, -1
5600 Xsand_stonesand_3, FALSE, FALSE,
5601 EL_QUICKSAND_FULL, -1, -1
5604 Xsand_stonesand_4, FALSE, FALSE,
5605 EL_QUICKSAND_FULL, -1, -1
5609 Xsand_stoneout_1, FALSE, FALSE,
5610 EL_ROCK, ACTION_EMPTYING, -1
5613 Xsand_stoneout_2, FALSE, FALSE,
5614 EL_ROCK, ACTION_EMPTYING, -1
5618 Xsand_sandstone_1, FALSE, FALSE,
5619 EL_QUICKSAND_FILLING, -1, -1
5622 Xsand_sandstone_2, FALSE, FALSE,
5623 EL_QUICKSAND_FILLING, -1, -1
5626 Xsand_sandstone_3, FALSE, FALSE,
5627 EL_QUICKSAND_FILLING, -1, -1
5630 Xsand_sandstone_4, FALSE, FALSE,
5631 EL_QUICKSAND_FILLING, -1, -1
5635 Xsand_sandstone_1, FALSE, FALSE,
5636 EL_QUICKSAND_FULL, -1, -1
5639 Xsand_sandstone_2, FALSE, FALSE,
5640 EL_QUICKSAND_FULL, -1, -1
5643 Xsand_sandstone_3, FALSE, FALSE,
5644 EL_QUICKSAND_FULL, -1, -1
5647 Xsand_sandstone_4, FALSE, FALSE,
5648 EL_QUICKSAND_FULL, -1, -1
5652 Xplant, TRUE, FALSE,
5653 EL_EMC_PLANT, -1, -1
5656 Yplant, FALSE, FALSE,
5657 EL_EMC_PLANT, -1, -1
5660 Xlenses, TRUE, FALSE,
5661 EL_EMC_LENSES, -1, -1
5664 Xmagnify, TRUE, FALSE,
5665 EL_EMC_MAGNIFIER, -1, -1
5668 Xdripper, TRUE, FALSE,
5669 EL_EMC_DRIPPER, -1, -1
5672 XdripperB, FALSE, FALSE,
5673 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
5676 Xfake_blank, TRUE, FALSE,
5677 EL_INVISIBLE_WALL, -1, -1
5680 Xfake_blankB, FALSE, FALSE,
5681 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
5684 Xfake_grass, TRUE, FALSE,
5685 EL_EMC_FAKE_GRASS, -1, -1
5688 Xfake_grassB, FALSE, FALSE,
5689 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
5692 Xfake_door_1, TRUE, FALSE,
5693 EL_EM_GATE_1_GRAY, -1, -1
5696 Xfake_door_2, TRUE, FALSE,
5697 EL_EM_GATE_2_GRAY, -1, -1
5700 Xfake_door_3, TRUE, FALSE,
5701 EL_EM_GATE_3_GRAY, -1, -1
5704 Xfake_door_4, TRUE, FALSE,
5705 EL_EM_GATE_4_GRAY, -1, -1
5708 Xfake_door_5, TRUE, FALSE,
5709 EL_EMC_GATE_5_GRAY, -1, -1
5712 Xfake_door_6, TRUE, FALSE,
5713 EL_EMC_GATE_6_GRAY, -1, -1
5716 Xfake_door_7, TRUE, FALSE,
5717 EL_EMC_GATE_7_GRAY, -1, -1
5720 Xfake_door_8, TRUE, FALSE,
5721 EL_EMC_GATE_8_GRAY, -1, -1
5724 Xfake_acid_1, TRUE, FALSE,
5725 EL_EMC_FAKE_ACID, -1, -1
5728 Xfake_acid_2, FALSE, FALSE,
5729 EL_EMC_FAKE_ACID, -1, -1
5732 Xfake_acid_3, FALSE, FALSE,
5733 EL_EMC_FAKE_ACID, -1, -1
5736 Xfake_acid_4, FALSE, FALSE,
5737 EL_EMC_FAKE_ACID, -1, -1
5740 Xfake_acid_5, FALSE, FALSE,
5741 EL_EMC_FAKE_ACID, -1, -1
5744 Xfake_acid_6, FALSE, FALSE,
5745 EL_EMC_FAKE_ACID, -1, -1
5748 Xfake_acid_7, FALSE, FALSE,
5749 EL_EMC_FAKE_ACID, -1, -1
5752 Xfake_acid_8, FALSE, FALSE,
5753 EL_EMC_FAKE_ACID, -1, -1
5756 Xsteel_1, TRUE, FALSE,
5757 EL_STEELWALL, -1, -1
5760 Xsteel_2, TRUE, FALSE,
5761 EL_EMC_STEELWALL_2, -1, -1
5764 Xsteel_3, TRUE, FALSE,
5765 EL_EMC_STEELWALL_3, -1, -1
5768 Xsteel_4, TRUE, FALSE,
5769 EL_EMC_STEELWALL_4, -1, -1
5772 Xwall_1, TRUE, FALSE,
5776 Xwall_2, TRUE, FALSE,
5777 EL_EMC_WALL_14, -1, -1
5780 Xwall_3, TRUE, FALSE,
5781 EL_EMC_WALL_15, -1, -1
5784 Xwall_4, TRUE, FALSE,
5785 EL_EMC_WALL_16, -1, -1
5788 Xround_wall_1, TRUE, FALSE,
5789 EL_WALL_SLIPPERY, -1, -1
5792 Xround_wall_2, TRUE, FALSE,
5793 EL_EMC_WALL_SLIPPERY_2, -1, -1
5796 Xround_wall_3, TRUE, FALSE,
5797 EL_EMC_WALL_SLIPPERY_3, -1, -1
5800 Xround_wall_4, TRUE, FALSE,
5801 EL_EMC_WALL_SLIPPERY_4, -1, -1
5804 Xdecor_1, TRUE, FALSE,
5805 EL_EMC_WALL_8, -1, -1
5808 Xdecor_2, TRUE, FALSE,
5809 EL_EMC_WALL_6, -1, -1
5812 Xdecor_3, TRUE, FALSE,
5813 EL_EMC_WALL_4, -1, -1
5816 Xdecor_4, TRUE, FALSE,
5817 EL_EMC_WALL_7, -1, -1
5820 Xdecor_5, TRUE, FALSE,
5821 EL_EMC_WALL_5, -1, -1
5824 Xdecor_6, TRUE, FALSE,
5825 EL_EMC_WALL_9, -1, -1
5828 Xdecor_7, TRUE, FALSE,
5829 EL_EMC_WALL_10, -1, -1
5832 Xdecor_8, TRUE, FALSE,
5833 EL_EMC_WALL_1, -1, -1
5836 Xdecor_9, TRUE, FALSE,
5837 EL_EMC_WALL_2, -1, -1
5840 Xdecor_10, TRUE, FALSE,
5841 EL_EMC_WALL_3, -1, -1
5844 Xdecor_11, TRUE, FALSE,
5845 EL_EMC_WALL_11, -1, -1
5848 Xdecor_12, TRUE, FALSE,
5849 EL_EMC_WALL_12, -1, -1
5852 Xalpha_0, TRUE, FALSE,
5853 EL_CHAR('0'), -1, -1
5856 Xalpha_1, TRUE, FALSE,
5857 EL_CHAR('1'), -1, -1
5860 Xalpha_2, TRUE, FALSE,
5861 EL_CHAR('2'), -1, -1
5864 Xalpha_3, TRUE, FALSE,
5865 EL_CHAR('3'), -1, -1
5868 Xalpha_4, TRUE, FALSE,
5869 EL_CHAR('4'), -1, -1
5872 Xalpha_5, TRUE, FALSE,
5873 EL_CHAR('5'), -1, -1
5876 Xalpha_6, TRUE, FALSE,
5877 EL_CHAR('6'), -1, -1
5880 Xalpha_7, TRUE, FALSE,
5881 EL_CHAR('7'), -1, -1
5884 Xalpha_8, TRUE, FALSE,
5885 EL_CHAR('8'), -1, -1
5888 Xalpha_9, TRUE, FALSE,
5889 EL_CHAR('9'), -1, -1
5892 Xalpha_excla, TRUE, FALSE,
5893 EL_CHAR('!'), -1, -1
5896 Xalpha_quote, TRUE, FALSE,
5897 EL_CHAR('"'), -1, -1
5900 Xalpha_comma, TRUE, FALSE,
5901 EL_CHAR(','), -1, -1
5904 Xalpha_minus, TRUE, FALSE,
5905 EL_CHAR('-'), -1, -1
5908 Xalpha_perio, TRUE, FALSE,
5909 EL_CHAR('.'), -1, -1
5912 Xalpha_colon, TRUE, FALSE,
5913 EL_CHAR(':'), -1, -1
5916 Xalpha_quest, TRUE, FALSE,
5917 EL_CHAR('?'), -1, -1
5920 Xalpha_a, TRUE, FALSE,
5921 EL_CHAR('A'), -1, -1
5924 Xalpha_b, TRUE, FALSE,
5925 EL_CHAR('B'), -1, -1
5928 Xalpha_c, TRUE, FALSE,
5929 EL_CHAR('C'), -1, -1
5932 Xalpha_d, TRUE, FALSE,
5933 EL_CHAR('D'), -1, -1
5936 Xalpha_e, TRUE, FALSE,
5937 EL_CHAR('E'), -1, -1
5940 Xalpha_f, TRUE, FALSE,
5941 EL_CHAR('F'), -1, -1
5944 Xalpha_g, TRUE, FALSE,
5945 EL_CHAR('G'), -1, -1
5948 Xalpha_h, TRUE, FALSE,
5949 EL_CHAR('H'), -1, -1
5952 Xalpha_i, TRUE, FALSE,
5953 EL_CHAR('I'), -1, -1
5956 Xalpha_j, TRUE, FALSE,
5957 EL_CHAR('J'), -1, -1
5960 Xalpha_k, TRUE, FALSE,
5961 EL_CHAR('K'), -1, -1
5964 Xalpha_l, TRUE, FALSE,
5965 EL_CHAR('L'), -1, -1
5968 Xalpha_m, TRUE, FALSE,
5969 EL_CHAR('M'), -1, -1
5972 Xalpha_n, TRUE, FALSE,
5973 EL_CHAR('N'), -1, -1
5976 Xalpha_o, TRUE, FALSE,
5977 EL_CHAR('O'), -1, -1
5980 Xalpha_p, TRUE, FALSE,
5981 EL_CHAR('P'), -1, -1
5984 Xalpha_q, TRUE, FALSE,
5985 EL_CHAR('Q'), -1, -1
5988 Xalpha_r, TRUE, FALSE,
5989 EL_CHAR('R'), -1, -1
5992 Xalpha_s, TRUE, FALSE,
5993 EL_CHAR('S'), -1, -1
5996 Xalpha_t, TRUE, FALSE,
5997 EL_CHAR('T'), -1, -1
6000 Xalpha_u, TRUE, FALSE,
6001 EL_CHAR('U'), -1, -1
6004 Xalpha_v, TRUE, FALSE,
6005 EL_CHAR('V'), -1, -1
6008 Xalpha_w, TRUE, FALSE,
6009 EL_CHAR('W'), -1, -1
6012 Xalpha_x, TRUE, FALSE,
6013 EL_CHAR('X'), -1, -1
6016 Xalpha_y, TRUE, FALSE,
6017 EL_CHAR('Y'), -1, -1
6020 Xalpha_z, TRUE, FALSE,
6021 EL_CHAR('Z'), -1, -1
6024 Xalpha_arrow_e, TRUE, FALSE,
6025 EL_CHAR('>'), -1, -1
6028 Xalpha_arrow_w, TRUE, FALSE,
6029 EL_CHAR('<'), -1, -1
6032 Xalpha_copyr, TRUE, FALSE,
6033 EL_CHAR('©'), -1, -1
6037 Xboom_bug, FALSE, FALSE,
6038 EL_BUG, ACTION_EXPLODING, -1
6041 Xboom_bomb, FALSE, FALSE,
6042 EL_BOMB, ACTION_EXPLODING, -1
6045 Xboom_android, FALSE, FALSE,
6046 EL_EMC_ANDROID, ACTION_OTHER, -1
6049 Xboom_1, FALSE, FALSE,
6050 EL_DEFAULT, ACTION_EXPLODING, -1
6053 Xboom_2, FALSE, FALSE,
6054 EL_DEFAULT, ACTION_EXPLODING, -1
6057 Znormal, FALSE, FALSE,
6061 Zdynamite, FALSE, FALSE,
6065 Zplayer, FALSE, FALSE,
6069 ZBORDER, FALSE, FALSE,
6079 static struct Mapping_EM_to_RND_player
6088 em_player_mapping_list[] =
6092 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
6096 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
6100 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
6104 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
6108 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
6112 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
6116 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
6120 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
6124 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
6128 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
6132 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
6136 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
6140 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
6144 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
6148 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
6152 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
6156 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
6160 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
6164 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
6168 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
6172 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
6176 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
6180 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
6184 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
6188 EL_PLAYER_1, ACTION_DEFAULT, -1,
6192 EL_PLAYER_2, ACTION_DEFAULT, -1,
6196 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
6200 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
6204 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
6208 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
6212 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
6216 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
6220 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
6224 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
6228 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
6232 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
6236 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
6240 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
6244 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
6248 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
6252 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
6256 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
6260 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
6264 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
6268 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
6272 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
6276 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
6280 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
6284 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
6288 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
6292 EL_PLAYER_3, ACTION_DEFAULT, -1,
6296 EL_PLAYER_4, ACTION_DEFAULT, -1,
6305 int map_element_RND_to_EM(int element_rnd)
6307 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
6308 static boolean mapping_initialized = FALSE;
6310 if (!mapping_initialized)
6314 /* return "Xalpha_quest" for all undefined elements in mapping array */
6315 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
6316 mapping_RND_to_EM[i] = Xalpha_quest;
6318 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6319 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
6320 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
6321 em_object_mapping_list[i].element_em;
6323 mapping_initialized = TRUE;
6326 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
6327 return mapping_RND_to_EM[element_rnd];
6329 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
6334 int map_element_EM_to_RND(int element_em)
6336 static unsigned short mapping_EM_to_RND[TILE_MAX];
6337 static boolean mapping_initialized = FALSE;
6339 if (!mapping_initialized)
6343 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
6344 for (i = 0; i < TILE_MAX; i++)
6345 mapping_EM_to_RND[i] = EL_UNKNOWN;
6347 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6348 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
6349 em_object_mapping_list[i].element_rnd;
6351 mapping_initialized = TRUE;
6354 if (element_em >= 0 && element_em < TILE_MAX)
6355 return mapping_EM_to_RND[element_em];
6357 Error(ERR_WARN, "invalid EM level element %d", element_em);
6362 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
6364 struct LevelInfo_EM *level_em = level->native_em_level;
6365 struct LEVEL *lev = level_em->lev;
6368 for (i = 0; i < TILE_MAX; i++)
6369 lev->android_array[i] = Xblank;
6371 for (i = 0; i < level->num_android_clone_elements; i++)
6373 int element_rnd = level->android_clone_element[i];
6374 int element_em = map_element_RND_to_EM(element_rnd);
6376 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
6377 if (em_object_mapping_list[j].element_rnd == element_rnd)
6378 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
6382 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
6384 struct LevelInfo_EM *level_em = level->native_em_level;
6385 struct LEVEL *lev = level_em->lev;
6388 level->num_android_clone_elements = 0;
6390 for (i = 0; i < TILE_MAX; i++)
6392 int element_em = lev->android_array[i];
6394 boolean element_found = FALSE;
6396 if (element_em == Xblank)
6399 element_rnd = map_element_EM_to_RND(element_em);
6401 for (j = 0; j < level->num_android_clone_elements; j++)
6402 if (level->android_clone_element[j] == element_rnd)
6403 element_found = TRUE;
6407 level->android_clone_element[level->num_android_clone_elements++] =
6410 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
6415 if (level->num_android_clone_elements == 0)
6417 level->num_android_clone_elements = 1;
6418 level->android_clone_element[0] = EL_EMPTY;
6422 int map_direction_RND_to_EM(int direction)
6424 return (direction == MV_UP ? 0 :
6425 direction == MV_RIGHT ? 1 :
6426 direction == MV_DOWN ? 2 :
6427 direction == MV_LEFT ? 3 :
6431 int map_direction_EM_to_RND(int direction)
6433 return (direction == 0 ? MV_UP :
6434 direction == 1 ? MV_RIGHT :
6435 direction == 2 ? MV_DOWN :
6436 direction == 3 ? MV_LEFT :
6440 int map_element_RND_to_SP(int element_rnd)
6442 int element_sp = 0x20; /* map unknown elements to yellow "hardware" */
6444 if (element_rnd >= EL_SP_START &&
6445 element_rnd <= EL_SP_END)
6446 element_sp = element_rnd - EL_SP_START;
6447 else if (element_rnd == EL_EMPTY_SPACE)
6449 else if (element_rnd == EL_INVISIBLE_WALL)
6455 int map_element_SP_to_RND(int element_sp)
6457 int element_rnd = EL_UNKNOWN;
6459 if (element_sp >= 0x00 &&
6461 element_rnd = EL_SP_START + element_sp;
6462 else if (element_sp == 0x28)
6463 element_rnd = EL_INVISIBLE_WALL;
6468 int map_action_SP_to_RND(int action_sp)
6472 case actActive: return ACTION_ACTIVE;
6473 case actImpact: return ACTION_IMPACT;
6474 case actExploding: return ACTION_EXPLODING;
6475 case actDigging: return ACTION_DIGGING;
6476 case actSnapping: return ACTION_SNAPPING;
6477 case actCollecting: return ACTION_COLLECTING;
6478 case actPassing: return ACTION_PASSING;
6479 case actPushing: return ACTION_PUSHING;
6480 case actDropping: return ACTION_DROPPING;
6482 default: return ACTION_DEFAULT;
6486 int get_next_element(int element)
6490 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
6491 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
6492 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
6493 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
6494 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
6495 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
6496 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
6497 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
6498 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
6499 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
6500 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
6502 default: return element;
6507 int el_act_dir2img(int element, int action, int direction)
6509 element = GFX_ELEMENT(element);
6511 if (direction == MV_NONE)
6512 return element_info[element].graphic[action];
6514 direction = MV_DIR_TO_BIT(direction);
6516 return element_info[element].direction_graphic[action][direction];
6519 int el_act_dir2img(int element, int action, int direction)
6521 element = GFX_ELEMENT(element);
6522 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
6524 /* direction_graphic[][] == graphic[] for undefined direction graphics */
6525 return element_info[element].direction_graphic[action][direction];
6530 static int el_act_dir2crm(int element, int action, int direction)
6532 element = GFX_ELEMENT(element);
6534 if (direction == MV_NONE)
6535 return element_info[element].crumbled[action];
6537 direction = MV_DIR_TO_BIT(direction);
6539 return element_info[element].direction_crumbled[action][direction];
6542 static int el_act_dir2crm(int element, int action, int direction)
6544 element = GFX_ELEMENT(element);
6545 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
6547 /* direction_graphic[][] == graphic[] for undefined direction graphics */
6548 return element_info[element].direction_crumbled[action][direction];
6552 int el_act2img(int element, int action)
6554 element = GFX_ELEMENT(element);
6556 return element_info[element].graphic[action];
6559 int el_act2crm(int element, int action)
6561 element = GFX_ELEMENT(element);
6563 return element_info[element].crumbled[action];
6566 int el_dir2img(int element, int direction)
6568 element = GFX_ELEMENT(element);
6570 return el_act_dir2img(element, ACTION_DEFAULT, direction);
6573 int el2baseimg(int element)
6575 return element_info[element].graphic[ACTION_DEFAULT];
6578 int el2img(int element)
6580 element = GFX_ELEMENT(element);
6582 return element_info[element].graphic[ACTION_DEFAULT];
6585 int el2edimg(int element)
6587 element = GFX_ELEMENT(element);
6589 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
6592 int el2preimg(int element)
6594 element = GFX_ELEMENT(element);
6596 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
6599 int el2panelimg(int element)
6601 element = GFX_ELEMENT(element);
6603 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL];
6606 int font2baseimg(int font_nr)
6608 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
6611 int getBeltNrFromBeltElement(int element)
6613 return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
6614 element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
6615 element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
6618 int getBeltNrFromBeltActiveElement(int element)
6620 return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
6621 element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
6622 element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
6625 int getBeltNrFromBeltSwitchElement(int element)
6627 return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
6628 element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
6629 element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
6632 int getBeltDirNrFromBeltElement(int element)
6634 static int belt_base_element[4] =
6636 EL_CONVEYOR_BELT_1_LEFT,
6637 EL_CONVEYOR_BELT_2_LEFT,
6638 EL_CONVEYOR_BELT_3_LEFT,
6639 EL_CONVEYOR_BELT_4_LEFT
6642 int belt_nr = getBeltNrFromBeltElement(element);
6643 int belt_dir_nr = element - belt_base_element[belt_nr];
6645 return (belt_dir_nr % 3);
6648 int getBeltDirNrFromBeltSwitchElement(int element)
6650 static int belt_base_element[4] =
6652 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
6653 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
6654 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
6655 EL_CONVEYOR_BELT_4_SWITCH_LEFT
6658 int belt_nr = getBeltNrFromBeltSwitchElement(element);
6659 int belt_dir_nr = element - belt_base_element[belt_nr];
6661 return (belt_dir_nr % 3);
6664 int getBeltDirFromBeltElement(int element)
6666 static int belt_move_dir[3] =
6673 int belt_dir_nr = getBeltDirNrFromBeltElement(element);
6675 return belt_move_dir[belt_dir_nr];
6678 int getBeltDirFromBeltSwitchElement(int element)
6680 static int belt_move_dir[3] =
6687 int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
6689 return belt_move_dir[belt_dir_nr];
6692 int getBeltElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
6694 static int belt_base_element[4] =
6696 EL_CONVEYOR_BELT_1_LEFT,
6697 EL_CONVEYOR_BELT_2_LEFT,
6698 EL_CONVEYOR_BELT_3_LEFT,
6699 EL_CONVEYOR_BELT_4_LEFT
6702 return belt_base_element[belt_nr] + belt_dir_nr;
6705 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
6707 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
6709 return getBeltElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
6712 int getBeltSwitchElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
6714 static int belt_base_element[4] =
6716 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
6717 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
6718 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
6719 EL_CONVEYOR_BELT_4_SWITCH_LEFT
6722 return belt_base_element[belt_nr] + belt_dir_nr;
6725 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
6727 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
6729 return getBeltSwitchElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
6732 int getNumActivePlayers_EM()
6734 int num_players = 0;
6740 for (i = 0; i < MAX_PLAYERS; i++)
6741 if (tape.player_participates[i])
6747 int getGameFrameDelay_EM(int native_em_game_frame_delay)
6749 int game_frame_delay_value;
6751 game_frame_delay_value =
6752 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
6753 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
6756 if (tape.playing && tape.warp_forward && !tape.pausing)
6757 game_frame_delay_value = 0;
6759 return game_frame_delay_value;
6762 unsigned int InitRND(long seed)
6764 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
6765 return InitEngineRandom_EM(seed);
6766 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
6767 return InitEngineRandom_SP(seed);
6769 return InitEngineRandom_RND(seed);
6773 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
6774 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
6777 inline static int get_effective_element_EM(int tile, int frame_em)
6779 int element = object_mapping[tile].element_rnd;
6780 int action = object_mapping[tile].action;
6781 boolean is_backside = object_mapping[tile].is_backside;
6782 boolean action_removing = (action == ACTION_DIGGING ||
6783 action == ACTION_SNAPPING ||
6784 action == ACTION_COLLECTING);
6790 case Yacid_splash_eB:
6791 case Yacid_splash_wB:
6792 return (frame_em > 5 ? EL_EMPTY : element);
6795 case Ydiamond_stone:
6796 // if (!game.use_native_emc_graphics_engine)
6804 else /* frame_em == 7 */
6808 case Yacid_splash_eB:
6809 case Yacid_splash_wB:
6812 case Yemerald_stone:
6815 case Ydiamond_stone:
6819 case Xdrip_stretchB:
6838 case Xsand_stonein_1:
6839 case Xsand_stonein_2:
6840 case Xsand_stonein_3:
6841 case Xsand_stonein_4:
6845 return (is_backside || action_removing ? EL_EMPTY : element);
6850 inline static boolean check_linear_animation_EM(int tile)
6854 case Xsand_stonesand_1:
6855 case Xsand_stonesand_quickout_1:
6856 case Xsand_sandstone_1:
6857 case Xsand_stonein_1:
6858 case Xsand_stoneout_1:
6878 case Yacid_splash_eB:
6879 case Yacid_splash_wB:
6880 case Yemerald_stone:
6888 inline static void set_crumbled_graphics_EM(struct GraphicInfo_EM *g_em,
6889 boolean has_crumbled_graphics,
6890 int crumbled, int sync_frame)
6892 /* if element can be crumbled, but certain action graphics are just empty
6893 space (like instantly snapping sand to empty space in 1 frame), do not
6894 treat these empty space graphics as crumbled graphics in EMC engine */
6895 if (crumbled == IMG_EMPTY_SPACE)
6896 has_crumbled_graphics = FALSE;
6898 if (has_crumbled_graphics)
6900 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
6901 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
6902 g_crumbled->anim_delay,
6903 g_crumbled->anim_mode,
6904 g_crumbled->anim_start_frame,
6907 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
6908 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
6910 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
6912 g_em->has_crumbled_graphics = TRUE;
6916 g_em->crumbled_bitmap = NULL;
6917 g_em->crumbled_src_x = 0;
6918 g_em->crumbled_src_y = 0;
6919 g_em->crumbled_border_size = 0;
6921 g_em->has_crumbled_graphics = FALSE;
6925 void ResetGfxAnimation_EM(int x, int y, int tile)
6930 void SetGfxAnimation_EM(struct GraphicInfo_EM *g_em,
6931 int tile, int frame_em, int x, int y)
6933 int action = object_mapping[tile].action;
6935 int direction = object_mapping[tile].direction;
6936 int effective_element = get_effective_element_EM(tile, frame_em);
6937 int graphic = (direction == MV_NONE ?
6938 el_act2img(effective_element, action) :
6939 el_act_dir2img(effective_element, action, direction));
6940 struct GraphicInfo *g = &graphic_info[graphic];
6943 boolean action_removing = (action == ACTION_DIGGING ||
6944 action == ACTION_SNAPPING ||
6945 action == ACTION_COLLECTING);
6946 boolean action_moving = (action == ACTION_FALLING ||
6947 action == ACTION_MOVING ||
6948 action == ACTION_PUSHING ||
6949 action == ACTION_EATING ||
6950 action == ACTION_FILLING ||
6951 action == ACTION_EMPTYING);
6952 boolean action_falling = (action == ACTION_FALLING ||
6953 action == ACTION_FILLING ||
6954 action == ACTION_EMPTYING);
6956 /* special case: graphic uses "2nd movement tile" and has defined
6957 7 frames for movement animation (or less) => use default graphic
6958 for last (8th) frame which ends the movement animation */
6959 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
6961 action = ACTION_DEFAULT; /* (keep action_* unchanged for now) */
6962 graphic = (direction == MV_NONE ?
6963 el_act2img(effective_element, action) :
6964 el_act_dir2img(effective_element, action, direction));
6966 g = &graphic_info[graphic];
6970 if (tile == Xsand_stonesand_1 ||
6971 tile == Xsand_stonesand_2 ||
6972 tile == Xsand_stonesand_3 ||
6973 tile == Xsand_stonesand_4)
6974 printf("::: 1: quicksand frame %d [%d]\n", GfxFrame[x][y], tile);
6978 if ((action_removing || check_linear_animation_EM(tile)) && frame_em == 0)
6982 // printf("::: resetting... [%d]\n", tile);
6985 if (action_removing || check_linear_animation_EM(tile))
6987 GfxFrame[x][y] = frame_em;
6989 // printf("::: resetting... [%d]\n", tile);
6992 else if (action_moving)
6994 boolean is_backside = object_mapping[tile].is_backside;
6998 int direction = object_mapping[tile].direction;
6999 int move_dir = (action_falling ? MV_DOWN : direction);
7004 /* !!! TEST !!! NEW !!! DOES NOT WORK RIGHT YET !!! */
7005 if (g->double_movement && frame_em == 0)
7009 // printf("::: resetting... [%d]\n", tile);
7013 if (move_dir == MV_LEFT)
7014 GfxFrame[x - 1][y] = GfxFrame[x][y];
7015 else if (move_dir == MV_RIGHT)
7016 GfxFrame[x + 1][y] = GfxFrame[x][y];
7017 else if (move_dir == MV_UP)
7018 GfxFrame[x][y - 1] = GfxFrame[x][y];
7019 else if (move_dir == MV_DOWN)
7020 GfxFrame[x][y + 1] = GfxFrame[x][y];
7027 /* special case: animation for Xsand_stonesand_quickout_1/2 twice as fast */
7028 if (tile == Xsand_stonesand_quickout_1 ||
7029 tile == Xsand_stonesand_quickout_2)
7034 if (tile == Xsand_stonesand_1 ||
7035 tile == Xsand_stonesand_2 ||
7036 tile == Xsand_stonesand_3 ||
7037 tile == Xsand_stonesand_4)
7038 printf("::: 2: quicksand frame %d [%d]\n", GfxFrame[x][y], tile);
7042 if (graphic_info[graphic].anim_global_sync)
7043 sync_frame = FrameCounter;
7044 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
7045 sync_frame = GfxFrame[x][y];
7047 sync_frame = 0; /* playfield border (pseudo steel) */
7049 SetRandomAnimationValue(x, y);
7051 int frame = getAnimationFrame(g->anim_frames,
7054 g->anim_start_frame,
7057 g_em->unique_identifier =
7058 (graphic << 16) | ((frame % 8) << 12) | (g_em->width << 6) | g_em->height;
7062 void getGraphicSourceObjectExt_EM(struct GraphicInfo_EM *g_em,
7063 int tile, int frame_em, int x, int y)
7065 int action = object_mapping[tile].action;
7066 int direction = object_mapping[tile].direction;
7067 boolean is_backside = object_mapping[tile].is_backside;
7068 int effective_element = get_effective_element_EM(tile, frame_em);
7070 int effective_action = action;
7072 int effective_action = (frame_em < 7 ? action : ACTION_DEFAULT);
7074 int graphic = (direction == MV_NONE ?
7075 el_act2img(effective_element, effective_action) :
7076 el_act_dir2img(effective_element, effective_action,
7078 int crumbled = (direction == MV_NONE ?
7079 el_act2crm(effective_element, effective_action) :
7080 el_act_dir2crm(effective_element, effective_action,
7082 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7083 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7084 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7085 struct GraphicInfo *g = &graphic_info[graphic];
7087 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
7091 /* special case: graphic uses "2nd movement tile" and has defined
7092 7 frames for movement animation (or less) => use default graphic
7093 for last (8th) frame which ends the movement animation */
7094 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
7096 effective_action = ACTION_DEFAULT;
7097 graphic = (direction == MV_NONE ?
7098 el_act2img(effective_element, effective_action) :
7099 el_act_dir2img(effective_element, effective_action,
7101 crumbled = (direction == MV_NONE ?
7102 el_act2crm(effective_element, effective_action) :
7103 el_act_dir2crm(effective_element, effective_action,
7106 g = &graphic_info[graphic];
7116 if (frame_em == 0) /* reset animation frame for certain elements */
7118 if (check_linear_animation_EM(tile))
7123 if (graphic_info[graphic].anim_global_sync)
7124 sync_frame = FrameCounter;
7125 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
7126 sync_frame = GfxFrame[x][y];
7128 sync_frame = 0; /* playfield border (pseudo steel) */
7130 SetRandomAnimationValue(x, y);
7135 int xxx_sync_frame = (i == Xdrip_stretch ? 7 :
7136 i == Xdrip_stretchB ? 7 :
7137 i == Ydrip_s2 ? j + 8 :
7138 i == Ydrip_s2B ? j + 8 :
7147 i == Xfake_acid_1 ? 0 :
7148 i == Xfake_acid_2 ? 10 :
7149 i == Xfake_acid_3 ? 20 :
7150 i == Xfake_acid_4 ? 30 :
7151 i == Xfake_acid_5 ? 40 :
7152 i == Xfake_acid_6 ? 50 :
7153 i == Xfake_acid_7 ? 60 :
7154 i == Xfake_acid_8 ? 70 :
7156 i == Xball_2B ? j + 8 :
7157 i == Yball_eat ? j + 1 :
7158 i == Ykey_1_eat ? j + 1 :
7159 i == Ykey_2_eat ? j + 1 :
7160 i == Ykey_3_eat ? j + 1 :
7161 i == Ykey_4_eat ? j + 1 :
7162 i == Ykey_5_eat ? j + 1 :
7163 i == Ykey_6_eat ? j + 1 :
7164 i == Ykey_7_eat ? j + 1 :
7165 i == Ykey_8_eat ? j + 1 :
7166 i == Ylenses_eat ? j + 1 :
7167 i == Ymagnify_eat ? j + 1 :
7168 i == Ygrass_eat ? j + 1 :
7169 i == Ydirt_eat ? j + 1 :
7170 i == Xamoeba_1 ? 0 :
7171 i == Xamoeba_2 ? 1 :
7172 i == Xamoeba_3 ? 2 :
7173 i == Xamoeba_4 ? 3 :
7174 i == Xamoeba_5 ? 0 :
7175 i == Xamoeba_6 ? 1 :
7176 i == Xamoeba_7 ? 2 :
7177 i == Xamoeba_8 ? 3 :
7178 i == Xexit_2 ? j + 8 :
7179 i == Xexit_3 ? j + 16 :
7180 i == Xdynamite_1 ? 0 :
7181 i == Xdynamite_2 ? 8 :
7182 i == Xdynamite_3 ? 16 :
7183 i == Xdynamite_4 ? 24 :
7184 i == Xsand_stonein_1 ? j + 1 :
7185 i == Xsand_stonein_2 ? j + 9 :
7186 i == Xsand_stonein_3 ? j + 17 :
7187 i == Xsand_stonein_4 ? j + 25 :
7188 i == Xsand_stoneout_1 && j == 0 ? 0 :
7189 i == Xsand_stoneout_1 && j == 1 ? 0 :
7190 i == Xsand_stoneout_1 && j == 2 ? 1 :
7191 i == Xsand_stoneout_1 && j == 3 ? 2 :
7192 i == Xsand_stoneout_1 && j == 4 ? 2 :
7193 i == Xsand_stoneout_1 && j == 5 ? 3 :
7194 i == Xsand_stoneout_1 && j == 6 ? 4 :
7195 i == Xsand_stoneout_1 && j == 7 ? 4 :
7196 i == Xsand_stoneout_2 && j == 0 ? 5 :
7197 i == Xsand_stoneout_2 && j == 1 ? 6 :
7198 i == Xsand_stoneout_2 && j == 2 ? 7 :
7199 i == Xsand_stoneout_2 && j == 3 ? 8 :
7200 i == Xsand_stoneout_2 && j == 4 ? 9 :
7201 i == Xsand_stoneout_2 && j == 5 ? 11 :
7202 i == Xsand_stoneout_2 && j == 6 ? 13 :
7203 i == Xsand_stoneout_2 && j == 7 ? 15 :
7204 i == Xboom_bug && j == 1 ? 2 :
7205 i == Xboom_bug && j == 2 ? 2 :
7206 i == Xboom_bug && j == 3 ? 4 :
7207 i == Xboom_bug && j == 4 ? 4 :
7208 i == Xboom_bug && j == 5 ? 2 :
7209 i == Xboom_bug && j == 6 ? 2 :
7210 i == Xboom_bug && j == 7 ? 0 :
7211 i == Xboom_bomb && j == 1 ? 2 :
7212 i == Xboom_bomb && j == 2 ? 2 :
7213 i == Xboom_bomb && j == 3 ? 4 :
7214 i == Xboom_bomb && j == 4 ? 4 :
7215 i == Xboom_bomb && j == 5 ? 2 :
7216 i == Xboom_bomb && j == 6 ? 2 :
7217 i == Xboom_bomb && j == 7 ? 0 :
7218 i == Xboom_android && j == 7 ? 6 :
7219 i == Xboom_1 && j == 1 ? 2 :
7220 i == Xboom_1 && j == 2 ? 2 :
7221 i == Xboom_1 && j == 3 ? 4 :
7222 i == Xboom_1 && j == 4 ? 4 :
7223 i == Xboom_1 && j == 5 ? 6 :
7224 i == Xboom_1 && j == 6 ? 6 :
7225 i == Xboom_1 && j == 7 ? 8 :
7226 i == Xboom_2 && j == 0 ? 8 :
7227 i == Xboom_2 && j == 1 ? 8 :
7228 i == Xboom_2 && j == 2 ? 10 :
7229 i == Xboom_2 && j == 3 ? 10 :
7230 i == Xboom_2 && j == 4 ? 10 :
7231 i == Xboom_2 && j == 5 ? 12 :
7232 i == Xboom_2 && j == 6 ? 12 :
7233 i == Xboom_2 && j == 7 ? 12 :
7235 special_animation && j == 4 ? 3 :
7236 effective_action != action ? 0 :
7242 int xxx_effective_action;
7243 int xxx_has_action_graphics;
7246 int element = object_mapping[i].element_rnd;
7247 int action = object_mapping[i].action;
7248 int direction = object_mapping[i].direction;
7249 boolean is_backside = object_mapping[i].is_backside;
7251 boolean action_removing = (action == ACTION_DIGGING ||
7252 action == ACTION_SNAPPING ||
7253 action == ACTION_COLLECTING);
7255 boolean action_exploding = ((action == ACTION_EXPLODING ||
7256 action == ACTION_SMASHED_BY_ROCK ||
7257 action == ACTION_SMASHED_BY_SPRING) &&
7258 element != EL_DIAMOND);
7259 boolean action_active = (action == ACTION_ACTIVE);
7260 boolean action_other = (action == ACTION_OTHER);
7264 int effective_element = get_effective_element_EM(i, j);
7266 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
7267 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
7269 i == Xdrip_stretch ? element :
7270 i == Xdrip_stretchB ? element :
7271 i == Ydrip_s1 ? element :
7272 i == Ydrip_s1B ? element :
7273 i == Xball_1B ? element :
7274 i == Xball_2 ? element :
7275 i == Xball_2B ? element :
7276 i == Yball_eat ? element :
7277 i == Ykey_1_eat ? element :
7278 i == Ykey_2_eat ? element :
7279 i == Ykey_3_eat ? element :
7280 i == Ykey_4_eat ? element :
7281 i == Ykey_5_eat ? element :
7282 i == Ykey_6_eat ? element :
7283 i == Ykey_7_eat ? element :
7284 i == Ykey_8_eat ? element :
7285 i == Ylenses_eat ? element :
7286 i == Ymagnify_eat ? element :
7287 i == Ygrass_eat ? element :
7288 i == Ydirt_eat ? element :
7289 i == Yemerald_stone ? EL_EMERALD :
7290 i == Ydiamond_stone ? EL_ROCK :
7291 i == Xsand_stonein_1 ? element :
7292 i == Xsand_stonein_2 ? element :
7293 i == Xsand_stonein_3 ? element :
7294 i == Xsand_stonein_4 ? element :
7295 is_backside ? EL_EMPTY :
7296 action_removing ? EL_EMPTY :
7299 int effective_action = (j < 7 ? action :
7300 i == Xdrip_stretch ? action :
7301 i == Xdrip_stretchB ? action :
7302 i == Ydrip_s1 ? action :
7303 i == Ydrip_s1B ? action :
7304 i == Xball_1B ? action :
7305 i == Xball_2 ? action :
7306 i == Xball_2B ? action :
7307 i == Yball_eat ? action :
7308 i == Ykey_1_eat ? action :
7309 i == Ykey_2_eat ? action :
7310 i == Ykey_3_eat ? action :
7311 i == Ykey_4_eat ? action :
7312 i == Ykey_5_eat ? action :
7313 i == Ykey_6_eat ? action :
7314 i == Ykey_7_eat ? action :
7315 i == Ykey_8_eat ? action :
7316 i == Ylenses_eat ? action :
7317 i == Ymagnify_eat ? action :
7318 i == Ygrass_eat ? action :
7319 i == Ydirt_eat ? action :
7320 i == Xsand_stonein_1 ? action :
7321 i == Xsand_stonein_2 ? action :
7322 i == Xsand_stonein_3 ? action :
7323 i == Xsand_stonein_4 ? action :
7324 i == Xsand_stoneout_1 ? action :
7325 i == Xsand_stoneout_2 ? action :
7326 i == Xboom_android ? ACTION_EXPLODING :
7327 action_exploding ? ACTION_EXPLODING :
7328 action_active ? action :
7329 action_other ? action :
7331 int graphic = (el_act_dir2img(effective_element, effective_action,
7333 int crumbled = (el_act_dir2crm(effective_element, effective_action,
7335 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7336 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7337 boolean has_action_graphics = (graphic != base_graphic);
7338 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7339 struct GraphicInfo *g = &graphic_info[graphic];
7341 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
7343 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7346 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
7347 boolean special_animation = (action != ACTION_DEFAULT &&
7348 g->anim_frames == 3 &&
7349 g->anim_delay == 2 &&
7350 g->anim_mode & ANIM_LINEAR);
7351 xxx_sync_frame = (i == Xdrip_stretch ? 7 :
7352 i == Xdrip_stretchB ? 7 :
7353 i == Ydrip_s2 ? j + 8 :
7354 i == Ydrip_s2B ? j + 8 :
7363 i == Xfake_acid_1 ? 0 :
7364 i == Xfake_acid_2 ? 10 :
7365 i == Xfake_acid_3 ? 20 :
7366 i == Xfake_acid_4 ? 30 :
7367 i == Xfake_acid_5 ? 40 :
7368 i == Xfake_acid_6 ? 50 :
7369 i == Xfake_acid_7 ? 60 :
7370 i == Xfake_acid_8 ? 70 :
7372 i == Xball_2B ? j + 8 :
7373 i == Yball_eat ? j + 1 :
7374 i == Ykey_1_eat ? j + 1 :
7375 i == Ykey_2_eat ? j + 1 :
7376 i == Ykey_3_eat ? j + 1 :
7377 i == Ykey_4_eat ? j + 1 :
7378 i == Ykey_5_eat ? j + 1 :
7379 i == Ykey_6_eat ? j + 1 :
7380 i == Ykey_7_eat ? j + 1 :
7381 i == Ykey_8_eat ? j + 1 :
7382 i == Ylenses_eat ? j + 1 :
7383 i == Ymagnify_eat ? j + 1 :
7384 i == Ygrass_eat ? j + 1 :
7385 i == Ydirt_eat ? j + 1 :
7386 i == Xamoeba_1 ? 0 :
7387 i == Xamoeba_2 ? 1 :
7388 i == Xamoeba_3 ? 2 :
7389 i == Xamoeba_4 ? 3 :
7390 i == Xamoeba_5 ? 0 :
7391 i == Xamoeba_6 ? 1 :
7392 i == Xamoeba_7 ? 2 :
7393 i == Xamoeba_8 ? 3 :
7394 i == Xexit_2 ? j + 8 :
7395 i == Xexit_3 ? j + 16 :
7396 i == Xdynamite_1 ? 0 :
7397 i == Xdynamite_2 ? 8 :
7398 i == Xdynamite_3 ? 16 :
7399 i == Xdynamite_4 ? 24 :
7400 i == Xsand_stonein_1 ? j + 1 :
7401 i == Xsand_stonein_2 ? j + 9 :
7402 i == Xsand_stonein_3 ? j + 17 :
7403 i == Xsand_stonein_4 ? j + 25 :
7404 i == Xsand_stoneout_1 && j == 0 ? 0 :
7405 i == Xsand_stoneout_1 && j == 1 ? 0 :
7406 i == Xsand_stoneout_1 && j == 2 ? 1 :
7407 i == Xsand_stoneout_1 && j == 3 ? 2 :
7408 i == Xsand_stoneout_1 && j == 4 ? 2 :
7409 i == Xsand_stoneout_1 && j == 5 ? 3 :
7410 i == Xsand_stoneout_1 && j == 6 ? 4 :
7411 i == Xsand_stoneout_1 && j == 7 ? 4 :
7412 i == Xsand_stoneout_2 && j == 0 ? 5 :
7413 i == Xsand_stoneout_2 && j == 1 ? 6 :
7414 i == Xsand_stoneout_2 && j == 2 ? 7 :
7415 i == Xsand_stoneout_2 && j == 3 ? 8 :
7416 i == Xsand_stoneout_2 && j == 4 ? 9 :
7417 i == Xsand_stoneout_2 && j == 5 ? 11 :
7418 i == Xsand_stoneout_2 && j == 6 ? 13 :
7419 i == Xsand_stoneout_2 && j == 7 ? 15 :
7420 i == Xboom_bug && j == 1 ? 2 :
7421 i == Xboom_bug && j == 2 ? 2 :
7422 i == Xboom_bug && j == 3 ? 4 :
7423 i == Xboom_bug && j == 4 ? 4 :
7424 i == Xboom_bug && j == 5 ? 2 :
7425 i == Xboom_bug && j == 6 ? 2 :
7426 i == Xboom_bug && j == 7 ? 0 :
7427 i == Xboom_bomb && j == 1 ? 2 :
7428 i == Xboom_bomb && j == 2 ? 2 :
7429 i == Xboom_bomb && j == 3 ? 4 :
7430 i == Xboom_bomb && j == 4 ? 4 :
7431 i == Xboom_bomb && j == 5 ? 2 :
7432 i == Xboom_bomb && j == 6 ? 2 :
7433 i == Xboom_bomb && j == 7 ? 0 :
7434 i == Xboom_android && j == 7 ? 6 :
7435 i == Xboom_1 && j == 1 ? 2 :
7436 i == Xboom_1 && j == 2 ? 2 :
7437 i == Xboom_1 && j == 3 ? 4 :
7438 i == Xboom_1 && j == 4 ? 4 :
7439 i == Xboom_1 && j == 5 ? 6 :
7440 i == Xboom_1 && j == 6 ? 6 :
7441 i == Xboom_1 && j == 7 ? 8 :
7442 i == Xboom_2 && j == 0 ? 8 :
7443 i == Xboom_2 && j == 1 ? 8 :
7444 i == Xboom_2 && j == 2 ? 10 :
7445 i == Xboom_2 && j == 3 ? 10 :
7446 i == Xboom_2 && j == 4 ? 10 :
7447 i == Xboom_2 && j == 5 ? 12 :
7448 i == Xboom_2 && j == 6 ? 12 :
7449 i == Xboom_2 && j == 7 ? 12 :
7450 special_animation && j == 4 ? 3 :
7451 effective_action != action ? 0 :
7454 xxx_effective_action = effective_action;
7455 xxx_has_action_graphics = has_action_graphics;
7460 int frame = getAnimationFrame(g->anim_frames,
7463 g->anim_start_frame,
7477 int old_src_x = g_em->src_x;
7478 int old_src_y = g_em->src_y;
7482 getGraphicSourceExt(graphic, frame, &g_em->bitmap, &g_em->src_x, &g_em->src_y,
7483 g->double_movement && is_backside);
7485 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
7486 &g_em->src_x, &g_em->src_y, FALSE);
7491 if (tile == Ydiamond_stone)
7492 printf("::: stone smashing diamond... %d: %d, %d, %d, %d, %d -> %d [%d, %d, %d, %d, %d, %d] [%d]\n",
7497 g->anim_start_frame,
7500 g_em->src_x, g_em->src_y,
7501 g_em->src_offset_x, g_em->src_offset_y,
7502 g_em->dst_offset_x, g_em->dst_offset_y,
7514 if (graphic == IMG_BUG_MOVING_RIGHT)
7515 printf("::: %d, %d, %d: %d, %d [%d, %d -> %d, %d]\n", graphic, x, y,
7516 g->double_movement, is_backside,
7517 old_src_x, old_src_y, g_em->src_x, g_em->src_y);
7525 g_em->src_offset_x = 0;
7526 g_em->src_offset_y = 0;
7527 g_em->dst_offset_x = 0;
7528 g_em->dst_offset_y = 0;
7529 g_em->width = TILEX;
7530 g_em->height = TILEY;
7532 g_em->preserve_background = FALSE;
7535 /* (updating the "crumbled" graphic definitions is probably not really needed,
7536 as animations for crumbled graphics can't be longer than one EMC cycle) */
7538 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
7543 g_em->crumbled_bitmap = NULL;
7544 g_em->crumbled_src_x = 0;
7545 g_em->crumbled_src_y = 0;
7547 g_em->has_crumbled_graphics = FALSE;
7549 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
7551 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
7552 g_crumbled->anim_delay,
7553 g_crumbled->anim_mode,
7554 g_crumbled->anim_start_frame,
7557 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
7558 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
7560 g_em->has_crumbled_graphics = TRUE;
7566 int effective_action = xxx_effective_action;
7567 int has_action_graphics = xxx_has_action_graphics;
7569 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
7570 effective_action == ACTION_MOVING ||
7571 effective_action == ACTION_PUSHING ||
7572 effective_action == ACTION_EATING)) ||
7573 (!has_action_graphics && (effective_action == ACTION_FILLING ||
7574 effective_action == ACTION_EMPTYING)))
7577 (effective_action == ACTION_FALLING ||
7578 effective_action == ACTION_FILLING ||
7579 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
7580 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
7581 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
7582 int num_steps = (i == Ydrip_s1 ? 16 :
7583 i == Ydrip_s1B ? 16 :
7584 i == Ydrip_s2 ? 16 :
7585 i == Ydrip_s2B ? 16 :
7586 i == Xsand_stonein_1 ? 32 :
7587 i == Xsand_stonein_2 ? 32 :
7588 i == Xsand_stonein_3 ? 32 :
7589 i == Xsand_stonein_4 ? 32 :
7590 i == Xsand_stoneout_1 ? 16 :
7591 i == Xsand_stoneout_2 ? 16 : 8);
7592 int cx = ABS(dx) * (TILEX / num_steps);
7593 int cy = ABS(dy) * (TILEY / num_steps);
7594 int step_frame = (i == Ydrip_s2 ? j + 8 :
7595 i == Ydrip_s2B ? j + 8 :
7596 i == Xsand_stonein_2 ? j + 8 :
7597 i == Xsand_stonein_3 ? j + 16 :
7598 i == Xsand_stonein_4 ? j + 24 :
7599 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
7600 int step = (is_backside ? step_frame : num_steps - step_frame);
7602 if (is_backside) /* tile where movement starts */
7604 if (dx < 0 || dy < 0)
7606 g_em->src_offset_x = cx * step;
7607 g_em->src_offset_y = cy * step;
7611 g_em->dst_offset_x = cx * step;
7612 g_em->dst_offset_y = cy * step;
7615 else /* tile where movement ends */
7617 if (dx < 0 || dy < 0)
7619 g_em->dst_offset_x = cx * step;
7620 g_em->dst_offset_y = cy * step;
7624 g_em->src_offset_x = cx * step;
7625 g_em->src_offset_y = cy * step;
7629 g_em->width = TILEX - cx * step;
7630 g_em->height = TILEY - cy * step;
7633 /* create unique graphic identifier to decide if tile must be redrawn */
7634 /* bit 31 - 16 (16 bit): EM style graphic
7635 bit 15 - 12 ( 4 bit): EM style frame
7636 bit 11 - 6 ( 6 bit): graphic width
7637 bit 5 - 0 ( 6 bit): graphic height */
7638 g_em->unique_identifier =
7639 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
7645 void getGraphicSourcePlayerExt_EM(struct GraphicInfo_EM *g_em,
7646 int player_nr, int anim, int frame_em)
7648 int element = player_mapping[player_nr][anim].element_rnd;
7649 int action = player_mapping[player_nr][anim].action;
7650 int direction = player_mapping[player_nr][anim].direction;
7651 int graphic = (direction == MV_NONE ?
7652 el_act2img(element, action) :
7653 el_act_dir2img(element, action, direction));
7654 struct GraphicInfo *g = &graphic_info[graphic];
7657 InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
7659 stored_player[player_nr].StepFrame = frame_em;
7661 sync_frame = stored_player[player_nr].Frame;
7663 int frame = getAnimationFrame(g->anim_frames,
7666 g->anim_start_frame,
7669 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
7670 &g_em->src_x, &g_em->src_y, FALSE);
7673 printf("::: %d: %d, %d [%d]\n",
7675 stored_player[player_nr].Frame,
7676 stored_player[player_nr].StepFrame,
7681 void InitGraphicInfo_EM(void)
7684 struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
7685 struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
7690 int num_em_gfx_errors = 0;
7692 if (graphic_info_em_object[0][0].bitmap == NULL)
7694 /* EM graphics not yet initialized in em_open_all() */
7699 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
7702 /* always start with reliable default values */
7703 for (i = 0; i < TILE_MAX; i++)
7705 object_mapping[i].element_rnd = EL_UNKNOWN;
7706 object_mapping[i].is_backside = FALSE;
7707 object_mapping[i].action = ACTION_DEFAULT;
7708 object_mapping[i].direction = MV_NONE;
7711 /* always start with reliable default values */
7712 for (p = 0; p < MAX_PLAYERS; p++)
7714 for (i = 0; i < SPR_MAX; i++)
7716 player_mapping[p][i].element_rnd = EL_UNKNOWN;
7717 player_mapping[p][i].action = ACTION_DEFAULT;
7718 player_mapping[p][i].direction = MV_NONE;
7722 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
7724 int e = em_object_mapping_list[i].element_em;
7726 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
7727 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
7729 if (em_object_mapping_list[i].action != -1)
7730 object_mapping[e].action = em_object_mapping_list[i].action;
7732 if (em_object_mapping_list[i].direction != -1)
7733 object_mapping[e].direction =
7734 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
7737 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
7739 int a = em_player_mapping_list[i].action_em;
7740 int p = em_player_mapping_list[i].player_nr;
7742 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
7744 if (em_player_mapping_list[i].action != -1)
7745 player_mapping[p][a].action = em_player_mapping_list[i].action;
7747 if (em_player_mapping_list[i].direction != -1)
7748 player_mapping[p][a].direction =
7749 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
7752 for (i = 0; i < TILE_MAX; i++)
7754 int element = object_mapping[i].element_rnd;
7755 int action = object_mapping[i].action;
7756 int direction = object_mapping[i].direction;
7757 boolean is_backside = object_mapping[i].is_backside;
7759 boolean action_removing = (action == ACTION_DIGGING ||
7760 action == ACTION_SNAPPING ||
7761 action == ACTION_COLLECTING);
7763 boolean action_exploding = ((action == ACTION_EXPLODING ||
7764 action == ACTION_SMASHED_BY_ROCK ||
7765 action == ACTION_SMASHED_BY_SPRING) &&
7766 element != EL_DIAMOND);
7767 boolean action_active = (action == ACTION_ACTIVE);
7768 boolean action_other = (action == ACTION_OTHER);
7770 for (j = 0; j < 8; j++)
7773 int effective_element = get_effective_element_EM(i, j);
7775 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
7776 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
7778 i == Xdrip_stretch ? element :
7779 i == Xdrip_stretchB ? element :
7780 i == Ydrip_s1 ? element :
7781 i == Ydrip_s1B ? element :
7782 i == Xball_1B ? element :
7783 i == Xball_2 ? element :
7784 i == Xball_2B ? element :
7785 i == Yball_eat ? element :
7786 i == Ykey_1_eat ? element :
7787 i == Ykey_2_eat ? element :
7788 i == Ykey_3_eat ? element :
7789 i == Ykey_4_eat ? element :
7790 i == Ykey_5_eat ? element :
7791 i == Ykey_6_eat ? element :
7792 i == Ykey_7_eat ? element :
7793 i == Ykey_8_eat ? element :
7794 i == Ylenses_eat ? element :
7795 i == Ymagnify_eat ? element :
7796 i == Ygrass_eat ? element :
7797 i == Ydirt_eat ? element :
7798 i == Yemerald_stone ? EL_EMERALD :
7799 i == Ydiamond_stone ? EL_ROCK :
7800 i == Xsand_stonein_1 ? element :
7801 i == Xsand_stonein_2 ? element :
7802 i == Xsand_stonein_3 ? element :
7803 i == Xsand_stonein_4 ? element :
7804 is_backside ? EL_EMPTY :
7805 action_removing ? EL_EMPTY :
7808 int effective_action = (j < 7 ? action :
7809 i == Xdrip_stretch ? action :
7810 i == Xdrip_stretchB ? action :
7811 i == Ydrip_s1 ? action :
7812 i == Ydrip_s1B ? action :
7813 i == Xball_1B ? action :
7814 i == Xball_2 ? action :
7815 i == Xball_2B ? action :
7816 i == Yball_eat ? action :
7817 i == Ykey_1_eat ? action :
7818 i == Ykey_2_eat ? action :
7819 i == Ykey_3_eat ? action :
7820 i == Ykey_4_eat ? action :
7821 i == Ykey_5_eat ? action :
7822 i == Ykey_6_eat ? action :
7823 i == Ykey_7_eat ? action :
7824 i == Ykey_8_eat ? action :
7825 i == Ylenses_eat ? action :
7826 i == Ymagnify_eat ? action :
7827 i == Ygrass_eat ? action :
7828 i == Ydirt_eat ? action :
7829 i == Xsand_stonein_1 ? action :
7830 i == Xsand_stonein_2 ? action :
7831 i == Xsand_stonein_3 ? action :
7832 i == Xsand_stonein_4 ? action :
7833 i == Xsand_stoneout_1 ? action :
7834 i == Xsand_stoneout_2 ? action :
7835 i == Xboom_android ? ACTION_EXPLODING :
7836 action_exploding ? ACTION_EXPLODING :
7837 action_active ? action :
7838 action_other ? action :
7840 int graphic = (el_act_dir2img(effective_element, effective_action,
7842 int crumbled = (el_act_dir2crm(effective_element, effective_action,
7844 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7845 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7846 boolean has_action_graphics = (graphic != base_graphic);
7847 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7848 struct GraphicInfo *g = &graphic_info[graphic];
7850 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
7852 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7855 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
7856 boolean special_animation = (action != ACTION_DEFAULT &&
7857 g->anim_frames == 3 &&
7858 g->anim_delay == 2 &&
7859 g->anim_mode & ANIM_LINEAR);
7860 int sync_frame = (i == Xdrip_stretch ? 7 :
7861 i == Xdrip_stretchB ? 7 :
7862 i == Ydrip_s2 ? j + 8 :
7863 i == Ydrip_s2B ? j + 8 :
7872 i == Xfake_acid_1 ? 0 :
7873 i == Xfake_acid_2 ? 10 :
7874 i == Xfake_acid_3 ? 20 :
7875 i == Xfake_acid_4 ? 30 :
7876 i == Xfake_acid_5 ? 40 :
7877 i == Xfake_acid_6 ? 50 :
7878 i == Xfake_acid_7 ? 60 :
7879 i == Xfake_acid_8 ? 70 :
7881 i == Xball_2B ? j + 8 :
7882 i == Yball_eat ? j + 1 :
7883 i == Ykey_1_eat ? j + 1 :
7884 i == Ykey_2_eat ? j + 1 :
7885 i == Ykey_3_eat ? j + 1 :
7886 i == Ykey_4_eat ? j + 1 :
7887 i == Ykey_5_eat ? j + 1 :
7888 i == Ykey_6_eat ? j + 1 :
7889 i == Ykey_7_eat ? j + 1 :
7890 i == Ykey_8_eat ? j + 1 :
7891 i == Ylenses_eat ? j + 1 :
7892 i == Ymagnify_eat ? j + 1 :
7893 i == Ygrass_eat ? j + 1 :
7894 i == Ydirt_eat ? j + 1 :
7895 i == Xamoeba_1 ? 0 :
7896 i == Xamoeba_2 ? 1 :
7897 i == Xamoeba_3 ? 2 :
7898 i == Xamoeba_4 ? 3 :
7899 i == Xamoeba_5 ? 0 :
7900 i == Xamoeba_6 ? 1 :
7901 i == Xamoeba_7 ? 2 :
7902 i == Xamoeba_8 ? 3 :
7903 i == Xexit_2 ? j + 8 :
7904 i == Xexit_3 ? j + 16 :
7905 i == Xdynamite_1 ? 0 :
7906 i == Xdynamite_2 ? 8 :
7907 i == Xdynamite_3 ? 16 :
7908 i == Xdynamite_4 ? 24 :
7909 i == Xsand_stonein_1 ? j + 1 :
7910 i == Xsand_stonein_2 ? j + 9 :
7911 i == Xsand_stonein_3 ? j + 17 :
7912 i == Xsand_stonein_4 ? j + 25 :
7913 i == Xsand_stoneout_1 && j == 0 ? 0 :
7914 i == Xsand_stoneout_1 && j == 1 ? 0 :
7915 i == Xsand_stoneout_1 && j == 2 ? 1 :
7916 i == Xsand_stoneout_1 && j == 3 ? 2 :
7917 i == Xsand_stoneout_1 && j == 4 ? 2 :
7918 i == Xsand_stoneout_1 && j == 5 ? 3 :
7919 i == Xsand_stoneout_1 && j == 6 ? 4 :
7920 i == Xsand_stoneout_1 && j == 7 ? 4 :
7921 i == Xsand_stoneout_2 && j == 0 ? 5 :
7922 i == Xsand_stoneout_2 && j == 1 ? 6 :
7923 i == Xsand_stoneout_2 && j == 2 ? 7 :
7924 i == Xsand_stoneout_2 && j == 3 ? 8 :
7925 i == Xsand_stoneout_2 && j == 4 ? 9 :
7926 i == Xsand_stoneout_2 && j == 5 ? 11 :
7927 i == Xsand_stoneout_2 && j == 6 ? 13 :
7928 i == Xsand_stoneout_2 && j == 7 ? 15 :
7929 i == Xboom_bug && j == 1 ? 2 :
7930 i == Xboom_bug && j == 2 ? 2 :
7931 i == Xboom_bug && j == 3 ? 4 :
7932 i == Xboom_bug && j == 4 ? 4 :
7933 i == Xboom_bug && j == 5 ? 2 :
7934 i == Xboom_bug && j == 6 ? 2 :
7935 i == Xboom_bug && j == 7 ? 0 :
7936 i == Xboom_bomb && j == 1 ? 2 :
7937 i == Xboom_bomb && j == 2 ? 2 :
7938 i == Xboom_bomb && j == 3 ? 4 :
7939 i == Xboom_bomb && j == 4 ? 4 :
7940 i == Xboom_bomb && j == 5 ? 2 :
7941 i == Xboom_bomb && j == 6 ? 2 :
7942 i == Xboom_bomb && j == 7 ? 0 :
7943 i == Xboom_android && j == 7 ? 6 :
7944 i == Xboom_1 && j == 1 ? 2 :
7945 i == Xboom_1 && j == 2 ? 2 :
7946 i == Xboom_1 && j == 3 ? 4 :
7947 i == Xboom_1 && j == 4 ? 4 :
7948 i == Xboom_1 && j == 5 ? 6 :
7949 i == Xboom_1 && j == 6 ? 6 :
7950 i == Xboom_1 && j == 7 ? 8 :
7951 i == Xboom_2 && j == 0 ? 8 :
7952 i == Xboom_2 && j == 1 ? 8 :
7953 i == Xboom_2 && j == 2 ? 10 :
7954 i == Xboom_2 && j == 3 ? 10 :
7955 i == Xboom_2 && j == 4 ? 10 :
7956 i == Xboom_2 && j == 5 ? 12 :
7957 i == Xboom_2 && j == 6 ? 12 :
7958 i == Xboom_2 && j == 7 ? 12 :
7959 special_animation && j == 4 ? 3 :
7960 effective_action != action ? 0 :
7964 Bitmap *debug_bitmap = g_em->bitmap;
7965 int debug_src_x = g_em->src_x;
7966 int debug_src_y = g_em->src_y;
7969 int frame = getAnimationFrame(g->anim_frames,
7972 g->anim_start_frame,
7975 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
7976 g->double_movement && is_backside);
7978 g_em->bitmap = src_bitmap;
7979 g_em->src_x = src_x;
7980 g_em->src_y = src_y;
7981 g_em->src_offset_x = 0;
7982 g_em->src_offset_y = 0;
7983 g_em->dst_offset_x = 0;
7984 g_em->dst_offset_y = 0;
7985 g_em->width = TILEX;
7986 g_em->height = TILEY;
7988 g_em->preserve_background = FALSE;
7991 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
7996 g_em->crumbled_bitmap = NULL;
7997 g_em->crumbled_src_x = 0;
7998 g_em->crumbled_src_y = 0;
7999 g_em->crumbled_border_size = 0;
8001 g_em->has_crumbled_graphics = FALSE;
8004 if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
8005 printf("::: empty crumbled: %d [%s], %d, %d\n",
8006 effective_element, element_info[effective_element].token_name,
8007 effective_action, direction);
8010 /* if element can be crumbled, but certain action graphics are just empty
8011 space (like instantly snapping sand to empty space in 1 frame), do not
8012 treat these empty space graphics as crumbled graphics in EMC engine */
8013 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
8015 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
8016 g_crumbled->anim_delay,
8017 g_crumbled->anim_mode,
8018 g_crumbled->anim_start_frame,
8021 getGraphicSource(crumbled, frame_crumbled, &src_bitmap, &src_x, &src_y);
8023 g_em->has_crumbled_graphics = TRUE;
8024 g_em->crumbled_bitmap = src_bitmap;
8025 g_em->crumbled_src_x = src_x;
8026 g_em->crumbled_src_y = src_y;
8027 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
8031 if (g_em == &graphic_info_em_object[207][0])
8032 printf("... %d, %d [%d, %d, %d, %d] [%d, %d, %d, %d, %d, %d => %d]\n",
8033 graphic_info_em_object[207][0].crumbled_src_x,
8034 graphic_info_em_object[207][0].crumbled_src_y,
8036 crumbled, frame, src_x, src_y,
8041 g->anim_start_frame,
8043 gfx.anim_random_frame,
8048 printf("::: EMC tile %d is crumbled\n", i);
8054 if (element == EL_ROCK &&
8055 effective_action == ACTION_FILLING)
8056 printf("::: has_action_graphics == %d\n", has_action_graphics);
8059 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
8060 effective_action == ACTION_MOVING ||
8061 effective_action == ACTION_PUSHING ||
8062 effective_action == ACTION_EATING)) ||
8063 (!has_action_graphics && (effective_action == ACTION_FILLING ||
8064 effective_action == ACTION_EMPTYING)))
8067 (effective_action == ACTION_FALLING ||
8068 effective_action == ACTION_FILLING ||
8069 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
8070 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
8071 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
8072 int num_steps = (i == Ydrip_s1 ? 16 :
8073 i == Ydrip_s1B ? 16 :
8074 i == Ydrip_s2 ? 16 :
8075 i == Ydrip_s2B ? 16 :
8076 i == Xsand_stonein_1 ? 32 :
8077 i == Xsand_stonein_2 ? 32 :
8078 i == Xsand_stonein_3 ? 32 :
8079 i == Xsand_stonein_4 ? 32 :
8080 i == Xsand_stoneout_1 ? 16 :
8081 i == Xsand_stoneout_2 ? 16 : 8);
8082 int cx = ABS(dx) * (TILEX / num_steps);
8083 int cy = ABS(dy) * (TILEY / num_steps);
8084 int step_frame = (i == Ydrip_s2 ? j + 8 :
8085 i == Ydrip_s2B ? j + 8 :
8086 i == Xsand_stonein_2 ? j + 8 :
8087 i == Xsand_stonein_3 ? j + 16 :
8088 i == Xsand_stonein_4 ? j + 24 :
8089 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
8090 int step = (is_backside ? step_frame : num_steps - step_frame);
8092 if (is_backside) /* tile where movement starts */
8094 if (dx < 0 || dy < 0)
8096 g_em->src_offset_x = cx * step;
8097 g_em->src_offset_y = cy * step;
8101 g_em->dst_offset_x = cx * step;
8102 g_em->dst_offset_y = cy * step;
8105 else /* tile where movement ends */
8107 if (dx < 0 || dy < 0)
8109 g_em->dst_offset_x = cx * step;
8110 g_em->dst_offset_y = cy * step;
8114 g_em->src_offset_x = cx * step;
8115 g_em->src_offset_y = cy * step;
8119 g_em->width = TILEX - cx * step;
8120 g_em->height = TILEY - cy * step;
8123 /* create unique graphic identifier to decide if tile must be redrawn */
8124 /* bit 31 - 16 (16 bit): EM style graphic
8125 bit 15 - 12 ( 4 bit): EM style frame
8126 bit 11 - 6 ( 6 bit): graphic width
8127 bit 5 - 0 ( 6 bit): graphic height */
8128 g_em->unique_identifier =
8129 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
8133 /* skip check for EMC elements not contained in original EMC artwork */
8134 if (element == EL_EMC_FAKE_ACID)
8137 if (g_em->bitmap != debug_bitmap ||
8138 g_em->src_x != debug_src_x ||
8139 g_em->src_y != debug_src_y ||
8140 g_em->src_offset_x != 0 ||
8141 g_em->src_offset_y != 0 ||
8142 g_em->dst_offset_x != 0 ||
8143 g_em->dst_offset_y != 0 ||
8144 g_em->width != TILEX ||
8145 g_em->height != TILEY)
8147 static int last_i = -1;
8155 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
8156 i, element, element_info[element].token_name,
8157 element_action_info[effective_action].suffix, direction);
8159 if (element != effective_element)
8160 printf(" [%d ('%s')]",
8162 element_info[effective_element].token_name);
8166 if (g_em->bitmap != debug_bitmap)
8167 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
8168 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
8170 if (g_em->src_x != debug_src_x ||
8171 g_em->src_y != debug_src_y)
8172 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
8173 j, (is_backside ? 'B' : 'F'),
8174 g_em->src_x, g_em->src_y,
8175 g_em->src_x / 32, g_em->src_y / 32,
8176 debug_src_x, debug_src_y,
8177 debug_src_x / 32, debug_src_y / 32);
8179 if (g_em->src_offset_x != 0 ||
8180 g_em->src_offset_y != 0 ||
8181 g_em->dst_offset_x != 0 ||
8182 g_em->dst_offset_y != 0)
8183 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
8185 g_em->src_offset_x, g_em->src_offset_y,
8186 g_em->dst_offset_x, g_em->dst_offset_y);
8188 if (g_em->width != TILEX ||
8189 g_em->height != TILEY)
8190 printf(" %d (%d): size %d,%d should be %d,%d\n",
8192 g_em->width, g_em->height, TILEX, TILEY);
8194 num_em_gfx_errors++;
8201 for (i = 0; i < TILE_MAX; i++)
8203 for (j = 0; j < 8; j++)
8205 int element = object_mapping[i].element_rnd;
8206 int action = object_mapping[i].action;
8207 int direction = object_mapping[i].direction;
8208 boolean is_backside = object_mapping[i].is_backside;
8209 int graphic_action = el_act_dir2img(element, action, direction);
8210 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
8212 if ((action == ACTION_SMASHED_BY_ROCK ||
8213 action == ACTION_SMASHED_BY_SPRING ||
8214 action == ACTION_EATING) &&
8215 graphic_action == graphic_default)
8217 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
8218 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
8219 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
8220 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
8223 /* no separate animation for "smashed by rock" -- use rock instead */
8224 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
8225 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
8227 g_em->bitmap = g_xx->bitmap;
8228 g_em->src_x = g_xx->src_x;
8229 g_em->src_y = g_xx->src_y;
8230 g_em->src_offset_x = g_xx->src_offset_x;
8231 g_em->src_offset_y = g_xx->src_offset_y;
8232 g_em->dst_offset_x = g_xx->dst_offset_x;
8233 g_em->dst_offset_y = g_xx->dst_offset_y;
8234 g_em->width = g_xx->width;
8235 g_em->height = g_xx->height;
8236 g_em->unique_identifier = g_xx->unique_identifier;
8239 g_em->preserve_background = TRUE;
8244 for (p = 0; p < MAX_PLAYERS; p++)
8246 for (i = 0; i < SPR_MAX; i++)
8248 int element = player_mapping[p][i].element_rnd;
8249 int action = player_mapping[p][i].action;
8250 int direction = player_mapping[p][i].direction;
8252 for (j = 0; j < 8; j++)
8254 int effective_element = element;
8255 int effective_action = action;
8256 int graphic = (direction == MV_NONE ?
8257 el_act2img(effective_element, effective_action) :
8258 el_act_dir2img(effective_element, effective_action,
8260 struct GraphicInfo *g = &graphic_info[graphic];
8261 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
8267 Bitmap *debug_bitmap = g_em->bitmap;
8268 int debug_src_x = g_em->src_x;
8269 int debug_src_y = g_em->src_y;
8272 int frame = getAnimationFrame(g->anim_frames,
8275 g->anim_start_frame,
8278 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
8280 g_em->bitmap = src_bitmap;
8281 g_em->src_x = src_x;
8282 g_em->src_y = src_y;
8283 g_em->src_offset_x = 0;
8284 g_em->src_offset_y = 0;
8285 g_em->dst_offset_x = 0;
8286 g_em->dst_offset_y = 0;
8287 g_em->width = TILEX;
8288 g_em->height = TILEY;
8292 /* skip check for EMC elements not contained in original EMC artwork */
8293 if (element == EL_PLAYER_3 ||
8294 element == EL_PLAYER_4)
8297 if (g_em->bitmap != debug_bitmap ||
8298 g_em->src_x != debug_src_x ||
8299 g_em->src_y != debug_src_y)
8301 static int last_i = -1;
8309 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
8310 p, i, element, element_info[element].token_name,
8311 element_action_info[effective_action].suffix, direction);
8313 if (element != effective_element)
8314 printf(" [%d ('%s')]",
8316 element_info[effective_element].token_name);
8320 if (g_em->bitmap != debug_bitmap)
8321 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
8322 j, (int)(g_em->bitmap), (int)(debug_bitmap));
8324 if (g_em->src_x != debug_src_x ||
8325 g_em->src_y != debug_src_y)
8326 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
8328 g_em->src_x, g_em->src_y,
8329 g_em->src_x / 32, g_em->src_y / 32,
8330 debug_src_x, debug_src_y,
8331 debug_src_x / 32, debug_src_y / 32);
8333 num_em_gfx_errors++;
8343 printf("::: [%d errors found]\n", num_em_gfx_errors);
8349 void CheckSingleStepMode_EM(byte action[MAX_PLAYERS], int frame,
8350 boolean any_player_moving,
8351 boolean player_is_dropping)
8355 if (tape.single_step && tape.recording && !tape.pausing)
8357 boolean active_players = FALSE;
8359 for (i = 0; i < MAX_PLAYERS; i++)
8360 if (action[i] != JOY_NO_ACTION)
8361 active_players = TRUE;
8364 if (frame == 0 && !player_is_dropping)
8365 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
8369 void CheckSingleStepMode_SP(boolean murphy_is_waiting,
8370 boolean murphy_is_dropping)
8373 printf("::: waiting: %d, dropping: %d\n",
8374 murphy_is_waiting, murphy_is_dropping);
8377 if (tape.single_step && tape.recording && !tape.pausing)
8379 // if (murphy_is_waiting || murphy_is_dropping)
8380 if (murphy_is_waiting)
8383 printf("::: murphy is waiting -> pause mode\n");
8386 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
8391 void getGraphicSource_SP(struct GraphicInfo_SP *g_sp,
8392 int graphic, int sync_frame, int x, int y)
8394 int frame = getGraphicAnimationFrame(graphic, sync_frame);
8396 getGraphicSource(graphic, frame, &g_sp->bitmap, &g_sp->src_x, &g_sp->src_y);
8399 boolean isNextAnimationFrame_SP(int graphic, int sync_frame)
8401 return (IS_NEXT_FRAME(sync_frame, graphic));
8404 int getGraphicInfo_Delay(int graphic)
8406 return graphic_info[graphic].anim_delay;
8409 void PlayMenuSoundExt(int sound)
8411 if (sound == SND_UNDEFINED)
8414 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8415 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8418 if (IS_LOOP_SOUND(sound))
8419 PlaySoundLoop(sound);
8424 void PlayMenuSound()
8426 PlayMenuSoundExt(menu.sound[game_status]);
8429 void PlayMenuSoundStereo(int sound, int stereo_position)
8431 if (sound == SND_UNDEFINED)
8434 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8435 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8438 if (IS_LOOP_SOUND(sound))
8439 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
8441 PlaySoundStereo(sound, stereo_position);
8444 void PlayMenuSoundIfLoopExt(int sound)
8446 if (sound == SND_UNDEFINED)
8449 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8450 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8453 if (IS_LOOP_SOUND(sound))
8454 PlaySoundLoop(sound);
8457 void PlayMenuSoundIfLoop()
8459 PlayMenuSoundIfLoopExt(menu.sound[game_status]);
8462 void PlayMenuMusicExt(int music)
8464 if (music == MUS_UNDEFINED)
8467 if (!setup.sound_music)
8473 void PlayMenuMusic()
8475 PlayMenuMusicExt(menu.music[game_status]);
8478 void PlaySoundActivating()
8481 PlaySound(SND_MENU_ITEM_ACTIVATING);
8485 void PlaySoundSelecting()
8488 PlaySound(SND_MENU_ITEM_SELECTING);
8492 void ToggleFullscreenIfNeeded()
8494 boolean change_fullscreen = (setup.fullscreen !=
8495 video.fullscreen_enabled);
8496 boolean change_fullscreen_mode = (video.fullscreen_enabled &&
8497 !strEqual(setup.fullscreen_mode,
8498 video.fullscreen_mode_current));
8500 if (!video.fullscreen_available)
8503 if (change_fullscreen || change_fullscreen_mode)
8505 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
8507 /* save backbuffer content which gets lost when toggling fullscreen mode */
8508 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8510 if (change_fullscreen_mode)
8512 /* keep fullscreen, but change fullscreen mode (screen resolution) */
8513 video.fullscreen_enabled = FALSE; /* force new fullscreen mode */
8516 /* toggle fullscreen */
8517 ChangeVideoModeIfNeeded(setup.fullscreen);
8519 setup.fullscreen = video.fullscreen_enabled;
8521 /* restore backbuffer content from temporary backbuffer backup bitmap */
8522 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8524 FreeBitmap(tmp_backbuffer);
8527 /* update visible window/screen */
8528 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8530 redraw_mask = REDRAW_ALL;
8535 void ChangeViewportPropertiesIfNeeded()
8537 int *door_1_x = &DX;
8538 int *door_1_y = &DY;
8539 int *door_2_x = (game_status == GAME_MODE_EDITOR ? &EX : &VX);
8540 int *door_2_y = (game_status == GAME_MODE_EDITOR ? &EY : &VY);
8541 int gfx_game_mode = (game_status == GAME_MODE_PLAYING ||
8542 game_status == GAME_MODE_EDITOR ? game_status :
8544 struct RectWithBorder *vp_playfield = &viewport.playfield[gfx_game_mode];
8545 struct RectWithBorder *vp_door_1 = &viewport.door_1[gfx_game_mode];
8546 struct RectWithBorder *vp_door_2 = &viewport.door_2[gfx_game_mode];
8547 int border_size = vp_playfield->border_size;
8548 int new_sx = vp_playfield->x + border_size;
8549 int new_sy = vp_playfield->y + border_size;
8550 int new_scr_fieldx = (vp_playfield->width - 2 * border_size) / TILESIZE;
8551 int new_scr_fieldy = (vp_playfield->height - 2 * border_size) / TILESIZE;
8554 /* !!! TEST ONLY !!! */
8555 // InitGfxBuffers();
8559 if (viewport.window.width != WIN_XSIZE ||
8560 viewport.window.height != WIN_YSIZE)
8562 WIN_XSIZE = viewport.window.width;
8563 WIN_YSIZE = viewport.window.height;
8565 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
8569 SetDrawDeactivationMask(REDRAW_NONE);
8570 SetDrawBackgroundMask(REDRAW_FIELD);
8572 // RedrawBackground();
8576 if (new_scr_fieldx != SCR_FIELDX ||
8577 new_scr_fieldy != SCR_FIELDY ||
8580 vp_playfield->x != REAL_SX ||
8581 vp_playfield->y != REAL_SY ||
8582 vp_door_1->x != *door_1_x ||
8583 vp_door_1->y != *door_1_y ||
8584 vp_door_2->x != *door_2_x ||
8585 vp_door_2->y != *door_2_y)
8587 SCR_FIELDX = new_scr_fieldx;
8588 SCR_FIELDY = new_scr_fieldy;
8591 REAL_SX = vp_playfield->x;
8592 REAL_SY = vp_playfield->y;
8594 *door_1_x = vp_door_1->x;
8595 *door_1_y = vp_door_1->y;
8596 *door_2_x = vp_door_2->x;
8597 *door_2_y = vp_door_2->y;
8601 if (gfx_game_mode == GAME_MODE_MAIN)
8609 printf("::: %d, %d / %d, %d [%d]\n", VX, VY, EX, EY, game_status);