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()
798 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, bitmap_db_panel,
799 DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, 0, 0);
801 SetDoorBackgroundBitmap(bitmap_db_panel);
804 void DrawBackground(int x, int y, int width, int height)
806 /* !!! "drawto" might still point to playfield buffer here (see below) !!! */
807 /* (when entering hall of fame after playing) */
809 ClearRectangleOnBackground(drawto, x, y, width, height);
811 ClearRectangleOnBackground(backbuffer, x, y, width, height);
814 redraw_mask |= REDRAW_FIELD;
817 void DrawBackgroundForFont(int x, int y, int width, int height, int font_nr)
819 struct FontBitmapInfo *font = getFontBitmapInfo(font_nr);
821 if (font->bitmap == NULL)
824 DrawBackground(x, y, width, height);
827 void DrawBackgroundForGraphic(int x, int y, int width, int height, int graphic)
829 struct GraphicInfo *g = &graphic_info[graphic];
831 if (g->bitmap == NULL)
834 DrawBackground(x, y, width, height);
839 /* !!! "drawto" might still point to playfield buffer here (see above) !!! */
840 /* (when entering hall of fame after playing) */
841 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
843 /* !!! maybe this should be done before clearing the background !!! */
844 if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
846 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
847 SetDrawtoField(DRAW_BUFFERED);
850 SetDrawtoField(DRAW_BACKBUFFER);
853 void MarkTileDirty(int x, int y)
855 int xx = redraw_x1 + x;
856 int yy = redraw_y1 + y;
861 redraw[xx][yy] = TRUE;
862 redraw_mask |= REDRAW_TILES;
865 void SetBorderElement()
869 BorderElement = EL_EMPTY;
871 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
873 for (x = 0; x < lev_fieldx; x++)
875 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
876 BorderElement = EL_STEELWALL;
878 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
884 void FloodFillLevel(int from_x, int from_y, int fill_element,
885 short field[MAX_LEV_FIELDX][MAX_LEV_FIELDY],
886 int max_fieldx, int max_fieldy)
890 static int check[4][2] = { { -1, 0 }, { 0, -1 }, { 1, 0 }, { 0, 1 } };
891 static int safety = 0;
893 /* check if starting field still has the desired content */
894 if (field[from_x][from_y] == fill_element)
899 if (safety > max_fieldx * max_fieldy)
900 Error(ERR_EXIT, "Something went wrong in 'FloodFill()'. Please debug.");
902 old_element = field[from_x][from_y];
903 field[from_x][from_y] = fill_element;
905 for (i = 0; i < 4; i++)
907 x = from_x + check[i][0];
908 y = from_y + check[i][1];
910 if (IN_FIELD(x, y, max_fieldx, max_fieldy) && field[x][y] == old_element)
911 FloodFillLevel(x, y, fill_element, field, max_fieldx, max_fieldy);
917 void SetRandomAnimationValue(int x, int y)
919 gfx.anim_random_frame = GfxRandom[x][y];
922 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
924 /* animation synchronized with global frame counter, not move position */
925 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
926 sync_frame = FrameCounter;
928 return getAnimationFrame(graphic_info[graphic].anim_frames,
929 graphic_info[graphic].anim_delay,
930 graphic_info[graphic].anim_mode,
931 graphic_info[graphic].anim_start_frame,
935 void getSizedGraphicSource(int graphic, int frame, int tilesize_raw,
936 Bitmap **bitmap, int *x, int *y)
940 int width_mult, width_div;
941 int height_mult, height_div;
945 { 15, 16, 2, 3 }, /* 1 x 1 */
946 { 7, 8, 2, 3 }, /* 2 x 2 */
947 { 3, 4, 2, 3 }, /* 4 x 4 */
948 { 1, 2, 2, 3 }, /* 8 x 8 */
949 { 0, 1, 2, 3 }, /* 16 x 16 */
950 { 0, 1, 0, 1 }, /* 32 x 32 */
952 struct GraphicInfo *g = &graphic_info[graphic];
953 Bitmap *src_bitmap = g->bitmap;
954 int tilesize = MIN(MAX(1, tilesize_raw), TILESIZE);
955 int offset_calc_pos = log_2(tilesize);
956 int width_mult = offset_calc[offset_calc_pos].width_mult;
957 int width_div = offset_calc[offset_calc_pos].width_div;
958 int height_mult = offset_calc[offset_calc_pos].height_mult;
959 int height_div = offset_calc[offset_calc_pos].height_div;
960 int startx = src_bitmap->width * width_mult / width_div;
961 int starty = src_bitmap->height * height_mult / height_div;
962 int src_x = g->src_x * tilesize / TILESIZE;
963 int src_y = g->src_y * tilesize / TILESIZE;
964 int width = g->width * tilesize / TILESIZE;
965 int height = g->height * tilesize / TILESIZE;
966 int offset_x = g->offset_x * tilesize / TILESIZE;
967 int offset_y = g->offset_y * tilesize / TILESIZE;
969 if (g->offset_y == 0) /* frames are ordered horizontally */
971 int max_width = g->anim_frames_per_line * width;
972 int pos = (src_y / height) * max_width + src_x + frame * offset_x;
974 src_x = pos % max_width;
975 src_y = src_y % height + pos / max_width * height;
977 else if (g->offset_x == 0) /* frames are ordered vertically */
979 int max_height = g->anim_frames_per_line * height;
980 int pos = (src_x / width) * max_height + src_y + frame * offset_y;
982 src_x = src_x % width + pos / max_height * width;
983 src_y = pos % max_height;
985 else /* frames are ordered diagonally */
987 src_x = src_x + frame * offset_x;
988 src_y = src_y + frame * offset_y;
991 *bitmap = src_bitmap;
996 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
999 getSizedGraphicSource(graphic, 0, MINI_TILESIZE, bitmap, x, y);
1001 struct GraphicInfo *g = &graphic_info[graphic];
1002 int mini_startx = 0;
1003 int mini_starty = g->bitmap->height * 2 / 3;
1005 *bitmap = g->bitmap;
1006 *x = mini_startx + g->src_x / 2;
1007 *y = mini_starty + g->src_y / 2;
1011 inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1012 int *x, int *y, boolean get_backside)
1014 struct GraphicInfo *g = &graphic_info[graphic];
1015 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
1016 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
1018 *bitmap = g->bitmap;
1020 if (g->offset_y == 0) /* frames are ordered horizontally */
1022 int max_width = g->anim_frames_per_line * g->width;
1023 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
1025 *x = pos % max_width;
1026 *y = src_y % g->height + pos / max_width * g->height;
1028 else if (g->offset_x == 0) /* frames are ordered vertically */
1030 int max_height = g->anim_frames_per_line * g->height;
1031 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
1033 *x = src_x % g->width + pos / max_height * g->width;
1034 *y = pos % max_height;
1036 else /* frames are ordered diagonally */
1038 *x = src_x + frame * g->offset_x;
1039 *y = src_y + frame * g->offset_y;
1043 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
1045 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
1048 void DrawGraphic(int x, int y, int graphic, int frame)
1051 if (!IN_SCR_FIELD(x, y))
1053 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1054 printf("DrawGraphic(): This should never happen!\n");
1059 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
1060 MarkTileDirty(x, y);
1063 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1069 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1070 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
1073 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
1076 if (!IN_SCR_FIELD(x, y))
1078 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1079 printf("DrawGraphicThruMask(): This should never happen!\n");
1084 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
1086 MarkTileDirty(x, y);
1089 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
1095 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1097 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1098 dst_x - src_x, dst_y - src_y);
1099 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
1102 void DrawSizedGraphic(int x, int y, int graphic, int frame, int tilesize)
1104 DrawSizedGraphicExt(drawto, SX + x * tilesize, SY + y * tilesize, graphic,
1106 MarkTileDirty(x / tilesize, y / tilesize);
1109 void DrawSizedGraphicExt(DrawBuffer *d, int x, int y, int graphic, int frame,
1115 getSizedGraphicSource(graphic, frame, tilesize, &src_bitmap, &src_x, &src_y);
1116 BlitBitmap(src_bitmap, d, src_x, src_y, tilesize, tilesize, x, y);
1119 void DrawMiniGraphic(int x, int y, int graphic)
1121 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
1122 MarkTileDirty(x / 2, y / 2);
1125 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
1130 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1131 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
1134 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
1135 int graphic, int frame,
1136 int cut_mode, int mask_mode)
1141 int width = TILEX, height = TILEY;
1144 if (dx || dy) /* shifted graphic */
1146 if (x < BX1) /* object enters playfield from the left */
1153 else if (x > BX2) /* object enters playfield from the right */
1159 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
1165 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
1167 else if (dx) /* general horizontal movement */
1168 MarkTileDirty(x + SIGN(dx), y);
1170 if (y < BY1) /* object enters playfield from the top */
1172 if (cut_mode==CUT_BELOW) /* object completely above top border */
1180 else if (y > BY2) /* object enters playfield from the bottom */
1186 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
1192 else if (dy > 0 && cut_mode == CUT_ABOVE)
1194 if (y == BY2) /* object completely above bottom border */
1200 MarkTileDirty(x, y + 1);
1201 } /* object leaves playfield to the bottom */
1202 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1204 else if (dy) /* general vertical movement */
1205 MarkTileDirty(x, y + SIGN(dy));
1209 if (!IN_SCR_FIELD(x, y))
1211 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1212 printf("DrawGraphicShifted(): This should never happen!\n");
1217 if (width > 0 && height > 0)
1219 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1224 dst_x = FX + x * TILEX + dx;
1225 dst_y = FY + y * TILEY + dy;
1227 if (mask_mode == USE_MASKING)
1229 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1230 dst_x - src_x, dst_y - src_y);
1231 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1235 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1238 MarkTileDirty(x, y);
1242 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
1243 int graphic, int frame,
1244 int cut_mode, int mask_mode)
1249 int width = TILEX, height = TILEY;
1252 int x2 = x + SIGN(dx);
1253 int y2 = y + SIGN(dy);
1255 /* !!! DOES NOT WORK FOR SLOW MOVEMENT !!! */
1256 int sync_frame = GfxFrame[LEVELX(x)][LEVELY(y)];
1258 /* movement with two-tile animations must be sync'ed with movement position,
1259 not with current GfxFrame (which can be higher when using slow movement) */
1260 int anim_pos = (dx ? ABS(dx) : ABS(dy));
1261 int anim_frames = graphic_info[graphic].anim_frames;
1263 /* (we also need anim_delay here for movement animations with less frames) */
1264 int anim_delay = graphic_info[graphic].anim_delay;
1265 int sync_frame = anim_pos * anim_frames * anim_delay / TILESIZE;
1267 int sync_frame = anim_pos * anim_frames / TILESIZE;
1270 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
1271 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
1273 /* re-calculate animation frame for two-tile movement animation */
1274 frame = getGraphicAnimationFrame(graphic, sync_frame);
1278 printf("::: %d, %d, %d => %d [%d]\n",
1279 anim_pos, anim_frames, anim_delay, sync_frame, graphic);
1281 printf("::: %d, %d => %d\n",
1282 anim_pos, anim_frames, sync_frame);
1287 printf("::: %d [%d, %d] [%d] [%d]\n", frame, sync_frame, dy,
1288 GfxFrame[LEVELX(x)][LEVELY(y)], mask_mode);
1291 /* check if movement start graphic inside screen area and should be drawn */
1292 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
1294 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
1296 dst_x = FX + x1 * TILEX;
1297 dst_y = FY + y1 * TILEY;
1299 if (mask_mode == USE_MASKING)
1301 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1302 dst_x - src_x, dst_y - src_y);
1303 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1307 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1310 MarkTileDirty(x1, y1);
1313 /* check if movement end graphic inside screen area and should be drawn */
1314 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
1316 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
1318 dst_x = FX + x2 * TILEX;
1319 dst_y = FY + y2 * TILEY;
1321 if (mask_mode == USE_MASKING)
1323 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1324 dst_x - src_x, dst_y - src_y);
1325 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1329 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1332 MarkTileDirty(x2, y2);
1336 static void DrawGraphicShifted(int x, int y, int dx, int dy,
1337 int graphic, int frame,
1338 int cut_mode, int mask_mode)
1342 DrawGraphic(x, y, graphic, frame);
1347 if (graphic_info[graphic].double_movement) /* EM style movement images */
1348 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1350 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1353 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1354 int frame, int cut_mode)
1356 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
1359 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1360 int cut_mode, int mask_mode)
1362 int lx = LEVELX(x), ly = LEVELY(y);
1366 if (IN_LEV_FIELD(lx, ly))
1368 SetRandomAnimationValue(lx, ly);
1370 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
1371 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1373 /* do not use double (EM style) movement graphic when not moving */
1374 if (graphic_info[graphic].double_movement && !dx && !dy)
1376 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
1377 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1380 else /* border element */
1382 graphic = el2img(element);
1383 frame = getGraphicAnimationFrame(graphic, -1);
1386 if (element == EL_EXPANDABLE_WALL)
1388 boolean left_stopped = FALSE, right_stopped = FALSE;
1390 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1391 left_stopped = TRUE;
1392 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1393 right_stopped = TRUE;
1395 if (left_stopped && right_stopped)
1397 else if (left_stopped)
1399 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1400 frame = graphic_info[graphic].anim_frames - 1;
1402 else if (right_stopped)
1404 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1405 frame = graphic_info[graphic].anim_frames - 1;
1410 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1411 else if (mask_mode == USE_MASKING)
1412 DrawGraphicThruMask(x, y, graphic, frame);
1414 DrawGraphic(x, y, graphic, frame);
1417 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1418 int cut_mode, int mask_mode)
1420 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1421 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1422 cut_mode, mask_mode);
1425 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1428 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1431 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1434 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1437 void DrawLevelElementThruMask(int x, int y, int element)
1439 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1442 void DrawLevelFieldThruMask(int x, int y)
1444 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1447 /* !!! implementation of quicksand is totally broken !!! */
1448 #define IS_CRUMBLED_TILE(x, y, e) \
1449 (GFX_CRUMBLED(e) && (!IN_LEV_FIELD(x, y) || \
1450 !IS_MOVING(x, y) || \
1451 (e) == EL_QUICKSAND_EMPTYING || \
1452 (e) == EL_QUICKSAND_FAST_EMPTYING))
1454 static void DrawLevelFieldCrumbledInnerCorners(int x, int y, int dx, int dy,
1459 int width, height, cx, cy;
1460 int sx = SCREENX(x), sy = SCREENY(y);
1461 int crumbled_border_size = graphic_info[graphic].border_size;
1464 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1466 for (i = 1; i < 4; i++)
1468 int dxx = (i & 1 ? dx : 0);
1469 int dyy = (i & 2 ? dy : 0);
1472 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1475 /* check if neighbour field is of same crumble type */
1476 boolean same = (IS_CRUMBLED_TILE(xx, yy, element) &&
1477 graphic_info[graphic].class ==
1478 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class);
1480 /* return if check prevents inner corner */
1481 if (same == (dxx == dx && dyy == dy))
1485 /* if we reach this point, we have an inner corner */
1487 getGraphicSource(graphic, 1, &src_bitmap, &src_x, &src_y);
1489 width = crumbled_border_size;
1490 height = crumbled_border_size;
1491 cx = (dx > 0 ? TILEX - crumbled_border_size : 0);
1492 cy = (dy > 0 ? TILEY - crumbled_border_size : 0);
1494 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1495 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1498 static void DrawLevelFieldCrumbledBorders(int x, int y, int graphic, int frame,
1503 int width, height, bx, by, cx, cy;
1504 int sx = SCREENX(x), sy = SCREENY(y);
1505 int crumbled_border_size = graphic_info[graphic].border_size;
1508 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1510 /* draw simple, sloppy, non-corner-accurate crumbled border */
1513 width = (dir == 1 || dir == 2 ? crumbled_border_size : TILEX);
1514 height = (dir == 0 || dir == 3 ? crumbled_border_size : TILEY);
1515 cx = (dir == 2 ? TILEX - crumbled_border_size : 0);
1516 cy = (dir == 3 ? TILEY - crumbled_border_size : 0);
1518 if (dir == 1 || dir == 2) /* left or right crumbled border */
1520 width = crumbled_border_size;
1522 cx = (dir == 2 ? TILEX - crumbled_border_size : 0);
1525 else /* top or bottom crumbled border */
1528 height = crumbled_border_size;
1530 cy = (dir == 3 ? TILEY - crumbled_border_size : 0);
1534 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1535 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1537 /* (remaining middle border part must be at least as big as corner part) */
1538 if (!(graphic_info[graphic].style & STYLE_ACCURATE_BORDERS) ||
1539 crumbled_border_size >= TILESIZE / 3)
1542 /* correct corners of crumbled border, if needed */
1545 for (i = -1; i <= 1; i+=2)
1547 int xx = x + (dir == 0 || dir == 3 ? i : 0);
1548 int yy = y + (dir == 1 || dir == 2 ? i : 0);
1549 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1552 /* check if neighbour field is of same crumble type */
1553 if (IS_CRUMBLED_TILE(xx, yy, element) &&
1554 graphic_info[graphic].class ==
1555 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1557 /* no crumbled corner, but continued crumbled border */
1559 int c1 = (dir == 2 || dir == 3 ? TILESIZE - crumbled_border_size : 0);
1560 int c2 = (i == 1 ? TILESIZE - crumbled_border_size : 0);
1561 int b1 = (i == 1 ? crumbled_border_size :
1562 TILESIZE - 2 * crumbled_border_size);
1564 width = crumbled_border_size;
1565 height = crumbled_border_size;
1567 if (dir == 1 || dir == 2)
1582 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
1583 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1587 if (dir == 1 || dir == 2) /* left or right crumbled border */
1589 for (i = -1; i <= 1; i+=2)
1593 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1596 /* check if neighbour field is of same crumble type */
1597 if (IS_CRUMBLED_TILE(xx, yy, element) &&
1598 graphic_info[graphic].class ==
1599 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1601 /* no crumbled corner, but continued crumbled border */
1603 width = crumbled_border_size;
1604 height = crumbled_border_size;
1605 cx = (dir == 2 ? TILEX - crumbled_border_size : 0);
1606 cy = (i == 1 ? TILEY - crumbled_border_size : 0);
1608 by = (i == 1 ? crumbled_border_size :
1609 TILEY - 2 * crumbled_border_size);
1611 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
1612 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1616 else /* top or bottom crumbled border */
1618 for (i = -1; i <= 1; i+=2)
1622 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1625 /* check if neighbour field is of same crumble type */
1626 if (IS_CRUMBLED_TILE(xx, yy, element) &&
1627 graphic_info[graphic].class ==
1628 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1630 /* no crumbled corner, but continued crumbled border */
1632 width = crumbled_border_size;
1633 height = crumbled_border_size;
1634 cx = (i == 1 ? TILEX - crumbled_border_size : 0);
1635 cy = (dir == 3 ? TILEY - crumbled_border_size : 0);
1636 bx = (i == 1 ? crumbled_border_size :
1637 TILEX - 2 * crumbled_border_size);
1640 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
1641 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1648 static void DrawLevelFieldCrumbledExt(int x, int y, int graphic, int frame)
1650 int sx = SCREENX(x), sy = SCREENY(y);
1653 static int xy[4][2] =
1661 if (!IN_LEV_FIELD(x, y))
1664 element = TILE_GFX_ELEMENT(x, y);
1666 /* crumble field itself */
1667 if (IS_CRUMBLED_TILE(x, y, element))
1669 if (!IN_SCR_FIELD(sx, sy))
1672 for (i = 0; i < 4; i++)
1674 int xx = x + xy[i][0];
1675 int yy = y + xy[i][1];
1677 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1680 /* check if neighbour field is of same crumble type */
1682 if (IS_CRUMBLED_TILE(xx, yy, element) &&
1683 graphic_info[graphic].class ==
1684 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1687 if (IS_CRUMBLED_TILE(xx, yy, element))
1691 DrawLevelFieldCrumbledBorders(x, y, graphic, frame, i);
1694 if ((graphic_info[graphic].style & STYLE_INNER_CORNERS) &&
1695 graphic_info[graphic].anim_frames == 2)
1697 for (i = 0; i < 4; i++)
1699 int dx = (i & 1 ? +1 : -1);
1700 int dy = (i & 2 ? +1 : -1);
1702 DrawLevelFieldCrumbledInnerCorners(x, y, dx, dy, graphic);
1706 MarkTileDirty(sx, sy);
1708 else /* center field not crumbled -- crumble neighbour fields */
1710 for (i = 0; i < 4; i++)
1712 int xx = x + xy[i][0];
1713 int yy = y + xy[i][1];
1714 int sxx = sx + xy[i][0];
1715 int syy = sy + xy[i][1];
1717 if (!IN_LEV_FIELD(xx, yy) ||
1718 !IN_SCR_FIELD(sxx, syy))
1721 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
1724 element = TILE_GFX_ELEMENT(xx, yy);
1726 if (!IS_CRUMBLED_TILE(xx, yy, element))
1729 graphic = el_act2crm(element, ACTION_DEFAULT);
1731 DrawLevelFieldCrumbledBorders(xx, yy, graphic, 0, 3 - i);
1733 MarkTileDirty(sxx, syy);
1738 void DrawLevelFieldCrumbled(int x, int y)
1742 if (!IN_LEV_FIELD(x, y))
1746 /* !!! CHECK THIS !!! */
1749 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1750 GFX_CRUMBLED(GfxElement[x][y]))
1753 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1754 GfxElement[x][y] != EL_UNDEFINED &&
1755 GFX_CRUMBLED(GfxElement[x][y]))
1757 DrawLevelFieldCrumbledDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
1764 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
1766 graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
1769 DrawLevelFieldCrumbledExt(x, y, graphic, 0);
1772 void DrawLevelFieldCrumbledDigging(int x, int y, int direction,
1775 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1776 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1777 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1778 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1779 int sx = SCREENX(x), sy = SCREENY(y);
1781 DrawGraphic(sx, sy, graphic1, frame1);
1782 DrawLevelFieldCrumbledExt(x, y, graphic2, frame2);
1785 void DrawLevelFieldCrumbledNeighbours(int x, int y)
1787 int sx = SCREENX(x), sy = SCREENY(y);
1788 static int xy[4][2] =
1797 for (i = 0; i < 4; i++)
1799 int xx = x + xy[i][0];
1800 int yy = y + xy[i][1];
1801 int sxx = sx + xy[i][0];
1802 int syy = sy + xy[i][1];
1804 if (!IN_LEV_FIELD(xx, yy) ||
1805 !IN_SCR_FIELD(sxx, syy) ||
1806 !GFX_CRUMBLED(Feld[xx][yy]) ||
1810 DrawLevelField(xx, yy);
1814 static int getBorderElement(int x, int y)
1818 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1819 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1820 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1821 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1822 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1823 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1824 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1826 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1827 int steel_position = (x == -1 && y == -1 ? 0 :
1828 x == lev_fieldx && y == -1 ? 1 :
1829 x == -1 && y == lev_fieldy ? 2 :
1830 x == lev_fieldx && y == lev_fieldy ? 3 :
1831 x == -1 || x == lev_fieldx ? 4 :
1832 y == -1 || y == lev_fieldy ? 5 : 6);
1834 return border[steel_position][steel_type];
1837 void DrawScreenElement(int x, int y, int element)
1839 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1840 DrawLevelFieldCrumbled(LEVELX(x), LEVELY(y));
1843 void DrawLevelElement(int x, int y, int element)
1845 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1846 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1849 void DrawScreenField(int x, int y)
1851 int lx = LEVELX(x), ly = LEVELY(y);
1852 int element, content;
1854 if (!IN_LEV_FIELD(lx, ly))
1856 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1859 element = getBorderElement(lx, ly);
1861 DrawScreenElement(x, y, element);
1866 element = Feld[lx][ly];
1867 content = Store[lx][ly];
1869 if (IS_MOVING(lx, ly))
1871 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1872 boolean cut_mode = NO_CUTTING;
1874 if (element == EL_QUICKSAND_EMPTYING ||
1875 element == EL_QUICKSAND_FAST_EMPTYING ||
1876 element == EL_MAGIC_WALL_EMPTYING ||
1877 element == EL_BD_MAGIC_WALL_EMPTYING ||
1878 element == EL_DC_MAGIC_WALL_EMPTYING ||
1879 element == EL_AMOEBA_DROPPING)
1880 cut_mode = CUT_ABOVE;
1881 else if (element == EL_QUICKSAND_FILLING ||
1882 element == EL_QUICKSAND_FAST_FILLING ||
1883 element == EL_MAGIC_WALL_FILLING ||
1884 element == EL_BD_MAGIC_WALL_FILLING ||
1885 element == EL_DC_MAGIC_WALL_FILLING)
1886 cut_mode = CUT_BELOW;
1889 if (lx == 9 && ly == 1)
1890 printf("::: %s [%d] [%d, %d] [%d]\n",
1891 EL_NAME(TILE_GFX_ELEMENT(lx, ly)),
1892 el_act2crm(TILE_GFX_ELEMENT(lx, ly), ACTION_DEFAULT),
1893 element_info[EL_QUICKSAND_EMPTYING].graphic[ACTION_DEFAULT],
1894 element_info[EL_QUICKSAND_EMPTYING].crumbled[ACTION_DEFAULT],
1895 GFX_CRUMBLED(TILE_GFX_ELEMENT(lx, ly)));
1898 if (cut_mode == CUT_ABOVE)
1900 DrawScreenElement(x, y, element);
1902 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1905 DrawScreenElement(x, y, EL_EMPTY);
1908 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1909 else if (cut_mode == NO_CUTTING)
1910 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1913 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1916 if (cut_mode == CUT_BELOW &&
1917 IN_LEV_FIELD(lx, ly + 1) && IN_SCR_FIELD(x, y + 1))
1918 DrawLevelElement(lx, ly + 1, element);
1922 if (content == EL_ACID)
1924 int dir = MovDir[lx][ly];
1925 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
1926 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
1928 DrawLevelElementThruMask(newlx, newly, EL_ACID);
1931 else if (IS_BLOCKED(lx, ly))
1936 boolean cut_mode = NO_CUTTING;
1937 int element_old, content_old;
1939 Blocked2Moving(lx, ly, &oldx, &oldy);
1942 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1943 MovDir[oldx][oldy] == MV_RIGHT);
1945 element_old = Feld[oldx][oldy];
1946 content_old = Store[oldx][oldy];
1948 if (element_old == EL_QUICKSAND_EMPTYING ||
1949 element_old == EL_QUICKSAND_FAST_EMPTYING ||
1950 element_old == EL_MAGIC_WALL_EMPTYING ||
1951 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1952 element_old == EL_DC_MAGIC_WALL_EMPTYING ||
1953 element_old == EL_AMOEBA_DROPPING)
1954 cut_mode = CUT_ABOVE;
1956 DrawScreenElement(x, y, EL_EMPTY);
1959 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1961 else if (cut_mode == NO_CUTTING)
1962 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1965 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1968 else if (IS_DRAWABLE(element))
1969 DrawScreenElement(x, y, element);
1971 DrawScreenElement(x, y, EL_EMPTY);
1974 void DrawLevelField(int x, int y)
1976 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1977 DrawScreenField(SCREENX(x), SCREENY(y));
1978 else if (IS_MOVING(x, y))
1982 Moving2Blocked(x, y, &newx, &newy);
1983 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1984 DrawScreenField(SCREENX(newx), SCREENY(newy));
1986 else if (IS_BLOCKED(x, y))
1990 Blocked2Moving(x, y, &oldx, &oldy);
1991 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1992 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1996 void DrawMiniElement(int x, int y, int element)
2000 graphic = el2edimg(element);
2001 DrawMiniGraphic(x, y, graphic);
2004 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
2006 int x = sx + scroll_x, y = sy + scroll_y;
2008 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
2009 DrawMiniElement(sx, sy, EL_EMPTY);
2010 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
2011 DrawMiniElement(sx, sy, Feld[x][y]);
2013 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
2016 void DrawEnvelopeBackground(int envelope_nr, int startx, int starty,
2017 int x, int y, int xsize, int ysize, int font_nr)
2019 int font_width = getFontWidth(font_nr);
2020 int font_height = getFontHeight(font_nr);
2021 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2024 int dst_x = SX + startx + x * font_width;
2025 int dst_y = SY + starty + y * font_height;
2026 int width = graphic_info[graphic].width;
2027 int height = graphic_info[graphic].height;
2028 int inner_width = MAX(width - 2 * font_width, font_width);
2029 int inner_height = MAX(height - 2 * font_height, font_height);
2030 int inner_sx = (width >= 3 * font_width ? font_width : 0);
2031 int inner_sy = (height >= 3 * font_height ? font_height : 0);
2032 boolean draw_masked = graphic_info[graphic].draw_masked;
2034 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
2036 if (src_bitmap == NULL || width < font_width || height < font_height)
2038 ClearRectangle(drawto, dst_x, dst_y, font_width, font_height);
2042 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - font_width :
2043 inner_sx + (x - 1) * font_width % inner_width);
2044 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - font_height :
2045 inner_sy + (y - 1) * font_height % inner_height);
2049 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
2050 dst_x - src_x, dst_y - src_y);
2051 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, font_width, font_height,
2055 BlitBitmap(src_bitmap, drawto, src_x, src_y, font_width, font_height,
2059 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
2061 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2062 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2063 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2064 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2065 boolean no_delay = (tape.warp_forward);
2066 unsigned long anim_delay = 0;
2067 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
2068 int anim_delay_value = (no_delay ? 0 : frame_delay_value);
2069 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
2070 int font_width = getFontWidth(font_nr);
2071 int font_height = getFontHeight(font_nr);
2072 int max_xsize = level.envelope[envelope_nr].xsize;
2073 int max_ysize = level.envelope[envelope_nr].ysize;
2074 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
2075 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
2076 int xend = max_xsize;
2077 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
2078 int xstep = (xstart < xend ? 1 : 0);
2079 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2082 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
2084 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2085 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2086 int sx = (SXSIZE - xsize * font_width) / 2;
2087 int sy = (SYSIZE - ysize * font_height) / 2;
2090 SetDrawtoField(DRAW_BUFFERED);
2092 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
2094 SetDrawtoField(DRAW_BACKBUFFER);
2096 for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++)
2097 DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
2100 DrawTextBuffer(SX + sx + font_width, SY + sy + font_height,
2101 level.envelope[envelope_nr].text, font_nr, max_xsize,
2102 xsize - 2, ysize - 2, 0, mask_mode,
2103 level.envelope[envelope_nr].autowrap,
2104 level.envelope[envelope_nr].centered, FALSE);
2106 DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
2107 level.envelope[envelope_nr].text, font_nr, max_xsize,
2108 xsize - 2, ysize - 2, mask_mode);
2111 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2114 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
2118 void AnimateEnvelopeDoor(char *text, int anim_mode, int action)
2121 int envelope_nr = 0;
2123 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2124 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2125 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2126 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2127 boolean no_delay = (tape.warp_forward);
2128 unsigned long anim_delay = 0;
2129 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
2130 int anim_delay_value = (no_delay ? 0 : frame_delay_value);
2132 int max_word_len = maxWordLengthInString(text);
2133 int font_nr = (max_word_len > 7 ? FONT_TEXT_1 : FONT_TEXT_2);
2135 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
2137 int font_width = getFontWidth(font_nr);
2138 int font_height = getFontHeight(font_nr);
2142 int max_xsize = DXSIZE / font_width;
2143 int max_ysize = DYSIZE / font_height;
2145 int max_xsize = 7; /* tools.c: MAX_REQUEST_LINE_FONT1_LEN == 7 */
2146 int max_ysize = 13; /* tools.c: MAX_REQUEST_LINES == 13 */
2150 int max_xsize = level.envelope[envelope_nr].xsize;
2151 int max_ysize = level.envelope[envelope_nr].ysize;
2153 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
2154 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
2155 int xend = max_xsize;
2156 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
2157 int xstep = (xstart < xend ? 1 : 0);
2158 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2163 char *text_copy = getStringCopy(text);
2166 font_nr = FONT_TEXT_2;
2168 if (maxWordLengthInString(text) > 7) /* MAX_REQUEST_LINE_FONT1_LEN == 7 */
2170 max_xsize = 10; /* tools.c: MAX_REQUEST_LINE_FONT2_LEN == 10 */
2171 font_nr = FONT_TEXT_1;
2174 int max_word_len = 0;
2176 char *text_copy = getStringCopy(text);
2178 font_nr = FONT_TEXT_2;
2180 for (text_ptr = text; *text_ptr; text_ptr++)
2182 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
2184 if (max_word_len > 7) /* tools.c: MAX_REQUEST_LINE_FONT1_LEN == 7 */
2186 max_xsize = 10; /* tools.c: MAX_REQUEST_LINE_FONT2_LEN == 10 */
2187 font_nr = FONT_TEXT_1;
2196 for (text_ptr = text_copy; *text_ptr; text_ptr++)
2197 if (*text_ptr == ' ')
2202 dDX = SX + (SXSIZE - DXSIZE) / 2 - DX;
2203 dDY = SY + (SYSIZE - DYSIZE) / 2 - DY;
2205 dDX = SX + SXSIZE / 2 - max_xsize * font_width / 2 - DX;
2206 dDY = SY + SYSIZE / 2 - max_ysize * font_height / 2 - DY;
2209 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
2211 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2212 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2213 int sx = (SXSIZE - xsize * font_width) / 2;
2214 int sy = (SYSIZE - ysize * font_height) / 2;
2218 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2220 SetDrawtoField(DRAW_BUFFERED);
2222 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
2224 SetDrawtoField(DRAW_BACKBUFFER);
2227 for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++)
2228 DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
2233 DrawTextBuffer(SX + sx + font_width, SY + sy + font_height + 8,
2234 text_copy, font_nr, max_xsize,
2235 xsize - 2, ysize - 2, 2, mask_mode,
2236 FALSE, TRUE, FALSE);
2238 DrawTextBuffer(SX + sx + font_width, SY + sy + font_height,
2239 level.envelope[envelope_nr].text, font_nr, max_xsize,
2240 xsize - 2, ysize - 2, 0, mask_mode,
2241 level.envelope[envelope_nr].autowrap,
2242 level.envelope[envelope_nr].centered, FALSE);
2246 DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
2247 level.envelope[envelope_nr].text, font_nr, max_xsize,
2248 xsize - 2, ysize - 2, mask_mode);
2251 /* copy request gadgets to door backbuffer */
2253 if ((ysize - 2) > 13)
2254 BlitBitmap(bitmap_db_door, drawto,
2255 DOOR_GFX_PAGEX1 + (DXSIZE - (xsize - 2) * font_width) / 2,
2256 DOOR_GFX_PAGEY1 + 13 * font_height,
2257 (xsize - 2) * font_width,
2258 (ysize - 2 - 13) * font_height,
2259 SX + sx + font_width,
2260 SY + sy + font_height * (1 + 13));
2262 if ((ysize - 2) > 13)
2263 BlitBitmap(bitmap_db_door, drawto,
2264 DOOR_GFX_PAGEX1 + (DXSIZE - (xsize - 2) * font_width) / 2,
2265 DOOR_GFX_PAGEY1 + 13 * font_height,
2266 (xsize - 2) * font_width,
2267 (ysize - 2 - 13) * font_height,
2268 SX + sx + font_width,
2269 SY + sy + font_height * (1 + 13));
2273 redraw_mask = REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2274 // redraw_mask |= REDRAW_ALL | REDRAW_FROM_BACKBUFFER;
2276 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2286 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
2294 void ShowEnvelope(int envelope_nr)
2296 int element = EL_ENVELOPE_1 + envelope_nr;
2297 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2298 int sound_opening = element_info[element].sound[ACTION_OPENING];
2299 int sound_closing = element_info[element].sound[ACTION_CLOSING];
2300 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2301 boolean no_delay = (tape.warp_forward);
2302 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
2303 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
2304 int anim_mode = graphic_info[graphic].anim_mode;
2305 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2306 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2308 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
2310 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2312 if (anim_mode == ANIM_DEFAULT)
2313 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
2315 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
2318 Delay(wait_delay_value);
2320 WaitForEventToContinue();
2322 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2324 if (anim_mode != ANIM_NONE)
2325 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
2327 if (anim_mode == ANIM_DEFAULT)
2328 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
2330 game.envelope_active = FALSE;
2332 SetDrawtoField(DRAW_BUFFERED);
2334 redraw_mask |= REDRAW_FIELD;
2338 void ShowEnvelopeDoor(char *text, int action)
2341 int last_game_status = game_status; /* save current game status */
2342 // int last_draw_background_mask = gfx.draw_background_mask;
2343 int envelope_nr = 0;
2345 int element = EL_ENVELOPE_1 + envelope_nr;
2346 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2347 int sound_opening = element_info[element].sound[ACTION_OPENING];
2348 int sound_closing = element_info[element].sound[ACTION_CLOSING];
2350 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2351 boolean no_delay = (tape.warp_forward);
2352 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
2353 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
2355 int anim_mode = graphic_info[graphic].anim_mode;
2356 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2357 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2360 if (game_status == GAME_MODE_PLAYING)
2362 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
2363 BlitScreenToBitmap_EM(backbuffer);
2364 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
2365 BlitScreenToBitmap_SP(backbuffer);
2368 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
2372 SetDrawtoField(DRAW_BACKBUFFER);
2374 // SetDrawBackgroundMask(REDRAW_NONE);
2376 if (action == ACTION_OPENING)
2378 BlitBitmap(backbuffer, bitmap_db_store, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2380 if (game_status != GAME_MODE_MAIN)
2384 /* force DOOR font inside door area */
2385 game_status = GAME_MODE_PSEUDO_DOOR;
2388 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
2390 if (action == ACTION_OPENING)
2392 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2394 if (anim_mode == ANIM_DEFAULT)
2395 AnimateEnvelopeDoor(text, ANIM_DEFAULT, ACTION_OPENING);
2397 AnimateEnvelopeDoor(text, main_anim_mode, ACTION_OPENING);
2401 Delay(wait_delay_value);
2403 WaitForEventToContinue();
2408 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2410 if (anim_mode != ANIM_NONE)
2411 AnimateEnvelopeDoor(text, main_anim_mode, ACTION_CLOSING);
2413 if (anim_mode == ANIM_DEFAULT)
2414 AnimateEnvelopeDoor(text, ANIM_DEFAULT, ACTION_CLOSING);
2417 game.envelope_active = FALSE;
2420 game_status = last_game_status; /* restore current game status */
2422 if (action == ACTION_CLOSING)
2424 if (game_status != GAME_MODE_MAIN)
2427 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2430 SetDrawtoField(DRAW_BUFFERED);
2433 // SetDrawBackgroundMask(last_draw_background_mask);
2436 redraw_mask = REDRAW_FIELD;
2437 // redraw_mask |= REDRAW_ALL;
2439 redraw_mask |= REDRAW_FIELD;
2443 if (game_status == GAME_MODE_MAIN)
2448 if (game_status == GAME_MODE_PLAYING &&
2449 level.game_engine_type == GAME_ENGINE_TYPE_RND)
2450 SetDrawtoField(DRAW_BUFFERED);
2456 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
2460 int graphic = el2preimg(element);
2462 getSizedGraphicSource(graphic, 0, tilesize, &src_bitmap, &src_x, &src_y);
2463 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
2471 SetMainBackgroundImage(IMG_BACKGROUND_PLAYING);
2472 SetDrawBackgroundMask(REDRAW_FIELD);
2474 SetDrawBackgroundMask(REDRAW_NONE);
2479 for (x = BX1; x <= BX2; x++)
2480 for (y = BY1; y <= BY2; y++)
2481 DrawScreenField(x, y);
2483 redraw_mask |= REDRAW_FIELD;
2486 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
2490 for (x = 0; x < size_x; x++)
2491 for (y = 0; y < size_y; y++)
2492 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
2494 redraw_mask |= REDRAW_FIELD;
2497 static void DrawPreviewLevelExt(int from_x, int from_y)
2499 boolean show_level_border = (BorderElement != EL_EMPTY);
2500 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2501 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2502 int tile_size = preview.tile_size;
2503 int preview_width = preview.xsize * tile_size;
2504 int preview_height = preview.ysize * tile_size;
2505 int real_preview_xsize = MIN(level_xsize, preview.xsize);
2506 int real_preview_ysize = MIN(level_ysize, preview.ysize);
2507 int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
2508 int dst_y = SY + ALIGNED_YPOS(preview.y, preview_height, preview.valign);
2511 DrawBackground(dst_x, dst_y, preview_width, preview_height);
2513 dst_x += (preview_width - real_preview_xsize * tile_size) / 2;
2514 dst_y += (preview_height - real_preview_ysize * tile_size) / 2;
2516 for (x = 0; x < real_preview_xsize; x++)
2518 for (y = 0; y < real_preview_ysize; y++)
2520 int lx = from_x + x + (show_level_border ? -1 : 0);
2521 int ly = from_y + y + (show_level_border ? -1 : 0);
2522 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
2523 getBorderElement(lx, ly));
2525 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
2526 element, tile_size);
2530 redraw_mask |= REDRAW_MICROLEVEL;
2533 #define MICROLABEL_EMPTY 0
2534 #define MICROLABEL_LEVEL_NAME 1
2535 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
2536 #define MICROLABEL_LEVEL_AUTHOR 3
2537 #define MICROLABEL_IMPORTED_FROM_HEAD 4
2538 #define MICROLABEL_IMPORTED_FROM 5
2539 #define MICROLABEL_IMPORTED_BY_HEAD 6
2540 #define MICROLABEL_IMPORTED_BY 7
2542 static int getMaxTextLength(struct TextPosInfo *pos, int font_nr)
2544 int max_text_width = SXSIZE;
2545 int font_width = getFontWidth(font_nr);
2547 if (pos->align == ALIGN_CENTER)
2548 max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
2549 else if (pos->align == ALIGN_RIGHT)
2550 max_text_width = pos->x;
2552 max_text_width = SXSIZE - pos->x;
2554 return max_text_width / font_width;
2557 static void DrawPreviewLevelLabelExt(int mode)
2559 struct TextPosInfo *pos = &menu.main.text.level_info_2;
2560 char label_text[MAX_OUTPUT_LINESIZE + 1];
2561 int max_len_label_text;
2563 int font_nr = pos->font;
2566 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
2567 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
2568 mode == MICROLABEL_IMPORTED_BY_HEAD)
2569 font_nr = pos->font_alt;
2571 int font_nr = FONT_TEXT_2;
2574 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
2575 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
2576 mode == MICROLABEL_IMPORTED_BY_HEAD)
2577 font_nr = FONT_TEXT_3;
2581 max_len_label_text = getMaxTextLength(pos, font_nr);
2583 max_len_label_text = SXSIZE / getFontWidth(font_nr);
2587 if (pos->size != -1)
2588 max_len_label_text = pos->size;
2591 for (i = 0; i < max_len_label_text; i++)
2592 label_text[i] = ' ';
2593 label_text[max_len_label_text] = '\0';
2595 if (strlen(label_text) > 0)
2598 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2600 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
2601 int lypos = MICROLABEL2_YPOS;
2603 DrawText(lxpos, lypos, label_text, font_nr);
2608 (mode == MICROLABEL_LEVEL_NAME ? level.name :
2609 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
2610 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
2611 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
2612 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
2613 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
2614 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
2615 max_len_label_text);
2616 label_text[max_len_label_text] = '\0';
2618 if (strlen(label_text) > 0)
2621 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2623 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
2624 int lypos = MICROLABEL2_YPOS;
2626 DrawText(lxpos, lypos, label_text, font_nr);
2630 redraw_mask |= REDRAW_MICROLEVEL;
2633 void DrawPreviewLevel(boolean restart)
2635 static unsigned long scroll_delay = 0;
2636 static unsigned long label_delay = 0;
2637 static int from_x, from_y, scroll_direction;
2638 static int label_state, label_counter;
2639 unsigned long scroll_delay_value = preview.step_delay;
2640 boolean show_level_border = (BorderElement != EL_EMPTY);
2641 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2642 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2643 int last_game_status = game_status; /* save current game status */
2646 /* force PREVIEW font on preview level */
2647 game_status = GAME_MODE_PSEUDO_PREVIEW;
2655 if (preview.anim_mode == ANIM_CENTERED)
2657 if (level_xsize > preview.xsize)
2658 from_x = (level_xsize - preview.xsize) / 2;
2659 if (level_ysize > preview.ysize)
2660 from_y = (level_ysize - preview.ysize) / 2;
2663 from_x += preview.xoffset;
2664 from_y += preview.yoffset;
2666 scroll_direction = MV_RIGHT;
2670 DrawPreviewLevelExt(from_x, from_y);
2671 DrawPreviewLevelLabelExt(label_state);
2673 /* initialize delay counters */
2674 DelayReached(&scroll_delay, 0);
2675 DelayReached(&label_delay, 0);
2677 if (leveldir_current->name)
2679 struct TextPosInfo *pos = &menu.main.text.level_info_1;
2680 char label_text[MAX_OUTPUT_LINESIZE + 1];
2682 int font_nr = pos->font;
2684 int font_nr = FONT_TEXT_1;
2687 int max_len_label_text = getMaxTextLength(pos, font_nr);
2689 int max_len_label_text = SXSIZE / getFontWidth(font_nr);
2697 if (pos->size != -1)
2698 max_len_label_text = pos->size;
2701 strncpy(label_text, leveldir_current->name, max_len_label_text);
2702 label_text[max_len_label_text] = '\0';
2705 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2707 lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
2708 lypos = SY + MICROLABEL1_YPOS;
2710 DrawText(lxpos, lypos, label_text, font_nr);
2714 game_status = last_game_status; /* restore current game status */
2719 /* scroll preview level, if needed */
2720 if (preview.anim_mode != ANIM_NONE &&
2721 (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
2722 DelayReached(&scroll_delay, scroll_delay_value))
2724 switch (scroll_direction)
2729 from_x -= preview.step_offset;
2730 from_x = (from_x < 0 ? 0 : from_x);
2733 scroll_direction = MV_UP;
2737 if (from_x < level_xsize - preview.xsize)
2739 from_x += preview.step_offset;
2740 from_x = (from_x > level_xsize - preview.xsize ?
2741 level_xsize - preview.xsize : from_x);
2744 scroll_direction = MV_DOWN;
2750 from_y -= preview.step_offset;
2751 from_y = (from_y < 0 ? 0 : from_y);
2754 scroll_direction = MV_RIGHT;
2758 if (from_y < level_ysize - preview.ysize)
2760 from_y += preview.step_offset;
2761 from_y = (from_y > level_ysize - preview.ysize ?
2762 level_ysize - preview.ysize : from_y);
2765 scroll_direction = MV_LEFT;
2772 DrawPreviewLevelExt(from_x, from_y);
2775 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
2776 /* redraw micro level label, if needed */
2777 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
2778 !strEqual(level.author, ANONYMOUS_NAME) &&
2779 !strEqual(level.author, leveldir_current->name) &&
2780 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
2782 int max_label_counter = 23;
2784 if (leveldir_current->imported_from != NULL &&
2785 strlen(leveldir_current->imported_from) > 0)
2786 max_label_counter += 14;
2787 if (leveldir_current->imported_by != NULL &&
2788 strlen(leveldir_current->imported_by) > 0)
2789 max_label_counter += 14;
2791 label_counter = (label_counter + 1) % max_label_counter;
2792 label_state = (label_counter >= 0 && label_counter <= 7 ?
2793 MICROLABEL_LEVEL_NAME :
2794 label_counter >= 9 && label_counter <= 12 ?
2795 MICROLABEL_LEVEL_AUTHOR_HEAD :
2796 label_counter >= 14 && label_counter <= 21 ?
2797 MICROLABEL_LEVEL_AUTHOR :
2798 label_counter >= 23 && label_counter <= 26 ?
2799 MICROLABEL_IMPORTED_FROM_HEAD :
2800 label_counter >= 28 && label_counter <= 35 ?
2801 MICROLABEL_IMPORTED_FROM :
2802 label_counter >= 37 && label_counter <= 40 ?
2803 MICROLABEL_IMPORTED_BY_HEAD :
2804 label_counter >= 42 && label_counter <= 49 ?
2805 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
2807 if (leveldir_current->imported_from == NULL &&
2808 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
2809 label_state == MICROLABEL_IMPORTED_FROM))
2810 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
2811 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
2813 DrawPreviewLevelLabelExt(label_state);
2816 game_status = last_game_status; /* restore current game status */
2819 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
2820 int graphic, int sync_frame, int mask_mode)
2822 int frame = getGraphicAnimationFrame(graphic, sync_frame);
2824 if (mask_mode == USE_MASKING)
2825 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
2827 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
2830 inline void DrawGraphicAnimation(int x, int y, int graphic)
2832 int lx = LEVELX(x), ly = LEVELY(y);
2834 if (!IN_SCR_FIELD(x, y))
2837 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
2838 graphic, GfxFrame[lx][ly], NO_MASKING);
2839 MarkTileDirty(x, y);
2842 void DrawLevelGraphicAnimation(int x, int y, int graphic)
2844 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2847 void DrawLevelElementAnimation(int x, int y, int element)
2849 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2851 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2854 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
2856 int sx = SCREENX(x), sy = SCREENY(y);
2858 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2861 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2864 DrawGraphicAnimation(sx, sy, graphic);
2867 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
2868 DrawLevelFieldCrumbled(x, y);
2870 if (GFX_CRUMBLED(Feld[x][y]))
2871 DrawLevelFieldCrumbled(x, y);
2875 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
2877 int sx = SCREENX(x), sy = SCREENY(y);
2880 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2883 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2885 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2888 DrawGraphicAnimation(sx, sy, graphic);
2890 if (GFX_CRUMBLED(element))
2891 DrawLevelFieldCrumbled(x, y);
2894 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
2896 if (player->use_murphy)
2898 /* this works only because currently only one player can be "murphy" ... */
2899 static int last_horizontal_dir = MV_LEFT;
2900 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
2902 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2903 last_horizontal_dir = move_dir;
2905 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
2907 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
2909 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
2915 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
2918 static boolean equalGraphics(int graphic1, int graphic2)
2920 struct GraphicInfo *g1 = &graphic_info[graphic1];
2921 struct GraphicInfo *g2 = &graphic_info[graphic2];
2923 return (g1->bitmap == g2->bitmap &&
2924 g1->src_x == g2->src_x &&
2925 g1->src_y == g2->src_y &&
2926 g1->anim_frames == g2->anim_frames &&
2927 g1->anim_delay == g2->anim_delay &&
2928 g1->anim_mode == g2->anim_mode);
2931 void DrawAllPlayers()
2935 for (i = 0; i < MAX_PLAYERS; i++)
2936 if (stored_player[i].active)
2937 DrawPlayer(&stored_player[i]);
2940 void DrawPlayerField(int x, int y)
2942 if (!IS_PLAYER(x, y))
2945 DrawPlayer(PLAYERINFO(x, y));
2948 #define DRAW_PLAYER_OVER_PUSHED_ELEMENT 1
2950 void DrawPlayer(struct PlayerInfo *player)
2952 int jx = player->jx;
2953 int jy = player->jy;
2954 int move_dir = player->MovDir;
2955 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
2956 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
2957 int last_jx = (player->is_moving ? jx - dx : jx);
2958 int last_jy = (player->is_moving ? jy - dy : jy);
2959 int next_jx = jx + dx;
2960 int next_jy = jy + dy;
2961 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
2962 boolean player_is_opaque = FALSE;
2963 int sx = SCREENX(jx), sy = SCREENY(jy);
2964 int sxx = 0, syy = 0;
2965 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
2967 int action = ACTION_DEFAULT;
2968 int last_player_graphic = getPlayerGraphic(player, move_dir);
2969 int last_player_frame = player->Frame;
2972 /* GfxElement[][] is set to the element the player is digging or collecting;
2973 remove also for off-screen player if the player is not moving anymore */
2974 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
2975 GfxElement[jx][jy] = EL_UNDEFINED;
2977 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
2981 if (!IN_LEV_FIELD(jx, jy))
2983 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
2984 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
2985 printf("DrawPlayerField(): This should never happen!\n");
2990 if (element == EL_EXPLOSION)
2993 action = (player->is_pushing ? ACTION_PUSHING :
2994 player->is_digging ? ACTION_DIGGING :
2995 player->is_collecting ? ACTION_COLLECTING :
2996 player->is_moving ? ACTION_MOVING :
2997 player->is_snapping ? ACTION_SNAPPING :
2998 player->is_dropping ? ACTION_DROPPING :
2999 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
3001 if (player->is_waiting)
3002 move_dir = player->dir_waiting;
3004 InitPlayerGfxAnimation(player, action, move_dir);
3006 /* ----------------------------------------------------------------------- */
3007 /* draw things in the field the player is leaving, if needed */
3008 /* ----------------------------------------------------------------------- */
3010 if (player->is_moving)
3012 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
3014 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
3016 if (last_element == EL_DYNAMITE_ACTIVE ||
3017 last_element == EL_EM_DYNAMITE_ACTIVE ||
3018 last_element == EL_SP_DISK_RED_ACTIVE)
3019 DrawDynamite(last_jx, last_jy);
3021 DrawLevelFieldThruMask(last_jx, last_jy);
3023 else if (last_element == EL_DYNAMITE_ACTIVE ||
3024 last_element == EL_EM_DYNAMITE_ACTIVE ||
3025 last_element == EL_SP_DISK_RED_ACTIVE)
3026 DrawDynamite(last_jx, last_jy);
3028 /* !!! this is not enough to prevent flickering of players which are
3029 moving next to each others without a free tile between them -- this
3030 can only be solved by drawing all players layer by layer (first the
3031 background, then the foreground etc.) !!! => TODO */
3032 else if (!IS_PLAYER(last_jx, last_jy))
3033 DrawLevelField(last_jx, last_jy);
3036 DrawLevelField(last_jx, last_jy);
3039 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
3040 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
3043 if (!IN_SCR_FIELD(sx, sy))
3046 /* ----------------------------------------------------------------------- */
3047 /* draw things behind the player, if needed */
3048 /* ----------------------------------------------------------------------- */
3051 DrawLevelElement(jx, jy, Back[jx][jy]);
3052 else if (IS_ACTIVE_BOMB(element))
3053 DrawLevelElement(jx, jy, EL_EMPTY);
3056 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
3058 int old_element = GfxElement[jx][jy];
3059 int old_graphic = el_act_dir2img(old_element, action, move_dir);
3060 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
3062 if (GFX_CRUMBLED(old_element))
3063 DrawLevelFieldCrumbledDigging(jx, jy, move_dir, player->StepFrame);
3065 DrawGraphic(sx, sy, old_graphic, frame);
3067 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
3068 player_is_opaque = TRUE;
3072 GfxElement[jx][jy] = EL_UNDEFINED;
3074 /* make sure that pushed elements are drawn with correct frame rate */
3076 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
3078 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
3079 GfxFrame[jx][jy] = player->StepFrame;
3081 if (player->is_pushing && player->is_moving)
3082 GfxFrame[jx][jy] = player->StepFrame;
3085 DrawLevelField(jx, jy);
3089 #if !DRAW_PLAYER_OVER_PUSHED_ELEMENT
3090 /* ----------------------------------------------------------------------- */
3091 /* draw player himself */
3092 /* ----------------------------------------------------------------------- */
3094 graphic = getPlayerGraphic(player, move_dir);
3096 /* in the case of changed player action or direction, prevent the current
3097 animation frame from being restarted for identical animations */
3098 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
3099 player->Frame = last_player_frame;
3101 frame = getGraphicAnimationFrame(graphic, player->Frame);
3105 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3106 sxx = player->GfxPos;
3108 syy = player->GfxPos;
3111 if (!setup.soft_scrolling && ScreenMovPos)
3114 if (player_is_opaque)
3115 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
3117 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3119 if (SHIELD_ON(player))
3121 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
3122 IMG_SHIELD_NORMAL_ACTIVE);
3123 int frame = getGraphicAnimationFrame(graphic, -1);
3125 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3129 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
3132 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3133 sxx = player->GfxPos;
3135 syy = player->GfxPos;
3139 /* ----------------------------------------------------------------------- */
3140 /* draw things the player is pushing, if needed */
3141 /* ----------------------------------------------------------------------- */
3144 printf("::: %d, %d [%d, %d] [%d]\n",
3145 player->is_pushing, player_is_moving, player->GfxAction,
3146 player->is_moving, player_is_moving);
3150 if (player->is_pushing && player->is_moving)
3152 int px = SCREENX(jx), py = SCREENY(jy);
3153 int pxx = (TILEX - ABS(sxx)) * dx;
3154 int pyy = (TILEY - ABS(syy)) * dy;
3155 int gfx_frame = GfxFrame[jx][jy];
3161 if (!IS_MOVING(jx, jy)) /* push movement already finished */
3163 element = Feld[next_jx][next_jy];
3164 gfx_frame = GfxFrame[next_jx][next_jy];
3167 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
3170 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
3171 frame = getGraphicAnimationFrame(graphic, sync_frame);
3173 frame = getGraphicAnimationFrame(graphic, player->StepFrame);
3176 /* draw background element under pushed element (like the Sokoban field) */
3178 if (game.use_masked_pushing && IS_MOVING(jx, jy))
3180 /* this allows transparent pushing animation over non-black background */
3183 DrawLevelElement(jx, jy, Back[jx][jy]);
3185 DrawLevelElement(jx, jy, EL_EMPTY);
3187 if (Back[next_jx][next_jy])
3188 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3190 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
3192 else if (Back[next_jx][next_jy])
3193 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3195 if (Back[next_jx][next_jy])
3196 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3200 printf("::: %d, %d, %d, %d [%d] [%d, %d, %d] [%d] [%d, %d] [%d, %d]\n",
3201 jx, px, player->GfxPos, player->StepFrame,
3206 GfxFrame[jx][jy], GfxFrame[next_jx][next_jy]);
3210 /* do not draw (EM style) pushing animation when pushing is finished */
3211 /* (two-tile animations usually do not contain start and end frame) */
3212 if (graphic_info[graphic].double_movement && !IS_MOVING(jx, jy))
3213 DrawLevelElement(next_jx, next_jy, Feld[next_jx][next_jy]);
3215 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3217 /* masked drawing is needed for EMC style (double) movement graphics */
3218 /* !!! (ONLY WHEN DRAWING PUSHED ELEMENT OVER THE PLAYER) !!! */
3219 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3224 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
3225 /* ----------------------------------------------------------------------- */
3226 /* draw player himself */
3227 /* ----------------------------------------------------------------------- */
3229 graphic = getPlayerGraphic(player, move_dir);
3231 /* in the case of changed player action or direction, prevent the current
3232 animation frame from being restarted for identical animations */
3233 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
3234 player->Frame = last_player_frame;
3236 frame = getGraphicAnimationFrame(graphic, player->Frame);
3240 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3241 sxx = player->GfxPos;
3243 syy = player->GfxPos;
3246 if (!setup.soft_scrolling && ScreenMovPos)
3249 if (player_is_opaque)
3250 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
3252 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3254 if (SHIELD_ON(player))
3256 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
3257 IMG_SHIELD_NORMAL_ACTIVE);
3258 int frame = getGraphicAnimationFrame(graphic, -1);
3260 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3264 /* ----------------------------------------------------------------------- */
3265 /* draw things in front of player (active dynamite or dynabombs) */
3266 /* ----------------------------------------------------------------------- */
3268 if (IS_ACTIVE_BOMB(element))
3270 graphic = el2img(element);
3271 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
3273 if (game.emulation == EMU_SUPAPLEX)
3274 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
3276 DrawGraphicThruMask(sx, sy, graphic, frame);
3279 if (player_is_moving && last_element == EL_EXPLOSION)
3281 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
3282 GfxElement[last_jx][last_jy] : EL_EMPTY);
3283 int graphic = el_act2img(element, ACTION_EXPLODING);
3284 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
3285 int phase = ExplodePhase[last_jx][last_jy] - 1;
3286 int frame = getGraphicAnimationFrame(graphic, phase - delay);
3289 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
3292 /* ----------------------------------------------------------------------- */
3293 /* draw elements the player is just walking/passing through/under */
3294 /* ----------------------------------------------------------------------- */
3296 if (player_is_moving)
3298 /* handle the field the player is leaving ... */
3299 if (IS_ACCESSIBLE_INSIDE(last_element))
3300 DrawLevelField(last_jx, last_jy);
3301 else if (IS_ACCESSIBLE_UNDER(last_element))
3302 DrawLevelFieldThruMask(last_jx, last_jy);
3305 /* do not redraw accessible elements if the player is just pushing them */
3306 if (!player_is_moving || !player->is_pushing)
3308 /* ... and the field the player is entering */
3309 if (IS_ACCESSIBLE_INSIDE(element))
3310 DrawLevelField(jx, jy);
3311 else if (IS_ACCESSIBLE_UNDER(element))
3312 DrawLevelFieldThruMask(jx, jy);
3315 MarkTileDirty(sx, sy);
3318 /* ------------------------------------------------------------------------- */
3320 void WaitForEventToContinue()
3322 boolean still_wait = TRUE;
3324 /* simulate releasing mouse button over last gadget, if still pressed */
3326 HandleGadgets(-1, -1, 0);
3328 button_status = MB_RELEASED;
3344 case EVENT_BUTTONPRESS:
3345 case EVENT_KEYPRESS:
3349 case EVENT_KEYRELEASE:
3350 ClearPlayerAction();
3354 HandleOtherEvents(&event);
3358 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3365 /* don't eat all CPU time */
3370 #define MAX_REQUEST_LINES 13
3371 #define MAX_REQUEST_LINE_FONT1_LEN 7
3372 #define MAX_REQUEST_LINE_FONT2_LEN 10
3374 boolean Request(char *text, unsigned int req_state)
3376 int mx, my, ty, result = -1;
3377 unsigned int old_door_state;
3378 int last_game_status = game_status; /* save current game status */
3379 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
3380 int font_nr = FONT_TEXT_2;
3381 boolean use_envelope_request = TRUE * 0;
3383 int max_word_len = 0;
3389 if (maxWordLengthInString(text) > MAX_REQUEST_LINE_FONT1_LEN)
3391 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
3392 font_nr = FONT_TEXT_1;
3395 for (text_ptr = text; *text_ptr; text_ptr++)
3397 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
3399 if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
3401 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
3403 font_nr = FONT_TEXT_1;
3405 font_nr = FONT_LEVEL_NUMBER;
3413 if (game_status == GAME_MODE_PLAYING)
3415 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
3416 BlitScreenToBitmap_EM(backbuffer);
3417 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
3418 BlitScreenToBitmap_SP(backbuffer);
3421 /* disable deactivated drawing when quick-loading level tape recording */
3422 if (tape.playing && tape.deactivate_display)
3423 TapeDeactivateDisplayOff(TRUE);
3425 SetMouseCursor(CURSOR_DEFAULT);
3427 #if defined(NETWORK_AVALIABLE)
3428 /* pause network game while waiting for request to answer */
3429 if (options.network &&
3430 game_status == GAME_MODE_PLAYING &&
3431 req_state & REQUEST_WAIT_FOR_INPUT)
3432 SendToServer_PausePlaying();
3435 old_door_state = GetDoorState();
3437 /* simulate releasing mouse button over last gadget, if still pressed */
3439 HandleGadgets(-1, -1, 0);
3444 if (old_door_state & DOOR_OPEN_1 && !use_envelope_request)
3446 if (old_door_state & DOOR_OPEN_1)
3449 CloseDoor(DOOR_CLOSE_1);
3451 /* save old door content */
3452 BlitBitmap(bitmap_db_door, bitmap_db_door,
3453 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
3454 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
3458 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
3461 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3463 /* clear door drawing field */
3464 DrawBackground(DX, DY, DXSIZE, DYSIZE);
3466 /* force DOOR font inside door area */
3467 game_status = GAME_MODE_PSEUDO_DOOR;
3469 /* write text for request */
3470 for (text_ptr = text, ty = 0; ty < MAX_REQUEST_LINES; ty++)
3472 char text_line[max_request_line_len + 1];
3478 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
3480 tc = *(text_ptr + tx);
3481 if (!tc || tc == ' ')
3492 strncpy(text_line, text_ptr, tl);
3495 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
3496 DY + 8 + ty * (getFontHeight(font_nr) + 2),
3497 text_line, font_nr);
3499 text_ptr += tl + (tc == ' ' ? 1 : 0);
3502 game_status = last_game_status; /* restore current game status */
3505 if (use_envelope_request)
3509 CreateToolButtons();
3513 if (req_state & REQ_ASK)
3515 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
3516 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
3518 else if (req_state & REQ_CONFIRM)
3520 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
3522 else if (req_state & REQ_PLAYER)
3524 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
3525 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
3526 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
3527 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
3530 /* copy request gadgets to door backbuffer */
3531 BlitBitmap(drawto, bitmap_db_door,
3532 DX, DY, DXSIZE, DYSIZE,
3533 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
3536 if (use_envelope_request)
3538 ShowEnvelopeDoor(text, ACTION_OPENING);
3540 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3542 if ((req_state & REQ_ASK && (i == TOOL_CTRL_ID_YES ||
3543 i == TOOL_CTRL_ID_NO)) ||
3544 (req_state & REQ_CONFIRM && i == TOOL_CTRL_ID_CONFIRM) ||
3545 (req_state & REQ_PLAYER && (i == TOOL_CTRL_ID_PLAYER_1 &&
3546 i == TOOL_CTRL_ID_PLAYER_2 &&
3547 i == TOOL_CTRL_ID_PLAYER_3 &&
3548 i == TOOL_CTRL_ID_PLAYER_4)))
3550 int x = tool_gadget[i]->x + dDX;
3551 int y = tool_gadget[i]->y + dDY;
3553 ModifyGadget(tool_gadget[i], GDI_X, x, GDI_Y, y, GDI_END);
3560 if (!use_envelope_request)
3561 OpenDoor(DOOR_OPEN_1);
3563 OpenDoor(DOOR_OPEN_1);
3566 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
3568 if (game_status == GAME_MODE_PLAYING)
3570 SetPanelBackground();
3571 SetDrawBackgroundMask(REDRAW_DOOR_1);
3575 SetDrawBackgroundMask(REDRAW_FIELD);
3582 if (game_status != GAME_MODE_MAIN && !use_envelope_request)
3585 if (game_status != GAME_MODE_MAIN)
3589 button_status = MB_RELEASED;
3591 request_gadget_id = -1;
3593 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3605 case EVENT_BUTTONPRESS:
3606 case EVENT_BUTTONRELEASE:
3607 case EVENT_MOTIONNOTIFY:
3609 if (event.type == EVENT_MOTIONNOTIFY)
3611 if (!PointerInWindow(window))
3612 continue; /* window and pointer are on different screens */
3617 motion_status = TRUE;
3618 mx = ((MotionEvent *) &event)->x;
3619 my = ((MotionEvent *) &event)->y;
3623 motion_status = FALSE;
3624 mx = ((ButtonEvent *) &event)->x;
3625 my = ((ButtonEvent *) &event)->y;
3626 if (event.type == EVENT_BUTTONPRESS)
3627 button_status = ((ButtonEvent *) &event)->button;
3629 button_status = MB_RELEASED;
3632 /* this sets 'request_gadget_id' */
3633 HandleGadgets(mx, my, button_status);
3635 switch (request_gadget_id)
3637 case TOOL_CTRL_ID_YES:
3640 case TOOL_CTRL_ID_NO:
3643 case TOOL_CTRL_ID_CONFIRM:
3644 result = TRUE | FALSE;
3647 case TOOL_CTRL_ID_PLAYER_1:
3650 case TOOL_CTRL_ID_PLAYER_2:
3653 case TOOL_CTRL_ID_PLAYER_3:
3656 case TOOL_CTRL_ID_PLAYER_4:
3667 case EVENT_KEYPRESS:
3668 switch (GetEventKey((KeyEvent *)&event, TRUE))
3671 if (req_state & REQ_CONFIRM)
3687 if (req_state & REQ_PLAYER)
3691 case EVENT_KEYRELEASE:
3692 ClearPlayerAction();
3696 HandleOtherEvents(&event);
3700 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3702 int joy = AnyJoystick();
3704 if (joy & JOY_BUTTON_1)
3706 else if (joy & JOY_BUTTON_2)
3712 if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd)
3714 HandleGameActions();
3720 if (!PendingEvent()) /* delay only if no pending events */
3731 if (!PendingEvent()) /* delay only if no pending events */
3734 /* don't eat all CPU time */
3741 if (game_status != GAME_MODE_MAIN)
3747 if (use_envelope_request)
3748 ShowEnvelopeDoor(text, ACTION_CLOSING);
3752 if (!(req_state & REQ_STAY_OPEN) && !use_envelope_request)
3754 if (!(req_state & REQ_STAY_OPEN))
3757 CloseDoor(DOOR_CLOSE_1);
3759 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
3760 (req_state & REQ_REOPEN))
3761 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
3766 if (game_status == GAME_MODE_PLAYING)
3768 SetPanelBackground();
3769 SetDrawBackgroundMask(REDRAW_DOOR_1);
3773 SetDrawBackgroundMask(REDRAW_FIELD);
3776 #if defined(NETWORK_AVALIABLE)
3777 /* continue network game after request */
3778 if (options.network &&
3779 game_status == GAME_MODE_PLAYING &&
3780 req_state & REQUEST_WAIT_FOR_INPUT)
3781 SendToServer_ContinuePlaying();
3784 /* restore deactivated drawing when quick-loading level tape recording */
3785 if (tape.playing && tape.deactivate_display)
3786 TapeDeactivateDisplayOn();
3791 unsigned int OpenDoor(unsigned int door_state)
3793 if (door_state & DOOR_COPY_BACK)
3795 if (door_state & DOOR_OPEN_1)
3796 BlitBitmap(bitmap_db_door, bitmap_db_door,
3797 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
3798 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
3800 if (door_state & DOOR_OPEN_2)
3801 BlitBitmap(bitmap_db_door, bitmap_db_door,
3802 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
3803 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
3805 door_state &= ~DOOR_COPY_BACK;
3808 return MoveDoor(door_state);
3811 unsigned int CloseDoor(unsigned int door_state)
3813 unsigned int old_door_state = GetDoorState();
3815 if (!(door_state & DOOR_NO_COPY_BACK))
3817 if (old_door_state & DOOR_OPEN_1)
3818 BlitBitmap(backbuffer, bitmap_db_door,
3819 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
3821 if (old_door_state & DOOR_OPEN_2)
3822 BlitBitmap(backbuffer, bitmap_db_door,
3823 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
3825 door_state &= ~DOOR_NO_COPY_BACK;
3828 return MoveDoor(door_state);
3831 unsigned int GetDoorState()
3833 return MoveDoor(DOOR_GET_STATE);
3836 unsigned int SetDoorState(unsigned int door_state)
3838 return MoveDoor(door_state | DOOR_SET_STATE);
3841 unsigned int MoveDoor(unsigned int door_state)
3843 static int door1 = DOOR_OPEN_1;
3844 static int door2 = DOOR_CLOSE_2;
3845 unsigned long door_delay = 0;
3846 unsigned long door_delay_value;
3849 if (door_1.width < 0 || door_1.width > DXSIZE)
3850 door_1.width = DXSIZE;
3851 if (door_1.height < 0 || door_1.height > DYSIZE)
3852 door_1.height = DYSIZE;
3853 if (door_2.width < 0 || door_2.width > VXSIZE)
3854 door_2.width = VXSIZE;
3855 if (door_2.height < 0 || door_2.height > VYSIZE)
3856 door_2.height = VYSIZE;
3858 if (door_state == DOOR_GET_STATE)
3859 return (door1 | door2);
3861 if (door_state & DOOR_SET_STATE)
3863 if (door_state & DOOR_ACTION_1)
3864 door1 = door_state & DOOR_ACTION_1;
3865 if (door_state & DOOR_ACTION_2)
3866 door2 = door_state & DOOR_ACTION_2;
3868 return (door1 | door2);
3871 if (!(door_state & DOOR_FORCE_REDRAW))
3873 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
3874 door_state &= ~DOOR_OPEN_1;
3875 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
3876 door_state &= ~DOOR_CLOSE_1;
3877 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
3878 door_state &= ~DOOR_OPEN_2;
3879 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
3880 door_state &= ~DOOR_CLOSE_2;
3883 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
3886 if (setup.quick_doors)
3888 stepsize = 20; /* must be chosen to always draw last frame */
3889 door_delay_value = 0;
3892 if (global.autoplay_leveldir)
3894 door_state |= DOOR_NO_DELAY;
3895 door_state &= ~DOOR_CLOSE_ALL;
3899 if (game_status == GAME_MODE_EDITOR)
3900 door_state |= DOOR_NO_DELAY;
3903 if (door_state & DOOR_ACTION)
3905 boolean handle_door_1 = (door_state & DOOR_ACTION_1);
3906 boolean handle_door_2 = (door_state & DOOR_ACTION_2);
3907 boolean door_1_done = (!handle_door_1);
3908 boolean door_2_done = (!handle_door_2);
3909 boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
3910 boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
3911 int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
3912 int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
3913 int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
3914 int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
3915 int door_size = (handle_door_1 ? door_size_1 : door_size_2);
3916 int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
3917 int door_skip = max_door_size - door_size;
3918 int end = door_size;
3919 int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
3922 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
3924 /* opening door sound has priority over simultaneously closing door */
3925 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
3926 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
3927 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
3928 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
3931 for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
3934 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3935 GC gc = bitmap->stored_clip_gc;
3937 if (door_state & DOOR_ACTION_1)
3939 int a = MIN(x * door_1.step_offset, end);
3940 int p = (door_state & DOOR_OPEN_1 ? end - a : a);
3941 int i = p + door_skip;
3943 if (door_1.anim_mode & ANIM_STATIC_PANEL)
3945 BlitBitmap(bitmap_db_door, drawto,
3946 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
3947 DXSIZE, DYSIZE, DX, DY);
3951 BlitBitmap(bitmap_db_door, drawto,
3952 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
3953 DXSIZE, DYSIZE - p / 2, DX, DY);
3955 ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
3958 if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
3960 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
3961 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
3962 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
3963 int dst2_x = DX, dst2_y = DY;
3964 int width = i, height = DYSIZE;
3966 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3967 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3970 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3971 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3974 else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
3976 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
3977 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
3978 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
3979 int dst2_x = DX, dst2_y = DY;
3980 int width = DXSIZE, height = i;
3982 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3983 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3986 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3987 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3990 else if (x <= DXSIZE) /* ANIM_DEFAULT */
3992 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
3994 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
3995 BlitBitmapMasked(bitmap, drawto,
3996 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
3997 DX + DXSIZE - i, DY + j);
3998 BlitBitmapMasked(bitmap, drawto,
3999 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
4000 DX + DXSIZE - i, DY + 140 + j);
4001 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
4002 DY - (DOOR_GFX_PAGEY1 + j));
4003 BlitBitmapMasked(bitmap, drawto,
4004 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
4006 BlitBitmapMasked(bitmap, drawto,
4007 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
4010 BlitBitmapMasked(bitmap, drawto,
4011 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
4013 BlitBitmapMasked(bitmap, drawto,
4014 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
4016 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
4017 BlitBitmapMasked(bitmap, drawto,
4018 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
4019 DX + DXSIZE - i, DY + 77 + j);
4020 BlitBitmapMasked(bitmap, drawto,
4021 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
4022 DX + DXSIZE - i, DY + 203 + j);
4025 redraw_mask |= REDRAW_DOOR_1;
4026 door_1_done = (a == end);
4029 if (door_state & DOOR_ACTION_2)
4031 int a = MIN(x * door_2.step_offset, door_size);
4032 int p = (door_state & DOOR_OPEN_2 ? door_size - a : a);
4033 int i = p + door_skip;
4035 if (door_2.anim_mode & ANIM_STATIC_PANEL)
4037 BlitBitmap(bitmap_db_door, drawto,
4038 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
4039 VXSIZE, VYSIZE, VX, VY);
4041 else if (x <= VYSIZE)
4043 BlitBitmap(bitmap_db_door, drawto,
4044 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
4045 VXSIZE, VYSIZE - p / 2, VX, VY);
4047 ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
4050 if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
4052 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
4053 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
4054 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
4055 int dst2_x = VX, dst2_y = VY;
4056 int width = i, height = VYSIZE;
4058 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
4059 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
4062 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
4063 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
4066 else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
4068 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
4069 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
4070 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
4071 int dst2_x = VX, dst2_y = VY;
4072 int width = VXSIZE, height = i;
4074 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
4075 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
4078 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
4079 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
4082 else if (x <= VXSIZE) /* ANIM_DEFAULT */
4084 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
4086 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
4087 BlitBitmapMasked(bitmap, drawto,
4088 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
4089 VX + VXSIZE - i, VY + j);
4090 SetClipOrigin(bitmap, gc,
4091 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
4092 BlitBitmapMasked(bitmap, drawto,
4093 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
4096 BlitBitmapMasked(bitmap, drawto,
4097 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
4098 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
4099 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
4100 BlitBitmapMasked(bitmap, drawto,
4101 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
4103 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
4106 redraw_mask |= REDRAW_DOOR_2;
4107 door_2_done = (a == VXSIZE);
4110 if (!(door_state & DOOR_NO_DELAY))
4114 if (game_status == GAME_MODE_MAIN)
4117 WaitUntilDelayReached(&door_delay, door_delay_value);
4122 if (door_state & DOOR_ACTION_1)
4123 door1 = door_state & DOOR_ACTION_1;
4124 if (door_state & DOOR_ACTION_2)
4125 door2 = door_state & DOOR_ACTION_2;
4127 return (door1 | door2);
4130 void DrawSpecialEditorDoor()
4132 /* draw bigger toolbox window */
4133 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
4134 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
4136 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
4137 EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
4140 redraw_mask |= REDRAW_ALL;
4143 void UndrawSpecialEditorDoor()
4145 /* draw normal tape recorder window */
4146 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
4147 EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
4150 redraw_mask |= REDRAW_ALL;
4154 /* ---------- new tool button stuff ---------------------------------------- */
4156 /* graphic position values for tool buttons */
4157 #define TOOL_BUTTON_YES_XPOS 2
4158 #define TOOL_BUTTON_YES_YPOS 250
4159 #define TOOL_BUTTON_YES_GFX_YPOS 0
4160 #define TOOL_BUTTON_YES_XSIZE 46
4161 #define TOOL_BUTTON_YES_YSIZE 28
4162 #define TOOL_BUTTON_NO_XPOS 52
4163 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
4164 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
4165 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
4166 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
4167 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
4168 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
4169 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
4170 #define TOOL_BUTTON_CONFIRM_XSIZE 96
4171 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
4172 #define TOOL_BUTTON_PLAYER_XSIZE 30
4173 #define TOOL_BUTTON_PLAYER_YSIZE 30
4174 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
4175 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
4176 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
4177 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
4178 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
4179 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
4180 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
4181 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
4182 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
4183 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
4184 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
4185 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
4186 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
4187 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
4188 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
4189 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
4190 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
4191 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
4192 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
4193 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
4202 } toolbutton_info[NUM_TOOL_BUTTONS] =
4205 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
4206 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
4207 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
4212 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
4213 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
4214 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
4219 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
4220 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
4221 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
4222 TOOL_CTRL_ID_CONFIRM,
4226 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
4227 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
4228 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
4229 TOOL_CTRL_ID_PLAYER_1,
4233 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
4234 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
4235 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
4236 TOOL_CTRL_ID_PLAYER_2,
4240 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
4241 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
4242 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
4243 TOOL_CTRL_ID_PLAYER_3,
4247 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
4248 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
4249 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
4250 TOOL_CTRL_ID_PLAYER_4,
4255 void CreateToolButtons()
4259 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4261 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
4262 Bitmap *deco_bitmap = None;
4263 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
4264 struct GadgetInfo *gi;
4265 unsigned long event_mask;
4266 int gd_xoffset, gd_yoffset;
4267 int gd_x1, gd_x2, gd_y;
4270 event_mask = GD_EVENT_RELEASED;
4272 gd_xoffset = toolbutton_info[i].xpos;
4273 gd_yoffset = toolbutton_info[i].ypos;
4274 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
4275 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
4276 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
4278 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
4280 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
4282 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
4283 &deco_bitmap, &deco_x, &deco_y);
4284 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
4285 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
4288 gi = CreateGadget(GDI_CUSTOM_ID, id,
4289 GDI_INFO_TEXT, toolbutton_info[i].infotext,
4290 GDI_X, DX + toolbutton_info[i].x,
4291 GDI_Y, DY + toolbutton_info[i].y,
4292 GDI_WIDTH, toolbutton_info[i].width,
4293 GDI_HEIGHT, toolbutton_info[i].height,
4294 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
4295 GDI_STATE, GD_BUTTON_UNPRESSED,
4296 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
4297 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
4298 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
4299 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
4300 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
4301 GDI_DECORATION_SHIFTING, 1, 1,
4302 GDI_DIRECT_DRAW, FALSE,
4303 GDI_EVENT_MASK, event_mask,
4304 GDI_CALLBACK_ACTION, HandleToolButtons,
4308 Error(ERR_EXIT, "cannot create gadget");
4310 tool_gadget[id] = gi;
4314 void FreeToolButtons()
4318 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4319 FreeGadget(tool_gadget[i]);
4322 static void UnmapToolButtons()
4326 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4327 UnmapGadget(tool_gadget[i]);
4330 static void HandleToolButtons(struct GadgetInfo *gi)
4332 request_gadget_id = gi->custom_id;
4335 static struct Mapping_EM_to_RND_object
4338 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
4339 boolean is_backside; /* backside of moving element */
4345 em_object_mapping_list[] =
4348 Xblank, TRUE, FALSE,
4352 Yacid_splash_eB, FALSE, FALSE,
4353 EL_ACID_SPLASH_RIGHT, -1, -1
4356 Yacid_splash_wB, FALSE, FALSE,
4357 EL_ACID_SPLASH_LEFT, -1, -1
4360 #ifdef EM_ENGINE_BAD_ROLL
4362 Xstone_force_e, FALSE, FALSE,
4363 EL_ROCK, -1, MV_BIT_RIGHT
4366 Xstone_force_w, FALSE, FALSE,
4367 EL_ROCK, -1, MV_BIT_LEFT
4370 Xnut_force_e, FALSE, FALSE,
4371 EL_NUT, -1, MV_BIT_RIGHT
4374 Xnut_force_w, FALSE, FALSE,
4375 EL_NUT, -1, MV_BIT_LEFT
4378 Xspring_force_e, FALSE, FALSE,
4379 EL_SPRING, -1, MV_BIT_RIGHT
4382 Xspring_force_w, FALSE, FALSE,
4383 EL_SPRING, -1, MV_BIT_LEFT
4386 Xemerald_force_e, FALSE, FALSE,
4387 EL_EMERALD, -1, MV_BIT_RIGHT
4390 Xemerald_force_w, FALSE, FALSE,
4391 EL_EMERALD, -1, MV_BIT_LEFT
4394 Xdiamond_force_e, FALSE, FALSE,
4395 EL_DIAMOND, -1, MV_BIT_RIGHT
4398 Xdiamond_force_w, FALSE, FALSE,
4399 EL_DIAMOND, -1, MV_BIT_LEFT
4402 Xbomb_force_e, FALSE, FALSE,
4403 EL_BOMB, -1, MV_BIT_RIGHT
4406 Xbomb_force_w, FALSE, FALSE,
4407 EL_BOMB, -1, MV_BIT_LEFT
4409 #endif /* EM_ENGINE_BAD_ROLL */
4412 Xstone, TRUE, FALSE,
4416 Xstone_pause, FALSE, FALSE,
4420 Xstone_fall, FALSE, FALSE,
4424 Ystone_s, FALSE, FALSE,
4425 EL_ROCK, ACTION_FALLING, -1
4428 Ystone_sB, FALSE, TRUE,
4429 EL_ROCK, ACTION_FALLING, -1
4432 Ystone_e, FALSE, FALSE,
4433 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
4436 Ystone_eB, FALSE, TRUE,
4437 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
4440 Ystone_w, FALSE, FALSE,
4441 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
4444 Ystone_wB, FALSE, TRUE,
4445 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
4452 Xnut_pause, FALSE, FALSE,
4456 Xnut_fall, FALSE, FALSE,
4460 Ynut_s, FALSE, FALSE,
4461 EL_NUT, ACTION_FALLING, -1
4464 Ynut_sB, FALSE, TRUE,
4465 EL_NUT, ACTION_FALLING, -1
4468 Ynut_e, FALSE, FALSE,
4469 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
4472 Ynut_eB, FALSE, TRUE,
4473 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
4476 Ynut_w, FALSE, FALSE,
4477 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
4480 Ynut_wB, FALSE, TRUE,
4481 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
4484 Xbug_n, TRUE, FALSE,
4488 Xbug_e, TRUE, FALSE,
4489 EL_BUG_RIGHT, -1, -1
4492 Xbug_s, TRUE, FALSE,
4496 Xbug_w, TRUE, FALSE,
4500 Xbug_gon, FALSE, FALSE,
4504 Xbug_goe, FALSE, FALSE,
4505 EL_BUG_RIGHT, -1, -1
4508 Xbug_gos, FALSE, FALSE,
4512 Xbug_gow, FALSE, FALSE,
4516 Ybug_n, FALSE, FALSE,
4517 EL_BUG, ACTION_MOVING, MV_BIT_UP
4520 Ybug_nB, FALSE, TRUE,
4521 EL_BUG, ACTION_MOVING, MV_BIT_UP
4524 Ybug_e, FALSE, FALSE,
4525 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
4528 Ybug_eB, FALSE, TRUE,
4529 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
4532 Ybug_s, FALSE, FALSE,
4533 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
4536 Ybug_sB, FALSE, TRUE,
4537 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
4540 Ybug_w, FALSE, FALSE,
4541 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
4544 Ybug_wB, FALSE, TRUE,
4545 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
4548 Ybug_w_n, FALSE, FALSE,
4549 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
4552 Ybug_n_e, FALSE, FALSE,
4553 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
4556 Ybug_e_s, FALSE, FALSE,
4557 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
4560 Ybug_s_w, FALSE, FALSE,
4561 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
4564 Ybug_e_n, FALSE, FALSE,
4565 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
4568 Ybug_s_e, FALSE, FALSE,
4569 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
4572 Ybug_w_s, FALSE, FALSE,
4573 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
4576 Ybug_n_w, FALSE, FALSE,
4577 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
4580 Ybug_stone, FALSE, FALSE,
4581 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
4584 Ybug_spring, FALSE, FALSE,
4585 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
4588 Xtank_n, TRUE, FALSE,
4589 EL_SPACESHIP_UP, -1, -1
4592 Xtank_e, TRUE, FALSE,
4593 EL_SPACESHIP_RIGHT, -1, -1
4596 Xtank_s, TRUE, FALSE,
4597 EL_SPACESHIP_DOWN, -1, -1
4600 Xtank_w, TRUE, FALSE,
4601 EL_SPACESHIP_LEFT, -1, -1
4604 Xtank_gon, FALSE, FALSE,
4605 EL_SPACESHIP_UP, -1, -1
4608 Xtank_goe, FALSE, FALSE,
4609 EL_SPACESHIP_RIGHT, -1, -1
4612 Xtank_gos, FALSE, FALSE,
4613 EL_SPACESHIP_DOWN, -1, -1
4616 Xtank_gow, FALSE, FALSE,
4617 EL_SPACESHIP_LEFT, -1, -1
4620 Ytank_n, FALSE, FALSE,
4621 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
4624 Ytank_nB, FALSE, TRUE,
4625 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
4628 Ytank_e, FALSE, FALSE,
4629 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
4632 Ytank_eB, FALSE, TRUE,
4633 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
4636 Ytank_s, FALSE, FALSE,
4637 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
4640 Ytank_sB, FALSE, TRUE,
4641 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
4644 Ytank_w, FALSE, FALSE,
4645 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
4648 Ytank_wB, FALSE, TRUE,
4649 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
4652 Ytank_w_n, FALSE, FALSE,
4653 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
4656 Ytank_n_e, FALSE, FALSE,
4657 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
4660 Ytank_e_s, FALSE, FALSE,
4661 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
4664 Ytank_s_w, FALSE, FALSE,
4665 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
4668 Ytank_e_n, FALSE, FALSE,
4669 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
4672 Ytank_s_e, FALSE, FALSE,
4673 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
4676 Ytank_w_s, FALSE, FALSE,
4677 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
4680 Ytank_n_w, FALSE, FALSE,
4681 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
4684 Ytank_stone, FALSE, FALSE,
4685 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
4688 Ytank_spring, FALSE, FALSE,
4689 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
4692 Xandroid, TRUE, FALSE,
4693 EL_EMC_ANDROID, ACTION_ACTIVE, -1
4696 Xandroid_1_n, FALSE, FALSE,
4697 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
4700 Xandroid_2_n, FALSE, FALSE,
4701 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
4704 Xandroid_1_e, FALSE, FALSE,
4705 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
4708 Xandroid_2_e, FALSE, FALSE,
4709 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
4712 Xandroid_1_w, FALSE, FALSE,
4713 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
4716 Xandroid_2_w, FALSE, FALSE,
4717 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
4720 Xandroid_1_s, FALSE, FALSE,
4721 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
4724 Xandroid_2_s, FALSE, FALSE,
4725 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
4728 Yandroid_n, FALSE, FALSE,
4729 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
4732 Yandroid_nB, FALSE, TRUE,
4733 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
4736 Yandroid_ne, FALSE, FALSE,
4737 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
4740 Yandroid_neB, FALSE, TRUE,
4741 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
4744 Yandroid_e, FALSE, FALSE,
4745 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
4748 Yandroid_eB, FALSE, TRUE,
4749 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
4752 Yandroid_se, FALSE, FALSE,
4753 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
4756 Yandroid_seB, FALSE, TRUE,
4757 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
4760 Yandroid_s, FALSE, FALSE,
4761 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
4764 Yandroid_sB, FALSE, TRUE,
4765 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
4768 Yandroid_sw, FALSE, FALSE,
4769 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
4772 Yandroid_swB, FALSE, TRUE,
4773 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
4776 Yandroid_w, FALSE, FALSE,
4777 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
4780 Yandroid_wB, FALSE, TRUE,
4781 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
4784 Yandroid_nw, FALSE, FALSE,
4785 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
4788 Yandroid_nwB, FALSE, TRUE,
4789 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
4792 Xspring, TRUE, FALSE,
4796 Xspring_pause, FALSE, FALSE,
4800 Xspring_e, FALSE, FALSE,
4804 Xspring_w, FALSE, FALSE,
4808 Xspring_fall, FALSE, FALSE,
4812 Yspring_s, FALSE, FALSE,
4813 EL_SPRING, ACTION_FALLING, -1
4816 Yspring_sB, FALSE, TRUE,
4817 EL_SPRING, ACTION_FALLING, -1
4820 Yspring_e, FALSE, FALSE,
4821 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
4824 Yspring_eB, FALSE, TRUE,
4825 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
4828 Yspring_w, FALSE, FALSE,
4829 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
4832 Yspring_wB, FALSE, TRUE,
4833 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
4836 Yspring_kill_e, FALSE, FALSE,
4837 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
4840 Yspring_kill_eB, FALSE, TRUE,
4841 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
4844 Yspring_kill_w, FALSE, FALSE,
4845 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
4848 Yspring_kill_wB, FALSE, TRUE,
4849 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
4852 Xeater_n, TRUE, FALSE,
4853 EL_YAMYAM_UP, -1, -1
4856 Xeater_e, TRUE, FALSE,
4857 EL_YAMYAM_RIGHT, -1, -1
4860 Xeater_w, TRUE, FALSE,
4861 EL_YAMYAM_LEFT, -1, -1
4864 Xeater_s, TRUE, FALSE,
4865 EL_YAMYAM_DOWN, -1, -1
4868 Yeater_n, FALSE, FALSE,
4869 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
4872 Yeater_nB, FALSE, TRUE,
4873 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
4876 Yeater_e, FALSE, FALSE,
4877 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
4880 Yeater_eB, FALSE, TRUE,
4881 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
4884 Yeater_s, FALSE, FALSE,
4885 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
4888 Yeater_sB, FALSE, TRUE,
4889 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
4892 Yeater_w, FALSE, FALSE,
4893 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
4896 Yeater_wB, FALSE, TRUE,
4897 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
4900 Yeater_stone, FALSE, FALSE,
4901 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
4904 Yeater_spring, FALSE, FALSE,
4905 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
4908 Xalien, TRUE, FALSE,
4912 Xalien_pause, FALSE, FALSE,
4916 Yalien_n, FALSE, FALSE,
4917 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
4920 Yalien_nB, FALSE, TRUE,
4921 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
4924 Yalien_e, FALSE, FALSE,
4925 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
4928 Yalien_eB, FALSE, TRUE,
4929 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
4932 Yalien_s, FALSE, FALSE,
4933 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
4936 Yalien_sB, FALSE, TRUE,
4937 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
4940 Yalien_w, FALSE, FALSE,
4941 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
4944 Yalien_wB, FALSE, TRUE,
4945 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
4948 Yalien_stone, FALSE, FALSE,
4949 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
4952 Yalien_spring, FALSE, FALSE,
4953 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
4956 Xemerald, TRUE, FALSE,
4960 Xemerald_pause, FALSE, FALSE,
4964 Xemerald_fall, FALSE, FALSE,
4968 Xemerald_shine, FALSE, FALSE,
4969 EL_EMERALD, ACTION_TWINKLING, -1
4972 Yemerald_s, FALSE, FALSE,
4973 EL_EMERALD, ACTION_FALLING, -1
4976 Yemerald_sB, FALSE, TRUE,
4977 EL_EMERALD, ACTION_FALLING, -1
4980 Yemerald_e, FALSE, FALSE,
4981 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
4984 Yemerald_eB, FALSE, TRUE,
4985 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
4988 Yemerald_w, FALSE, FALSE,
4989 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
4992 Yemerald_wB, FALSE, TRUE,
4993 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
4996 Yemerald_eat, FALSE, FALSE,
4997 EL_EMERALD, ACTION_COLLECTING, -1
5000 Yemerald_stone, FALSE, FALSE,
5001 EL_NUT, ACTION_BREAKING, -1
5004 Xdiamond, TRUE, FALSE,
5008 Xdiamond_pause, FALSE, FALSE,
5012 Xdiamond_fall, FALSE, FALSE,
5016 Xdiamond_shine, FALSE, FALSE,
5017 EL_DIAMOND, ACTION_TWINKLING, -1
5020 Ydiamond_s, FALSE, FALSE,
5021 EL_DIAMOND, ACTION_FALLING, -1
5024 Ydiamond_sB, FALSE, TRUE,
5025 EL_DIAMOND, ACTION_FALLING, -1
5028 Ydiamond_e, FALSE, FALSE,
5029 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
5032 Ydiamond_eB, FALSE, TRUE,
5033 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
5036 Ydiamond_w, FALSE, FALSE,
5037 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
5040 Ydiamond_wB, FALSE, TRUE,
5041 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
5044 Ydiamond_eat, FALSE, FALSE,
5045 EL_DIAMOND, ACTION_COLLECTING, -1
5048 Ydiamond_stone, FALSE, FALSE,
5049 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
5052 Xdrip_fall, TRUE, FALSE,
5053 EL_AMOEBA_DROP, -1, -1
5056 Xdrip_stretch, FALSE, FALSE,
5057 EL_AMOEBA_DROP, ACTION_FALLING, -1
5060 Xdrip_stretchB, FALSE, TRUE,
5061 EL_AMOEBA_DROP, ACTION_FALLING, -1
5064 Xdrip_eat, FALSE, FALSE,
5065 EL_AMOEBA_DROP, ACTION_GROWING, -1
5068 Ydrip_s1, FALSE, FALSE,
5069 EL_AMOEBA_DROP, ACTION_FALLING, -1
5072 Ydrip_s1B, FALSE, TRUE,
5073 EL_AMOEBA_DROP, ACTION_FALLING, -1
5076 Ydrip_s2, FALSE, FALSE,
5077 EL_AMOEBA_DROP, ACTION_FALLING, -1
5080 Ydrip_s2B, FALSE, TRUE,
5081 EL_AMOEBA_DROP, ACTION_FALLING, -1
5088 Xbomb_pause, FALSE, FALSE,
5092 Xbomb_fall, FALSE, FALSE,
5096 Ybomb_s, FALSE, FALSE,
5097 EL_BOMB, ACTION_FALLING, -1
5100 Ybomb_sB, FALSE, TRUE,
5101 EL_BOMB, ACTION_FALLING, -1
5104 Ybomb_e, FALSE, FALSE,
5105 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
5108 Ybomb_eB, FALSE, TRUE,
5109 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
5112 Ybomb_w, FALSE, FALSE,
5113 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
5116 Ybomb_wB, FALSE, TRUE,
5117 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
5120 Ybomb_eat, FALSE, FALSE,
5121 EL_BOMB, ACTION_ACTIVATING, -1
5124 Xballoon, TRUE, FALSE,
5128 Yballoon_n, FALSE, FALSE,
5129 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
5132 Yballoon_nB, FALSE, TRUE,
5133 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
5136 Yballoon_e, FALSE, FALSE,
5137 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
5140 Yballoon_eB, FALSE, TRUE,
5141 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
5144 Yballoon_s, FALSE, FALSE,
5145 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
5148 Yballoon_sB, FALSE, TRUE,
5149 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
5152 Yballoon_w, FALSE, FALSE,
5153 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
5156 Yballoon_wB, FALSE, TRUE,
5157 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
5160 Xgrass, TRUE, FALSE,
5161 EL_EMC_GRASS, -1, -1
5164 Ygrass_nB, FALSE, FALSE,
5165 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
5168 Ygrass_eB, FALSE, FALSE,
5169 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
5172 Ygrass_sB, FALSE, FALSE,
5173 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
5176 Ygrass_wB, FALSE, FALSE,
5177 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
5184 Ydirt_nB, FALSE, FALSE,
5185 EL_SAND, ACTION_DIGGING, MV_BIT_UP
5188 Ydirt_eB, FALSE, FALSE,
5189 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
5192 Ydirt_sB, FALSE, FALSE,
5193 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
5196 Ydirt_wB, FALSE, FALSE,
5197 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
5200 Xacid_ne, TRUE, FALSE,
5201 EL_ACID_POOL_TOPRIGHT, -1, -1
5204 Xacid_se, TRUE, FALSE,
5205 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
5208 Xacid_s, TRUE, FALSE,
5209 EL_ACID_POOL_BOTTOM, -1, -1
5212 Xacid_sw, TRUE, FALSE,
5213 EL_ACID_POOL_BOTTOMLEFT, -1, -1
5216 Xacid_nw, TRUE, FALSE,
5217 EL_ACID_POOL_TOPLEFT, -1, -1
5220 Xacid_1, TRUE, FALSE,
5224 Xacid_2, FALSE, FALSE,
5228 Xacid_3, FALSE, FALSE,
5232 Xacid_4, FALSE, FALSE,
5236 Xacid_5, FALSE, FALSE,
5240 Xacid_6, FALSE, FALSE,
5244 Xacid_7, FALSE, FALSE,
5248 Xacid_8, FALSE, FALSE,
5252 Xball_1, TRUE, FALSE,
5253 EL_EMC_MAGIC_BALL, -1, -1
5256 Xball_1B, FALSE, FALSE,
5257 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5260 Xball_2, FALSE, FALSE,
5261 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5264 Xball_2B, FALSE, FALSE,
5265 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5268 Yball_eat, FALSE, FALSE,
5269 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
5272 Ykey_1_eat, FALSE, FALSE,
5273 EL_EM_KEY_1, ACTION_COLLECTING, -1
5276 Ykey_2_eat, FALSE, FALSE,
5277 EL_EM_KEY_2, ACTION_COLLECTING, -1
5280 Ykey_3_eat, FALSE, FALSE,
5281 EL_EM_KEY_3, ACTION_COLLECTING, -1
5284 Ykey_4_eat, FALSE, FALSE,
5285 EL_EM_KEY_4, ACTION_COLLECTING, -1
5288 Ykey_5_eat, FALSE, FALSE,
5289 EL_EMC_KEY_5, ACTION_COLLECTING, -1
5292 Ykey_6_eat, FALSE, FALSE,
5293 EL_EMC_KEY_6, ACTION_COLLECTING, -1
5296 Ykey_7_eat, FALSE, FALSE,
5297 EL_EMC_KEY_7, ACTION_COLLECTING, -1
5300 Ykey_8_eat, FALSE, FALSE,
5301 EL_EMC_KEY_8, ACTION_COLLECTING, -1
5304 Ylenses_eat, FALSE, FALSE,
5305 EL_EMC_LENSES, ACTION_COLLECTING, -1
5308 Ymagnify_eat, FALSE, FALSE,
5309 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
5312 Ygrass_eat, FALSE, FALSE,
5313 EL_EMC_GRASS, ACTION_SNAPPING, -1
5316 Ydirt_eat, FALSE, FALSE,
5317 EL_SAND, ACTION_SNAPPING, -1
5320 Xgrow_ns, TRUE, FALSE,
5321 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
5324 Ygrow_ns_eat, FALSE, FALSE,
5325 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
5328 Xgrow_ew, TRUE, FALSE,
5329 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
5332 Ygrow_ew_eat, FALSE, FALSE,
5333 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
5336 Xwonderwall, TRUE, FALSE,
5337 EL_MAGIC_WALL, -1, -1
5340 XwonderwallB, FALSE, FALSE,
5341 EL_MAGIC_WALL, ACTION_ACTIVE, -1
5344 Xamoeba_1, TRUE, FALSE,
5345 EL_AMOEBA_DRY, ACTION_OTHER, -1
5348 Xamoeba_2, FALSE, FALSE,
5349 EL_AMOEBA_DRY, ACTION_OTHER, -1
5352 Xamoeba_3, FALSE, FALSE,
5353 EL_AMOEBA_DRY, ACTION_OTHER, -1
5356 Xamoeba_4, FALSE, FALSE,
5357 EL_AMOEBA_DRY, ACTION_OTHER, -1
5360 Xamoeba_5, TRUE, FALSE,
5361 EL_AMOEBA_WET, ACTION_OTHER, -1
5364 Xamoeba_6, FALSE, FALSE,
5365 EL_AMOEBA_WET, ACTION_OTHER, -1
5368 Xamoeba_7, FALSE, FALSE,
5369 EL_AMOEBA_WET, ACTION_OTHER, -1
5372 Xamoeba_8, FALSE, FALSE,
5373 EL_AMOEBA_WET, ACTION_OTHER, -1
5376 Xdoor_1, TRUE, FALSE,
5377 EL_EM_GATE_1, -1, -1
5380 Xdoor_2, TRUE, FALSE,
5381 EL_EM_GATE_2, -1, -1
5384 Xdoor_3, TRUE, FALSE,
5385 EL_EM_GATE_3, -1, -1
5388 Xdoor_4, TRUE, FALSE,
5389 EL_EM_GATE_4, -1, -1
5392 Xdoor_5, TRUE, FALSE,
5393 EL_EMC_GATE_5, -1, -1
5396 Xdoor_6, TRUE, FALSE,
5397 EL_EMC_GATE_6, -1, -1
5400 Xdoor_7, TRUE, FALSE,
5401 EL_EMC_GATE_7, -1, -1
5404 Xdoor_8, TRUE, FALSE,
5405 EL_EMC_GATE_8, -1, -1
5408 Xkey_1, TRUE, FALSE,
5412 Xkey_2, TRUE, FALSE,
5416 Xkey_3, TRUE, FALSE,
5420 Xkey_4, TRUE, FALSE,
5424 Xkey_5, TRUE, FALSE,
5425 EL_EMC_KEY_5, -1, -1
5428 Xkey_6, TRUE, FALSE,
5429 EL_EMC_KEY_6, -1, -1
5432 Xkey_7, TRUE, FALSE,
5433 EL_EMC_KEY_7, -1, -1
5436 Xkey_8, TRUE, FALSE,
5437 EL_EMC_KEY_8, -1, -1
5440 Xwind_n, TRUE, FALSE,
5441 EL_BALLOON_SWITCH_UP, -1, -1
5444 Xwind_e, TRUE, FALSE,
5445 EL_BALLOON_SWITCH_RIGHT, -1, -1
5448 Xwind_s, TRUE, FALSE,
5449 EL_BALLOON_SWITCH_DOWN, -1, -1
5452 Xwind_w, TRUE, FALSE,
5453 EL_BALLOON_SWITCH_LEFT, -1, -1
5456 Xwind_nesw, TRUE, FALSE,
5457 EL_BALLOON_SWITCH_ANY, -1, -1
5460 Xwind_stop, TRUE, FALSE,
5461 EL_BALLOON_SWITCH_NONE, -1, -1
5465 EL_EM_EXIT_CLOSED, -1, -1
5468 Xexit_1, TRUE, FALSE,
5469 EL_EM_EXIT_OPEN, -1, -1
5472 Xexit_2, FALSE, FALSE,
5473 EL_EM_EXIT_OPEN, -1, -1
5476 Xexit_3, FALSE, FALSE,
5477 EL_EM_EXIT_OPEN, -1, -1
5480 Xdynamite, TRUE, FALSE,
5481 EL_EM_DYNAMITE, -1, -1
5484 Ydynamite_eat, FALSE, FALSE,
5485 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
5488 Xdynamite_1, TRUE, FALSE,
5489 EL_EM_DYNAMITE_ACTIVE, -1, -1
5492 Xdynamite_2, FALSE, FALSE,
5493 EL_EM_DYNAMITE_ACTIVE, -1, -1
5496 Xdynamite_3, FALSE, FALSE,
5497 EL_EM_DYNAMITE_ACTIVE, -1, -1
5500 Xdynamite_4, FALSE, FALSE,
5501 EL_EM_DYNAMITE_ACTIVE, -1, -1
5504 Xbumper, TRUE, FALSE,
5505 EL_EMC_SPRING_BUMPER, -1, -1
5508 XbumperB, FALSE, FALSE,
5509 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
5512 Xwheel, TRUE, FALSE,
5513 EL_ROBOT_WHEEL, -1, -1
5516 XwheelB, FALSE, FALSE,
5517 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
5520 Xswitch, TRUE, FALSE,
5521 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
5524 XswitchB, FALSE, FALSE,
5525 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
5529 EL_QUICKSAND_EMPTY, -1, -1
5532 Xsand_stone, TRUE, FALSE,
5533 EL_QUICKSAND_FULL, -1, -1
5536 Xsand_stonein_1, FALSE, TRUE,
5537 EL_ROCK, ACTION_FILLING, -1
5540 Xsand_stonein_2, FALSE, TRUE,
5541 EL_ROCK, ACTION_FILLING, -1
5544 Xsand_stonein_3, FALSE, TRUE,
5545 EL_ROCK, ACTION_FILLING, -1
5548 Xsand_stonein_4, FALSE, TRUE,
5549 EL_ROCK, ACTION_FILLING, -1
5553 Xsand_stonesand_1, FALSE, FALSE,
5554 EL_QUICKSAND_EMPTYING, -1, -1
5557 Xsand_stonesand_2, FALSE, FALSE,
5558 EL_QUICKSAND_EMPTYING, -1, -1
5561 Xsand_stonesand_3, FALSE, FALSE,
5562 EL_QUICKSAND_EMPTYING, -1, -1
5565 Xsand_stonesand_4, FALSE, FALSE,
5566 EL_QUICKSAND_EMPTYING, -1, -1
5569 Xsand_stonesand_quickout_1, FALSE, FALSE,
5570 EL_QUICKSAND_EMPTYING, -1, -1
5573 Xsand_stonesand_quickout_2, FALSE, FALSE,
5574 EL_QUICKSAND_EMPTYING, -1, -1
5578 Xsand_stonesand_1, FALSE, FALSE,
5579 EL_QUICKSAND_FULL, -1, -1
5582 Xsand_stonesand_2, FALSE, FALSE,
5583 EL_QUICKSAND_FULL, -1, -1
5586 Xsand_stonesand_3, FALSE, FALSE,
5587 EL_QUICKSAND_FULL, -1, -1
5590 Xsand_stonesand_4, FALSE, FALSE,
5591 EL_QUICKSAND_FULL, -1, -1
5595 Xsand_stoneout_1, FALSE, FALSE,
5596 EL_ROCK, ACTION_EMPTYING, -1
5599 Xsand_stoneout_2, FALSE, FALSE,
5600 EL_ROCK, ACTION_EMPTYING, -1
5604 Xsand_sandstone_1, FALSE, FALSE,
5605 EL_QUICKSAND_FILLING, -1, -1
5608 Xsand_sandstone_2, FALSE, FALSE,
5609 EL_QUICKSAND_FILLING, -1, -1
5612 Xsand_sandstone_3, FALSE, FALSE,
5613 EL_QUICKSAND_FILLING, -1, -1
5616 Xsand_sandstone_4, FALSE, FALSE,
5617 EL_QUICKSAND_FILLING, -1, -1
5621 Xsand_sandstone_1, FALSE, FALSE,
5622 EL_QUICKSAND_FULL, -1, -1
5625 Xsand_sandstone_2, FALSE, FALSE,
5626 EL_QUICKSAND_FULL, -1, -1
5629 Xsand_sandstone_3, FALSE, FALSE,
5630 EL_QUICKSAND_FULL, -1, -1
5633 Xsand_sandstone_4, FALSE, FALSE,
5634 EL_QUICKSAND_FULL, -1, -1
5638 Xplant, TRUE, FALSE,
5639 EL_EMC_PLANT, -1, -1
5642 Yplant, FALSE, FALSE,
5643 EL_EMC_PLANT, -1, -1
5646 Xlenses, TRUE, FALSE,
5647 EL_EMC_LENSES, -1, -1
5650 Xmagnify, TRUE, FALSE,
5651 EL_EMC_MAGNIFIER, -1, -1
5654 Xdripper, TRUE, FALSE,
5655 EL_EMC_DRIPPER, -1, -1
5658 XdripperB, FALSE, FALSE,
5659 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
5662 Xfake_blank, TRUE, FALSE,
5663 EL_INVISIBLE_WALL, -1, -1
5666 Xfake_blankB, FALSE, FALSE,
5667 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
5670 Xfake_grass, TRUE, FALSE,
5671 EL_EMC_FAKE_GRASS, -1, -1
5674 Xfake_grassB, FALSE, FALSE,
5675 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
5678 Xfake_door_1, TRUE, FALSE,
5679 EL_EM_GATE_1_GRAY, -1, -1
5682 Xfake_door_2, TRUE, FALSE,
5683 EL_EM_GATE_2_GRAY, -1, -1
5686 Xfake_door_3, TRUE, FALSE,
5687 EL_EM_GATE_3_GRAY, -1, -1
5690 Xfake_door_4, TRUE, FALSE,
5691 EL_EM_GATE_4_GRAY, -1, -1
5694 Xfake_door_5, TRUE, FALSE,
5695 EL_EMC_GATE_5_GRAY, -1, -1
5698 Xfake_door_6, TRUE, FALSE,
5699 EL_EMC_GATE_6_GRAY, -1, -1
5702 Xfake_door_7, TRUE, FALSE,
5703 EL_EMC_GATE_7_GRAY, -1, -1
5706 Xfake_door_8, TRUE, FALSE,
5707 EL_EMC_GATE_8_GRAY, -1, -1
5710 Xfake_acid_1, TRUE, FALSE,
5711 EL_EMC_FAKE_ACID, -1, -1
5714 Xfake_acid_2, FALSE, FALSE,
5715 EL_EMC_FAKE_ACID, -1, -1
5718 Xfake_acid_3, FALSE, FALSE,
5719 EL_EMC_FAKE_ACID, -1, -1
5722 Xfake_acid_4, FALSE, FALSE,
5723 EL_EMC_FAKE_ACID, -1, -1
5726 Xfake_acid_5, FALSE, FALSE,
5727 EL_EMC_FAKE_ACID, -1, -1
5730 Xfake_acid_6, FALSE, FALSE,
5731 EL_EMC_FAKE_ACID, -1, -1
5734 Xfake_acid_7, FALSE, FALSE,
5735 EL_EMC_FAKE_ACID, -1, -1
5738 Xfake_acid_8, FALSE, FALSE,
5739 EL_EMC_FAKE_ACID, -1, -1
5742 Xsteel_1, TRUE, FALSE,
5743 EL_STEELWALL, -1, -1
5746 Xsteel_2, TRUE, FALSE,
5747 EL_EMC_STEELWALL_2, -1, -1
5750 Xsteel_3, TRUE, FALSE,
5751 EL_EMC_STEELWALL_3, -1, -1
5754 Xsteel_4, TRUE, FALSE,
5755 EL_EMC_STEELWALL_4, -1, -1
5758 Xwall_1, TRUE, FALSE,
5762 Xwall_2, TRUE, FALSE,
5763 EL_EMC_WALL_14, -1, -1
5766 Xwall_3, TRUE, FALSE,
5767 EL_EMC_WALL_15, -1, -1
5770 Xwall_4, TRUE, FALSE,
5771 EL_EMC_WALL_16, -1, -1
5774 Xround_wall_1, TRUE, FALSE,
5775 EL_WALL_SLIPPERY, -1, -1
5778 Xround_wall_2, TRUE, FALSE,
5779 EL_EMC_WALL_SLIPPERY_2, -1, -1
5782 Xround_wall_3, TRUE, FALSE,
5783 EL_EMC_WALL_SLIPPERY_3, -1, -1
5786 Xround_wall_4, TRUE, FALSE,
5787 EL_EMC_WALL_SLIPPERY_4, -1, -1
5790 Xdecor_1, TRUE, FALSE,
5791 EL_EMC_WALL_8, -1, -1
5794 Xdecor_2, TRUE, FALSE,
5795 EL_EMC_WALL_6, -1, -1
5798 Xdecor_3, TRUE, FALSE,
5799 EL_EMC_WALL_4, -1, -1
5802 Xdecor_4, TRUE, FALSE,
5803 EL_EMC_WALL_7, -1, -1
5806 Xdecor_5, TRUE, FALSE,
5807 EL_EMC_WALL_5, -1, -1
5810 Xdecor_6, TRUE, FALSE,
5811 EL_EMC_WALL_9, -1, -1
5814 Xdecor_7, TRUE, FALSE,
5815 EL_EMC_WALL_10, -1, -1
5818 Xdecor_8, TRUE, FALSE,
5819 EL_EMC_WALL_1, -1, -1
5822 Xdecor_9, TRUE, FALSE,
5823 EL_EMC_WALL_2, -1, -1
5826 Xdecor_10, TRUE, FALSE,
5827 EL_EMC_WALL_3, -1, -1
5830 Xdecor_11, TRUE, FALSE,
5831 EL_EMC_WALL_11, -1, -1
5834 Xdecor_12, TRUE, FALSE,
5835 EL_EMC_WALL_12, -1, -1
5838 Xalpha_0, TRUE, FALSE,
5839 EL_CHAR('0'), -1, -1
5842 Xalpha_1, TRUE, FALSE,
5843 EL_CHAR('1'), -1, -1
5846 Xalpha_2, TRUE, FALSE,
5847 EL_CHAR('2'), -1, -1
5850 Xalpha_3, TRUE, FALSE,
5851 EL_CHAR('3'), -1, -1
5854 Xalpha_4, TRUE, FALSE,
5855 EL_CHAR('4'), -1, -1
5858 Xalpha_5, TRUE, FALSE,
5859 EL_CHAR('5'), -1, -1
5862 Xalpha_6, TRUE, FALSE,
5863 EL_CHAR('6'), -1, -1
5866 Xalpha_7, TRUE, FALSE,
5867 EL_CHAR('7'), -1, -1
5870 Xalpha_8, TRUE, FALSE,
5871 EL_CHAR('8'), -1, -1
5874 Xalpha_9, TRUE, FALSE,
5875 EL_CHAR('9'), -1, -1
5878 Xalpha_excla, TRUE, FALSE,
5879 EL_CHAR('!'), -1, -1
5882 Xalpha_quote, TRUE, FALSE,
5883 EL_CHAR('"'), -1, -1
5886 Xalpha_comma, TRUE, FALSE,
5887 EL_CHAR(','), -1, -1
5890 Xalpha_minus, TRUE, FALSE,
5891 EL_CHAR('-'), -1, -1
5894 Xalpha_perio, TRUE, FALSE,
5895 EL_CHAR('.'), -1, -1
5898 Xalpha_colon, TRUE, FALSE,
5899 EL_CHAR(':'), -1, -1
5902 Xalpha_quest, TRUE, FALSE,
5903 EL_CHAR('?'), -1, -1
5906 Xalpha_a, TRUE, FALSE,
5907 EL_CHAR('A'), -1, -1
5910 Xalpha_b, TRUE, FALSE,
5911 EL_CHAR('B'), -1, -1
5914 Xalpha_c, TRUE, FALSE,
5915 EL_CHAR('C'), -1, -1
5918 Xalpha_d, TRUE, FALSE,
5919 EL_CHAR('D'), -1, -1
5922 Xalpha_e, TRUE, FALSE,
5923 EL_CHAR('E'), -1, -1
5926 Xalpha_f, TRUE, FALSE,
5927 EL_CHAR('F'), -1, -1
5930 Xalpha_g, TRUE, FALSE,
5931 EL_CHAR('G'), -1, -1
5934 Xalpha_h, TRUE, FALSE,
5935 EL_CHAR('H'), -1, -1
5938 Xalpha_i, TRUE, FALSE,
5939 EL_CHAR('I'), -1, -1
5942 Xalpha_j, TRUE, FALSE,
5943 EL_CHAR('J'), -1, -1
5946 Xalpha_k, TRUE, FALSE,
5947 EL_CHAR('K'), -1, -1
5950 Xalpha_l, TRUE, FALSE,
5951 EL_CHAR('L'), -1, -1
5954 Xalpha_m, TRUE, FALSE,
5955 EL_CHAR('M'), -1, -1
5958 Xalpha_n, TRUE, FALSE,
5959 EL_CHAR('N'), -1, -1
5962 Xalpha_o, TRUE, FALSE,
5963 EL_CHAR('O'), -1, -1
5966 Xalpha_p, TRUE, FALSE,
5967 EL_CHAR('P'), -1, -1
5970 Xalpha_q, TRUE, FALSE,
5971 EL_CHAR('Q'), -1, -1
5974 Xalpha_r, TRUE, FALSE,
5975 EL_CHAR('R'), -1, -1
5978 Xalpha_s, TRUE, FALSE,
5979 EL_CHAR('S'), -1, -1
5982 Xalpha_t, TRUE, FALSE,
5983 EL_CHAR('T'), -1, -1
5986 Xalpha_u, TRUE, FALSE,
5987 EL_CHAR('U'), -1, -1
5990 Xalpha_v, TRUE, FALSE,
5991 EL_CHAR('V'), -1, -1
5994 Xalpha_w, TRUE, FALSE,
5995 EL_CHAR('W'), -1, -1
5998 Xalpha_x, TRUE, FALSE,
5999 EL_CHAR('X'), -1, -1
6002 Xalpha_y, TRUE, FALSE,
6003 EL_CHAR('Y'), -1, -1
6006 Xalpha_z, TRUE, FALSE,
6007 EL_CHAR('Z'), -1, -1
6010 Xalpha_arrow_e, TRUE, FALSE,
6011 EL_CHAR('>'), -1, -1
6014 Xalpha_arrow_w, TRUE, FALSE,
6015 EL_CHAR('<'), -1, -1
6018 Xalpha_copyr, TRUE, FALSE,
6019 EL_CHAR('©'), -1, -1
6023 Xboom_bug, FALSE, FALSE,
6024 EL_BUG, ACTION_EXPLODING, -1
6027 Xboom_bomb, FALSE, FALSE,
6028 EL_BOMB, ACTION_EXPLODING, -1
6031 Xboom_android, FALSE, FALSE,
6032 EL_EMC_ANDROID, ACTION_OTHER, -1
6035 Xboom_1, FALSE, FALSE,
6036 EL_DEFAULT, ACTION_EXPLODING, -1
6039 Xboom_2, FALSE, FALSE,
6040 EL_DEFAULT, ACTION_EXPLODING, -1
6043 Znormal, FALSE, FALSE,
6047 Zdynamite, FALSE, FALSE,
6051 Zplayer, FALSE, FALSE,
6055 ZBORDER, FALSE, FALSE,
6065 static struct Mapping_EM_to_RND_player
6074 em_player_mapping_list[] =
6078 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
6082 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
6086 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
6090 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
6094 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
6098 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
6102 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
6106 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
6110 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
6114 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
6118 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
6122 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
6126 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
6130 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
6134 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
6138 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
6142 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
6146 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
6150 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
6154 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
6158 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
6162 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
6166 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
6170 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
6174 EL_PLAYER_1, ACTION_DEFAULT, -1,
6178 EL_PLAYER_2, ACTION_DEFAULT, -1,
6182 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
6186 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
6190 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
6194 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
6198 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
6202 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
6206 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
6210 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
6214 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
6218 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
6222 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
6226 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
6230 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
6234 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
6238 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
6242 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
6246 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
6250 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
6254 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
6258 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
6262 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
6266 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
6270 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
6274 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
6278 EL_PLAYER_3, ACTION_DEFAULT, -1,
6282 EL_PLAYER_4, ACTION_DEFAULT, -1,
6291 int map_element_RND_to_EM(int element_rnd)
6293 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
6294 static boolean mapping_initialized = FALSE;
6296 if (!mapping_initialized)
6300 /* return "Xalpha_quest" for all undefined elements in mapping array */
6301 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
6302 mapping_RND_to_EM[i] = Xalpha_quest;
6304 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6305 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
6306 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
6307 em_object_mapping_list[i].element_em;
6309 mapping_initialized = TRUE;
6312 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
6313 return mapping_RND_to_EM[element_rnd];
6315 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
6320 int map_element_EM_to_RND(int element_em)
6322 static unsigned short mapping_EM_to_RND[TILE_MAX];
6323 static boolean mapping_initialized = FALSE;
6325 if (!mapping_initialized)
6329 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
6330 for (i = 0; i < TILE_MAX; i++)
6331 mapping_EM_to_RND[i] = EL_UNKNOWN;
6333 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6334 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
6335 em_object_mapping_list[i].element_rnd;
6337 mapping_initialized = TRUE;
6340 if (element_em >= 0 && element_em < TILE_MAX)
6341 return mapping_EM_to_RND[element_em];
6343 Error(ERR_WARN, "invalid EM level element %d", element_em);
6348 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
6350 struct LevelInfo_EM *level_em = level->native_em_level;
6351 struct LEVEL *lev = level_em->lev;
6354 for (i = 0; i < TILE_MAX; i++)
6355 lev->android_array[i] = Xblank;
6357 for (i = 0; i < level->num_android_clone_elements; i++)
6359 int element_rnd = level->android_clone_element[i];
6360 int element_em = map_element_RND_to_EM(element_rnd);
6362 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
6363 if (em_object_mapping_list[j].element_rnd == element_rnd)
6364 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
6368 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
6370 struct LevelInfo_EM *level_em = level->native_em_level;
6371 struct LEVEL *lev = level_em->lev;
6374 level->num_android_clone_elements = 0;
6376 for (i = 0; i < TILE_MAX; i++)
6378 int element_em = lev->android_array[i];
6380 boolean element_found = FALSE;
6382 if (element_em == Xblank)
6385 element_rnd = map_element_EM_to_RND(element_em);
6387 for (j = 0; j < level->num_android_clone_elements; j++)
6388 if (level->android_clone_element[j] == element_rnd)
6389 element_found = TRUE;
6393 level->android_clone_element[level->num_android_clone_elements++] =
6396 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
6401 if (level->num_android_clone_elements == 0)
6403 level->num_android_clone_elements = 1;
6404 level->android_clone_element[0] = EL_EMPTY;
6408 int map_direction_RND_to_EM(int direction)
6410 return (direction == MV_UP ? 0 :
6411 direction == MV_RIGHT ? 1 :
6412 direction == MV_DOWN ? 2 :
6413 direction == MV_LEFT ? 3 :
6417 int map_direction_EM_to_RND(int direction)
6419 return (direction == 0 ? MV_UP :
6420 direction == 1 ? MV_RIGHT :
6421 direction == 2 ? MV_DOWN :
6422 direction == 3 ? MV_LEFT :
6426 int map_element_RND_to_SP(int element_rnd)
6428 int element_sp = 0x20; /* map unknown elements to yellow "hardware" */
6430 if (element_rnd >= EL_SP_START &&
6431 element_rnd <= EL_SP_END)
6432 element_sp = element_rnd - EL_SP_START;
6433 else if (element_rnd == EL_EMPTY_SPACE)
6435 else if (element_rnd == EL_INVISIBLE_WALL)
6441 int map_element_SP_to_RND(int element_sp)
6443 int element_rnd = EL_UNKNOWN;
6445 if (element_sp >= 0x00 &&
6447 element_rnd = EL_SP_START + element_sp;
6448 else if (element_sp == 0x28)
6449 element_rnd = EL_INVISIBLE_WALL;
6454 int map_action_SP_to_RND(int action_sp)
6458 case actActive: return ACTION_ACTIVE;
6459 case actImpact: return ACTION_IMPACT;
6460 case actExploding: return ACTION_EXPLODING;
6461 case actDigging: return ACTION_DIGGING;
6462 case actSnapping: return ACTION_SNAPPING;
6463 case actCollecting: return ACTION_COLLECTING;
6464 case actPassing: return ACTION_PASSING;
6465 case actPushing: return ACTION_PUSHING;
6466 case actDropping: return ACTION_DROPPING;
6468 default: return ACTION_DEFAULT;
6472 int get_next_element(int element)
6476 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
6477 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
6478 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
6479 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
6480 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
6481 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
6482 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
6483 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
6484 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
6485 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
6486 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
6488 default: return element;
6493 int el_act_dir2img(int element, int action, int direction)
6495 element = GFX_ELEMENT(element);
6497 if (direction == MV_NONE)
6498 return element_info[element].graphic[action];
6500 direction = MV_DIR_TO_BIT(direction);
6502 return element_info[element].direction_graphic[action][direction];
6505 int el_act_dir2img(int element, int action, int direction)
6507 element = GFX_ELEMENT(element);
6508 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
6510 /* direction_graphic[][] == graphic[] for undefined direction graphics */
6511 return element_info[element].direction_graphic[action][direction];
6516 static int el_act_dir2crm(int element, int action, int direction)
6518 element = GFX_ELEMENT(element);
6520 if (direction == MV_NONE)
6521 return element_info[element].crumbled[action];
6523 direction = MV_DIR_TO_BIT(direction);
6525 return element_info[element].direction_crumbled[action][direction];
6528 static int el_act_dir2crm(int element, int action, int direction)
6530 element = GFX_ELEMENT(element);
6531 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
6533 /* direction_graphic[][] == graphic[] for undefined direction graphics */
6534 return element_info[element].direction_crumbled[action][direction];
6538 int el_act2img(int element, int action)
6540 element = GFX_ELEMENT(element);
6542 return element_info[element].graphic[action];
6545 int el_act2crm(int element, int action)
6547 element = GFX_ELEMENT(element);
6549 return element_info[element].crumbled[action];
6552 int el_dir2img(int element, int direction)
6554 element = GFX_ELEMENT(element);
6556 return el_act_dir2img(element, ACTION_DEFAULT, direction);
6559 int el2baseimg(int element)
6561 return element_info[element].graphic[ACTION_DEFAULT];
6564 int el2img(int element)
6566 element = GFX_ELEMENT(element);
6568 return element_info[element].graphic[ACTION_DEFAULT];
6571 int el2edimg(int element)
6573 element = GFX_ELEMENT(element);
6575 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
6578 int el2preimg(int element)
6580 element = GFX_ELEMENT(element);
6582 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
6585 int el2panelimg(int element)
6587 element = GFX_ELEMENT(element);
6589 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL];
6592 int font2baseimg(int font_nr)
6594 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
6597 int getBeltNrFromBeltElement(int element)
6599 return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
6600 element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
6601 element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
6604 int getBeltNrFromBeltActiveElement(int element)
6606 return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
6607 element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
6608 element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
6611 int getBeltNrFromBeltSwitchElement(int element)
6613 return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
6614 element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
6615 element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
6618 int getBeltDirNrFromBeltElement(int element)
6620 static int belt_base_element[4] =
6622 EL_CONVEYOR_BELT_1_LEFT,
6623 EL_CONVEYOR_BELT_2_LEFT,
6624 EL_CONVEYOR_BELT_3_LEFT,
6625 EL_CONVEYOR_BELT_4_LEFT
6628 int belt_nr = getBeltNrFromBeltElement(element);
6629 int belt_dir_nr = element - belt_base_element[belt_nr];
6631 return (belt_dir_nr % 3);
6634 int getBeltDirNrFromBeltSwitchElement(int element)
6636 static int belt_base_element[4] =
6638 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
6639 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
6640 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
6641 EL_CONVEYOR_BELT_4_SWITCH_LEFT
6644 int belt_nr = getBeltNrFromBeltSwitchElement(element);
6645 int belt_dir_nr = element - belt_base_element[belt_nr];
6647 return (belt_dir_nr % 3);
6650 int getBeltDirFromBeltElement(int element)
6652 static int belt_move_dir[3] =
6659 int belt_dir_nr = getBeltDirNrFromBeltElement(element);
6661 return belt_move_dir[belt_dir_nr];
6664 int getBeltDirFromBeltSwitchElement(int element)
6666 static int belt_move_dir[3] =
6673 int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
6675 return belt_move_dir[belt_dir_nr];
6678 int getBeltElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
6680 static int belt_base_element[4] =
6682 EL_CONVEYOR_BELT_1_LEFT,
6683 EL_CONVEYOR_BELT_2_LEFT,
6684 EL_CONVEYOR_BELT_3_LEFT,
6685 EL_CONVEYOR_BELT_4_LEFT
6688 return belt_base_element[belt_nr] + belt_dir_nr;
6691 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
6693 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
6695 return getBeltElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
6698 int getBeltSwitchElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
6700 static int belt_base_element[4] =
6702 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
6703 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
6704 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
6705 EL_CONVEYOR_BELT_4_SWITCH_LEFT
6708 return belt_base_element[belt_nr] + belt_dir_nr;
6711 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
6713 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
6715 return getBeltSwitchElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
6718 int getNumActivePlayers_EM()
6720 int num_players = 0;
6726 for (i = 0; i < MAX_PLAYERS; i++)
6727 if (tape.player_participates[i])
6733 int getGameFrameDelay_EM(int native_em_game_frame_delay)
6735 int game_frame_delay_value;
6737 game_frame_delay_value =
6738 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
6739 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
6742 if (tape.playing && tape.warp_forward && !tape.pausing)
6743 game_frame_delay_value = 0;
6745 return game_frame_delay_value;
6748 unsigned int InitRND(long seed)
6750 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
6751 return InitEngineRandom_EM(seed);
6752 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
6753 return InitEngineRandom_SP(seed);
6755 return InitEngineRandom_RND(seed);
6759 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
6760 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
6763 inline static int get_effective_element_EM(int tile, int frame_em)
6765 int element = object_mapping[tile].element_rnd;
6766 int action = object_mapping[tile].action;
6767 boolean is_backside = object_mapping[tile].is_backside;
6768 boolean action_removing = (action == ACTION_DIGGING ||
6769 action == ACTION_SNAPPING ||
6770 action == ACTION_COLLECTING);
6776 case Yacid_splash_eB:
6777 case Yacid_splash_wB:
6778 return (frame_em > 5 ? EL_EMPTY : element);
6781 case Ydiamond_stone:
6782 // if (!game.use_native_emc_graphics_engine)
6790 else /* frame_em == 7 */
6794 case Yacid_splash_eB:
6795 case Yacid_splash_wB:
6798 case Yemerald_stone:
6801 case Ydiamond_stone:
6805 case Xdrip_stretchB:
6824 case Xsand_stonein_1:
6825 case Xsand_stonein_2:
6826 case Xsand_stonein_3:
6827 case Xsand_stonein_4:
6831 return (is_backside || action_removing ? EL_EMPTY : element);
6836 inline static boolean check_linear_animation_EM(int tile)
6840 case Xsand_stonesand_1:
6841 case Xsand_stonesand_quickout_1:
6842 case Xsand_sandstone_1:
6843 case Xsand_stonein_1:
6844 case Xsand_stoneout_1:
6864 case Yacid_splash_eB:
6865 case Yacid_splash_wB:
6866 case Yemerald_stone:
6874 inline static void set_crumbled_graphics_EM(struct GraphicInfo_EM *g_em,
6875 boolean has_crumbled_graphics,
6876 int crumbled, int sync_frame)
6878 /* if element can be crumbled, but certain action graphics are just empty
6879 space (like instantly snapping sand to empty space in 1 frame), do not
6880 treat these empty space graphics as crumbled graphics in EMC engine */
6881 if (crumbled == IMG_EMPTY_SPACE)
6882 has_crumbled_graphics = FALSE;
6884 if (has_crumbled_graphics)
6886 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
6887 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
6888 g_crumbled->anim_delay,
6889 g_crumbled->anim_mode,
6890 g_crumbled->anim_start_frame,
6893 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
6894 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
6896 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
6898 g_em->has_crumbled_graphics = TRUE;
6902 g_em->crumbled_bitmap = NULL;
6903 g_em->crumbled_src_x = 0;
6904 g_em->crumbled_src_y = 0;
6905 g_em->crumbled_border_size = 0;
6907 g_em->has_crumbled_graphics = FALSE;
6911 void ResetGfxAnimation_EM(int x, int y, int tile)
6916 void SetGfxAnimation_EM(struct GraphicInfo_EM *g_em,
6917 int tile, int frame_em, int x, int y)
6919 int action = object_mapping[tile].action;
6921 int direction = object_mapping[tile].direction;
6922 int effective_element = get_effective_element_EM(tile, frame_em);
6923 int graphic = (direction == MV_NONE ?
6924 el_act2img(effective_element, action) :
6925 el_act_dir2img(effective_element, action, direction));
6926 struct GraphicInfo *g = &graphic_info[graphic];
6929 boolean action_removing = (action == ACTION_DIGGING ||
6930 action == ACTION_SNAPPING ||
6931 action == ACTION_COLLECTING);
6932 boolean action_moving = (action == ACTION_FALLING ||
6933 action == ACTION_MOVING ||
6934 action == ACTION_PUSHING ||
6935 action == ACTION_EATING ||
6936 action == ACTION_FILLING ||
6937 action == ACTION_EMPTYING);
6938 boolean action_falling = (action == ACTION_FALLING ||
6939 action == ACTION_FILLING ||
6940 action == ACTION_EMPTYING);
6942 /* special case: graphic uses "2nd movement tile" and has defined
6943 7 frames for movement animation (or less) => use default graphic
6944 for last (8th) frame which ends the movement animation */
6945 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
6947 action = ACTION_DEFAULT; /* (keep action_* unchanged for now) */
6948 graphic = (direction == MV_NONE ?
6949 el_act2img(effective_element, action) :
6950 el_act_dir2img(effective_element, action, direction));
6952 g = &graphic_info[graphic];
6956 if (tile == Xsand_stonesand_1 ||
6957 tile == Xsand_stonesand_2 ||
6958 tile == Xsand_stonesand_3 ||
6959 tile == Xsand_stonesand_4)
6960 printf("::: 1: quicksand frame %d [%d]\n", GfxFrame[x][y], tile);
6964 if ((action_removing || check_linear_animation_EM(tile)) && frame_em == 0)
6968 // printf("::: resetting... [%d]\n", tile);
6971 if (action_removing || check_linear_animation_EM(tile))
6973 GfxFrame[x][y] = frame_em;
6975 // printf("::: resetting... [%d]\n", tile);
6978 else if (action_moving)
6980 boolean is_backside = object_mapping[tile].is_backside;
6984 int direction = object_mapping[tile].direction;
6985 int move_dir = (action_falling ? MV_DOWN : direction);
6990 /* !!! TEST !!! NEW !!! DOES NOT WORK RIGHT YET !!! */
6991 if (g->double_movement && frame_em == 0)
6995 // printf("::: resetting... [%d]\n", tile);
6999 if (move_dir == MV_LEFT)
7000 GfxFrame[x - 1][y] = GfxFrame[x][y];
7001 else if (move_dir == MV_RIGHT)
7002 GfxFrame[x + 1][y] = GfxFrame[x][y];
7003 else if (move_dir == MV_UP)
7004 GfxFrame[x][y - 1] = GfxFrame[x][y];
7005 else if (move_dir == MV_DOWN)
7006 GfxFrame[x][y + 1] = GfxFrame[x][y];
7013 /* special case: animation for Xsand_stonesand_quickout_1/2 twice as fast */
7014 if (tile == Xsand_stonesand_quickout_1 ||
7015 tile == Xsand_stonesand_quickout_2)
7020 if (tile == Xsand_stonesand_1 ||
7021 tile == Xsand_stonesand_2 ||
7022 tile == Xsand_stonesand_3 ||
7023 tile == Xsand_stonesand_4)
7024 printf("::: 2: quicksand frame %d [%d]\n", GfxFrame[x][y], tile);
7028 if (graphic_info[graphic].anim_global_sync)
7029 sync_frame = FrameCounter;
7030 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
7031 sync_frame = GfxFrame[x][y];
7033 sync_frame = 0; /* playfield border (pseudo steel) */
7035 SetRandomAnimationValue(x, y);
7037 int frame = getAnimationFrame(g->anim_frames,
7040 g->anim_start_frame,
7043 g_em->unique_identifier =
7044 (graphic << 16) | ((frame % 8) << 12) | (g_em->width << 6) | g_em->height;
7048 void getGraphicSourceObjectExt_EM(struct GraphicInfo_EM *g_em,
7049 int tile, int frame_em, int x, int y)
7051 int action = object_mapping[tile].action;
7052 int direction = object_mapping[tile].direction;
7053 boolean is_backside = object_mapping[tile].is_backside;
7054 int effective_element = get_effective_element_EM(tile, frame_em);
7056 int effective_action = action;
7058 int effective_action = (frame_em < 7 ? action : ACTION_DEFAULT);
7060 int graphic = (direction == MV_NONE ?
7061 el_act2img(effective_element, effective_action) :
7062 el_act_dir2img(effective_element, effective_action,
7064 int crumbled = (direction == MV_NONE ?
7065 el_act2crm(effective_element, effective_action) :
7066 el_act_dir2crm(effective_element, effective_action,
7068 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7069 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7070 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7071 struct GraphicInfo *g = &graphic_info[graphic];
7073 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
7077 /* special case: graphic uses "2nd movement tile" and has defined
7078 7 frames for movement animation (or less) => use default graphic
7079 for last (8th) frame which ends the movement animation */
7080 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
7082 effective_action = ACTION_DEFAULT;
7083 graphic = (direction == MV_NONE ?
7084 el_act2img(effective_element, effective_action) :
7085 el_act_dir2img(effective_element, effective_action,
7087 crumbled = (direction == MV_NONE ?
7088 el_act2crm(effective_element, effective_action) :
7089 el_act_dir2crm(effective_element, effective_action,
7092 g = &graphic_info[graphic];
7102 if (frame_em == 0) /* reset animation frame for certain elements */
7104 if (check_linear_animation_EM(tile))
7109 if (graphic_info[graphic].anim_global_sync)
7110 sync_frame = FrameCounter;
7111 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
7112 sync_frame = GfxFrame[x][y];
7114 sync_frame = 0; /* playfield border (pseudo steel) */
7116 SetRandomAnimationValue(x, y);
7121 int xxx_sync_frame = (i == Xdrip_stretch ? 7 :
7122 i == Xdrip_stretchB ? 7 :
7123 i == Ydrip_s2 ? j + 8 :
7124 i == Ydrip_s2B ? j + 8 :
7133 i == Xfake_acid_1 ? 0 :
7134 i == Xfake_acid_2 ? 10 :
7135 i == Xfake_acid_3 ? 20 :
7136 i == Xfake_acid_4 ? 30 :
7137 i == Xfake_acid_5 ? 40 :
7138 i == Xfake_acid_6 ? 50 :
7139 i == Xfake_acid_7 ? 60 :
7140 i == Xfake_acid_8 ? 70 :
7142 i == Xball_2B ? j + 8 :
7143 i == Yball_eat ? j + 1 :
7144 i == Ykey_1_eat ? j + 1 :
7145 i == Ykey_2_eat ? j + 1 :
7146 i == Ykey_3_eat ? j + 1 :
7147 i == Ykey_4_eat ? j + 1 :
7148 i == Ykey_5_eat ? j + 1 :
7149 i == Ykey_6_eat ? j + 1 :
7150 i == Ykey_7_eat ? j + 1 :
7151 i == Ykey_8_eat ? j + 1 :
7152 i == Ylenses_eat ? j + 1 :
7153 i == Ymagnify_eat ? j + 1 :
7154 i == Ygrass_eat ? j + 1 :
7155 i == Ydirt_eat ? j + 1 :
7156 i == Xamoeba_1 ? 0 :
7157 i == Xamoeba_2 ? 1 :
7158 i == Xamoeba_3 ? 2 :
7159 i == Xamoeba_4 ? 3 :
7160 i == Xamoeba_5 ? 0 :
7161 i == Xamoeba_6 ? 1 :
7162 i == Xamoeba_7 ? 2 :
7163 i == Xamoeba_8 ? 3 :
7164 i == Xexit_2 ? j + 8 :
7165 i == Xexit_3 ? j + 16 :
7166 i == Xdynamite_1 ? 0 :
7167 i == Xdynamite_2 ? 8 :
7168 i == Xdynamite_3 ? 16 :
7169 i == Xdynamite_4 ? 24 :
7170 i == Xsand_stonein_1 ? j + 1 :
7171 i == Xsand_stonein_2 ? j + 9 :
7172 i == Xsand_stonein_3 ? j + 17 :
7173 i == Xsand_stonein_4 ? j + 25 :
7174 i == Xsand_stoneout_1 && j == 0 ? 0 :
7175 i == Xsand_stoneout_1 && j == 1 ? 0 :
7176 i == Xsand_stoneout_1 && j == 2 ? 1 :
7177 i == Xsand_stoneout_1 && j == 3 ? 2 :
7178 i == Xsand_stoneout_1 && j == 4 ? 2 :
7179 i == Xsand_stoneout_1 && j == 5 ? 3 :
7180 i == Xsand_stoneout_1 && j == 6 ? 4 :
7181 i == Xsand_stoneout_1 && j == 7 ? 4 :
7182 i == Xsand_stoneout_2 && j == 0 ? 5 :
7183 i == Xsand_stoneout_2 && j == 1 ? 6 :
7184 i == Xsand_stoneout_2 && j == 2 ? 7 :
7185 i == Xsand_stoneout_2 && j == 3 ? 8 :
7186 i == Xsand_stoneout_2 && j == 4 ? 9 :
7187 i == Xsand_stoneout_2 && j == 5 ? 11 :
7188 i == Xsand_stoneout_2 && j == 6 ? 13 :
7189 i == Xsand_stoneout_2 && j == 7 ? 15 :
7190 i == Xboom_bug && j == 1 ? 2 :
7191 i == Xboom_bug && j == 2 ? 2 :
7192 i == Xboom_bug && j == 3 ? 4 :
7193 i == Xboom_bug && j == 4 ? 4 :
7194 i == Xboom_bug && j == 5 ? 2 :
7195 i == Xboom_bug && j == 6 ? 2 :
7196 i == Xboom_bug && j == 7 ? 0 :
7197 i == Xboom_bomb && j == 1 ? 2 :
7198 i == Xboom_bomb && j == 2 ? 2 :
7199 i == Xboom_bomb && j == 3 ? 4 :
7200 i == Xboom_bomb && j == 4 ? 4 :
7201 i == Xboom_bomb && j == 5 ? 2 :
7202 i == Xboom_bomb && j == 6 ? 2 :
7203 i == Xboom_bomb && j == 7 ? 0 :
7204 i == Xboom_android && j == 7 ? 6 :
7205 i == Xboom_1 && j == 1 ? 2 :
7206 i == Xboom_1 && j == 2 ? 2 :
7207 i == Xboom_1 && j == 3 ? 4 :
7208 i == Xboom_1 && j == 4 ? 4 :
7209 i == Xboom_1 && j == 5 ? 6 :
7210 i == Xboom_1 && j == 6 ? 6 :
7211 i == Xboom_1 && j == 7 ? 8 :
7212 i == Xboom_2 && j == 0 ? 8 :
7213 i == Xboom_2 && j == 1 ? 8 :
7214 i == Xboom_2 && j == 2 ? 10 :
7215 i == Xboom_2 && j == 3 ? 10 :
7216 i == Xboom_2 && j == 4 ? 10 :
7217 i == Xboom_2 && j == 5 ? 12 :
7218 i == Xboom_2 && j == 6 ? 12 :
7219 i == Xboom_2 && j == 7 ? 12 :
7221 special_animation && j == 4 ? 3 :
7222 effective_action != action ? 0 :
7228 int xxx_effective_action;
7229 int xxx_has_action_graphics;
7232 int element = object_mapping[i].element_rnd;
7233 int action = object_mapping[i].action;
7234 int direction = object_mapping[i].direction;
7235 boolean is_backside = object_mapping[i].is_backside;
7237 boolean action_removing = (action == ACTION_DIGGING ||
7238 action == ACTION_SNAPPING ||
7239 action == ACTION_COLLECTING);
7241 boolean action_exploding = ((action == ACTION_EXPLODING ||
7242 action == ACTION_SMASHED_BY_ROCK ||
7243 action == ACTION_SMASHED_BY_SPRING) &&
7244 element != EL_DIAMOND);
7245 boolean action_active = (action == ACTION_ACTIVE);
7246 boolean action_other = (action == ACTION_OTHER);
7250 int effective_element = get_effective_element_EM(i, j);
7252 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
7253 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
7255 i == Xdrip_stretch ? element :
7256 i == Xdrip_stretchB ? element :
7257 i == Ydrip_s1 ? element :
7258 i == Ydrip_s1B ? element :
7259 i == Xball_1B ? element :
7260 i == Xball_2 ? element :
7261 i == Xball_2B ? element :
7262 i == Yball_eat ? element :
7263 i == Ykey_1_eat ? element :
7264 i == Ykey_2_eat ? element :
7265 i == Ykey_3_eat ? element :
7266 i == Ykey_4_eat ? element :
7267 i == Ykey_5_eat ? element :
7268 i == Ykey_6_eat ? element :
7269 i == Ykey_7_eat ? element :
7270 i == Ykey_8_eat ? element :
7271 i == Ylenses_eat ? element :
7272 i == Ymagnify_eat ? element :
7273 i == Ygrass_eat ? element :
7274 i == Ydirt_eat ? element :
7275 i == Yemerald_stone ? EL_EMERALD :
7276 i == Ydiamond_stone ? EL_ROCK :
7277 i == Xsand_stonein_1 ? element :
7278 i == Xsand_stonein_2 ? element :
7279 i == Xsand_stonein_3 ? element :
7280 i == Xsand_stonein_4 ? element :
7281 is_backside ? EL_EMPTY :
7282 action_removing ? EL_EMPTY :
7285 int effective_action = (j < 7 ? action :
7286 i == Xdrip_stretch ? action :
7287 i == Xdrip_stretchB ? action :
7288 i == Ydrip_s1 ? action :
7289 i == Ydrip_s1B ? action :
7290 i == Xball_1B ? action :
7291 i == Xball_2 ? action :
7292 i == Xball_2B ? action :
7293 i == Yball_eat ? action :
7294 i == Ykey_1_eat ? action :
7295 i == Ykey_2_eat ? action :
7296 i == Ykey_3_eat ? action :
7297 i == Ykey_4_eat ? action :
7298 i == Ykey_5_eat ? action :
7299 i == Ykey_6_eat ? action :
7300 i == Ykey_7_eat ? action :
7301 i == Ykey_8_eat ? action :
7302 i == Ylenses_eat ? action :
7303 i == Ymagnify_eat ? action :
7304 i == Ygrass_eat ? action :
7305 i == Ydirt_eat ? action :
7306 i == Xsand_stonein_1 ? action :
7307 i == Xsand_stonein_2 ? action :
7308 i == Xsand_stonein_3 ? action :
7309 i == Xsand_stonein_4 ? action :
7310 i == Xsand_stoneout_1 ? action :
7311 i == Xsand_stoneout_2 ? action :
7312 i == Xboom_android ? ACTION_EXPLODING :
7313 action_exploding ? ACTION_EXPLODING :
7314 action_active ? action :
7315 action_other ? action :
7317 int graphic = (el_act_dir2img(effective_element, effective_action,
7319 int crumbled = (el_act_dir2crm(effective_element, effective_action,
7321 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7322 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7323 boolean has_action_graphics = (graphic != base_graphic);
7324 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7325 struct GraphicInfo *g = &graphic_info[graphic];
7327 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
7329 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7332 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
7333 boolean special_animation = (action != ACTION_DEFAULT &&
7334 g->anim_frames == 3 &&
7335 g->anim_delay == 2 &&
7336 g->anim_mode & ANIM_LINEAR);
7337 xxx_sync_frame = (i == Xdrip_stretch ? 7 :
7338 i == Xdrip_stretchB ? 7 :
7339 i == Ydrip_s2 ? j + 8 :
7340 i == Ydrip_s2B ? j + 8 :
7349 i == Xfake_acid_1 ? 0 :
7350 i == Xfake_acid_2 ? 10 :
7351 i == Xfake_acid_3 ? 20 :
7352 i == Xfake_acid_4 ? 30 :
7353 i == Xfake_acid_5 ? 40 :
7354 i == Xfake_acid_6 ? 50 :
7355 i == Xfake_acid_7 ? 60 :
7356 i == Xfake_acid_8 ? 70 :
7358 i == Xball_2B ? j + 8 :
7359 i == Yball_eat ? j + 1 :
7360 i == Ykey_1_eat ? j + 1 :
7361 i == Ykey_2_eat ? j + 1 :
7362 i == Ykey_3_eat ? j + 1 :
7363 i == Ykey_4_eat ? j + 1 :
7364 i == Ykey_5_eat ? j + 1 :
7365 i == Ykey_6_eat ? j + 1 :
7366 i == Ykey_7_eat ? j + 1 :
7367 i == Ykey_8_eat ? j + 1 :
7368 i == Ylenses_eat ? j + 1 :
7369 i == Ymagnify_eat ? j + 1 :
7370 i == Ygrass_eat ? j + 1 :
7371 i == Ydirt_eat ? j + 1 :
7372 i == Xamoeba_1 ? 0 :
7373 i == Xamoeba_2 ? 1 :
7374 i == Xamoeba_3 ? 2 :
7375 i == Xamoeba_4 ? 3 :
7376 i == Xamoeba_5 ? 0 :
7377 i == Xamoeba_6 ? 1 :
7378 i == Xamoeba_7 ? 2 :
7379 i == Xamoeba_8 ? 3 :
7380 i == Xexit_2 ? j + 8 :
7381 i == Xexit_3 ? j + 16 :
7382 i == Xdynamite_1 ? 0 :
7383 i == Xdynamite_2 ? 8 :
7384 i == Xdynamite_3 ? 16 :
7385 i == Xdynamite_4 ? 24 :
7386 i == Xsand_stonein_1 ? j + 1 :
7387 i == Xsand_stonein_2 ? j + 9 :
7388 i == Xsand_stonein_3 ? j + 17 :
7389 i == Xsand_stonein_4 ? j + 25 :
7390 i == Xsand_stoneout_1 && j == 0 ? 0 :
7391 i == Xsand_stoneout_1 && j == 1 ? 0 :
7392 i == Xsand_stoneout_1 && j == 2 ? 1 :
7393 i == Xsand_stoneout_1 && j == 3 ? 2 :
7394 i == Xsand_stoneout_1 && j == 4 ? 2 :
7395 i == Xsand_stoneout_1 && j == 5 ? 3 :
7396 i == Xsand_stoneout_1 && j == 6 ? 4 :
7397 i == Xsand_stoneout_1 && j == 7 ? 4 :
7398 i == Xsand_stoneout_2 && j == 0 ? 5 :
7399 i == Xsand_stoneout_2 && j == 1 ? 6 :
7400 i == Xsand_stoneout_2 && j == 2 ? 7 :
7401 i == Xsand_stoneout_2 && j == 3 ? 8 :
7402 i == Xsand_stoneout_2 && j == 4 ? 9 :
7403 i == Xsand_stoneout_2 && j == 5 ? 11 :
7404 i == Xsand_stoneout_2 && j == 6 ? 13 :
7405 i == Xsand_stoneout_2 && j == 7 ? 15 :
7406 i == Xboom_bug && j == 1 ? 2 :
7407 i == Xboom_bug && j == 2 ? 2 :
7408 i == Xboom_bug && j == 3 ? 4 :
7409 i == Xboom_bug && j == 4 ? 4 :
7410 i == Xboom_bug && j == 5 ? 2 :
7411 i == Xboom_bug && j == 6 ? 2 :
7412 i == Xboom_bug && j == 7 ? 0 :
7413 i == Xboom_bomb && j == 1 ? 2 :
7414 i == Xboom_bomb && j == 2 ? 2 :
7415 i == Xboom_bomb && j == 3 ? 4 :
7416 i == Xboom_bomb && j == 4 ? 4 :
7417 i == Xboom_bomb && j == 5 ? 2 :
7418 i == Xboom_bomb && j == 6 ? 2 :
7419 i == Xboom_bomb && j == 7 ? 0 :
7420 i == Xboom_android && j == 7 ? 6 :
7421 i == Xboom_1 && j == 1 ? 2 :
7422 i == Xboom_1 && j == 2 ? 2 :
7423 i == Xboom_1 && j == 3 ? 4 :
7424 i == Xboom_1 && j == 4 ? 4 :
7425 i == Xboom_1 && j == 5 ? 6 :
7426 i == Xboom_1 && j == 6 ? 6 :
7427 i == Xboom_1 && j == 7 ? 8 :
7428 i == Xboom_2 && j == 0 ? 8 :
7429 i == Xboom_2 && j == 1 ? 8 :
7430 i == Xboom_2 && j == 2 ? 10 :
7431 i == Xboom_2 && j == 3 ? 10 :
7432 i == Xboom_2 && j == 4 ? 10 :
7433 i == Xboom_2 && j == 5 ? 12 :
7434 i == Xboom_2 && j == 6 ? 12 :
7435 i == Xboom_2 && j == 7 ? 12 :
7436 special_animation && j == 4 ? 3 :
7437 effective_action != action ? 0 :
7440 xxx_effective_action = effective_action;
7441 xxx_has_action_graphics = has_action_graphics;
7446 int frame = getAnimationFrame(g->anim_frames,
7449 g->anim_start_frame,
7463 int old_src_x = g_em->src_x;
7464 int old_src_y = g_em->src_y;
7468 getGraphicSourceExt(graphic, frame, &g_em->bitmap, &g_em->src_x, &g_em->src_y,
7469 g->double_movement && is_backside);
7471 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
7472 &g_em->src_x, &g_em->src_y, FALSE);
7477 if (tile == Ydiamond_stone)
7478 printf("::: stone smashing diamond... %d: %d, %d, %d, %d, %d -> %d [%d, %d, %d, %d, %d, %d] [%d]\n",
7483 g->anim_start_frame,
7486 g_em->src_x, g_em->src_y,
7487 g_em->src_offset_x, g_em->src_offset_y,
7488 g_em->dst_offset_x, g_em->dst_offset_y,
7500 if (graphic == IMG_BUG_MOVING_RIGHT)
7501 printf("::: %d, %d, %d: %d, %d [%d, %d -> %d, %d]\n", graphic, x, y,
7502 g->double_movement, is_backside,
7503 old_src_x, old_src_y, g_em->src_x, g_em->src_y);
7511 g_em->src_offset_x = 0;
7512 g_em->src_offset_y = 0;
7513 g_em->dst_offset_x = 0;
7514 g_em->dst_offset_y = 0;
7515 g_em->width = TILEX;
7516 g_em->height = TILEY;
7518 g_em->preserve_background = FALSE;
7521 /* (updating the "crumbled" graphic definitions is probably not really needed,
7522 as animations for crumbled graphics can't be longer than one EMC cycle) */
7524 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
7529 g_em->crumbled_bitmap = NULL;
7530 g_em->crumbled_src_x = 0;
7531 g_em->crumbled_src_y = 0;
7533 g_em->has_crumbled_graphics = FALSE;
7535 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
7537 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
7538 g_crumbled->anim_delay,
7539 g_crumbled->anim_mode,
7540 g_crumbled->anim_start_frame,
7543 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
7544 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
7546 g_em->has_crumbled_graphics = TRUE;
7552 int effective_action = xxx_effective_action;
7553 int has_action_graphics = xxx_has_action_graphics;
7555 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
7556 effective_action == ACTION_MOVING ||
7557 effective_action == ACTION_PUSHING ||
7558 effective_action == ACTION_EATING)) ||
7559 (!has_action_graphics && (effective_action == ACTION_FILLING ||
7560 effective_action == ACTION_EMPTYING)))
7563 (effective_action == ACTION_FALLING ||
7564 effective_action == ACTION_FILLING ||
7565 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
7566 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
7567 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
7568 int num_steps = (i == Ydrip_s1 ? 16 :
7569 i == Ydrip_s1B ? 16 :
7570 i == Ydrip_s2 ? 16 :
7571 i == Ydrip_s2B ? 16 :
7572 i == Xsand_stonein_1 ? 32 :
7573 i == Xsand_stonein_2 ? 32 :
7574 i == Xsand_stonein_3 ? 32 :
7575 i == Xsand_stonein_4 ? 32 :
7576 i == Xsand_stoneout_1 ? 16 :
7577 i == Xsand_stoneout_2 ? 16 : 8);
7578 int cx = ABS(dx) * (TILEX / num_steps);
7579 int cy = ABS(dy) * (TILEY / num_steps);
7580 int step_frame = (i == Ydrip_s2 ? j + 8 :
7581 i == Ydrip_s2B ? j + 8 :
7582 i == Xsand_stonein_2 ? j + 8 :
7583 i == Xsand_stonein_3 ? j + 16 :
7584 i == Xsand_stonein_4 ? j + 24 :
7585 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
7586 int step = (is_backside ? step_frame : num_steps - step_frame);
7588 if (is_backside) /* tile where movement starts */
7590 if (dx < 0 || dy < 0)
7592 g_em->src_offset_x = cx * step;
7593 g_em->src_offset_y = cy * step;
7597 g_em->dst_offset_x = cx * step;
7598 g_em->dst_offset_y = cy * step;
7601 else /* tile where movement ends */
7603 if (dx < 0 || dy < 0)
7605 g_em->dst_offset_x = cx * step;
7606 g_em->dst_offset_y = cy * step;
7610 g_em->src_offset_x = cx * step;
7611 g_em->src_offset_y = cy * step;
7615 g_em->width = TILEX - cx * step;
7616 g_em->height = TILEY - cy * step;
7619 /* create unique graphic identifier to decide if tile must be redrawn */
7620 /* bit 31 - 16 (16 bit): EM style graphic
7621 bit 15 - 12 ( 4 bit): EM style frame
7622 bit 11 - 6 ( 6 bit): graphic width
7623 bit 5 - 0 ( 6 bit): graphic height */
7624 g_em->unique_identifier =
7625 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
7631 void getGraphicSourcePlayerExt_EM(struct GraphicInfo_EM *g_em,
7632 int player_nr, int anim, int frame_em)
7634 int element = player_mapping[player_nr][anim].element_rnd;
7635 int action = player_mapping[player_nr][anim].action;
7636 int direction = player_mapping[player_nr][anim].direction;
7637 int graphic = (direction == MV_NONE ?
7638 el_act2img(element, action) :
7639 el_act_dir2img(element, action, direction));
7640 struct GraphicInfo *g = &graphic_info[graphic];
7643 InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
7645 stored_player[player_nr].StepFrame = frame_em;
7647 sync_frame = stored_player[player_nr].Frame;
7649 int frame = getAnimationFrame(g->anim_frames,
7652 g->anim_start_frame,
7655 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
7656 &g_em->src_x, &g_em->src_y, FALSE);
7659 printf("::: %d: %d, %d [%d]\n",
7661 stored_player[player_nr].Frame,
7662 stored_player[player_nr].StepFrame,
7667 void InitGraphicInfo_EM(void)
7670 struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
7671 struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
7676 int num_em_gfx_errors = 0;
7678 if (graphic_info_em_object[0][0].bitmap == NULL)
7680 /* EM graphics not yet initialized in em_open_all() */
7685 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
7688 /* always start with reliable default values */
7689 for (i = 0; i < TILE_MAX; i++)
7691 object_mapping[i].element_rnd = EL_UNKNOWN;
7692 object_mapping[i].is_backside = FALSE;
7693 object_mapping[i].action = ACTION_DEFAULT;
7694 object_mapping[i].direction = MV_NONE;
7697 /* always start with reliable default values */
7698 for (p = 0; p < MAX_PLAYERS; p++)
7700 for (i = 0; i < SPR_MAX; i++)
7702 player_mapping[p][i].element_rnd = EL_UNKNOWN;
7703 player_mapping[p][i].action = ACTION_DEFAULT;
7704 player_mapping[p][i].direction = MV_NONE;
7708 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
7710 int e = em_object_mapping_list[i].element_em;
7712 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
7713 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
7715 if (em_object_mapping_list[i].action != -1)
7716 object_mapping[e].action = em_object_mapping_list[i].action;
7718 if (em_object_mapping_list[i].direction != -1)
7719 object_mapping[e].direction =
7720 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
7723 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
7725 int a = em_player_mapping_list[i].action_em;
7726 int p = em_player_mapping_list[i].player_nr;
7728 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
7730 if (em_player_mapping_list[i].action != -1)
7731 player_mapping[p][a].action = em_player_mapping_list[i].action;
7733 if (em_player_mapping_list[i].direction != -1)
7734 player_mapping[p][a].direction =
7735 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
7738 for (i = 0; i < TILE_MAX; i++)
7740 int element = object_mapping[i].element_rnd;
7741 int action = object_mapping[i].action;
7742 int direction = object_mapping[i].direction;
7743 boolean is_backside = object_mapping[i].is_backside;
7745 boolean action_removing = (action == ACTION_DIGGING ||
7746 action == ACTION_SNAPPING ||
7747 action == ACTION_COLLECTING);
7749 boolean action_exploding = ((action == ACTION_EXPLODING ||
7750 action == ACTION_SMASHED_BY_ROCK ||
7751 action == ACTION_SMASHED_BY_SPRING) &&
7752 element != EL_DIAMOND);
7753 boolean action_active = (action == ACTION_ACTIVE);
7754 boolean action_other = (action == ACTION_OTHER);
7756 for (j = 0; j < 8; j++)
7759 int effective_element = get_effective_element_EM(i, j);
7761 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
7762 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
7764 i == Xdrip_stretch ? element :
7765 i == Xdrip_stretchB ? element :
7766 i == Ydrip_s1 ? element :
7767 i == Ydrip_s1B ? element :
7768 i == Xball_1B ? element :
7769 i == Xball_2 ? element :
7770 i == Xball_2B ? element :
7771 i == Yball_eat ? element :
7772 i == Ykey_1_eat ? element :
7773 i == Ykey_2_eat ? element :
7774 i == Ykey_3_eat ? element :
7775 i == Ykey_4_eat ? element :
7776 i == Ykey_5_eat ? element :
7777 i == Ykey_6_eat ? element :
7778 i == Ykey_7_eat ? element :
7779 i == Ykey_8_eat ? element :
7780 i == Ylenses_eat ? element :
7781 i == Ymagnify_eat ? element :
7782 i == Ygrass_eat ? element :
7783 i == Ydirt_eat ? element :
7784 i == Yemerald_stone ? EL_EMERALD :
7785 i == Ydiamond_stone ? EL_ROCK :
7786 i == Xsand_stonein_1 ? element :
7787 i == Xsand_stonein_2 ? element :
7788 i == Xsand_stonein_3 ? element :
7789 i == Xsand_stonein_4 ? element :
7790 is_backside ? EL_EMPTY :
7791 action_removing ? EL_EMPTY :
7794 int effective_action = (j < 7 ? action :
7795 i == Xdrip_stretch ? action :
7796 i == Xdrip_stretchB ? action :
7797 i == Ydrip_s1 ? action :
7798 i == Ydrip_s1B ? action :
7799 i == Xball_1B ? action :
7800 i == Xball_2 ? action :
7801 i == Xball_2B ? action :
7802 i == Yball_eat ? action :
7803 i == Ykey_1_eat ? action :
7804 i == Ykey_2_eat ? action :
7805 i == Ykey_3_eat ? action :
7806 i == Ykey_4_eat ? action :
7807 i == Ykey_5_eat ? action :
7808 i == Ykey_6_eat ? action :
7809 i == Ykey_7_eat ? action :
7810 i == Ykey_8_eat ? action :
7811 i == Ylenses_eat ? action :
7812 i == Ymagnify_eat ? action :
7813 i == Ygrass_eat ? action :
7814 i == Ydirt_eat ? action :
7815 i == Xsand_stonein_1 ? action :
7816 i == Xsand_stonein_2 ? action :
7817 i == Xsand_stonein_3 ? action :
7818 i == Xsand_stonein_4 ? action :
7819 i == Xsand_stoneout_1 ? action :
7820 i == Xsand_stoneout_2 ? action :
7821 i == Xboom_android ? ACTION_EXPLODING :
7822 action_exploding ? ACTION_EXPLODING :
7823 action_active ? action :
7824 action_other ? action :
7826 int graphic = (el_act_dir2img(effective_element, effective_action,
7828 int crumbled = (el_act_dir2crm(effective_element, effective_action,
7830 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7831 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7832 boolean has_action_graphics = (graphic != base_graphic);
7833 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7834 struct GraphicInfo *g = &graphic_info[graphic];
7836 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
7838 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7841 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
7842 boolean special_animation = (action != ACTION_DEFAULT &&
7843 g->anim_frames == 3 &&
7844 g->anim_delay == 2 &&
7845 g->anim_mode & ANIM_LINEAR);
7846 int sync_frame = (i == Xdrip_stretch ? 7 :
7847 i == Xdrip_stretchB ? 7 :
7848 i == Ydrip_s2 ? j + 8 :
7849 i == Ydrip_s2B ? j + 8 :
7858 i == Xfake_acid_1 ? 0 :
7859 i == Xfake_acid_2 ? 10 :
7860 i == Xfake_acid_3 ? 20 :
7861 i == Xfake_acid_4 ? 30 :
7862 i == Xfake_acid_5 ? 40 :
7863 i == Xfake_acid_6 ? 50 :
7864 i == Xfake_acid_7 ? 60 :
7865 i == Xfake_acid_8 ? 70 :
7867 i == Xball_2B ? j + 8 :
7868 i == Yball_eat ? j + 1 :
7869 i == Ykey_1_eat ? j + 1 :
7870 i == Ykey_2_eat ? j + 1 :
7871 i == Ykey_3_eat ? j + 1 :
7872 i == Ykey_4_eat ? j + 1 :
7873 i == Ykey_5_eat ? j + 1 :
7874 i == Ykey_6_eat ? j + 1 :
7875 i == Ykey_7_eat ? j + 1 :
7876 i == Ykey_8_eat ? j + 1 :
7877 i == Ylenses_eat ? j + 1 :
7878 i == Ymagnify_eat ? j + 1 :
7879 i == Ygrass_eat ? j + 1 :
7880 i == Ydirt_eat ? j + 1 :
7881 i == Xamoeba_1 ? 0 :
7882 i == Xamoeba_2 ? 1 :
7883 i == Xamoeba_3 ? 2 :
7884 i == Xamoeba_4 ? 3 :
7885 i == Xamoeba_5 ? 0 :
7886 i == Xamoeba_6 ? 1 :
7887 i == Xamoeba_7 ? 2 :
7888 i == Xamoeba_8 ? 3 :
7889 i == Xexit_2 ? j + 8 :
7890 i == Xexit_3 ? j + 16 :
7891 i == Xdynamite_1 ? 0 :
7892 i == Xdynamite_2 ? 8 :
7893 i == Xdynamite_3 ? 16 :
7894 i == Xdynamite_4 ? 24 :
7895 i == Xsand_stonein_1 ? j + 1 :
7896 i == Xsand_stonein_2 ? j + 9 :
7897 i == Xsand_stonein_3 ? j + 17 :
7898 i == Xsand_stonein_4 ? j + 25 :
7899 i == Xsand_stoneout_1 && j == 0 ? 0 :
7900 i == Xsand_stoneout_1 && j == 1 ? 0 :
7901 i == Xsand_stoneout_1 && j == 2 ? 1 :
7902 i == Xsand_stoneout_1 && j == 3 ? 2 :
7903 i == Xsand_stoneout_1 && j == 4 ? 2 :
7904 i == Xsand_stoneout_1 && j == 5 ? 3 :
7905 i == Xsand_stoneout_1 && j == 6 ? 4 :
7906 i == Xsand_stoneout_1 && j == 7 ? 4 :
7907 i == Xsand_stoneout_2 && j == 0 ? 5 :
7908 i == Xsand_stoneout_2 && j == 1 ? 6 :
7909 i == Xsand_stoneout_2 && j == 2 ? 7 :
7910 i == Xsand_stoneout_2 && j == 3 ? 8 :
7911 i == Xsand_stoneout_2 && j == 4 ? 9 :
7912 i == Xsand_stoneout_2 && j == 5 ? 11 :
7913 i == Xsand_stoneout_2 && j == 6 ? 13 :
7914 i == Xsand_stoneout_2 && j == 7 ? 15 :
7915 i == Xboom_bug && j == 1 ? 2 :
7916 i == Xboom_bug && j == 2 ? 2 :
7917 i == Xboom_bug && j == 3 ? 4 :
7918 i == Xboom_bug && j == 4 ? 4 :
7919 i == Xboom_bug && j == 5 ? 2 :
7920 i == Xboom_bug && j == 6 ? 2 :
7921 i == Xboom_bug && j == 7 ? 0 :
7922 i == Xboom_bomb && j == 1 ? 2 :
7923 i == Xboom_bomb && j == 2 ? 2 :
7924 i == Xboom_bomb && j == 3 ? 4 :
7925 i == Xboom_bomb && j == 4 ? 4 :
7926 i == Xboom_bomb && j == 5 ? 2 :
7927 i == Xboom_bomb && j == 6 ? 2 :
7928 i == Xboom_bomb && j == 7 ? 0 :
7929 i == Xboom_android && j == 7 ? 6 :
7930 i == Xboom_1 && j == 1 ? 2 :
7931 i == Xboom_1 && j == 2 ? 2 :
7932 i == Xboom_1 && j == 3 ? 4 :
7933 i == Xboom_1 && j == 4 ? 4 :
7934 i == Xboom_1 && j == 5 ? 6 :
7935 i == Xboom_1 && j == 6 ? 6 :
7936 i == Xboom_1 && j == 7 ? 8 :
7937 i == Xboom_2 && j == 0 ? 8 :
7938 i == Xboom_2 && j == 1 ? 8 :
7939 i == Xboom_2 && j == 2 ? 10 :
7940 i == Xboom_2 && j == 3 ? 10 :
7941 i == Xboom_2 && j == 4 ? 10 :
7942 i == Xboom_2 && j == 5 ? 12 :
7943 i == Xboom_2 && j == 6 ? 12 :
7944 i == Xboom_2 && j == 7 ? 12 :
7945 special_animation && j == 4 ? 3 :
7946 effective_action != action ? 0 :
7950 Bitmap *debug_bitmap = g_em->bitmap;
7951 int debug_src_x = g_em->src_x;
7952 int debug_src_y = g_em->src_y;
7955 int frame = getAnimationFrame(g->anim_frames,
7958 g->anim_start_frame,
7961 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
7962 g->double_movement && is_backside);
7964 g_em->bitmap = src_bitmap;
7965 g_em->src_x = src_x;
7966 g_em->src_y = src_y;
7967 g_em->src_offset_x = 0;
7968 g_em->src_offset_y = 0;
7969 g_em->dst_offset_x = 0;
7970 g_em->dst_offset_y = 0;
7971 g_em->width = TILEX;
7972 g_em->height = TILEY;
7974 g_em->preserve_background = FALSE;
7977 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
7982 g_em->crumbled_bitmap = NULL;
7983 g_em->crumbled_src_x = 0;
7984 g_em->crumbled_src_y = 0;
7985 g_em->crumbled_border_size = 0;
7987 g_em->has_crumbled_graphics = FALSE;
7990 if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
7991 printf("::: empty crumbled: %d [%s], %d, %d\n",
7992 effective_element, element_info[effective_element].token_name,
7993 effective_action, direction);
7996 /* if element can be crumbled, but certain action graphics are just empty
7997 space (like instantly snapping sand to empty space in 1 frame), do not
7998 treat these empty space graphics as crumbled graphics in EMC engine */
7999 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
8001 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
8002 g_crumbled->anim_delay,
8003 g_crumbled->anim_mode,
8004 g_crumbled->anim_start_frame,
8007 getGraphicSource(crumbled, frame_crumbled, &src_bitmap, &src_x, &src_y);
8009 g_em->has_crumbled_graphics = TRUE;
8010 g_em->crumbled_bitmap = src_bitmap;
8011 g_em->crumbled_src_x = src_x;
8012 g_em->crumbled_src_y = src_y;
8013 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
8017 if (g_em == &graphic_info_em_object[207][0])
8018 printf("... %d, %d [%d, %d, %d, %d] [%d, %d, %d, %d, %d, %d => %d]\n",
8019 graphic_info_em_object[207][0].crumbled_src_x,
8020 graphic_info_em_object[207][0].crumbled_src_y,
8022 crumbled, frame, src_x, src_y,
8027 g->anim_start_frame,
8029 gfx.anim_random_frame,
8034 printf("::: EMC tile %d is crumbled\n", i);
8040 if (element == EL_ROCK &&
8041 effective_action == ACTION_FILLING)
8042 printf("::: has_action_graphics == %d\n", has_action_graphics);
8045 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
8046 effective_action == ACTION_MOVING ||
8047 effective_action == ACTION_PUSHING ||
8048 effective_action == ACTION_EATING)) ||
8049 (!has_action_graphics && (effective_action == ACTION_FILLING ||
8050 effective_action == ACTION_EMPTYING)))
8053 (effective_action == ACTION_FALLING ||
8054 effective_action == ACTION_FILLING ||
8055 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
8056 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
8057 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
8058 int num_steps = (i == Ydrip_s1 ? 16 :
8059 i == Ydrip_s1B ? 16 :
8060 i == Ydrip_s2 ? 16 :
8061 i == Ydrip_s2B ? 16 :
8062 i == Xsand_stonein_1 ? 32 :
8063 i == Xsand_stonein_2 ? 32 :
8064 i == Xsand_stonein_3 ? 32 :
8065 i == Xsand_stonein_4 ? 32 :
8066 i == Xsand_stoneout_1 ? 16 :
8067 i == Xsand_stoneout_2 ? 16 : 8);
8068 int cx = ABS(dx) * (TILEX / num_steps);
8069 int cy = ABS(dy) * (TILEY / num_steps);
8070 int step_frame = (i == Ydrip_s2 ? j + 8 :
8071 i == Ydrip_s2B ? j + 8 :
8072 i == Xsand_stonein_2 ? j + 8 :
8073 i == Xsand_stonein_3 ? j + 16 :
8074 i == Xsand_stonein_4 ? j + 24 :
8075 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
8076 int step = (is_backside ? step_frame : num_steps - step_frame);
8078 if (is_backside) /* tile where movement starts */
8080 if (dx < 0 || dy < 0)
8082 g_em->src_offset_x = cx * step;
8083 g_em->src_offset_y = cy * step;
8087 g_em->dst_offset_x = cx * step;
8088 g_em->dst_offset_y = cy * step;
8091 else /* tile where movement ends */
8093 if (dx < 0 || dy < 0)
8095 g_em->dst_offset_x = cx * step;
8096 g_em->dst_offset_y = cy * step;
8100 g_em->src_offset_x = cx * step;
8101 g_em->src_offset_y = cy * step;
8105 g_em->width = TILEX - cx * step;
8106 g_em->height = TILEY - cy * step;
8109 /* create unique graphic identifier to decide if tile must be redrawn */
8110 /* bit 31 - 16 (16 bit): EM style graphic
8111 bit 15 - 12 ( 4 bit): EM style frame
8112 bit 11 - 6 ( 6 bit): graphic width
8113 bit 5 - 0 ( 6 bit): graphic height */
8114 g_em->unique_identifier =
8115 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
8119 /* skip check for EMC elements not contained in original EMC artwork */
8120 if (element == EL_EMC_FAKE_ACID)
8123 if (g_em->bitmap != debug_bitmap ||
8124 g_em->src_x != debug_src_x ||
8125 g_em->src_y != debug_src_y ||
8126 g_em->src_offset_x != 0 ||
8127 g_em->src_offset_y != 0 ||
8128 g_em->dst_offset_x != 0 ||
8129 g_em->dst_offset_y != 0 ||
8130 g_em->width != TILEX ||
8131 g_em->height != TILEY)
8133 static int last_i = -1;
8141 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
8142 i, element, element_info[element].token_name,
8143 element_action_info[effective_action].suffix, direction);
8145 if (element != effective_element)
8146 printf(" [%d ('%s')]",
8148 element_info[effective_element].token_name);
8152 if (g_em->bitmap != debug_bitmap)
8153 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
8154 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
8156 if (g_em->src_x != debug_src_x ||
8157 g_em->src_y != debug_src_y)
8158 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
8159 j, (is_backside ? 'B' : 'F'),
8160 g_em->src_x, g_em->src_y,
8161 g_em->src_x / 32, g_em->src_y / 32,
8162 debug_src_x, debug_src_y,
8163 debug_src_x / 32, debug_src_y / 32);
8165 if (g_em->src_offset_x != 0 ||
8166 g_em->src_offset_y != 0 ||
8167 g_em->dst_offset_x != 0 ||
8168 g_em->dst_offset_y != 0)
8169 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
8171 g_em->src_offset_x, g_em->src_offset_y,
8172 g_em->dst_offset_x, g_em->dst_offset_y);
8174 if (g_em->width != TILEX ||
8175 g_em->height != TILEY)
8176 printf(" %d (%d): size %d,%d should be %d,%d\n",
8178 g_em->width, g_em->height, TILEX, TILEY);
8180 num_em_gfx_errors++;
8187 for (i = 0; i < TILE_MAX; i++)
8189 for (j = 0; j < 8; j++)
8191 int element = object_mapping[i].element_rnd;
8192 int action = object_mapping[i].action;
8193 int direction = object_mapping[i].direction;
8194 boolean is_backside = object_mapping[i].is_backside;
8195 int graphic_action = el_act_dir2img(element, action, direction);
8196 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
8198 if ((action == ACTION_SMASHED_BY_ROCK ||
8199 action == ACTION_SMASHED_BY_SPRING ||
8200 action == ACTION_EATING) &&
8201 graphic_action == graphic_default)
8203 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
8204 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
8205 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
8206 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
8209 /* no separate animation for "smashed by rock" -- use rock instead */
8210 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
8211 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
8213 g_em->bitmap = g_xx->bitmap;
8214 g_em->src_x = g_xx->src_x;
8215 g_em->src_y = g_xx->src_y;
8216 g_em->src_offset_x = g_xx->src_offset_x;
8217 g_em->src_offset_y = g_xx->src_offset_y;
8218 g_em->dst_offset_x = g_xx->dst_offset_x;
8219 g_em->dst_offset_y = g_xx->dst_offset_y;
8220 g_em->width = g_xx->width;
8221 g_em->height = g_xx->height;
8222 g_em->unique_identifier = g_xx->unique_identifier;
8225 g_em->preserve_background = TRUE;
8230 for (p = 0; p < MAX_PLAYERS; p++)
8232 for (i = 0; i < SPR_MAX; i++)
8234 int element = player_mapping[p][i].element_rnd;
8235 int action = player_mapping[p][i].action;
8236 int direction = player_mapping[p][i].direction;
8238 for (j = 0; j < 8; j++)
8240 int effective_element = element;
8241 int effective_action = action;
8242 int graphic = (direction == MV_NONE ?
8243 el_act2img(effective_element, effective_action) :
8244 el_act_dir2img(effective_element, effective_action,
8246 struct GraphicInfo *g = &graphic_info[graphic];
8247 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
8253 Bitmap *debug_bitmap = g_em->bitmap;
8254 int debug_src_x = g_em->src_x;
8255 int debug_src_y = g_em->src_y;
8258 int frame = getAnimationFrame(g->anim_frames,
8261 g->anim_start_frame,
8264 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
8266 g_em->bitmap = src_bitmap;
8267 g_em->src_x = src_x;
8268 g_em->src_y = src_y;
8269 g_em->src_offset_x = 0;
8270 g_em->src_offset_y = 0;
8271 g_em->dst_offset_x = 0;
8272 g_em->dst_offset_y = 0;
8273 g_em->width = TILEX;
8274 g_em->height = TILEY;
8278 /* skip check for EMC elements not contained in original EMC artwork */
8279 if (element == EL_PLAYER_3 ||
8280 element == EL_PLAYER_4)
8283 if (g_em->bitmap != debug_bitmap ||
8284 g_em->src_x != debug_src_x ||
8285 g_em->src_y != debug_src_y)
8287 static int last_i = -1;
8295 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
8296 p, i, element, element_info[element].token_name,
8297 element_action_info[effective_action].suffix, direction);
8299 if (element != effective_element)
8300 printf(" [%d ('%s')]",
8302 element_info[effective_element].token_name);
8306 if (g_em->bitmap != debug_bitmap)
8307 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
8308 j, (int)(g_em->bitmap), (int)(debug_bitmap));
8310 if (g_em->src_x != debug_src_x ||
8311 g_em->src_y != debug_src_y)
8312 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
8314 g_em->src_x, g_em->src_y,
8315 g_em->src_x / 32, g_em->src_y / 32,
8316 debug_src_x, debug_src_y,
8317 debug_src_x / 32, debug_src_y / 32);
8319 num_em_gfx_errors++;
8329 printf("::: [%d errors found]\n", num_em_gfx_errors);
8335 void CheckSingleStepMode_EM(byte action[MAX_PLAYERS], int frame,
8336 boolean any_player_moving,
8337 boolean player_is_dropping)
8341 if (tape.single_step && tape.recording && !tape.pausing)
8343 boolean active_players = FALSE;
8345 for (i = 0; i < MAX_PLAYERS; i++)
8346 if (action[i] != JOY_NO_ACTION)
8347 active_players = TRUE;
8350 if (frame == 0 && !player_is_dropping)
8351 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
8355 void CheckSingleStepMode_SP(boolean murphy_is_waiting,
8356 boolean murphy_is_dropping)
8359 printf("::: waiting: %d, dropping: %d\n",
8360 murphy_is_waiting, murphy_is_dropping);
8363 if (tape.single_step && tape.recording && !tape.pausing)
8365 // if (murphy_is_waiting || murphy_is_dropping)
8366 if (murphy_is_waiting)
8369 printf("::: murphy is waiting -> pause mode\n");
8372 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
8377 void getGraphicSource_SP(struct GraphicInfo_SP *g_sp,
8378 int graphic, int sync_frame, int x, int y)
8380 int frame = getGraphicAnimationFrame(graphic, sync_frame);
8382 getGraphicSource(graphic, frame, &g_sp->bitmap, &g_sp->src_x, &g_sp->src_y);
8385 boolean isNextAnimationFrame_SP(int graphic, int sync_frame)
8387 return (IS_NEXT_FRAME(sync_frame, graphic));
8390 int getGraphicInfo_Delay(int graphic)
8392 return graphic_info[graphic].anim_delay;
8395 void PlayMenuSoundExt(int sound)
8397 if (sound == SND_UNDEFINED)
8400 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8401 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8404 if (IS_LOOP_SOUND(sound))
8405 PlaySoundLoop(sound);
8410 void PlayMenuSound()
8412 PlayMenuSoundExt(menu.sound[game_status]);
8415 void PlayMenuSoundStereo(int sound, int stereo_position)
8417 if (sound == SND_UNDEFINED)
8420 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8421 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8424 if (IS_LOOP_SOUND(sound))
8425 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
8427 PlaySoundStereo(sound, stereo_position);
8430 void PlayMenuSoundIfLoopExt(int sound)
8432 if (sound == SND_UNDEFINED)
8435 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8436 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8439 if (IS_LOOP_SOUND(sound))
8440 PlaySoundLoop(sound);
8443 void PlayMenuSoundIfLoop()
8445 PlayMenuSoundIfLoopExt(menu.sound[game_status]);
8448 void PlayMenuMusicExt(int music)
8450 if (music == MUS_UNDEFINED)
8453 if (!setup.sound_music)
8459 void PlayMenuMusic()
8461 PlayMenuMusicExt(menu.music[game_status]);
8464 void PlaySoundActivating()
8467 PlaySound(SND_MENU_ITEM_ACTIVATING);
8471 void PlaySoundSelecting()
8474 PlaySound(SND_MENU_ITEM_SELECTING);
8478 void ToggleFullscreenIfNeeded()
8480 boolean change_fullscreen = (setup.fullscreen !=
8481 video.fullscreen_enabled);
8482 boolean change_fullscreen_mode = (video.fullscreen_enabled &&
8483 !strEqual(setup.fullscreen_mode,
8484 video.fullscreen_mode_current));
8486 if (!video.fullscreen_available)
8489 if (change_fullscreen || change_fullscreen_mode)
8491 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
8493 /* save backbuffer content which gets lost when toggling fullscreen mode */
8494 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8496 if (change_fullscreen_mode)
8498 /* keep fullscreen, but change fullscreen mode (screen resolution) */
8499 video.fullscreen_enabled = FALSE; /* force new fullscreen mode */
8502 /* toggle fullscreen */
8503 ChangeVideoModeIfNeeded(setup.fullscreen);
8505 setup.fullscreen = video.fullscreen_enabled;
8507 /* restore backbuffer content from temporary backbuffer backup bitmap */
8508 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8510 FreeBitmap(tmp_backbuffer);
8513 /* update visible window/screen */
8514 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8516 redraw_mask = REDRAW_ALL;
8521 void ChangeViewportPropertiesIfNeeded()
8523 int *door_1_x = &DX;
8524 int *door_1_y = &DY;
8525 int *door_2_x = (game_status == GAME_MODE_EDITOR ? &EX : &VX);
8526 int *door_2_y = (game_status == GAME_MODE_EDITOR ? &EY : &VY);
8527 int gfx_game_mode = (game_status == GAME_MODE_PLAYING ||
8528 game_status == GAME_MODE_EDITOR ? game_status :
8530 struct RectWithBorder *vp_playfield = &viewport.playfield[gfx_game_mode];
8531 struct RectWithBorder *vp_door_1 = &viewport.door_1[gfx_game_mode];
8532 struct RectWithBorder *vp_door_2 = &viewport.door_2[gfx_game_mode];
8533 int border_size = vp_playfield->border_size;
8534 int new_sx = vp_playfield->x + border_size;
8535 int new_sy = vp_playfield->y + border_size;
8536 int new_scr_fieldx = (vp_playfield->width - 2 * border_size) / TILESIZE;
8537 int new_scr_fieldy = (vp_playfield->height - 2 * border_size) / TILESIZE;
8540 /* !!! TEST ONLY !!! */
8541 // InitGfxBuffers();
8545 if (viewport.window.width != WIN_XSIZE ||
8546 viewport.window.height != WIN_YSIZE)
8548 WIN_XSIZE = viewport.window.width;
8549 WIN_YSIZE = viewport.window.height;
8551 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
8555 SetDrawDeactivationMask(REDRAW_NONE);
8556 SetDrawBackgroundMask(REDRAW_FIELD);
8558 // RedrawBackground();
8562 if (new_scr_fieldx != SCR_FIELDX ||
8563 new_scr_fieldy != SCR_FIELDY ||
8566 vp_playfield->x != REAL_SX ||
8567 vp_playfield->y != REAL_SY ||
8568 vp_door_1->x != *door_1_x ||
8569 vp_door_1->y != *door_1_y ||
8570 vp_door_2->x != *door_2_x ||
8571 vp_door_2->y != *door_2_y)
8573 SCR_FIELDX = new_scr_fieldx;
8574 SCR_FIELDY = new_scr_fieldy;
8577 REAL_SX = vp_playfield->x;
8578 REAL_SY = vp_playfield->y;
8580 *door_1_x = vp_door_1->x;
8581 *door_1_y = vp_door_1->y;
8582 *door_2_x = vp_door_2->x;
8583 *door_2_y = vp_door_2->y;
8587 if (gfx_game_mode == GAME_MODE_MAIN)
8595 printf("::: %d, %d / %d, %d [%d]\n", VX, VY, EX, EY, game_status);