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"
25 /* select level set with EMC X11 graphics before activating EM GFX debugging */
26 #define DEBUG_EM_GFX 0
28 /* tool button identifiers */
29 #define TOOL_CTRL_ID_YES 0
30 #define TOOL_CTRL_ID_NO 1
31 #define TOOL_CTRL_ID_CONFIRM 2
32 #define TOOL_CTRL_ID_PLAYER_1 3
33 #define TOOL_CTRL_ID_PLAYER_2 4
34 #define TOOL_CTRL_ID_PLAYER_3 5
35 #define TOOL_CTRL_ID_PLAYER_4 6
37 #define NUM_TOOL_BUTTONS 7
39 /* forward declaration for internal use */
40 static void UnmapToolButtons();
41 static void HandleToolButtons(struct GadgetInfo *);
42 static int el_act_dir2crm(int, int, int);
43 static int el_act2crm(int, int);
45 static struct GadgetInfo *tool_gadget[NUM_TOOL_BUTTONS];
46 static int request_gadget_id = -1;
48 static char *print_if_not_empty(int element)
50 static char *s = NULL;
51 char *token_name = element_info[element].token_name;
56 s = checked_malloc(strlen(token_name) + 10 + 1);
58 if (element != EL_EMPTY)
59 sprintf(s, "%d\t['%s']", element, token_name);
61 sprintf(s, "%d", element);
66 void DumpTile(int x, int y)
71 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
78 printf("Field Info: SCREEN(%d, %d), LEVEL(%d, %d)\n", sx, sy, x, y);
81 if (!IN_LEV_FIELD(x, y))
83 printf("(not in level field)\n");
89 printf(" Feld: %d\t['%s']\n", Feld[x][y],
90 element_info[Feld[x][y]].token_name);
91 printf(" Back: %s\n", print_if_not_empty(Back[x][y]));
92 printf(" Store: %s\n", print_if_not_empty(Store[x][y]));
93 printf(" Store2: %s\n", print_if_not_empty(Store2[x][y]));
94 printf(" StorePlayer: %s\n", print_if_not_empty(StorePlayer[x][y]));
95 printf(" MovPos: %d\n", MovPos[x][y]);
96 printf(" MovDir: %d\n", MovDir[x][y]);
97 printf(" MovDelay: %d\n", MovDelay[x][y]);
98 printf(" ChangeDelay: %d\n", ChangeDelay[x][y]);
99 printf(" CustomValue: %d\n", CustomValue[x][y]);
100 printf(" GfxElement: %d\n", GfxElement[x][y]);
101 printf(" GfxAction: %d\n", GfxAction[x][y]);
102 printf(" GfxFrame: %d\n", GfxFrame[x][y]);
106 void SetDrawtoField(int mode)
108 if (mode == DRAW_BUFFERED && setup.soft_scrolling)
119 drawto_field = fieldbuffer;
121 else /* DRAW_DIRECT, DRAW_BACKBUFFER */
127 BX2 = SCR_FIELDX - 1;
128 BY2 = SCR_FIELDY - 1;
132 drawto_field = (mode == DRAW_DIRECT ? window : backbuffer);
136 void RedrawPlayfield(boolean force_redraw, int x, int y, int width, int height)
138 if (game_status == GAME_MODE_PLAYING &&
139 level.game_engine_type == GAME_ENGINE_TYPE_EM)
141 /* currently there is no partial redraw -- always redraw whole playfield */
142 RedrawPlayfield_EM(TRUE);
144 /* blit playfield from scroll buffer to normal back buffer for fading in */
145 BlitScreenToBitmap_EM(backbuffer);
147 else if (game_status == GAME_MODE_PLAYING && !game.envelope_active)
153 width = gfx.sxsize + 2 * TILEX;
154 height = gfx.sysize + 2 * TILEY;
157 if (force_redraw || setup.direct_draw)
160 int x1 = (x - SX) / TILEX, y1 = (y - SY) / TILEY;
161 int x2 = (x - SX + width) / TILEX, y2 = (y - SY + height) / TILEY;
163 if (setup.direct_draw)
164 SetDrawtoField(DRAW_BACKBUFFER);
166 for (xx = BX1; xx <= BX2; xx++)
167 for (yy = BY1; yy <= BY2; yy++)
168 if (xx >= x1 && xx <= x2 && yy >= y1 && yy <= y2)
169 DrawScreenField(xx, yy);
172 if (setup.direct_draw)
173 SetDrawtoField(DRAW_DIRECT);
176 if (setup.soft_scrolling)
178 int fx = FX, fy = FY;
180 fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0);
181 fy += (ScreenMovDir & (MV_UP|MV_DOWN) ? ScreenGfxPos : 0);
183 BlitBitmap(fieldbuffer, backbuffer, fx,fy, SXSIZE,SYSIZE, SX,SY);
195 BlitBitmap(drawto, window, x, y, width, height, x, y);
198 void DrawMaskedBorder_Rect(int x, int y, int width, int height)
200 Bitmap *bitmap = graphic_info[IMG_GLOBAL_BORDER].bitmap;
202 SetClipOrigin(bitmap, bitmap->stored_clip_gc, 0, 0);
203 BlitBitmapMasked(bitmap, backbuffer, x, y, width, height, x, y);
206 void DrawMaskedBorder_FIELD()
208 if (game_status >= GAME_MODE_TITLE &&
209 game_status <= GAME_MODE_PLAYING &&
210 border.draw_masked[game_status])
211 DrawMaskedBorder_Rect(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
214 void DrawMaskedBorder_DOOR_1()
216 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
217 (game_status != GAME_MODE_EDITOR ||
218 border.draw_masked[GFX_SPECIAL_ARG_EDITOR]))
219 DrawMaskedBorder_Rect(DX, DY, DXSIZE, DYSIZE);
222 void DrawMaskedBorder_DOOR_2()
224 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
225 game_status != GAME_MODE_EDITOR)
226 DrawMaskedBorder_Rect(VX, VY, VXSIZE, VYSIZE);
229 void DrawMaskedBorder_DOOR_3()
231 /* currently not available */
234 void DrawMaskedBorder_ALL()
236 DrawMaskedBorder_FIELD();
237 DrawMaskedBorder_DOOR_1();
238 DrawMaskedBorder_DOOR_2();
239 DrawMaskedBorder_DOOR_3();
242 void DrawMaskedBorder(int redraw_mask)
244 /* do not draw masked screen borders when displaying title screens */
245 if (effectiveGameStatus() == GAME_MODE_TITLE)
248 if (redraw_mask & REDRAW_ALL)
249 DrawMaskedBorder_ALL();
252 if (redraw_mask & REDRAW_FIELD)
253 DrawMaskedBorder_FIELD();
254 if (redraw_mask & REDRAW_DOOR_1)
255 DrawMaskedBorder_DOOR_1();
256 if (redraw_mask & REDRAW_DOOR_2)
257 DrawMaskedBorder_DOOR_2();
258 if (redraw_mask & REDRAW_DOOR_3)
259 DrawMaskedBorder_DOOR_3();
266 DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
268 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
269 redraw_mask &= ~REDRAW_MAIN;
271 if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD)
272 redraw_mask |= REDRAW_FIELD;
274 if (redraw_mask & REDRAW_FIELD)
275 redraw_mask &= ~REDRAW_TILES;
277 if (redraw_mask == REDRAW_NONE)
280 if (redraw_mask & REDRAW_TILES &&
281 game_status == GAME_MODE_PLAYING &&
282 border.draw_masked[GAME_MODE_PLAYING])
283 redraw_mask |= REDRAW_FIELD;
285 if (global.fps_slowdown && game_status == GAME_MODE_PLAYING)
287 static boolean last_frame_skipped = FALSE;
288 boolean skip_even_when_not_scrolling = TRUE;
289 boolean just_scrolling = (ScreenMovDir != 0);
290 boolean verbose = FALSE;
292 if (global.fps_slowdown_factor > 1 &&
293 (FrameCounter % global.fps_slowdown_factor) &&
294 (just_scrolling || skip_even_when_not_scrolling))
296 redraw_mask &= ~REDRAW_MAIN;
298 last_frame_skipped = TRUE;
301 printf("FRAME SKIPPED\n");
305 if (last_frame_skipped)
306 redraw_mask |= REDRAW_FIELD;
308 last_frame_skipped = FALSE;
311 printf("frame not skipped\n");
315 /* synchronize X11 graphics at this point; if we would synchronize the
316 display immediately after the buffer switching (after the XFlush),
317 this could mean that we have to wait for the graphics to complete,
318 although we could go on doing calculations for the next frame */
322 /* prevent drawing masked border to backbuffer when using playfield buffer */
323 if (game_status != GAME_MODE_PLAYING ||
324 redraw_mask & REDRAW_FROM_BACKBUFFER ||
325 buffer == backbuffer)
326 DrawMaskedBorder(redraw_mask);
328 DrawMaskedBorder(redraw_mask & REDRAW_DOORS);
330 if (redraw_mask & REDRAW_ALL)
332 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
334 redraw_mask = REDRAW_NONE;
337 if (redraw_mask & REDRAW_FIELD)
339 if (game_status != GAME_MODE_PLAYING ||
340 redraw_mask & REDRAW_FROM_BACKBUFFER)
342 BlitBitmap(backbuffer, window,
343 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
347 int fx = FX, fy = FY;
349 if (setup.soft_scrolling)
351 fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
352 fy += (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
355 if (setup.soft_scrolling ||
356 ABS(ScreenMovPos) + ScrollStepSize == TILEX ||
357 ABS(ScreenMovPos) == ScrollStepSize ||
358 redraw_tiles > REDRAWTILES_THRESHOLD)
360 if (border.draw_masked[GAME_MODE_PLAYING])
362 if (buffer != backbuffer)
364 /* copy playfield buffer to backbuffer to add masked border */
365 BlitBitmap(buffer, backbuffer, fx, fy, SXSIZE, SYSIZE, SX, SY);
366 DrawMaskedBorder(REDRAW_FIELD);
369 BlitBitmap(backbuffer, window,
370 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
375 BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
380 printf("redrawing all (ScreenGfxPos == %d) because %s\n",
382 (setup.soft_scrolling ?
383 "setup.soft_scrolling" :
384 ABS(ScreenGfxPos) + ScrollStepSize == TILEX ?
385 "ABS(ScreenGfxPos) + ScrollStepSize == TILEX" :
386 ABS(ScreenGfxPos) == ScrollStepSize ?
387 "ABS(ScreenGfxPos) == ScrollStepSize" :
388 "redraw_tiles > REDRAWTILES_THRESHOLD"));
394 redraw_mask &= ~REDRAW_MAIN;
397 if (redraw_mask & REDRAW_DOORS)
399 if (redraw_mask & REDRAW_DOOR_1)
400 BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
402 if (redraw_mask & REDRAW_DOOR_2)
403 BlitBitmap(backbuffer, window, VX, VY, VXSIZE, VYSIZE, VX, VY);
405 if (redraw_mask & REDRAW_DOOR_3)
406 BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
408 redraw_mask &= ~REDRAW_DOORS;
411 if (redraw_mask & REDRAW_MICROLEVEL)
413 BlitBitmap(backbuffer, window, SX, SY + 10 * TILEY, SXSIZE, 7 * TILEY,
414 SX, SY + 10 * TILEY);
416 redraw_mask &= ~REDRAW_MICROLEVEL;
419 if (redraw_mask & REDRAW_TILES)
421 for (x = 0; x < SCR_FIELDX; x++)
422 for (y = 0 ; y < SCR_FIELDY; y++)
423 if (redraw[redraw_x1 + x][redraw_y1 + y])
424 BlitBitmap(buffer, window,
425 FX + x * TILEX, FY + y * TILEY, TILEX, TILEY,
426 SX + x * TILEX, SY + y * TILEY);
429 if (redraw_mask & REDRAW_FPS) /* display frames per second */
434 sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
435 if (!global.fps_slowdown)
438 sprintf(text, "%.1f fps%s", global.frames_per_second, info1);
439 DrawTextExt(window, SX, SY, text, FONT_TEXT_2, BLIT_OPAQUE);
444 for (x = 0; x < MAX_BUF_XSIZE; x++)
445 for (y = 0; y < MAX_BUF_YSIZE; y++)
448 redraw_mask = REDRAW_NONE;
454 long fading_delay = 300;
456 if (setup.fading && (redraw_mask & REDRAW_FIELD))
463 ClearRectangle(window, REAL_SX,REAL_SY,FULL_SXSIZE,FULL_SYSIZE);
466 for (i = 0; i < 2 * FULL_SYSIZE; i++)
468 for (y = 0; y < FULL_SYSIZE; y++)
470 BlitBitmap(backbuffer, window,
471 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
479 for (i = 1; i < FULL_SYSIZE; i+=2)
480 BlitBitmap(backbuffer, window,
481 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
487 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, 0);
488 BlitBitmapMasked(backbuffer, window,
489 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
494 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, -1);
495 BlitBitmapMasked(backbuffer, window,
496 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
501 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, -1);
502 BlitBitmapMasked(backbuffer, window,
503 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
508 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, 0);
509 BlitBitmapMasked(backbuffer, window,
510 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
515 redraw_mask &= ~REDRAW_MAIN;
522 void FadeExt(int fade_mask, int fade_mode)
524 static int fade_mode_skip = FADE_MODE_NONE;
525 void (*draw_border_function)(void) = NULL;
527 Bitmap *bitmap = (fade_mode != FADE_MODE_FADE_IN ? bitmap_db_cross : NULL);
529 Bitmap *bitmap = (fade_mode & FADE_TYPE_TRANSFORM ? bitmap_db_cross : NULL);
531 int x, y, width, height;
532 int fade_delay, post_delay;
534 redraw_mask |= fade_mask;
536 if (fade_mode & FADE_TYPE_SKIP)
539 printf("::: will skip %d ... [%d]\n", fade_mode, fade_mode_skip);
542 fade_mode_skip = fade_mode;
547 if (fade_mode_skip & FADE_TYPE_SKIP)
550 printf("::: skipping %d ... [%d]\n", fade_mode, fade_mode_skip);
553 /* skip all fade operations until specified fade operation */
554 if (fade_mode & fade_mode_skip)
555 fade_mode_skip = FADE_MODE_NONE;
561 if (global.autoplay_leveldir)
563 // fading.fade_mode = FADE_MODE_NONE;
570 if (fading.fade_mode == FADE_MODE_NONE)
578 if (fade_mask & REDRAW_FIELD)
583 height = FULL_SYSIZE;
585 fade_delay = fading.fade_delay;
586 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
588 draw_border_function = DrawMaskedBorder_FIELD;
590 else /* REDRAW_ALL */
597 fade_delay = fading.fade_delay;
598 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
602 if (!setup.fade_screens || fade_delay == 0)
604 if (!setup.fade_screens || fade_delay == 0 || fading.anim_mode == ANIM_NONE)
607 if (fade_mode == FADE_MODE_FADE_OUT)
608 ClearRectangle(backbuffer, x, y, width, height);
615 FadeRectangle(bitmap, x, y, width, height, fade_mode, fade_delay, post_delay,
616 draw_border_function);
618 redraw_mask &= ~fade_mask;
621 void FadeIn(int fade_mask)
624 // printf("::: now fading in...\n");
626 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
627 FadeExt(fade_mask, fading.fade_mode);
629 FadeExt(fade_mask, FADE_MODE_FADE_IN);
632 if (fading.fade_mode == FADE_MODE_CROSSFADE)
633 FadeExt(fade_mask, FADE_MODE_CROSSFADE);
635 FadeExt(fade_mask, FADE_MODE_FADE_IN);
637 FadeExt(fade_mask, FADE_MODE_FADE_IN);
642 void FadeOut(int fade_mask)
645 // printf("::: fading.fade_mode == %d\n", fading.fade_mode);
647 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
648 FadeCrossSaveBackbuffer();
650 FadeExt(fade_mask, FADE_MODE_FADE_OUT);
653 if (fading.fade_mode == FADE_MODE_CROSSFADE)
654 FadeCrossSaveBackbuffer();
656 FadeExt(fade_mask, FADE_MODE_FADE_OUT);
658 FadeExt(fade_mask, FADE_MODE_FADE_OUT);
663 void FadeCross(int fade_mask)
665 FadeExt(fade_mask, FADE_MODE_CROSSFADE);
668 void FadeCrossSaveBackbuffer()
670 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
673 static void FadeSetLeaveNext(struct TitleFadingInfo fading_leave, boolean set)
675 static struct TitleFadingInfo fading_leave_stored;
678 fading_leave_stored = fading_leave;
680 fading = fading_leave_stored;
683 void FadeSetEnterMenu()
685 fading = menu.enter_menu;
687 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
690 void FadeSetLeaveMenu()
692 fading = menu.leave_menu;
694 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
697 void FadeSetEnterScreen()
699 fading = menu.enter_screen[game_status];
701 FadeSetLeaveNext(menu.leave_screen[game_status], TRUE); /* store */
704 void FadeSetLeaveScreen()
706 FadeSetLeaveNext(menu.leave_screen[game_status], FALSE); /* recall */
709 void FadeSetFromType(int type)
711 if (type & TYPE_ENTER_SCREEN)
712 FadeSetEnterScreen();
713 else if (type & TYPE_ENTER)
715 else if (type & TYPE_LEAVE)
719 void FadeSetDisabled()
721 static struct TitleFadingInfo fading_none = { FADE_MODE_NONE, -1, -1, -1 };
723 fading = fading_none;
726 void FadeSkipNextFadeIn()
728 FadeExt(0, FADE_MODE_SKIP_FADE_IN);
731 void FadeSkipNextFadeOut()
733 FadeExt(0, FADE_MODE_SKIP_FADE_OUT);
736 void SetWindowBackgroundImageIfDefined(int graphic)
738 if (graphic_info[graphic].bitmap)
739 SetWindowBackgroundBitmap(graphic_info[graphic].bitmap);
742 void SetMainBackgroundImageIfDefined(int graphic)
744 if (graphic_info[graphic].bitmap)
745 SetMainBackgroundBitmap(graphic_info[graphic].bitmap);
748 void SetDoorBackgroundImageIfDefined(int graphic)
750 if (graphic_info[graphic].bitmap)
751 SetDoorBackgroundBitmap(graphic_info[graphic].bitmap);
754 void SetWindowBackgroundImage(int graphic)
756 SetWindowBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
757 graphic_info[graphic].bitmap ?
758 graphic_info[graphic].bitmap :
759 graphic_info[IMG_BACKGROUND].bitmap);
762 void SetMainBackgroundImage(int graphic)
764 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
765 graphic_info[graphic].bitmap ?
766 graphic_info[graphic].bitmap :
767 graphic_info[IMG_BACKGROUND].bitmap);
770 void SetDoorBackgroundImage(int graphic)
772 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
773 graphic_info[graphic].bitmap ?
774 graphic_info[graphic].bitmap :
775 graphic_info[IMG_BACKGROUND].bitmap);
778 void SetPanelBackground()
780 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, bitmap_db_panel,
781 DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, 0, 0);
783 SetDoorBackgroundBitmap(bitmap_db_panel);
786 void DrawBackground(int x, int y, int width, int height)
788 /* !!! "drawto" might still point to playfield buffer here (see below) !!! */
789 /* (when entering hall of fame after playing) */
791 ClearRectangleOnBackground(drawto, x, y, width, height);
793 ClearRectangleOnBackground(backbuffer, x, y, width, height);
796 redraw_mask |= REDRAW_FIELD;
799 void DrawBackgroundForFont(int x, int y, int width, int height, int font_nr)
801 struct FontBitmapInfo *font = getFontBitmapInfo(font_nr);
803 if (font->bitmap == NULL)
806 DrawBackground(x, y, width, height);
809 void DrawBackgroundForGraphic(int x, int y, int width, int height, int graphic)
811 struct GraphicInfo *g = &graphic_info[graphic];
813 if (g->bitmap == NULL)
816 DrawBackground(x, y, width, height);
821 /* !!! "drawto" might still point to playfield buffer here (see above) !!! */
822 /* (when entering hall of fame after playing) */
823 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
825 /* !!! maybe this should be done before clearing the background !!! */
826 if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
828 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
829 SetDrawtoField(DRAW_BUFFERED);
832 SetDrawtoField(DRAW_BACKBUFFER);
834 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
836 ClearRectangle(window, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
837 SetDrawtoField(DRAW_DIRECT);
841 void MarkTileDirty(int x, int y)
843 int xx = redraw_x1 + x;
844 int yy = redraw_y1 + y;
849 redraw[xx][yy] = TRUE;
850 redraw_mask |= REDRAW_TILES;
853 void SetBorderElement()
857 BorderElement = EL_EMPTY;
859 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
861 for (x = 0; x < lev_fieldx; x++)
863 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
864 BorderElement = EL_STEELWALL;
866 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
872 void FloodFillLevel(int from_x, int from_y, int fill_element,
873 short field[MAX_LEV_FIELDX][MAX_LEV_FIELDY],
874 int max_fieldx, int max_fieldy)
878 static int check[4][2] = { { -1, 0 }, { 0, -1 }, { 1, 0 }, { 0, 1 } };
879 static int safety = 0;
881 /* check if starting field still has the desired content */
882 if (field[from_x][from_y] == fill_element)
887 if (safety > max_fieldx * max_fieldy)
888 Error(ERR_EXIT, "Something went wrong in 'FloodFill()'. Please debug.");
890 old_element = field[from_x][from_y];
891 field[from_x][from_y] = fill_element;
893 for (i = 0; i < 4; i++)
895 x = from_x + check[i][0];
896 y = from_y + check[i][1];
898 if (IN_FIELD(x, y, max_fieldx, max_fieldy) && field[x][y] == old_element)
899 FloodFillLevel(x, y, fill_element, field, max_fieldx, max_fieldy);
905 void SetRandomAnimationValue(int x, int y)
907 gfx.anim_random_frame = GfxRandom[x][y];
910 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
912 /* animation synchronized with global frame counter, not move position */
913 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
914 sync_frame = FrameCounter;
916 return getAnimationFrame(graphic_info[graphic].anim_frames,
917 graphic_info[graphic].anim_delay,
918 graphic_info[graphic].anim_mode,
919 graphic_info[graphic].anim_start_frame,
923 void getSizedGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y,
928 int width_mult, width_div;
929 int height_mult, height_div;
933 { 15, 16, 2, 3 }, /* 1 x 1 */
934 { 7, 8, 2, 3 }, /* 2 x 2 */
935 { 3, 4, 2, 3 }, /* 4 x 4 */
936 { 1, 2, 2, 3 }, /* 8 x 8 */
937 { 0, 1, 2, 3 }, /* 16 x 16 */
938 { 0, 1, 0, 1 }, /* 32 x 32 */
940 int tilesize = MIN(MAX(1, tilesize_raw), TILESIZE);
941 int offset_calc_pos = log_2(tilesize);
942 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
943 int width_mult = offset_calc[offset_calc_pos].width_mult;
944 int width_div = offset_calc[offset_calc_pos].width_div;
945 int height_mult = offset_calc[offset_calc_pos].height_mult;
946 int height_div = offset_calc[offset_calc_pos].height_div;
947 int startx = src_bitmap->width * width_mult / width_div;
948 int starty = src_bitmap->height * height_mult / height_div;
949 int src_x = startx + graphic_info[graphic].src_x * tilesize / TILESIZE;
950 int src_y = starty + graphic_info[graphic].src_y * tilesize / TILESIZE;
952 *bitmap = src_bitmap;
957 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
960 getSizedGraphicSource(graphic, bitmap, x, y, MINI_TILESIZE);
962 struct GraphicInfo *g = &graphic_info[graphic];
964 int mini_starty = g->bitmap->height * 2 / 3;
967 *x = mini_startx + g->src_x / 2;
968 *y = mini_starty + g->src_y / 2;
972 inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
973 int *x, int *y, boolean get_backside)
975 struct GraphicInfo *g = &graphic_info[graphic];
976 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
977 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
981 if (g->offset_y == 0) /* frames are ordered horizontally */
983 int max_width = g->anim_frames_per_line * g->width;
984 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
986 *x = pos % max_width;
987 *y = src_y % g->height + pos / max_width * g->height;
989 else if (g->offset_x == 0) /* frames are ordered vertically */
991 int max_height = g->anim_frames_per_line * g->height;
992 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
994 *x = src_x % g->width + pos / max_height * g->width;
995 *y = pos % max_height;
997 else /* frames are ordered diagonally */
999 *x = src_x + frame * g->offset_x;
1000 *y = src_y + frame * g->offset_y;
1004 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
1006 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
1009 void DrawGraphic(int x, int y, int graphic, int frame)
1012 if (!IN_SCR_FIELD(x, y))
1014 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1015 printf("DrawGraphic(): This should never happen!\n");
1020 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
1021 MarkTileDirty(x, y);
1024 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1030 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1031 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
1034 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
1037 if (!IN_SCR_FIELD(x, y))
1039 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1040 printf("DrawGraphicThruMask(): This should never happen!\n");
1045 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
1047 MarkTileDirty(x, y);
1050 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
1056 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1058 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1059 dst_x - src_x, dst_y - src_y);
1060 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
1063 void DrawSizedGraphic(int x, int y, int graphic, int tilesize)
1065 DrawSizedGraphicExt(drawto, SX + x * tilesize, SY + y * tilesize, graphic,
1067 MarkTileDirty(x / tilesize, y / tilesize);
1070 void DrawSizedGraphicExt(DrawBuffer *d, int x, int y, int graphic, int tilesize)
1075 getSizedGraphicSource(graphic, &src_bitmap, &src_x, &src_y, tilesize);
1076 BlitBitmap(src_bitmap, d, src_x, src_y, tilesize, tilesize, x, y);
1079 void DrawMiniGraphic(int x, int y, int graphic)
1081 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
1082 MarkTileDirty(x / 2, y / 2);
1085 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
1090 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1091 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
1094 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
1095 int graphic, int frame,
1096 int cut_mode, int mask_mode)
1101 int width = TILEX, height = TILEY;
1104 if (dx || dy) /* shifted graphic */
1106 if (x < BX1) /* object enters playfield from the left */
1113 else if (x > BX2) /* object enters playfield from the right */
1119 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
1125 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
1127 else if (dx) /* general horizontal movement */
1128 MarkTileDirty(x + SIGN(dx), y);
1130 if (y < BY1) /* object enters playfield from the top */
1132 if (cut_mode==CUT_BELOW) /* object completely above top border */
1140 else if (y > BY2) /* object enters playfield from the bottom */
1146 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
1152 else if (dy > 0 && cut_mode == CUT_ABOVE)
1154 if (y == BY2) /* object completely above bottom border */
1160 MarkTileDirty(x, y + 1);
1161 } /* object leaves playfield to the bottom */
1162 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1164 else if (dy) /* general vertical movement */
1165 MarkTileDirty(x, y + SIGN(dy));
1169 if (!IN_SCR_FIELD(x, y))
1171 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1172 printf("DrawGraphicShifted(): This should never happen!\n");
1177 if (width > 0 && height > 0)
1179 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1184 dst_x = FX + x * TILEX + dx;
1185 dst_y = FY + y * TILEY + dy;
1187 if (mask_mode == USE_MASKING)
1189 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1190 dst_x - src_x, dst_y - src_y);
1191 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1195 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1198 MarkTileDirty(x, y);
1202 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
1203 int graphic, int frame,
1204 int cut_mode, int mask_mode)
1209 int width = TILEX, height = TILEY;
1212 int x2 = x + SIGN(dx);
1213 int y2 = y + SIGN(dy);
1214 int anim_frames = graphic_info[graphic].anim_frames;
1215 int sync_frame = (dx ? ABS(dx) : ABS(dy)) * anim_frames / TILESIZE;
1216 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
1217 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
1219 /* re-calculate animation frame for two-tile movement animation */
1220 frame = getGraphicAnimationFrame(graphic, sync_frame);
1222 /* check if movement start graphic inside screen area and should be drawn */
1223 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
1225 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
1227 dst_x = FX + x1 * TILEX;
1228 dst_y = FY + y1 * TILEY;
1230 if (mask_mode == USE_MASKING)
1232 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1233 dst_x - src_x, dst_y - src_y);
1234 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1238 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1241 MarkTileDirty(x1, y1);
1244 /* check if movement end graphic inside screen area and should be drawn */
1245 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
1247 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
1249 dst_x = FX + x2 * TILEX;
1250 dst_y = FY + y2 * TILEY;
1252 if (mask_mode == USE_MASKING)
1254 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1255 dst_x - src_x, dst_y - src_y);
1256 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1260 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1263 MarkTileDirty(x2, y2);
1267 static void DrawGraphicShifted(int x, int y, int dx, int dy,
1268 int graphic, int frame,
1269 int cut_mode, int mask_mode)
1273 DrawGraphic(x, y, graphic, frame);
1278 if (graphic_info[graphic].double_movement) /* EM style movement images */
1279 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1281 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1284 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1285 int frame, int cut_mode)
1287 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
1290 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1291 int cut_mode, int mask_mode)
1293 int lx = LEVELX(x), ly = LEVELY(y);
1297 if (IN_LEV_FIELD(lx, ly))
1299 SetRandomAnimationValue(lx, ly);
1301 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
1302 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1304 /* do not use double (EM style) movement graphic when not moving */
1305 if (graphic_info[graphic].double_movement && !dx && !dy)
1307 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
1308 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1311 else /* border element */
1313 graphic = el2img(element);
1314 frame = getGraphicAnimationFrame(graphic, -1);
1317 if (element == EL_EXPANDABLE_WALL)
1319 boolean left_stopped = FALSE, right_stopped = FALSE;
1321 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1322 left_stopped = TRUE;
1323 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1324 right_stopped = TRUE;
1326 if (left_stopped && right_stopped)
1328 else if (left_stopped)
1330 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1331 frame = graphic_info[graphic].anim_frames - 1;
1333 else if (right_stopped)
1335 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1336 frame = graphic_info[graphic].anim_frames - 1;
1341 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1342 else if (mask_mode == USE_MASKING)
1343 DrawGraphicThruMask(x, y, graphic, frame);
1345 DrawGraphic(x, y, graphic, frame);
1348 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1349 int cut_mode, int mask_mode)
1351 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1352 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1353 cut_mode, mask_mode);
1356 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1359 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1362 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1365 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1368 void DrawLevelElementThruMask(int x, int y, int element)
1370 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1373 void DrawLevelFieldThruMask(int x, int y)
1375 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1378 static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
1382 int sx = SCREENX(x), sy = SCREENY(y);
1384 int width, height, cx, cy, i;
1385 int crumbled_border_size = graphic_info[graphic].border_size;
1386 static int xy[4][2] =
1394 if (!IN_LEV_FIELD(x, y))
1397 element = TILE_GFX_ELEMENT(x, y);
1399 /* crumble field itself */
1400 if (GFX_CRUMBLED(element) && !IS_MOVING(x, y))
1402 if (!IN_SCR_FIELD(sx, sy))
1405 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1407 for (i = 0; i < 4; i++)
1409 int xx = x + xy[i][0];
1410 int yy = y + xy[i][1];
1412 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1415 /* check if neighbour field is of same type */
1416 if (GFX_CRUMBLED(element) && !IS_MOVING(xx, yy))
1419 if (i == 1 || i == 2)
1421 width = crumbled_border_size;
1423 cx = (i == 2 ? TILEX - crumbled_border_size : 0);
1429 height = crumbled_border_size;
1431 cy = (i == 3 ? TILEY - crumbled_border_size : 0);
1434 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1435 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1438 MarkTileDirty(sx, sy);
1440 else /* crumble neighbour fields */
1442 for (i = 0; i < 4; i++)
1444 int xx = x + xy[i][0];
1445 int yy = y + xy[i][1];
1446 int sxx = sx + xy[i][0];
1447 int syy = sy + xy[i][1];
1449 if (!IN_LEV_FIELD(xx, yy) ||
1450 !IN_SCR_FIELD(sxx, syy) ||
1454 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
1457 element = TILE_GFX_ELEMENT(xx, yy);
1459 if (!GFX_CRUMBLED(element))
1462 graphic = el_act2crm(element, ACTION_DEFAULT);
1463 crumbled_border_size = graphic_info[graphic].border_size;
1465 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1467 if (i == 1 || i == 2)
1469 width = crumbled_border_size;
1471 cx = (i == 1 ? TILEX - crumbled_border_size : 0);
1477 height = crumbled_border_size;
1479 cy = (i == 0 ? TILEY - crumbled_border_size : 0);
1482 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1483 width, height, FX + sxx * TILEX + cx, FY + syy * TILEY + cy);
1485 MarkTileDirty(sxx, syy);
1490 void DrawLevelFieldCrumbledSand(int x, int y)
1494 if (!IN_LEV_FIELD(x, y))
1498 /* !!! CHECK THIS !!! */
1501 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1502 GFX_CRUMBLED(GfxElement[x][y]))
1505 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1506 GfxElement[x][y] != EL_UNDEFINED &&
1507 GFX_CRUMBLED(GfxElement[x][y]))
1509 DrawLevelFieldCrumbledSandDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
1516 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
1518 graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
1521 DrawLevelFieldCrumbledSandExt(x, y, graphic, 0);
1524 void DrawLevelFieldCrumbledSandDigging(int x, int y, int direction,
1527 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1528 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1529 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1530 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1531 int sx = SCREENX(x), sy = SCREENY(y);
1533 DrawGraphic(sx, sy, graphic1, frame1);
1534 DrawLevelFieldCrumbledSandExt(x, y, graphic2, frame2);
1537 void DrawLevelFieldCrumbledSandNeighbours(int x, int y)
1539 int sx = SCREENX(x), sy = SCREENY(y);
1540 static int xy[4][2] =
1549 for (i = 0; i < 4; i++)
1551 int xx = x + xy[i][0];
1552 int yy = y + xy[i][1];
1553 int sxx = sx + xy[i][0];
1554 int syy = sy + xy[i][1];
1556 if (!IN_LEV_FIELD(xx, yy) ||
1557 !IN_SCR_FIELD(sxx, syy) ||
1558 !GFX_CRUMBLED(Feld[xx][yy]) ||
1562 DrawLevelField(xx, yy);
1566 static int getBorderElement(int x, int y)
1570 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1571 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1572 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1573 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1574 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1575 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1576 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1578 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1579 int steel_position = (x == -1 && y == -1 ? 0 :
1580 x == lev_fieldx && y == -1 ? 1 :
1581 x == -1 && y == lev_fieldy ? 2 :
1582 x == lev_fieldx && y == lev_fieldy ? 3 :
1583 x == -1 || x == lev_fieldx ? 4 :
1584 y == -1 || y == lev_fieldy ? 5 : 6);
1586 return border[steel_position][steel_type];
1589 void DrawScreenElement(int x, int y, int element)
1591 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1592 DrawLevelFieldCrumbledSand(LEVELX(x), LEVELY(y));
1595 void DrawLevelElement(int x, int y, int element)
1597 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1598 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1601 void DrawScreenField(int x, int y)
1603 int lx = LEVELX(x), ly = LEVELY(y);
1604 int element, content;
1606 if (!IN_LEV_FIELD(lx, ly))
1608 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1611 element = getBorderElement(lx, ly);
1613 DrawScreenElement(x, y, element);
1617 element = Feld[lx][ly];
1618 content = Store[lx][ly];
1620 if (IS_MOVING(lx, ly))
1622 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1623 boolean cut_mode = NO_CUTTING;
1625 if (element == EL_QUICKSAND_EMPTYING ||
1626 element == EL_QUICKSAND_FAST_EMPTYING ||
1627 element == EL_MAGIC_WALL_EMPTYING ||
1628 element == EL_BD_MAGIC_WALL_EMPTYING ||
1629 element == EL_DC_MAGIC_WALL_EMPTYING ||
1630 element == EL_AMOEBA_DROPPING)
1631 cut_mode = CUT_ABOVE;
1632 else if (element == EL_QUICKSAND_FILLING ||
1633 element == EL_QUICKSAND_FAST_FILLING ||
1634 element == EL_MAGIC_WALL_FILLING ||
1635 element == EL_BD_MAGIC_WALL_FILLING ||
1636 element == EL_DC_MAGIC_WALL_FILLING)
1637 cut_mode = CUT_BELOW;
1639 if (cut_mode == CUT_ABOVE)
1640 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1642 DrawScreenElement(x, y, EL_EMPTY);
1645 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1646 else if (cut_mode == NO_CUTTING)
1647 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1649 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1651 if (content == EL_ACID)
1653 int dir = MovDir[lx][ly];
1654 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
1655 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
1657 DrawLevelElementThruMask(newlx, newly, EL_ACID);
1660 else if (IS_BLOCKED(lx, ly))
1665 boolean cut_mode = NO_CUTTING;
1666 int element_old, content_old;
1668 Blocked2Moving(lx, ly, &oldx, &oldy);
1671 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1672 MovDir[oldx][oldy] == MV_RIGHT);
1674 element_old = Feld[oldx][oldy];
1675 content_old = Store[oldx][oldy];
1677 if (element_old == EL_QUICKSAND_EMPTYING ||
1678 element_old == EL_QUICKSAND_FAST_EMPTYING ||
1679 element_old == EL_MAGIC_WALL_EMPTYING ||
1680 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1681 element_old == EL_DC_MAGIC_WALL_EMPTYING ||
1682 element_old == EL_AMOEBA_DROPPING)
1683 cut_mode = CUT_ABOVE;
1685 DrawScreenElement(x, y, EL_EMPTY);
1688 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1690 else if (cut_mode == NO_CUTTING)
1691 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1694 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1697 else if (IS_DRAWABLE(element))
1698 DrawScreenElement(x, y, element);
1700 DrawScreenElement(x, y, EL_EMPTY);
1703 void DrawLevelField(int x, int y)
1705 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1706 DrawScreenField(SCREENX(x), SCREENY(y));
1707 else if (IS_MOVING(x, y))
1711 Moving2Blocked(x, y, &newx, &newy);
1712 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1713 DrawScreenField(SCREENX(newx), SCREENY(newy));
1715 else if (IS_BLOCKED(x, y))
1719 Blocked2Moving(x, y, &oldx, &oldy);
1720 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1721 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1725 void DrawMiniElement(int x, int y, int element)
1729 graphic = el2edimg(element);
1730 DrawMiniGraphic(x, y, graphic);
1733 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1735 int x = sx + scroll_x, y = sy + scroll_y;
1737 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1738 DrawMiniElement(sx, sy, EL_EMPTY);
1739 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1740 DrawMiniElement(sx, sy, Feld[x][y]);
1742 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1745 void DrawEnvelopeBackground(int envelope_nr, int startx, int starty,
1746 int x, int y, int xsize, int ysize, int font_nr)
1748 int font_width = getFontWidth(font_nr);
1749 int font_height = getFontHeight(font_nr);
1750 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1753 int dst_x = SX + startx + x * font_width;
1754 int dst_y = SY + starty + y * font_height;
1755 int width = graphic_info[graphic].width;
1756 int height = graphic_info[graphic].height;
1757 int inner_width = MAX(width - 2 * font_width, font_width);
1758 int inner_height = MAX(height - 2 * font_height, font_height);
1759 int inner_sx = (width >= 3 * font_width ? font_width : 0);
1760 int inner_sy = (height >= 3 * font_height ? font_height : 0);
1761 boolean draw_masked = graphic_info[graphic].draw_masked;
1763 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1765 if (src_bitmap == NULL || width < font_width || height < font_height)
1767 ClearRectangle(drawto, dst_x, dst_y, font_width, font_height);
1771 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - font_width :
1772 inner_sx + (x - 1) * font_width % inner_width);
1773 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - font_height :
1774 inner_sy + (y - 1) * font_height % inner_height);
1778 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1779 dst_x - src_x, dst_y - src_y);
1780 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1784 BlitBitmap(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1788 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
1790 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1791 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1792 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
1793 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1794 boolean no_delay = (tape.warp_forward);
1795 unsigned long anim_delay = 0;
1796 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
1797 int anim_delay_value = (no_delay ? 0 : frame_delay_value);
1798 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
1799 int font_width = getFontWidth(font_nr);
1800 int font_height = getFontHeight(font_nr);
1801 int max_xsize = level.envelope[envelope_nr].xsize;
1802 int max_ysize = level.envelope[envelope_nr].ysize;
1803 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
1804 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
1805 int xend = max_xsize;
1806 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
1807 int xstep = (xstart < xend ? 1 : 0);
1808 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
1811 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
1813 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
1814 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
1815 int sx = (SXSIZE - xsize * font_width) / 2;
1816 int sy = (SYSIZE - ysize * font_height) / 2;
1819 SetDrawtoField(DRAW_BUFFERED);
1821 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
1823 SetDrawtoField(DRAW_BACKBUFFER);
1825 for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++)
1826 DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
1829 DrawTextBuffer(SX + sx + font_width, SY + sy + font_height,
1830 level.envelope[envelope_nr].text, font_nr, max_xsize,
1831 xsize - 2, ysize - 2, mask_mode,
1832 level.envelope[envelope_nr].autowrap,
1833 level.envelope[envelope_nr].centered, FALSE);
1835 DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
1836 level.envelope[envelope_nr].text, font_nr, max_xsize,
1837 xsize - 2, ysize - 2, mask_mode);
1840 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
1843 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
1847 void ShowEnvelope(int envelope_nr)
1849 int element = EL_ENVELOPE_1 + envelope_nr;
1850 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1851 int sound_opening = element_info[element].sound[ACTION_OPENING];
1852 int sound_closing = element_info[element].sound[ACTION_CLOSING];
1853 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1854 boolean no_delay = (tape.warp_forward);
1855 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
1856 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
1857 int anim_mode = graphic_info[graphic].anim_mode;
1858 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
1859 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
1861 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
1863 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
1865 if (anim_mode == ANIM_DEFAULT)
1866 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
1868 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
1871 Delay(wait_delay_value);
1873 WaitForEventToContinue();
1875 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
1877 if (anim_mode != ANIM_NONE)
1878 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
1880 if (anim_mode == ANIM_DEFAULT)
1881 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
1883 game.envelope_active = FALSE;
1885 SetDrawtoField(DRAW_BUFFERED);
1887 redraw_mask |= REDRAW_FIELD;
1891 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
1895 int graphic = el2preimg(element);
1897 getSizedGraphicSource(graphic, &src_bitmap, &src_x, &src_y, tilesize);
1898 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
1905 SetDrawBackgroundMask(REDRAW_NONE);
1908 for (x = BX1; x <= BX2; x++)
1909 for (y = BY1; y <= BY2; y++)
1910 DrawScreenField(x, y);
1912 redraw_mask |= REDRAW_FIELD;
1915 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1919 for (x = 0; x < size_x; x++)
1920 for (y = 0; y < size_y; y++)
1921 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1923 redraw_mask |= REDRAW_FIELD;
1926 static void DrawPreviewLevelExt(int from_x, int from_y)
1928 boolean show_level_border = (BorderElement != EL_EMPTY);
1929 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
1930 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
1931 int tile_size = preview.tile_size;
1932 int preview_width = preview.xsize * tile_size;
1933 int preview_height = preview.ysize * tile_size;
1934 int real_preview_xsize = MIN(level_xsize, preview.xsize);
1935 int real_preview_ysize = MIN(level_ysize, preview.ysize);
1936 int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
1937 int dst_y = SY + ALIGNED_YPOS(preview.y, preview_height, preview.valign);
1940 DrawBackground(dst_x, dst_y, preview_width, preview_height);
1942 dst_x += (preview_width - real_preview_xsize * tile_size) / 2;
1943 dst_y += (preview_height - real_preview_ysize * tile_size) / 2;
1945 for (x = 0; x < real_preview_xsize; x++)
1947 for (y = 0; y < real_preview_ysize; y++)
1949 int lx = from_x + x + (show_level_border ? -1 : 0);
1950 int ly = from_y + y + (show_level_border ? -1 : 0);
1951 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
1952 getBorderElement(lx, ly));
1954 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
1955 element, tile_size);
1959 redraw_mask |= REDRAW_MICROLEVEL;
1962 #define MICROLABEL_EMPTY 0
1963 #define MICROLABEL_LEVEL_NAME 1
1964 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
1965 #define MICROLABEL_LEVEL_AUTHOR 3
1966 #define MICROLABEL_IMPORTED_FROM_HEAD 4
1967 #define MICROLABEL_IMPORTED_FROM 5
1968 #define MICROLABEL_IMPORTED_BY_HEAD 6
1969 #define MICROLABEL_IMPORTED_BY 7
1971 static int getMaxTextLength(struct TextPosInfo *pos, int font_nr)
1973 int max_text_width = SXSIZE;
1974 int font_width = getFontWidth(font_nr);
1976 if (pos->align == ALIGN_CENTER)
1977 max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
1978 else if (pos->align == ALIGN_RIGHT)
1979 max_text_width = pos->x;
1981 max_text_width = SXSIZE - pos->x;
1983 return max_text_width / font_width;
1986 static void DrawPreviewLevelLabelExt(int mode)
1988 struct TextPosInfo *pos = &menu.main.text.level_info_2;
1989 char label_text[MAX_OUTPUT_LINESIZE + 1];
1990 int max_len_label_text;
1992 int font_nr = pos->font;
1995 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
1996 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
1997 mode == MICROLABEL_IMPORTED_BY_HEAD)
1998 font_nr = pos->font_alt;
2000 int font_nr = FONT_TEXT_2;
2003 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
2004 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
2005 mode == MICROLABEL_IMPORTED_BY_HEAD)
2006 font_nr = FONT_TEXT_3;
2010 max_len_label_text = getMaxTextLength(pos, font_nr);
2012 max_len_label_text = SXSIZE / getFontWidth(font_nr);
2016 if (pos->size != -1)
2017 max_len_label_text = pos->size;
2020 for (i = 0; i < max_len_label_text; i++)
2021 label_text[i] = ' ';
2022 label_text[max_len_label_text] = '\0';
2024 if (strlen(label_text) > 0)
2027 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2029 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
2030 int lypos = MICROLABEL2_YPOS;
2032 DrawText(lxpos, lypos, label_text, font_nr);
2037 (mode == MICROLABEL_LEVEL_NAME ? level.name :
2038 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
2039 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
2040 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
2041 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
2042 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
2043 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
2044 max_len_label_text);
2045 label_text[max_len_label_text] = '\0';
2047 if (strlen(label_text) > 0)
2050 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2052 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
2053 int lypos = MICROLABEL2_YPOS;
2055 DrawText(lxpos, lypos, label_text, font_nr);
2059 redraw_mask |= REDRAW_MICROLEVEL;
2062 void DrawPreviewLevel(boolean restart)
2064 static unsigned long scroll_delay = 0;
2065 static unsigned long label_delay = 0;
2066 static int from_x, from_y, scroll_direction;
2067 static int label_state, label_counter;
2068 unsigned long scroll_delay_value = preview.step_delay;
2069 boolean show_level_border = (BorderElement != EL_EMPTY);
2070 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2071 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2072 int last_game_status = game_status; /* save current game status */
2075 /* force PREVIEW font on preview level */
2076 game_status = GAME_MODE_PSEUDO_PREVIEW;
2084 if (preview.anim_mode == ANIM_CENTERED)
2086 if (level_xsize > preview.xsize)
2087 from_x = (level_xsize - preview.xsize) / 2;
2088 if (level_ysize > preview.ysize)
2089 from_y = (level_ysize - preview.ysize) / 2;
2092 from_x += preview.xoffset;
2093 from_y += preview.yoffset;
2095 scroll_direction = MV_RIGHT;
2099 DrawPreviewLevelExt(from_x, from_y);
2100 DrawPreviewLevelLabelExt(label_state);
2102 /* initialize delay counters */
2103 DelayReached(&scroll_delay, 0);
2104 DelayReached(&label_delay, 0);
2106 if (leveldir_current->name)
2108 struct TextPosInfo *pos = &menu.main.text.level_info_1;
2109 char label_text[MAX_OUTPUT_LINESIZE + 1];
2111 int font_nr = pos->font;
2113 int font_nr = FONT_TEXT_1;
2116 int max_len_label_text = getMaxTextLength(pos, font_nr);
2118 int max_len_label_text = SXSIZE / getFontWidth(font_nr);
2126 if (pos->size != -1)
2127 max_len_label_text = pos->size;
2130 strncpy(label_text, leveldir_current->name, max_len_label_text);
2131 label_text[max_len_label_text] = '\0';
2134 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2136 lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
2137 lypos = SY + MICROLABEL1_YPOS;
2139 DrawText(lxpos, lypos, label_text, font_nr);
2143 game_status = last_game_status; /* restore current game status */
2148 /* scroll preview level, if needed */
2149 if (preview.anim_mode != ANIM_NONE &&
2150 (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
2151 DelayReached(&scroll_delay, scroll_delay_value))
2153 switch (scroll_direction)
2158 from_x -= preview.step_offset;
2159 from_x = (from_x < 0 ? 0 : from_x);
2162 scroll_direction = MV_UP;
2166 if (from_x < level_xsize - preview.xsize)
2168 from_x += preview.step_offset;
2169 from_x = (from_x > level_xsize - preview.xsize ?
2170 level_xsize - preview.xsize : from_x);
2173 scroll_direction = MV_DOWN;
2179 from_y -= preview.step_offset;
2180 from_y = (from_y < 0 ? 0 : from_y);
2183 scroll_direction = MV_RIGHT;
2187 if (from_y < level_ysize - preview.ysize)
2189 from_y += preview.step_offset;
2190 from_y = (from_y > level_ysize - preview.ysize ?
2191 level_ysize - preview.ysize : from_y);
2194 scroll_direction = MV_LEFT;
2201 DrawPreviewLevelExt(from_x, from_y);
2204 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
2205 /* redraw micro level label, if needed */
2206 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
2207 !strEqual(level.author, ANONYMOUS_NAME) &&
2208 !strEqual(level.author, leveldir_current->name) &&
2209 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
2211 int max_label_counter = 23;
2213 if (leveldir_current->imported_from != NULL &&
2214 strlen(leveldir_current->imported_from) > 0)
2215 max_label_counter += 14;
2216 if (leveldir_current->imported_by != NULL &&
2217 strlen(leveldir_current->imported_by) > 0)
2218 max_label_counter += 14;
2220 label_counter = (label_counter + 1) % max_label_counter;
2221 label_state = (label_counter >= 0 && label_counter <= 7 ?
2222 MICROLABEL_LEVEL_NAME :
2223 label_counter >= 9 && label_counter <= 12 ?
2224 MICROLABEL_LEVEL_AUTHOR_HEAD :
2225 label_counter >= 14 && label_counter <= 21 ?
2226 MICROLABEL_LEVEL_AUTHOR :
2227 label_counter >= 23 && label_counter <= 26 ?
2228 MICROLABEL_IMPORTED_FROM_HEAD :
2229 label_counter >= 28 && label_counter <= 35 ?
2230 MICROLABEL_IMPORTED_FROM :
2231 label_counter >= 37 && label_counter <= 40 ?
2232 MICROLABEL_IMPORTED_BY_HEAD :
2233 label_counter >= 42 && label_counter <= 49 ?
2234 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
2236 if (leveldir_current->imported_from == NULL &&
2237 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
2238 label_state == MICROLABEL_IMPORTED_FROM))
2239 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
2240 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
2242 DrawPreviewLevelLabelExt(label_state);
2245 game_status = last_game_status; /* restore current game status */
2248 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
2249 int graphic, int sync_frame, int mask_mode)
2251 int frame = getGraphicAnimationFrame(graphic, sync_frame);
2253 if (mask_mode == USE_MASKING)
2254 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
2256 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
2259 inline void DrawGraphicAnimation(int x, int y, int graphic)
2261 int lx = LEVELX(x), ly = LEVELY(y);
2263 if (!IN_SCR_FIELD(x, y))
2266 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
2267 graphic, GfxFrame[lx][ly], NO_MASKING);
2268 MarkTileDirty(x, y);
2271 void DrawLevelGraphicAnimation(int x, int y, int graphic)
2273 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2276 void DrawLevelElementAnimation(int x, int y, int element)
2278 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2280 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2283 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
2285 int sx = SCREENX(x), sy = SCREENY(y);
2287 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2290 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2293 DrawGraphicAnimation(sx, sy, graphic);
2296 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
2297 DrawLevelFieldCrumbledSand(x, y);
2299 if (GFX_CRUMBLED(Feld[x][y]))
2300 DrawLevelFieldCrumbledSand(x, y);
2304 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
2306 int sx = SCREENX(x), sy = SCREENY(y);
2309 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2312 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2314 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2317 DrawGraphicAnimation(sx, sy, graphic);
2319 if (GFX_CRUMBLED(element))
2320 DrawLevelFieldCrumbledSand(x, y);
2323 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
2325 if (player->use_murphy)
2327 /* this works only because currently only one player can be "murphy" ... */
2328 static int last_horizontal_dir = MV_LEFT;
2329 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
2331 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2332 last_horizontal_dir = move_dir;
2334 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
2336 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
2338 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
2344 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
2347 static boolean equalGraphics(int graphic1, int graphic2)
2349 struct GraphicInfo *g1 = &graphic_info[graphic1];
2350 struct GraphicInfo *g2 = &graphic_info[graphic2];
2352 return (g1->bitmap == g2->bitmap &&
2353 g1->src_x == g2->src_x &&
2354 g1->src_y == g2->src_y &&
2355 g1->anim_frames == g2->anim_frames &&
2356 g1->anim_delay == g2->anim_delay &&
2357 g1->anim_mode == g2->anim_mode);
2360 void DrawAllPlayers()
2364 for (i = 0; i < MAX_PLAYERS; i++)
2365 if (stored_player[i].active)
2366 DrawPlayer(&stored_player[i]);
2369 void DrawPlayerField(int x, int y)
2371 if (!IS_PLAYER(x, y))
2374 DrawPlayer(PLAYERINFO(x, y));
2377 void DrawPlayer(struct PlayerInfo *player)
2379 int jx = player->jx;
2380 int jy = player->jy;
2381 int move_dir = player->MovDir;
2382 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
2383 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
2384 int last_jx = (player->is_moving ? jx - dx : jx);
2385 int last_jy = (player->is_moving ? jy - dy : jy);
2386 int next_jx = jx + dx;
2387 int next_jy = jy + dy;
2388 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
2389 boolean player_is_opaque = FALSE;
2390 int sx = SCREENX(jx), sy = SCREENY(jy);
2391 int sxx = 0, syy = 0;
2392 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
2394 int action = ACTION_DEFAULT;
2395 int last_player_graphic = getPlayerGraphic(player, move_dir);
2396 int last_player_frame = player->Frame;
2399 /* GfxElement[][] is set to the element the player is digging or collecting;
2400 remove also for off-screen player if the player is not moving anymore */
2401 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
2402 GfxElement[jx][jy] = EL_UNDEFINED;
2404 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
2408 if (!IN_LEV_FIELD(jx, jy))
2410 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
2411 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
2412 printf("DrawPlayerField(): This should never happen!\n");
2417 if (element == EL_EXPLOSION)
2420 action = (player->is_pushing ? ACTION_PUSHING :
2421 player->is_digging ? ACTION_DIGGING :
2422 player->is_collecting ? ACTION_COLLECTING :
2423 player->is_moving ? ACTION_MOVING :
2424 player->is_snapping ? ACTION_SNAPPING :
2425 player->is_dropping ? ACTION_DROPPING :
2426 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
2428 if (player->is_waiting)
2429 move_dir = player->dir_waiting;
2431 InitPlayerGfxAnimation(player, action, move_dir);
2433 /* ----------------------------------------------------------------------- */
2434 /* draw things in the field the player is leaving, if needed */
2435 /* ----------------------------------------------------------------------- */
2437 if (player->is_moving)
2439 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
2441 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
2443 if (last_element == EL_DYNAMITE_ACTIVE ||
2444 last_element == EL_EM_DYNAMITE_ACTIVE ||
2445 last_element == EL_SP_DISK_RED_ACTIVE)
2446 DrawDynamite(last_jx, last_jy);
2448 DrawLevelFieldThruMask(last_jx, last_jy);
2450 else if (last_element == EL_DYNAMITE_ACTIVE ||
2451 last_element == EL_EM_DYNAMITE_ACTIVE ||
2452 last_element == EL_SP_DISK_RED_ACTIVE)
2453 DrawDynamite(last_jx, last_jy);
2455 /* !!! this is not enough to prevent flickering of players which are
2456 moving next to each others without a free tile between them -- this
2457 can only be solved by drawing all players layer by layer (first the
2458 background, then the foreground etc.) !!! => TODO */
2459 else if (!IS_PLAYER(last_jx, last_jy))
2460 DrawLevelField(last_jx, last_jy);
2463 DrawLevelField(last_jx, last_jy);
2466 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
2467 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
2470 if (!IN_SCR_FIELD(sx, sy))
2473 if (setup.direct_draw)
2474 SetDrawtoField(DRAW_BUFFERED);
2476 /* ----------------------------------------------------------------------- */
2477 /* draw things behind the player, if needed */
2478 /* ----------------------------------------------------------------------- */
2481 DrawLevelElement(jx, jy, Back[jx][jy]);
2482 else if (IS_ACTIVE_BOMB(element))
2483 DrawLevelElement(jx, jy, EL_EMPTY);
2486 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
2488 int old_element = GfxElement[jx][jy];
2489 int old_graphic = el_act_dir2img(old_element, action, move_dir);
2490 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
2492 if (GFX_CRUMBLED(old_element))
2493 DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
2495 DrawGraphic(sx, sy, old_graphic, frame);
2497 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
2498 player_is_opaque = TRUE;
2502 GfxElement[jx][jy] = EL_UNDEFINED;
2504 /* make sure that pushed elements are drawn with correct frame rate */
2506 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2508 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
2509 GfxFrame[jx][jy] = player->StepFrame;
2511 if (player->is_pushing && player->is_moving)
2512 GfxFrame[jx][jy] = player->StepFrame;
2515 DrawLevelField(jx, jy);
2519 /* ----------------------------------------------------------------------- */
2520 /* draw player himself */
2521 /* ----------------------------------------------------------------------- */
2523 graphic = getPlayerGraphic(player, move_dir);
2525 /* in the case of changed player action or direction, prevent the current
2526 animation frame from being restarted for identical animations */
2527 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
2528 player->Frame = last_player_frame;
2530 frame = getGraphicAnimationFrame(graphic, player->Frame);
2534 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2535 sxx = player->GfxPos;
2537 syy = player->GfxPos;
2540 if (!setup.soft_scrolling && ScreenMovPos)
2543 if (player_is_opaque)
2544 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
2546 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2548 if (SHIELD_ON(player))
2550 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
2551 IMG_SHIELD_NORMAL_ACTIVE);
2552 int frame = getGraphicAnimationFrame(graphic, -1);
2554 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2557 /* ----------------------------------------------------------------------- */
2558 /* draw things the player is pushing, if needed */
2559 /* ----------------------------------------------------------------------- */
2562 printf("::: %d, %d [%d, %d] [%d]\n",
2563 player->is_pushing, player_is_moving, player->GfxAction,
2564 player->is_moving, player_is_moving);
2568 if (player->is_pushing && player->is_moving)
2570 int px = SCREENX(jx), py = SCREENY(jy);
2571 int pxx = (TILEX - ABS(sxx)) * dx;
2572 int pyy = (TILEY - ABS(syy)) * dy;
2573 int gfx_frame = GfxFrame[jx][jy];
2579 if (!IS_MOVING(jx, jy)) /* push movement already finished */
2581 element = Feld[next_jx][next_jy];
2582 gfx_frame = GfxFrame[next_jx][next_jy];
2585 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2588 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
2589 frame = getGraphicAnimationFrame(graphic, sync_frame);
2591 frame = getGraphicAnimationFrame(graphic, player->StepFrame);
2594 /* draw background element under pushed element (like the Sokoban field) */
2595 if (Back[next_jx][next_jy])
2596 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
2598 /* masked drawing is needed for EMC style (double) movement graphics */
2599 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
2603 /* ----------------------------------------------------------------------- */
2604 /* draw things in front of player (active dynamite or dynabombs) */
2605 /* ----------------------------------------------------------------------- */
2607 if (IS_ACTIVE_BOMB(element))
2609 graphic = el2img(element);
2610 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
2612 if (game.emulation == EMU_SUPAPLEX)
2613 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
2615 DrawGraphicThruMask(sx, sy, graphic, frame);
2618 if (player_is_moving && last_element == EL_EXPLOSION)
2620 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
2621 GfxElement[last_jx][last_jy] : EL_EMPTY);
2622 int graphic = el_act2img(element, ACTION_EXPLODING);
2623 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
2624 int phase = ExplodePhase[last_jx][last_jy] - 1;
2625 int frame = getGraphicAnimationFrame(graphic, phase - delay);
2628 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
2631 /* ----------------------------------------------------------------------- */
2632 /* draw elements the player is just walking/passing through/under */
2633 /* ----------------------------------------------------------------------- */
2635 if (player_is_moving)
2637 /* handle the field the player is leaving ... */
2638 if (IS_ACCESSIBLE_INSIDE(last_element))
2639 DrawLevelField(last_jx, last_jy);
2640 else if (IS_ACCESSIBLE_UNDER(last_element))
2641 DrawLevelFieldThruMask(last_jx, last_jy);
2644 /* do not redraw accessible elements if the player is just pushing them */
2645 if (!player_is_moving || !player->is_pushing)
2647 /* ... and the field the player is entering */
2648 if (IS_ACCESSIBLE_INSIDE(element))
2649 DrawLevelField(jx, jy);
2650 else if (IS_ACCESSIBLE_UNDER(element))
2651 DrawLevelFieldThruMask(jx, jy);
2654 if (setup.direct_draw)
2656 int dst_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
2657 int dst_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
2658 int x_size = TILEX * (1 + ABS(jx - last_jx));
2659 int y_size = TILEY * (1 + ABS(jy - last_jy));
2661 BlitBitmap(drawto_field, window,
2662 dst_x, dst_y, x_size, y_size, dst_x, dst_y);
2663 SetDrawtoField(DRAW_DIRECT);
2666 MarkTileDirty(sx, sy);
2669 /* ------------------------------------------------------------------------- */
2671 void WaitForEventToContinue()
2673 boolean still_wait = TRUE;
2675 /* simulate releasing mouse button over last gadget, if still pressed */
2677 HandleGadgets(-1, -1, 0);
2679 button_status = MB_RELEASED;
2695 case EVENT_BUTTONPRESS:
2696 case EVENT_KEYPRESS:
2700 case EVENT_KEYRELEASE:
2701 ClearPlayerAction();
2705 HandleOtherEvents(&event);
2709 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2716 /* don't eat all CPU time */
2721 #define MAX_REQUEST_LINES 13
2722 #define MAX_REQUEST_LINE_FONT1_LEN 7
2723 #define MAX_REQUEST_LINE_FONT2_LEN 10
2725 boolean Request(char *text, unsigned int req_state)
2727 int mx, my, ty, result = -1;
2728 unsigned int old_door_state;
2729 int last_game_status = game_status; /* save current game status */
2730 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
2731 int font_nr = FONT_TEXT_2;
2732 int max_word_len = 0;
2735 for (text_ptr = text; *text_ptr; text_ptr++)
2737 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
2739 if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
2741 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
2743 font_nr = FONT_TEXT_1;
2745 font_nr = FONT_LEVEL_NUMBER;
2752 if (game_status == GAME_MODE_PLAYING &&
2753 level.game_engine_type == GAME_ENGINE_TYPE_EM)
2754 BlitScreenToBitmap_EM(backbuffer);
2756 /* disable deactivated drawing when quick-loading level tape recording */
2757 if (tape.playing && tape.deactivate_display)
2758 TapeDeactivateDisplayOff(TRUE);
2760 SetMouseCursor(CURSOR_DEFAULT);
2762 #if defined(NETWORK_AVALIABLE)
2763 /* pause network game while waiting for request to answer */
2764 if (options.network &&
2765 game_status == GAME_MODE_PLAYING &&
2766 req_state & REQUEST_WAIT_FOR_INPUT)
2767 SendToServer_PausePlaying();
2770 old_door_state = GetDoorState();
2772 /* simulate releasing mouse button over last gadget, if still pressed */
2774 HandleGadgets(-1, -1, 0);
2778 if (old_door_state & DOOR_OPEN_1)
2780 CloseDoor(DOOR_CLOSE_1);
2782 /* save old door content */
2783 BlitBitmap(bitmap_db_door, bitmap_db_door,
2784 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2785 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
2789 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2792 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2794 /* clear door drawing field */
2795 DrawBackground(DX, DY, DXSIZE, DYSIZE);
2797 /* force DOOR font inside door area */
2798 game_status = GAME_MODE_PSEUDO_DOOR;
2800 /* write text for request */
2801 for (ty = 0; ty < MAX_REQUEST_LINES; ty++)
2803 char text_line[max_request_line_len + 1];
2809 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
2812 if (!tc || tc == ' ')
2823 strncpy(text_line, text, tl);
2826 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
2827 DY + 8 + ty * (getFontHeight(font_nr) + 2),
2828 text_line, font_nr);
2830 text += tl + (tc == ' ' ? 1 : 0);
2833 game_status = last_game_status; /* restore current game status */
2835 if (req_state & REQ_ASK)
2837 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2838 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2840 else if (req_state & REQ_CONFIRM)
2842 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2844 else if (req_state & REQ_PLAYER)
2846 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2847 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2848 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2849 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2852 /* copy request gadgets to door backbuffer */
2853 BlitBitmap(drawto, bitmap_db_door,
2854 DX, DY, DXSIZE, DYSIZE,
2855 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2857 OpenDoor(DOOR_OPEN_1);
2859 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
2861 if (game_status == GAME_MODE_PLAYING)
2863 SetPanelBackground();
2864 SetDrawBackgroundMask(REDRAW_DOOR_1);
2868 SetDrawBackgroundMask(REDRAW_FIELD);
2874 if (game_status != GAME_MODE_MAIN)
2877 button_status = MB_RELEASED;
2879 request_gadget_id = -1;
2881 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2893 case EVENT_BUTTONPRESS:
2894 case EVENT_BUTTONRELEASE:
2895 case EVENT_MOTIONNOTIFY:
2897 if (event.type == EVENT_MOTIONNOTIFY)
2899 if (!PointerInWindow(window))
2900 continue; /* window and pointer are on different screens */
2905 motion_status = TRUE;
2906 mx = ((MotionEvent *) &event)->x;
2907 my = ((MotionEvent *) &event)->y;
2911 motion_status = FALSE;
2912 mx = ((ButtonEvent *) &event)->x;
2913 my = ((ButtonEvent *) &event)->y;
2914 if (event.type == EVENT_BUTTONPRESS)
2915 button_status = ((ButtonEvent *) &event)->button;
2917 button_status = MB_RELEASED;
2920 /* this sets 'request_gadget_id' */
2921 HandleGadgets(mx, my, button_status);
2923 switch (request_gadget_id)
2925 case TOOL_CTRL_ID_YES:
2928 case TOOL_CTRL_ID_NO:
2931 case TOOL_CTRL_ID_CONFIRM:
2932 result = TRUE | FALSE;
2935 case TOOL_CTRL_ID_PLAYER_1:
2938 case TOOL_CTRL_ID_PLAYER_2:
2941 case TOOL_CTRL_ID_PLAYER_3:
2944 case TOOL_CTRL_ID_PLAYER_4:
2955 case EVENT_KEYPRESS:
2956 switch (GetEventKey((KeyEvent *)&event, TRUE))
2959 if (req_state & REQ_CONFIRM)
2975 if (req_state & REQ_PLAYER)
2979 case EVENT_KEYRELEASE:
2980 ClearPlayerAction();
2984 HandleOtherEvents(&event);
2988 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2990 int joy = AnyJoystick();
2992 if (joy & JOY_BUTTON_1)
2994 else if (joy & JOY_BUTTON_2)
3000 if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd)
3002 HandleGameActions();
3009 if (!PendingEvent()) /* delay only if no pending events */
3018 if (!PendingEvent()) /* delay only if no pending events */
3021 /* don't eat all CPU time */
3028 if (game_status != GAME_MODE_MAIN)
3033 if (!(req_state & REQ_STAY_OPEN))
3035 CloseDoor(DOOR_CLOSE_1);
3037 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
3038 (req_state & REQ_REOPEN))
3039 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
3044 if (game_status == GAME_MODE_PLAYING)
3046 SetPanelBackground();
3047 SetDrawBackgroundMask(REDRAW_DOOR_1);
3051 SetDrawBackgroundMask(REDRAW_FIELD);
3054 #if defined(NETWORK_AVALIABLE)
3055 /* continue network game after request */
3056 if (options.network &&
3057 game_status == GAME_MODE_PLAYING &&
3058 req_state & REQUEST_WAIT_FOR_INPUT)
3059 SendToServer_ContinuePlaying();
3062 /* restore deactivated drawing when quick-loading level tape recording */
3063 if (tape.playing && tape.deactivate_display)
3064 TapeDeactivateDisplayOn();
3069 unsigned int OpenDoor(unsigned int door_state)
3071 if (door_state & DOOR_COPY_BACK)
3073 if (door_state & DOOR_OPEN_1)
3074 BlitBitmap(bitmap_db_door, bitmap_db_door,
3075 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
3076 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
3078 if (door_state & DOOR_OPEN_2)
3079 BlitBitmap(bitmap_db_door, bitmap_db_door,
3080 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
3081 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
3083 door_state &= ~DOOR_COPY_BACK;
3086 return MoveDoor(door_state);
3089 unsigned int CloseDoor(unsigned int door_state)
3091 unsigned int old_door_state = GetDoorState();
3093 if (!(door_state & DOOR_NO_COPY_BACK))
3095 if (old_door_state & DOOR_OPEN_1)
3096 BlitBitmap(backbuffer, bitmap_db_door,
3097 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
3099 if (old_door_state & DOOR_OPEN_2)
3100 BlitBitmap(backbuffer, bitmap_db_door,
3101 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
3103 door_state &= ~DOOR_NO_COPY_BACK;
3106 return MoveDoor(door_state);
3109 unsigned int GetDoorState()
3111 return MoveDoor(DOOR_GET_STATE);
3114 unsigned int SetDoorState(unsigned int door_state)
3116 return MoveDoor(door_state | DOOR_SET_STATE);
3119 unsigned int MoveDoor(unsigned int door_state)
3121 static int door1 = DOOR_OPEN_1;
3122 static int door2 = DOOR_CLOSE_2;
3123 unsigned long door_delay = 0;
3124 unsigned long door_delay_value;
3127 if (door_1.width < 0 || door_1.width > DXSIZE)
3128 door_1.width = DXSIZE;
3129 if (door_1.height < 0 || door_1.height > DYSIZE)
3130 door_1.height = DYSIZE;
3131 if (door_2.width < 0 || door_2.width > VXSIZE)
3132 door_2.width = VXSIZE;
3133 if (door_2.height < 0 || door_2.height > VYSIZE)
3134 door_2.height = VYSIZE;
3136 if (door_state == DOOR_GET_STATE)
3137 return (door1 | door2);
3139 if (door_state & DOOR_SET_STATE)
3141 if (door_state & DOOR_ACTION_1)
3142 door1 = door_state & DOOR_ACTION_1;
3143 if (door_state & DOOR_ACTION_2)
3144 door2 = door_state & DOOR_ACTION_2;
3146 return (door1 | door2);
3149 if (!(door_state & DOOR_FORCE_REDRAW))
3151 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
3152 door_state &= ~DOOR_OPEN_1;
3153 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
3154 door_state &= ~DOOR_CLOSE_1;
3155 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
3156 door_state &= ~DOOR_OPEN_2;
3157 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
3158 door_state &= ~DOOR_CLOSE_2;
3161 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
3164 if (setup.quick_doors)
3166 stepsize = 20; /* must be chosen to always draw last frame */
3167 door_delay_value = 0;
3170 if (global.autoplay_leveldir)
3172 door_state |= DOOR_NO_DELAY;
3173 door_state &= ~DOOR_CLOSE_ALL;
3176 if (door_state & DOOR_ACTION)
3178 boolean handle_door_1 = (door_state & DOOR_ACTION_1);
3179 boolean handle_door_2 = (door_state & DOOR_ACTION_2);
3180 boolean door_1_done = (!handle_door_1);
3181 boolean door_2_done = (!handle_door_2);
3182 boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
3183 boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
3184 int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
3185 int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
3186 int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
3187 int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
3188 int door_size = (handle_door_1 ? door_size_1 : door_size_2);
3189 int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
3190 int door_skip = max_door_size - door_size;
3191 int end = door_size;
3192 int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
3195 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
3197 /* opening door sound has priority over simultaneously closing door */
3198 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
3199 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
3200 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
3201 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
3204 for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
3207 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3208 GC gc = bitmap->stored_clip_gc;
3210 if (door_state & DOOR_ACTION_1)
3212 int a = MIN(x * door_1.step_offset, end);
3213 int p = (door_state & DOOR_OPEN_1 ? end - a : a);
3214 int i = p + door_skip;
3216 if (door_1.anim_mode & ANIM_STATIC_PANEL)
3218 BlitBitmap(bitmap_db_door, drawto,
3219 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
3220 DXSIZE, DYSIZE, DX, DY);
3224 BlitBitmap(bitmap_db_door, drawto,
3225 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
3226 DXSIZE, DYSIZE - p / 2, DX, DY);
3228 ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
3231 if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
3233 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
3234 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
3235 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
3236 int dst2_x = DX, dst2_y = DY;
3237 int width = i, height = DYSIZE;
3239 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3240 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3243 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3244 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3247 else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
3249 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
3250 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
3251 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
3252 int dst2_x = DX, dst2_y = DY;
3253 int width = DXSIZE, height = i;
3255 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3256 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3259 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3260 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3263 else if (x <= DXSIZE) /* ANIM_DEFAULT */
3265 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
3267 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
3268 BlitBitmapMasked(bitmap, drawto,
3269 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
3270 DX + DXSIZE - i, DY + j);
3271 BlitBitmapMasked(bitmap, drawto,
3272 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
3273 DX + DXSIZE - i, DY + 140 + j);
3274 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
3275 DY - (DOOR_GFX_PAGEY1 + j));
3276 BlitBitmapMasked(bitmap, drawto,
3277 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
3279 BlitBitmapMasked(bitmap, drawto,
3280 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
3283 BlitBitmapMasked(bitmap, drawto,
3284 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
3286 BlitBitmapMasked(bitmap, drawto,
3287 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
3289 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
3290 BlitBitmapMasked(bitmap, drawto,
3291 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
3292 DX + DXSIZE - i, DY + 77 + j);
3293 BlitBitmapMasked(bitmap, drawto,
3294 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
3295 DX + DXSIZE - i, DY + 203 + j);
3298 redraw_mask |= REDRAW_DOOR_1;
3299 door_1_done = (a == end);
3302 if (door_state & DOOR_ACTION_2)
3304 int a = MIN(x * door_2.step_offset, door_size);
3305 int p = (door_state & DOOR_OPEN_2 ? door_size - a : a);
3306 int i = p + door_skip;
3308 if (door_2.anim_mode & ANIM_STATIC_PANEL)
3310 BlitBitmap(bitmap_db_door, drawto,
3311 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
3312 VXSIZE, VYSIZE, VX, VY);
3314 else if (x <= VYSIZE)
3316 BlitBitmap(bitmap_db_door, drawto,
3317 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
3318 VXSIZE, VYSIZE - p / 2, VX, VY);
3320 ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
3323 if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
3325 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
3326 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
3327 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
3328 int dst2_x = VX, dst2_y = VY;
3329 int width = i, height = VYSIZE;
3331 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3332 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3335 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3336 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3339 else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
3341 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
3342 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
3343 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
3344 int dst2_x = VX, dst2_y = VY;
3345 int width = VXSIZE, height = i;
3347 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3348 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3351 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3352 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3355 else if (x <= VXSIZE) /* ANIM_DEFAULT */
3357 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
3359 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3360 BlitBitmapMasked(bitmap, drawto,
3361 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
3362 VX + VXSIZE - i, VY + j);
3363 SetClipOrigin(bitmap, gc,
3364 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
3365 BlitBitmapMasked(bitmap, drawto,
3366 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
3369 BlitBitmapMasked(bitmap, drawto,
3370 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3371 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
3372 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3373 BlitBitmapMasked(bitmap, drawto,
3374 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3376 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
3379 redraw_mask |= REDRAW_DOOR_2;
3380 door_2_done = (a == VXSIZE);
3383 if (!(door_state & DOOR_NO_DELAY))
3387 if (game_status == GAME_MODE_MAIN)
3390 WaitUntilDelayReached(&door_delay, door_delay_value);
3395 if (door_state & DOOR_ACTION_1)
3396 door1 = door_state & DOOR_ACTION_1;
3397 if (door_state & DOOR_ACTION_2)
3398 door2 = door_state & DOOR_ACTION_2;
3400 return (door1 | door2);
3403 void DrawSpecialEditorDoor()
3405 /* draw bigger toolbox window */
3406 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
3407 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
3409 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3410 EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
3413 redraw_mask |= REDRAW_ALL;
3416 void UndrawSpecialEditorDoor()
3418 /* draw normal tape recorder window */
3419 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3420 EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
3423 redraw_mask |= REDRAW_ALL;
3427 /* ---------- new tool button stuff ---------------------------------------- */
3429 /* graphic position values for tool buttons */
3430 #define TOOL_BUTTON_YES_XPOS 2
3431 #define TOOL_BUTTON_YES_YPOS 250
3432 #define TOOL_BUTTON_YES_GFX_YPOS 0
3433 #define TOOL_BUTTON_YES_XSIZE 46
3434 #define TOOL_BUTTON_YES_YSIZE 28
3435 #define TOOL_BUTTON_NO_XPOS 52
3436 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
3437 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
3438 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
3439 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
3440 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
3441 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
3442 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
3443 #define TOOL_BUTTON_CONFIRM_XSIZE 96
3444 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
3445 #define TOOL_BUTTON_PLAYER_XSIZE 30
3446 #define TOOL_BUTTON_PLAYER_YSIZE 30
3447 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
3448 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
3449 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
3450 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
3451 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3452 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3453 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3454 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3455 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3456 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3457 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3458 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3459 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3460 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3461 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3462 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3463 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3464 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3465 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3466 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3475 } toolbutton_info[NUM_TOOL_BUTTONS] =
3478 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
3479 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
3480 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
3485 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
3486 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
3487 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
3492 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
3493 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
3494 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
3495 TOOL_CTRL_ID_CONFIRM,
3499 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3500 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
3501 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3502 TOOL_CTRL_ID_PLAYER_1,
3506 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3507 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
3508 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3509 TOOL_CTRL_ID_PLAYER_2,
3513 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3514 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
3515 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3516 TOOL_CTRL_ID_PLAYER_3,
3520 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3521 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
3522 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3523 TOOL_CTRL_ID_PLAYER_4,
3528 void CreateToolButtons()
3532 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3534 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3535 Bitmap *deco_bitmap = None;
3536 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
3537 struct GadgetInfo *gi;
3538 unsigned long event_mask;
3539 int gd_xoffset, gd_yoffset;
3540 int gd_x1, gd_x2, gd_y;
3543 event_mask = GD_EVENT_RELEASED;
3545 gd_xoffset = toolbutton_info[i].xpos;
3546 gd_yoffset = toolbutton_info[i].ypos;
3547 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
3548 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
3549 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
3551 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
3553 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
3555 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
3556 &deco_bitmap, &deco_x, &deco_y);
3557 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
3558 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
3561 gi = CreateGadget(GDI_CUSTOM_ID, id,
3562 GDI_INFO_TEXT, toolbutton_info[i].infotext,
3563 GDI_X, DX + toolbutton_info[i].x,
3564 GDI_Y, DY + toolbutton_info[i].y,
3565 GDI_WIDTH, toolbutton_info[i].width,
3566 GDI_HEIGHT, toolbutton_info[i].height,
3567 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
3568 GDI_STATE, GD_BUTTON_UNPRESSED,
3569 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
3570 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
3571 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
3572 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
3573 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
3574 GDI_DECORATION_SHIFTING, 1, 1,
3575 GDI_DIRECT_DRAW, FALSE,
3576 GDI_EVENT_MASK, event_mask,
3577 GDI_CALLBACK_ACTION, HandleToolButtons,
3581 Error(ERR_EXIT, "cannot create gadget");
3583 tool_gadget[id] = gi;
3587 void FreeToolButtons()
3591 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3592 FreeGadget(tool_gadget[i]);
3595 static void UnmapToolButtons()
3599 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3600 UnmapGadget(tool_gadget[i]);
3603 static void HandleToolButtons(struct GadgetInfo *gi)
3605 request_gadget_id = gi->custom_id;
3608 static struct Mapping_EM_to_RND_object
3611 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
3612 boolean is_backside; /* backside of moving element */
3618 em_object_mapping_list[] =
3621 Xblank, TRUE, FALSE,
3625 Yacid_splash_eB, FALSE, FALSE,
3626 EL_ACID_SPLASH_RIGHT, -1, -1
3629 Yacid_splash_wB, FALSE, FALSE,
3630 EL_ACID_SPLASH_LEFT, -1, -1
3633 #ifdef EM_ENGINE_BAD_ROLL
3635 Xstone_force_e, FALSE, FALSE,
3636 EL_ROCK, -1, MV_BIT_RIGHT
3639 Xstone_force_w, FALSE, FALSE,
3640 EL_ROCK, -1, MV_BIT_LEFT
3643 Xnut_force_e, FALSE, FALSE,
3644 EL_NUT, -1, MV_BIT_RIGHT
3647 Xnut_force_w, FALSE, FALSE,
3648 EL_NUT, -1, MV_BIT_LEFT
3651 Xspring_force_e, FALSE, FALSE,
3652 EL_SPRING, -1, MV_BIT_RIGHT
3655 Xspring_force_w, FALSE, FALSE,
3656 EL_SPRING, -1, MV_BIT_LEFT
3659 Xemerald_force_e, FALSE, FALSE,
3660 EL_EMERALD, -1, MV_BIT_RIGHT
3663 Xemerald_force_w, FALSE, FALSE,
3664 EL_EMERALD, -1, MV_BIT_LEFT
3667 Xdiamond_force_e, FALSE, FALSE,
3668 EL_DIAMOND, -1, MV_BIT_RIGHT
3671 Xdiamond_force_w, FALSE, FALSE,
3672 EL_DIAMOND, -1, MV_BIT_LEFT
3675 Xbomb_force_e, FALSE, FALSE,
3676 EL_BOMB, -1, MV_BIT_RIGHT
3679 Xbomb_force_w, FALSE, FALSE,
3680 EL_BOMB, -1, MV_BIT_LEFT
3682 #endif /* EM_ENGINE_BAD_ROLL */
3685 Xstone, TRUE, FALSE,
3689 Xstone_pause, FALSE, FALSE,
3693 Xstone_fall, FALSE, FALSE,
3697 Ystone_s, FALSE, FALSE,
3698 EL_ROCK, ACTION_FALLING, -1
3701 Ystone_sB, FALSE, TRUE,
3702 EL_ROCK, ACTION_FALLING, -1
3705 Ystone_e, FALSE, FALSE,
3706 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3709 Ystone_eB, FALSE, TRUE,
3710 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3713 Ystone_w, FALSE, FALSE,
3714 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3717 Ystone_wB, FALSE, TRUE,
3718 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3725 Xnut_pause, FALSE, FALSE,
3729 Xnut_fall, FALSE, FALSE,
3733 Ynut_s, FALSE, FALSE,
3734 EL_NUT, ACTION_FALLING, -1
3737 Ynut_sB, FALSE, TRUE,
3738 EL_NUT, ACTION_FALLING, -1
3741 Ynut_e, FALSE, FALSE,
3742 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3745 Ynut_eB, FALSE, TRUE,
3746 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3749 Ynut_w, FALSE, FALSE,
3750 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3753 Ynut_wB, FALSE, TRUE,
3754 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3757 Xbug_n, TRUE, FALSE,
3761 Xbug_e, TRUE, FALSE,
3762 EL_BUG_RIGHT, -1, -1
3765 Xbug_s, TRUE, FALSE,
3769 Xbug_w, TRUE, FALSE,
3773 Xbug_gon, FALSE, FALSE,
3777 Xbug_goe, FALSE, FALSE,
3778 EL_BUG_RIGHT, -1, -1
3781 Xbug_gos, FALSE, FALSE,
3785 Xbug_gow, FALSE, FALSE,
3789 Ybug_n, FALSE, FALSE,
3790 EL_BUG, ACTION_MOVING, MV_BIT_UP
3793 Ybug_nB, FALSE, TRUE,
3794 EL_BUG, ACTION_MOVING, MV_BIT_UP
3797 Ybug_e, FALSE, FALSE,
3798 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3801 Ybug_eB, FALSE, TRUE,
3802 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3805 Ybug_s, FALSE, FALSE,
3806 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3809 Ybug_sB, FALSE, TRUE,
3810 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3813 Ybug_w, FALSE, FALSE,
3814 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3817 Ybug_wB, FALSE, TRUE,
3818 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3821 Ybug_w_n, FALSE, FALSE,
3822 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3825 Ybug_n_e, FALSE, FALSE,
3826 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3829 Ybug_e_s, FALSE, FALSE,
3830 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3833 Ybug_s_w, FALSE, FALSE,
3834 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3837 Ybug_e_n, FALSE, FALSE,
3838 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3841 Ybug_s_e, FALSE, FALSE,
3842 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3845 Ybug_w_s, FALSE, FALSE,
3846 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3849 Ybug_n_w, FALSE, FALSE,
3850 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3853 Ybug_stone, FALSE, FALSE,
3854 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
3857 Ybug_spring, FALSE, FALSE,
3858 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
3861 Xtank_n, TRUE, FALSE,
3862 EL_SPACESHIP_UP, -1, -1
3865 Xtank_e, TRUE, FALSE,
3866 EL_SPACESHIP_RIGHT, -1, -1
3869 Xtank_s, TRUE, FALSE,
3870 EL_SPACESHIP_DOWN, -1, -1
3873 Xtank_w, TRUE, FALSE,
3874 EL_SPACESHIP_LEFT, -1, -1
3877 Xtank_gon, FALSE, FALSE,
3878 EL_SPACESHIP_UP, -1, -1
3881 Xtank_goe, FALSE, FALSE,
3882 EL_SPACESHIP_RIGHT, -1, -1
3885 Xtank_gos, FALSE, FALSE,
3886 EL_SPACESHIP_DOWN, -1, -1
3889 Xtank_gow, FALSE, FALSE,
3890 EL_SPACESHIP_LEFT, -1, -1
3893 Ytank_n, FALSE, FALSE,
3894 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3897 Ytank_nB, FALSE, TRUE,
3898 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3901 Ytank_e, FALSE, FALSE,
3902 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3905 Ytank_eB, FALSE, TRUE,
3906 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3909 Ytank_s, FALSE, FALSE,
3910 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3913 Ytank_sB, FALSE, TRUE,
3914 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3917 Ytank_w, FALSE, FALSE,
3918 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3921 Ytank_wB, FALSE, TRUE,
3922 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3925 Ytank_w_n, FALSE, FALSE,
3926 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3929 Ytank_n_e, FALSE, FALSE,
3930 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3933 Ytank_e_s, FALSE, FALSE,
3934 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3937 Ytank_s_w, FALSE, FALSE,
3938 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3941 Ytank_e_n, FALSE, FALSE,
3942 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3945 Ytank_s_e, FALSE, FALSE,
3946 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3949 Ytank_w_s, FALSE, FALSE,
3950 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3953 Ytank_n_w, FALSE, FALSE,
3954 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3957 Ytank_stone, FALSE, FALSE,
3958 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
3961 Ytank_spring, FALSE, FALSE,
3962 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
3965 Xandroid, TRUE, FALSE,
3966 EL_EMC_ANDROID, ACTION_ACTIVE, -1
3969 Xandroid_1_n, FALSE, FALSE,
3970 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3973 Xandroid_2_n, FALSE, FALSE,
3974 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3977 Xandroid_1_e, FALSE, FALSE,
3978 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3981 Xandroid_2_e, FALSE, FALSE,
3982 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3985 Xandroid_1_w, FALSE, FALSE,
3986 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3989 Xandroid_2_w, FALSE, FALSE,
3990 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3993 Xandroid_1_s, FALSE, FALSE,
3994 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3997 Xandroid_2_s, FALSE, FALSE,
3998 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
4001 Yandroid_n, FALSE, FALSE,
4002 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
4005 Yandroid_nB, FALSE, TRUE,
4006 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
4009 Yandroid_ne, FALSE, FALSE,
4010 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
4013 Yandroid_neB, FALSE, TRUE,
4014 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
4017 Yandroid_e, FALSE, FALSE,
4018 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
4021 Yandroid_eB, FALSE, TRUE,
4022 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
4025 Yandroid_se, FALSE, FALSE,
4026 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
4029 Yandroid_seB, FALSE, TRUE,
4030 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
4033 Yandroid_s, FALSE, FALSE,
4034 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
4037 Yandroid_sB, FALSE, TRUE,
4038 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
4041 Yandroid_sw, FALSE, FALSE,
4042 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
4045 Yandroid_swB, FALSE, TRUE,
4046 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
4049 Yandroid_w, FALSE, FALSE,
4050 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
4053 Yandroid_wB, FALSE, TRUE,
4054 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
4057 Yandroid_nw, FALSE, FALSE,
4058 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
4061 Yandroid_nwB, FALSE, TRUE,
4062 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
4065 Xspring, TRUE, FALSE,
4069 Xspring_pause, FALSE, FALSE,
4073 Xspring_e, FALSE, FALSE,
4077 Xspring_w, FALSE, FALSE,
4081 Xspring_fall, FALSE, FALSE,
4085 Yspring_s, FALSE, FALSE,
4086 EL_SPRING, ACTION_FALLING, -1
4089 Yspring_sB, FALSE, TRUE,
4090 EL_SPRING, ACTION_FALLING, -1
4093 Yspring_e, FALSE, FALSE,
4094 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
4097 Yspring_eB, FALSE, TRUE,
4098 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
4101 Yspring_w, FALSE, FALSE,
4102 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
4105 Yspring_wB, FALSE, TRUE,
4106 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
4109 Yspring_kill_e, FALSE, FALSE,
4110 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
4113 Yspring_kill_eB, FALSE, TRUE,
4114 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
4117 Yspring_kill_w, FALSE, FALSE,
4118 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
4121 Yspring_kill_wB, FALSE, TRUE,
4122 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
4125 Xeater_n, TRUE, FALSE,
4126 EL_YAMYAM_UP, -1, -1
4129 Xeater_e, TRUE, FALSE,
4130 EL_YAMYAM_RIGHT, -1, -1
4133 Xeater_w, TRUE, FALSE,
4134 EL_YAMYAM_LEFT, -1, -1
4137 Xeater_s, TRUE, FALSE,
4138 EL_YAMYAM_DOWN, -1, -1
4141 Yeater_n, FALSE, FALSE,
4142 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
4145 Yeater_nB, FALSE, TRUE,
4146 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
4149 Yeater_e, FALSE, FALSE,
4150 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
4153 Yeater_eB, FALSE, TRUE,
4154 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
4157 Yeater_s, FALSE, FALSE,
4158 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
4161 Yeater_sB, FALSE, TRUE,
4162 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
4165 Yeater_w, FALSE, FALSE,
4166 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
4169 Yeater_wB, FALSE, TRUE,
4170 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
4173 Yeater_stone, FALSE, FALSE,
4174 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
4177 Yeater_spring, FALSE, FALSE,
4178 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
4181 Xalien, TRUE, FALSE,
4185 Xalien_pause, FALSE, FALSE,
4189 Yalien_n, FALSE, FALSE,
4190 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
4193 Yalien_nB, FALSE, TRUE,
4194 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
4197 Yalien_e, FALSE, FALSE,
4198 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
4201 Yalien_eB, FALSE, TRUE,
4202 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
4205 Yalien_s, FALSE, FALSE,
4206 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
4209 Yalien_sB, FALSE, TRUE,
4210 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
4213 Yalien_w, FALSE, FALSE,
4214 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
4217 Yalien_wB, FALSE, TRUE,
4218 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
4221 Yalien_stone, FALSE, FALSE,
4222 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
4225 Yalien_spring, FALSE, FALSE,
4226 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
4229 Xemerald, TRUE, FALSE,
4233 Xemerald_pause, FALSE, FALSE,
4237 Xemerald_fall, FALSE, FALSE,
4241 Xemerald_shine, FALSE, FALSE,
4242 EL_EMERALD, ACTION_TWINKLING, -1
4245 Yemerald_s, FALSE, FALSE,
4246 EL_EMERALD, ACTION_FALLING, -1
4249 Yemerald_sB, FALSE, TRUE,
4250 EL_EMERALD, ACTION_FALLING, -1
4253 Yemerald_e, FALSE, FALSE,
4254 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
4257 Yemerald_eB, FALSE, TRUE,
4258 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
4261 Yemerald_w, FALSE, FALSE,
4262 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
4265 Yemerald_wB, FALSE, TRUE,
4266 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
4269 Yemerald_eat, FALSE, FALSE,
4270 EL_EMERALD, ACTION_COLLECTING, -1
4273 Yemerald_stone, FALSE, FALSE,
4274 EL_NUT, ACTION_BREAKING, -1
4277 Xdiamond, TRUE, FALSE,
4281 Xdiamond_pause, FALSE, FALSE,
4285 Xdiamond_fall, FALSE, FALSE,
4289 Xdiamond_shine, FALSE, FALSE,
4290 EL_DIAMOND, ACTION_TWINKLING, -1
4293 Ydiamond_s, FALSE, FALSE,
4294 EL_DIAMOND, ACTION_FALLING, -1
4297 Ydiamond_sB, FALSE, TRUE,
4298 EL_DIAMOND, ACTION_FALLING, -1
4301 Ydiamond_e, FALSE, FALSE,
4302 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
4305 Ydiamond_eB, FALSE, TRUE,
4306 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
4309 Ydiamond_w, FALSE, FALSE,
4310 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
4313 Ydiamond_wB, FALSE, TRUE,
4314 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
4317 Ydiamond_eat, FALSE, FALSE,
4318 EL_DIAMOND, ACTION_COLLECTING, -1
4321 Ydiamond_stone, FALSE, FALSE,
4322 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
4325 Xdrip_fall, TRUE, FALSE,
4326 EL_AMOEBA_DROP, -1, -1
4329 Xdrip_stretch, FALSE, FALSE,
4330 EL_AMOEBA_DROP, ACTION_FALLING, -1
4333 Xdrip_stretchB, FALSE, TRUE,
4334 EL_AMOEBA_DROP, ACTION_FALLING, -1
4337 Xdrip_eat, FALSE, FALSE,
4338 EL_AMOEBA_DROP, ACTION_GROWING, -1
4341 Ydrip_s1, FALSE, FALSE,
4342 EL_AMOEBA_DROP, ACTION_FALLING, -1
4345 Ydrip_s1B, FALSE, TRUE,
4346 EL_AMOEBA_DROP, ACTION_FALLING, -1
4349 Ydrip_s2, FALSE, FALSE,
4350 EL_AMOEBA_DROP, ACTION_FALLING, -1
4353 Ydrip_s2B, FALSE, TRUE,
4354 EL_AMOEBA_DROP, ACTION_FALLING, -1
4361 Xbomb_pause, FALSE, FALSE,
4365 Xbomb_fall, FALSE, FALSE,
4369 Ybomb_s, FALSE, FALSE,
4370 EL_BOMB, ACTION_FALLING, -1
4373 Ybomb_sB, FALSE, TRUE,
4374 EL_BOMB, ACTION_FALLING, -1
4377 Ybomb_e, FALSE, FALSE,
4378 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
4381 Ybomb_eB, FALSE, TRUE,
4382 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
4385 Ybomb_w, FALSE, FALSE,
4386 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
4389 Ybomb_wB, FALSE, TRUE,
4390 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
4393 Ybomb_eat, FALSE, FALSE,
4394 EL_BOMB, ACTION_ACTIVATING, -1
4397 Xballoon, TRUE, FALSE,
4401 Yballoon_n, FALSE, FALSE,
4402 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
4405 Yballoon_nB, FALSE, TRUE,
4406 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
4409 Yballoon_e, FALSE, FALSE,
4410 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
4413 Yballoon_eB, FALSE, TRUE,
4414 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
4417 Yballoon_s, FALSE, FALSE,
4418 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
4421 Yballoon_sB, FALSE, TRUE,
4422 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
4425 Yballoon_w, FALSE, FALSE,
4426 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
4429 Yballoon_wB, FALSE, TRUE,
4430 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
4433 Xgrass, TRUE, FALSE,
4434 EL_EMC_GRASS, -1, -1
4437 Ygrass_nB, FALSE, FALSE,
4438 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
4441 Ygrass_eB, FALSE, FALSE,
4442 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
4445 Ygrass_sB, FALSE, FALSE,
4446 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
4449 Ygrass_wB, FALSE, FALSE,
4450 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
4457 Ydirt_nB, FALSE, FALSE,
4458 EL_SAND, ACTION_DIGGING, MV_BIT_UP
4461 Ydirt_eB, FALSE, FALSE,
4462 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
4465 Ydirt_sB, FALSE, FALSE,
4466 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
4469 Ydirt_wB, FALSE, FALSE,
4470 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
4473 Xacid_ne, TRUE, FALSE,
4474 EL_ACID_POOL_TOPRIGHT, -1, -1
4477 Xacid_se, TRUE, FALSE,
4478 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
4481 Xacid_s, TRUE, FALSE,
4482 EL_ACID_POOL_BOTTOM, -1, -1
4485 Xacid_sw, TRUE, FALSE,
4486 EL_ACID_POOL_BOTTOMLEFT, -1, -1
4489 Xacid_nw, TRUE, FALSE,
4490 EL_ACID_POOL_TOPLEFT, -1, -1
4493 Xacid_1, TRUE, FALSE,
4497 Xacid_2, FALSE, FALSE,
4501 Xacid_3, FALSE, FALSE,
4505 Xacid_4, FALSE, FALSE,
4509 Xacid_5, FALSE, FALSE,
4513 Xacid_6, FALSE, FALSE,
4517 Xacid_7, FALSE, FALSE,
4521 Xacid_8, FALSE, FALSE,
4525 Xball_1, TRUE, FALSE,
4526 EL_EMC_MAGIC_BALL, -1, -1
4529 Xball_1B, FALSE, FALSE,
4530 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4533 Xball_2, FALSE, FALSE,
4534 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4537 Xball_2B, FALSE, FALSE,
4538 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4541 Yball_eat, FALSE, FALSE,
4542 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
4545 Ykey_1_eat, FALSE, FALSE,
4546 EL_EM_KEY_1, ACTION_COLLECTING, -1
4549 Ykey_2_eat, FALSE, FALSE,
4550 EL_EM_KEY_2, ACTION_COLLECTING, -1
4553 Ykey_3_eat, FALSE, FALSE,
4554 EL_EM_KEY_3, ACTION_COLLECTING, -1
4557 Ykey_4_eat, FALSE, FALSE,
4558 EL_EM_KEY_4, ACTION_COLLECTING, -1
4561 Ykey_5_eat, FALSE, FALSE,
4562 EL_EMC_KEY_5, ACTION_COLLECTING, -1
4565 Ykey_6_eat, FALSE, FALSE,
4566 EL_EMC_KEY_6, ACTION_COLLECTING, -1
4569 Ykey_7_eat, FALSE, FALSE,
4570 EL_EMC_KEY_7, ACTION_COLLECTING, -1
4573 Ykey_8_eat, FALSE, FALSE,
4574 EL_EMC_KEY_8, ACTION_COLLECTING, -1
4577 Ylenses_eat, FALSE, FALSE,
4578 EL_EMC_LENSES, ACTION_COLLECTING, -1
4581 Ymagnify_eat, FALSE, FALSE,
4582 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
4585 Ygrass_eat, FALSE, FALSE,
4586 EL_EMC_GRASS, ACTION_SNAPPING, -1
4589 Ydirt_eat, FALSE, FALSE,
4590 EL_SAND, ACTION_SNAPPING, -1
4593 Xgrow_ns, TRUE, FALSE,
4594 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
4597 Ygrow_ns_eat, FALSE, FALSE,
4598 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
4601 Xgrow_ew, TRUE, FALSE,
4602 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
4605 Ygrow_ew_eat, FALSE, FALSE,
4606 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
4609 Xwonderwall, TRUE, FALSE,
4610 EL_MAGIC_WALL, -1, -1
4613 XwonderwallB, FALSE, FALSE,
4614 EL_MAGIC_WALL, ACTION_ACTIVE, -1
4617 Xamoeba_1, TRUE, FALSE,
4618 EL_AMOEBA_DRY, ACTION_OTHER, -1
4621 Xamoeba_2, FALSE, FALSE,
4622 EL_AMOEBA_DRY, ACTION_OTHER, -1
4625 Xamoeba_3, FALSE, FALSE,
4626 EL_AMOEBA_DRY, ACTION_OTHER, -1
4629 Xamoeba_4, FALSE, FALSE,
4630 EL_AMOEBA_DRY, ACTION_OTHER, -1
4633 Xamoeba_5, TRUE, FALSE,
4634 EL_AMOEBA_WET, ACTION_OTHER, -1
4637 Xamoeba_6, FALSE, FALSE,
4638 EL_AMOEBA_WET, ACTION_OTHER, -1
4641 Xamoeba_7, FALSE, FALSE,
4642 EL_AMOEBA_WET, ACTION_OTHER, -1
4645 Xamoeba_8, FALSE, FALSE,
4646 EL_AMOEBA_WET, ACTION_OTHER, -1
4649 Xdoor_1, TRUE, FALSE,
4650 EL_EM_GATE_1, -1, -1
4653 Xdoor_2, TRUE, FALSE,
4654 EL_EM_GATE_2, -1, -1
4657 Xdoor_3, TRUE, FALSE,
4658 EL_EM_GATE_3, -1, -1
4661 Xdoor_4, TRUE, FALSE,
4662 EL_EM_GATE_4, -1, -1
4665 Xdoor_5, TRUE, FALSE,
4666 EL_EMC_GATE_5, -1, -1
4669 Xdoor_6, TRUE, FALSE,
4670 EL_EMC_GATE_6, -1, -1
4673 Xdoor_7, TRUE, FALSE,
4674 EL_EMC_GATE_7, -1, -1
4677 Xdoor_8, TRUE, FALSE,
4678 EL_EMC_GATE_8, -1, -1
4681 Xkey_1, TRUE, FALSE,
4685 Xkey_2, TRUE, FALSE,
4689 Xkey_3, TRUE, FALSE,
4693 Xkey_4, TRUE, FALSE,
4697 Xkey_5, TRUE, FALSE,
4698 EL_EMC_KEY_5, -1, -1
4701 Xkey_6, TRUE, FALSE,
4702 EL_EMC_KEY_6, -1, -1
4705 Xkey_7, TRUE, FALSE,
4706 EL_EMC_KEY_7, -1, -1
4709 Xkey_8, TRUE, FALSE,
4710 EL_EMC_KEY_8, -1, -1
4713 Xwind_n, TRUE, FALSE,
4714 EL_BALLOON_SWITCH_UP, -1, -1
4717 Xwind_e, TRUE, FALSE,
4718 EL_BALLOON_SWITCH_RIGHT, -1, -1
4721 Xwind_s, TRUE, FALSE,
4722 EL_BALLOON_SWITCH_DOWN, -1, -1
4725 Xwind_w, TRUE, FALSE,
4726 EL_BALLOON_SWITCH_LEFT, -1, -1
4729 Xwind_nesw, TRUE, FALSE,
4730 EL_BALLOON_SWITCH_ANY, -1, -1
4733 Xwind_stop, TRUE, FALSE,
4734 EL_BALLOON_SWITCH_NONE, -1, -1
4738 EL_EM_EXIT_CLOSED, -1, -1
4741 Xexit_1, TRUE, FALSE,
4742 EL_EM_EXIT_OPEN, -1, -1
4745 Xexit_2, FALSE, FALSE,
4746 EL_EM_EXIT_OPEN, -1, -1
4749 Xexit_3, FALSE, FALSE,
4750 EL_EM_EXIT_OPEN, -1, -1
4753 Xdynamite, TRUE, FALSE,
4754 EL_EM_DYNAMITE, -1, -1
4757 Ydynamite_eat, FALSE, FALSE,
4758 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
4761 Xdynamite_1, TRUE, FALSE,
4762 EL_EM_DYNAMITE_ACTIVE, -1, -1
4765 Xdynamite_2, FALSE, FALSE,
4766 EL_EM_DYNAMITE_ACTIVE, -1, -1
4769 Xdynamite_3, FALSE, FALSE,
4770 EL_EM_DYNAMITE_ACTIVE, -1, -1
4773 Xdynamite_4, FALSE, FALSE,
4774 EL_EM_DYNAMITE_ACTIVE, -1, -1
4777 Xbumper, TRUE, FALSE,
4778 EL_EMC_SPRING_BUMPER, -1, -1
4781 XbumperB, FALSE, FALSE,
4782 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
4785 Xwheel, TRUE, FALSE,
4786 EL_ROBOT_WHEEL, -1, -1
4789 XwheelB, FALSE, FALSE,
4790 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
4793 Xswitch, TRUE, FALSE,
4794 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
4797 XswitchB, FALSE, FALSE,
4798 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
4802 EL_QUICKSAND_EMPTY, -1, -1
4805 Xsand_stone, TRUE, FALSE,
4806 EL_QUICKSAND_FULL, -1, -1
4809 Xsand_stonein_1, FALSE, TRUE,
4810 EL_ROCK, ACTION_FILLING, -1
4813 Xsand_stonein_2, FALSE, TRUE,
4814 EL_ROCK, ACTION_FILLING, -1
4817 Xsand_stonein_3, FALSE, TRUE,
4818 EL_ROCK, ACTION_FILLING, -1
4821 Xsand_stonein_4, FALSE, TRUE,
4822 EL_ROCK, ACTION_FILLING, -1
4825 Xsand_stonesand_1, FALSE, FALSE,
4826 EL_QUICKSAND_FULL, -1, -1
4829 Xsand_stonesand_2, FALSE, FALSE,
4830 EL_QUICKSAND_FULL, -1, -1
4833 Xsand_stonesand_3, FALSE, FALSE,
4834 EL_QUICKSAND_FULL, -1, -1
4837 Xsand_stonesand_4, FALSE, FALSE,
4838 EL_QUICKSAND_FULL, -1, -1
4841 Xsand_stoneout_1, FALSE, FALSE,
4842 EL_ROCK, ACTION_EMPTYING, -1
4845 Xsand_stoneout_2, FALSE, FALSE,
4846 EL_ROCK, ACTION_EMPTYING, -1
4849 Xsand_sandstone_1, FALSE, FALSE,
4850 EL_QUICKSAND_FULL, -1, -1
4853 Xsand_sandstone_2, FALSE, FALSE,
4854 EL_QUICKSAND_FULL, -1, -1
4857 Xsand_sandstone_3, FALSE, FALSE,
4858 EL_QUICKSAND_FULL, -1, -1
4861 Xsand_sandstone_4, FALSE, FALSE,
4862 EL_QUICKSAND_FULL, -1, -1
4865 Xplant, TRUE, FALSE,
4866 EL_EMC_PLANT, -1, -1
4869 Yplant, FALSE, FALSE,
4870 EL_EMC_PLANT, -1, -1
4873 Xlenses, TRUE, FALSE,
4874 EL_EMC_LENSES, -1, -1
4877 Xmagnify, TRUE, FALSE,
4878 EL_EMC_MAGNIFIER, -1, -1
4881 Xdripper, TRUE, FALSE,
4882 EL_EMC_DRIPPER, -1, -1
4885 XdripperB, FALSE, FALSE,
4886 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
4889 Xfake_blank, TRUE, FALSE,
4890 EL_INVISIBLE_WALL, -1, -1
4893 Xfake_blankB, FALSE, FALSE,
4894 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
4897 Xfake_grass, TRUE, FALSE,
4898 EL_EMC_FAKE_GRASS, -1, -1
4901 Xfake_grassB, FALSE, FALSE,
4902 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
4905 Xfake_door_1, TRUE, FALSE,
4906 EL_EM_GATE_1_GRAY, -1, -1
4909 Xfake_door_2, TRUE, FALSE,
4910 EL_EM_GATE_2_GRAY, -1, -1
4913 Xfake_door_3, TRUE, FALSE,
4914 EL_EM_GATE_3_GRAY, -1, -1
4917 Xfake_door_4, TRUE, FALSE,
4918 EL_EM_GATE_4_GRAY, -1, -1
4921 Xfake_door_5, TRUE, FALSE,
4922 EL_EMC_GATE_5_GRAY, -1, -1
4925 Xfake_door_6, TRUE, FALSE,
4926 EL_EMC_GATE_6_GRAY, -1, -1
4929 Xfake_door_7, TRUE, FALSE,
4930 EL_EMC_GATE_7_GRAY, -1, -1
4933 Xfake_door_8, TRUE, FALSE,
4934 EL_EMC_GATE_8_GRAY, -1, -1
4937 Xfake_acid_1, TRUE, FALSE,
4938 EL_EMC_FAKE_ACID, -1, -1
4941 Xfake_acid_2, FALSE, FALSE,
4942 EL_EMC_FAKE_ACID, -1, -1
4945 Xfake_acid_3, FALSE, FALSE,
4946 EL_EMC_FAKE_ACID, -1, -1
4949 Xfake_acid_4, FALSE, FALSE,
4950 EL_EMC_FAKE_ACID, -1, -1
4953 Xfake_acid_5, FALSE, FALSE,
4954 EL_EMC_FAKE_ACID, -1, -1
4957 Xfake_acid_6, FALSE, FALSE,
4958 EL_EMC_FAKE_ACID, -1, -1
4961 Xfake_acid_7, FALSE, FALSE,
4962 EL_EMC_FAKE_ACID, -1, -1
4965 Xfake_acid_8, FALSE, FALSE,
4966 EL_EMC_FAKE_ACID, -1, -1
4969 Xsteel_1, TRUE, FALSE,
4970 EL_STEELWALL, -1, -1
4973 Xsteel_2, TRUE, FALSE,
4974 EL_EMC_STEELWALL_2, -1, -1
4977 Xsteel_3, TRUE, FALSE,
4978 EL_EMC_STEELWALL_3, -1, -1
4981 Xsteel_4, TRUE, FALSE,
4982 EL_EMC_STEELWALL_4, -1, -1
4985 Xwall_1, TRUE, FALSE,
4989 Xwall_2, TRUE, FALSE,
4990 EL_EMC_WALL_14, -1, -1
4993 Xwall_3, TRUE, FALSE,
4994 EL_EMC_WALL_15, -1, -1
4997 Xwall_4, TRUE, FALSE,
4998 EL_EMC_WALL_16, -1, -1
5001 Xround_wall_1, TRUE, FALSE,
5002 EL_WALL_SLIPPERY, -1, -1
5005 Xround_wall_2, TRUE, FALSE,
5006 EL_EMC_WALL_SLIPPERY_2, -1, -1
5009 Xround_wall_3, TRUE, FALSE,
5010 EL_EMC_WALL_SLIPPERY_3, -1, -1
5013 Xround_wall_4, TRUE, FALSE,
5014 EL_EMC_WALL_SLIPPERY_4, -1, -1
5017 Xdecor_1, TRUE, FALSE,
5018 EL_EMC_WALL_8, -1, -1
5021 Xdecor_2, TRUE, FALSE,
5022 EL_EMC_WALL_6, -1, -1
5025 Xdecor_3, TRUE, FALSE,
5026 EL_EMC_WALL_4, -1, -1
5029 Xdecor_4, TRUE, FALSE,
5030 EL_EMC_WALL_7, -1, -1
5033 Xdecor_5, TRUE, FALSE,
5034 EL_EMC_WALL_5, -1, -1
5037 Xdecor_6, TRUE, FALSE,
5038 EL_EMC_WALL_9, -1, -1
5041 Xdecor_7, TRUE, FALSE,
5042 EL_EMC_WALL_10, -1, -1
5045 Xdecor_8, TRUE, FALSE,
5046 EL_EMC_WALL_1, -1, -1
5049 Xdecor_9, TRUE, FALSE,
5050 EL_EMC_WALL_2, -1, -1
5053 Xdecor_10, TRUE, FALSE,
5054 EL_EMC_WALL_3, -1, -1
5057 Xdecor_11, TRUE, FALSE,
5058 EL_EMC_WALL_11, -1, -1
5061 Xdecor_12, TRUE, FALSE,
5062 EL_EMC_WALL_12, -1, -1
5065 Xalpha_0, TRUE, FALSE,
5066 EL_CHAR('0'), -1, -1
5069 Xalpha_1, TRUE, FALSE,
5070 EL_CHAR('1'), -1, -1
5073 Xalpha_2, TRUE, FALSE,
5074 EL_CHAR('2'), -1, -1
5077 Xalpha_3, TRUE, FALSE,
5078 EL_CHAR('3'), -1, -1
5081 Xalpha_4, TRUE, FALSE,
5082 EL_CHAR('4'), -1, -1
5085 Xalpha_5, TRUE, FALSE,
5086 EL_CHAR('5'), -1, -1
5089 Xalpha_6, TRUE, FALSE,
5090 EL_CHAR('6'), -1, -1
5093 Xalpha_7, TRUE, FALSE,
5094 EL_CHAR('7'), -1, -1
5097 Xalpha_8, TRUE, FALSE,
5098 EL_CHAR('8'), -1, -1
5101 Xalpha_9, TRUE, FALSE,
5102 EL_CHAR('9'), -1, -1
5105 Xalpha_excla, TRUE, FALSE,
5106 EL_CHAR('!'), -1, -1
5109 Xalpha_quote, TRUE, FALSE,
5110 EL_CHAR('"'), -1, -1
5113 Xalpha_comma, TRUE, FALSE,
5114 EL_CHAR(','), -1, -1
5117 Xalpha_minus, TRUE, FALSE,
5118 EL_CHAR('-'), -1, -1
5121 Xalpha_perio, TRUE, FALSE,
5122 EL_CHAR('.'), -1, -1
5125 Xalpha_colon, TRUE, FALSE,
5126 EL_CHAR(':'), -1, -1
5129 Xalpha_quest, TRUE, FALSE,
5130 EL_CHAR('?'), -1, -1
5133 Xalpha_a, TRUE, FALSE,
5134 EL_CHAR('A'), -1, -1
5137 Xalpha_b, TRUE, FALSE,
5138 EL_CHAR('B'), -1, -1
5141 Xalpha_c, TRUE, FALSE,
5142 EL_CHAR('C'), -1, -1
5145 Xalpha_d, TRUE, FALSE,
5146 EL_CHAR('D'), -1, -1
5149 Xalpha_e, TRUE, FALSE,
5150 EL_CHAR('E'), -1, -1
5153 Xalpha_f, TRUE, FALSE,
5154 EL_CHAR('F'), -1, -1
5157 Xalpha_g, TRUE, FALSE,
5158 EL_CHAR('G'), -1, -1
5161 Xalpha_h, TRUE, FALSE,
5162 EL_CHAR('H'), -1, -1
5165 Xalpha_i, TRUE, FALSE,
5166 EL_CHAR('I'), -1, -1
5169 Xalpha_j, TRUE, FALSE,
5170 EL_CHAR('J'), -1, -1
5173 Xalpha_k, TRUE, FALSE,
5174 EL_CHAR('K'), -1, -1
5177 Xalpha_l, TRUE, FALSE,
5178 EL_CHAR('L'), -1, -1
5181 Xalpha_m, TRUE, FALSE,
5182 EL_CHAR('M'), -1, -1
5185 Xalpha_n, TRUE, FALSE,
5186 EL_CHAR('N'), -1, -1
5189 Xalpha_o, TRUE, FALSE,
5190 EL_CHAR('O'), -1, -1
5193 Xalpha_p, TRUE, FALSE,
5194 EL_CHAR('P'), -1, -1
5197 Xalpha_q, TRUE, FALSE,
5198 EL_CHAR('Q'), -1, -1
5201 Xalpha_r, TRUE, FALSE,
5202 EL_CHAR('R'), -1, -1
5205 Xalpha_s, TRUE, FALSE,
5206 EL_CHAR('S'), -1, -1
5209 Xalpha_t, TRUE, FALSE,
5210 EL_CHAR('T'), -1, -1
5213 Xalpha_u, TRUE, FALSE,
5214 EL_CHAR('U'), -1, -1
5217 Xalpha_v, TRUE, FALSE,
5218 EL_CHAR('V'), -1, -1
5221 Xalpha_w, TRUE, FALSE,
5222 EL_CHAR('W'), -1, -1
5225 Xalpha_x, TRUE, FALSE,
5226 EL_CHAR('X'), -1, -1
5229 Xalpha_y, TRUE, FALSE,
5230 EL_CHAR('Y'), -1, -1
5233 Xalpha_z, TRUE, FALSE,
5234 EL_CHAR('Z'), -1, -1
5237 Xalpha_arrow_e, TRUE, FALSE,
5238 EL_CHAR('>'), -1, -1
5241 Xalpha_arrow_w, TRUE, FALSE,
5242 EL_CHAR('<'), -1, -1
5245 Xalpha_copyr, TRUE, FALSE,
5246 EL_CHAR('©'), -1, -1
5250 Xboom_bug, FALSE, FALSE,
5251 EL_BUG, ACTION_EXPLODING, -1
5254 Xboom_bomb, FALSE, FALSE,
5255 EL_BOMB, ACTION_EXPLODING, -1
5258 Xboom_android, FALSE, FALSE,
5259 EL_EMC_ANDROID, ACTION_OTHER, -1
5262 Xboom_1, FALSE, FALSE,
5263 EL_DEFAULT, ACTION_EXPLODING, -1
5266 Xboom_2, FALSE, FALSE,
5267 EL_DEFAULT, ACTION_EXPLODING, -1
5270 Znormal, FALSE, FALSE,
5274 Zdynamite, FALSE, FALSE,
5278 Zplayer, FALSE, FALSE,
5282 ZBORDER, FALSE, FALSE,
5292 static struct Mapping_EM_to_RND_player
5301 em_player_mapping_list[] =
5305 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
5309 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
5313 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
5317 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
5321 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
5325 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
5329 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
5333 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
5337 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
5341 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
5345 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
5349 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
5353 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
5357 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
5361 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
5365 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
5369 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
5373 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
5377 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
5381 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
5385 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
5389 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
5393 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
5397 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
5401 EL_PLAYER_1, ACTION_DEFAULT, -1,
5405 EL_PLAYER_2, ACTION_DEFAULT, -1,
5409 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
5413 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
5417 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
5421 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
5425 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
5429 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
5433 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
5437 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
5441 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
5445 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
5449 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
5453 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
5457 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
5461 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
5465 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
5469 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
5473 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
5477 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
5481 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
5485 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
5489 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
5493 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
5497 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
5501 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
5505 EL_PLAYER_3, ACTION_DEFAULT, -1,
5509 EL_PLAYER_4, ACTION_DEFAULT, -1,
5518 int map_element_RND_to_EM(int element_rnd)
5520 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
5521 static boolean mapping_initialized = FALSE;
5523 if (!mapping_initialized)
5527 /* return "Xalpha_quest" for all undefined elements in mapping array */
5528 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
5529 mapping_RND_to_EM[i] = Xalpha_quest;
5531 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5532 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
5533 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
5534 em_object_mapping_list[i].element_em;
5536 mapping_initialized = TRUE;
5539 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
5540 return mapping_RND_to_EM[element_rnd];
5542 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
5547 int map_element_EM_to_RND(int element_em)
5549 static unsigned short mapping_EM_to_RND[TILE_MAX];
5550 static boolean mapping_initialized = FALSE;
5552 if (!mapping_initialized)
5556 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
5557 for (i = 0; i < TILE_MAX; i++)
5558 mapping_EM_to_RND[i] = EL_UNKNOWN;
5560 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5561 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
5562 em_object_mapping_list[i].element_rnd;
5564 mapping_initialized = TRUE;
5567 if (element_em >= 0 && element_em < TILE_MAX)
5568 return mapping_EM_to_RND[element_em];
5570 Error(ERR_WARN, "invalid EM level element %d", element_em);
5575 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
5577 struct LevelInfo_EM *level_em = level->native_em_level;
5578 struct LEVEL *lev = level_em->lev;
5581 for (i = 0; i < TILE_MAX; i++)
5582 lev->android_array[i] = Xblank;
5584 for (i = 0; i < level->num_android_clone_elements; i++)
5586 int element_rnd = level->android_clone_element[i];
5587 int element_em = map_element_RND_to_EM(element_rnd);
5589 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
5590 if (em_object_mapping_list[j].element_rnd == element_rnd)
5591 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
5595 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
5597 struct LevelInfo_EM *level_em = level->native_em_level;
5598 struct LEVEL *lev = level_em->lev;
5601 level->num_android_clone_elements = 0;
5603 for (i = 0; i < TILE_MAX; i++)
5605 int element_em = lev->android_array[i];
5607 boolean element_found = FALSE;
5609 if (element_em == Xblank)
5612 element_rnd = map_element_EM_to_RND(element_em);
5614 for (j = 0; j < level->num_android_clone_elements; j++)
5615 if (level->android_clone_element[j] == element_rnd)
5616 element_found = TRUE;
5620 level->android_clone_element[level->num_android_clone_elements++] =
5623 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
5628 if (level->num_android_clone_elements == 0)
5630 level->num_android_clone_elements = 1;
5631 level->android_clone_element[0] = EL_EMPTY;
5635 int map_direction_RND_to_EM(int direction)
5637 return (direction == MV_UP ? 0 :
5638 direction == MV_RIGHT ? 1 :
5639 direction == MV_DOWN ? 2 :
5640 direction == MV_LEFT ? 3 :
5644 int map_direction_EM_to_RND(int direction)
5646 return (direction == 0 ? MV_UP :
5647 direction == 1 ? MV_RIGHT :
5648 direction == 2 ? MV_DOWN :
5649 direction == 3 ? MV_LEFT :
5653 int get_next_element(int element)
5657 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
5658 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
5659 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
5660 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
5661 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
5662 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
5663 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
5664 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
5665 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
5666 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
5667 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
5669 default: return element;
5674 int el_act_dir2img(int element, int action, int direction)
5676 element = GFX_ELEMENT(element);
5678 if (direction == MV_NONE)
5679 return element_info[element].graphic[action];
5681 direction = MV_DIR_TO_BIT(direction);
5683 return element_info[element].direction_graphic[action][direction];
5686 int el_act_dir2img(int element, int action, int direction)
5688 element = GFX_ELEMENT(element);
5689 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5691 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5692 return element_info[element].direction_graphic[action][direction];
5697 static int el_act_dir2crm(int element, int action, int direction)
5699 element = GFX_ELEMENT(element);
5701 if (direction == MV_NONE)
5702 return element_info[element].crumbled[action];
5704 direction = MV_DIR_TO_BIT(direction);
5706 return element_info[element].direction_crumbled[action][direction];
5709 static int el_act_dir2crm(int element, int action, int direction)
5711 element = GFX_ELEMENT(element);
5712 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5714 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5715 return element_info[element].direction_crumbled[action][direction];
5719 int el_act2img(int element, int action)
5721 element = GFX_ELEMENT(element);
5723 return element_info[element].graphic[action];
5726 int el_act2crm(int element, int action)
5728 element = GFX_ELEMENT(element);
5730 return element_info[element].crumbled[action];
5733 int el_dir2img(int element, int direction)
5735 element = GFX_ELEMENT(element);
5737 return el_act_dir2img(element, ACTION_DEFAULT, direction);
5740 int el2baseimg(int element)
5742 return element_info[element].graphic[ACTION_DEFAULT];
5745 int el2img(int element)
5747 element = GFX_ELEMENT(element);
5749 return element_info[element].graphic[ACTION_DEFAULT];
5752 int el2edimg(int element)
5754 element = GFX_ELEMENT(element);
5756 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
5759 int el2preimg(int element)
5761 element = GFX_ELEMENT(element);
5763 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
5766 int el2panelimg(int element)
5768 element = GFX_ELEMENT(element);
5770 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL];
5773 int font2baseimg(int font_nr)
5775 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
5778 int getBeltNrFromBeltElement(int element)
5780 return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
5781 element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
5782 element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
5785 int getBeltNrFromBeltActiveElement(int element)
5787 return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
5788 element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
5789 element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
5792 int getBeltNrFromBeltSwitchElement(int element)
5794 return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
5795 element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
5796 element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
5799 int getBeltDirNrFromBeltElement(int element)
5801 static int belt_base_element[4] =
5803 EL_CONVEYOR_BELT_1_LEFT,
5804 EL_CONVEYOR_BELT_2_LEFT,
5805 EL_CONVEYOR_BELT_3_LEFT,
5806 EL_CONVEYOR_BELT_4_LEFT
5809 int belt_nr = getBeltNrFromBeltElement(element);
5810 int belt_dir_nr = element - belt_base_element[belt_nr];
5812 return (belt_dir_nr % 3);
5815 int getBeltDirNrFromBeltSwitchElement(int element)
5817 static int belt_base_element[4] =
5819 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
5820 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
5821 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
5822 EL_CONVEYOR_BELT_4_SWITCH_LEFT
5825 int belt_nr = getBeltNrFromBeltSwitchElement(element);
5826 int belt_dir_nr = element - belt_base_element[belt_nr];
5828 return (belt_dir_nr % 3);
5831 int getBeltDirFromBeltElement(int element)
5833 static int belt_move_dir[3] =
5840 int belt_dir_nr = getBeltDirNrFromBeltElement(element);
5842 return belt_move_dir[belt_dir_nr];
5845 int getBeltDirFromBeltSwitchElement(int element)
5847 static int belt_move_dir[3] =
5854 int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
5856 return belt_move_dir[belt_dir_nr];
5859 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
5861 static int belt_base_element[4] =
5863 EL_CONVEYOR_BELT_1_LEFT,
5864 EL_CONVEYOR_BELT_2_LEFT,
5865 EL_CONVEYOR_BELT_3_LEFT,
5866 EL_CONVEYOR_BELT_4_LEFT
5868 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
5870 return belt_base_element[belt_nr] + belt_dir_nr;
5873 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
5875 static int belt_base_element[4] =
5877 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
5878 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
5879 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
5880 EL_CONVEYOR_BELT_4_SWITCH_LEFT
5882 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
5884 return belt_base_element[belt_nr] + belt_dir_nr;
5887 int getNumActivePlayers_EM()
5889 int num_players = 0;
5895 for (i = 0; i < MAX_PLAYERS; i++)
5896 if (tape.player_participates[i])
5902 int getGameFrameDelay_EM(int native_em_game_frame_delay)
5904 int game_frame_delay_value;
5906 game_frame_delay_value =
5907 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
5908 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
5911 if (tape.playing && tape.warp_forward && !tape.pausing)
5912 game_frame_delay_value = 0;
5914 return game_frame_delay_value;
5917 unsigned int InitRND(long seed)
5919 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
5920 return InitEngineRandom_EM(seed);
5922 return InitEngineRandom_RND(seed);
5926 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
5927 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
5930 void ResetGfxAnimation_EM(int x, int y, int tile)
5935 void getGraphicSourceObjectExt_EM(int tile, int frame_em,
5936 Bitmap **src_bitmap, int *src_x, int *src_y,
5939 int element = object_mapping[tile].element_rnd;
5940 int action = object_mapping[tile].action;
5941 int direction = object_mapping[tile].direction;
5942 boolean is_backside = object_mapping[tile].is_backside;
5943 boolean action_removing = (action == ACTION_DIGGING ||
5944 action == ACTION_SNAPPING ||
5945 action == ACTION_COLLECTING);
5946 int effective_element = (frame_em > 0 ? element :
5947 is_backside ? EL_EMPTY :
5948 action_removing ? EL_EMPTY :
5950 int graphic = (direction == MV_NONE ?
5951 el_act2img(effective_element, action) :
5952 el_act_dir2img(effective_element, action, direction));
5953 struct GraphicInfo *g = &graphic_info[graphic];
5956 if (graphic_info[graphic].anim_global_sync)
5957 sync_frame = FrameCounter;
5959 sync_frame = 7 - frame_em;
5961 SetRandomAnimationValue(x, y);
5963 int frame = getAnimationFrame(g->anim_frames,
5966 g->anim_start_frame,
5969 getGraphicSourceExt(graphic, frame, src_bitmap, src_x, src_y, FALSE);
5972 void getGraphicSourcePlayerExt_EM(int player_nr, int anim, int frame_em,
5973 Bitmap **src_bitmap, int *src_x, int *src_y)
5975 int element = player_mapping[player_nr][anim].element_rnd;
5976 int action = player_mapping[player_nr][anim].action;
5977 int direction = player_mapping[player_nr][anim].direction;
5978 int graphic = (direction == MV_NONE ?
5979 el_act2img(element, action) :
5980 el_act_dir2img(element, action, direction));
5981 struct GraphicInfo *g = &graphic_info[graphic];
5984 InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
5986 stored_player[player_nr].StepFrame = 7 - frame_em;
5988 sync_frame = stored_player[player_nr].Frame;
5991 printf("::: %d: %d, %d [%d]\n",
5993 stored_player[player_nr].Frame,
5994 stored_player[player_nr].StepFrame,
5998 int frame = getAnimationFrame(g->anim_frames,
6001 g->anim_start_frame,
6004 getGraphicSourceExt(graphic, frame, src_bitmap, src_x, src_y, FALSE);
6007 void InitGraphicInfo_EM(void)
6010 struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
6011 struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
6016 int num_em_gfx_errors = 0;
6018 if (graphic_info_em_object[0][0].bitmap == NULL)
6020 /* EM graphics not yet initialized in em_open_all() */
6025 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
6028 /* always start with reliable default values */
6029 for (i = 0; i < TILE_MAX; i++)
6031 object_mapping[i].element_rnd = EL_UNKNOWN;
6032 object_mapping[i].is_backside = FALSE;
6033 object_mapping[i].action = ACTION_DEFAULT;
6034 object_mapping[i].direction = MV_NONE;
6037 /* always start with reliable default values */
6038 for (p = 0; p < MAX_PLAYERS; p++)
6040 for (i = 0; i < SPR_MAX; i++)
6042 player_mapping[p][i].element_rnd = EL_UNKNOWN;
6043 player_mapping[p][i].action = ACTION_DEFAULT;
6044 player_mapping[p][i].direction = MV_NONE;
6048 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6050 int e = em_object_mapping_list[i].element_em;
6052 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
6053 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
6055 if (em_object_mapping_list[i].action != -1)
6056 object_mapping[e].action = em_object_mapping_list[i].action;
6058 if (em_object_mapping_list[i].direction != -1)
6059 object_mapping[e].direction =
6060 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
6063 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
6065 int a = em_player_mapping_list[i].action_em;
6066 int p = em_player_mapping_list[i].player_nr;
6068 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
6070 if (em_player_mapping_list[i].action != -1)
6071 player_mapping[p][a].action = em_player_mapping_list[i].action;
6073 if (em_player_mapping_list[i].direction != -1)
6074 player_mapping[p][a].direction =
6075 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
6078 for (i = 0; i < TILE_MAX; i++)
6080 int element = object_mapping[i].element_rnd;
6081 int action = object_mapping[i].action;
6082 int direction = object_mapping[i].direction;
6083 boolean is_backside = object_mapping[i].is_backside;
6084 boolean action_removing = (action == ACTION_DIGGING ||
6085 action == ACTION_SNAPPING ||
6086 action == ACTION_COLLECTING);
6087 boolean action_exploding = ((action == ACTION_EXPLODING ||
6088 action == ACTION_SMASHED_BY_ROCK ||
6089 action == ACTION_SMASHED_BY_SPRING) &&
6090 element != EL_DIAMOND);
6091 boolean action_active = (action == ACTION_ACTIVE);
6092 boolean action_other = (action == ACTION_OTHER);
6094 for (j = 0; j < 8; j++)
6096 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
6097 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
6099 i == Xdrip_stretch ? element :
6100 i == Xdrip_stretchB ? element :
6101 i == Ydrip_s1 ? element :
6102 i == Ydrip_s1B ? element :
6103 i == Xball_1B ? element :
6104 i == Xball_2 ? element :
6105 i == Xball_2B ? element :
6106 i == Yball_eat ? element :
6107 i == Ykey_1_eat ? element :
6108 i == Ykey_2_eat ? element :
6109 i == Ykey_3_eat ? element :
6110 i == Ykey_4_eat ? element :
6111 i == Ykey_5_eat ? element :
6112 i == Ykey_6_eat ? element :
6113 i == Ykey_7_eat ? element :
6114 i == Ykey_8_eat ? element :
6115 i == Ylenses_eat ? element :
6116 i == Ymagnify_eat ? element :
6117 i == Ygrass_eat ? element :
6118 i == Ydirt_eat ? element :
6119 i == Yemerald_stone ? EL_EMERALD :
6120 i == Ydiamond_stone ? EL_ROCK :
6121 i == Xsand_stonein_1 ? element :
6122 i == Xsand_stonein_2 ? element :
6123 i == Xsand_stonein_3 ? element :
6124 i == Xsand_stonein_4 ? element :
6125 is_backside ? EL_EMPTY :
6126 action_removing ? EL_EMPTY :
6128 int effective_action = (j < 7 ? action :
6129 i == Xdrip_stretch ? action :
6130 i == Xdrip_stretchB ? action :
6131 i == Ydrip_s1 ? action :
6132 i == Ydrip_s1B ? action :
6133 i == Xball_1B ? action :
6134 i == Xball_2 ? action :
6135 i == Xball_2B ? action :
6136 i == Yball_eat ? action :
6137 i == Ykey_1_eat ? action :
6138 i == Ykey_2_eat ? action :
6139 i == Ykey_3_eat ? action :
6140 i == Ykey_4_eat ? action :
6141 i == Ykey_5_eat ? action :
6142 i == Ykey_6_eat ? action :
6143 i == Ykey_7_eat ? action :
6144 i == Ykey_8_eat ? action :
6145 i == Ylenses_eat ? action :
6146 i == Ymagnify_eat ? action :
6147 i == Ygrass_eat ? action :
6148 i == Ydirt_eat ? action :
6149 i == Xsand_stonein_1 ? action :
6150 i == Xsand_stonein_2 ? action :
6151 i == Xsand_stonein_3 ? action :
6152 i == Xsand_stonein_4 ? action :
6153 i == Xsand_stoneout_1 ? action :
6154 i == Xsand_stoneout_2 ? action :
6155 i == Xboom_android ? ACTION_EXPLODING :
6156 action_exploding ? ACTION_EXPLODING :
6157 action_active ? action :
6158 action_other ? action :
6160 int graphic = (el_act_dir2img(effective_element, effective_action,
6162 int crumbled = (el_act_dir2crm(effective_element, effective_action,
6164 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
6165 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
6166 boolean has_action_graphics = (graphic != base_graphic);
6167 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
6168 struct GraphicInfo *g = &graphic_info[graphic];
6169 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
6172 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
6173 boolean special_animation = (action != ACTION_DEFAULT &&
6174 g->anim_frames == 3 &&
6175 g->anim_delay == 2 &&
6176 g->anim_mode & ANIM_LINEAR);
6177 int sync_frame = (i == Xdrip_stretch ? 7 :
6178 i == Xdrip_stretchB ? 7 :
6179 i == Ydrip_s2 ? j + 8 :
6180 i == Ydrip_s2B ? j + 8 :
6189 i == Xfake_acid_1 ? 0 :
6190 i == Xfake_acid_2 ? 10 :
6191 i == Xfake_acid_3 ? 20 :
6192 i == Xfake_acid_4 ? 30 :
6193 i == Xfake_acid_5 ? 40 :
6194 i == Xfake_acid_6 ? 50 :
6195 i == Xfake_acid_7 ? 60 :
6196 i == Xfake_acid_8 ? 70 :
6198 i == Xball_2B ? j + 8 :
6199 i == Yball_eat ? j + 1 :
6200 i == Ykey_1_eat ? j + 1 :
6201 i == Ykey_2_eat ? j + 1 :
6202 i == Ykey_3_eat ? j + 1 :
6203 i == Ykey_4_eat ? j + 1 :
6204 i == Ykey_5_eat ? j + 1 :
6205 i == Ykey_6_eat ? j + 1 :
6206 i == Ykey_7_eat ? j + 1 :
6207 i == Ykey_8_eat ? j + 1 :
6208 i == Ylenses_eat ? j + 1 :
6209 i == Ymagnify_eat ? j + 1 :
6210 i == Ygrass_eat ? j + 1 :
6211 i == Ydirt_eat ? j + 1 :
6212 i == Xamoeba_1 ? 0 :
6213 i == Xamoeba_2 ? 1 :
6214 i == Xamoeba_3 ? 2 :
6215 i == Xamoeba_4 ? 3 :
6216 i == Xamoeba_5 ? 0 :
6217 i == Xamoeba_6 ? 1 :
6218 i == Xamoeba_7 ? 2 :
6219 i == Xamoeba_8 ? 3 :
6220 i == Xexit_2 ? j + 8 :
6221 i == Xexit_3 ? j + 16 :
6222 i == Xdynamite_1 ? 0 :
6223 i == Xdynamite_2 ? 8 :
6224 i == Xdynamite_3 ? 16 :
6225 i == Xdynamite_4 ? 24 :
6226 i == Xsand_stonein_1 ? j + 1 :
6227 i == Xsand_stonein_2 ? j + 9 :
6228 i == Xsand_stonein_3 ? j + 17 :
6229 i == Xsand_stonein_4 ? j + 25 :
6230 i == Xsand_stoneout_1 && j == 0 ? 0 :
6231 i == Xsand_stoneout_1 && j == 1 ? 0 :
6232 i == Xsand_stoneout_1 && j == 2 ? 1 :
6233 i == Xsand_stoneout_1 && j == 3 ? 2 :
6234 i == Xsand_stoneout_1 && j == 4 ? 2 :
6235 i == Xsand_stoneout_1 && j == 5 ? 3 :
6236 i == Xsand_stoneout_1 && j == 6 ? 4 :
6237 i == Xsand_stoneout_1 && j == 7 ? 4 :
6238 i == Xsand_stoneout_2 && j == 0 ? 5 :
6239 i == Xsand_stoneout_2 && j == 1 ? 6 :
6240 i == Xsand_stoneout_2 && j == 2 ? 7 :
6241 i == Xsand_stoneout_2 && j == 3 ? 8 :
6242 i == Xsand_stoneout_2 && j == 4 ? 9 :
6243 i == Xsand_stoneout_2 && j == 5 ? 11 :
6244 i == Xsand_stoneout_2 && j == 6 ? 13 :
6245 i == Xsand_stoneout_2 && j == 7 ? 15 :
6246 i == Xboom_bug && j == 1 ? 2 :
6247 i == Xboom_bug && j == 2 ? 2 :
6248 i == Xboom_bug && j == 3 ? 4 :
6249 i == Xboom_bug && j == 4 ? 4 :
6250 i == Xboom_bug && j == 5 ? 2 :
6251 i == Xboom_bug && j == 6 ? 2 :
6252 i == Xboom_bug && j == 7 ? 0 :
6253 i == Xboom_bomb && j == 1 ? 2 :
6254 i == Xboom_bomb && j == 2 ? 2 :
6255 i == Xboom_bomb && j == 3 ? 4 :
6256 i == Xboom_bomb && j == 4 ? 4 :
6257 i == Xboom_bomb && j == 5 ? 2 :
6258 i == Xboom_bomb && j == 6 ? 2 :
6259 i == Xboom_bomb && j == 7 ? 0 :
6260 i == Xboom_android && j == 7 ? 6 :
6261 i == Xboom_1 && j == 1 ? 2 :
6262 i == Xboom_1 && j == 2 ? 2 :
6263 i == Xboom_1 && j == 3 ? 4 :
6264 i == Xboom_1 && j == 4 ? 4 :
6265 i == Xboom_1 && j == 5 ? 6 :
6266 i == Xboom_1 && j == 6 ? 6 :
6267 i == Xboom_1 && j == 7 ? 8 :
6268 i == Xboom_2 && j == 0 ? 8 :
6269 i == Xboom_2 && j == 1 ? 8 :
6270 i == Xboom_2 && j == 2 ? 10 :
6271 i == Xboom_2 && j == 3 ? 10 :
6272 i == Xboom_2 && j == 4 ? 10 :
6273 i == Xboom_2 && j == 5 ? 12 :
6274 i == Xboom_2 && j == 6 ? 12 :
6275 i == Xboom_2 && j == 7 ? 12 :
6276 special_animation && j == 4 ? 3 :
6277 effective_action != action ? 0 :
6281 Bitmap *debug_bitmap = g_em->bitmap;
6282 int debug_src_x = g_em->src_x;
6283 int debug_src_y = g_em->src_y;
6286 int frame = getAnimationFrame(g->anim_frames,
6289 g->anim_start_frame,
6292 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
6293 g->double_movement && is_backside);
6295 g_em->bitmap = src_bitmap;
6296 g_em->src_x = src_x;
6297 g_em->src_y = src_y;
6298 g_em->src_offset_x = 0;
6299 g_em->src_offset_y = 0;
6300 g_em->dst_offset_x = 0;
6301 g_em->dst_offset_y = 0;
6302 g_em->width = TILEX;
6303 g_em->height = TILEY;
6305 g_em->crumbled_bitmap = NULL;
6306 g_em->crumbled_src_x = 0;
6307 g_em->crumbled_src_y = 0;
6308 g_em->crumbled_border_size = 0;
6310 g_em->has_crumbled_graphics = FALSE;
6311 g_em->preserve_background = FALSE;
6314 if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
6315 printf("::: empty crumbled: %d [%s], %d, %d\n",
6316 effective_element, element_info[effective_element].token_name,
6317 effective_action, direction);
6320 /* if element can be crumbled, but certain action graphics are just empty
6321 space (like snapping sand with the original R'n'D graphics), do not
6322 treat these empty space graphics as crumbled graphics in EMC engine */
6323 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
6325 getGraphicSource(crumbled, frame, &src_bitmap, &src_x, &src_y);
6327 g_em->has_crumbled_graphics = TRUE;
6328 g_em->crumbled_bitmap = src_bitmap;
6329 g_em->crumbled_src_x = src_x;
6330 g_em->crumbled_src_y = src_y;
6331 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
6335 if (element == EL_ROCK &&
6336 effective_action == ACTION_FILLING)
6337 printf("::: has_action_graphics == %d\n", has_action_graphics);
6340 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
6341 effective_action == ACTION_MOVING ||
6342 effective_action == ACTION_PUSHING ||
6343 effective_action == ACTION_EATING)) ||
6344 (!has_action_graphics && (effective_action == ACTION_FILLING ||
6345 effective_action == ACTION_EMPTYING)))
6348 (effective_action == ACTION_FALLING ||
6349 effective_action == ACTION_FILLING ||
6350 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
6351 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
6352 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
6353 int num_steps = (i == Ydrip_s1 ? 16 :
6354 i == Ydrip_s1B ? 16 :
6355 i == Ydrip_s2 ? 16 :
6356 i == Ydrip_s2B ? 16 :
6357 i == Xsand_stonein_1 ? 32 :
6358 i == Xsand_stonein_2 ? 32 :
6359 i == Xsand_stonein_3 ? 32 :
6360 i == Xsand_stonein_4 ? 32 :
6361 i == Xsand_stoneout_1 ? 16 :
6362 i == Xsand_stoneout_2 ? 16 : 8);
6363 int cx = ABS(dx) * (TILEX / num_steps);
6364 int cy = ABS(dy) * (TILEY / num_steps);
6365 int step_frame = (i == Ydrip_s2 ? j + 8 :
6366 i == Ydrip_s2B ? j + 8 :
6367 i == Xsand_stonein_2 ? j + 8 :
6368 i == Xsand_stonein_3 ? j + 16 :
6369 i == Xsand_stonein_4 ? j + 24 :
6370 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
6371 int step = (is_backside ? step_frame : num_steps - step_frame);
6373 if (is_backside) /* tile where movement starts */
6375 if (dx < 0 || dy < 0)
6377 g_em->src_offset_x = cx * step;
6378 g_em->src_offset_y = cy * step;
6382 g_em->dst_offset_x = cx * step;
6383 g_em->dst_offset_y = cy * step;
6386 else /* tile where movement ends */
6388 if (dx < 0 || dy < 0)
6390 g_em->dst_offset_x = cx * step;
6391 g_em->dst_offset_y = cy * step;
6395 g_em->src_offset_x = cx * step;
6396 g_em->src_offset_y = cy * step;
6400 g_em->width = TILEX - cx * step;
6401 g_em->height = TILEY - cy * step;
6404 /* create unique graphic identifier to decide if tile must be redrawn */
6405 /* bit 31 - 16 (16 bit): EM style graphic
6406 bit 15 - 12 ( 4 bit): EM style frame
6407 bit 11 - 6 ( 6 bit): graphic width
6408 bit 5 - 0 ( 6 bit): graphic height */
6409 g_em->unique_identifier =
6410 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
6414 /* skip check for EMC elements not contained in original EMC artwork */
6415 if (element == EL_EMC_FAKE_ACID)
6418 if (g_em->bitmap != debug_bitmap ||
6419 g_em->src_x != debug_src_x ||
6420 g_em->src_y != debug_src_y ||
6421 g_em->src_offset_x != 0 ||
6422 g_em->src_offset_y != 0 ||
6423 g_em->dst_offset_x != 0 ||
6424 g_em->dst_offset_y != 0 ||
6425 g_em->width != TILEX ||
6426 g_em->height != TILEY)
6428 static int last_i = -1;
6436 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
6437 i, element, element_info[element].token_name,
6438 element_action_info[effective_action].suffix, direction);
6440 if (element != effective_element)
6441 printf(" [%d ('%s')]",
6443 element_info[effective_element].token_name);
6447 if (g_em->bitmap != debug_bitmap)
6448 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
6449 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
6451 if (g_em->src_x != debug_src_x ||
6452 g_em->src_y != debug_src_y)
6453 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
6454 j, (is_backside ? 'B' : 'F'),
6455 g_em->src_x, g_em->src_y,
6456 g_em->src_x / 32, g_em->src_y / 32,
6457 debug_src_x, debug_src_y,
6458 debug_src_x / 32, debug_src_y / 32);
6460 if (g_em->src_offset_x != 0 ||
6461 g_em->src_offset_y != 0 ||
6462 g_em->dst_offset_x != 0 ||
6463 g_em->dst_offset_y != 0)
6464 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
6466 g_em->src_offset_x, g_em->src_offset_y,
6467 g_em->dst_offset_x, g_em->dst_offset_y);
6469 if (g_em->width != TILEX ||
6470 g_em->height != TILEY)
6471 printf(" %d (%d): size %d,%d should be %d,%d\n",
6473 g_em->width, g_em->height, TILEX, TILEY);
6475 num_em_gfx_errors++;
6482 for (i = 0; i < TILE_MAX; i++)
6484 for (j = 0; j < 8; j++)
6486 int element = object_mapping[i].element_rnd;
6487 int action = object_mapping[i].action;
6488 int direction = object_mapping[i].direction;
6489 boolean is_backside = object_mapping[i].is_backside;
6490 int graphic_action = el_act_dir2img(element, action, direction);
6491 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
6493 if ((action == ACTION_SMASHED_BY_ROCK ||
6494 action == ACTION_SMASHED_BY_SPRING ||
6495 action == ACTION_EATING) &&
6496 graphic_action == graphic_default)
6498 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
6499 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
6500 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
6501 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
6504 /* no separate animation for "smashed by rock" -- use rock instead */
6505 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
6506 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
6508 g_em->bitmap = g_xx->bitmap;
6509 g_em->src_x = g_xx->src_x;
6510 g_em->src_y = g_xx->src_y;
6511 g_em->src_offset_x = g_xx->src_offset_x;
6512 g_em->src_offset_y = g_xx->src_offset_y;
6513 g_em->dst_offset_x = g_xx->dst_offset_x;
6514 g_em->dst_offset_y = g_xx->dst_offset_y;
6515 g_em->width = g_xx->width;
6516 g_em->height = g_xx->height;
6517 g_em->unique_identifier = g_xx->unique_identifier;
6520 g_em->preserve_background = TRUE;
6525 for (p = 0; p < MAX_PLAYERS; p++)
6527 for (i = 0; i < SPR_MAX; i++)
6529 int element = player_mapping[p][i].element_rnd;
6530 int action = player_mapping[p][i].action;
6531 int direction = player_mapping[p][i].direction;
6533 for (j = 0; j < 8; j++)
6535 int effective_element = element;
6536 int effective_action = action;
6537 int graphic = (direction == MV_NONE ?
6538 el_act2img(effective_element, effective_action) :
6539 el_act_dir2img(effective_element, effective_action,
6541 struct GraphicInfo *g = &graphic_info[graphic];
6542 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
6548 Bitmap *debug_bitmap = g_em->bitmap;
6549 int debug_src_x = g_em->src_x;
6550 int debug_src_y = g_em->src_y;
6553 int frame = getAnimationFrame(g->anim_frames,
6556 g->anim_start_frame,
6559 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
6561 g_em->bitmap = src_bitmap;
6562 g_em->src_x = src_x;
6563 g_em->src_y = src_y;
6564 g_em->src_offset_x = 0;
6565 g_em->src_offset_y = 0;
6566 g_em->dst_offset_x = 0;
6567 g_em->dst_offset_y = 0;
6568 g_em->width = TILEX;
6569 g_em->height = TILEY;
6573 /* skip check for EMC elements not contained in original EMC artwork */
6574 if (element == EL_PLAYER_3 ||
6575 element == EL_PLAYER_4)
6578 if (g_em->bitmap != debug_bitmap ||
6579 g_em->src_x != debug_src_x ||
6580 g_em->src_y != debug_src_y)
6582 static int last_i = -1;
6590 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
6591 p, i, element, element_info[element].token_name,
6592 element_action_info[effective_action].suffix, direction);
6594 if (element != effective_element)
6595 printf(" [%d ('%s')]",
6597 element_info[effective_element].token_name);
6601 if (g_em->bitmap != debug_bitmap)
6602 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
6603 j, (int)(g_em->bitmap), (int)(debug_bitmap));
6605 if (g_em->src_x != debug_src_x ||
6606 g_em->src_y != debug_src_y)
6607 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
6609 g_em->src_x, g_em->src_y,
6610 g_em->src_x / 32, g_em->src_y / 32,
6611 debug_src_x, debug_src_y,
6612 debug_src_x / 32, debug_src_y / 32);
6614 num_em_gfx_errors++;
6624 printf("::: [%d errors found]\n", num_em_gfx_errors);
6630 void PlayMenuSoundExt(int sound)
6632 if (sound == SND_UNDEFINED)
6635 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6636 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6639 if (IS_LOOP_SOUND(sound))
6640 PlaySoundLoop(sound);
6645 void PlayMenuSound()
6647 PlayMenuSoundExt(menu.sound[game_status]);
6650 void PlayMenuSoundStereo(int sound, int stereo_position)
6652 if (sound == SND_UNDEFINED)
6655 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6656 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6659 if (IS_LOOP_SOUND(sound))
6660 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
6662 PlaySoundStereo(sound, stereo_position);
6665 void PlayMenuSoundIfLoopExt(int sound)
6667 if (sound == SND_UNDEFINED)
6670 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6671 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6674 if (IS_LOOP_SOUND(sound))
6675 PlaySoundLoop(sound);
6678 void PlayMenuSoundIfLoop()
6680 PlayMenuSoundIfLoopExt(menu.sound[game_status]);
6683 void PlayMenuMusicExt(int music)
6685 if (music == MUS_UNDEFINED)
6688 if (!setup.sound_music)
6694 void PlayMenuMusic()
6696 PlayMenuMusicExt(menu.music[game_status]);
6699 void PlaySoundActivating()
6702 PlaySound(SND_MENU_ITEM_ACTIVATING);
6706 void PlaySoundSelecting()
6709 PlaySound(SND_MENU_ITEM_SELECTING);
6713 void ToggleFullscreenIfNeeded()
6715 boolean change_fullscreen = (setup.fullscreen !=
6716 video.fullscreen_enabled);
6717 boolean change_fullscreen_mode = (video.fullscreen_enabled &&
6718 !strEqual(setup.fullscreen_mode,
6719 video.fullscreen_mode_current));
6721 if (!video.fullscreen_available)
6725 if (change_fullscreen || change_fullscreen_mode)
6727 if (setup.fullscreen != video.fullscreen_enabled ||
6728 setup.fullscreen_mode != video.fullscreen_mode_current)
6731 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
6733 /* save backbuffer content which gets lost when toggling fullscreen mode */
6734 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6737 if (change_fullscreen_mode)
6739 if (setup.fullscreen && video.fullscreen_enabled)
6742 /* keep fullscreen, but change fullscreen mode (screen resolution) */
6744 /* (this is now set in sdl.c) */
6746 video.fullscreen_mode_current = setup.fullscreen_mode;
6748 video.fullscreen_enabled = FALSE; /* force new fullscreen mode */
6751 /* toggle fullscreen */
6752 ChangeVideoModeIfNeeded(setup.fullscreen);
6754 setup.fullscreen = video.fullscreen_enabled;
6756 /* restore backbuffer content from temporary backbuffer backup bitmap */
6757 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6759 FreeBitmap(tmp_backbuffer);
6762 /* update visible window/screen */
6763 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6765 redraw_mask = REDRAW_ALL;