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 /* never draw masked screen borders when displaying request outside door */
338 if (effectiveGameStatus() == GAME_MODE_PSEUDO_DOOR &&
339 global.use_envelope_request)
342 if (redraw_mask & REDRAW_ALL)
343 DrawMaskedBorder_ALL();
346 if (redraw_mask & REDRAW_FIELD)
347 DrawMaskedBorder_FIELD();
348 if (redraw_mask & REDRAW_DOOR_1)
349 DrawMaskedBorder_DOOR_1();
350 if (redraw_mask & REDRAW_DOOR_2)
351 DrawMaskedBorder_DOOR_2();
352 if (redraw_mask & REDRAW_DOOR_3)
353 DrawMaskedBorder_DOOR_3();
357 void BlitScreenToBitmap_RND(Bitmap *target_bitmap)
359 DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
360 int fx = FX, fy = FY;
361 int full_lev_fieldx = lev_fieldx + (BorderElement != EL_EMPTY ? 2 : 0);
362 int full_lev_fieldy = lev_fieldy + (BorderElement != EL_EMPTY ? 2 : 0);
364 int dx = (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
365 int dy = (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
366 int dx_var = dx * TILESIZE_VAR / TILESIZE;
367 int dy_var = dy * TILESIZE_VAR / TILESIZE;
370 ffx = (scroll_x - SBX_Left) * TILEX_VAR + dx_var;
371 ffy = (scroll_y - SBY_Upper) * TILEY_VAR + dy_var;
373 if (EVEN(SCR_FIELDX))
375 if (ffx < SBX_Right * TILEX_VAR + TILEX_VAR / 2 + TILEX_VAR)
376 fx += dx_var - MIN(ffx, TILEX_VAR / 2) + TILEX_VAR;
378 fx += (dx_var > 0 ? TILEX_VAR : 0);
385 if (EVEN(SCR_FIELDY))
387 if (ffy < SBY_Lower * TILEY_VAR + TILEY_VAR / 2 + TILEY_VAR)
388 fy += dy_var - MIN(ffy, TILEY_VAR / 2) + TILEY_VAR;
390 fy += (dy_var > 0 ? TILEY_VAR : 0);
397 if (full_lev_fieldx <= SCR_FIELDX)
399 if (EVEN(SCR_FIELDX))
400 fx = 2 * TILEX_VAR - (ODD(lev_fieldx) ? TILEX_VAR / 2 : 0);
402 fx = 2 * TILEX_VAR - (EVEN(lev_fieldx) ? TILEX_VAR / 2 : 0);
405 if (full_lev_fieldy <= SCR_FIELDY)
407 if (EVEN(SCR_FIELDY))
408 fy = 2 * TILEY_VAR - (ODD(lev_fieldy) ? TILEY_VAR / 2 : 0);
410 fy = 2 * TILEY_VAR - (EVEN(lev_fieldy) ? TILEY_VAR / 2 : 0);
413 BlitBitmap(buffer, target_bitmap, fx, fy, SXSIZE, SYSIZE, SX, SY);
416 void BlitScreenToBitmap(Bitmap *target_bitmap)
418 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
419 BlitScreenToBitmap_EM(target_bitmap);
420 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
421 BlitScreenToBitmap_SP(target_bitmap);
422 else if (level.game_engine_type == GAME_ENGINE_TYPE_RND)
423 BlitScreenToBitmap_RND(target_bitmap);
426 void BackToFront_OLD()
428 DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
431 /* !!! TEST ONLY !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
432 /* (force full redraw) */
433 if (game_status == GAME_MODE_PLAYING)
434 redraw_mask |= REDRAW_FIELD;
437 if (redraw_mask == REDRAW_NONE)
442 if (redraw_mask & REDRAW_ALL)
443 printf("[REDRAW_ALL]");
444 if (redraw_mask & REDRAW_FIELD)
445 printf("[REDRAW_FIELD]");
446 if (redraw_mask & REDRAW_DOOR_1)
447 printf("[REDRAW_DOOR_1]");
448 if (redraw_mask & REDRAW_DOOR_2)
449 printf("[REDRAW_DOOR_2]");
450 if (redraw_mask & REDRAW_FROM_BACKBUFFER)
451 printf("[REDRAW_FROM_BACKBUFFER]");
452 printf(" [%d]\n", FrameCounter);
455 if (global.fps_slowdown && game_status == GAME_MODE_PLAYING)
457 static boolean last_frame_skipped = FALSE;
458 boolean skip_even_when_not_scrolling = TRUE;
459 boolean just_scrolling = (ScreenMovDir != 0);
460 boolean verbose = FALSE;
462 if (global.fps_slowdown_factor > 1 &&
463 (FrameCounter % global.fps_slowdown_factor) &&
464 (just_scrolling || skip_even_when_not_scrolling))
466 redraw_mask &= ~REDRAW_MAIN;
468 last_frame_skipped = TRUE;
471 printf("FRAME SKIPPED\n");
475 if (last_frame_skipped)
476 redraw_mask |= REDRAW_FIELD;
478 last_frame_skipped = FALSE;
481 printf("frame not skipped\n");
485 /* synchronize X11 graphics at this point; if we would synchronize the
486 display immediately after the buffer switching (after the XFlush),
487 this could mean that we have to wait for the graphics to complete,
488 although we could go on doing calculations for the next frame */
492 /* never draw masked border to backbuffer when using playfield buffer */
493 if (game_status != GAME_MODE_PLAYING ||
494 redraw_mask & REDRAW_FROM_BACKBUFFER ||
495 buffer == backbuffer)
496 DrawMaskedBorder(redraw_mask);
498 DrawMaskedBorder(redraw_mask & REDRAW_DOORS);
500 if (redraw_mask & REDRAW_ALL)
502 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
504 redraw_mask = REDRAW_NONE;
507 if (redraw_mask & REDRAW_FIELD)
509 if (game_status != GAME_MODE_PLAYING ||
510 redraw_mask & REDRAW_FROM_BACKBUFFER)
512 BlitBitmap(backbuffer, window,
513 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
517 BlitScreenToBitmap_RND(window);
520 redraw_mask &= ~REDRAW_MAIN;
523 if (redraw_mask & REDRAW_DOORS)
525 if (redraw_mask & REDRAW_DOOR_1)
526 BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
528 if (redraw_mask & REDRAW_DOOR_2)
529 BlitBitmap(backbuffer, window, VX, VY, VXSIZE, VYSIZE, VX, VY);
531 if (redraw_mask & REDRAW_DOOR_3)
532 BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
534 redraw_mask &= ~REDRAW_DOORS;
537 if (redraw_mask & REDRAW_MICROLEVEL)
539 BlitBitmap(backbuffer, window, SX, SY + 10 * TILEY, SXSIZE, 7 * TILEY,
540 SX, SY + 10 * TILEY);
542 redraw_mask &= ~REDRAW_MICROLEVEL;
545 if (redraw_mask & REDRAW_FPS) /* display frames per second */
550 sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
551 if (!global.fps_slowdown)
554 sprintf(text, "%04.1f fps%s", global.frames_per_second, info1);
556 DrawTextExt(window, SX + SXSIZE + SX, 0, text, FONT_TEXT_2, BLIT_OPAQUE);
559 redraw_mask = REDRAW_NONE;
564 if (redraw_mask == REDRAW_NONE)
567 // draw masked border to all viewports, if defined
568 DrawMaskedBorder(redraw_mask);
570 // blit backbuffer to visible screen
571 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
573 redraw_mask = REDRAW_NONE;
576 static void FadeCrossSaveBackbuffer()
578 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
581 static void FadeExt(int fade_mask, int fade_mode, int fade_type)
583 static int fade_type_skip = FADE_TYPE_NONE;
584 void (*draw_border_function)(void) = NULL;
585 Bitmap *bitmap = (fade_mode & FADE_TYPE_TRANSFORM ? bitmap_db_cross : NULL);
586 int x, y, width, height;
587 int fade_delay, post_delay;
589 if (fade_type == FADE_TYPE_FADE_OUT)
591 if (fade_type_skip != FADE_TYPE_NONE)
593 /* skip all fade operations until specified fade operation */
594 if (fade_type & fade_type_skip)
595 fade_type_skip = FADE_TYPE_NONE;
600 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
602 FadeCrossSaveBackbuffer();
608 redraw_mask |= fade_mask;
610 if (fade_type == FADE_TYPE_SKIP)
612 fade_type_skip = fade_mode;
617 fade_delay = fading.fade_delay;
618 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
620 if (fade_type_skip != FADE_TYPE_NONE)
622 /* skip all fade operations until specified fade operation */
623 if (fade_type & fade_type_skip)
624 fade_type_skip = FADE_TYPE_NONE;
629 if (global.autoplay_leveldir)
634 if (fade_mask == REDRAW_FIELD)
639 height = FULL_SYSIZE;
641 if (border.draw_masked_when_fading)
642 draw_border_function = DrawMaskedBorder_FIELD; /* update when fading */
644 DrawMaskedBorder_FIELD(); /* draw once */
646 else /* REDRAW_ALL */
654 if (!setup.fade_screens ||
656 fading.fade_mode == FADE_MODE_NONE)
658 if (fade_mode == FADE_MODE_FADE_OUT)
661 BlitBitmap(backbuffer, window, x, y, width, height, x, y);
663 redraw_mask &= ~fade_mask;
668 FadeRectangle(bitmap, x, y, width, height, fade_mode, fade_delay, post_delay,
669 draw_border_function);
671 redraw_mask &= ~fade_mask;
674 void FadeIn(int fade_mask)
676 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
677 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_IN);
679 FadeExt(fade_mask, FADE_MODE_FADE_IN, FADE_TYPE_FADE_IN);
682 void FadeOut(int fade_mask)
684 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
685 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_OUT);
687 FadeExt(fade_mask, FADE_MODE_FADE_OUT, FADE_TYPE_FADE_OUT);
689 global.border_status = game_status;
692 static void FadeSetLeaveNext(struct TitleFadingInfo fading_leave, boolean set)
694 static struct TitleFadingInfo fading_leave_stored;
697 fading_leave_stored = fading_leave;
699 fading = fading_leave_stored;
702 void FadeSetEnterMenu()
704 fading = menu.enter_menu;
706 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
709 void FadeSetLeaveMenu()
711 fading = menu.leave_menu;
713 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
716 void FadeSetEnterScreen()
718 fading = menu.enter_screen[game_status];
720 FadeSetLeaveNext(menu.leave_screen[game_status], TRUE); /* store */
723 void FadeSetNextScreen()
725 fading = menu.next_screen;
727 // (do not overwrite fade mode set by FadeSetEnterScreen)
728 // FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
731 void FadeSetLeaveScreen()
733 FadeSetLeaveNext(menu.leave_screen[game_status], FALSE); /* recall */
736 void FadeSetFromType(int type)
738 if (type & TYPE_ENTER_SCREEN)
739 FadeSetEnterScreen();
740 else if (type & TYPE_ENTER)
742 else if (type & TYPE_LEAVE)
746 void FadeSetDisabled()
748 static struct TitleFadingInfo fading_none = { FADE_MODE_NONE, -1, -1, -1 };
750 fading = fading_none;
753 void FadeSkipNextFadeIn()
755 FadeExt(0, FADE_MODE_SKIP_FADE_IN, FADE_TYPE_SKIP);
758 void FadeSkipNextFadeOut()
760 FadeExt(0, FADE_MODE_SKIP_FADE_OUT, FADE_TYPE_SKIP);
763 void SetWindowBackgroundImageIfDefined(int graphic)
765 if (graphic_info[graphic].bitmap)
766 SetWindowBackgroundBitmap(graphic_info[graphic].bitmap);
769 void SetMainBackgroundImageIfDefined(int graphic)
771 if (graphic_info[graphic].bitmap)
772 SetMainBackgroundBitmap(graphic_info[graphic].bitmap);
775 void SetDoorBackgroundImageIfDefined(int graphic)
777 if (graphic_info[graphic].bitmap)
778 SetDoorBackgroundBitmap(graphic_info[graphic].bitmap);
781 void SetWindowBackgroundImage(int graphic)
783 SetWindowBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
784 graphic_info[graphic].bitmap ?
785 graphic_info[graphic].bitmap :
786 graphic_info[IMG_BACKGROUND].bitmap);
789 void SetMainBackgroundImage(int graphic)
791 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
792 graphic_info[graphic].bitmap ?
793 graphic_info[graphic].bitmap :
794 graphic_info[IMG_BACKGROUND].bitmap);
797 void SetDoorBackgroundImage(int graphic)
799 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
800 graphic_info[graphic].bitmap ?
801 graphic_info[graphic].bitmap :
802 graphic_info[IMG_BACKGROUND].bitmap);
805 void SetPanelBackground()
807 struct GraphicInfo *gfx = &graphic_info[IMG_BACKGROUND_PANEL];
809 BlitBitmapTiled(gfx->bitmap, bitmap_db_panel, gfx->src_x, gfx->src_y,
810 gfx->width, gfx->height, 0, 0, DXSIZE, DYSIZE);
812 SetDoorBackgroundBitmap(bitmap_db_panel);
815 void DrawBackground(int x, int y, int width, int height)
817 /* "drawto" might still point to playfield buffer here (hall of fame) */
818 ClearRectangleOnBackground(backbuffer, x, y, width, height);
820 if (IN_GFX_FIELD_FULL(x, y))
821 redraw_mask |= REDRAW_FIELD;
822 else if (IN_GFX_DOOR_1(x, y))
823 redraw_mask |= REDRAW_DOOR_1;
824 else if (IN_GFX_DOOR_2(x, y))
825 redraw_mask |= REDRAW_DOOR_2;
826 else if (IN_GFX_DOOR_3(x, y))
827 redraw_mask |= REDRAW_DOOR_3;
830 void DrawBackgroundForFont(int x, int y, int width, int height, int font_nr)
832 struct FontBitmapInfo *font = getFontBitmapInfo(font_nr);
834 if (font->bitmap == NULL)
837 DrawBackground(x, y, width, height);
840 void DrawBackgroundForGraphic(int x, int y, int width, int height, int graphic)
842 struct GraphicInfo *g = &graphic_info[graphic];
844 if (g->bitmap == NULL)
847 DrawBackground(x, y, width, height);
852 /* !!! "drawto" might still point to playfield buffer here (see above) !!! */
853 /* (when entering hall of fame after playing) */
854 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
856 /* !!! maybe this should be done before clearing the background !!! */
857 if (game_status == GAME_MODE_PLAYING)
859 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
860 SetDrawtoField(DRAW_FIELDBUFFER);
863 SetDrawtoField(DRAW_BACKBUFFER);
866 void MarkTileDirty(int x, int y)
868 redraw_mask |= REDRAW_FIELD;
871 void SetBorderElement()
875 BorderElement = EL_EMPTY;
877 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
879 for (x = 0; x < lev_fieldx; x++)
881 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
882 BorderElement = EL_STEELWALL;
884 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
890 void FloodFillLevel(int from_x, int from_y, int fill_element,
891 short field[MAX_LEV_FIELDX][MAX_LEV_FIELDY],
892 int max_fieldx, int max_fieldy)
896 static int check[4][2] = { { -1, 0 }, { 0, -1 }, { 1, 0 }, { 0, 1 } };
897 static int safety = 0;
899 /* check if starting field still has the desired content */
900 if (field[from_x][from_y] == fill_element)
905 if (safety > max_fieldx * max_fieldy)
906 Error(ERR_EXIT, "Something went wrong in 'FloodFill()'. Please debug.");
908 old_element = field[from_x][from_y];
909 field[from_x][from_y] = fill_element;
911 for (i = 0; i < 4; i++)
913 x = from_x + check[i][0];
914 y = from_y + check[i][1];
916 if (IN_FIELD(x, y, max_fieldx, max_fieldy) && field[x][y] == old_element)
917 FloodFillLevel(x, y, fill_element, field, max_fieldx, max_fieldy);
923 void SetRandomAnimationValue(int x, int y)
925 gfx.anim_random_frame = GfxRandom[x][y];
928 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
930 /* animation synchronized with global frame counter, not move position */
931 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
932 sync_frame = FrameCounter;
934 return getAnimationFrame(graphic_info[graphic].anim_frames,
935 graphic_info[graphic].anim_delay,
936 graphic_info[graphic].anim_mode,
937 graphic_info[graphic].anim_start_frame,
941 void getSizedGraphicSourceExt(int graphic, int frame, int tilesize,
942 Bitmap **bitmap, int *x, int *y,
943 boolean get_backside)
945 struct GraphicInfo *g = &graphic_info[graphic];
946 Bitmap *src_bitmap = g->bitmap;
947 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
948 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
949 int tilesize_capped = MIN(MAX(1, tilesize), TILESIZE);
951 // if no in-game graphics defined, always use standard graphic size
952 if (g->bitmaps[IMG_BITMAP_GAME] == NULL)
955 if (tilesize == gfx.standard_tile_size)
956 src_bitmap = g->bitmaps[IMG_BITMAP_STANDARD];
957 else if (tilesize == game.tile_size)
958 src_bitmap = g->bitmaps[IMG_BITMAP_GAME];
960 src_bitmap = g->bitmaps[IMG_BITMAP_1x1 - log_2(tilesize_capped)];
962 if (g->offset_y == 0) /* frames are ordered horizontally */
964 int max_width = g->anim_frames_per_line * g->width;
965 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
967 src_x = pos % max_width;
968 src_y = src_y % g->height + pos / max_width * g->height;
970 else if (g->offset_x == 0) /* frames are ordered vertically */
972 int max_height = g->anim_frames_per_line * g->height;
973 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
975 src_x = src_x % g->width + pos / max_height * g->width;
976 src_y = pos % max_height;
978 else /* frames are ordered diagonally */
980 src_x = src_x + frame * g->offset_x;
981 src_y = src_y + frame * g->offset_y;
984 *bitmap = src_bitmap;
985 *x = src_x * tilesize / TILESIZE;
986 *y = src_y * tilesize / TILESIZE;
989 void getFixedGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
990 int *x, int *y, boolean get_backside)
992 getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y,
996 void getSizedGraphicSource(int graphic, int frame, int tilesize,
997 Bitmap **bitmap, int *x, int *y)
999 getSizedGraphicSourceExt(graphic, frame, tilesize, bitmap, x, y, FALSE);
1002 void getFixedGraphicSource(int graphic, int frame,
1003 Bitmap **bitmap, int *x, int *y)
1005 getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y, FALSE);
1008 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1010 getSizedGraphicSource(graphic, 0, MINI_TILESIZE, bitmap, x, y);
1013 inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1014 int *x, int *y, boolean get_backside)
1016 struct GraphicInfo *g = &graphic_info[graphic];
1017 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
1018 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
1020 if (TILESIZE_VAR != TILESIZE)
1021 return getSizedGraphicSourceExt(graphic, frame, TILESIZE_VAR, bitmap, x, y,
1024 *bitmap = g->bitmap;
1026 if (g->offset_y == 0) /* frames are ordered horizontally */
1028 int max_width = g->anim_frames_per_line * g->width;
1029 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
1031 *x = pos % max_width;
1032 *y = src_y % g->height + pos / max_width * g->height;
1034 else if (g->offset_x == 0) /* frames are ordered vertically */
1036 int max_height = g->anim_frames_per_line * g->height;
1037 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
1039 *x = src_x % g->width + pos / max_height * g->width;
1040 *y = pos % max_height;
1042 else /* frames are ordered diagonally */
1044 *x = src_x + frame * g->offset_x;
1045 *y = src_y + frame * g->offset_y;
1049 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
1051 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
1054 void DrawGraphic(int x, int y, int graphic, int frame)
1057 if (!IN_SCR_FIELD(x, y))
1059 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1060 printf("DrawGraphic(): This should never happen!\n");
1065 DrawGraphicExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR, graphic,
1068 MarkTileDirty(x, y);
1071 void DrawFixedGraphic(int x, int y, int graphic, int frame)
1074 if (!IN_SCR_FIELD(x, y))
1076 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1077 printf("DrawGraphic(): This should never happen!\n");
1082 DrawFixedGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic,
1084 MarkTileDirty(x, y);
1087 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1093 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1095 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX_VAR, TILEY_VAR, x, y);
1098 void DrawFixedGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1104 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1105 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
1108 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
1111 if (!IN_SCR_FIELD(x, y))
1113 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1114 printf("DrawGraphicThruMask(): This should never happen!\n");
1119 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
1122 MarkTileDirty(x, y);
1125 void DrawFixedGraphicThruMask(int x, int y, int graphic, int frame)
1128 if (!IN_SCR_FIELD(x, y))
1130 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1131 printf("DrawGraphicThruMask(): This should never happen!\n");
1136 DrawFixedGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
1138 MarkTileDirty(x, y);
1141 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
1147 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1149 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX_VAR, TILEY_VAR,
1153 void DrawFixedGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y,
1154 int graphic, int frame)
1156 struct GraphicInfo *g = &graphic_info[graphic];
1160 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1162 BlitBitmapMasked(src_bitmap, d, src_x, src_y, g->width, g->height,
1166 void DrawSizedGraphic(int x, int y, int graphic, int frame, int tilesize)
1168 DrawSizedGraphicExt(drawto, SX + x * tilesize, SY + y * tilesize, graphic,
1170 MarkTileDirty(x / tilesize, y / tilesize);
1173 void DrawSizedGraphicExt(DrawBuffer *d, int x, int y, int graphic, int frame,
1179 getSizedGraphicSource(graphic, frame, tilesize, &src_bitmap, &src_x, &src_y);
1180 BlitBitmap(src_bitmap, d, src_x, src_y, tilesize, tilesize, x, y);
1183 void DrawMiniGraphic(int x, int y, int graphic)
1185 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
1186 MarkTileDirty(x / 2, y / 2);
1189 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
1194 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1195 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
1198 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
1199 int graphic, int frame,
1200 int cut_mode, int mask_mode)
1205 int width = TILEX, height = TILEY;
1208 if (dx || dy) /* shifted graphic */
1210 if (x < BX1) /* object enters playfield from the left */
1217 else if (x > BX2) /* object enters playfield from the right */
1223 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
1229 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
1231 else if (dx) /* general horizontal movement */
1232 MarkTileDirty(x + SIGN(dx), y);
1234 if (y < BY1) /* object enters playfield from the top */
1236 if (cut_mode==CUT_BELOW) /* object completely above top border */
1244 else if (y > BY2) /* object enters playfield from the bottom */
1250 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
1256 else if (dy > 0 && cut_mode == CUT_ABOVE)
1258 if (y == BY2) /* object completely above bottom border */
1264 MarkTileDirty(x, y + 1);
1265 } /* object leaves playfield to the bottom */
1266 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1268 else if (dy) /* general vertical movement */
1269 MarkTileDirty(x, y + SIGN(dy));
1273 if (!IN_SCR_FIELD(x, y))
1275 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1276 printf("DrawGraphicShifted(): This should never happen!\n");
1281 width = width * TILESIZE_VAR / TILESIZE;
1282 height = height * TILESIZE_VAR / TILESIZE;
1283 cx = cx * TILESIZE_VAR / TILESIZE;
1284 cy = cy * TILESIZE_VAR / TILESIZE;
1285 dx = dx * TILESIZE_VAR / TILESIZE;
1286 dy = dy * TILESIZE_VAR / TILESIZE;
1288 if (width > 0 && height > 0)
1290 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1295 dst_x = FX + x * TILEX_VAR + dx;
1296 dst_y = FY + y * TILEY_VAR + dy;
1298 if (mask_mode == USE_MASKING)
1299 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1302 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1305 MarkTileDirty(x, y);
1309 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
1310 int graphic, int frame,
1311 int cut_mode, int mask_mode)
1316 int width = TILEX_VAR, height = TILEY_VAR;
1319 int x2 = x + SIGN(dx);
1320 int y2 = y + SIGN(dy);
1322 /* movement with two-tile animations must be sync'ed with movement position,
1323 not with current GfxFrame (which can be higher when using slow movement) */
1324 int anim_pos = (dx ? ABS(dx) : ABS(dy));
1325 int anim_frames = graphic_info[graphic].anim_frames;
1327 /* (we also need anim_delay here for movement animations with less frames) */
1328 int anim_delay = graphic_info[graphic].anim_delay;
1329 int sync_frame = anim_pos * anim_frames * anim_delay / TILESIZE;
1331 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
1332 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
1334 /* re-calculate animation frame for two-tile movement animation */
1335 frame = getGraphicAnimationFrame(graphic, sync_frame);
1337 /* check if movement start graphic inside screen area and should be drawn */
1338 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
1340 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
1342 dst_x = FX + x1 * TILEX_VAR;
1343 dst_y = FY + y1 * TILEY_VAR;
1345 if (mask_mode == USE_MASKING)
1346 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1349 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1352 MarkTileDirty(x1, y1);
1355 /* check if movement end graphic inside screen area and should be drawn */
1356 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
1358 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
1360 dst_x = FX + x2 * TILEX_VAR;
1361 dst_y = FY + y2 * TILEY_VAR;
1363 if (mask_mode == USE_MASKING)
1364 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1367 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1370 MarkTileDirty(x2, y2);
1374 static void DrawGraphicShifted(int x, int y, int dx, int dy,
1375 int graphic, int frame,
1376 int cut_mode, int mask_mode)
1380 DrawGraphic(x, y, graphic, frame);
1385 if (graphic_info[graphic].double_movement) /* EM style movement images */
1386 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1388 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1391 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1392 int frame, int cut_mode)
1394 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
1397 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1398 int cut_mode, int mask_mode)
1400 int lx = LEVELX(x), ly = LEVELY(y);
1404 if (IN_LEV_FIELD(lx, ly))
1406 SetRandomAnimationValue(lx, ly);
1408 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
1409 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1411 /* do not use double (EM style) movement graphic when not moving */
1412 if (graphic_info[graphic].double_movement && !dx && !dy)
1414 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
1415 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1418 else /* border element */
1420 graphic = el2img(element);
1421 frame = getGraphicAnimationFrame(graphic, -1);
1424 if (element == EL_EXPANDABLE_WALL)
1426 boolean left_stopped = FALSE, right_stopped = FALSE;
1428 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1429 left_stopped = TRUE;
1430 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1431 right_stopped = TRUE;
1433 if (left_stopped && right_stopped)
1435 else if (left_stopped)
1437 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1438 frame = graphic_info[graphic].anim_frames - 1;
1440 else if (right_stopped)
1442 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1443 frame = graphic_info[graphic].anim_frames - 1;
1448 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1449 else if (mask_mode == USE_MASKING)
1450 DrawGraphicThruMask(x, y, graphic, frame);
1452 DrawGraphic(x, y, graphic, frame);
1455 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1456 int cut_mode, int mask_mode)
1458 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1459 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1460 cut_mode, mask_mode);
1463 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1466 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1469 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1472 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1475 void DrawLevelElementThruMask(int x, int y, int element)
1477 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1480 void DrawLevelFieldThruMask(int x, int y)
1482 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1485 /* !!! implementation of quicksand is totally broken !!! */
1486 #define IS_CRUMBLED_TILE(x, y, e) \
1487 (GFX_CRUMBLED(e) && (!IN_LEV_FIELD(x, y) || \
1488 !IS_MOVING(x, y) || \
1489 (e) == EL_QUICKSAND_EMPTYING || \
1490 (e) == EL_QUICKSAND_FAST_EMPTYING))
1492 static void DrawLevelFieldCrumbledInnerCorners(int x, int y, int dx, int dy,
1497 int width, height, cx, cy;
1498 int sx = SCREENX(x), sy = SCREENY(y);
1499 int crumbled_border_size = graphic_info[graphic].border_size;
1502 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1504 for (i = 1; i < 4; i++)
1506 int dxx = (i & 1 ? dx : 0);
1507 int dyy = (i & 2 ? dy : 0);
1510 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1513 /* check if neighbour field is of same crumble type */
1514 boolean same = (IS_CRUMBLED_TILE(xx, yy, element) &&
1515 graphic_info[graphic].class ==
1516 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class);
1518 /* return if check prevents inner corner */
1519 if (same == (dxx == dx && dyy == dy))
1523 /* if we reach this point, we have an inner corner */
1525 getGraphicSource(graphic, 1, &src_bitmap, &src_x, &src_y);
1527 width = crumbled_border_size * TILESIZE_VAR / TILESIZE;
1528 height = crumbled_border_size * TILESIZE_VAR / TILESIZE;
1529 cx = (dx > 0 ? TILESIZE_VAR - width : 0);
1530 cy = (dy > 0 ? TILESIZE_VAR - height : 0);
1532 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1533 width, height, FX + sx * TILEX_VAR + cx, FY + sy * TILEY_VAR + cy);
1536 static void DrawLevelFieldCrumbledBorders(int x, int y, int graphic, int frame,
1541 int width, height, bx, by, cx, cy;
1542 int sx = SCREENX(x), sy = SCREENY(y);
1543 int crumbled_border_size = graphic_info[graphic].border_size;
1544 int crumbled_border_size_var = crumbled_border_size * TILESIZE_VAR / TILESIZE;
1545 int crumbled_border_pos_var = TILESIZE_VAR - crumbled_border_size_var;
1548 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1550 /* draw simple, sloppy, non-corner-accurate crumbled border */
1552 width = (dir == 1 || dir == 2 ? crumbled_border_size_var : TILESIZE_VAR);
1553 height = (dir == 0 || dir == 3 ? crumbled_border_size_var : TILESIZE_VAR);
1554 cx = (dir == 2 ? crumbled_border_pos_var : 0);
1555 cy = (dir == 3 ? crumbled_border_pos_var : 0);
1557 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy, width, height,
1558 FX + sx * TILEX_VAR + cx,
1559 FY + sy * TILEY_VAR + cy);
1561 /* (remaining middle border part must be at least as big as corner part) */
1562 if (!(graphic_info[graphic].style & STYLE_ACCURATE_BORDERS) ||
1563 crumbled_border_size >= TILESIZE / 3)
1566 /* correct corners of crumbled border, if needed */
1568 for (i = -1; i <= 1; i += 2)
1570 int xx = x + (dir == 0 || dir == 3 ? i : 0);
1571 int yy = y + (dir == 1 || dir == 2 ? i : 0);
1572 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1575 /* check if neighbour field is of same crumble type */
1576 if (IS_CRUMBLED_TILE(xx, yy, element) &&
1577 graphic_info[graphic].class ==
1578 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1580 /* no crumbled corner, but continued crumbled border */
1582 int c1 = (dir == 2 || dir == 3 ? crumbled_border_pos_var : 0);
1583 int c2 = (i == 1 ? crumbled_border_pos_var : 0);
1584 int b1 = (i == 1 ? crumbled_border_size_var :
1585 TILESIZE_VAR - 2 * crumbled_border_size_var);
1587 width = crumbled_border_size_var;
1588 height = crumbled_border_size_var;
1590 if (dir == 1 || dir == 2)
1605 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
1607 FX + sx * TILEX_VAR + cx,
1608 FY + sy * TILEY_VAR + cy);
1613 static void DrawLevelFieldCrumbledExt(int x, int y, int graphic, int frame)
1615 int sx = SCREENX(x), sy = SCREENY(y);
1618 static int xy[4][2] =
1626 if (!IN_LEV_FIELD(x, y))
1629 element = TILE_GFX_ELEMENT(x, y);
1631 /* crumble field itself */
1632 if (IS_CRUMBLED_TILE(x, y, element))
1634 if (!IN_SCR_FIELD(sx, sy))
1637 for (i = 0; i < 4; i++)
1639 int xx = x + xy[i][0];
1640 int yy = y + xy[i][1];
1642 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1645 /* check if neighbour field is of same crumble type */
1646 if (IS_CRUMBLED_TILE(xx, yy, element) &&
1647 graphic_info[graphic].class ==
1648 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1651 DrawLevelFieldCrumbledBorders(x, y, graphic, frame, i);
1654 if ((graphic_info[graphic].style & STYLE_INNER_CORNERS) &&
1655 graphic_info[graphic].anim_frames == 2)
1657 for (i = 0; i < 4; i++)
1659 int dx = (i & 1 ? +1 : -1);
1660 int dy = (i & 2 ? +1 : -1);
1662 DrawLevelFieldCrumbledInnerCorners(x, y, dx, dy, graphic);
1666 MarkTileDirty(sx, sy);
1668 else /* center field not crumbled -- crumble neighbour fields */
1670 for (i = 0; i < 4; i++)
1672 int xx = x + xy[i][0];
1673 int yy = y + xy[i][1];
1674 int sxx = sx + xy[i][0];
1675 int syy = sy + xy[i][1];
1677 if (!IN_LEV_FIELD(xx, yy) ||
1678 !IN_SCR_FIELD(sxx, syy))
1681 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
1684 element = TILE_GFX_ELEMENT(xx, yy);
1686 if (!IS_CRUMBLED_TILE(xx, yy, element))
1689 graphic = el_act2crm(element, ACTION_DEFAULT);
1691 DrawLevelFieldCrumbledBorders(xx, yy, graphic, 0, 3 - i);
1693 MarkTileDirty(sxx, syy);
1698 void DrawLevelFieldCrumbled(int x, int y)
1702 if (!IN_LEV_FIELD(x, y))
1705 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1706 GfxElement[x][y] != EL_UNDEFINED &&
1707 GFX_CRUMBLED(GfxElement[x][y]))
1709 DrawLevelFieldCrumbledDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
1714 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
1716 DrawLevelFieldCrumbledExt(x, y, graphic, 0);
1719 void DrawLevelFieldCrumbledDigging(int x, int y, int direction,
1722 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1723 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1724 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1725 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1726 int sx = SCREENX(x), sy = SCREENY(y);
1728 DrawGraphic(sx, sy, graphic1, frame1);
1729 DrawLevelFieldCrumbledExt(x, y, graphic2, frame2);
1732 void DrawLevelFieldCrumbledNeighbours(int x, int y)
1734 int sx = SCREENX(x), sy = SCREENY(y);
1735 static int xy[4][2] =
1744 for (i = 0; i < 4; i++)
1746 int xx = x + xy[i][0];
1747 int yy = y + xy[i][1];
1748 int sxx = sx + xy[i][0];
1749 int syy = sy + xy[i][1];
1751 if (!IN_LEV_FIELD(xx, yy) ||
1752 !IN_SCR_FIELD(sxx, syy) ||
1753 !GFX_CRUMBLED(Feld[xx][yy]) ||
1757 DrawLevelField(xx, yy);
1761 static int getBorderElement(int x, int y)
1765 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1766 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1767 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1768 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1769 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1770 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1771 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1773 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1774 int steel_position = (x == -1 && y == -1 ? 0 :
1775 x == lev_fieldx && y == -1 ? 1 :
1776 x == -1 && y == lev_fieldy ? 2 :
1777 x == lev_fieldx && y == lev_fieldy ? 3 :
1778 x == -1 || x == lev_fieldx ? 4 :
1779 y == -1 || y == lev_fieldy ? 5 : 6);
1781 return border[steel_position][steel_type];
1784 void DrawScreenElement(int x, int y, int element)
1786 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1787 DrawLevelFieldCrumbled(LEVELX(x), LEVELY(y));
1790 void DrawLevelElement(int x, int y, int element)
1792 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1793 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1796 void DrawScreenField(int x, int y)
1798 int lx = LEVELX(x), ly = LEVELY(y);
1799 int element, content;
1801 if (!IN_LEV_FIELD(lx, ly))
1803 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1806 element = getBorderElement(lx, ly);
1808 DrawScreenElement(x, y, element);
1813 element = Feld[lx][ly];
1814 content = Store[lx][ly];
1816 if (IS_MOVING(lx, ly))
1818 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1819 boolean cut_mode = NO_CUTTING;
1821 if (element == EL_QUICKSAND_EMPTYING ||
1822 element == EL_QUICKSAND_FAST_EMPTYING ||
1823 element == EL_MAGIC_WALL_EMPTYING ||
1824 element == EL_BD_MAGIC_WALL_EMPTYING ||
1825 element == EL_DC_MAGIC_WALL_EMPTYING ||
1826 element == EL_AMOEBA_DROPPING)
1827 cut_mode = CUT_ABOVE;
1828 else if (element == EL_QUICKSAND_FILLING ||
1829 element == EL_QUICKSAND_FAST_FILLING ||
1830 element == EL_MAGIC_WALL_FILLING ||
1831 element == EL_BD_MAGIC_WALL_FILLING ||
1832 element == EL_DC_MAGIC_WALL_FILLING)
1833 cut_mode = CUT_BELOW;
1835 if (cut_mode == CUT_ABOVE)
1836 DrawScreenElement(x, y, element);
1838 DrawScreenElement(x, y, EL_EMPTY);
1841 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1842 else if (cut_mode == NO_CUTTING)
1843 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1846 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1848 if (cut_mode == CUT_BELOW &&
1849 IN_LEV_FIELD(lx, ly + 1) && IN_SCR_FIELD(x, y + 1))
1850 DrawLevelElement(lx, ly + 1, element);
1853 if (content == EL_ACID)
1855 int dir = MovDir[lx][ly];
1856 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
1857 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
1859 DrawLevelElementThruMask(newlx, newly, EL_ACID);
1862 else if (IS_BLOCKED(lx, ly))
1867 boolean cut_mode = NO_CUTTING;
1868 int element_old, content_old;
1870 Blocked2Moving(lx, ly, &oldx, &oldy);
1873 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1874 MovDir[oldx][oldy] == MV_RIGHT);
1876 element_old = Feld[oldx][oldy];
1877 content_old = Store[oldx][oldy];
1879 if (element_old == EL_QUICKSAND_EMPTYING ||
1880 element_old == EL_QUICKSAND_FAST_EMPTYING ||
1881 element_old == EL_MAGIC_WALL_EMPTYING ||
1882 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1883 element_old == EL_DC_MAGIC_WALL_EMPTYING ||
1884 element_old == EL_AMOEBA_DROPPING)
1885 cut_mode = CUT_ABOVE;
1887 DrawScreenElement(x, y, EL_EMPTY);
1890 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1892 else if (cut_mode == NO_CUTTING)
1893 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1896 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1899 else if (IS_DRAWABLE(element))
1900 DrawScreenElement(x, y, element);
1902 DrawScreenElement(x, y, EL_EMPTY);
1905 void DrawLevelField(int x, int y)
1907 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1908 DrawScreenField(SCREENX(x), SCREENY(y));
1909 else if (IS_MOVING(x, y))
1913 Moving2Blocked(x, y, &newx, &newy);
1914 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1915 DrawScreenField(SCREENX(newx), SCREENY(newy));
1917 else if (IS_BLOCKED(x, y))
1921 Blocked2Moving(x, y, &oldx, &oldy);
1922 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1923 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1927 void DrawSizedElement(int x, int y, int element, int tilesize)
1931 graphic = el2edimg(element);
1932 DrawSizedGraphic(x, y, graphic, 0, tilesize);
1935 void DrawMiniElement(int x, int y, int element)
1939 graphic = el2edimg(element);
1940 DrawMiniGraphic(x, y, graphic);
1943 void DrawSizedElementOrWall(int sx, int sy, int scroll_x, int scroll_y,
1946 int x = sx + scroll_x, y = sy + scroll_y;
1948 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1949 DrawSizedElement(sx, sy, EL_EMPTY, tilesize);
1950 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1951 DrawSizedElement(sx, sy, Feld[x][y], tilesize);
1953 DrawSizedGraphic(sx, sy, el2edimg(getBorderElement(x, y)), 0, tilesize);
1956 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1958 int x = sx + scroll_x, y = sy + scroll_y;
1960 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1961 DrawMiniElement(sx, sy, EL_EMPTY);
1962 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1963 DrawMiniElement(sx, sy, Feld[x][y]);
1965 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1968 void DrawEnvelopeBackgroundTiles(int graphic, int startx, int starty,
1969 int x, int y, int xsize, int ysize,
1970 int tile_width, int tile_height)
1974 int dst_x = startx + x * tile_width;
1975 int dst_y = starty + y * tile_height;
1976 int width = graphic_info[graphic].width;
1977 int height = graphic_info[graphic].height;
1978 int inner_width_raw = MAX(width - 2 * tile_width, tile_width);
1979 int inner_height_raw = MAX(height - 2 * tile_height, tile_height);
1980 int inner_width = inner_width_raw - (inner_width_raw % tile_width);
1981 int inner_height = inner_height_raw - (inner_height_raw % tile_height);
1982 int inner_sx = (width >= 3 * tile_width ? tile_width : 0);
1983 int inner_sy = (height >= 3 * tile_height ? tile_height : 0);
1984 boolean draw_masked = graphic_info[graphic].draw_masked;
1986 getFixedGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1988 if (src_bitmap == NULL || width < tile_width || height < tile_height)
1990 ClearRectangle(drawto, dst_x, dst_y, tile_width, tile_height);
1994 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - tile_width :
1995 inner_sx + (x - 1) * tile_width % inner_width);
1996 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - tile_height :
1997 inner_sy + (y - 1) * tile_height % inner_height);
2000 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
2003 BlitBitmap(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
2007 void DrawEnvelopeBackground(int graphic, int startx, int starty,
2008 int x, int y, int xsize, int ysize, int font_nr)
2010 int font_width = getFontWidth(font_nr);
2011 int font_height = getFontHeight(font_nr);
2013 DrawEnvelopeBackgroundTiles(graphic, startx, starty, x, y, xsize, ysize,
2014 font_width, font_height);
2017 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
2019 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2020 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2021 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2022 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2023 boolean no_delay = (tape.warp_forward);
2024 unsigned int anim_delay = 0;
2025 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
2026 int anim_delay_value = (no_delay ? 0 : frame_delay_value) / 2;
2027 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
2028 int font_width = getFontWidth(font_nr);
2029 int font_height = getFontHeight(font_nr);
2030 int max_xsize = level.envelope[envelope_nr].xsize;
2031 int max_ysize = level.envelope[envelope_nr].ysize;
2032 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
2033 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
2034 int xend = max_xsize;
2035 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
2036 int xstep = (xstart < xend ? 1 : 0);
2037 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2039 int end = MAX(xend - xstart, yend - ystart);
2042 for (i = start; i <= end; i++)
2044 int last_frame = end; // last frame of this "for" loop
2045 int x = xstart + i * xstep;
2046 int y = ystart + i * ystep;
2047 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2048 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2049 int sx = SX + (SXSIZE - xsize * font_width) / 2;
2050 int sy = SY + (SYSIZE - ysize * font_height) / 2;
2053 SetDrawtoField(DRAW_FIELDBUFFER);
2055 BlitScreenToBitmap(backbuffer);
2057 SetDrawtoField(DRAW_BACKBUFFER);
2059 for (yy = 0; yy < ysize; yy++)
2060 for (xx = 0; xx < xsize; xx++)
2061 DrawEnvelopeBackground(graphic, sx, sy, xx, yy, xsize, ysize, font_nr);
2063 DrawTextBuffer(sx + font_width, sy + font_height,
2064 level.envelope[envelope_nr].text, font_nr, max_xsize,
2065 xsize - 2, ysize - 2, 0, mask_mode,
2066 level.envelope[envelope_nr].autowrap,
2067 level.envelope[envelope_nr].centered, FALSE);
2069 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2072 SkipUntilDelayReached(&anim_delay, anim_delay_value, &i, last_frame);
2076 void ShowEnvelope(int envelope_nr)
2078 int element = EL_ENVELOPE_1 + envelope_nr;
2079 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2080 int sound_opening = element_info[element].sound[ACTION_OPENING];
2081 int sound_closing = element_info[element].sound[ACTION_CLOSING];
2082 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2083 boolean no_delay = (tape.warp_forward);
2084 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
2085 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
2086 int anim_mode = graphic_info[graphic].anim_mode;
2087 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2088 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2090 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
2092 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2094 if (anim_mode == ANIM_DEFAULT)
2095 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
2097 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
2100 Delay(wait_delay_value);
2102 WaitForEventToContinue();
2104 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2106 if (anim_mode != ANIM_NONE)
2107 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
2109 if (anim_mode == ANIM_DEFAULT)
2110 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
2112 game.envelope_active = FALSE;
2114 SetDrawtoField(DRAW_FIELDBUFFER);
2116 redraw_mask |= REDRAW_FIELD;
2120 static void setRequestPosition(int *x, int *y, boolean add_border_size)
2122 int border_size = request.border_size;
2123 int sx_center = (request.x != -1 ? request.x : SX + SXSIZE / 2);
2124 int sy_center = (request.y != -1 ? request.y : SY + SYSIZE / 2);
2125 int sx = sx_center - request.width / 2;
2126 int sy = sy_center - request.height / 2;
2128 if (add_border_size)
2138 void DrawEnvelopeRequest(char *text)
2140 char *text_final = text;
2141 char *text_door_style = NULL;
2142 int graphic = IMG_BACKGROUND_REQUEST;
2143 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2144 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2145 int font_nr = FONT_REQUEST;
2146 int font_width = getFontWidth(font_nr);
2147 int font_height = getFontHeight(font_nr);
2148 int border_size = request.border_size;
2149 int line_spacing = request.line_spacing;
2150 int line_height = font_height + line_spacing;
2151 int text_width = request.width - 2 * border_size;
2152 int text_height = request.height - 2 * border_size;
2153 int line_length = text_width / font_width;
2154 int max_lines = text_height / line_height;
2155 int width = request.width;
2156 int height = request.height;
2157 int tile_size = request.step_offset;
2158 int x_steps = width / tile_size;
2159 int y_steps = height / tile_size;
2163 if (request.wrap_single_words)
2165 char *src_text_ptr, *dst_text_ptr;
2167 text_door_style = checked_malloc(2 * strlen(text) + 1);
2169 src_text_ptr = text;
2170 dst_text_ptr = text_door_style;
2172 while (*src_text_ptr)
2174 if (*src_text_ptr == ' ' ||
2175 *src_text_ptr == '?' ||
2176 *src_text_ptr == '!')
2177 *dst_text_ptr++ = '\n';
2179 if (*src_text_ptr != ' ')
2180 *dst_text_ptr++ = *src_text_ptr;
2185 *dst_text_ptr = '\0';
2187 text_final = text_door_style;
2190 setRequestPosition(&sx, &sy, FALSE);
2192 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
2194 for (y = 0; y < y_steps; y++)
2195 for (x = 0; x < x_steps; x++)
2196 DrawEnvelopeBackgroundTiles(graphic, sx, sy,
2197 x, y, x_steps, y_steps,
2198 tile_size, tile_size);
2200 DrawTextBuffer(sx + border_size, sy + border_size, text_final, font_nr,
2201 line_length, -1, max_lines, line_spacing, mask_mode,
2202 request.autowrap, request.centered, FALSE);
2204 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2205 RedrawGadget(tool_gadget[i]);
2207 // store readily prepared envelope request for later use when animating
2208 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2210 if (text_door_style)
2211 free(text_door_style);
2214 void AnimateEnvelopeRequest(int anim_mode, int action)
2216 int graphic = IMG_BACKGROUND_REQUEST;
2217 boolean draw_masked = graphic_info[graphic].draw_masked;
2218 int delay_value_normal = request.step_delay;
2219 int delay_value_fast = delay_value_normal / 2;
2220 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2221 boolean no_delay = (tape.warp_forward);
2222 int delay_value = (ffwd_delay ? delay_value_fast : delay_value_normal);
2223 int anim_delay_value = (no_delay ? 0 : delay_value + 500 * 0) / 2;
2224 unsigned int anim_delay = 0;
2226 int width = request.width;
2227 int height = request.height;
2228 int tile_size = request.step_offset;
2229 int max_xsize = width / tile_size;
2230 int max_ysize = height / tile_size;
2231 int max_xsize_inner = max_xsize - 2;
2232 int max_ysize_inner = max_ysize - 2;
2234 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize_inner : 0);
2235 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize_inner : 0);
2236 int xend = max_xsize_inner;
2237 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize_inner : 0);
2238 int xstep = (xstart < xend ? 1 : 0);
2239 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2241 int end = MAX(xend - xstart, yend - ystart);
2244 if (setup.quick_doors)
2252 if (action == ACTION_OPENING)
2253 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2254 else if (action == ACTION_CLOSING)
2255 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2258 for (i = start; i <= end; i++)
2260 int last_frame = end; // last frame of this "for" loop
2261 int x = xstart + i * xstep;
2262 int y = ystart + i * ystep;
2263 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2264 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2265 int sx_center = (request.x != -1 ? request.x : SX + SXSIZE / 2);
2266 int sy_center = (request.y != -1 ? request.y : SY + SYSIZE / 2);
2267 int src_x = sx_center - width / 2;
2268 int src_y = sy_center - height / 2;
2269 int dst_x = sx_center - xsize * tile_size / 2;
2270 int dst_y = sy_center - ysize * tile_size / 2;
2271 int xsize_size_left = (xsize - 1) * tile_size;
2272 int ysize_size_top = (ysize - 1) * tile_size;
2273 int max_xsize_pos = (max_xsize - 1) * tile_size;
2274 int max_ysize_pos = (max_ysize - 1) * tile_size;
2277 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2279 for (yy = 0; yy < 2; yy++)
2281 for (xx = 0; xx < 2; xx++)
2283 int src_xx = src_x + xx * max_xsize_pos;
2284 int src_yy = src_y + yy * max_ysize_pos;
2285 int dst_xx = dst_x + xx * xsize_size_left;
2286 int dst_yy = dst_y + yy * ysize_size_top;
2287 int xx_size = (xx ? tile_size : xsize_size_left);
2288 int yy_size = (yy ? tile_size : ysize_size_top);
2291 BlitBitmapMasked(bitmap_db_cross, backbuffer,
2292 src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
2294 BlitBitmap(bitmap_db_cross, backbuffer,
2295 src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
2299 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2304 SkipUntilDelayReached(&anim_delay, anim_delay_value, &i, last_frame);
2309 void ShowEnvelopeRequest(char *text, unsigned int req_state, int action)
2311 int last_game_status = game_status; /* save current game status */
2312 int graphic = IMG_BACKGROUND_REQUEST;
2313 int sound_opening = SND_REQUEST_OPENING;
2314 int sound_closing = SND_REQUEST_CLOSING;
2315 int anim_mode = graphic_info[graphic].anim_mode;
2316 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2317 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2319 if (game_status == GAME_MODE_PLAYING)
2320 BlitScreenToBitmap(backbuffer);
2322 SetDrawtoField(DRAW_BACKBUFFER);
2324 // SetDrawBackgroundMask(REDRAW_NONE);
2326 if (action == ACTION_OPENING)
2328 BlitBitmap(backbuffer, bitmap_db_store, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2330 if (req_state & REQ_ASK)
2332 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2333 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2335 else if (req_state & REQ_CONFIRM)
2337 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2339 else if (req_state & REQ_PLAYER)
2341 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2342 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2343 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2344 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2347 DrawEnvelopeRequest(text);
2349 if (game_status != GAME_MODE_MAIN)
2353 /* force DOOR font inside door area */
2354 game_status = GAME_MODE_PSEUDO_DOOR;
2356 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
2358 if (action == ACTION_OPENING)
2360 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2362 if (anim_mode == ANIM_DEFAULT)
2363 AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_OPENING);
2365 AnimateEnvelopeRequest(main_anim_mode, ACTION_OPENING);
2369 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2371 if (anim_mode != ANIM_NONE)
2372 AnimateEnvelopeRequest(main_anim_mode, ACTION_CLOSING);
2374 if (anim_mode == ANIM_DEFAULT)
2375 AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_CLOSING);
2378 game.envelope_active = FALSE;
2380 game_status = last_game_status; /* restore current game status */
2382 if (action == ACTION_CLOSING)
2384 if (game_status != GAME_MODE_MAIN)
2387 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2390 // SetDrawBackgroundMask(last_draw_background_mask);
2392 redraw_mask |= REDRAW_FIELD;
2394 if (game_status == GAME_MODE_MAIN)
2399 if (action == ACTION_CLOSING &&
2400 game_status == GAME_MODE_PLAYING &&
2401 level.game_engine_type == GAME_ENGINE_TYPE_RND)
2402 SetDrawtoField(DRAW_FIELDBUFFER);
2405 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
2409 int graphic = el2preimg(element);
2411 getSizedGraphicSource(graphic, 0, tilesize, &src_bitmap, &src_x, &src_y);
2412 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
2415 void DrawLevel(int draw_background_mask)
2419 SetMainBackgroundImage(IMG_BACKGROUND_PLAYING);
2420 SetDrawBackgroundMask(draw_background_mask);
2424 for (x = BX1; x <= BX2; x++)
2425 for (y = BY1; y <= BY2; y++)
2426 DrawScreenField(x, y);
2428 redraw_mask |= REDRAW_FIELD;
2431 void DrawSizedLevel(int size_x, int size_y, int scroll_x, int scroll_y,
2436 for (x = 0; x < size_x; x++)
2437 for (y = 0; y < size_y; y++)
2438 DrawSizedElementOrWall(x, y, scroll_x, scroll_y, tilesize);
2440 redraw_mask |= REDRAW_FIELD;
2443 void DrawMiniLevel(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 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
2451 redraw_mask |= REDRAW_FIELD;
2454 static void DrawPreviewLevelPlayfieldExt(int from_x, int from_y)
2456 boolean show_level_border = (BorderElement != EL_EMPTY);
2457 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2458 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2459 int tile_size = preview.tile_size;
2460 int preview_width = preview.xsize * tile_size;
2461 int preview_height = preview.ysize * tile_size;
2462 int real_preview_xsize = MIN(level_xsize, preview.xsize);
2463 int real_preview_ysize = MIN(level_ysize, preview.ysize);
2464 int real_preview_width = real_preview_xsize * tile_size;
2465 int real_preview_height = real_preview_ysize * tile_size;
2466 int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
2467 int dst_y = SY + ALIGNED_YPOS(preview.y, preview_height, preview.valign);
2470 if (!IN_GFX_FIELD_FULL(dst_x, dst_y + preview_height - 1))
2473 DrawBackground(dst_x, dst_y, preview_width, preview_height);
2475 dst_x += (preview_width - real_preview_width) / 2;
2476 dst_y += (preview_height - real_preview_height) / 2;
2478 for (x = 0; x < real_preview_xsize; x++)
2480 for (y = 0; y < real_preview_ysize; y++)
2482 int lx = from_x + x + (show_level_border ? -1 : 0);
2483 int ly = from_y + y + (show_level_border ? -1 : 0);
2484 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
2485 getBorderElement(lx, ly));
2487 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
2488 element, tile_size);
2492 redraw_mask |= REDRAW_MICROLEVEL;
2495 #define MICROLABEL_EMPTY 0
2496 #define MICROLABEL_LEVEL_NAME 1
2497 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
2498 #define MICROLABEL_LEVEL_AUTHOR 3
2499 #define MICROLABEL_IMPORTED_FROM_HEAD 4
2500 #define MICROLABEL_IMPORTED_FROM 5
2501 #define MICROLABEL_IMPORTED_BY_HEAD 6
2502 #define MICROLABEL_IMPORTED_BY 7
2504 static int getMaxTextLength(struct TextPosInfo *pos, int font_nr)
2506 int max_text_width = SXSIZE;
2507 int font_width = getFontWidth(font_nr);
2509 if (pos->align == ALIGN_CENTER)
2510 max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
2511 else if (pos->align == ALIGN_RIGHT)
2512 max_text_width = pos->x;
2514 max_text_width = SXSIZE - pos->x;
2516 return max_text_width / font_width;
2519 static void DrawPreviewLevelLabelExt(int mode)
2521 struct TextPosInfo *pos = &menu.main.text.level_info_2;
2522 char label_text[MAX_OUTPUT_LINESIZE + 1];
2523 int max_len_label_text;
2524 int font_nr = pos->font;
2527 if (!IN_GFX_FIELD_FULL(pos->x, pos->y + getFontHeight(pos->font)))
2530 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
2531 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
2532 mode == MICROLABEL_IMPORTED_BY_HEAD)
2533 font_nr = pos->font_alt;
2535 max_len_label_text = getMaxTextLength(pos, font_nr);
2537 if (pos->size != -1)
2538 max_len_label_text = pos->size;
2540 for (i = 0; i < max_len_label_text; i++)
2541 label_text[i] = ' ';
2542 label_text[max_len_label_text] = '\0';
2544 if (strlen(label_text) > 0)
2545 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2548 (mode == MICROLABEL_LEVEL_NAME ? level.name :
2549 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
2550 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
2551 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
2552 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
2553 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
2554 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
2555 max_len_label_text);
2556 label_text[max_len_label_text] = '\0';
2558 if (strlen(label_text) > 0)
2559 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2561 redraw_mask |= REDRAW_MICROLEVEL;
2564 static void DrawPreviewLevelExt(boolean restart)
2566 static unsigned int scroll_delay = 0;
2567 static unsigned int label_delay = 0;
2568 static int from_x, from_y, scroll_direction;
2569 static int label_state, label_counter;
2570 unsigned int scroll_delay_value = preview.step_delay;
2571 boolean show_level_border = (BorderElement != EL_EMPTY);
2572 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2573 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2574 int last_game_status = game_status; /* save current game status */
2581 if (preview.anim_mode == ANIM_CENTERED)
2583 if (level_xsize > preview.xsize)
2584 from_x = (level_xsize - preview.xsize) / 2;
2585 if (level_ysize > preview.ysize)
2586 from_y = (level_ysize - preview.ysize) / 2;
2589 from_x += preview.xoffset;
2590 from_y += preview.yoffset;
2592 scroll_direction = MV_RIGHT;
2596 DrawPreviewLevelPlayfieldExt(from_x, from_y);
2597 DrawPreviewLevelLabelExt(label_state);
2599 /* initialize delay counters */
2600 DelayReached(&scroll_delay, 0);
2601 DelayReached(&label_delay, 0);
2603 if (leveldir_current->name)
2605 struct TextPosInfo *pos = &menu.main.text.level_info_1;
2606 char label_text[MAX_OUTPUT_LINESIZE + 1];
2607 int font_nr = pos->font;
2608 int max_len_label_text = getMaxTextLength(pos, font_nr);
2610 if (pos->size != -1)
2611 max_len_label_text = pos->size;
2613 strncpy(label_text, leveldir_current->name, max_len_label_text);
2614 label_text[max_len_label_text] = '\0';
2616 if (IN_GFX_FIELD_FULL(pos->x, pos->y + getFontHeight(pos->font)))
2617 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2620 game_status = last_game_status; /* restore current game status */
2625 /* scroll preview level, if needed */
2626 if (preview.anim_mode != ANIM_NONE &&
2627 (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
2628 DelayReached(&scroll_delay, scroll_delay_value))
2630 switch (scroll_direction)
2635 from_x -= preview.step_offset;
2636 from_x = (from_x < 0 ? 0 : from_x);
2639 scroll_direction = MV_UP;
2643 if (from_x < level_xsize - preview.xsize)
2645 from_x += preview.step_offset;
2646 from_x = (from_x > level_xsize - preview.xsize ?
2647 level_xsize - preview.xsize : from_x);
2650 scroll_direction = MV_DOWN;
2656 from_y -= preview.step_offset;
2657 from_y = (from_y < 0 ? 0 : from_y);
2660 scroll_direction = MV_RIGHT;
2664 if (from_y < level_ysize - preview.ysize)
2666 from_y += preview.step_offset;
2667 from_y = (from_y > level_ysize - preview.ysize ?
2668 level_ysize - preview.ysize : from_y);
2671 scroll_direction = MV_LEFT;
2678 DrawPreviewLevelPlayfieldExt(from_x, from_y);
2681 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
2682 /* redraw micro level label, if needed */
2683 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
2684 !strEqual(level.author, ANONYMOUS_NAME) &&
2685 !strEqual(level.author, leveldir_current->name) &&
2686 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
2688 int max_label_counter = 23;
2690 if (leveldir_current->imported_from != NULL &&
2691 strlen(leveldir_current->imported_from) > 0)
2692 max_label_counter += 14;
2693 if (leveldir_current->imported_by != NULL &&
2694 strlen(leveldir_current->imported_by) > 0)
2695 max_label_counter += 14;
2697 label_counter = (label_counter + 1) % max_label_counter;
2698 label_state = (label_counter >= 0 && label_counter <= 7 ?
2699 MICROLABEL_LEVEL_NAME :
2700 label_counter >= 9 && label_counter <= 12 ?
2701 MICROLABEL_LEVEL_AUTHOR_HEAD :
2702 label_counter >= 14 && label_counter <= 21 ?
2703 MICROLABEL_LEVEL_AUTHOR :
2704 label_counter >= 23 && label_counter <= 26 ?
2705 MICROLABEL_IMPORTED_FROM_HEAD :
2706 label_counter >= 28 && label_counter <= 35 ?
2707 MICROLABEL_IMPORTED_FROM :
2708 label_counter >= 37 && label_counter <= 40 ?
2709 MICROLABEL_IMPORTED_BY_HEAD :
2710 label_counter >= 42 && label_counter <= 49 ?
2711 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
2713 if (leveldir_current->imported_from == NULL &&
2714 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
2715 label_state == MICROLABEL_IMPORTED_FROM))
2716 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
2717 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
2719 DrawPreviewLevelLabelExt(label_state);
2722 game_status = last_game_status; /* restore current game status */
2725 void DrawPreviewLevelInitial()
2727 DrawPreviewLevelExt(TRUE);
2730 void DrawPreviewLevelAnimation()
2732 DrawPreviewLevelExt(FALSE);
2735 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
2736 int graphic, int sync_frame, int mask_mode)
2738 int frame = getGraphicAnimationFrame(graphic, sync_frame);
2740 if (mask_mode == USE_MASKING)
2741 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
2743 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
2746 inline void DrawFixedGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
2747 int graphic, int sync_frame,
2750 int frame = getGraphicAnimationFrame(graphic, sync_frame);
2752 if (mask_mode == USE_MASKING)
2753 DrawFixedGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
2755 DrawFixedGraphicExt(dst_bitmap, x, y, graphic, frame);
2758 inline void DrawGraphicAnimation(int x, int y, int graphic)
2760 int lx = LEVELX(x), ly = LEVELY(y);
2762 if (!IN_SCR_FIELD(x, y))
2765 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
2766 graphic, GfxFrame[lx][ly], NO_MASKING);
2768 MarkTileDirty(x, y);
2771 inline void DrawFixedGraphicAnimation(int x, int y, int graphic)
2773 int lx = LEVELX(x), ly = LEVELY(y);
2775 if (!IN_SCR_FIELD(x, y))
2778 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
2779 graphic, GfxFrame[lx][ly], NO_MASKING);
2780 MarkTileDirty(x, y);
2783 void DrawLevelGraphicAnimation(int x, int y, int graphic)
2785 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2788 void DrawLevelElementAnimation(int x, int y, int element)
2790 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2792 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2795 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
2797 int sx = SCREENX(x), sy = SCREENY(y);
2799 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2802 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2805 DrawGraphicAnimation(sx, sy, graphic);
2808 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
2809 DrawLevelFieldCrumbled(x, y);
2811 if (GFX_CRUMBLED(Feld[x][y]))
2812 DrawLevelFieldCrumbled(x, y);
2816 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
2818 int sx = SCREENX(x), sy = SCREENY(y);
2821 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2824 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2826 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2829 DrawGraphicAnimation(sx, sy, graphic);
2831 if (GFX_CRUMBLED(element))
2832 DrawLevelFieldCrumbled(x, y);
2835 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
2837 if (player->use_murphy)
2839 /* this works only because currently only one player can be "murphy" ... */
2840 static int last_horizontal_dir = MV_LEFT;
2841 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
2843 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2844 last_horizontal_dir = move_dir;
2846 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
2848 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
2850 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
2856 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
2859 static boolean equalGraphics(int graphic1, int graphic2)
2861 struct GraphicInfo *g1 = &graphic_info[graphic1];
2862 struct GraphicInfo *g2 = &graphic_info[graphic2];
2864 return (g1->bitmap == g2->bitmap &&
2865 g1->src_x == g2->src_x &&
2866 g1->src_y == g2->src_y &&
2867 g1->anim_frames == g2->anim_frames &&
2868 g1->anim_delay == g2->anim_delay &&
2869 g1->anim_mode == g2->anim_mode);
2872 void DrawAllPlayers()
2876 for (i = 0; i < MAX_PLAYERS; i++)
2877 if (stored_player[i].active)
2878 DrawPlayer(&stored_player[i]);
2881 void DrawPlayerField(int x, int y)
2883 if (!IS_PLAYER(x, y))
2886 DrawPlayer(PLAYERINFO(x, y));
2889 #define DRAW_PLAYER_OVER_PUSHED_ELEMENT 1
2891 void DrawPlayer(struct PlayerInfo *player)
2893 int jx = player->jx;
2894 int jy = player->jy;
2895 int move_dir = player->MovDir;
2896 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
2897 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
2898 int last_jx = (player->is_moving ? jx - dx : jx);
2899 int last_jy = (player->is_moving ? jy - dy : jy);
2900 int next_jx = jx + dx;
2901 int next_jy = jy + dy;
2902 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
2903 boolean player_is_opaque = FALSE;
2904 int sx = SCREENX(jx), sy = SCREENY(jy);
2905 int sxx = 0, syy = 0;
2906 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
2908 int action = ACTION_DEFAULT;
2909 int last_player_graphic = getPlayerGraphic(player, move_dir);
2910 int last_player_frame = player->Frame;
2913 /* GfxElement[][] is set to the element the player is digging or collecting;
2914 remove also for off-screen player if the player is not moving anymore */
2915 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
2916 GfxElement[jx][jy] = EL_UNDEFINED;
2918 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
2922 if (!IN_LEV_FIELD(jx, jy))
2924 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
2925 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
2926 printf("DrawPlayerField(): This should never happen!\n");
2931 if (element == EL_EXPLOSION)
2934 action = (player->is_pushing ? ACTION_PUSHING :
2935 player->is_digging ? ACTION_DIGGING :
2936 player->is_collecting ? ACTION_COLLECTING :
2937 player->is_moving ? ACTION_MOVING :
2938 player->is_snapping ? ACTION_SNAPPING :
2939 player->is_dropping ? ACTION_DROPPING :
2940 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
2942 if (player->is_waiting)
2943 move_dir = player->dir_waiting;
2945 InitPlayerGfxAnimation(player, action, move_dir);
2947 /* ----------------------------------------------------------------------- */
2948 /* draw things in the field the player is leaving, if needed */
2949 /* ----------------------------------------------------------------------- */
2951 if (player->is_moving)
2953 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
2955 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
2957 if (last_element == EL_DYNAMITE_ACTIVE ||
2958 last_element == EL_EM_DYNAMITE_ACTIVE ||
2959 last_element == EL_SP_DISK_RED_ACTIVE)
2960 DrawDynamite(last_jx, last_jy);
2962 DrawLevelFieldThruMask(last_jx, last_jy);
2964 else if (last_element == EL_DYNAMITE_ACTIVE ||
2965 last_element == EL_EM_DYNAMITE_ACTIVE ||
2966 last_element == EL_SP_DISK_RED_ACTIVE)
2967 DrawDynamite(last_jx, last_jy);
2969 /* !!! this is not enough to prevent flickering of players which are
2970 moving next to each others without a free tile between them -- this
2971 can only be solved by drawing all players layer by layer (first the
2972 background, then the foreground etc.) !!! => TODO */
2973 else if (!IS_PLAYER(last_jx, last_jy))
2974 DrawLevelField(last_jx, last_jy);
2977 DrawLevelField(last_jx, last_jy);
2980 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
2981 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
2984 if (!IN_SCR_FIELD(sx, sy))
2987 /* ----------------------------------------------------------------------- */
2988 /* draw things behind the player, if needed */
2989 /* ----------------------------------------------------------------------- */
2992 DrawLevelElement(jx, jy, Back[jx][jy]);
2993 else if (IS_ACTIVE_BOMB(element))
2994 DrawLevelElement(jx, jy, EL_EMPTY);
2997 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
2999 int old_element = GfxElement[jx][jy];
3000 int old_graphic = el_act_dir2img(old_element, action, move_dir);
3001 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
3003 if (GFX_CRUMBLED(old_element))
3004 DrawLevelFieldCrumbledDigging(jx, jy, move_dir, player->StepFrame);
3006 DrawGraphic(sx, sy, old_graphic, frame);
3008 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
3009 player_is_opaque = TRUE;
3013 GfxElement[jx][jy] = EL_UNDEFINED;
3015 /* make sure that pushed elements are drawn with correct frame rate */
3016 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
3018 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
3019 GfxFrame[jx][jy] = player->StepFrame;
3021 DrawLevelField(jx, jy);
3025 #if !DRAW_PLAYER_OVER_PUSHED_ELEMENT
3026 /* ----------------------------------------------------------------------- */
3027 /* draw player himself */
3028 /* ----------------------------------------------------------------------- */
3030 graphic = getPlayerGraphic(player, move_dir);
3032 /* in the case of changed player action or direction, prevent the current
3033 animation frame from being restarted for identical animations */
3034 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
3035 player->Frame = last_player_frame;
3037 frame = getGraphicAnimationFrame(graphic, player->Frame);
3041 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3042 sxx = player->GfxPos;
3044 syy = player->GfxPos;
3047 if (player_is_opaque)
3048 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
3050 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3052 if (SHIELD_ON(player))
3054 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
3055 IMG_SHIELD_NORMAL_ACTIVE);
3056 int frame = getGraphicAnimationFrame(graphic, -1);
3058 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3062 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
3065 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3066 sxx = player->GfxPos;
3068 syy = player->GfxPos;
3072 /* ----------------------------------------------------------------------- */
3073 /* draw things the player is pushing, if needed */
3074 /* ----------------------------------------------------------------------- */
3076 if (player->is_pushing && player->is_moving)
3078 int px = SCREENX(jx), py = SCREENY(jy);
3079 int pxx = (TILEX - ABS(sxx)) * dx;
3080 int pyy = (TILEY - ABS(syy)) * dy;
3081 int gfx_frame = GfxFrame[jx][jy];
3087 if (!IS_MOVING(jx, jy)) /* push movement already finished */
3089 element = Feld[next_jx][next_jy];
3090 gfx_frame = GfxFrame[next_jx][next_jy];
3093 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
3095 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
3096 frame = getGraphicAnimationFrame(graphic, sync_frame);
3098 /* draw background element under pushed element (like the Sokoban field) */
3099 if (game.use_masked_pushing && IS_MOVING(jx, jy))
3101 /* this allows transparent pushing animation over non-black background */
3104 DrawLevelElement(jx, jy, Back[jx][jy]);
3106 DrawLevelElement(jx, jy, EL_EMPTY);
3108 if (Back[next_jx][next_jy])
3109 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3111 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
3113 else if (Back[next_jx][next_jy])
3114 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3117 /* do not draw (EM style) pushing animation when pushing is finished */
3118 /* (two-tile animations usually do not contain start and end frame) */
3119 if (graphic_info[graphic].double_movement && !IS_MOVING(jx, jy))
3120 DrawLevelElement(next_jx, next_jy, Feld[next_jx][next_jy]);
3122 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3124 /* masked drawing is needed for EMC style (double) movement graphics */
3125 /* !!! (ONLY WHEN DRAWING PUSHED ELEMENT OVER THE PLAYER) !!! */
3126 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3130 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
3131 /* ----------------------------------------------------------------------- */
3132 /* draw player himself */
3133 /* ----------------------------------------------------------------------- */
3135 graphic = getPlayerGraphic(player, move_dir);
3137 /* in the case of changed player action or direction, prevent the current
3138 animation frame from being restarted for identical animations */
3139 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
3140 player->Frame = last_player_frame;
3142 frame = getGraphicAnimationFrame(graphic, player->Frame);
3146 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3147 sxx = player->GfxPos;
3149 syy = player->GfxPos;
3152 if (player_is_opaque)
3153 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
3155 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3157 if (SHIELD_ON(player))
3159 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
3160 IMG_SHIELD_NORMAL_ACTIVE);
3161 int frame = getGraphicAnimationFrame(graphic, -1);
3163 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3167 /* ----------------------------------------------------------------------- */
3168 /* draw things in front of player (active dynamite or dynabombs) */
3169 /* ----------------------------------------------------------------------- */
3171 if (IS_ACTIVE_BOMB(element))
3173 graphic = el2img(element);
3174 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
3176 if (game.emulation == EMU_SUPAPLEX)
3177 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
3179 DrawGraphicThruMask(sx, sy, graphic, frame);
3182 if (player_is_moving && last_element == EL_EXPLOSION)
3184 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
3185 GfxElement[last_jx][last_jy] : EL_EMPTY);
3186 int graphic = el_act2img(element, ACTION_EXPLODING);
3187 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
3188 int phase = ExplodePhase[last_jx][last_jy] - 1;
3189 int frame = getGraphicAnimationFrame(graphic, phase - delay);
3192 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
3195 /* ----------------------------------------------------------------------- */
3196 /* draw elements the player is just walking/passing through/under */
3197 /* ----------------------------------------------------------------------- */
3199 if (player_is_moving)
3201 /* handle the field the player is leaving ... */
3202 if (IS_ACCESSIBLE_INSIDE(last_element))
3203 DrawLevelField(last_jx, last_jy);
3204 else if (IS_ACCESSIBLE_UNDER(last_element))
3205 DrawLevelFieldThruMask(last_jx, last_jy);
3208 /* do not redraw accessible elements if the player is just pushing them */
3209 if (!player_is_moving || !player->is_pushing)
3211 /* ... and the field the player is entering */
3212 if (IS_ACCESSIBLE_INSIDE(element))
3213 DrawLevelField(jx, jy);
3214 else if (IS_ACCESSIBLE_UNDER(element))
3215 DrawLevelFieldThruMask(jx, jy);
3218 MarkTileDirty(sx, sy);
3221 /* ------------------------------------------------------------------------- */
3223 void WaitForEventToContinue()
3225 boolean still_wait = TRUE;
3227 /* simulate releasing mouse button over last gadget, if still pressed */
3229 HandleGadgets(-1, -1, 0);
3231 button_status = MB_RELEASED;
3245 case EVENT_BUTTONPRESS:
3246 case EVENT_KEYPRESS:
3250 case EVENT_KEYRELEASE:
3251 ClearPlayerAction();
3255 HandleOtherEvents(&event);
3259 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3266 /* don't eat all CPU time */
3271 #define MAX_REQUEST_LINES 13
3272 #define MAX_REQUEST_LINE_FONT1_LEN 7
3273 #define MAX_REQUEST_LINE_FONT2_LEN 10
3275 static int RequestHandleEvents(unsigned int req_state)
3277 int last_game_status = game_status; /* save current game status */
3281 button_status = MB_RELEASED;
3283 request_gadget_id = -1;
3292 while (NextValidEvent(&event))
3296 case EVENT_BUTTONPRESS:
3297 case EVENT_BUTTONRELEASE:
3298 case EVENT_MOTIONNOTIFY:
3300 if (event.type == EVENT_MOTIONNOTIFY)
3305 motion_status = TRUE;
3306 mx = ((MotionEvent *) &event)->x;
3307 my = ((MotionEvent *) &event)->y;
3311 motion_status = FALSE;
3312 mx = ((ButtonEvent *) &event)->x;
3313 my = ((ButtonEvent *) &event)->y;
3314 if (event.type == EVENT_BUTTONPRESS)
3315 button_status = ((ButtonEvent *) &event)->button;
3317 button_status = MB_RELEASED;
3320 /* this sets 'request_gadget_id' */
3321 HandleGadgets(mx, my, button_status);
3323 switch (request_gadget_id)
3325 case TOOL_CTRL_ID_YES:
3328 case TOOL_CTRL_ID_NO:
3331 case TOOL_CTRL_ID_CONFIRM:
3332 result = TRUE | FALSE;
3335 case TOOL_CTRL_ID_PLAYER_1:
3338 case TOOL_CTRL_ID_PLAYER_2:
3341 case TOOL_CTRL_ID_PLAYER_3:
3344 case TOOL_CTRL_ID_PLAYER_4:
3355 case EVENT_KEYPRESS:
3356 switch (GetEventKey((KeyEvent *)&event, TRUE))
3359 if (req_state & REQ_CONFIRM)
3364 #if defined(TARGET_SDL2)
3371 #if defined(TARGET_SDL2)
3381 if (req_state & REQ_PLAYER)
3385 case EVENT_KEYRELEASE:
3386 ClearPlayerAction();
3390 HandleOtherEvents(&event);
3395 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3397 int joy = AnyJoystick();
3399 if (joy & JOY_BUTTON_1)
3401 else if (joy & JOY_BUTTON_2)
3405 if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd)
3407 HandleGameActions();
3413 if (!PendingEvent()) /* delay only if no pending events */
3417 game_status = GAME_MODE_PSEUDO_DOOR;
3421 game_status = last_game_status; /* restore current game status */
3427 static boolean RequestDoor(char *text, unsigned int req_state)
3429 unsigned int old_door_state;
3430 int last_game_status = game_status; /* save current game status */
3431 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
3432 int font_nr = FONT_TEXT_2;
3437 if (maxWordLengthInString(text) > MAX_REQUEST_LINE_FONT1_LEN)
3439 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
3440 font_nr = FONT_TEXT_1;
3443 if (game_status == GAME_MODE_PLAYING)
3444 BlitScreenToBitmap(backbuffer);
3446 /* disable deactivated drawing when quick-loading level tape recording */
3447 if (tape.playing && tape.deactivate_display)
3448 TapeDeactivateDisplayOff(TRUE);
3450 SetMouseCursor(CURSOR_DEFAULT);
3452 #if defined(NETWORK_AVALIABLE)
3453 /* pause network game while waiting for request to answer */
3454 if (options.network &&
3455 game_status == GAME_MODE_PLAYING &&
3456 req_state & REQUEST_WAIT_FOR_INPUT)
3457 SendToServer_PausePlaying();
3460 old_door_state = GetDoorState();
3462 /* simulate releasing mouse button over last gadget, if still pressed */
3464 HandleGadgets(-1, -1, 0);
3468 /* draw released gadget before proceeding */
3471 if (old_door_state & DOOR_OPEN_1)
3473 CloseDoor(DOOR_CLOSE_1);
3475 /* save old door content */
3476 BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
3477 0 * DXSIZE, 0, DXSIZE, DYSIZE, 1 * DXSIZE, 0);
3480 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
3481 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3483 /* clear door drawing field */
3484 DrawBackground(DX, DY, DXSIZE, DYSIZE);
3486 /* force DOOR font inside door area */
3487 game_status = GAME_MODE_PSEUDO_DOOR;
3489 /* write text for request */
3490 for (text_ptr = text, ty = 0; ty < MAX_REQUEST_LINES; ty++)
3492 char text_line[max_request_line_len + 1];
3498 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
3500 tc = *(text_ptr + tx);
3501 // if (!tc || tc == ' ')
3502 if (!tc || tc == ' ' || tc == '?' || tc == '!')
3506 if ((tc == '?' || tc == '!') && tl == 0)
3516 strncpy(text_line, text_ptr, tl);
3519 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
3520 DY + 8 + ty * (getFontHeight(font_nr) + 2),
3521 text_line, font_nr);
3523 text_ptr += tl + (tc == ' ' ? 1 : 0);
3524 // text_ptr += tl + (tc == ' ' || tc == '?' || tc == '!' ? 1 : 0);
3527 game_status = last_game_status; /* restore current game status */
3529 if (req_state & REQ_ASK)
3531 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
3532 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
3534 else if (req_state & REQ_CONFIRM)
3536 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
3538 else if (req_state & REQ_PLAYER)
3540 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
3541 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
3542 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
3543 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
3546 /* copy request gadgets to door backbuffer */
3547 BlitBitmap(drawto, bitmap_db_door_1, DX, DY, DXSIZE, DYSIZE, 0, 0);
3549 OpenDoor(DOOR_OPEN_1);
3551 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
3553 if (game_status == GAME_MODE_PLAYING)
3555 SetPanelBackground();
3556 SetDrawBackgroundMask(REDRAW_DOOR_1);
3560 SetDrawBackgroundMask(REDRAW_FIELD);
3566 if (game_status != GAME_MODE_MAIN)
3569 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3571 // ---------- handle request buttons ----------
3572 result = RequestHandleEvents(req_state);
3574 if (game_status != GAME_MODE_MAIN)
3579 if (!(req_state & REQ_STAY_OPEN))
3581 CloseDoor(DOOR_CLOSE_1);
3583 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
3584 (req_state & REQ_REOPEN))
3585 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
3590 if (game_status == GAME_MODE_PLAYING)
3592 SetPanelBackground();
3593 SetDrawBackgroundMask(REDRAW_DOOR_1);
3597 SetDrawBackgroundMask(REDRAW_FIELD);
3600 #if defined(NETWORK_AVALIABLE)
3601 /* continue network game after request */
3602 if (options.network &&
3603 game_status == GAME_MODE_PLAYING &&
3604 req_state & REQUEST_WAIT_FOR_INPUT)
3605 SendToServer_ContinuePlaying();
3608 /* restore deactivated drawing when quick-loading level tape recording */
3609 if (tape.playing && tape.deactivate_display)
3610 TapeDeactivateDisplayOn();
3615 static boolean RequestEnvelope(char *text, unsigned int req_state)
3619 if (game_status == GAME_MODE_PLAYING)
3620 BlitScreenToBitmap(backbuffer);
3622 /* disable deactivated drawing when quick-loading level tape recording */
3623 if (tape.playing && tape.deactivate_display)
3624 TapeDeactivateDisplayOff(TRUE);
3626 SetMouseCursor(CURSOR_DEFAULT);
3628 #if defined(NETWORK_AVALIABLE)
3629 /* pause network game while waiting for request to answer */
3630 if (options.network &&
3631 game_status == GAME_MODE_PLAYING &&
3632 req_state & REQUEST_WAIT_FOR_INPUT)
3633 SendToServer_PausePlaying();
3636 /* simulate releasing mouse button over last gadget, if still pressed */
3638 HandleGadgets(-1, -1, 0);
3642 // (replace with setting corresponding request background)
3643 // SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
3644 // SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3646 /* clear door drawing field */
3647 // DrawBackground(DX, DY, DXSIZE, DYSIZE);
3649 ShowEnvelopeRequest(text, req_state, ACTION_OPENING);
3651 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
3653 if (game_status == GAME_MODE_PLAYING)
3655 SetPanelBackground();
3656 SetDrawBackgroundMask(REDRAW_DOOR_1);
3660 SetDrawBackgroundMask(REDRAW_FIELD);
3666 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3668 // ---------- handle request buttons ----------
3669 result = RequestHandleEvents(req_state);
3671 if (game_status != GAME_MODE_MAIN)
3676 ShowEnvelopeRequest(text, req_state, ACTION_CLOSING);
3680 if (game_status == GAME_MODE_PLAYING)
3682 SetPanelBackground();
3683 SetDrawBackgroundMask(REDRAW_DOOR_1);
3687 SetDrawBackgroundMask(REDRAW_FIELD);
3690 #if defined(NETWORK_AVALIABLE)
3691 /* continue network game after request */
3692 if (options.network &&
3693 game_status == GAME_MODE_PLAYING &&
3694 req_state & REQUEST_WAIT_FOR_INPUT)
3695 SendToServer_ContinuePlaying();
3698 /* restore deactivated drawing when quick-loading level tape recording */
3699 if (tape.playing && tape.deactivate_display)
3700 TapeDeactivateDisplayOn();
3705 boolean Request(char *text, unsigned int req_state)
3707 if (global.use_envelope_request)
3708 return RequestEnvelope(text, req_state);
3710 return RequestDoor(text, req_state);
3713 static int compareDoorPartOrderInfo(const void *object1, const void *object2)
3715 const struct DoorPartOrderInfo *dpo1 = (struct DoorPartOrderInfo *)object1;
3716 const struct DoorPartOrderInfo *dpo2 = (struct DoorPartOrderInfo *)object2;
3719 if (dpo1->sort_priority != dpo2->sort_priority)
3720 compare_result = dpo1->sort_priority - dpo2->sort_priority;
3722 compare_result = dpo1->nr - dpo2->nr;
3724 return compare_result;
3727 void InitGraphicCompatibilityInfo_Doors()
3733 struct DoorInfo *door;
3737 { DOOR_1, IMG_DOOR_1_GFX_PART_1, IMG_DOOR_1_GFX_PART_8, &door_1 },
3738 { DOOR_2, IMG_DOOR_2_GFX_PART_1, IMG_DOOR_2_GFX_PART_8, &door_2 },
3740 { -1, -1, -1, NULL }
3742 struct Rect door_rect_list[] =
3744 { DX, DY, DXSIZE, DYSIZE },
3745 { VX, VY, VXSIZE, VYSIZE }
3749 for (i = 0; doors[i].door_token != -1; i++)
3751 int door_token = doors[i].door_token;
3752 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
3753 int part_1 = doors[i].part_1;
3754 int part_8 = doors[i].part_8;
3755 int part_2 = part_1 + 1;
3756 int part_3 = part_1 + 2;
3757 struct DoorInfo *door = doors[i].door;
3758 struct Rect *door_rect = &door_rect_list[door_index];
3759 boolean door_gfx_redefined = FALSE;
3761 /* check if any door part graphic definitions have been redefined */
3763 for (j = 0; door_part_controls[j].door_token != -1; j++)
3765 struct DoorPartControlInfo *dpc = &door_part_controls[j];
3766 struct FileInfo *fi = getImageListEntryFromImageID(dpc->graphic);
3768 if (dpc->door_token == door_token && fi->redefined)
3769 door_gfx_redefined = TRUE;
3772 /* check for old-style door graphic/animation modifications */
3774 if (!door_gfx_redefined)
3776 if (door->anim_mode & ANIM_STATIC_PANEL)
3778 door->panel.step_xoffset = 0;
3779 door->panel.step_yoffset = 0;
3782 if (door->anim_mode & (ANIM_HORIZONTAL | ANIM_VERTICAL))
3784 struct GraphicInfo *g_part_1 = &graphic_info[part_1];
3785 struct GraphicInfo *g_part_2 = &graphic_info[part_2];
3786 int num_door_steps, num_panel_steps;
3788 /* remove door part graphics other than the two default wings */
3790 for (j = 0; door_part_controls[j].door_token != -1; j++)
3792 struct DoorPartControlInfo *dpc = &door_part_controls[j];
3793 struct GraphicInfo *g = &graphic_info[dpc->graphic];
3795 if (dpc->graphic >= part_3 &&
3796 dpc->graphic <= part_8)
3800 /* set graphics and screen positions of the default wings */
3802 g_part_1->width = door_rect->width;
3803 g_part_1->height = door_rect->height;
3804 g_part_2->width = door_rect->width;
3805 g_part_2->height = door_rect->height;
3806 g_part_2->src_x = door_rect->width;
3807 g_part_2->src_y = g_part_1->src_y;
3809 door->part_2.x = door->part_1.x;
3810 door->part_2.y = door->part_1.y;
3812 if (door->width != -1)
3814 g_part_1->width = door->width;
3815 g_part_2->width = door->width;
3817 // special treatment for graphics and screen position of right wing
3818 g_part_2->src_x += door_rect->width - door->width;
3819 door->part_2.x += door_rect->width - door->width;
3822 if (door->height != -1)
3824 g_part_1->height = door->height;
3825 g_part_2->height = door->height;
3827 // special treatment for graphics and screen position of bottom wing
3828 g_part_2->src_y += door_rect->height - door->height;
3829 door->part_2.y += door_rect->height - door->height;
3832 /* set animation delays for the default wings and panels */
3834 door->part_1.step_delay = door->step_delay;
3835 door->part_2.step_delay = door->step_delay;
3836 door->panel.step_delay = door->step_delay;
3838 /* set animation draw order for the default wings */
3840 door->part_1.sort_priority = 2; /* draw left wing over ... */
3841 door->part_2.sort_priority = 1; /* ... right wing */
3843 /* set animation draw offset for the default wings */
3845 if (door->anim_mode & ANIM_HORIZONTAL)
3847 door->part_1.step_xoffset = door->step_offset;
3848 door->part_1.step_yoffset = 0;
3849 door->part_2.step_xoffset = door->step_offset * -1;
3850 door->part_2.step_yoffset = 0;
3852 num_door_steps = g_part_1->width / door->step_offset;
3854 else // ANIM_VERTICAL
3856 door->part_1.step_xoffset = 0;
3857 door->part_1.step_yoffset = door->step_offset;
3858 door->part_2.step_xoffset = 0;
3859 door->part_2.step_yoffset = door->step_offset * -1;
3861 num_door_steps = g_part_1->height / door->step_offset;
3864 /* set animation draw offset for the default panels */
3866 if (door->step_offset > 1)
3868 num_panel_steps = 2 * door_rect->height / door->step_offset;
3869 door->panel.start_step = num_panel_steps - num_door_steps;
3870 door->panel.start_step_closing = door->panel.start_step;
3874 num_panel_steps = door_rect->height / door->step_offset;
3875 door->panel.start_step = num_panel_steps - num_door_steps / 2;
3876 door->panel.start_step_closing = door->panel.start_step;
3877 door->panel.step_delay *= 2;
3888 for (i = 0; door_part_controls[i].door_token != -1; i++)
3890 struct DoorPartControlInfo *dpc = &door_part_controls[i];
3891 struct DoorPartOrderInfo *dpo = &door_part_order[i];
3893 /* initialize "start_step_opening" and "start_step_closing", if needed */
3894 if (dpc->pos->start_step_opening == 0 &&
3895 dpc->pos->start_step_closing == 0)
3897 // dpc->pos->start_step_opening = dpc->pos->start_step;
3898 dpc->pos->start_step_closing = dpc->pos->start_step;
3901 /* fill structure for door part draw order (sorted below) */
3903 dpo->sort_priority = dpc->pos->sort_priority;
3906 /* sort door part controls according to sort_priority and graphic number */
3907 qsort(door_part_order, MAX_DOOR_PARTS,
3908 sizeof(struct DoorPartOrderInfo), compareDoorPartOrderInfo);
3911 unsigned int OpenDoor(unsigned int door_state)
3913 if (door_state & DOOR_COPY_BACK)
3915 if (door_state & DOOR_OPEN_1)
3916 BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
3917 1 * DXSIZE, 0, DXSIZE, DYSIZE, 0 * DXSIZE, 0);
3919 if (door_state & DOOR_OPEN_2)
3920 BlitBitmap(bitmap_db_door_2, bitmap_db_door_2,
3921 1 * VXSIZE, 0, VXSIZE, VYSIZE, 0 * VXSIZE, 0);
3923 door_state &= ~DOOR_COPY_BACK;
3926 return MoveDoor(door_state);
3929 unsigned int CloseDoor(unsigned int door_state)
3931 unsigned int old_door_state = GetDoorState();
3933 if (!(door_state & DOOR_NO_COPY_BACK))
3935 if (old_door_state & DOOR_OPEN_1)
3936 BlitBitmap(backbuffer, bitmap_db_door_1,
3937 DX, DY, DXSIZE, DYSIZE, 0, 0);
3939 if (old_door_state & DOOR_OPEN_2)
3940 BlitBitmap(backbuffer, bitmap_db_door_2,
3941 VX, VY, VXSIZE, VYSIZE, 0, 0);
3943 door_state &= ~DOOR_NO_COPY_BACK;
3946 return MoveDoor(door_state);
3949 unsigned int GetDoorState()
3951 return MoveDoor(DOOR_GET_STATE);
3954 unsigned int SetDoorState(unsigned int door_state)
3956 return MoveDoor(door_state | DOOR_SET_STATE);
3959 int euclid(int a, int b)
3961 return (b ? euclid(b, a % b) : a);
3964 unsigned int MoveDoor(unsigned int door_state)
3966 struct Rect door_rect_list[] =
3968 { DX, DY, DXSIZE, DYSIZE },
3969 { VX, VY, VXSIZE, VYSIZE }
3971 static int door1 = DOOR_OPEN_1;
3972 static int door2 = DOOR_CLOSE_2;
3973 unsigned int door_delay = 0;
3974 unsigned int door_delay_value;
3977 if (door_state == DOOR_GET_STATE)
3978 return (door1 | door2);
3980 if (door_state & DOOR_SET_STATE)
3982 if (door_state & DOOR_ACTION_1)
3983 door1 = door_state & DOOR_ACTION_1;
3984 if (door_state & DOOR_ACTION_2)
3985 door2 = door_state & DOOR_ACTION_2;
3987 return (door1 | door2);
3990 if (!(door_state & DOOR_FORCE_REDRAW))
3992 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
3993 door_state &= ~DOOR_OPEN_1;
3994 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
3995 door_state &= ~DOOR_CLOSE_1;
3996 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
3997 door_state &= ~DOOR_OPEN_2;
3998 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
3999 door_state &= ~DOOR_CLOSE_2;
4002 if (global.autoplay_leveldir)
4004 door_state |= DOOR_NO_DELAY;
4005 door_state &= ~DOOR_CLOSE_ALL;
4008 if (game_status == GAME_MODE_EDITOR)
4009 door_state |= DOOR_NO_DELAY;
4011 if (door_state & DOOR_ACTION)
4013 boolean door_panel_drawn[NUM_DOORS];
4014 boolean panel_has_doors[NUM_DOORS];
4015 boolean door_part_skip[MAX_DOOR_PARTS];
4016 boolean door_part_done[MAX_DOOR_PARTS];
4017 boolean door_part_done_all;
4018 int num_steps[MAX_DOOR_PARTS];
4019 int max_move_delay = 0; // delay for complete animations of all doors
4020 int max_step_delay = 0; // delay (ms) between two animation frames
4021 int num_move_steps = 0; // number of animation steps for all doors
4022 int max_move_delay_doors_only = 0; // delay for doors only (no panel)
4023 int num_move_steps_doors_only = 0; // steps for doors only (no panel)
4024 int current_move_delay = 0;
4028 for (i = 0; i < NUM_DOORS; i++)
4029 panel_has_doors[i] = FALSE;
4031 for (i = 0; i < MAX_DOOR_PARTS; i++)
4033 struct DoorPartControlInfo *dpc = &door_part_controls[i];
4034 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4035 int door_token = dpc->door_token;
4037 door_part_done[i] = FALSE;
4038 door_part_skip[i] = (!(door_state & door_token) ||
4042 for (i = 0; i < MAX_DOOR_PARTS; i++)
4044 int nr = door_part_order[i].nr;
4045 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
4046 struct DoorPartPosInfo *pos = dpc->pos;
4047 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4048 int door_token = dpc->door_token;
4049 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
4050 boolean is_panel = DOOR_PART_IS_PANEL(nr);
4051 int step_xoffset = ABS(pos->step_xoffset);
4052 int step_yoffset = ABS(pos->step_yoffset);
4053 int step_delay = pos->step_delay;
4054 int current_door_state = door_state & door_token;
4055 boolean door_opening = ((current_door_state & DOOR_OPEN) != 0);
4056 boolean door_closing = ((current_door_state & DOOR_CLOSE) != 0);
4057 boolean part_opening = (is_panel ? door_closing : door_opening);
4058 int start_step = (part_opening ? pos->start_step_opening :
4059 pos->start_step_closing);
4060 float move_xsize = (step_xoffset ? g->width : 0);
4061 float move_ysize = (step_yoffset ? g->height : 0);
4062 int move_xsteps = (step_xoffset ? ceil(move_xsize / step_xoffset) : 0);
4063 int move_ysteps = (step_yoffset ? ceil(move_ysize / step_yoffset) : 0);
4064 int move_steps = (move_xsteps && move_ysteps ?
4065 MIN(move_xsteps, move_ysteps) :
4066 move_xsteps ? move_xsteps : move_ysteps) - start_step;
4067 int move_delay = move_steps * step_delay;
4069 if (door_part_skip[nr])
4072 max_move_delay = MAX(max_move_delay, move_delay);
4073 max_step_delay = (max_step_delay == 0 ? step_delay :
4074 euclid(max_step_delay, step_delay));
4075 num_steps[nr] = move_steps;
4079 max_move_delay_doors_only = MAX(max_move_delay_doors_only, move_delay);
4081 panel_has_doors[door_index] = TRUE;
4085 max_step_delay = MAX(1, max_step_delay); // prevent division by zero
4087 num_move_steps = max_move_delay / max_step_delay;
4088 num_move_steps_doors_only = max_move_delay_doors_only / max_step_delay;
4090 door_delay_value = max_step_delay;
4092 if ((door_state & DOOR_NO_DELAY) || setup.quick_doors)
4094 start = num_move_steps - 1;
4098 /* opening door sound has priority over simultaneously closing door */
4099 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
4100 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
4101 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
4102 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
4105 for (k = start; k < num_move_steps; k++)
4107 int last_frame = num_move_steps - 1; // last frame of this "for" loop
4109 door_part_done_all = TRUE;
4111 for (i = 0; i < NUM_DOORS; i++)
4112 door_panel_drawn[i] = FALSE;
4114 for (i = 0; i < MAX_DOOR_PARTS; i++)
4116 int nr = door_part_order[i].nr;
4117 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
4118 struct DoorPartPosInfo *pos = dpc->pos;
4119 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4120 int door_token = dpc->door_token;
4121 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
4122 boolean is_panel = DOOR_PART_IS_PANEL(nr);
4123 boolean is_panel_and_door_has_closed = FALSE;
4124 struct Rect *door_rect = &door_rect_list[door_index];
4125 Bitmap *bitmap_db_door = (door_token == DOOR_1 ? bitmap_db_door_1 :
4127 Bitmap *bitmap = (is_panel ? bitmap_db_door : g->bitmap);
4128 int current_door_state = door_state & door_token;
4129 boolean door_opening = ((current_door_state & DOOR_OPEN) != 0);
4130 boolean door_closing = !door_opening;
4131 boolean part_opening = (is_panel ? door_closing : door_opening);
4132 boolean part_closing = !part_opening;
4133 int start_step = (part_opening ? pos->start_step_opening :
4134 pos->start_step_closing);
4135 int step_delay = pos->step_delay;
4136 int step_factor = step_delay / max_step_delay;
4137 int k1 = (step_factor ? k / step_factor + 1 : k);
4138 int k2 = (part_opening ? k1 + start_step : num_steps[nr] - k1);
4139 int kk = MAX(0, k2);
4142 int src_x, src_y, src_xx, src_yy;
4143 int dst_x, dst_y, dst_xx, dst_yy;
4146 if (door_part_skip[nr])
4149 if (!(door_state & door_token))
4157 int k2_door = (door_opening ? k : num_move_steps_doors_only - k - 1);
4158 int kk_door = MAX(0, k2_door);
4159 int sync_frame = kk_door * door_delay_value;
4160 int frame = getGraphicAnimationFrame(dpc->graphic, sync_frame);
4162 getGraphicSource(dpc->graphic, frame, &bitmap, &g_src_x, &g_src_y);
4167 if (!door_panel_drawn[door_index])
4169 ClearRectangle(drawto, door_rect->x, door_rect->y,
4170 door_rect->width, door_rect->height);
4172 door_panel_drawn[door_index] = TRUE;
4175 // draw opening or closing door parts
4177 if (pos->step_xoffset < 0) // door part on right side
4180 dst_xx = pos->x + ABS(kk * pos->step_xoffset);
4183 if (dst_xx + width > door_rect->width)
4184 width = door_rect->width - dst_xx;
4186 else // door part on left side
4189 dst_xx = pos->x - kk * pos->step_xoffset;
4193 src_xx = ABS(dst_xx);
4197 width = g->width - src_xx;
4199 // printf("::: k == %d [%d] \n", k, start_step);
4202 if (pos->step_yoffset < 0) // door part on bottom side
4205 dst_yy = pos->y + ABS(kk * pos->step_yoffset);
4208 if (dst_yy + height > door_rect->height)
4209 height = door_rect->height - dst_yy;
4211 else // door part on top side
4214 dst_yy = pos->y - kk * pos->step_yoffset;
4218 src_yy = ABS(dst_yy);
4222 height = g->height - src_yy;
4225 src_x = g_src_x + src_xx;
4226 src_y = g_src_y + src_yy;
4228 dst_x = door_rect->x + dst_xx;
4229 dst_y = door_rect->y + dst_yy;
4231 is_panel_and_door_has_closed =
4234 panel_has_doors[door_index] &&
4235 k >= num_move_steps_doors_only - 1);
4237 if (width >= 0 && width <= g->width &&
4238 height >= 0 && height <= g->height &&
4239 !is_panel_and_door_has_closed)
4241 if (is_panel || !pos->draw_masked)
4242 BlitBitmap(bitmap, drawto, src_x, src_y, width, height,
4245 BlitBitmapMasked(bitmap, drawto, src_x, src_y, width, height,
4249 redraw_mask |= REDRAW_DOOR_FROM_TOKEN(door_token);
4251 if ((part_opening && (width < 0 || height < 0)) ||
4252 (part_closing && (width >= g->width && height >= g->height)))
4253 door_part_done[nr] = TRUE;
4255 // continue door part animations, but not panel after door has closed
4256 if (!door_part_done[nr] && !is_panel_and_door_has_closed)
4257 door_part_done_all = FALSE;
4260 if (!(door_state & DOOR_NO_DELAY))
4264 if (game_status == GAME_MODE_MAIN)
4267 SkipUntilDelayReached(&door_delay, door_delay_value, &k, last_frame);
4269 current_move_delay += max_step_delay;
4272 if (door_part_done_all)
4277 if (door_state & DOOR_ACTION_1)
4278 door1 = door_state & DOOR_ACTION_1;
4279 if (door_state & DOOR_ACTION_2)
4280 door2 = door_state & DOOR_ACTION_2;
4282 return (door1 | door2);
4285 void DrawSpecialEditorDoor()
4287 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
4288 int top_border_width = gfx1->width;
4289 int top_border_height = gfx1->height;
4290 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
4291 int ex = EX - outer_border;
4292 int ey = EY - outer_border;
4293 int vy = VY - outer_border;
4294 int exsize = EXSIZE + 2 * outer_border;
4296 /* draw bigger level editor toolbox window */
4297 BlitBitmap(gfx1->bitmap, drawto, gfx1->src_x, gfx1->src_y,
4298 top_border_width, top_border_height, ex, ey - top_border_height);
4299 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto, ex, vy,
4300 exsize, EYSIZE - VYSIZE + outer_border, ex, ey);
4302 redraw_mask |= REDRAW_ALL;
4305 void UndrawSpecialEditorDoor()
4307 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
4308 int top_border_width = gfx1->width;
4309 int top_border_height = gfx1->height;
4310 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
4311 int ex = EX - outer_border;
4312 int ey = EY - outer_border;
4313 int ey_top = ey - top_border_height;
4314 int exsize = EXSIZE + 2 * outer_border;
4315 int eysize = EYSIZE + 2 * outer_border;
4317 /* draw normal tape recorder window */
4318 if (graphic_info[IMG_GLOBAL_BORDER].bitmap)
4320 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
4321 ex, ey_top, top_border_width, top_border_height,
4323 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
4324 ex, ey, exsize, eysize, ex, ey);
4328 // if screen background is set to "[NONE]", clear editor toolbox window
4329 ClearRectangle(drawto, ex, ey_top, top_border_width, top_border_height);
4330 ClearRectangle(drawto, ex, ey, exsize, eysize);
4333 redraw_mask |= REDRAW_ALL;
4337 /* ---------- new tool button stuff ---------------------------------------- */
4342 struct TextPosInfo *pos;
4345 } toolbutton_info[NUM_TOOL_BUTTONS] =
4348 IMG_REQUEST_BUTTON_GFX_YES, &request.button.yes,
4349 TOOL_CTRL_ID_YES, "yes"
4352 IMG_REQUEST_BUTTON_GFX_NO, &request.button.no,
4353 TOOL_CTRL_ID_NO, "no"
4356 IMG_REQUEST_BUTTON_GFX_CONFIRM, &request.button.confirm,
4357 TOOL_CTRL_ID_CONFIRM, "confirm"
4360 IMG_REQUEST_BUTTON_GFX_PLAYER_1, &request.button.player_1,
4361 TOOL_CTRL_ID_PLAYER_1, "player 1"
4364 IMG_REQUEST_BUTTON_GFX_PLAYER_2, &request.button.player_2,
4365 TOOL_CTRL_ID_PLAYER_2, "player 2"
4368 IMG_REQUEST_BUTTON_GFX_PLAYER_3, &request.button.player_3,
4369 TOOL_CTRL_ID_PLAYER_3, "player 3"
4372 IMG_REQUEST_BUTTON_GFX_PLAYER_4, &request.button.player_4,
4373 TOOL_CTRL_ID_PLAYER_4, "player 4"
4377 void CreateToolButtons()
4381 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4383 struct GraphicInfo *gfx = &graphic_info[toolbutton_info[i].graphic];
4384 struct TextPosInfo *pos = toolbutton_info[i].pos;
4385 struct GadgetInfo *gi;
4386 Bitmap *deco_bitmap = None;
4387 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
4388 unsigned int event_mask = GD_EVENT_RELEASED;
4391 int gd_x = gfx->src_x;
4392 int gd_y = gfx->src_y;
4393 int gd_xp = gfx->src_x + gfx->pressed_xoffset;
4394 int gd_yp = gfx->src_y + gfx->pressed_yoffset;
4397 if (global.use_envelope_request)
4398 setRequestPosition(&dx, &dy, TRUE);
4400 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
4402 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
4404 getSizedGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr), 0,
4405 pos->size, &deco_bitmap, &deco_x, &deco_y);
4406 deco_xpos = (gfx->width - pos->size) / 2;
4407 deco_ypos = (gfx->height - pos->size) / 2;
4410 gi = CreateGadget(GDI_CUSTOM_ID, id,
4411 GDI_INFO_TEXT, toolbutton_info[i].infotext,
4412 GDI_X, dx + GDI_ACTIVE_POS(pos->x),
4413 GDI_Y, dy + GDI_ACTIVE_POS(pos->y),
4414 GDI_WIDTH, gfx->width,
4415 GDI_HEIGHT, gfx->height,
4416 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
4417 GDI_STATE, GD_BUTTON_UNPRESSED,
4418 GDI_DESIGN_UNPRESSED, gfx->bitmap, gd_x, gd_y,
4419 GDI_DESIGN_PRESSED, gfx->bitmap, gd_xp, gd_yp,
4420 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
4421 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
4422 GDI_DECORATION_SIZE, pos->size, pos->size,
4423 GDI_DECORATION_SHIFTING, 1, 1,
4424 GDI_DIRECT_DRAW, FALSE,
4425 GDI_EVENT_MASK, event_mask,
4426 GDI_CALLBACK_ACTION, HandleToolButtons,
4430 Error(ERR_EXIT, "cannot create gadget");
4432 tool_gadget[id] = gi;
4436 void FreeToolButtons()
4440 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4441 FreeGadget(tool_gadget[i]);
4444 static void UnmapToolButtons()
4448 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4449 UnmapGadget(tool_gadget[i]);
4452 static void HandleToolButtons(struct GadgetInfo *gi)
4454 request_gadget_id = gi->custom_id;
4457 static struct Mapping_EM_to_RND_object
4460 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
4461 boolean is_backside; /* backside of moving element */
4467 em_object_mapping_list[] =
4470 Xblank, TRUE, FALSE,
4474 Yacid_splash_eB, FALSE, FALSE,
4475 EL_ACID_SPLASH_RIGHT, -1, -1
4478 Yacid_splash_wB, FALSE, FALSE,
4479 EL_ACID_SPLASH_LEFT, -1, -1
4482 #ifdef EM_ENGINE_BAD_ROLL
4484 Xstone_force_e, FALSE, FALSE,
4485 EL_ROCK, -1, MV_BIT_RIGHT
4488 Xstone_force_w, FALSE, FALSE,
4489 EL_ROCK, -1, MV_BIT_LEFT
4492 Xnut_force_e, FALSE, FALSE,
4493 EL_NUT, -1, MV_BIT_RIGHT
4496 Xnut_force_w, FALSE, FALSE,
4497 EL_NUT, -1, MV_BIT_LEFT
4500 Xspring_force_e, FALSE, FALSE,
4501 EL_SPRING, -1, MV_BIT_RIGHT
4504 Xspring_force_w, FALSE, FALSE,
4505 EL_SPRING, -1, MV_BIT_LEFT
4508 Xemerald_force_e, FALSE, FALSE,
4509 EL_EMERALD, -1, MV_BIT_RIGHT
4512 Xemerald_force_w, FALSE, FALSE,
4513 EL_EMERALD, -1, MV_BIT_LEFT
4516 Xdiamond_force_e, FALSE, FALSE,
4517 EL_DIAMOND, -1, MV_BIT_RIGHT
4520 Xdiamond_force_w, FALSE, FALSE,
4521 EL_DIAMOND, -1, MV_BIT_LEFT
4524 Xbomb_force_e, FALSE, FALSE,
4525 EL_BOMB, -1, MV_BIT_RIGHT
4528 Xbomb_force_w, FALSE, FALSE,
4529 EL_BOMB, -1, MV_BIT_LEFT
4531 #endif /* EM_ENGINE_BAD_ROLL */
4534 Xstone, TRUE, FALSE,
4538 Xstone_pause, FALSE, FALSE,
4542 Xstone_fall, FALSE, FALSE,
4546 Ystone_s, FALSE, FALSE,
4547 EL_ROCK, ACTION_FALLING, -1
4550 Ystone_sB, FALSE, TRUE,
4551 EL_ROCK, ACTION_FALLING, -1
4554 Ystone_e, FALSE, FALSE,
4555 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
4558 Ystone_eB, FALSE, TRUE,
4559 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
4562 Ystone_w, FALSE, FALSE,
4563 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
4566 Ystone_wB, FALSE, TRUE,
4567 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
4574 Xnut_pause, FALSE, FALSE,
4578 Xnut_fall, FALSE, FALSE,
4582 Ynut_s, FALSE, FALSE,
4583 EL_NUT, ACTION_FALLING, -1
4586 Ynut_sB, FALSE, TRUE,
4587 EL_NUT, ACTION_FALLING, -1
4590 Ynut_e, FALSE, FALSE,
4591 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
4594 Ynut_eB, FALSE, TRUE,
4595 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
4598 Ynut_w, FALSE, FALSE,
4599 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
4602 Ynut_wB, FALSE, TRUE,
4603 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
4606 Xbug_n, TRUE, FALSE,
4610 Xbug_e, TRUE, FALSE,
4611 EL_BUG_RIGHT, -1, -1
4614 Xbug_s, TRUE, FALSE,
4618 Xbug_w, TRUE, FALSE,
4622 Xbug_gon, FALSE, FALSE,
4626 Xbug_goe, FALSE, FALSE,
4627 EL_BUG_RIGHT, -1, -1
4630 Xbug_gos, FALSE, FALSE,
4634 Xbug_gow, FALSE, FALSE,
4638 Ybug_n, FALSE, FALSE,
4639 EL_BUG, ACTION_MOVING, MV_BIT_UP
4642 Ybug_nB, FALSE, TRUE,
4643 EL_BUG, ACTION_MOVING, MV_BIT_UP
4646 Ybug_e, FALSE, FALSE,
4647 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
4650 Ybug_eB, FALSE, TRUE,
4651 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
4654 Ybug_s, FALSE, FALSE,
4655 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
4658 Ybug_sB, FALSE, TRUE,
4659 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
4662 Ybug_w, FALSE, FALSE,
4663 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
4666 Ybug_wB, FALSE, TRUE,
4667 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
4670 Ybug_w_n, FALSE, FALSE,
4671 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
4674 Ybug_n_e, FALSE, FALSE,
4675 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
4678 Ybug_e_s, FALSE, FALSE,
4679 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
4682 Ybug_s_w, FALSE, FALSE,
4683 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
4686 Ybug_e_n, FALSE, FALSE,
4687 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
4690 Ybug_s_e, FALSE, FALSE,
4691 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
4694 Ybug_w_s, FALSE, FALSE,
4695 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
4698 Ybug_n_w, FALSE, FALSE,
4699 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
4702 Ybug_stone, FALSE, FALSE,
4703 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
4706 Ybug_spring, FALSE, FALSE,
4707 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
4710 Xtank_n, TRUE, FALSE,
4711 EL_SPACESHIP_UP, -1, -1
4714 Xtank_e, TRUE, FALSE,
4715 EL_SPACESHIP_RIGHT, -1, -1
4718 Xtank_s, TRUE, FALSE,
4719 EL_SPACESHIP_DOWN, -1, -1
4722 Xtank_w, TRUE, FALSE,
4723 EL_SPACESHIP_LEFT, -1, -1
4726 Xtank_gon, FALSE, FALSE,
4727 EL_SPACESHIP_UP, -1, -1
4730 Xtank_goe, FALSE, FALSE,
4731 EL_SPACESHIP_RIGHT, -1, -1
4734 Xtank_gos, FALSE, FALSE,
4735 EL_SPACESHIP_DOWN, -1, -1
4738 Xtank_gow, FALSE, FALSE,
4739 EL_SPACESHIP_LEFT, -1, -1
4742 Ytank_n, FALSE, FALSE,
4743 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
4746 Ytank_nB, FALSE, TRUE,
4747 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
4750 Ytank_e, FALSE, FALSE,
4751 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
4754 Ytank_eB, FALSE, TRUE,
4755 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
4758 Ytank_s, FALSE, FALSE,
4759 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
4762 Ytank_sB, FALSE, TRUE,
4763 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
4766 Ytank_w, FALSE, FALSE,
4767 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
4770 Ytank_wB, FALSE, TRUE,
4771 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
4774 Ytank_w_n, FALSE, FALSE,
4775 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
4778 Ytank_n_e, FALSE, FALSE,
4779 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
4782 Ytank_e_s, FALSE, FALSE,
4783 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
4786 Ytank_s_w, FALSE, FALSE,
4787 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
4790 Ytank_e_n, FALSE, FALSE,
4791 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
4794 Ytank_s_e, FALSE, FALSE,
4795 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
4798 Ytank_w_s, FALSE, FALSE,
4799 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
4802 Ytank_n_w, FALSE, FALSE,
4803 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
4806 Ytank_stone, FALSE, FALSE,
4807 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
4810 Ytank_spring, FALSE, FALSE,
4811 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
4814 Xandroid, TRUE, FALSE,
4815 EL_EMC_ANDROID, ACTION_ACTIVE, -1
4818 Xandroid_1_n, FALSE, FALSE,
4819 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
4822 Xandroid_2_n, FALSE, FALSE,
4823 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
4826 Xandroid_1_e, FALSE, FALSE,
4827 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
4830 Xandroid_2_e, FALSE, FALSE,
4831 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
4834 Xandroid_1_w, FALSE, FALSE,
4835 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
4838 Xandroid_2_w, FALSE, FALSE,
4839 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
4842 Xandroid_1_s, FALSE, FALSE,
4843 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
4846 Xandroid_2_s, FALSE, FALSE,
4847 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
4850 Yandroid_n, FALSE, FALSE,
4851 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
4854 Yandroid_nB, FALSE, TRUE,
4855 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
4858 Yandroid_ne, FALSE, FALSE,
4859 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
4862 Yandroid_neB, FALSE, TRUE,
4863 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
4866 Yandroid_e, FALSE, FALSE,
4867 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
4870 Yandroid_eB, FALSE, TRUE,
4871 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
4874 Yandroid_se, FALSE, FALSE,
4875 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
4878 Yandroid_seB, FALSE, TRUE,
4879 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
4882 Yandroid_s, FALSE, FALSE,
4883 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
4886 Yandroid_sB, FALSE, TRUE,
4887 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
4890 Yandroid_sw, FALSE, FALSE,
4891 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
4894 Yandroid_swB, FALSE, TRUE,
4895 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
4898 Yandroid_w, FALSE, FALSE,
4899 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
4902 Yandroid_wB, FALSE, TRUE,
4903 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
4906 Yandroid_nw, FALSE, FALSE,
4907 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
4910 Yandroid_nwB, FALSE, TRUE,
4911 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
4914 Xspring, TRUE, FALSE,
4918 Xspring_pause, FALSE, FALSE,
4922 Xspring_e, FALSE, FALSE,
4926 Xspring_w, FALSE, FALSE,
4930 Xspring_fall, FALSE, FALSE,
4934 Yspring_s, FALSE, FALSE,
4935 EL_SPRING, ACTION_FALLING, -1
4938 Yspring_sB, FALSE, TRUE,
4939 EL_SPRING, ACTION_FALLING, -1
4942 Yspring_e, FALSE, FALSE,
4943 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
4946 Yspring_eB, FALSE, TRUE,
4947 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
4950 Yspring_w, FALSE, FALSE,
4951 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
4954 Yspring_wB, FALSE, TRUE,
4955 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
4958 Yspring_kill_e, FALSE, FALSE,
4959 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
4962 Yspring_kill_eB, FALSE, TRUE,
4963 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
4966 Yspring_kill_w, FALSE, FALSE,
4967 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
4970 Yspring_kill_wB, FALSE, TRUE,
4971 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
4974 Xeater_n, TRUE, FALSE,
4975 EL_YAMYAM_UP, -1, -1
4978 Xeater_e, TRUE, FALSE,
4979 EL_YAMYAM_RIGHT, -1, -1
4982 Xeater_w, TRUE, FALSE,
4983 EL_YAMYAM_LEFT, -1, -1
4986 Xeater_s, TRUE, FALSE,
4987 EL_YAMYAM_DOWN, -1, -1
4990 Yeater_n, FALSE, FALSE,
4991 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
4994 Yeater_nB, FALSE, TRUE,
4995 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
4998 Yeater_e, FALSE, FALSE,
4999 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
5002 Yeater_eB, FALSE, TRUE,
5003 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
5006 Yeater_s, FALSE, FALSE,
5007 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
5010 Yeater_sB, FALSE, TRUE,
5011 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
5014 Yeater_w, FALSE, FALSE,
5015 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
5018 Yeater_wB, FALSE, TRUE,
5019 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
5022 Yeater_stone, FALSE, FALSE,
5023 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
5026 Yeater_spring, FALSE, FALSE,
5027 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
5030 Xalien, TRUE, FALSE,
5034 Xalien_pause, FALSE, FALSE,
5038 Yalien_n, FALSE, FALSE,
5039 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
5042 Yalien_nB, FALSE, TRUE,
5043 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
5046 Yalien_e, FALSE, FALSE,
5047 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
5050 Yalien_eB, FALSE, TRUE,
5051 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
5054 Yalien_s, FALSE, FALSE,
5055 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
5058 Yalien_sB, FALSE, TRUE,
5059 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
5062 Yalien_w, FALSE, FALSE,
5063 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
5066 Yalien_wB, FALSE, TRUE,
5067 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
5070 Yalien_stone, FALSE, FALSE,
5071 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
5074 Yalien_spring, FALSE, FALSE,
5075 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
5078 Xemerald, TRUE, FALSE,
5082 Xemerald_pause, FALSE, FALSE,
5086 Xemerald_fall, FALSE, FALSE,
5090 Xemerald_shine, FALSE, FALSE,
5091 EL_EMERALD, ACTION_TWINKLING, -1
5094 Yemerald_s, FALSE, FALSE,
5095 EL_EMERALD, ACTION_FALLING, -1
5098 Yemerald_sB, FALSE, TRUE,
5099 EL_EMERALD, ACTION_FALLING, -1
5102 Yemerald_e, FALSE, FALSE,
5103 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
5106 Yemerald_eB, FALSE, TRUE,
5107 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
5110 Yemerald_w, FALSE, FALSE,
5111 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
5114 Yemerald_wB, FALSE, TRUE,
5115 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
5118 Yemerald_eat, FALSE, FALSE,
5119 EL_EMERALD, ACTION_COLLECTING, -1
5122 Yemerald_stone, FALSE, FALSE,
5123 EL_NUT, ACTION_BREAKING, -1
5126 Xdiamond, TRUE, FALSE,
5130 Xdiamond_pause, FALSE, FALSE,
5134 Xdiamond_fall, FALSE, FALSE,
5138 Xdiamond_shine, FALSE, FALSE,
5139 EL_DIAMOND, ACTION_TWINKLING, -1
5142 Ydiamond_s, FALSE, FALSE,
5143 EL_DIAMOND, ACTION_FALLING, -1
5146 Ydiamond_sB, FALSE, TRUE,
5147 EL_DIAMOND, ACTION_FALLING, -1
5150 Ydiamond_e, FALSE, FALSE,
5151 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
5154 Ydiamond_eB, FALSE, TRUE,
5155 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
5158 Ydiamond_w, FALSE, FALSE,
5159 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
5162 Ydiamond_wB, FALSE, TRUE,
5163 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
5166 Ydiamond_eat, FALSE, FALSE,
5167 EL_DIAMOND, ACTION_COLLECTING, -1
5170 Ydiamond_stone, FALSE, FALSE,
5171 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
5174 Xdrip_fall, TRUE, FALSE,
5175 EL_AMOEBA_DROP, -1, -1
5178 Xdrip_stretch, FALSE, FALSE,
5179 EL_AMOEBA_DROP, ACTION_FALLING, -1
5182 Xdrip_stretchB, FALSE, TRUE,
5183 EL_AMOEBA_DROP, ACTION_FALLING, -1
5186 Xdrip_eat, FALSE, FALSE,
5187 EL_AMOEBA_DROP, ACTION_GROWING, -1
5190 Ydrip_s1, FALSE, FALSE,
5191 EL_AMOEBA_DROP, ACTION_FALLING, -1
5194 Ydrip_s1B, FALSE, TRUE,
5195 EL_AMOEBA_DROP, ACTION_FALLING, -1
5198 Ydrip_s2, FALSE, FALSE,
5199 EL_AMOEBA_DROP, ACTION_FALLING, -1
5202 Ydrip_s2B, FALSE, TRUE,
5203 EL_AMOEBA_DROP, ACTION_FALLING, -1
5210 Xbomb_pause, FALSE, FALSE,
5214 Xbomb_fall, FALSE, FALSE,
5218 Ybomb_s, FALSE, FALSE,
5219 EL_BOMB, ACTION_FALLING, -1
5222 Ybomb_sB, FALSE, TRUE,
5223 EL_BOMB, ACTION_FALLING, -1
5226 Ybomb_e, FALSE, FALSE,
5227 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
5230 Ybomb_eB, FALSE, TRUE,
5231 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
5234 Ybomb_w, FALSE, FALSE,
5235 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
5238 Ybomb_wB, FALSE, TRUE,
5239 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
5242 Ybomb_eat, FALSE, FALSE,
5243 EL_BOMB, ACTION_ACTIVATING, -1
5246 Xballoon, TRUE, FALSE,
5250 Yballoon_n, FALSE, FALSE,
5251 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
5254 Yballoon_nB, FALSE, TRUE,
5255 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
5258 Yballoon_e, FALSE, FALSE,
5259 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
5262 Yballoon_eB, FALSE, TRUE,
5263 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
5266 Yballoon_s, FALSE, FALSE,
5267 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
5270 Yballoon_sB, FALSE, TRUE,
5271 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
5274 Yballoon_w, FALSE, FALSE,
5275 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
5278 Yballoon_wB, FALSE, TRUE,
5279 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
5282 Xgrass, TRUE, FALSE,
5283 EL_EMC_GRASS, -1, -1
5286 Ygrass_nB, FALSE, FALSE,
5287 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
5290 Ygrass_eB, FALSE, FALSE,
5291 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
5294 Ygrass_sB, FALSE, FALSE,
5295 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
5298 Ygrass_wB, FALSE, FALSE,
5299 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
5306 Ydirt_nB, FALSE, FALSE,
5307 EL_SAND, ACTION_DIGGING, MV_BIT_UP
5310 Ydirt_eB, FALSE, FALSE,
5311 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
5314 Ydirt_sB, FALSE, FALSE,
5315 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
5318 Ydirt_wB, FALSE, FALSE,
5319 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
5322 Xacid_ne, TRUE, FALSE,
5323 EL_ACID_POOL_TOPRIGHT, -1, -1
5326 Xacid_se, TRUE, FALSE,
5327 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
5330 Xacid_s, TRUE, FALSE,
5331 EL_ACID_POOL_BOTTOM, -1, -1
5334 Xacid_sw, TRUE, FALSE,
5335 EL_ACID_POOL_BOTTOMLEFT, -1, -1
5338 Xacid_nw, TRUE, FALSE,
5339 EL_ACID_POOL_TOPLEFT, -1, -1
5342 Xacid_1, TRUE, FALSE,
5346 Xacid_2, FALSE, FALSE,
5350 Xacid_3, FALSE, FALSE,
5354 Xacid_4, FALSE, FALSE,
5358 Xacid_5, FALSE, FALSE,
5362 Xacid_6, FALSE, FALSE,
5366 Xacid_7, FALSE, FALSE,
5370 Xacid_8, FALSE, FALSE,
5374 Xball_1, TRUE, FALSE,
5375 EL_EMC_MAGIC_BALL, -1, -1
5378 Xball_1B, FALSE, FALSE,
5379 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5382 Xball_2, FALSE, FALSE,
5383 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5386 Xball_2B, FALSE, FALSE,
5387 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5390 Yball_eat, FALSE, FALSE,
5391 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
5394 Ykey_1_eat, FALSE, FALSE,
5395 EL_EM_KEY_1, ACTION_COLLECTING, -1
5398 Ykey_2_eat, FALSE, FALSE,
5399 EL_EM_KEY_2, ACTION_COLLECTING, -1
5402 Ykey_3_eat, FALSE, FALSE,
5403 EL_EM_KEY_3, ACTION_COLLECTING, -1
5406 Ykey_4_eat, FALSE, FALSE,
5407 EL_EM_KEY_4, ACTION_COLLECTING, -1
5410 Ykey_5_eat, FALSE, FALSE,
5411 EL_EMC_KEY_5, ACTION_COLLECTING, -1
5414 Ykey_6_eat, FALSE, FALSE,
5415 EL_EMC_KEY_6, ACTION_COLLECTING, -1
5418 Ykey_7_eat, FALSE, FALSE,
5419 EL_EMC_KEY_7, ACTION_COLLECTING, -1
5422 Ykey_8_eat, FALSE, FALSE,
5423 EL_EMC_KEY_8, ACTION_COLLECTING, -1
5426 Ylenses_eat, FALSE, FALSE,
5427 EL_EMC_LENSES, ACTION_COLLECTING, -1
5430 Ymagnify_eat, FALSE, FALSE,
5431 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
5434 Ygrass_eat, FALSE, FALSE,
5435 EL_EMC_GRASS, ACTION_SNAPPING, -1
5438 Ydirt_eat, FALSE, FALSE,
5439 EL_SAND, ACTION_SNAPPING, -1
5442 Xgrow_ns, TRUE, FALSE,
5443 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
5446 Ygrow_ns_eat, FALSE, FALSE,
5447 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
5450 Xgrow_ew, TRUE, FALSE,
5451 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
5454 Ygrow_ew_eat, FALSE, FALSE,
5455 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
5458 Xwonderwall, TRUE, FALSE,
5459 EL_MAGIC_WALL, -1, -1
5462 XwonderwallB, FALSE, FALSE,
5463 EL_MAGIC_WALL, ACTION_ACTIVE, -1
5466 Xamoeba_1, TRUE, FALSE,
5467 EL_AMOEBA_DRY, ACTION_OTHER, -1
5470 Xamoeba_2, FALSE, FALSE,
5471 EL_AMOEBA_DRY, ACTION_OTHER, -1
5474 Xamoeba_3, FALSE, FALSE,
5475 EL_AMOEBA_DRY, ACTION_OTHER, -1
5478 Xamoeba_4, FALSE, FALSE,
5479 EL_AMOEBA_DRY, ACTION_OTHER, -1
5482 Xamoeba_5, TRUE, FALSE,
5483 EL_AMOEBA_WET, ACTION_OTHER, -1
5486 Xamoeba_6, FALSE, FALSE,
5487 EL_AMOEBA_WET, ACTION_OTHER, -1
5490 Xamoeba_7, FALSE, FALSE,
5491 EL_AMOEBA_WET, ACTION_OTHER, -1
5494 Xamoeba_8, FALSE, FALSE,
5495 EL_AMOEBA_WET, ACTION_OTHER, -1
5498 Xdoor_1, TRUE, FALSE,
5499 EL_EM_GATE_1, -1, -1
5502 Xdoor_2, TRUE, FALSE,
5503 EL_EM_GATE_2, -1, -1
5506 Xdoor_3, TRUE, FALSE,
5507 EL_EM_GATE_3, -1, -1
5510 Xdoor_4, TRUE, FALSE,
5511 EL_EM_GATE_4, -1, -1
5514 Xdoor_5, TRUE, FALSE,
5515 EL_EMC_GATE_5, -1, -1
5518 Xdoor_6, TRUE, FALSE,
5519 EL_EMC_GATE_6, -1, -1
5522 Xdoor_7, TRUE, FALSE,
5523 EL_EMC_GATE_7, -1, -1
5526 Xdoor_8, TRUE, FALSE,
5527 EL_EMC_GATE_8, -1, -1
5530 Xkey_1, TRUE, FALSE,
5534 Xkey_2, TRUE, FALSE,
5538 Xkey_3, TRUE, FALSE,
5542 Xkey_4, TRUE, FALSE,
5546 Xkey_5, TRUE, FALSE,
5547 EL_EMC_KEY_5, -1, -1
5550 Xkey_6, TRUE, FALSE,
5551 EL_EMC_KEY_6, -1, -1
5554 Xkey_7, TRUE, FALSE,
5555 EL_EMC_KEY_7, -1, -1
5558 Xkey_8, TRUE, FALSE,
5559 EL_EMC_KEY_8, -1, -1
5562 Xwind_n, TRUE, FALSE,
5563 EL_BALLOON_SWITCH_UP, -1, -1
5566 Xwind_e, TRUE, FALSE,
5567 EL_BALLOON_SWITCH_RIGHT, -1, -1
5570 Xwind_s, TRUE, FALSE,
5571 EL_BALLOON_SWITCH_DOWN, -1, -1
5574 Xwind_w, TRUE, FALSE,
5575 EL_BALLOON_SWITCH_LEFT, -1, -1
5578 Xwind_nesw, TRUE, FALSE,
5579 EL_BALLOON_SWITCH_ANY, -1, -1
5582 Xwind_stop, TRUE, FALSE,
5583 EL_BALLOON_SWITCH_NONE, -1, -1
5587 EL_EM_EXIT_CLOSED, -1, -1
5590 Xexit_1, TRUE, FALSE,
5591 EL_EM_EXIT_OPEN, -1, -1
5594 Xexit_2, FALSE, FALSE,
5595 EL_EM_EXIT_OPEN, -1, -1
5598 Xexit_3, FALSE, FALSE,
5599 EL_EM_EXIT_OPEN, -1, -1
5602 Xdynamite, TRUE, FALSE,
5603 EL_EM_DYNAMITE, -1, -1
5606 Ydynamite_eat, FALSE, FALSE,
5607 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
5610 Xdynamite_1, TRUE, FALSE,
5611 EL_EM_DYNAMITE_ACTIVE, -1, -1
5614 Xdynamite_2, FALSE, FALSE,
5615 EL_EM_DYNAMITE_ACTIVE, -1, -1
5618 Xdynamite_3, FALSE, FALSE,
5619 EL_EM_DYNAMITE_ACTIVE, -1, -1
5622 Xdynamite_4, FALSE, FALSE,
5623 EL_EM_DYNAMITE_ACTIVE, -1, -1
5626 Xbumper, TRUE, FALSE,
5627 EL_EMC_SPRING_BUMPER, -1, -1
5630 XbumperB, FALSE, FALSE,
5631 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
5634 Xwheel, TRUE, FALSE,
5635 EL_ROBOT_WHEEL, -1, -1
5638 XwheelB, FALSE, FALSE,
5639 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
5642 Xswitch, TRUE, FALSE,
5643 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
5646 XswitchB, FALSE, FALSE,
5647 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
5651 EL_QUICKSAND_EMPTY, -1, -1
5654 Xsand_stone, TRUE, FALSE,
5655 EL_QUICKSAND_FULL, -1, -1
5658 Xsand_stonein_1, FALSE, TRUE,
5659 EL_ROCK, ACTION_FILLING, -1
5662 Xsand_stonein_2, FALSE, TRUE,
5663 EL_ROCK, ACTION_FILLING, -1
5666 Xsand_stonein_3, FALSE, TRUE,
5667 EL_ROCK, ACTION_FILLING, -1
5670 Xsand_stonein_4, FALSE, TRUE,
5671 EL_ROCK, ACTION_FILLING, -1
5674 Xsand_stonesand_1, FALSE, FALSE,
5675 EL_QUICKSAND_EMPTYING, -1, -1
5678 Xsand_stonesand_2, FALSE, FALSE,
5679 EL_QUICKSAND_EMPTYING, -1, -1
5682 Xsand_stonesand_3, FALSE, FALSE,
5683 EL_QUICKSAND_EMPTYING, -1, -1
5686 Xsand_stonesand_4, FALSE, FALSE,
5687 EL_QUICKSAND_EMPTYING, -1, -1
5690 Xsand_stonesand_quickout_1, FALSE, FALSE,
5691 EL_QUICKSAND_EMPTYING, -1, -1
5694 Xsand_stonesand_quickout_2, FALSE, FALSE,
5695 EL_QUICKSAND_EMPTYING, -1, -1
5698 Xsand_stoneout_1, FALSE, FALSE,
5699 EL_ROCK, ACTION_EMPTYING, -1
5702 Xsand_stoneout_2, FALSE, FALSE,
5703 EL_ROCK, ACTION_EMPTYING, -1
5706 Xsand_sandstone_1, FALSE, FALSE,
5707 EL_QUICKSAND_FILLING, -1, -1
5710 Xsand_sandstone_2, FALSE, FALSE,
5711 EL_QUICKSAND_FILLING, -1, -1
5714 Xsand_sandstone_3, FALSE, FALSE,
5715 EL_QUICKSAND_FILLING, -1, -1
5718 Xsand_sandstone_4, FALSE, FALSE,
5719 EL_QUICKSAND_FILLING, -1, -1
5722 Xplant, TRUE, FALSE,
5723 EL_EMC_PLANT, -1, -1
5726 Yplant, FALSE, FALSE,
5727 EL_EMC_PLANT, -1, -1
5730 Xlenses, TRUE, FALSE,
5731 EL_EMC_LENSES, -1, -1
5734 Xmagnify, TRUE, FALSE,
5735 EL_EMC_MAGNIFIER, -1, -1
5738 Xdripper, TRUE, FALSE,
5739 EL_EMC_DRIPPER, -1, -1
5742 XdripperB, FALSE, FALSE,
5743 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
5746 Xfake_blank, TRUE, FALSE,
5747 EL_INVISIBLE_WALL, -1, -1
5750 Xfake_blankB, FALSE, FALSE,
5751 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
5754 Xfake_grass, TRUE, FALSE,
5755 EL_EMC_FAKE_GRASS, -1, -1
5758 Xfake_grassB, FALSE, FALSE,
5759 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
5762 Xfake_door_1, TRUE, FALSE,
5763 EL_EM_GATE_1_GRAY, -1, -1
5766 Xfake_door_2, TRUE, FALSE,
5767 EL_EM_GATE_2_GRAY, -1, -1
5770 Xfake_door_3, TRUE, FALSE,
5771 EL_EM_GATE_3_GRAY, -1, -1
5774 Xfake_door_4, TRUE, FALSE,
5775 EL_EM_GATE_4_GRAY, -1, -1
5778 Xfake_door_5, TRUE, FALSE,
5779 EL_EMC_GATE_5_GRAY, -1, -1
5782 Xfake_door_6, TRUE, FALSE,
5783 EL_EMC_GATE_6_GRAY, -1, -1
5786 Xfake_door_7, TRUE, FALSE,
5787 EL_EMC_GATE_7_GRAY, -1, -1
5790 Xfake_door_8, TRUE, FALSE,
5791 EL_EMC_GATE_8_GRAY, -1, -1
5794 Xfake_acid_1, TRUE, FALSE,
5795 EL_EMC_FAKE_ACID, -1, -1
5798 Xfake_acid_2, FALSE, FALSE,
5799 EL_EMC_FAKE_ACID, -1, -1
5802 Xfake_acid_3, FALSE, FALSE,
5803 EL_EMC_FAKE_ACID, -1, -1
5806 Xfake_acid_4, FALSE, FALSE,
5807 EL_EMC_FAKE_ACID, -1, -1
5810 Xfake_acid_5, FALSE, FALSE,
5811 EL_EMC_FAKE_ACID, -1, -1
5814 Xfake_acid_6, FALSE, FALSE,
5815 EL_EMC_FAKE_ACID, -1, -1
5818 Xfake_acid_7, FALSE, FALSE,
5819 EL_EMC_FAKE_ACID, -1, -1
5822 Xfake_acid_8, FALSE, FALSE,
5823 EL_EMC_FAKE_ACID, -1, -1
5826 Xsteel_1, TRUE, FALSE,
5827 EL_STEELWALL, -1, -1
5830 Xsteel_2, TRUE, FALSE,
5831 EL_EMC_STEELWALL_2, -1, -1
5834 Xsteel_3, TRUE, FALSE,
5835 EL_EMC_STEELWALL_3, -1, -1
5838 Xsteel_4, TRUE, FALSE,
5839 EL_EMC_STEELWALL_4, -1, -1
5842 Xwall_1, TRUE, FALSE,
5846 Xwall_2, TRUE, FALSE,
5847 EL_EMC_WALL_14, -1, -1
5850 Xwall_3, TRUE, FALSE,
5851 EL_EMC_WALL_15, -1, -1
5854 Xwall_4, TRUE, FALSE,
5855 EL_EMC_WALL_16, -1, -1
5858 Xround_wall_1, TRUE, FALSE,
5859 EL_WALL_SLIPPERY, -1, -1
5862 Xround_wall_2, TRUE, FALSE,
5863 EL_EMC_WALL_SLIPPERY_2, -1, -1
5866 Xround_wall_3, TRUE, FALSE,
5867 EL_EMC_WALL_SLIPPERY_3, -1, -1
5870 Xround_wall_4, TRUE, FALSE,
5871 EL_EMC_WALL_SLIPPERY_4, -1, -1
5874 Xdecor_1, TRUE, FALSE,
5875 EL_EMC_WALL_8, -1, -1
5878 Xdecor_2, TRUE, FALSE,
5879 EL_EMC_WALL_6, -1, -1
5882 Xdecor_3, TRUE, FALSE,
5883 EL_EMC_WALL_4, -1, -1
5886 Xdecor_4, TRUE, FALSE,
5887 EL_EMC_WALL_7, -1, -1
5890 Xdecor_5, TRUE, FALSE,
5891 EL_EMC_WALL_5, -1, -1
5894 Xdecor_6, TRUE, FALSE,
5895 EL_EMC_WALL_9, -1, -1
5898 Xdecor_7, TRUE, FALSE,
5899 EL_EMC_WALL_10, -1, -1
5902 Xdecor_8, TRUE, FALSE,
5903 EL_EMC_WALL_1, -1, -1
5906 Xdecor_9, TRUE, FALSE,
5907 EL_EMC_WALL_2, -1, -1
5910 Xdecor_10, TRUE, FALSE,
5911 EL_EMC_WALL_3, -1, -1
5914 Xdecor_11, TRUE, FALSE,
5915 EL_EMC_WALL_11, -1, -1
5918 Xdecor_12, TRUE, FALSE,
5919 EL_EMC_WALL_12, -1, -1
5922 Xalpha_0, TRUE, FALSE,
5923 EL_CHAR('0'), -1, -1
5926 Xalpha_1, TRUE, FALSE,
5927 EL_CHAR('1'), -1, -1
5930 Xalpha_2, TRUE, FALSE,
5931 EL_CHAR('2'), -1, -1
5934 Xalpha_3, TRUE, FALSE,
5935 EL_CHAR('3'), -1, -1
5938 Xalpha_4, TRUE, FALSE,
5939 EL_CHAR('4'), -1, -1
5942 Xalpha_5, TRUE, FALSE,
5943 EL_CHAR('5'), -1, -1
5946 Xalpha_6, TRUE, FALSE,
5947 EL_CHAR('6'), -1, -1
5950 Xalpha_7, TRUE, FALSE,
5951 EL_CHAR('7'), -1, -1
5954 Xalpha_8, TRUE, FALSE,
5955 EL_CHAR('8'), -1, -1
5958 Xalpha_9, TRUE, FALSE,
5959 EL_CHAR('9'), -1, -1
5962 Xalpha_excla, TRUE, FALSE,
5963 EL_CHAR('!'), -1, -1
5966 Xalpha_quote, TRUE, FALSE,
5967 EL_CHAR('"'), -1, -1
5970 Xalpha_comma, TRUE, FALSE,
5971 EL_CHAR(','), -1, -1
5974 Xalpha_minus, TRUE, FALSE,
5975 EL_CHAR('-'), -1, -1
5978 Xalpha_perio, TRUE, FALSE,
5979 EL_CHAR('.'), -1, -1
5982 Xalpha_colon, TRUE, FALSE,
5983 EL_CHAR(':'), -1, -1
5986 Xalpha_quest, TRUE, FALSE,
5987 EL_CHAR('?'), -1, -1
5990 Xalpha_a, TRUE, FALSE,
5991 EL_CHAR('A'), -1, -1
5994 Xalpha_b, TRUE, FALSE,
5995 EL_CHAR('B'), -1, -1
5998 Xalpha_c, TRUE, FALSE,
5999 EL_CHAR('C'), -1, -1
6002 Xalpha_d, TRUE, FALSE,
6003 EL_CHAR('D'), -1, -1
6006 Xalpha_e, TRUE, FALSE,
6007 EL_CHAR('E'), -1, -1
6010 Xalpha_f, TRUE, FALSE,
6011 EL_CHAR('F'), -1, -1
6014 Xalpha_g, TRUE, FALSE,
6015 EL_CHAR('G'), -1, -1
6018 Xalpha_h, TRUE, FALSE,
6019 EL_CHAR('H'), -1, -1
6022 Xalpha_i, TRUE, FALSE,
6023 EL_CHAR('I'), -1, -1
6026 Xalpha_j, TRUE, FALSE,
6027 EL_CHAR('J'), -1, -1
6030 Xalpha_k, TRUE, FALSE,
6031 EL_CHAR('K'), -1, -1
6034 Xalpha_l, TRUE, FALSE,
6035 EL_CHAR('L'), -1, -1
6038 Xalpha_m, TRUE, FALSE,
6039 EL_CHAR('M'), -1, -1
6042 Xalpha_n, TRUE, FALSE,
6043 EL_CHAR('N'), -1, -1
6046 Xalpha_o, TRUE, FALSE,
6047 EL_CHAR('O'), -1, -1
6050 Xalpha_p, TRUE, FALSE,
6051 EL_CHAR('P'), -1, -1
6054 Xalpha_q, TRUE, FALSE,
6055 EL_CHAR('Q'), -1, -1
6058 Xalpha_r, TRUE, FALSE,
6059 EL_CHAR('R'), -1, -1
6062 Xalpha_s, TRUE, FALSE,
6063 EL_CHAR('S'), -1, -1
6066 Xalpha_t, TRUE, FALSE,
6067 EL_CHAR('T'), -1, -1
6070 Xalpha_u, TRUE, FALSE,
6071 EL_CHAR('U'), -1, -1
6074 Xalpha_v, TRUE, FALSE,
6075 EL_CHAR('V'), -1, -1
6078 Xalpha_w, TRUE, FALSE,
6079 EL_CHAR('W'), -1, -1
6082 Xalpha_x, TRUE, FALSE,
6083 EL_CHAR('X'), -1, -1
6086 Xalpha_y, TRUE, FALSE,
6087 EL_CHAR('Y'), -1, -1
6090 Xalpha_z, TRUE, FALSE,
6091 EL_CHAR('Z'), -1, -1
6094 Xalpha_arrow_e, TRUE, FALSE,
6095 EL_CHAR('>'), -1, -1
6098 Xalpha_arrow_w, TRUE, FALSE,
6099 EL_CHAR('<'), -1, -1
6102 Xalpha_copyr, TRUE, FALSE,
6103 EL_CHAR(CHAR_BYTE_COPYRIGHT), -1, -1
6107 Xboom_bug, FALSE, FALSE,
6108 EL_BUG, ACTION_EXPLODING, -1
6111 Xboom_bomb, FALSE, FALSE,
6112 EL_BOMB, ACTION_EXPLODING, -1
6115 Xboom_android, FALSE, FALSE,
6116 EL_EMC_ANDROID, ACTION_OTHER, -1
6119 Xboom_1, FALSE, FALSE,
6120 EL_DEFAULT, ACTION_EXPLODING, -1
6123 Xboom_2, FALSE, FALSE,
6124 EL_DEFAULT, ACTION_EXPLODING, -1
6127 Znormal, FALSE, FALSE,
6131 Zdynamite, FALSE, FALSE,
6135 Zplayer, FALSE, FALSE,
6139 ZBORDER, FALSE, FALSE,
6149 static struct Mapping_EM_to_RND_player
6158 em_player_mapping_list[] =
6162 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
6166 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
6170 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
6174 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
6178 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
6182 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
6186 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
6190 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
6194 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
6198 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
6202 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
6206 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
6210 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
6214 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
6218 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
6222 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
6226 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
6230 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
6234 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
6238 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
6242 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
6246 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
6250 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
6254 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
6258 EL_PLAYER_1, ACTION_DEFAULT, -1,
6262 EL_PLAYER_2, ACTION_DEFAULT, -1,
6266 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
6270 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
6274 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
6278 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
6282 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
6286 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
6290 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
6294 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
6298 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
6302 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
6306 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
6310 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
6314 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
6318 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
6322 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
6326 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
6330 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
6334 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
6338 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
6342 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
6346 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
6350 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
6354 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
6358 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
6362 EL_PLAYER_3, ACTION_DEFAULT, -1,
6366 EL_PLAYER_4, ACTION_DEFAULT, -1,
6375 int map_element_RND_to_EM(int element_rnd)
6377 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
6378 static boolean mapping_initialized = FALSE;
6380 if (!mapping_initialized)
6384 /* return "Xalpha_quest" for all undefined elements in mapping array */
6385 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
6386 mapping_RND_to_EM[i] = Xalpha_quest;
6388 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6389 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
6390 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
6391 em_object_mapping_list[i].element_em;
6393 mapping_initialized = TRUE;
6396 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
6397 return mapping_RND_to_EM[element_rnd];
6399 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
6404 int map_element_EM_to_RND(int element_em)
6406 static unsigned short mapping_EM_to_RND[TILE_MAX];
6407 static boolean mapping_initialized = FALSE;
6409 if (!mapping_initialized)
6413 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
6414 for (i = 0; i < TILE_MAX; i++)
6415 mapping_EM_to_RND[i] = EL_UNKNOWN;
6417 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6418 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
6419 em_object_mapping_list[i].element_rnd;
6421 mapping_initialized = TRUE;
6424 if (element_em >= 0 && element_em < TILE_MAX)
6425 return mapping_EM_to_RND[element_em];
6427 Error(ERR_WARN, "invalid EM level element %d", element_em);
6432 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
6434 struct LevelInfo_EM *level_em = level->native_em_level;
6435 struct LEVEL *lev = level_em->lev;
6438 for (i = 0; i < TILE_MAX; i++)
6439 lev->android_array[i] = Xblank;
6441 for (i = 0; i < level->num_android_clone_elements; i++)
6443 int element_rnd = level->android_clone_element[i];
6444 int element_em = map_element_RND_to_EM(element_rnd);
6446 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
6447 if (em_object_mapping_list[j].element_rnd == element_rnd)
6448 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
6452 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
6454 struct LevelInfo_EM *level_em = level->native_em_level;
6455 struct LEVEL *lev = level_em->lev;
6458 level->num_android_clone_elements = 0;
6460 for (i = 0; i < TILE_MAX; i++)
6462 int element_em = lev->android_array[i];
6464 boolean element_found = FALSE;
6466 if (element_em == Xblank)
6469 element_rnd = map_element_EM_to_RND(element_em);
6471 for (j = 0; j < level->num_android_clone_elements; j++)
6472 if (level->android_clone_element[j] == element_rnd)
6473 element_found = TRUE;
6477 level->android_clone_element[level->num_android_clone_elements++] =
6480 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
6485 if (level->num_android_clone_elements == 0)
6487 level->num_android_clone_elements = 1;
6488 level->android_clone_element[0] = EL_EMPTY;
6492 int map_direction_RND_to_EM(int direction)
6494 return (direction == MV_UP ? 0 :
6495 direction == MV_RIGHT ? 1 :
6496 direction == MV_DOWN ? 2 :
6497 direction == MV_LEFT ? 3 :
6501 int map_direction_EM_to_RND(int direction)
6503 return (direction == 0 ? MV_UP :
6504 direction == 1 ? MV_RIGHT :
6505 direction == 2 ? MV_DOWN :
6506 direction == 3 ? MV_LEFT :
6510 int map_element_RND_to_SP(int element_rnd)
6512 int element_sp = 0x20; /* map unknown elements to yellow "hardware" */
6514 if (element_rnd >= EL_SP_START &&
6515 element_rnd <= EL_SP_END)
6516 element_sp = element_rnd - EL_SP_START;
6517 else if (element_rnd == EL_EMPTY_SPACE)
6519 else if (element_rnd == EL_INVISIBLE_WALL)
6525 int map_element_SP_to_RND(int element_sp)
6527 int element_rnd = EL_UNKNOWN;
6529 if (element_sp >= 0x00 &&
6531 element_rnd = EL_SP_START + element_sp;
6532 else if (element_sp == 0x28)
6533 element_rnd = EL_INVISIBLE_WALL;
6538 int map_action_SP_to_RND(int action_sp)
6542 case actActive: return ACTION_ACTIVE;
6543 case actImpact: return ACTION_IMPACT;
6544 case actExploding: return ACTION_EXPLODING;
6545 case actDigging: return ACTION_DIGGING;
6546 case actSnapping: return ACTION_SNAPPING;
6547 case actCollecting: return ACTION_COLLECTING;
6548 case actPassing: return ACTION_PASSING;
6549 case actPushing: return ACTION_PUSHING;
6550 case actDropping: return ACTION_DROPPING;
6552 default: return ACTION_DEFAULT;
6556 int get_next_element(int element)
6560 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
6561 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
6562 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
6563 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
6564 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
6565 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
6566 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
6567 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
6568 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
6569 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
6570 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
6572 default: return element;
6576 int el_act_dir2img(int element, int action, int direction)
6578 element = GFX_ELEMENT(element);
6579 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
6581 /* direction_graphic[][] == graphic[] for undefined direction graphics */
6582 return element_info[element].direction_graphic[action][direction];
6585 static int el_act_dir2crm(int element, int action, int direction)
6587 element = GFX_ELEMENT(element);
6588 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
6590 /* direction_graphic[][] == graphic[] for undefined direction graphics */
6591 return element_info[element].direction_crumbled[action][direction];
6594 int el_act2img(int element, int action)
6596 element = GFX_ELEMENT(element);
6598 return element_info[element].graphic[action];
6601 int el_act2crm(int element, int action)
6603 element = GFX_ELEMENT(element);
6605 return element_info[element].crumbled[action];
6608 int el_dir2img(int element, int direction)
6610 element = GFX_ELEMENT(element);
6612 return el_act_dir2img(element, ACTION_DEFAULT, direction);
6615 int el2baseimg(int element)
6617 return element_info[element].graphic[ACTION_DEFAULT];
6620 int el2img(int element)
6622 element = GFX_ELEMENT(element);
6624 return element_info[element].graphic[ACTION_DEFAULT];
6627 int el2edimg(int element)
6629 element = GFX_ELEMENT(element);
6631 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
6634 int el2preimg(int element)
6636 element = GFX_ELEMENT(element);
6638 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
6641 int el2panelimg(int element)
6643 element = GFX_ELEMENT(element);
6645 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL];
6648 int font2baseimg(int font_nr)
6650 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
6653 int getBeltNrFromBeltElement(int element)
6655 return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
6656 element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
6657 element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
6660 int getBeltNrFromBeltActiveElement(int element)
6662 return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
6663 element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
6664 element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
6667 int getBeltNrFromBeltSwitchElement(int element)
6669 return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
6670 element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
6671 element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
6674 int getBeltDirNrFromBeltElement(int element)
6676 static int belt_base_element[4] =
6678 EL_CONVEYOR_BELT_1_LEFT,
6679 EL_CONVEYOR_BELT_2_LEFT,
6680 EL_CONVEYOR_BELT_3_LEFT,
6681 EL_CONVEYOR_BELT_4_LEFT
6684 int belt_nr = getBeltNrFromBeltElement(element);
6685 int belt_dir_nr = element - belt_base_element[belt_nr];
6687 return (belt_dir_nr % 3);
6690 int getBeltDirNrFromBeltSwitchElement(int element)
6692 static int belt_base_element[4] =
6694 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
6695 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
6696 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
6697 EL_CONVEYOR_BELT_4_SWITCH_LEFT
6700 int belt_nr = getBeltNrFromBeltSwitchElement(element);
6701 int belt_dir_nr = element - belt_base_element[belt_nr];
6703 return (belt_dir_nr % 3);
6706 int getBeltDirFromBeltElement(int element)
6708 static int belt_move_dir[3] =
6715 int belt_dir_nr = getBeltDirNrFromBeltElement(element);
6717 return belt_move_dir[belt_dir_nr];
6720 int getBeltDirFromBeltSwitchElement(int element)
6722 static int belt_move_dir[3] =
6729 int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
6731 return belt_move_dir[belt_dir_nr];
6734 int getBeltElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
6736 static int belt_base_element[4] =
6738 EL_CONVEYOR_BELT_1_LEFT,
6739 EL_CONVEYOR_BELT_2_LEFT,
6740 EL_CONVEYOR_BELT_3_LEFT,
6741 EL_CONVEYOR_BELT_4_LEFT
6744 return belt_base_element[belt_nr] + belt_dir_nr;
6747 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
6749 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
6751 return getBeltElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
6754 int getBeltSwitchElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
6756 static int belt_base_element[4] =
6758 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
6759 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
6760 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
6761 EL_CONVEYOR_BELT_4_SWITCH_LEFT
6764 return belt_base_element[belt_nr] + belt_dir_nr;
6767 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
6769 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
6771 return getBeltSwitchElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
6774 boolean getTeamMode_EM()
6776 return game.team_mode;
6779 int getGameFrameDelay_EM(int native_em_game_frame_delay)
6781 int game_frame_delay_value;
6783 game_frame_delay_value =
6784 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
6785 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
6788 if (tape.playing && tape.warp_forward && !tape.pausing)
6789 game_frame_delay_value = 0;
6791 return game_frame_delay_value;
6794 unsigned int InitRND(int seed)
6796 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
6797 return InitEngineRandom_EM(seed);
6798 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
6799 return InitEngineRandom_SP(seed);
6801 return InitEngineRandom_RND(seed);
6804 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
6805 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
6807 inline static int get_effective_element_EM(int tile, int frame_em)
6809 int element = object_mapping[tile].element_rnd;
6810 int action = object_mapping[tile].action;
6811 boolean is_backside = object_mapping[tile].is_backside;
6812 boolean action_removing = (action == ACTION_DIGGING ||
6813 action == ACTION_SNAPPING ||
6814 action == ACTION_COLLECTING);
6820 case Yacid_splash_eB:
6821 case Yacid_splash_wB:
6822 return (frame_em > 5 ? EL_EMPTY : element);
6828 else /* frame_em == 7 */
6832 case Yacid_splash_eB:
6833 case Yacid_splash_wB:
6836 case Yemerald_stone:
6839 case Ydiamond_stone:
6843 case Xdrip_stretchB:
6862 case Xsand_stonein_1:
6863 case Xsand_stonein_2:
6864 case Xsand_stonein_3:
6865 case Xsand_stonein_4:
6869 return (is_backside || action_removing ? EL_EMPTY : element);
6874 inline static boolean check_linear_animation_EM(int tile)
6878 case Xsand_stonesand_1:
6879 case Xsand_stonesand_quickout_1:
6880 case Xsand_sandstone_1:
6881 case Xsand_stonein_1:
6882 case Xsand_stoneout_1:
6901 case Yacid_splash_eB:
6902 case Yacid_splash_wB:
6903 case Yemerald_stone:
6910 inline static void set_crumbled_graphics_EM(struct GraphicInfo_EM *g_em,
6911 boolean has_crumbled_graphics,
6912 int crumbled, int sync_frame)
6914 /* if element can be crumbled, but certain action graphics are just empty
6915 space (like instantly snapping sand to empty space in 1 frame), do not
6916 treat these empty space graphics as crumbled graphics in EMC engine */
6917 if (crumbled == IMG_EMPTY_SPACE)
6918 has_crumbled_graphics = FALSE;
6920 if (has_crumbled_graphics)
6922 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
6923 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
6924 g_crumbled->anim_delay,
6925 g_crumbled->anim_mode,
6926 g_crumbled->anim_start_frame,
6929 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
6930 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
6932 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
6934 g_em->has_crumbled_graphics = TRUE;
6938 g_em->crumbled_bitmap = NULL;
6939 g_em->crumbled_src_x = 0;
6940 g_em->crumbled_src_y = 0;
6941 g_em->crumbled_border_size = 0;
6943 g_em->has_crumbled_graphics = FALSE;
6947 void ResetGfxAnimation_EM(int x, int y, int tile)
6952 void SetGfxAnimation_EM(struct GraphicInfo_EM *g_em,
6953 int tile, int frame_em, int x, int y)
6955 int action = object_mapping[tile].action;
6956 int direction = object_mapping[tile].direction;
6957 int effective_element = get_effective_element_EM(tile, frame_em);
6958 int graphic = (direction == MV_NONE ?
6959 el_act2img(effective_element, action) :
6960 el_act_dir2img(effective_element, action, direction));
6961 struct GraphicInfo *g = &graphic_info[graphic];
6963 boolean action_removing = (action == ACTION_DIGGING ||
6964 action == ACTION_SNAPPING ||
6965 action == ACTION_COLLECTING);
6966 boolean action_moving = (action == ACTION_FALLING ||
6967 action == ACTION_MOVING ||
6968 action == ACTION_PUSHING ||
6969 action == ACTION_EATING ||
6970 action == ACTION_FILLING ||
6971 action == ACTION_EMPTYING);
6972 boolean action_falling = (action == ACTION_FALLING ||
6973 action == ACTION_FILLING ||
6974 action == ACTION_EMPTYING);
6976 /* special case: graphic uses "2nd movement tile" and has defined
6977 7 frames for movement animation (or less) => use default graphic
6978 for last (8th) frame which ends the movement animation */
6979 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
6981 action = ACTION_DEFAULT; /* (keep action_* unchanged for now) */
6982 graphic = (direction == MV_NONE ?
6983 el_act2img(effective_element, action) :
6984 el_act_dir2img(effective_element, action, direction));
6986 g = &graphic_info[graphic];
6989 if ((action_removing || check_linear_animation_EM(tile)) && frame_em == 0)
6993 else if (action_moving)
6995 boolean is_backside = object_mapping[tile].is_backside;
6999 int direction = object_mapping[tile].direction;
7000 int move_dir = (action_falling ? MV_DOWN : direction);
7005 /* !!! TEST !!! NEW !!! DOES NOT WORK RIGHT YET !!! */
7006 if (g->double_movement && frame_em == 0)
7010 if (move_dir == MV_LEFT)
7011 GfxFrame[x - 1][y] = GfxFrame[x][y];
7012 else if (move_dir == MV_RIGHT)
7013 GfxFrame[x + 1][y] = GfxFrame[x][y];
7014 else if (move_dir == MV_UP)
7015 GfxFrame[x][y - 1] = GfxFrame[x][y];
7016 else if (move_dir == MV_DOWN)
7017 GfxFrame[x][y + 1] = GfxFrame[x][y];
7024 /* special case: animation for Xsand_stonesand_quickout_1/2 twice as fast */
7025 if (tile == Xsand_stonesand_quickout_1 ||
7026 tile == Xsand_stonesand_quickout_2)
7030 if (graphic_info[graphic].anim_global_sync)
7031 sync_frame = FrameCounter;
7032 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
7033 sync_frame = GfxFrame[x][y];
7035 sync_frame = 0; /* playfield border (pseudo steel) */
7037 SetRandomAnimationValue(x, y);
7039 int frame = getAnimationFrame(g->anim_frames,
7042 g->anim_start_frame,
7045 g_em->unique_identifier =
7046 (graphic << 16) | ((frame % 8) << 12) | (g_em->width << 6) | g_em->height;
7049 void getGraphicSourceObjectExt_EM(struct GraphicInfo_EM *g_em,
7050 int tile, int frame_em, int x, int y)
7052 int action = object_mapping[tile].action;
7053 int direction = object_mapping[tile].direction;
7054 boolean is_backside = object_mapping[tile].is_backside;
7055 int effective_element = get_effective_element_EM(tile, frame_em);
7056 int effective_action = action;
7057 int graphic = (direction == MV_NONE ?
7058 el_act2img(effective_element, effective_action) :
7059 el_act_dir2img(effective_element, effective_action,
7061 int crumbled = (direction == MV_NONE ?
7062 el_act2crm(effective_element, effective_action) :
7063 el_act_dir2crm(effective_element, effective_action,
7065 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7066 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7067 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7068 struct GraphicInfo *g = &graphic_info[graphic];
7071 /* special case: graphic uses "2nd movement tile" and has defined
7072 7 frames for movement animation (or less) => use default graphic
7073 for last (8th) frame which ends the movement animation */
7074 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
7076 effective_action = ACTION_DEFAULT;
7077 graphic = (direction == MV_NONE ?
7078 el_act2img(effective_element, effective_action) :
7079 el_act_dir2img(effective_element, effective_action,
7081 crumbled = (direction == MV_NONE ?
7082 el_act2crm(effective_element, effective_action) :
7083 el_act_dir2crm(effective_element, effective_action,
7086 g = &graphic_info[graphic];
7089 if (graphic_info[graphic].anim_global_sync)
7090 sync_frame = FrameCounter;
7091 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
7092 sync_frame = GfxFrame[x][y];
7094 sync_frame = 0; /* playfield border (pseudo steel) */
7096 SetRandomAnimationValue(x, y);
7098 int frame = getAnimationFrame(g->anim_frames,
7101 g->anim_start_frame,
7104 getGraphicSourceExt(graphic, frame, &g_em->bitmap, &g_em->src_x, &g_em->src_y,
7105 g->double_movement && is_backside);
7107 /* (updating the "crumbled" graphic definitions is probably not really needed,
7108 as animations for crumbled graphics can't be longer than one EMC cycle) */
7109 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
7113 void getGraphicSourcePlayerExt_EM(struct GraphicInfo_EM *g_em,
7114 int player_nr, int anim, int frame_em)
7116 int element = player_mapping[player_nr][anim].element_rnd;
7117 int action = player_mapping[player_nr][anim].action;
7118 int direction = player_mapping[player_nr][anim].direction;
7119 int graphic = (direction == MV_NONE ?
7120 el_act2img(element, action) :
7121 el_act_dir2img(element, action, direction));
7122 struct GraphicInfo *g = &graphic_info[graphic];
7125 InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
7127 stored_player[player_nr].StepFrame = frame_em;
7129 sync_frame = stored_player[player_nr].Frame;
7131 int frame = getAnimationFrame(g->anim_frames,
7134 g->anim_start_frame,
7137 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
7138 &g_em->src_x, &g_em->src_y, FALSE);
7141 void InitGraphicInfo_EM(void)
7146 int num_em_gfx_errors = 0;
7148 if (graphic_info_em_object[0][0].bitmap == NULL)
7150 /* EM graphics not yet initialized in em_open_all() */
7155 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
7158 /* always start with reliable default values */
7159 for (i = 0; i < TILE_MAX; i++)
7161 object_mapping[i].element_rnd = EL_UNKNOWN;
7162 object_mapping[i].is_backside = FALSE;
7163 object_mapping[i].action = ACTION_DEFAULT;
7164 object_mapping[i].direction = MV_NONE;
7167 /* always start with reliable default values */
7168 for (p = 0; p < MAX_PLAYERS; p++)
7170 for (i = 0; i < SPR_MAX; i++)
7172 player_mapping[p][i].element_rnd = EL_UNKNOWN;
7173 player_mapping[p][i].action = ACTION_DEFAULT;
7174 player_mapping[p][i].direction = MV_NONE;
7178 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
7180 int e = em_object_mapping_list[i].element_em;
7182 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
7183 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
7185 if (em_object_mapping_list[i].action != -1)
7186 object_mapping[e].action = em_object_mapping_list[i].action;
7188 if (em_object_mapping_list[i].direction != -1)
7189 object_mapping[e].direction =
7190 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
7193 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
7195 int a = em_player_mapping_list[i].action_em;
7196 int p = em_player_mapping_list[i].player_nr;
7198 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
7200 if (em_player_mapping_list[i].action != -1)
7201 player_mapping[p][a].action = em_player_mapping_list[i].action;
7203 if (em_player_mapping_list[i].direction != -1)
7204 player_mapping[p][a].direction =
7205 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
7208 for (i = 0; i < TILE_MAX; i++)
7210 int element = object_mapping[i].element_rnd;
7211 int action = object_mapping[i].action;
7212 int direction = object_mapping[i].direction;
7213 boolean is_backside = object_mapping[i].is_backside;
7214 boolean action_exploding = ((action == ACTION_EXPLODING ||
7215 action == ACTION_SMASHED_BY_ROCK ||
7216 action == ACTION_SMASHED_BY_SPRING) &&
7217 element != EL_DIAMOND);
7218 boolean action_active = (action == ACTION_ACTIVE);
7219 boolean action_other = (action == ACTION_OTHER);
7221 for (j = 0; j < 8; j++)
7223 int effective_element = get_effective_element_EM(i, j);
7224 int effective_action = (j < 7 ? action :
7225 i == Xdrip_stretch ? action :
7226 i == Xdrip_stretchB ? action :
7227 i == Ydrip_s1 ? action :
7228 i == Ydrip_s1B ? action :
7229 i == Xball_1B ? action :
7230 i == Xball_2 ? action :
7231 i == Xball_2B ? action :
7232 i == Yball_eat ? action :
7233 i == Ykey_1_eat ? action :
7234 i == Ykey_2_eat ? action :
7235 i == Ykey_3_eat ? action :
7236 i == Ykey_4_eat ? action :
7237 i == Ykey_5_eat ? action :
7238 i == Ykey_6_eat ? action :
7239 i == Ykey_7_eat ? action :
7240 i == Ykey_8_eat ? action :
7241 i == Ylenses_eat ? action :
7242 i == Ymagnify_eat ? action :
7243 i == Ygrass_eat ? action :
7244 i == Ydirt_eat ? action :
7245 i == Xsand_stonein_1 ? action :
7246 i == Xsand_stonein_2 ? action :
7247 i == Xsand_stonein_3 ? action :
7248 i == Xsand_stonein_4 ? action :
7249 i == Xsand_stoneout_1 ? action :
7250 i == Xsand_stoneout_2 ? action :
7251 i == Xboom_android ? ACTION_EXPLODING :
7252 action_exploding ? ACTION_EXPLODING :
7253 action_active ? action :
7254 action_other ? action :
7256 int graphic = (el_act_dir2img(effective_element, effective_action,
7258 int crumbled = (el_act_dir2crm(effective_element, effective_action,
7260 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7261 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7262 boolean has_action_graphics = (graphic != base_graphic);
7263 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7264 struct GraphicInfo *g = &graphic_info[graphic];
7265 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7268 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
7269 boolean special_animation = (action != ACTION_DEFAULT &&
7270 g->anim_frames == 3 &&
7271 g->anim_delay == 2 &&
7272 g->anim_mode & ANIM_LINEAR);
7273 int sync_frame = (i == Xdrip_stretch ? 7 :
7274 i == Xdrip_stretchB ? 7 :
7275 i == Ydrip_s2 ? j + 8 :
7276 i == Ydrip_s2B ? j + 8 :
7285 i == Xfake_acid_1 ? 0 :
7286 i == Xfake_acid_2 ? 10 :
7287 i == Xfake_acid_3 ? 20 :
7288 i == Xfake_acid_4 ? 30 :
7289 i == Xfake_acid_5 ? 40 :
7290 i == Xfake_acid_6 ? 50 :
7291 i == Xfake_acid_7 ? 60 :
7292 i == Xfake_acid_8 ? 70 :
7294 i == Xball_2B ? j + 8 :
7295 i == Yball_eat ? j + 1 :
7296 i == Ykey_1_eat ? j + 1 :
7297 i == Ykey_2_eat ? j + 1 :
7298 i == Ykey_3_eat ? j + 1 :
7299 i == Ykey_4_eat ? j + 1 :
7300 i == Ykey_5_eat ? j + 1 :
7301 i == Ykey_6_eat ? j + 1 :
7302 i == Ykey_7_eat ? j + 1 :
7303 i == Ykey_8_eat ? j + 1 :
7304 i == Ylenses_eat ? j + 1 :
7305 i == Ymagnify_eat ? j + 1 :
7306 i == Ygrass_eat ? j + 1 :
7307 i == Ydirt_eat ? j + 1 :
7308 i == Xamoeba_1 ? 0 :
7309 i == Xamoeba_2 ? 1 :
7310 i == Xamoeba_3 ? 2 :
7311 i == Xamoeba_4 ? 3 :
7312 i == Xamoeba_5 ? 0 :
7313 i == Xamoeba_6 ? 1 :
7314 i == Xamoeba_7 ? 2 :
7315 i == Xamoeba_8 ? 3 :
7316 i == Xexit_2 ? j + 8 :
7317 i == Xexit_3 ? j + 16 :
7318 i == Xdynamite_1 ? 0 :
7319 i == Xdynamite_2 ? 8 :
7320 i == Xdynamite_3 ? 16 :
7321 i == Xdynamite_4 ? 24 :
7322 i == Xsand_stonein_1 ? j + 1 :
7323 i == Xsand_stonein_2 ? j + 9 :
7324 i == Xsand_stonein_3 ? j + 17 :
7325 i == Xsand_stonein_4 ? j + 25 :
7326 i == Xsand_stoneout_1 && j == 0 ? 0 :
7327 i == Xsand_stoneout_1 && j == 1 ? 0 :
7328 i == Xsand_stoneout_1 && j == 2 ? 1 :
7329 i == Xsand_stoneout_1 && j == 3 ? 2 :
7330 i == Xsand_stoneout_1 && j == 4 ? 2 :
7331 i == Xsand_stoneout_1 && j == 5 ? 3 :
7332 i == Xsand_stoneout_1 && j == 6 ? 4 :
7333 i == Xsand_stoneout_1 && j == 7 ? 4 :
7334 i == Xsand_stoneout_2 && j == 0 ? 5 :
7335 i == Xsand_stoneout_2 && j == 1 ? 6 :
7336 i == Xsand_stoneout_2 && j == 2 ? 7 :
7337 i == Xsand_stoneout_2 && j == 3 ? 8 :
7338 i == Xsand_stoneout_2 && j == 4 ? 9 :
7339 i == Xsand_stoneout_2 && j == 5 ? 11 :
7340 i == Xsand_stoneout_2 && j == 6 ? 13 :
7341 i == Xsand_stoneout_2 && j == 7 ? 15 :
7342 i == Xboom_bug && j == 1 ? 2 :
7343 i == Xboom_bug && j == 2 ? 2 :
7344 i == Xboom_bug && j == 3 ? 4 :
7345 i == Xboom_bug && j == 4 ? 4 :
7346 i == Xboom_bug && j == 5 ? 2 :
7347 i == Xboom_bug && j == 6 ? 2 :
7348 i == Xboom_bug && j == 7 ? 0 :
7349 i == Xboom_bomb && j == 1 ? 2 :
7350 i == Xboom_bomb && j == 2 ? 2 :
7351 i == Xboom_bomb && j == 3 ? 4 :
7352 i == Xboom_bomb && j == 4 ? 4 :
7353 i == Xboom_bomb && j == 5 ? 2 :
7354 i == Xboom_bomb && j == 6 ? 2 :
7355 i == Xboom_bomb && j == 7 ? 0 :
7356 i == Xboom_android && j == 7 ? 6 :
7357 i == Xboom_1 && j == 1 ? 2 :
7358 i == Xboom_1 && j == 2 ? 2 :
7359 i == Xboom_1 && j == 3 ? 4 :
7360 i == Xboom_1 && j == 4 ? 4 :
7361 i == Xboom_1 && j == 5 ? 6 :
7362 i == Xboom_1 && j == 6 ? 6 :
7363 i == Xboom_1 && j == 7 ? 8 :
7364 i == Xboom_2 && j == 0 ? 8 :
7365 i == Xboom_2 && j == 1 ? 8 :
7366 i == Xboom_2 && j == 2 ? 10 :
7367 i == Xboom_2 && j == 3 ? 10 :
7368 i == Xboom_2 && j == 4 ? 10 :
7369 i == Xboom_2 && j == 5 ? 12 :
7370 i == Xboom_2 && j == 6 ? 12 :
7371 i == Xboom_2 && j == 7 ? 12 :
7372 special_animation && j == 4 ? 3 :
7373 effective_action != action ? 0 :
7377 Bitmap *debug_bitmap = g_em->bitmap;
7378 int debug_src_x = g_em->src_x;
7379 int debug_src_y = g_em->src_y;
7382 int frame = getAnimationFrame(g->anim_frames,
7385 g->anim_start_frame,
7388 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
7389 g->double_movement && is_backside);
7391 g_em->bitmap = src_bitmap;
7392 g_em->src_x = src_x;
7393 g_em->src_y = src_y;
7394 g_em->src_offset_x = 0;
7395 g_em->src_offset_y = 0;
7396 g_em->dst_offset_x = 0;
7397 g_em->dst_offset_y = 0;
7398 g_em->width = TILEX;
7399 g_em->height = TILEY;
7401 g_em->preserve_background = FALSE;
7403 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
7406 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
7407 effective_action == ACTION_MOVING ||
7408 effective_action == ACTION_PUSHING ||
7409 effective_action == ACTION_EATING)) ||
7410 (!has_action_graphics && (effective_action == ACTION_FILLING ||
7411 effective_action == ACTION_EMPTYING)))
7414 (effective_action == ACTION_FALLING ||
7415 effective_action == ACTION_FILLING ||
7416 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
7417 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
7418 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
7419 int num_steps = (i == Ydrip_s1 ? 16 :
7420 i == Ydrip_s1B ? 16 :
7421 i == Ydrip_s2 ? 16 :
7422 i == Ydrip_s2B ? 16 :
7423 i == Xsand_stonein_1 ? 32 :
7424 i == Xsand_stonein_2 ? 32 :
7425 i == Xsand_stonein_3 ? 32 :
7426 i == Xsand_stonein_4 ? 32 :
7427 i == Xsand_stoneout_1 ? 16 :
7428 i == Xsand_stoneout_2 ? 16 : 8);
7429 int cx = ABS(dx) * (TILEX / num_steps);
7430 int cy = ABS(dy) * (TILEY / num_steps);
7431 int step_frame = (i == Ydrip_s2 ? j + 8 :
7432 i == Ydrip_s2B ? j + 8 :
7433 i == Xsand_stonein_2 ? j + 8 :
7434 i == Xsand_stonein_3 ? j + 16 :
7435 i == Xsand_stonein_4 ? j + 24 :
7436 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
7437 int step = (is_backside ? step_frame : num_steps - step_frame);
7439 if (is_backside) /* tile where movement starts */
7441 if (dx < 0 || dy < 0)
7443 g_em->src_offset_x = cx * step;
7444 g_em->src_offset_y = cy * step;
7448 g_em->dst_offset_x = cx * step;
7449 g_em->dst_offset_y = cy * step;
7452 else /* tile where movement ends */
7454 if (dx < 0 || dy < 0)
7456 g_em->dst_offset_x = cx * step;
7457 g_em->dst_offset_y = cy * step;
7461 g_em->src_offset_x = cx * step;
7462 g_em->src_offset_y = cy * step;
7466 g_em->width = TILEX - cx * step;
7467 g_em->height = TILEY - cy * step;
7470 /* create unique graphic identifier to decide if tile must be redrawn */
7471 /* bit 31 - 16 (16 bit): EM style graphic
7472 bit 15 - 12 ( 4 bit): EM style frame
7473 bit 11 - 6 ( 6 bit): graphic width
7474 bit 5 - 0 ( 6 bit): graphic height */
7475 g_em->unique_identifier =
7476 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
7480 /* skip check for EMC elements not contained in original EMC artwork */
7481 if (element == EL_EMC_FAKE_ACID)
7484 if (g_em->bitmap != debug_bitmap ||
7485 g_em->src_x != debug_src_x ||
7486 g_em->src_y != debug_src_y ||
7487 g_em->src_offset_x != 0 ||
7488 g_em->src_offset_y != 0 ||
7489 g_em->dst_offset_x != 0 ||
7490 g_em->dst_offset_y != 0 ||
7491 g_em->width != TILEX ||
7492 g_em->height != TILEY)
7494 static int last_i = -1;
7502 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
7503 i, element, element_info[element].token_name,
7504 element_action_info[effective_action].suffix, direction);
7506 if (element != effective_element)
7507 printf(" [%d ('%s')]",
7509 element_info[effective_element].token_name);
7513 if (g_em->bitmap != debug_bitmap)
7514 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
7515 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
7517 if (g_em->src_x != debug_src_x ||
7518 g_em->src_y != debug_src_y)
7519 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
7520 j, (is_backside ? 'B' : 'F'),
7521 g_em->src_x, g_em->src_y,
7522 g_em->src_x / 32, g_em->src_y / 32,
7523 debug_src_x, debug_src_y,
7524 debug_src_x / 32, debug_src_y / 32);
7526 if (g_em->src_offset_x != 0 ||
7527 g_em->src_offset_y != 0 ||
7528 g_em->dst_offset_x != 0 ||
7529 g_em->dst_offset_y != 0)
7530 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
7532 g_em->src_offset_x, g_em->src_offset_y,
7533 g_em->dst_offset_x, g_em->dst_offset_y);
7535 if (g_em->width != TILEX ||
7536 g_em->height != TILEY)
7537 printf(" %d (%d): size %d,%d should be %d,%d\n",
7539 g_em->width, g_em->height, TILEX, TILEY);
7541 num_em_gfx_errors++;
7548 for (i = 0; i < TILE_MAX; i++)
7550 for (j = 0; j < 8; j++)
7552 int element = object_mapping[i].element_rnd;
7553 int action = object_mapping[i].action;
7554 int direction = object_mapping[i].direction;
7555 boolean is_backside = object_mapping[i].is_backside;
7556 int graphic_action = el_act_dir2img(element, action, direction);
7557 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
7559 if ((action == ACTION_SMASHED_BY_ROCK ||
7560 action == ACTION_SMASHED_BY_SPRING ||
7561 action == ACTION_EATING) &&
7562 graphic_action == graphic_default)
7564 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
7565 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
7566 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
7567 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
7570 /* no separate animation for "smashed by rock" -- use rock instead */
7571 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7572 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
7574 g_em->bitmap = g_xx->bitmap;
7575 g_em->src_x = g_xx->src_x;
7576 g_em->src_y = g_xx->src_y;
7577 g_em->src_offset_x = g_xx->src_offset_x;
7578 g_em->src_offset_y = g_xx->src_offset_y;
7579 g_em->dst_offset_x = g_xx->dst_offset_x;
7580 g_em->dst_offset_y = g_xx->dst_offset_y;
7581 g_em->width = g_xx->width;
7582 g_em->height = g_xx->height;
7583 g_em->unique_identifier = g_xx->unique_identifier;
7586 g_em->preserve_background = TRUE;
7591 for (p = 0; p < MAX_PLAYERS; p++)
7593 for (i = 0; i < SPR_MAX; i++)
7595 int element = player_mapping[p][i].element_rnd;
7596 int action = player_mapping[p][i].action;
7597 int direction = player_mapping[p][i].direction;
7599 for (j = 0; j < 8; j++)
7601 int effective_element = element;
7602 int effective_action = action;
7603 int graphic = (direction == MV_NONE ?
7604 el_act2img(effective_element, effective_action) :
7605 el_act_dir2img(effective_element, effective_action,
7607 struct GraphicInfo *g = &graphic_info[graphic];
7608 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
7614 Bitmap *debug_bitmap = g_em->bitmap;
7615 int debug_src_x = g_em->src_x;
7616 int debug_src_y = g_em->src_y;
7619 int frame = getAnimationFrame(g->anim_frames,
7622 g->anim_start_frame,
7625 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
7627 g_em->bitmap = src_bitmap;
7628 g_em->src_x = src_x;
7629 g_em->src_y = src_y;
7630 g_em->src_offset_x = 0;
7631 g_em->src_offset_y = 0;
7632 g_em->dst_offset_x = 0;
7633 g_em->dst_offset_y = 0;
7634 g_em->width = TILEX;
7635 g_em->height = TILEY;
7639 /* skip check for EMC elements not contained in original EMC artwork */
7640 if (element == EL_PLAYER_3 ||
7641 element == EL_PLAYER_4)
7644 if (g_em->bitmap != debug_bitmap ||
7645 g_em->src_x != debug_src_x ||
7646 g_em->src_y != debug_src_y)
7648 static int last_i = -1;
7656 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
7657 p, i, element, element_info[element].token_name,
7658 element_action_info[effective_action].suffix, direction);
7660 if (element != effective_element)
7661 printf(" [%d ('%s')]",
7663 element_info[effective_element].token_name);
7667 if (g_em->bitmap != debug_bitmap)
7668 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
7669 j, (int)(g_em->bitmap), (int)(debug_bitmap));
7671 if (g_em->src_x != debug_src_x ||
7672 g_em->src_y != debug_src_y)
7673 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
7675 g_em->src_x, g_em->src_y,
7676 g_em->src_x / 32, g_em->src_y / 32,
7677 debug_src_x, debug_src_y,
7678 debug_src_x / 32, debug_src_y / 32);
7680 num_em_gfx_errors++;
7690 printf("::: [%d errors found]\n", num_em_gfx_errors);
7696 void CheckSaveEngineSnapshot_EM(byte action[MAX_PLAYERS], int frame,
7697 boolean any_player_moving,
7698 boolean any_player_snapping,
7699 boolean any_player_dropping)
7701 static boolean player_was_waiting = TRUE;
7703 if (frame == 0 && !any_player_dropping)
7705 if (!player_was_waiting)
7707 if (!SaveEngineSnapshotToList())
7710 player_was_waiting = TRUE;
7713 else if (any_player_moving || any_player_snapping || any_player_dropping)
7715 player_was_waiting = FALSE;
7719 void CheckSaveEngineSnapshot_SP(boolean murphy_is_waiting,
7720 boolean murphy_is_dropping)
7722 static boolean player_was_waiting = TRUE;
7724 if (murphy_is_waiting)
7726 if (!player_was_waiting)
7728 if (!SaveEngineSnapshotToList())
7731 player_was_waiting = TRUE;
7736 player_was_waiting = FALSE;
7740 void CheckSingleStepMode_EM(byte action[MAX_PLAYERS], int frame,
7741 boolean any_player_moving,
7742 boolean any_player_snapping,
7743 boolean any_player_dropping)
7745 if (tape.single_step && tape.recording && !tape.pausing)
7746 if (frame == 0 && !any_player_dropping)
7747 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
7749 CheckSaveEngineSnapshot_EM(action, frame, any_player_moving,
7750 any_player_snapping, any_player_dropping);
7753 void CheckSingleStepMode_SP(boolean murphy_is_waiting,
7754 boolean murphy_is_dropping)
7756 if (tape.single_step && tape.recording && !tape.pausing)
7757 if (murphy_is_waiting)
7758 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
7760 CheckSaveEngineSnapshot_SP(murphy_is_waiting, murphy_is_dropping);
7763 void getGraphicSource_SP(struct GraphicInfo_SP *g_sp,
7764 int graphic, int sync_frame, int x, int y)
7766 int frame = getGraphicAnimationFrame(graphic, sync_frame);
7768 getGraphicSource(graphic, frame, &g_sp->bitmap, &g_sp->src_x, &g_sp->src_y);
7771 boolean isNextAnimationFrame_SP(int graphic, int sync_frame)
7773 return (IS_NEXT_FRAME(sync_frame, graphic));
7776 int getGraphicInfo_Delay(int graphic)
7778 return graphic_info[graphic].anim_delay;
7781 void PlayMenuSoundExt(int sound)
7783 if (sound == SND_UNDEFINED)
7786 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
7787 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
7790 if (IS_LOOP_SOUND(sound))
7791 PlaySoundLoop(sound);
7796 void PlayMenuSound()
7798 PlayMenuSoundExt(menu.sound[game_status]);
7801 void PlayMenuSoundStereo(int sound, int stereo_position)
7803 if (sound == SND_UNDEFINED)
7806 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
7807 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
7810 if (IS_LOOP_SOUND(sound))
7811 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
7813 PlaySoundStereo(sound, stereo_position);
7816 void PlayMenuSoundIfLoopExt(int sound)
7818 if (sound == SND_UNDEFINED)
7821 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
7822 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
7825 if (IS_LOOP_SOUND(sound))
7826 PlaySoundLoop(sound);
7829 void PlayMenuSoundIfLoop()
7831 PlayMenuSoundIfLoopExt(menu.sound[game_status]);
7834 void PlayMenuMusicExt(int music)
7836 if (music == MUS_UNDEFINED)
7839 if (!setup.sound_music)
7845 void PlayMenuMusic()
7847 PlayMenuMusicExt(menu.music[game_status]);
7850 void PlaySoundActivating()
7853 PlaySound(SND_MENU_ITEM_ACTIVATING);
7857 void PlaySoundSelecting()
7860 PlaySound(SND_MENU_ITEM_SELECTING);
7864 void ToggleFullscreenOrChangeWindowScalingIfNeeded()
7866 boolean change_fullscreen = (setup.fullscreen !=
7867 video.fullscreen_enabled);
7868 boolean change_fullscreen_mode = (video.fullscreen_enabled &&
7869 !strEqual(setup.fullscreen_mode,
7870 video.fullscreen_mode_current));
7871 boolean change_window_scaling_percent = (!video.fullscreen_enabled &&
7872 setup.window_scaling_percent !=
7873 video.window_scaling_percent);
7875 if (change_window_scaling_percent && video.fullscreen_enabled)
7878 if (!change_window_scaling_percent && !video.fullscreen_available)
7881 #if defined(TARGET_SDL2)
7882 if (change_window_scaling_percent)
7884 SDLSetWindowScaling(setup.window_scaling_percent);
7888 else if (change_fullscreen)
7890 SDLSetWindowFullscreen(setup.fullscreen);
7892 /* set setup value according to successfully changed fullscreen mode */
7893 setup.fullscreen = video.fullscreen_enabled;
7899 if (change_fullscreen ||
7900 change_fullscreen_mode ||
7901 change_window_scaling_percent)
7903 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
7905 /* save backbuffer content which gets lost when toggling fullscreen mode */
7906 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
7908 if (change_fullscreen_mode)
7910 /* keep fullscreen, but change fullscreen mode (screen resolution) */
7911 video.fullscreen_enabled = FALSE; /* force new fullscreen mode */
7914 if (change_window_scaling_percent)
7916 /* keep window mode, but change window scaling */
7917 video.fullscreen_enabled = TRUE; /* force new window scaling */
7920 /* toggle fullscreen */
7921 ChangeVideoModeIfNeeded(setup.fullscreen);
7923 /* set setup value according to successfully changed fullscreen mode */
7924 setup.fullscreen = video.fullscreen_enabled;
7926 /* restore backbuffer content from temporary backbuffer backup bitmap */
7927 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
7929 FreeBitmap(tmp_backbuffer);
7931 /* update visible window/screen */
7932 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
7936 void ChangeViewportPropertiesIfNeeded()
7938 int gfx_game_mode = game_status;
7939 int gfx_game_mode2 = (game_status == GAME_MODE_EDITOR ? GAME_MODE_DEFAULT :
7941 struct RectWithBorder *vp_playfield = &viewport.playfield[gfx_game_mode];
7942 struct RectWithBorder *vp_door_1 = &viewport.door_1[gfx_game_mode];
7943 struct RectWithBorder *vp_door_2 = &viewport.door_2[gfx_game_mode2];
7944 struct RectWithBorder *vp_door_3 = &viewport.door_2[GAME_MODE_EDITOR];
7945 int border_size = vp_playfield->border_size;
7946 int new_sx = vp_playfield->x + border_size;
7947 int new_sy = vp_playfield->y + border_size;
7948 int new_sxsize = vp_playfield->width - 2 * border_size;
7949 int new_sysize = vp_playfield->height - 2 * border_size;
7950 int new_real_sx = vp_playfield->x;
7951 int new_real_sy = vp_playfield->y;
7952 int new_full_sxsize = vp_playfield->width;
7953 int new_full_sysize = vp_playfield->height;
7954 int new_dx = vp_door_1->x;
7955 int new_dy = vp_door_1->y;
7956 int new_dxsize = vp_door_1->width;
7957 int new_dysize = vp_door_1->height;
7958 int new_vx = vp_door_2->x;
7959 int new_vy = vp_door_2->y;
7960 int new_vxsize = vp_door_2->width;
7961 int new_vysize = vp_door_2->height;
7962 int new_ex = vp_door_3->x;
7963 int new_ey = vp_door_3->y;
7964 int new_exsize = vp_door_3->width;
7965 int new_eysize = vp_door_3->height;
7966 int new_tilesize_var =
7967 (setup.small_game_graphics ? MINI_TILESIZE : game.tile_size);
7969 int tilesize = (gfx_game_mode == GAME_MODE_PLAYING ? new_tilesize_var :
7970 gfx_game_mode == GAME_MODE_EDITOR ? MINI_TILESIZE : TILESIZE);
7971 int new_scr_fieldx = new_sxsize / tilesize;
7972 int new_scr_fieldy = new_sysize / tilesize;
7973 int new_scr_fieldx_buffers = new_sxsize / new_tilesize_var;
7974 int new_scr_fieldy_buffers = new_sysize / new_tilesize_var;
7975 boolean init_gfx_buffers = FALSE;
7976 boolean init_video_buffer = FALSE;
7977 boolean init_gadgets_and_toons = FALSE;
7978 boolean init_em_graphics = FALSE;
7979 boolean drawing_area_changed = FALSE;
7981 if (viewport.window.width != WIN_XSIZE ||
7982 viewport.window.height != WIN_YSIZE)
7984 WIN_XSIZE = viewport.window.width;
7985 WIN_YSIZE = viewport.window.height;
7987 init_video_buffer = TRUE;
7988 init_gfx_buffers = TRUE;
7990 // printf("::: video: init_video_buffer, init_gfx_buffers\n");
7993 if (new_scr_fieldx != SCR_FIELDX ||
7994 new_scr_fieldy != SCR_FIELDY)
7996 /* this always toggles between MAIN and GAME when using small tile size */
7998 SCR_FIELDX = new_scr_fieldx;
7999 SCR_FIELDY = new_scr_fieldy;
8001 // printf("::: new_scr_fieldx != SCR_FIELDX ...\n");
8012 new_sxsize != SXSIZE ||
8013 new_sysize != SYSIZE ||
8014 new_dxsize != DXSIZE ||
8015 new_dysize != DYSIZE ||
8016 new_vxsize != VXSIZE ||
8017 new_vysize != VYSIZE ||
8018 new_exsize != EXSIZE ||
8019 new_eysize != EYSIZE ||
8020 new_real_sx != REAL_SX ||
8021 new_real_sy != REAL_SY ||
8022 new_full_sxsize != FULL_SXSIZE ||
8023 new_full_sysize != FULL_SYSIZE ||
8024 new_tilesize_var != TILESIZE_VAR
8027 if (new_tilesize_var != TILESIZE_VAR)
8029 // printf("::: new_tilesize_var != TILESIZE_VAR\n");
8031 // changing tile size invalidates scroll values of engine snapshots
8032 FreeEngineSnapshotSingle();
8034 // changing tile size requires update of graphic mapping for EM engine
8035 init_em_graphics = TRUE;
8040 new_sxsize != SXSIZE ||
8041 new_sysize != SYSIZE ||
8042 new_real_sx != REAL_SX ||
8043 new_real_sy != REAL_SY ||
8044 new_full_sxsize != FULL_SXSIZE ||
8045 new_full_sysize != FULL_SYSIZE)
8047 if (!init_video_buffer)
8048 drawing_area_changed = TRUE;
8059 SXSIZE = new_sxsize;
8060 SYSIZE = new_sysize;
8061 DXSIZE = new_dxsize;
8062 DYSIZE = new_dysize;
8063 VXSIZE = new_vxsize;
8064 VYSIZE = new_vysize;
8065 EXSIZE = new_exsize;
8066 EYSIZE = new_eysize;
8067 REAL_SX = new_real_sx;
8068 REAL_SY = new_real_sy;
8069 FULL_SXSIZE = new_full_sxsize;
8070 FULL_SYSIZE = new_full_sysize;
8071 TILESIZE_VAR = new_tilesize_var;
8073 init_gfx_buffers = TRUE;
8074 init_gadgets_and_toons = TRUE;
8076 // printf("::: viewports: init_gfx_buffers\n");
8077 // printf("::: viewports: init_gadgets_and_toons\n");
8080 if (init_gfx_buffers)
8082 // printf("::: init_gfx_buffers\n");
8084 SCR_FIELDX = new_scr_fieldx_buffers;
8085 SCR_FIELDY = new_scr_fieldy_buffers;
8089 SCR_FIELDX = new_scr_fieldx;
8090 SCR_FIELDY = new_scr_fieldy;
8092 gfx.drawing_area_changed = drawing_area_changed;
8094 SetDrawDeactivationMask(REDRAW_NONE);
8095 SetDrawBackgroundMask(REDRAW_FIELD);
8098 if (init_video_buffer)
8100 // printf("::: init_video_buffer\n");
8102 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
8105 if (init_gadgets_and_toons)
8107 // printf("::: init_gadgets_and_toons\n");
8113 if (init_em_graphics)
8115 InitGraphicInfo_EM();