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 static 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 if (border.draw_masked[GAME_MODE_PLAYING])
415 if (buffer != backbuffer)
417 /* copy playfield buffer to backbuffer to add masked border */
418 BlitBitmap(buffer, backbuffer, fx, fy, SXSIZE, SYSIZE, SX, SY);
419 DrawMaskedBorder(REDRAW_FIELD);
422 BlitBitmap(backbuffer, target_bitmap,
423 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
428 BlitBitmap(buffer, target_bitmap, fx, fy, SXSIZE, SYSIZE, SX, SY);
432 void BlitScreenToBitmap(Bitmap *target_bitmap)
434 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
435 BlitScreenToBitmap_EM(target_bitmap);
436 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
437 BlitScreenToBitmap_SP(target_bitmap);
438 else if (level.game_engine_type == GAME_ENGINE_TYPE_RND)
439 BlitScreenToBitmap_RND(target_bitmap);
444 DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
447 /* !!! TEST ONLY !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
448 /* (force full redraw) */
449 if (game_status == GAME_MODE_PLAYING)
450 redraw_mask |= REDRAW_FIELD;
453 if (redraw_mask == REDRAW_NONE)
458 if (redraw_mask & REDRAW_ALL)
459 printf("[REDRAW_ALL]");
460 if (redraw_mask & REDRAW_FIELD)
461 printf("[REDRAW_FIELD]");
462 if (redraw_mask & REDRAW_DOOR_1)
463 printf("[REDRAW_DOOR_1]");
464 if (redraw_mask & REDRAW_DOOR_2)
465 printf("[REDRAW_DOOR_2]");
466 if (redraw_mask & REDRAW_FROM_BACKBUFFER)
467 printf("[REDRAW_FROM_BACKBUFFER]");
468 printf(" [%d]\n", FrameCounter);
471 if (global.fps_slowdown && game_status == GAME_MODE_PLAYING)
473 static boolean last_frame_skipped = FALSE;
474 boolean skip_even_when_not_scrolling = TRUE;
475 boolean just_scrolling = (ScreenMovDir != 0);
476 boolean verbose = FALSE;
478 if (global.fps_slowdown_factor > 1 &&
479 (FrameCounter % global.fps_slowdown_factor) &&
480 (just_scrolling || skip_even_when_not_scrolling))
482 redraw_mask &= ~REDRAW_MAIN;
484 last_frame_skipped = TRUE;
487 printf("FRAME SKIPPED\n");
491 if (last_frame_skipped)
492 redraw_mask |= REDRAW_FIELD;
494 last_frame_skipped = FALSE;
497 printf("frame not skipped\n");
501 /* synchronize X11 graphics at this point; if we would synchronize the
502 display immediately after the buffer switching (after the XFlush),
503 this could mean that we have to wait for the graphics to complete,
504 although we could go on doing calculations for the next frame */
508 /* never draw masked border to backbuffer when using playfield buffer */
509 if (game_status != GAME_MODE_PLAYING ||
510 redraw_mask & REDRAW_FROM_BACKBUFFER ||
511 buffer == backbuffer)
512 DrawMaskedBorder(redraw_mask);
514 DrawMaskedBorder(redraw_mask & REDRAW_DOORS);
516 if (redraw_mask & REDRAW_ALL)
518 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
520 redraw_mask = REDRAW_NONE;
523 if (redraw_mask & REDRAW_FIELD)
525 if (game_status != GAME_MODE_PLAYING ||
526 redraw_mask & REDRAW_FROM_BACKBUFFER)
528 BlitBitmap(backbuffer, window,
529 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
533 BlitScreenToBitmap_RND(window);
536 redraw_mask &= ~REDRAW_MAIN;
539 if (redraw_mask & REDRAW_DOORS)
541 if (redraw_mask & REDRAW_DOOR_1)
542 BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
544 if (redraw_mask & REDRAW_DOOR_2)
545 BlitBitmap(backbuffer, window, VX, VY, VXSIZE, VYSIZE, VX, VY);
547 if (redraw_mask & REDRAW_DOOR_3)
548 BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
550 redraw_mask &= ~REDRAW_DOORS;
553 if (redraw_mask & REDRAW_MICROLEVEL)
555 BlitBitmap(backbuffer, window, SX, SY + 10 * TILEY, SXSIZE, 7 * TILEY,
556 SX, SY + 10 * TILEY);
558 redraw_mask &= ~REDRAW_MICROLEVEL;
561 if (redraw_mask & REDRAW_FPS) /* display frames per second */
566 sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
567 if (!global.fps_slowdown)
570 sprintf(text, "%04.1f fps%s", global.frames_per_second, info1);
572 DrawTextExt(window, SX + SXSIZE + SX, 0, text, FONT_TEXT_2, BLIT_OPAQUE);
575 redraw_mask = REDRAW_NONE;
578 static void FadeCrossSaveBackbuffer()
580 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
583 static void FadeExt(int fade_mask, int fade_mode, int fade_type)
585 static int fade_type_skip = FADE_TYPE_NONE;
586 void (*draw_border_function)(void) = NULL;
587 Bitmap *bitmap = (fade_mode & FADE_TYPE_TRANSFORM ? bitmap_db_cross : NULL);
588 int x, y, width, height;
589 int fade_delay, post_delay;
591 if (fade_type == FADE_TYPE_FADE_OUT)
593 if (fade_type_skip != FADE_TYPE_NONE)
595 /* skip all fade operations until specified fade operation */
596 if (fade_type & fade_type_skip)
597 fade_type_skip = FADE_TYPE_NONE;
602 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
604 FadeCrossSaveBackbuffer();
610 redraw_mask |= fade_mask;
612 if (fade_type == FADE_TYPE_SKIP)
614 fade_type_skip = fade_mode;
619 fade_delay = fading.fade_delay;
620 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
622 if (fade_type_skip != FADE_TYPE_NONE)
624 /* skip all fade operations until specified fade operation */
625 if (fade_type & fade_type_skip)
626 fade_type_skip = FADE_TYPE_NONE;
631 if (global.autoplay_leveldir)
636 if (fade_mask == REDRAW_FIELD)
641 height = FULL_SYSIZE;
643 if (border.draw_masked_when_fading)
644 draw_border_function = DrawMaskedBorder_FIELD; /* update when fading */
646 DrawMaskedBorder_FIELD(); /* draw once */
648 else /* REDRAW_ALL */
656 if (!setup.fade_screens ||
658 fading.fade_mode == FADE_MODE_NONE)
660 if (fade_mode == FADE_MODE_FADE_OUT)
663 BlitBitmap(backbuffer, window, x, y, width, height, x, y);
665 redraw_mask &= ~fade_mask;
670 FadeRectangle(bitmap, x, y, width, height, fade_mode, fade_delay, post_delay,
671 draw_border_function);
673 redraw_mask &= ~fade_mask;
676 void FadeIn(int fade_mask)
678 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
679 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_IN);
681 FadeExt(fade_mask, FADE_MODE_FADE_IN, FADE_TYPE_FADE_IN);
684 void FadeOut(int fade_mask)
686 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
687 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_OUT);
689 FadeExt(fade_mask, FADE_MODE_FADE_OUT, FADE_TYPE_FADE_OUT);
691 global.border_status = game_status;
694 static void FadeSetLeaveNext(struct TitleFadingInfo fading_leave, boolean set)
696 static struct TitleFadingInfo fading_leave_stored;
699 fading_leave_stored = fading_leave;
701 fading = fading_leave_stored;
704 void FadeSetEnterMenu()
706 fading = menu.enter_menu;
708 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
711 void FadeSetLeaveMenu()
713 fading = menu.leave_menu;
715 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
718 void FadeSetEnterScreen()
720 fading = menu.enter_screen[game_status];
722 FadeSetLeaveNext(menu.leave_screen[game_status], TRUE); /* store */
725 void FadeSetNextScreen()
727 fading = menu.next_screen;
729 // (do not overwrite fade mode set by FadeSetEnterScreen)
730 // FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
733 void FadeSetLeaveScreen()
735 FadeSetLeaveNext(menu.leave_screen[game_status], FALSE); /* recall */
738 void FadeSetFromType(int type)
740 if (type & TYPE_ENTER_SCREEN)
741 FadeSetEnterScreen();
742 else if (type & TYPE_ENTER)
744 else if (type & TYPE_LEAVE)
748 void FadeSetDisabled()
750 static struct TitleFadingInfo fading_none = { FADE_MODE_NONE, -1, -1, -1 };
752 fading = fading_none;
755 void FadeSkipNextFadeIn()
757 FadeExt(0, FADE_MODE_SKIP_FADE_IN, FADE_TYPE_SKIP);
760 void FadeSkipNextFadeOut()
762 FadeExt(0, FADE_MODE_SKIP_FADE_OUT, FADE_TYPE_SKIP);
765 void SetWindowBackgroundImageIfDefined(int graphic)
767 if (graphic_info[graphic].bitmap)
768 SetWindowBackgroundBitmap(graphic_info[graphic].bitmap);
771 void SetMainBackgroundImageIfDefined(int graphic)
773 if (graphic_info[graphic].bitmap)
774 SetMainBackgroundBitmap(graphic_info[graphic].bitmap);
777 void SetDoorBackgroundImageIfDefined(int graphic)
779 if (graphic_info[graphic].bitmap)
780 SetDoorBackgroundBitmap(graphic_info[graphic].bitmap);
783 void SetWindowBackgroundImage(int graphic)
785 SetWindowBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
786 graphic_info[graphic].bitmap ?
787 graphic_info[graphic].bitmap :
788 graphic_info[IMG_BACKGROUND].bitmap);
791 void SetMainBackgroundImage(int graphic)
793 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
794 graphic_info[graphic].bitmap ?
795 graphic_info[graphic].bitmap :
796 graphic_info[IMG_BACKGROUND].bitmap);
799 void SetDoorBackgroundImage(int graphic)
801 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
802 graphic_info[graphic].bitmap ?
803 graphic_info[graphic].bitmap :
804 graphic_info[IMG_BACKGROUND].bitmap);
807 void SetPanelBackground()
809 struct GraphicInfo *gfx = &graphic_info[IMG_BACKGROUND_PANEL];
811 BlitBitmapTiled(gfx->bitmap, bitmap_db_panel, gfx->src_x, gfx->src_y,
812 gfx->width, gfx->height, 0, 0, DXSIZE, DYSIZE);
814 SetDoorBackgroundBitmap(bitmap_db_panel);
817 void DrawBackground(int x, int y, int width, int height)
819 /* "drawto" might still point to playfield buffer here (hall of fame) */
820 ClearRectangleOnBackground(backbuffer, x, y, width, height);
822 if (IN_GFX_FIELD_FULL(x, y))
823 redraw_mask |= REDRAW_FIELD;
824 else if (IN_GFX_DOOR_1(x, y))
825 redraw_mask |= REDRAW_DOOR_1;
826 else if (IN_GFX_DOOR_2(x, y))
827 redraw_mask |= REDRAW_DOOR_2;
828 else if (IN_GFX_DOOR_3(x, y))
829 redraw_mask |= REDRAW_DOOR_3;
832 void DrawBackgroundForFont(int x, int y, int width, int height, int font_nr)
834 struct FontBitmapInfo *font = getFontBitmapInfo(font_nr);
836 if (font->bitmap == NULL)
839 DrawBackground(x, y, width, height);
842 void DrawBackgroundForGraphic(int x, int y, int width, int height, int graphic)
844 struct GraphicInfo *g = &graphic_info[graphic];
846 if (g->bitmap == NULL)
849 DrawBackground(x, y, width, height);
854 /* !!! "drawto" might still point to playfield buffer here (see above) !!! */
855 /* (when entering hall of fame after playing) */
856 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
858 /* !!! maybe this should be done before clearing the background !!! */
859 if (game_status == GAME_MODE_PLAYING)
861 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
862 SetDrawtoField(DRAW_FIELDBUFFER);
865 SetDrawtoField(DRAW_BACKBUFFER);
868 void MarkTileDirty(int x, int y)
870 redraw_mask |= REDRAW_FIELD;
873 void SetBorderElement()
877 BorderElement = EL_EMPTY;
879 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
881 for (x = 0; x < lev_fieldx; x++)
883 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
884 BorderElement = EL_STEELWALL;
886 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
892 void FloodFillLevel(int from_x, int from_y, int fill_element,
893 short field[MAX_LEV_FIELDX][MAX_LEV_FIELDY],
894 int max_fieldx, int max_fieldy)
898 static int check[4][2] = { { -1, 0 }, { 0, -1 }, { 1, 0 }, { 0, 1 } };
899 static int safety = 0;
901 /* check if starting field still has the desired content */
902 if (field[from_x][from_y] == fill_element)
907 if (safety > max_fieldx * max_fieldy)
908 Error(ERR_EXIT, "Something went wrong in 'FloodFill()'. Please debug.");
910 old_element = field[from_x][from_y];
911 field[from_x][from_y] = fill_element;
913 for (i = 0; i < 4; i++)
915 x = from_x + check[i][0];
916 y = from_y + check[i][1];
918 if (IN_FIELD(x, y, max_fieldx, max_fieldy) && field[x][y] == old_element)
919 FloodFillLevel(x, y, fill_element, field, max_fieldx, max_fieldy);
925 void SetRandomAnimationValue(int x, int y)
927 gfx.anim_random_frame = GfxRandom[x][y];
930 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
932 /* animation synchronized with global frame counter, not move position */
933 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
934 sync_frame = FrameCounter;
936 return getAnimationFrame(graphic_info[graphic].anim_frames,
937 graphic_info[graphic].anim_delay,
938 graphic_info[graphic].anim_mode,
939 graphic_info[graphic].anim_start_frame,
943 void getSizedGraphicSourceExt(int graphic, int frame, int tilesize,
944 Bitmap **bitmap, int *x, int *y,
945 boolean get_backside)
947 struct GraphicInfo *g = &graphic_info[graphic];
948 Bitmap *src_bitmap = g->bitmap;
949 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
950 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
951 int tilesize_capped = MIN(MAX(1, tilesize), TILESIZE);
953 // if no in-game graphics defined, always use standard graphic size
954 if (g->bitmaps[IMG_BITMAP_GAME] == NULL)
957 if (tilesize == gfx.standard_tile_size)
958 src_bitmap = g->bitmaps[IMG_BITMAP_STANDARD];
959 else if (tilesize == game.tile_size)
960 src_bitmap = g->bitmaps[IMG_BITMAP_GAME];
962 src_bitmap = g->bitmaps[IMG_BITMAP_1x1 - log_2(tilesize_capped)];
964 if (g->offset_y == 0) /* frames are ordered horizontally */
966 int max_width = g->anim_frames_per_line * g->width;
967 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
969 src_x = pos % max_width;
970 src_y = src_y % g->height + pos / max_width * g->height;
972 else if (g->offset_x == 0) /* frames are ordered vertically */
974 int max_height = g->anim_frames_per_line * g->height;
975 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
977 src_x = src_x % g->width + pos / max_height * g->width;
978 src_y = pos % max_height;
980 else /* frames are ordered diagonally */
982 src_x = src_x + frame * g->offset_x;
983 src_y = src_y + frame * g->offset_y;
986 *bitmap = src_bitmap;
987 *x = src_x * tilesize / TILESIZE;
988 *y = src_y * tilesize / TILESIZE;
991 void getFixedGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
992 int *x, int *y, boolean get_backside)
994 getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y,
998 void getSizedGraphicSource(int graphic, int frame, int tilesize,
999 Bitmap **bitmap, int *x, int *y)
1001 getSizedGraphicSourceExt(graphic, frame, tilesize, bitmap, x, y, FALSE);
1004 void getFixedGraphicSource(int graphic, int frame,
1005 Bitmap **bitmap, int *x, int *y)
1007 getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y, FALSE);
1010 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1012 getSizedGraphicSource(graphic, 0, MINI_TILESIZE, bitmap, x, y);
1015 inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1016 int *x, int *y, boolean get_backside)
1018 struct GraphicInfo *g = &graphic_info[graphic];
1019 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
1020 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
1022 if (TILESIZE_VAR != TILESIZE)
1023 return getSizedGraphicSourceExt(graphic, frame, TILESIZE_VAR, bitmap, x, y,
1026 *bitmap = g->bitmap;
1028 if (g->offset_y == 0) /* frames are ordered horizontally */
1030 int max_width = g->anim_frames_per_line * g->width;
1031 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
1033 *x = pos % max_width;
1034 *y = src_y % g->height + pos / max_width * g->height;
1036 else if (g->offset_x == 0) /* frames are ordered vertically */
1038 int max_height = g->anim_frames_per_line * g->height;
1039 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
1041 *x = src_x % g->width + pos / max_height * g->width;
1042 *y = pos % max_height;
1044 else /* frames are ordered diagonally */
1046 *x = src_x + frame * g->offset_x;
1047 *y = src_y + frame * g->offset_y;
1051 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
1053 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
1056 void DrawGraphic(int x, int y, int graphic, int frame)
1059 if (!IN_SCR_FIELD(x, y))
1061 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1062 printf("DrawGraphic(): This should never happen!\n");
1067 DrawGraphicExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR, graphic,
1070 MarkTileDirty(x, y);
1073 void DrawFixedGraphic(int x, int y, int graphic, int frame)
1076 if (!IN_SCR_FIELD(x, y))
1078 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1079 printf("DrawGraphic(): This should never happen!\n");
1084 DrawFixedGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic,
1086 MarkTileDirty(x, y);
1089 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1095 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1097 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX_VAR, TILEY_VAR, x, y);
1100 void DrawFixedGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1106 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1107 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
1110 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
1113 if (!IN_SCR_FIELD(x, y))
1115 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1116 printf("DrawGraphicThruMask(): This should never happen!\n");
1121 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
1124 MarkTileDirty(x, y);
1127 void DrawFixedGraphicThruMask(int x, int y, int graphic, int frame)
1130 if (!IN_SCR_FIELD(x, y))
1132 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1133 printf("DrawGraphicThruMask(): This should never happen!\n");
1138 DrawFixedGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
1140 MarkTileDirty(x, y);
1143 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
1149 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1151 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX_VAR, TILEY_VAR,
1155 void DrawFixedGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y,
1156 int graphic, int frame)
1158 struct GraphicInfo *g = &graphic_info[graphic];
1162 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1164 BlitBitmapMasked(src_bitmap, d, src_x, src_y, g->width, g->height,
1168 void DrawSizedGraphic(int x, int y, int graphic, int frame, int tilesize)
1170 DrawSizedGraphicExt(drawto, SX + x * tilesize, SY + y * tilesize, graphic,
1172 MarkTileDirty(x / tilesize, y / tilesize);
1175 void DrawSizedGraphicExt(DrawBuffer *d, int x, int y, int graphic, int frame,
1181 getSizedGraphicSource(graphic, frame, tilesize, &src_bitmap, &src_x, &src_y);
1182 BlitBitmap(src_bitmap, d, src_x, src_y, tilesize, tilesize, x, y);
1185 void DrawMiniGraphic(int x, int y, int graphic)
1187 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
1188 MarkTileDirty(x / 2, y / 2);
1191 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
1196 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1197 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
1200 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
1201 int graphic, int frame,
1202 int cut_mode, int mask_mode)
1207 int width = TILEX, height = TILEY;
1210 if (dx || dy) /* shifted graphic */
1212 if (x < BX1) /* object enters playfield from the left */
1219 else if (x > BX2) /* object enters playfield from the right */
1225 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
1231 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
1233 else if (dx) /* general horizontal movement */
1234 MarkTileDirty(x + SIGN(dx), y);
1236 if (y < BY1) /* object enters playfield from the top */
1238 if (cut_mode==CUT_BELOW) /* object completely above top border */
1246 else if (y > BY2) /* object enters playfield from the bottom */
1252 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
1258 else if (dy > 0 && cut_mode == CUT_ABOVE)
1260 if (y == BY2) /* object completely above bottom border */
1266 MarkTileDirty(x, y + 1);
1267 } /* object leaves playfield to the bottom */
1268 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1270 else if (dy) /* general vertical movement */
1271 MarkTileDirty(x, y + SIGN(dy));
1275 if (!IN_SCR_FIELD(x, y))
1277 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1278 printf("DrawGraphicShifted(): This should never happen!\n");
1283 width = width * TILESIZE_VAR / TILESIZE;
1284 height = height * TILESIZE_VAR / TILESIZE;
1285 cx = cx * TILESIZE_VAR / TILESIZE;
1286 cy = cy * TILESIZE_VAR / TILESIZE;
1287 dx = dx * TILESIZE_VAR / TILESIZE;
1288 dy = dy * TILESIZE_VAR / TILESIZE;
1290 if (width > 0 && height > 0)
1292 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1297 dst_x = FX + x * TILEX_VAR + dx;
1298 dst_y = FY + y * TILEY_VAR + dy;
1300 if (mask_mode == USE_MASKING)
1301 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1304 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1307 MarkTileDirty(x, y);
1311 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
1312 int graphic, int frame,
1313 int cut_mode, int mask_mode)
1318 int width = TILEX_VAR, height = TILEY_VAR;
1321 int x2 = x + SIGN(dx);
1322 int y2 = y + SIGN(dy);
1324 /* movement with two-tile animations must be sync'ed with movement position,
1325 not with current GfxFrame (which can be higher when using slow movement) */
1326 int anim_pos = (dx ? ABS(dx) : ABS(dy));
1327 int anim_frames = graphic_info[graphic].anim_frames;
1329 /* (we also need anim_delay here for movement animations with less frames) */
1330 int anim_delay = graphic_info[graphic].anim_delay;
1331 int sync_frame = anim_pos * anim_frames * anim_delay / TILESIZE;
1333 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
1334 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
1336 /* re-calculate animation frame for two-tile movement animation */
1337 frame = getGraphicAnimationFrame(graphic, sync_frame);
1339 /* check if movement start graphic inside screen area and should be drawn */
1340 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
1342 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
1344 dst_x = FX + x1 * TILEX_VAR;
1345 dst_y = FY + y1 * TILEY_VAR;
1347 if (mask_mode == USE_MASKING)
1348 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1351 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1354 MarkTileDirty(x1, y1);
1357 /* check if movement end graphic inside screen area and should be drawn */
1358 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
1360 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
1362 dst_x = FX + x2 * TILEX_VAR;
1363 dst_y = FY + y2 * TILEY_VAR;
1365 if (mask_mode == USE_MASKING)
1366 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1369 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1372 MarkTileDirty(x2, y2);
1376 static void DrawGraphicShifted(int x, int y, int dx, int dy,
1377 int graphic, int frame,
1378 int cut_mode, int mask_mode)
1382 DrawGraphic(x, y, graphic, frame);
1387 if (graphic_info[graphic].double_movement) /* EM style movement images */
1388 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1390 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1393 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1394 int frame, int cut_mode)
1396 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
1399 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1400 int cut_mode, int mask_mode)
1402 int lx = LEVELX(x), ly = LEVELY(y);
1406 if (IN_LEV_FIELD(lx, ly))
1408 SetRandomAnimationValue(lx, ly);
1410 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
1411 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1413 /* do not use double (EM style) movement graphic when not moving */
1414 if (graphic_info[graphic].double_movement && !dx && !dy)
1416 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
1417 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1420 else /* border element */
1422 graphic = el2img(element);
1423 frame = getGraphicAnimationFrame(graphic, -1);
1426 if (element == EL_EXPANDABLE_WALL)
1428 boolean left_stopped = FALSE, right_stopped = FALSE;
1430 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1431 left_stopped = TRUE;
1432 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1433 right_stopped = TRUE;
1435 if (left_stopped && right_stopped)
1437 else if (left_stopped)
1439 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1440 frame = graphic_info[graphic].anim_frames - 1;
1442 else if (right_stopped)
1444 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1445 frame = graphic_info[graphic].anim_frames - 1;
1450 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1451 else if (mask_mode == USE_MASKING)
1452 DrawGraphicThruMask(x, y, graphic, frame);
1454 DrawGraphic(x, y, graphic, frame);
1457 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1458 int cut_mode, int mask_mode)
1460 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1461 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1462 cut_mode, mask_mode);
1465 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1468 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1471 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1474 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1477 void DrawLevelElementThruMask(int x, int y, int element)
1479 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1482 void DrawLevelFieldThruMask(int x, int y)
1484 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1487 /* !!! implementation of quicksand is totally broken !!! */
1488 #define IS_CRUMBLED_TILE(x, y, e) \
1489 (GFX_CRUMBLED(e) && (!IN_LEV_FIELD(x, y) || \
1490 !IS_MOVING(x, y) || \
1491 (e) == EL_QUICKSAND_EMPTYING || \
1492 (e) == EL_QUICKSAND_FAST_EMPTYING))
1494 static void DrawLevelFieldCrumbledInnerCorners(int x, int y, int dx, int dy,
1499 int width, height, cx, cy;
1500 int sx = SCREENX(x), sy = SCREENY(y);
1501 int crumbled_border_size = graphic_info[graphic].border_size;
1504 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1506 for (i = 1; i < 4; i++)
1508 int dxx = (i & 1 ? dx : 0);
1509 int dyy = (i & 2 ? dy : 0);
1512 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1515 /* check if neighbour field is of same crumble type */
1516 boolean same = (IS_CRUMBLED_TILE(xx, yy, element) &&
1517 graphic_info[graphic].class ==
1518 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class);
1520 /* return if check prevents inner corner */
1521 if (same == (dxx == dx && dyy == dy))
1525 /* if we reach this point, we have an inner corner */
1527 getGraphicSource(graphic, 1, &src_bitmap, &src_x, &src_y);
1529 width = crumbled_border_size * TILESIZE_VAR / TILESIZE;
1530 height = crumbled_border_size * TILESIZE_VAR / TILESIZE;
1531 cx = (dx > 0 ? TILESIZE_VAR - width : 0);
1532 cy = (dy > 0 ? TILESIZE_VAR - height : 0);
1534 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1535 width, height, FX + sx * TILEX_VAR + cx, FY + sy * TILEY_VAR + cy);
1538 static void DrawLevelFieldCrumbledBorders(int x, int y, int graphic, int frame,
1543 int width, height, bx, by, cx, cy;
1544 int sx = SCREENX(x), sy = SCREENY(y);
1545 int crumbled_border_size = graphic_info[graphic].border_size;
1546 int crumbled_border_size_var = crumbled_border_size * TILESIZE_VAR / TILESIZE;
1547 int crumbled_border_pos_var = TILESIZE_VAR - crumbled_border_size_var;
1550 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1552 /* draw simple, sloppy, non-corner-accurate crumbled border */
1554 width = (dir == 1 || dir == 2 ? crumbled_border_size_var : TILESIZE_VAR);
1555 height = (dir == 0 || dir == 3 ? crumbled_border_size_var : TILESIZE_VAR);
1556 cx = (dir == 2 ? crumbled_border_pos_var : 0);
1557 cy = (dir == 3 ? crumbled_border_pos_var : 0);
1559 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy, width, height,
1560 FX + sx * TILEX_VAR + cx,
1561 FY + sy * TILEY_VAR + cy);
1563 /* (remaining middle border part must be at least as big as corner part) */
1564 if (!(graphic_info[graphic].style & STYLE_ACCURATE_BORDERS) ||
1565 crumbled_border_size >= TILESIZE / 3)
1568 /* correct corners of crumbled border, if needed */
1570 for (i = -1; i <= 1; i += 2)
1572 int xx = x + (dir == 0 || dir == 3 ? i : 0);
1573 int yy = y + (dir == 1 || dir == 2 ? i : 0);
1574 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1577 /* check if neighbour field is of same crumble type */
1578 if (IS_CRUMBLED_TILE(xx, yy, element) &&
1579 graphic_info[graphic].class ==
1580 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1582 /* no crumbled corner, but continued crumbled border */
1584 int c1 = (dir == 2 || dir == 3 ? crumbled_border_pos_var : 0);
1585 int c2 = (i == 1 ? crumbled_border_pos_var : 0);
1586 int b1 = (i == 1 ? crumbled_border_size_var :
1587 TILESIZE_VAR - 2 * crumbled_border_size_var);
1589 width = crumbled_border_size_var;
1590 height = crumbled_border_size_var;
1592 if (dir == 1 || dir == 2)
1607 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
1609 FX + sx * TILEX_VAR + cx,
1610 FY + sy * TILEY_VAR + cy);
1615 static void DrawLevelFieldCrumbledExt(int x, int y, int graphic, int frame)
1617 int sx = SCREENX(x), sy = SCREENY(y);
1620 static int xy[4][2] =
1628 if (!IN_LEV_FIELD(x, y))
1631 element = TILE_GFX_ELEMENT(x, y);
1633 /* crumble field itself */
1634 if (IS_CRUMBLED_TILE(x, y, element))
1636 if (!IN_SCR_FIELD(sx, sy))
1639 for (i = 0; i < 4; i++)
1641 int xx = x + xy[i][0];
1642 int yy = y + xy[i][1];
1644 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1647 /* check if neighbour field is of same crumble type */
1648 if (IS_CRUMBLED_TILE(xx, yy, element) &&
1649 graphic_info[graphic].class ==
1650 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1653 DrawLevelFieldCrumbledBorders(x, y, graphic, frame, i);
1656 if ((graphic_info[graphic].style & STYLE_INNER_CORNERS) &&
1657 graphic_info[graphic].anim_frames == 2)
1659 for (i = 0; i < 4; i++)
1661 int dx = (i & 1 ? +1 : -1);
1662 int dy = (i & 2 ? +1 : -1);
1664 DrawLevelFieldCrumbledInnerCorners(x, y, dx, dy, graphic);
1668 MarkTileDirty(sx, sy);
1670 else /* center field not crumbled -- crumble neighbour fields */
1672 for (i = 0; i < 4; i++)
1674 int xx = x + xy[i][0];
1675 int yy = y + xy[i][1];
1676 int sxx = sx + xy[i][0];
1677 int syy = sy + xy[i][1];
1679 if (!IN_LEV_FIELD(xx, yy) ||
1680 !IN_SCR_FIELD(sxx, syy))
1683 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
1686 element = TILE_GFX_ELEMENT(xx, yy);
1688 if (!IS_CRUMBLED_TILE(xx, yy, element))
1691 graphic = el_act2crm(element, ACTION_DEFAULT);
1693 DrawLevelFieldCrumbledBorders(xx, yy, graphic, 0, 3 - i);
1695 MarkTileDirty(sxx, syy);
1700 void DrawLevelFieldCrumbled(int x, int y)
1704 if (!IN_LEV_FIELD(x, y))
1707 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1708 GfxElement[x][y] != EL_UNDEFINED &&
1709 GFX_CRUMBLED(GfxElement[x][y]))
1711 DrawLevelFieldCrumbledDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
1716 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
1718 DrawLevelFieldCrumbledExt(x, y, graphic, 0);
1721 void DrawLevelFieldCrumbledDigging(int x, int y, int direction,
1724 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1725 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1726 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1727 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1728 int sx = SCREENX(x), sy = SCREENY(y);
1730 DrawGraphic(sx, sy, graphic1, frame1);
1731 DrawLevelFieldCrumbledExt(x, y, graphic2, frame2);
1734 void DrawLevelFieldCrumbledNeighbours(int x, int y)
1736 int sx = SCREENX(x), sy = SCREENY(y);
1737 static int xy[4][2] =
1746 for (i = 0; i < 4; i++)
1748 int xx = x + xy[i][0];
1749 int yy = y + xy[i][1];
1750 int sxx = sx + xy[i][0];
1751 int syy = sy + xy[i][1];
1753 if (!IN_LEV_FIELD(xx, yy) ||
1754 !IN_SCR_FIELD(sxx, syy) ||
1755 !GFX_CRUMBLED(Feld[xx][yy]) ||
1759 DrawLevelField(xx, yy);
1763 static int getBorderElement(int x, int y)
1767 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1768 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1769 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1770 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1771 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1772 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1773 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1775 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1776 int steel_position = (x == -1 && y == -1 ? 0 :
1777 x == lev_fieldx && y == -1 ? 1 :
1778 x == -1 && y == lev_fieldy ? 2 :
1779 x == lev_fieldx && y == lev_fieldy ? 3 :
1780 x == -1 || x == lev_fieldx ? 4 :
1781 y == -1 || y == lev_fieldy ? 5 : 6);
1783 return border[steel_position][steel_type];
1786 void DrawScreenElement(int x, int y, int element)
1788 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1789 DrawLevelFieldCrumbled(LEVELX(x), LEVELY(y));
1792 void DrawLevelElement(int x, int y, int element)
1794 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1795 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1798 void DrawScreenField(int x, int y)
1800 int lx = LEVELX(x), ly = LEVELY(y);
1801 int element, content;
1803 if (!IN_LEV_FIELD(lx, ly))
1805 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1808 element = getBorderElement(lx, ly);
1810 DrawScreenElement(x, y, element);
1815 element = Feld[lx][ly];
1816 content = Store[lx][ly];
1818 if (IS_MOVING(lx, ly))
1820 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1821 boolean cut_mode = NO_CUTTING;
1823 if (element == EL_QUICKSAND_EMPTYING ||
1824 element == EL_QUICKSAND_FAST_EMPTYING ||
1825 element == EL_MAGIC_WALL_EMPTYING ||
1826 element == EL_BD_MAGIC_WALL_EMPTYING ||
1827 element == EL_DC_MAGIC_WALL_EMPTYING ||
1828 element == EL_AMOEBA_DROPPING)
1829 cut_mode = CUT_ABOVE;
1830 else if (element == EL_QUICKSAND_FILLING ||
1831 element == EL_QUICKSAND_FAST_FILLING ||
1832 element == EL_MAGIC_WALL_FILLING ||
1833 element == EL_BD_MAGIC_WALL_FILLING ||
1834 element == EL_DC_MAGIC_WALL_FILLING)
1835 cut_mode = CUT_BELOW;
1837 if (cut_mode == CUT_ABOVE)
1838 DrawScreenElement(x, y, element);
1840 DrawScreenElement(x, y, EL_EMPTY);
1843 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1844 else if (cut_mode == NO_CUTTING)
1845 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1848 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1850 if (cut_mode == CUT_BELOW &&
1851 IN_LEV_FIELD(lx, ly + 1) && IN_SCR_FIELD(x, y + 1))
1852 DrawLevelElement(lx, ly + 1, element);
1855 if (content == EL_ACID)
1857 int dir = MovDir[lx][ly];
1858 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
1859 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
1861 DrawLevelElementThruMask(newlx, newly, EL_ACID);
1864 else if (IS_BLOCKED(lx, ly))
1869 boolean cut_mode = NO_CUTTING;
1870 int element_old, content_old;
1872 Blocked2Moving(lx, ly, &oldx, &oldy);
1875 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1876 MovDir[oldx][oldy] == MV_RIGHT);
1878 element_old = Feld[oldx][oldy];
1879 content_old = Store[oldx][oldy];
1881 if (element_old == EL_QUICKSAND_EMPTYING ||
1882 element_old == EL_QUICKSAND_FAST_EMPTYING ||
1883 element_old == EL_MAGIC_WALL_EMPTYING ||
1884 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1885 element_old == EL_DC_MAGIC_WALL_EMPTYING ||
1886 element_old == EL_AMOEBA_DROPPING)
1887 cut_mode = CUT_ABOVE;
1889 DrawScreenElement(x, y, EL_EMPTY);
1892 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1894 else if (cut_mode == NO_CUTTING)
1895 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1898 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1901 else if (IS_DRAWABLE(element))
1902 DrawScreenElement(x, y, element);
1904 DrawScreenElement(x, y, EL_EMPTY);
1907 void DrawLevelField(int x, int y)
1909 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1910 DrawScreenField(SCREENX(x), SCREENY(y));
1911 else if (IS_MOVING(x, y))
1915 Moving2Blocked(x, y, &newx, &newy);
1916 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1917 DrawScreenField(SCREENX(newx), SCREENY(newy));
1919 else if (IS_BLOCKED(x, y))
1923 Blocked2Moving(x, y, &oldx, &oldy);
1924 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1925 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1929 void DrawSizedElement(int x, int y, int element, int tilesize)
1933 graphic = el2edimg(element);
1934 DrawSizedGraphic(x, y, graphic, 0, tilesize);
1937 void DrawMiniElement(int x, int y, int element)
1941 graphic = el2edimg(element);
1942 DrawMiniGraphic(x, y, graphic);
1945 void DrawSizedElementOrWall(int sx, int sy, int scroll_x, int scroll_y,
1948 int x = sx + scroll_x, y = sy + scroll_y;
1950 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1951 DrawSizedElement(sx, sy, EL_EMPTY, tilesize);
1952 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1953 DrawSizedElement(sx, sy, Feld[x][y], tilesize);
1955 DrawSizedGraphic(sx, sy, el2edimg(getBorderElement(x, y)), 0, tilesize);
1958 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1960 int x = sx + scroll_x, y = sy + scroll_y;
1962 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1963 DrawMiniElement(sx, sy, EL_EMPTY);
1964 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1965 DrawMiniElement(sx, sy, Feld[x][y]);
1967 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1970 void DrawEnvelopeBackgroundTiles(int graphic, int startx, int starty,
1971 int x, int y, int xsize, int ysize,
1972 int tile_width, int tile_height)
1976 int dst_x = startx + x * tile_width;
1977 int dst_y = starty + y * tile_height;
1978 int width = graphic_info[graphic].width;
1979 int height = graphic_info[graphic].height;
1980 int inner_width_raw = MAX(width - 2 * tile_width, tile_width);
1981 int inner_height_raw = MAX(height - 2 * tile_height, tile_height);
1982 int inner_width = inner_width_raw - (inner_width_raw % tile_width);
1983 int inner_height = inner_height_raw - (inner_height_raw % tile_height);
1984 int inner_sx = (width >= 3 * tile_width ? tile_width : 0);
1985 int inner_sy = (height >= 3 * tile_height ? tile_height : 0);
1986 boolean draw_masked = graphic_info[graphic].draw_masked;
1988 getFixedGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1990 if (src_bitmap == NULL || width < tile_width || height < tile_height)
1992 ClearRectangle(drawto, dst_x, dst_y, tile_width, tile_height);
1996 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - tile_width :
1997 inner_sx + (x - 1) * tile_width % inner_width);
1998 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - tile_height :
1999 inner_sy + (y - 1) * tile_height % inner_height);
2002 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
2005 BlitBitmap(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
2009 void DrawEnvelopeBackground(int graphic, int startx, int starty,
2010 int x, int y, int xsize, int ysize, int font_nr)
2012 int font_width = getFontWidth(font_nr);
2013 int font_height = getFontHeight(font_nr);
2015 DrawEnvelopeBackgroundTiles(graphic, startx, starty, x, y, xsize, ysize,
2016 font_width, font_height);
2019 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
2021 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2022 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2023 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2024 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2025 boolean no_delay = (tape.warp_forward);
2026 unsigned int anim_delay = 0;
2027 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
2028 int anim_delay_value = (no_delay ? 0 : frame_delay_value) / 2;
2029 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
2030 int font_width = getFontWidth(font_nr);
2031 int font_height = getFontHeight(font_nr);
2032 int max_xsize = level.envelope[envelope_nr].xsize;
2033 int max_ysize = level.envelope[envelope_nr].ysize;
2034 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
2035 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
2036 int xend = max_xsize;
2037 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
2038 int xstep = (xstart < xend ? 1 : 0);
2039 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2041 int end = MAX(xend - xstart, yend - ystart);
2044 for (i = start; i <= end; i++)
2046 int last_frame = end; // last frame of this "for" loop
2047 int x = xstart + i * xstep;
2048 int y = ystart + i * ystep;
2049 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2050 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2051 int sx = SX + (SXSIZE - xsize * font_width) / 2;
2052 int sy = SY + (SYSIZE - ysize * font_height) / 2;
2055 SetDrawtoField(DRAW_FIELDBUFFER);
2057 BlitScreenToBitmap(backbuffer);
2059 SetDrawtoField(DRAW_BACKBUFFER);
2061 for (yy = 0; yy < ysize; yy++)
2062 for (xx = 0; xx < xsize; xx++)
2063 DrawEnvelopeBackground(graphic, sx, sy, xx, yy, xsize, ysize, font_nr);
2065 DrawTextBuffer(sx + font_width, sy + font_height,
2066 level.envelope[envelope_nr].text, font_nr, max_xsize,
2067 xsize - 2, ysize - 2, 0, mask_mode,
2068 level.envelope[envelope_nr].autowrap,
2069 level.envelope[envelope_nr].centered, FALSE);
2071 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2074 SkipUntilDelayReached(&anim_delay, anim_delay_value, &i, last_frame);
2078 void ShowEnvelope(int envelope_nr)
2080 int element = EL_ENVELOPE_1 + envelope_nr;
2081 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2082 int sound_opening = element_info[element].sound[ACTION_OPENING];
2083 int sound_closing = element_info[element].sound[ACTION_CLOSING];
2084 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2085 boolean no_delay = (tape.warp_forward);
2086 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
2087 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
2088 int anim_mode = graphic_info[graphic].anim_mode;
2089 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2090 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2092 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
2094 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2096 if (anim_mode == ANIM_DEFAULT)
2097 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
2099 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
2102 Delay(wait_delay_value);
2104 WaitForEventToContinue();
2106 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2108 if (anim_mode != ANIM_NONE)
2109 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
2111 if (anim_mode == ANIM_DEFAULT)
2112 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
2114 game.envelope_active = FALSE;
2116 SetDrawtoField(DRAW_FIELDBUFFER);
2118 redraw_mask |= REDRAW_FIELD;
2122 static void setRequestPosition(int *x, int *y, boolean add_border_size)
2124 int border_size = request.border_size;
2125 int sx_center = (request.x != -1 ? request.x : SX + SXSIZE / 2);
2126 int sy_center = (request.y != -1 ? request.y : SY + SYSIZE / 2);
2127 int sx = sx_center - request.width / 2;
2128 int sy = sy_center - request.height / 2;
2130 if (add_border_size)
2140 void DrawEnvelopeRequest(char *text)
2142 char *text_final = text;
2143 char *text_door_style = NULL;
2144 int graphic = IMG_BACKGROUND_REQUEST;
2145 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2146 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2147 int font_nr = FONT_REQUEST;
2148 int font_width = getFontWidth(font_nr);
2149 int font_height = getFontHeight(font_nr);
2150 int border_size = request.border_size;
2151 int line_spacing = request.line_spacing;
2152 int line_height = font_height + line_spacing;
2153 int text_width = request.width - 2 * border_size;
2154 int text_height = request.height - 2 * border_size;
2155 int line_length = text_width / font_width;
2156 int max_lines = text_height / line_height;
2157 int width = request.width;
2158 int height = request.height;
2159 int tile_size = request.step_offset;
2160 int x_steps = width / tile_size;
2161 int y_steps = height / tile_size;
2165 if (request.wrap_single_words)
2167 char *src_text_ptr, *dst_text_ptr;
2169 text_door_style = checked_malloc(2 * strlen(text) + 1);
2171 src_text_ptr = text;
2172 dst_text_ptr = text_door_style;
2174 while (*src_text_ptr)
2176 if (*src_text_ptr == ' ' ||
2177 *src_text_ptr == '?' ||
2178 *src_text_ptr == '!')
2179 *dst_text_ptr++ = '\n';
2181 if (*src_text_ptr != ' ')
2182 *dst_text_ptr++ = *src_text_ptr;
2187 *dst_text_ptr = '\0';
2189 text_final = text_door_style;
2192 setRequestPosition(&sx, &sy, FALSE);
2194 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
2196 for (y = 0; y < y_steps; y++)
2197 for (x = 0; x < x_steps; x++)
2198 DrawEnvelopeBackgroundTiles(graphic, sx, sy,
2199 x, y, x_steps, y_steps,
2200 tile_size, tile_size);
2202 DrawTextBuffer(sx + border_size, sy + border_size, text_final, font_nr,
2203 line_length, -1, max_lines, line_spacing, mask_mode,
2204 request.autowrap, request.centered, FALSE);
2206 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2207 RedrawGadget(tool_gadget[i]);
2209 // store readily prepared envelope request for later use when animating
2210 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2212 if (text_door_style)
2213 free(text_door_style);
2216 void AnimateEnvelopeRequest(int anim_mode, int action)
2218 int graphic = IMG_BACKGROUND_REQUEST;
2219 boolean draw_masked = graphic_info[graphic].draw_masked;
2220 int delay_value_normal = request.step_delay;
2221 int delay_value_fast = delay_value_normal / 2;
2222 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2223 boolean no_delay = (tape.warp_forward);
2224 int delay_value = (ffwd_delay ? delay_value_fast : delay_value_normal);
2225 int anim_delay_value = (no_delay ? 0 : delay_value + 500 * 0) / 2;
2226 unsigned int anim_delay = 0;
2228 int width = request.width;
2229 int height = request.height;
2230 int tile_size = request.step_offset;
2231 int max_xsize = width / tile_size;
2232 int max_ysize = height / tile_size;
2233 int max_xsize_inner = max_xsize - 2;
2234 int max_ysize_inner = max_ysize - 2;
2236 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize_inner : 0);
2237 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize_inner : 0);
2238 int xend = max_xsize_inner;
2239 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize_inner : 0);
2240 int xstep = (xstart < xend ? 1 : 0);
2241 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2243 int end = MAX(xend - xstart, yend - ystart);
2246 if (setup.quick_doors)
2254 if (action == ACTION_OPENING)
2255 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2256 else if (action == ACTION_CLOSING)
2257 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2260 for (i = start; i <= end; i++)
2262 int last_frame = end; // last frame of this "for" loop
2263 int x = xstart + i * xstep;
2264 int y = ystart + i * ystep;
2265 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2266 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2267 int sx_center = (request.x != -1 ? request.x : SX + SXSIZE / 2);
2268 int sy_center = (request.y != -1 ? request.y : SY + SYSIZE / 2);
2269 int src_x = sx_center - width / 2;
2270 int src_y = sy_center - height / 2;
2271 int dst_x = sx_center - xsize * tile_size / 2;
2272 int dst_y = sy_center - ysize * tile_size / 2;
2273 int xsize_size_left = (xsize - 1) * tile_size;
2274 int ysize_size_top = (ysize - 1) * tile_size;
2275 int max_xsize_pos = (max_xsize - 1) * tile_size;
2276 int max_ysize_pos = (max_ysize - 1) * tile_size;
2279 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2281 for (yy = 0; yy < 2; yy++)
2283 for (xx = 0; xx < 2; xx++)
2285 int src_xx = src_x + xx * max_xsize_pos;
2286 int src_yy = src_y + yy * max_ysize_pos;
2287 int dst_xx = dst_x + xx * xsize_size_left;
2288 int dst_yy = dst_y + yy * ysize_size_top;
2289 int xx_size = (xx ? tile_size : xsize_size_left);
2290 int yy_size = (yy ? tile_size : ysize_size_top);
2293 BlitBitmapMasked(bitmap_db_cross, backbuffer,
2294 src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
2296 BlitBitmap(bitmap_db_cross, backbuffer,
2297 src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
2301 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2306 SkipUntilDelayReached(&anim_delay, anim_delay_value, &i, last_frame);
2311 void ShowEnvelopeRequest(char *text, unsigned int req_state, int action)
2313 int last_game_status = game_status; /* save current game status */
2314 int graphic = IMG_BACKGROUND_REQUEST;
2315 int sound_opening = SND_REQUEST_OPENING;
2316 int sound_closing = SND_REQUEST_CLOSING;
2317 int anim_mode = graphic_info[graphic].anim_mode;
2318 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2319 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2321 if (game_status == GAME_MODE_PLAYING)
2322 BlitScreenToBitmap(backbuffer);
2324 SetDrawtoField(DRAW_BACKBUFFER);
2326 // SetDrawBackgroundMask(REDRAW_NONE);
2328 if (action == ACTION_OPENING)
2330 BlitBitmap(backbuffer, bitmap_db_store, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2332 if (req_state & REQ_ASK)
2334 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2335 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2337 else if (req_state & REQ_CONFIRM)
2339 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2341 else if (req_state & REQ_PLAYER)
2343 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2344 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2345 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2346 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2349 DrawEnvelopeRequest(text);
2351 if (game_status != GAME_MODE_MAIN)
2355 /* force DOOR font inside door area */
2356 game_status = GAME_MODE_PSEUDO_DOOR;
2358 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
2360 if (action == ACTION_OPENING)
2362 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2364 if (anim_mode == ANIM_DEFAULT)
2365 AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_OPENING);
2367 AnimateEnvelopeRequest(main_anim_mode, ACTION_OPENING);
2371 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2373 if (anim_mode != ANIM_NONE)
2374 AnimateEnvelopeRequest(main_anim_mode, ACTION_CLOSING);
2376 if (anim_mode == ANIM_DEFAULT)
2377 AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_CLOSING);
2380 game.envelope_active = FALSE;
2382 game_status = last_game_status; /* restore current game status */
2384 if (action == ACTION_CLOSING)
2386 if (game_status != GAME_MODE_MAIN)
2389 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2392 // SetDrawBackgroundMask(last_draw_background_mask);
2394 redraw_mask |= REDRAW_FIELD;
2396 if (game_status == GAME_MODE_MAIN)
2401 if (action == ACTION_CLOSING &&
2402 game_status == GAME_MODE_PLAYING &&
2403 level.game_engine_type == GAME_ENGINE_TYPE_RND)
2404 SetDrawtoField(DRAW_FIELDBUFFER);
2407 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
2411 int graphic = el2preimg(element);
2413 getSizedGraphicSource(graphic, 0, tilesize, &src_bitmap, &src_x, &src_y);
2414 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
2417 void DrawLevel(int draw_background_mask)
2421 SetMainBackgroundImage(IMG_BACKGROUND_PLAYING);
2422 SetDrawBackgroundMask(draw_background_mask);
2426 for (x = BX1; x <= BX2; x++)
2427 for (y = BY1; y <= BY2; y++)
2428 DrawScreenField(x, y);
2430 redraw_mask |= REDRAW_FIELD;
2433 void DrawSizedLevel(int size_x, int size_y, int scroll_x, int scroll_y,
2438 for (x = 0; x < size_x; x++)
2439 for (y = 0; y < size_y; y++)
2440 DrawSizedElementOrWall(x, y, scroll_x, scroll_y, tilesize);
2442 redraw_mask |= REDRAW_FIELD;
2445 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
2449 for (x = 0; x < size_x; x++)
2450 for (y = 0; y < size_y; y++)
2451 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
2453 redraw_mask |= REDRAW_FIELD;
2456 static void DrawPreviewLevelPlayfieldExt(int from_x, int from_y)
2458 boolean show_level_border = (BorderElement != EL_EMPTY);
2459 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2460 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2461 int tile_size = preview.tile_size;
2462 int preview_width = preview.xsize * tile_size;
2463 int preview_height = preview.ysize * tile_size;
2464 int real_preview_xsize = MIN(level_xsize, preview.xsize);
2465 int real_preview_ysize = MIN(level_ysize, preview.ysize);
2466 int real_preview_width = real_preview_xsize * tile_size;
2467 int real_preview_height = real_preview_ysize * tile_size;
2468 int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
2469 int dst_y = SY + ALIGNED_YPOS(preview.y, preview_height, preview.valign);
2472 if (!IN_GFX_FIELD_FULL(dst_x, dst_y + preview_height - 1))
2475 DrawBackground(dst_x, dst_y, preview_width, preview_height);
2477 dst_x += (preview_width - real_preview_width) / 2;
2478 dst_y += (preview_height - real_preview_height) / 2;
2480 for (x = 0; x < real_preview_xsize; x++)
2482 for (y = 0; y < real_preview_ysize; y++)
2484 int lx = from_x + x + (show_level_border ? -1 : 0);
2485 int ly = from_y + y + (show_level_border ? -1 : 0);
2486 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
2487 getBorderElement(lx, ly));
2489 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
2490 element, tile_size);
2494 redraw_mask |= REDRAW_MICROLEVEL;
2497 #define MICROLABEL_EMPTY 0
2498 #define MICROLABEL_LEVEL_NAME 1
2499 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
2500 #define MICROLABEL_LEVEL_AUTHOR 3
2501 #define MICROLABEL_IMPORTED_FROM_HEAD 4
2502 #define MICROLABEL_IMPORTED_FROM 5
2503 #define MICROLABEL_IMPORTED_BY_HEAD 6
2504 #define MICROLABEL_IMPORTED_BY 7
2506 static int getMaxTextLength(struct TextPosInfo *pos, int font_nr)
2508 int max_text_width = SXSIZE;
2509 int font_width = getFontWidth(font_nr);
2511 if (pos->align == ALIGN_CENTER)
2512 max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
2513 else if (pos->align == ALIGN_RIGHT)
2514 max_text_width = pos->x;
2516 max_text_width = SXSIZE - pos->x;
2518 return max_text_width / font_width;
2521 static void DrawPreviewLevelLabelExt(int mode)
2523 struct TextPosInfo *pos = &menu.main.text.level_info_2;
2524 char label_text[MAX_OUTPUT_LINESIZE + 1];
2525 int max_len_label_text;
2526 int font_nr = pos->font;
2529 if (!IN_GFX_FIELD_FULL(pos->x, pos->y + getFontHeight(pos->font)))
2532 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
2533 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
2534 mode == MICROLABEL_IMPORTED_BY_HEAD)
2535 font_nr = pos->font_alt;
2537 max_len_label_text = getMaxTextLength(pos, font_nr);
2539 if (pos->size != -1)
2540 max_len_label_text = pos->size;
2542 for (i = 0; i < max_len_label_text; i++)
2543 label_text[i] = ' ';
2544 label_text[max_len_label_text] = '\0';
2546 if (strlen(label_text) > 0)
2547 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2550 (mode == MICROLABEL_LEVEL_NAME ? level.name :
2551 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
2552 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
2553 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
2554 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
2555 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
2556 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
2557 max_len_label_text);
2558 label_text[max_len_label_text] = '\0';
2560 if (strlen(label_text) > 0)
2561 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2563 redraw_mask |= REDRAW_MICROLEVEL;
2566 static void DrawPreviewLevelExt(boolean restart)
2568 static unsigned int scroll_delay = 0;
2569 static unsigned int label_delay = 0;
2570 static int from_x, from_y, scroll_direction;
2571 static int label_state, label_counter;
2572 unsigned int scroll_delay_value = preview.step_delay;
2573 boolean show_level_border = (BorderElement != EL_EMPTY);
2574 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2575 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2576 int last_game_status = game_status; /* save current game status */
2583 if (preview.anim_mode == ANIM_CENTERED)
2585 if (level_xsize > preview.xsize)
2586 from_x = (level_xsize - preview.xsize) / 2;
2587 if (level_ysize > preview.ysize)
2588 from_y = (level_ysize - preview.ysize) / 2;
2591 from_x += preview.xoffset;
2592 from_y += preview.yoffset;
2594 scroll_direction = MV_RIGHT;
2598 DrawPreviewLevelPlayfieldExt(from_x, from_y);
2599 DrawPreviewLevelLabelExt(label_state);
2601 /* initialize delay counters */
2602 DelayReached(&scroll_delay, 0);
2603 DelayReached(&label_delay, 0);
2605 if (leveldir_current->name)
2607 struct TextPosInfo *pos = &menu.main.text.level_info_1;
2608 char label_text[MAX_OUTPUT_LINESIZE + 1];
2609 int font_nr = pos->font;
2610 int max_len_label_text = getMaxTextLength(pos, font_nr);
2612 if (pos->size != -1)
2613 max_len_label_text = pos->size;
2615 strncpy(label_text, leveldir_current->name, max_len_label_text);
2616 label_text[max_len_label_text] = '\0';
2618 if (IN_GFX_FIELD_FULL(pos->x, pos->y + getFontHeight(pos->font)))
2619 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2622 game_status = last_game_status; /* restore current game status */
2627 /* scroll preview level, if needed */
2628 if (preview.anim_mode != ANIM_NONE &&
2629 (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
2630 DelayReached(&scroll_delay, scroll_delay_value))
2632 switch (scroll_direction)
2637 from_x -= preview.step_offset;
2638 from_x = (from_x < 0 ? 0 : from_x);
2641 scroll_direction = MV_UP;
2645 if (from_x < level_xsize - preview.xsize)
2647 from_x += preview.step_offset;
2648 from_x = (from_x > level_xsize - preview.xsize ?
2649 level_xsize - preview.xsize : from_x);
2652 scroll_direction = MV_DOWN;
2658 from_y -= preview.step_offset;
2659 from_y = (from_y < 0 ? 0 : from_y);
2662 scroll_direction = MV_RIGHT;
2666 if (from_y < level_ysize - preview.ysize)
2668 from_y += preview.step_offset;
2669 from_y = (from_y > level_ysize - preview.ysize ?
2670 level_ysize - preview.ysize : from_y);
2673 scroll_direction = MV_LEFT;
2680 DrawPreviewLevelPlayfieldExt(from_x, from_y);
2683 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
2684 /* redraw micro level label, if needed */
2685 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
2686 !strEqual(level.author, ANONYMOUS_NAME) &&
2687 !strEqual(level.author, leveldir_current->name) &&
2688 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
2690 int max_label_counter = 23;
2692 if (leveldir_current->imported_from != NULL &&
2693 strlen(leveldir_current->imported_from) > 0)
2694 max_label_counter += 14;
2695 if (leveldir_current->imported_by != NULL &&
2696 strlen(leveldir_current->imported_by) > 0)
2697 max_label_counter += 14;
2699 label_counter = (label_counter + 1) % max_label_counter;
2700 label_state = (label_counter >= 0 && label_counter <= 7 ?
2701 MICROLABEL_LEVEL_NAME :
2702 label_counter >= 9 && label_counter <= 12 ?
2703 MICROLABEL_LEVEL_AUTHOR_HEAD :
2704 label_counter >= 14 && label_counter <= 21 ?
2705 MICROLABEL_LEVEL_AUTHOR :
2706 label_counter >= 23 && label_counter <= 26 ?
2707 MICROLABEL_IMPORTED_FROM_HEAD :
2708 label_counter >= 28 && label_counter <= 35 ?
2709 MICROLABEL_IMPORTED_FROM :
2710 label_counter >= 37 && label_counter <= 40 ?
2711 MICROLABEL_IMPORTED_BY_HEAD :
2712 label_counter >= 42 && label_counter <= 49 ?
2713 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
2715 if (leveldir_current->imported_from == NULL &&
2716 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
2717 label_state == MICROLABEL_IMPORTED_FROM))
2718 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
2719 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
2721 DrawPreviewLevelLabelExt(label_state);
2724 game_status = last_game_status; /* restore current game status */
2727 void DrawPreviewLevelInitial()
2729 DrawPreviewLevelExt(TRUE);
2732 void DrawPreviewLevelAnimation()
2734 DrawPreviewLevelExt(FALSE);
2737 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
2738 int graphic, int sync_frame, int mask_mode)
2740 int frame = getGraphicAnimationFrame(graphic, sync_frame);
2742 if (mask_mode == USE_MASKING)
2743 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
2745 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
2748 inline void DrawFixedGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
2749 int graphic, int sync_frame,
2752 int frame = getGraphicAnimationFrame(graphic, sync_frame);
2754 if (mask_mode == USE_MASKING)
2755 DrawFixedGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
2757 DrawFixedGraphicExt(dst_bitmap, x, y, graphic, frame);
2760 inline void DrawGraphicAnimation(int x, int y, int graphic)
2762 int lx = LEVELX(x), ly = LEVELY(y);
2764 if (!IN_SCR_FIELD(x, y))
2767 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
2768 graphic, GfxFrame[lx][ly], NO_MASKING);
2770 MarkTileDirty(x, y);
2773 inline void DrawFixedGraphicAnimation(int x, int y, int graphic)
2775 int lx = LEVELX(x), ly = LEVELY(y);
2777 if (!IN_SCR_FIELD(x, y))
2780 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
2781 graphic, GfxFrame[lx][ly], NO_MASKING);
2782 MarkTileDirty(x, y);
2785 void DrawLevelGraphicAnimation(int x, int y, int graphic)
2787 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2790 void DrawLevelElementAnimation(int x, int y, int element)
2792 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2794 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2797 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
2799 int sx = SCREENX(x), sy = SCREENY(y);
2801 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2804 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2807 DrawGraphicAnimation(sx, sy, graphic);
2810 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
2811 DrawLevelFieldCrumbled(x, y);
2813 if (GFX_CRUMBLED(Feld[x][y]))
2814 DrawLevelFieldCrumbled(x, y);
2818 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
2820 int sx = SCREENX(x), sy = SCREENY(y);
2823 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2826 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2828 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2831 DrawGraphicAnimation(sx, sy, graphic);
2833 if (GFX_CRUMBLED(element))
2834 DrawLevelFieldCrumbled(x, y);
2837 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
2839 if (player->use_murphy)
2841 /* this works only because currently only one player can be "murphy" ... */
2842 static int last_horizontal_dir = MV_LEFT;
2843 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
2845 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2846 last_horizontal_dir = move_dir;
2848 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
2850 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
2852 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
2858 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
2861 static boolean equalGraphics(int graphic1, int graphic2)
2863 struct GraphicInfo *g1 = &graphic_info[graphic1];
2864 struct GraphicInfo *g2 = &graphic_info[graphic2];
2866 return (g1->bitmap == g2->bitmap &&
2867 g1->src_x == g2->src_x &&
2868 g1->src_y == g2->src_y &&
2869 g1->anim_frames == g2->anim_frames &&
2870 g1->anim_delay == g2->anim_delay &&
2871 g1->anim_mode == g2->anim_mode);
2874 void DrawAllPlayers()
2878 for (i = 0; i < MAX_PLAYERS; i++)
2879 if (stored_player[i].active)
2880 DrawPlayer(&stored_player[i]);
2883 void DrawPlayerField(int x, int y)
2885 if (!IS_PLAYER(x, y))
2888 DrawPlayer(PLAYERINFO(x, y));
2891 #define DRAW_PLAYER_OVER_PUSHED_ELEMENT 1
2893 void DrawPlayer(struct PlayerInfo *player)
2895 int jx = player->jx;
2896 int jy = player->jy;
2897 int move_dir = player->MovDir;
2898 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
2899 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
2900 int last_jx = (player->is_moving ? jx - dx : jx);
2901 int last_jy = (player->is_moving ? jy - dy : jy);
2902 int next_jx = jx + dx;
2903 int next_jy = jy + dy;
2904 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
2905 boolean player_is_opaque = FALSE;
2906 int sx = SCREENX(jx), sy = SCREENY(jy);
2907 int sxx = 0, syy = 0;
2908 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
2910 int action = ACTION_DEFAULT;
2911 int last_player_graphic = getPlayerGraphic(player, move_dir);
2912 int last_player_frame = player->Frame;
2915 /* GfxElement[][] is set to the element the player is digging or collecting;
2916 remove also for off-screen player if the player is not moving anymore */
2917 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
2918 GfxElement[jx][jy] = EL_UNDEFINED;
2920 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
2924 if (!IN_LEV_FIELD(jx, jy))
2926 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
2927 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
2928 printf("DrawPlayerField(): This should never happen!\n");
2933 if (element == EL_EXPLOSION)
2936 action = (player->is_pushing ? ACTION_PUSHING :
2937 player->is_digging ? ACTION_DIGGING :
2938 player->is_collecting ? ACTION_COLLECTING :
2939 player->is_moving ? ACTION_MOVING :
2940 player->is_snapping ? ACTION_SNAPPING :
2941 player->is_dropping ? ACTION_DROPPING :
2942 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
2944 if (player->is_waiting)
2945 move_dir = player->dir_waiting;
2947 InitPlayerGfxAnimation(player, action, move_dir);
2949 /* ----------------------------------------------------------------------- */
2950 /* draw things in the field the player is leaving, if needed */
2951 /* ----------------------------------------------------------------------- */
2953 if (player->is_moving)
2955 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
2957 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
2959 if (last_element == EL_DYNAMITE_ACTIVE ||
2960 last_element == EL_EM_DYNAMITE_ACTIVE ||
2961 last_element == EL_SP_DISK_RED_ACTIVE)
2962 DrawDynamite(last_jx, last_jy);
2964 DrawLevelFieldThruMask(last_jx, last_jy);
2966 else if (last_element == EL_DYNAMITE_ACTIVE ||
2967 last_element == EL_EM_DYNAMITE_ACTIVE ||
2968 last_element == EL_SP_DISK_RED_ACTIVE)
2969 DrawDynamite(last_jx, last_jy);
2971 /* !!! this is not enough to prevent flickering of players which are
2972 moving next to each others without a free tile between them -- this
2973 can only be solved by drawing all players layer by layer (first the
2974 background, then the foreground etc.) !!! => TODO */
2975 else if (!IS_PLAYER(last_jx, last_jy))
2976 DrawLevelField(last_jx, last_jy);
2979 DrawLevelField(last_jx, last_jy);
2982 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
2983 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
2986 if (!IN_SCR_FIELD(sx, sy))
2989 /* ----------------------------------------------------------------------- */
2990 /* draw things behind the player, if needed */
2991 /* ----------------------------------------------------------------------- */
2994 DrawLevelElement(jx, jy, Back[jx][jy]);
2995 else if (IS_ACTIVE_BOMB(element))
2996 DrawLevelElement(jx, jy, EL_EMPTY);
2999 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
3001 int old_element = GfxElement[jx][jy];
3002 int old_graphic = el_act_dir2img(old_element, action, move_dir);
3003 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
3005 if (GFX_CRUMBLED(old_element))
3006 DrawLevelFieldCrumbledDigging(jx, jy, move_dir, player->StepFrame);
3008 DrawGraphic(sx, sy, old_graphic, frame);
3010 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
3011 player_is_opaque = TRUE;
3015 GfxElement[jx][jy] = EL_UNDEFINED;
3017 /* make sure that pushed elements are drawn with correct frame rate */
3018 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
3020 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
3021 GfxFrame[jx][jy] = player->StepFrame;
3023 DrawLevelField(jx, jy);
3027 #if !DRAW_PLAYER_OVER_PUSHED_ELEMENT
3028 /* ----------------------------------------------------------------------- */
3029 /* draw player himself */
3030 /* ----------------------------------------------------------------------- */
3032 graphic = getPlayerGraphic(player, move_dir);
3034 /* in the case of changed player action or direction, prevent the current
3035 animation frame from being restarted for identical animations */
3036 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
3037 player->Frame = last_player_frame;
3039 frame = getGraphicAnimationFrame(graphic, player->Frame);
3043 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3044 sxx = player->GfxPos;
3046 syy = player->GfxPos;
3049 if (player_is_opaque)
3050 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
3052 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3054 if (SHIELD_ON(player))
3056 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
3057 IMG_SHIELD_NORMAL_ACTIVE);
3058 int frame = getGraphicAnimationFrame(graphic, -1);
3060 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3064 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
3067 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3068 sxx = player->GfxPos;
3070 syy = player->GfxPos;
3074 /* ----------------------------------------------------------------------- */
3075 /* draw things the player is pushing, if needed */
3076 /* ----------------------------------------------------------------------- */
3078 if (player->is_pushing && player->is_moving)
3080 int px = SCREENX(jx), py = SCREENY(jy);
3081 int pxx = (TILEX - ABS(sxx)) * dx;
3082 int pyy = (TILEY - ABS(syy)) * dy;
3083 int gfx_frame = GfxFrame[jx][jy];
3089 if (!IS_MOVING(jx, jy)) /* push movement already finished */
3091 element = Feld[next_jx][next_jy];
3092 gfx_frame = GfxFrame[next_jx][next_jy];
3095 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
3097 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
3098 frame = getGraphicAnimationFrame(graphic, sync_frame);
3100 /* draw background element under pushed element (like the Sokoban field) */
3101 if (game.use_masked_pushing && IS_MOVING(jx, jy))
3103 /* this allows transparent pushing animation over non-black background */
3106 DrawLevelElement(jx, jy, Back[jx][jy]);
3108 DrawLevelElement(jx, jy, EL_EMPTY);
3110 if (Back[next_jx][next_jy])
3111 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3113 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
3115 else if (Back[next_jx][next_jy])
3116 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3119 /* do not draw (EM style) pushing animation when pushing is finished */
3120 /* (two-tile animations usually do not contain start and end frame) */
3121 if (graphic_info[graphic].double_movement && !IS_MOVING(jx, jy))
3122 DrawLevelElement(next_jx, next_jy, Feld[next_jx][next_jy]);
3124 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3126 /* masked drawing is needed for EMC style (double) movement graphics */
3127 /* !!! (ONLY WHEN DRAWING PUSHED ELEMENT OVER THE PLAYER) !!! */
3128 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3132 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
3133 /* ----------------------------------------------------------------------- */
3134 /* draw player himself */
3135 /* ----------------------------------------------------------------------- */
3137 graphic = getPlayerGraphic(player, move_dir);
3139 /* in the case of changed player action or direction, prevent the current
3140 animation frame from being restarted for identical animations */
3141 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
3142 player->Frame = last_player_frame;
3144 frame = getGraphicAnimationFrame(graphic, player->Frame);
3148 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3149 sxx = player->GfxPos;
3151 syy = player->GfxPos;
3154 if (player_is_opaque)
3155 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
3157 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3159 if (SHIELD_ON(player))
3161 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
3162 IMG_SHIELD_NORMAL_ACTIVE);
3163 int frame = getGraphicAnimationFrame(graphic, -1);
3165 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3169 /* ----------------------------------------------------------------------- */
3170 /* draw things in front of player (active dynamite or dynabombs) */
3171 /* ----------------------------------------------------------------------- */
3173 if (IS_ACTIVE_BOMB(element))
3175 graphic = el2img(element);
3176 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
3178 if (game.emulation == EMU_SUPAPLEX)
3179 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
3181 DrawGraphicThruMask(sx, sy, graphic, frame);
3184 if (player_is_moving && last_element == EL_EXPLOSION)
3186 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
3187 GfxElement[last_jx][last_jy] : EL_EMPTY);
3188 int graphic = el_act2img(element, ACTION_EXPLODING);
3189 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
3190 int phase = ExplodePhase[last_jx][last_jy] - 1;
3191 int frame = getGraphicAnimationFrame(graphic, phase - delay);
3194 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
3197 /* ----------------------------------------------------------------------- */
3198 /* draw elements the player is just walking/passing through/under */
3199 /* ----------------------------------------------------------------------- */
3201 if (player_is_moving)
3203 /* handle the field the player is leaving ... */
3204 if (IS_ACCESSIBLE_INSIDE(last_element))
3205 DrawLevelField(last_jx, last_jy);
3206 else if (IS_ACCESSIBLE_UNDER(last_element))
3207 DrawLevelFieldThruMask(last_jx, last_jy);
3210 /* do not redraw accessible elements if the player is just pushing them */
3211 if (!player_is_moving || !player->is_pushing)
3213 /* ... and the field the player is entering */
3214 if (IS_ACCESSIBLE_INSIDE(element))
3215 DrawLevelField(jx, jy);
3216 else if (IS_ACCESSIBLE_UNDER(element))
3217 DrawLevelFieldThruMask(jx, jy);
3220 MarkTileDirty(sx, sy);
3223 /* ------------------------------------------------------------------------- */
3225 void WaitForEventToContinue()
3227 boolean still_wait = TRUE;
3229 /* simulate releasing mouse button over last gadget, if still pressed */
3231 HandleGadgets(-1, -1, 0);
3233 button_status = MB_RELEASED;
3247 case EVENT_BUTTONPRESS:
3248 case EVENT_KEYPRESS:
3252 case EVENT_KEYRELEASE:
3253 ClearPlayerAction();
3257 HandleOtherEvents(&event);
3261 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3268 /* don't eat all CPU time */
3273 #define MAX_REQUEST_LINES 13
3274 #define MAX_REQUEST_LINE_FONT1_LEN 7
3275 #define MAX_REQUEST_LINE_FONT2_LEN 10
3277 static int RequestHandleEvents(unsigned int req_state)
3279 int last_game_status = game_status; /* save current game status */
3283 button_status = MB_RELEASED;
3285 request_gadget_id = -1;
3294 while (NextValidEvent(&event))
3298 case EVENT_BUTTONPRESS:
3299 case EVENT_BUTTONRELEASE:
3300 case EVENT_MOTIONNOTIFY:
3302 if (event.type == EVENT_MOTIONNOTIFY)
3307 motion_status = TRUE;
3308 mx = ((MotionEvent *) &event)->x;
3309 my = ((MotionEvent *) &event)->y;
3313 motion_status = FALSE;
3314 mx = ((ButtonEvent *) &event)->x;
3315 my = ((ButtonEvent *) &event)->y;
3316 if (event.type == EVENT_BUTTONPRESS)
3317 button_status = ((ButtonEvent *) &event)->button;
3319 button_status = MB_RELEASED;
3322 /* this sets 'request_gadget_id' */
3323 HandleGadgets(mx, my, button_status);
3325 switch (request_gadget_id)
3327 case TOOL_CTRL_ID_YES:
3330 case TOOL_CTRL_ID_NO:
3333 case TOOL_CTRL_ID_CONFIRM:
3334 result = TRUE | FALSE;
3337 case TOOL_CTRL_ID_PLAYER_1:
3340 case TOOL_CTRL_ID_PLAYER_2:
3343 case TOOL_CTRL_ID_PLAYER_3:
3346 case TOOL_CTRL_ID_PLAYER_4:
3357 case EVENT_KEYPRESS:
3358 switch (GetEventKey((KeyEvent *)&event, TRUE))
3361 if (req_state & REQ_CONFIRM)
3366 #if defined(TARGET_SDL2)
3373 #if defined(TARGET_SDL2)
3383 if (req_state & REQ_PLAYER)
3387 case EVENT_KEYRELEASE:
3388 ClearPlayerAction();
3392 HandleOtherEvents(&event);
3397 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3399 int joy = AnyJoystick();
3401 if (joy & JOY_BUTTON_1)
3403 else if (joy & JOY_BUTTON_2)
3407 if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd)
3409 HandleGameActions();
3415 if (!PendingEvent()) /* delay only if no pending events */
3419 game_status = GAME_MODE_PSEUDO_DOOR;
3423 game_status = last_game_status; /* restore current game status */
3429 static boolean RequestDoor(char *text, unsigned int req_state)
3431 unsigned int old_door_state;
3432 int last_game_status = game_status; /* save current game status */
3433 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
3434 int font_nr = FONT_TEXT_2;
3439 if (maxWordLengthInString(text) > MAX_REQUEST_LINE_FONT1_LEN)
3441 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
3442 font_nr = FONT_TEXT_1;
3445 if (game_status == GAME_MODE_PLAYING)
3446 BlitScreenToBitmap(backbuffer);
3448 /* disable deactivated drawing when quick-loading level tape recording */
3449 if (tape.playing && tape.deactivate_display)
3450 TapeDeactivateDisplayOff(TRUE);
3452 SetMouseCursor(CURSOR_DEFAULT);
3454 #if defined(NETWORK_AVALIABLE)
3455 /* pause network game while waiting for request to answer */
3456 if (options.network &&
3457 game_status == GAME_MODE_PLAYING &&
3458 req_state & REQUEST_WAIT_FOR_INPUT)
3459 SendToServer_PausePlaying();
3462 old_door_state = GetDoorState();
3464 /* simulate releasing mouse button over last gadget, if still pressed */
3466 HandleGadgets(-1, -1, 0);
3470 /* draw released gadget before proceeding */
3473 if (old_door_state & DOOR_OPEN_1)
3475 CloseDoor(DOOR_CLOSE_1);
3477 /* save old door content */
3478 BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
3479 0 * DXSIZE, 0, DXSIZE, DYSIZE, 1 * DXSIZE, 0);
3482 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
3483 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3485 /* clear door drawing field */
3486 DrawBackground(DX, DY, DXSIZE, DYSIZE);
3488 /* force DOOR font inside door area */
3489 game_status = GAME_MODE_PSEUDO_DOOR;
3491 /* write text for request */
3492 for (text_ptr = text, ty = 0; ty < MAX_REQUEST_LINES; ty++)
3494 char text_line[max_request_line_len + 1];
3500 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
3502 tc = *(text_ptr + tx);
3503 // if (!tc || tc == ' ')
3504 if (!tc || tc == ' ' || tc == '?' || tc == '!')
3508 if ((tc == '?' || tc == '!') && tl == 0)
3518 strncpy(text_line, text_ptr, tl);
3521 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
3522 DY + 8 + ty * (getFontHeight(font_nr) + 2),
3523 text_line, font_nr);
3525 text_ptr += tl + (tc == ' ' ? 1 : 0);
3526 // text_ptr += tl + (tc == ' ' || tc == '?' || tc == '!' ? 1 : 0);
3529 game_status = last_game_status; /* restore current game status */
3531 if (req_state & REQ_ASK)
3533 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
3534 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
3536 else if (req_state & REQ_CONFIRM)
3538 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
3540 else if (req_state & REQ_PLAYER)
3542 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
3543 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
3544 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
3545 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
3548 /* copy request gadgets to door backbuffer */
3549 BlitBitmap(drawto, bitmap_db_door_1, DX, DY, DXSIZE, DYSIZE, 0, 0);
3551 OpenDoor(DOOR_OPEN_1);
3553 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
3555 if (game_status == GAME_MODE_PLAYING)
3557 SetPanelBackground();
3558 SetDrawBackgroundMask(REDRAW_DOOR_1);
3562 SetDrawBackgroundMask(REDRAW_FIELD);
3568 if (game_status != GAME_MODE_MAIN)
3571 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3573 // ---------- handle request buttons ----------
3574 result = RequestHandleEvents(req_state);
3576 if (game_status != GAME_MODE_MAIN)
3581 if (!(req_state & REQ_STAY_OPEN))
3583 CloseDoor(DOOR_CLOSE_1);
3585 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
3586 (req_state & REQ_REOPEN))
3587 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
3592 if (game_status == GAME_MODE_PLAYING)
3594 SetPanelBackground();
3595 SetDrawBackgroundMask(REDRAW_DOOR_1);
3599 SetDrawBackgroundMask(REDRAW_FIELD);
3602 #if defined(NETWORK_AVALIABLE)
3603 /* continue network game after request */
3604 if (options.network &&
3605 game_status == GAME_MODE_PLAYING &&
3606 req_state & REQUEST_WAIT_FOR_INPUT)
3607 SendToServer_ContinuePlaying();
3610 /* restore deactivated drawing when quick-loading level tape recording */
3611 if (tape.playing && tape.deactivate_display)
3612 TapeDeactivateDisplayOn();
3617 static boolean RequestEnvelope(char *text, unsigned int req_state)
3621 if (game_status == GAME_MODE_PLAYING)
3622 BlitScreenToBitmap(backbuffer);
3624 /* disable deactivated drawing when quick-loading level tape recording */
3625 if (tape.playing && tape.deactivate_display)
3626 TapeDeactivateDisplayOff(TRUE);
3628 SetMouseCursor(CURSOR_DEFAULT);
3630 #if defined(NETWORK_AVALIABLE)
3631 /* pause network game while waiting for request to answer */
3632 if (options.network &&
3633 game_status == GAME_MODE_PLAYING &&
3634 req_state & REQUEST_WAIT_FOR_INPUT)
3635 SendToServer_PausePlaying();
3638 /* simulate releasing mouse button over last gadget, if still pressed */
3640 HandleGadgets(-1, -1, 0);
3644 // (replace with setting corresponding request background)
3645 // SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
3646 // SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3648 /* clear door drawing field */
3649 // DrawBackground(DX, DY, DXSIZE, DYSIZE);
3651 ShowEnvelopeRequest(text, req_state, ACTION_OPENING);
3653 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
3655 if (game_status == GAME_MODE_PLAYING)
3657 SetPanelBackground();
3658 SetDrawBackgroundMask(REDRAW_DOOR_1);
3662 SetDrawBackgroundMask(REDRAW_FIELD);
3668 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3670 // ---------- handle request buttons ----------
3671 result = RequestHandleEvents(req_state);
3673 if (game_status != GAME_MODE_MAIN)
3678 ShowEnvelopeRequest(text, req_state, ACTION_CLOSING);
3682 if (game_status == GAME_MODE_PLAYING)
3684 SetPanelBackground();
3685 SetDrawBackgroundMask(REDRAW_DOOR_1);
3689 SetDrawBackgroundMask(REDRAW_FIELD);
3692 #if defined(NETWORK_AVALIABLE)
3693 /* continue network game after request */
3694 if (options.network &&
3695 game_status == GAME_MODE_PLAYING &&
3696 req_state & REQUEST_WAIT_FOR_INPUT)
3697 SendToServer_ContinuePlaying();
3700 /* restore deactivated drawing when quick-loading level tape recording */
3701 if (tape.playing && tape.deactivate_display)
3702 TapeDeactivateDisplayOn();
3707 boolean Request(char *text, unsigned int req_state)
3709 if (global.use_envelope_request)
3710 return RequestEnvelope(text, req_state);
3712 return RequestDoor(text, req_state);
3715 static int compareDoorPartOrderInfo(const void *object1, const void *object2)
3717 const struct DoorPartOrderInfo *dpo1 = (struct DoorPartOrderInfo *)object1;
3718 const struct DoorPartOrderInfo *dpo2 = (struct DoorPartOrderInfo *)object2;
3721 if (dpo1->sort_priority != dpo2->sort_priority)
3722 compare_result = dpo1->sort_priority - dpo2->sort_priority;
3724 compare_result = dpo1->nr - dpo2->nr;
3726 return compare_result;
3729 void InitGraphicCompatibilityInfo_Doors()
3735 struct DoorInfo *door;
3739 { DOOR_1, IMG_DOOR_1_GFX_PART_1, IMG_DOOR_1_GFX_PART_8, &door_1 },
3740 { DOOR_2, IMG_DOOR_2_GFX_PART_1, IMG_DOOR_2_GFX_PART_8, &door_2 },
3742 { -1, -1, -1, NULL }
3744 struct Rect door_rect_list[] =
3746 { DX, DY, DXSIZE, DYSIZE },
3747 { VX, VY, VXSIZE, VYSIZE }
3751 for (i = 0; doors[i].door_token != -1; i++)
3753 int door_token = doors[i].door_token;
3754 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
3755 int part_1 = doors[i].part_1;
3756 int part_8 = doors[i].part_8;
3757 int part_2 = part_1 + 1;
3758 int part_3 = part_1 + 2;
3759 struct DoorInfo *door = doors[i].door;
3760 struct Rect *door_rect = &door_rect_list[door_index];
3761 boolean door_gfx_redefined = FALSE;
3763 /* check if any door part graphic definitions have been redefined */
3765 for (j = 0; door_part_controls[j].door_token != -1; j++)
3767 struct DoorPartControlInfo *dpc = &door_part_controls[j];
3768 struct FileInfo *fi = getImageListEntryFromImageID(dpc->graphic);
3770 if (dpc->door_token == door_token && fi->redefined)
3771 door_gfx_redefined = TRUE;
3774 /* check for old-style door graphic/animation modifications */
3776 if (!door_gfx_redefined)
3778 if (door->anim_mode & ANIM_STATIC_PANEL)
3780 door->panel.step_xoffset = 0;
3781 door->panel.step_yoffset = 0;
3784 if (door->anim_mode & (ANIM_HORIZONTAL | ANIM_VERTICAL))
3786 struct GraphicInfo *g_part_1 = &graphic_info[part_1];
3787 struct GraphicInfo *g_part_2 = &graphic_info[part_2];
3788 int num_door_steps, num_panel_steps;
3790 /* remove door part graphics other than the two default wings */
3792 for (j = 0; door_part_controls[j].door_token != -1; j++)
3794 struct DoorPartControlInfo *dpc = &door_part_controls[j];
3795 struct GraphicInfo *g = &graphic_info[dpc->graphic];
3797 if (dpc->graphic >= part_3 &&
3798 dpc->graphic <= part_8)
3802 /* set graphics and screen positions of the default wings */
3804 g_part_1->width = door_rect->width;
3805 g_part_1->height = door_rect->height;
3806 g_part_2->width = door_rect->width;
3807 g_part_2->height = door_rect->height;
3808 g_part_2->src_x = door_rect->width;
3809 g_part_2->src_y = g_part_1->src_y;
3811 door->part_2.x = door->part_1.x;
3812 door->part_2.y = door->part_1.y;
3814 if (door->width != -1)
3816 g_part_1->width = door->width;
3817 g_part_2->width = door->width;
3819 // special treatment for graphics and screen position of right wing
3820 g_part_2->src_x += door_rect->width - door->width;
3821 door->part_2.x += door_rect->width - door->width;
3824 if (door->height != -1)
3826 g_part_1->height = door->height;
3827 g_part_2->height = door->height;
3829 // special treatment for graphics and screen position of bottom wing
3830 g_part_2->src_y += door_rect->height - door->height;
3831 door->part_2.y += door_rect->height - door->height;
3834 /* set animation delays for the default wings and panels */
3836 door->part_1.step_delay = door->step_delay;
3837 door->part_2.step_delay = door->step_delay;
3838 door->panel.step_delay = door->step_delay;
3840 /* set animation draw order for the default wings */
3842 door->part_1.sort_priority = 2; /* draw left wing over ... */
3843 door->part_2.sort_priority = 1; /* ... right wing */
3845 /* set animation draw offset for the default wings */
3847 if (door->anim_mode & ANIM_HORIZONTAL)
3849 door->part_1.step_xoffset = door->step_offset;
3850 door->part_1.step_yoffset = 0;
3851 door->part_2.step_xoffset = door->step_offset * -1;
3852 door->part_2.step_yoffset = 0;
3854 num_door_steps = g_part_1->width / door->step_offset;
3856 else // ANIM_VERTICAL
3858 door->part_1.step_xoffset = 0;
3859 door->part_1.step_yoffset = door->step_offset;
3860 door->part_2.step_xoffset = 0;
3861 door->part_2.step_yoffset = door->step_offset * -1;
3863 num_door_steps = g_part_1->height / door->step_offset;
3866 /* set animation draw offset for the default panels */
3868 if (door->step_offset > 1)
3870 num_panel_steps = 2 * door_rect->height / door->step_offset;
3871 door->panel.start_step = num_panel_steps - num_door_steps;
3872 door->panel.start_step_closing = door->panel.start_step;
3876 num_panel_steps = door_rect->height / door->step_offset;
3877 door->panel.start_step = num_panel_steps - num_door_steps / 2;
3878 door->panel.start_step_closing = door->panel.start_step;
3879 door->panel.step_delay *= 2;
3890 for (i = 0; door_part_controls[i].door_token != -1; i++)
3892 struct DoorPartControlInfo *dpc = &door_part_controls[i];
3893 struct DoorPartOrderInfo *dpo = &door_part_order[i];
3895 /* initialize "start_step_opening" and "start_step_closing", if needed */
3896 if (dpc->pos->start_step_opening == 0 &&
3897 dpc->pos->start_step_closing == 0)
3899 // dpc->pos->start_step_opening = dpc->pos->start_step;
3900 dpc->pos->start_step_closing = dpc->pos->start_step;
3903 /* fill structure for door part draw order (sorted below) */
3905 dpo->sort_priority = dpc->pos->sort_priority;
3908 /* sort door part controls according to sort_priority and graphic number */
3909 qsort(door_part_order, MAX_DOOR_PARTS,
3910 sizeof(struct DoorPartOrderInfo), compareDoorPartOrderInfo);
3913 unsigned int OpenDoor(unsigned int door_state)
3915 if (door_state & DOOR_COPY_BACK)
3917 if (door_state & DOOR_OPEN_1)
3918 BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
3919 1 * DXSIZE, 0, DXSIZE, DYSIZE, 0 * DXSIZE, 0);
3921 if (door_state & DOOR_OPEN_2)
3922 BlitBitmap(bitmap_db_door_2, bitmap_db_door_2,
3923 1 * VXSIZE, 0, VXSIZE, VYSIZE, 0 * VXSIZE, 0);
3925 door_state &= ~DOOR_COPY_BACK;
3928 return MoveDoor(door_state);
3931 unsigned int CloseDoor(unsigned int door_state)
3933 unsigned int old_door_state = GetDoorState();
3935 if (!(door_state & DOOR_NO_COPY_BACK))
3937 if (old_door_state & DOOR_OPEN_1)
3938 BlitBitmap(backbuffer, bitmap_db_door_1,
3939 DX, DY, DXSIZE, DYSIZE, 0, 0);
3941 if (old_door_state & DOOR_OPEN_2)
3942 BlitBitmap(backbuffer, bitmap_db_door_2,
3943 VX, VY, VXSIZE, VYSIZE, 0, 0);
3945 door_state &= ~DOOR_NO_COPY_BACK;
3948 return MoveDoor(door_state);
3951 unsigned int GetDoorState()
3953 return MoveDoor(DOOR_GET_STATE);
3956 unsigned int SetDoorState(unsigned int door_state)
3958 return MoveDoor(door_state | DOOR_SET_STATE);
3961 int euclid(int a, int b)
3963 return (b ? euclid(b, a % b) : a);
3966 unsigned int MoveDoor(unsigned int door_state)
3968 struct Rect door_rect_list[] =
3970 { DX, DY, DXSIZE, DYSIZE },
3971 { VX, VY, VXSIZE, VYSIZE }
3973 static int door1 = DOOR_OPEN_1;
3974 static int door2 = DOOR_CLOSE_2;
3975 unsigned int door_delay = 0;
3976 unsigned int door_delay_value;
3979 if (door_state == DOOR_GET_STATE)
3980 return (door1 | door2);
3982 if (door_state & DOOR_SET_STATE)
3984 if (door_state & DOOR_ACTION_1)
3985 door1 = door_state & DOOR_ACTION_1;
3986 if (door_state & DOOR_ACTION_2)
3987 door2 = door_state & DOOR_ACTION_2;
3989 return (door1 | door2);
3992 if (!(door_state & DOOR_FORCE_REDRAW))
3994 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
3995 door_state &= ~DOOR_OPEN_1;
3996 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
3997 door_state &= ~DOOR_CLOSE_1;
3998 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
3999 door_state &= ~DOOR_OPEN_2;
4000 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
4001 door_state &= ~DOOR_CLOSE_2;
4004 if (global.autoplay_leveldir)
4006 door_state |= DOOR_NO_DELAY;
4007 door_state &= ~DOOR_CLOSE_ALL;
4010 if (game_status == GAME_MODE_EDITOR)
4011 door_state |= DOOR_NO_DELAY;
4013 if (door_state & DOOR_ACTION)
4015 boolean door_panel_drawn[NUM_DOORS];
4016 boolean panel_has_doors[NUM_DOORS];
4017 boolean door_part_skip[MAX_DOOR_PARTS];
4018 boolean door_part_done[MAX_DOOR_PARTS];
4019 boolean door_part_done_all;
4020 int num_steps[MAX_DOOR_PARTS];
4021 int max_move_delay = 0; // delay for complete animations of all doors
4022 int max_step_delay = 0; // delay (ms) between two animation frames
4023 int num_move_steps = 0; // number of animation steps for all doors
4024 int max_move_delay_doors_only = 0; // delay for doors only (no panel)
4025 int num_move_steps_doors_only = 0; // steps for doors only (no panel)
4026 int current_move_delay = 0;
4030 for (i = 0; i < NUM_DOORS; i++)
4031 panel_has_doors[i] = FALSE;
4033 for (i = 0; i < MAX_DOOR_PARTS; i++)
4035 struct DoorPartControlInfo *dpc = &door_part_controls[i];
4036 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4037 int door_token = dpc->door_token;
4039 door_part_done[i] = FALSE;
4040 door_part_skip[i] = (!(door_state & door_token) ||
4044 for (i = 0; i < MAX_DOOR_PARTS; i++)
4046 int nr = door_part_order[i].nr;
4047 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
4048 struct DoorPartPosInfo *pos = dpc->pos;
4049 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4050 int door_token = dpc->door_token;
4051 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
4052 boolean is_panel = DOOR_PART_IS_PANEL(nr);
4053 int step_xoffset = ABS(pos->step_xoffset);
4054 int step_yoffset = ABS(pos->step_yoffset);
4055 int step_delay = pos->step_delay;
4056 int current_door_state = door_state & door_token;
4057 boolean door_opening = ((current_door_state & DOOR_OPEN) != 0);
4058 boolean door_closing = ((current_door_state & DOOR_CLOSE) != 0);
4059 boolean part_opening = (is_panel ? door_closing : door_opening);
4060 int start_step = (part_opening ? pos->start_step_opening :
4061 pos->start_step_closing);
4062 float move_xsize = (step_xoffset ? g->width : 0);
4063 float move_ysize = (step_yoffset ? g->height : 0);
4064 int move_xsteps = (step_xoffset ? ceil(move_xsize / step_xoffset) : 0);
4065 int move_ysteps = (step_yoffset ? ceil(move_ysize / step_yoffset) : 0);
4066 int move_steps = (move_xsteps && move_ysteps ?
4067 MIN(move_xsteps, move_ysteps) :
4068 move_xsteps ? move_xsteps : move_ysteps) - start_step;
4069 int move_delay = move_steps * step_delay;
4071 if (door_part_skip[nr])
4074 max_move_delay = MAX(max_move_delay, move_delay);
4075 max_step_delay = (max_step_delay == 0 ? step_delay :
4076 euclid(max_step_delay, step_delay));
4077 num_steps[nr] = move_steps;
4081 max_move_delay_doors_only = MAX(max_move_delay_doors_only, move_delay);
4083 panel_has_doors[door_index] = TRUE;
4087 max_step_delay = MAX(1, max_step_delay); // prevent division by zero
4089 num_move_steps = max_move_delay / max_step_delay;
4090 num_move_steps_doors_only = max_move_delay_doors_only / max_step_delay;
4092 door_delay_value = max_step_delay;
4094 if ((door_state & DOOR_NO_DELAY) || setup.quick_doors)
4096 start = num_move_steps - 1;
4100 /* opening door sound has priority over simultaneously closing door */
4101 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
4102 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
4103 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
4104 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
4107 for (k = start; k < num_move_steps; k++)
4109 int last_frame = num_move_steps - 1; // last frame of this "for" loop
4111 door_part_done_all = TRUE;
4113 for (i = 0; i < NUM_DOORS; i++)
4114 door_panel_drawn[i] = FALSE;
4116 for (i = 0; i < MAX_DOOR_PARTS; i++)
4118 int nr = door_part_order[i].nr;
4119 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
4120 struct DoorPartPosInfo *pos = dpc->pos;
4121 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4122 int door_token = dpc->door_token;
4123 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
4124 boolean is_panel = DOOR_PART_IS_PANEL(nr);
4125 boolean is_panel_and_door_has_closed = FALSE;
4126 struct Rect *door_rect = &door_rect_list[door_index];
4127 Bitmap *bitmap_db_door = (door_token == DOOR_1 ? bitmap_db_door_1 :
4129 Bitmap *bitmap = (is_panel ? bitmap_db_door : g->bitmap);
4130 int current_door_state = door_state & door_token;
4131 boolean door_opening = ((current_door_state & DOOR_OPEN) != 0);
4132 boolean door_closing = !door_opening;
4133 boolean part_opening = (is_panel ? door_closing : door_opening);
4134 boolean part_closing = !part_opening;
4135 int start_step = (part_opening ? pos->start_step_opening :
4136 pos->start_step_closing);
4137 int step_delay = pos->step_delay;
4138 int step_factor = step_delay / max_step_delay;
4139 int k1 = (step_factor ? k / step_factor + 1 : k);
4140 int k2 = (part_opening ? k1 + start_step : num_steps[nr] - k1);
4141 int kk = MAX(0, k2);
4144 int src_x, src_y, src_xx, src_yy;
4145 int dst_x, dst_y, dst_xx, dst_yy;
4148 if (door_part_skip[nr])
4151 if (!(door_state & door_token))
4159 int k2_door = (door_opening ? k : num_move_steps_doors_only - k - 1);
4160 int kk_door = MAX(0, k2_door);
4161 int sync_frame = kk_door * door_delay_value;
4162 int frame = getGraphicAnimationFrame(dpc->graphic, sync_frame);
4164 getGraphicSource(dpc->graphic, frame, &bitmap, &g_src_x, &g_src_y);
4169 if (!door_panel_drawn[door_index])
4171 ClearRectangle(drawto, door_rect->x, door_rect->y,
4172 door_rect->width, door_rect->height);
4174 door_panel_drawn[door_index] = TRUE;
4177 // draw opening or closing door parts
4179 if (pos->step_xoffset < 0) // door part on right side
4182 dst_xx = pos->x + ABS(kk * pos->step_xoffset);
4185 if (dst_xx + width > door_rect->width)
4186 width = door_rect->width - dst_xx;
4188 else // door part on left side
4191 dst_xx = pos->x - kk * pos->step_xoffset;
4195 src_xx = ABS(dst_xx);
4199 width = g->width - src_xx;
4201 // printf("::: k == %d [%d] \n", k, start_step);
4204 if (pos->step_yoffset < 0) // door part on bottom side
4207 dst_yy = pos->y + ABS(kk * pos->step_yoffset);
4210 if (dst_yy + height > door_rect->height)
4211 height = door_rect->height - dst_yy;
4213 else // door part on top side
4216 dst_yy = pos->y - kk * pos->step_yoffset;
4220 src_yy = ABS(dst_yy);
4224 height = g->height - src_yy;
4227 src_x = g_src_x + src_xx;
4228 src_y = g_src_y + src_yy;
4230 dst_x = door_rect->x + dst_xx;
4231 dst_y = door_rect->y + dst_yy;
4233 is_panel_and_door_has_closed =
4236 panel_has_doors[door_index] &&
4237 k >= num_move_steps_doors_only - 1);
4239 if (width >= 0 && width <= g->width &&
4240 height >= 0 && height <= g->height &&
4241 !is_panel_and_door_has_closed)
4243 if (is_panel || !pos->draw_masked)
4244 BlitBitmap(bitmap, drawto, src_x, src_y, width, height,
4247 BlitBitmapMasked(bitmap, drawto, src_x, src_y, width, height,
4251 redraw_mask |= REDRAW_DOOR_FROM_TOKEN(door_token);
4253 if ((part_opening && (width < 0 || height < 0)) ||
4254 (part_closing && (width >= g->width && height >= g->height)))
4255 door_part_done[nr] = TRUE;
4257 // continue door part animations, but not panel after door has closed
4258 if (!door_part_done[nr] && !is_panel_and_door_has_closed)
4259 door_part_done_all = FALSE;
4262 if (!(door_state & DOOR_NO_DELAY))
4266 if (game_status == GAME_MODE_MAIN)
4269 SkipUntilDelayReached(&door_delay, door_delay_value, &k, last_frame);
4271 current_move_delay += max_step_delay;
4274 if (door_part_done_all)
4279 if (door_state & DOOR_ACTION_1)
4280 door1 = door_state & DOOR_ACTION_1;
4281 if (door_state & DOOR_ACTION_2)
4282 door2 = door_state & DOOR_ACTION_2;
4284 return (door1 | door2);
4287 void DrawSpecialEditorDoor()
4289 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
4290 int top_border_width = gfx1->width;
4291 int top_border_height = gfx1->height;
4292 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
4293 int ex = EX - outer_border;
4294 int ey = EY - outer_border;
4295 int vy = VY - outer_border;
4296 int exsize = EXSIZE + 2 * outer_border;
4298 /* draw bigger level editor toolbox window */
4299 BlitBitmap(gfx1->bitmap, drawto, gfx1->src_x, gfx1->src_y,
4300 top_border_width, top_border_height, ex, ey - top_border_height);
4301 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto, ex, vy,
4302 exsize, EYSIZE - VYSIZE + outer_border, ex, ey);
4304 redraw_mask |= REDRAW_ALL;
4307 void UndrawSpecialEditorDoor()
4309 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
4310 int top_border_width = gfx1->width;
4311 int top_border_height = gfx1->height;
4312 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
4313 int ex = EX - outer_border;
4314 int ey = EY - outer_border;
4315 int ey_top = ey - top_border_height;
4316 int exsize = EXSIZE + 2 * outer_border;
4317 int eysize = EYSIZE + 2 * outer_border;
4319 /* draw normal tape recorder window */
4320 if (graphic_info[IMG_GLOBAL_BORDER].bitmap)
4322 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
4323 ex, ey_top, top_border_width, top_border_height,
4325 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
4326 ex, ey, exsize, eysize, ex, ey);
4330 // if screen background is set to "[NONE]", clear editor toolbox window
4331 ClearRectangle(drawto, ex, ey_top, top_border_width, top_border_height);
4332 ClearRectangle(drawto, ex, ey, exsize, eysize);
4335 redraw_mask |= REDRAW_ALL;
4339 /* ---------- new tool button stuff ---------------------------------------- */
4344 struct TextPosInfo *pos;
4347 } toolbutton_info[NUM_TOOL_BUTTONS] =
4350 IMG_REQUEST_BUTTON_GFX_YES, &request.button.yes,
4351 TOOL_CTRL_ID_YES, "yes"
4354 IMG_REQUEST_BUTTON_GFX_NO, &request.button.no,
4355 TOOL_CTRL_ID_NO, "no"
4358 IMG_REQUEST_BUTTON_GFX_CONFIRM, &request.button.confirm,
4359 TOOL_CTRL_ID_CONFIRM, "confirm"
4362 IMG_REQUEST_BUTTON_GFX_PLAYER_1, &request.button.player_1,
4363 TOOL_CTRL_ID_PLAYER_1, "player 1"
4366 IMG_REQUEST_BUTTON_GFX_PLAYER_2, &request.button.player_2,
4367 TOOL_CTRL_ID_PLAYER_2, "player 2"
4370 IMG_REQUEST_BUTTON_GFX_PLAYER_3, &request.button.player_3,
4371 TOOL_CTRL_ID_PLAYER_3, "player 3"
4374 IMG_REQUEST_BUTTON_GFX_PLAYER_4, &request.button.player_4,
4375 TOOL_CTRL_ID_PLAYER_4, "player 4"
4379 void CreateToolButtons()
4383 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4385 struct GraphicInfo *gfx = &graphic_info[toolbutton_info[i].graphic];
4386 struct TextPosInfo *pos = toolbutton_info[i].pos;
4387 struct GadgetInfo *gi;
4388 Bitmap *deco_bitmap = None;
4389 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
4390 unsigned int event_mask = GD_EVENT_RELEASED;
4393 int gd_x = gfx->src_x;
4394 int gd_y = gfx->src_y;
4395 int gd_xp = gfx->src_x + gfx->pressed_xoffset;
4396 int gd_yp = gfx->src_y + gfx->pressed_yoffset;
4399 if (global.use_envelope_request)
4400 setRequestPosition(&dx, &dy, TRUE);
4402 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
4404 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
4406 getSizedGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr), 0,
4407 pos->size, &deco_bitmap, &deco_x, &deco_y);
4408 deco_xpos = (gfx->width - pos->size) / 2;
4409 deco_ypos = (gfx->height - pos->size) / 2;
4412 gi = CreateGadget(GDI_CUSTOM_ID, id,
4413 GDI_INFO_TEXT, toolbutton_info[i].infotext,
4414 GDI_X, dx + GDI_ACTIVE_POS(pos->x),
4415 GDI_Y, dy + GDI_ACTIVE_POS(pos->y),
4416 GDI_WIDTH, gfx->width,
4417 GDI_HEIGHT, gfx->height,
4418 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
4419 GDI_STATE, GD_BUTTON_UNPRESSED,
4420 GDI_DESIGN_UNPRESSED, gfx->bitmap, gd_x, gd_y,
4421 GDI_DESIGN_PRESSED, gfx->bitmap, gd_xp, gd_yp,
4422 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
4423 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
4424 GDI_DECORATION_SIZE, pos->size, pos->size,
4425 GDI_DECORATION_SHIFTING, 1, 1,
4426 GDI_DIRECT_DRAW, FALSE,
4427 GDI_EVENT_MASK, event_mask,
4428 GDI_CALLBACK_ACTION, HandleToolButtons,
4432 Error(ERR_EXIT, "cannot create gadget");
4434 tool_gadget[id] = gi;
4438 void FreeToolButtons()
4442 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4443 FreeGadget(tool_gadget[i]);
4446 static void UnmapToolButtons()
4450 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4451 UnmapGadget(tool_gadget[i]);
4454 static void HandleToolButtons(struct GadgetInfo *gi)
4456 request_gadget_id = gi->custom_id;
4459 static struct Mapping_EM_to_RND_object
4462 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
4463 boolean is_backside; /* backside of moving element */
4469 em_object_mapping_list[] =
4472 Xblank, TRUE, FALSE,
4476 Yacid_splash_eB, FALSE, FALSE,
4477 EL_ACID_SPLASH_RIGHT, -1, -1
4480 Yacid_splash_wB, FALSE, FALSE,
4481 EL_ACID_SPLASH_LEFT, -1, -1
4484 #ifdef EM_ENGINE_BAD_ROLL
4486 Xstone_force_e, FALSE, FALSE,
4487 EL_ROCK, -1, MV_BIT_RIGHT
4490 Xstone_force_w, FALSE, FALSE,
4491 EL_ROCK, -1, MV_BIT_LEFT
4494 Xnut_force_e, FALSE, FALSE,
4495 EL_NUT, -1, MV_BIT_RIGHT
4498 Xnut_force_w, FALSE, FALSE,
4499 EL_NUT, -1, MV_BIT_LEFT
4502 Xspring_force_e, FALSE, FALSE,
4503 EL_SPRING, -1, MV_BIT_RIGHT
4506 Xspring_force_w, FALSE, FALSE,
4507 EL_SPRING, -1, MV_BIT_LEFT
4510 Xemerald_force_e, FALSE, FALSE,
4511 EL_EMERALD, -1, MV_BIT_RIGHT
4514 Xemerald_force_w, FALSE, FALSE,
4515 EL_EMERALD, -1, MV_BIT_LEFT
4518 Xdiamond_force_e, FALSE, FALSE,
4519 EL_DIAMOND, -1, MV_BIT_RIGHT
4522 Xdiamond_force_w, FALSE, FALSE,
4523 EL_DIAMOND, -1, MV_BIT_LEFT
4526 Xbomb_force_e, FALSE, FALSE,
4527 EL_BOMB, -1, MV_BIT_RIGHT
4530 Xbomb_force_w, FALSE, FALSE,
4531 EL_BOMB, -1, MV_BIT_LEFT
4533 #endif /* EM_ENGINE_BAD_ROLL */
4536 Xstone, TRUE, FALSE,
4540 Xstone_pause, FALSE, FALSE,
4544 Xstone_fall, FALSE, FALSE,
4548 Ystone_s, FALSE, FALSE,
4549 EL_ROCK, ACTION_FALLING, -1
4552 Ystone_sB, FALSE, TRUE,
4553 EL_ROCK, ACTION_FALLING, -1
4556 Ystone_e, FALSE, FALSE,
4557 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
4560 Ystone_eB, FALSE, TRUE,
4561 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
4564 Ystone_w, FALSE, FALSE,
4565 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
4568 Ystone_wB, FALSE, TRUE,
4569 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
4576 Xnut_pause, FALSE, FALSE,
4580 Xnut_fall, FALSE, FALSE,
4584 Ynut_s, FALSE, FALSE,
4585 EL_NUT, ACTION_FALLING, -1
4588 Ynut_sB, FALSE, TRUE,
4589 EL_NUT, ACTION_FALLING, -1
4592 Ynut_e, FALSE, FALSE,
4593 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
4596 Ynut_eB, FALSE, TRUE,
4597 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
4600 Ynut_w, FALSE, FALSE,
4601 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
4604 Ynut_wB, FALSE, TRUE,
4605 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
4608 Xbug_n, TRUE, FALSE,
4612 Xbug_e, TRUE, FALSE,
4613 EL_BUG_RIGHT, -1, -1
4616 Xbug_s, TRUE, FALSE,
4620 Xbug_w, TRUE, FALSE,
4624 Xbug_gon, FALSE, FALSE,
4628 Xbug_goe, FALSE, FALSE,
4629 EL_BUG_RIGHT, -1, -1
4632 Xbug_gos, FALSE, FALSE,
4636 Xbug_gow, FALSE, FALSE,
4640 Ybug_n, FALSE, FALSE,
4641 EL_BUG, ACTION_MOVING, MV_BIT_UP
4644 Ybug_nB, FALSE, TRUE,
4645 EL_BUG, ACTION_MOVING, MV_BIT_UP
4648 Ybug_e, FALSE, FALSE,
4649 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
4652 Ybug_eB, FALSE, TRUE,
4653 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
4656 Ybug_s, FALSE, FALSE,
4657 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
4660 Ybug_sB, FALSE, TRUE,
4661 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
4664 Ybug_w, FALSE, FALSE,
4665 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
4668 Ybug_wB, FALSE, TRUE,
4669 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
4672 Ybug_w_n, FALSE, FALSE,
4673 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
4676 Ybug_n_e, FALSE, FALSE,
4677 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
4680 Ybug_e_s, FALSE, FALSE,
4681 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
4684 Ybug_s_w, FALSE, FALSE,
4685 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
4688 Ybug_e_n, FALSE, FALSE,
4689 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
4692 Ybug_s_e, FALSE, FALSE,
4693 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
4696 Ybug_w_s, FALSE, FALSE,
4697 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
4700 Ybug_n_w, FALSE, FALSE,
4701 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
4704 Ybug_stone, FALSE, FALSE,
4705 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
4708 Ybug_spring, FALSE, FALSE,
4709 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
4712 Xtank_n, TRUE, FALSE,
4713 EL_SPACESHIP_UP, -1, -1
4716 Xtank_e, TRUE, FALSE,
4717 EL_SPACESHIP_RIGHT, -1, -1
4720 Xtank_s, TRUE, FALSE,
4721 EL_SPACESHIP_DOWN, -1, -1
4724 Xtank_w, TRUE, FALSE,
4725 EL_SPACESHIP_LEFT, -1, -1
4728 Xtank_gon, FALSE, FALSE,
4729 EL_SPACESHIP_UP, -1, -1
4732 Xtank_goe, FALSE, FALSE,
4733 EL_SPACESHIP_RIGHT, -1, -1
4736 Xtank_gos, FALSE, FALSE,
4737 EL_SPACESHIP_DOWN, -1, -1
4740 Xtank_gow, FALSE, FALSE,
4741 EL_SPACESHIP_LEFT, -1, -1
4744 Ytank_n, FALSE, FALSE,
4745 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
4748 Ytank_nB, FALSE, TRUE,
4749 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
4752 Ytank_e, FALSE, FALSE,
4753 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
4756 Ytank_eB, FALSE, TRUE,
4757 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
4760 Ytank_s, FALSE, FALSE,
4761 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
4764 Ytank_sB, FALSE, TRUE,
4765 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
4768 Ytank_w, FALSE, FALSE,
4769 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
4772 Ytank_wB, FALSE, TRUE,
4773 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
4776 Ytank_w_n, FALSE, FALSE,
4777 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
4780 Ytank_n_e, FALSE, FALSE,
4781 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
4784 Ytank_e_s, FALSE, FALSE,
4785 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
4788 Ytank_s_w, FALSE, FALSE,
4789 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
4792 Ytank_e_n, FALSE, FALSE,
4793 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
4796 Ytank_s_e, FALSE, FALSE,
4797 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
4800 Ytank_w_s, FALSE, FALSE,
4801 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
4804 Ytank_n_w, FALSE, FALSE,
4805 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
4808 Ytank_stone, FALSE, FALSE,
4809 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
4812 Ytank_spring, FALSE, FALSE,
4813 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
4816 Xandroid, TRUE, FALSE,
4817 EL_EMC_ANDROID, ACTION_ACTIVE, -1
4820 Xandroid_1_n, FALSE, FALSE,
4821 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
4824 Xandroid_2_n, FALSE, FALSE,
4825 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
4828 Xandroid_1_e, FALSE, FALSE,
4829 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
4832 Xandroid_2_e, FALSE, FALSE,
4833 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
4836 Xandroid_1_w, FALSE, FALSE,
4837 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
4840 Xandroid_2_w, FALSE, FALSE,
4841 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
4844 Xandroid_1_s, FALSE, FALSE,
4845 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
4848 Xandroid_2_s, FALSE, FALSE,
4849 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
4852 Yandroid_n, FALSE, FALSE,
4853 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
4856 Yandroid_nB, FALSE, TRUE,
4857 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
4860 Yandroid_ne, FALSE, FALSE,
4861 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
4864 Yandroid_neB, FALSE, TRUE,
4865 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
4868 Yandroid_e, FALSE, FALSE,
4869 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
4872 Yandroid_eB, FALSE, TRUE,
4873 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
4876 Yandroid_se, FALSE, FALSE,
4877 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
4880 Yandroid_seB, FALSE, TRUE,
4881 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
4884 Yandroid_s, FALSE, FALSE,
4885 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
4888 Yandroid_sB, FALSE, TRUE,
4889 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
4892 Yandroid_sw, FALSE, FALSE,
4893 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
4896 Yandroid_swB, FALSE, TRUE,
4897 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
4900 Yandroid_w, FALSE, FALSE,
4901 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
4904 Yandroid_wB, FALSE, TRUE,
4905 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
4908 Yandroid_nw, FALSE, FALSE,
4909 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
4912 Yandroid_nwB, FALSE, TRUE,
4913 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
4916 Xspring, TRUE, FALSE,
4920 Xspring_pause, FALSE, FALSE,
4924 Xspring_e, FALSE, FALSE,
4928 Xspring_w, FALSE, FALSE,
4932 Xspring_fall, FALSE, FALSE,
4936 Yspring_s, FALSE, FALSE,
4937 EL_SPRING, ACTION_FALLING, -1
4940 Yspring_sB, FALSE, TRUE,
4941 EL_SPRING, ACTION_FALLING, -1
4944 Yspring_e, FALSE, FALSE,
4945 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
4948 Yspring_eB, FALSE, TRUE,
4949 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
4952 Yspring_w, FALSE, FALSE,
4953 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
4956 Yspring_wB, FALSE, TRUE,
4957 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
4960 Yspring_kill_e, FALSE, FALSE,
4961 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
4964 Yspring_kill_eB, FALSE, TRUE,
4965 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
4968 Yspring_kill_w, FALSE, FALSE,
4969 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
4972 Yspring_kill_wB, FALSE, TRUE,
4973 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
4976 Xeater_n, TRUE, FALSE,
4977 EL_YAMYAM_UP, -1, -1
4980 Xeater_e, TRUE, FALSE,
4981 EL_YAMYAM_RIGHT, -1, -1
4984 Xeater_w, TRUE, FALSE,
4985 EL_YAMYAM_LEFT, -1, -1
4988 Xeater_s, TRUE, FALSE,
4989 EL_YAMYAM_DOWN, -1, -1
4992 Yeater_n, FALSE, FALSE,
4993 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
4996 Yeater_nB, FALSE, TRUE,
4997 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
5000 Yeater_e, FALSE, FALSE,
5001 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
5004 Yeater_eB, FALSE, TRUE,
5005 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
5008 Yeater_s, FALSE, FALSE,
5009 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
5012 Yeater_sB, FALSE, TRUE,
5013 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
5016 Yeater_w, FALSE, FALSE,
5017 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
5020 Yeater_wB, FALSE, TRUE,
5021 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
5024 Yeater_stone, FALSE, FALSE,
5025 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
5028 Yeater_spring, FALSE, FALSE,
5029 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
5032 Xalien, TRUE, FALSE,
5036 Xalien_pause, FALSE, FALSE,
5040 Yalien_n, FALSE, FALSE,
5041 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
5044 Yalien_nB, FALSE, TRUE,
5045 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
5048 Yalien_e, FALSE, FALSE,
5049 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
5052 Yalien_eB, FALSE, TRUE,
5053 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
5056 Yalien_s, FALSE, FALSE,
5057 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
5060 Yalien_sB, FALSE, TRUE,
5061 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
5064 Yalien_w, FALSE, FALSE,
5065 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
5068 Yalien_wB, FALSE, TRUE,
5069 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
5072 Yalien_stone, FALSE, FALSE,
5073 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
5076 Yalien_spring, FALSE, FALSE,
5077 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
5080 Xemerald, TRUE, FALSE,
5084 Xemerald_pause, FALSE, FALSE,
5088 Xemerald_fall, FALSE, FALSE,
5092 Xemerald_shine, FALSE, FALSE,
5093 EL_EMERALD, ACTION_TWINKLING, -1
5096 Yemerald_s, FALSE, FALSE,
5097 EL_EMERALD, ACTION_FALLING, -1
5100 Yemerald_sB, FALSE, TRUE,
5101 EL_EMERALD, ACTION_FALLING, -1
5104 Yemerald_e, FALSE, FALSE,
5105 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
5108 Yemerald_eB, FALSE, TRUE,
5109 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
5112 Yemerald_w, FALSE, FALSE,
5113 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
5116 Yemerald_wB, FALSE, TRUE,
5117 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
5120 Yemerald_eat, FALSE, FALSE,
5121 EL_EMERALD, ACTION_COLLECTING, -1
5124 Yemerald_stone, FALSE, FALSE,
5125 EL_NUT, ACTION_BREAKING, -1
5128 Xdiamond, TRUE, FALSE,
5132 Xdiamond_pause, FALSE, FALSE,
5136 Xdiamond_fall, FALSE, FALSE,
5140 Xdiamond_shine, FALSE, FALSE,
5141 EL_DIAMOND, ACTION_TWINKLING, -1
5144 Ydiamond_s, FALSE, FALSE,
5145 EL_DIAMOND, ACTION_FALLING, -1
5148 Ydiamond_sB, FALSE, TRUE,
5149 EL_DIAMOND, ACTION_FALLING, -1
5152 Ydiamond_e, FALSE, FALSE,
5153 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
5156 Ydiamond_eB, FALSE, TRUE,
5157 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
5160 Ydiamond_w, FALSE, FALSE,
5161 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
5164 Ydiamond_wB, FALSE, TRUE,
5165 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
5168 Ydiamond_eat, FALSE, FALSE,
5169 EL_DIAMOND, ACTION_COLLECTING, -1
5172 Ydiamond_stone, FALSE, FALSE,
5173 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
5176 Xdrip_fall, TRUE, FALSE,
5177 EL_AMOEBA_DROP, -1, -1
5180 Xdrip_stretch, FALSE, FALSE,
5181 EL_AMOEBA_DROP, ACTION_FALLING, -1
5184 Xdrip_stretchB, FALSE, TRUE,
5185 EL_AMOEBA_DROP, ACTION_FALLING, -1
5188 Xdrip_eat, FALSE, FALSE,
5189 EL_AMOEBA_DROP, ACTION_GROWING, -1
5192 Ydrip_s1, FALSE, FALSE,
5193 EL_AMOEBA_DROP, ACTION_FALLING, -1
5196 Ydrip_s1B, FALSE, TRUE,
5197 EL_AMOEBA_DROP, ACTION_FALLING, -1
5200 Ydrip_s2, FALSE, FALSE,
5201 EL_AMOEBA_DROP, ACTION_FALLING, -1
5204 Ydrip_s2B, FALSE, TRUE,
5205 EL_AMOEBA_DROP, ACTION_FALLING, -1
5212 Xbomb_pause, FALSE, FALSE,
5216 Xbomb_fall, FALSE, FALSE,
5220 Ybomb_s, FALSE, FALSE,
5221 EL_BOMB, ACTION_FALLING, -1
5224 Ybomb_sB, FALSE, TRUE,
5225 EL_BOMB, ACTION_FALLING, -1
5228 Ybomb_e, FALSE, FALSE,
5229 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
5232 Ybomb_eB, FALSE, TRUE,
5233 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
5236 Ybomb_w, FALSE, FALSE,
5237 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
5240 Ybomb_wB, FALSE, TRUE,
5241 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
5244 Ybomb_eat, FALSE, FALSE,
5245 EL_BOMB, ACTION_ACTIVATING, -1
5248 Xballoon, TRUE, FALSE,
5252 Yballoon_n, FALSE, FALSE,
5253 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
5256 Yballoon_nB, FALSE, TRUE,
5257 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
5260 Yballoon_e, FALSE, FALSE,
5261 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
5264 Yballoon_eB, FALSE, TRUE,
5265 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
5268 Yballoon_s, FALSE, FALSE,
5269 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
5272 Yballoon_sB, FALSE, TRUE,
5273 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
5276 Yballoon_w, FALSE, FALSE,
5277 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
5280 Yballoon_wB, FALSE, TRUE,
5281 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
5284 Xgrass, TRUE, FALSE,
5285 EL_EMC_GRASS, -1, -1
5288 Ygrass_nB, FALSE, FALSE,
5289 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
5292 Ygrass_eB, FALSE, FALSE,
5293 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
5296 Ygrass_sB, FALSE, FALSE,
5297 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
5300 Ygrass_wB, FALSE, FALSE,
5301 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
5308 Ydirt_nB, FALSE, FALSE,
5309 EL_SAND, ACTION_DIGGING, MV_BIT_UP
5312 Ydirt_eB, FALSE, FALSE,
5313 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
5316 Ydirt_sB, FALSE, FALSE,
5317 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
5320 Ydirt_wB, FALSE, FALSE,
5321 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
5324 Xacid_ne, TRUE, FALSE,
5325 EL_ACID_POOL_TOPRIGHT, -1, -1
5328 Xacid_se, TRUE, FALSE,
5329 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
5332 Xacid_s, TRUE, FALSE,
5333 EL_ACID_POOL_BOTTOM, -1, -1
5336 Xacid_sw, TRUE, FALSE,
5337 EL_ACID_POOL_BOTTOMLEFT, -1, -1
5340 Xacid_nw, TRUE, FALSE,
5341 EL_ACID_POOL_TOPLEFT, -1, -1
5344 Xacid_1, TRUE, FALSE,
5348 Xacid_2, FALSE, FALSE,
5352 Xacid_3, FALSE, FALSE,
5356 Xacid_4, FALSE, FALSE,
5360 Xacid_5, FALSE, FALSE,
5364 Xacid_6, FALSE, FALSE,
5368 Xacid_7, FALSE, FALSE,
5372 Xacid_8, FALSE, FALSE,
5376 Xball_1, TRUE, FALSE,
5377 EL_EMC_MAGIC_BALL, -1, -1
5380 Xball_1B, FALSE, FALSE,
5381 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5384 Xball_2, FALSE, FALSE,
5385 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5388 Xball_2B, FALSE, FALSE,
5389 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5392 Yball_eat, FALSE, FALSE,
5393 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
5396 Ykey_1_eat, FALSE, FALSE,
5397 EL_EM_KEY_1, ACTION_COLLECTING, -1
5400 Ykey_2_eat, FALSE, FALSE,
5401 EL_EM_KEY_2, ACTION_COLLECTING, -1
5404 Ykey_3_eat, FALSE, FALSE,
5405 EL_EM_KEY_3, ACTION_COLLECTING, -1
5408 Ykey_4_eat, FALSE, FALSE,
5409 EL_EM_KEY_4, ACTION_COLLECTING, -1
5412 Ykey_5_eat, FALSE, FALSE,
5413 EL_EMC_KEY_5, ACTION_COLLECTING, -1
5416 Ykey_6_eat, FALSE, FALSE,
5417 EL_EMC_KEY_6, ACTION_COLLECTING, -1
5420 Ykey_7_eat, FALSE, FALSE,
5421 EL_EMC_KEY_7, ACTION_COLLECTING, -1
5424 Ykey_8_eat, FALSE, FALSE,
5425 EL_EMC_KEY_8, ACTION_COLLECTING, -1
5428 Ylenses_eat, FALSE, FALSE,
5429 EL_EMC_LENSES, ACTION_COLLECTING, -1
5432 Ymagnify_eat, FALSE, FALSE,
5433 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
5436 Ygrass_eat, FALSE, FALSE,
5437 EL_EMC_GRASS, ACTION_SNAPPING, -1
5440 Ydirt_eat, FALSE, FALSE,
5441 EL_SAND, ACTION_SNAPPING, -1
5444 Xgrow_ns, TRUE, FALSE,
5445 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
5448 Ygrow_ns_eat, FALSE, FALSE,
5449 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
5452 Xgrow_ew, TRUE, FALSE,
5453 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
5456 Ygrow_ew_eat, FALSE, FALSE,
5457 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
5460 Xwonderwall, TRUE, FALSE,
5461 EL_MAGIC_WALL, -1, -1
5464 XwonderwallB, FALSE, FALSE,
5465 EL_MAGIC_WALL, ACTION_ACTIVE, -1
5468 Xamoeba_1, TRUE, FALSE,
5469 EL_AMOEBA_DRY, ACTION_OTHER, -1
5472 Xamoeba_2, FALSE, FALSE,
5473 EL_AMOEBA_DRY, ACTION_OTHER, -1
5476 Xamoeba_3, FALSE, FALSE,
5477 EL_AMOEBA_DRY, ACTION_OTHER, -1
5480 Xamoeba_4, FALSE, FALSE,
5481 EL_AMOEBA_DRY, ACTION_OTHER, -1
5484 Xamoeba_5, TRUE, FALSE,
5485 EL_AMOEBA_WET, ACTION_OTHER, -1
5488 Xamoeba_6, FALSE, FALSE,
5489 EL_AMOEBA_WET, ACTION_OTHER, -1
5492 Xamoeba_7, FALSE, FALSE,
5493 EL_AMOEBA_WET, ACTION_OTHER, -1
5496 Xamoeba_8, FALSE, FALSE,
5497 EL_AMOEBA_WET, ACTION_OTHER, -1
5500 Xdoor_1, TRUE, FALSE,
5501 EL_EM_GATE_1, -1, -1
5504 Xdoor_2, TRUE, FALSE,
5505 EL_EM_GATE_2, -1, -1
5508 Xdoor_3, TRUE, FALSE,
5509 EL_EM_GATE_3, -1, -1
5512 Xdoor_4, TRUE, FALSE,
5513 EL_EM_GATE_4, -1, -1
5516 Xdoor_5, TRUE, FALSE,
5517 EL_EMC_GATE_5, -1, -1
5520 Xdoor_6, TRUE, FALSE,
5521 EL_EMC_GATE_6, -1, -1
5524 Xdoor_7, TRUE, FALSE,
5525 EL_EMC_GATE_7, -1, -1
5528 Xdoor_8, TRUE, FALSE,
5529 EL_EMC_GATE_8, -1, -1
5532 Xkey_1, TRUE, FALSE,
5536 Xkey_2, TRUE, FALSE,
5540 Xkey_3, TRUE, FALSE,
5544 Xkey_4, TRUE, FALSE,
5548 Xkey_5, TRUE, FALSE,
5549 EL_EMC_KEY_5, -1, -1
5552 Xkey_6, TRUE, FALSE,
5553 EL_EMC_KEY_6, -1, -1
5556 Xkey_7, TRUE, FALSE,
5557 EL_EMC_KEY_7, -1, -1
5560 Xkey_8, TRUE, FALSE,
5561 EL_EMC_KEY_8, -1, -1
5564 Xwind_n, TRUE, FALSE,
5565 EL_BALLOON_SWITCH_UP, -1, -1
5568 Xwind_e, TRUE, FALSE,
5569 EL_BALLOON_SWITCH_RIGHT, -1, -1
5572 Xwind_s, TRUE, FALSE,
5573 EL_BALLOON_SWITCH_DOWN, -1, -1
5576 Xwind_w, TRUE, FALSE,
5577 EL_BALLOON_SWITCH_LEFT, -1, -1
5580 Xwind_nesw, TRUE, FALSE,
5581 EL_BALLOON_SWITCH_ANY, -1, -1
5584 Xwind_stop, TRUE, FALSE,
5585 EL_BALLOON_SWITCH_NONE, -1, -1
5589 EL_EM_EXIT_CLOSED, -1, -1
5592 Xexit_1, TRUE, FALSE,
5593 EL_EM_EXIT_OPEN, -1, -1
5596 Xexit_2, FALSE, FALSE,
5597 EL_EM_EXIT_OPEN, -1, -1
5600 Xexit_3, FALSE, FALSE,
5601 EL_EM_EXIT_OPEN, -1, -1
5604 Xdynamite, TRUE, FALSE,
5605 EL_EM_DYNAMITE, -1, -1
5608 Ydynamite_eat, FALSE, FALSE,
5609 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
5612 Xdynamite_1, TRUE, FALSE,
5613 EL_EM_DYNAMITE_ACTIVE, -1, -1
5616 Xdynamite_2, FALSE, FALSE,
5617 EL_EM_DYNAMITE_ACTIVE, -1, -1
5620 Xdynamite_3, FALSE, FALSE,
5621 EL_EM_DYNAMITE_ACTIVE, -1, -1
5624 Xdynamite_4, FALSE, FALSE,
5625 EL_EM_DYNAMITE_ACTIVE, -1, -1
5628 Xbumper, TRUE, FALSE,
5629 EL_EMC_SPRING_BUMPER, -1, -1
5632 XbumperB, FALSE, FALSE,
5633 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
5636 Xwheel, TRUE, FALSE,
5637 EL_ROBOT_WHEEL, -1, -1
5640 XwheelB, FALSE, FALSE,
5641 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
5644 Xswitch, TRUE, FALSE,
5645 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
5648 XswitchB, FALSE, FALSE,
5649 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
5653 EL_QUICKSAND_EMPTY, -1, -1
5656 Xsand_stone, TRUE, FALSE,
5657 EL_QUICKSAND_FULL, -1, -1
5660 Xsand_stonein_1, FALSE, TRUE,
5661 EL_ROCK, ACTION_FILLING, -1
5664 Xsand_stonein_2, FALSE, TRUE,
5665 EL_ROCK, ACTION_FILLING, -1
5668 Xsand_stonein_3, FALSE, TRUE,
5669 EL_ROCK, ACTION_FILLING, -1
5672 Xsand_stonein_4, FALSE, TRUE,
5673 EL_ROCK, ACTION_FILLING, -1
5676 Xsand_stonesand_1, FALSE, FALSE,
5677 EL_QUICKSAND_EMPTYING, -1, -1
5680 Xsand_stonesand_2, FALSE, FALSE,
5681 EL_QUICKSAND_EMPTYING, -1, -1
5684 Xsand_stonesand_3, FALSE, FALSE,
5685 EL_QUICKSAND_EMPTYING, -1, -1
5688 Xsand_stonesand_4, FALSE, FALSE,
5689 EL_QUICKSAND_EMPTYING, -1, -1
5692 Xsand_stonesand_quickout_1, FALSE, FALSE,
5693 EL_QUICKSAND_EMPTYING, -1, -1
5696 Xsand_stonesand_quickout_2, FALSE, FALSE,
5697 EL_QUICKSAND_EMPTYING, -1, -1
5700 Xsand_stoneout_1, FALSE, FALSE,
5701 EL_ROCK, ACTION_EMPTYING, -1
5704 Xsand_stoneout_2, FALSE, FALSE,
5705 EL_ROCK, ACTION_EMPTYING, -1
5708 Xsand_sandstone_1, FALSE, FALSE,
5709 EL_QUICKSAND_FILLING, -1, -1
5712 Xsand_sandstone_2, FALSE, FALSE,
5713 EL_QUICKSAND_FILLING, -1, -1
5716 Xsand_sandstone_3, FALSE, FALSE,
5717 EL_QUICKSAND_FILLING, -1, -1
5720 Xsand_sandstone_4, FALSE, FALSE,
5721 EL_QUICKSAND_FILLING, -1, -1
5724 Xplant, TRUE, FALSE,
5725 EL_EMC_PLANT, -1, -1
5728 Yplant, FALSE, FALSE,
5729 EL_EMC_PLANT, -1, -1
5732 Xlenses, TRUE, FALSE,
5733 EL_EMC_LENSES, -1, -1
5736 Xmagnify, TRUE, FALSE,
5737 EL_EMC_MAGNIFIER, -1, -1
5740 Xdripper, TRUE, FALSE,
5741 EL_EMC_DRIPPER, -1, -1
5744 XdripperB, FALSE, FALSE,
5745 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
5748 Xfake_blank, TRUE, FALSE,
5749 EL_INVISIBLE_WALL, -1, -1
5752 Xfake_blankB, FALSE, FALSE,
5753 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
5756 Xfake_grass, TRUE, FALSE,
5757 EL_EMC_FAKE_GRASS, -1, -1
5760 Xfake_grassB, FALSE, FALSE,
5761 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
5764 Xfake_door_1, TRUE, FALSE,
5765 EL_EM_GATE_1_GRAY, -1, -1
5768 Xfake_door_2, TRUE, FALSE,
5769 EL_EM_GATE_2_GRAY, -1, -1
5772 Xfake_door_3, TRUE, FALSE,
5773 EL_EM_GATE_3_GRAY, -1, -1
5776 Xfake_door_4, TRUE, FALSE,
5777 EL_EM_GATE_4_GRAY, -1, -1
5780 Xfake_door_5, TRUE, FALSE,
5781 EL_EMC_GATE_5_GRAY, -1, -1
5784 Xfake_door_6, TRUE, FALSE,
5785 EL_EMC_GATE_6_GRAY, -1, -1
5788 Xfake_door_7, TRUE, FALSE,
5789 EL_EMC_GATE_7_GRAY, -1, -1
5792 Xfake_door_8, TRUE, FALSE,
5793 EL_EMC_GATE_8_GRAY, -1, -1
5796 Xfake_acid_1, TRUE, FALSE,
5797 EL_EMC_FAKE_ACID, -1, -1
5800 Xfake_acid_2, FALSE, FALSE,
5801 EL_EMC_FAKE_ACID, -1, -1
5804 Xfake_acid_3, FALSE, FALSE,
5805 EL_EMC_FAKE_ACID, -1, -1
5808 Xfake_acid_4, FALSE, FALSE,
5809 EL_EMC_FAKE_ACID, -1, -1
5812 Xfake_acid_5, FALSE, FALSE,
5813 EL_EMC_FAKE_ACID, -1, -1
5816 Xfake_acid_6, FALSE, FALSE,
5817 EL_EMC_FAKE_ACID, -1, -1
5820 Xfake_acid_7, FALSE, FALSE,
5821 EL_EMC_FAKE_ACID, -1, -1
5824 Xfake_acid_8, FALSE, FALSE,
5825 EL_EMC_FAKE_ACID, -1, -1
5828 Xsteel_1, TRUE, FALSE,
5829 EL_STEELWALL, -1, -1
5832 Xsteel_2, TRUE, FALSE,
5833 EL_EMC_STEELWALL_2, -1, -1
5836 Xsteel_3, TRUE, FALSE,
5837 EL_EMC_STEELWALL_3, -1, -1
5840 Xsteel_4, TRUE, FALSE,
5841 EL_EMC_STEELWALL_4, -1, -1
5844 Xwall_1, TRUE, FALSE,
5848 Xwall_2, TRUE, FALSE,
5849 EL_EMC_WALL_14, -1, -1
5852 Xwall_3, TRUE, FALSE,
5853 EL_EMC_WALL_15, -1, -1
5856 Xwall_4, TRUE, FALSE,
5857 EL_EMC_WALL_16, -1, -1
5860 Xround_wall_1, TRUE, FALSE,
5861 EL_WALL_SLIPPERY, -1, -1
5864 Xround_wall_2, TRUE, FALSE,
5865 EL_EMC_WALL_SLIPPERY_2, -1, -1
5868 Xround_wall_3, TRUE, FALSE,
5869 EL_EMC_WALL_SLIPPERY_3, -1, -1
5872 Xround_wall_4, TRUE, FALSE,
5873 EL_EMC_WALL_SLIPPERY_4, -1, -1
5876 Xdecor_1, TRUE, FALSE,
5877 EL_EMC_WALL_8, -1, -1
5880 Xdecor_2, TRUE, FALSE,
5881 EL_EMC_WALL_6, -1, -1
5884 Xdecor_3, TRUE, FALSE,
5885 EL_EMC_WALL_4, -1, -1
5888 Xdecor_4, TRUE, FALSE,
5889 EL_EMC_WALL_7, -1, -1
5892 Xdecor_5, TRUE, FALSE,
5893 EL_EMC_WALL_5, -1, -1
5896 Xdecor_6, TRUE, FALSE,
5897 EL_EMC_WALL_9, -1, -1
5900 Xdecor_7, TRUE, FALSE,
5901 EL_EMC_WALL_10, -1, -1
5904 Xdecor_8, TRUE, FALSE,
5905 EL_EMC_WALL_1, -1, -1
5908 Xdecor_9, TRUE, FALSE,
5909 EL_EMC_WALL_2, -1, -1
5912 Xdecor_10, TRUE, FALSE,
5913 EL_EMC_WALL_3, -1, -1
5916 Xdecor_11, TRUE, FALSE,
5917 EL_EMC_WALL_11, -1, -1
5920 Xdecor_12, TRUE, FALSE,
5921 EL_EMC_WALL_12, -1, -1
5924 Xalpha_0, TRUE, FALSE,
5925 EL_CHAR('0'), -1, -1
5928 Xalpha_1, TRUE, FALSE,
5929 EL_CHAR('1'), -1, -1
5932 Xalpha_2, TRUE, FALSE,
5933 EL_CHAR('2'), -1, -1
5936 Xalpha_3, TRUE, FALSE,
5937 EL_CHAR('3'), -1, -1
5940 Xalpha_4, TRUE, FALSE,
5941 EL_CHAR('4'), -1, -1
5944 Xalpha_5, TRUE, FALSE,
5945 EL_CHAR('5'), -1, -1
5948 Xalpha_6, TRUE, FALSE,
5949 EL_CHAR('6'), -1, -1
5952 Xalpha_7, TRUE, FALSE,
5953 EL_CHAR('7'), -1, -1
5956 Xalpha_8, TRUE, FALSE,
5957 EL_CHAR('8'), -1, -1
5960 Xalpha_9, TRUE, FALSE,
5961 EL_CHAR('9'), -1, -1
5964 Xalpha_excla, TRUE, FALSE,
5965 EL_CHAR('!'), -1, -1
5968 Xalpha_quote, TRUE, FALSE,
5969 EL_CHAR('"'), -1, -1
5972 Xalpha_comma, TRUE, FALSE,
5973 EL_CHAR(','), -1, -1
5976 Xalpha_minus, TRUE, FALSE,
5977 EL_CHAR('-'), -1, -1
5980 Xalpha_perio, TRUE, FALSE,
5981 EL_CHAR('.'), -1, -1
5984 Xalpha_colon, TRUE, FALSE,
5985 EL_CHAR(':'), -1, -1
5988 Xalpha_quest, TRUE, FALSE,
5989 EL_CHAR('?'), -1, -1
5992 Xalpha_a, TRUE, FALSE,
5993 EL_CHAR('A'), -1, -1
5996 Xalpha_b, TRUE, FALSE,
5997 EL_CHAR('B'), -1, -1
6000 Xalpha_c, TRUE, FALSE,
6001 EL_CHAR('C'), -1, -1
6004 Xalpha_d, TRUE, FALSE,
6005 EL_CHAR('D'), -1, -1
6008 Xalpha_e, TRUE, FALSE,
6009 EL_CHAR('E'), -1, -1
6012 Xalpha_f, TRUE, FALSE,
6013 EL_CHAR('F'), -1, -1
6016 Xalpha_g, TRUE, FALSE,
6017 EL_CHAR('G'), -1, -1
6020 Xalpha_h, TRUE, FALSE,
6021 EL_CHAR('H'), -1, -1
6024 Xalpha_i, TRUE, FALSE,
6025 EL_CHAR('I'), -1, -1
6028 Xalpha_j, TRUE, FALSE,
6029 EL_CHAR('J'), -1, -1
6032 Xalpha_k, TRUE, FALSE,
6033 EL_CHAR('K'), -1, -1
6036 Xalpha_l, TRUE, FALSE,
6037 EL_CHAR('L'), -1, -1
6040 Xalpha_m, TRUE, FALSE,
6041 EL_CHAR('M'), -1, -1
6044 Xalpha_n, TRUE, FALSE,
6045 EL_CHAR('N'), -1, -1
6048 Xalpha_o, TRUE, FALSE,
6049 EL_CHAR('O'), -1, -1
6052 Xalpha_p, TRUE, FALSE,
6053 EL_CHAR('P'), -1, -1
6056 Xalpha_q, TRUE, FALSE,
6057 EL_CHAR('Q'), -1, -1
6060 Xalpha_r, TRUE, FALSE,
6061 EL_CHAR('R'), -1, -1
6064 Xalpha_s, TRUE, FALSE,
6065 EL_CHAR('S'), -1, -1
6068 Xalpha_t, TRUE, FALSE,
6069 EL_CHAR('T'), -1, -1
6072 Xalpha_u, TRUE, FALSE,
6073 EL_CHAR('U'), -1, -1
6076 Xalpha_v, TRUE, FALSE,
6077 EL_CHAR('V'), -1, -1
6080 Xalpha_w, TRUE, FALSE,
6081 EL_CHAR('W'), -1, -1
6084 Xalpha_x, TRUE, FALSE,
6085 EL_CHAR('X'), -1, -1
6088 Xalpha_y, TRUE, FALSE,
6089 EL_CHAR('Y'), -1, -1
6092 Xalpha_z, TRUE, FALSE,
6093 EL_CHAR('Z'), -1, -1
6096 Xalpha_arrow_e, TRUE, FALSE,
6097 EL_CHAR('>'), -1, -1
6100 Xalpha_arrow_w, TRUE, FALSE,
6101 EL_CHAR('<'), -1, -1
6104 Xalpha_copyr, TRUE, FALSE,
6105 EL_CHAR(CHAR_BYTE_COPYRIGHT), -1, -1
6109 Xboom_bug, FALSE, FALSE,
6110 EL_BUG, ACTION_EXPLODING, -1
6113 Xboom_bomb, FALSE, FALSE,
6114 EL_BOMB, ACTION_EXPLODING, -1
6117 Xboom_android, FALSE, FALSE,
6118 EL_EMC_ANDROID, ACTION_OTHER, -1
6121 Xboom_1, FALSE, FALSE,
6122 EL_DEFAULT, ACTION_EXPLODING, -1
6125 Xboom_2, FALSE, FALSE,
6126 EL_DEFAULT, ACTION_EXPLODING, -1
6129 Znormal, FALSE, FALSE,
6133 Zdynamite, FALSE, FALSE,
6137 Zplayer, FALSE, FALSE,
6141 ZBORDER, FALSE, FALSE,
6151 static struct Mapping_EM_to_RND_player
6160 em_player_mapping_list[] =
6164 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
6168 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
6172 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
6176 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
6180 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
6184 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
6188 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
6192 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
6196 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
6200 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
6204 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
6208 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
6212 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
6216 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
6220 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
6224 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
6228 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
6232 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
6236 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
6240 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
6244 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
6248 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
6252 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
6256 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
6260 EL_PLAYER_1, ACTION_DEFAULT, -1,
6264 EL_PLAYER_2, ACTION_DEFAULT, -1,
6268 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
6272 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
6276 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
6280 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
6284 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
6288 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
6292 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
6296 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
6300 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
6304 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
6308 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
6312 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
6316 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
6320 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
6324 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
6328 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
6332 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
6336 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
6340 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
6344 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
6348 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
6352 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
6356 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
6360 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
6364 EL_PLAYER_3, ACTION_DEFAULT, -1,
6368 EL_PLAYER_4, ACTION_DEFAULT, -1,
6377 int map_element_RND_to_EM(int element_rnd)
6379 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
6380 static boolean mapping_initialized = FALSE;
6382 if (!mapping_initialized)
6386 /* return "Xalpha_quest" for all undefined elements in mapping array */
6387 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
6388 mapping_RND_to_EM[i] = Xalpha_quest;
6390 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6391 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
6392 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
6393 em_object_mapping_list[i].element_em;
6395 mapping_initialized = TRUE;
6398 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
6399 return mapping_RND_to_EM[element_rnd];
6401 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
6406 int map_element_EM_to_RND(int element_em)
6408 static unsigned short mapping_EM_to_RND[TILE_MAX];
6409 static boolean mapping_initialized = FALSE;
6411 if (!mapping_initialized)
6415 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
6416 for (i = 0; i < TILE_MAX; i++)
6417 mapping_EM_to_RND[i] = EL_UNKNOWN;
6419 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6420 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
6421 em_object_mapping_list[i].element_rnd;
6423 mapping_initialized = TRUE;
6426 if (element_em >= 0 && element_em < TILE_MAX)
6427 return mapping_EM_to_RND[element_em];
6429 Error(ERR_WARN, "invalid EM level element %d", element_em);
6434 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
6436 struct LevelInfo_EM *level_em = level->native_em_level;
6437 struct LEVEL *lev = level_em->lev;
6440 for (i = 0; i < TILE_MAX; i++)
6441 lev->android_array[i] = Xblank;
6443 for (i = 0; i < level->num_android_clone_elements; i++)
6445 int element_rnd = level->android_clone_element[i];
6446 int element_em = map_element_RND_to_EM(element_rnd);
6448 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
6449 if (em_object_mapping_list[j].element_rnd == element_rnd)
6450 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
6454 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
6456 struct LevelInfo_EM *level_em = level->native_em_level;
6457 struct LEVEL *lev = level_em->lev;
6460 level->num_android_clone_elements = 0;
6462 for (i = 0; i < TILE_MAX; i++)
6464 int element_em = lev->android_array[i];
6466 boolean element_found = FALSE;
6468 if (element_em == Xblank)
6471 element_rnd = map_element_EM_to_RND(element_em);
6473 for (j = 0; j < level->num_android_clone_elements; j++)
6474 if (level->android_clone_element[j] == element_rnd)
6475 element_found = TRUE;
6479 level->android_clone_element[level->num_android_clone_elements++] =
6482 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
6487 if (level->num_android_clone_elements == 0)
6489 level->num_android_clone_elements = 1;
6490 level->android_clone_element[0] = EL_EMPTY;
6494 int map_direction_RND_to_EM(int direction)
6496 return (direction == MV_UP ? 0 :
6497 direction == MV_RIGHT ? 1 :
6498 direction == MV_DOWN ? 2 :
6499 direction == MV_LEFT ? 3 :
6503 int map_direction_EM_to_RND(int direction)
6505 return (direction == 0 ? MV_UP :
6506 direction == 1 ? MV_RIGHT :
6507 direction == 2 ? MV_DOWN :
6508 direction == 3 ? MV_LEFT :
6512 int map_element_RND_to_SP(int element_rnd)
6514 int element_sp = 0x20; /* map unknown elements to yellow "hardware" */
6516 if (element_rnd >= EL_SP_START &&
6517 element_rnd <= EL_SP_END)
6518 element_sp = element_rnd - EL_SP_START;
6519 else if (element_rnd == EL_EMPTY_SPACE)
6521 else if (element_rnd == EL_INVISIBLE_WALL)
6527 int map_element_SP_to_RND(int element_sp)
6529 int element_rnd = EL_UNKNOWN;
6531 if (element_sp >= 0x00 &&
6533 element_rnd = EL_SP_START + element_sp;
6534 else if (element_sp == 0x28)
6535 element_rnd = EL_INVISIBLE_WALL;
6540 int map_action_SP_to_RND(int action_sp)
6544 case actActive: return ACTION_ACTIVE;
6545 case actImpact: return ACTION_IMPACT;
6546 case actExploding: return ACTION_EXPLODING;
6547 case actDigging: return ACTION_DIGGING;
6548 case actSnapping: return ACTION_SNAPPING;
6549 case actCollecting: return ACTION_COLLECTING;
6550 case actPassing: return ACTION_PASSING;
6551 case actPushing: return ACTION_PUSHING;
6552 case actDropping: return ACTION_DROPPING;
6554 default: return ACTION_DEFAULT;
6558 int get_next_element(int element)
6562 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
6563 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
6564 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
6565 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
6566 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
6567 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
6568 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
6569 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
6570 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
6571 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
6572 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
6574 default: return element;
6578 int el_act_dir2img(int element, int action, int direction)
6580 element = GFX_ELEMENT(element);
6581 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
6583 /* direction_graphic[][] == graphic[] for undefined direction graphics */
6584 return element_info[element].direction_graphic[action][direction];
6587 static int el_act_dir2crm(int element, int action, int direction)
6589 element = GFX_ELEMENT(element);
6590 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
6592 /* direction_graphic[][] == graphic[] for undefined direction graphics */
6593 return element_info[element].direction_crumbled[action][direction];
6596 int el_act2img(int element, int action)
6598 element = GFX_ELEMENT(element);
6600 return element_info[element].graphic[action];
6603 int el_act2crm(int element, int action)
6605 element = GFX_ELEMENT(element);
6607 return element_info[element].crumbled[action];
6610 int el_dir2img(int element, int direction)
6612 element = GFX_ELEMENT(element);
6614 return el_act_dir2img(element, ACTION_DEFAULT, direction);
6617 int el2baseimg(int element)
6619 return element_info[element].graphic[ACTION_DEFAULT];
6622 int el2img(int element)
6624 element = GFX_ELEMENT(element);
6626 return element_info[element].graphic[ACTION_DEFAULT];
6629 int el2edimg(int element)
6631 element = GFX_ELEMENT(element);
6633 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
6636 int el2preimg(int element)
6638 element = GFX_ELEMENT(element);
6640 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
6643 int el2panelimg(int element)
6645 element = GFX_ELEMENT(element);
6647 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL];
6650 int font2baseimg(int font_nr)
6652 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
6655 int getBeltNrFromBeltElement(int element)
6657 return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
6658 element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
6659 element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
6662 int getBeltNrFromBeltActiveElement(int element)
6664 return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
6665 element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
6666 element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
6669 int getBeltNrFromBeltSwitchElement(int element)
6671 return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
6672 element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
6673 element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
6676 int getBeltDirNrFromBeltElement(int element)
6678 static int belt_base_element[4] =
6680 EL_CONVEYOR_BELT_1_LEFT,
6681 EL_CONVEYOR_BELT_2_LEFT,
6682 EL_CONVEYOR_BELT_3_LEFT,
6683 EL_CONVEYOR_BELT_4_LEFT
6686 int belt_nr = getBeltNrFromBeltElement(element);
6687 int belt_dir_nr = element - belt_base_element[belt_nr];
6689 return (belt_dir_nr % 3);
6692 int getBeltDirNrFromBeltSwitchElement(int element)
6694 static int belt_base_element[4] =
6696 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
6697 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
6698 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
6699 EL_CONVEYOR_BELT_4_SWITCH_LEFT
6702 int belt_nr = getBeltNrFromBeltSwitchElement(element);
6703 int belt_dir_nr = element - belt_base_element[belt_nr];
6705 return (belt_dir_nr % 3);
6708 int getBeltDirFromBeltElement(int element)
6710 static int belt_move_dir[3] =
6717 int belt_dir_nr = getBeltDirNrFromBeltElement(element);
6719 return belt_move_dir[belt_dir_nr];
6722 int getBeltDirFromBeltSwitchElement(int element)
6724 static int belt_move_dir[3] =
6731 int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
6733 return belt_move_dir[belt_dir_nr];
6736 int getBeltElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
6738 static int belt_base_element[4] =
6740 EL_CONVEYOR_BELT_1_LEFT,
6741 EL_CONVEYOR_BELT_2_LEFT,
6742 EL_CONVEYOR_BELT_3_LEFT,
6743 EL_CONVEYOR_BELT_4_LEFT
6746 return belt_base_element[belt_nr] + belt_dir_nr;
6749 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
6751 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
6753 return getBeltElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
6756 int getBeltSwitchElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
6758 static int belt_base_element[4] =
6760 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
6761 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
6762 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
6763 EL_CONVEYOR_BELT_4_SWITCH_LEFT
6766 return belt_base_element[belt_nr] + belt_dir_nr;
6769 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
6771 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
6773 return getBeltSwitchElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
6776 boolean getTeamMode_EM()
6778 return game.team_mode;
6781 int getGameFrameDelay_EM(int native_em_game_frame_delay)
6783 int game_frame_delay_value;
6785 game_frame_delay_value =
6786 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
6787 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
6790 if (tape.playing && tape.warp_forward && !tape.pausing)
6791 game_frame_delay_value = 0;
6793 return game_frame_delay_value;
6796 unsigned int InitRND(int seed)
6798 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
6799 return InitEngineRandom_EM(seed);
6800 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
6801 return InitEngineRandom_SP(seed);
6803 return InitEngineRandom_RND(seed);
6806 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
6807 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
6809 inline static int get_effective_element_EM(int tile, int frame_em)
6811 int element = object_mapping[tile].element_rnd;
6812 int action = object_mapping[tile].action;
6813 boolean is_backside = object_mapping[tile].is_backside;
6814 boolean action_removing = (action == ACTION_DIGGING ||
6815 action == ACTION_SNAPPING ||
6816 action == ACTION_COLLECTING);
6822 case Yacid_splash_eB:
6823 case Yacid_splash_wB:
6824 return (frame_em > 5 ? EL_EMPTY : element);
6830 else /* frame_em == 7 */
6834 case Yacid_splash_eB:
6835 case Yacid_splash_wB:
6838 case Yemerald_stone:
6841 case Ydiamond_stone:
6845 case Xdrip_stretchB:
6864 case Xsand_stonein_1:
6865 case Xsand_stonein_2:
6866 case Xsand_stonein_3:
6867 case Xsand_stonein_4:
6871 return (is_backside || action_removing ? EL_EMPTY : element);
6876 inline static boolean check_linear_animation_EM(int tile)
6880 case Xsand_stonesand_1:
6881 case Xsand_stonesand_quickout_1:
6882 case Xsand_sandstone_1:
6883 case Xsand_stonein_1:
6884 case Xsand_stoneout_1:
6903 case Yacid_splash_eB:
6904 case Yacid_splash_wB:
6905 case Yemerald_stone:
6912 inline static void set_crumbled_graphics_EM(struct GraphicInfo_EM *g_em,
6913 boolean has_crumbled_graphics,
6914 int crumbled, int sync_frame)
6916 /* if element can be crumbled, but certain action graphics are just empty
6917 space (like instantly snapping sand to empty space in 1 frame), do not
6918 treat these empty space graphics as crumbled graphics in EMC engine */
6919 if (crumbled == IMG_EMPTY_SPACE)
6920 has_crumbled_graphics = FALSE;
6922 if (has_crumbled_graphics)
6924 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
6925 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
6926 g_crumbled->anim_delay,
6927 g_crumbled->anim_mode,
6928 g_crumbled->anim_start_frame,
6931 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
6932 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
6934 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
6936 g_em->has_crumbled_graphics = TRUE;
6940 g_em->crumbled_bitmap = NULL;
6941 g_em->crumbled_src_x = 0;
6942 g_em->crumbled_src_y = 0;
6943 g_em->crumbled_border_size = 0;
6945 g_em->has_crumbled_graphics = FALSE;
6949 void ResetGfxAnimation_EM(int x, int y, int tile)
6954 void SetGfxAnimation_EM(struct GraphicInfo_EM *g_em,
6955 int tile, int frame_em, int x, int y)
6957 int action = object_mapping[tile].action;
6958 int direction = object_mapping[tile].direction;
6959 int effective_element = get_effective_element_EM(tile, frame_em);
6960 int graphic = (direction == MV_NONE ?
6961 el_act2img(effective_element, action) :
6962 el_act_dir2img(effective_element, action, direction));
6963 struct GraphicInfo *g = &graphic_info[graphic];
6965 boolean action_removing = (action == ACTION_DIGGING ||
6966 action == ACTION_SNAPPING ||
6967 action == ACTION_COLLECTING);
6968 boolean action_moving = (action == ACTION_FALLING ||
6969 action == ACTION_MOVING ||
6970 action == ACTION_PUSHING ||
6971 action == ACTION_EATING ||
6972 action == ACTION_FILLING ||
6973 action == ACTION_EMPTYING);
6974 boolean action_falling = (action == ACTION_FALLING ||
6975 action == ACTION_FILLING ||
6976 action == ACTION_EMPTYING);
6978 /* special case: graphic uses "2nd movement tile" and has defined
6979 7 frames for movement animation (or less) => use default graphic
6980 for last (8th) frame which ends the movement animation */
6981 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
6983 action = ACTION_DEFAULT; /* (keep action_* unchanged for now) */
6984 graphic = (direction == MV_NONE ?
6985 el_act2img(effective_element, action) :
6986 el_act_dir2img(effective_element, action, direction));
6988 g = &graphic_info[graphic];
6991 if ((action_removing || check_linear_animation_EM(tile)) && frame_em == 0)
6995 else if (action_moving)
6997 boolean is_backside = object_mapping[tile].is_backside;
7001 int direction = object_mapping[tile].direction;
7002 int move_dir = (action_falling ? MV_DOWN : direction);
7007 /* !!! TEST !!! NEW !!! DOES NOT WORK RIGHT YET !!! */
7008 if (g->double_movement && frame_em == 0)
7012 if (move_dir == MV_LEFT)
7013 GfxFrame[x - 1][y] = GfxFrame[x][y];
7014 else if (move_dir == MV_RIGHT)
7015 GfxFrame[x + 1][y] = GfxFrame[x][y];
7016 else if (move_dir == MV_UP)
7017 GfxFrame[x][y - 1] = GfxFrame[x][y];
7018 else if (move_dir == MV_DOWN)
7019 GfxFrame[x][y + 1] = GfxFrame[x][y];
7026 /* special case: animation for Xsand_stonesand_quickout_1/2 twice as fast */
7027 if (tile == Xsand_stonesand_quickout_1 ||
7028 tile == Xsand_stonesand_quickout_2)
7032 if (graphic_info[graphic].anim_global_sync)
7033 sync_frame = FrameCounter;
7034 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
7035 sync_frame = GfxFrame[x][y];
7037 sync_frame = 0; /* playfield border (pseudo steel) */
7039 SetRandomAnimationValue(x, y);
7041 int frame = getAnimationFrame(g->anim_frames,
7044 g->anim_start_frame,
7047 g_em->unique_identifier =
7048 (graphic << 16) | ((frame % 8) << 12) | (g_em->width << 6) | g_em->height;
7051 void getGraphicSourceObjectExt_EM(struct GraphicInfo_EM *g_em,
7052 int tile, int frame_em, int x, int y)
7054 int action = object_mapping[tile].action;
7055 int direction = object_mapping[tile].direction;
7056 boolean is_backside = object_mapping[tile].is_backside;
7057 int effective_element = get_effective_element_EM(tile, frame_em);
7058 int effective_action = action;
7059 int graphic = (direction == MV_NONE ?
7060 el_act2img(effective_element, effective_action) :
7061 el_act_dir2img(effective_element, effective_action,
7063 int crumbled = (direction == MV_NONE ?
7064 el_act2crm(effective_element, effective_action) :
7065 el_act_dir2crm(effective_element, effective_action,
7067 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7068 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7069 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7070 struct GraphicInfo *g = &graphic_info[graphic];
7073 /* special case: graphic uses "2nd movement tile" and has defined
7074 7 frames for movement animation (or less) => use default graphic
7075 for last (8th) frame which ends the movement animation */
7076 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
7078 effective_action = ACTION_DEFAULT;
7079 graphic = (direction == MV_NONE ?
7080 el_act2img(effective_element, effective_action) :
7081 el_act_dir2img(effective_element, effective_action,
7083 crumbled = (direction == MV_NONE ?
7084 el_act2crm(effective_element, effective_action) :
7085 el_act_dir2crm(effective_element, effective_action,
7088 g = &graphic_info[graphic];
7091 if (graphic_info[graphic].anim_global_sync)
7092 sync_frame = FrameCounter;
7093 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
7094 sync_frame = GfxFrame[x][y];
7096 sync_frame = 0; /* playfield border (pseudo steel) */
7098 SetRandomAnimationValue(x, y);
7100 int frame = getAnimationFrame(g->anim_frames,
7103 g->anim_start_frame,
7106 getGraphicSourceExt(graphic, frame, &g_em->bitmap, &g_em->src_x, &g_em->src_y,
7107 g->double_movement && is_backside);
7109 /* (updating the "crumbled" graphic definitions is probably not really needed,
7110 as animations for crumbled graphics can't be longer than one EMC cycle) */
7111 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
7115 void getGraphicSourcePlayerExt_EM(struct GraphicInfo_EM *g_em,
7116 int player_nr, int anim, int frame_em)
7118 int element = player_mapping[player_nr][anim].element_rnd;
7119 int action = player_mapping[player_nr][anim].action;
7120 int direction = player_mapping[player_nr][anim].direction;
7121 int graphic = (direction == MV_NONE ?
7122 el_act2img(element, action) :
7123 el_act_dir2img(element, action, direction));
7124 struct GraphicInfo *g = &graphic_info[graphic];
7127 InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
7129 stored_player[player_nr].StepFrame = frame_em;
7131 sync_frame = stored_player[player_nr].Frame;
7133 int frame = getAnimationFrame(g->anim_frames,
7136 g->anim_start_frame,
7139 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
7140 &g_em->src_x, &g_em->src_y, FALSE);
7143 void InitGraphicInfo_EM(void)
7148 int num_em_gfx_errors = 0;
7150 if (graphic_info_em_object[0][0].bitmap == NULL)
7152 /* EM graphics not yet initialized in em_open_all() */
7157 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
7160 /* always start with reliable default values */
7161 for (i = 0; i < TILE_MAX; i++)
7163 object_mapping[i].element_rnd = EL_UNKNOWN;
7164 object_mapping[i].is_backside = FALSE;
7165 object_mapping[i].action = ACTION_DEFAULT;
7166 object_mapping[i].direction = MV_NONE;
7169 /* always start with reliable default values */
7170 for (p = 0; p < MAX_PLAYERS; p++)
7172 for (i = 0; i < SPR_MAX; i++)
7174 player_mapping[p][i].element_rnd = EL_UNKNOWN;
7175 player_mapping[p][i].action = ACTION_DEFAULT;
7176 player_mapping[p][i].direction = MV_NONE;
7180 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
7182 int e = em_object_mapping_list[i].element_em;
7184 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
7185 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
7187 if (em_object_mapping_list[i].action != -1)
7188 object_mapping[e].action = em_object_mapping_list[i].action;
7190 if (em_object_mapping_list[i].direction != -1)
7191 object_mapping[e].direction =
7192 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
7195 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
7197 int a = em_player_mapping_list[i].action_em;
7198 int p = em_player_mapping_list[i].player_nr;
7200 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
7202 if (em_player_mapping_list[i].action != -1)
7203 player_mapping[p][a].action = em_player_mapping_list[i].action;
7205 if (em_player_mapping_list[i].direction != -1)
7206 player_mapping[p][a].direction =
7207 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
7210 for (i = 0; i < TILE_MAX; i++)
7212 int element = object_mapping[i].element_rnd;
7213 int action = object_mapping[i].action;
7214 int direction = object_mapping[i].direction;
7215 boolean is_backside = object_mapping[i].is_backside;
7216 boolean action_exploding = ((action == ACTION_EXPLODING ||
7217 action == ACTION_SMASHED_BY_ROCK ||
7218 action == ACTION_SMASHED_BY_SPRING) &&
7219 element != EL_DIAMOND);
7220 boolean action_active = (action == ACTION_ACTIVE);
7221 boolean action_other = (action == ACTION_OTHER);
7223 for (j = 0; j < 8; j++)
7225 int effective_element = get_effective_element_EM(i, j);
7226 int effective_action = (j < 7 ? action :
7227 i == Xdrip_stretch ? action :
7228 i == Xdrip_stretchB ? action :
7229 i == Ydrip_s1 ? action :
7230 i == Ydrip_s1B ? action :
7231 i == Xball_1B ? action :
7232 i == Xball_2 ? action :
7233 i == Xball_2B ? action :
7234 i == Yball_eat ? action :
7235 i == Ykey_1_eat ? action :
7236 i == Ykey_2_eat ? action :
7237 i == Ykey_3_eat ? action :
7238 i == Ykey_4_eat ? action :
7239 i == Ykey_5_eat ? action :
7240 i == Ykey_6_eat ? action :
7241 i == Ykey_7_eat ? action :
7242 i == Ykey_8_eat ? action :
7243 i == Ylenses_eat ? action :
7244 i == Ymagnify_eat ? action :
7245 i == Ygrass_eat ? action :
7246 i == Ydirt_eat ? action :
7247 i == Xsand_stonein_1 ? action :
7248 i == Xsand_stonein_2 ? action :
7249 i == Xsand_stonein_3 ? action :
7250 i == Xsand_stonein_4 ? action :
7251 i == Xsand_stoneout_1 ? action :
7252 i == Xsand_stoneout_2 ? action :
7253 i == Xboom_android ? ACTION_EXPLODING :
7254 action_exploding ? ACTION_EXPLODING :
7255 action_active ? action :
7256 action_other ? action :
7258 int graphic = (el_act_dir2img(effective_element, effective_action,
7260 int crumbled = (el_act_dir2crm(effective_element, effective_action,
7262 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7263 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7264 boolean has_action_graphics = (graphic != base_graphic);
7265 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7266 struct GraphicInfo *g = &graphic_info[graphic];
7267 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7270 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
7271 boolean special_animation = (action != ACTION_DEFAULT &&
7272 g->anim_frames == 3 &&
7273 g->anim_delay == 2 &&
7274 g->anim_mode & ANIM_LINEAR);
7275 int sync_frame = (i == Xdrip_stretch ? 7 :
7276 i == Xdrip_stretchB ? 7 :
7277 i == Ydrip_s2 ? j + 8 :
7278 i == Ydrip_s2B ? j + 8 :
7287 i == Xfake_acid_1 ? 0 :
7288 i == Xfake_acid_2 ? 10 :
7289 i == Xfake_acid_3 ? 20 :
7290 i == Xfake_acid_4 ? 30 :
7291 i == Xfake_acid_5 ? 40 :
7292 i == Xfake_acid_6 ? 50 :
7293 i == Xfake_acid_7 ? 60 :
7294 i == Xfake_acid_8 ? 70 :
7296 i == Xball_2B ? j + 8 :
7297 i == Yball_eat ? j + 1 :
7298 i == Ykey_1_eat ? j + 1 :
7299 i == Ykey_2_eat ? j + 1 :
7300 i == Ykey_3_eat ? j + 1 :
7301 i == Ykey_4_eat ? j + 1 :
7302 i == Ykey_5_eat ? j + 1 :
7303 i == Ykey_6_eat ? j + 1 :
7304 i == Ykey_7_eat ? j + 1 :
7305 i == Ykey_8_eat ? j + 1 :
7306 i == Ylenses_eat ? j + 1 :
7307 i == Ymagnify_eat ? j + 1 :
7308 i == Ygrass_eat ? j + 1 :
7309 i == Ydirt_eat ? j + 1 :
7310 i == Xamoeba_1 ? 0 :
7311 i == Xamoeba_2 ? 1 :
7312 i == Xamoeba_3 ? 2 :
7313 i == Xamoeba_4 ? 3 :
7314 i == Xamoeba_5 ? 0 :
7315 i == Xamoeba_6 ? 1 :
7316 i == Xamoeba_7 ? 2 :
7317 i == Xamoeba_8 ? 3 :
7318 i == Xexit_2 ? j + 8 :
7319 i == Xexit_3 ? j + 16 :
7320 i == Xdynamite_1 ? 0 :
7321 i == Xdynamite_2 ? 8 :
7322 i == Xdynamite_3 ? 16 :
7323 i == Xdynamite_4 ? 24 :
7324 i == Xsand_stonein_1 ? j + 1 :
7325 i == Xsand_stonein_2 ? j + 9 :
7326 i == Xsand_stonein_3 ? j + 17 :
7327 i == Xsand_stonein_4 ? j + 25 :
7328 i == Xsand_stoneout_1 && j == 0 ? 0 :
7329 i == Xsand_stoneout_1 && j == 1 ? 0 :
7330 i == Xsand_stoneout_1 && j == 2 ? 1 :
7331 i == Xsand_stoneout_1 && j == 3 ? 2 :
7332 i == Xsand_stoneout_1 && j == 4 ? 2 :
7333 i == Xsand_stoneout_1 && j == 5 ? 3 :
7334 i == Xsand_stoneout_1 && j == 6 ? 4 :
7335 i == Xsand_stoneout_1 && j == 7 ? 4 :
7336 i == Xsand_stoneout_2 && j == 0 ? 5 :
7337 i == Xsand_stoneout_2 && j == 1 ? 6 :
7338 i == Xsand_stoneout_2 && j == 2 ? 7 :
7339 i == Xsand_stoneout_2 && j == 3 ? 8 :
7340 i == Xsand_stoneout_2 && j == 4 ? 9 :
7341 i == Xsand_stoneout_2 && j == 5 ? 11 :
7342 i == Xsand_stoneout_2 && j == 6 ? 13 :
7343 i == Xsand_stoneout_2 && j == 7 ? 15 :
7344 i == Xboom_bug && j == 1 ? 2 :
7345 i == Xboom_bug && j == 2 ? 2 :
7346 i == Xboom_bug && j == 3 ? 4 :
7347 i == Xboom_bug && j == 4 ? 4 :
7348 i == Xboom_bug && j == 5 ? 2 :
7349 i == Xboom_bug && j == 6 ? 2 :
7350 i == Xboom_bug && j == 7 ? 0 :
7351 i == Xboom_bomb && j == 1 ? 2 :
7352 i == Xboom_bomb && j == 2 ? 2 :
7353 i == Xboom_bomb && j == 3 ? 4 :
7354 i == Xboom_bomb && j == 4 ? 4 :
7355 i == Xboom_bomb && j == 5 ? 2 :
7356 i == Xboom_bomb && j == 6 ? 2 :
7357 i == Xboom_bomb && j == 7 ? 0 :
7358 i == Xboom_android && j == 7 ? 6 :
7359 i == Xboom_1 && j == 1 ? 2 :
7360 i == Xboom_1 && j == 2 ? 2 :
7361 i == Xboom_1 && j == 3 ? 4 :
7362 i == Xboom_1 && j == 4 ? 4 :
7363 i == Xboom_1 && j == 5 ? 6 :
7364 i == Xboom_1 && j == 6 ? 6 :
7365 i == Xboom_1 && j == 7 ? 8 :
7366 i == Xboom_2 && j == 0 ? 8 :
7367 i == Xboom_2 && j == 1 ? 8 :
7368 i == Xboom_2 && j == 2 ? 10 :
7369 i == Xboom_2 && j == 3 ? 10 :
7370 i == Xboom_2 && j == 4 ? 10 :
7371 i == Xboom_2 && j == 5 ? 12 :
7372 i == Xboom_2 && j == 6 ? 12 :
7373 i == Xboom_2 && j == 7 ? 12 :
7374 special_animation && j == 4 ? 3 :
7375 effective_action != action ? 0 :
7379 Bitmap *debug_bitmap = g_em->bitmap;
7380 int debug_src_x = g_em->src_x;
7381 int debug_src_y = g_em->src_y;
7384 int frame = getAnimationFrame(g->anim_frames,
7387 g->anim_start_frame,
7390 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
7391 g->double_movement && is_backside);
7393 g_em->bitmap = src_bitmap;
7394 g_em->src_x = src_x;
7395 g_em->src_y = src_y;
7396 g_em->src_offset_x = 0;
7397 g_em->src_offset_y = 0;
7398 g_em->dst_offset_x = 0;
7399 g_em->dst_offset_y = 0;
7400 g_em->width = TILEX;
7401 g_em->height = TILEY;
7403 g_em->preserve_background = FALSE;
7405 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
7408 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
7409 effective_action == ACTION_MOVING ||
7410 effective_action == ACTION_PUSHING ||
7411 effective_action == ACTION_EATING)) ||
7412 (!has_action_graphics && (effective_action == ACTION_FILLING ||
7413 effective_action == ACTION_EMPTYING)))
7416 (effective_action == ACTION_FALLING ||
7417 effective_action == ACTION_FILLING ||
7418 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
7419 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
7420 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
7421 int num_steps = (i == Ydrip_s1 ? 16 :
7422 i == Ydrip_s1B ? 16 :
7423 i == Ydrip_s2 ? 16 :
7424 i == Ydrip_s2B ? 16 :
7425 i == Xsand_stonein_1 ? 32 :
7426 i == Xsand_stonein_2 ? 32 :
7427 i == Xsand_stonein_3 ? 32 :
7428 i == Xsand_stonein_4 ? 32 :
7429 i == Xsand_stoneout_1 ? 16 :
7430 i == Xsand_stoneout_2 ? 16 : 8);
7431 int cx = ABS(dx) * (TILEX / num_steps);
7432 int cy = ABS(dy) * (TILEY / num_steps);
7433 int step_frame = (i == Ydrip_s2 ? j + 8 :
7434 i == Ydrip_s2B ? j + 8 :
7435 i == Xsand_stonein_2 ? j + 8 :
7436 i == Xsand_stonein_3 ? j + 16 :
7437 i == Xsand_stonein_4 ? j + 24 :
7438 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
7439 int step = (is_backside ? step_frame : num_steps - step_frame);
7441 if (is_backside) /* tile where movement starts */
7443 if (dx < 0 || dy < 0)
7445 g_em->src_offset_x = cx * step;
7446 g_em->src_offset_y = cy * step;
7450 g_em->dst_offset_x = cx * step;
7451 g_em->dst_offset_y = cy * step;
7454 else /* tile where movement ends */
7456 if (dx < 0 || dy < 0)
7458 g_em->dst_offset_x = cx * step;
7459 g_em->dst_offset_y = cy * step;
7463 g_em->src_offset_x = cx * step;
7464 g_em->src_offset_y = cy * step;
7468 g_em->width = TILEX - cx * step;
7469 g_em->height = TILEY - cy * step;
7472 /* create unique graphic identifier to decide if tile must be redrawn */
7473 /* bit 31 - 16 (16 bit): EM style graphic
7474 bit 15 - 12 ( 4 bit): EM style frame
7475 bit 11 - 6 ( 6 bit): graphic width
7476 bit 5 - 0 ( 6 bit): graphic height */
7477 g_em->unique_identifier =
7478 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
7482 /* skip check for EMC elements not contained in original EMC artwork */
7483 if (element == EL_EMC_FAKE_ACID)
7486 if (g_em->bitmap != debug_bitmap ||
7487 g_em->src_x != debug_src_x ||
7488 g_em->src_y != debug_src_y ||
7489 g_em->src_offset_x != 0 ||
7490 g_em->src_offset_y != 0 ||
7491 g_em->dst_offset_x != 0 ||
7492 g_em->dst_offset_y != 0 ||
7493 g_em->width != TILEX ||
7494 g_em->height != TILEY)
7496 static int last_i = -1;
7504 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
7505 i, element, element_info[element].token_name,
7506 element_action_info[effective_action].suffix, direction);
7508 if (element != effective_element)
7509 printf(" [%d ('%s')]",
7511 element_info[effective_element].token_name);
7515 if (g_em->bitmap != debug_bitmap)
7516 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
7517 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
7519 if (g_em->src_x != debug_src_x ||
7520 g_em->src_y != debug_src_y)
7521 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
7522 j, (is_backside ? 'B' : 'F'),
7523 g_em->src_x, g_em->src_y,
7524 g_em->src_x / 32, g_em->src_y / 32,
7525 debug_src_x, debug_src_y,
7526 debug_src_x / 32, debug_src_y / 32);
7528 if (g_em->src_offset_x != 0 ||
7529 g_em->src_offset_y != 0 ||
7530 g_em->dst_offset_x != 0 ||
7531 g_em->dst_offset_y != 0)
7532 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
7534 g_em->src_offset_x, g_em->src_offset_y,
7535 g_em->dst_offset_x, g_em->dst_offset_y);
7537 if (g_em->width != TILEX ||
7538 g_em->height != TILEY)
7539 printf(" %d (%d): size %d,%d should be %d,%d\n",
7541 g_em->width, g_em->height, TILEX, TILEY);
7543 num_em_gfx_errors++;
7550 for (i = 0; i < TILE_MAX; i++)
7552 for (j = 0; j < 8; j++)
7554 int element = object_mapping[i].element_rnd;
7555 int action = object_mapping[i].action;
7556 int direction = object_mapping[i].direction;
7557 boolean is_backside = object_mapping[i].is_backside;
7558 int graphic_action = el_act_dir2img(element, action, direction);
7559 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
7561 if ((action == ACTION_SMASHED_BY_ROCK ||
7562 action == ACTION_SMASHED_BY_SPRING ||
7563 action == ACTION_EATING) &&
7564 graphic_action == graphic_default)
7566 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
7567 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
7568 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
7569 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
7572 /* no separate animation for "smashed by rock" -- use rock instead */
7573 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7574 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
7576 g_em->bitmap = g_xx->bitmap;
7577 g_em->src_x = g_xx->src_x;
7578 g_em->src_y = g_xx->src_y;
7579 g_em->src_offset_x = g_xx->src_offset_x;
7580 g_em->src_offset_y = g_xx->src_offset_y;
7581 g_em->dst_offset_x = g_xx->dst_offset_x;
7582 g_em->dst_offset_y = g_xx->dst_offset_y;
7583 g_em->width = g_xx->width;
7584 g_em->height = g_xx->height;
7585 g_em->unique_identifier = g_xx->unique_identifier;
7588 g_em->preserve_background = TRUE;
7593 for (p = 0; p < MAX_PLAYERS; p++)
7595 for (i = 0; i < SPR_MAX; i++)
7597 int element = player_mapping[p][i].element_rnd;
7598 int action = player_mapping[p][i].action;
7599 int direction = player_mapping[p][i].direction;
7601 for (j = 0; j < 8; j++)
7603 int effective_element = element;
7604 int effective_action = action;
7605 int graphic = (direction == MV_NONE ?
7606 el_act2img(effective_element, effective_action) :
7607 el_act_dir2img(effective_element, effective_action,
7609 struct GraphicInfo *g = &graphic_info[graphic];
7610 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
7616 Bitmap *debug_bitmap = g_em->bitmap;
7617 int debug_src_x = g_em->src_x;
7618 int debug_src_y = g_em->src_y;
7621 int frame = getAnimationFrame(g->anim_frames,
7624 g->anim_start_frame,
7627 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
7629 g_em->bitmap = src_bitmap;
7630 g_em->src_x = src_x;
7631 g_em->src_y = src_y;
7632 g_em->src_offset_x = 0;
7633 g_em->src_offset_y = 0;
7634 g_em->dst_offset_x = 0;
7635 g_em->dst_offset_y = 0;
7636 g_em->width = TILEX;
7637 g_em->height = TILEY;
7641 /* skip check for EMC elements not contained in original EMC artwork */
7642 if (element == EL_PLAYER_3 ||
7643 element == EL_PLAYER_4)
7646 if (g_em->bitmap != debug_bitmap ||
7647 g_em->src_x != debug_src_x ||
7648 g_em->src_y != debug_src_y)
7650 static int last_i = -1;
7658 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
7659 p, i, element, element_info[element].token_name,
7660 element_action_info[effective_action].suffix, direction);
7662 if (element != effective_element)
7663 printf(" [%d ('%s')]",
7665 element_info[effective_element].token_name);
7669 if (g_em->bitmap != debug_bitmap)
7670 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
7671 j, (int)(g_em->bitmap), (int)(debug_bitmap));
7673 if (g_em->src_x != debug_src_x ||
7674 g_em->src_y != debug_src_y)
7675 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
7677 g_em->src_x, g_em->src_y,
7678 g_em->src_x / 32, g_em->src_y / 32,
7679 debug_src_x, debug_src_y,
7680 debug_src_x / 32, debug_src_y / 32);
7682 num_em_gfx_errors++;
7692 printf("::: [%d errors found]\n", num_em_gfx_errors);
7698 void CheckSaveEngineSnapshot_EM(byte action[MAX_PLAYERS], int frame,
7699 boolean any_player_moving,
7700 boolean any_player_snapping,
7701 boolean any_player_dropping)
7703 static boolean player_was_waiting = TRUE;
7705 if (frame == 0 && !any_player_dropping)
7707 if (!player_was_waiting)
7709 if (!SaveEngineSnapshotToList())
7712 player_was_waiting = TRUE;
7715 else if (any_player_moving || any_player_snapping || any_player_dropping)
7717 player_was_waiting = FALSE;
7721 void CheckSaveEngineSnapshot_SP(boolean murphy_is_waiting,
7722 boolean murphy_is_dropping)
7724 static boolean player_was_waiting = TRUE;
7726 if (murphy_is_waiting)
7728 if (!player_was_waiting)
7730 if (!SaveEngineSnapshotToList())
7733 player_was_waiting = TRUE;
7738 player_was_waiting = FALSE;
7742 void CheckSingleStepMode_EM(byte action[MAX_PLAYERS], int frame,
7743 boolean any_player_moving,
7744 boolean any_player_snapping,
7745 boolean any_player_dropping)
7747 if (tape.single_step && tape.recording && !tape.pausing)
7748 if (frame == 0 && !any_player_dropping)
7749 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
7751 CheckSaveEngineSnapshot_EM(action, frame, any_player_moving,
7752 any_player_snapping, any_player_dropping);
7755 void CheckSingleStepMode_SP(boolean murphy_is_waiting,
7756 boolean murphy_is_dropping)
7758 if (tape.single_step && tape.recording && !tape.pausing)
7759 if (murphy_is_waiting)
7760 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
7762 CheckSaveEngineSnapshot_SP(murphy_is_waiting, murphy_is_dropping);
7765 void getGraphicSource_SP(struct GraphicInfo_SP *g_sp,
7766 int graphic, int sync_frame, int x, int y)
7768 int frame = getGraphicAnimationFrame(graphic, sync_frame);
7770 getGraphicSource(graphic, frame, &g_sp->bitmap, &g_sp->src_x, &g_sp->src_y);
7773 boolean isNextAnimationFrame_SP(int graphic, int sync_frame)
7775 return (IS_NEXT_FRAME(sync_frame, graphic));
7778 int getGraphicInfo_Delay(int graphic)
7780 return graphic_info[graphic].anim_delay;
7783 void PlayMenuSoundExt(int sound)
7785 if (sound == SND_UNDEFINED)
7788 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
7789 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
7792 if (IS_LOOP_SOUND(sound))
7793 PlaySoundLoop(sound);
7798 void PlayMenuSound()
7800 PlayMenuSoundExt(menu.sound[game_status]);
7803 void PlayMenuSoundStereo(int sound, int stereo_position)
7805 if (sound == SND_UNDEFINED)
7808 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
7809 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
7812 if (IS_LOOP_SOUND(sound))
7813 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
7815 PlaySoundStereo(sound, stereo_position);
7818 void PlayMenuSoundIfLoopExt(int sound)
7820 if (sound == SND_UNDEFINED)
7823 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
7824 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
7827 if (IS_LOOP_SOUND(sound))
7828 PlaySoundLoop(sound);
7831 void PlayMenuSoundIfLoop()
7833 PlayMenuSoundIfLoopExt(menu.sound[game_status]);
7836 void PlayMenuMusicExt(int music)
7838 if (music == MUS_UNDEFINED)
7841 if (!setup.sound_music)
7847 void PlayMenuMusic()
7849 PlayMenuMusicExt(menu.music[game_status]);
7852 void PlaySoundActivating()
7855 PlaySound(SND_MENU_ITEM_ACTIVATING);
7859 void PlaySoundSelecting()
7862 PlaySound(SND_MENU_ITEM_SELECTING);
7866 void ToggleFullscreenOrChangeWindowScalingIfNeeded()
7868 boolean change_fullscreen = (setup.fullscreen !=
7869 video.fullscreen_enabled);
7870 boolean change_fullscreen_mode = (video.fullscreen_enabled &&
7871 !strEqual(setup.fullscreen_mode,
7872 video.fullscreen_mode_current));
7873 boolean change_window_scaling_percent = (!video.fullscreen_enabled &&
7874 setup.window_scaling_percent !=
7875 video.window_scaling_percent);
7877 if (change_window_scaling_percent && video.fullscreen_enabled)
7880 if (!change_window_scaling_percent && !video.fullscreen_available)
7883 #if defined(TARGET_SDL2)
7884 if (change_window_scaling_percent)
7886 SDLSetWindowScaling(setup.window_scaling_percent);
7890 else if (change_fullscreen)
7892 SDLSetWindowFullscreen(setup.fullscreen);
7894 /* set setup value according to successfully changed fullscreen mode */
7895 setup.fullscreen = video.fullscreen_enabled;
7901 if (change_fullscreen ||
7902 change_fullscreen_mode ||
7903 change_window_scaling_percent)
7905 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
7907 /* save backbuffer content which gets lost when toggling fullscreen mode */
7908 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
7910 if (change_fullscreen_mode)
7912 /* keep fullscreen, but change fullscreen mode (screen resolution) */
7913 video.fullscreen_enabled = FALSE; /* force new fullscreen mode */
7916 if (change_window_scaling_percent)
7918 /* keep window mode, but change window scaling */
7919 video.fullscreen_enabled = TRUE; /* force new window scaling */
7922 /* toggle fullscreen */
7923 ChangeVideoModeIfNeeded(setup.fullscreen);
7925 /* set setup value according to successfully changed fullscreen mode */
7926 setup.fullscreen = video.fullscreen_enabled;
7928 /* restore backbuffer content from temporary backbuffer backup bitmap */
7929 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
7931 FreeBitmap(tmp_backbuffer);
7933 /* update visible window/screen */
7934 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
7938 void ChangeViewportPropertiesIfNeeded()
7940 int gfx_game_mode = game_status;
7941 int gfx_game_mode2 = (game_status == GAME_MODE_EDITOR ? GAME_MODE_DEFAULT :
7943 struct RectWithBorder *vp_playfield = &viewport.playfield[gfx_game_mode];
7944 struct RectWithBorder *vp_door_1 = &viewport.door_1[gfx_game_mode];
7945 struct RectWithBorder *vp_door_2 = &viewport.door_2[gfx_game_mode2];
7946 struct RectWithBorder *vp_door_3 = &viewport.door_2[GAME_MODE_EDITOR];
7947 int border_size = vp_playfield->border_size;
7948 int new_sx = vp_playfield->x + border_size;
7949 int new_sy = vp_playfield->y + border_size;
7950 int new_sxsize = vp_playfield->width - 2 * border_size;
7951 int new_sysize = vp_playfield->height - 2 * border_size;
7952 int new_real_sx = vp_playfield->x;
7953 int new_real_sy = vp_playfield->y;
7954 int new_full_sxsize = vp_playfield->width;
7955 int new_full_sysize = vp_playfield->height;
7956 int new_dx = vp_door_1->x;
7957 int new_dy = vp_door_1->y;
7958 int new_dxsize = vp_door_1->width;
7959 int new_dysize = vp_door_1->height;
7960 int new_vx = vp_door_2->x;
7961 int new_vy = vp_door_2->y;
7962 int new_vxsize = vp_door_2->width;
7963 int new_vysize = vp_door_2->height;
7964 int new_ex = vp_door_3->x;
7965 int new_ey = vp_door_3->y;
7966 int new_exsize = vp_door_3->width;
7967 int new_eysize = vp_door_3->height;
7968 int new_tilesize_var =
7969 (setup.small_game_graphics ? MINI_TILESIZE : game.tile_size);
7971 int tilesize = (gfx_game_mode == GAME_MODE_PLAYING ? new_tilesize_var :
7972 gfx_game_mode == GAME_MODE_EDITOR ? MINI_TILESIZE : TILESIZE);
7973 int new_scr_fieldx = new_sxsize / tilesize;
7974 int new_scr_fieldy = new_sysize / tilesize;
7975 int new_scr_fieldx_buffers = new_sxsize / new_tilesize_var;
7976 int new_scr_fieldy_buffers = new_sysize / new_tilesize_var;
7977 boolean init_gfx_buffers = FALSE;
7978 boolean init_video_buffer = FALSE;
7979 boolean init_gadgets_and_toons = FALSE;
7980 boolean init_em_graphics = FALSE;
7981 boolean drawing_area_changed = FALSE;
7983 if (viewport.window.width != WIN_XSIZE ||
7984 viewport.window.height != WIN_YSIZE)
7986 WIN_XSIZE = viewport.window.width;
7987 WIN_YSIZE = viewport.window.height;
7989 init_video_buffer = TRUE;
7990 init_gfx_buffers = TRUE;
7992 // printf("::: video: init_video_buffer, init_gfx_buffers\n");
7995 if (new_scr_fieldx != SCR_FIELDX ||
7996 new_scr_fieldy != SCR_FIELDY)
7998 /* this always toggles between MAIN and GAME when using small tile size */
8000 SCR_FIELDX = new_scr_fieldx;
8001 SCR_FIELDY = new_scr_fieldy;
8003 // printf("::: new_scr_fieldx != SCR_FIELDX ...\n");
8014 new_sxsize != SXSIZE ||
8015 new_sysize != SYSIZE ||
8016 new_dxsize != DXSIZE ||
8017 new_dysize != DYSIZE ||
8018 new_vxsize != VXSIZE ||
8019 new_vysize != VYSIZE ||
8020 new_exsize != EXSIZE ||
8021 new_eysize != EYSIZE ||
8022 new_real_sx != REAL_SX ||
8023 new_real_sy != REAL_SY ||
8024 new_full_sxsize != FULL_SXSIZE ||
8025 new_full_sysize != FULL_SYSIZE ||
8026 new_tilesize_var != TILESIZE_VAR
8029 if (new_tilesize_var != TILESIZE_VAR)
8031 // printf("::: new_tilesize_var != TILESIZE_VAR\n");
8033 // changing tile size invalidates scroll values of engine snapshots
8034 FreeEngineSnapshotSingle();
8036 // changing tile size requires update of graphic mapping for EM engine
8037 init_em_graphics = TRUE;
8042 new_sxsize != SXSIZE ||
8043 new_sysize != SYSIZE ||
8044 new_real_sx != REAL_SX ||
8045 new_real_sy != REAL_SY ||
8046 new_full_sxsize != FULL_SXSIZE ||
8047 new_full_sysize != FULL_SYSIZE)
8049 if (!init_video_buffer)
8050 drawing_area_changed = TRUE;
8061 SXSIZE = new_sxsize;
8062 SYSIZE = new_sysize;
8063 DXSIZE = new_dxsize;
8064 DYSIZE = new_dysize;
8065 VXSIZE = new_vxsize;
8066 VYSIZE = new_vysize;
8067 EXSIZE = new_exsize;
8068 EYSIZE = new_eysize;
8069 REAL_SX = new_real_sx;
8070 REAL_SY = new_real_sy;
8071 FULL_SXSIZE = new_full_sxsize;
8072 FULL_SYSIZE = new_full_sysize;
8073 TILESIZE_VAR = new_tilesize_var;
8075 init_gfx_buffers = TRUE;
8076 init_gadgets_and_toons = TRUE;
8078 // printf("::: viewports: init_gfx_buffers\n");
8079 // printf("::: viewports: init_gadgets_and_toons\n");
8082 if (init_gfx_buffers)
8084 // printf("::: init_gfx_buffers\n");
8086 SCR_FIELDX = new_scr_fieldx_buffers;
8087 SCR_FIELDY = new_scr_fieldy_buffers;
8091 SCR_FIELDX = new_scr_fieldx;
8092 SCR_FIELDY = new_scr_fieldy;
8094 gfx.drawing_area_changed = drawing_area_changed;
8096 SetDrawDeactivationMask(REDRAW_NONE);
8097 SetDrawBackgroundMask(REDRAW_FIELD);
8100 if (init_video_buffer)
8102 // printf("::: init_video_buffer\n");
8104 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
8107 if (init_gadgets_and_toons)
8109 // printf("::: init_gadgets_and_toons\n");
8115 if (init_em_graphics)
8117 InitGraphicInfo_EM();