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);
858 SetDrawtoField(DRAW_BACKBUFFER);
862 void MarkTileDirty(int x, int y)
864 redraw_mask |= REDRAW_FIELD;
867 void SetBorderElement()
871 BorderElement = EL_EMPTY;
873 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
875 for (x = 0; x < lev_fieldx; x++)
877 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
878 BorderElement = EL_STEELWALL;
880 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
886 void FloodFillLevel(int from_x, int from_y, int fill_element,
887 short field[MAX_LEV_FIELDX][MAX_LEV_FIELDY],
888 int max_fieldx, int max_fieldy)
892 static int check[4][2] = { { -1, 0 }, { 0, -1 }, { 1, 0 }, { 0, 1 } };
893 static int safety = 0;
895 /* check if starting field still has the desired content */
896 if (field[from_x][from_y] == fill_element)
901 if (safety > max_fieldx * max_fieldy)
902 Error(ERR_EXIT, "Something went wrong in 'FloodFill()'. Please debug.");
904 old_element = field[from_x][from_y];
905 field[from_x][from_y] = fill_element;
907 for (i = 0; i < 4; i++)
909 x = from_x + check[i][0];
910 y = from_y + check[i][1];
912 if (IN_FIELD(x, y, max_fieldx, max_fieldy) && field[x][y] == old_element)
913 FloodFillLevel(x, y, fill_element, field, max_fieldx, max_fieldy);
919 void SetRandomAnimationValue(int x, int y)
921 gfx.anim_random_frame = GfxRandom[x][y];
924 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
926 /* animation synchronized with global frame counter, not move position */
927 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
928 sync_frame = FrameCounter;
930 return getAnimationFrame(graphic_info[graphic].anim_frames,
931 graphic_info[graphic].anim_delay,
932 graphic_info[graphic].anim_mode,
933 graphic_info[graphic].anim_start_frame,
937 void getSizedGraphicSourceExt(int graphic, int frame, int tilesize,
938 Bitmap **bitmap, int *x, int *y,
939 boolean get_backside)
941 struct GraphicInfo *g = &graphic_info[graphic];
942 Bitmap *src_bitmap = g->bitmap;
943 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
944 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
945 int tilesize_capped = MIN(MAX(1, tilesize), TILESIZE);
947 // if no in-game graphics defined, always use standard graphic size
948 if (g->bitmaps[IMG_BITMAP_GAME] == NULL)
951 if (tilesize == gfx.standard_tile_size)
952 src_bitmap = g->bitmaps[IMG_BITMAP_STANDARD];
953 else if (tilesize == game.tile_size)
954 src_bitmap = g->bitmaps[IMG_BITMAP_GAME];
956 src_bitmap = g->bitmaps[IMG_BITMAP_1x1 - log_2(tilesize_capped)];
958 if (g->offset_y == 0) /* frames are ordered horizontally */
960 int max_width = g->anim_frames_per_line * g->width;
961 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
963 src_x = pos % max_width;
964 src_y = src_y % g->height + pos / max_width * g->height;
966 else if (g->offset_x == 0) /* frames are ordered vertically */
968 int max_height = g->anim_frames_per_line * g->height;
969 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
971 src_x = src_x % g->width + pos / max_height * g->width;
972 src_y = pos % max_height;
974 else /* frames are ordered diagonally */
976 src_x = src_x + frame * g->offset_x;
977 src_y = src_y + frame * g->offset_y;
980 *bitmap = src_bitmap;
981 *x = src_x * tilesize / TILESIZE;
982 *y = src_y * tilesize / TILESIZE;
985 void getFixedGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
986 int *x, int *y, boolean get_backside)
988 getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y,
992 void getSizedGraphicSource(int graphic, int frame, int tilesize,
993 Bitmap **bitmap, int *x, int *y)
995 getSizedGraphicSourceExt(graphic, frame, tilesize, bitmap, x, y, FALSE);
998 void getFixedGraphicSource(int graphic, int frame,
999 Bitmap **bitmap, int *x, int *y)
1001 getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y, FALSE);
1004 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1006 getSizedGraphicSource(graphic, 0, MINI_TILESIZE, bitmap, x, y);
1009 inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1010 int *x, int *y, boolean get_backside)
1012 struct GraphicInfo *g = &graphic_info[graphic];
1013 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
1014 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
1016 if (TILESIZE_VAR != TILESIZE)
1017 return getSizedGraphicSourceExt(graphic, frame, TILESIZE_VAR, bitmap, x, y,
1020 *bitmap = g->bitmap;
1022 if (g->offset_y == 0) /* frames are ordered horizontally */
1024 int max_width = g->anim_frames_per_line * g->width;
1025 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
1027 *x = pos % max_width;
1028 *y = src_y % g->height + pos / max_width * g->height;
1030 else if (g->offset_x == 0) /* frames are ordered vertically */
1032 int max_height = g->anim_frames_per_line * g->height;
1033 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
1035 *x = src_x % g->width + pos / max_height * g->width;
1036 *y = pos % max_height;
1038 else /* frames are ordered diagonally */
1040 *x = src_x + frame * g->offset_x;
1041 *y = src_y + frame * g->offset_y;
1045 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
1047 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
1050 void DrawGraphic(int x, int y, int graphic, int frame)
1053 if (!IN_SCR_FIELD(x, y))
1055 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1056 printf("DrawGraphic(): This should never happen!\n");
1061 DrawGraphicExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR, graphic,
1064 MarkTileDirty(x, y);
1067 void DrawFixedGraphic(int x, int y, int graphic, int frame)
1070 if (!IN_SCR_FIELD(x, y))
1072 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1073 printf("DrawGraphic(): This should never happen!\n");
1078 DrawFixedGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic,
1080 MarkTileDirty(x, y);
1083 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1089 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1091 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX_VAR, TILEY_VAR, x, y);
1094 void DrawFixedGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1100 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1101 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
1104 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
1107 if (!IN_SCR_FIELD(x, y))
1109 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1110 printf("DrawGraphicThruMask(): This should never happen!\n");
1115 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
1118 MarkTileDirty(x, y);
1121 void DrawFixedGraphicThruMask(int x, int y, int graphic, int frame)
1124 if (!IN_SCR_FIELD(x, y))
1126 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1127 printf("DrawGraphicThruMask(): This should never happen!\n");
1132 DrawFixedGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
1134 MarkTileDirty(x, y);
1137 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
1143 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1145 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX_VAR, TILEY_VAR,
1149 void DrawFixedGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y,
1150 int graphic, int frame)
1152 struct GraphicInfo *g = &graphic_info[graphic];
1156 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1158 BlitBitmapMasked(src_bitmap, d, src_x, src_y, g->width, g->height,
1162 void DrawSizedGraphic(int x, int y, int graphic, int frame, int tilesize)
1164 DrawSizedGraphicExt(drawto, SX + x * tilesize, SY + y * tilesize, graphic,
1166 MarkTileDirty(x / tilesize, y / tilesize);
1169 void DrawSizedGraphicExt(DrawBuffer *d, int x, int y, int graphic, int frame,
1175 getSizedGraphicSource(graphic, frame, tilesize, &src_bitmap, &src_x, &src_y);
1176 BlitBitmap(src_bitmap, d, src_x, src_y, tilesize, tilesize, x, y);
1179 void DrawMiniGraphic(int x, int y, int graphic)
1181 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
1182 MarkTileDirty(x / 2, y / 2);
1185 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
1190 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1191 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
1194 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
1195 int graphic, int frame,
1196 int cut_mode, int mask_mode)
1201 int width = TILEX, height = TILEY;
1204 if (dx || dy) /* shifted graphic */
1206 if (x < BX1) /* object enters playfield from the left */
1213 else if (x > BX2) /* object enters playfield from the right */
1219 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
1225 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
1227 else if (dx) /* general horizontal movement */
1228 MarkTileDirty(x + SIGN(dx), y);
1230 if (y < BY1) /* object enters playfield from the top */
1232 if (cut_mode==CUT_BELOW) /* object completely above top border */
1240 else if (y > BY2) /* object enters playfield from the bottom */
1246 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
1252 else if (dy > 0 && cut_mode == CUT_ABOVE)
1254 if (y == BY2) /* object completely above bottom border */
1260 MarkTileDirty(x, y + 1);
1261 } /* object leaves playfield to the bottom */
1262 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1264 else if (dy) /* general vertical movement */
1265 MarkTileDirty(x, y + SIGN(dy));
1269 if (!IN_SCR_FIELD(x, y))
1271 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1272 printf("DrawGraphicShifted(): This should never happen!\n");
1277 width = width * TILESIZE_VAR / TILESIZE;
1278 height = height * TILESIZE_VAR / TILESIZE;
1279 cx = cx * TILESIZE_VAR / TILESIZE;
1280 cy = cy * TILESIZE_VAR / TILESIZE;
1281 dx = dx * TILESIZE_VAR / TILESIZE;
1282 dy = dy * TILESIZE_VAR / TILESIZE;
1284 if (width > 0 && height > 0)
1286 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1291 dst_x = FX + x * TILEX_VAR + dx;
1292 dst_y = FY + y * TILEY_VAR + dy;
1294 if (mask_mode == USE_MASKING)
1295 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1298 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1301 MarkTileDirty(x, y);
1305 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
1306 int graphic, int frame,
1307 int cut_mode, int mask_mode)
1312 int width = TILEX_VAR, height = TILEY_VAR;
1315 int x2 = x + SIGN(dx);
1316 int y2 = y + SIGN(dy);
1318 /* movement with two-tile animations must be sync'ed with movement position,
1319 not with current GfxFrame (which can be higher when using slow movement) */
1320 int anim_pos = (dx ? ABS(dx) : ABS(dy));
1321 int anim_frames = graphic_info[graphic].anim_frames;
1323 /* (we also need anim_delay here for movement animations with less frames) */
1324 int anim_delay = graphic_info[graphic].anim_delay;
1325 int sync_frame = anim_pos * anim_frames * anim_delay / TILESIZE;
1327 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
1328 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
1330 /* re-calculate animation frame for two-tile movement animation */
1331 frame = getGraphicAnimationFrame(graphic, sync_frame);
1333 /* check if movement start graphic inside screen area and should be drawn */
1334 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
1336 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
1338 dst_x = FX + x1 * TILEX_VAR;
1339 dst_y = FY + y1 * TILEY_VAR;
1341 if (mask_mode == USE_MASKING)
1342 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1345 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1348 MarkTileDirty(x1, y1);
1351 /* check if movement end graphic inside screen area and should be drawn */
1352 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
1354 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
1356 dst_x = FX + x2 * TILEX_VAR;
1357 dst_y = FY + y2 * TILEY_VAR;
1359 if (mask_mode == USE_MASKING)
1360 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1363 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1366 MarkTileDirty(x2, y2);
1370 static void DrawGraphicShifted(int x, int y, int dx, int dy,
1371 int graphic, int frame,
1372 int cut_mode, int mask_mode)
1376 DrawGraphic(x, y, graphic, frame);
1381 if (graphic_info[graphic].double_movement) /* EM style movement images */
1382 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1384 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1387 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1388 int frame, int cut_mode)
1390 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
1393 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1394 int cut_mode, int mask_mode)
1396 int lx = LEVELX(x), ly = LEVELY(y);
1400 if (IN_LEV_FIELD(lx, ly))
1402 SetRandomAnimationValue(lx, ly);
1404 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
1405 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1407 /* do not use double (EM style) movement graphic when not moving */
1408 if (graphic_info[graphic].double_movement && !dx && !dy)
1410 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
1411 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1414 else /* border element */
1416 graphic = el2img(element);
1417 frame = getGraphicAnimationFrame(graphic, -1);
1420 if (element == EL_EXPANDABLE_WALL)
1422 boolean left_stopped = FALSE, right_stopped = FALSE;
1424 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1425 left_stopped = TRUE;
1426 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1427 right_stopped = TRUE;
1429 if (left_stopped && right_stopped)
1431 else if (left_stopped)
1433 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1434 frame = graphic_info[graphic].anim_frames - 1;
1436 else if (right_stopped)
1438 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1439 frame = graphic_info[graphic].anim_frames - 1;
1444 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1445 else if (mask_mode == USE_MASKING)
1446 DrawGraphicThruMask(x, y, graphic, frame);
1448 DrawGraphic(x, y, graphic, frame);
1451 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1452 int cut_mode, int mask_mode)
1454 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1455 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1456 cut_mode, mask_mode);
1459 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1462 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1465 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1468 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1471 void DrawLevelElementThruMask(int x, int y, int element)
1473 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1476 void DrawLevelFieldThruMask(int x, int y)
1478 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1481 /* !!! implementation of quicksand is totally broken !!! */
1482 #define IS_CRUMBLED_TILE(x, y, e) \
1483 (GFX_CRUMBLED(e) && (!IN_LEV_FIELD(x, y) || \
1484 !IS_MOVING(x, y) || \
1485 (e) == EL_QUICKSAND_EMPTYING || \
1486 (e) == EL_QUICKSAND_FAST_EMPTYING))
1488 static void DrawLevelFieldCrumbledInnerCorners(int x, int y, int dx, int dy,
1493 int width, height, cx, cy;
1494 int sx = SCREENX(x), sy = SCREENY(y);
1495 int crumbled_border_size = graphic_info[graphic].border_size;
1498 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1500 for (i = 1; i < 4; i++)
1502 int dxx = (i & 1 ? dx : 0);
1503 int dyy = (i & 2 ? dy : 0);
1506 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1509 /* check if neighbour field is of same crumble type */
1510 boolean same = (IS_CRUMBLED_TILE(xx, yy, element) &&
1511 graphic_info[graphic].class ==
1512 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class);
1514 /* return if check prevents inner corner */
1515 if (same == (dxx == dx && dyy == dy))
1519 /* if we reach this point, we have an inner corner */
1521 getGraphicSource(graphic, 1, &src_bitmap, &src_x, &src_y);
1523 width = crumbled_border_size * TILESIZE_VAR / TILESIZE;
1524 height = crumbled_border_size * TILESIZE_VAR / TILESIZE;
1525 cx = (dx > 0 ? TILESIZE_VAR - width : 0);
1526 cy = (dy > 0 ? TILESIZE_VAR - height : 0);
1528 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1529 width, height, FX + sx * TILEX_VAR + cx, FY + sy * TILEY_VAR + cy);
1532 static void DrawLevelFieldCrumbledBorders(int x, int y, int graphic, int frame,
1537 int width, height, bx, by, cx, cy;
1538 int sx = SCREENX(x), sy = SCREENY(y);
1539 int crumbled_border_size = graphic_info[graphic].border_size;
1540 int crumbled_border_size_var = crumbled_border_size * TILESIZE_VAR / TILESIZE;
1541 int crumbled_border_pos_var = TILESIZE_VAR - crumbled_border_size_var;
1544 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1546 /* draw simple, sloppy, non-corner-accurate crumbled border */
1548 width = (dir == 1 || dir == 2 ? crumbled_border_size_var : TILESIZE_VAR);
1549 height = (dir == 0 || dir == 3 ? crumbled_border_size_var : TILESIZE_VAR);
1550 cx = (dir == 2 ? crumbled_border_pos_var : 0);
1551 cy = (dir == 3 ? crumbled_border_pos_var : 0);
1553 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy, width, height,
1554 FX + sx * TILEX_VAR + cx,
1555 FY + sy * TILEY_VAR + cy);
1557 /* (remaining middle border part must be at least as big as corner part) */
1558 if (!(graphic_info[graphic].style & STYLE_ACCURATE_BORDERS) ||
1559 crumbled_border_size >= TILESIZE / 3)
1562 /* correct corners of crumbled border, if needed */
1564 for (i = -1; i <= 1; i += 2)
1566 int xx = x + (dir == 0 || dir == 3 ? i : 0);
1567 int yy = y + (dir == 1 || dir == 2 ? i : 0);
1568 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1571 /* check if neighbour field is of same crumble type */
1572 if (IS_CRUMBLED_TILE(xx, yy, element) &&
1573 graphic_info[graphic].class ==
1574 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1576 /* no crumbled corner, but continued crumbled border */
1578 int c1 = (dir == 2 || dir == 3 ? crumbled_border_pos_var : 0);
1579 int c2 = (i == 1 ? crumbled_border_pos_var : 0);
1580 int b1 = (i == 1 ? crumbled_border_size_var :
1581 TILESIZE_VAR - 2 * crumbled_border_size_var);
1583 width = crumbled_border_size_var;
1584 height = crumbled_border_size_var;
1586 if (dir == 1 || dir == 2)
1601 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
1603 FX + sx * TILEX_VAR + cx,
1604 FY + sy * TILEY_VAR + cy);
1609 static void DrawLevelFieldCrumbledExt(int x, int y, int graphic, int frame)
1611 int sx = SCREENX(x), sy = SCREENY(y);
1614 static int xy[4][2] =
1622 if (!IN_LEV_FIELD(x, y))
1625 element = TILE_GFX_ELEMENT(x, y);
1627 /* crumble field itself */
1628 if (IS_CRUMBLED_TILE(x, y, element))
1630 if (!IN_SCR_FIELD(sx, sy))
1633 for (i = 0; i < 4; i++)
1635 int xx = x + xy[i][0];
1636 int yy = y + xy[i][1];
1638 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1641 /* check if neighbour field is of same crumble type */
1642 if (IS_CRUMBLED_TILE(xx, yy, element) &&
1643 graphic_info[graphic].class ==
1644 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1647 DrawLevelFieldCrumbledBorders(x, y, graphic, frame, i);
1650 if ((graphic_info[graphic].style & STYLE_INNER_CORNERS) &&
1651 graphic_info[graphic].anim_frames == 2)
1653 for (i = 0; i < 4; i++)
1655 int dx = (i & 1 ? +1 : -1);
1656 int dy = (i & 2 ? +1 : -1);
1658 DrawLevelFieldCrumbledInnerCorners(x, y, dx, dy, graphic);
1662 MarkTileDirty(sx, sy);
1664 else /* center field not crumbled -- crumble neighbour fields */
1666 for (i = 0; i < 4; i++)
1668 int xx = x + xy[i][0];
1669 int yy = y + xy[i][1];
1670 int sxx = sx + xy[i][0];
1671 int syy = sy + xy[i][1];
1673 if (!IN_LEV_FIELD(xx, yy) ||
1674 !IN_SCR_FIELD(sxx, syy))
1677 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
1680 element = TILE_GFX_ELEMENT(xx, yy);
1682 if (!IS_CRUMBLED_TILE(xx, yy, element))
1685 graphic = el_act2crm(element, ACTION_DEFAULT);
1687 DrawLevelFieldCrumbledBorders(xx, yy, graphic, 0, 3 - i);
1689 MarkTileDirty(sxx, syy);
1694 void DrawLevelFieldCrumbled(int x, int y)
1698 if (!IN_LEV_FIELD(x, y))
1701 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1702 GfxElement[x][y] != EL_UNDEFINED &&
1703 GFX_CRUMBLED(GfxElement[x][y]))
1705 DrawLevelFieldCrumbledDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
1710 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
1712 DrawLevelFieldCrumbledExt(x, y, graphic, 0);
1715 void DrawLevelFieldCrumbledDigging(int x, int y, int direction,
1718 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1719 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1720 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1721 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1722 int sx = SCREENX(x), sy = SCREENY(y);
1724 DrawGraphic(sx, sy, graphic1, frame1);
1725 DrawLevelFieldCrumbledExt(x, y, graphic2, frame2);
1728 void DrawLevelFieldCrumbledNeighbours(int x, int y)
1730 int sx = SCREENX(x), sy = SCREENY(y);
1731 static int xy[4][2] =
1740 for (i = 0; i < 4; i++)
1742 int xx = x + xy[i][0];
1743 int yy = y + xy[i][1];
1744 int sxx = sx + xy[i][0];
1745 int syy = sy + xy[i][1];
1747 if (!IN_LEV_FIELD(xx, yy) ||
1748 !IN_SCR_FIELD(sxx, syy) ||
1749 !GFX_CRUMBLED(Feld[xx][yy]) ||
1753 DrawLevelField(xx, yy);
1757 static int getBorderElement(int x, int y)
1761 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1762 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1763 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1764 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1765 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1766 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1767 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1769 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1770 int steel_position = (x == -1 && y == -1 ? 0 :
1771 x == lev_fieldx && y == -1 ? 1 :
1772 x == -1 && y == lev_fieldy ? 2 :
1773 x == lev_fieldx && y == lev_fieldy ? 3 :
1774 x == -1 || x == lev_fieldx ? 4 :
1775 y == -1 || y == lev_fieldy ? 5 : 6);
1777 return border[steel_position][steel_type];
1780 void DrawScreenElement(int x, int y, int element)
1782 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1783 DrawLevelFieldCrumbled(LEVELX(x), LEVELY(y));
1786 void DrawLevelElement(int x, int y, int element)
1788 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1789 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1792 void DrawScreenField(int x, int y)
1794 int lx = LEVELX(x), ly = LEVELY(y);
1795 int element, content;
1797 if (!IN_LEV_FIELD(lx, ly))
1799 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1802 element = getBorderElement(lx, ly);
1804 DrawScreenElement(x, y, element);
1809 element = Feld[lx][ly];
1810 content = Store[lx][ly];
1812 if (IS_MOVING(lx, ly))
1814 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1815 boolean cut_mode = NO_CUTTING;
1817 if (element == EL_QUICKSAND_EMPTYING ||
1818 element == EL_QUICKSAND_FAST_EMPTYING ||
1819 element == EL_MAGIC_WALL_EMPTYING ||
1820 element == EL_BD_MAGIC_WALL_EMPTYING ||
1821 element == EL_DC_MAGIC_WALL_EMPTYING ||
1822 element == EL_AMOEBA_DROPPING)
1823 cut_mode = CUT_ABOVE;
1824 else if (element == EL_QUICKSAND_FILLING ||
1825 element == EL_QUICKSAND_FAST_FILLING ||
1826 element == EL_MAGIC_WALL_FILLING ||
1827 element == EL_BD_MAGIC_WALL_FILLING ||
1828 element == EL_DC_MAGIC_WALL_FILLING)
1829 cut_mode = CUT_BELOW;
1831 if (cut_mode == CUT_ABOVE)
1832 DrawScreenElement(x, y, element);
1834 DrawScreenElement(x, y, EL_EMPTY);
1837 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1838 else if (cut_mode == NO_CUTTING)
1839 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1842 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1844 if (cut_mode == CUT_BELOW &&
1845 IN_LEV_FIELD(lx, ly + 1) && IN_SCR_FIELD(x, y + 1))
1846 DrawLevelElement(lx, ly + 1, element);
1849 if (content == EL_ACID)
1851 int dir = MovDir[lx][ly];
1852 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
1853 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
1855 DrawLevelElementThruMask(newlx, newly, EL_ACID);
1858 else if (IS_BLOCKED(lx, ly))
1863 boolean cut_mode = NO_CUTTING;
1864 int element_old, content_old;
1866 Blocked2Moving(lx, ly, &oldx, &oldy);
1869 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1870 MovDir[oldx][oldy] == MV_RIGHT);
1872 element_old = Feld[oldx][oldy];
1873 content_old = Store[oldx][oldy];
1875 if (element_old == EL_QUICKSAND_EMPTYING ||
1876 element_old == EL_QUICKSAND_FAST_EMPTYING ||
1877 element_old == EL_MAGIC_WALL_EMPTYING ||
1878 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1879 element_old == EL_DC_MAGIC_WALL_EMPTYING ||
1880 element_old == EL_AMOEBA_DROPPING)
1881 cut_mode = CUT_ABOVE;
1883 DrawScreenElement(x, y, EL_EMPTY);
1886 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1888 else if (cut_mode == NO_CUTTING)
1889 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1892 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1895 else if (IS_DRAWABLE(element))
1896 DrawScreenElement(x, y, element);
1898 DrawScreenElement(x, y, EL_EMPTY);
1901 void DrawLevelField(int x, int y)
1903 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1904 DrawScreenField(SCREENX(x), SCREENY(y));
1905 else if (IS_MOVING(x, y))
1909 Moving2Blocked(x, y, &newx, &newy);
1910 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1911 DrawScreenField(SCREENX(newx), SCREENY(newy));
1913 else if (IS_BLOCKED(x, y))
1917 Blocked2Moving(x, y, &oldx, &oldy);
1918 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1919 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1923 void DrawSizedElement(int x, int y, int element, int tilesize)
1927 graphic = el2edimg(element);
1928 DrawSizedGraphic(x, y, graphic, 0, tilesize);
1931 void DrawMiniElement(int x, int y, int element)
1935 graphic = el2edimg(element);
1936 DrawMiniGraphic(x, y, graphic);
1939 void DrawSizedElementOrWall(int sx, int sy, int scroll_x, int scroll_y,
1942 int x = sx + scroll_x, y = sy + scroll_y;
1944 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1945 DrawSizedElement(sx, sy, EL_EMPTY, tilesize);
1946 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1947 DrawSizedElement(sx, sy, Feld[x][y], tilesize);
1949 DrawSizedGraphic(sx, sy, el2edimg(getBorderElement(x, y)), 0, tilesize);
1952 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1954 int x = sx + scroll_x, y = sy + scroll_y;
1956 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1957 DrawMiniElement(sx, sy, EL_EMPTY);
1958 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1959 DrawMiniElement(sx, sy, Feld[x][y]);
1961 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1964 void DrawEnvelopeBackgroundTiles(int graphic, int startx, int starty,
1965 int x, int y, int xsize, int ysize,
1966 int tile_width, int tile_height)
1970 int dst_x = startx + x * tile_width;
1971 int dst_y = starty + y * tile_height;
1972 int width = graphic_info[graphic].width;
1973 int height = graphic_info[graphic].height;
1974 int inner_width_raw = MAX(width - 2 * tile_width, tile_width);
1975 int inner_height_raw = MAX(height - 2 * tile_height, tile_height);
1976 int inner_width = inner_width_raw - (inner_width_raw % tile_width);
1977 int inner_height = inner_height_raw - (inner_height_raw % tile_height);
1978 int inner_sx = (width >= 3 * tile_width ? tile_width : 0);
1979 int inner_sy = (height >= 3 * tile_height ? tile_height : 0);
1980 boolean draw_masked = graphic_info[graphic].draw_masked;
1982 getFixedGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1984 if (src_bitmap == NULL || width < tile_width || height < tile_height)
1986 ClearRectangle(drawto, dst_x, dst_y, tile_width, tile_height);
1990 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - tile_width :
1991 inner_sx + (x - 1) * tile_width % inner_width);
1992 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - tile_height :
1993 inner_sy + (y - 1) * tile_height % inner_height);
1996 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
1999 BlitBitmap(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
2003 void DrawEnvelopeBackground(int graphic, int startx, int starty,
2004 int x, int y, int xsize, int ysize, int font_nr)
2006 int font_width = getFontWidth(font_nr);
2007 int font_height = getFontHeight(font_nr);
2009 DrawEnvelopeBackgroundTiles(graphic, startx, starty, x, y, xsize, ysize,
2010 font_width, font_height);
2013 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
2015 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2016 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2017 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2018 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2019 boolean no_delay = (tape.warp_forward);
2020 unsigned int anim_delay = 0;
2021 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
2022 int anim_delay_value = (no_delay ? 0 : frame_delay_value) / 2;
2023 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
2024 int font_width = getFontWidth(font_nr);
2025 int font_height = getFontHeight(font_nr);
2026 int max_xsize = level.envelope[envelope_nr].xsize;
2027 int max_ysize = level.envelope[envelope_nr].ysize;
2028 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
2029 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
2030 int xend = max_xsize;
2031 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
2032 int xstep = (xstart < xend ? 1 : 0);
2033 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2035 int end = MAX(xend - xstart, yend - ystart);
2038 for (i = start; i <= end; i++)
2040 int last_frame = end; // last frame of this "for" loop
2041 int x = xstart + i * xstep;
2042 int y = ystart + i * ystep;
2043 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2044 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2045 int sx = SX + (SXSIZE - xsize * font_width) / 2;
2046 int sy = SY + (SYSIZE - ysize * font_height) / 2;
2049 SetDrawtoField(DRAW_FIELDBUFFER);
2051 BlitScreenToBitmap(backbuffer);
2053 SetDrawtoField(DRAW_BACKBUFFER);
2055 for (yy = 0; yy < ysize; yy++)
2056 for (xx = 0; xx < xsize; xx++)
2057 DrawEnvelopeBackground(graphic, sx, sy, xx, yy, xsize, ysize, font_nr);
2059 DrawTextBuffer(sx + font_width, sy + font_height,
2060 level.envelope[envelope_nr].text, font_nr, max_xsize,
2061 xsize - 2, ysize - 2, 0, mask_mode,
2062 level.envelope[envelope_nr].autowrap,
2063 level.envelope[envelope_nr].centered, FALSE);
2065 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2068 SkipUntilDelayReached(&anim_delay, anim_delay_value, &i, last_frame);
2072 void ShowEnvelope(int envelope_nr)
2074 int element = EL_ENVELOPE_1 + envelope_nr;
2075 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2076 int sound_opening = element_info[element].sound[ACTION_OPENING];
2077 int sound_closing = element_info[element].sound[ACTION_CLOSING];
2078 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2079 boolean no_delay = (tape.warp_forward);
2080 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
2081 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
2082 int anim_mode = graphic_info[graphic].anim_mode;
2083 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2084 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2086 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
2088 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2090 if (anim_mode == ANIM_DEFAULT)
2091 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
2093 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
2096 Delay(wait_delay_value);
2098 WaitForEventToContinue();
2100 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2102 if (anim_mode != ANIM_NONE)
2103 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
2105 if (anim_mode == ANIM_DEFAULT)
2106 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
2108 game.envelope_active = FALSE;
2110 SetDrawtoField(DRAW_FIELDBUFFER);
2112 redraw_mask |= REDRAW_FIELD;
2116 static void setRequestCenterPosition(int *x, int *y)
2118 int sx_center = (request.x != -1 ? request.x : SX + SXSIZE / 2);
2119 int sy_center = (request.y != -1 ? request.y : SY + SYSIZE / 2);
2125 static void setRequestPosition(int *x, int *y, boolean add_border_size)
2127 int border_size = request.border_size;
2128 int sx_center, sy_center;
2131 setRequestCenterPosition(&sx_center, &sy_center);
2133 sx = sx_center - request.width / 2;
2134 sy = sy_center - request.height / 2;
2136 if (add_border_size)
2146 void DrawEnvelopeRequest(char *text)
2148 char *text_final = text;
2149 char *text_door_style = NULL;
2150 int graphic = IMG_BACKGROUND_REQUEST;
2151 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2152 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2153 int font_nr = FONT_REQUEST;
2154 int font_width = getFontWidth(font_nr);
2155 int font_height = getFontHeight(font_nr);
2156 int border_size = request.border_size;
2157 int line_spacing = request.line_spacing;
2158 int line_height = font_height + line_spacing;
2159 int text_width = request.width - 2 * border_size;
2160 int text_height = request.height - 2 * border_size;
2161 int line_length = text_width / font_width;
2162 int max_lines = text_height / line_height;
2163 int width = request.width;
2164 int height = request.height;
2165 int tile_size = request.step_offset;
2166 int x_steps = width / tile_size;
2167 int y_steps = height / tile_size;
2171 if (request.wrap_single_words)
2173 char *src_text_ptr, *dst_text_ptr;
2175 text_door_style = checked_malloc(2 * strlen(text) + 1);
2177 src_text_ptr = text;
2178 dst_text_ptr = text_door_style;
2180 while (*src_text_ptr)
2182 if (*src_text_ptr == ' ' ||
2183 *src_text_ptr == '?' ||
2184 *src_text_ptr == '!')
2185 *dst_text_ptr++ = '\n';
2187 if (*src_text_ptr != ' ')
2188 *dst_text_ptr++ = *src_text_ptr;
2193 *dst_text_ptr = '\0';
2195 text_final = text_door_style;
2198 setRequestPosition(&sx, &sy, FALSE);
2200 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
2202 for (y = 0; y < y_steps; y++)
2203 for (x = 0; x < x_steps; x++)
2204 DrawEnvelopeBackgroundTiles(graphic, sx, sy,
2205 x, y, x_steps, y_steps,
2206 tile_size, tile_size);
2208 DrawTextBuffer(sx + border_size, sy + border_size, text_final, font_nr,
2209 line_length, -1, max_lines, line_spacing, mask_mode,
2210 request.autowrap, request.centered, FALSE);
2212 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2213 RedrawGadget(tool_gadget[i]);
2215 // store readily prepared envelope request for later use when animating
2216 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2218 if (text_door_style)
2219 free(text_door_style);
2222 void AnimateEnvelopeRequest(int anim_mode, int action)
2224 int graphic = IMG_BACKGROUND_REQUEST;
2225 boolean draw_masked = graphic_info[graphic].draw_masked;
2226 int delay_value_normal = request.step_delay;
2227 int delay_value_fast = delay_value_normal / 2;
2228 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2229 boolean no_delay = (tape.warp_forward);
2230 int delay_value = (ffwd_delay ? delay_value_fast : delay_value_normal);
2231 int anim_delay_value = (no_delay ? 0 : delay_value + 500 * 0) / 2;
2232 unsigned int anim_delay = 0;
2234 int width = request.width;
2235 int height = request.height;
2236 int tile_size = request.step_offset;
2237 int max_xsize = width / tile_size;
2238 int max_ysize = height / tile_size;
2239 int max_xsize_inner = max_xsize - 2;
2240 int max_ysize_inner = max_ysize - 2;
2242 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize_inner : 0);
2243 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize_inner : 0);
2244 int xend = max_xsize_inner;
2245 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize_inner : 0);
2246 int xstep = (xstart < xend ? 1 : 0);
2247 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2249 int end = MAX(xend - xstart, yend - ystart);
2252 if (setup.quick_doors)
2260 if (action == ACTION_OPENING)
2261 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2262 else if (action == ACTION_CLOSING)
2263 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2266 for (i = start; i <= end; i++)
2268 int last_frame = end; // last frame of this "for" loop
2269 int x = xstart + i * xstep;
2270 int y = ystart + i * ystep;
2271 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2272 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2273 int xsize_size_left = (xsize - 1) * tile_size;
2274 int ysize_size_top = (ysize - 1) * tile_size;
2275 int max_xsize_pos = (max_xsize - 1) * tile_size;
2276 int max_ysize_pos = (max_ysize - 1) * tile_size;
2277 int sx_center, sy_center;
2282 setRequestCenterPosition(&sx_center, &sy_center);
2284 src_x = sx_center - width / 2;
2285 src_y = sy_center - height / 2;
2286 dst_x = sx_center - xsize * tile_size / 2;
2287 dst_y = sy_center - ysize * tile_size / 2;
2289 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2291 for (yy = 0; yy < 2; yy++)
2293 for (xx = 0; xx < 2; xx++)
2295 int src_xx = src_x + xx * max_xsize_pos;
2296 int src_yy = src_y + yy * max_ysize_pos;
2297 int dst_xx = dst_x + xx * xsize_size_left;
2298 int dst_yy = dst_y + yy * ysize_size_top;
2299 int xx_size = (xx ? tile_size : xsize_size_left);
2300 int yy_size = (yy ? tile_size : ysize_size_top);
2303 BlitBitmapMasked(bitmap_db_cross, backbuffer,
2304 src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
2306 BlitBitmap(bitmap_db_cross, backbuffer,
2307 src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
2311 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2316 SkipUntilDelayReached(&anim_delay, anim_delay_value, &i, last_frame);
2320 void ShowEnvelopeRequest(char *text, unsigned int req_state, int action)
2322 int last_game_status = game_status; /* save current game status */
2323 int graphic = IMG_BACKGROUND_REQUEST;
2324 int sound_opening = SND_REQUEST_OPENING;
2325 int sound_closing = SND_REQUEST_CLOSING;
2326 int anim_mode = graphic_info[graphic].anim_mode;
2327 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2328 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2330 if (game_status == GAME_MODE_PLAYING)
2331 BlitScreenToBitmap(backbuffer);
2333 SetDrawtoField(DRAW_BACKBUFFER);
2335 // SetDrawBackgroundMask(REDRAW_NONE);
2337 if (action == ACTION_OPENING)
2339 BlitBitmap(backbuffer, bitmap_db_store, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2341 if (req_state & REQ_ASK)
2343 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2344 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2346 else if (req_state & REQ_CONFIRM)
2348 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2350 else if (req_state & REQ_PLAYER)
2352 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2353 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2354 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2355 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2358 DrawEnvelopeRequest(text);
2360 if (game_status != GAME_MODE_MAIN)
2364 /* force DOOR font inside door area */
2365 game_status = GAME_MODE_PSEUDO_DOOR;
2367 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
2369 if (action == ACTION_OPENING)
2371 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2373 if (anim_mode == ANIM_DEFAULT)
2374 AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_OPENING);
2376 AnimateEnvelopeRequest(main_anim_mode, ACTION_OPENING);
2380 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2382 if (anim_mode != ANIM_NONE)
2383 AnimateEnvelopeRequest(main_anim_mode, ACTION_CLOSING);
2385 if (anim_mode == ANIM_DEFAULT)
2386 AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_CLOSING);
2389 game.envelope_active = FALSE;
2391 game_status = last_game_status; /* restore current game status */
2393 if (action == ACTION_CLOSING)
2395 if (game_status != GAME_MODE_MAIN)
2398 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2401 // SetDrawBackgroundMask(last_draw_background_mask);
2403 redraw_mask |= REDRAW_FIELD;
2405 if (game_status == GAME_MODE_MAIN)
2410 if (action == ACTION_CLOSING &&
2411 game_status == GAME_MODE_PLAYING &&
2412 level.game_engine_type == GAME_ENGINE_TYPE_RND)
2413 SetDrawtoField(DRAW_FIELDBUFFER);
2416 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
2420 int graphic = el2preimg(element);
2422 getSizedGraphicSource(graphic, 0, tilesize, &src_bitmap, &src_x, &src_y);
2423 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
2426 void DrawLevel(int draw_background_mask)
2430 SetMainBackgroundImage(IMG_BACKGROUND_PLAYING);
2431 SetDrawBackgroundMask(draw_background_mask);
2435 for (x = BX1; x <= BX2; x++)
2436 for (y = BY1; y <= BY2; y++)
2437 DrawScreenField(x, y);
2439 redraw_mask |= REDRAW_FIELD;
2442 void DrawSizedLevel(int size_x, int size_y, int scroll_x, int scroll_y,
2447 for (x = 0; x < size_x; x++)
2448 for (y = 0; y < size_y; y++)
2449 DrawSizedElementOrWall(x, y, scroll_x, scroll_y, tilesize);
2451 redraw_mask |= REDRAW_FIELD;
2454 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
2458 for (x = 0; x < size_x; x++)
2459 for (y = 0; y < size_y; y++)
2460 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
2462 redraw_mask |= REDRAW_FIELD;
2465 static void DrawPreviewLevelPlayfieldExt(int from_x, int from_y)
2467 boolean show_level_border = (BorderElement != EL_EMPTY);
2468 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2469 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2470 int tile_size = preview.tile_size;
2471 int preview_width = preview.xsize * tile_size;
2472 int preview_height = preview.ysize * tile_size;
2473 int real_preview_xsize = MIN(level_xsize, preview.xsize);
2474 int real_preview_ysize = MIN(level_ysize, preview.ysize);
2475 int real_preview_width = real_preview_xsize * tile_size;
2476 int real_preview_height = real_preview_ysize * tile_size;
2477 int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
2478 int dst_y = SY + ALIGNED_YPOS(preview.y, preview_height, preview.valign);
2481 if (!IN_GFX_FIELD_FULL(dst_x, dst_y + preview_height - 1))
2484 DrawBackground(dst_x, dst_y, preview_width, preview_height);
2486 dst_x += (preview_width - real_preview_width) / 2;
2487 dst_y += (preview_height - real_preview_height) / 2;
2489 for (x = 0; x < real_preview_xsize; x++)
2491 for (y = 0; y < real_preview_ysize; y++)
2493 int lx = from_x + x + (show_level_border ? -1 : 0);
2494 int ly = from_y + y + (show_level_border ? -1 : 0);
2495 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
2496 getBorderElement(lx, ly));
2498 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
2499 element, tile_size);
2503 redraw_mask |= REDRAW_MICROLEVEL;
2506 #define MICROLABEL_EMPTY 0
2507 #define MICROLABEL_LEVEL_NAME 1
2508 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
2509 #define MICROLABEL_LEVEL_AUTHOR 3
2510 #define MICROLABEL_IMPORTED_FROM_HEAD 4
2511 #define MICROLABEL_IMPORTED_FROM 5
2512 #define MICROLABEL_IMPORTED_BY_HEAD 6
2513 #define MICROLABEL_IMPORTED_BY 7
2515 static int getMaxTextLength(struct TextPosInfo *pos, int font_nr)
2517 int max_text_width = SXSIZE;
2518 int font_width = getFontWidth(font_nr);
2520 if (pos->align == ALIGN_CENTER)
2521 max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
2522 else if (pos->align == ALIGN_RIGHT)
2523 max_text_width = pos->x;
2525 max_text_width = SXSIZE - pos->x;
2527 return max_text_width / font_width;
2530 static void DrawPreviewLevelLabelExt(int mode)
2532 struct TextPosInfo *pos = &menu.main.text.level_info_2;
2533 char label_text[MAX_OUTPUT_LINESIZE + 1];
2534 int max_len_label_text;
2535 int font_nr = pos->font;
2538 if (!IN_GFX_FIELD_FULL(pos->x, pos->y + getFontHeight(pos->font)))
2541 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
2542 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
2543 mode == MICROLABEL_IMPORTED_BY_HEAD)
2544 font_nr = pos->font_alt;
2546 max_len_label_text = getMaxTextLength(pos, font_nr);
2548 if (pos->size != -1)
2549 max_len_label_text = pos->size;
2551 for (i = 0; i < max_len_label_text; i++)
2552 label_text[i] = ' ';
2553 label_text[max_len_label_text] = '\0';
2555 if (strlen(label_text) > 0)
2556 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2559 (mode == MICROLABEL_LEVEL_NAME ? level.name :
2560 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
2561 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
2562 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
2563 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
2564 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
2565 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
2566 max_len_label_text);
2567 label_text[max_len_label_text] = '\0';
2569 if (strlen(label_text) > 0)
2570 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2572 redraw_mask |= REDRAW_MICROLEVEL;
2575 static void DrawPreviewLevelExt(boolean restart)
2577 static unsigned int scroll_delay = 0;
2578 static unsigned int label_delay = 0;
2579 static int from_x, from_y, scroll_direction;
2580 static int label_state, label_counter;
2581 unsigned int scroll_delay_value = preview.step_delay;
2582 boolean show_level_border = (BorderElement != EL_EMPTY);
2583 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2584 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2585 int last_game_status = game_status; /* save current game status */
2592 if (preview.anim_mode == ANIM_CENTERED)
2594 if (level_xsize > preview.xsize)
2595 from_x = (level_xsize - preview.xsize) / 2;
2596 if (level_ysize > preview.ysize)
2597 from_y = (level_ysize - preview.ysize) / 2;
2600 from_x += preview.xoffset;
2601 from_y += preview.yoffset;
2603 scroll_direction = MV_RIGHT;
2607 DrawPreviewLevelPlayfieldExt(from_x, from_y);
2608 DrawPreviewLevelLabelExt(label_state);
2610 /* initialize delay counters */
2611 DelayReached(&scroll_delay, 0);
2612 DelayReached(&label_delay, 0);
2614 if (leveldir_current->name)
2616 struct TextPosInfo *pos = &menu.main.text.level_info_1;
2617 char label_text[MAX_OUTPUT_LINESIZE + 1];
2618 int font_nr = pos->font;
2619 int max_len_label_text = getMaxTextLength(pos, font_nr);
2621 if (pos->size != -1)
2622 max_len_label_text = pos->size;
2624 strncpy(label_text, leveldir_current->name, max_len_label_text);
2625 label_text[max_len_label_text] = '\0';
2627 if (IN_GFX_FIELD_FULL(pos->x, pos->y + getFontHeight(pos->font)))
2628 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2631 game_status = last_game_status; /* restore current game status */
2636 /* scroll preview level, if needed */
2637 if (preview.anim_mode != ANIM_NONE &&
2638 (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
2639 DelayReached(&scroll_delay, scroll_delay_value))
2641 switch (scroll_direction)
2646 from_x -= preview.step_offset;
2647 from_x = (from_x < 0 ? 0 : from_x);
2650 scroll_direction = MV_UP;
2654 if (from_x < level_xsize - preview.xsize)
2656 from_x += preview.step_offset;
2657 from_x = (from_x > level_xsize - preview.xsize ?
2658 level_xsize - preview.xsize : from_x);
2661 scroll_direction = MV_DOWN;
2667 from_y -= preview.step_offset;
2668 from_y = (from_y < 0 ? 0 : from_y);
2671 scroll_direction = MV_RIGHT;
2675 if (from_y < level_ysize - preview.ysize)
2677 from_y += preview.step_offset;
2678 from_y = (from_y > level_ysize - preview.ysize ?
2679 level_ysize - preview.ysize : from_y);
2682 scroll_direction = MV_LEFT;
2689 DrawPreviewLevelPlayfieldExt(from_x, from_y);
2692 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
2693 /* redraw micro level label, if needed */
2694 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
2695 !strEqual(level.author, ANONYMOUS_NAME) &&
2696 !strEqual(level.author, leveldir_current->name) &&
2697 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
2699 int max_label_counter = 23;
2701 if (leveldir_current->imported_from != NULL &&
2702 strlen(leveldir_current->imported_from) > 0)
2703 max_label_counter += 14;
2704 if (leveldir_current->imported_by != NULL &&
2705 strlen(leveldir_current->imported_by) > 0)
2706 max_label_counter += 14;
2708 label_counter = (label_counter + 1) % max_label_counter;
2709 label_state = (label_counter >= 0 && label_counter <= 7 ?
2710 MICROLABEL_LEVEL_NAME :
2711 label_counter >= 9 && label_counter <= 12 ?
2712 MICROLABEL_LEVEL_AUTHOR_HEAD :
2713 label_counter >= 14 && label_counter <= 21 ?
2714 MICROLABEL_LEVEL_AUTHOR :
2715 label_counter >= 23 && label_counter <= 26 ?
2716 MICROLABEL_IMPORTED_FROM_HEAD :
2717 label_counter >= 28 && label_counter <= 35 ?
2718 MICROLABEL_IMPORTED_FROM :
2719 label_counter >= 37 && label_counter <= 40 ?
2720 MICROLABEL_IMPORTED_BY_HEAD :
2721 label_counter >= 42 && label_counter <= 49 ?
2722 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
2724 if (leveldir_current->imported_from == NULL &&
2725 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
2726 label_state == MICROLABEL_IMPORTED_FROM))
2727 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
2728 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
2730 DrawPreviewLevelLabelExt(label_state);
2733 game_status = last_game_status; /* restore current game status */
2736 void DrawPreviewLevelInitial()
2738 DrawPreviewLevelExt(TRUE);
2741 void DrawPreviewLevelAnimation()
2743 DrawPreviewLevelExt(FALSE);
2746 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
2747 int graphic, int sync_frame, int mask_mode)
2749 int frame = getGraphicAnimationFrame(graphic, sync_frame);
2751 if (mask_mode == USE_MASKING)
2752 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
2754 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
2757 inline void DrawFixedGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
2758 int graphic, int sync_frame,
2761 int frame = getGraphicAnimationFrame(graphic, sync_frame);
2763 if (mask_mode == USE_MASKING)
2764 DrawFixedGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
2766 DrawFixedGraphicExt(dst_bitmap, x, y, graphic, frame);
2769 inline void DrawGraphicAnimation(int x, int y, int graphic)
2771 int lx = LEVELX(x), ly = LEVELY(y);
2773 if (!IN_SCR_FIELD(x, y))
2776 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
2777 graphic, GfxFrame[lx][ly], NO_MASKING);
2779 MarkTileDirty(x, y);
2782 inline void DrawFixedGraphicAnimation(int x, int y, int graphic)
2784 int lx = LEVELX(x), ly = LEVELY(y);
2786 if (!IN_SCR_FIELD(x, y))
2789 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
2790 graphic, GfxFrame[lx][ly], NO_MASKING);
2791 MarkTileDirty(x, y);
2794 void DrawLevelGraphicAnimation(int x, int y, int graphic)
2796 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2799 void DrawLevelElementAnimation(int x, int y, int element)
2801 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2803 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2806 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
2808 int sx = SCREENX(x), sy = SCREENY(y);
2810 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2813 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2816 DrawGraphicAnimation(sx, sy, graphic);
2819 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
2820 DrawLevelFieldCrumbled(x, y);
2822 if (GFX_CRUMBLED(Feld[x][y]))
2823 DrawLevelFieldCrumbled(x, y);
2827 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
2829 int sx = SCREENX(x), sy = SCREENY(y);
2832 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2835 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2837 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2840 DrawGraphicAnimation(sx, sy, graphic);
2842 if (GFX_CRUMBLED(element))
2843 DrawLevelFieldCrumbled(x, y);
2846 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
2848 if (player->use_murphy)
2850 /* this works only because currently only one player can be "murphy" ... */
2851 static int last_horizontal_dir = MV_LEFT;
2852 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
2854 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2855 last_horizontal_dir = move_dir;
2857 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
2859 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
2861 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
2867 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
2870 static boolean equalGraphics(int graphic1, int graphic2)
2872 struct GraphicInfo *g1 = &graphic_info[graphic1];
2873 struct GraphicInfo *g2 = &graphic_info[graphic2];
2875 return (g1->bitmap == g2->bitmap &&
2876 g1->src_x == g2->src_x &&
2877 g1->src_y == g2->src_y &&
2878 g1->anim_frames == g2->anim_frames &&
2879 g1->anim_delay == g2->anim_delay &&
2880 g1->anim_mode == g2->anim_mode);
2883 void DrawAllPlayers()
2887 for (i = 0; i < MAX_PLAYERS; i++)
2888 if (stored_player[i].active)
2889 DrawPlayer(&stored_player[i]);
2892 void DrawPlayerField(int x, int y)
2894 if (!IS_PLAYER(x, y))
2897 DrawPlayer(PLAYERINFO(x, y));
2900 #define DRAW_PLAYER_OVER_PUSHED_ELEMENT 1
2902 void DrawPlayer(struct PlayerInfo *player)
2904 int jx = player->jx;
2905 int jy = player->jy;
2906 int move_dir = player->MovDir;
2907 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
2908 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
2909 int last_jx = (player->is_moving ? jx - dx : jx);
2910 int last_jy = (player->is_moving ? jy - dy : jy);
2911 int next_jx = jx + dx;
2912 int next_jy = jy + dy;
2913 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
2914 boolean player_is_opaque = FALSE;
2915 int sx = SCREENX(jx), sy = SCREENY(jy);
2916 int sxx = 0, syy = 0;
2917 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
2919 int action = ACTION_DEFAULT;
2920 int last_player_graphic = getPlayerGraphic(player, move_dir);
2921 int last_player_frame = player->Frame;
2924 /* GfxElement[][] is set to the element the player is digging or collecting;
2925 remove also for off-screen player if the player is not moving anymore */
2926 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
2927 GfxElement[jx][jy] = EL_UNDEFINED;
2929 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
2933 if (!IN_LEV_FIELD(jx, jy))
2935 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
2936 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
2937 printf("DrawPlayerField(): This should never happen!\n");
2942 if (element == EL_EXPLOSION)
2945 action = (player->is_pushing ? ACTION_PUSHING :
2946 player->is_digging ? ACTION_DIGGING :
2947 player->is_collecting ? ACTION_COLLECTING :
2948 player->is_moving ? ACTION_MOVING :
2949 player->is_snapping ? ACTION_SNAPPING :
2950 player->is_dropping ? ACTION_DROPPING :
2951 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
2953 if (player->is_waiting)
2954 move_dir = player->dir_waiting;
2956 InitPlayerGfxAnimation(player, action, move_dir);
2958 /* ----------------------------------------------------------------------- */
2959 /* draw things in the field the player is leaving, if needed */
2960 /* ----------------------------------------------------------------------- */
2962 if (player->is_moving)
2964 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
2966 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
2968 if (last_element == EL_DYNAMITE_ACTIVE ||
2969 last_element == EL_EM_DYNAMITE_ACTIVE ||
2970 last_element == EL_SP_DISK_RED_ACTIVE)
2971 DrawDynamite(last_jx, last_jy);
2973 DrawLevelFieldThruMask(last_jx, last_jy);
2975 else if (last_element == EL_DYNAMITE_ACTIVE ||
2976 last_element == EL_EM_DYNAMITE_ACTIVE ||
2977 last_element == EL_SP_DISK_RED_ACTIVE)
2978 DrawDynamite(last_jx, last_jy);
2980 /* !!! this is not enough to prevent flickering of players which are
2981 moving next to each others without a free tile between them -- this
2982 can only be solved by drawing all players layer by layer (first the
2983 background, then the foreground etc.) !!! => TODO */
2984 else if (!IS_PLAYER(last_jx, last_jy))
2985 DrawLevelField(last_jx, last_jy);
2988 DrawLevelField(last_jx, last_jy);
2991 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
2992 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
2995 if (!IN_SCR_FIELD(sx, sy))
2998 /* ----------------------------------------------------------------------- */
2999 /* draw things behind the player, if needed */
3000 /* ----------------------------------------------------------------------- */
3003 DrawLevelElement(jx, jy, Back[jx][jy]);
3004 else if (IS_ACTIVE_BOMB(element))
3005 DrawLevelElement(jx, jy, EL_EMPTY);
3008 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
3010 int old_element = GfxElement[jx][jy];
3011 int old_graphic = el_act_dir2img(old_element, action, move_dir);
3012 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
3014 if (GFX_CRUMBLED(old_element))
3015 DrawLevelFieldCrumbledDigging(jx, jy, move_dir, player->StepFrame);
3017 DrawGraphic(sx, sy, old_graphic, frame);
3019 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
3020 player_is_opaque = TRUE;
3024 GfxElement[jx][jy] = EL_UNDEFINED;
3026 /* make sure that pushed elements are drawn with correct frame rate */
3027 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
3029 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
3030 GfxFrame[jx][jy] = player->StepFrame;
3032 DrawLevelField(jx, jy);
3036 #if !DRAW_PLAYER_OVER_PUSHED_ELEMENT
3037 /* ----------------------------------------------------------------------- */
3038 /* draw player himself */
3039 /* ----------------------------------------------------------------------- */
3041 graphic = getPlayerGraphic(player, move_dir);
3043 /* in the case of changed player action or direction, prevent the current
3044 animation frame from being restarted for identical animations */
3045 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
3046 player->Frame = last_player_frame;
3048 frame = getGraphicAnimationFrame(graphic, player->Frame);
3052 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3053 sxx = player->GfxPos;
3055 syy = player->GfxPos;
3058 if (player_is_opaque)
3059 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
3061 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3063 if (SHIELD_ON(player))
3065 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
3066 IMG_SHIELD_NORMAL_ACTIVE);
3067 int frame = getGraphicAnimationFrame(graphic, -1);
3069 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3073 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
3076 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3077 sxx = player->GfxPos;
3079 syy = player->GfxPos;
3083 /* ----------------------------------------------------------------------- */
3084 /* draw things the player is pushing, if needed */
3085 /* ----------------------------------------------------------------------- */
3087 if (player->is_pushing && player->is_moving)
3089 int px = SCREENX(jx), py = SCREENY(jy);
3090 int pxx = (TILEX - ABS(sxx)) * dx;
3091 int pyy = (TILEY - ABS(syy)) * dy;
3092 int gfx_frame = GfxFrame[jx][jy];
3098 if (!IS_MOVING(jx, jy)) /* push movement already finished */
3100 element = Feld[next_jx][next_jy];
3101 gfx_frame = GfxFrame[next_jx][next_jy];
3104 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
3106 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
3107 frame = getGraphicAnimationFrame(graphic, sync_frame);
3109 /* draw background element under pushed element (like the Sokoban field) */
3110 if (game.use_masked_pushing && IS_MOVING(jx, jy))
3112 /* this allows transparent pushing animation over non-black background */
3115 DrawLevelElement(jx, jy, Back[jx][jy]);
3117 DrawLevelElement(jx, jy, EL_EMPTY);
3119 if (Back[next_jx][next_jy])
3120 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3122 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
3124 else if (Back[next_jx][next_jy])
3125 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3128 /* do not draw (EM style) pushing animation when pushing is finished */
3129 /* (two-tile animations usually do not contain start and end frame) */
3130 if (graphic_info[graphic].double_movement && !IS_MOVING(jx, jy))
3131 DrawLevelElement(next_jx, next_jy, Feld[next_jx][next_jy]);
3133 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3135 /* masked drawing is needed for EMC style (double) movement graphics */
3136 /* !!! (ONLY WHEN DRAWING PUSHED ELEMENT OVER THE PLAYER) !!! */
3137 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3141 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
3142 /* ----------------------------------------------------------------------- */
3143 /* draw player himself */
3144 /* ----------------------------------------------------------------------- */
3146 graphic = getPlayerGraphic(player, move_dir);
3148 /* in the case of changed player action or direction, prevent the current
3149 animation frame from being restarted for identical animations */
3150 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
3151 player->Frame = last_player_frame;
3153 frame = getGraphicAnimationFrame(graphic, player->Frame);
3157 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3158 sxx = player->GfxPos;
3160 syy = player->GfxPos;
3163 if (player_is_opaque)
3164 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
3166 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3168 if (SHIELD_ON(player))
3170 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
3171 IMG_SHIELD_NORMAL_ACTIVE);
3172 int frame = getGraphicAnimationFrame(graphic, -1);
3174 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3178 /* ----------------------------------------------------------------------- */
3179 /* draw things in front of player (active dynamite or dynabombs) */
3180 /* ----------------------------------------------------------------------- */
3182 if (IS_ACTIVE_BOMB(element))
3184 graphic = el2img(element);
3185 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
3187 if (game.emulation == EMU_SUPAPLEX)
3188 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
3190 DrawGraphicThruMask(sx, sy, graphic, frame);
3193 if (player_is_moving && last_element == EL_EXPLOSION)
3195 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
3196 GfxElement[last_jx][last_jy] : EL_EMPTY);
3197 int graphic = el_act2img(element, ACTION_EXPLODING);
3198 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
3199 int phase = ExplodePhase[last_jx][last_jy] - 1;
3200 int frame = getGraphicAnimationFrame(graphic, phase - delay);
3203 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
3206 /* ----------------------------------------------------------------------- */
3207 /* draw elements the player is just walking/passing through/under */
3208 /* ----------------------------------------------------------------------- */
3210 if (player_is_moving)
3212 /* handle the field the player is leaving ... */
3213 if (IS_ACCESSIBLE_INSIDE(last_element))
3214 DrawLevelField(last_jx, last_jy);
3215 else if (IS_ACCESSIBLE_UNDER(last_element))
3216 DrawLevelFieldThruMask(last_jx, last_jy);
3219 /* do not redraw accessible elements if the player is just pushing them */
3220 if (!player_is_moving || !player->is_pushing)
3222 /* ... and the field the player is entering */
3223 if (IS_ACCESSIBLE_INSIDE(element))
3224 DrawLevelField(jx, jy);
3225 else if (IS_ACCESSIBLE_UNDER(element))
3226 DrawLevelFieldThruMask(jx, jy);
3229 MarkTileDirty(sx, sy);
3232 /* ------------------------------------------------------------------------- */
3234 void WaitForEventToContinue()
3236 boolean still_wait = TRUE;
3238 /* simulate releasing mouse button over last gadget, if still pressed */
3240 HandleGadgets(-1, -1, 0);
3242 button_status = MB_RELEASED;
3256 case EVENT_BUTTONPRESS:
3257 case EVENT_KEYPRESS:
3261 case EVENT_KEYRELEASE:
3262 ClearPlayerAction();
3266 HandleOtherEvents(&event);
3270 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3277 /* don't eat all CPU time */
3282 #define MAX_REQUEST_LINES 13
3283 #define MAX_REQUEST_LINE_FONT1_LEN 7
3284 #define MAX_REQUEST_LINE_FONT2_LEN 10
3286 static int RequestHandleEvents(unsigned int req_state)
3288 boolean level_solved = (game_status == GAME_MODE_PLAYING &&
3289 local_player->LevelSolved_GameEnd);
3290 int last_game_status = game_status; /* save current game status */
3291 int width = request.width;
3292 int height = request.height;
3296 setRequestPosition(&sx, &sy, FALSE);
3298 button_status = MB_RELEASED;
3300 request_gadget_id = -1;
3307 SetDrawtoField(DRAW_FIELDBUFFER);
3309 HandleGameActions();
3311 SetDrawtoField(DRAW_BACKBUFFER);
3313 if (global.use_envelope_request)
3315 /* copy current state of request area to middle of playfield area */
3316 BlitBitmap(bitmap_db_cross, drawto, sx, sy, width, height, sx, sy);
3324 while (NextValidEvent(&event))
3328 case EVENT_BUTTONPRESS:
3329 case EVENT_BUTTONRELEASE:
3330 case EVENT_MOTIONNOTIFY:
3334 if (event.type == EVENT_MOTIONNOTIFY)
3339 motion_status = TRUE;
3340 mx = ((MotionEvent *) &event)->x;
3341 my = ((MotionEvent *) &event)->y;
3345 motion_status = FALSE;
3346 mx = ((ButtonEvent *) &event)->x;
3347 my = ((ButtonEvent *) &event)->y;
3348 if (event.type == EVENT_BUTTONPRESS)
3349 button_status = ((ButtonEvent *) &event)->button;
3351 button_status = MB_RELEASED;
3354 /* this sets 'request_gadget_id' */
3355 HandleGadgets(mx, my, button_status);
3357 switch (request_gadget_id)
3359 case TOOL_CTRL_ID_YES:
3362 case TOOL_CTRL_ID_NO:
3365 case TOOL_CTRL_ID_CONFIRM:
3366 result = TRUE | FALSE;
3369 case TOOL_CTRL_ID_PLAYER_1:
3372 case TOOL_CTRL_ID_PLAYER_2:
3375 case TOOL_CTRL_ID_PLAYER_3:
3378 case TOOL_CTRL_ID_PLAYER_4:
3389 case EVENT_KEYPRESS:
3390 switch (GetEventKey((KeyEvent *)&event, TRUE))
3393 if (req_state & REQ_CONFIRM)
3398 #if defined(TARGET_SDL2)
3405 #if defined(TARGET_SDL2)
3415 if (req_state & REQ_PLAYER)
3419 case EVENT_KEYRELEASE:
3420 ClearPlayerAction();
3424 HandleOtherEvents(&event);
3429 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3431 int joy = AnyJoystick();
3433 if (joy & JOY_BUTTON_1)
3435 else if (joy & JOY_BUTTON_2)
3441 if (global.use_envelope_request)
3443 /* copy back current state of pressed buttons inside request area */
3444 BlitBitmap(drawto, bitmap_db_cross, sx, sy, width, height, sx, sy);
3451 if (!PendingEvent()) /* delay only if no pending events */
3455 game_status = GAME_MODE_PSEUDO_DOOR;
3459 game_status = last_game_status; /* restore current game status */
3465 static boolean RequestDoor(char *text, unsigned int req_state)
3467 unsigned int old_door_state;
3468 int last_game_status = game_status; /* save current game status */
3469 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
3470 int font_nr = FONT_TEXT_2;
3475 if (maxWordLengthInString(text) > MAX_REQUEST_LINE_FONT1_LEN)
3477 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
3478 font_nr = FONT_TEXT_1;
3481 if (game_status == GAME_MODE_PLAYING)
3482 BlitScreenToBitmap(backbuffer);
3484 /* disable deactivated drawing when quick-loading level tape recording */
3485 if (tape.playing && tape.deactivate_display)
3486 TapeDeactivateDisplayOff(TRUE);
3488 SetMouseCursor(CURSOR_DEFAULT);
3490 #if defined(NETWORK_AVALIABLE)
3491 /* pause network game while waiting for request to answer */
3492 if (options.network &&
3493 game_status == GAME_MODE_PLAYING &&
3494 req_state & REQUEST_WAIT_FOR_INPUT)
3495 SendToServer_PausePlaying();
3498 old_door_state = GetDoorState();
3500 /* simulate releasing mouse button over last gadget, if still pressed */
3502 HandleGadgets(-1, -1, 0);
3506 /* draw released gadget before proceeding */
3509 if (old_door_state & DOOR_OPEN_1)
3511 CloseDoor(DOOR_CLOSE_1);
3513 /* save old door content */
3514 BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
3515 0 * DXSIZE, 0, DXSIZE, DYSIZE, 1 * DXSIZE, 0);
3518 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
3519 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3521 /* clear door drawing field */
3522 DrawBackground(DX, DY, DXSIZE, DYSIZE);
3524 /* force DOOR font inside door area */
3525 game_status = GAME_MODE_PSEUDO_DOOR;
3527 /* write text for request */
3528 for (text_ptr = text, ty = 0; ty < MAX_REQUEST_LINES; ty++)
3530 char text_line[max_request_line_len + 1];
3536 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
3538 tc = *(text_ptr + tx);
3539 // if (!tc || tc == ' ')
3540 if (!tc || tc == ' ' || tc == '?' || tc == '!')
3544 if ((tc == '?' || tc == '!') && tl == 0)
3554 strncpy(text_line, text_ptr, tl);
3557 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
3558 DY + 8 + ty * (getFontHeight(font_nr) + 2),
3559 text_line, font_nr);
3561 text_ptr += tl + (tc == ' ' ? 1 : 0);
3562 // text_ptr += tl + (tc == ' ' || tc == '?' || tc == '!' ? 1 : 0);
3565 game_status = last_game_status; /* restore current game status */
3567 if (req_state & REQ_ASK)
3569 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
3570 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
3572 else if (req_state & REQ_CONFIRM)
3574 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
3576 else if (req_state & REQ_PLAYER)
3578 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
3579 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
3580 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
3581 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
3584 /* copy request gadgets to door backbuffer */
3585 BlitBitmap(drawto, bitmap_db_door_1, DX, DY, DXSIZE, DYSIZE, 0, 0);
3587 OpenDoor(DOOR_OPEN_1);
3589 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
3591 if (game_status == GAME_MODE_PLAYING)
3593 SetPanelBackground();
3594 SetDrawBackgroundMask(REDRAW_DOOR_1);
3598 SetDrawBackgroundMask(REDRAW_FIELD);
3604 if (game_status != GAME_MODE_MAIN)
3607 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3609 // ---------- handle request buttons ----------
3610 result = RequestHandleEvents(req_state);
3612 if (game_status != GAME_MODE_MAIN)
3617 if (!(req_state & REQ_STAY_OPEN))
3619 CloseDoor(DOOR_CLOSE_1);
3621 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
3622 (req_state & REQ_REOPEN))
3623 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
3628 if (game_status == GAME_MODE_PLAYING)
3630 SetPanelBackground();
3631 SetDrawBackgroundMask(REDRAW_DOOR_1);
3635 SetDrawBackgroundMask(REDRAW_FIELD);
3638 #if defined(NETWORK_AVALIABLE)
3639 /* continue network game after request */
3640 if (options.network &&
3641 game_status == GAME_MODE_PLAYING &&
3642 req_state & REQUEST_WAIT_FOR_INPUT)
3643 SendToServer_ContinuePlaying();
3646 /* restore deactivated drawing when quick-loading level tape recording */
3647 if (tape.playing && tape.deactivate_display)
3648 TapeDeactivateDisplayOn();
3653 static boolean RequestEnvelope(char *text, unsigned int req_state)
3657 if (game_status == GAME_MODE_PLAYING)
3658 BlitScreenToBitmap(backbuffer);
3660 /* disable deactivated drawing when quick-loading level tape recording */
3661 if (tape.playing && tape.deactivate_display)
3662 TapeDeactivateDisplayOff(TRUE);
3664 SetMouseCursor(CURSOR_DEFAULT);
3666 #if defined(NETWORK_AVALIABLE)
3667 /* pause network game while waiting for request to answer */
3668 if (options.network &&
3669 game_status == GAME_MODE_PLAYING &&
3670 req_state & REQUEST_WAIT_FOR_INPUT)
3671 SendToServer_PausePlaying();
3674 /* simulate releasing mouse button over last gadget, if still pressed */
3676 HandleGadgets(-1, -1, 0);
3680 // (replace with setting corresponding request background)
3681 // SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
3682 // SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3684 /* clear door drawing field */
3685 // DrawBackground(DX, DY, DXSIZE, DYSIZE);
3687 ShowEnvelopeRequest(text, req_state, ACTION_OPENING);
3689 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
3691 if (game_status == GAME_MODE_PLAYING)
3693 SetPanelBackground();
3694 SetDrawBackgroundMask(REDRAW_DOOR_1);
3698 SetDrawBackgroundMask(REDRAW_FIELD);
3704 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3706 // ---------- handle request buttons ----------
3707 result = RequestHandleEvents(req_state);
3709 if (game_status != GAME_MODE_MAIN)
3714 ShowEnvelopeRequest(text, req_state, ACTION_CLOSING);
3718 if (game_status == GAME_MODE_PLAYING)
3720 SetPanelBackground();
3721 SetDrawBackgroundMask(REDRAW_DOOR_1);
3725 SetDrawBackgroundMask(REDRAW_FIELD);
3728 #if defined(NETWORK_AVALIABLE)
3729 /* continue network game after request */
3730 if (options.network &&
3731 game_status == GAME_MODE_PLAYING &&
3732 req_state & REQUEST_WAIT_FOR_INPUT)
3733 SendToServer_ContinuePlaying();
3736 /* restore deactivated drawing when quick-loading level tape recording */
3737 if (tape.playing && tape.deactivate_display)
3738 TapeDeactivateDisplayOn();
3743 boolean Request(char *text, unsigned int req_state)
3745 if (global.use_envelope_request)
3746 return RequestEnvelope(text, req_state);
3748 return RequestDoor(text, req_state);
3751 static int compareDoorPartOrderInfo(const void *object1, const void *object2)
3753 const struct DoorPartOrderInfo *dpo1 = (struct DoorPartOrderInfo *)object1;
3754 const struct DoorPartOrderInfo *dpo2 = (struct DoorPartOrderInfo *)object2;
3757 if (dpo1->sort_priority != dpo2->sort_priority)
3758 compare_result = dpo1->sort_priority - dpo2->sort_priority;
3760 compare_result = dpo1->nr - dpo2->nr;
3762 return compare_result;
3765 void InitGraphicCompatibilityInfo_Doors()
3771 struct DoorInfo *door;
3775 { DOOR_1, IMG_DOOR_1_GFX_PART_1, IMG_DOOR_1_GFX_PART_8, &door_1 },
3776 { DOOR_2, IMG_DOOR_2_GFX_PART_1, IMG_DOOR_2_GFX_PART_8, &door_2 },
3778 { -1, -1, -1, NULL }
3780 struct Rect door_rect_list[] =
3782 { DX, DY, DXSIZE, DYSIZE },
3783 { VX, VY, VXSIZE, VYSIZE }
3787 for (i = 0; doors[i].door_token != -1; i++)
3789 int door_token = doors[i].door_token;
3790 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
3791 int part_1 = doors[i].part_1;
3792 int part_8 = doors[i].part_8;
3793 int part_2 = part_1 + 1;
3794 int part_3 = part_1 + 2;
3795 struct DoorInfo *door = doors[i].door;
3796 struct Rect *door_rect = &door_rect_list[door_index];
3797 boolean door_gfx_redefined = FALSE;
3799 /* check if any door part graphic definitions have been redefined */
3801 for (j = 0; door_part_controls[j].door_token != -1; j++)
3803 struct DoorPartControlInfo *dpc = &door_part_controls[j];
3804 struct FileInfo *fi = getImageListEntryFromImageID(dpc->graphic);
3806 if (dpc->door_token == door_token && fi->redefined)
3807 door_gfx_redefined = TRUE;
3810 /* check for old-style door graphic/animation modifications */
3812 if (!door_gfx_redefined)
3814 if (door->anim_mode & ANIM_STATIC_PANEL)
3816 door->panel.step_xoffset = 0;
3817 door->panel.step_yoffset = 0;
3820 if (door->anim_mode & (ANIM_HORIZONTAL | ANIM_VERTICAL))
3822 struct GraphicInfo *g_part_1 = &graphic_info[part_1];
3823 struct GraphicInfo *g_part_2 = &graphic_info[part_2];
3824 int num_door_steps, num_panel_steps;
3826 /* remove door part graphics other than the two default wings */
3828 for (j = 0; door_part_controls[j].door_token != -1; j++)
3830 struct DoorPartControlInfo *dpc = &door_part_controls[j];
3831 struct GraphicInfo *g = &graphic_info[dpc->graphic];
3833 if (dpc->graphic >= part_3 &&
3834 dpc->graphic <= part_8)
3838 /* set graphics and screen positions of the default wings */
3840 g_part_1->width = door_rect->width;
3841 g_part_1->height = door_rect->height;
3842 g_part_2->width = door_rect->width;
3843 g_part_2->height = door_rect->height;
3844 g_part_2->src_x = door_rect->width;
3845 g_part_2->src_y = g_part_1->src_y;
3847 door->part_2.x = door->part_1.x;
3848 door->part_2.y = door->part_1.y;
3850 if (door->width != -1)
3852 g_part_1->width = door->width;
3853 g_part_2->width = door->width;
3855 // special treatment for graphics and screen position of right wing
3856 g_part_2->src_x += door_rect->width - door->width;
3857 door->part_2.x += door_rect->width - door->width;
3860 if (door->height != -1)
3862 g_part_1->height = door->height;
3863 g_part_2->height = door->height;
3865 // special treatment for graphics and screen position of bottom wing
3866 g_part_2->src_y += door_rect->height - door->height;
3867 door->part_2.y += door_rect->height - door->height;
3870 /* set animation delays for the default wings and panels */
3872 door->part_1.step_delay = door->step_delay;
3873 door->part_2.step_delay = door->step_delay;
3874 door->panel.step_delay = door->step_delay;
3876 /* set animation draw order for the default wings */
3878 door->part_1.sort_priority = 2; /* draw left wing over ... */
3879 door->part_2.sort_priority = 1; /* ... right wing */
3881 /* set animation draw offset for the default wings */
3883 if (door->anim_mode & ANIM_HORIZONTAL)
3885 door->part_1.step_xoffset = door->step_offset;
3886 door->part_1.step_yoffset = 0;
3887 door->part_2.step_xoffset = door->step_offset * -1;
3888 door->part_2.step_yoffset = 0;
3890 num_door_steps = g_part_1->width / door->step_offset;
3892 else // ANIM_VERTICAL
3894 door->part_1.step_xoffset = 0;
3895 door->part_1.step_yoffset = door->step_offset;
3896 door->part_2.step_xoffset = 0;
3897 door->part_2.step_yoffset = door->step_offset * -1;
3899 num_door_steps = g_part_1->height / door->step_offset;
3902 /* set animation draw offset for the default panels */
3904 if (door->step_offset > 1)
3906 num_panel_steps = 2 * door_rect->height / door->step_offset;
3907 door->panel.start_step = num_panel_steps - num_door_steps;
3908 door->panel.start_step_closing = door->panel.start_step;
3912 num_panel_steps = door_rect->height / door->step_offset;
3913 door->panel.start_step = num_panel_steps - num_door_steps / 2;
3914 door->panel.start_step_closing = door->panel.start_step;
3915 door->panel.step_delay *= 2;
3926 for (i = 0; door_part_controls[i].door_token != -1; i++)
3928 struct DoorPartControlInfo *dpc = &door_part_controls[i];
3929 struct DoorPartOrderInfo *dpo = &door_part_order[i];
3931 /* initialize "start_step_opening" and "start_step_closing", if needed */
3932 if (dpc->pos->start_step_opening == 0 &&
3933 dpc->pos->start_step_closing == 0)
3935 // dpc->pos->start_step_opening = dpc->pos->start_step;
3936 dpc->pos->start_step_closing = dpc->pos->start_step;
3939 /* fill structure for door part draw order (sorted below) */
3941 dpo->sort_priority = dpc->pos->sort_priority;
3944 /* sort door part controls according to sort_priority and graphic number */
3945 qsort(door_part_order, MAX_DOOR_PARTS,
3946 sizeof(struct DoorPartOrderInfo), compareDoorPartOrderInfo);
3949 unsigned int OpenDoor(unsigned int door_state)
3951 if (door_state & DOOR_COPY_BACK)
3953 if (door_state & DOOR_OPEN_1)
3954 BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
3955 1 * DXSIZE, 0, DXSIZE, DYSIZE, 0 * DXSIZE, 0);
3957 if (door_state & DOOR_OPEN_2)
3958 BlitBitmap(bitmap_db_door_2, bitmap_db_door_2,
3959 1 * VXSIZE, 0, VXSIZE, VYSIZE, 0 * VXSIZE, 0);
3961 door_state &= ~DOOR_COPY_BACK;
3964 return MoveDoor(door_state);
3967 unsigned int CloseDoor(unsigned int door_state)
3969 unsigned int old_door_state = GetDoorState();
3971 if (!(door_state & DOOR_NO_COPY_BACK))
3973 if (old_door_state & DOOR_OPEN_1)
3974 BlitBitmap(backbuffer, bitmap_db_door_1,
3975 DX, DY, DXSIZE, DYSIZE, 0, 0);
3977 if (old_door_state & DOOR_OPEN_2)
3978 BlitBitmap(backbuffer, bitmap_db_door_2,
3979 VX, VY, VXSIZE, VYSIZE, 0, 0);
3981 door_state &= ~DOOR_NO_COPY_BACK;
3984 return MoveDoor(door_state);
3987 unsigned int GetDoorState()
3989 return MoveDoor(DOOR_GET_STATE);
3992 unsigned int SetDoorState(unsigned int door_state)
3994 return MoveDoor(door_state | DOOR_SET_STATE);
3997 int euclid(int a, int b)
3999 return (b ? euclid(b, a % b) : a);
4002 unsigned int MoveDoor(unsigned int door_state)
4004 struct Rect door_rect_list[] =
4006 { DX, DY, DXSIZE, DYSIZE },
4007 { VX, VY, VXSIZE, VYSIZE }
4009 static int door1 = DOOR_OPEN_1;
4010 static int door2 = DOOR_CLOSE_2;
4011 unsigned int door_delay = 0;
4012 unsigned int door_delay_value;
4015 if (door_state == DOOR_GET_STATE)
4016 return (door1 | door2);
4018 if (door_state & DOOR_SET_STATE)
4020 if (door_state & DOOR_ACTION_1)
4021 door1 = door_state & DOOR_ACTION_1;
4022 if (door_state & DOOR_ACTION_2)
4023 door2 = door_state & DOOR_ACTION_2;
4025 return (door1 | door2);
4028 if (!(door_state & DOOR_FORCE_REDRAW))
4030 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
4031 door_state &= ~DOOR_OPEN_1;
4032 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
4033 door_state &= ~DOOR_CLOSE_1;
4034 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
4035 door_state &= ~DOOR_OPEN_2;
4036 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
4037 door_state &= ~DOOR_CLOSE_2;
4040 if (global.autoplay_leveldir)
4042 door_state |= DOOR_NO_DELAY;
4043 door_state &= ~DOOR_CLOSE_ALL;
4046 if (game_status == GAME_MODE_EDITOR)
4047 door_state |= DOOR_NO_DELAY;
4049 if (door_state & DOOR_ACTION)
4051 boolean door_panel_drawn[NUM_DOORS];
4052 boolean panel_has_doors[NUM_DOORS];
4053 boolean door_part_skip[MAX_DOOR_PARTS];
4054 boolean door_part_done[MAX_DOOR_PARTS];
4055 boolean door_part_done_all;
4056 int num_steps[MAX_DOOR_PARTS];
4057 int max_move_delay = 0; // delay for complete animations of all doors
4058 int max_step_delay = 0; // delay (ms) between two animation frames
4059 int num_move_steps = 0; // number of animation steps for all doors
4060 int max_move_delay_doors_only = 0; // delay for doors only (no panel)
4061 int num_move_steps_doors_only = 0; // steps for doors only (no panel)
4062 int current_move_delay = 0;
4066 for (i = 0; i < NUM_DOORS; i++)
4067 panel_has_doors[i] = FALSE;
4069 for (i = 0; i < MAX_DOOR_PARTS; i++)
4071 struct DoorPartControlInfo *dpc = &door_part_controls[i];
4072 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4073 int door_token = dpc->door_token;
4075 door_part_done[i] = FALSE;
4076 door_part_skip[i] = (!(door_state & door_token) ||
4080 for (i = 0; i < MAX_DOOR_PARTS; i++)
4082 int nr = door_part_order[i].nr;
4083 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
4084 struct DoorPartPosInfo *pos = dpc->pos;
4085 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4086 int door_token = dpc->door_token;
4087 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
4088 boolean is_panel = DOOR_PART_IS_PANEL(nr);
4089 int step_xoffset = ABS(pos->step_xoffset);
4090 int step_yoffset = ABS(pos->step_yoffset);
4091 int step_delay = pos->step_delay;
4092 int current_door_state = door_state & door_token;
4093 boolean door_opening = ((current_door_state & DOOR_OPEN) != 0);
4094 boolean door_closing = ((current_door_state & DOOR_CLOSE) != 0);
4095 boolean part_opening = (is_panel ? door_closing : door_opening);
4096 int start_step = (part_opening ? pos->start_step_opening :
4097 pos->start_step_closing);
4098 float move_xsize = (step_xoffset ? g->width : 0);
4099 float move_ysize = (step_yoffset ? g->height : 0);
4100 int move_xsteps = (step_xoffset ? ceil(move_xsize / step_xoffset) : 0);
4101 int move_ysteps = (step_yoffset ? ceil(move_ysize / step_yoffset) : 0);
4102 int move_steps = (move_xsteps && move_ysteps ?
4103 MIN(move_xsteps, move_ysteps) :
4104 move_xsteps ? move_xsteps : move_ysteps) - start_step;
4105 int move_delay = move_steps * step_delay;
4107 if (door_part_skip[nr])
4110 max_move_delay = MAX(max_move_delay, move_delay);
4111 max_step_delay = (max_step_delay == 0 ? step_delay :
4112 euclid(max_step_delay, step_delay));
4113 num_steps[nr] = move_steps;
4117 max_move_delay_doors_only = MAX(max_move_delay_doors_only, move_delay);
4119 panel_has_doors[door_index] = TRUE;
4123 max_step_delay = MAX(1, max_step_delay); // prevent division by zero
4125 num_move_steps = max_move_delay / max_step_delay;
4126 num_move_steps_doors_only = max_move_delay_doors_only / max_step_delay;
4128 door_delay_value = max_step_delay;
4130 if ((door_state & DOOR_NO_DELAY) || setup.quick_doors)
4132 start = num_move_steps - 1;
4136 /* opening door sound has priority over simultaneously closing door */
4137 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
4138 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
4139 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
4140 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
4143 for (k = start; k < num_move_steps; k++)
4145 int last_frame = num_move_steps - 1; // last frame of this "for" loop
4147 door_part_done_all = TRUE;
4149 for (i = 0; i < NUM_DOORS; i++)
4150 door_panel_drawn[i] = FALSE;
4152 for (i = 0; i < MAX_DOOR_PARTS; i++)
4154 int nr = door_part_order[i].nr;
4155 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
4156 struct DoorPartPosInfo *pos = dpc->pos;
4157 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4158 int door_token = dpc->door_token;
4159 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
4160 boolean is_panel = DOOR_PART_IS_PANEL(nr);
4161 boolean is_panel_and_door_has_closed = FALSE;
4162 struct Rect *door_rect = &door_rect_list[door_index];
4163 Bitmap *bitmap_db_door = (door_token == DOOR_1 ? bitmap_db_door_1 :
4165 Bitmap *bitmap = (is_panel ? bitmap_db_door : g->bitmap);
4166 int current_door_state = door_state & door_token;
4167 boolean door_opening = ((current_door_state & DOOR_OPEN) != 0);
4168 boolean door_closing = !door_opening;
4169 boolean part_opening = (is_panel ? door_closing : door_opening);
4170 boolean part_closing = !part_opening;
4171 int start_step = (part_opening ? pos->start_step_opening :
4172 pos->start_step_closing);
4173 int step_delay = pos->step_delay;
4174 int step_factor = step_delay / max_step_delay;
4175 int k1 = (step_factor ? k / step_factor + 1 : k);
4176 int k2 = (part_opening ? k1 + start_step : num_steps[nr] - k1);
4177 int kk = MAX(0, k2);
4180 int src_x, src_y, src_xx, src_yy;
4181 int dst_x, dst_y, dst_xx, dst_yy;
4184 if (door_part_skip[nr])
4187 if (!(door_state & door_token))
4195 int k2_door = (door_opening ? k : num_move_steps_doors_only - k - 1);
4196 int kk_door = MAX(0, k2_door);
4197 int sync_frame = kk_door * door_delay_value;
4198 int frame = getGraphicAnimationFrame(dpc->graphic, sync_frame);
4200 getGraphicSource(dpc->graphic, frame, &bitmap, &g_src_x, &g_src_y);
4205 if (!door_panel_drawn[door_index])
4207 ClearRectangle(drawto, door_rect->x, door_rect->y,
4208 door_rect->width, door_rect->height);
4210 door_panel_drawn[door_index] = TRUE;
4213 // draw opening or closing door parts
4215 if (pos->step_xoffset < 0) // door part on right side
4218 dst_xx = pos->x + ABS(kk * pos->step_xoffset);
4221 if (dst_xx + width > door_rect->width)
4222 width = door_rect->width - dst_xx;
4224 else // door part on left side
4227 dst_xx = pos->x - kk * pos->step_xoffset;
4231 src_xx = ABS(dst_xx);
4235 width = g->width - src_xx;
4237 // printf("::: k == %d [%d] \n", k, start_step);
4240 if (pos->step_yoffset < 0) // door part on bottom side
4243 dst_yy = pos->y + ABS(kk * pos->step_yoffset);
4246 if (dst_yy + height > door_rect->height)
4247 height = door_rect->height - dst_yy;
4249 else // door part on top side
4252 dst_yy = pos->y - kk * pos->step_yoffset;
4256 src_yy = ABS(dst_yy);
4260 height = g->height - src_yy;
4263 src_x = g_src_x + src_xx;
4264 src_y = g_src_y + src_yy;
4266 dst_x = door_rect->x + dst_xx;
4267 dst_y = door_rect->y + dst_yy;
4269 is_panel_and_door_has_closed =
4272 panel_has_doors[door_index] &&
4273 k >= num_move_steps_doors_only - 1);
4275 if (width >= 0 && width <= g->width &&
4276 height >= 0 && height <= g->height &&
4277 !is_panel_and_door_has_closed)
4279 if (is_panel || !pos->draw_masked)
4280 BlitBitmap(bitmap, drawto, src_x, src_y, width, height,
4283 BlitBitmapMasked(bitmap, drawto, src_x, src_y, width, height,
4287 redraw_mask |= REDRAW_DOOR_FROM_TOKEN(door_token);
4289 if ((part_opening && (width < 0 || height < 0)) ||
4290 (part_closing && (width >= g->width && height >= g->height)))
4291 door_part_done[nr] = TRUE;
4293 // continue door part animations, but not panel after door has closed
4294 if (!door_part_done[nr] && !is_panel_and_door_has_closed)
4295 door_part_done_all = FALSE;
4298 if (!(door_state & DOOR_NO_DELAY))
4302 if (game_status == GAME_MODE_MAIN)
4305 SkipUntilDelayReached(&door_delay, door_delay_value, &k, last_frame);
4307 current_move_delay += max_step_delay;
4310 if (door_part_done_all)
4315 if (door_state & DOOR_ACTION_1)
4316 door1 = door_state & DOOR_ACTION_1;
4317 if (door_state & DOOR_ACTION_2)
4318 door2 = door_state & DOOR_ACTION_2;
4320 return (door1 | door2);
4323 void DrawSpecialEditorDoor()
4325 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
4326 int top_border_width = gfx1->width;
4327 int top_border_height = gfx1->height;
4328 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
4329 int ex = EX - outer_border;
4330 int ey = EY - outer_border;
4331 int vy = VY - outer_border;
4332 int exsize = EXSIZE + 2 * outer_border;
4334 /* draw bigger level editor toolbox window */
4335 BlitBitmap(gfx1->bitmap, drawto, gfx1->src_x, gfx1->src_y,
4336 top_border_width, top_border_height, ex, ey - top_border_height);
4337 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto, ex, vy,
4338 exsize, EYSIZE - VYSIZE + outer_border, ex, ey);
4340 redraw_mask |= REDRAW_ALL;
4343 void UndrawSpecialEditorDoor()
4345 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
4346 int top_border_width = gfx1->width;
4347 int top_border_height = gfx1->height;
4348 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
4349 int ex = EX - outer_border;
4350 int ey = EY - outer_border;
4351 int ey_top = ey - top_border_height;
4352 int exsize = EXSIZE + 2 * outer_border;
4353 int eysize = EYSIZE + 2 * outer_border;
4355 /* draw normal tape recorder window */
4356 if (graphic_info[IMG_GLOBAL_BORDER].bitmap)
4358 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
4359 ex, ey_top, top_border_width, top_border_height,
4361 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
4362 ex, ey, exsize, eysize, ex, ey);
4366 // if screen background is set to "[NONE]", clear editor toolbox window
4367 ClearRectangle(drawto, ex, ey_top, top_border_width, top_border_height);
4368 ClearRectangle(drawto, ex, ey, exsize, eysize);
4371 redraw_mask |= REDRAW_ALL;
4375 /* ---------- new tool button stuff ---------------------------------------- */
4380 struct TextPosInfo *pos;
4383 } toolbutton_info[NUM_TOOL_BUTTONS] =
4386 IMG_REQUEST_BUTTON_GFX_YES, &request.button.yes,
4387 TOOL_CTRL_ID_YES, "yes"
4390 IMG_REQUEST_BUTTON_GFX_NO, &request.button.no,
4391 TOOL_CTRL_ID_NO, "no"
4394 IMG_REQUEST_BUTTON_GFX_CONFIRM, &request.button.confirm,
4395 TOOL_CTRL_ID_CONFIRM, "confirm"
4398 IMG_REQUEST_BUTTON_GFX_PLAYER_1, &request.button.player_1,
4399 TOOL_CTRL_ID_PLAYER_1, "player 1"
4402 IMG_REQUEST_BUTTON_GFX_PLAYER_2, &request.button.player_2,
4403 TOOL_CTRL_ID_PLAYER_2, "player 2"
4406 IMG_REQUEST_BUTTON_GFX_PLAYER_3, &request.button.player_3,
4407 TOOL_CTRL_ID_PLAYER_3, "player 3"
4410 IMG_REQUEST_BUTTON_GFX_PLAYER_4, &request.button.player_4,
4411 TOOL_CTRL_ID_PLAYER_4, "player 4"
4415 void CreateToolButtons()
4419 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4421 struct GraphicInfo *gfx = &graphic_info[toolbutton_info[i].graphic];
4422 struct TextPosInfo *pos = toolbutton_info[i].pos;
4423 struct GadgetInfo *gi;
4424 Bitmap *deco_bitmap = None;
4425 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
4426 unsigned int event_mask = GD_EVENT_RELEASED;
4429 int gd_x = gfx->src_x;
4430 int gd_y = gfx->src_y;
4431 int gd_xp = gfx->src_x + gfx->pressed_xoffset;
4432 int gd_yp = gfx->src_y + gfx->pressed_yoffset;
4435 if (global.use_envelope_request)
4436 setRequestPosition(&dx, &dy, TRUE);
4438 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
4440 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
4442 getSizedGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr), 0,
4443 pos->size, &deco_bitmap, &deco_x, &deco_y);
4444 deco_xpos = (gfx->width - pos->size) / 2;
4445 deco_ypos = (gfx->height - pos->size) / 2;
4448 gi = CreateGadget(GDI_CUSTOM_ID, id,
4449 GDI_INFO_TEXT, toolbutton_info[i].infotext,
4450 GDI_X, dx + GDI_ACTIVE_POS(pos->x),
4451 GDI_Y, dy + GDI_ACTIVE_POS(pos->y),
4452 GDI_WIDTH, gfx->width,
4453 GDI_HEIGHT, gfx->height,
4454 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
4455 GDI_STATE, GD_BUTTON_UNPRESSED,
4456 GDI_DESIGN_UNPRESSED, gfx->bitmap, gd_x, gd_y,
4457 GDI_DESIGN_PRESSED, gfx->bitmap, gd_xp, gd_yp,
4458 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
4459 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
4460 GDI_DECORATION_SIZE, pos->size, pos->size,
4461 GDI_DECORATION_SHIFTING, 1, 1,
4462 GDI_DIRECT_DRAW, FALSE,
4463 GDI_EVENT_MASK, event_mask,
4464 GDI_CALLBACK_ACTION, HandleToolButtons,
4468 Error(ERR_EXIT, "cannot create gadget");
4470 tool_gadget[id] = gi;
4474 void FreeToolButtons()
4478 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4479 FreeGadget(tool_gadget[i]);
4482 static void UnmapToolButtons()
4486 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4487 UnmapGadget(tool_gadget[i]);
4490 static void HandleToolButtons(struct GadgetInfo *gi)
4492 request_gadget_id = gi->custom_id;
4495 static struct Mapping_EM_to_RND_object
4498 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
4499 boolean is_backside; /* backside of moving element */
4505 em_object_mapping_list[] =
4508 Xblank, TRUE, FALSE,
4512 Yacid_splash_eB, FALSE, FALSE,
4513 EL_ACID_SPLASH_RIGHT, -1, -1
4516 Yacid_splash_wB, FALSE, FALSE,
4517 EL_ACID_SPLASH_LEFT, -1, -1
4520 #ifdef EM_ENGINE_BAD_ROLL
4522 Xstone_force_e, FALSE, FALSE,
4523 EL_ROCK, -1, MV_BIT_RIGHT
4526 Xstone_force_w, FALSE, FALSE,
4527 EL_ROCK, -1, MV_BIT_LEFT
4530 Xnut_force_e, FALSE, FALSE,
4531 EL_NUT, -1, MV_BIT_RIGHT
4534 Xnut_force_w, FALSE, FALSE,
4535 EL_NUT, -1, MV_BIT_LEFT
4538 Xspring_force_e, FALSE, FALSE,
4539 EL_SPRING, -1, MV_BIT_RIGHT
4542 Xspring_force_w, FALSE, FALSE,
4543 EL_SPRING, -1, MV_BIT_LEFT
4546 Xemerald_force_e, FALSE, FALSE,
4547 EL_EMERALD, -1, MV_BIT_RIGHT
4550 Xemerald_force_w, FALSE, FALSE,
4551 EL_EMERALD, -1, MV_BIT_LEFT
4554 Xdiamond_force_e, FALSE, FALSE,
4555 EL_DIAMOND, -1, MV_BIT_RIGHT
4558 Xdiamond_force_w, FALSE, FALSE,
4559 EL_DIAMOND, -1, MV_BIT_LEFT
4562 Xbomb_force_e, FALSE, FALSE,
4563 EL_BOMB, -1, MV_BIT_RIGHT
4566 Xbomb_force_w, FALSE, FALSE,
4567 EL_BOMB, -1, MV_BIT_LEFT
4569 #endif /* EM_ENGINE_BAD_ROLL */
4572 Xstone, TRUE, FALSE,
4576 Xstone_pause, FALSE, FALSE,
4580 Xstone_fall, FALSE, FALSE,
4584 Ystone_s, FALSE, FALSE,
4585 EL_ROCK, ACTION_FALLING, -1
4588 Ystone_sB, FALSE, TRUE,
4589 EL_ROCK, ACTION_FALLING, -1
4592 Ystone_e, FALSE, FALSE,
4593 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
4596 Ystone_eB, FALSE, TRUE,
4597 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
4600 Ystone_w, FALSE, FALSE,
4601 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
4604 Ystone_wB, FALSE, TRUE,
4605 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
4612 Xnut_pause, FALSE, FALSE,
4616 Xnut_fall, FALSE, FALSE,
4620 Ynut_s, FALSE, FALSE,
4621 EL_NUT, ACTION_FALLING, -1
4624 Ynut_sB, FALSE, TRUE,
4625 EL_NUT, ACTION_FALLING, -1
4628 Ynut_e, FALSE, FALSE,
4629 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
4632 Ynut_eB, FALSE, TRUE,
4633 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
4636 Ynut_w, FALSE, FALSE,
4637 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
4640 Ynut_wB, FALSE, TRUE,
4641 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
4644 Xbug_n, TRUE, FALSE,
4648 Xbug_e, TRUE, FALSE,
4649 EL_BUG_RIGHT, -1, -1
4652 Xbug_s, TRUE, FALSE,
4656 Xbug_w, TRUE, FALSE,
4660 Xbug_gon, FALSE, FALSE,
4664 Xbug_goe, FALSE, FALSE,
4665 EL_BUG_RIGHT, -1, -1
4668 Xbug_gos, FALSE, FALSE,
4672 Xbug_gow, FALSE, FALSE,
4676 Ybug_n, FALSE, FALSE,
4677 EL_BUG, ACTION_MOVING, MV_BIT_UP
4680 Ybug_nB, FALSE, TRUE,
4681 EL_BUG, ACTION_MOVING, MV_BIT_UP
4684 Ybug_e, FALSE, FALSE,
4685 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
4688 Ybug_eB, FALSE, TRUE,
4689 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
4692 Ybug_s, FALSE, FALSE,
4693 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
4696 Ybug_sB, FALSE, TRUE,
4697 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
4700 Ybug_w, FALSE, FALSE,
4701 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
4704 Ybug_wB, FALSE, TRUE,
4705 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
4708 Ybug_w_n, FALSE, FALSE,
4709 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
4712 Ybug_n_e, FALSE, FALSE,
4713 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
4716 Ybug_e_s, FALSE, FALSE,
4717 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
4720 Ybug_s_w, FALSE, FALSE,
4721 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
4724 Ybug_e_n, FALSE, FALSE,
4725 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
4728 Ybug_s_e, FALSE, FALSE,
4729 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
4732 Ybug_w_s, FALSE, FALSE,
4733 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
4736 Ybug_n_w, FALSE, FALSE,
4737 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
4740 Ybug_stone, FALSE, FALSE,
4741 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
4744 Ybug_spring, FALSE, FALSE,
4745 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
4748 Xtank_n, TRUE, FALSE,
4749 EL_SPACESHIP_UP, -1, -1
4752 Xtank_e, TRUE, FALSE,
4753 EL_SPACESHIP_RIGHT, -1, -1
4756 Xtank_s, TRUE, FALSE,
4757 EL_SPACESHIP_DOWN, -1, -1
4760 Xtank_w, TRUE, FALSE,
4761 EL_SPACESHIP_LEFT, -1, -1
4764 Xtank_gon, FALSE, FALSE,
4765 EL_SPACESHIP_UP, -1, -1
4768 Xtank_goe, FALSE, FALSE,
4769 EL_SPACESHIP_RIGHT, -1, -1
4772 Xtank_gos, FALSE, FALSE,
4773 EL_SPACESHIP_DOWN, -1, -1
4776 Xtank_gow, FALSE, FALSE,
4777 EL_SPACESHIP_LEFT, -1, -1
4780 Ytank_n, FALSE, FALSE,
4781 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
4784 Ytank_nB, FALSE, TRUE,
4785 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
4788 Ytank_e, FALSE, FALSE,
4789 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
4792 Ytank_eB, FALSE, TRUE,
4793 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
4796 Ytank_s, FALSE, FALSE,
4797 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
4800 Ytank_sB, FALSE, TRUE,
4801 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
4804 Ytank_w, FALSE, FALSE,
4805 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
4808 Ytank_wB, FALSE, TRUE,
4809 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
4812 Ytank_w_n, FALSE, FALSE,
4813 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
4816 Ytank_n_e, FALSE, FALSE,
4817 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
4820 Ytank_e_s, FALSE, FALSE,
4821 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
4824 Ytank_s_w, FALSE, FALSE,
4825 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
4828 Ytank_e_n, FALSE, FALSE,
4829 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
4832 Ytank_s_e, FALSE, FALSE,
4833 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
4836 Ytank_w_s, FALSE, FALSE,
4837 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
4840 Ytank_n_w, FALSE, FALSE,
4841 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
4844 Ytank_stone, FALSE, FALSE,
4845 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
4848 Ytank_spring, FALSE, FALSE,
4849 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
4852 Xandroid, TRUE, FALSE,
4853 EL_EMC_ANDROID, ACTION_ACTIVE, -1
4856 Xandroid_1_n, FALSE, FALSE,
4857 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
4860 Xandroid_2_n, FALSE, FALSE,
4861 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
4864 Xandroid_1_e, FALSE, FALSE,
4865 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
4868 Xandroid_2_e, FALSE, FALSE,
4869 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
4872 Xandroid_1_w, FALSE, FALSE,
4873 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
4876 Xandroid_2_w, FALSE, FALSE,
4877 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
4880 Xandroid_1_s, FALSE, FALSE,
4881 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
4884 Xandroid_2_s, FALSE, FALSE,
4885 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
4888 Yandroid_n, FALSE, FALSE,
4889 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
4892 Yandroid_nB, FALSE, TRUE,
4893 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
4896 Yandroid_ne, FALSE, FALSE,
4897 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
4900 Yandroid_neB, FALSE, TRUE,
4901 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
4904 Yandroid_e, FALSE, FALSE,
4905 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
4908 Yandroid_eB, FALSE, TRUE,
4909 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
4912 Yandroid_se, FALSE, FALSE,
4913 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
4916 Yandroid_seB, FALSE, TRUE,
4917 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
4920 Yandroid_s, FALSE, FALSE,
4921 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
4924 Yandroid_sB, FALSE, TRUE,
4925 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
4928 Yandroid_sw, FALSE, FALSE,
4929 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
4932 Yandroid_swB, FALSE, TRUE,
4933 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
4936 Yandroid_w, FALSE, FALSE,
4937 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
4940 Yandroid_wB, FALSE, TRUE,
4941 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
4944 Yandroid_nw, FALSE, FALSE,
4945 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
4948 Yandroid_nwB, FALSE, TRUE,
4949 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
4952 Xspring, TRUE, FALSE,
4956 Xspring_pause, FALSE, FALSE,
4960 Xspring_e, FALSE, FALSE,
4964 Xspring_w, FALSE, FALSE,
4968 Xspring_fall, FALSE, FALSE,
4972 Yspring_s, FALSE, FALSE,
4973 EL_SPRING, ACTION_FALLING, -1
4976 Yspring_sB, FALSE, TRUE,
4977 EL_SPRING, ACTION_FALLING, -1
4980 Yspring_e, FALSE, FALSE,
4981 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
4984 Yspring_eB, FALSE, TRUE,
4985 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
4988 Yspring_w, FALSE, FALSE,
4989 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
4992 Yspring_wB, FALSE, TRUE,
4993 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
4996 Yspring_kill_e, FALSE, FALSE,
4997 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
5000 Yspring_kill_eB, FALSE, TRUE,
5001 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
5004 Yspring_kill_w, FALSE, FALSE,
5005 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
5008 Yspring_kill_wB, FALSE, TRUE,
5009 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
5012 Xeater_n, TRUE, FALSE,
5013 EL_YAMYAM_UP, -1, -1
5016 Xeater_e, TRUE, FALSE,
5017 EL_YAMYAM_RIGHT, -1, -1
5020 Xeater_w, TRUE, FALSE,
5021 EL_YAMYAM_LEFT, -1, -1
5024 Xeater_s, TRUE, FALSE,
5025 EL_YAMYAM_DOWN, -1, -1
5028 Yeater_n, FALSE, FALSE,
5029 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
5032 Yeater_nB, FALSE, TRUE,
5033 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
5036 Yeater_e, FALSE, FALSE,
5037 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
5040 Yeater_eB, FALSE, TRUE,
5041 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
5044 Yeater_s, FALSE, FALSE,
5045 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
5048 Yeater_sB, FALSE, TRUE,
5049 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
5052 Yeater_w, FALSE, FALSE,
5053 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
5056 Yeater_wB, FALSE, TRUE,
5057 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
5060 Yeater_stone, FALSE, FALSE,
5061 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
5064 Yeater_spring, FALSE, FALSE,
5065 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
5068 Xalien, TRUE, FALSE,
5072 Xalien_pause, FALSE, FALSE,
5076 Yalien_n, FALSE, FALSE,
5077 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
5080 Yalien_nB, FALSE, TRUE,
5081 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
5084 Yalien_e, FALSE, FALSE,
5085 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
5088 Yalien_eB, FALSE, TRUE,
5089 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
5092 Yalien_s, FALSE, FALSE,
5093 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
5096 Yalien_sB, FALSE, TRUE,
5097 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
5100 Yalien_w, FALSE, FALSE,
5101 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
5104 Yalien_wB, FALSE, TRUE,
5105 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
5108 Yalien_stone, FALSE, FALSE,
5109 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
5112 Yalien_spring, FALSE, FALSE,
5113 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
5116 Xemerald, TRUE, FALSE,
5120 Xemerald_pause, FALSE, FALSE,
5124 Xemerald_fall, FALSE, FALSE,
5128 Xemerald_shine, FALSE, FALSE,
5129 EL_EMERALD, ACTION_TWINKLING, -1
5132 Yemerald_s, FALSE, FALSE,
5133 EL_EMERALD, ACTION_FALLING, -1
5136 Yemerald_sB, FALSE, TRUE,
5137 EL_EMERALD, ACTION_FALLING, -1
5140 Yemerald_e, FALSE, FALSE,
5141 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
5144 Yemerald_eB, FALSE, TRUE,
5145 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
5148 Yemerald_w, FALSE, FALSE,
5149 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
5152 Yemerald_wB, FALSE, TRUE,
5153 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
5156 Yemerald_eat, FALSE, FALSE,
5157 EL_EMERALD, ACTION_COLLECTING, -1
5160 Yemerald_stone, FALSE, FALSE,
5161 EL_NUT, ACTION_BREAKING, -1
5164 Xdiamond, TRUE, FALSE,
5168 Xdiamond_pause, FALSE, FALSE,
5172 Xdiamond_fall, FALSE, FALSE,
5176 Xdiamond_shine, FALSE, FALSE,
5177 EL_DIAMOND, ACTION_TWINKLING, -1
5180 Ydiamond_s, FALSE, FALSE,
5181 EL_DIAMOND, ACTION_FALLING, -1
5184 Ydiamond_sB, FALSE, TRUE,
5185 EL_DIAMOND, ACTION_FALLING, -1
5188 Ydiamond_e, FALSE, FALSE,
5189 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
5192 Ydiamond_eB, FALSE, TRUE,
5193 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
5196 Ydiamond_w, FALSE, FALSE,
5197 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
5200 Ydiamond_wB, FALSE, TRUE,
5201 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
5204 Ydiamond_eat, FALSE, FALSE,
5205 EL_DIAMOND, ACTION_COLLECTING, -1
5208 Ydiamond_stone, FALSE, FALSE,
5209 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
5212 Xdrip_fall, TRUE, FALSE,
5213 EL_AMOEBA_DROP, -1, -1
5216 Xdrip_stretch, FALSE, FALSE,
5217 EL_AMOEBA_DROP, ACTION_FALLING, -1
5220 Xdrip_stretchB, FALSE, TRUE,
5221 EL_AMOEBA_DROP, ACTION_FALLING, -1
5224 Xdrip_eat, FALSE, FALSE,
5225 EL_AMOEBA_DROP, ACTION_GROWING, -1
5228 Ydrip_s1, FALSE, FALSE,
5229 EL_AMOEBA_DROP, ACTION_FALLING, -1
5232 Ydrip_s1B, FALSE, TRUE,
5233 EL_AMOEBA_DROP, ACTION_FALLING, -1
5236 Ydrip_s2, FALSE, FALSE,
5237 EL_AMOEBA_DROP, ACTION_FALLING, -1
5240 Ydrip_s2B, FALSE, TRUE,
5241 EL_AMOEBA_DROP, ACTION_FALLING, -1
5248 Xbomb_pause, FALSE, FALSE,
5252 Xbomb_fall, FALSE, FALSE,
5256 Ybomb_s, FALSE, FALSE,
5257 EL_BOMB, ACTION_FALLING, -1
5260 Ybomb_sB, FALSE, TRUE,
5261 EL_BOMB, ACTION_FALLING, -1
5264 Ybomb_e, FALSE, FALSE,
5265 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
5268 Ybomb_eB, FALSE, TRUE,
5269 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
5272 Ybomb_w, FALSE, FALSE,
5273 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
5276 Ybomb_wB, FALSE, TRUE,
5277 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
5280 Ybomb_eat, FALSE, FALSE,
5281 EL_BOMB, ACTION_ACTIVATING, -1
5284 Xballoon, TRUE, FALSE,
5288 Yballoon_n, FALSE, FALSE,
5289 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
5292 Yballoon_nB, FALSE, TRUE,
5293 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
5296 Yballoon_e, FALSE, FALSE,
5297 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
5300 Yballoon_eB, FALSE, TRUE,
5301 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
5304 Yballoon_s, FALSE, FALSE,
5305 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
5308 Yballoon_sB, FALSE, TRUE,
5309 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
5312 Yballoon_w, FALSE, FALSE,
5313 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
5316 Yballoon_wB, FALSE, TRUE,
5317 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
5320 Xgrass, TRUE, FALSE,
5321 EL_EMC_GRASS, -1, -1
5324 Ygrass_nB, FALSE, FALSE,
5325 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
5328 Ygrass_eB, FALSE, FALSE,
5329 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
5332 Ygrass_sB, FALSE, FALSE,
5333 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
5336 Ygrass_wB, FALSE, FALSE,
5337 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
5344 Ydirt_nB, FALSE, FALSE,
5345 EL_SAND, ACTION_DIGGING, MV_BIT_UP
5348 Ydirt_eB, FALSE, FALSE,
5349 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
5352 Ydirt_sB, FALSE, FALSE,
5353 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
5356 Ydirt_wB, FALSE, FALSE,
5357 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
5360 Xacid_ne, TRUE, FALSE,
5361 EL_ACID_POOL_TOPRIGHT, -1, -1
5364 Xacid_se, TRUE, FALSE,
5365 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
5368 Xacid_s, TRUE, FALSE,
5369 EL_ACID_POOL_BOTTOM, -1, -1
5372 Xacid_sw, TRUE, FALSE,
5373 EL_ACID_POOL_BOTTOMLEFT, -1, -1
5376 Xacid_nw, TRUE, FALSE,
5377 EL_ACID_POOL_TOPLEFT, -1, -1
5380 Xacid_1, TRUE, FALSE,
5384 Xacid_2, FALSE, FALSE,
5388 Xacid_3, FALSE, FALSE,
5392 Xacid_4, FALSE, FALSE,
5396 Xacid_5, FALSE, FALSE,
5400 Xacid_6, FALSE, FALSE,
5404 Xacid_7, FALSE, FALSE,
5408 Xacid_8, FALSE, FALSE,
5412 Xball_1, TRUE, FALSE,
5413 EL_EMC_MAGIC_BALL, -1, -1
5416 Xball_1B, FALSE, FALSE,
5417 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5420 Xball_2, FALSE, FALSE,
5421 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5424 Xball_2B, FALSE, FALSE,
5425 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5428 Yball_eat, FALSE, FALSE,
5429 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
5432 Ykey_1_eat, FALSE, FALSE,
5433 EL_EM_KEY_1, ACTION_COLLECTING, -1
5436 Ykey_2_eat, FALSE, FALSE,
5437 EL_EM_KEY_2, ACTION_COLLECTING, -1
5440 Ykey_3_eat, FALSE, FALSE,
5441 EL_EM_KEY_3, ACTION_COLLECTING, -1
5444 Ykey_4_eat, FALSE, FALSE,
5445 EL_EM_KEY_4, ACTION_COLLECTING, -1
5448 Ykey_5_eat, FALSE, FALSE,
5449 EL_EMC_KEY_5, ACTION_COLLECTING, -1
5452 Ykey_6_eat, FALSE, FALSE,
5453 EL_EMC_KEY_6, ACTION_COLLECTING, -1
5456 Ykey_7_eat, FALSE, FALSE,
5457 EL_EMC_KEY_7, ACTION_COLLECTING, -1
5460 Ykey_8_eat, FALSE, FALSE,
5461 EL_EMC_KEY_8, ACTION_COLLECTING, -1
5464 Ylenses_eat, FALSE, FALSE,
5465 EL_EMC_LENSES, ACTION_COLLECTING, -1
5468 Ymagnify_eat, FALSE, FALSE,
5469 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
5472 Ygrass_eat, FALSE, FALSE,
5473 EL_EMC_GRASS, ACTION_SNAPPING, -1
5476 Ydirt_eat, FALSE, FALSE,
5477 EL_SAND, ACTION_SNAPPING, -1
5480 Xgrow_ns, TRUE, FALSE,
5481 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
5484 Ygrow_ns_eat, FALSE, FALSE,
5485 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
5488 Xgrow_ew, TRUE, FALSE,
5489 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
5492 Ygrow_ew_eat, FALSE, FALSE,
5493 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
5496 Xwonderwall, TRUE, FALSE,
5497 EL_MAGIC_WALL, -1, -1
5500 XwonderwallB, FALSE, FALSE,
5501 EL_MAGIC_WALL, ACTION_ACTIVE, -1
5504 Xamoeba_1, TRUE, FALSE,
5505 EL_AMOEBA_DRY, ACTION_OTHER, -1
5508 Xamoeba_2, FALSE, FALSE,
5509 EL_AMOEBA_DRY, ACTION_OTHER, -1
5512 Xamoeba_3, FALSE, FALSE,
5513 EL_AMOEBA_DRY, ACTION_OTHER, -1
5516 Xamoeba_4, FALSE, FALSE,
5517 EL_AMOEBA_DRY, ACTION_OTHER, -1
5520 Xamoeba_5, TRUE, FALSE,
5521 EL_AMOEBA_WET, ACTION_OTHER, -1
5524 Xamoeba_6, FALSE, FALSE,
5525 EL_AMOEBA_WET, ACTION_OTHER, -1
5528 Xamoeba_7, FALSE, FALSE,
5529 EL_AMOEBA_WET, ACTION_OTHER, -1
5532 Xamoeba_8, FALSE, FALSE,
5533 EL_AMOEBA_WET, ACTION_OTHER, -1
5536 Xdoor_1, TRUE, FALSE,
5537 EL_EM_GATE_1, -1, -1
5540 Xdoor_2, TRUE, FALSE,
5541 EL_EM_GATE_2, -1, -1
5544 Xdoor_3, TRUE, FALSE,
5545 EL_EM_GATE_3, -1, -1
5548 Xdoor_4, TRUE, FALSE,
5549 EL_EM_GATE_4, -1, -1
5552 Xdoor_5, TRUE, FALSE,
5553 EL_EMC_GATE_5, -1, -1
5556 Xdoor_6, TRUE, FALSE,
5557 EL_EMC_GATE_6, -1, -1
5560 Xdoor_7, TRUE, FALSE,
5561 EL_EMC_GATE_7, -1, -1
5564 Xdoor_8, TRUE, FALSE,
5565 EL_EMC_GATE_8, -1, -1
5568 Xkey_1, TRUE, FALSE,
5572 Xkey_2, TRUE, FALSE,
5576 Xkey_3, TRUE, FALSE,
5580 Xkey_4, TRUE, FALSE,
5584 Xkey_5, TRUE, FALSE,
5585 EL_EMC_KEY_5, -1, -1
5588 Xkey_6, TRUE, FALSE,
5589 EL_EMC_KEY_6, -1, -1
5592 Xkey_7, TRUE, FALSE,
5593 EL_EMC_KEY_7, -1, -1
5596 Xkey_8, TRUE, FALSE,
5597 EL_EMC_KEY_8, -1, -1
5600 Xwind_n, TRUE, FALSE,
5601 EL_BALLOON_SWITCH_UP, -1, -1
5604 Xwind_e, TRUE, FALSE,
5605 EL_BALLOON_SWITCH_RIGHT, -1, -1
5608 Xwind_s, TRUE, FALSE,
5609 EL_BALLOON_SWITCH_DOWN, -1, -1
5612 Xwind_w, TRUE, FALSE,
5613 EL_BALLOON_SWITCH_LEFT, -1, -1
5616 Xwind_nesw, TRUE, FALSE,
5617 EL_BALLOON_SWITCH_ANY, -1, -1
5620 Xwind_stop, TRUE, FALSE,
5621 EL_BALLOON_SWITCH_NONE, -1, -1
5625 EL_EM_EXIT_CLOSED, -1, -1
5628 Xexit_1, TRUE, FALSE,
5629 EL_EM_EXIT_OPEN, -1, -1
5632 Xexit_2, FALSE, FALSE,
5633 EL_EM_EXIT_OPEN, -1, -1
5636 Xexit_3, FALSE, FALSE,
5637 EL_EM_EXIT_OPEN, -1, -1
5640 Xdynamite, TRUE, FALSE,
5641 EL_EM_DYNAMITE, -1, -1
5644 Ydynamite_eat, FALSE, FALSE,
5645 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
5648 Xdynamite_1, TRUE, FALSE,
5649 EL_EM_DYNAMITE_ACTIVE, -1, -1
5652 Xdynamite_2, FALSE, FALSE,
5653 EL_EM_DYNAMITE_ACTIVE, -1, -1
5656 Xdynamite_3, FALSE, FALSE,
5657 EL_EM_DYNAMITE_ACTIVE, -1, -1
5660 Xdynamite_4, FALSE, FALSE,
5661 EL_EM_DYNAMITE_ACTIVE, -1, -1
5664 Xbumper, TRUE, FALSE,
5665 EL_EMC_SPRING_BUMPER, -1, -1
5668 XbumperB, FALSE, FALSE,
5669 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
5672 Xwheel, TRUE, FALSE,
5673 EL_ROBOT_WHEEL, -1, -1
5676 XwheelB, FALSE, FALSE,
5677 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
5680 Xswitch, TRUE, FALSE,
5681 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
5684 XswitchB, FALSE, FALSE,
5685 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
5689 EL_QUICKSAND_EMPTY, -1, -1
5692 Xsand_stone, TRUE, FALSE,
5693 EL_QUICKSAND_FULL, -1, -1
5696 Xsand_stonein_1, FALSE, TRUE,
5697 EL_ROCK, ACTION_FILLING, -1
5700 Xsand_stonein_2, FALSE, TRUE,
5701 EL_ROCK, ACTION_FILLING, -1
5704 Xsand_stonein_3, FALSE, TRUE,
5705 EL_ROCK, ACTION_FILLING, -1
5708 Xsand_stonein_4, FALSE, TRUE,
5709 EL_ROCK, ACTION_FILLING, -1
5712 Xsand_stonesand_1, FALSE, FALSE,
5713 EL_QUICKSAND_EMPTYING, -1, -1
5716 Xsand_stonesand_2, FALSE, FALSE,
5717 EL_QUICKSAND_EMPTYING, -1, -1
5720 Xsand_stonesand_3, FALSE, FALSE,
5721 EL_QUICKSAND_EMPTYING, -1, -1
5724 Xsand_stonesand_4, FALSE, FALSE,
5725 EL_QUICKSAND_EMPTYING, -1, -1
5728 Xsand_stonesand_quickout_1, FALSE, FALSE,
5729 EL_QUICKSAND_EMPTYING, -1, -1
5732 Xsand_stonesand_quickout_2, FALSE, FALSE,
5733 EL_QUICKSAND_EMPTYING, -1, -1
5736 Xsand_stoneout_1, FALSE, FALSE,
5737 EL_ROCK, ACTION_EMPTYING, -1
5740 Xsand_stoneout_2, FALSE, FALSE,
5741 EL_ROCK, ACTION_EMPTYING, -1
5744 Xsand_sandstone_1, FALSE, FALSE,
5745 EL_QUICKSAND_FILLING, -1, -1
5748 Xsand_sandstone_2, FALSE, FALSE,
5749 EL_QUICKSAND_FILLING, -1, -1
5752 Xsand_sandstone_3, FALSE, FALSE,
5753 EL_QUICKSAND_FILLING, -1, -1
5756 Xsand_sandstone_4, FALSE, FALSE,
5757 EL_QUICKSAND_FILLING, -1, -1
5760 Xplant, TRUE, FALSE,
5761 EL_EMC_PLANT, -1, -1
5764 Yplant, FALSE, FALSE,
5765 EL_EMC_PLANT, -1, -1
5768 Xlenses, TRUE, FALSE,
5769 EL_EMC_LENSES, -1, -1
5772 Xmagnify, TRUE, FALSE,
5773 EL_EMC_MAGNIFIER, -1, -1
5776 Xdripper, TRUE, FALSE,
5777 EL_EMC_DRIPPER, -1, -1
5780 XdripperB, FALSE, FALSE,
5781 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
5784 Xfake_blank, TRUE, FALSE,
5785 EL_INVISIBLE_WALL, -1, -1
5788 Xfake_blankB, FALSE, FALSE,
5789 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
5792 Xfake_grass, TRUE, FALSE,
5793 EL_EMC_FAKE_GRASS, -1, -1
5796 Xfake_grassB, FALSE, FALSE,
5797 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
5800 Xfake_door_1, TRUE, FALSE,
5801 EL_EM_GATE_1_GRAY, -1, -1
5804 Xfake_door_2, TRUE, FALSE,
5805 EL_EM_GATE_2_GRAY, -1, -1
5808 Xfake_door_3, TRUE, FALSE,
5809 EL_EM_GATE_3_GRAY, -1, -1
5812 Xfake_door_4, TRUE, FALSE,
5813 EL_EM_GATE_4_GRAY, -1, -1
5816 Xfake_door_5, TRUE, FALSE,
5817 EL_EMC_GATE_5_GRAY, -1, -1
5820 Xfake_door_6, TRUE, FALSE,
5821 EL_EMC_GATE_6_GRAY, -1, -1
5824 Xfake_door_7, TRUE, FALSE,
5825 EL_EMC_GATE_7_GRAY, -1, -1
5828 Xfake_door_8, TRUE, FALSE,
5829 EL_EMC_GATE_8_GRAY, -1, -1
5832 Xfake_acid_1, TRUE, FALSE,
5833 EL_EMC_FAKE_ACID, -1, -1
5836 Xfake_acid_2, FALSE, FALSE,
5837 EL_EMC_FAKE_ACID, -1, -1
5840 Xfake_acid_3, FALSE, FALSE,
5841 EL_EMC_FAKE_ACID, -1, -1
5844 Xfake_acid_4, FALSE, FALSE,
5845 EL_EMC_FAKE_ACID, -1, -1
5848 Xfake_acid_5, FALSE, FALSE,
5849 EL_EMC_FAKE_ACID, -1, -1
5852 Xfake_acid_6, FALSE, FALSE,
5853 EL_EMC_FAKE_ACID, -1, -1
5856 Xfake_acid_7, FALSE, FALSE,
5857 EL_EMC_FAKE_ACID, -1, -1
5860 Xfake_acid_8, FALSE, FALSE,
5861 EL_EMC_FAKE_ACID, -1, -1
5864 Xsteel_1, TRUE, FALSE,
5865 EL_STEELWALL, -1, -1
5868 Xsteel_2, TRUE, FALSE,
5869 EL_EMC_STEELWALL_2, -1, -1
5872 Xsteel_3, TRUE, FALSE,
5873 EL_EMC_STEELWALL_3, -1, -1
5876 Xsteel_4, TRUE, FALSE,
5877 EL_EMC_STEELWALL_4, -1, -1
5880 Xwall_1, TRUE, FALSE,
5884 Xwall_2, TRUE, FALSE,
5885 EL_EMC_WALL_14, -1, -1
5888 Xwall_3, TRUE, FALSE,
5889 EL_EMC_WALL_15, -1, -1
5892 Xwall_4, TRUE, FALSE,
5893 EL_EMC_WALL_16, -1, -1
5896 Xround_wall_1, TRUE, FALSE,
5897 EL_WALL_SLIPPERY, -1, -1
5900 Xround_wall_2, TRUE, FALSE,
5901 EL_EMC_WALL_SLIPPERY_2, -1, -1
5904 Xround_wall_3, TRUE, FALSE,
5905 EL_EMC_WALL_SLIPPERY_3, -1, -1
5908 Xround_wall_4, TRUE, FALSE,
5909 EL_EMC_WALL_SLIPPERY_4, -1, -1
5912 Xdecor_1, TRUE, FALSE,
5913 EL_EMC_WALL_8, -1, -1
5916 Xdecor_2, TRUE, FALSE,
5917 EL_EMC_WALL_6, -1, -1
5920 Xdecor_3, TRUE, FALSE,
5921 EL_EMC_WALL_4, -1, -1
5924 Xdecor_4, TRUE, FALSE,
5925 EL_EMC_WALL_7, -1, -1
5928 Xdecor_5, TRUE, FALSE,
5929 EL_EMC_WALL_5, -1, -1
5932 Xdecor_6, TRUE, FALSE,
5933 EL_EMC_WALL_9, -1, -1
5936 Xdecor_7, TRUE, FALSE,
5937 EL_EMC_WALL_10, -1, -1
5940 Xdecor_8, TRUE, FALSE,
5941 EL_EMC_WALL_1, -1, -1
5944 Xdecor_9, TRUE, FALSE,
5945 EL_EMC_WALL_2, -1, -1
5948 Xdecor_10, TRUE, FALSE,
5949 EL_EMC_WALL_3, -1, -1
5952 Xdecor_11, TRUE, FALSE,
5953 EL_EMC_WALL_11, -1, -1
5956 Xdecor_12, TRUE, FALSE,
5957 EL_EMC_WALL_12, -1, -1
5960 Xalpha_0, TRUE, FALSE,
5961 EL_CHAR('0'), -1, -1
5964 Xalpha_1, TRUE, FALSE,
5965 EL_CHAR('1'), -1, -1
5968 Xalpha_2, TRUE, FALSE,
5969 EL_CHAR('2'), -1, -1
5972 Xalpha_3, TRUE, FALSE,
5973 EL_CHAR('3'), -1, -1
5976 Xalpha_4, TRUE, FALSE,
5977 EL_CHAR('4'), -1, -1
5980 Xalpha_5, TRUE, FALSE,
5981 EL_CHAR('5'), -1, -1
5984 Xalpha_6, TRUE, FALSE,
5985 EL_CHAR('6'), -1, -1
5988 Xalpha_7, TRUE, FALSE,
5989 EL_CHAR('7'), -1, -1
5992 Xalpha_8, TRUE, FALSE,
5993 EL_CHAR('8'), -1, -1
5996 Xalpha_9, TRUE, FALSE,
5997 EL_CHAR('9'), -1, -1
6000 Xalpha_excla, TRUE, FALSE,
6001 EL_CHAR('!'), -1, -1
6004 Xalpha_quote, TRUE, FALSE,
6005 EL_CHAR('"'), -1, -1
6008 Xalpha_comma, TRUE, FALSE,
6009 EL_CHAR(','), -1, -1
6012 Xalpha_minus, TRUE, FALSE,
6013 EL_CHAR('-'), -1, -1
6016 Xalpha_perio, TRUE, FALSE,
6017 EL_CHAR('.'), -1, -1
6020 Xalpha_colon, TRUE, FALSE,
6021 EL_CHAR(':'), -1, -1
6024 Xalpha_quest, TRUE, FALSE,
6025 EL_CHAR('?'), -1, -1
6028 Xalpha_a, TRUE, FALSE,
6029 EL_CHAR('A'), -1, -1
6032 Xalpha_b, TRUE, FALSE,
6033 EL_CHAR('B'), -1, -1
6036 Xalpha_c, TRUE, FALSE,
6037 EL_CHAR('C'), -1, -1
6040 Xalpha_d, TRUE, FALSE,
6041 EL_CHAR('D'), -1, -1
6044 Xalpha_e, TRUE, FALSE,
6045 EL_CHAR('E'), -1, -1
6048 Xalpha_f, TRUE, FALSE,
6049 EL_CHAR('F'), -1, -1
6052 Xalpha_g, TRUE, FALSE,
6053 EL_CHAR('G'), -1, -1
6056 Xalpha_h, TRUE, FALSE,
6057 EL_CHAR('H'), -1, -1
6060 Xalpha_i, TRUE, FALSE,
6061 EL_CHAR('I'), -1, -1
6064 Xalpha_j, TRUE, FALSE,
6065 EL_CHAR('J'), -1, -1
6068 Xalpha_k, TRUE, FALSE,
6069 EL_CHAR('K'), -1, -1
6072 Xalpha_l, TRUE, FALSE,
6073 EL_CHAR('L'), -1, -1
6076 Xalpha_m, TRUE, FALSE,
6077 EL_CHAR('M'), -1, -1
6080 Xalpha_n, TRUE, FALSE,
6081 EL_CHAR('N'), -1, -1
6084 Xalpha_o, TRUE, FALSE,
6085 EL_CHAR('O'), -1, -1
6088 Xalpha_p, TRUE, FALSE,
6089 EL_CHAR('P'), -1, -1
6092 Xalpha_q, TRUE, FALSE,
6093 EL_CHAR('Q'), -1, -1
6096 Xalpha_r, TRUE, FALSE,
6097 EL_CHAR('R'), -1, -1
6100 Xalpha_s, TRUE, FALSE,
6101 EL_CHAR('S'), -1, -1
6104 Xalpha_t, TRUE, FALSE,
6105 EL_CHAR('T'), -1, -1
6108 Xalpha_u, TRUE, FALSE,
6109 EL_CHAR('U'), -1, -1
6112 Xalpha_v, TRUE, FALSE,
6113 EL_CHAR('V'), -1, -1
6116 Xalpha_w, TRUE, FALSE,
6117 EL_CHAR('W'), -1, -1
6120 Xalpha_x, TRUE, FALSE,
6121 EL_CHAR('X'), -1, -1
6124 Xalpha_y, TRUE, FALSE,
6125 EL_CHAR('Y'), -1, -1
6128 Xalpha_z, TRUE, FALSE,
6129 EL_CHAR('Z'), -1, -1
6132 Xalpha_arrow_e, TRUE, FALSE,
6133 EL_CHAR('>'), -1, -1
6136 Xalpha_arrow_w, TRUE, FALSE,
6137 EL_CHAR('<'), -1, -1
6140 Xalpha_copyr, TRUE, FALSE,
6141 EL_CHAR(CHAR_BYTE_COPYRIGHT), -1, -1
6145 Xboom_bug, FALSE, FALSE,
6146 EL_BUG, ACTION_EXPLODING, -1
6149 Xboom_bomb, FALSE, FALSE,
6150 EL_BOMB, ACTION_EXPLODING, -1
6153 Xboom_android, FALSE, FALSE,
6154 EL_EMC_ANDROID, ACTION_OTHER, -1
6157 Xboom_1, FALSE, FALSE,
6158 EL_DEFAULT, ACTION_EXPLODING, -1
6161 Xboom_2, FALSE, FALSE,
6162 EL_DEFAULT, ACTION_EXPLODING, -1
6165 Znormal, FALSE, FALSE,
6169 Zdynamite, FALSE, FALSE,
6173 Zplayer, FALSE, FALSE,
6177 ZBORDER, FALSE, FALSE,
6187 static struct Mapping_EM_to_RND_player
6196 em_player_mapping_list[] =
6200 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
6204 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
6208 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
6212 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
6216 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
6220 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
6224 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
6228 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
6232 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
6236 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
6240 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
6244 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
6248 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
6252 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
6256 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
6260 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
6264 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
6268 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
6272 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
6276 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
6280 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
6284 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
6288 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
6292 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
6296 EL_PLAYER_1, ACTION_DEFAULT, -1,
6300 EL_PLAYER_2, ACTION_DEFAULT, -1,
6304 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
6308 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
6312 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
6316 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
6320 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
6324 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
6328 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
6332 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
6336 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
6340 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
6344 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
6348 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
6352 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
6356 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
6360 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
6364 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
6368 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
6372 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
6376 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
6380 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
6384 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
6388 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
6392 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
6396 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
6400 EL_PLAYER_3, ACTION_DEFAULT, -1,
6404 EL_PLAYER_4, ACTION_DEFAULT, -1,
6413 int map_element_RND_to_EM(int element_rnd)
6415 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
6416 static boolean mapping_initialized = FALSE;
6418 if (!mapping_initialized)
6422 /* return "Xalpha_quest" for all undefined elements in mapping array */
6423 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
6424 mapping_RND_to_EM[i] = Xalpha_quest;
6426 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6427 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
6428 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
6429 em_object_mapping_list[i].element_em;
6431 mapping_initialized = TRUE;
6434 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
6435 return mapping_RND_to_EM[element_rnd];
6437 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
6442 int map_element_EM_to_RND(int element_em)
6444 static unsigned short mapping_EM_to_RND[TILE_MAX];
6445 static boolean mapping_initialized = FALSE;
6447 if (!mapping_initialized)
6451 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
6452 for (i = 0; i < TILE_MAX; i++)
6453 mapping_EM_to_RND[i] = EL_UNKNOWN;
6455 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6456 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
6457 em_object_mapping_list[i].element_rnd;
6459 mapping_initialized = TRUE;
6462 if (element_em >= 0 && element_em < TILE_MAX)
6463 return mapping_EM_to_RND[element_em];
6465 Error(ERR_WARN, "invalid EM level element %d", element_em);
6470 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
6472 struct LevelInfo_EM *level_em = level->native_em_level;
6473 struct LEVEL *lev = level_em->lev;
6476 for (i = 0; i < TILE_MAX; i++)
6477 lev->android_array[i] = Xblank;
6479 for (i = 0; i < level->num_android_clone_elements; i++)
6481 int element_rnd = level->android_clone_element[i];
6482 int element_em = map_element_RND_to_EM(element_rnd);
6484 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
6485 if (em_object_mapping_list[j].element_rnd == element_rnd)
6486 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
6490 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
6492 struct LevelInfo_EM *level_em = level->native_em_level;
6493 struct LEVEL *lev = level_em->lev;
6496 level->num_android_clone_elements = 0;
6498 for (i = 0; i < TILE_MAX; i++)
6500 int element_em = lev->android_array[i];
6502 boolean element_found = FALSE;
6504 if (element_em == Xblank)
6507 element_rnd = map_element_EM_to_RND(element_em);
6509 for (j = 0; j < level->num_android_clone_elements; j++)
6510 if (level->android_clone_element[j] == element_rnd)
6511 element_found = TRUE;
6515 level->android_clone_element[level->num_android_clone_elements++] =
6518 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
6523 if (level->num_android_clone_elements == 0)
6525 level->num_android_clone_elements = 1;
6526 level->android_clone_element[0] = EL_EMPTY;
6530 int map_direction_RND_to_EM(int direction)
6532 return (direction == MV_UP ? 0 :
6533 direction == MV_RIGHT ? 1 :
6534 direction == MV_DOWN ? 2 :
6535 direction == MV_LEFT ? 3 :
6539 int map_direction_EM_to_RND(int direction)
6541 return (direction == 0 ? MV_UP :
6542 direction == 1 ? MV_RIGHT :
6543 direction == 2 ? MV_DOWN :
6544 direction == 3 ? MV_LEFT :
6548 int map_element_RND_to_SP(int element_rnd)
6550 int element_sp = 0x20; /* map unknown elements to yellow "hardware" */
6552 if (element_rnd >= EL_SP_START &&
6553 element_rnd <= EL_SP_END)
6554 element_sp = element_rnd - EL_SP_START;
6555 else if (element_rnd == EL_EMPTY_SPACE)
6557 else if (element_rnd == EL_INVISIBLE_WALL)
6563 int map_element_SP_to_RND(int element_sp)
6565 int element_rnd = EL_UNKNOWN;
6567 if (element_sp >= 0x00 &&
6569 element_rnd = EL_SP_START + element_sp;
6570 else if (element_sp == 0x28)
6571 element_rnd = EL_INVISIBLE_WALL;
6576 int map_action_SP_to_RND(int action_sp)
6580 case actActive: return ACTION_ACTIVE;
6581 case actImpact: return ACTION_IMPACT;
6582 case actExploding: return ACTION_EXPLODING;
6583 case actDigging: return ACTION_DIGGING;
6584 case actSnapping: return ACTION_SNAPPING;
6585 case actCollecting: return ACTION_COLLECTING;
6586 case actPassing: return ACTION_PASSING;
6587 case actPushing: return ACTION_PUSHING;
6588 case actDropping: return ACTION_DROPPING;
6590 default: return ACTION_DEFAULT;
6594 int get_next_element(int element)
6598 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
6599 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
6600 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
6601 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
6602 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
6603 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
6604 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
6605 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
6606 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
6607 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
6608 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
6610 default: return element;
6614 int el_act_dir2img(int element, int action, int direction)
6616 element = GFX_ELEMENT(element);
6617 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
6619 /* direction_graphic[][] == graphic[] for undefined direction graphics */
6620 return element_info[element].direction_graphic[action][direction];
6623 static int el_act_dir2crm(int element, int action, int direction)
6625 element = GFX_ELEMENT(element);
6626 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
6628 /* direction_graphic[][] == graphic[] for undefined direction graphics */
6629 return element_info[element].direction_crumbled[action][direction];
6632 int el_act2img(int element, int action)
6634 element = GFX_ELEMENT(element);
6636 return element_info[element].graphic[action];
6639 int el_act2crm(int element, int action)
6641 element = GFX_ELEMENT(element);
6643 return element_info[element].crumbled[action];
6646 int el_dir2img(int element, int direction)
6648 element = GFX_ELEMENT(element);
6650 return el_act_dir2img(element, ACTION_DEFAULT, direction);
6653 int el2baseimg(int element)
6655 return element_info[element].graphic[ACTION_DEFAULT];
6658 int el2img(int element)
6660 element = GFX_ELEMENT(element);
6662 return element_info[element].graphic[ACTION_DEFAULT];
6665 int el2edimg(int element)
6667 element = GFX_ELEMENT(element);
6669 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
6672 int el2preimg(int element)
6674 element = GFX_ELEMENT(element);
6676 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
6679 int el2panelimg(int element)
6681 element = GFX_ELEMENT(element);
6683 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL];
6686 int font2baseimg(int font_nr)
6688 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
6691 int getBeltNrFromBeltElement(int element)
6693 return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
6694 element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
6695 element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
6698 int getBeltNrFromBeltActiveElement(int element)
6700 return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
6701 element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
6702 element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
6705 int getBeltNrFromBeltSwitchElement(int element)
6707 return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
6708 element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
6709 element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
6712 int getBeltDirNrFromBeltElement(int element)
6714 static int belt_base_element[4] =
6716 EL_CONVEYOR_BELT_1_LEFT,
6717 EL_CONVEYOR_BELT_2_LEFT,
6718 EL_CONVEYOR_BELT_3_LEFT,
6719 EL_CONVEYOR_BELT_4_LEFT
6722 int belt_nr = getBeltNrFromBeltElement(element);
6723 int belt_dir_nr = element - belt_base_element[belt_nr];
6725 return (belt_dir_nr % 3);
6728 int getBeltDirNrFromBeltSwitchElement(int element)
6730 static int belt_base_element[4] =
6732 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
6733 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
6734 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
6735 EL_CONVEYOR_BELT_4_SWITCH_LEFT
6738 int belt_nr = getBeltNrFromBeltSwitchElement(element);
6739 int belt_dir_nr = element - belt_base_element[belt_nr];
6741 return (belt_dir_nr % 3);
6744 int getBeltDirFromBeltElement(int element)
6746 static int belt_move_dir[3] =
6753 int belt_dir_nr = getBeltDirNrFromBeltElement(element);
6755 return belt_move_dir[belt_dir_nr];
6758 int getBeltDirFromBeltSwitchElement(int element)
6760 static int belt_move_dir[3] =
6767 int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
6769 return belt_move_dir[belt_dir_nr];
6772 int getBeltElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
6774 static int belt_base_element[4] =
6776 EL_CONVEYOR_BELT_1_LEFT,
6777 EL_CONVEYOR_BELT_2_LEFT,
6778 EL_CONVEYOR_BELT_3_LEFT,
6779 EL_CONVEYOR_BELT_4_LEFT
6782 return belt_base_element[belt_nr] + belt_dir_nr;
6785 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
6787 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
6789 return getBeltElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
6792 int getBeltSwitchElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
6794 static int belt_base_element[4] =
6796 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
6797 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
6798 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
6799 EL_CONVEYOR_BELT_4_SWITCH_LEFT
6802 return belt_base_element[belt_nr] + belt_dir_nr;
6805 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
6807 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
6809 return getBeltSwitchElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
6812 boolean getTeamMode_EM()
6814 return game.team_mode;
6817 int getGameFrameDelay_EM(int native_em_game_frame_delay)
6819 int game_frame_delay_value;
6821 game_frame_delay_value =
6822 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
6823 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
6826 if (tape.playing && tape.warp_forward && !tape.pausing)
6827 game_frame_delay_value = 0;
6829 return game_frame_delay_value;
6832 unsigned int InitRND(int seed)
6834 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
6835 return InitEngineRandom_EM(seed);
6836 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
6837 return InitEngineRandom_SP(seed);
6839 return InitEngineRandom_RND(seed);
6842 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
6843 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
6845 inline static int get_effective_element_EM(int tile, int frame_em)
6847 int element = object_mapping[tile].element_rnd;
6848 int action = object_mapping[tile].action;
6849 boolean is_backside = object_mapping[tile].is_backside;
6850 boolean action_removing = (action == ACTION_DIGGING ||
6851 action == ACTION_SNAPPING ||
6852 action == ACTION_COLLECTING);
6858 case Yacid_splash_eB:
6859 case Yacid_splash_wB:
6860 return (frame_em > 5 ? EL_EMPTY : element);
6866 else /* frame_em == 7 */
6870 case Yacid_splash_eB:
6871 case Yacid_splash_wB:
6874 case Yemerald_stone:
6877 case Ydiamond_stone:
6881 case Xdrip_stretchB:
6900 case Xsand_stonein_1:
6901 case Xsand_stonein_2:
6902 case Xsand_stonein_3:
6903 case Xsand_stonein_4:
6907 return (is_backside || action_removing ? EL_EMPTY : element);
6912 inline static boolean check_linear_animation_EM(int tile)
6916 case Xsand_stonesand_1:
6917 case Xsand_stonesand_quickout_1:
6918 case Xsand_sandstone_1:
6919 case Xsand_stonein_1:
6920 case Xsand_stoneout_1:
6939 case Yacid_splash_eB:
6940 case Yacid_splash_wB:
6941 case Yemerald_stone:
6948 inline static void set_crumbled_graphics_EM(struct GraphicInfo_EM *g_em,
6949 boolean has_crumbled_graphics,
6950 int crumbled, int sync_frame)
6952 /* if element can be crumbled, but certain action graphics are just empty
6953 space (like instantly snapping sand to empty space in 1 frame), do not
6954 treat these empty space graphics as crumbled graphics in EMC engine */
6955 if (crumbled == IMG_EMPTY_SPACE)
6956 has_crumbled_graphics = FALSE;
6958 if (has_crumbled_graphics)
6960 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
6961 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
6962 g_crumbled->anim_delay,
6963 g_crumbled->anim_mode,
6964 g_crumbled->anim_start_frame,
6967 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
6968 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
6970 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
6972 g_em->has_crumbled_graphics = TRUE;
6976 g_em->crumbled_bitmap = NULL;
6977 g_em->crumbled_src_x = 0;
6978 g_em->crumbled_src_y = 0;
6979 g_em->crumbled_border_size = 0;
6981 g_em->has_crumbled_graphics = FALSE;
6985 void ResetGfxAnimation_EM(int x, int y, int tile)
6990 void SetGfxAnimation_EM(struct GraphicInfo_EM *g_em,
6991 int tile, int frame_em, int x, int y)
6993 int action = object_mapping[tile].action;
6994 int direction = object_mapping[tile].direction;
6995 int effective_element = get_effective_element_EM(tile, frame_em);
6996 int graphic = (direction == MV_NONE ?
6997 el_act2img(effective_element, action) :
6998 el_act_dir2img(effective_element, action, direction));
6999 struct GraphicInfo *g = &graphic_info[graphic];
7001 boolean action_removing = (action == ACTION_DIGGING ||
7002 action == ACTION_SNAPPING ||
7003 action == ACTION_COLLECTING);
7004 boolean action_moving = (action == ACTION_FALLING ||
7005 action == ACTION_MOVING ||
7006 action == ACTION_PUSHING ||
7007 action == ACTION_EATING ||
7008 action == ACTION_FILLING ||
7009 action == ACTION_EMPTYING);
7010 boolean action_falling = (action == ACTION_FALLING ||
7011 action == ACTION_FILLING ||
7012 action == ACTION_EMPTYING);
7014 /* special case: graphic uses "2nd movement tile" and has defined
7015 7 frames for movement animation (or less) => use default graphic
7016 for last (8th) frame which ends the movement animation */
7017 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
7019 action = ACTION_DEFAULT; /* (keep action_* unchanged for now) */
7020 graphic = (direction == MV_NONE ?
7021 el_act2img(effective_element, action) :
7022 el_act_dir2img(effective_element, action, direction));
7024 g = &graphic_info[graphic];
7027 if ((action_removing || check_linear_animation_EM(tile)) && frame_em == 0)
7031 else if (action_moving)
7033 boolean is_backside = object_mapping[tile].is_backside;
7037 int direction = object_mapping[tile].direction;
7038 int move_dir = (action_falling ? MV_DOWN : direction);
7043 /* !!! TEST !!! NEW !!! DOES NOT WORK RIGHT YET !!! */
7044 if (g->double_movement && frame_em == 0)
7048 if (move_dir == MV_LEFT)
7049 GfxFrame[x - 1][y] = GfxFrame[x][y];
7050 else if (move_dir == MV_RIGHT)
7051 GfxFrame[x + 1][y] = GfxFrame[x][y];
7052 else if (move_dir == MV_UP)
7053 GfxFrame[x][y - 1] = GfxFrame[x][y];
7054 else if (move_dir == MV_DOWN)
7055 GfxFrame[x][y + 1] = GfxFrame[x][y];
7062 /* special case: animation for Xsand_stonesand_quickout_1/2 twice as fast */
7063 if (tile == Xsand_stonesand_quickout_1 ||
7064 tile == Xsand_stonesand_quickout_2)
7068 if (graphic_info[graphic].anim_global_sync)
7069 sync_frame = FrameCounter;
7070 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
7071 sync_frame = GfxFrame[x][y];
7073 sync_frame = 0; /* playfield border (pseudo steel) */
7075 SetRandomAnimationValue(x, y);
7077 int frame = getAnimationFrame(g->anim_frames,
7080 g->anim_start_frame,
7083 g_em->unique_identifier =
7084 (graphic << 16) | ((frame % 8) << 12) | (g_em->width << 6) | g_em->height;
7087 void getGraphicSourceObjectExt_EM(struct GraphicInfo_EM *g_em,
7088 int tile, int frame_em, int x, int y)
7090 int action = object_mapping[tile].action;
7091 int direction = object_mapping[tile].direction;
7092 boolean is_backside = object_mapping[tile].is_backside;
7093 int effective_element = get_effective_element_EM(tile, frame_em);
7094 int effective_action = action;
7095 int graphic = (direction == MV_NONE ?
7096 el_act2img(effective_element, effective_action) :
7097 el_act_dir2img(effective_element, effective_action,
7099 int crumbled = (direction == MV_NONE ?
7100 el_act2crm(effective_element, effective_action) :
7101 el_act_dir2crm(effective_element, effective_action,
7103 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7104 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7105 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7106 struct GraphicInfo *g = &graphic_info[graphic];
7109 /* special case: graphic uses "2nd movement tile" and has defined
7110 7 frames for movement animation (or less) => use default graphic
7111 for last (8th) frame which ends the movement animation */
7112 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
7114 effective_action = ACTION_DEFAULT;
7115 graphic = (direction == MV_NONE ?
7116 el_act2img(effective_element, effective_action) :
7117 el_act_dir2img(effective_element, effective_action,
7119 crumbled = (direction == MV_NONE ?
7120 el_act2crm(effective_element, effective_action) :
7121 el_act_dir2crm(effective_element, effective_action,
7124 g = &graphic_info[graphic];
7127 if (graphic_info[graphic].anim_global_sync)
7128 sync_frame = FrameCounter;
7129 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
7130 sync_frame = GfxFrame[x][y];
7132 sync_frame = 0; /* playfield border (pseudo steel) */
7134 SetRandomAnimationValue(x, y);
7136 int frame = getAnimationFrame(g->anim_frames,
7139 g->anim_start_frame,
7142 getGraphicSourceExt(graphic, frame, &g_em->bitmap, &g_em->src_x, &g_em->src_y,
7143 g->double_movement && is_backside);
7145 /* (updating the "crumbled" graphic definitions is probably not really needed,
7146 as animations for crumbled graphics can't be longer than one EMC cycle) */
7147 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
7151 void getGraphicSourcePlayerExt_EM(struct GraphicInfo_EM *g_em,
7152 int player_nr, int anim, int frame_em)
7154 int element = player_mapping[player_nr][anim].element_rnd;
7155 int action = player_mapping[player_nr][anim].action;
7156 int direction = player_mapping[player_nr][anim].direction;
7157 int graphic = (direction == MV_NONE ?
7158 el_act2img(element, action) :
7159 el_act_dir2img(element, action, direction));
7160 struct GraphicInfo *g = &graphic_info[graphic];
7163 InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
7165 stored_player[player_nr].StepFrame = frame_em;
7167 sync_frame = stored_player[player_nr].Frame;
7169 int frame = getAnimationFrame(g->anim_frames,
7172 g->anim_start_frame,
7175 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
7176 &g_em->src_x, &g_em->src_y, FALSE);
7179 void InitGraphicInfo_EM(void)
7184 int num_em_gfx_errors = 0;
7186 if (graphic_info_em_object[0][0].bitmap == NULL)
7188 /* EM graphics not yet initialized in em_open_all() */
7193 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
7196 /* always start with reliable default values */
7197 for (i = 0; i < TILE_MAX; i++)
7199 object_mapping[i].element_rnd = EL_UNKNOWN;
7200 object_mapping[i].is_backside = FALSE;
7201 object_mapping[i].action = ACTION_DEFAULT;
7202 object_mapping[i].direction = MV_NONE;
7205 /* always start with reliable default values */
7206 for (p = 0; p < MAX_PLAYERS; p++)
7208 for (i = 0; i < SPR_MAX; i++)
7210 player_mapping[p][i].element_rnd = EL_UNKNOWN;
7211 player_mapping[p][i].action = ACTION_DEFAULT;
7212 player_mapping[p][i].direction = MV_NONE;
7216 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
7218 int e = em_object_mapping_list[i].element_em;
7220 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
7221 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
7223 if (em_object_mapping_list[i].action != -1)
7224 object_mapping[e].action = em_object_mapping_list[i].action;
7226 if (em_object_mapping_list[i].direction != -1)
7227 object_mapping[e].direction =
7228 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
7231 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
7233 int a = em_player_mapping_list[i].action_em;
7234 int p = em_player_mapping_list[i].player_nr;
7236 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
7238 if (em_player_mapping_list[i].action != -1)
7239 player_mapping[p][a].action = em_player_mapping_list[i].action;
7241 if (em_player_mapping_list[i].direction != -1)
7242 player_mapping[p][a].direction =
7243 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
7246 for (i = 0; i < TILE_MAX; i++)
7248 int element = object_mapping[i].element_rnd;
7249 int action = object_mapping[i].action;
7250 int direction = object_mapping[i].direction;
7251 boolean is_backside = object_mapping[i].is_backside;
7252 boolean action_exploding = ((action == ACTION_EXPLODING ||
7253 action == ACTION_SMASHED_BY_ROCK ||
7254 action == ACTION_SMASHED_BY_SPRING) &&
7255 element != EL_DIAMOND);
7256 boolean action_active = (action == ACTION_ACTIVE);
7257 boolean action_other = (action == ACTION_OTHER);
7259 for (j = 0; j < 8; j++)
7261 int effective_element = get_effective_element_EM(i, j);
7262 int effective_action = (j < 7 ? action :
7263 i == Xdrip_stretch ? action :
7264 i == Xdrip_stretchB ? action :
7265 i == Ydrip_s1 ? action :
7266 i == Ydrip_s1B ? action :
7267 i == Xball_1B ? action :
7268 i == Xball_2 ? action :
7269 i == Xball_2B ? action :
7270 i == Yball_eat ? action :
7271 i == Ykey_1_eat ? action :
7272 i == Ykey_2_eat ? action :
7273 i == Ykey_3_eat ? action :
7274 i == Ykey_4_eat ? action :
7275 i == Ykey_5_eat ? action :
7276 i == Ykey_6_eat ? action :
7277 i == Ykey_7_eat ? action :
7278 i == Ykey_8_eat ? action :
7279 i == Ylenses_eat ? action :
7280 i == Ymagnify_eat ? action :
7281 i == Ygrass_eat ? action :
7282 i == Ydirt_eat ? action :
7283 i == Xsand_stonein_1 ? action :
7284 i == Xsand_stonein_2 ? action :
7285 i == Xsand_stonein_3 ? action :
7286 i == Xsand_stonein_4 ? action :
7287 i == Xsand_stoneout_1 ? action :
7288 i == Xsand_stoneout_2 ? action :
7289 i == Xboom_android ? ACTION_EXPLODING :
7290 action_exploding ? ACTION_EXPLODING :
7291 action_active ? action :
7292 action_other ? action :
7294 int graphic = (el_act_dir2img(effective_element, effective_action,
7296 int crumbled = (el_act_dir2crm(effective_element, effective_action,
7298 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7299 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7300 boolean has_action_graphics = (graphic != base_graphic);
7301 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7302 struct GraphicInfo *g = &graphic_info[graphic];
7303 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7306 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
7307 boolean special_animation = (action != ACTION_DEFAULT &&
7308 g->anim_frames == 3 &&
7309 g->anim_delay == 2 &&
7310 g->anim_mode & ANIM_LINEAR);
7311 int sync_frame = (i == Xdrip_stretch ? 7 :
7312 i == Xdrip_stretchB ? 7 :
7313 i == Ydrip_s2 ? j + 8 :
7314 i == Ydrip_s2B ? j + 8 :
7323 i == Xfake_acid_1 ? 0 :
7324 i == Xfake_acid_2 ? 10 :
7325 i == Xfake_acid_3 ? 20 :
7326 i == Xfake_acid_4 ? 30 :
7327 i == Xfake_acid_5 ? 40 :
7328 i == Xfake_acid_6 ? 50 :
7329 i == Xfake_acid_7 ? 60 :
7330 i == Xfake_acid_8 ? 70 :
7332 i == Xball_2B ? j + 8 :
7333 i == Yball_eat ? j + 1 :
7334 i == Ykey_1_eat ? j + 1 :
7335 i == Ykey_2_eat ? j + 1 :
7336 i == Ykey_3_eat ? j + 1 :
7337 i == Ykey_4_eat ? j + 1 :
7338 i == Ykey_5_eat ? j + 1 :
7339 i == Ykey_6_eat ? j + 1 :
7340 i == Ykey_7_eat ? j + 1 :
7341 i == Ykey_8_eat ? j + 1 :
7342 i == Ylenses_eat ? j + 1 :
7343 i == Ymagnify_eat ? j + 1 :
7344 i == Ygrass_eat ? j + 1 :
7345 i == Ydirt_eat ? j + 1 :
7346 i == Xamoeba_1 ? 0 :
7347 i == Xamoeba_2 ? 1 :
7348 i == Xamoeba_3 ? 2 :
7349 i == Xamoeba_4 ? 3 :
7350 i == Xamoeba_5 ? 0 :
7351 i == Xamoeba_6 ? 1 :
7352 i == Xamoeba_7 ? 2 :
7353 i == Xamoeba_8 ? 3 :
7354 i == Xexit_2 ? j + 8 :
7355 i == Xexit_3 ? j + 16 :
7356 i == Xdynamite_1 ? 0 :
7357 i == Xdynamite_2 ? 8 :
7358 i == Xdynamite_3 ? 16 :
7359 i == Xdynamite_4 ? 24 :
7360 i == Xsand_stonein_1 ? j + 1 :
7361 i == Xsand_stonein_2 ? j + 9 :
7362 i == Xsand_stonein_3 ? j + 17 :
7363 i == Xsand_stonein_4 ? j + 25 :
7364 i == Xsand_stoneout_1 && j == 0 ? 0 :
7365 i == Xsand_stoneout_1 && j == 1 ? 0 :
7366 i == Xsand_stoneout_1 && j == 2 ? 1 :
7367 i == Xsand_stoneout_1 && j == 3 ? 2 :
7368 i == Xsand_stoneout_1 && j == 4 ? 2 :
7369 i == Xsand_stoneout_1 && j == 5 ? 3 :
7370 i == Xsand_stoneout_1 && j == 6 ? 4 :
7371 i == Xsand_stoneout_1 && j == 7 ? 4 :
7372 i == Xsand_stoneout_2 && j == 0 ? 5 :
7373 i == Xsand_stoneout_2 && j == 1 ? 6 :
7374 i == Xsand_stoneout_2 && j == 2 ? 7 :
7375 i == Xsand_stoneout_2 && j == 3 ? 8 :
7376 i == Xsand_stoneout_2 && j == 4 ? 9 :
7377 i == Xsand_stoneout_2 && j == 5 ? 11 :
7378 i == Xsand_stoneout_2 && j == 6 ? 13 :
7379 i == Xsand_stoneout_2 && j == 7 ? 15 :
7380 i == Xboom_bug && j == 1 ? 2 :
7381 i == Xboom_bug && j == 2 ? 2 :
7382 i == Xboom_bug && j == 3 ? 4 :
7383 i == Xboom_bug && j == 4 ? 4 :
7384 i == Xboom_bug && j == 5 ? 2 :
7385 i == Xboom_bug && j == 6 ? 2 :
7386 i == Xboom_bug && j == 7 ? 0 :
7387 i == Xboom_bomb && j == 1 ? 2 :
7388 i == Xboom_bomb && j == 2 ? 2 :
7389 i == Xboom_bomb && j == 3 ? 4 :
7390 i == Xboom_bomb && j == 4 ? 4 :
7391 i == Xboom_bomb && j == 5 ? 2 :
7392 i == Xboom_bomb && j == 6 ? 2 :
7393 i == Xboom_bomb && j == 7 ? 0 :
7394 i == Xboom_android && j == 7 ? 6 :
7395 i == Xboom_1 && j == 1 ? 2 :
7396 i == Xboom_1 && j == 2 ? 2 :
7397 i == Xboom_1 && j == 3 ? 4 :
7398 i == Xboom_1 && j == 4 ? 4 :
7399 i == Xboom_1 && j == 5 ? 6 :
7400 i == Xboom_1 && j == 6 ? 6 :
7401 i == Xboom_1 && j == 7 ? 8 :
7402 i == Xboom_2 && j == 0 ? 8 :
7403 i == Xboom_2 && j == 1 ? 8 :
7404 i == Xboom_2 && j == 2 ? 10 :
7405 i == Xboom_2 && j == 3 ? 10 :
7406 i == Xboom_2 && j == 4 ? 10 :
7407 i == Xboom_2 && j == 5 ? 12 :
7408 i == Xboom_2 && j == 6 ? 12 :
7409 i == Xboom_2 && j == 7 ? 12 :
7410 special_animation && j == 4 ? 3 :
7411 effective_action != action ? 0 :
7415 Bitmap *debug_bitmap = g_em->bitmap;
7416 int debug_src_x = g_em->src_x;
7417 int debug_src_y = g_em->src_y;
7420 int frame = getAnimationFrame(g->anim_frames,
7423 g->anim_start_frame,
7426 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
7427 g->double_movement && is_backside);
7429 g_em->bitmap = src_bitmap;
7430 g_em->src_x = src_x;
7431 g_em->src_y = src_y;
7432 g_em->src_offset_x = 0;
7433 g_em->src_offset_y = 0;
7434 g_em->dst_offset_x = 0;
7435 g_em->dst_offset_y = 0;
7436 g_em->width = TILEX;
7437 g_em->height = TILEY;
7439 g_em->preserve_background = FALSE;
7441 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
7444 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
7445 effective_action == ACTION_MOVING ||
7446 effective_action == ACTION_PUSHING ||
7447 effective_action == ACTION_EATING)) ||
7448 (!has_action_graphics && (effective_action == ACTION_FILLING ||
7449 effective_action == ACTION_EMPTYING)))
7452 (effective_action == ACTION_FALLING ||
7453 effective_action == ACTION_FILLING ||
7454 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
7455 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
7456 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
7457 int num_steps = (i == Ydrip_s1 ? 16 :
7458 i == Ydrip_s1B ? 16 :
7459 i == Ydrip_s2 ? 16 :
7460 i == Ydrip_s2B ? 16 :
7461 i == Xsand_stonein_1 ? 32 :
7462 i == Xsand_stonein_2 ? 32 :
7463 i == Xsand_stonein_3 ? 32 :
7464 i == Xsand_stonein_4 ? 32 :
7465 i == Xsand_stoneout_1 ? 16 :
7466 i == Xsand_stoneout_2 ? 16 : 8);
7467 int cx = ABS(dx) * (TILEX / num_steps);
7468 int cy = ABS(dy) * (TILEY / num_steps);
7469 int step_frame = (i == Ydrip_s2 ? j + 8 :
7470 i == Ydrip_s2B ? j + 8 :
7471 i == Xsand_stonein_2 ? j + 8 :
7472 i == Xsand_stonein_3 ? j + 16 :
7473 i == Xsand_stonein_4 ? j + 24 :
7474 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
7475 int step = (is_backside ? step_frame : num_steps - step_frame);
7477 if (is_backside) /* tile where movement starts */
7479 if (dx < 0 || dy < 0)
7481 g_em->src_offset_x = cx * step;
7482 g_em->src_offset_y = cy * step;
7486 g_em->dst_offset_x = cx * step;
7487 g_em->dst_offset_y = cy * step;
7490 else /* tile where movement ends */
7492 if (dx < 0 || dy < 0)
7494 g_em->dst_offset_x = cx * step;
7495 g_em->dst_offset_y = cy * step;
7499 g_em->src_offset_x = cx * step;
7500 g_em->src_offset_y = cy * step;
7504 g_em->width = TILEX - cx * step;
7505 g_em->height = TILEY - cy * step;
7508 /* create unique graphic identifier to decide if tile must be redrawn */
7509 /* bit 31 - 16 (16 bit): EM style graphic
7510 bit 15 - 12 ( 4 bit): EM style frame
7511 bit 11 - 6 ( 6 bit): graphic width
7512 bit 5 - 0 ( 6 bit): graphic height */
7513 g_em->unique_identifier =
7514 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
7518 /* skip check for EMC elements not contained in original EMC artwork */
7519 if (element == EL_EMC_FAKE_ACID)
7522 if (g_em->bitmap != debug_bitmap ||
7523 g_em->src_x != debug_src_x ||
7524 g_em->src_y != debug_src_y ||
7525 g_em->src_offset_x != 0 ||
7526 g_em->src_offset_y != 0 ||
7527 g_em->dst_offset_x != 0 ||
7528 g_em->dst_offset_y != 0 ||
7529 g_em->width != TILEX ||
7530 g_em->height != TILEY)
7532 static int last_i = -1;
7540 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
7541 i, element, element_info[element].token_name,
7542 element_action_info[effective_action].suffix, direction);
7544 if (element != effective_element)
7545 printf(" [%d ('%s')]",
7547 element_info[effective_element].token_name);
7551 if (g_em->bitmap != debug_bitmap)
7552 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
7553 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
7555 if (g_em->src_x != debug_src_x ||
7556 g_em->src_y != debug_src_y)
7557 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
7558 j, (is_backside ? 'B' : 'F'),
7559 g_em->src_x, g_em->src_y,
7560 g_em->src_x / 32, g_em->src_y / 32,
7561 debug_src_x, debug_src_y,
7562 debug_src_x / 32, debug_src_y / 32);
7564 if (g_em->src_offset_x != 0 ||
7565 g_em->src_offset_y != 0 ||
7566 g_em->dst_offset_x != 0 ||
7567 g_em->dst_offset_y != 0)
7568 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
7570 g_em->src_offset_x, g_em->src_offset_y,
7571 g_em->dst_offset_x, g_em->dst_offset_y);
7573 if (g_em->width != TILEX ||
7574 g_em->height != TILEY)
7575 printf(" %d (%d): size %d,%d should be %d,%d\n",
7577 g_em->width, g_em->height, TILEX, TILEY);
7579 num_em_gfx_errors++;
7586 for (i = 0; i < TILE_MAX; i++)
7588 for (j = 0; j < 8; j++)
7590 int element = object_mapping[i].element_rnd;
7591 int action = object_mapping[i].action;
7592 int direction = object_mapping[i].direction;
7593 boolean is_backside = object_mapping[i].is_backside;
7594 int graphic_action = el_act_dir2img(element, action, direction);
7595 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
7597 if ((action == ACTION_SMASHED_BY_ROCK ||
7598 action == ACTION_SMASHED_BY_SPRING ||
7599 action == ACTION_EATING) &&
7600 graphic_action == graphic_default)
7602 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
7603 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
7604 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
7605 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
7608 /* no separate animation for "smashed by rock" -- use rock instead */
7609 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7610 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
7612 g_em->bitmap = g_xx->bitmap;
7613 g_em->src_x = g_xx->src_x;
7614 g_em->src_y = g_xx->src_y;
7615 g_em->src_offset_x = g_xx->src_offset_x;
7616 g_em->src_offset_y = g_xx->src_offset_y;
7617 g_em->dst_offset_x = g_xx->dst_offset_x;
7618 g_em->dst_offset_y = g_xx->dst_offset_y;
7619 g_em->width = g_xx->width;
7620 g_em->height = g_xx->height;
7621 g_em->unique_identifier = g_xx->unique_identifier;
7624 g_em->preserve_background = TRUE;
7629 for (p = 0; p < MAX_PLAYERS; p++)
7631 for (i = 0; i < SPR_MAX; i++)
7633 int element = player_mapping[p][i].element_rnd;
7634 int action = player_mapping[p][i].action;
7635 int direction = player_mapping[p][i].direction;
7637 for (j = 0; j < 8; j++)
7639 int effective_element = element;
7640 int effective_action = action;
7641 int graphic = (direction == MV_NONE ?
7642 el_act2img(effective_element, effective_action) :
7643 el_act_dir2img(effective_element, effective_action,
7645 struct GraphicInfo *g = &graphic_info[graphic];
7646 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
7652 Bitmap *debug_bitmap = g_em->bitmap;
7653 int debug_src_x = g_em->src_x;
7654 int debug_src_y = g_em->src_y;
7657 int frame = getAnimationFrame(g->anim_frames,
7660 g->anim_start_frame,
7663 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
7665 g_em->bitmap = src_bitmap;
7666 g_em->src_x = src_x;
7667 g_em->src_y = src_y;
7668 g_em->src_offset_x = 0;
7669 g_em->src_offset_y = 0;
7670 g_em->dst_offset_x = 0;
7671 g_em->dst_offset_y = 0;
7672 g_em->width = TILEX;
7673 g_em->height = TILEY;
7677 /* skip check for EMC elements not contained in original EMC artwork */
7678 if (element == EL_PLAYER_3 ||
7679 element == EL_PLAYER_4)
7682 if (g_em->bitmap != debug_bitmap ||
7683 g_em->src_x != debug_src_x ||
7684 g_em->src_y != debug_src_y)
7686 static int last_i = -1;
7694 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
7695 p, i, element, element_info[element].token_name,
7696 element_action_info[effective_action].suffix, direction);
7698 if (element != effective_element)
7699 printf(" [%d ('%s')]",
7701 element_info[effective_element].token_name);
7705 if (g_em->bitmap != debug_bitmap)
7706 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
7707 j, (int)(g_em->bitmap), (int)(debug_bitmap));
7709 if (g_em->src_x != debug_src_x ||
7710 g_em->src_y != debug_src_y)
7711 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
7713 g_em->src_x, g_em->src_y,
7714 g_em->src_x / 32, g_em->src_y / 32,
7715 debug_src_x, debug_src_y,
7716 debug_src_x / 32, debug_src_y / 32);
7718 num_em_gfx_errors++;
7728 printf("::: [%d errors found]\n", num_em_gfx_errors);
7734 void CheckSaveEngineSnapshot_EM(byte action[MAX_PLAYERS], int frame,
7735 boolean any_player_moving,
7736 boolean any_player_snapping,
7737 boolean any_player_dropping)
7739 static boolean player_was_waiting = TRUE;
7741 if (frame == 0 && !any_player_dropping)
7743 if (!player_was_waiting)
7745 if (!SaveEngineSnapshotToList())
7748 player_was_waiting = TRUE;
7751 else if (any_player_moving || any_player_snapping || any_player_dropping)
7753 player_was_waiting = FALSE;
7757 void CheckSaveEngineSnapshot_SP(boolean murphy_is_waiting,
7758 boolean murphy_is_dropping)
7760 static boolean player_was_waiting = TRUE;
7762 if (murphy_is_waiting)
7764 if (!player_was_waiting)
7766 if (!SaveEngineSnapshotToList())
7769 player_was_waiting = TRUE;
7774 player_was_waiting = FALSE;
7778 void CheckSingleStepMode_EM(byte action[MAX_PLAYERS], int frame,
7779 boolean any_player_moving,
7780 boolean any_player_snapping,
7781 boolean any_player_dropping)
7783 if (tape.single_step && tape.recording && !tape.pausing)
7784 if (frame == 0 && !any_player_dropping)
7785 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
7787 CheckSaveEngineSnapshot_EM(action, frame, any_player_moving,
7788 any_player_snapping, any_player_dropping);
7791 void CheckSingleStepMode_SP(boolean murphy_is_waiting,
7792 boolean murphy_is_dropping)
7794 if (tape.single_step && tape.recording && !tape.pausing)
7795 if (murphy_is_waiting)
7796 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
7798 CheckSaveEngineSnapshot_SP(murphy_is_waiting, murphy_is_dropping);
7801 void getGraphicSource_SP(struct GraphicInfo_SP *g_sp,
7802 int graphic, int sync_frame, int x, int y)
7804 int frame = getGraphicAnimationFrame(graphic, sync_frame);
7806 getGraphicSource(graphic, frame, &g_sp->bitmap, &g_sp->src_x, &g_sp->src_y);
7809 boolean isNextAnimationFrame_SP(int graphic, int sync_frame)
7811 return (IS_NEXT_FRAME(sync_frame, graphic));
7814 int getGraphicInfo_Delay(int graphic)
7816 return graphic_info[graphic].anim_delay;
7819 void PlayMenuSoundExt(int sound)
7821 if (sound == SND_UNDEFINED)
7824 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
7825 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
7828 if (IS_LOOP_SOUND(sound))
7829 PlaySoundLoop(sound);
7834 void PlayMenuSound()
7836 PlayMenuSoundExt(menu.sound[game_status]);
7839 void PlayMenuSoundStereo(int sound, int stereo_position)
7841 if (sound == SND_UNDEFINED)
7844 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
7845 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
7848 if (IS_LOOP_SOUND(sound))
7849 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
7851 PlaySoundStereo(sound, stereo_position);
7854 void PlayMenuSoundIfLoopExt(int sound)
7856 if (sound == SND_UNDEFINED)
7859 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
7860 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
7863 if (IS_LOOP_SOUND(sound))
7864 PlaySoundLoop(sound);
7867 void PlayMenuSoundIfLoop()
7869 PlayMenuSoundIfLoopExt(menu.sound[game_status]);
7872 void PlayMenuMusicExt(int music)
7874 if (music == MUS_UNDEFINED)
7877 if (!setup.sound_music)
7883 void PlayMenuMusic()
7885 PlayMenuMusicExt(menu.music[game_status]);
7888 void PlaySoundActivating()
7891 PlaySound(SND_MENU_ITEM_ACTIVATING);
7895 void PlaySoundSelecting()
7898 PlaySound(SND_MENU_ITEM_SELECTING);
7902 void ToggleFullscreenOrChangeWindowScalingIfNeeded()
7904 boolean change_fullscreen = (setup.fullscreen !=
7905 video.fullscreen_enabled);
7906 boolean change_fullscreen_mode = (video.fullscreen_enabled &&
7907 !strEqual(setup.fullscreen_mode,
7908 video.fullscreen_mode_current));
7909 boolean change_window_scaling_percent = (!video.fullscreen_enabled &&
7910 setup.window_scaling_percent !=
7911 video.window_scaling_percent);
7913 if (change_window_scaling_percent && video.fullscreen_enabled)
7916 if (!change_window_scaling_percent && !video.fullscreen_available)
7919 #if defined(TARGET_SDL2)
7920 if (change_window_scaling_percent)
7922 SDLSetWindowScaling(setup.window_scaling_percent);
7926 else if (change_fullscreen)
7928 SDLSetWindowFullscreen(setup.fullscreen);
7930 /* set setup value according to successfully changed fullscreen mode */
7931 setup.fullscreen = video.fullscreen_enabled;
7937 if (change_fullscreen ||
7938 change_fullscreen_mode ||
7939 change_window_scaling_percent)
7941 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
7943 /* save backbuffer content which gets lost when toggling fullscreen mode */
7944 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
7946 if (change_fullscreen_mode)
7948 /* keep fullscreen, but change fullscreen mode (screen resolution) */
7949 video.fullscreen_enabled = FALSE; /* force new fullscreen mode */
7952 if (change_window_scaling_percent)
7954 /* keep window mode, but change window scaling */
7955 video.fullscreen_enabled = TRUE; /* force new window scaling */
7958 /* toggle fullscreen */
7959 ChangeVideoModeIfNeeded(setup.fullscreen);
7961 /* set setup value according to successfully changed fullscreen mode */
7962 setup.fullscreen = video.fullscreen_enabled;
7964 /* restore backbuffer content from temporary backbuffer backup bitmap */
7965 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
7967 FreeBitmap(tmp_backbuffer);
7969 /* update visible window/screen */
7970 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
7974 void ChangeViewportPropertiesIfNeeded()
7976 int gfx_game_mode = game_status;
7977 int gfx_game_mode2 = (game_status == GAME_MODE_EDITOR ? GAME_MODE_DEFAULT :
7979 struct RectWithBorder *vp_playfield = &viewport.playfield[gfx_game_mode];
7980 struct RectWithBorder *vp_door_1 = &viewport.door_1[gfx_game_mode];
7981 struct RectWithBorder *vp_door_2 = &viewport.door_2[gfx_game_mode2];
7982 struct RectWithBorder *vp_door_3 = &viewport.door_2[GAME_MODE_EDITOR];
7983 int border_size = vp_playfield->border_size;
7984 int new_sx = vp_playfield->x + border_size;
7985 int new_sy = vp_playfield->y + border_size;
7986 int new_sxsize = vp_playfield->width - 2 * border_size;
7987 int new_sysize = vp_playfield->height - 2 * border_size;
7988 int new_real_sx = vp_playfield->x;
7989 int new_real_sy = vp_playfield->y;
7990 int new_full_sxsize = vp_playfield->width;
7991 int new_full_sysize = vp_playfield->height;
7992 int new_dx = vp_door_1->x;
7993 int new_dy = vp_door_1->y;
7994 int new_dxsize = vp_door_1->width;
7995 int new_dysize = vp_door_1->height;
7996 int new_vx = vp_door_2->x;
7997 int new_vy = vp_door_2->y;
7998 int new_vxsize = vp_door_2->width;
7999 int new_vysize = vp_door_2->height;
8000 int new_ex = vp_door_3->x;
8001 int new_ey = vp_door_3->y;
8002 int new_exsize = vp_door_3->width;
8003 int new_eysize = vp_door_3->height;
8004 int new_tilesize_var =
8005 (setup.small_game_graphics ? MINI_TILESIZE : game.tile_size);
8007 int tilesize = (gfx_game_mode == GAME_MODE_PLAYING ? new_tilesize_var :
8008 gfx_game_mode == GAME_MODE_EDITOR ? MINI_TILESIZE : TILESIZE);
8009 int new_scr_fieldx = new_sxsize / tilesize;
8010 int new_scr_fieldy = new_sysize / tilesize;
8011 int new_scr_fieldx_buffers = new_sxsize / new_tilesize_var;
8012 int new_scr_fieldy_buffers = new_sysize / new_tilesize_var;
8013 boolean init_gfx_buffers = FALSE;
8014 boolean init_video_buffer = FALSE;
8015 boolean init_gadgets_and_toons = FALSE;
8016 boolean init_em_graphics = FALSE;
8017 boolean drawing_area_changed = FALSE;
8019 if (viewport.window.width != WIN_XSIZE ||
8020 viewport.window.height != WIN_YSIZE)
8022 WIN_XSIZE = viewport.window.width;
8023 WIN_YSIZE = viewport.window.height;
8025 init_video_buffer = TRUE;
8026 init_gfx_buffers = TRUE;
8028 // printf("::: video: init_video_buffer, init_gfx_buffers\n");
8031 if (new_scr_fieldx != SCR_FIELDX ||
8032 new_scr_fieldy != SCR_FIELDY)
8034 /* this always toggles between MAIN and GAME when using small tile size */
8036 SCR_FIELDX = new_scr_fieldx;
8037 SCR_FIELDY = new_scr_fieldy;
8039 // printf("::: new_scr_fieldx != SCR_FIELDX ...\n");
8050 new_sxsize != SXSIZE ||
8051 new_sysize != SYSIZE ||
8052 new_dxsize != DXSIZE ||
8053 new_dysize != DYSIZE ||
8054 new_vxsize != VXSIZE ||
8055 new_vysize != VYSIZE ||
8056 new_exsize != EXSIZE ||
8057 new_eysize != EYSIZE ||
8058 new_real_sx != REAL_SX ||
8059 new_real_sy != REAL_SY ||
8060 new_full_sxsize != FULL_SXSIZE ||
8061 new_full_sysize != FULL_SYSIZE ||
8062 new_tilesize_var != TILESIZE_VAR
8065 if (new_tilesize_var != TILESIZE_VAR)
8067 // printf("::: new_tilesize_var != TILESIZE_VAR\n");
8069 // changing tile size invalidates scroll values of engine snapshots
8070 FreeEngineSnapshotSingle();
8072 // changing tile size requires update of graphic mapping for EM engine
8073 init_em_graphics = TRUE;
8078 new_sxsize != SXSIZE ||
8079 new_sysize != SYSIZE ||
8080 new_real_sx != REAL_SX ||
8081 new_real_sy != REAL_SY ||
8082 new_full_sxsize != FULL_SXSIZE ||
8083 new_full_sysize != FULL_SYSIZE)
8085 if (!init_video_buffer)
8086 drawing_area_changed = TRUE;
8097 SXSIZE = new_sxsize;
8098 SYSIZE = new_sysize;
8099 DXSIZE = new_dxsize;
8100 DYSIZE = new_dysize;
8101 VXSIZE = new_vxsize;
8102 VYSIZE = new_vysize;
8103 EXSIZE = new_exsize;
8104 EYSIZE = new_eysize;
8105 REAL_SX = new_real_sx;
8106 REAL_SY = new_real_sy;
8107 FULL_SXSIZE = new_full_sxsize;
8108 FULL_SYSIZE = new_full_sysize;
8109 TILESIZE_VAR = new_tilesize_var;
8111 init_gfx_buffers = TRUE;
8112 init_gadgets_and_toons = TRUE;
8114 // printf("::: viewports: init_gfx_buffers\n");
8115 // printf("::: viewports: init_gadgets_and_toons\n");
8118 if (init_gfx_buffers)
8120 // printf("::: init_gfx_buffers\n");
8122 SCR_FIELDX = new_scr_fieldx_buffers;
8123 SCR_FIELDY = new_scr_fieldy_buffers;
8127 SCR_FIELDX = new_scr_fieldx;
8128 SCR_FIELDY = new_scr_fieldy;
8130 gfx.drawing_area_changed = drawing_area_changed;
8132 SetDrawDeactivationMask(REDRAW_NONE);
8133 SetDrawBackgroundMask(REDRAW_FIELD);
8136 if (init_video_buffer)
8138 // printf("::: init_video_buffer\n");
8140 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
8143 if (init_gadgets_and_toons)
8145 // printf("::: init_gadgets_and_toons\n");
8151 if (init_em_graphics)
8153 InitGraphicInfo_EM();