1 // ============================================================================
2 // Rocks'n'Diamonds - McDuffin Strikes Back!
3 // ----------------------------------------------------------------------------
4 // (c) 1995-2014 by Artsoft Entertainment
7 // http://www.artsoft.org/
8 // ----------------------------------------------------------------------------
10 // ============================================================================
14 #include "libgame/libgame.h"
26 /* select level set with EMC X11 graphics before activating EM GFX debugging */
27 #define DEBUG_EM_GFX 0
29 /* tool button identifiers */
30 #define TOOL_CTRL_ID_YES 0
31 #define TOOL_CTRL_ID_NO 1
32 #define TOOL_CTRL_ID_CONFIRM 2
33 #define TOOL_CTRL_ID_PLAYER_1 3
34 #define TOOL_CTRL_ID_PLAYER_2 4
35 #define TOOL_CTRL_ID_PLAYER_3 5
36 #define TOOL_CTRL_ID_PLAYER_4 6
38 #define NUM_TOOL_BUTTONS 7
40 /* constants for number of doors and door parts */
42 #define NUM_PANELS NUM_DOORS
43 // #define NUM_PANELS 0
44 #define MAX_PARTS_PER_DOOR 8
45 #define MAX_DOOR_PARTS (NUM_DOORS * MAX_PARTS_PER_DOOR + NUM_PANELS)
46 #define DOOR_PART_IS_PANEL(i) ((i) >= NUM_DOORS * MAX_PARTS_PER_DOOR)
49 struct DoorPartOrderInfo
55 static struct DoorPartOrderInfo door_part_order[MAX_DOOR_PARTS];
57 struct DoorPartControlInfo
61 struct DoorPartPosInfo *pos;
64 static struct DoorPartControlInfo door_part_controls[] =
68 IMG_DOOR_1_GFX_PART_1,
73 IMG_DOOR_1_GFX_PART_2,
78 IMG_DOOR_1_GFX_PART_3,
83 IMG_DOOR_1_GFX_PART_4,
88 IMG_DOOR_1_GFX_PART_5,
93 IMG_DOOR_1_GFX_PART_6,
98 IMG_DOOR_1_GFX_PART_7,
103 IMG_DOOR_1_GFX_PART_8,
109 IMG_DOOR_2_GFX_PART_1,
114 IMG_DOOR_2_GFX_PART_2,
119 IMG_DOOR_2_GFX_PART_3,
124 IMG_DOOR_2_GFX_PART_4,
129 IMG_DOOR_2_GFX_PART_5,
134 IMG_DOOR_2_GFX_PART_6,
139 IMG_DOOR_2_GFX_PART_7,
144 IMG_DOOR_2_GFX_PART_8,
150 IMG_BACKGROUND_PANEL,
167 /* forward declaration for internal use */
168 static void UnmapToolButtons();
169 static void HandleToolButtons(struct GadgetInfo *);
170 static int el_act_dir2crm(int, int, int);
171 static int el_act2crm(int, int);
173 static struct GadgetInfo *tool_gadget[NUM_TOOL_BUTTONS];
174 static int request_gadget_id = -1;
176 static char *print_if_not_empty(int element)
178 static char *s = NULL;
179 char *token_name = element_info[element].token_name;
184 s = checked_malloc(strlen(token_name) + 10 + 1);
186 if (element != EL_EMPTY)
187 sprintf(s, "%d\t['%s']", element, token_name);
189 sprintf(s, "%d", element);
194 void DumpTile(int x, int y)
199 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
205 printf_line("-", 79);
206 printf("Field Info: SCREEN(%d, %d), LEVEL(%d, %d)\n", sx, sy, x, y);
207 printf_line("-", 79);
209 if (!IN_LEV_FIELD(x, y))
211 printf("(not in level field)\n");
217 printf(" Feld: %d\t['%s']\n", Feld[x][y],
218 element_info[Feld[x][y]].token_name);
219 printf(" Back: %s\n", print_if_not_empty(Back[x][y]));
220 printf(" Store: %s\n", print_if_not_empty(Store[x][y]));
221 printf(" Store2: %s\n", print_if_not_empty(Store2[x][y]));
222 printf(" StorePlayer: %s\n", print_if_not_empty(StorePlayer[x][y]));
223 printf(" MovPos: %d\n", MovPos[x][y]);
224 printf(" MovDir: %d\n", MovDir[x][y]);
225 printf(" MovDelay: %d\n", MovDelay[x][y]);
226 printf(" ChangeDelay: %d\n", ChangeDelay[x][y]);
227 printf(" CustomValue: %d\n", CustomValue[x][y]);
228 printf(" GfxElement: %d\n", GfxElement[x][y]);
229 printf(" GfxAction: %d\n", GfxAction[x][y]);
230 printf(" GfxFrame: %d\n", GfxFrame[x][y]);
234 void SetDrawtoField(int mode)
236 if (mode == DRAW_FIELDBUFFER)
242 BX2 = SCR_FIELDX + 1;
243 BY2 = SCR_FIELDY + 1;
245 drawto_field = fieldbuffer;
247 else /* DRAW_BACKBUFFER */
253 BX2 = SCR_FIELDX - 1;
254 BY2 = SCR_FIELDY - 1;
256 drawto_field = backbuffer;
260 static void RedrawPlayfield_RND()
262 if (game.envelope_active)
265 DrawLevel(REDRAW_ALL);
269 void RedrawPlayfield()
271 if (game_status != GAME_MODE_PLAYING)
274 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
275 RedrawPlayfield_EM(TRUE);
276 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
277 RedrawPlayfield_SP(TRUE);
278 else if (level.game_engine_type == GAME_ENGINE_TYPE_RND)
279 RedrawPlayfield_RND();
281 BlitScreenToBitmap(backbuffer);
283 BlitBitmap(drawto, window, gfx.sx, gfx.sy, gfx.sxsize, gfx.sysize,
287 void DrawMaskedBorder_Rect(int x, int y, int width, int height)
289 Bitmap *bitmap = graphic_info[IMG_GLOBAL_BORDER].bitmap;
291 BlitBitmapMasked(bitmap, backbuffer, x, y, width, height, x, y);
294 void DrawMaskedBorder_FIELD()
296 if (global.border_status >= GAME_MODE_TITLE &&
297 global.border_status <= GAME_MODE_PLAYING &&
298 border.draw_masked[global.border_status])
299 DrawMaskedBorder_Rect(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
302 void DrawMaskedBorder_DOOR_1()
304 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
305 (global.border_status != GAME_MODE_EDITOR ||
306 border.draw_masked[GFX_SPECIAL_ARG_EDITOR]))
307 DrawMaskedBorder_Rect(DX, DY, DXSIZE, DYSIZE);
310 void DrawMaskedBorder_DOOR_2()
312 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
313 global.border_status != GAME_MODE_EDITOR)
314 DrawMaskedBorder_Rect(VX, VY, VXSIZE, VYSIZE);
317 void DrawMaskedBorder_DOOR_3()
319 /* currently not available */
322 void DrawMaskedBorder_ALL()
324 DrawMaskedBorder_FIELD();
325 DrawMaskedBorder_DOOR_1();
326 DrawMaskedBorder_DOOR_2();
327 DrawMaskedBorder_DOOR_3();
330 void DrawMaskedBorder(int redraw_mask)
332 /* never draw masked screen borders on borderless screens */
333 if (effectiveGameStatus() == GAME_MODE_LOADING ||
334 effectiveGameStatus() == GAME_MODE_TITLE)
337 if (redraw_mask & REDRAW_ALL)
338 DrawMaskedBorder_ALL();
341 if (redraw_mask & REDRAW_FIELD)
342 DrawMaskedBorder_FIELD();
343 if (redraw_mask & REDRAW_DOOR_1)
344 DrawMaskedBorder_DOOR_1();
345 if (redraw_mask & REDRAW_DOOR_2)
346 DrawMaskedBorder_DOOR_2();
347 if (redraw_mask & REDRAW_DOOR_3)
348 DrawMaskedBorder_DOOR_3();
352 void BlitScreenToBitmap_RND(Bitmap *target_bitmap)
354 int fx = FX, fy = FY;
355 int full_lev_fieldx = lev_fieldx + (BorderElement != EL_EMPTY ? 2 : 0);
356 int full_lev_fieldy = lev_fieldy + (BorderElement != EL_EMPTY ? 2 : 0);
358 int dx = (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
359 int dy = (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
360 int dx_var = dx * TILESIZE_VAR / TILESIZE;
361 int dy_var = dy * TILESIZE_VAR / TILESIZE;
364 ffx = (scroll_x - SBX_Left) * TILEX_VAR + dx_var;
365 ffy = (scroll_y - SBY_Upper) * TILEY_VAR + dy_var;
367 if (EVEN(SCR_FIELDX))
369 if (ffx < SBX_Right * TILEX_VAR + TILEX_VAR / 2 + TILEX_VAR)
370 fx += dx_var - MIN(ffx, TILEX_VAR / 2) + TILEX_VAR;
372 fx += (dx_var > 0 ? TILEX_VAR : 0);
379 if (EVEN(SCR_FIELDY))
381 if (ffy < SBY_Lower * TILEY_VAR + TILEY_VAR / 2 + TILEY_VAR)
382 fy += dy_var - MIN(ffy, TILEY_VAR / 2) + TILEY_VAR;
384 fy += (dy_var > 0 ? TILEY_VAR : 0);
391 if (full_lev_fieldx <= SCR_FIELDX)
393 if (EVEN(SCR_FIELDX))
394 fx = 2 * TILEX_VAR - (ODD(lev_fieldx) ? TILEX_VAR / 2 : 0);
396 fx = 2 * TILEX_VAR - (EVEN(lev_fieldx) ? TILEX_VAR / 2 : 0);
399 if (full_lev_fieldy <= SCR_FIELDY)
401 if (EVEN(SCR_FIELDY))
402 fy = 2 * TILEY_VAR - (ODD(lev_fieldy) ? TILEY_VAR / 2 : 0);
404 fy = 2 * TILEY_VAR - (EVEN(lev_fieldy) ? TILEY_VAR / 2 : 0);
407 BlitBitmap(drawto_field, target_bitmap, fx, fy, SXSIZE, SYSIZE, SX, SY);
410 void BlitScreenToBitmap(Bitmap *target_bitmap)
412 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
413 BlitScreenToBitmap_EM(target_bitmap);
414 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
415 BlitScreenToBitmap_SP(target_bitmap);
416 else if (level.game_engine_type == GAME_ENGINE_TYPE_RND)
417 BlitScreenToBitmap_RND(target_bitmap);
420 void BackToFront_OLD()
422 DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
425 /* !!! TEST ONLY !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
426 /* (force full redraw) */
427 if (game_status == GAME_MODE_PLAYING)
428 redraw_mask |= REDRAW_FIELD;
431 if (redraw_mask == REDRAW_NONE)
436 if (redraw_mask & REDRAW_ALL)
437 printf("[REDRAW_ALL]");
438 if (redraw_mask & REDRAW_FIELD)
439 printf("[REDRAW_FIELD]");
440 if (redraw_mask & REDRAW_DOOR_1)
441 printf("[REDRAW_DOOR_1]");
442 if (redraw_mask & REDRAW_DOOR_2)
443 printf("[REDRAW_DOOR_2]");
444 if (redraw_mask & REDRAW_FROM_BACKBUFFER)
445 printf("[REDRAW_FROM_BACKBUFFER]");
446 printf(" [%d]\n", FrameCounter);
449 if (global.fps_slowdown && game_status == GAME_MODE_PLAYING)
451 static boolean last_frame_skipped = FALSE;
452 boolean skip_even_when_not_scrolling = TRUE;
453 boolean just_scrolling = (ScreenMovDir != 0);
454 boolean verbose = FALSE;
456 if (global.fps_slowdown_factor > 1 &&
457 (FrameCounter % global.fps_slowdown_factor) &&
458 (just_scrolling || skip_even_when_not_scrolling))
460 redraw_mask &= ~REDRAW_MAIN;
462 last_frame_skipped = TRUE;
465 printf("FRAME SKIPPED\n");
469 if (last_frame_skipped)
470 redraw_mask |= REDRAW_FIELD;
472 last_frame_skipped = FALSE;
475 printf("frame not skipped\n");
479 /* synchronize X11 graphics at this point; if we would synchronize the
480 display immediately after the buffer switching (after the XFlush),
481 this could mean that we have to wait for the graphics to complete,
482 although we could go on doing calculations for the next frame */
486 /* never draw masked border to backbuffer when using playfield buffer */
487 if (game_status != GAME_MODE_PLAYING ||
488 redraw_mask & REDRAW_FROM_BACKBUFFER ||
489 buffer == backbuffer)
490 DrawMaskedBorder(redraw_mask);
492 DrawMaskedBorder(redraw_mask & REDRAW_DOORS);
494 if (redraw_mask & REDRAW_ALL)
496 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
498 redraw_mask = REDRAW_NONE;
501 if (redraw_mask & REDRAW_FIELD)
503 if (game_status != GAME_MODE_PLAYING ||
504 redraw_mask & REDRAW_FROM_BACKBUFFER)
506 BlitBitmap(backbuffer, window,
507 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
511 BlitScreenToBitmap_RND(window);
514 redraw_mask &= ~REDRAW_MAIN;
517 if (redraw_mask & REDRAW_DOORS)
519 if (redraw_mask & REDRAW_DOOR_1)
520 BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
522 if (redraw_mask & REDRAW_DOOR_2)
523 BlitBitmap(backbuffer, window, VX, VY, VXSIZE, VYSIZE, VX, VY);
525 if (redraw_mask & REDRAW_DOOR_3)
526 BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
528 redraw_mask &= ~REDRAW_DOORS;
531 if (redraw_mask & REDRAW_MICROLEVEL)
533 BlitBitmap(backbuffer, window, SX, SY + 10 * TILEY, SXSIZE, 7 * TILEY,
534 SX, SY + 10 * TILEY);
536 redraw_mask &= ~REDRAW_MICROLEVEL;
539 if (redraw_mask & REDRAW_FPS) /* display frames per second */
544 sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
545 if (!global.fps_slowdown)
548 sprintf(text, "%04.1f fps%s", global.frames_per_second, info1);
550 DrawTextExt(window, SX + SXSIZE + SX, 0, text, FONT_TEXT_2, BLIT_OPAQUE);
553 redraw_mask = REDRAW_NONE;
558 if (redraw_mask == REDRAW_NONE)
561 // draw masked border to all viewports, if defined
562 DrawMaskedBorder(redraw_mask);
564 // blit backbuffer to visible screen
565 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
567 redraw_mask = REDRAW_NONE;
570 static void FadeCrossSaveBackbuffer()
572 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
575 static void FadeExt(int fade_mask, int fade_mode, int fade_type)
577 static int fade_type_skip = FADE_TYPE_NONE;
578 void (*draw_border_function)(void) = NULL;
579 Bitmap *bitmap = (fade_mode & FADE_TYPE_TRANSFORM ? bitmap_db_cross : NULL);
580 int x, y, width, height;
581 int fade_delay, post_delay;
583 if (fade_type == FADE_TYPE_FADE_OUT)
585 if (fade_type_skip != FADE_TYPE_NONE)
587 /* skip all fade operations until specified fade operation */
588 if (fade_type & fade_type_skip)
589 fade_type_skip = FADE_TYPE_NONE;
594 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
596 FadeCrossSaveBackbuffer();
602 redraw_mask |= fade_mask;
604 if (fade_type == FADE_TYPE_SKIP)
606 fade_type_skip = fade_mode;
611 fade_delay = fading.fade_delay;
612 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
614 if (fade_type_skip != FADE_TYPE_NONE)
616 /* skip all fade operations until specified fade operation */
617 if (fade_type & fade_type_skip)
618 fade_type_skip = FADE_TYPE_NONE;
623 if (global.autoplay_leveldir)
628 if (fade_mask == REDRAW_FIELD)
633 height = FULL_SYSIZE;
635 if (border.draw_masked_when_fading)
636 draw_border_function = DrawMaskedBorder_FIELD; /* update when fading */
638 DrawMaskedBorder_FIELD(); /* draw once */
640 else /* REDRAW_ALL */
648 if (!setup.fade_screens ||
650 fading.fade_mode == FADE_MODE_NONE)
652 if (fade_mode == FADE_MODE_FADE_OUT)
655 BlitBitmap(backbuffer, window, x, y, width, height, x, y);
657 redraw_mask &= ~fade_mask;
662 FadeRectangle(bitmap, x, y, width, height, fade_mode, fade_delay, post_delay,
663 draw_border_function);
665 redraw_mask &= ~fade_mask;
668 void FadeIn(int fade_mask)
670 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
671 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_IN);
673 FadeExt(fade_mask, FADE_MODE_FADE_IN, FADE_TYPE_FADE_IN);
676 void FadeOut(int fade_mask)
678 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
679 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_OUT);
681 FadeExt(fade_mask, FADE_MODE_FADE_OUT, FADE_TYPE_FADE_OUT);
683 global.border_status = game_status;
686 static void FadeSetLeaveNext(struct TitleFadingInfo fading_leave, boolean set)
688 static struct TitleFadingInfo fading_leave_stored;
691 fading_leave_stored = fading_leave;
693 fading = fading_leave_stored;
696 void FadeSetEnterMenu()
698 fading = menu.enter_menu;
700 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
703 void FadeSetLeaveMenu()
705 fading = menu.leave_menu;
707 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
710 void FadeSetEnterScreen()
712 fading = menu.enter_screen[game_status];
714 FadeSetLeaveNext(menu.leave_screen[game_status], TRUE); /* store */
717 void FadeSetNextScreen()
719 fading = menu.next_screen;
721 // (do not overwrite fade mode set by FadeSetEnterScreen)
722 // FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
725 void FadeSetLeaveScreen()
727 FadeSetLeaveNext(menu.leave_screen[game_status], FALSE); /* recall */
730 void FadeSetFromType(int type)
732 if (type & TYPE_ENTER_SCREEN)
733 FadeSetEnterScreen();
734 else if (type & TYPE_ENTER)
736 else if (type & TYPE_LEAVE)
740 void FadeSetDisabled()
742 static struct TitleFadingInfo fading_none = { FADE_MODE_NONE, -1, -1, -1 };
744 fading = fading_none;
747 void FadeSkipNextFadeIn()
749 FadeExt(0, FADE_MODE_SKIP_FADE_IN, FADE_TYPE_SKIP);
752 void FadeSkipNextFadeOut()
754 FadeExt(0, FADE_MODE_SKIP_FADE_OUT, FADE_TYPE_SKIP);
757 void SetWindowBackgroundImageIfDefined(int graphic)
759 if (graphic_info[graphic].bitmap)
760 SetWindowBackgroundBitmap(graphic_info[graphic].bitmap);
763 void SetMainBackgroundImageIfDefined(int graphic)
765 if (graphic_info[graphic].bitmap)
766 SetMainBackgroundBitmap(graphic_info[graphic].bitmap);
769 void SetDoorBackgroundImageIfDefined(int graphic)
771 if (graphic_info[graphic].bitmap)
772 SetDoorBackgroundBitmap(graphic_info[graphic].bitmap);
775 void SetWindowBackgroundImage(int graphic)
777 SetWindowBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
778 graphic_info[graphic].bitmap ?
779 graphic_info[graphic].bitmap :
780 graphic_info[IMG_BACKGROUND].bitmap);
783 void SetMainBackgroundImage(int graphic)
785 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
786 graphic_info[graphic].bitmap ?
787 graphic_info[graphic].bitmap :
788 graphic_info[IMG_BACKGROUND].bitmap);
791 void SetDoorBackgroundImage(int graphic)
793 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
794 graphic_info[graphic].bitmap ?
795 graphic_info[graphic].bitmap :
796 graphic_info[IMG_BACKGROUND].bitmap);
799 void SetPanelBackground()
801 struct GraphicInfo *gfx = &graphic_info[IMG_BACKGROUND_PANEL];
803 BlitBitmapTiled(gfx->bitmap, bitmap_db_panel, gfx->src_x, gfx->src_y,
804 gfx->width, gfx->height, 0, 0, DXSIZE, DYSIZE);
806 SetDoorBackgroundBitmap(bitmap_db_panel);
809 void DrawBackground(int x, int y, int width, int height)
811 /* "drawto" might still point to playfield buffer here (hall of fame) */
812 ClearRectangleOnBackground(backbuffer, x, y, width, height);
814 if (IN_GFX_FIELD_FULL(x, y))
815 redraw_mask |= REDRAW_FIELD;
816 else if (IN_GFX_DOOR_1(x, y))
817 redraw_mask |= REDRAW_DOOR_1;
818 else if (IN_GFX_DOOR_2(x, y))
819 redraw_mask |= REDRAW_DOOR_2;
820 else if (IN_GFX_DOOR_3(x, y))
821 redraw_mask |= REDRAW_DOOR_3;
824 void DrawBackgroundForFont(int x, int y, int width, int height, int font_nr)
826 struct FontBitmapInfo *font = getFontBitmapInfo(font_nr);
828 if (font->bitmap == NULL)
831 DrawBackground(x, y, width, height);
834 void DrawBackgroundForGraphic(int x, int y, int width, int height, int graphic)
836 struct GraphicInfo *g = &graphic_info[graphic];
838 if (g->bitmap == NULL)
841 DrawBackground(x, y, width, height);
846 /* !!! "drawto" might still point to playfield buffer here (see above) !!! */
847 /* (when entering hall of fame after playing) */
848 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
850 /* !!! maybe this should be done before clearing the background !!! */
851 if (game_status == GAME_MODE_PLAYING)
853 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
854 SetDrawtoField(DRAW_FIELDBUFFER);
857 SetDrawtoField(DRAW_BACKBUFFER);
860 void MarkTileDirty(int x, int y)
862 redraw_mask |= REDRAW_FIELD;
865 void SetBorderElement()
869 BorderElement = EL_EMPTY;
871 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
873 for (x = 0; x < lev_fieldx; x++)
875 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
876 BorderElement = EL_STEELWALL;
878 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
884 void FloodFillLevel(int from_x, int from_y, int fill_element,
885 short field[MAX_LEV_FIELDX][MAX_LEV_FIELDY],
886 int max_fieldx, int max_fieldy)
890 static int check[4][2] = { { -1, 0 }, { 0, -1 }, { 1, 0 }, { 0, 1 } };
891 static int safety = 0;
893 /* check if starting field still has the desired content */
894 if (field[from_x][from_y] == fill_element)
899 if (safety > max_fieldx * max_fieldy)
900 Error(ERR_EXIT, "Something went wrong in 'FloodFill()'. Please debug.");
902 old_element = field[from_x][from_y];
903 field[from_x][from_y] = fill_element;
905 for (i = 0; i < 4; i++)
907 x = from_x + check[i][0];
908 y = from_y + check[i][1];
910 if (IN_FIELD(x, y, max_fieldx, max_fieldy) && field[x][y] == old_element)
911 FloodFillLevel(x, y, fill_element, field, max_fieldx, max_fieldy);
917 void SetRandomAnimationValue(int x, int y)
919 gfx.anim_random_frame = GfxRandom[x][y];
922 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
924 /* animation synchronized with global frame counter, not move position */
925 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
926 sync_frame = FrameCounter;
928 return getAnimationFrame(graphic_info[graphic].anim_frames,
929 graphic_info[graphic].anim_delay,
930 graphic_info[graphic].anim_mode,
931 graphic_info[graphic].anim_start_frame,
935 void getSizedGraphicSourceExt(int graphic, int frame, int tilesize,
936 Bitmap **bitmap, int *x, int *y,
937 boolean get_backside)
939 struct GraphicInfo *g = &graphic_info[graphic];
940 Bitmap *src_bitmap = g->bitmap;
941 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
942 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
943 int tilesize_capped = MIN(MAX(1, tilesize), TILESIZE);
945 // if no in-game graphics defined, always use standard graphic size
946 if (g->bitmaps[IMG_BITMAP_GAME] == NULL)
949 if (tilesize == gfx.standard_tile_size)
950 src_bitmap = g->bitmaps[IMG_BITMAP_STANDARD];
951 else if (tilesize == game.tile_size)
952 src_bitmap = g->bitmaps[IMG_BITMAP_GAME];
954 src_bitmap = g->bitmaps[IMG_BITMAP_1x1 - log_2(tilesize_capped)];
956 if (g->offset_y == 0) /* frames are ordered horizontally */
958 int max_width = g->anim_frames_per_line * g->width;
959 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
961 src_x = pos % max_width;
962 src_y = src_y % g->height + pos / max_width * g->height;
964 else if (g->offset_x == 0) /* frames are ordered vertically */
966 int max_height = g->anim_frames_per_line * g->height;
967 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
969 src_x = src_x % g->width + pos / max_height * g->width;
970 src_y = pos % max_height;
972 else /* frames are ordered diagonally */
974 src_x = src_x + frame * g->offset_x;
975 src_y = src_y + frame * g->offset_y;
978 *bitmap = src_bitmap;
979 *x = src_x * tilesize / TILESIZE;
980 *y = src_y * tilesize / TILESIZE;
983 void getFixedGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
984 int *x, int *y, boolean get_backside)
986 getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y,
990 void getSizedGraphicSource(int graphic, int frame, int tilesize,
991 Bitmap **bitmap, int *x, int *y)
993 getSizedGraphicSourceExt(graphic, frame, tilesize, bitmap, x, y, FALSE);
996 void getFixedGraphicSource(int graphic, int frame,
997 Bitmap **bitmap, int *x, int *y)
999 getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y, FALSE);
1002 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1004 getSizedGraphicSource(graphic, 0, MINI_TILESIZE, bitmap, x, y);
1007 inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1008 int *x, int *y, boolean get_backside)
1010 struct GraphicInfo *g = &graphic_info[graphic];
1011 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
1012 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
1014 if (TILESIZE_VAR != TILESIZE)
1015 return getSizedGraphicSourceExt(graphic, frame, TILESIZE_VAR, bitmap, x, y,
1018 *bitmap = g->bitmap;
1020 if (g->offset_y == 0) /* frames are ordered horizontally */
1022 int max_width = g->anim_frames_per_line * g->width;
1023 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
1025 *x = pos % max_width;
1026 *y = src_y % g->height + pos / max_width * g->height;
1028 else if (g->offset_x == 0) /* frames are ordered vertically */
1030 int max_height = g->anim_frames_per_line * g->height;
1031 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
1033 *x = src_x % g->width + pos / max_height * g->width;
1034 *y = pos % max_height;
1036 else /* frames are ordered diagonally */
1038 *x = src_x + frame * g->offset_x;
1039 *y = src_y + frame * g->offset_y;
1043 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
1045 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
1048 void DrawGraphic(int x, int y, int graphic, int frame)
1051 if (!IN_SCR_FIELD(x, y))
1053 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1054 printf("DrawGraphic(): This should never happen!\n");
1059 DrawGraphicExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR, graphic,
1062 MarkTileDirty(x, y);
1065 void DrawFixedGraphic(int x, int y, int graphic, int frame)
1068 if (!IN_SCR_FIELD(x, y))
1070 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1071 printf("DrawGraphic(): This should never happen!\n");
1076 DrawFixedGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic,
1078 MarkTileDirty(x, y);
1081 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1087 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1089 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX_VAR, TILEY_VAR, x, y);
1092 void DrawFixedGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1098 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1099 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
1102 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
1105 if (!IN_SCR_FIELD(x, y))
1107 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1108 printf("DrawGraphicThruMask(): This should never happen!\n");
1113 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
1116 MarkTileDirty(x, y);
1119 void DrawFixedGraphicThruMask(int x, int y, int graphic, int frame)
1122 if (!IN_SCR_FIELD(x, y))
1124 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1125 printf("DrawGraphicThruMask(): This should never happen!\n");
1130 DrawFixedGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
1132 MarkTileDirty(x, y);
1135 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
1141 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1143 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX_VAR, TILEY_VAR,
1147 void DrawFixedGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y,
1148 int graphic, int frame)
1150 struct GraphicInfo *g = &graphic_info[graphic];
1154 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1156 BlitBitmapMasked(src_bitmap, d, src_x, src_y, g->width, g->height,
1160 void DrawSizedGraphic(int x, int y, int graphic, int frame, int tilesize)
1162 DrawSizedGraphicExt(drawto, SX + x * tilesize, SY + y * tilesize, graphic,
1164 MarkTileDirty(x / tilesize, y / tilesize);
1167 void DrawSizedGraphicExt(DrawBuffer *d, int x, int y, int graphic, int frame,
1173 getSizedGraphicSource(graphic, frame, tilesize, &src_bitmap, &src_x, &src_y);
1174 BlitBitmap(src_bitmap, d, src_x, src_y, tilesize, tilesize, x, y);
1177 void DrawMiniGraphic(int x, int y, int graphic)
1179 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
1180 MarkTileDirty(x / 2, y / 2);
1183 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
1188 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1189 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
1192 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
1193 int graphic, int frame,
1194 int cut_mode, int mask_mode)
1199 int width = TILEX, height = TILEY;
1202 if (dx || dy) /* shifted graphic */
1204 if (x < BX1) /* object enters playfield from the left */
1211 else if (x > BX2) /* object enters playfield from the right */
1217 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
1223 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
1225 else if (dx) /* general horizontal movement */
1226 MarkTileDirty(x + SIGN(dx), y);
1228 if (y < BY1) /* object enters playfield from the top */
1230 if (cut_mode==CUT_BELOW) /* object completely above top border */
1238 else if (y > BY2) /* object enters playfield from the bottom */
1244 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
1250 else if (dy > 0 && cut_mode == CUT_ABOVE)
1252 if (y == BY2) /* object completely above bottom border */
1258 MarkTileDirty(x, y + 1);
1259 } /* object leaves playfield to the bottom */
1260 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1262 else if (dy) /* general vertical movement */
1263 MarkTileDirty(x, y + SIGN(dy));
1267 if (!IN_SCR_FIELD(x, y))
1269 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1270 printf("DrawGraphicShifted(): This should never happen!\n");
1275 width = width * TILESIZE_VAR / TILESIZE;
1276 height = height * TILESIZE_VAR / TILESIZE;
1277 cx = cx * TILESIZE_VAR / TILESIZE;
1278 cy = cy * TILESIZE_VAR / TILESIZE;
1279 dx = dx * TILESIZE_VAR / TILESIZE;
1280 dy = dy * TILESIZE_VAR / TILESIZE;
1282 if (width > 0 && height > 0)
1284 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1289 dst_x = FX + x * TILEX_VAR + dx;
1290 dst_y = FY + y * TILEY_VAR + dy;
1292 if (mask_mode == USE_MASKING)
1293 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1296 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1299 MarkTileDirty(x, y);
1303 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
1304 int graphic, int frame,
1305 int cut_mode, int mask_mode)
1310 int width = TILEX_VAR, height = TILEY_VAR;
1313 int x2 = x + SIGN(dx);
1314 int y2 = y + SIGN(dy);
1316 /* movement with two-tile animations must be sync'ed with movement position,
1317 not with current GfxFrame (which can be higher when using slow movement) */
1318 int anim_pos = (dx ? ABS(dx) : ABS(dy));
1319 int anim_frames = graphic_info[graphic].anim_frames;
1321 /* (we also need anim_delay here for movement animations with less frames) */
1322 int anim_delay = graphic_info[graphic].anim_delay;
1323 int sync_frame = anim_pos * anim_frames * anim_delay / TILESIZE;
1325 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
1326 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
1328 /* re-calculate animation frame for two-tile movement animation */
1329 frame = getGraphicAnimationFrame(graphic, sync_frame);
1331 /* check if movement start graphic inside screen area and should be drawn */
1332 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
1334 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
1336 dst_x = FX + x1 * TILEX_VAR;
1337 dst_y = FY + y1 * TILEY_VAR;
1339 if (mask_mode == USE_MASKING)
1340 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1343 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1346 MarkTileDirty(x1, y1);
1349 /* check if movement end graphic inside screen area and should be drawn */
1350 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
1352 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
1354 dst_x = FX + x2 * TILEX_VAR;
1355 dst_y = FY + y2 * TILEY_VAR;
1357 if (mask_mode == USE_MASKING)
1358 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1361 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1364 MarkTileDirty(x2, y2);
1368 static void DrawGraphicShifted(int x, int y, int dx, int dy,
1369 int graphic, int frame,
1370 int cut_mode, int mask_mode)
1374 DrawGraphic(x, y, graphic, frame);
1379 if (graphic_info[graphic].double_movement) /* EM style movement images */
1380 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1382 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1385 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1386 int frame, int cut_mode)
1388 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
1391 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1392 int cut_mode, int mask_mode)
1394 int lx = LEVELX(x), ly = LEVELY(y);
1398 if (IN_LEV_FIELD(lx, ly))
1400 SetRandomAnimationValue(lx, ly);
1402 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
1403 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1405 /* do not use double (EM style) movement graphic when not moving */
1406 if (graphic_info[graphic].double_movement && !dx && !dy)
1408 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
1409 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1412 else /* border element */
1414 graphic = el2img(element);
1415 frame = getGraphicAnimationFrame(graphic, -1);
1418 if (element == EL_EXPANDABLE_WALL)
1420 boolean left_stopped = FALSE, right_stopped = FALSE;
1422 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1423 left_stopped = TRUE;
1424 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1425 right_stopped = TRUE;
1427 if (left_stopped && right_stopped)
1429 else if (left_stopped)
1431 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1432 frame = graphic_info[graphic].anim_frames - 1;
1434 else if (right_stopped)
1436 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1437 frame = graphic_info[graphic].anim_frames - 1;
1442 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1443 else if (mask_mode == USE_MASKING)
1444 DrawGraphicThruMask(x, y, graphic, frame);
1446 DrawGraphic(x, y, graphic, frame);
1449 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1450 int cut_mode, int mask_mode)
1452 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1453 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1454 cut_mode, mask_mode);
1457 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1460 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1463 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1466 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1469 void DrawLevelElementThruMask(int x, int y, int element)
1471 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1474 void DrawLevelFieldThruMask(int x, int y)
1476 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1479 /* !!! implementation of quicksand is totally broken !!! */
1480 #define IS_CRUMBLED_TILE(x, y, e) \
1481 (GFX_CRUMBLED(e) && (!IN_LEV_FIELD(x, y) || \
1482 !IS_MOVING(x, y) || \
1483 (e) == EL_QUICKSAND_EMPTYING || \
1484 (e) == EL_QUICKSAND_FAST_EMPTYING))
1486 static void DrawLevelFieldCrumbledInnerCorners(int x, int y, int dx, int dy,
1491 int width, height, cx, cy;
1492 int sx = SCREENX(x), sy = SCREENY(y);
1493 int crumbled_border_size = graphic_info[graphic].border_size;
1496 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1498 for (i = 1; i < 4; i++)
1500 int dxx = (i & 1 ? dx : 0);
1501 int dyy = (i & 2 ? dy : 0);
1504 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1507 /* check if neighbour field is of same crumble type */
1508 boolean same = (IS_CRUMBLED_TILE(xx, yy, element) &&
1509 graphic_info[graphic].class ==
1510 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class);
1512 /* return if check prevents inner corner */
1513 if (same == (dxx == dx && dyy == dy))
1517 /* if we reach this point, we have an inner corner */
1519 getGraphicSource(graphic, 1, &src_bitmap, &src_x, &src_y);
1521 width = crumbled_border_size * TILESIZE_VAR / TILESIZE;
1522 height = crumbled_border_size * TILESIZE_VAR / TILESIZE;
1523 cx = (dx > 0 ? TILESIZE_VAR - width : 0);
1524 cy = (dy > 0 ? TILESIZE_VAR - height : 0);
1526 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1527 width, height, FX + sx * TILEX_VAR + cx, FY + sy * TILEY_VAR + cy);
1530 static void DrawLevelFieldCrumbledBorders(int x, int y, int graphic, int frame,
1535 int width, height, bx, by, cx, cy;
1536 int sx = SCREENX(x), sy = SCREENY(y);
1537 int crumbled_border_size = graphic_info[graphic].border_size;
1538 int crumbled_border_size_var = crumbled_border_size * TILESIZE_VAR / TILESIZE;
1539 int crumbled_border_pos_var = TILESIZE_VAR - crumbled_border_size_var;
1542 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1544 /* draw simple, sloppy, non-corner-accurate crumbled border */
1546 width = (dir == 1 || dir == 2 ? crumbled_border_size_var : TILESIZE_VAR);
1547 height = (dir == 0 || dir == 3 ? crumbled_border_size_var : TILESIZE_VAR);
1548 cx = (dir == 2 ? crumbled_border_pos_var : 0);
1549 cy = (dir == 3 ? crumbled_border_pos_var : 0);
1551 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy, width, height,
1552 FX + sx * TILEX_VAR + cx,
1553 FY + sy * TILEY_VAR + cy);
1555 /* (remaining middle border part must be at least as big as corner part) */
1556 if (!(graphic_info[graphic].style & STYLE_ACCURATE_BORDERS) ||
1557 crumbled_border_size >= TILESIZE / 3)
1560 /* correct corners of crumbled border, if needed */
1562 for (i = -1; i <= 1; i += 2)
1564 int xx = x + (dir == 0 || dir == 3 ? i : 0);
1565 int yy = y + (dir == 1 || dir == 2 ? i : 0);
1566 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1569 /* check if neighbour field is of same crumble type */
1570 if (IS_CRUMBLED_TILE(xx, yy, element) &&
1571 graphic_info[graphic].class ==
1572 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1574 /* no crumbled corner, but continued crumbled border */
1576 int c1 = (dir == 2 || dir == 3 ? crumbled_border_pos_var : 0);
1577 int c2 = (i == 1 ? crumbled_border_pos_var : 0);
1578 int b1 = (i == 1 ? crumbled_border_size_var :
1579 TILESIZE_VAR - 2 * crumbled_border_size_var);
1581 width = crumbled_border_size_var;
1582 height = crumbled_border_size_var;
1584 if (dir == 1 || dir == 2)
1599 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
1601 FX + sx * TILEX_VAR + cx,
1602 FY + sy * TILEY_VAR + cy);
1607 static void DrawLevelFieldCrumbledExt(int x, int y, int graphic, int frame)
1609 int sx = SCREENX(x), sy = SCREENY(y);
1612 static int xy[4][2] =
1620 if (!IN_LEV_FIELD(x, y))
1623 element = TILE_GFX_ELEMENT(x, y);
1625 /* crumble field itself */
1626 if (IS_CRUMBLED_TILE(x, y, element))
1628 if (!IN_SCR_FIELD(sx, sy))
1631 for (i = 0; i < 4; i++)
1633 int xx = x + xy[i][0];
1634 int yy = y + xy[i][1];
1636 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1639 /* check if neighbour field is of same crumble type */
1640 if (IS_CRUMBLED_TILE(xx, yy, element) &&
1641 graphic_info[graphic].class ==
1642 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1645 DrawLevelFieldCrumbledBorders(x, y, graphic, frame, i);
1648 if ((graphic_info[graphic].style & STYLE_INNER_CORNERS) &&
1649 graphic_info[graphic].anim_frames == 2)
1651 for (i = 0; i < 4; i++)
1653 int dx = (i & 1 ? +1 : -1);
1654 int dy = (i & 2 ? +1 : -1);
1656 DrawLevelFieldCrumbledInnerCorners(x, y, dx, dy, graphic);
1660 MarkTileDirty(sx, sy);
1662 else /* center field not crumbled -- crumble neighbour fields */
1664 for (i = 0; i < 4; i++)
1666 int xx = x + xy[i][0];
1667 int yy = y + xy[i][1];
1668 int sxx = sx + xy[i][0];
1669 int syy = sy + xy[i][1];
1671 if (!IN_LEV_FIELD(xx, yy) ||
1672 !IN_SCR_FIELD(sxx, syy))
1675 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
1678 element = TILE_GFX_ELEMENT(xx, yy);
1680 if (!IS_CRUMBLED_TILE(xx, yy, element))
1683 graphic = el_act2crm(element, ACTION_DEFAULT);
1685 DrawLevelFieldCrumbledBorders(xx, yy, graphic, 0, 3 - i);
1687 MarkTileDirty(sxx, syy);
1692 void DrawLevelFieldCrumbled(int x, int y)
1696 if (!IN_LEV_FIELD(x, y))
1699 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1700 GfxElement[x][y] != EL_UNDEFINED &&
1701 GFX_CRUMBLED(GfxElement[x][y]))
1703 DrawLevelFieldCrumbledDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
1708 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
1710 DrawLevelFieldCrumbledExt(x, y, graphic, 0);
1713 void DrawLevelFieldCrumbledDigging(int x, int y, int direction,
1716 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1717 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1718 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1719 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1720 int sx = SCREENX(x), sy = SCREENY(y);
1722 DrawGraphic(sx, sy, graphic1, frame1);
1723 DrawLevelFieldCrumbledExt(x, y, graphic2, frame2);
1726 void DrawLevelFieldCrumbledNeighbours(int x, int y)
1728 int sx = SCREENX(x), sy = SCREENY(y);
1729 static int xy[4][2] =
1738 for (i = 0; i < 4; i++)
1740 int xx = x + xy[i][0];
1741 int yy = y + xy[i][1];
1742 int sxx = sx + xy[i][0];
1743 int syy = sy + xy[i][1];
1745 if (!IN_LEV_FIELD(xx, yy) ||
1746 !IN_SCR_FIELD(sxx, syy) ||
1747 !GFX_CRUMBLED(Feld[xx][yy]) ||
1751 DrawLevelField(xx, yy);
1755 static int getBorderElement(int x, int y)
1759 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1760 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1761 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1762 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1763 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1764 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1765 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1767 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1768 int steel_position = (x == -1 && y == -1 ? 0 :
1769 x == lev_fieldx && y == -1 ? 1 :
1770 x == -1 && y == lev_fieldy ? 2 :
1771 x == lev_fieldx && y == lev_fieldy ? 3 :
1772 x == -1 || x == lev_fieldx ? 4 :
1773 y == -1 || y == lev_fieldy ? 5 : 6);
1775 return border[steel_position][steel_type];
1778 void DrawScreenElement(int x, int y, int element)
1780 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1781 DrawLevelFieldCrumbled(LEVELX(x), LEVELY(y));
1784 void DrawLevelElement(int x, int y, int element)
1786 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1787 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1790 void DrawScreenField(int x, int y)
1792 int lx = LEVELX(x), ly = LEVELY(y);
1793 int element, content;
1795 if (!IN_LEV_FIELD(lx, ly))
1797 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1800 element = getBorderElement(lx, ly);
1802 DrawScreenElement(x, y, element);
1807 element = Feld[lx][ly];
1808 content = Store[lx][ly];
1810 if (IS_MOVING(lx, ly))
1812 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1813 boolean cut_mode = NO_CUTTING;
1815 if (element == EL_QUICKSAND_EMPTYING ||
1816 element == EL_QUICKSAND_FAST_EMPTYING ||
1817 element == EL_MAGIC_WALL_EMPTYING ||
1818 element == EL_BD_MAGIC_WALL_EMPTYING ||
1819 element == EL_DC_MAGIC_WALL_EMPTYING ||
1820 element == EL_AMOEBA_DROPPING)
1821 cut_mode = CUT_ABOVE;
1822 else if (element == EL_QUICKSAND_FILLING ||
1823 element == EL_QUICKSAND_FAST_FILLING ||
1824 element == EL_MAGIC_WALL_FILLING ||
1825 element == EL_BD_MAGIC_WALL_FILLING ||
1826 element == EL_DC_MAGIC_WALL_FILLING)
1827 cut_mode = CUT_BELOW;
1829 if (cut_mode == CUT_ABOVE)
1830 DrawScreenElement(x, y, element);
1832 DrawScreenElement(x, y, EL_EMPTY);
1835 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1836 else if (cut_mode == NO_CUTTING)
1837 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1840 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1842 if (cut_mode == CUT_BELOW &&
1843 IN_LEV_FIELD(lx, ly + 1) && IN_SCR_FIELD(x, y + 1))
1844 DrawLevelElement(lx, ly + 1, element);
1847 if (content == EL_ACID)
1849 int dir = MovDir[lx][ly];
1850 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
1851 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
1853 DrawLevelElementThruMask(newlx, newly, EL_ACID);
1856 else if (IS_BLOCKED(lx, ly))
1861 boolean cut_mode = NO_CUTTING;
1862 int element_old, content_old;
1864 Blocked2Moving(lx, ly, &oldx, &oldy);
1867 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1868 MovDir[oldx][oldy] == MV_RIGHT);
1870 element_old = Feld[oldx][oldy];
1871 content_old = Store[oldx][oldy];
1873 if (element_old == EL_QUICKSAND_EMPTYING ||
1874 element_old == EL_QUICKSAND_FAST_EMPTYING ||
1875 element_old == EL_MAGIC_WALL_EMPTYING ||
1876 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1877 element_old == EL_DC_MAGIC_WALL_EMPTYING ||
1878 element_old == EL_AMOEBA_DROPPING)
1879 cut_mode = CUT_ABOVE;
1881 DrawScreenElement(x, y, EL_EMPTY);
1884 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1886 else if (cut_mode == NO_CUTTING)
1887 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1890 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1893 else if (IS_DRAWABLE(element))
1894 DrawScreenElement(x, y, element);
1896 DrawScreenElement(x, y, EL_EMPTY);
1899 void DrawLevelField(int x, int y)
1901 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1902 DrawScreenField(SCREENX(x), SCREENY(y));
1903 else if (IS_MOVING(x, y))
1907 Moving2Blocked(x, y, &newx, &newy);
1908 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1909 DrawScreenField(SCREENX(newx), SCREENY(newy));
1911 else if (IS_BLOCKED(x, y))
1915 Blocked2Moving(x, y, &oldx, &oldy);
1916 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1917 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1921 void DrawSizedElement(int x, int y, int element, int tilesize)
1925 graphic = el2edimg(element);
1926 DrawSizedGraphic(x, y, graphic, 0, tilesize);
1929 void DrawMiniElement(int x, int y, int element)
1933 graphic = el2edimg(element);
1934 DrawMiniGraphic(x, y, graphic);
1937 void DrawSizedElementOrWall(int sx, int sy, int scroll_x, int scroll_y,
1940 int x = sx + scroll_x, y = sy + scroll_y;
1942 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1943 DrawSizedElement(sx, sy, EL_EMPTY, tilesize);
1944 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1945 DrawSizedElement(sx, sy, Feld[x][y], tilesize);
1947 DrawSizedGraphic(sx, sy, el2edimg(getBorderElement(x, y)), 0, tilesize);
1950 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1952 int x = sx + scroll_x, y = sy + scroll_y;
1954 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1955 DrawMiniElement(sx, sy, EL_EMPTY);
1956 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1957 DrawMiniElement(sx, sy, Feld[x][y]);
1959 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1962 void DrawEnvelopeBackgroundTiles(int graphic, int startx, int starty,
1963 int x, int y, int xsize, int ysize,
1964 int tile_width, int tile_height)
1968 int dst_x = startx + x * tile_width;
1969 int dst_y = starty + y * tile_height;
1970 int width = graphic_info[graphic].width;
1971 int height = graphic_info[graphic].height;
1972 int inner_width_raw = MAX(width - 2 * tile_width, tile_width);
1973 int inner_height_raw = MAX(height - 2 * tile_height, tile_height);
1974 int inner_width = inner_width_raw - (inner_width_raw % tile_width);
1975 int inner_height = inner_height_raw - (inner_height_raw % tile_height);
1976 int inner_sx = (width >= 3 * tile_width ? tile_width : 0);
1977 int inner_sy = (height >= 3 * tile_height ? tile_height : 0);
1978 boolean draw_masked = graphic_info[graphic].draw_masked;
1980 getFixedGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1982 if (src_bitmap == NULL || width < tile_width || height < tile_height)
1984 ClearRectangle(drawto, dst_x, dst_y, tile_width, tile_height);
1988 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - tile_width :
1989 inner_sx + (x - 1) * tile_width % inner_width);
1990 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - tile_height :
1991 inner_sy + (y - 1) * tile_height % inner_height);
1994 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
1997 BlitBitmap(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
2001 void DrawEnvelopeBackground(int graphic, int startx, int starty,
2002 int x, int y, int xsize, int ysize, int font_nr)
2004 int font_width = getFontWidth(font_nr);
2005 int font_height = getFontHeight(font_nr);
2007 DrawEnvelopeBackgroundTiles(graphic, startx, starty, x, y, xsize, ysize,
2008 font_width, font_height);
2011 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
2013 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2014 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2015 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2016 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2017 boolean no_delay = (tape.warp_forward);
2018 unsigned int anim_delay = 0;
2019 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
2020 int anim_delay_value = (no_delay ? 0 : frame_delay_value) / 2;
2021 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
2022 int font_width = getFontWidth(font_nr);
2023 int font_height = getFontHeight(font_nr);
2024 int max_xsize = level.envelope[envelope_nr].xsize;
2025 int max_ysize = level.envelope[envelope_nr].ysize;
2026 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
2027 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
2028 int xend = max_xsize;
2029 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
2030 int xstep = (xstart < xend ? 1 : 0);
2031 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2033 int end = MAX(xend - xstart, yend - ystart);
2036 for (i = start; i <= end; i++)
2038 int last_frame = end; // last frame of this "for" loop
2039 int x = xstart + i * xstep;
2040 int y = ystart + i * ystep;
2041 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2042 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2043 int sx = SX + (SXSIZE - xsize * font_width) / 2;
2044 int sy = SY + (SYSIZE - ysize * font_height) / 2;
2047 SetDrawtoField(DRAW_FIELDBUFFER);
2049 BlitScreenToBitmap(backbuffer);
2051 SetDrawtoField(DRAW_BACKBUFFER);
2053 for (yy = 0; yy < ysize; yy++)
2054 for (xx = 0; xx < xsize; xx++)
2055 DrawEnvelopeBackground(graphic, sx, sy, xx, yy, xsize, ysize, font_nr);
2057 DrawTextBuffer(sx + font_width, sy + font_height,
2058 level.envelope[envelope_nr].text, font_nr, max_xsize,
2059 xsize - 2, ysize - 2, 0, mask_mode,
2060 level.envelope[envelope_nr].autowrap,
2061 level.envelope[envelope_nr].centered, FALSE);
2063 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2066 SkipUntilDelayReached(&anim_delay, anim_delay_value, &i, last_frame);
2070 void ShowEnvelope(int envelope_nr)
2072 int element = EL_ENVELOPE_1 + envelope_nr;
2073 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2074 int sound_opening = element_info[element].sound[ACTION_OPENING];
2075 int sound_closing = element_info[element].sound[ACTION_CLOSING];
2076 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2077 boolean no_delay = (tape.warp_forward);
2078 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
2079 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
2080 int anim_mode = graphic_info[graphic].anim_mode;
2081 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2082 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2084 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
2086 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2088 if (anim_mode == ANIM_DEFAULT)
2089 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
2091 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
2094 Delay(wait_delay_value);
2096 WaitForEventToContinue();
2098 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2100 if (anim_mode != ANIM_NONE)
2101 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
2103 if (anim_mode == ANIM_DEFAULT)
2104 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
2106 game.envelope_active = FALSE;
2108 SetDrawtoField(DRAW_FIELDBUFFER);
2110 redraw_mask |= REDRAW_FIELD;
2114 static void setRequestCenterPosition(int *x, int *y)
2116 int sx_center = (request.x != -1 ? request.x : SX + SXSIZE / 2);
2117 int sy_center = (request.y != -1 ? request.y : SY + SYSIZE / 2);
2123 static void setRequestPosition(int *x, int *y, boolean add_border_size)
2125 int border_size = request.border_size;
2126 int sx_center, sy_center;
2129 setRequestCenterPosition(&sx_center, &sy_center);
2131 sx = sx_center - request.width / 2;
2132 sy = sy_center - request.height / 2;
2134 if (add_border_size)
2144 void DrawEnvelopeRequest(char *text)
2146 char *text_final = text;
2147 char *text_door_style = NULL;
2148 int graphic = IMG_BACKGROUND_REQUEST;
2149 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2150 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2151 int font_nr = FONT_REQUEST;
2152 int font_width = getFontWidth(font_nr);
2153 int font_height = getFontHeight(font_nr);
2154 int border_size = request.border_size;
2155 int line_spacing = request.line_spacing;
2156 int line_height = font_height + line_spacing;
2157 int text_width = request.width - 2 * border_size;
2158 int text_height = request.height - 2 * border_size;
2159 int line_length = text_width / font_width;
2160 int max_lines = text_height / line_height;
2161 int width = request.width;
2162 int height = request.height;
2163 int tile_size = request.step_offset;
2164 int x_steps = width / tile_size;
2165 int y_steps = height / tile_size;
2169 if (request.wrap_single_words)
2171 char *src_text_ptr, *dst_text_ptr;
2173 text_door_style = checked_malloc(2 * strlen(text) + 1);
2175 src_text_ptr = text;
2176 dst_text_ptr = text_door_style;
2178 while (*src_text_ptr)
2180 if (*src_text_ptr == ' ' ||
2181 *src_text_ptr == '?' ||
2182 *src_text_ptr == '!')
2183 *dst_text_ptr++ = '\n';
2185 if (*src_text_ptr != ' ')
2186 *dst_text_ptr++ = *src_text_ptr;
2191 *dst_text_ptr = '\0';
2193 text_final = text_door_style;
2196 setRequestPosition(&sx, &sy, FALSE);
2198 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
2200 for (y = 0; y < y_steps; y++)
2201 for (x = 0; x < x_steps; x++)
2202 DrawEnvelopeBackgroundTiles(graphic, sx, sy,
2203 x, y, x_steps, y_steps,
2204 tile_size, tile_size);
2206 DrawTextBuffer(sx + border_size, sy + border_size, text_final, font_nr,
2207 line_length, -1, max_lines, line_spacing, mask_mode,
2208 request.autowrap, request.centered, FALSE);
2210 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2211 RedrawGadget(tool_gadget[i]);
2213 // store readily prepared envelope request for later use when animating
2214 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2216 if (text_door_style)
2217 free(text_door_style);
2220 void AnimateEnvelopeRequest(int anim_mode, int action)
2222 int graphic = IMG_BACKGROUND_REQUEST;
2223 boolean draw_masked = graphic_info[graphic].draw_masked;
2224 int delay_value_normal = request.step_delay;
2225 int delay_value_fast = delay_value_normal / 2;
2226 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2227 boolean no_delay = (tape.warp_forward);
2228 int delay_value = (ffwd_delay ? delay_value_fast : delay_value_normal);
2229 int anim_delay_value = (no_delay ? 0 : delay_value + 500 * 0) / 2;
2230 unsigned int anim_delay = 0;
2232 int width = request.width;
2233 int height = request.height;
2234 int tile_size = request.step_offset;
2235 int max_xsize = width / tile_size;
2236 int max_ysize = height / tile_size;
2237 int max_xsize_inner = max_xsize - 2;
2238 int max_ysize_inner = max_ysize - 2;
2240 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize_inner : 0);
2241 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize_inner : 0);
2242 int xend = max_xsize_inner;
2243 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize_inner : 0);
2244 int xstep = (xstart < xend ? 1 : 0);
2245 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2247 int end = MAX(xend - xstart, yend - ystart);
2250 if (setup.quick_doors)
2258 if (action == ACTION_OPENING)
2259 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2260 else if (action == ACTION_CLOSING)
2261 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2264 for (i = start; i <= end; i++)
2266 int last_frame = end; // last frame of this "for" loop
2267 int x = xstart + i * xstep;
2268 int y = ystart + i * ystep;
2269 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2270 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2271 int xsize_size_left = (xsize - 1) * tile_size;
2272 int ysize_size_top = (ysize - 1) * tile_size;
2273 int max_xsize_pos = (max_xsize - 1) * tile_size;
2274 int max_ysize_pos = (max_ysize - 1) * tile_size;
2275 int sx_center, sy_center;
2280 setRequestCenterPosition(&sx_center, &sy_center);
2282 src_x = sx_center - width / 2;
2283 src_y = sy_center - height / 2;
2284 dst_x = sx_center - xsize * tile_size / 2;
2285 dst_y = sy_center - ysize * tile_size / 2;
2287 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2289 for (yy = 0; yy < 2; yy++)
2291 for (xx = 0; xx < 2; xx++)
2293 int src_xx = src_x + xx * max_xsize_pos;
2294 int src_yy = src_y + yy * max_ysize_pos;
2295 int dst_xx = dst_x + xx * xsize_size_left;
2296 int dst_yy = dst_y + yy * ysize_size_top;
2297 int xx_size = (xx ? tile_size : xsize_size_left);
2298 int yy_size = (yy ? tile_size : ysize_size_top);
2301 BlitBitmapMasked(bitmap_db_cross, backbuffer,
2302 src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
2304 BlitBitmap(bitmap_db_cross, backbuffer,
2305 src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
2309 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2314 SkipUntilDelayReached(&anim_delay, anim_delay_value, &i, last_frame);
2319 void ShowEnvelopeRequest(char *text, unsigned int req_state, int action)
2321 int last_game_status = game_status; /* save current game status */
2322 int graphic = IMG_BACKGROUND_REQUEST;
2323 int sound_opening = SND_REQUEST_OPENING;
2324 int sound_closing = SND_REQUEST_CLOSING;
2325 int anim_mode = graphic_info[graphic].anim_mode;
2326 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2327 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2329 if (game_status == GAME_MODE_PLAYING)
2330 BlitScreenToBitmap(backbuffer);
2332 SetDrawtoField(DRAW_BACKBUFFER);
2334 // SetDrawBackgroundMask(REDRAW_NONE);
2336 if (action == ACTION_OPENING)
2338 BlitBitmap(backbuffer, bitmap_db_store, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2340 if (req_state & REQ_ASK)
2342 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2343 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2345 else if (req_state & REQ_CONFIRM)
2347 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2349 else if (req_state & REQ_PLAYER)
2351 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2352 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2353 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2354 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2357 DrawEnvelopeRequest(text);
2359 if (game_status != GAME_MODE_MAIN)
2363 /* force DOOR font inside door area */
2364 game_status = GAME_MODE_PSEUDO_DOOR;
2366 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
2368 if (action == ACTION_OPENING)
2370 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2372 if (anim_mode == ANIM_DEFAULT)
2373 AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_OPENING);
2375 AnimateEnvelopeRequest(main_anim_mode, ACTION_OPENING);
2379 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2381 if (anim_mode != ANIM_NONE)
2382 AnimateEnvelopeRequest(main_anim_mode, ACTION_CLOSING);
2384 if (anim_mode == ANIM_DEFAULT)
2385 AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_CLOSING);
2388 game.envelope_active = FALSE;
2390 game_status = last_game_status; /* restore current game status */
2392 if (action == ACTION_CLOSING)
2394 if (game_status != GAME_MODE_MAIN)
2397 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2400 // SetDrawBackgroundMask(last_draw_background_mask);
2402 redraw_mask |= REDRAW_FIELD;
2404 if (game_status == GAME_MODE_MAIN)
2409 if (action == ACTION_CLOSING &&
2410 game_status == GAME_MODE_PLAYING &&
2411 level.game_engine_type == GAME_ENGINE_TYPE_RND)
2412 SetDrawtoField(DRAW_FIELDBUFFER);
2415 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
2419 int graphic = el2preimg(element);
2421 getSizedGraphicSource(graphic, 0, tilesize, &src_bitmap, &src_x, &src_y);
2422 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
2425 void DrawLevel(int draw_background_mask)
2429 SetMainBackgroundImage(IMG_BACKGROUND_PLAYING);
2430 SetDrawBackgroundMask(draw_background_mask);
2434 for (x = BX1; x <= BX2; x++)
2435 for (y = BY1; y <= BY2; y++)
2436 DrawScreenField(x, y);
2438 redraw_mask |= REDRAW_FIELD;
2441 void DrawSizedLevel(int size_x, int size_y, int scroll_x, int scroll_y,
2446 for (x = 0; x < size_x; x++)
2447 for (y = 0; y < size_y; y++)
2448 DrawSizedElementOrWall(x, y, scroll_x, scroll_y, tilesize);
2450 redraw_mask |= REDRAW_FIELD;
2453 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
2457 for (x = 0; x < size_x; x++)
2458 for (y = 0; y < size_y; y++)
2459 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
2461 redraw_mask |= REDRAW_FIELD;
2464 static void DrawPreviewLevelPlayfieldExt(int from_x, int from_y)
2466 boolean show_level_border = (BorderElement != EL_EMPTY);
2467 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2468 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2469 int tile_size = preview.tile_size;
2470 int preview_width = preview.xsize * tile_size;
2471 int preview_height = preview.ysize * tile_size;
2472 int real_preview_xsize = MIN(level_xsize, preview.xsize);
2473 int real_preview_ysize = MIN(level_ysize, preview.ysize);
2474 int real_preview_width = real_preview_xsize * tile_size;
2475 int real_preview_height = real_preview_ysize * tile_size;
2476 int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
2477 int dst_y = SY + ALIGNED_YPOS(preview.y, preview_height, preview.valign);
2480 if (!IN_GFX_FIELD_FULL(dst_x, dst_y + preview_height - 1))
2483 DrawBackground(dst_x, dst_y, preview_width, preview_height);
2485 dst_x += (preview_width - real_preview_width) / 2;
2486 dst_y += (preview_height - real_preview_height) / 2;
2488 for (x = 0; x < real_preview_xsize; x++)
2490 for (y = 0; y < real_preview_ysize; y++)
2492 int lx = from_x + x + (show_level_border ? -1 : 0);
2493 int ly = from_y + y + (show_level_border ? -1 : 0);
2494 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
2495 getBorderElement(lx, ly));
2497 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
2498 element, tile_size);
2502 redraw_mask |= REDRAW_MICROLEVEL;
2505 #define MICROLABEL_EMPTY 0
2506 #define MICROLABEL_LEVEL_NAME 1
2507 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
2508 #define MICROLABEL_LEVEL_AUTHOR 3
2509 #define MICROLABEL_IMPORTED_FROM_HEAD 4
2510 #define MICROLABEL_IMPORTED_FROM 5
2511 #define MICROLABEL_IMPORTED_BY_HEAD 6
2512 #define MICROLABEL_IMPORTED_BY 7
2514 static int getMaxTextLength(struct TextPosInfo *pos, int font_nr)
2516 int max_text_width = SXSIZE;
2517 int font_width = getFontWidth(font_nr);
2519 if (pos->align == ALIGN_CENTER)
2520 max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
2521 else if (pos->align == ALIGN_RIGHT)
2522 max_text_width = pos->x;
2524 max_text_width = SXSIZE - pos->x;
2526 return max_text_width / font_width;
2529 static void DrawPreviewLevelLabelExt(int mode)
2531 struct TextPosInfo *pos = &menu.main.text.level_info_2;
2532 char label_text[MAX_OUTPUT_LINESIZE + 1];
2533 int max_len_label_text;
2534 int font_nr = pos->font;
2537 if (!IN_GFX_FIELD_FULL(pos->x, pos->y + getFontHeight(pos->font)))
2540 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
2541 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
2542 mode == MICROLABEL_IMPORTED_BY_HEAD)
2543 font_nr = pos->font_alt;
2545 max_len_label_text = getMaxTextLength(pos, font_nr);
2547 if (pos->size != -1)
2548 max_len_label_text = pos->size;
2550 for (i = 0; i < max_len_label_text; i++)
2551 label_text[i] = ' ';
2552 label_text[max_len_label_text] = '\0';
2554 if (strlen(label_text) > 0)
2555 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2558 (mode == MICROLABEL_LEVEL_NAME ? level.name :
2559 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
2560 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
2561 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
2562 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
2563 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
2564 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
2565 max_len_label_text);
2566 label_text[max_len_label_text] = '\0';
2568 if (strlen(label_text) > 0)
2569 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2571 redraw_mask |= REDRAW_MICROLEVEL;
2574 static void DrawPreviewLevelExt(boolean restart)
2576 static unsigned int scroll_delay = 0;
2577 static unsigned int label_delay = 0;
2578 static int from_x, from_y, scroll_direction;
2579 static int label_state, label_counter;
2580 unsigned int scroll_delay_value = preview.step_delay;
2581 boolean show_level_border = (BorderElement != EL_EMPTY);
2582 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2583 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2584 int last_game_status = game_status; /* save current game status */
2591 if (preview.anim_mode == ANIM_CENTERED)
2593 if (level_xsize > preview.xsize)
2594 from_x = (level_xsize - preview.xsize) / 2;
2595 if (level_ysize > preview.ysize)
2596 from_y = (level_ysize - preview.ysize) / 2;
2599 from_x += preview.xoffset;
2600 from_y += preview.yoffset;
2602 scroll_direction = MV_RIGHT;
2606 DrawPreviewLevelPlayfieldExt(from_x, from_y);
2607 DrawPreviewLevelLabelExt(label_state);
2609 /* initialize delay counters */
2610 DelayReached(&scroll_delay, 0);
2611 DelayReached(&label_delay, 0);
2613 if (leveldir_current->name)
2615 struct TextPosInfo *pos = &menu.main.text.level_info_1;
2616 char label_text[MAX_OUTPUT_LINESIZE + 1];
2617 int font_nr = pos->font;
2618 int max_len_label_text = getMaxTextLength(pos, font_nr);
2620 if (pos->size != -1)
2621 max_len_label_text = pos->size;
2623 strncpy(label_text, leveldir_current->name, max_len_label_text);
2624 label_text[max_len_label_text] = '\0';
2626 if (IN_GFX_FIELD_FULL(pos->x, pos->y + getFontHeight(pos->font)))
2627 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2630 game_status = last_game_status; /* restore current game status */
2635 /* scroll preview level, if needed */
2636 if (preview.anim_mode != ANIM_NONE &&
2637 (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
2638 DelayReached(&scroll_delay, scroll_delay_value))
2640 switch (scroll_direction)
2645 from_x -= preview.step_offset;
2646 from_x = (from_x < 0 ? 0 : from_x);
2649 scroll_direction = MV_UP;
2653 if (from_x < level_xsize - preview.xsize)
2655 from_x += preview.step_offset;
2656 from_x = (from_x > level_xsize - preview.xsize ?
2657 level_xsize - preview.xsize : from_x);
2660 scroll_direction = MV_DOWN;
2666 from_y -= preview.step_offset;
2667 from_y = (from_y < 0 ? 0 : from_y);
2670 scroll_direction = MV_RIGHT;
2674 if (from_y < level_ysize - preview.ysize)
2676 from_y += preview.step_offset;
2677 from_y = (from_y > level_ysize - preview.ysize ?
2678 level_ysize - preview.ysize : from_y);
2681 scroll_direction = MV_LEFT;
2688 DrawPreviewLevelPlayfieldExt(from_x, from_y);
2691 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
2692 /* redraw micro level label, if needed */
2693 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
2694 !strEqual(level.author, ANONYMOUS_NAME) &&
2695 !strEqual(level.author, leveldir_current->name) &&
2696 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
2698 int max_label_counter = 23;
2700 if (leveldir_current->imported_from != NULL &&
2701 strlen(leveldir_current->imported_from) > 0)
2702 max_label_counter += 14;
2703 if (leveldir_current->imported_by != NULL &&
2704 strlen(leveldir_current->imported_by) > 0)
2705 max_label_counter += 14;
2707 label_counter = (label_counter + 1) % max_label_counter;
2708 label_state = (label_counter >= 0 && label_counter <= 7 ?
2709 MICROLABEL_LEVEL_NAME :
2710 label_counter >= 9 && label_counter <= 12 ?
2711 MICROLABEL_LEVEL_AUTHOR_HEAD :
2712 label_counter >= 14 && label_counter <= 21 ?
2713 MICROLABEL_LEVEL_AUTHOR :
2714 label_counter >= 23 && label_counter <= 26 ?
2715 MICROLABEL_IMPORTED_FROM_HEAD :
2716 label_counter >= 28 && label_counter <= 35 ?
2717 MICROLABEL_IMPORTED_FROM :
2718 label_counter >= 37 && label_counter <= 40 ?
2719 MICROLABEL_IMPORTED_BY_HEAD :
2720 label_counter >= 42 && label_counter <= 49 ?
2721 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
2723 if (leveldir_current->imported_from == NULL &&
2724 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
2725 label_state == MICROLABEL_IMPORTED_FROM))
2726 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
2727 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
2729 DrawPreviewLevelLabelExt(label_state);
2732 game_status = last_game_status; /* restore current game status */
2735 void DrawPreviewLevelInitial()
2737 DrawPreviewLevelExt(TRUE);
2740 void DrawPreviewLevelAnimation()
2742 DrawPreviewLevelExt(FALSE);
2745 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
2746 int graphic, int sync_frame, int mask_mode)
2748 int frame = getGraphicAnimationFrame(graphic, sync_frame);
2750 if (mask_mode == USE_MASKING)
2751 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
2753 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
2756 inline void DrawFixedGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
2757 int graphic, int sync_frame,
2760 int frame = getGraphicAnimationFrame(graphic, sync_frame);
2762 if (mask_mode == USE_MASKING)
2763 DrawFixedGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
2765 DrawFixedGraphicExt(dst_bitmap, x, y, graphic, frame);
2768 inline void DrawGraphicAnimation(int x, int y, int graphic)
2770 int lx = LEVELX(x), ly = LEVELY(y);
2772 if (!IN_SCR_FIELD(x, y))
2775 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
2776 graphic, GfxFrame[lx][ly], NO_MASKING);
2778 MarkTileDirty(x, y);
2781 inline void DrawFixedGraphicAnimation(int x, int y, int graphic)
2783 int lx = LEVELX(x), ly = LEVELY(y);
2785 if (!IN_SCR_FIELD(x, y))
2788 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
2789 graphic, GfxFrame[lx][ly], NO_MASKING);
2790 MarkTileDirty(x, y);
2793 void DrawLevelGraphicAnimation(int x, int y, int graphic)
2795 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2798 void DrawLevelElementAnimation(int x, int y, int element)
2800 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2802 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2805 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
2807 int sx = SCREENX(x), sy = SCREENY(y);
2809 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2812 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2815 DrawGraphicAnimation(sx, sy, graphic);
2818 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
2819 DrawLevelFieldCrumbled(x, y);
2821 if (GFX_CRUMBLED(Feld[x][y]))
2822 DrawLevelFieldCrumbled(x, y);
2826 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
2828 int sx = SCREENX(x), sy = SCREENY(y);
2831 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2834 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2836 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2839 DrawGraphicAnimation(sx, sy, graphic);
2841 if (GFX_CRUMBLED(element))
2842 DrawLevelFieldCrumbled(x, y);
2845 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
2847 if (player->use_murphy)
2849 /* this works only because currently only one player can be "murphy" ... */
2850 static int last_horizontal_dir = MV_LEFT;
2851 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
2853 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2854 last_horizontal_dir = move_dir;
2856 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
2858 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
2860 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
2866 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
2869 static boolean equalGraphics(int graphic1, int graphic2)
2871 struct GraphicInfo *g1 = &graphic_info[graphic1];
2872 struct GraphicInfo *g2 = &graphic_info[graphic2];
2874 return (g1->bitmap == g2->bitmap &&
2875 g1->src_x == g2->src_x &&
2876 g1->src_y == g2->src_y &&
2877 g1->anim_frames == g2->anim_frames &&
2878 g1->anim_delay == g2->anim_delay &&
2879 g1->anim_mode == g2->anim_mode);
2882 void DrawAllPlayers()
2886 for (i = 0; i < MAX_PLAYERS; i++)
2887 if (stored_player[i].active)
2888 DrawPlayer(&stored_player[i]);
2891 void DrawPlayerField(int x, int y)
2893 if (!IS_PLAYER(x, y))
2896 DrawPlayer(PLAYERINFO(x, y));
2899 #define DRAW_PLAYER_OVER_PUSHED_ELEMENT 1
2901 void DrawPlayer(struct PlayerInfo *player)
2903 int jx = player->jx;
2904 int jy = player->jy;
2905 int move_dir = player->MovDir;
2906 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
2907 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
2908 int last_jx = (player->is_moving ? jx - dx : jx);
2909 int last_jy = (player->is_moving ? jy - dy : jy);
2910 int next_jx = jx + dx;
2911 int next_jy = jy + dy;
2912 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
2913 boolean player_is_opaque = FALSE;
2914 int sx = SCREENX(jx), sy = SCREENY(jy);
2915 int sxx = 0, syy = 0;
2916 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
2918 int action = ACTION_DEFAULT;
2919 int last_player_graphic = getPlayerGraphic(player, move_dir);
2920 int last_player_frame = player->Frame;
2923 /* GfxElement[][] is set to the element the player is digging or collecting;
2924 remove also for off-screen player if the player is not moving anymore */
2925 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
2926 GfxElement[jx][jy] = EL_UNDEFINED;
2928 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
2932 if (!IN_LEV_FIELD(jx, jy))
2934 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
2935 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
2936 printf("DrawPlayerField(): This should never happen!\n");
2941 if (element == EL_EXPLOSION)
2944 action = (player->is_pushing ? ACTION_PUSHING :
2945 player->is_digging ? ACTION_DIGGING :
2946 player->is_collecting ? ACTION_COLLECTING :
2947 player->is_moving ? ACTION_MOVING :
2948 player->is_snapping ? ACTION_SNAPPING :
2949 player->is_dropping ? ACTION_DROPPING :
2950 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
2952 if (player->is_waiting)
2953 move_dir = player->dir_waiting;
2955 InitPlayerGfxAnimation(player, action, move_dir);
2957 /* ----------------------------------------------------------------------- */
2958 /* draw things in the field the player is leaving, if needed */
2959 /* ----------------------------------------------------------------------- */
2961 if (player->is_moving)
2963 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
2965 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
2967 if (last_element == EL_DYNAMITE_ACTIVE ||
2968 last_element == EL_EM_DYNAMITE_ACTIVE ||
2969 last_element == EL_SP_DISK_RED_ACTIVE)
2970 DrawDynamite(last_jx, last_jy);
2972 DrawLevelFieldThruMask(last_jx, last_jy);
2974 else if (last_element == EL_DYNAMITE_ACTIVE ||
2975 last_element == EL_EM_DYNAMITE_ACTIVE ||
2976 last_element == EL_SP_DISK_RED_ACTIVE)
2977 DrawDynamite(last_jx, last_jy);
2979 /* !!! this is not enough to prevent flickering of players which are
2980 moving next to each others without a free tile between them -- this
2981 can only be solved by drawing all players layer by layer (first the
2982 background, then the foreground etc.) !!! => TODO */
2983 else if (!IS_PLAYER(last_jx, last_jy))
2984 DrawLevelField(last_jx, last_jy);
2987 DrawLevelField(last_jx, last_jy);
2990 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
2991 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
2994 if (!IN_SCR_FIELD(sx, sy))
2997 /* ----------------------------------------------------------------------- */
2998 /* draw things behind the player, if needed */
2999 /* ----------------------------------------------------------------------- */
3002 DrawLevelElement(jx, jy, Back[jx][jy]);
3003 else if (IS_ACTIVE_BOMB(element))
3004 DrawLevelElement(jx, jy, EL_EMPTY);
3007 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
3009 int old_element = GfxElement[jx][jy];
3010 int old_graphic = el_act_dir2img(old_element, action, move_dir);
3011 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
3013 if (GFX_CRUMBLED(old_element))
3014 DrawLevelFieldCrumbledDigging(jx, jy, move_dir, player->StepFrame);
3016 DrawGraphic(sx, sy, old_graphic, frame);
3018 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
3019 player_is_opaque = TRUE;
3023 GfxElement[jx][jy] = EL_UNDEFINED;
3025 /* make sure that pushed elements are drawn with correct frame rate */
3026 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
3028 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
3029 GfxFrame[jx][jy] = player->StepFrame;
3031 DrawLevelField(jx, jy);
3035 #if !DRAW_PLAYER_OVER_PUSHED_ELEMENT
3036 /* ----------------------------------------------------------------------- */
3037 /* draw player himself */
3038 /* ----------------------------------------------------------------------- */
3040 graphic = getPlayerGraphic(player, move_dir);
3042 /* in the case of changed player action or direction, prevent the current
3043 animation frame from being restarted for identical animations */
3044 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
3045 player->Frame = last_player_frame;
3047 frame = getGraphicAnimationFrame(graphic, player->Frame);
3051 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3052 sxx = player->GfxPos;
3054 syy = player->GfxPos;
3057 if (player_is_opaque)
3058 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
3060 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3062 if (SHIELD_ON(player))
3064 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
3065 IMG_SHIELD_NORMAL_ACTIVE);
3066 int frame = getGraphicAnimationFrame(graphic, -1);
3068 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3072 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
3075 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3076 sxx = player->GfxPos;
3078 syy = player->GfxPos;
3082 /* ----------------------------------------------------------------------- */
3083 /* draw things the player is pushing, if needed */
3084 /* ----------------------------------------------------------------------- */
3086 if (player->is_pushing && player->is_moving)
3088 int px = SCREENX(jx), py = SCREENY(jy);
3089 int pxx = (TILEX - ABS(sxx)) * dx;
3090 int pyy = (TILEY - ABS(syy)) * dy;
3091 int gfx_frame = GfxFrame[jx][jy];
3097 if (!IS_MOVING(jx, jy)) /* push movement already finished */
3099 element = Feld[next_jx][next_jy];
3100 gfx_frame = GfxFrame[next_jx][next_jy];
3103 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
3105 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
3106 frame = getGraphicAnimationFrame(graphic, sync_frame);
3108 /* draw background element under pushed element (like the Sokoban field) */
3109 if (game.use_masked_pushing && IS_MOVING(jx, jy))
3111 /* this allows transparent pushing animation over non-black background */
3114 DrawLevelElement(jx, jy, Back[jx][jy]);
3116 DrawLevelElement(jx, jy, EL_EMPTY);
3118 if (Back[next_jx][next_jy])
3119 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3121 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
3123 else if (Back[next_jx][next_jy])
3124 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3127 /* do not draw (EM style) pushing animation when pushing is finished */
3128 /* (two-tile animations usually do not contain start and end frame) */
3129 if (graphic_info[graphic].double_movement && !IS_MOVING(jx, jy))
3130 DrawLevelElement(next_jx, next_jy, Feld[next_jx][next_jy]);
3132 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3134 /* masked drawing is needed for EMC style (double) movement graphics */
3135 /* !!! (ONLY WHEN DRAWING PUSHED ELEMENT OVER THE PLAYER) !!! */
3136 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3140 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
3141 /* ----------------------------------------------------------------------- */
3142 /* draw player himself */
3143 /* ----------------------------------------------------------------------- */
3145 graphic = getPlayerGraphic(player, move_dir);
3147 /* in the case of changed player action or direction, prevent the current
3148 animation frame from being restarted for identical animations */
3149 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
3150 player->Frame = last_player_frame;
3152 frame = getGraphicAnimationFrame(graphic, player->Frame);
3156 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3157 sxx = player->GfxPos;
3159 syy = player->GfxPos;
3162 if (player_is_opaque)
3163 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
3165 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3167 if (SHIELD_ON(player))
3169 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
3170 IMG_SHIELD_NORMAL_ACTIVE);
3171 int frame = getGraphicAnimationFrame(graphic, -1);
3173 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3177 /* ----------------------------------------------------------------------- */
3178 /* draw things in front of player (active dynamite or dynabombs) */
3179 /* ----------------------------------------------------------------------- */
3181 if (IS_ACTIVE_BOMB(element))
3183 graphic = el2img(element);
3184 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
3186 if (game.emulation == EMU_SUPAPLEX)
3187 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
3189 DrawGraphicThruMask(sx, sy, graphic, frame);
3192 if (player_is_moving && last_element == EL_EXPLOSION)
3194 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
3195 GfxElement[last_jx][last_jy] : EL_EMPTY);
3196 int graphic = el_act2img(element, ACTION_EXPLODING);
3197 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
3198 int phase = ExplodePhase[last_jx][last_jy] - 1;
3199 int frame = getGraphicAnimationFrame(graphic, phase - delay);
3202 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
3205 /* ----------------------------------------------------------------------- */
3206 /* draw elements the player is just walking/passing through/under */
3207 /* ----------------------------------------------------------------------- */
3209 if (player_is_moving)
3211 /* handle the field the player is leaving ... */
3212 if (IS_ACCESSIBLE_INSIDE(last_element))
3213 DrawLevelField(last_jx, last_jy);
3214 else if (IS_ACCESSIBLE_UNDER(last_element))
3215 DrawLevelFieldThruMask(last_jx, last_jy);
3218 /* do not redraw accessible elements if the player is just pushing them */
3219 if (!player_is_moving || !player->is_pushing)
3221 /* ... and the field the player is entering */
3222 if (IS_ACCESSIBLE_INSIDE(element))
3223 DrawLevelField(jx, jy);
3224 else if (IS_ACCESSIBLE_UNDER(element))
3225 DrawLevelFieldThruMask(jx, jy);
3228 MarkTileDirty(sx, sy);
3231 /* ------------------------------------------------------------------------- */
3233 void WaitForEventToContinue()
3235 boolean still_wait = TRUE;
3237 /* simulate releasing mouse button over last gadget, if still pressed */
3239 HandleGadgets(-1, -1, 0);
3241 button_status = MB_RELEASED;
3255 case EVENT_BUTTONPRESS:
3256 case EVENT_KEYPRESS:
3260 case EVENT_KEYRELEASE:
3261 ClearPlayerAction();
3265 HandleOtherEvents(&event);
3269 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3276 /* don't eat all CPU time */
3281 #define MAX_REQUEST_LINES 13
3282 #define MAX_REQUEST_LINE_FONT1_LEN 7
3283 #define MAX_REQUEST_LINE_FONT2_LEN 10
3285 static int RequestHandleEvents(unsigned int req_state)
3287 boolean level_solved = (game_status == GAME_MODE_PLAYING &&
3288 local_player->LevelSolved_GameEnd);
3289 int last_game_status = game_status; /* save current game status */
3290 int width = request.width;
3291 int height = request.height;
3295 setRequestPosition(&sx, &sy, FALSE);
3297 button_status = MB_RELEASED;
3299 request_gadget_id = -1;
3306 SetDrawtoField(DRAW_FIELDBUFFER);
3308 HandleGameActions();
3310 SetDrawtoField(DRAW_BACKBUFFER);
3312 if (global.use_envelope_request)
3314 /* copy current state of request area to middle of playfield area */
3315 BlitBitmap(bitmap_db_cross, drawto, sx, sy, width, height, sx, sy);
3323 while (NextValidEvent(&event))
3327 case EVENT_BUTTONPRESS:
3328 case EVENT_BUTTONRELEASE:
3329 case EVENT_MOTIONNOTIFY:
3333 if (event.type == EVENT_MOTIONNOTIFY)
3338 motion_status = TRUE;
3339 mx = ((MotionEvent *) &event)->x;
3340 my = ((MotionEvent *) &event)->y;
3344 motion_status = FALSE;
3345 mx = ((ButtonEvent *) &event)->x;
3346 my = ((ButtonEvent *) &event)->y;
3347 if (event.type == EVENT_BUTTONPRESS)
3348 button_status = ((ButtonEvent *) &event)->button;
3350 button_status = MB_RELEASED;
3353 /* this sets 'request_gadget_id' */
3354 HandleGadgets(mx, my, button_status);
3356 switch (request_gadget_id)
3358 case TOOL_CTRL_ID_YES:
3361 case TOOL_CTRL_ID_NO:
3364 case TOOL_CTRL_ID_CONFIRM:
3365 result = TRUE | FALSE;
3368 case TOOL_CTRL_ID_PLAYER_1:
3371 case TOOL_CTRL_ID_PLAYER_2:
3374 case TOOL_CTRL_ID_PLAYER_3:
3377 case TOOL_CTRL_ID_PLAYER_4:
3388 case EVENT_KEYPRESS:
3389 switch (GetEventKey((KeyEvent *)&event, TRUE))
3392 if (req_state & REQ_CONFIRM)
3397 #if defined(TARGET_SDL2)
3404 #if defined(TARGET_SDL2)
3414 if (req_state & REQ_PLAYER)
3418 case EVENT_KEYRELEASE:
3419 ClearPlayerAction();
3423 HandleOtherEvents(&event);
3428 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3430 int joy = AnyJoystick();
3432 if (joy & JOY_BUTTON_1)
3434 else if (joy & JOY_BUTTON_2)
3440 if (global.use_envelope_request)
3442 /* copy back current state of pressed buttons inside request area */
3443 BlitBitmap(drawto, bitmap_db_cross, sx, sy, width, height, sx, sy);
3450 if (!PendingEvent()) /* delay only if no pending events */
3454 game_status = GAME_MODE_PSEUDO_DOOR;
3458 game_status = last_game_status; /* restore current game status */
3464 static boolean RequestDoor(char *text, unsigned int req_state)
3466 unsigned int old_door_state;
3467 int last_game_status = game_status; /* save current game status */
3468 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
3469 int font_nr = FONT_TEXT_2;
3474 if (maxWordLengthInString(text) > MAX_REQUEST_LINE_FONT1_LEN)
3476 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
3477 font_nr = FONT_TEXT_1;
3480 if (game_status == GAME_MODE_PLAYING)
3481 BlitScreenToBitmap(backbuffer);
3483 /* disable deactivated drawing when quick-loading level tape recording */
3484 if (tape.playing && tape.deactivate_display)
3485 TapeDeactivateDisplayOff(TRUE);
3487 SetMouseCursor(CURSOR_DEFAULT);
3489 #if defined(NETWORK_AVALIABLE)
3490 /* pause network game while waiting for request to answer */
3491 if (options.network &&
3492 game_status == GAME_MODE_PLAYING &&
3493 req_state & REQUEST_WAIT_FOR_INPUT)
3494 SendToServer_PausePlaying();
3497 old_door_state = GetDoorState();
3499 /* simulate releasing mouse button over last gadget, if still pressed */
3501 HandleGadgets(-1, -1, 0);
3505 /* draw released gadget before proceeding */
3508 if (old_door_state & DOOR_OPEN_1)
3510 CloseDoor(DOOR_CLOSE_1);
3512 /* save old door content */
3513 BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
3514 0 * DXSIZE, 0, DXSIZE, DYSIZE, 1 * DXSIZE, 0);
3517 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
3518 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3520 /* clear door drawing field */
3521 DrawBackground(DX, DY, DXSIZE, DYSIZE);
3523 /* force DOOR font inside door area */
3524 game_status = GAME_MODE_PSEUDO_DOOR;
3526 /* write text for request */
3527 for (text_ptr = text, ty = 0; ty < MAX_REQUEST_LINES; ty++)
3529 char text_line[max_request_line_len + 1];
3535 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
3537 tc = *(text_ptr + tx);
3538 // if (!tc || tc == ' ')
3539 if (!tc || tc == ' ' || tc == '?' || tc == '!')
3543 if ((tc == '?' || tc == '!') && tl == 0)
3553 strncpy(text_line, text_ptr, tl);
3556 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
3557 DY + 8 + ty * (getFontHeight(font_nr) + 2),
3558 text_line, font_nr);
3560 text_ptr += tl + (tc == ' ' ? 1 : 0);
3561 // text_ptr += tl + (tc == ' ' || tc == '?' || tc == '!' ? 1 : 0);
3564 game_status = last_game_status; /* restore current game status */
3566 if (req_state & REQ_ASK)
3568 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
3569 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
3571 else if (req_state & REQ_CONFIRM)
3573 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
3575 else if (req_state & REQ_PLAYER)
3577 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
3578 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
3579 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
3580 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
3583 /* copy request gadgets to door backbuffer */
3584 BlitBitmap(drawto, bitmap_db_door_1, DX, DY, DXSIZE, DYSIZE, 0, 0);
3586 OpenDoor(DOOR_OPEN_1);
3588 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
3590 if (game_status == GAME_MODE_PLAYING)
3592 SetPanelBackground();
3593 SetDrawBackgroundMask(REDRAW_DOOR_1);
3597 SetDrawBackgroundMask(REDRAW_FIELD);
3603 if (game_status != GAME_MODE_MAIN)
3606 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3608 // ---------- handle request buttons ----------
3609 result = RequestHandleEvents(req_state);
3611 if (game_status != GAME_MODE_MAIN)
3616 if (!(req_state & REQ_STAY_OPEN))
3618 CloseDoor(DOOR_CLOSE_1);
3620 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
3621 (req_state & REQ_REOPEN))
3622 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
3627 if (game_status == GAME_MODE_PLAYING)
3629 SetPanelBackground();
3630 SetDrawBackgroundMask(REDRAW_DOOR_1);
3634 SetDrawBackgroundMask(REDRAW_FIELD);
3637 #if defined(NETWORK_AVALIABLE)
3638 /* continue network game after request */
3639 if (options.network &&
3640 game_status == GAME_MODE_PLAYING &&
3641 req_state & REQUEST_WAIT_FOR_INPUT)
3642 SendToServer_ContinuePlaying();
3645 /* restore deactivated drawing when quick-loading level tape recording */
3646 if (tape.playing && tape.deactivate_display)
3647 TapeDeactivateDisplayOn();
3652 static boolean RequestEnvelope(char *text, unsigned int req_state)
3656 if (game_status == GAME_MODE_PLAYING)
3657 BlitScreenToBitmap(backbuffer);
3659 /* disable deactivated drawing when quick-loading level tape recording */
3660 if (tape.playing && tape.deactivate_display)
3661 TapeDeactivateDisplayOff(TRUE);
3663 SetMouseCursor(CURSOR_DEFAULT);
3665 #if defined(NETWORK_AVALIABLE)
3666 /* pause network game while waiting for request to answer */
3667 if (options.network &&
3668 game_status == GAME_MODE_PLAYING &&
3669 req_state & REQUEST_WAIT_FOR_INPUT)
3670 SendToServer_PausePlaying();
3673 /* simulate releasing mouse button over last gadget, if still pressed */
3675 HandleGadgets(-1, -1, 0);
3679 // (replace with setting corresponding request background)
3680 // SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
3681 // SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3683 /* clear door drawing field */
3684 // DrawBackground(DX, DY, DXSIZE, DYSIZE);
3686 ShowEnvelopeRequest(text, req_state, ACTION_OPENING);
3688 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
3690 if (game_status == GAME_MODE_PLAYING)
3692 SetPanelBackground();
3693 SetDrawBackgroundMask(REDRAW_DOOR_1);
3697 SetDrawBackgroundMask(REDRAW_FIELD);
3703 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3705 // ---------- handle request buttons ----------
3706 result = RequestHandleEvents(req_state);
3708 if (game_status != GAME_MODE_MAIN)
3713 ShowEnvelopeRequest(text, req_state, ACTION_CLOSING);
3717 if (game_status == GAME_MODE_PLAYING)
3719 SetPanelBackground();
3720 SetDrawBackgroundMask(REDRAW_DOOR_1);
3724 SetDrawBackgroundMask(REDRAW_FIELD);
3727 #if defined(NETWORK_AVALIABLE)
3728 /* continue network game after request */
3729 if (options.network &&
3730 game_status == GAME_MODE_PLAYING &&
3731 req_state & REQUEST_WAIT_FOR_INPUT)
3732 SendToServer_ContinuePlaying();
3735 /* restore deactivated drawing when quick-loading level tape recording */
3736 if (tape.playing && tape.deactivate_display)
3737 TapeDeactivateDisplayOn();
3742 boolean Request(char *text, unsigned int req_state)
3744 if (global.use_envelope_request)
3745 return RequestEnvelope(text, req_state);
3747 return RequestDoor(text, req_state);
3750 static int compareDoorPartOrderInfo(const void *object1, const void *object2)
3752 const struct DoorPartOrderInfo *dpo1 = (struct DoorPartOrderInfo *)object1;
3753 const struct DoorPartOrderInfo *dpo2 = (struct DoorPartOrderInfo *)object2;
3756 if (dpo1->sort_priority != dpo2->sort_priority)
3757 compare_result = dpo1->sort_priority - dpo2->sort_priority;
3759 compare_result = dpo1->nr - dpo2->nr;
3761 return compare_result;
3764 void InitGraphicCompatibilityInfo_Doors()
3770 struct DoorInfo *door;
3774 { DOOR_1, IMG_DOOR_1_GFX_PART_1, IMG_DOOR_1_GFX_PART_8, &door_1 },
3775 { DOOR_2, IMG_DOOR_2_GFX_PART_1, IMG_DOOR_2_GFX_PART_8, &door_2 },
3777 { -1, -1, -1, NULL }
3779 struct Rect door_rect_list[] =
3781 { DX, DY, DXSIZE, DYSIZE },
3782 { VX, VY, VXSIZE, VYSIZE }
3786 for (i = 0; doors[i].door_token != -1; i++)
3788 int door_token = doors[i].door_token;
3789 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
3790 int part_1 = doors[i].part_1;
3791 int part_8 = doors[i].part_8;
3792 int part_2 = part_1 + 1;
3793 int part_3 = part_1 + 2;
3794 struct DoorInfo *door = doors[i].door;
3795 struct Rect *door_rect = &door_rect_list[door_index];
3796 boolean door_gfx_redefined = FALSE;
3798 /* check if any door part graphic definitions have been redefined */
3800 for (j = 0; door_part_controls[j].door_token != -1; j++)
3802 struct DoorPartControlInfo *dpc = &door_part_controls[j];
3803 struct FileInfo *fi = getImageListEntryFromImageID(dpc->graphic);
3805 if (dpc->door_token == door_token && fi->redefined)
3806 door_gfx_redefined = TRUE;
3809 /* check for old-style door graphic/animation modifications */
3811 if (!door_gfx_redefined)
3813 if (door->anim_mode & ANIM_STATIC_PANEL)
3815 door->panel.step_xoffset = 0;
3816 door->panel.step_yoffset = 0;
3819 if (door->anim_mode & (ANIM_HORIZONTAL | ANIM_VERTICAL))
3821 struct GraphicInfo *g_part_1 = &graphic_info[part_1];
3822 struct GraphicInfo *g_part_2 = &graphic_info[part_2];
3823 int num_door_steps, num_panel_steps;
3825 /* remove door part graphics other than the two default wings */
3827 for (j = 0; door_part_controls[j].door_token != -1; j++)
3829 struct DoorPartControlInfo *dpc = &door_part_controls[j];
3830 struct GraphicInfo *g = &graphic_info[dpc->graphic];
3832 if (dpc->graphic >= part_3 &&
3833 dpc->graphic <= part_8)
3837 /* set graphics and screen positions of the default wings */
3839 g_part_1->width = door_rect->width;
3840 g_part_1->height = door_rect->height;
3841 g_part_2->width = door_rect->width;
3842 g_part_2->height = door_rect->height;
3843 g_part_2->src_x = door_rect->width;
3844 g_part_2->src_y = g_part_1->src_y;
3846 door->part_2.x = door->part_1.x;
3847 door->part_2.y = door->part_1.y;
3849 if (door->width != -1)
3851 g_part_1->width = door->width;
3852 g_part_2->width = door->width;
3854 // special treatment for graphics and screen position of right wing
3855 g_part_2->src_x += door_rect->width - door->width;
3856 door->part_2.x += door_rect->width - door->width;
3859 if (door->height != -1)
3861 g_part_1->height = door->height;
3862 g_part_2->height = door->height;
3864 // special treatment for graphics and screen position of bottom wing
3865 g_part_2->src_y += door_rect->height - door->height;
3866 door->part_2.y += door_rect->height - door->height;
3869 /* set animation delays for the default wings and panels */
3871 door->part_1.step_delay = door->step_delay;
3872 door->part_2.step_delay = door->step_delay;
3873 door->panel.step_delay = door->step_delay;
3875 /* set animation draw order for the default wings */
3877 door->part_1.sort_priority = 2; /* draw left wing over ... */
3878 door->part_2.sort_priority = 1; /* ... right wing */
3880 /* set animation draw offset for the default wings */
3882 if (door->anim_mode & ANIM_HORIZONTAL)
3884 door->part_1.step_xoffset = door->step_offset;
3885 door->part_1.step_yoffset = 0;
3886 door->part_2.step_xoffset = door->step_offset * -1;
3887 door->part_2.step_yoffset = 0;
3889 num_door_steps = g_part_1->width / door->step_offset;
3891 else // ANIM_VERTICAL
3893 door->part_1.step_xoffset = 0;
3894 door->part_1.step_yoffset = door->step_offset;
3895 door->part_2.step_xoffset = 0;
3896 door->part_2.step_yoffset = door->step_offset * -1;
3898 num_door_steps = g_part_1->height / door->step_offset;
3901 /* set animation draw offset for the default panels */
3903 if (door->step_offset > 1)
3905 num_panel_steps = 2 * door_rect->height / door->step_offset;
3906 door->panel.start_step = num_panel_steps - num_door_steps;
3907 door->panel.start_step_closing = door->panel.start_step;
3911 num_panel_steps = door_rect->height / door->step_offset;
3912 door->panel.start_step = num_panel_steps - num_door_steps / 2;
3913 door->panel.start_step_closing = door->panel.start_step;
3914 door->panel.step_delay *= 2;
3925 for (i = 0; door_part_controls[i].door_token != -1; i++)
3927 struct DoorPartControlInfo *dpc = &door_part_controls[i];
3928 struct DoorPartOrderInfo *dpo = &door_part_order[i];
3930 /* initialize "start_step_opening" and "start_step_closing", if needed */
3931 if (dpc->pos->start_step_opening == 0 &&
3932 dpc->pos->start_step_closing == 0)
3934 // dpc->pos->start_step_opening = dpc->pos->start_step;
3935 dpc->pos->start_step_closing = dpc->pos->start_step;
3938 /* fill structure for door part draw order (sorted below) */
3940 dpo->sort_priority = dpc->pos->sort_priority;
3943 /* sort door part controls according to sort_priority and graphic number */
3944 qsort(door_part_order, MAX_DOOR_PARTS,
3945 sizeof(struct DoorPartOrderInfo), compareDoorPartOrderInfo);
3948 unsigned int OpenDoor(unsigned int door_state)
3950 if (door_state & DOOR_COPY_BACK)
3952 if (door_state & DOOR_OPEN_1)
3953 BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
3954 1 * DXSIZE, 0, DXSIZE, DYSIZE, 0 * DXSIZE, 0);
3956 if (door_state & DOOR_OPEN_2)
3957 BlitBitmap(bitmap_db_door_2, bitmap_db_door_2,
3958 1 * VXSIZE, 0, VXSIZE, VYSIZE, 0 * VXSIZE, 0);
3960 door_state &= ~DOOR_COPY_BACK;
3963 return MoveDoor(door_state);
3966 unsigned int CloseDoor(unsigned int door_state)
3968 unsigned int old_door_state = GetDoorState();
3970 if (!(door_state & DOOR_NO_COPY_BACK))
3972 if (old_door_state & DOOR_OPEN_1)
3973 BlitBitmap(backbuffer, bitmap_db_door_1,
3974 DX, DY, DXSIZE, DYSIZE, 0, 0);
3976 if (old_door_state & DOOR_OPEN_2)
3977 BlitBitmap(backbuffer, bitmap_db_door_2,
3978 VX, VY, VXSIZE, VYSIZE, 0, 0);
3980 door_state &= ~DOOR_NO_COPY_BACK;
3983 return MoveDoor(door_state);
3986 unsigned int GetDoorState()
3988 return MoveDoor(DOOR_GET_STATE);
3991 unsigned int SetDoorState(unsigned int door_state)
3993 return MoveDoor(door_state | DOOR_SET_STATE);
3996 int euclid(int a, int b)
3998 return (b ? euclid(b, a % b) : a);
4001 unsigned int MoveDoor(unsigned int door_state)
4003 struct Rect door_rect_list[] =
4005 { DX, DY, DXSIZE, DYSIZE },
4006 { VX, VY, VXSIZE, VYSIZE }
4008 static int door1 = DOOR_OPEN_1;
4009 static int door2 = DOOR_CLOSE_2;
4010 unsigned int door_delay = 0;
4011 unsigned int door_delay_value;
4014 if (door_state == DOOR_GET_STATE)
4015 return (door1 | door2);
4017 if (door_state & DOOR_SET_STATE)
4019 if (door_state & DOOR_ACTION_1)
4020 door1 = door_state & DOOR_ACTION_1;
4021 if (door_state & DOOR_ACTION_2)
4022 door2 = door_state & DOOR_ACTION_2;
4024 return (door1 | door2);
4027 if (!(door_state & DOOR_FORCE_REDRAW))
4029 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
4030 door_state &= ~DOOR_OPEN_1;
4031 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
4032 door_state &= ~DOOR_CLOSE_1;
4033 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
4034 door_state &= ~DOOR_OPEN_2;
4035 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
4036 door_state &= ~DOOR_CLOSE_2;
4039 if (global.autoplay_leveldir)
4041 door_state |= DOOR_NO_DELAY;
4042 door_state &= ~DOOR_CLOSE_ALL;
4045 if (game_status == GAME_MODE_EDITOR)
4046 door_state |= DOOR_NO_DELAY;
4048 if (door_state & DOOR_ACTION)
4050 boolean door_panel_drawn[NUM_DOORS];
4051 boolean panel_has_doors[NUM_DOORS];
4052 boolean door_part_skip[MAX_DOOR_PARTS];
4053 boolean door_part_done[MAX_DOOR_PARTS];
4054 boolean door_part_done_all;
4055 int num_steps[MAX_DOOR_PARTS];
4056 int max_move_delay = 0; // delay for complete animations of all doors
4057 int max_step_delay = 0; // delay (ms) between two animation frames
4058 int num_move_steps = 0; // number of animation steps for all doors
4059 int max_move_delay_doors_only = 0; // delay for doors only (no panel)
4060 int num_move_steps_doors_only = 0; // steps for doors only (no panel)
4061 int current_move_delay = 0;
4065 for (i = 0; i < NUM_DOORS; i++)
4066 panel_has_doors[i] = FALSE;
4068 for (i = 0; i < MAX_DOOR_PARTS; i++)
4070 struct DoorPartControlInfo *dpc = &door_part_controls[i];
4071 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4072 int door_token = dpc->door_token;
4074 door_part_done[i] = FALSE;
4075 door_part_skip[i] = (!(door_state & door_token) ||
4079 for (i = 0; i < MAX_DOOR_PARTS; i++)
4081 int nr = door_part_order[i].nr;
4082 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
4083 struct DoorPartPosInfo *pos = dpc->pos;
4084 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4085 int door_token = dpc->door_token;
4086 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
4087 boolean is_panel = DOOR_PART_IS_PANEL(nr);
4088 int step_xoffset = ABS(pos->step_xoffset);
4089 int step_yoffset = ABS(pos->step_yoffset);
4090 int step_delay = pos->step_delay;
4091 int current_door_state = door_state & door_token;
4092 boolean door_opening = ((current_door_state & DOOR_OPEN) != 0);
4093 boolean door_closing = ((current_door_state & DOOR_CLOSE) != 0);
4094 boolean part_opening = (is_panel ? door_closing : door_opening);
4095 int start_step = (part_opening ? pos->start_step_opening :
4096 pos->start_step_closing);
4097 float move_xsize = (step_xoffset ? g->width : 0);
4098 float move_ysize = (step_yoffset ? g->height : 0);
4099 int move_xsteps = (step_xoffset ? ceil(move_xsize / step_xoffset) : 0);
4100 int move_ysteps = (step_yoffset ? ceil(move_ysize / step_yoffset) : 0);
4101 int move_steps = (move_xsteps && move_ysteps ?
4102 MIN(move_xsteps, move_ysteps) :
4103 move_xsteps ? move_xsteps : move_ysteps) - start_step;
4104 int move_delay = move_steps * step_delay;
4106 if (door_part_skip[nr])
4109 max_move_delay = MAX(max_move_delay, move_delay);
4110 max_step_delay = (max_step_delay == 0 ? step_delay :
4111 euclid(max_step_delay, step_delay));
4112 num_steps[nr] = move_steps;
4116 max_move_delay_doors_only = MAX(max_move_delay_doors_only, move_delay);
4118 panel_has_doors[door_index] = TRUE;
4122 max_step_delay = MAX(1, max_step_delay); // prevent division by zero
4124 num_move_steps = max_move_delay / max_step_delay;
4125 num_move_steps_doors_only = max_move_delay_doors_only / max_step_delay;
4127 door_delay_value = max_step_delay;
4129 if ((door_state & DOOR_NO_DELAY) || setup.quick_doors)
4131 start = num_move_steps - 1;
4135 /* opening door sound has priority over simultaneously closing door */
4136 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
4137 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
4138 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
4139 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
4142 for (k = start; k < num_move_steps; k++)
4144 int last_frame = num_move_steps - 1; // last frame of this "for" loop
4146 door_part_done_all = TRUE;
4148 for (i = 0; i < NUM_DOORS; i++)
4149 door_panel_drawn[i] = FALSE;
4151 for (i = 0; i < MAX_DOOR_PARTS; i++)
4153 int nr = door_part_order[i].nr;
4154 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
4155 struct DoorPartPosInfo *pos = dpc->pos;
4156 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4157 int door_token = dpc->door_token;
4158 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
4159 boolean is_panel = DOOR_PART_IS_PANEL(nr);
4160 boolean is_panel_and_door_has_closed = FALSE;
4161 struct Rect *door_rect = &door_rect_list[door_index];
4162 Bitmap *bitmap_db_door = (door_token == DOOR_1 ? bitmap_db_door_1 :
4164 Bitmap *bitmap = (is_panel ? bitmap_db_door : g->bitmap);
4165 int current_door_state = door_state & door_token;
4166 boolean door_opening = ((current_door_state & DOOR_OPEN) != 0);
4167 boolean door_closing = !door_opening;
4168 boolean part_opening = (is_panel ? door_closing : door_opening);
4169 boolean part_closing = !part_opening;
4170 int start_step = (part_opening ? pos->start_step_opening :
4171 pos->start_step_closing);
4172 int step_delay = pos->step_delay;
4173 int step_factor = step_delay / max_step_delay;
4174 int k1 = (step_factor ? k / step_factor + 1 : k);
4175 int k2 = (part_opening ? k1 + start_step : num_steps[nr] - k1);
4176 int kk = MAX(0, k2);
4179 int src_x, src_y, src_xx, src_yy;
4180 int dst_x, dst_y, dst_xx, dst_yy;
4183 if (door_part_skip[nr])
4186 if (!(door_state & door_token))
4194 int k2_door = (door_opening ? k : num_move_steps_doors_only - k - 1);
4195 int kk_door = MAX(0, k2_door);
4196 int sync_frame = kk_door * door_delay_value;
4197 int frame = getGraphicAnimationFrame(dpc->graphic, sync_frame);
4199 getGraphicSource(dpc->graphic, frame, &bitmap, &g_src_x, &g_src_y);
4204 if (!door_panel_drawn[door_index])
4206 ClearRectangle(drawto, door_rect->x, door_rect->y,
4207 door_rect->width, door_rect->height);
4209 door_panel_drawn[door_index] = TRUE;
4212 // draw opening or closing door parts
4214 if (pos->step_xoffset < 0) // door part on right side
4217 dst_xx = pos->x + ABS(kk * pos->step_xoffset);
4220 if (dst_xx + width > door_rect->width)
4221 width = door_rect->width - dst_xx;
4223 else // door part on left side
4226 dst_xx = pos->x - kk * pos->step_xoffset;
4230 src_xx = ABS(dst_xx);
4234 width = g->width - src_xx;
4236 // printf("::: k == %d [%d] \n", k, start_step);
4239 if (pos->step_yoffset < 0) // door part on bottom side
4242 dst_yy = pos->y + ABS(kk * pos->step_yoffset);
4245 if (dst_yy + height > door_rect->height)
4246 height = door_rect->height - dst_yy;
4248 else // door part on top side
4251 dst_yy = pos->y - kk * pos->step_yoffset;
4255 src_yy = ABS(dst_yy);
4259 height = g->height - src_yy;
4262 src_x = g_src_x + src_xx;
4263 src_y = g_src_y + src_yy;
4265 dst_x = door_rect->x + dst_xx;
4266 dst_y = door_rect->y + dst_yy;
4268 is_panel_and_door_has_closed =
4271 panel_has_doors[door_index] &&
4272 k >= num_move_steps_doors_only - 1);
4274 if (width >= 0 && width <= g->width &&
4275 height >= 0 && height <= g->height &&
4276 !is_panel_and_door_has_closed)
4278 if (is_panel || !pos->draw_masked)
4279 BlitBitmap(bitmap, drawto, src_x, src_y, width, height,
4282 BlitBitmapMasked(bitmap, drawto, src_x, src_y, width, height,
4286 redraw_mask |= REDRAW_DOOR_FROM_TOKEN(door_token);
4288 if ((part_opening && (width < 0 || height < 0)) ||
4289 (part_closing && (width >= g->width && height >= g->height)))
4290 door_part_done[nr] = TRUE;
4292 // continue door part animations, but not panel after door has closed
4293 if (!door_part_done[nr] && !is_panel_and_door_has_closed)
4294 door_part_done_all = FALSE;
4297 if (!(door_state & DOOR_NO_DELAY))
4301 if (game_status == GAME_MODE_MAIN)
4304 SkipUntilDelayReached(&door_delay, door_delay_value, &k, last_frame);
4306 current_move_delay += max_step_delay;
4309 if (door_part_done_all)
4314 if (door_state & DOOR_ACTION_1)
4315 door1 = door_state & DOOR_ACTION_1;
4316 if (door_state & DOOR_ACTION_2)
4317 door2 = door_state & DOOR_ACTION_2;
4319 return (door1 | door2);
4322 void DrawSpecialEditorDoor()
4324 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
4325 int top_border_width = gfx1->width;
4326 int top_border_height = gfx1->height;
4327 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
4328 int ex = EX - outer_border;
4329 int ey = EY - outer_border;
4330 int vy = VY - outer_border;
4331 int exsize = EXSIZE + 2 * outer_border;
4333 /* draw bigger level editor toolbox window */
4334 BlitBitmap(gfx1->bitmap, drawto, gfx1->src_x, gfx1->src_y,
4335 top_border_width, top_border_height, ex, ey - top_border_height);
4336 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto, ex, vy,
4337 exsize, EYSIZE - VYSIZE + outer_border, ex, ey);
4339 redraw_mask |= REDRAW_ALL;
4342 void UndrawSpecialEditorDoor()
4344 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
4345 int top_border_width = gfx1->width;
4346 int top_border_height = gfx1->height;
4347 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
4348 int ex = EX - outer_border;
4349 int ey = EY - outer_border;
4350 int ey_top = ey - top_border_height;
4351 int exsize = EXSIZE + 2 * outer_border;
4352 int eysize = EYSIZE + 2 * outer_border;
4354 /* draw normal tape recorder window */
4355 if (graphic_info[IMG_GLOBAL_BORDER].bitmap)
4357 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
4358 ex, ey_top, top_border_width, top_border_height,
4360 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
4361 ex, ey, exsize, eysize, ex, ey);
4365 // if screen background is set to "[NONE]", clear editor toolbox window
4366 ClearRectangle(drawto, ex, ey_top, top_border_width, top_border_height);
4367 ClearRectangle(drawto, ex, ey, exsize, eysize);
4370 redraw_mask |= REDRAW_ALL;
4374 /* ---------- new tool button stuff ---------------------------------------- */
4379 struct TextPosInfo *pos;
4382 } toolbutton_info[NUM_TOOL_BUTTONS] =
4385 IMG_REQUEST_BUTTON_GFX_YES, &request.button.yes,
4386 TOOL_CTRL_ID_YES, "yes"
4389 IMG_REQUEST_BUTTON_GFX_NO, &request.button.no,
4390 TOOL_CTRL_ID_NO, "no"
4393 IMG_REQUEST_BUTTON_GFX_CONFIRM, &request.button.confirm,
4394 TOOL_CTRL_ID_CONFIRM, "confirm"
4397 IMG_REQUEST_BUTTON_GFX_PLAYER_1, &request.button.player_1,
4398 TOOL_CTRL_ID_PLAYER_1, "player 1"
4401 IMG_REQUEST_BUTTON_GFX_PLAYER_2, &request.button.player_2,
4402 TOOL_CTRL_ID_PLAYER_2, "player 2"
4405 IMG_REQUEST_BUTTON_GFX_PLAYER_3, &request.button.player_3,
4406 TOOL_CTRL_ID_PLAYER_3, "player 3"
4409 IMG_REQUEST_BUTTON_GFX_PLAYER_4, &request.button.player_4,
4410 TOOL_CTRL_ID_PLAYER_4, "player 4"
4414 void CreateToolButtons()
4418 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4420 struct GraphicInfo *gfx = &graphic_info[toolbutton_info[i].graphic];
4421 struct TextPosInfo *pos = toolbutton_info[i].pos;
4422 struct GadgetInfo *gi;
4423 Bitmap *deco_bitmap = None;
4424 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
4425 unsigned int event_mask = GD_EVENT_RELEASED;
4428 int gd_x = gfx->src_x;
4429 int gd_y = gfx->src_y;
4430 int gd_xp = gfx->src_x + gfx->pressed_xoffset;
4431 int gd_yp = gfx->src_y + gfx->pressed_yoffset;
4434 if (global.use_envelope_request)
4435 setRequestPosition(&dx, &dy, TRUE);
4437 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
4439 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
4441 getSizedGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr), 0,
4442 pos->size, &deco_bitmap, &deco_x, &deco_y);
4443 deco_xpos = (gfx->width - pos->size) / 2;
4444 deco_ypos = (gfx->height - pos->size) / 2;
4447 gi = CreateGadget(GDI_CUSTOM_ID, id,
4448 GDI_INFO_TEXT, toolbutton_info[i].infotext,
4449 GDI_X, dx + GDI_ACTIVE_POS(pos->x),
4450 GDI_Y, dy + GDI_ACTIVE_POS(pos->y),
4451 GDI_WIDTH, gfx->width,
4452 GDI_HEIGHT, gfx->height,
4453 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
4454 GDI_STATE, GD_BUTTON_UNPRESSED,
4455 GDI_DESIGN_UNPRESSED, gfx->bitmap, gd_x, gd_y,
4456 GDI_DESIGN_PRESSED, gfx->bitmap, gd_xp, gd_yp,
4457 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
4458 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
4459 GDI_DECORATION_SIZE, pos->size, pos->size,
4460 GDI_DECORATION_SHIFTING, 1, 1,
4461 GDI_DIRECT_DRAW, FALSE,
4462 GDI_EVENT_MASK, event_mask,
4463 GDI_CALLBACK_ACTION, HandleToolButtons,
4467 Error(ERR_EXIT, "cannot create gadget");
4469 tool_gadget[id] = gi;
4473 void FreeToolButtons()
4477 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4478 FreeGadget(tool_gadget[i]);
4481 static void UnmapToolButtons()
4485 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4486 UnmapGadget(tool_gadget[i]);
4489 static void HandleToolButtons(struct GadgetInfo *gi)
4491 request_gadget_id = gi->custom_id;
4494 static struct Mapping_EM_to_RND_object
4497 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
4498 boolean is_backside; /* backside of moving element */
4504 em_object_mapping_list[] =
4507 Xblank, TRUE, FALSE,
4511 Yacid_splash_eB, FALSE, FALSE,
4512 EL_ACID_SPLASH_RIGHT, -1, -1
4515 Yacid_splash_wB, FALSE, FALSE,
4516 EL_ACID_SPLASH_LEFT, -1, -1
4519 #ifdef EM_ENGINE_BAD_ROLL
4521 Xstone_force_e, FALSE, FALSE,
4522 EL_ROCK, -1, MV_BIT_RIGHT
4525 Xstone_force_w, FALSE, FALSE,
4526 EL_ROCK, -1, MV_BIT_LEFT
4529 Xnut_force_e, FALSE, FALSE,
4530 EL_NUT, -1, MV_BIT_RIGHT
4533 Xnut_force_w, FALSE, FALSE,
4534 EL_NUT, -1, MV_BIT_LEFT
4537 Xspring_force_e, FALSE, FALSE,
4538 EL_SPRING, -1, MV_BIT_RIGHT
4541 Xspring_force_w, FALSE, FALSE,
4542 EL_SPRING, -1, MV_BIT_LEFT
4545 Xemerald_force_e, FALSE, FALSE,
4546 EL_EMERALD, -1, MV_BIT_RIGHT
4549 Xemerald_force_w, FALSE, FALSE,
4550 EL_EMERALD, -1, MV_BIT_LEFT
4553 Xdiamond_force_e, FALSE, FALSE,
4554 EL_DIAMOND, -1, MV_BIT_RIGHT
4557 Xdiamond_force_w, FALSE, FALSE,
4558 EL_DIAMOND, -1, MV_BIT_LEFT
4561 Xbomb_force_e, FALSE, FALSE,
4562 EL_BOMB, -1, MV_BIT_RIGHT
4565 Xbomb_force_w, FALSE, FALSE,
4566 EL_BOMB, -1, MV_BIT_LEFT
4568 #endif /* EM_ENGINE_BAD_ROLL */
4571 Xstone, TRUE, FALSE,
4575 Xstone_pause, FALSE, FALSE,
4579 Xstone_fall, FALSE, FALSE,
4583 Ystone_s, FALSE, FALSE,
4584 EL_ROCK, ACTION_FALLING, -1
4587 Ystone_sB, FALSE, TRUE,
4588 EL_ROCK, ACTION_FALLING, -1
4591 Ystone_e, FALSE, FALSE,
4592 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
4595 Ystone_eB, FALSE, TRUE,
4596 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
4599 Ystone_w, FALSE, FALSE,
4600 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
4603 Ystone_wB, FALSE, TRUE,
4604 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
4611 Xnut_pause, FALSE, FALSE,
4615 Xnut_fall, FALSE, FALSE,
4619 Ynut_s, FALSE, FALSE,
4620 EL_NUT, ACTION_FALLING, -1
4623 Ynut_sB, FALSE, TRUE,
4624 EL_NUT, ACTION_FALLING, -1
4627 Ynut_e, FALSE, FALSE,
4628 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
4631 Ynut_eB, FALSE, TRUE,
4632 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
4635 Ynut_w, FALSE, FALSE,
4636 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
4639 Ynut_wB, FALSE, TRUE,
4640 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
4643 Xbug_n, TRUE, FALSE,
4647 Xbug_e, TRUE, FALSE,
4648 EL_BUG_RIGHT, -1, -1
4651 Xbug_s, TRUE, FALSE,
4655 Xbug_w, TRUE, FALSE,
4659 Xbug_gon, FALSE, FALSE,
4663 Xbug_goe, FALSE, FALSE,
4664 EL_BUG_RIGHT, -1, -1
4667 Xbug_gos, FALSE, FALSE,
4671 Xbug_gow, FALSE, FALSE,
4675 Ybug_n, FALSE, FALSE,
4676 EL_BUG, ACTION_MOVING, MV_BIT_UP
4679 Ybug_nB, FALSE, TRUE,
4680 EL_BUG, ACTION_MOVING, MV_BIT_UP
4683 Ybug_e, FALSE, FALSE,
4684 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
4687 Ybug_eB, FALSE, TRUE,
4688 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
4691 Ybug_s, FALSE, FALSE,
4692 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
4695 Ybug_sB, FALSE, TRUE,
4696 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
4699 Ybug_w, FALSE, FALSE,
4700 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
4703 Ybug_wB, FALSE, TRUE,
4704 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
4707 Ybug_w_n, FALSE, FALSE,
4708 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
4711 Ybug_n_e, FALSE, FALSE,
4712 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
4715 Ybug_e_s, FALSE, FALSE,
4716 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
4719 Ybug_s_w, FALSE, FALSE,
4720 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
4723 Ybug_e_n, FALSE, FALSE,
4724 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
4727 Ybug_s_e, FALSE, FALSE,
4728 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
4731 Ybug_w_s, FALSE, FALSE,
4732 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
4735 Ybug_n_w, FALSE, FALSE,
4736 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
4739 Ybug_stone, FALSE, FALSE,
4740 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
4743 Ybug_spring, FALSE, FALSE,
4744 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
4747 Xtank_n, TRUE, FALSE,
4748 EL_SPACESHIP_UP, -1, -1
4751 Xtank_e, TRUE, FALSE,
4752 EL_SPACESHIP_RIGHT, -1, -1
4755 Xtank_s, TRUE, FALSE,
4756 EL_SPACESHIP_DOWN, -1, -1
4759 Xtank_w, TRUE, FALSE,
4760 EL_SPACESHIP_LEFT, -1, -1
4763 Xtank_gon, FALSE, FALSE,
4764 EL_SPACESHIP_UP, -1, -1
4767 Xtank_goe, FALSE, FALSE,
4768 EL_SPACESHIP_RIGHT, -1, -1
4771 Xtank_gos, FALSE, FALSE,
4772 EL_SPACESHIP_DOWN, -1, -1
4775 Xtank_gow, FALSE, FALSE,
4776 EL_SPACESHIP_LEFT, -1, -1
4779 Ytank_n, FALSE, FALSE,
4780 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
4783 Ytank_nB, FALSE, TRUE,
4784 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
4787 Ytank_e, FALSE, FALSE,
4788 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
4791 Ytank_eB, FALSE, TRUE,
4792 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
4795 Ytank_s, FALSE, FALSE,
4796 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
4799 Ytank_sB, FALSE, TRUE,
4800 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
4803 Ytank_w, FALSE, FALSE,
4804 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
4807 Ytank_wB, FALSE, TRUE,
4808 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
4811 Ytank_w_n, FALSE, FALSE,
4812 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
4815 Ytank_n_e, FALSE, FALSE,
4816 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
4819 Ytank_e_s, FALSE, FALSE,
4820 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
4823 Ytank_s_w, FALSE, FALSE,
4824 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
4827 Ytank_e_n, FALSE, FALSE,
4828 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
4831 Ytank_s_e, FALSE, FALSE,
4832 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
4835 Ytank_w_s, FALSE, FALSE,
4836 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
4839 Ytank_n_w, FALSE, FALSE,
4840 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
4843 Ytank_stone, FALSE, FALSE,
4844 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
4847 Ytank_spring, FALSE, FALSE,
4848 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
4851 Xandroid, TRUE, FALSE,
4852 EL_EMC_ANDROID, ACTION_ACTIVE, -1
4855 Xandroid_1_n, FALSE, FALSE,
4856 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
4859 Xandroid_2_n, FALSE, FALSE,
4860 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
4863 Xandroid_1_e, FALSE, FALSE,
4864 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
4867 Xandroid_2_e, FALSE, FALSE,
4868 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
4871 Xandroid_1_w, FALSE, FALSE,
4872 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
4875 Xandroid_2_w, FALSE, FALSE,
4876 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
4879 Xandroid_1_s, FALSE, FALSE,
4880 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
4883 Xandroid_2_s, FALSE, FALSE,
4884 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
4887 Yandroid_n, FALSE, FALSE,
4888 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
4891 Yandroid_nB, FALSE, TRUE,
4892 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
4895 Yandroid_ne, FALSE, FALSE,
4896 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
4899 Yandroid_neB, FALSE, TRUE,
4900 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
4903 Yandroid_e, FALSE, FALSE,
4904 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
4907 Yandroid_eB, FALSE, TRUE,
4908 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
4911 Yandroid_se, FALSE, FALSE,
4912 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
4915 Yandroid_seB, FALSE, TRUE,
4916 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
4919 Yandroid_s, FALSE, FALSE,
4920 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
4923 Yandroid_sB, FALSE, TRUE,
4924 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
4927 Yandroid_sw, FALSE, FALSE,
4928 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
4931 Yandroid_swB, FALSE, TRUE,
4932 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
4935 Yandroid_w, FALSE, FALSE,
4936 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
4939 Yandroid_wB, FALSE, TRUE,
4940 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
4943 Yandroid_nw, FALSE, FALSE,
4944 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
4947 Yandroid_nwB, FALSE, TRUE,
4948 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
4951 Xspring, TRUE, FALSE,
4955 Xspring_pause, FALSE, FALSE,
4959 Xspring_e, FALSE, FALSE,
4963 Xspring_w, FALSE, FALSE,
4967 Xspring_fall, FALSE, FALSE,
4971 Yspring_s, FALSE, FALSE,
4972 EL_SPRING, ACTION_FALLING, -1
4975 Yspring_sB, FALSE, TRUE,
4976 EL_SPRING, ACTION_FALLING, -1
4979 Yspring_e, FALSE, FALSE,
4980 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
4983 Yspring_eB, FALSE, TRUE,
4984 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
4987 Yspring_w, FALSE, FALSE,
4988 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
4991 Yspring_wB, FALSE, TRUE,
4992 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
4995 Yspring_kill_e, FALSE, FALSE,
4996 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
4999 Yspring_kill_eB, FALSE, TRUE,
5000 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
5003 Yspring_kill_w, FALSE, FALSE,
5004 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
5007 Yspring_kill_wB, FALSE, TRUE,
5008 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
5011 Xeater_n, TRUE, FALSE,
5012 EL_YAMYAM_UP, -1, -1
5015 Xeater_e, TRUE, FALSE,
5016 EL_YAMYAM_RIGHT, -1, -1
5019 Xeater_w, TRUE, FALSE,
5020 EL_YAMYAM_LEFT, -1, -1
5023 Xeater_s, TRUE, FALSE,
5024 EL_YAMYAM_DOWN, -1, -1
5027 Yeater_n, FALSE, FALSE,
5028 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
5031 Yeater_nB, FALSE, TRUE,
5032 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
5035 Yeater_e, FALSE, FALSE,
5036 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
5039 Yeater_eB, FALSE, TRUE,
5040 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
5043 Yeater_s, FALSE, FALSE,
5044 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
5047 Yeater_sB, FALSE, TRUE,
5048 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
5051 Yeater_w, FALSE, FALSE,
5052 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
5055 Yeater_wB, FALSE, TRUE,
5056 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
5059 Yeater_stone, FALSE, FALSE,
5060 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
5063 Yeater_spring, FALSE, FALSE,
5064 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
5067 Xalien, TRUE, FALSE,
5071 Xalien_pause, FALSE, FALSE,
5075 Yalien_n, FALSE, FALSE,
5076 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
5079 Yalien_nB, FALSE, TRUE,
5080 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
5083 Yalien_e, FALSE, FALSE,
5084 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
5087 Yalien_eB, FALSE, TRUE,
5088 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
5091 Yalien_s, FALSE, FALSE,
5092 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
5095 Yalien_sB, FALSE, TRUE,
5096 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
5099 Yalien_w, FALSE, FALSE,
5100 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
5103 Yalien_wB, FALSE, TRUE,
5104 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
5107 Yalien_stone, FALSE, FALSE,
5108 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
5111 Yalien_spring, FALSE, FALSE,
5112 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
5115 Xemerald, TRUE, FALSE,
5119 Xemerald_pause, FALSE, FALSE,
5123 Xemerald_fall, FALSE, FALSE,
5127 Xemerald_shine, FALSE, FALSE,
5128 EL_EMERALD, ACTION_TWINKLING, -1
5131 Yemerald_s, FALSE, FALSE,
5132 EL_EMERALD, ACTION_FALLING, -1
5135 Yemerald_sB, FALSE, TRUE,
5136 EL_EMERALD, ACTION_FALLING, -1
5139 Yemerald_e, FALSE, FALSE,
5140 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
5143 Yemerald_eB, FALSE, TRUE,
5144 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
5147 Yemerald_w, FALSE, FALSE,
5148 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
5151 Yemerald_wB, FALSE, TRUE,
5152 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
5155 Yemerald_eat, FALSE, FALSE,
5156 EL_EMERALD, ACTION_COLLECTING, -1
5159 Yemerald_stone, FALSE, FALSE,
5160 EL_NUT, ACTION_BREAKING, -1
5163 Xdiamond, TRUE, FALSE,
5167 Xdiamond_pause, FALSE, FALSE,
5171 Xdiamond_fall, FALSE, FALSE,
5175 Xdiamond_shine, FALSE, FALSE,
5176 EL_DIAMOND, ACTION_TWINKLING, -1
5179 Ydiamond_s, FALSE, FALSE,
5180 EL_DIAMOND, ACTION_FALLING, -1
5183 Ydiamond_sB, FALSE, TRUE,
5184 EL_DIAMOND, ACTION_FALLING, -1
5187 Ydiamond_e, FALSE, FALSE,
5188 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
5191 Ydiamond_eB, FALSE, TRUE,
5192 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
5195 Ydiamond_w, FALSE, FALSE,
5196 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
5199 Ydiamond_wB, FALSE, TRUE,
5200 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
5203 Ydiamond_eat, FALSE, FALSE,
5204 EL_DIAMOND, ACTION_COLLECTING, -1
5207 Ydiamond_stone, FALSE, FALSE,
5208 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
5211 Xdrip_fall, TRUE, FALSE,
5212 EL_AMOEBA_DROP, -1, -1
5215 Xdrip_stretch, FALSE, FALSE,
5216 EL_AMOEBA_DROP, ACTION_FALLING, -1
5219 Xdrip_stretchB, FALSE, TRUE,
5220 EL_AMOEBA_DROP, ACTION_FALLING, -1
5223 Xdrip_eat, FALSE, FALSE,
5224 EL_AMOEBA_DROP, ACTION_GROWING, -1
5227 Ydrip_s1, FALSE, FALSE,
5228 EL_AMOEBA_DROP, ACTION_FALLING, -1
5231 Ydrip_s1B, FALSE, TRUE,
5232 EL_AMOEBA_DROP, ACTION_FALLING, -1
5235 Ydrip_s2, FALSE, FALSE,
5236 EL_AMOEBA_DROP, ACTION_FALLING, -1
5239 Ydrip_s2B, FALSE, TRUE,
5240 EL_AMOEBA_DROP, ACTION_FALLING, -1
5247 Xbomb_pause, FALSE, FALSE,
5251 Xbomb_fall, FALSE, FALSE,
5255 Ybomb_s, FALSE, FALSE,
5256 EL_BOMB, ACTION_FALLING, -1
5259 Ybomb_sB, FALSE, TRUE,
5260 EL_BOMB, ACTION_FALLING, -1
5263 Ybomb_e, FALSE, FALSE,
5264 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
5267 Ybomb_eB, FALSE, TRUE,
5268 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
5271 Ybomb_w, FALSE, FALSE,
5272 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
5275 Ybomb_wB, FALSE, TRUE,
5276 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
5279 Ybomb_eat, FALSE, FALSE,
5280 EL_BOMB, ACTION_ACTIVATING, -1
5283 Xballoon, TRUE, FALSE,
5287 Yballoon_n, FALSE, FALSE,
5288 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
5291 Yballoon_nB, FALSE, TRUE,
5292 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
5295 Yballoon_e, FALSE, FALSE,
5296 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
5299 Yballoon_eB, FALSE, TRUE,
5300 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
5303 Yballoon_s, FALSE, FALSE,
5304 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
5307 Yballoon_sB, FALSE, TRUE,
5308 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
5311 Yballoon_w, FALSE, FALSE,
5312 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
5315 Yballoon_wB, FALSE, TRUE,
5316 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
5319 Xgrass, TRUE, FALSE,
5320 EL_EMC_GRASS, -1, -1
5323 Ygrass_nB, FALSE, FALSE,
5324 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
5327 Ygrass_eB, FALSE, FALSE,
5328 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
5331 Ygrass_sB, FALSE, FALSE,
5332 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
5335 Ygrass_wB, FALSE, FALSE,
5336 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
5343 Ydirt_nB, FALSE, FALSE,
5344 EL_SAND, ACTION_DIGGING, MV_BIT_UP
5347 Ydirt_eB, FALSE, FALSE,
5348 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
5351 Ydirt_sB, FALSE, FALSE,
5352 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
5355 Ydirt_wB, FALSE, FALSE,
5356 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
5359 Xacid_ne, TRUE, FALSE,
5360 EL_ACID_POOL_TOPRIGHT, -1, -1
5363 Xacid_se, TRUE, FALSE,
5364 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
5367 Xacid_s, TRUE, FALSE,
5368 EL_ACID_POOL_BOTTOM, -1, -1
5371 Xacid_sw, TRUE, FALSE,
5372 EL_ACID_POOL_BOTTOMLEFT, -1, -1
5375 Xacid_nw, TRUE, FALSE,
5376 EL_ACID_POOL_TOPLEFT, -1, -1
5379 Xacid_1, TRUE, FALSE,
5383 Xacid_2, FALSE, FALSE,
5387 Xacid_3, FALSE, FALSE,
5391 Xacid_4, FALSE, FALSE,
5395 Xacid_5, FALSE, FALSE,
5399 Xacid_6, FALSE, FALSE,
5403 Xacid_7, FALSE, FALSE,
5407 Xacid_8, FALSE, FALSE,
5411 Xball_1, TRUE, FALSE,
5412 EL_EMC_MAGIC_BALL, -1, -1
5415 Xball_1B, FALSE, FALSE,
5416 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5419 Xball_2, FALSE, FALSE,
5420 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5423 Xball_2B, FALSE, FALSE,
5424 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5427 Yball_eat, FALSE, FALSE,
5428 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
5431 Ykey_1_eat, FALSE, FALSE,
5432 EL_EM_KEY_1, ACTION_COLLECTING, -1
5435 Ykey_2_eat, FALSE, FALSE,
5436 EL_EM_KEY_2, ACTION_COLLECTING, -1
5439 Ykey_3_eat, FALSE, FALSE,
5440 EL_EM_KEY_3, ACTION_COLLECTING, -1
5443 Ykey_4_eat, FALSE, FALSE,
5444 EL_EM_KEY_4, ACTION_COLLECTING, -1
5447 Ykey_5_eat, FALSE, FALSE,
5448 EL_EMC_KEY_5, ACTION_COLLECTING, -1
5451 Ykey_6_eat, FALSE, FALSE,
5452 EL_EMC_KEY_6, ACTION_COLLECTING, -1
5455 Ykey_7_eat, FALSE, FALSE,
5456 EL_EMC_KEY_7, ACTION_COLLECTING, -1
5459 Ykey_8_eat, FALSE, FALSE,
5460 EL_EMC_KEY_8, ACTION_COLLECTING, -1
5463 Ylenses_eat, FALSE, FALSE,
5464 EL_EMC_LENSES, ACTION_COLLECTING, -1
5467 Ymagnify_eat, FALSE, FALSE,
5468 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
5471 Ygrass_eat, FALSE, FALSE,
5472 EL_EMC_GRASS, ACTION_SNAPPING, -1
5475 Ydirt_eat, FALSE, FALSE,
5476 EL_SAND, ACTION_SNAPPING, -1
5479 Xgrow_ns, TRUE, FALSE,
5480 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
5483 Ygrow_ns_eat, FALSE, FALSE,
5484 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
5487 Xgrow_ew, TRUE, FALSE,
5488 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
5491 Ygrow_ew_eat, FALSE, FALSE,
5492 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
5495 Xwonderwall, TRUE, FALSE,
5496 EL_MAGIC_WALL, -1, -1
5499 XwonderwallB, FALSE, FALSE,
5500 EL_MAGIC_WALL, ACTION_ACTIVE, -1
5503 Xamoeba_1, TRUE, FALSE,
5504 EL_AMOEBA_DRY, ACTION_OTHER, -1
5507 Xamoeba_2, FALSE, FALSE,
5508 EL_AMOEBA_DRY, ACTION_OTHER, -1
5511 Xamoeba_3, FALSE, FALSE,
5512 EL_AMOEBA_DRY, ACTION_OTHER, -1
5515 Xamoeba_4, FALSE, FALSE,
5516 EL_AMOEBA_DRY, ACTION_OTHER, -1
5519 Xamoeba_5, TRUE, FALSE,
5520 EL_AMOEBA_WET, ACTION_OTHER, -1
5523 Xamoeba_6, FALSE, FALSE,
5524 EL_AMOEBA_WET, ACTION_OTHER, -1
5527 Xamoeba_7, FALSE, FALSE,
5528 EL_AMOEBA_WET, ACTION_OTHER, -1
5531 Xamoeba_8, FALSE, FALSE,
5532 EL_AMOEBA_WET, ACTION_OTHER, -1
5535 Xdoor_1, TRUE, FALSE,
5536 EL_EM_GATE_1, -1, -1
5539 Xdoor_2, TRUE, FALSE,
5540 EL_EM_GATE_2, -1, -1
5543 Xdoor_3, TRUE, FALSE,
5544 EL_EM_GATE_3, -1, -1
5547 Xdoor_4, TRUE, FALSE,
5548 EL_EM_GATE_4, -1, -1
5551 Xdoor_5, TRUE, FALSE,
5552 EL_EMC_GATE_5, -1, -1
5555 Xdoor_6, TRUE, FALSE,
5556 EL_EMC_GATE_6, -1, -1
5559 Xdoor_7, TRUE, FALSE,
5560 EL_EMC_GATE_7, -1, -1
5563 Xdoor_8, TRUE, FALSE,
5564 EL_EMC_GATE_8, -1, -1
5567 Xkey_1, TRUE, FALSE,
5571 Xkey_2, TRUE, FALSE,
5575 Xkey_3, TRUE, FALSE,
5579 Xkey_4, TRUE, FALSE,
5583 Xkey_5, TRUE, FALSE,
5584 EL_EMC_KEY_5, -1, -1
5587 Xkey_6, TRUE, FALSE,
5588 EL_EMC_KEY_6, -1, -1
5591 Xkey_7, TRUE, FALSE,
5592 EL_EMC_KEY_7, -1, -1
5595 Xkey_8, TRUE, FALSE,
5596 EL_EMC_KEY_8, -1, -1
5599 Xwind_n, TRUE, FALSE,
5600 EL_BALLOON_SWITCH_UP, -1, -1
5603 Xwind_e, TRUE, FALSE,
5604 EL_BALLOON_SWITCH_RIGHT, -1, -1
5607 Xwind_s, TRUE, FALSE,
5608 EL_BALLOON_SWITCH_DOWN, -1, -1
5611 Xwind_w, TRUE, FALSE,
5612 EL_BALLOON_SWITCH_LEFT, -1, -1
5615 Xwind_nesw, TRUE, FALSE,
5616 EL_BALLOON_SWITCH_ANY, -1, -1
5619 Xwind_stop, TRUE, FALSE,
5620 EL_BALLOON_SWITCH_NONE, -1, -1
5624 EL_EM_EXIT_CLOSED, -1, -1
5627 Xexit_1, TRUE, FALSE,
5628 EL_EM_EXIT_OPEN, -1, -1
5631 Xexit_2, FALSE, FALSE,
5632 EL_EM_EXIT_OPEN, -1, -1
5635 Xexit_3, FALSE, FALSE,
5636 EL_EM_EXIT_OPEN, -1, -1
5639 Xdynamite, TRUE, FALSE,
5640 EL_EM_DYNAMITE, -1, -1
5643 Ydynamite_eat, FALSE, FALSE,
5644 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
5647 Xdynamite_1, TRUE, FALSE,
5648 EL_EM_DYNAMITE_ACTIVE, -1, -1
5651 Xdynamite_2, FALSE, FALSE,
5652 EL_EM_DYNAMITE_ACTIVE, -1, -1
5655 Xdynamite_3, FALSE, FALSE,
5656 EL_EM_DYNAMITE_ACTIVE, -1, -1
5659 Xdynamite_4, FALSE, FALSE,
5660 EL_EM_DYNAMITE_ACTIVE, -1, -1
5663 Xbumper, TRUE, FALSE,
5664 EL_EMC_SPRING_BUMPER, -1, -1
5667 XbumperB, FALSE, FALSE,
5668 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
5671 Xwheel, TRUE, FALSE,
5672 EL_ROBOT_WHEEL, -1, -1
5675 XwheelB, FALSE, FALSE,
5676 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
5679 Xswitch, TRUE, FALSE,
5680 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
5683 XswitchB, FALSE, FALSE,
5684 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
5688 EL_QUICKSAND_EMPTY, -1, -1
5691 Xsand_stone, TRUE, FALSE,
5692 EL_QUICKSAND_FULL, -1, -1
5695 Xsand_stonein_1, FALSE, TRUE,
5696 EL_ROCK, ACTION_FILLING, -1
5699 Xsand_stonein_2, FALSE, TRUE,
5700 EL_ROCK, ACTION_FILLING, -1
5703 Xsand_stonein_3, FALSE, TRUE,
5704 EL_ROCK, ACTION_FILLING, -1
5707 Xsand_stonein_4, FALSE, TRUE,
5708 EL_ROCK, ACTION_FILLING, -1
5711 Xsand_stonesand_1, FALSE, FALSE,
5712 EL_QUICKSAND_EMPTYING, -1, -1
5715 Xsand_stonesand_2, FALSE, FALSE,
5716 EL_QUICKSAND_EMPTYING, -1, -1
5719 Xsand_stonesand_3, FALSE, FALSE,
5720 EL_QUICKSAND_EMPTYING, -1, -1
5723 Xsand_stonesand_4, FALSE, FALSE,
5724 EL_QUICKSAND_EMPTYING, -1, -1
5727 Xsand_stonesand_quickout_1, FALSE, FALSE,
5728 EL_QUICKSAND_EMPTYING, -1, -1
5731 Xsand_stonesand_quickout_2, FALSE, FALSE,
5732 EL_QUICKSAND_EMPTYING, -1, -1
5735 Xsand_stoneout_1, FALSE, FALSE,
5736 EL_ROCK, ACTION_EMPTYING, -1
5739 Xsand_stoneout_2, FALSE, FALSE,
5740 EL_ROCK, ACTION_EMPTYING, -1
5743 Xsand_sandstone_1, FALSE, FALSE,
5744 EL_QUICKSAND_FILLING, -1, -1
5747 Xsand_sandstone_2, FALSE, FALSE,
5748 EL_QUICKSAND_FILLING, -1, -1
5751 Xsand_sandstone_3, FALSE, FALSE,
5752 EL_QUICKSAND_FILLING, -1, -1
5755 Xsand_sandstone_4, FALSE, FALSE,
5756 EL_QUICKSAND_FILLING, -1, -1
5759 Xplant, TRUE, FALSE,
5760 EL_EMC_PLANT, -1, -1
5763 Yplant, FALSE, FALSE,
5764 EL_EMC_PLANT, -1, -1
5767 Xlenses, TRUE, FALSE,
5768 EL_EMC_LENSES, -1, -1
5771 Xmagnify, TRUE, FALSE,
5772 EL_EMC_MAGNIFIER, -1, -1
5775 Xdripper, TRUE, FALSE,
5776 EL_EMC_DRIPPER, -1, -1
5779 XdripperB, FALSE, FALSE,
5780 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
5783 Xfake_blank, TRUE, FALSE,
5784 EL_INVISIBLE_WALL, -1, -1
5787 Xfake_blankB, FALSE, FALSE,
5788 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
5791 Xfake_grass, TRUE, FALSE,
5792 EL_EMC_FAKE_GRASS, -1, -1
5795 Xfake_grassB, FALSE, FALSE,
5796 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
5799 Xfake_door_1, TRUE, FALSE,
5800 EL_EM_GATE_1_GRAY, -1, -1
5803 Xfake_door_2, TRUE, FALSE,
5804 EL_EM_GATE_2_GRAY, -1, -1
5807 Xfake_door_3, TRUE, FALSE,
5808 EL_EM_GATE_3_GRAY, -1, -1
5811 Xfake_door_4, TRUE, FALSE,
5812 EL_EM_GATE_4_GRAY, -1, -1
5815 Xfake_door_5, TRUE, FALSE,
5816 EL_EMC_GATE_5_GRAY, -1, -1
5819 Xfake_door_6, TRUE, FALSE,
5820 EL_EMC_GATE_6_GRAY, -1, -1
5823 Xfake_door_7, TRUE, FALSE,
5824 EL_EMC_GATE_7_GRAY, -1, -1
5827 Xfake_door_8, TRUE, FALSE,
5828 EL_EMC_GATE_8_GRAY, -1, -1
5831 Xfake_acid_1, TRUE, FALSE,
5832 EL_EMC_FAKE_ACID, -1, -1
5835 Xfake_acid_2, FALSE, FALSE,
5836 EL_EMC_FAKE_ACID, -1, -1
5839 Xfake_acid_3, FALSE, FALSE,
5840 EL_EMC_FAKE_ACID, -1, -1
5843 Xfake_acid_4, FALSE, FALSE,
5844 EL_EMC_FAKE_ACID, -1, -1
5847 Xfake_acid_5, FALSE, FALSE,
5848 EL_EMC_FAKE_ACID, -1, -1
5851 Xfake_acid_6, FALSE, FALSE,
5852 EL_EMC_FAKE_ACID, -1, -1
5855 Xfake_acid_7, FALSE, FALSE,
5856 EL_EMC_FAKE_ACID, -1, -1
5859 Xfake_acid_8, FALSE, FALSE,
5860 EL_EMC_FAKE_ACID, -1, -1
5863 Xsteel_1, TRUE, FALSE,
5864 EL_STEELWALL, -1, -1
5867 Xsteel_2, TRUE, FALSE,
5868 EL_EMC_STEELWALL_2, -1, -1
5871 Xsteel_3, TRUE, FALSE,
5872 EL_EMC_STEELWALL_3, -1, -1
5875 Xsteel_4, TRUE, FALSE,
5876 EL_EMC_STEELWALL_4, -1, -1
5879 Xwall_1, TRUE, FALSE,
5883 Xwall_2, TRUE, FALSE,
5884 EL_EMC_WALL_14, -1, -1
5887 Xwall_3, TRUE, FALSE,
5888 EL_EMC_WALL_15, -1, -1
5891 Xwall_4, TRUE, FALSE,
5892 EL_EMC_WALL_16, -1, -1
5895 Xround_wall_1, TRUE, FALSE,
5896 EL_WALL_SLIPPERY, -1, -1
5899 Xround_wall_2, TRUE, FALSE,
5900 EL_EMC_WALL_SLIPPERY_2, -1, -1
5903 Xround_wall_3, TRUE, FALSE,
5904 EL_EMC_WALL_SLIPPERY_3, -1, -1
5907 Xround_wall_4, TRUE, FALSE,
5908 EL_EMC_WALL_SLIPPERY_4, -1, -1
5911 Xdecor_1, TRUE, FALSE,
5912 EL_EMC_WALL_8, -1, -1
5915 Xdecor_2, TRUE, FALSE,
5916 EL_EMC_WALL_6, -1, -1
5919 Xdecor_3, TRUE, FALSE,
5920 EL_EMC_WALL_4, -1, -1
5923 Xdecor_4, TRUE, FALSE,
5924 EL_EMC_WALL_7, -1, -1
5927 Xdecor_5, TRUE, FALSE,
5928 EL_EMC_WALL_5, -1, -1
5931 Xdecor_6, TRUE, FALSE,
5932 EL_EMC_WALL_9, -1, -1
5935 Xdecor_7, TRUE, FALSE,
5936 EL_EMC_WALL_10, -1, -1
5939 Xdecor_8, TRUE, FALSE,
5940 EL_EMC_WALL_1, -1, -1
5943 Xdecor_9, TRUE, FALSE,
5944 EL_EMC_WALL_2, -1, -1
5947 Xdecor_10, TRUE, FALSE,
5948 EL_EMC_WALL_3, -1, -1
5951 Xdecor_11, TRUE, FALSE,
5952 EL_EMC_WALL_11, -1, -1
5955 Xdecor_12, TRUE, FALSE,
5956 EL_EMC_WALL_12, -1, -1
5959 Xalpha_0, TRUE, FALSE,
5960 EL_CHAR('0'), -1, -1
5963 Xalpha_1, TRUE, FALSE,
5964 EL_CHAR('1'), -1, -1
5967 Xalpha_2, TRUE, FALSE,
5968 EL_CHAR('2'), -1, -1
5971 Xalpha_3, TRUE, FALSE,
5972 EL_CHAR('3'), -1, -1
5975 Xalpha_4, TRUE, FALSE,
5976 EL_CHAR('4'), -1, -1
5979 Xalpha_5, TRUE, FALSE,
5980 EL_CHAR('5'), -1, -1
5983 Xalpha_6, TRUE, FALSE,
5984 EL_CHAR('6'), -1, -1
5987 Xalpha_7, TRUE, FALSE,
5988 EL_CHAR('7'), -1, -1
5991 Xalpha_8, TRUE, FALSE,
5992 EL_CHAR('8'), -1, -1
5995 Xalpha_9, TRUE, FALSE,
5996 EL_CHAR('9'), -1, -1
5999 Xalpha_excla, TRUE, FALSE,
6000 EL_CHAR('!'), -1, -1
6003 Xalpha_quote, TRUE, FALSE,
6004 EL_CHAR('"'), -1, -1
6007 Xalpha_comma, TRUE, FALSE,
6008 EL_CHAR(','), -1, -1
6011 Xalpha_minus, TRUE, FALSE,
6012 EL_CHAR('-'), -1, -1
6015 Xalpha_perio, TRUE, FALSE,
6016 EL_CHAR('.'), -1, -1
6019 Xalpha_colon, TRUE, FALSE,
6020 EL_CHAR(':'), -1, -1
6023 Xalpha_quest, TRUE, FALSE,
6024 EL_CHAR('?'), -1, -1
6027 Xalpha_a, TRUE, FALSE,
6028 EL_CHAR('A'), -1, -1
6031 Xalpha_b, TRUE, FALSE,
6032 EL_CHAR('B'), -1, -1
6035 Xalpha_c, TRUE, FALSE,
6036 EL_CHAR('C'), -1, -1
6039 Xalpha_d, TRUE, FALSE,
6040 EL_CHAR('D'), -1, -1
6043 Xalpha_e, TRUE, FALSE,
6044 EL_CHAR('E'), -1, -1
6047 Xalpha_f, TRUE, FALSE,
6048 EL_CHAR('F'), -1, -1
6051 Xalpha_g, TRUE, FALSE,
6052 EL_CHAR('G'), -1, -1
6055 Xalpha_h, TRUE, FALSE,
6056 EL_CHAR('H'), -1, -1
6059 Xalpha_i, TRUE, FALSE,
6060 EL_CHAR('I'), -1, -1
6063 Xalpha_j, TRUE, FALSE,
6064 EL_CHAR('J'), -1, -1
6067 Xalpha_k, TRUE, FALSE,
6068 EL_CHAR('K'), -1, -1
6071 Xalpha_l, TRUE, FALSE,
6072 EL_CHAR('L'), -1, -1
6075 Xalpha_m, TRUE, FALSE,
6076 EL_CHAR('M'), -1, -1
6079 Xalpha_n, TRUE, FALSE,
6080 EL_CHAR('N'), -1, -1
6083 Xalpha_o, TRUE, FALSE,
6084 EL_CHAR('O'), -1, -1
6087 Xalpha_p, TRUE, FALSE,
6088 EL_CHAR('P'), -1, -1
6091 Xalpha_q, TRUE, FALSE,
6092 EL_CHAR('Q'), -1, -1
6095 Xalpha_r, TRUE, FALSE,
6096 EL_CHAR('R'), -1, -1
6099 Xalpha_s, TRUE, FALSE,
6100 EL_CHAR('S'), -1, -1
6103 Xalpha_t, TRUE, FALSE,
6104 EL_CHAR('T'), -1, -1
6107 Xalpha_u, TRUE, FALSE,
6108 EL_CHAR('U'), -1, -1
6111 Xalpha_v, TRUE, FALSE,
6112 EL_CHAR('V'), -1, -1
6115 Xalpha_w, TRUE, FALSE,
6116 EL_CHAR('W'), -1, -1
6119 Xalpha_x, TRUE, FALSE,
6120 EL_CHAR('X'), -1, -1
6123 Xalpha_y, TRUE, FALSE,
6124 EL_CHAR('Y'), -1, -1
6127 Xalpha_z, TRUE, FALSE,
6128 EL_CHAR('Z'), -1, -1
6131 Xalpha_arrow_e, TRUE, FALSE,
6132 EL_CHAR('>'), -1, -1
6135 Xalpha_arrow_w, TRUE, FALSE,
6136 EL_CHAR('<'), -1, -1
6139 Xalpha_copyr, TRUE, FALSE,
6140 EL_CHAR(CHAR_BYTE_COPYRIGHT), -1, -1
6144 Xboom_bug, FALSE, FALSE,
6145 EL_BUG, ACTION_EXPLODING, -1
6148 Xboom_bomb, FALSE, FALSE,
6149 EL_BOMB, ACTION_EXPLODING, -1
6152 Xboom_android, FALSE, FALSE,
6153 EL_EMC_ANDROID, ACTION_OTHER, -1
6156 Xboom_1, FALSE, FALSE,
6157 EL_DEFAULT, ACTION_EXPLODING, -1
6160 Xboom_2, FALSE, FALSE,
6161 EL_DEFAULT, ACTION_EXPLODING, -1
6164 Znormal, FALSE, FALSE,
6168 Zdynamite, FALSE, FALSE,
6172 Zplayer, FALSE, FALSE,
6176 ZBORDER, FALSE, FALSE,
6186 static struct Mapping_EM_to_RND_player
6195 em_player_mapping_list[] =
6199 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
6203 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
6207 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
6211 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
6215 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
6219 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
6223 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
6227 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
6231 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
6235 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
6239 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
6243 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
6247 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
6251 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
6255 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
6259 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
6263 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
6267 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
6271 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
6275 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
6279 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
6283 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
6287 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
6291 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
6295 EL_PLAYER_1, ACTION_DEFAULT, -1,
6299 EL_PLAYER_2, ACTION_DEFAULT, -1,
6303 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
6307 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
6311 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
6315 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
6319 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
6323 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
6327 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
6331 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
6335 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
6339 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
6343 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
6347 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
6351 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
6355 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
6359 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
6363 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
6367 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
6371 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
6375 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
6379 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
6383 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
6387 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
6391 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
6395 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
6399 EL_PLAYER_3, ACTION_DEFAULT, -1,
6403 EL_PLAYER_4, ACTION_DEFAULT, -1,
6412 int map_element_RND_to_EM(int element_rnd)
6414 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
6415 static boolean mapping_initialized = FALSE;
6417 if (!mapping_initialized)
6421 /* return "Xalpha_quest" for all undefined elements in mapping array */
6422 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
6423 mapping_RND_to_EM[i] = Xalpha_quest;
6425 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6426 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
6427 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
6428 em_object_mapping_list[i].element_em;
6430 mapping_initialized = TRUE;
6433 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
6434 return mapping_RND_to_EM[element_rnd];
6436 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
6441 int map_element_EM_to_RND(int element_em)
6443 static unsigned short mapping_EM_to_RND[TILE_MAX];
6444 static boolean mapping_initialized = FALSE;
6446 if (!mapping_initialized)
6450 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
6451 for (i = 0; i < TILE_MAX; i++)
6452 mapping_EM_to_RND[i] = EL_UNKNOWN;
6454 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6455 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
6456 em_object_mapping_list[i].element_rnd;
6458 mapping_initialized = TRUE;
6461 if (element_em >= 0 && element_em < TILE_MAX)
6462 return mapping_EM_to_RND[element_em];
6464 Error(ERR_WARN, "invalid EM level element %d", element_em);
6469 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
6471 struct LevelInfo_EM *level_em = level->native_em_level;
6472 struct LEVEL *lev = level_em->lev;
6475 for (i = 0; i < TILE_MAX; i++)
6476 lev->android_array[i] = Xblank;
6478 for (i = 0; i < level->num_android_clone_elements; i++)
6480 int element_rnd = level->android_clone_element[i];
6481 int element_em = map_element_RND_to_EM(element_rnd);
6483 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
6484 if (em_object_mapping_list[j].element_rnd == element_rnd)
6485 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
6489 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
6491 struct LevelInfo_EM *level_em = level->native_em_level;
6492 struct LEVEL *lev = level_em->lev;
6495 level->num_android_clone_elements = 0;
6497 for (i = 0; i < TILE_MAX; i++)
6499 int element_em = lev->android_array[i];
6501 boolean element_found = FALSE;
6503 if (element_em == Xblank)
6506 element_rnd = map_element_EM_to_RND(element_em);
6508 for (j = 0; j < level->num_android_clone_elements; j++)
6509 if (level->android_clone_element[j] == element_rnd)
6510 element_found = TRUE;
6514 level->android_clone_element[level->num_android_clone_elements++] =
6517 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
6522 if (level->num_android_clone_elements == 0)
6524 level->num_android_clone_elements = 1;
6525 level->android_clone_element[0] = EL_EMPTY;
6529 int map_direction_RND_to_EM(int direction)
6531 return (direction == MV_UP ? 0 :
6532 direction == MV_RIGHT ? 1 :
6533 direction == MV_DOWN ? 2 :
6534 direction == MV_LEFT ? 3 :
6538 int map_direction_EM_to_RND(int direction)
6540 return (direction == 0 ? MV_UP :
6541 direction == 1 ? MV_RIGHT :
6542 direction == 2 ? MV_DOWN :
6543 direction == 3 ? MV_LEFT :
6547 int map_element_RND_to_SP(int element_rnd)
6549 int element_sp = 0x20; /* map unknown elements to yellow "hardware" */
6551 if (element_rnd >= EL_SP_START &&
6552 element_rnd <= EL_SP_END)
6553 element_sp = element_rnd - EL_SP_START;
6554 else if (element_rnd == EL_EMPTY_SPACE)
6556 else if (element_rnd == EL_INVISIBLE_WALL)
6562 int map_element_SP_to_RND(int element_sp)
6564 int element_rnd = EL_UNKNOWN;
6566 if (element_sp >= 0x00 &&
6568 element_rnd = EL_SP_START + element_sp;
6569 else if (element_sp == 0x28)
6570 element_rnd = EL_INVISIBLE_WALL;
6575 int map_action_SP_to_RND(int action_sp)
6579 case actActive: return ACTION_ACTIVE;
6580 case actImpact: return ACTION_IMPACT;
6581 case actExploding: return ACTION_EXPLODING;
6582 case actDigging: return ACTION_DIGGING;
6583 case actSnapping: return ACTION_SNAPPING;
6584 case actCollecting: return ACTION_COLLECTING;
6585 case actPassing: return ACTION_PASSING;
6586 case actPushing: return ACTION_PUSHING;
6587 case actDropping: return ACTION_DROPPING;
6589 default: return ACTION_DEFAULT;
6593 int get_next_element(int element)
6597 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
6598 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
6599 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
6600 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
6601 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
6602 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
6603 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
6604 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
6605 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
6606 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
6607 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
6609 default: return element;
6613 int el_act_dir2img(int element, int action, int direction)
6615 element = GFX_ELEMENT(element);
6616 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
6618 /* direction_graphic[][] == graphic[] for undefined direction graphics */
6619 return element_info[element].direction_graphic[action][direction];
6622 static int el_act_dir2crm(int element, int action, int direction)
6624 element = GFX_ELEMENT(element);
6625 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
6627 /* direction_graphic[][] == graphic[] for undefined direction graphics */
6628 return element_info[element].direction_crumbled[action][direction];
6631 int el_act2img(int element, int action)
6633 element = GFX_ELEMENT(element);
6635 return element_info[element].graphic[action];
6638 int el_act2crm(int element, int action)
6640 element = GFX_ELEMENT(element);
6642 return element_info[element].crumbled[action];
6645 int el_dir2img(int element, int direction)
6647 element = GFX_ELEMENT(element);
6649 return el_act_dir2img(element, ACTION_DEFAULT, direction);
6652 int el2baseimg(int element)
6654 return element_info[element].graphic[ACTION_DEFAULT];
6657 int el2img(int element)
6659 element = GFX_ELEMENT(element);
6661 return element_info[element].graphic[ACTION_DEFAULT];
6664 int el2edimg(int element)
6666 element = GFX_ELEMENT(element);
6668 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
6671 int el2preimg(int element)
6673 element = GFX_ELEMENT(element);
6675 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
6678 int el2panelimg(int element)
6680 element = GFX_ELEMENT(element);
6682 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL];
6685 int font2baseimg(int font_nr)
6687 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
6690 int getBeltNrFromBeltElement(int element)
6692 return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
6693 element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
6694 element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
6697 int getBeltNrFromBeltActiveElement(int element)
6699 return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
6700 element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
6701 element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
6704 int getBeltNrFromBeltSwitchElement(int element)
6706 return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
6707 element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
6708 element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
6711 int getBeltDirNrFromBeltElement(int element)
6713 static int belt_base_element[4] =
6715 EL_CONVEYOR_BELT_1_LEFT,
6716 EL_CONVEYOR_BELT_2_LEFT,
6717 EL_CONVEYOR_BELT_3_LEFT,
6718 EL_CONVEYOR_BELT_4_LEFT
6721 int belt_nr = getBeltNrFromBeltElement(element);
6722 int belt_dir_nr = element - belt_base_element[belt_nr];
6724 return (belt_dir_nr % 3);
6727 int getBeltDirNrFromBeltSwitchElement(int element)
6729 static int belt_base_element[4] =
6731 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
6732 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
6733 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
6734 EL_CONVEYOR_BELT_4_SWITCH_LEFT
6737 int belt_nr = getBeltNrFromBeltSwitchElement(element);
6738 int belt_dir_nr = element - belt_base_element[belt_nr];
6740 return (belt_dir_nr % 3);
6743 int getBeltDirFromBeltElement(int element)
6745 static int belt_move_dir[3] =
6752 int belt_dir_nr = getBeltDirNrFromBeltElement(element);
6754 return belt_move_dir[belt_dir_nr];
6757 int getBeltDirFromBeltSwitchElement(int element)
6759 static int belt_move_dir[3] =
6766 int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
6768 return belt_move_dir[belt_dir_nr];
6771 int getBeltElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
6773 static int belt_base_element[4] =
6775 EL_CONVEYOR_BELT_1_LEFT,
6776 EL_CONVEYOR_BELT_2_LEFT,
6777 EL_CONVEYOR_BELT_3_LEFT,
6778 EL_CONVEYOR_BELT_4_LEFT
6781 return belt_base_element[belt_nr] + belt_dir_nr;
6784 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
6786 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
6788 return getBeltElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
6791 int getBeltSwitchElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
6793 static int belt_base_element[4] =
6795 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
6796 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
6797 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
6798 EL_CONVEYOR_BELT_4_SWITCH_LEFT
6801 return belt_base_element[belt_nr] + belt_dir_nr;
6804 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
6806 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
6808 return getBeltSwitchElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
6811 boolean getTeamMode_EM()
6813 return game.team_mode;
6816 int getGameFrameDelay_EM(int native_em_game_frame_delay)
6818 int game_frame_delay_value;
6820 game_frame_delay_value =
6821 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
6822 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
6825 if (tape.playing && tape.warp_forward && !tape.pausing)
6826 game_frame_delay_value = 0;
6828 return game_frame_delay_value;
6831 unsigned int InitRND(int seed)
6833 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
6834 return InitEngineRandom_EM(seed);
6835 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
6836 return InitEngineRandom_SP(seed);
6838 return InitEngineRandom_RND(seed);
6841 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
6842 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
6844 inline static int get_effective_element_EM(int tile, int frame_em)
6846 int element = object_mapping[tile].element_rnd;
6847 int action = object_mapping[tile].action;
6848 boolean is_backside = object_mapping[tile].is_backside;
6849 boolean action_removing = (action == ACTION_DIGGING ||
6850 action == ACTION_SNAPPING ||
6851 action == ACTION_COLLECTING);
6857 case Yacid_splash_eB:
6858 case Yacid_splash_wB:
6859 return (frame_em > 5 ? EL_EMPTY : element);
6865 else /* frame_em == 7 */
6869 case Yacid_splash_eB:
6870 case Yacid_splash_wB:
6873 case Yemerald_stone:
6876 case Ydiamond_stone:
6880 case Xdrip_stretchB:
6899 case Xsand_stonein_1:
6900 case Xsand_stonein_2:
6901 case Xsand_stonein_3:
6902 case Xsand_stonein_4:
6906 return (is_backside || action_removing ? EL_EMPTY : element);
6911 inline static boolean check_linear_animation_EM(int tile)
6915 case Xsand_stonesand_1:
6916 case Xsand_stonesand_quickout_1:
6917 case Xsand_sandstone_1:
6918 case Xsand_stonein_1:
6919 case Xsand_stoneout_1:
6938 case Yacid_splash_eB:
6939 case Yacid_splash_wB:
6940 case Yemerald_stone:
6947 inline static void set_crumbled_graphics_EM(struct GraphicInfo_EM *g_em,
6948 boolean has_crumbled_graphics,
6949 int crumbled, int sync_frame)
6951 /* if element can be crumbled, but certain action graphics are just empty
6952 space (like instantly snapping sand to empty space in 1 frame), do not
6953 treat these empty space graphics as crumbled graphics in EMC engine */
6954 if (crumbled == IMG_EMPTY_SPACE)
6955 has_crumbled_graphics = FALSE;
6957 if (has_crumbled_graphics)
6959 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
6960 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
6961 g_crumbled->anim_delay,
6962 g_crumbled->anim_mode,
6963 g_crumbled->anim_start_frame,
6966 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
6967 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
6969 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
6971 g_em->has_crumbled_graphics = TRUE;
6975 g_em->crumbled_bitmap = NULL;
6976 g_em->crumbled_src_x = 0;
6977 g_em->crumbled_src_y = 0;
6978 g_em->crumbled_border_size = 0;
6980 g_em->has_crumbled_graphics = FALSE;
6984 void ResetGfxAnimation_EM(int x, int y, int tile)
6989 void SetGfxAnimation_EM(struct GraphicInfo_EM *g_em,
6990 int tile, int frame_em, int x, int y)
6992 int action = object_mapping[tile].action;
6993 int direction = object_mapping[tile].direction;
6994 int effective_element = get_effective_element_EM(tile, frame_em);
6995 int graphic = (direction == MV_NONE ?
6996 el_act2img(effective_element, action) :
6997 el_act_dir2img(effective_element, action, direction));
6998 struct GraphicInfo *g = &graphic_info[graphic];
7000 boolean action_removing = (action == ACTION_DIGGING ||
7001 action == ACTION_SNAPPING ||
7002 action == ACTION_COLLECTING);
7003 boolean action_moving = (action == ACTION_FALLING ||
7004 action == ACTION_MOVING ||
7005 action == ACTION_PUSHING ||
7006 action == ACTION_EATING ||
7007 action == ACTION_FILLING ||
7008 action == ACTION_EMPTYING);
7009 boolean action_falling = (action == ACTION_FALLING ||
7010 action == ACTION_FILLING ||
7011 action == ACTION_EMPTYING);
7013 /* special case: graphic uses "2nd movement tile" and has defined
7014 7 frames for movement animation (or less) => use default graphic
7015 for last (8th) frame which ends the movement animation */
7016 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
7018 action = ACTION_DEFAULT; /* (keep action_* unchanged for now) */
7019 graphic = (direction == MV_NONE ?
7020 el_act2img(effective_element, action) :
7021 el_act_dir2img(effective_element, action, direction));
7023 g = &graphic_info[graphic];
7026 if ((action_removing || check_linear_animation_EM(tile)) && frame_em == 0)
7030 else if (action_moving)
7032 boolean is_backside = object_mapping[tile].is_backside;
7036 int direction = object_mapping[tile].direction;
7037 int move_dir = (action_falling ? MV_DOWN : direction);
7042 /* !!! TEST !!! NEW !!! DOES NOT WORK RIGHT YET !!! */
7043 if (g->double_movement && frame_em == 0)
7047 if (move_dir == MV_LEFT)
7048 GfxFrame[x - 1][y] = GfxFrame[x][y];
7049 else if (move_dir == MV_RIGHT)
7050 GfxFrame[x + 1][y] = GfxFrame[x][y];
7051 else if (move_dir == MV_UP)
7052 GfxFrame[x][y - 1] = GfxFrame[x][y];
7053 else if (move_dir == MV_DOWN)
7054 GfxFrame[x][y + 1] = GfxFrame[x][y];
7061 /* special case: animation for Xsand_stonesand_quickout_1/2 twice as fast */
7062 if (tile == Xsand_stonesand_quickout_1 ||
7063 tile == Xsand_stonesand_quickout_2)
7067 if (graphic_info[graphic].anim_global_sync)
7068 sync_frame = FrameCounter;
7069 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
7070 sync_frame = GfxFrame[x][y];
7072 sync_frame = 0; /* playfield border (pseudo steel) */
7074 SetRandomAnimationValue(x, y);
7076 int frame = getAnimationFrame(g->anim_frames,
7079 g->anim_start_frame,
7082 g_em->unique_identifier =
7083 (graphic << 16) | ((frame % 8) << 12) | (g_em->width << 6) | g_em->height;
7086 void getGraphicSourceObjectExt_EM(struct GraphicInfo_EM *g_em,
7087 int tile, int frame_em, int x, int y)
7089 int action = object_mapping[tile].action;
7090 int direction = object_mapping[tile].direction;
7091 boolean is_backside = object_mapping[tile].is_backside;
7092 int effective_element = get_effective_element_EM(tile, frame_em);
7093 int effective_action = action;
7094 int graphic = (direction == MV_NONE ?
7095 el_act2img(effective_element, effective_action) :
7096 el_act_dir2img(effective_element, effective_action,
7098 int crumbled = (direction == MV_NONE ?
7099 el_act2crm(effective_element, effective_action) :
7100 el_act_dir2crm(effective_element, effective_action,
7102 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7103 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7104 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7105 struct GraphicInfo *g = &graphic_info[graphic];
7108 /* special case: graphic uses "2nd movement tile" and has defined
7109 7 frames for movement animation (or less) => use default graphic
7110 for last (8th) frame which ends the movement animation */
7111 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
7113 effective_action = ACTION_DEFAULT;
7114 graphic = (direction == MV_NONE ?
7115 el_act2img(effective_element, effective_action) :
7116 el_act_dir2img(effective_element, effective_action,
7118 crumbled = (direction == MV_NONE ?
7119 el_act2crm(effective_element, effective_action) :
7120 el_act_dir2crm(effective_element, effective_action,
7123 g = &graphic_info[graphic];
7126 if (graphic_info[graphic].anim_global_sync)
7127 sync_frame = FrameCounter;
7128 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
7129 sync_frame = GfxFrame[x][y];
7131 sync_frame = 0; /* playfield border (pseudo steel) */
7133 SetRandomAnimationValue(x, y);
7135 int frame = getAnimationFrame(g->anim_frames,
7138 g->anim_start_frame,
7141 getGraphicSourceExt(graphic, frame, &g_em->bitmap, &g_em->src_x, &g_em->src_y,
7142 g->double_movement && is_backside);
7144 /* (updating the "crumbled" graphic definitions is probably not really needed,
7145 as animations for crumbled graphics can't be longer than one EMC cycle) */
7146 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
7150 void getGraphicSourcePlayerExt_EM(struct GraphicInfo_EM *g_em,
7151 int player_nr, int anim, int frame_em)
7153 int element = player_mapping[player_nr][anim].element_rnd;
7154 int action = player_mapping[player_nr][anim].action;
7155 int direction = player_mapping[player_nr][anim].direction;
7156 int graphic = (direction == MV_NONE ?
7157 el_act2img(element, action) :
7158 el_act_dir2img(element, action, direction));
7159 struct GraphicInfo *g = &graphic_info[graphic];
7162 InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
7164 stored_player[player_nr].StepFrame = frame_em;
7166 sync_frame = stored_player[player_nr].Frame;
7168 int frame = getAnimationFrame(g->anim_frames,
7171 g->anim_start_frame,
7174 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
7175 &g_em->src_x, &g_em->src_y, FALSE);
7178 void InitGraphicInfo_EM(void)
7183 int num_em_gfx_errors = 0;
7185 if (graphic_info_em_object[0][0].bitmap == NULL)
7187 /* EM graphics not yet initialized in em_open_all() */
7192 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
7195 /* always start with reliable default values */
7196 for (i = 0; i < TILE_MAX; i++)
7198 object_mapping[i].element_rnd = EL_UNKNOWN;
7199 object_mapping[i].is_backside = FALSE;
7200 object_mapping[i].action = ACTION_DEFAULT;
7201 object_mapping[i].direction = MV_NONE;
7204 /* always start with reliable default values */
7205 for (p = 0; p < MAX_PLAYERS; p++)
7207 for (i = 0; i < SPR_MAX; i++)
7209 player_mapping[p][i].element_rnd = EL_UNKNOWN;
7210 player_mapping[p][i].action = ACTION_DEFAULT;
7211 player_mapping[p][i].direction = MV_NONE;
7215 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
7217 int e = em_object_mapping_list[i].element_em;
7219 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
7220 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
7222 if (em_object_mapping_list[i].action != -1)
7223 object_mapping[e].action = em_object_mapping_list[i].action;
7225 if (em_object_mapping_list[i].direction != -1)
7226 object_mapping[e].direction =
7227 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
7230 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
7232 int a = em_player_mapping_list[i].action_em;
7233 int p = em_player_mapping_list[i].player_nr;
7235 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
7237 if (em_player_mapping_list[i].action != -1)
7238 player_mapping[p][a].action = em_player_mapping_list[i].action;
7240 if (em_player_mapping_list[i].direction != -1)
7241 player_mapping[p][a].direction =
7242 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
7245 for (i = 0; i < TILE_MAX; i++)
7247 int element = object_mapping[i].element_rnd;
7248 int action = object_mapping[i].action;
7249 int direction = object_mapping[i].direction;
7250 boolean is_backside = object_mapping[i].is_backside;
7251 boolean action_exploding = ((action == ACTION_EXPLODING ||
7252 action == ACTION_SMASHED_BY_ROCK ||
7253 action == ACTION_SMASHED_BY_SPRING) &&
7254 element != EL_DIAMOND);
7255 boolean action_active = (action == ACTION_ACTIVE);
7256 boolean action_other = (action == ACTION_OTHER);
7258 for (j = 0; j < 8; j++)
7260 int effective_element = get_effective_element_EM(i, j);
7261 int effective_action = (j < 7 ? action :
7262 i == Xdrip_stretch ? action :
7263 i == Xdrip_stretchB ? action :
7264 i == Ydrip_s1 ? action :
7265 i == Ydrip_s1B ? action :
7266 i == Xball_1B ? action :
7267 i == Xball_2 ? action :
7268 i == Xball_2B ? action :
7269 i == Yball_eat ? action :
7270 i == Ykey_1_eat ? action :
7271 i == Ykey_2_eat ? action :
7272 i == Ykey_3_eat ? action :
7273 i == Ykey_4_eat ? action :
7274 i == Ykey_5_eat ? action :
7275 i == Ykey_6_eat ? action :
7276 i == Ykey_7_eat ? action :
7277 i == Ykey_8_eat ? action :
7278 i == Ylenses_eat ? action :
7279 i == Ymagnify_eat ? action :
7280 i == Ygrass_eat ? action :
7281 i == Ydirt_eat ? action :
7282 i == Xsand_stonein_1 ? action :
7283 i == Xsand_stonein_2 ? action :
7284 i == Xsand_stonein_3 ? action :
7285 i == Xsand_stonein_4 ? action :
7286 i == Xsand_stoneout_1 ? action :
7287 i == Xsand_stoneout_2 ? action :
7288 i == Xboom_android ? ACTION_EXPLODING :
7289 action_exploding ? ACTION_EXPLODING :
7290 action_active ? action :
7291 action_other ? action :
7293 int graphic = (el_act_dir2img(effective_element, effective_action,
7295 int crumbled = (el_act_dir2crm(effective_element, effective_action,
7297 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7298 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7299 boolean has_action_graphics = (graphic != base_graphic);
7300 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7301 struct GraphicInfo *g = &graphic_info[graphic];
7302 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7305 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
7306 boolean special_animation = (action != ACTION_DEFAULT &&
7307 g->anim_frames == 3 &&
7308 g->anim_delay == 2 &&
7309 g->anim_mode & ANIM_LINEAR);
7310 int sync_frame = (i == Xdrip_stretch ? 7 :
7311 i == Xdrip_stretchB ? 7 :
7312 i == Ydrip_s2 ? j + 8 :
7313 i == Ydrip_s2B ? j + 8 :
7322 i == Xfake_acid_1 ? 0 :
7323 i == Xfake_acid_2 ? 10 :
7324 i == Xfake_acid_3 ? 20 :
7325 i == Xfake_acid_4 ? 30 :
7326 i == Xfake_acid_5 ? 40 :
7327 i == Xfake_acid_6 ? 50 :
7328 i == Xfake_acid_7 ? 60 :
7329 i == Xfake_acid_8 ? 70 :
7331 i == Xball_2B ? j + 8 :
7332 i == Yball_eat ? j + 1 :
7333 i == Ykey_1_eat ? j + 1 :
7334 i == Ykey_2_eat ? j + 1 :
7335 i == Ykey_3_eat ? j + 1 :
7336 i == Ykey_4_eat ? j + 1 :
7337 i == Ykey_5_eat ? j + 1 :
7338 i == Ykey_6_eat ? j + 1 :
7339 i == Ykey_7_eat ? j + 1 :
7340 i == Ykey_8_eat ? j + 1 :
7341 i == Ylenses_eat ? j + 1 :
7342 i == Ymagnify_eat ? j + 1 :
7343 i == Ygrass_eat ? j + 1 :
7344 i == Ydirt_eat ? j + 1 :
7345 i == Xamoeba_1 ? 0 :
7346 i == Xamoeba_2 ? 1 :
7347 i == Xamoeba_3 ? 2 :
7348 i == Xamoeba_4 ? 3 :
7349 i == Xamoeba_5 ? 0 :
7350 i == Xamoeba_6 ? 1 :
7351 i == Xamoeba_7 ? 2 :
7352 i == Xamoeba_8 ? 3 :
7353 i == Xexit_2 ? j + 8 :
7354 i == Xexit_3 ? j + 16 :
7355 i == Xdynamite_1 ? 0 :
7356 i == Xdynamite_2 ? 8 :
7357 i == Xdynamite_3 ? 16 :
7358 i == Xdynamite_4 ? 24 :
7359 i == Xsand_stonein_1 ? j + 1 :
7360 i == Xsand_stonein_2 ? j + 9 :
7361 i == Xsand_stonein_3 ? j + 17 :
7362 i == Xsand_stonein_4 ? j + 25 :
7363 i == Xsand_stoneout_1 && j == 0 ? 0 :
7364 i == Xsand_stoneout_1 && j == 1 ? 0 :
7365 i == Xsand_stoneout_1 && j == 2 ? 1 :
7366 i == Xsand_stoneout_1 && j == 3 ? 2 :
7367 i == Xsand_stoneout_1 && j == 4 ? 2 :
7368 i == Xsand_stoneout_1 && j == 5 ? 3 :
7369 i == Xsand_stoneout_1 && j == 6 ? 4 :
7370 i == Xsand_stoneout_1 && j == 7 ? 4 :
7371 i == Xsand_stoneout_2 && j == 0 ? 5 :
7372 i == Xsand_stoneout_2 && j == 1 ? 6 :
7373 i == Xsand_stoneout_2 && j == 2 ? 7 :
7374 i == Xsand_stoneout_2 && j == 3 ? 8 :
7375 i == Xsand_stoneout_2 && j == 4 ? 9 :
7376 i == Xsand_stoneout_2 && j == 5 ? 11 :
7377 i == Xsand_stoneout_2 && j == 6 ? 13 :
7378 i == Xsand_stoneout_2 && j == 7 ? 15 :
7379 i == Xboom_bug && j == 1 ? 2 :
7380 i == Xboom_bug && j == 2 ? 2 :
7381 i == Xboom_bug && j == 3 ? 4 :
7382 i == Xboom_bug && j == 4 ? 4 :
7383 i == Xboom_bug && j == 5 ? 2 :
7384 i == Xboom_bug && j == 6 ? 2 :
7385 i == Xboom_bug && j == 7 ? 0 :
7386 i == Xboom_bomb && j == 1 ? 2 :
7387 i == Xboom_bomb && j == 2 ? 2 :
7388 i == Xboom_bomb && j == 3 ? 4 :
7389 i == Xboom_bomb && j == 4 ? 4 :
7390 i == Xboom_bomb && j == 5 ? 2 :
7391 i == Xboom_bomb && j == 6 ? 2 :
7392 i == Xboom_bomb && j == 7 ? 0 :
7393 i == Xboom_android && j == 7 ? 6 :
7394 i == Xboom_1 && j == 1 ? 2 :
7395 i == Xboom_1 && j == 2 ? 2 :
7396 i == Xboom_1 && j == 3 ? 4 :
7397 i == Xboom_1 && j == 4 ? 4 :
7398 i == Xboom_1 && j == 5 ? 6 :
7399 i == Xboom_1 && j == 6 ? 6 :
7400 i == Xboom_1 && j == 7 ? 8 :
7401 i == Xboom_2 && j == 0 ? 8 :
7402 i == Xboom_2 && j == 1 ? 8 :
7403 i == Xboom_2 && j == 2 ? 10 :
7404 i == Xboom_2 && j == 3 ? 10 :
7405 i == Xboom_2 && j == 4 ? 10 :
7406 i == Xboom_2 && j == 5 ? 12 :
7407 i == Xboom_2 && j == 6 ? 12 :
7408 i == Xboom_2 && j == 7 ? 12 :
7409 special_animation && j == 4 ? 3 :
7410 effective_action != action ? 0 :
7414 Bitmap *debug_bitmap = g_em->bitmap;
7415 int debug_src_x = g_em->src_x;
7416 int debug_src_y = g_em->src_y;
7419 int frame = getAnimationFrame(g->anim_frames,
7422 g->anim_start_frame,
7425 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
7426 g->double_movement && is_backside);
7428 g_em->bitmap = src_bitmap;
7429 g_em->src_x = src_x;
7430 g_em->src_y = src_y;
7431 g_em->src_offset_x = 0;
7432 g_em->src_offset_y = 0;
7433 g_em->dst_offset_x = 0;
7434 g_em->dst_offset_y = 0;
7435 g_em->width = TILEX;
7436 g_em->height = TILEY;
7438 g_em->preserve_background = FALSE;
7440 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
7443 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
7444 effective_action == ACTION_MOVING ||
7445 effective_action == ACTION_PUSHING ||
7446 effective_action == ACTION_EATING)) ||
7447 (!has_action_graphics && (effective_action == ACTION_FILLING ||
7448 effective_action == ACTION_EMPTYING)))
7451 (effective_action == ACTION_FALLING ||
7452 effective_action == ACTION_FILLING ||
7453 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
7454 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
7455 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
7456 int num_steps = (i == Ydrip_s1 ? 16 :
7457 i == Ydrip_s1B ? 16 :
7458 i == Ydrip_s2 ? 16 :
7459 i == Ydrip_s2B ? 16 :
7460 i == Xsand_stonein_1 ? 32 :
7461 i == Xsand_stonein_2 ? 32 :
7462 i == Xsand_stonein_3 ? 32 :
7463 i == Xsand_stonein_4 ? 32 :
7464 i == Xsand_stoneout_1 ? 16 :
7465 i == Xsand_stoneout_2 ? 16 : 8);
7466 int cx = ABS(dx) * (TILEX / num_steps);
7467 int cy = ABS(dy) * (TILEY / num_steps);
7468 int step_frame = (i == Ydrip_s2 ? j + 8 :
7469 i == Ydrip_s2B ? j + 8 :
7470 i == Xsand_stonein_2 ? j + 8 :
7471 i == Xsand_stonein_3 ? j + 16 :
7472 i == Xsand_stonein_4 ? j + 24 :
7473 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
7474 int step = (is_backside ? step_frame : num_steps - step_frame);
7476 if (is_backside) /* tile where movement starts */
7478 if (dx < 0 || dy < 0)
7480 g_em->src_offset_x = cx * step;
7481 g_em->src_offset_y = cy * step;
7485 g_em->dst_offset_x = cx * step;
7486 g_em->dst_offset_y = cy * step;
7489 else /* tile where movement ends */
7491 if (dx < 0 || dy < 0)
7493 g_em->dst_offset_x = cx * step;
7494 g_em->dst_offset_y = cy * step;
7498 g_em->src_offset_x = cx * step;
7499 g_em->src_offset_y = cy * step;
7503 g_em->width = TILEX - cx * step;
7504 g_em->height = TILEY - cy * step;
7507 /* create unique graphic identifier to decide if tile must be redrawn */
7508 /* bit 31 - 16 (16 bit): EM style graphic
7509 bit 15 - 12 ( 4 bit): EM style frame
7510 bit 11 - 6 ( 6 bit): graphic width
7511 bit 5 - 0 ( 6 bit): graphic height */
7512 g_em->unique_identifier =
7513 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
7517 /* skip check for EMC elements not contained in original EMC artwork */
7518 if (element == EL_EMC_FAKE_ACID)
7521 if (g_em->bitmap != debug_bitmap ||
7522 g_em->src_x != debug_src_x ||
7523 g_em->src_y != debug_src_y ||
7524 g_em->src_offset_x != 0 ||
7525 g_em->src_offset_y != 0 ||
7526 g_em->dst_offset_x != 0 ||
7527 g_em->dst_offset_y != 0 ||
7528 g_em->width != TILEX ||
7529 g_em->height != TILEY)
7531 static int last_i = -1;
7539 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
7540 i, element, element_info[element].token_name,
7541 element_action_info[effective_action].suffix, direction);
7543 if (element != effective_element)
7544 printf(" [%d ('%s')]",
7546 element_info[effective_element].token_name);
7550 if (g_em->bitmap != debug_bitmap)
7551 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
7552 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
7554 if (g_em->src_x != debug_src_x ||
7555 g_em->src_y != debug_src_y)
7556 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
7557 j, (is_backside ? 'B' : 'F'),
7558 g_em->src_x, g_em->src_y,
7559 g_em->src_x / 32, g_em->src_y / 32,
7560 debug_src_x, debug_src_y,
7561 debug_src_x / 32, debug_src_y / 32);
7563 if (g_em->src_offset_x != 0 ||
7564 g_em->src_offset_y != 0 ||
7565 g_em->dst_offset_x != 0 ||
7566 g_em->dst_offset_y != 0)
7567 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
7569 g_em->src_offset_x, g_em->src_offset_y,
7570 g_em->dst_offset_x, g_em->dst_offset_y);
7572 if (g_em->width != TILEX ||
7573 g_em->height != TILEY)
7574 printf(" %d (%d): size %d,%d should be %d,%d\n",
7576 g_em->width, g_em->height, TILEX, TILEY);
7578 num_em_gfx_errors++;
7585 for (i = 0; i < TILE_MAX; i++)
7587 for (j = 0; j < 8; j++)
7589 int element = object_mapping[i].element_rnd;
7590 int action = object_mapping[i].action;
7591 int direction = object_mapping[i].direction;
7592 boolean is_backside = object_mapping[i].is_backside;
7593 int graphic_action = el_act_dir2img(element, action, direction);
7594 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
7596 if ((action == ACTION_SMASHED_BY_ROCK ||
7597 action == ACTION_SMASHED_BY_SPRING ||
7598 action == ACTION_EATING) &&
7599 graphic_action == graphic_default)
7601 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
7602 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
7603 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
7604 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
7607 /* no separate animation for "smashed by rock" -- use rock instead */
7608 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7609 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
7611 g_em->bitmap = g_xx->bitmap;
7612 g_em->src_x = g_xx->src_x;
7613 g_em->src_y = g_xx->src_y;
7614 g_em->src_offset_x = g_xx->src_offset_x;
7615 g_em->src_offset_y = g_xx->src_offset_y;
7616 g_em->dst_offset_x = g_xx->dst_offset_x;
7617 g_em->dst_offset_y = g_xx->dst_offset_y;
7618 g_em->width = g_xx->width;
7619 g_em->height = g_xx->height;
7620 g_em->unique_identifier = g_xx->unique_identifier;
7623 g_em->preserve_background = TRUE;
7628 for (p = 0; p < MAX_PLAYERS; p++)
7630 for (i = 0; i < SPR_MAX; i++)
7632 int element = player_mapping[p][i].element_rnd;
7633 int action = player_mapping[p][i].action;
7634 int direction = player_mapping[p][i].direction;
7636 for (j = 0; j < 8; j++)
7638 int effective_element = element;
7639 int effective_action = action;
7640 int graphic = (direction == MV_NONE ?
7641 el_act2img(effective_element, effective_action) :
7642 el_act_dir2img(effective_element, effective_action,
7644 struct GraphicInfo *g = &graphic_info[graphic];
7645 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
7651 Bitmap *debug_bitmap = g_em->bitmap;
7652 int debug_src_x = g_em->src_x;
7653 int debug_src_y = g_em->src_y;
7656 int frame = getAnimationFrame(g->anim_frames,
7659 g->anim_start_frame,
7662 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
7664 g_em->bitmap = src_bitmap;
7665 g_em->src_x = src_x;
7666 g_em->src_y = src_y;
7667 g_em->src_offset_x = 0;
7668 g_em->src_offset_y = 0;
7669 g_em->dst_offset_x = 0;
7670 g_em->dst_offset_y = 0;
7671 g_em->width = TILEX;
7672 g_em->height = TILEY;
7676 /* skip check for EMC elements not contained in original EMC artwork */
7677 if (element == EL_PLAYER_3 ||
7678 element == EL_PLAYER_4)
7681 if (g_em->bitmap != debug_bitmap ||
7682 g_em->src_x != debug_src_x ||
7683 g_em->src_y != debug_src_y)
7685 static int last_i = -1;
7693 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
7694 p, i, element, element_info[element].token_name,
7695 element_action_info[effective_action].suffix, direction);
7697 if (element != effective_element)
7698 printf(" [%d ('%s')]",
7700 element_info[effective_element].token_name);
7704 if (g_em->bitmap != debug_bitmap)
7705 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
7706 j, (int)(g_em->bitmap), (int)(debug_bitmap));
7708 if (g_em->src_x != debug_src_x ||
7709 g_em->src_y != debug_src_y)
7710 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
7712 g_em->src_x, g_em->src_y,
7713 g_em->src_x / 32, g_em->src_y / 32,
7714 debug_src_x, debug_src_y,
7715 debug_src_x / 32, debug_src_y / 32);
7717 num_em_gfx_errors++;
7727 printf("::: [%d errors found]\n", num_em_gfx_errors);
7733 void CheckSaveEngineSnapshot_EM(byte action[MAX_PLAYERS], int frame,
7734 boolean any_player_moving,
7735 boolean any_player_snapping,
7736 boolean any_player_dropping)
7738 static boolean player_was_waiting = TRUE;
7740 if (frame == 0 && !any_player_dropping)
7742 if (!player_was_waiting)
7744 if (!SaveEngineSnapshotToList())
7747 player_was_waiting = TRUE;
7750 else if (any_player_moving || any_player_snapping || any_player_dropping)
7752 player_was_waiting = FALSE;
7756 void CheckSaveEngineSnapshot_SP(boolean murphy_is_waiting,
7757 boolean murphy_is_dropping)
7759 static boolean player_was_waiting = TRUE;
7761 if (murphy_is_waiting)
7763 if (!player_was_waiting)
7765 if (!SaveEngineSnapshotToList())
7768 player_was_waiting = TRUE;
7773 player_was_waiting = FALSE;
7777 void CheckSingleStepMode_EM(byte action[MAX_PLAYERS], int frame,
7778 boolean any_player_moving,
7779 boolean any_player_snapping,
7780 boolean any_player_dropping)
7782 if (tape.single_step && tape.recording && !tape.pausing)
7783 if (frame == 0 && !any_player_dropping)
7784 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
7786 CheckSaveEngineSnapshot_EM(action, frame, any_player_moving,
7787 any_player_snapping, any_player_dropping);
7790 void CheckSingleStepMode_SP(boolean murphy_is_waiting,
7791 boolean murphy_is_dropping)
7793 if (tape.single_step && tape.recording && !tape.pausing)
7794 if (murphy_is_waiting)
7795 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
7797 CheckSaveEngineSnapshot_SP(murphy_is_waiting, murphy_is_dropping);
7800 void getGraphicSource_SP(struct GraphicInfo_SP *g_sp,
7801 int graphic, int sync_frame, int x, int y)
7803 int frame = getGraphicAnimationFrame(graphic, sync_frame);
7805 getGraphicSource(graphic, frame, &g_sp->bitmap, &g_sp->src_x, &g_sp->src_y);
7808 boolean isNextAnimationFrame_SP(int graphic, int sync_frame)
7810 return (IS_NEXT_FRAME(sync_frame, graphic));
7813 int getGraphicInfo_Delay(int graphic)
7815 return graphic_info[graphic].anim_delay;
7818 void PlayMenuSoundExt(int sound)
7820 if (sound == SND_UNDEFINED)
7823 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
7824 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
7827 if (IS_LOOP_SOUND(sound))
7828 PlaySoundLoop(sound);
7833 void PlayMenuSound()
7835 PlayMenuSoundExt(menu.sound[game_status]);
7838 void PlayMenuSoundStereo(int sound, int stereo_position)
7840 if (sound == SND_UNDEFINED)
7843 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
7844 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
7847 if (IS_LOOP_SOUND(sound))
7848 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
7850 PlaySoundStereo(sound, stereo_position);
7853 void PlayMenuSoundIfLoopExt(int sound)
7855 if (sound == SND_UNDEFINED)
7858 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
7859 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
7862 if (IS_LOOP_SOUND(sound))
7863 PlaySoundLoop(sound);
7866 void PlayMenuSoundIfLoop()
7868 PlayMenuSoundIfLoopExt(menu.sound[game_status]);
7871 void PlayMenuMusicExt(int music)
7873 if (music == MUS_UNDEFINED)
7876 if (!setup.sound_music)
7882 void PlayMenuMusic()
7884 PlayMenuMusicExt(menu.music[game_status]);
7887 void PlaySoundActivating()
7890 PlaySound(SND_MENU_ITEM_ACTIVATING);
7894 void PlaySoundSelecting()
7897 PlaySound(SND_MENU_ITEM_SELECTING);
7901 void ToggleFullscreenOrChangeWindowScalingIfNeeded()
7903 boolean change_fullscreen = (setup.fullscreen !=
7904 video.fullscreen_enabled);
7905 boolean change_fullscreen_mode = (video.fullscreen_enabled &&
7906 !strEqual(setup.fullscreen_mode,
7907 video.fullscreen_mode_current));
7908 boolean change_window_scaling_percent = (!video.fullscreen_enabled &&
7909 setup.window_scaling_percent !=
7910 video.window_scaling_percent);
7912 if (change_window_scaling_percent && video.fullscreen_enabled)
7915 if (!change_window_scaling_percent && !video.fullscreen_available)
7918 #if defined(TARGET_SDL2)
7919 if (change_window_scaling_percent)
7921 SDLSetWindowScaling(setup.window_scaling_percent);
7925 else if (change_fullscreen)
7927 SDLSetWindowFullscreen(setup.fullscreen);
7929 /* set setup value according to successfully changed fullscreen mode */
7930 setup.fullscreen = video.fullscreen_enabled;
7936 if (change_fullscreen ||
7937 change_fullscreen_mode ||
7938 change_window_scaling_percent)
7940 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
7942 /* save backbuffer content which gets lost when toggling fullscreen mode */
7943 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
7945 if (change_fullscreen_mode)
7947 /* keep fullscreen, but change fullscreen mode (screen resolution) */
7948 video.fullscreen_enabled = FALSE; /* force new fullscreen mode */
7951 if (change_window_scaling_percent)
7953 /* keep window mode, but change window scaling */
7954 video.fullscreen_enabled = TRUE; /* force new window scaling */
7957 /* toggle fullscreen */
7958 ChangeVideoModeIfNeeded(setup.fullscreen);
7960 /* set setup value according to successfully changed fullscreen mode */
7961 setup.fullscreen = video.fullscreen_enabled;
7963 /* restore backbuffer content from temporary backbuffer backup bitmap */
7964 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
7966 FreeBitmap(tmp_backbuffer);
7968 /* update visible window/screen */
7969 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
7973 void ChangeViewportPropertiesIfNeeded()
7975 int gfx_game_mode = game_status;
7976 int gfx_game_mode2 = (game_status == GAME_MODE_EDITOR ? GAME_MODE_DEFAULT :
7978 struct RectWithBorder *vp_playfield = &viewport.playfield[gfx_game_mode];
7979 struct RectWithBorder *vp_door_1 = &viewport.door_1[gfx_game_mode];
7980 struct RectWithBorder *vp_door_2 = &viewport.door_2[gfx_game_mode2];
7981 struct RectWithBorder *vp_door_3 = &viewport.door_2[GAME_MODE_EDITOR];
7982 int border_size = vp_playfield->border_size;
7983 int new_sx = vp_playfield->x + border_size;
7984 int new_sy = vp_playfield->y + border_size;
7985 int new_sxsize = vp_playfield->width - 2 * border_size;
7986 int new_sysize = vp_playfield->height - 2 * border_size;
7987 int new_real_sx = vp_playfield->x;
7988 int new_real_sy = vp_playfield->y;
7989 int new_full_sxsize = vp_playfield->width;
7990 int new_full_sysize = vp_playfield->height;
7991 int new_dx = vp_door_1->x;
7992 int new_dy = vp_door_1->y;
7993 int new_dxsize = vp_door_1->width;
7994 int new_dysize = vp_door_1->height;
7995 int new_vx = vp_door_2->x;
7996 int new_vy = vp_door_2->y;
7997 int new_vxsize = vp_door_2->width;
7998 int new_vysize = vp_door_2->height;
7999 int new_ex = vp_door_3->x;
8000 int new_ey = vp_door_3->y;
8001 int new_exsize = vp_door_3->width;
8002 int new_eysize = vp_door_3->height;
8003 int new_tilesize_var =
8004 (setup.small_game_graphics ? MINI_TILESIZE : game.tile_size);
8006 int tilesize = (gfx_game_mode == GAME_MODE_PLAYING ? new_tilesize_var :
8007 gfx_game_mode == GAME_MODE_EDITOR ? MINI_TILESIZE : TILESIZE);
8008 int new_scr_fieldx = new_sxsize / tilesize;
8009 int new_scr_fieldy = new_sysize / tilesize;
8010 int new_scr_fieldx_buffers = new_sxsize / new_tilesize_var;
8011 int new_scr_fieldy_buffers = new_sysize / new_tilesize_var;
8012 boolean init_gfx_buffers = FALSE;
8013 boolean init_video_buffer = FALSE;
8014 boolean init_gadgets_and_toons = FALSE;
8015 boolean init_em_graphics = FALSE;
8016 boolean drawing_area_changed = FALSE;
8018 if (viewport.window.width != WIN_XSIZE ||
8019 viewport.window.height != WIN_YSIZE)
8021 WIN_XSIZE = viewport.window.width;
8022 WIN_YSIZE = viewport.window.height;
8024 init_video_buffer = TRUE;
8025 init_gfx_buffers = TRUE;
8027 // printf("::: video: init_video_buffer, init_gfx_buffers\n");
8030 if (new_scr_fieldx != SCR_FIELDX ||
8031 new_scr_fieldy != SCR_FIELDY)
8033 /* this always toggles between MAIN and GAME when using small tile size */
8035 SCR_FIELDX = new_scr_fieldx;
8036 SCR_FIELDY = new_scr_fieldy;
8038 // printf("::: new_scr_fieldx != SCR_FIELDX ...\n");
8049 new_sxsize != SXSIZE ||
8050 new_sysize != SYSIZE ||
8051 new_dxsize != DXSIZE ||
8052 new_dysize != DYSIZE ||
8053 new_vxsize != VXSIZE ||
8054 new_vysize != VYSIZE ||
8055 new_exsize != EXSIZE ||
8056 new_eysize != EYSIZE ||
8057 new_real_sx != REAL_SX ||
8058 new_real_sy != REAL_SY ||
8059 new_full_sxsize != FULL_SXSIZE ||
8060 new_full_sysize != FULL_SYSIZE ||
8061 new_tilesize_var != TILESIZE_VAR
8064 if (new_tilesize_var != TILESIZE_VAR)
8066 // printf("::: new_tilesize_var != TILESIZE_VAR\n");
8068 // changing tile size invalidates scroll values of engine snapshots
8069 FreeEngineSnapshotSingle();
8071 // changing tile size requires update of graphic mapping for EM engine
8072 init_em_graphics = TRUE;
8077 new_sxsize != SXSIZE ||
8078 new_sysize != SYSIZE ||
8079 new_real_sx != REAL_SX ||
8080 new_real_sy != REAL_SY ||
8081 new_full_sxsize != FULL_SXSIZE ||
8082 new_full_sysize != FULL_SYSIZE)
8084 if (!init_video_buffer)
8085 drawing_area_changed = TRUE;
8096 SXSIZE = new_sxsize;
8097 SYSIZE = new_sysize;
8098 DXSIZE = new_dxsize;
8099 DYSIZE = new_dysize;
8100 VXSIZE = new_vxsize;
8101 VYSIZE = new_vysize;
8102 EXSIZE = new_exsize;
8103 EYSIZE = new_eysize;
8104 REAL_SX = new_real_sx;
8105 REAL_SY = new_real_sy;
8106 FULL_SXSIZE = new_full_sxsize;
8107 FULL_SYSIZE = new_full_sysize;
8108 TILESIZE_VAR = new_tilesize_var;
8110 init_gfx_buffers = TRUE;
8111 init_gadgets_and_toons = TRUE;
8113 // printf("::: viewports: init_gfx_buffers\n");
8114 // printf("::: viewports: init_gadgets_and_toons\n");
8117 if (init_gfx_buffers)
8119 // printf("::: init_gfx_buffers\n");
8121 SCR_FIELDX = new_scr_fieldx_buffers;
8122 SCR_FIELDY = new_scr_fieldy_buffers;
8126 SCR_FIELDX = new_scr_fieldx;
8127 SCR_FIELDY = new_scr_fieldy;
8129 gfx.drawing_area_changed = drawing_area_changed;
8131 SetDrawDeactivationMask(REDRAW_NONE);
8132 SetDrawBackgroundMask(REDRAW_FIELD);
8135 if (init_video_buffer)
8137 // printf("::: init_video_buffer\n");
8139 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
8142 if (init_gadgets_and_toons)
8144 // printf("::: init_gadgets_and_toons\n");
8150 if (init_em_graphics)
8152 InitGraphicInfo_EM();