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_BACKBUFFER */
127 BX2 = SCR_FIELDX - 1;
128 BY2 = SCR_FIELDY - 1;
132 drawto_field = 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;
160 int x1 = (x - SX) / TILEX, y1 = (y - SY) / TILEY;
161 int x2 = (x - SX + width) / TILEX, y2 = (y - SY + height) / TILEY;
163 for (xx = BX1; xx <= BX2; xx++)
164 for (yy = BY1; yy <= BY2; yy++)
165 if (xx >= x1 && xx <= x2 && yy >= y1 && yy <= y2)
166 DrawScreenField(xx, yy);
170 if (setup.soft_scrolling)
172 int fx = FX, fy = FY;
174 fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0);
175 fy += (ScreenMovDir & (MV_UP|MV_DOWN) ? ScreenGfxPos : 0);
177 BlitBitmap(fieldbuffer, backbuffer, fx,fy, SXSIZE,SYSIZE, SX,SY);
189 BlitBitmap(drawto, window, x, y, width, height, x, y);
192 void DrawMaskedBorder_Rect(int x, int y, int width, int height)
194 Bitmap *bitmap = graphic_info[IMG_GLOBAL_BORDER].bitmap;
196 SetClipOrigin(bitmap, bitmap->stored_clip_gc, 0, 0);
197 BlitBitmapMasked(bitmap, backbuffer, x, y, width, height, x, y);
200 void DrawMaskedBorder_FIELD()
202 if (global.border_status >= GAME_MODE_TITLE &&
203 global.border_status <= GAME_MODE_PLAYING &&
204 border.draw_masked[global.border_status])
205 DrawMaskedBorder_Rect(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
208 void DrawMaskedBorder_DOOR_1()
210 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
211 (global.border_status != GAME_MODE_EDITOR ||
212 border.draw_masked[GFX_SPECIAL_ARG_EDITOR]))
213 DrawMaskedBorder_Rect(DX, DY, DXSIZE, DYSIZE);
216 void DrawMaskedBorder_DOOR_2()
218 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
219 global.border_status != GAME_MODE_EDITOR)
220 DrawMaskedBorder_Rect(VX, VY, VXSIZE, VYSIZE);
223 void DrawMaskedBorder_DOOR_3()
225 /* currently not available */
228 void DrawMaskedBorder_ALL()
230 DrawMaskedBorder_FIELD();
231 DrawMaskedBorder_DOOR_1();
232 DrawMaskedBorder_DOOR_2();
233 DrawMaskedBorder_DOOR_3();
236 void DrawMaskedBorder(int redraw_mask)
238 /* never draw masked screen borders on borderless screens */
239 if (effectiveGameStatus() == GAME_MODE_LOADING ||
240 effectiveGameStatus() == GAME_MODE_TITLE)
243 if (redraw_mask & REDRAW_ALL)
244 DrawMaskedBorder_ALL();
247 if (redraw_mask & REDRAW_FIELD)
248 DrawMaskedBorder_FIELD();
249 if (redraw_mask & REDRAW_DOOR_1)
250 DrawMaskedBorder_DOOR_1();
251 if (redraw_mask & REDRAW_DOOR_2)
252 DrawMaskedBorder_DOOR_2();
253 if (redraw_mask & REDRAW_DOOR_3)
254 DrawMaskedBorder_DOOR_3();
261 DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
263 if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD)
264 redraw_mask |= REDRAW_FIELD;
266 if (redraw_mask & REDRAW_FIELD)
267 redraw_mask &= ~REDRAW_TILES;
269 if (redraw_mask == REDRAW_NONE)
272 if (redraw_mask & REDRAW_TILES &&
273 game_status == GAME_MODE_PLAYING &&
274 border.draw_masked[GAME_MODE_PLAYING])
275 redraw_mask |= REDRAW_FIELD;
277 if (global.fps_slowdown && game_status == GAME_MODE_PLAYING)
279 static boolean last_frame_skipped = FALSE;
280 boolean skip_even_when_not_scrolling = TRUE;
281 boolean just_scrolling = (ScreenMovDir != 0);
282 boolean verbose = FALSE;
284 if (global.fps_slowdown_factor > 1 &&
285 (FrameCounter % global.fps_slowdown_factor) &&
286 (just_scrolling || skip_even_when_not_scrolling))
288 redraw_mask &= ~REDRAW_MAIN;
290 last_frame_skipped = TRUE;
293 printf("FRAME SKIPPED\n");
297 if (last_frame_skipped)
298 redraw_mask |= REDRAW_FIELD;
300 last_frame_skipped = FALSE;
303 printf("frame not skipped\n");
307 /* synchronize X11 graphics at this point; if we would synchronize the
308 display immediately after the buffer switching (after the XFlush),
309 this could mean that we have to wait for the graphics to complete,
310 although we could go on doing calculations for the next frame */
314 /* prevent drawing masked border to backbuffer when using playfield buffer */
315 if (game_status != GAME_MODE_PLAYING ||
316 redraw_mask & REDRAW_FROM_BACKBUFFER ||
317 buffer == backbuffer)
318 DrawMaskedBorder(redraw_mask);
320 DrawMaskedBorder(redraw_mask & REDRAW_DOORS);
322 if (redraw_mask & REDRAW_ALL)
324 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
326 redraw_mask = REDRAW_NONE;
329 if (redraw_mask & REDRAW_FIELD)
331 if (game_status != GAME_MODE_PLAYING ||
332 redraw_mask & REDRAW_FROM_BACKBUFFER)
334 BlitBitmap(backbuffer, window,
335 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
339 int fx = FX, fy = FY;
341 if (setup.soft_scrolling)
343 fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
344 fy += (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
347 if (setup.soft_scrolling ||
348 ABS(ScreenMovPos) + ScrollStepSize == TILEX ||
349 ABS(ScreenMovPos) == ScrollStepSize ||
350 redraw_tiles > REDRAWTILES_THRESHOLD)
352 if (border.draw_masked[GAME_MODE_PLAYING])
354 if (buffer != backbuffer)
356 /* copy playfield buffer to backbuffer to add masked border */
357 BlitBitmap(buffer, backbuffer, fx, fy, SXSIZE, SYSIZE, SX, SY);
358 DrawMaskedBorder(REDRAW_FIELD);
361 BlitBitmap(backbuffer, window,
362 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
367 BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
372 printf("redrawing all (ScreenGfxPos == %d) because %s\n",
374 (setup.soft_scrolling ?
375 "setup.soft_scrolling" :
376 ABS(ScreenGfxPos) + ScrollStepSize == TILEX ?
377 "ABS(ScreenGfxPos) + ScrollStepSize == TILEX" :
378 ABS(ScreenGfxPos) == ScrollStepSize ?
379 "ABS(ScreenGfxPos) == ScrollStepSize" :
380 "redraw_tiles > REDRAWTILES_THRESHOLD"));
386 redraw_mask &= ~REDRAW_MAIN;
389 if (redraw_mask & REDRAW_DOORS)
391 if (redraw_mask & REDRAW_DOOR_1)
392 BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
394 if (redraw_mask & REDRAW_DOOR_2)
395 BlitBitmap(backbuffer, window, VX, VY, VXSIZE, VYSIZE, VX, VY);
397 if (redraw_mask & REDRAW_DOOR_3)
398 BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
400 redraw_mask &= ~REDRAW_DOORS;
403 if (redraw_mask & REDRAW_MICROLEVEL)
405 BlitBitmap(backbuffer, window, SX, SY + 10 * TILEY, SXSIZE, 7 * TILEY,
406 SX, SY + 10 * TILEY);
408 redraw_mask &= ~REDRAW_MICROLEVEL;
411 if (redraw_mask & REDRAW_TILES)
413 for (x = 0; x < SCR_FIELDX; x++)
414 for (y = 0 ; y < SCR_FIELDY; y++)
415 if (redraw[redraw_x1 + x][redraw_y1 + y])
416 BlitBitmap(buffer, window,
417 FX + x * TILEX, FY + y * TILEY, TILEX, TILEY,
418 SX + x * TILEX, SY + y * TILEY);
421 if (redraw_mask & REDRAW_FPS) /* display frames per second */
426 sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
427 if (!global.fps_slowdown)
430 sprintf(text, "%.1f fps%s", global.frames_per_second, info1);
431 DrawTextExt(window, SX, SY, text, FONT_TEXT_2, BLIT_OPAQUE);
436 for (x = 0; x < MAX_BUF_XSIZE; x++)
437 for (y = 0; y < MAX_BUF_YSIZE; y++)
440 redraw_mask = REDRAW_NONE;
443 static void FadeCrossSaveBackbuffer()
445 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
448 static void FadeExt(int fade_mask, int fade_mode, int fade_type)
450 static int fade_type_skip = FADE_TYPE_NONE;
451 void (*draw_border_function)(void) = NULL;
452 Bitmap *bitmap = (fade_mode & FADE_TYPE_TRANSFORM ? bitmap_db_cross : NULL);
453 int x, y, width, height;
454 int fade_delay, post_delay;
456 if (fade_type == FADE_TYPE_FADE_OUT)
458 if (fade_type_skip != FADE_TYPE_NONE)
461 printf("::: skipping %d ... [%d] (X)\n", fade_mode, fade_type_skip);
464 /* skip all fade operations until specified fade operation */
465 if (fade_type & fade_type_skip)
466 fade_type_skip = FADE_TYPE_NONE;
471 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
473 FadeCrossSaveBackbuffer();
479 redraw_mask |= fade_mask;
481 if (fade_type == FADE_TYPE_SKIP)
484 printf("::: will skip %d ... [%d]\n", fade_mode, fade_type_skip);
487 fade_type_skip = fade_mode;
492 if (fade_type_skip != FADE_TYPE_NONE)
495 printf("::: skipping %d ... [%d]\n", fade_mode, fade_type_skip);
498 /* skip all fade operations until specified fade operation */
499 if (fade_type & fade_type_skip)
500 fade_type_skip = FADE_TYPE_NONE;
506 if (global.autoplay_leveldir)
508 // fading.fade_mode = FADE_MODE_NONE;
515 if (fading.fade_mode == FADE_MODE_NONE)
523 /* !!! what abount fade_mask == REDRAW_FIELD | REDRAW_ALL ??? !!! */
526 printf("::: NOW FADING %d ... [%d]\n", fade_mode, fade_type);
530 if (fade_mask == REDRAW_NONE)
531 fade_mask = REDRAW_FIELD;
534 // if (fade_mask & REDRAW_FIELD)
535 if (fade_mask == REDRAW_FIELD)
540 height = FULL_SYSIZE;
542 fade_delay = fading.fade_delay;
543 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
545 if (border.draw_masked_when_fading)
546 draw_border_function = DrawMaskedBorder_FIELD; /* update when fading */
548 DrawMaskedBorder_FIELD(); /* draw once */
550 else /* REDRAW_ALL */
557 fade_delay = fading.fade_delay;
558 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
562 if (!setup.fade_screens ||
564 fading.fade_mode == FADE_MODE_NONE)
566 if (!setup.fade_screens || fade_delay == 0)
569 if (fade_mode == FADE_MODE_FADE_OUT)
573 if (fade_mode == FADE_MODE_FADE_OUT &&
574 fading.fade_mode != FADE_MODE_NONE)
575 ClearRectangle(backbuffer, x, y, width, height);
579 BlitBitmap(backbuffer, window, x, y, width, height, x, y);
580 redraw_mask = REDRAW_NONE;
588 FadeRectangle(bitmap, x, y, width, height, fade_mode, fade_delay, post_delay,
589 draw_border_function);
591 redraw_mask &= ~fade_mask;
594 void FadeIn(int fade_mask)
596 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
597 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_IN);
599 FadeExt(fade_mask, FADE_MODE_FADE_IN, FADE_TYPE_FADE_IN);
602 void FadeOut(int fade_mask)
604 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
605 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_OUT);
607 FadeExt(fade_mask, FADE_MODE_FADE_OUT, FADE_TYPE_FADE_OUT);
609 global.border_status = game_status;
612 static void FadeSetLeaveNext(struct TitleFadingInfo fading_leave, boolean set)
614 static struct TitleFadingInfo fading_leave_stored;
617 fading_leave_stored = fading_leave;
619 fading = fading_leave_stored;
622 void FadeSetEnterMenu()
624 fading = menu.enter_menu;
627 printf("::: storing enter_menu\n");
630 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
633 void FadeSetLeaveMenu()
635 fading = menu.leave_menu;
638 printf("::: storing leave_menu\n");
641 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
644 void FadeSetEnterScreen()
646 fading = menu.enter_screen[game_status];
649 printf("::: storing leave_screen[%d]\n", game_status);
652 FadeSetLeaveNext(menu.leave_screen[game_status], TRUE); /* store */
655 void FadeSetNextScreen()
657 fading = menu.next_screen;
660 printf("::: storing next_screen\n");
663 // (do not overwrite fade mode set by FadeSetEnterScreen)
664 // FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
667 void FadeSetLeaveScreen()
670 printf("::: recalling last stored value\n");
673 FadeSetLeaveNext(menu.leave_screen[game_status], FALSE); /* recall */
676 void FadeSetFromType(int type)
678 if (type & TYPE_ENTER_SCREEN)
679 FadeSetEnterScreen();
680 else if (type & TYPE_ENTER)
682 else if (type & TYPE_LEAVE)
686 void FadeSetDisabled()
688 static struct TitleFadingInfo fading_none = { FADE_MODE_NONE, -1, -1, -1 };
690 fading = fading_none;
693 void FadeSkipNextFadeIn()
695 FadeExt(0, FADE_MODE_SKIP_FADE_IN, FADE_TYPE_SKIP);
698 void FadeSkipNextFadeOut()
700 FadeExt(0, FADE_MODE_SKIP_FADE_OUT, FADE_TYPE_SKIP);
703 void SetWindowBackgroundImageIfDefined(int graphic)
705 if (graphic_info[graphic].bitmap)
706 SetWindowBackgroundBitmap(graphic_info[graphic].bitmap);
709 void SetMainBackgroundImageIfDefined(int graphic)
711 if (graphic_info[graphic].bitmap)
712 SetMainBackgroundBitmap(graphic_info[graphic].bitmap);
715 void SetDoorBackgroundImageIfDefined(int graphic)
717 if (graphic_info[graphic].bitmap)
718 SetDoorBackgroundBitmap(graphic_info[graphic].bitmap);
721 void SetWindowBackgroundImage(int graphic)
723 SetWindowBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
724 graphic_info[graphic].bitmap ?
725 graphic_info[graphic].bitmap :
726 graphic_info[IMG_BACKGROUND].bitmap);
729 void SetMainBackgroundImage(int graphic)
731 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
732 graphic_info[graphic].bitmap ?
733 graphic_info[graphic].bitmap :
734 graphic_info[IMG_BACKGROUND].bitmap);
737 void SetDoorBackgroundImage(int graphic)
739 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
740 graphic_info[graphic].bitmap ?
741 graphic_info[graphic].bitmap :
742 graphic_info[IMG_BACKGROUND].bitmap);
745 void SetPanelBackground()
747 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, bitmap_db_panel,
748 DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, 0, 0);
750 SetDoorBackgroundBitmap(bitmap_db_panel);
753 void DrawBackground(int x, int y, int width, int height)
755 /* !!! "drawto" might still point to playfield buffer here (see below) !!! */
756 /* (when entering hall of fame after playing) */
758 ClearRectangleOnBackground(drawto, x, y, width, height);
760 ClearRectangleOnBackground(backbuffer, x, y, width, height);
763 redraw_mask |= REDRAW_FIELD;
766 void DrawBackgroundForFont(int x, int y, int width, int height, int font_nr)
768 struct FontBitmapInfo *font = getFontBitmapInfo(font_nr);
770 if (font->bitmap == NULL)
773 DrawBackground(x, y, width, height);
776 void DrawBackgroundForGraphic(int x, int y, int width, int height, int graphic)
778 struct GraphicInfo *g = &graphic_info[graphic];
780 if (g->bitmap == NULL)
783 DrawBackground(x, y, width, height);
788 /* !!! "drawto" might still point to playfield buffer here (see above) !!! */
789 /* (when entering hall of fame after playing) */
790 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
792 /* !!! maybe this should be done before clearing the background !!! */
793 if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
795 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
796 SetDrawtoField(DRAW_BUFFERED);
799 SetDrawtoField(DRAW_BACKBUFFER);
802 void MarkTileDirty(int x, int y)
804 int xx = redraw_x1 + x;
805 int yy = redraw_y1 + y;
810 redraw[xx][yy] = TRUE;
811 redraw_mask |= REDRAW_TILES;
814 void SetBorderElement()
818 BorderElement = EL_EMPTY;
820 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
822 for (x = 0; x < lev_fieldx; x++)
824 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
825 BorderElement = EL_STEELWALL;
827 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
833 void FloodFillLevel(int from_x, int from_y, int fill_element,
834 short field[MAX_LEV_FIELDX][MAX_LEV_FIELDY],
835 int max_fieldx, int max_fieldy)
839 static int check[4][2] = { { -1, 0 }, { 0, -1 }, { 1, 0 }, { 0, 1 } };
840 static int safety = 0;
842 /* check if starting field still has the desired content */
843 if (field[from_x][from_y] == fill_element)
848 if (safety > max_fieldx * max_fieldy)
849 Error(ERR_EXIT, "Something went wrong in 'FloodFill()'. Please debug.");
851 old_element = field[from_x][from_y];
852 field[from_x][from_y] = fill_element;
854 for (i = 0; i < 4; i++)
856 x = from_x + check[i][0];
857 y = from_y + check[i][1];
859 if (IN_FIELD(x, y, max_fieldx, max_fieldy) && field[x][y] == old_element)
860 FloodFillLevel(x, y, fill_element, field, max_fieldx, max_fieldy);
866 void SetRandomAnimationValue(int x, int y)
868 gfx.anim_random_frame = GfxRandom[x][y];
871 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
873 /* animation synchronized with global frame counter, not move position */
874 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
875 sync_frame = FrameCounter;
877 return getAnimationFrame(graphic_info[graphic].anim_frames,
878 graphic_info[graphic].anim_delay,
879 graphic_info[graphic].anim_mode,
880 graphic_info[graphic].anim_start_frame,
884 void getSizedGraphicSource(int graphic, int frame, int tilesize_raw,
885 Bitmap **bitmap, int *x, int *y)
889 int width_mult, width_div;
890 int height_mult, height_div;
894 { 15, 16, 2, 3 }, /* 1 x 1 */
895 { 7, 8, 2, 3 }, /* 2 x 2 */
896 { 3, 4, 2, 3 }, /* 4 x 4 */
897 { 1, 2, 2, 3 }, /* 8 x 8 */
898 { 0, 1, 2, 3 }, /* 16 x 16 */
899 { 0, 1, 0, 1 }, /* 32 x 32 */
901 struct GraphicInfo *g = &graphic_info[graphic];
902 Bitmap *src_bitmap = g->bitmap;
903 int tilesize = MIN(MAX(1, tilesize_raw), TILESIZE);
904 int offset_calc_pos = log_2(tilesize);
905 int width_mult = offset_calc[offset_calc_pos].width_mult;
906 int width_div = offset_calc[offset_calc_pos].width_div;
907 int height_mult = offset_calc[offset_calc_pos].height_mult;
908 int height_div = offset_calc[offset_calc_pos].height_div;
909 int startx = src_bitmap->width * width_mult / width_div;
910 int starty = src_bitmap->height * height_mult / height_div;
911 int src_x = g->src_x * tilesize / TILESIZE;
912 int src_y = g->src_y * tilesize / TILESIZE;
913 int width = g->width * tilesize / TILESIZE;
914 int height = g->height * tilesize / TILESIZE;
915 int offset_x = g->offset_x * tilesize / TILESIZE;
916 int offset_y = g->offset_y * tilesize / TILESIZE;
918 if (g->offset_y == 0) /* frames are ordered horizontally */
920 int max_width = g->anim_frames_per_line * width;
921 int pos = (src_y / height) * max_width + src_x + frame * offset_x;
923 src_x = pos % max_width;
924 src_y = src_y % height + pos / max_width * height;
926 else if (g->offset_x == 0) /* frames are ordered vertically */
928 int max_height = g->anim_frames_per_line * height;
929 int pos = (src_x / width) * max_height + src_y + frame * offset_y;
931 src_x = src_x % width + pos / max_height * width;
932 src_y = pos % max_height;
934 else /* frames are ordered diagonally */
936 src_x = src_x + frame * offset_x;
937 src_y = src_y + frame * offset_y;
940 *bitmap = src_bitmap;
945 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
948 getSizedGraphicSource(graphic, 0, MINI_TILESIZE, bitmap, x, y);
950 struct GraphicInfo *g = &graphic_info[graphic];
952 int mini_starty = g->bitmap->height * 2 / 3;
955 *x = mini_startx + g->src_x / 2;
956 *y = mini_starty + g->src_y / 2;
960 inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
961 int *x, int *y, boolean get_backside)
963 struct GraphicInfo *g = &graphic_info[graphic];
964 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
965 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
969 if (g->offset_y == 0) /* frames are ordered horizontally */
971 int max_width = g->anim_frames_per_line * g->width;
972 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
974 *x = pos % max_width;
975 *y = src_y % g->height + pos / max_width * g->height;
977 else if (g->offset_x == 0) /* frames are ordered vertically */
979 int max_height = g->anim_frames_per_line * g->height;
980 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
982 *x = src_x % g->width + pos / max_height * g->width;
983 *y = pos % max_height;
985 else /* frames are ordered diagonally */
987 *x = src_x + frame * g->offset_x;
988 *y = src_y + frame * g->offset_y;
992 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
994 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
997 void DrawGraphic(int x, int y, int graphic, int frame)
1000 if (!IN_SCR_FIELD(x, y))
1002 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1003 printf("DrawGraphic(): This should never happen!\n");
1008 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
1009 MarkTileDirty(x, y);
1012 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1018 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1019 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
1022 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
1025 if (!IN_SCR_FIELD(x, y))
1027 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1028 printf("DrawGraphicThruMask(): This should never happen!\n");
1033 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
1035 MarkTileDirty(x, y);
1038 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
1044 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1046 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1047 dst_x - src_x, dst_y - src_y);
1048 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
1051 void DrawSizedGraphic(int x, int y, int graphic, int frame, int tilesize)
1053 DrawSizedGraphicExt(drawto, SX + x * tilesize, SY + y * tilesize, graphic,
1055 MarkTileDirty(x / tilesize, y / tilesize);
1058 void DrawSizedGraphicExt(DrawBuffer *d, int x, int y, int graphic, int frame,
1064 getSizedGraphicSource(graphic, frame, tilesize, &src_bitmap, &src_x, &src_y);
1065 BlitBitmap(src_bitmap, d, src_x, src_y, tilesize, tilesize, x, y);
1068 void DrawMiniGraphic(int x, int y, int graphic)
1070 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
1071 MarkTileDirty(x / 2, y / 2);
1074 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
1079 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1080 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
1083 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
1084 int graphic, int frame,
1085 int cut_mode, int mask_mode)
1090 int width = TILEX, height = TILEY;
1093 if (dx || dy) /* shifted graphic */
1095 if (x < BX1) /* object enters playfield from the left */
1102 else if (x > BX2) /* object enters playfield from the right */
1108 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
1114 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
1116 else if (dx) /* general horizontal movement */
1117 MarkTileDirty(x + SIGN(dx), y);
1119 if (y < BY1) /* object enters playfield from the top */
1121 if (cut_mode==CUT_BELOW) /* object completely above top border */
1129 else if (y > BY2) /* object enters playfield from the bottom */
1135 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
1141 else if (dy > 0 && cut_mode == CUT_ABOVE)
1143 if (y == BY2) /* object completely above bottom border */
1149 MarkTileDirty(x, y + 1);
1150 } /* object leaves playfield to the bottom */
1151 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1153 else if (dy) /* general vertical movement */
1154 MarkTileDirty(x, y + SIGN(dy));
1158 if (!IN_SCR_FIELD(x, y))
1160 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1161 printf("DrawGraphicShifted(): This should never happen!\n");
1166 if (width > 0 && height > 0)
1168 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1173 dst_x = FX + x * TILEX + dx;
1174 dst_y = FY + y * TILEY + dy;
1176 if (mask_mode == USE_MASKING)
1178 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1179 dst_x - src_x, dst_y - src_y);
1180 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1184 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1187 MarkTileDirty(x, y);
1191 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
1192 int graphic, int frame,
1193 int cut_mode, int mask_mode)
1198 int width = TILEX, height = TILEY;
1201 int x2 = x + SIGN(dx);
1202 int y2 = y + SIGN(dy);
1203 int anim_frames = graphic_info[graphic].anim_frames;
1204 int sync_frame = (dx ? ABS(dx) : ABS(dy)) * anim_frames / TILESIZE;
1205 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
1206 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
1208 /* re-calculate animation frame for two-tile movement animation */
1209 frame = getGraphicAnimationFrame(graphic, sync_frame);
1211 /* check if movement start graphic inside screen area and should be drawn */
1212 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
1214 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
1216 dst_x = FX + x1 * TILEX;
1217 dst_y = FY + y1 * TILEY;
1219 if (mask_mode == USE_MASKING)
1221 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1222 dst_x - src_x, dst_y - src_y);
1223 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1227 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1230 MarkTileDirty(x1, y1);
1233 /* check if movement end graphic inside screen area and should be drawn */
1234 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
1236 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
1238 dst_x = FX + x2 * TILEX;
1239 dst_y = FY + y2 * TILEY;
1241 if (mask_mode == USE_MASKING)
1243 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1244 dst_x - src_x, dst_y - src_y);
1245 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1249 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1252 MarkTileDirty(x2, y2);
1256 static void DrawGraphicShifted(int x, int y, int dx, int dy,
1257 int graphic, int frame,
1258 int cut_mode, int mask_mode)
1262 DrawGraphic(x, y, graphic, frame);
1267 if (graphic_info[graphic].double_movement) /* EM style movement images */
1268 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1270 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1273 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1274 int frame, int cut_mode)
1276 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
1279 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1280 int cut_mode, int mask_mode)
1282 int lx = LEVELX(x), ly = LEVELY(y);
1286 if (IN_LEV_FIELD(lx, ly))
1288 SetRandomAnimationValue(lx, ly);
1290 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
1291 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1293 /* do not use double (EM style) movement graphic when not moving */
1294 if (graphic_info[graphic].double_movement && !dx && !dy)
1296 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
1297 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1300 else /* border element */
1302 graphic = el2img(element);
1303 frame = getGraphicAnimationFrame(graphic, -1);
1306 if (element == EL_EXPANDABLE_WALL)
1308 boolean left_stopped = FALSE, right_stopped = FALSE;
1310 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1311 left_stopped = TRUE;
1312 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1313 right_stopped = TRUE;
1315 if (left_stopped && right_stopped)
1317 else if (left_stopped)
1319 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1320 frame = graphic_info[graphic].anim_frames - 1;
1322 else if (right_stopped)
1324 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1325 frame = graphic_info[graphic].anim_frames - 1;
1330 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1331 else if (mask_mode == USE_MASKING)
1332 DrawGraphicThruMask(x, y, graphic, frame);
1334 DrawGraphic(x, y, graphic, frame);
1337 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1338 int cut_mode, int mask_mode)
1340 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1341 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1342 cut_mode, mask_mode);
1345 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1348 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1351 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1354 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1357 void DrawLevelElementThruMask(int x, int y, int element)
1359 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1362 void DrawLevelFieldThruMask(int x, int y)
1364 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1367 /* !!! implementation of quicksand is totally broken !!! */
1368 #define IS_CRUMBLED_TILE(x, y, e) \
1369 (GFX_CRUMBLED(e) && (!IN_LEV_FIELD(x, y) || \
1370 !IS_MOVING(x, y) || \
1371 (e) == EL_QUICKSAND_EMPTYING || \
1372 (e) == EL_QUICKSAND_FAST_EMPTYING))
1374 static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
1378 int sx = SCREENX(x), sy = SCREENY(y);
1380 int width, height, cx, cy, i;
1381 int crumbled_border_size = graphic_info[graphic].border_size;
1382 static int xy[4][2] =
1390 if (!IN_LEV_FIELD(x, y))
1393 element = TILE_GFX_ELEMENT(x, y);
1395 /* crumble field itself */
1397 if (IS_CRUMBLED_TILE(x, y, element))
1399 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 */
1417 if (IS_CRUMBLED_TILE(xx, yy, element))
1420 if (GFX_CRUMBLED(element) && !IS_MOVING(xx, yy))
1424 if (i == 1 || i == 2)
1426 width = crumbled_border_size;
1428 cx = (i == 2 ? TILEX - crumbled_border_size : 0);
1434 height = crumbled_border_size;
1436 cy = (i == 3 ? TILEY - crumbled_border_size : 0);
1439 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1440 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1443 MarkTileDirty(sx, sy);
1445 else /* crumble neighbour fields */
1447 for (i = 0; i < 4; i++)
1449 int xx = x + xy[i][0];
1450 int yy = y + xy[i][1];
1451 int sxx = sx + xy[i][0];
1452 int syy = sy + xy[i][1];
1455 if (!IN_LEV_FIELD(xx, yy) ||
1456 !IN_SCR_FIELD(sxx, syy))
1459 if (!IN_LEV_FIELD(xx, yy) ||
1460 !IN_SCR_FIELD(sxx, syy) ||
1465 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
1468 element = TILE_GFX_ELEMENT(xx, yy);
1471 if (!IS_CRUMBLED_TILE(xx, yy, element))
1474 if (!GFX_CRUMBLED(element))
1478 graphic = el_act2crm(element, ACTION_DEFAULT);
1479 crumbled_border_size = graphic_info[graphic].border_size;
1481 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1483 if (i == 1 || i == 2)
1485 width = crumbled_border_size;
1487 cx = (i == 1 ? TILEX - crumbled_border_size : 0);
1493 height = crumbled_border_size;
1495 cy = (i == 0 ? TILEY - crumbled_border_size : 0);
1498 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1499 width, height, FX + sxx * TILEX + cx, FY + syy * TILEY + cy);
1501 MarkTileDirty(sxx, syy);
1506 void DrawLevelFieldCrumbledSand(int x, int y)
1510 if (!IN_LEV_FIELD(x, y))
1514 /* !!! CHECK THIS !!! */
1517 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1518 GFX_CRUMBLED(GfxElement[x][y]))
1521 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1522 GfxElement[x][y] != EL_UNDEFINED &&
1523 GFX_CRUMBLED(GfxElement[x][y]))
1525 DrawLevelFieldCrumbledSandDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
1532 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
1534 graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
1537 DrawLevelFieldCrumbledSandExt(x, y, graphic, 0);
1540 void DrawLevelFieldCrumbledSandDigging(int x, int y, int direction,
1543 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1544 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1545 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1546 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1547 int sx = SCREENX(x), sy = SCREENY(y);
1549 DrawGraphic(sx, sy, graphic1, frame1);
1550 DrawLevelFieldCrumbledSandExt(x, y, graphic2, frame2);
1553 void DrawLevelFieldCrumbledSandNeighbours(int x, int y)
1555 int sx = SCREENX(x), sy = SCREENY(y);
1556 static int xy[4][2] =
1565 for (i = 0; i < 4; i++)
1567 int xx = x + xy[i][0];
1568 int yy = y + xy[i][1];
1569 int sxx = sx + xy[i][0];
1570 int syy = sy + xy[i][1];
1572 if (!IN_LEV_FIELD(xx, yy) ||
1573 !IN_SCR_FIELD(sxx, syy) ||
1574 !GFX_CRUMBLED(Feld[xx][yy]) ||
1578 DrawLevelField(xx, yy);
1582 static int getBorderElement(int x, int y)
1586 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1587 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1588 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1589 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1590 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1591 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1592 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1594 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1595 int steel_position = (x == -1 && y == -1 ? 0 :
1596 x == lev_fieldx && y == -1 ? 1 :
1597 x == -1 && y == lev_fieldy ? 2 :
1598 x == lev_fieldx && y == lev_fieldy ? 3 :
1599 x == -1 || x == lev_fieldx ? 4 :
1600 y == -1 || y == lev_fieldy ? 5 : 6);
1602 return border[steel_position][steel_type];
1605 void DrawScreenElement(int x, int y, int element)
1607 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1608 DrawLevelFieldCrumbledSand(LEVELX(x), LEVELY(y));
1611 void DrawLevelElement(int x, int y, int element)
1613 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1614 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1617 void DrawScreenField(int x, int y)
1619 int lx = LEVELX(x), ly = LEVELY(y);
1620 int element, content;
1622 if (!IN_LEV_FIELD(lx, ly))
1624 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1627 element = getBorderElement(lx, ly);
1629 DrawScreenElement(x, y, element);
1634 element = Feld[lx][ly];
1635 content = Store[lx][ly];
1637 if (IS_MOVING(lx, ly))
1639 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1640 boolean cut_mode = NO_CUTTING;
1642 if (element == EL_QUICKSAND_EMPTYING ||
1643 element == EL_QUICKSAND_FAST_EMPTYING ||
1644 element == EL_MAGIC_WALL_EMPTYING ||
1645 element == EL_BD_MAGIC_WALL_EMPTYING ||
1646 element == EL_DC_MAGIC_WALL_EMPTYING ||
1647 element == EL_AMOEBA_DROPPING)
1648 cut_mode = CUT_ABOVE;
1649 else if (element == EL_QUICKSAND_FILLING ||
1650 element == EL_QUICKSAND_FAST_FILLING ||
1651 element == EL_MAGIC_WALL_FILLING ||
1652 element == EL_BD_MAGIC_WALL_FILLING ||
1653 element == EL_DC_MAGIC_WALL_FILLING)
1654 cut_mode = CUT_BELOW;
1657 if (lx == 9 && ly == 1)
1658 printf("::: %s [%d] [%d, %d] [%d]\n",
1659 EL_NAME(TILE_GFX_ELEMENT(lx, ly)),
1660 el_act2crm(TILE_GFX_ELEMENT(lx, ly), ACTION_DEFAULT),
1661 element_info[EL_QUICKSAND_EMPTYING].graphic[ACTION_DEFAULT],
1662 element_info[EL_QUICKSAND_EMPTYING].crumbled[ACTION_DEFAULT],
1663 GFX_CRUMBLED(TILE_GFX_ELEMENT(lx, ly)));
1666 if (cut_mode == CUT_ABOVE)
1668 DrawScreenElement(x, y, element);
1670 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1673 DrawScreenElement(x, y, EL_EMPTY);
1676 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1677 else if (cut_mode == NO_CUTTING)
1678 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1681 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1684 if (cut_mode == CUT_BELOW &&
1685 IN_LEV_FIELD(lx, ly + 1) && IN_SCR_FIELD(x, y + 1))
1686 DrawLevelElement(lx, ly + 1, element);
1690 if (content == EL_ACID)
1692 int dir = MovDir[lx][ly];
1693 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
1694 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
1696 DrawLevelElementThruMask(newlx, newly, EL_ACID);
1699 else if (IS_BLOCKED(lx, ly))
1704 boolean cut_mode = NO_CUTTING;
1705 int element_old, content_old;
1707 Blocked2Moving(lx, ly, &oldx, &oldy);
1710 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1711 MovDir[oldx][oldy] == MV_RIGHT);
1713 element_old = Feld[oldx][oldy];
1714 content_old = Store[oldx][oldy];
1716 if (element_old == EL_QUICKSAND_EMPTYING ||
1717 element_old == EL_QUICKSAND_FAST_EMPTYING ||
1718 element_old == EL_MAGIC_WALL_EMPTYING ||
1719 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1720 element_old == EL_DC_MAGIC_WALL_EMPTYING ||
1721 element_old == EL_AMOEBA_DROPPING)
1722 cut_mode = CUT_ABOVE;
1724 DrawScreenElement(x, y, EL_EMPTY);
1727 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1729 else if (cut_mode == NO_CUTTING)
1730 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1733 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1736 else if (IS_DRAWABLE(element))
1737 DrawScreenElement(x, y, element);
1739 DrawScreenElement(x, y, EL_EMPTY);
1742 void DrawLevelField(int x, int y)
1744 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1745 DrawScreenField(SCREENX(x), SCREENY(y));
1746 else if (IS_MOVING(x, y))
1750 Moving2Blocked(x, y, &newx, &newy);
1751 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1752 DrawScreenField(SCREENX(newx), SCREENY(newy));
1754 else if (IS_BLOCKED(x, y))
1758 Blocked2Moving(x, y, &oldx, &oldy);
1759 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1760 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1764 void DrawMiniElement(int x, int y, int element)
1768 graphic = el2edimg(element);
1769 DrawMiniGraphic(x, y, graphic);
1772 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1774 int x = sx + scroll_x, y = sy + scroll_y;
1776 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1777 DrawMiniElement(sx, sy, EL_EMPTY);
1778 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1779 DrawMiniElement(sx, sy, Feld[x][y]);
1781 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1784 void DrawEnvelopeBackground(int envelope_nr, int startx, int starty,
1785 int x, int y, int xsize, int ysize, int font_nr)
1787 int font_width = getFontWidth(font_nr);
1788 int font_height = getFontHeight(font_nr);
1789 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1792 int dst_x = SX + startx + x * font_width;
1793 int dst_y = SY + starty + y * font_height;
1794 int width = graphic_info[graphic].width;
1795 int height = graphic_info[graphic].height;
1796 int inner_width = MAX(width - 2 * font_width, font_width);
1797 int inner_height = MAX(height - 2 * font_height, font_height);
1798 int inner_sx = (width >= 3 * font_width ? font_width : 0);
1799 int inner_sy = (height >= 3 * font_height ? font_height : 0);
1800 boolean draw_masked = graphic_info[graphic].draw_masked;
1802 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1804 if (src_bitmap == NULL || width < font_width || height < font_height)
1806 ClearRectangle(drawto, dst_x, dst_y, font_width, font_height);
1810 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - font_width :
1811 inner_sx + (x - 1) * font_width % inner_width);
1812 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - font_height :
1813 inner_sy + (y - 1) * font_height % inner_height);
1817 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1818 dst_x - src_x, dst_y - src_y);
1819 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1823 BlitBitmap(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1827 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
1829 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1830 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1831 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
1832 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1833 boolean no_delay = (tape.warp_forward);
1834 unsigned long anim_delay = 0;
1835 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
1836 int anim_delay_value = (no_delay ? 0 : frame_delay_value);
1837 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
1838 int font_width = getFontWidth(font_nr);
1839 int font_height = getFontHeight(font_nr);
1840 int max_xsize = level.envelope[envelope_nr].xsize;
1841 int max_ysize = level.envelope[envelope_nr].ysize;
1842 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
1843 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
1844 int xend = max_xsize;
1845 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
1846 int xstep = (xstart < xend ? 1 : 0);
1847 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
1850 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
1852 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
1853 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
1854 int sx = (SXSIZE - xsize * font_width) / 2;
1855 int sy = (SYSIZE - ysize * font_height) / 2;
1858 SetDrawtoField(DRAW_BUFFERED);
1860 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
1862 SetDrawtoField(DRAW_BACKBUFFER);
1864 for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++)
1865 DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
1868 DrawTextBuffer(SX + sx + font_width, SY + sy + font_height,
1869 level.envelope[envelope_nr].text, font_nr, max_xsize,
1870 xsize - 2, ysize - 2, mask_mode,
1871 level.envelope[envelope_nr].autowrap,
1872 level.envelope[envelope_nr].centered, FALSE);
1874 DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
1875 level.envelope[envelope_nr].text, font_nr, max_xsize,
1876 xsize - 2, ysize - 2, mask_mode);
1879 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
1882 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
1886 void ShowEnvelope(int envelope_nr)
1888 int element = EL_ENVELOPE_1 + envelope_nr;
1889 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1890 int sound_opening = element_info[element].sound[ACTION_OPENING];
1891 int sound_closing = element_info[element].sound[ACTION_CLOSING];
1892 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1893 boolean no_delay = (tape.warp_forward);
1894 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
1895 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
1896 int anim_mode = graphic_info[graphic].anim_mode;
1897 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
1898 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
1900 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
1902 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
1904 if (anim_mode == ANIM_DEFAULT)
1905 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
1907 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
1910 Delay(wait_delay_value);
1912 WaitForEventToContinue();
1914 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
1916 if (anim_mode != ANIM_NONE)
1917 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
1919 if (anim_mode == ANIM_DEFAULT)
1920 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
1922 game.envelope_active = FALSE;
1924 SetDrawtoField(DRAW_BUFFERED);
1926 redraw_mask |= REDRAW_FIELD;
1930 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
1934 int graphic = el2preimg(element);
1936 getSizedGraphicSource(graphic, 0, tilesize, &src_bitmap, &src_x, &src_y);
1937 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
1944 SetDrawBackgroundMask(REDRAW_NONE);
1947 for (x = BX1; x <= BX2; x++)
1948 for (y = BY1; y <= BY2; y++)
1949 DrawScreenField(x, y);
1951 redraw_mask |= REDRAW_FIELD;
1954 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1958 for (x = 0; x < size_x; x++)
1959 for (y = 0; y < size_y; y++)
1960 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1962 redraw_mask |= REDRAW_FIELD;
1965 static void DrawPreviewLevelExt(int from_x, int from_y)
1967 boolean show_level_border = (BorderElement != EL_EMPTY);
1968 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
1969 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
1970 int tile_size = preview.tile_size;
1971 int preview_width = preview.xsize * tile_size;
1972 int preview_height = preview.ysize * tile_size;
1973 int real_preview_xsize = MIN(level_xsize, preview.xsize);
1974 int real_preview_ysize = MIN(level_ysize, preview.ysize);
1975 int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
1976 int dst_y = SY + ALIGNED_YPOS(preview.y, preview_height, preview.valign);
1979 DrawBackground(dst_x, dst_y, preview_width, preview_height);
1981 dst_x += (preview_width - real_preview_xsize * tile_size) / 2;
1982 dst_y += (preview_height - real_preview_ysize * tile_size) / 2;
1984 for (x = 0; x < real_preview_xsize; x++)
1986 for (y = 0; y < real_preview_ysize; y++)
1988 int lx = from_x + x + (show_level_border ? -1 : 0);
1989 int ly = from_y + y + (show_level_border ? -1 : 0);
1990 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
1991 getBorderElement(lx, ly));
1993 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
1994 element, tile_size);
1998 redraw_mask |= REDRAW_MICROLEVEL;
2001 #define MICROLABEL_EMPTY 0
2002 #define MICROLABEL_LEVEL_NAME 1
2003 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
2004 #define MICROLABEL_LEVEL_AUTHOR 3
2005 #define MICROLABEL_IMPORTED_FROM_HEAD 4
2006 #define MICROLABEL_IMPORTED_FROM 5
2007 #define MICROLABEL_IMPORTED_BY_HEAD 6
2008 #define MICROLABEL_IMPORTED_BY 7
2010 static int getMaxTextLength(struct TextPosInfo *pos, int font_nr)
2012 int max_text_width = SXSIZE;
2013 int font_width = getFontWidth(font_nr);
2015 if (pos->align == ALIGN_CENTER)
2016 max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
2017 else if (pos->align == ALIGN_RIGHT)
2018 max_text_width = pos->x;
2020 max_text_width = SXSIZE - pos->x;
2022 return max_text_width / font_width;
2025 static void DrawPreviewLevelLabelExt(int mode)
2027 struct TextPosInfo *pos = &menu.main.text.level_info_2;
2028 char label_text[MAX_OUTPUT_LINESIZE + 1];
2029 int max_len_label_text;
2031 int font_nr = pos->font;
2034 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
2035 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
2036 mode == MICROLABEL_IMPORTED_BY_HEAD)
2037 font_nr = pos->font_alt;
2039 int font_nr = FONT_TEXT_2;
2042 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
2043 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
2044 mode == MICROLABEL_IMPORTED_BY_HEAD)
2045 font_nr = FONT_TEXT_3;
2049 max_len_label_text = getMaxTextLength(pos, font_nr);
2051 max_len_label_text = SXSIZE / getFontWidth(font_nr);
2055 if (pos->size != -1)
2056 max_len_label_text = pos->size;
2059 for (i = 0; i < max_len_label_text; i++)
2060 label_text[i] = ' ';
2061 label_text[max_len_label_text] = '\0';
2063 if (strlen(label_text) > 0)
2066 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2068 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
2069 int lypos = MICROLABEL2_YPOS;
2071 DrawText(lxpos, lypos, label_text, font_nr);
2076 (mode == MICROLABEL_LEVEL_NAME ? level.name :
2077 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
2078 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
2079 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
2080 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
2081 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
2082 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
2083 max_len_label_text);
2084 label_text[max_len_label_text] = '\0';
2086 if (strlen(label_text) > 0)
2089 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2091 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
2092 int lypos = MICROLABEL2_YPOS;
2094 DrawText(lxpos, lypos, label_text, font_nr);
2098 redraw_mask |= REDRAW_MICROLEVEL;
2101 void DrawPreviewLevel(boolean restart)
2103 static unsigned long scroll_delay = 0;
2104 static unsigned long label_delay = 0;
2105 static int from_x, from_y, scroll_direction;
2106 static int label_state, label_counter;
2107 unsigned long scroll_delay_value = preview.step_delay;
2108 boolean show_level_border = (BorderElement != EL_EMPTY);
2109 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2110 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2111 int last_game_status = game_status; /* save current game status */
2114 /* force PREVIEW font on preview level */
2115 game_status = GAME_MODE_PSEUDO_PREVIEW;
2123 if (preview.anim_mode == ANIM_CENTERED)
2125 if (level_xsize > preview.xsize)
2126 from_x = (level_xsize - preview.xsize) / 2;
2127 if (level_ysize > preview.ysize)
2128 from_y = (level_ysize - preview.ysize) / 2;
2131 from_x += preview.xoffset;
2132 from_y += preview.yoffset;
2134 scroll_direction = MV_RIGHT;
2138 DrawPreviewLevelExt(from_x, from_y);
2139 DrawPreviewLevelLabelExt(label_state);
2141 /* initialize delay counters */
2142 DelayReached(&scroll_delay, 0);
2143 DelayReached(&label_delay, 0);
2145 if (leveldir_current->name)
2147 struct TextPosInfo *pos = &menu.main.text.level_info_1;
2148 char label_text[MAX_OUTPUT_LINESIZE + 1];
2150 int font_nr = pos->font;
2152 int font_nr = FONT_TEXT_1;
2155 int max_len_label_text = getMaxTextLength(pos, font_nr);
2157 int max_len_label_text = SXSIZE / getFontWidth(font_nr);
2165 if (pos->size != -1)
2166 max_len_label_text = pos->size;
2169 strncpy(label_text, leveldir_current->name, max_len_label_text);
2170 label_text[max_len_label_text] = '\0';
2173 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2175 lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
2176 lypos = SY + MICROLABEL1_YPOS;
2178 DrawText(lxpos, lypos, label_text, font_nr);
2182 game_status = last_game_status; /* restore current game status */
2187 /* scroll preview level, if needed */
2188 if (preview.anim_mode != ANIM_NONE &&
2189 (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
2190 DelayReached(&scroll_delay, scroll_delay_value))
2192 switch (scroll_direction)
2197 from_x -= preview.step_offset;
2198 from_x = (from_x < 0 ? 0 : from_x);
2201 scroll_direction = MV_UP;
2205 if (from_x < level_xsize - preview.xsize)
2207 from_x += preview.step_offset;
2208 from_x = (from_x > level_xsize - preview.xsize ?
2209 level_xsize - preview.xsize : from_x);
2212 scroll_direction = MV_DOWN;
2218 from_y -= preview.step_offset;
2219 from_y = (from_y < 0 ? 0 : from_y);
2222 scroll_direction = MV_RIGHT;
2226 if (from_y < level_ysize - preview.ysize)
2228 from_y += preview.step_offset;
2229 from_y = (from_y > level_ysize - preview.ysize ?
2230 level_ysize - preview.ysize : from_y);
2233 scroll_direction = MV_LEFT;
2240 DrawPreviewLevelExt(from_x, from_y);
2243 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
2244 /* redraw micro level label, if needed */
2245 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
2246 !strEqual(level.author, ANONYMOUS_NAME) &&
2247 !strEqual(level.author, leveldir_current->name) &&
2248 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
2250 int max_label_counter = 23;
2252 if (leveldir_current->imported_from != NULL &&
2253 strlen(leveldir_current->imported_from) > 0)
2254 max_label_counter += 14;
2255 if (leveldir_current->imported_by != NULL &&
2256 strlen(leveldir_current->imported_by) > 0)
2257 max_label_counter += 14;
2259 label_counter = (label_counter + 1) % max_label_counter;
2260 label_state = (label_counter >= 0 && label_counter <= 7 ?
2261 MICROLABEL_LEVEL_NAME :
2262 label_counter >= 9 && label_counter <= 12 ?
2263 MICROLABEL_LEVEL_AUTHOR_HEAD :
2264 label_counter >= 14 && label_counter <= 21 ?
2265 MICROLABEL_LEVEL_AUTHOR :
2266 label_counter >= 23 && label_counter <= 26 ?
2267 MICROLABEL_IMPORTED_FROM_HEAD :
2268 label_counter >= 28 && label_counter <= 35 ?
2269 MICROLABEL_IMPORTED_FROM :
2270 label_counter >= 37 && label_counter <= 40 ?
2271 MICROLABEL_IMPORTED_BY_HEAD :
2272 label_counter >= 42 && label_counter <= 49 ?
2273 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
2275 if (leveldir_current->imported_from == NULL &&
2276 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
2277 label_state == MICROLABEL_IMPORTED_FROM))
2278 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
2279 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
2281 DrawPreviewLevelLabelExt(label_state);
2284 game_status = last_game_status; /* restore current game status */
2287 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
2288 int graphic, int sync_frame, int mask_mode)
2290 int frame = getGraphicAnimationFrame(graphic, sync_frame);
2292 if (mask_mode == USE_MASKING)
2293 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
2295 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
2298 inline void DrawGraphicAnimation(int x, int y, int graphic)
2300 int lx = LEVELX(x), ly = LEVELY(y);
2302 if (!IN_SCR_FIELD(x, y))
2305 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
2306 graphic, GfxFrame[lx][ly], NO_MASKING);
2307 MarkTileDirty(x, y);
2310 void DrawLevelGraphicAnimation(int x, int y, int graphic)
2312 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2315 void DrawLevelElementAnimation(int x, int y, int element)
2317 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2319 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2322 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
2324 int sx = SCREENX(x), sy = SCREENY(y);
2326 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2329 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2332 DrawGraphicAnimation(sx, sy, graphic);
2335 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
2336 DrawLevelFieldCrumbledSand(x, y);
2338 if (GFX_CRUMBLED(Feld[x][y]))
2339 DrawLevelFieldCrumbledSand(x, y);
2343 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
2345 int sx = SCREENX(x), sy = SCREENY(y);
2348 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2351 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2353 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2356 DrawGraphicAnimation(sx, sy, graphic);
2358 if (GFX_CRUMBLED(element))
2359 DrawLevelFieldCrumbledSand(x, y);
2362 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
2364 if (player->use_murphy)
2366 /* this works only because currently only one player can be "murphy" ... */
2367 static int last_horizontal_dir = MV_LEFT;
2368 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
2370 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2371 last_horizontal_dir = move_dir;
2373 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
2375 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
2377 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
2383 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
2386 static boolean equalGraphics(int graphic1, int graphic2)
2388 struct GraphicInfo *g1 = &graphic_info[graphic1];
2389 struct GraphicInfo *g2 = &graphic_info[graphic2];
2391 return (g1->bitmap == g2->bitmap &&
2392 g1->src_x == g2->src_x &&
2393 g1->src_y == g2->src_y &&
2394 g1->anim_frames == g2->anim_frames &&
2395 g1->anim_delay == g2->anim_delay &&
2396 g1->anim_mode == g2->anim_mode);
2399 void DrawAllPlayers()
2403 for (i = 0; i < MAX_PLAYERS; i++)
2404 if (stored_player[i].active)
2405 DrawPlayer(&stored_player[i]);
2408 void DrawPlayerField(int x, int y)
2410 if (!IS_PLAYER(x, y))
2413 DrawPlayer(PLAYERINFO(x, y));
2416 void DrawPlayer(struct PlayerInfo *player)
2418 int jx = player->jx;
2419 int jy = player->jy;
2420 int move_dir = player->MovDir;
2421 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
2422 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
2423 int last_jx = (player->is_moving ? jx - dx : jx);
2424 int last_jy = (player->is_moving ? jy - dy : jy);
2425 int next_jx = jx + dx;
2426 int next_jy = jy + dy;
2427 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
2428 boolean player_is_opaque = FALSE;
2429 int sx = SCREENX(jx), sy = SCREENY(jy);
2430 int sxx = 0, syy = 0;
2431 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
2433 int action = ACTION_DEFAULT;
2434 int last_player_graphic = getPlayerGraphic(player, move_dir);
2435 int last_player_frame = player->Frame;
2438 /* GfxElement[][] is set to the element the player is digging or collecting;
2439 remove also for off-screen player if the player is not moving anymore */
2440 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
2441 GfxElement[jx][jy] = EL_UNDEFINED;
2443 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
2447 if (!IN_LEV_FIELD(jx, jy))
2449 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
2450 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
2451 printf("DrawPlayerField(): This should never happen!\n");
2456 if (element == EL_EXPLOSION)
2459 action = (player->is_pushing ? ACTION_PUSHING :
2460 player->is_digging ? ACTION_DIGGING :
2461 player->is_collecting ? ACTION_COLLECTING :
2462 player->is_moving ? ACTION_MOVING :
2463 player->is_snapping ? ACTION_SNAPPING :
2464 player->is_dropping ? ACTION_DROPPING :
2465 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
2467 if (player->is_waiting)
2468 move_dir = player->dir_waiting;
2470 InitPlayerGfxAnimation(player, action, move_dir);
2472 /* ----------------------------------------------------------------------- */
2473 /* draw things in the field the player is leaving, if needed */
2474 /* ----------------------------------------------------------------------- */
2476 if (player->is_moving)
2478 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
2480 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
2482 if (last_element == EL_DYNAMITE_ACTIVE ||
2483 last_element == EL_EM_DYNAMITE_ACTIVE ||
2484 last_element == EL_SP_DISK_RED_ACTIVE)
2485 DrawDynamite(last_jx, last_jy);
2487 DrawLevelFieldThruMask(last_jx, last_jy);
2489 else if (last_element == EL_DYNAMITE_ACTIVE ||
2490 last_element == EL_EM_DYNAMITE_ACTIVE ||
2491 last_element == EL_SP_DISK_RED_ACTIVE)
2492 DrawDynamite(last_jx, last_jy);
2494 /* !!! this is not enough to prevent flickering of players which are
2495 moving next to each others without a free tile between them -- this
2496 can only be solved by drawing all players layer by layer (first the
2497 background, then the foreground etc.) !!! => TODO */
2498 else if (!IS_PLAYER(last_jx, last_jy))
2499 DrawLevelField(last_jx, last_jy);
2502 DrawLevelField(last_jx, last_jy);
2505 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
2506 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
2509 if (!IN_SCR_FIELD(sx, sy))
2512 /* ----------------------------------------------------------------------- */
2513 /* draw things behind the player, if needed */
2514 /* ----------------------------------------------------------------------- */
2517 DrawLevelElement(jx, jy, Back[jx][jy]);
2518 else if (IS_ACTIVE_BOMB(element))
2519 DrawLevelElement(jx, jy, EL_EMPTY);
2522 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
2524 int old_element = GfxElement[jx][jy];
2525 int old_graphic = el_act_dir2img(old_element, action, move_dir);
2526 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
2528 if (GFX_CRUMBLED(old_element))
2529 DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
2531 DrawGraphic(sx, sy, old_graphic, frame);
2533 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
2534 player_is_opaque = TRUE;
2538 GfxElement[jx][jy] = EL_UNDEFINED;
2540 /* make sure that pushed elements are drawn with correct frame rate */
2542 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2544 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
2545 GfxFrame[jx][jy] = player->StepFrame;
2547 if (player->is_pushing && player->is_moving)
2548 GfxFrame[jx][jy] = player->StepFrame;
2551 DrawLevelField(jx, jy);
2555 /* ----------------------------------------------------------------------- */
2556 /* draw player himself */
2557 /* ----------------------------------------------------------------------- */
2559 graphic = getPlayerGraphic(player, move_dir);
2561 /* in the case of changed player action or direction, prevent the current
2562 animation frame from being restarted for identical animations */
2563 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
2564 player->Frame = last_player_frame;
2566 frame = getGraphicAnimationFrame(graphic, player->Frame);
2570 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2571 sxx = player->GfxPos;
2573 syy = player->GfxPos;
2576 if (!setup.soft_scrolling && ScreenMovPos)
2579 if (player_is_opaque)
2580 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
2582 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2584 if (SHIELD_ON(player))
2586 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
2587 IMG_SHIELD_NORMAL_ACTIVE);
2588 int frame = getGraphicAnimationFrame(graphic, -1);
2590 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2593 /* ----------------------------------------------------------------------- */
2594 /* draw things the player is pushing, if needed */
2595 /* ----------------------------------------------------------------------- */
2598 printf("::: %d, %d [%d, %d] [%d]\n",
2599 player->is_pushing, player_is_moving, player->GfxAction,
2600 player->is_moving, player_is_moving);
2604 if (player->is_pushing && player->is_moving)
2606 int px = SCREENX(jx), py = SCREENY(jy);
2607 int pxx = (TILEX - ABS(sxx)) * dx;
2608 int pyy = (TILEY - ABS(syy)) * dy;
2609 int gfx_frame = GfxFrame[jx][jy];
2615 if (!IS_MOVING(jx, jy)) /* push movement already finished */
2617 element = Feld[next_jx][next_jy];
2618 gfx_frame = GfxFrame[next_jx][next_jy];
2621 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2624 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
2625 frame = getGraphicAnimationFrame(graphic, sync_frame);
2627 frame = getGraphicAnimationFrame(graphic, player->StepFrame);
2630 /* draw background element under pushed element (like the Sokoban field) */
2631 if (Back[next_jx][next_jy])
2632 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
2634 /* masked drawing is needed for EMC style (double) movement graphics */
2635 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
2639 /* ----------------------------------------------------------------------- */
2640 /* draw things in front of player (active dynamite or dynabombs) */
2641 /* ----------------------------------------------------------------------- */
2643 if (IS_ACTIVE_BOMB(element))
2645 graphic = el2img(element);
2646 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
2648 if (game.emulation == EMU_SUPAPLEX)
2649 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
2651 DrawGraphicThruMask(sx, sy, graphic, frame);
2654 if (player_is_moving && last_element == EL_EXPLOSION)
2656 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
2657 GfxElement[last_jx][last_jy] : EL_EMPTY);
2658 int graphic = el_act2img(element, ACTION_EXPLODING);
2659 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
2660 int phase = ExplodePhase[last_jx][last_jy] - 1;
2661 int frame = getGraphicAnimationFrame(graphic, phase - delay);
2664 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
2667 /* ----------------------------------------------------------------------- */
2668 /* draw elements the player is just walking/passing through/under */
2669 /* ----------------------------------------------------------------------- */
2671 if (player_is_moving)
2673 /* handle the field the player is leaving ... */
2674 if (IS_ACCESSIBLE_INSIDE(last_element))
2675 DrawLevelField(last_jx, last_jy);
2676 else if (IS_ACCESSIBLE_UNDER(last_element))
2677 DrawLevelFieldThruMask(last_jx, last_jy);
2680 /* do not redraw accessible elements if the player is just pushing them */
2681 if (!player_is_moving || !player->is_pushing)
2683 /* ... and the field the player is entering */
2684 if (IS_ACCESSIBLE_INSIDE(element))
2685 DrawLevelField(jx, jy);
2686 else if (IS_ACCESSIBLE_UNDER(element))
2687 DrawLevelFieldThruMask(jx, jy);
2690 MarkTileDirty(sx, sy);
2693 /* ------------------------------------------------------------------------- */
2695 void WaitForEventToContinue()
2697 boolean still_wait = TRUE;
2699 /* simulate releasing mouse button over last gadget, if still pressed */
2701 HandleGadgets(-1, -1, 0);
2703 button_status = MB_RELEASED;
2719 case EVENT_BUTTONPRESS:
2720 case EVENT_KEYPRESS:
2724 case EVENT_KEYRELEASE:
2725 ClearPlayerAction();
2729 HandleOtherEvents(&event);
2733 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2740 /* don't eat all CPU time */
2745 #define MAX_REQUEST_LINES 13
2746 #define MAX_REQUEST_LINE_FONT1_LEN 7
2747 #define MAX_REQUEST_LINE_FONT2_LEN 10
2749 boolean Request(char *text, unsigned int req_state)
2751 int mx, my, ty, result = -1;
2752 unsigned int old_door_state;
2753 int last_game_status = game_status; /* save current game status */
2754 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
2755 int font_nr = FONT_TEXT_2;
2756 int max_word_len = 0;
2759 for (text_ptr = text; *text_ptr; text_ptr++)
2761 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
2763 if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
2765 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
2767 font_nr = FONT_TEXT_1;
2769 font_nr = FONT_LEVEL_NUMBER;
2776 if (game_status == GAME_MODE_PLAYING &&
2777 level.game_engine_type == GAME_ENGINE_TYPE_EM)
2778 BlitScreenToBitmap_EM(backbuffer);
2780 /* disable deactivated drawing when quick-loading level tape recording */
2781 if (tape.playing && tape.deactivate_display)
2782 TapeDeactivateDisplayOff(TRUE);
2784 SetMouseCursor(CURSOR_DEFAULT);
2786 #if defined(NETWORK_AVALIABLE)
2787 /* pause network game while waiting for request to answer */
2788 if (options.network &&
2789 game_status == GAME_MODE_PLAYING &&
2790 req_state & REQUEST_WAIT_FOR_INPUT)
2791 SendToServer_PausePlaying();
2794 old_door_state = GetDoorState();
2796 /* simulate releasing mouse button over last gadget, if still pressed */
2798 HandleGadgets(-1, -1, 0);
2802 if (old_door_state & DOOR_OPEN_1)
2804 CloseDoor(DOOR_CLOSE_1);
2806 /* save old door content */
2807 BlitBitmap(bitmap_db_door, bitmap_db_door,
2808 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2809 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
2813 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2816 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2818 /* clear door drawing field */
2819 DrawBackground(DX, DY, DXSIZE, DYSIZE);
2821 /* force DOOR font inside door area */
2822 game_status = GAME_MODE_PSEUDO_DOOR;
2824 /* write text for request */
2825 for (ty = 0; ty < MAX_REQUEST_LINES; ty++)
2827 char text_line[max_request_line_len + 1];
2833 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
2836 if (!tc || tc == ' ')
2847 strncpy(text_line, text, tl);
2850 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
2851 DY + 8 + ty * (getFontHeight(font_nr) + 2),
2852 text_line, font_nr);
2854 text += tl + (tc == ' ' ? 1 : 0);
2857 game_status = last_game_status; /* restore current game status */
2859 if (req_state & REQ_ASK)
2861 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2862 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2864 else if (req_state & REQ_CONFIRM)
2866 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2868 else if (req_state & REQ_PLAYER)
2870 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2871 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2872 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2873 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2876 /* copy request gadgets to door backbuffer */
2877 BlitBitmap(drawto, bitmap_db_door,
2878 DX, DY, DXSIZE, DYSIZE,
2879 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2881 OpenDoor(DOOR_OPEN_1);
2883 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
2885 if (game_status == GAME_MODE_PLAYING)
2887 SetPanelBackground();
2888 SetDrawBackgroundMask(REDRAW_DOOR_1);
2892 SetDrawBackgroundMask(REDRAW_FIELD);
2898 if (game_status != GAME_MODE_MAIN)
2901 button_status = MB_RELEASED;
2903 request_gadget_id = -1;
2905 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2917 case EVENT_BUTTONPRESS:
2918 case EVENT_BUTTONRELEASE:
2919 case EVENT_MOTIONNOTIFY:
2921 if (event.type == EVENT_MOTIONNOTIFY)
2923 if (!PointerInWindow(window))
2924 continue; /* window and pointer are on different screens */
2929 motion_status = TRUE;
2930 mx = ((MotionEvent *) &event)->x;
2931 my = ((MotionEvent *) &event)->y;
2935 motion_status = FALSE;
2936 mx = ((ButtonEvent *) &event)->x;
2937 my = ((ButtonEvent *) &event)->y;
2938 if (event.type == EVENT_BUTTONPRESS)
2939 button_status = ((ButtonEvent *) &event)->button;
2941 button_status = MB_RELEASED;
2944 /* this sets 'request_gadget_id' */
2945 HandleGadgets(mx, my, button_status);
2947 switch (request_gadget_id)
2949 case TOOL_CTRL_ID_YES:
2952 case TOOL_CTRL_ID_NO:
2955 case TOOL_CTRL_ID_CONFIRM:
2956 result = TRUE | FALSE;
2959 case TOOL_CTRL_ID_PLAYER_1:
2962 case TOOL_CTRL_ID_PLAYER_2:
2965 case TOOL_CTRL_ID_PLAYER_3:
2968 case TOOL_CTRL_ID_PLAYER_4:
2979 case EVENT_KEYPRESS:
2980 switch (GetEventKey((KeyEvent *)&event, TRUE))
2983 if (req_state & REQ_CONFIRM)
2999 if (req_state & REQ_PLAYER)
3003 case EVENT_KEYRELEASE:
3004 ClearPlayerAction();
3008 HandleOtherEvents(&event);
3012 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3014 int joy = AnyJoystick();
3016 if (joy & JOY_BUTTON_1)
3018 else if (joy & JOY_BUTTON_2)
3024 if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd)
3026 HandleGameActions();
3032 if (!PendingEvent()) /* delay only if no pending events */
3043 if (!PendingEvent()) /* delay only if no pending events */
3046 /* don't eat all CPU time */
3053 if (game_status != GAME_MODE_MAIN)
3058 if (!(req_state & REQ_STAY_OPEN))
3060 CloseDoor(DOOR_CLOSE_1);
3062 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
3063 (req_state & REQ_REOPEN))
3064 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
3069 if (game_status == GAME_MODE_PLAYING)
3071 SetPanelBackground();
3072 SetDrawBackgroundMask(REDRAW_DOOR_1);
3076 SetDrawBackgroundMask(REDRAW_FIELD);
3079 #if defined(NETWORK_AVALIABLE)
3080 /* continue network game after request */
3081 if (options.network &&
3082 game_status == GAME_MODE_PLAYING &&
3083 req_state & REQUEST_WAIT_FOR_INPUT)
3084 SendToServer_ContinuePlaying();
3087 /* restore deactivated drawing when quick-loading level tape recording */
3088 if (tape.playing && tape.deactivate_display)
3089 TapeDeactivateDisplayOn();
3094 unsigned int OpenDoor(unsigned int door_state)
3096 if (door_state & DOOR_COPY_BACK)
3098 if (door_state & DOOR_OPEN_1)
3099 BlitBitmap(bitmap_db_door, bitmap_db_door,
3100 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
3101 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
3103 if (door_state & DOOR_OPEN_2)
3104 BlitBitmap(bitmap_db_door, bitmap_db_door,
3105 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
3106 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
3108 door_state &= ~DOOR_COPY_BACK;
3111 return MoveDoor(door_state);
3114 unsigned int CloseDoor(unsigned int door_state)
3116 unsigned int old_door_state = GetDoorState();
3118 if (!(door_state & DOOR_NO_COPY_BACK))
3120 if (old_door_state & DOOR_OPEN_1)
3121 BlitBitmap(backbuffer, bitmap_db_door,
3122 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
3124 if (old_door_state & DOOR_OPEN_2)
3125 BlitBitmap(backbuffer, bitmap_db_door,
3126 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
3128 door_state &= ~DOOR_NO_COPY_BACK;
3131 return MoveDoor(door_state);
3134 unsigned int GetDoorState()
3136 return MoveDoor(DOOR_GET_STATE);
3139 unsigned int SetDoorState(unsigned int door_state)
3141 return MoveDoor(door_state | DOOR_SET_STATE);
3144 unsigned int MoveDoor(unsigned int door_state)
3146 static int door1 = DOOR_OPEN_1;
3147 static int door2 = DOOR_CLOSE_2;
3148 unsigned long door_delay = 0;
3149 unsigned long door_delay_value;
3152 if (door_1.width < 0 || door_1.width > DXSIZE)
3153 door_1.width = DXSIZE;
3154 if (door_1.height < 0 || door_1.height > DYSIZE)
3155 door_1.height = DYSIZE;
3156 if (door_2.width < 0 || door_2.width > VXSIZE)
3157 door_2.width = VXSIZE;
3158 if (door_2.height < 0 || door_2.height > VYSIZE)
3159 door_2.height = VYSIZE;
3161 if (door_state == DOOR_GET_STATE)
3162 return (door1 | door2);
3164 if (door_state & DOOR_SET_STATE)
3166 if (door_state & DOOR_ACTION_1)
3167 door1 = door_state & DOOR_ACTION_1;
3168 if (door_state & DOOR_ACTION_2)
3169 door2 = door_state & DOOR_ACTION_2;
3171 return (door1 | door2);
3174 if (!(door_state & DOOR_FORCE_REDRAW))
3176 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
3177 door_state &= ~DOOR_OPEN_1;
3178 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
3179 door_state &= ~DOOR_CLOSE_1;
3180 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
3181 door_state &= ~DOOR_OPEN_2;
3182 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
3183 door_state &= ~DOOR_CLOSE_2;
3186 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
3189 if (setup.quick_doors)
3191 stepsize = 20; /* must be chosen to always draw last frame */
3192 door_delay_value = 0;
3195 if (global.autoplay_leveldir)
3197 door_state |= DOOR_NO_DELAY;
3198 door_state &= ~DOOR_CLOSE_ALL;
3201 if (door_state & DOOR_ACTION)
3203 boolean handle_door_1 = (door_state & DOOR_ACTION_1);
3204 boolean handle_door_2 = (door_state & DOOR_ACTION_2);
3205 boolean door_1_done = (!handle_door_1);
3206 boolean door_2_done = (!handle_door_2);
3207 boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
3208 boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
3209 int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
3210 int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
3211 int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
3212 int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
3213 int door_size = (handle_door_1 ? door_size_1 : door_size_2);
3214 int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
3215 int door_skip = max_door_size - door_size;
3216 int end = door_size;
3217 int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
3220 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
3222 /* opening door sound has priority over simultaneously closing door */
3223 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
3224 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
3225 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
3226 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
3229 for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
3232 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3233 GC gc = bitmap->stored_clip_gc;
3235 if (door_state & DOOR_ACTION_1)
3237 int a = MIN(x * door_1.step_offset, end);
3238 int p = (door_state & DOOR_OPEN_1 ? end - a : a);
3239 int i = p + door_skip;
3241 if (door_1.anim_mode & ANIM_STATIC_PANEL)
3243 BlitBitmap(bitmap_db_door, drawto,
3244 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
3245 DXSIZE, DYSIZE, DX, DY);
3249 BlitBitmap(bitmap_db_door, drawto,
3250 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
3251 DXSIZE, DYSIZE - p / 2, DX, DY);
3253 ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
3256 if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
3258 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
3259 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
3260 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
3261 int dst2_x = DX, dst2_y = DY;
3262 int width = i, height = DYSIZE;
3264 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3265 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3268 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3269 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3272 else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
3274 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
3275 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
3276 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
3277 int dst2_x = DX, dst2_y = DY;
3278 int width = DXSIZE, height = i;
3280 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3281 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3284 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3285 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3288 else if (x <= DXSIZE) /* ANIM_DEFAULT */
3290 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
3292 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
3293 BlitBitmapMasked(bitmap, drawto,
3294 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
3295 DX + DXSIZE - i, DY + j);
3296 BlitBitmapMasked(bitmap, drawto,
3297 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
3298 DX + DXSIZE - i, DY + 140 + j);
3299 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
3300 DY - (DOOR_GFX_PAGEY1 + j));
3301 BlitBitmapMasked(bitmap, drawto,
3302 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
3304 BlitBitmapMasked(bitmap, drawto,
3305 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
3308 BlitBitmapMasked(bitmap, drawto,
3309 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
3311 BlitBitmapMasked(bitmap, drawto,
3312 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
3314 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
3315 BlitBitmapMasked(bitmap, drawto,
3316 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
3317 DX + DXSIZE - i, DY + 77 + j);
3318 BlitBitmapMasked(bitmap, drawto,
3319 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
3320 DX + DXSIZE - i, DY + 203 + j);
3323 redraw_mask |= REDRAW_DOOR_1;
3324 door_1_done = (a == end);
3327 if (door_state & DOOR_ACTION_2)
3329 int a = MIN(x * door_2.step_offset, door_size);
3330 int p = (door_state & DOOR_OPEN_2 ? door_size - a : a);
3331 int i = p + door_skip;
3333 if (door_2.anim_mode & ANIM_STATIC_PANEL)
3335 BlitBitmap(bitmap_db_door, drawto,
3336 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
3337 VXSIZE, VYSIZE, VX, VY);
3339 else if (x <= VYSIZE)
3341 BlitBitmap(bitmap_db_door, drawto,
3342 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
3343 VXSIZE, VYSIZE - p / 2, VX, VY);
3345 ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
3348 if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
3350 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
3351 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
3352 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
3353 int dst2_x = VX, dst2_y = VY;
3354 int width = i, height = VYSIZE;
3356 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3357 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3360 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3361 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3364 else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
3366 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
3367 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
3368 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
3369 int dst2_x = VX, dst2_y = VY;
3370 int width = VXSIZE, height = i;
3372 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3373 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3376 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3377 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3380 else if (x <= VXSIZE) /* ANIM_DEFAULT */
3382 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
3384 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3385 BlitBitmapMasked(bitmap, drawto,
3386 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
3387 VX + VXSIZE - i, VY + j);
3388 SetClipOrigin(bitmap, gc,
3389 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
3390 BlitBitmapMasked(bitmap, drawto,
3391 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
3394 BlitBitmapMasked(bitmap, drawto,
3395 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3396 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
3397 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3398 BlitBitmapMasked(bitmap, drawto,
3399 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3401 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
3404 redraw_mask |= REDRAW_DOOR_2;
3405 door_2_done = (a == VXSIZE);
3408 if (!(door_state & DOOR_NO_DELAY))
3412 if (game_status == GAME_MODE_MAIN)
3415 WaitUntilDelayReached(&door_delay, door_delay_value);
3420 if (door_state & DOOR_ACTION_1)
3421 door1 = door_state & DOOR_ACTION_1;
3422 if (door_state & DOOR_ACTION_2)
3423 door2 = door_state & DOOR_ACTION_2;
3425 return (door1 | door2);
3428 void DrawSpecialEditorDoor()
3430 /* draw bigger toolbox window */
3431 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
3432 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
3434 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3435 EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
3438 redraw_mask |= REDRAW_ALL;
3441 void UndrawSpecialEditorDoor()
3443 /* draw normal tape recorder window */
3444 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3445 EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
3448 redraw_mask |= REDRAW_ALL;
3452 /* ---------- new tool button stuff ---------------------------------------- */
3454 /* graphic position values for tool buttons */
3455 #define TOOL_BUTTON_YES_XPOS 2
3456 #define TOOL_BUTTON_YES_YPOS 250
3457 #define TOOL_BUTTON_YES_GFX_YPOS 0
3458 #define TOOL_BUTTON_YES_XSIZE 46
3459 #define TOOL_BUTTON_YES_YSIZE 28
3460 #define TOOL_BUTTON_NO_XPOS 52
3461 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
3462 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
3463 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
3464 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
3465 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
3466 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
3467 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
3468 #define TOOL_BUTTON_CONFIRM_XSIZE 96
3469 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
3470 #define TOOL_BUTTON_PLAYER_XSIZE 30
3471 #define TOOL_BUTTON_PLAYER_YSIZE 30
3472 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
3473 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
3474 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
3475 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
3476 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3477 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3478 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3479 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3480 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3481 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3482 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3483 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3484 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3485 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3486 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3487 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3488 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3489 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3490 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3491 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3500 } toolbutton_info[NUM_TOOL_BUTTONS] =
3503 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
3504 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
3505 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
3510 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
3511 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
3512 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
3517 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
3518 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
3519 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
3520 TOOL_CTRL_ID_CONFIRM,
3524 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3525 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
3526 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3527 TOOL_CTRL_ID_PLAYER_1,
3531 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3532 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
3533 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3534 TOOL_CTRL_ID_PLAYER_2,
3538 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3539 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
3540 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3541 TOOL_CTRL_ID_PLAYER_3,
3545 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3546 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
3547 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3548 TOOL_CTRL_ID_PLAYER_4,
3553 void CreateToolButtons()
3557 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3559 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3560 Bitmap *deco_bitmap = None;
3561 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
3562 struct GadgetInfo *gi;
3563 unsigned long event_mask;
3564 int gd_xoffset, gd_yoffset;
3565 int gd_x1, gd_x2, gd_y;
3568 event_mask = GD_EVENT_RELEASED;
3570 gd_xoffset = toolbutton_info[i].xpos;
3571 gd_yoffset = toolbutton_info[i].ypos;
3572 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
3573 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
3574 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
3576 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
3578 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
3580 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
3581 &deco_bitmap, &deco_x, &deco_y);
3582 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
3583 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
3586 gi = CreateGadget(GDI_CUSTOM_ID, id,
3587 GDI_INFO_TEXT, toolbutton_info[i].infotext,
3588 GDI_X, DX + toolbutton_info[i].x,
3589 GDI_Y, DY + toolbutton_info[i].y,
3590 GDI_WIDTH, toolbutton_info[i].width,
3591 GDI_HEIGHT, toolbutton_info[i].height,
3592 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
3593 GDI_STATE, GD_BUTTON_UNPRESSED,
3594 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
3595 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
3596 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
3597 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
3598 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
3599 GDI_DECORATION_SHIFTING, 1, 1,
3600 GDI_DIRECT_DRAW, FALSE,
3601 GDI_EVENT_MASK, event_mask,
3602 GDI_CALLBACK_ACTION, HandleToolButtons,
3606 Error(ERR_EXIT, "cannot create gadget");
3608 tool_gadget[id] = gi;
3612 void FreeToolButtons()
3616 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3617 FreeGadget(tool_gadget[i]);
3620 static void UnmapToolButtons()
3624 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3625 UnmapGadget(tool_gadget[i]);
3628 static void HandleToolButtons(struct GadgetInfo *gi)
3630 request_gadget_id = gi->custom_id;
3633 static struct Mapping_EM_to_RND_object
3636 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
3637 boolean is_backside; /* backside of moving element */
3643 em_object_mapping_list[] =
3646 Xblank, TRUE, FALSE,
3650 Yacid_splash_eB, FALSE, FALSE,
3651 EL_ACID_SPLASH_RIGHT, -1, -1
3654 Yacid_splash_wB, FALSE, FALSE,
3655 EL_ACID_SPLASH_LEFT, -1, -1
3658 #ifdef EM_ENGINE_BAD_ROLL
3660 Xstone_force_e, FALSE, FALSE,
3661 EL_ROCK, -1, MV_BIT_RIGHT
3664 Xstone_force_w, FALSE, FALSE,
3665 EL_ROCK, -1, MV_BIT_LEFT
3668 Xnut_force_e, FALSE, FALSE,
3669 EL_NUT, -1, MV_BIT_RIGHT
3672 Xnut_force_w, FALSE, FALSE,
3673 EL_NUT, -1, MV_BIT_LEFT
3676 Xspring_force_e, FALSE, FALSE,
3677 EL_SPRING, -1, MV_BIT_RIGHT
3680 Xspring_force_w, FALSE, FALSE,
3681 EL_SPRING, -1, MV_BIT_LEFT
3684 Xemerald_force_e, FALSE, FALSE,
3685 EL_EMERALD, -1, MV_BIT_RIGHT
3688 Xemerald_force_w, FALSE, FALSE,
3689 EL_EMERALD, -1, MV_BIT_LEFT
3692 Xdiamond_force_e, FALSE, FALSE,
3693 EL_DIAMOND, -1, MV_BIT_RIGHT
3696 Xdiamond_force_w, FALSE, FALSE,
3697 EL_DIAMOND, -1, MV_BIT_LEFT
3700 Xbomb_force_e, FALSE, FALSE,
3701 EL_BOMB, -1, MV_BIT_RIGHT
3704 Xbomb_force_w, FALSE, FALSE,
3705 EL_BOMB, -1, MV_BIT_LEFT
3707 #endif /* EM_ENGINE_BAD_ROLL */
3710 Xstone, TRUE, FALSE,
3714 Xstone_pause, FALSE, FALSE,
3718 Xstone_fall, FALSE, FALSE,
3722 Ystone_s, FALSE, FALSE,
3723 EL_ROCK, ACTION_FALLING, -1
3726 Ystone_sB, FALSE, TRUE,
3727 EL_ROCK, ACTION_FALLING, -1
3730 Ystone_e, FALSE, FALSE,
3731 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3734 Ystone_eB, FALSE, TRUE,
3735 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3738 Ystone_w, FALSE, FALSE,
3739 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3742 Ystone_wB, FALSE, TRUE,
3743 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3750 Xnut_pause, FALSE, FALSE,
3754 Xnut_fall, FALSE, FALSE,
3758 Ynut_s, FALSE, FALSE,
3759 EL_NUT, ACTION_FALLING, -1
3762 Ynut_sB, FALSE, TRUE,
3763 EL_NUT, ACTION_FALLING, -1
3766 Ynut_e, FALSE, FALSE,
3767 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3770 Ynut_eB, FALSE, TRUE,
3771 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3774 Ynut_w, FALSE, FALSE,
3775 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3778 Ynut_wB, FALSE, TRUE,
3779 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3782 Xbug_n, TRUE, FALSE,
3786 Xbug_e, TRUE, FALSE,
3787 EL_BUG_RIGHT, -1, -1
3790 Xbug_s, TRUE, FALSE,
3794 Xbug_w, TRUE, FALSE,
3798 Xbug_gon, FALSE, FALSE,
3802 Xbug_goe, FALSE, FALSE,
3803 EL_BUG_RIGHT, -1, -1
3806 Xbug_gos, FALSE, FALSE,
3810 Xbug_gow, FALSE, FALSE,
3814 Ybug_n, FALSE, FALSE,
3815 EL_BUG, ACTION_MOVING, MV_BIT_UP
3818 Ybug_nB, FALSE, TRUE,
3819 EL_BUG, ACTION_MOVING, MV_BIT_UP
3822 Ybug_e, FALSE, FALSE,
3823 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3826 Ybug_eB, FALSE, TRUE,
3827 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3830 Ybug_s, FALSE, FALSE,
3831 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3834 Ybug_sB, FALSE, TRUE,
3835 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3838 Ybug_w, FALSE, FALSE,
3839 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3842 Ybug_wB, FALSE, TRUE,
3843 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3846 Ybug_w_n, FALSE, FALSE,
3847 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3850 Ybug_n_e, FALSE, FALSE,
3851 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3854 Ybug_e_s, FALSE, FALSE,
3855 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3858 Ybug_s_w, FALSE, FALSE,
3859 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3862 Ybug_e_n, FALSE, FALSE,
3863 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3866 Ybug_s_e, FALSE, FALSE,
3867 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3870 Ybug_w_s, FALSE, FALSE,
3871 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3874 Ybug_n_w, FALSE, FALSE,
3875 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3878 Ybug_stone, FALSE, FALSE,
3879 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
3882 Ybug_spring, FALSE, FALSE,
3883 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
3886 Xtank_n, TRUE, FALSE,
3887 EL_SPACESHIP_UP, -1, -1
3890 Xtank_e, TRUE, FALSE,
3891 EL_SPACESHIP_RIGHT, -1, -1
3894 Xtank_s, TRUE, FALSE,
3895 EL_SPACESHIP_DOWN, -1, -1
3898 Xtank_w, TRUE, FALSE,
3899 EL_SPACESHIP_LEFT, -1, -1
3902 Xtank_gon, FALSE, FALSE,
3903 EL_SPACESHIP_UP, -1, -1
3906 Xtank_goe, FALSE, FALSE,
3907 EL_SPACESHIP_RIGHT, -1, -1
3910 Xtank_gos, FALSE, FALSE,
3911 EL_SPACESHIP_DOWN, -1, -1
3914 Xtank_gow, FALSE, FALSE,
3915 EL_SPACESHIP_LEFT, -1, -1
3918 Ytank_n, FALSE, FALSE,
3919 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3922 Ytank_nB, FALSE, TRUE,
3923 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3926 Ytank_e, FALSE, FALSE,
3927 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3930 Ytank_eB, FALSE, TRUE,
3931 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3934 Ytank_s, FALSE, FALSE,
3935 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3938 Ytank_sB, FALSE, TRUE,
3939 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3942 Ytank_w, FALSE, FALSE,
3943 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3946 Ytank_wB, FALSE, TRUE,
3947 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3950 Ytank_w_n, FALSE, FALSE,
3951 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3954 Ytank_n_e, FALSE, FALSE,
3955 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3958 Ytank_e_s, FALSE, FALSE,
3959 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3962 Ytank_s_w, FALSE, FALSE,
3963 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3966 Ytank_e_n, FALSE, FALSE,
3967 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3970 Ytank_s_e, FALSE, FALSE,
3971 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3974 Ytank_w_s, FALSE, FALSE,
3975 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3978 Ytank_n_w, FALSE, FALSE,
3979 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3982 Ytank_stone, FALSE, FALSE,
3983 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
3986 Ytank_spring, FALSE, FALSE,
3987 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
3990 Xandroid, TRUE, FALSE,
3991 EL_EMC_ANDROID, ACTION_ACTIVE, -1
3994 Xandroid_1_n, FALSE, FALSE,
3995 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3998 Xandroid_2_n, FALSE, FALSE,
3999 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
4002 Xandroid_1_e, FALSE, FALSE,
4003 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
4006 Xandroid_2_e, FALSE, FALSE,
4007 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
4010 Xandroid_1_w, FALSE, FALSE,
4011 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
4014 Xandroid_2_w, FALSE, FALSE,
4015 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
4018 Xandroid_1_s, FALSE, FALSE,
4019 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
4022 Xandroid_2_s, FALSE, FALSE,
4023 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
4026 Yandroid_n, FALSE, FALSE,
4027 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
4030 Yandroid_nB, FALSE, TRUE,
4031 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
4034 Yandroid_ne, FALSE, FALSE,
4035 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
4038 Yandroid_neB, FALSE, TRUE,
4039 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
4042 Yandroid_e, FALSE, FALSE,
4043 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
4046 Yandroid_eB, FALSE, TRUE,
4047 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
4050 Yandroid_se, FALSE, FALSE,
4051 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
4054 Yandroid_seB, FALSE, TRUE,
4055 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
4058 Yandroid_s, FALSE, FALSE,
4059 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
4062 Yandroid_sB, FALSE, TRUE,
4063 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
4066 Yandroid_sw, FALSE, FALSE,
4067 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
4070 Yandroid_swB, FALSE, TRUE,
4071 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
4074 Yandroid_w, FALSE, FALSE,
4075 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
4078 Yandroid_wB, FALSE, TRUE,
4079 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
4082 Yandroid_nw, FALSE, FALSE,
4083 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
4086 Yandroid_nwB, FALSE, TRUE,
4087 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
4090 Xspring, TRUE, FALSE,
4094 Xspring_pause, FALSE, FALSE,
4098 Xspring_e, FALSE, FALSE,
4102 Xspring_w, FALSE, FALSE,
4106 Xspring_fall, FALSE, FALSE,
4110 Yspring_s, FALSE, FALSE,
4111 EL_SPRING, ACTION_FALLING, -1
4114 Yspring_sB, FALSE, TRUE,
4115 EL_SPRING, ACTION_FALLING, -1
4118 Yspring_e, FALSE, FALSE,
4119 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
4122 Yspring_eB, FALSE, TRUE,
4123 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
4126 Yspring_w, FALSE, FALSE,
4127 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
4130 Yspring_wB, FALSE, TRUE,
4131 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
4134 Yspring_kill_e, FALSE, FALSE,
4135 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
4138 Yspring_kill_eB, FALSE, TRUE,
4139 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
4142 Yspring_kill_w, FALSE, FALSE,
4143 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
4146 Yspring_kill_wB, FALSE, TRUE,
4147 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
4150 Xeater_n, TRUE, FALSE,
4151 EL_YAMYAM_UP, -1, -1
4154 Xeater_e, TRUE, FALSE,
4155 EL_YAMYAM_RIGHT, -1, -1
4158 Xeater_w, TRUE, FALSE,
4159 EL_YAMYAM_LEFT, -1, -1
4162 Xeater_s, TRUE, FALSE,
4163 EL_YAMYAM_DOWN, -1, -1
4166 Yeater_n, FALSE, FALSE,
4167 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
4170 Yeater_nB, FALSE, TRUE,
4171 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
4174 Yeater_e, FALSE, FALSE,
4175 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
4178 Yeater_eB, FALSE, TRUE,
4179 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
4182 Yeater_s, FALSE, FALSE,
4183 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
4186 Yeater_sB, FALSE, TRUE,
4187 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
4190 Yeater_w, FALSE, FALSE,
4191 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
4194 Yeater_wB, FALSE, TRUE,
4195 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
4198 Yeater_stone, FALSE, FALSE,
4199 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
4202 Yeater_spring, FALSE, FALSE,
4203 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
4206 Xalien, TRUE, FALSE,
4210 Xalien_pause, FALSE, FALSE,
4214 Yalien_n, FALSE, FALSE,
4215 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
4218 Yalien_nB, FALSE, TRUE,
4219 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
4222 Yalien_e, FALSE, FALSE,
4223 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
4226 Yalien_eB, FALSE, TRUE,
4227 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
4230 Yalien_s, FALSE, FALSE,
4231 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
4234 Yalien_sB, FALSE, TRUE,
4235 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
4238 Yalien_w, FALSE, FALSE,
4239 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
4242 Yalien_wB, FALSE, TRUE,
4243 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
4246 Yalien_stone, FALSE, FALSE,
4247 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
4250 Yalien_spring, FALSE, FALSE,
4251 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
4254 Xemerald, TRUE, FALSE,
4258 Xemerald_pause, FALSE, FALSE,
4262 Xemerald_fall, FALSE, FALSE,
4266 Xemerald_shine, FALSE, FALSE,
4267 EL_EMERALD, ACTION_TWINKLING, -1
4270 Yemerald_s, FALSE, FALSE,
4271 EL_EMERALD, ACTION_FALLING, -1
4274 Yemerald_sB, FALSE, TRUE,
4275 EL_EMERALD, ACTION_FALLING, -1
4278 Yemerald_e, FALSE, FALSE,
4279 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
4282 Yemerald_eB, FALSE, TRUE,
4283 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
4286 Yemerald_w, FALSE, FALSE,
4287 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
4290 Yemerald_wB, FALSE, TRUE,
4291 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
4294 Yemerald_eat, FALSE, FALSE,
4295 EL_EMERALD, ACTION_COLLECTING, -1
4298 Yemerald_stone, FALSE, FALSE,
4299 EL_NUT, ACTION_BREAKING, -1
4302 Xdiamond, TRUE, FALSE,
4306 Xdiamond_pause, FALSE, FALSE,
4310 Xdiamond_fall, FALSE, FALSE,
4314 Xdiamond_shine, FALSE, FALSE,
4315 EL_DIAMOND, ACTION_TWINKLING, -1
4318 Ydiamond_s, FALSE, FALSE,
4319 EL_DIAMOND, ACTION_FALLING, -1
4322 Ydiamond_sB, FALSE, TRUE,
4323 EL_DIAMOND, ACTION_FALLING, -1
4326 Ydiamond_e, FALSE, FALSE,
4327 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
4330 Ydiamond_eB, FALSE, TRUE,
4331 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
4334 Ydiamond_w, FALSE, FALSE,
4335 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
4338 Ydiamond_wB, FALSE, TRUE,
4339 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
4342 Ydiamond_eat, FALSE, FALSE,
4343 EL_DIAMOND, ACTION_COLLECTING, -1
4346 Ydiamond_stone, FALSE, FALSE,
4347 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
4350 Xdrip_fall, TRUE, FALSE,
4351 EL_AMOEBA_DROP, -1, -1
4354 Xdrip_stretch, FALSE, FALSE,
4355 EL_AMOEBA_DROP, ACTION_FALLING, -1
4358 Xdrip_stretchB, FALSE, TRUE,
4359 EL_AMOEBA_DROP, ACTION_FALLING, -1
4362 Xdrip_eat, FALSE, FALSE,
4363 EL_AMOEBA_DROP, ACTION_GROWING, -1
4366 Ydrip_s1, FALSE, FALSE,
4367 EL_AMOEBA_DROP, ACTION_FALLING, -1
4370 Ydrip_s1B, FALSE, TRUE,
4371 EL_AMOEBA_DROP, ACTION_FALLING, -1
4374 Ydrip_s2, FALSE, FALSE,
4375 EL_AMOEBA_DROP, ACTION_FALLING, -1
4378 Ydrip_s2B, FALSE, TRUE,
4379 EL_AMOEBA_DROP, ACTION_FALLING, -1
4386 Xbomb_pause, FALSE, FALSE,
4390 Xbomb_fall, FALSE, FALSE,
4394 Ybomb_s, FALSE, FALSE,
4395 EL_BOMB, ACTION_FALLING, -1
4398 Ybomb_sB, FALSE, TRUE,
4399 EL_BOMB, ACTION_FALLING, -1
4402 Ybomb_e, FALSE, FALSE,
4403 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
4406 Ybomb_eB, FALSE, TRUE,
4407 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
4410 Ybomb_w, FALSE, FALSE,
4411 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
4414 Ybomb_wB, FALSE, TRUE,
4415 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
4418 Ybomb_eat, FALSE, FALSE,
4419 EL_BOMB, ACTION_ACTIVATING, -1
4422 Xballoon, TRUE, FALSE,
4426 Yballoon_n, FALSE, FALSE,
4427 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
4430 Yballoon_nB, FALSE, TRUE,
4431 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
4434 Yballoon_e, FALSE, FALSE,
4435 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
4438 Yballoon_eB, FALSE, TRUE,
4439 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
4442 Yballoon_s, FALSE, FALSE,
4443 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
4446 Yballoon_sB, FALSE, TRUE,
4447 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
4450 Yballoon_w, FALSE, FALSE,
4451 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
4454 Yballoon_wB, FALSE, TRUE,
4455 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
4458 Xgrass, TRUE, FALSE,
4459 EL_EMC_GRASS, -1, -1
4462 Ygrass_nB, FALSE, FALSE,
4463 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
4466 Ygrass_eB, FALSE, FALSE,
4467 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
4470 Ygrass_sB, FALSE, FALSE,
4471 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
4474 Ygrass_wB, FALSE, FALSE,
4475 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
4482 Ydirt_nB, FALSE, FALSE,
4483 EL_SAND, ACTION_DIGGING, MV_BIT_UP
4486 Ydirt_eB, FALSE, FALSE,
4487 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
4490 Ydirt_sB, FALSE, FALSE,
4491 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
4494 Ydirt_wB, FALSE, FALSE,
4495 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
4498 Xacid_ne, TRUE, FALSE,
4499 EL_ACID_POOL_TOPRIGHT, -1, -1
4502 Xacid_se, TRUE, FALSE,
4503 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
4506 Xacid_s, TRUE, FALSE,
4507 EL_ACID_POOL_BOTTOM, -1, -1
4510 Xacid_sw, TRUE, FALSE,
4511 EL_ACID_POOL_BOTTOMLEFT, -1, -1
4514 Xacid_nw, TRUE, FALSE,
4515 EL_ACID_POOL_TOPLEFT, -1, -1
4518 Xacid_1, TRUE, FALSE,
4522 Xacid_2, FALSE, FALSE,
4526 Xacid_3, FALSE, FALSE,
4530 Xacid_4, FALSE, FALSE,
4534 Xacid_5, FALSE, FALSE,
4538 Xacid_6, FALSE, FALSE,
4542 Xacid_7, FALSE, FALSE,
4546 Xacid_8, FALSE, FALSE,
4550 Xball_1, TRUE, FALSE,
4551 EL_EMC_MAGIC_BALL, -1, -1
4554 Xball_1B, FALSE, FALSE,
4555 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4558 Xball_2, FALSE, FALSE,
4559 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4562 Xball_2B, FALSE, FALSE,
4563 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4566 Yball_eat, FALSE, FALSE,
4567 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
4570 Ykey_1_eat, FALSE, FALSE,
4571 EL_EM_KEY_1, ACTION_COLLECTING, -1
4574 Ykey_2_eat, FALSE, FALSE,
4575 EL_EM_KEY_2, ACTION_COLLECTING, -1
4578 Ykey_3_eat, FALSE, FALSE,
4579 EL_EM_KEY_3, ACTION_COLLECTING, -1
4582 Ykey_4_eat, FALSE, FALSE,
4583 EL_EM_KEY_4, ACTION_COLLECTING, -1
4586 Ykey_5_eat, FALSE, FALSE,
4587 EL_EMC_KEY_5, ACTION_COLLECTING, -1
4590 Ykey_6_eat, FALSE, FALSE,
4591 EL_EMC_KEY_6, ACTION_COLLECTING, -1
4594 Ykey_7_eat, FALSE, FALSE,
4595 EL_EMC_KEY_7, ACTION_COLLECTING, -1
4598 Ykey_8_eat, FALSE, FALSE,
4599 EL_EMC_KEY_8, ACTION_COLLECTING, -1
4602 Ylenses_eat, FALSE, FALSE,
4603 EL_EMC_LENSES, ACTION_COLLECTING, -1
4606 Ymagnify_eat, FALSE, FALSE,
4607 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
4610 Ygrass_eat, FALSE, FALSE,
4611 EL_EMC_GRASS, ACTION_SNAPPING, -1
4614 Ydirt_eat, FALSE, FALSE,
4615 EL_SAND, ACTION_SNAPPING, -1
4618 Xgrow_ns, TRUE, FALSE,
4619 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
4622 Ygrow_ns_eat, FALSE, FALSE,
4623 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
4626 Xgrow_ew, TRUE, FALSE,
4627 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
4630 Ygrow_ew_eat, FALSE, FALSE,
4631 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
4634 Xwonderwall, TRUE, FALSE,
4635 EL_MAGIC_WALL, -1, -1
4638 XwonderwallB, FALSE, FALSE,
4639 EL_MAGIC_WALL, ACTION_ACTIVE, -1
4642 Xamoeba_1, TRUE, FALSE,
4643 EL_AMOEBA_DRY, ACTION_OTHER, -1
4646 Xamoeba_2, FALSE, FALSE,
4647 EL_AMOEBA_DRY, ACTION_OTHER, -1
4650 Xamoeba_3, FALSE, FALSE,
4651 EL_AMOEBA_DRY, ACTION_OTHER, -1
4654 Xamoeba_4, FALSE, FALSE,
4655 EL_AMOEBA_DRY, ACTION_OTHER, -1
4658 Xamoeba_5, TRUE, FALSE,
4659 EL_AMOEBA_WET, ACTION_OTHER, -1
4662 Xamoeba_6, FALSE, FALSE,
4663 EL_AMOEBA_WET, ACTION_OTHER, -1
4666 Xamoeba_7, FALSE, FALSE,
4667 EL_AMOEBA_WET, ACTION_OTHER, -1
4670 Xamoeba_8, FALSE, FALSE,
4671 EL_AMOEBA_WET, ACTION_OTHER, -1
4674 Xdoor_1, TRUE, FALSE,
4675 EL_EM_GATE_1, -1, -1
4678 Xdoor_2, TRUE, FALSE,
4679 EL_EM_GATE_2, -1, -1
4682 Xdoor_3, TRUE, FALSE,
4683 EL_EM_GATE_3, -1, -1
4686 Xdoor_4, TRUE, FALSE,
4687 EL_EM_GATE_4, -1, -1
4690 Xdoor_5, TRUE, FALSE,
4691 EL_EMC_GATE_5, -1, -1
4694 Xdoor_6, TRUE, FALSE,
4695 EL_EMC_GATE_6, -1, -1
4698 Xdoor_7, TRUE, FALSE,
4699 EL_EMC_GATE_7, -1, -1
4702 Xdoor_8, TRUE, FALSE,
4703 EL_EMC_GATE_8, -1, -1
4706 Xkey_1, TRUE, FALSE,
4710 Xkey_2, TRUE, FALSE,
4714 Xkey_3, TRUE, FALSE,
4718 Xkey_4, TRUE, FALSE,
4722 Xkey_5, TRUE, FALSE,
4723 EL_EMC_KEY_5, -1, -1
4726 Xkey_6, TRUE, FALSE,
4727 EL_EMC_KEY_6, -1, -1
4730 Xkey_7, TRUE, FALSE,
4731 EL_EMC_KEY_7, -1, -1
4734 Xkey_8, TRUE, FALSE,
4735 EL_EMC_KEY_8, -1, -1
4738 Xwind_n, TRUE, FALSE,
4739 EL_BALLOON_SWITCH_UP, -1, -1
4742 Xwind_e, TRUE, FALSE,
4743 EL_BALLOON_SWITCH_RIGHT, -1, -1
4746 Xwind_s, TRUE, FALSE,
4747 EL_BALLOON_SWITCH_DOWN, -1, -1
4750 Xwind_w, TRUE, FALSE,
4751 EL_BALLOON_SWITCH_LEFT, -1, -1
4754 Xwind_nesw, TRUE, FALSE,
4755 EL_BALLOON_SWITCH_ANY, -1, -1
4758 Xwind_stop, TRUE, FALSE,
4759 EL_BALLOON_SWITCH_NONE, -1, -1
4763 EL_EM_EXIT_CLOSED, -1, -1
4766 Xexit_1, TRUE, FALSE,
4767 EL_EM_EXIT_OPEN, -1, -1
4770 Xexit_2, FALSE, FALSE,
4771 EL_EM_EXIT_OPEN, -1, -1
4774 Xexit_3, FALSE, FALSE,
4775 EL_EM_EXIT_OPEN, -1, -1
4778 Xdynamite, TRUE, FALSE,
4779 EL_EM_DYNAMITE, -1, -1
4782 Ydynamite_eat, FALSE, FALSE,
4783 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
4786 Xdynamite_1, TRUE, FALSE,
4787 EL_EM_DYNAMITE_ACTIVE, -1, -1
4790 Xdynamite_2, FALSE, FALSE,
4791 EL_EM_DYNAMITE_ACTIVE, -1, -1
4794 Xdynamite_3, FALSE, FALSE,
4795 EL_EM_DYNAMITE_ACTIVE, -1, -1
4798 Xdynamite_4, FALSE, FALSE,
4799 EL_EM_DYNAMITE_ACTIVE, -1, -1
4802 Xbumper, TRUE, FALSE,
4803 EL_EMC_SPRING_BUMPER, -1, -1
4806 XbumperB, FALSE, FALSE,
4807 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
4810 Xwheel, TRUE, FALSE,
4811 EL_ROBOT_WHEEL, -1, -1
4814 XwheelB, FALSE, FALSE,
4815 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
4818 Xswitch, TRUE, FALSE,
4819 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
4822 XswitchB, FALSE, FALSE,
4823 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
4827 EL_QUICKSAND_EMPTY, -1, -1
4830 Xsand_stone, TRUE, FALSE,
4831 EL_QUICKSAND_FULL, -1, -1
4834 Xsand_stonein_1, FALSE, TRUE,
4835 EL_ROCK, ACTION_FILLING, -1
4838 Xsand_stonein_2, FALSE, TRUE,
4839 EL_ROCK, ACTION_FILLING, -1
4842 Xsand_stonein_3, FALSE, TRUE,
4843 EL_ROCK, ACTION_FILLING, -1
4846 Xsand_stonein_4, FALSE, TRUE,
4847 EL_ROCK, ACTION_FILLING, -1
4851 Xsand_stonesand_1, FALSE, FALSE,
4852 EL_QUICKSAND_EMPTYING, -1, -1
4855 Xsand_stonesand_2, FALSE, FALSE,
4856 EL_QUICKSAND_EMPTYING, -1, -1
4859 Xsand_stonesand_3, FALSE, FALSE,
4860 EL_QUICKSAND_EMPTYING, -1, -1
4863 Xsand_stonesand_4, FALSE, FALSE,
4864 EL_QUICKSAND_EMPTYING, -1, -1
4867 Xsand_stonesand_quickout_1, FALSE, FALSE,
4868 EL_QUICKSAND_EMPTYING, -1, -1
4871 Xsand_stonesand_quickout_2, FALSE, FALSE,
4872 EL_QUICKSAND_EMPTYING, -1, -1
4876 Xsand_stonesand_1, FALSE, FALSE,
4877 EL_QUICKSAND_FULL, -1, -1
4880 Xsand_stonesand_2, FALSE, FALSE,
4881 EL_QUICKSAND_FULL, -1, -1
4884 Xsand_stonesand_3, FALSE, FALSE,
4885 EL_QUICKSAND_FULL, -1, -1
4888 Xsand_stonesand_4, FALSE, FALSE,
4889 EL_QUICKSAND_FULL, -1, -1
4893 Xsand_stoneout_1, FALSE, FALSE,
4894 EL_ROCK, ACTION_EMPTYING, -1
4897 Xsand_stoneout_2, FALSE, FALSE,
4898 EL_ROCK, ACTION_EMPTYING, -1
4902 Xsand_sandstone_1, FALSE, FALSE,
4903 EL_QUICKSAND_FILLING, -1, -1
4906 Xsand_sandstone_2, FALSE, FALSE,
4907 EL_QUICKSAND_FILLING, -1, -1
4910 Xsand_sandstone_3, FALSE, FALSE,
4911 EL_QUICKSAND_FILLING, -1, -1
4914 Xsand_sandstone_4, FALSE, FALSE,
4915 EL_QUICKSAND_FILLING, -1, -1
4919 Xsand_sandstone_1, FALSE, FALSE,
4920 EL_QUICKSAND_FULL, -1, -1
4923 Xsand_sandstone_2, FALSE, FALSE,
4924 EL_QUICKSAND_FULL, -1, -1
4927 Xsand_sandstone_3, FALSE, FALSE,
4928 EL_QUICKSAND_FULL, -1, -1
4931 Xsand_sandstone_4, FALSE, FALSE,
4932 EL_QUICKSAND_FULL, -1, -1
4936 Xplant, TRUE, FALSE,
4937 EL_EMC_PLANT, -1, -1
4940 Yplant, FALSE, FALSE,
4941 EL_EMC_PLANT, -1, -1
4944 Xlenses, TRUE, FALSE,
4945 EL_EMC_LENSES, -1, -1
4948 Xmagnify, TRUE, FALSE,
4949 EL_EMC_MAGNIFIER, -1, -1
4952 Xdripper, TRUE, FALSE,
4953 EL_EMC_DRIPPER, -1, -1
4956 XdripperB, FALSE, FALSE,
4957 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
4960 Xfake_blank, TRUE, FALSE,
4961 EL_INVISIBLE_WALL, -1, -1
4964 Xfake_blankB, FALSE, FALSE,
4965 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
4968 Xfake_grass, TRUE, FALSE,
4969 EL_EMC_FAKE_GRASS, -1, -1
4972 Xfake_grassB, FALSE, FALSE,
4973 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
4976 Xfake_door_1, TRUE, FALSE,
4977 EL_EM_GATE_1_GRAY, -1, -1
4980 Xfake_door_2, TRUE, FALSE,
4981 EL_EM_GATE_2_GRAY, -1, -1
4984 Xfake_door_3, TRUE, FALSE,
4985 EL_EM_GATE_3_GRAY, -1, -1
4988 Xfake_door_4, TRUE, FALSE,
4989 EL_EM_GATE_4_GRAY, -1, -1
4992 Xfake_door_5, TRUE, FALSE,
4993 EL_EMC_GATE_5_GRAY, -1, -1
4996 Xfake_door_6, TRUE, FALSE,
4997 EL_EMC_GATE_6_GRAY, -1, -1
5000 Xfake_door_7, TRUE, FALSE,
5001 EL_EMC_GATE_7_GRAY, -1, -1
5004 Xfake_door_8, TRUE, FALSE,
5005 EL_EMC_GATE_8_GRAY, -1, -1
5008 Xfake_acid_1, TRUE, FALSE,
5009 EL_EMC_FAKE_ACID, -1, -1
5012 Xfake_acid_2, FALSE, FALSE,
5013 EL_EMC_FAKE_ACID, -1, -1
5016 Xfake_acid_3, FALSE, FALSE,
5017 EL_EMC_FAKE_ACID, -1, -1
5020 Xfake_acid_4, FALSE, FALSE,
5021 EL_EMC_FAKE_ACID, -1, -1
5024 Xfake_acid_5, FALSE, FALSE,
5025 EL_EMC_FAKE_ACID, -1, -1
5028 Xfake_acid_6, FALSE, FALSE,
5029 EL_EMC_FAKE_ACID, -1, -1
5032 Xfake_acid_7, FALSE, FALSE,
5033 EL_EMC_FAKE_ACID, -1, -1
5036 Xfake_acid_8, FALSE, FALSE,
5037 EL_EMC_FAKE_ACID, -1, -1
5040 Xsteel_1, TRUE, FALSE,
5041 EL_STEELWALL, -1, -1
5044 Xsteel_2, TRUE, FALSE,
5045 EL_EMC_STEELWALL_2, -1, -1
5048 Xsteel_3, TRUE, FALSE,
5049 EL_EMC_STEELWALL_3, -1, -1
5052 Xsteel_4, TRUE, FALSE,
5053 EL_EMC_STEELWALL_4, -1, -1
5056 Xwall_1, TRUE, FALSE,
5060 Xwall_2, TRUE, FALSE,
5061 EL_EMC_WALL_14, -1, -1
5064 Xwall_3, TRUE, FALSE,
5065 EL_EMC_WALL_15, -1, -1
5068 Xwall_4, TRUE, FALSE,
5069 EL_EMC_WALL_16, -1, -1
5072 Xround_wall_1, TRUE, FALSE,
5073 EL_WALL_SLIPPERY, -1, -1
5076 Xround_wall_2, TRUE, FALSE,
5077 EL_EMC_WALL_SLIPPERY_2, -1, -1
5080 Xround_wall_3, TRUE, FALSE,
5081 EL_EMC_WALL_SLIPPERY_3, -1, -1
5084 Xround_wall_4, TRUE, FALSE,
5085 EL_EMC_WALL_SLIPPERY_4, -1, -1
5088 Xdecor_1, TRUE, FALSE,
5089 EL_EMC_WALL_8, -1, -1
5092 Xdecor_2, TRUE, FALSE,
5093 EL_EMC_WALL_6, -1, -1
5096 Xdecor_3, TRUE, FALSE,
5097 EL_EMC_WALL_4, -1, -1
5100 Xdecor_4, TRUE, FALSE,
5101 EL_EMC_WALL_7, -1, -1
5104 Xdecor_5, TRUE, FALSE,
5105 EL_EMC_WALL_5, -1, -1
5108 Xdecor_6, TRUE, FALSE,
5109 EL_EMC_WALL_9, -1, -1
5112 Xdecor_7, TRUE, FALSE,
5113 EL_EMC_WALL_10, -1, -1
5116 Xdecor_8, TRUE, FALSE,
5117 EL_EMC_WALL_1, -1, -1
5120 Xdecor_9, TRUE, FALSE,
5121 EL_EMC_WALL_2, -1, -1
5124 Xdecor_10, TRUE, FALSE,
5125 EL_EMC_WALL_3, -1, -1
5128 Xdecor_11, TRUE, FALSE,
5129 EL_EMC_WALL_11, -1, -1
5132 Xdecor_12, TRUE, FALSE,
5133 EL_EMC_WALL_12, -1, -1
5136 Xalpha_0, TRUE, FALSE,
5137 EL_CHAR('0'), -1, -1
5140 Xalpha_1, TRUE, FALSE,
5141 EL_CHAR('1'), -1, -1
5144 Xalpha_2, TRUE, FALSE,
5145 EL_CHAR('2'), -1, -1
5148 Xalpha_3, TRUE, FALSE,
5149 EL_CHAR('3'), -1, -1
5152 Xalpha_4, TRUE, FALSE,
5153 EL_CHAR('4'), -1, -1
5156 Xalpha_5, TRUE, FALSE,
5157 EL_CHAR('5'), -1, -1
5160 Xalpha_6, TRUE, FALSE,
5161 EL_CHAR('6'), -1, -1
5164 Xalpha_7, TRUE, FALSE,
5165 EL_CHAR('7'), -1, -1
5168 Xalpha_8, TRUE, FALSE,
5169 EL_CHAR('8'), -1, -1
5172 Xalpha_9, TRUE, FALSE,
5173 EL_CHAR('9'), -1, -1
5176 Xalpha_excla, TRUE, FALSE,
5177 EL_CHAR('!'), -1, -1
5180 Xalpha_quote, TRUE, FALSE,
5181 EL_CHAR('"'), -1, -1
5184 Xalpha_comma, TRUE, FALSE,
5185 EL_CHAR(','), -1, -1
5188 Xalpha_minus, TRUE, FALSE,
5189 EL_CHAR('-'), -1, -1
5192 Xalpha_perio, TRUE, FALSE,
5193 EL_CHAR('.'), -1, -1
5196 Xalpha_colon, TRUE, FALSE,
5197 EL_CHAR(':'), -1, -1
5200 Xalpha_quest, TRUE, FALSE,
5201 EL_CHAR('?'), -1, -1
5204 Xalpha_a, TRUE, FALSE,
5205 EL_CHAR('A'), -1, -1
5208 Xalpha_b, TRUE, FALSE,
5209 EL_CHAR('B'), -1, -1
5212 Xalpha_c, TRUE, FALSE,
5213 EL_CHAR('C'), -1, -1
5216 Xalpha_d, TRUE, FALSE,
5217 EL_CHAR('D'), -1, -1
5220 Xalpha_e, TRUE, FALSE,
5221 EL_CHAR('E'), -1, -1
5224 Xalpha_f, TRUE, FALSE,
5225 EL_CHAR('F'), -1, -1
5228 Xalpha_g, TRUE, FALSE,
5229 EL_CHAR('G'), -1, -1
5232 Xalpha_h, TRUE, FALSE,
5233 EL_CHAR('H'), -1, -1
5236 Xalpha_i, TRUE, FALSE,
5237 EL_CHAR('I'), -1, -1
5240 Xalpha_j, TRUE, FALSE,
5241 EL_CHAR('J'), -1, -1
5244 Xalpha_k, TRUE, FALSE,
5245 EL_CHAR('K'), -1, -1
5248 Xalpha_l, TRUE, FALSE,
5249 EL_CHAR('L'), -1, -1
5252 Xalpha_m, TRUE, FALSE,
5253 EL_CHAR('M'), -1, -1
5256 Xalpha_n, TRUE, FALSE,
5257 EL_CHAR('N'), -1, -1
5260 Xalpha_o, TRUE, FALSE,
5261 EL_CHAR('O'), -1, -1
5264 Xalpha_p, TRUE, FALSE,
5265 EL_CHAR('P'), -1, -1
5268 Xalpha_q, TRUE, FALSE,
5269 EL_CHAR('Q'), -1, -1
5272 Xalpha_r, TRUE, FALSE,
5273 EL_CHAR('R'), -1, -1
5276 Xalpha_s, TRUE, FALSE,
5277 EL_CHAR('S'), -1, -1
5280 Xalpha_t, TRUE, FALSE,
5281 EL_CHAR('T'), -1, -1
5284 Xalpha_u, TRUE, FALSE,
5285 EL_CHAR('U'), -1, -1
5288 Xalpha_v, TRUE, FALSE,
5289 EL_CHAR('V'), -1, -1
5292 Xalpha_w, TRUE, FALSE,
5293 EL_CHAR('W'), -1, -1
5296 Xalpha_x, TRUE, FALSE,
5297 EL_CHAR('X'), -1, -1
5300 Xalpha_y, TRUE, FALSE,
5301 EL_CHAR('Y'), -1, -1
5304 Xalpha_z, TRUE, FALSE,
5305 EL_CHAR('Z'), -1, -1
5308 Xalpha_arrow_e, TRUE, FALSE,
5309 EL_CHAR('>'), -1, -1
5312 Xalpha_arrow_w, TRUE, FALSE,
5313 EL_CHAR('<'), -1, -1
5316 Xalpha_copyr, TRUE, FALSE,
5317 EL_CHAR('©'), -1, -1
5321 Xboom_bug, FALSE, FALSE,
5322 EL_BUG, ACTION_EXPLODING, -1
5325 Xboom_bomb, FALSE, FALSE,
5326 EL_BOMB, ACTION_EXPLODING, -1
5329 Xboom_android, FALSE, FALSE,
5330 EL_EMC_ANDROID, ACTION_OTHER, -1
5333 Xboom_1, FALSE, FALSE,
5334 EL_DEFAULT, ACTION_EXPLODING, -1
5337 Xboom_2, FALSE, FALSE,
5338 EL_DEFAULT, ACTION_EXPLODING, -1
5341 Znormal, FALSE, FALSE,
5345 Zdynamite, FALSE, FALSE,
5349 Zplayer, FALSE, FALSE,
5353 ZBORDER, FALSE, FALSE,
5363 static struct Mapping_EM_to_RND_player
5372 em_player_mapping_list[] =
5376 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
5380 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
5384 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
5388 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
5392 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
5396 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
5400 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
5404 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
5408 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
5412 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
5416 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
5420 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
5424 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
5428 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
5432 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
5436 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
5440 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
5444 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
5448 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
5452 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
5456 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
5460 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
5464 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
5468 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
5472 EL_PLAYER_1, ACTION_DEFAULT, -1,
5476 EL_PLAYER_2, ACTION_DEFAULT, -1,
5480 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
5484 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
5488 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
5492 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
5496 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
5500 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
5504 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
5508 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
5512 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
5516 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
5520 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
5524 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
5528 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
5532 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
5536 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
5540 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
5544 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
5548 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
5552 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
5556 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
5560 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
5564 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
5568 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
5572 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
5576 EL_PLAYER_3, ACTION_DEFAULT, -1,
5580 EL_PLAYER_4, ACTION_DEFAULT, -1,
5589 int map_element_RND_to_EM(int element_rnd)
5591 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
5592 static boolean mapping_initialized = FALSE;
5594 if (!mapping_initialized)
5598 /* return "Xalpha_quest" for all undefined elements in mapping array */
5599 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
5600 mapping_RND_to_EM[i] = Xalpha_quest;
5602 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5603 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
5604 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
5605 em_object_mapping_list[i].element_em;
5607 mapping_initialized = TRUE;
5610 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
5611 return mapping_RND_to_EM[element_rnd];
5613 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
5618 int map_element_EM_to_RND(int element_em)
5620 static unsigned short mapping_EM_to_RND[TILE_MAX];
5621 static boolean mapping_initialized = FALSE;
5623 if (!mapping_initialized)
5627 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
5628 for (i = 0; i < TILE_MAX; i++)
5629 mapping_EM_to_RND[i] = EL_UNKNOWN;
5631 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5632 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
5633 em_object_mapping_list[i].element_rnd;
5635 mapping_initialized = TRUE;
5638 if (element_em >= 0 && element_em < TILE_MAX)
5639 return mapping_EM_to_RND[element_em];
5641 Error(ERR_WARN, "invalid EM level element %d", element_em);
5646 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
5648 struct LevelInfo_EM *level_em = level->native_em_level;
5649 struct LEVEL *lev = level_em->lev;
5652 for (i = 0; i < TILE_MAX; i++)
5653 lev->android_array[i] = Xblank;
5655 for (i = 0; i < level->num_android_clone_elements; i++)
5657 int element_rnd = level->android_clone_element[i];
5658 int element_em = map_element_RND_to_EM(element_rnd);
5660 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
5661 if (em_object_mapping_list[j].element_rnd == element_rnd)
5662 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
5666 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
5668 struct LevelInfo_EM *level_em = level->native_em_level;
5669 struct LEVEL *lev = level_em->lev;
5672 level->num_android_clone_elements = 0;
5674 for (i = 0; i < TILE_MAX; i++)
5676 int element_em = lev->android_array[i];
5678 boolean element_found = FALSE;
5680 if (element_em == Xblank)
5683 element_rnd = map_element_EM_to_RND(element_em);
5685 for (j = 0; j < level->num_android_clone_elements; j++)
5686 if (level->android_clone_element[j] == element_rnd)
5687 element_found = TRUE;
5691 level->android_clone_element[level->num_android_clone_elements++] =
5694 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
5699 if (level->num_android_clone_elements == 0)
5701 level->num_android_clone_elements = 1;
5702 level->android_clone_element[0] = EL_EMPTY;
5706 int map_direction_RND_to_EM(int direction)
5708 return (direction == MV_UP ? 0 :
5709 direction == MV_RIGHT ? 1 :
5710 direction == MV_DOWN ? 2 :
5711 direction == MV_LEFT ? 3 :
5715 int map_direction_EM_to_RND(int direction)
5717 return (direction == 0 ? MV_UP :
5718 direction == 1 ? MV_RIGHT :
5719 direction == 2 ? MV_DOWN :
5720 direction == 3 ? MV_LEFT :
5724 int get_next_element(int element)
5728 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
5729 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
5730 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
5731 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
5732 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
5733 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
5734 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
5735 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
5736 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
5737 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
5738 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
5740 default: return element;
5745 int el_act_dir2img(int element, int action, int direction)
5747 element = GFX_ELEMENT(element);
5749 if (direction == MV_NONE)
5750 return element_info[element].graphic[action];
5752 direction = MV_DIR_TO_BIT(direction);
5754 return element_info[element].direction_graphic[action][direction];
5757 int el_act_dir2img(int element, int action, int direction)
5759 element = GFX_ELEMENT(element);
5760 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5762 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5763 return element_info[element].direction_graphic[action][direction];
5768 static int el_act_dir2crm(int element, int action, int direction)
5770 element = GFX_ELEMENT(element);
5772 if (direction == MV_NONE)
5773 return element_info[element].crumbled[action];
5775 direction = MV_DIR_TO_BIT(direction);
5777 return element_info[element].direction_crumbled[action][direction];
5780 static int el_act_dir2crm(int element, int action, int direction)
5782 element = GFX_ELEMENT(element);
5783 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5785 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5786 return element_info[element].direction_crumbled[action][direction];
5790 int el_act2img(int element, int action)
5792 element = GFX_ELEMENT(element);
5794 return element_info[element].graphic[action];
5797 int el_act2crm(int element, int action)
5799 element = GFX_ELEMENT(element);
5801 return element_info[element].crumbled[action];
5804 int el_dir2img(int element, int direction)
5806 element = GFX_ELEMENT(element);
5808 return el_act_dir2img(element, ACTION_DEFAULT, direction);
5811 int el2baseimg(int element)
5813 return element_info[element].graphic[ACTION_DEFAULT];
5816 int el2img(int element)
5818 element = GFX_ELEMENT(element);
5820 return element_info[element].graphic[ACTION_DEFAULT];
5823 int el2edimg(int element)
5825 element = GFX_ELEMENT(element);
5827 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
5830 int el2preimg(int element)
5832 element = GFX_ELEMENT(element);
5834 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
5837 int el2panelimg(int element)
5839 element = GFX_ELEMENT(element);
5841 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL];
5844 int font2baseimg(int font_nr)
5846 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
5849 int getBeltNrFromBeltElement(int element)
5851 return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
5852 element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
5853 element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
5856 int getBeltNrFromBeltActiveElement(int element)
5858 return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
5859 element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
5860 element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
5863 int getBeltNrFromBeltSwitchElement(int element)
5865 return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
5866 element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
5867 element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
5870 int getBeltDirNrFromBeltElement(int element)
5872 static int belt_base_element[4] =
5874 EL_CONVEYOR_BELT_1_LEFT,
5875 EL_CONVEYOR_BELT_2_LEFT,
5876 EL_CONVEYOR_BELT_3_LEFT,
5877 EL_CONVEYOR_BELT_4_LEFT
5880 int belt_nr = getBeltNrFromBeltElement(element);
5881 int belt_dir_nr = element - belt_base_element[belt_nr];
5883 return (belt_dir_nr % 3);
5886 int getBeltDirNrFromBeltSwitchElement(int element)
5888 static int belt_base_element[4] =
5890 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
5891 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
5892 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
5893 EL_CONVEYOR_BELT_4_SWITCH_LEFT
5896 int belt_nr = getBeltNrFromBeltSwitchElement(element);
5897 int belt_dir_nr = element - belt_base_element[belt_nr];
5899 return (belt_dir_nr % 3);
5902 int getBeltDirFromBeltElement(int element)
5904 static int belt_move_dir[3] =
5911 int belt_dir_nr = getBeltDirNrFromBeltElement(element);
5913 return belt_move_dir[belt_dir_nr];
5916 int getBeltDirFromBeltSwitchElement(int element)
5918 static int belt_move_dir[3] =
5925 int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
5927 return belt_move_dir[belt_dir_nr];
5930 int getBeltElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
5932 static int belt_base_element[4] =
5934 EL_CONVEYOR_BELT_1_LEFT,
5935 EL_CONVEYOR_BELT_2_LEFT,
5936 EL_CONVEYOR_BELT_3_LEFT,
5937 EL_CONVEYOR_BELT_4_LEFT
5940 return belt_base_element[belt_nr] + belt_dir_nr;
5943 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
5945 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
5947 return getBeltElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
5950 int getBeltSwitchElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
5952 static int belt_base_element[4] =
5954 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
5955 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
5956 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
5957 EL_CONVEYOR_BELT_4_SWITCH_LEFT
5960 return belt_base_element[belt_nr] + belt_dir_nr;
5963 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
5965 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
5967 return getBeltSwitchElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
5970 int getNumActivePlayers_EM()
5972 int num_players = 0;
5978 for (i = 0; i < MAX_PLAYERS; i++)
5979 if (tape.player_participates[i])
5985 int getGameFrameDelay_EM(int native_em_game_frame_delay)
5987 int game_frame_delay_value;
5989 game_frame_delay_value =
5990 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
5991 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
5994 if (tape.playing && tape.warp_forward && !tape.pausing)
5995 game_frame_delay_value = 0;
5997 return game_frame_delay_value;
6000 unsigned int InitRND(long seed)
6002 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
6003 return InitEngineRandom_EM(seed);
6005 return InitEngineRandom_RND(seed);
6009 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
6010 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
6013 inline static int get_effective_element_EM(int tile, int frame_em)
6015 int element = object_mapping[tile].element_rnd;
6016 int action = object_mapping[tile].action;
6017 boolean is_backside = object_mapping[tile].is_backside;
6018 boolean action_removing = (action == ACTION_DIGGING ||
6019 action == ACTION_SNAPPING ||
6020 action == ACTION_COLLECTING);
6026 case Yacid_splash_eB:
6027 case Yacid_splash_wB:
6028 return (frame_em > 5 ? EL_EMPTY : element);
6034 else /* frame_em == 7 */
6038 case Yacid_splash_eB:
6039 case Yacid_splash_wB:
6042 case Yemerald_stone:
6045 case Ydiamond_stone:
6049 case Xdrip_stretchB:
6068 case Xsand_stonein_1:
6069 case Xsand_stonein_2:
6070 case Xsand_stonein_3:
6071 case Xsand_stonein_4:
6075 return (is_backside || action_removing ? EL_EMPTY : element);
6080 inline static boolean check_linear_animation_EM(int tile)
6084 case Xsand_stonesand_1:
6085 case Xsand_stonesand_quickout_1:
6086 case Xsand_sandstone_1:
6087 case Xsand_stonein_1:
6088 case Xsand_stoneout_1:
6113 inline static void set_crumbled_graphics_EM(struct GraphicInfo_EM *g_em,
6114 boolean has_crumbled_graphics,
6115 int crumbled, int sync_frame)
6117 /* if element can be crumbled, but certain action graphics are just empty
6118 space (like instantly snapping sand to empty space in 1 frame), do not
6119 treat these empty space graphics as crumbled graphics in EMC engine */
6120 if (crumbled == IMG_EMPTY_SPACE)
6121 has_crumbled_graphics = FALSE;
6123 if (has_crumbled_graphics)
6125 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
6126 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
6127 g_crumbled->anim_delay,
6128 g_crumbled->anim_mode,
6129 g_crumbled->anim_start_frame,
6132 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
6133 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
6135 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
6137 g_em->has_crumbled_graphics = TRUE;
6141 g_em->crumbled_bitmap = NULL;
6142 g_em->crumbled_src_x = 0;
6143 g_em->crumbled_src_y = 0;
6144 g_em->crumbled_border_size = 0;
6146 g_em->has_crumbled_graphics = FALSE;
6150 void ResetGfxAnimation_EM(int x, int y, int tile)
6155 void SetGfxAnimation_EM(struct GraphicInfo_EM *g_em,
6156 int tile, int frame_em, int x, int y)
6158 int action = object_mapping[tile].action;
6160 int direction = object_mapping[tile].direction;
6161 int effective_element = get_effective_element_EM(tile, frame_em);
6162 int graphic = (direction == MV_NONE ?
6163 el_act2img(effective_element, action) :
6164 el_act_dir2img(effective_element, action, direction));
6165 struct GraphicInfo *g = &graphic_info[graphic];
6168 boolean action_removing = (action == ACTION_DIGGING ||
6169 action == ACTION_SNAPPING ||
6170 action == ACTION_COLLECTING);
6171 boolean action_moving = (action == ACTION_FALLING ||
6172 action == ACTION_MOVING ||
6173 action == ACTION_PUSHING ||
6174 action == ACTION_EATING ||
6175 action == ACTION_FILLING ||
6176 action == ACTION_EMPTYING);
6177 boolean action_falling = (action == ACTION_FALLING ||
6178 action == ACTION_FILLING ||
6179 action == ACTION_EMPTYING);
6182 if (tile == Xsand_stonesand_1 ||
6183 tile == Xsand_stonesand_2 ||
6184 tile == Xsand_stonesand_3 ||
6185 tile == Xsand_stonesand_4)
6186 printf("::: 1: quicksand frame %d [%d]\n", GfxFrame[x][y], tile);
6190 if ((action_removing || check_linear_animation_EM(tile)) && frame_em == 0)
6194 // printf("::: resetting... [%d]\n", tile);
6197 if (action_removing || check_linear_animation_EM(tile))
6199 GfxFrame[x][y] = frame_em;
6201 // printf("::: resetting... [%d]\n", tile);
6204 else if (action_moving)
6206 boolean is_backside = object_mapping[tile].is_backside;
6210 int direction = object_mapping[tile].direction;
6211 int move_dir = (action_falling ? MV_DOWN : direction);
6215 if (move_dir == MV_LEFT)
6216 GfxFrame[x - 1][y] = GfxFrame[x][y];
6217 else if (move_dir == MV_RIGHT)
6218 GfxFrame[x + 1][y] = GfxFrame[x][y];
6219 else if (move_dir == MV_UP)
6220 GfxFrame[x][y - 1] = GfxFrame[x][y];
6221 else if (move_dir == MV_DOWN)
6222 GfxFrame[x][y + 1] = GfxFrame[x][y];
6229 /* special case: animation for Xsand_stonesand_quickout_1/2 twice as fast */
6230 if (tile == Xsand_stonesand_quickout_1 ||
6231 tile == Xsand_stonesand_quickout_2)
6236 if (tile == Xsand_stonesand_1 ||
6237 tile == Xsand_stonesand_2 ||
6238 tile == Xsand_stonesand_3 ||
6239 tile == Xsand_stonesand_4)
6240 printf("::: 2: quicksand frame %d [%d]\n", GfxFrame[x][y], tile);
6244 if (graphic_info[graphic].anim_global_sync)
6245 sync_frame = FrameCounter;
6246 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
6247 sync_frame = GfxFrame[x][y];
6249 sync_frame = 0; /* playfield border (pseudo steel) */
6251 SetRandomAnimationValue(x, y);
6253 int frame = getAnimationFrame(g->anim_frames,
6256 g->anim_start_frame,
6259 g_em->unique_identifier =
6260 (graphic << 16) | ((frame % 8) << 12) | (g_em->width << 6) | g_em->height;
6264 void getGraphicSourceObjectExt_EM(struct GraphicInfo_EM *g_em,
6265 int tile, int frame_em, int x, int y)
6267 int action = object_mapping[tile].action;
6268 int direction = object_mapping[tile].direction;
6269 int effective_element = get_effective_element_EM(tile, frame_em);
6270 int graphic = (direction == MV_NONE ?
6271 el_act2img(effective_element, action) :
6272 el_act_dir2img(effective_element, action, direction));
6273 int crumbled = (direction == MV_NONE ?
6274 el_act2crm(effective_element, action) :
6275 el_act_dir2crm(effective_element, action, direction));
6276 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
6277 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
6278 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
6279 struct GraphicInfo *g = &graphic_info[graphic];
6281 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
6286 if (frame_em == 0) /* reset animation frame for certain elements */
6288 if (check_linear_animation_EM(tile))
6293 if (graphic_info[graphic].anim_global_sync)
6294 sync_frame = FrameCounter;
6295 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
6296 sync_frame = GfxFrame[x][y];
6298 sync_frame = 0; /* playfield border (pseudo steel) */
6300 SetRandomAnimationValue(x, y);
6302 int frame = getAnimationFrame(g->anim_frames,
6305 g->anim_start_frame,
6308 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
6309 &g_em->src_x, &g_em->src_y, FALSE);
6311 /* (updating the "crumbled" graphic definitions is probably not really needed,
6312 as animations for crumbled graphics can't be longer than one EMC cycle) */
6314 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
6319 g_em->crumbled_bitmap = NULL;
6320 g_em->crumbled_src_x = 0;
6321 g_em->crumbled_src_y = 0;
6323 g_em->has_crumbled_graphics = FALSE;
6325 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
6327 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
6328 g_crumbled->anim_delay,
6329 g_crumbled->anim_mode,
6330 g_crumbled->anim_start_frame,
6333 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
6334 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
6336 g_em->has_crumbled_graphics = TRUE;
6341 void getGraphicSourcePlayerExt_EM(struct GraphicInfo_EM *g_em,
6342 int player_nr, int anim, int frame_em)
6344 int element = player_mapping[player_nr][anim].element_rnd;
6345 int action = player_mapping[player_nr][anim].action;
6346 int direction = player_mapping[player_nr][anim].direction;
6347 int graphic = (direction == MV_NONE ?
6348 el_act2img(element, action) :
6349 el_act_dir2img(element, action, direction));
6350 struct GraphicInfo *g = &graphic_info[graphic];
6353 InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
6355 stored_player[player_nr].StepFrame = frame_em;
6357 sync_frame = stored_player[player_nr].Frame;
6359 int frame = getAnimationFrame(g->anim_frames,
6362 g->anim_start_frame,
6365 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
6366 &g_em->src_x, &g_em->src_y, FALSE);
6369 printf("::: %d: %d, %d [%d]\n",
6371 stored_player[player_nr].Frame,
6372 stored_player[player_nr].StepFrame,
6377 void InitGraphicInfo_EM(void)
6380 struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
6381 struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
6386 int num_em_gfx_errors = 0;
6388 if (graphic_info_em_object[0][0].bitmap == NULL)
6390 /* EM graphics not yet initialized in em_open_all() */
6395 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
6398 /* always start with reliable default values */
6399 for (i = 0; i < TILE_MAX; i++)
6401 object_mapping[i].element_rnd = EL_UNKNOWN;
6402 object_mapping[i].is_backside = FALSE;
6403 object_mapping[i].action = ACTION_DEFAULT;
6404 object_mapping[i].direction = MV_NONE;
6407 /* always start with reliable default values */
6408 for (p = 0; p < MAX_PLAYERS; p++)
6410 for (i = 0; i < SPR_MAX; i++)
6412 player_mapping[p][i].element_rnd = EL_UNKNOWN;
6413 player_mapping[p][i].action = ACTION_DEFAULT;
6414 player_mapping[p][i].direction = MV_NONE;
6418 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6420 int e = em_object_mapping_list[i].element_em;
6422 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
6423 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
6425 if (em_object_mapping_list[i].action != -1)
6426 object_mapping[e].action = em_object_mapping_list[i].action;
6428 if (em_object_mapping_list[i].direction != -1)
6429 object_mapping[e].direction =
6430 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
6433 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
6435 int a = em_player_mapping_list[i].action_em;
6436 int p = em_player_mapping_list[i].player_nr;
6438 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
6440 if (em_player_mapping_list[i].action != -1)
6441 player_mapping[p][a].action = em_player_mapping_list[i].action;
6443 if (em_player_mapping_list[i].direction != -1)
6444 player_mapping[p][a].direction =
6445 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
6448 for (i = 0; i < TILE_MAX; i++)
6450 int element = object_mapping[i].element_rnd;
6451 int action = object_mapping[i].action;
6452 int direction = object_mapping[i].direction;
6453 boolean is_backside = object_mapping[i].is_backside;
6455 boolean action_removing = (action == ACTION_DIGGING ||
6456 action == ACTION_SNAPPING ||
6457 action == ACTION_COLLECTING);
6459 boolean action_exploding = ((action == ACTION_EXPLODING ||
6460 action == ACTION_SMASHED_BY_ROCK ||
6461 action == ACTION_SMASHED_BY_SPRING) &&
6462 element != EL_DIAMOND);
6463 boolean action_active = (action == ACTION_ACTIVE);
6464 boolean action_other = (action == ACTION_OTHER);
6466 for (j = 0; j < 8; j++)
6469 int effective_element = get_effective_element_EM(i, j);
6471 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
6472 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
6474 i == Xdrip_stretch ? element :
6475 i == Xdrip_stretchB ? element :
6476 i == Ydrip_s1 ? element :
6477 i == Ydrip_s1B ? element :
6478 i == Xball_1B ? element :
6479 i == Xball_2 ? element :
6480 i == Xball_2B ? element :
6481 i == Yball_eat ? element :
6482 i == Ykey_1_eat ? element :
6483 i == Ykey_2_eat ? element :
6484 i == Ykey_3_eat ? element :
6485 i == Ykey_4_eat ? element :
6486 i == Ykey_5_eat ? element :
6487 i == Ykey_6_eat ? element :
6488 i == Ykey_7_eat ? element :
6489 i == Ykey_8_eat ? element :
6490 i == Ylenses_eat ? element :
6491 i == Ymagnify_eat ? element :
6492 i == Ygrass_eat ? element :
6493 i == Ydirt_eat ? element :
6494 i == Yemerald_stone ? EL_EMERALD :
6495 i == Ydiamond_stone ? EL_ROCK :
6496 i == Xsand_stonein_1 ? element :
6497 i == Xsand_stonein_2 ? element :
6498 i == Xsand_stonein_3 ? element :
6499 i == Xsand_stonein_4 ? element :
6500 is_backside ? EL_EMPTY :
6501 action_removing ? EL_EMPTY :
6504 int effective_action = (j < 7 ? action :
6505 i == Xdrip_stretch ? action :
6506 i == Xdrip_stretchB ? action :
6507 i == Ydrip_s1 ? action :
6508 i == Ydrip_s1B ? action :
6509 i == Xball_1B ? action :
6510 i == Xball_2 ? action :
6511 i == Xball_2B ? action :
6512 i == Yball_eat ? action :
6513 i == Ykey_1_eat ? action :
6514 i == Ykey_2_eat ? action :
6515 i == Ykey_3_eat ? action :
6516 i == Ykey_4_eat ? action :
6517 i == Ykey_5_eat ? action :
6518 i == Ykey_6_eat ? action :
6519 i == Ykey_7_eat ? action :
6520 i == Ykey_8_eat ? action :
6521 i == Ylenses_eat ? action :
6522 i == Ymagnify_eat ? action :
6523 i == Ygrass_eat ? action :
6524 i == Ydirt_eat ? action :
6525 i == Xsand_stonein_1 ? action :
6526 i == Xsand_stonein_2 ? action :
6527 i == Xsand_stonein_3 ? action :
6528 i == Xsand_stonein_4 ? action :
6529 i == Xsand_stoneout_1 ? action :
6530 i == Xsand_stoneout_2 ? action :
6531 i == Xboom_android ? ACTION_EXPLODING :
6532 action_exploding ? ACTION_EXPLODING :
6533 action_active ? action :
6534 action_other ? action :
6536 int graphic = (el_act_dir2img(effective_element, effective_action,
6538 int crumbled = (el_act_dir2crm(effective_element, effective_action,
6540 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
6541 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
6542 boolean has_action_graphics = (graphic != base_graphic);
6543 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
6544 struct GraphicInfo *g = &graphic_info[graphic];
6546 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
6548 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
6551 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
6552 boolean special_animation = (action != ACTION_DEFAULT &&
6553 g->anim_frames == 3 &&
6554 g->anim_delay == 2 &&
6555 g->anim_mode & ANIM_LINEAR);
6556 int sync_frame = (i == Xdrip_stretch ? 7 :
6557 i == Xdrip_stretchB ? 7 :
6558 i == Ydrip_s2 ? j + 8 :
6559 i == Ydrip_s2B ? j + 8 :
6568 i == Xfake_acid_1 ? 0 :
6569 i == Xfake_acid_2 ? 10 :
6570 i == Xfake_acid_3 ? 20 :
6571 i == Xfake_acid_4 ? 30 :
6572 i == Xfake_acid_5 ? 40 :
6573 i == Xfake_acid_6 ? 50 :
6574 i == Xfake_acid_7 ? 60 :
6575 i == Xfake_acid_8 ? 70 :
6577 i == Xball_2B ? j + 8 :
6578 i == Yball_eat ? j + 1 :
6579 i == Ykey_1_eat ? j + 1 :
6580 i == Ykey_2_eat ? j + 1 :
6581 i == Ykey_3_eat ? j + 1 :
6582 i == Ykey_4_eat ? j + 1 :
6583 i == Ykey_5_eat ? j + 1 :
6584 i == Ykey_6_eat ? j + 1 :
6585 i == Ykey_7_eat ? j + 1 :
6586 i == Ykey_8_eat ? j + 1 :
6587 i == Ylenses_eat ? j + 1 :
6588 i == Ymagnify_eat ? j + 1 :
6589 i == Ygrass_eat ? j + 1 :
6590 i == Ydirt_eat ? j + 1 :
6591 i == Xamoeba_1 ? 0 :
6592 i == Xamoeba_2 ? 1 :
6593 i == Xamoeba_3 ? 2 :
6594 i == Xamoeba_4 ? 3 :
6595 i == Xamoeba_5 ? 0 :
6596 i == Xamoeba_6 ? 1 :
6597 i == Xamoeba_7 ? 2 :
6598 i == Xamoeba_8 ? 3 :
6599 i == Xexit_2 ? j + 8 :
6600 i == Xexit_3 ? j + 16 :
6601 i == Xdynamite_1 ? 0 :
6602 i == Xdynamite_2 ? 8 :
6603 i == Xdynamite_3 ? 16 :
6604 i == Xdynamite_4 ? 24 :
6605 i == Xsand_stonein_1 ? j + 1 :
6606 i == Xsand_stonein_2 ? j + 9 :
6607 i == Xsand_stonein_3 ? j + 17 :
6608 i == Xsand_stonein_4 ? j + 25 :
6609 i == Xsand_stoneout_1 && j == 0 ? 0 :
6610 i == Xsand_stoneout_1 && j == 1 ? 0 :
6611 i == Xsand_stoneout_1 && j == 2 ? 1 :
6612 i == Xsand_stoneout_1 && j == 3 ? 2 :
6613 i == Xsand_stoneout_1 && j == 4 ? 2 :
6614 i == Xsand_stoneout_1 && j == 5 ? 3 :
6615 i == Xsand_stoneout_1 && j == 6 ? 4 :
6616 i == Xsand_stoneout_1 && j == 7 ? 4 :
6617 i == Xsand_stoneout_2 && j == 0 ? 5 :
6618 i == Xsand_stoneout_2 && j == 1 ? 6 :
6619 i == Xsand_stoneout_2 && j == 2 ? 7 :
6620 i == Xsand_stoneout_2 && j == 3 ? 8 :
6621 i == Xsand_stoneout_2 && j == 4 ? 9 :
6622 i == Xsand_stoneout_2 && j == 5 ? 11 :
6623 i == Xsand_stoneout_2 && j == 6 ? 13 :
6624 i == Xsand_stoneout_2 && j == 7 ? 15 :
6625 i == Xboom_bug && j == 1 ? 2 :
6626 i == Xboom_bug && j == 2 ? 2 :
6627 i == Xboom_bug && j == 3 ? 4 :
6628 i == Xboom_bug && j == 4 ? 4 :
6629 i == Xboom_bug && j == 5 ? 2 :
6630 i == Xboom_bug && j == 6 ? 2 :
6631 i == Xboom_bug && j == 7 ? 0 :
6632 i == Xboom_bomb && j == 1 ? 2 :
6633 i == Xboom_bomb && j == 2 ? 2 :
6634 i == Xboom_bomb && j == 3 ? 4 :
6635 i == Xboom_bomb && j == 4 ? 4 :
6636 i == Xboom_bomb && j == 5 ? 2 :
6637 i == Xboom_bomb && j == 6 ? 2 :
6638 i == Xboom_bomb && j == 7 ? 0 :
6639 i == Xboom_android && j == 7 ? 6 :
6640 i == Xboom_1 && j == 1 ? 2 :
6641 i == Xboom_1 && j == 2 ? 2 :
6642 i == Xboom_1 && j == 3 ? 4 :
6643 i == Xboom_1 && j == 4 ? 4 :
6644 i == Xboom_1 && j == 5 ? 6 :
6645 i == Xboom_1 && j == 6 ? 6 :
6646 i == Xboom_1 && j == 7 ? 8 :
6647 i == Xboom_2 && j == 0 ? 8 :
6648 i == Xboom_2 && j == 1 ? 8 :
6649 i == Xboom_2 && j == 2 ? 10 :
6650 i == Xboom_2 && j == 3 ? 10 :
6651 i == Xboom_2 && j == 4 ? 10 :
6652 i == Xboom_2 && j == 5 ? 12 :
6653 i == Xboom_2 && j == 6 ? 12 :
6654 i == Xboom_2 && j == 7 ? 12 :
6655 special_animation && j == 4 ? 3 :
6656 effective_action != action ? 0 :
6660 Bitmap *debug_bitmap = g_em->bitmap;
6661 int debug_src_x = g_em->src_x;
6662 int debug_src_y = g_em->src_y;
6665 int frame = getAnimationFrame(g->anim_frames,
6668 g->anim_start_frame,
6671 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
6672 g->double_movement && is_backside);
6674 g_em->bitmap = src_bitmap;
6675 g_em->src_x = src_x;
6676 g_em->src_y = src_y;
6677 g_em->src_offset_x = 0;
6678 g_em->src_offset_y = 0;
6679 g_em->dst_offset_x = 0;
6680 g_em->dst_offset_y = 0;
6681 g_em->width = TILEX;
6682 g_em->height = TILEY;
6684 g_em->preserve_background = FALSE;
6687 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
6692 g_em->crumbled_bitmap = NULL;
6693 g_em->crumbled_src_x = 0;
6694 g_em->crumbled_src_y = 0;
6695 g_em->crumbled_border_size = 0;
6697 g_em->has_crumbled_graphics = FALSE;
6700 if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
6701 printf("::: empty crumbled: %d [%s], %d, %d\n",
6702 effective_element, element_info[effective_element].token_name,
6703 effective_action, direction);
6706 /* if element can be crumbled, but certain action graphics are just empty
6707 space (like instantly snapping sand to empty space in 1 frame), do not
6708 treat these empty space graphics as crumbled graphics in EMC engine */
6709 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
6711 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
6712 g_crumbled->anim_delay,
6713 g_crumbled->anim_mode,
6714 g_crumbled->anim_start_frame,
6717 getGraphicSource(crumbled, frame_crumbled, &src_bitmap, &src_x, &src_y);
6719 g_em->has_crumbled_graphics = TRUE;
6720 g_em->crumbled_bitmap = src_bitmap;
6721 g_em->crumbled_src_x = src_x;
6722 g_em->crumbled_src_y = src_y;
6723 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
6727 if (g_em == &graphic_info_em_object[207][0])
6728 printf("... %d, %d [%d, %d, %d, %d] [%d, %d, %d, %d, %d, %d => %d]\n",
6729 graphic_info_em_object[207][0].crumbled_src_x,
6730 graphic_info_em_object[207][0].crumbled_src_y,
6732 crumbled, frame, src_x, src_y,
6737 g->anim_start_frame,
6739 gfx.anim_random_frame,
6744 printf("::: EMC tile %d is crumbled\n", i);
6750 if (element == EL_ROCK &&
6751 effective_action == ACTION_FILLING)
6752 printf("::: has_action_graphics == %d\n", has_action_graphics);
6755 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
6756 effective_action == ACTION_MOVING ||
6757 effective_action == ACTION_PUSHING ||
6758 effective_action == ACTION_EATING)) ||
6759 (!has_action_graphics && (effective_action == ACTION_FILLING ||
6760 effective_action == ACTION_EMPTYING)))
6763 (effective_action == ACTION_FALLING ||
6764 effective_action == ACTION_FILLING ||
6765 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
6766 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
6767 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
6768 int num_steps = (i == Ydrip_s1 ? 16 :
6769 i == Ydrip_s1B ? 16 :
6770 i == Ydrip_s2 ? 16 :
6771 i == Ydrip_s2B ? 16 :
6772 i == Xsand_stonein_1 ? 32 :
6773 i == Xsand_stonein_2 ? 32 :
6774 i == Xsand_stonein_3 ? 32 :
6775 i == Xsand_stonein_4 ? 32 :
6776 i == Xsand_stoneout_1 ? 16 :
6777 i == Xsand_stoneout_2 ? 16 : 8);
6778 int cx = ABS(dx) * (TILEX / num_steps);
6779 int cy = ABS(dy) * (TILEY / num_steps);
6780 int step_frame = (i == Ydrip_s2 ? j + 8 :
6781 i == Ydrip_s2B ? j + 8 :
6782 i == Xsand_stonein_2 ? j + 8 :
6783 i == Xsand_stonein_3 ? j + 16 :
6784 i == Xsand_stonein_4 ? j + 24 :
6785 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
6786 int step = (is_backside ? step_frame : num_steps - step_frame);
6788 if (is_backside) /* tile where movement starts */
6790 if (dx < 0 || dy < 0)
6792 g_em->src_offset_x = cx * step;
6793 g_em->src_offset_y = cy * step;
6797 g_em->dst_offset_x = cx * step;
6798 g_em->dst_offset_y = cy * step;
6801 else /* tile where movement ends */
6803 if (dx < 0 || dy < 0)
6805 g_em->dst_offset_x = cx * step;
6806 g_em->dst_offset_y = cy * step;
6810 g_em->src_offset_x = cx * step;
6811 g_em->src_offset_y = cy * step;
6815 g_em->width = TILEX - cx * step;
6816 g_em->height = TILEY - cy * step;
6819 /* create unique graphic identifier to decide if tile must be redrawn */
6820 /* bit 31 - 16 (16 bit): EM style graphic
6821 bit 15 - 12 ( 4 bit): EM style frame
6822 bit 11 - 6 ( 6 bit): graphic width
6823 bit 5 - 0 ( 6 bit): graphic height */
6824 g_em->unique_identifier =
6825 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
6829 /* skip check for EMC elements not contained in original EMC artwork */
6830 if (element == EL_EMC_FAKE_ACID)
6833 if (g_em->bitmap != debug_bitmap ||
6834 g_em->src_x != debug_src_x ||
6835 g_em->src_y != debug_src_y ||
6836 g_em->src_offset_x != 0 ||
6837 g_em->src_offset_y != 0 ||
6838 g_em->dst_offset_x != 0 ||
6839 g_em->dst_offset_y != 0 ||
6840 g_em->width != TILEX ||
6841 g_em->height != TILEY)
6843 static int last_i = -1;
6851 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
6852 i, element, element_info[element].token_name,
6853 element_action_info[effective_action].suffix, direction);
6855 if (element != effective_element)
6856 printf(" [%d ('%s')]",
6858 element_info[effective_element].token_name);
6862 if (g_em->bitmap != debug_bitmap)
6863 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
6864 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
6866 if (g_em->src_x != debug_src_x ||
6867 g_em->src_y != debug_src_y)
6868 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
6869 j, (is_backside ? 'B' : 'F'),
6870 g_em->src_x, g_em->src_y,
6871 g_em->src_x / 32, g_em->src_y / 32,
6872 debug_src_x, debug_src_y,
6873 debug_src_x / 32, debug_src_y / 32);
6875 if (g_em->src_offset_x != 0 ||
6876 g_em->src_offset_y != 0 ||
6877 g_em->dst_offset_x != 0 ||
6878 g_em->dst_offset_y != 0)
6879 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
6881 g_em->src_offset_x, g_em->src_offset_y,
6882 g_em->dst_offset_x, g_em->dst_offset_y);
6884 if (g_em->width != TILEX ||
6885 g_em->height != TILEY)
6886 printf(" %d (%d): size %d,%d should be %d,%d\n",
6888 g_em->width, g_em->height, TILEX, TILEY);
6890 num_em_gfx_errors++;
6897 for (i = 0; i < TILE_MAX; i++)
6899 for (j = 0; j < 8; j++)
6901 int element = object_mapping[i].element_rnd;
6902 int action = object_mapping[i].action;
6903 int direction = object_mapping[i].direction;
6904 boolean is_backside = object_mapping[i].is_backside;
6905 int graphic_action = el_act_dir2img(element, action, direction);
6906 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
6908 if ((action == ACTION_SMASHED_BY_ROCK ||
6909 action == ACTION_SMASHED_BY_SPRING ||
6910 action == ACTION_EATING) &&
6911 graphic_action == graphic_default)
6913 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
6914 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
6915 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
6916 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
6919 /* no separate animation for "smashed by rock" -- use rock instead */
6920 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
6921 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
6923 g_em->bitmap = g_xx->bitmap;
6924 g_em->src_x = g_xx->src_x;
6925 g_em->src_y = g_xx->src_y;
6926 g_em->src_offset_x = g_xx->src_offset_x;
6927 g_em->src_offset_y = g_xx->src_offset_y;
6928 g_em->dst_offset_x = g_xx->dst_offset_x;
6929 g_em->dst_offset_y = g_xx->dst_offset_y;
6930 g_em->width = g_xx->width;
6931 g_em->height = g_xx->height;
6932 g_em->unique_identifier = g_xx->unique_identifier;
6935 g_em->preserve_background = TRUE;
6940 for (p = 0; p < MAX_PLAYERS; p++)
6942 for (i = 0; i < SPR_MAX; i++)
6944 int element = player_mapping[p][i].element_rnd;
6945 int action = player_mapping[p][i].action;
6946 int direction = player_mapping[p][i].direction;
6948 for (j = 0; j < 8; j++)
6950 int effective_element = element;
6951 int effective_action = action;
6952 int graphic = (direction == MV_NONE ?
6953 el_act2img(effective_element, effective_action) :
6954 el_act_dir2img(effective_element, effective_action,
6956 struct GraphicInfo *g = &graphic_info[graphic];
6957 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
6963 Bitmap *debug_bitmap = g_em->bitmap;
6964 int debug_src_x = g_em->src_x;
6965 int debug_src_y = g_em->src_y;
6968 int frame = getAnimationFrame(g->anim_frames,
6971 g->anim_start_frame,
6974 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
6976 g_em->bitmap = src_bitmap;
6977 g_em->src_x = src_x;
6978 g_em->src_y = src_y;
6979 g_em->src_offset_x = 0;
6980 g_em->src_offset_y = 0;
6981 g_em->dst_offset_x = 0;
6982 g_em->dst_offset_y = 0;
6983 g_em->width = TILEX;
6984 g_em->height = TILEY;
6988 /* skip check for EMC elements not contained in original EMC artwork */
6989 if (element == EL_PLAYER_3 ||
6990 element == EL_PLAYER_4)
6993 if (g_em->bitmap != debug_bitmap ||
6994 g_em->src_x != debug_src_x ||
6995 g_em->src_y != debug_src_y)
6997 static int last_i = -1;
7005 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
7006 p, i, element, element_info[element].token_name,
7007 element_action_info[effective_action].suffix, direction);
7009 if (element != effective_element)
7010 printf(" [%d ('%s')]",
7012 element_info[effective_element].token_name);
7016 if (g_em->bitmap != debug_bitmap)
7017 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
7018 j, (int)(g_em->bitmap), (int)(debug_bitmap));
7020 if (g_em->src_x != debug_src_x ||
7021 g_em->src_y != debug_src_y)
7022 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
7024 g_em->src_x, g_em->src_y,
7025 g_em->src_x / 32, g_em->src_y / 32,
7026 debug_src_x, debug_src_y,
7027 debug_src_x / 32, debug_src_y / 32);
7029 num_em_gfx_errors++;
7039 printf("::: [%d errors found]\n", num_em_gfx_errors);
7045 void PlayMenuSoundExt(int sound)
7047 if (sound == SND_UNDEFINED)
7050 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
7051 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
7054 if (IS_LOOP_SOUND(sound))
7055 PlaySoundLoop(sound);
7060 void PlayMenuSound()
7062 PlayMenuSoundExt(menu.sound[game_status]);
7065 void PlayMenuSoundStereo(int sound, int stereo_position)
7067 if (sound == SND_UNDEFINED)
7070 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
7071 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
7074 if (IS_LOOP_SOUND(sound))
7075 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
7077 PlaySoundStereo(sound, stereo_position);
7080 void PlayMenuSoundIfLoopExt(int sound)
7082 if (sound == SND_UNDEFINED)
7085 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
7086 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
7089 if (IS_LOOP_SOUND(sound))
7090 PlaySoundLoop(sound);
7093 void PlayMenuSoundIfLoop()
7095 PlayMenuSoundIfLoopExt(menu.sound[game_status]);
7098 void PlayMenuMusicExt(int music)
7100 if (music == MUS_UNDEFINED)
7103 if (!setup.sound_music)
7109 void PlayMenuMusic()
7111 PlayMenuMusicExt(menu.music[game_status]);
7114 void PlaySoundActivating()
7117 PlaySound(SND_MENU_ITEM_ACTIVATING);
7121 void PlaySoundSelecting()
7124 PlaySound(SND_MENU_ITEM_SELECTING);
7128 void ToggleFullscreenIfNeeded()
7130 boolean change_fullscreen = (setup.fullscreen !=
7131 video.fullscreen_enabled);
7132 boolean change_fullscreen_mode = (video.fullscreen_enabled &&
7133 !strEqual(setup.fullscreen_mode,
7134 video.fullscreen_mode_current));
7136 if (!video.fullscreen_available)
7140 if (change_fullscreen || change_fullscreen_mode)
7142 if (setup.fullscreen != video.fullscreen_enabled ||
7143 setup.fullscreen_mode != video.fullscreen_mode_current)
7146 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
7148 /* save backbuffer content which gets lost when toggling fullscreen mode */
7149 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
7152 if (change_fullscreen_mode)
7154 if (setup.fullscreen && video.fullscreen_enabled)
7157 /* keep fullscreen, but change fullscreen mode (screen resolution) */
7159 /* (this is now set in sdl.c) */
7161 video.fullscreen_mode_current = setup.fullscreen_mode;
7163 video.fullscreen_enabled = FALSE; /* force new fullscreen mode */
7166 /* toggle fullscreen */
7167 ChangeVideoModeIfNeeded(setup.fullscreen);
7169 setup.fullscreen = video.fullscreen_enabled;
7171 /* restore backbuffer content from temporary backbuffer backup bitmap */
7172 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
7174 FreeBitmap(tmp_backbuffer);
7177 /* update visible window/screen */
7178 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
7180 redraw_mask = REDRAW_ALL;