1 // ============================================================================
2 // Rocks'n'Diamonds - McDuffin Strikes Back!
3 // ----------------------------------------------------------------------------
4 // (c) 1995-2014 by Artsoft Entertainment
7 // http://www.artsoft.org/
8 // ----------------------------------------------------------------------------
10 // ============================================================================
14 #include "libgame/libgame.h"
26 /* select level set with EMC X11 graphics before activating EM GFX debugging */
27 #define DEBUG_EM_GFX 0
29 /* tool button identifiers */
30 #define TOOL_CTRL_ID_YES 0
31 #define TOOL_CTRL_ID_NO 1
32 #define TOOL_CTRL_ID_CONFIRM 2
33 #define TOOL_CTRL_ID_PLAYER_1 3
34 #define TOOL_CTRL_ID_PLAYER_2 4
35 #define TOOL_CTRL_ID_PLAYER_3 5
36 #define TOOL_CTRL_ID_PLAYER_4 6
38 #define NUM_TOOL_BUTTONS 7
40 /* constants for number of doors and door parts */
42 #define NUM_PANELS NUM_DOORS
43 // #define NUM_PANELS 0
44 #define MAX_PARTS_PER_DOOR 8
45 #define MAX_DOOR_PARTS (NUM_DOORS * MAX_PARTS_PER_DOOR + NUM_PANELS)
46 #define DOOR_PART_IS_PANEL(i) ((i) >= NUM_DOORS * MAX_PARTS_PER_DOOR)
49 struct DoorPartOrderInfo
55 static struct DoorPartOrderInfo door_part_order[MAX_DOOR_PARTS];
57 struct DoorPartControlInfo
61 struct DoorPartPosInfo *pos;
64 static struct DoorPartControlInfo door_part_controls[] =
68 IMG_DOOR_1_GFX_PART_1,
73 IMG_DOOR_1_GFX_PART_2,
78 IMG_DOOR_1_GFX_PART_3,
83 IMG_DOOR_1_GFX_PART_4,
88 IMG_DOOR_1_GFX_PART_5,
93 IMG_DOOR_1_GFX_PART_6,
98 IMG_DOOR_1_GFX_PART_7,
103 IMG_DOOR_1_GFX_PART_8,
109 IMG_DOOR_2_GFX_PART_1,
114 IMG_DOOR_2_GFX_PART_2,
119 IMG_DOOR_2_GFX_PART_3,
124 IMG_DOOR_2_GFX_PART_4,
129 IMG_DOOR_2_GFX_PART_5,
134 IMG_DOOR_2_GFX_PART_6,
139 IMG_DOOR_2_GFX_PART_7,
144 IMG_DOOR_2_GFX_PART_8,
150 IMG_BACKGROUND_PANEL,
167 /* forward declaration for internal use */
168 static void UnmapToolButtons();
169 static void HandleToolButtons(struct GadgetInfo *);
170 static int el_act_dir2crm(int, int, int);
171 static int el_act2crm(int, int);
173 static struct GadgetInfo *tool_gadget[NUM_TOOL_BUTTONS];
174 static int request_gadget_id = -1;
176 static char *print_if_not_empty(int element)
178 static char *s = NULL;
179 char *token_name = element_info[element].token_name;
184 s = checked_malloc(strlen(token_name) + 10 + 1);
186 if (element != EL_EMPTY)
187 sprintf(s, "%d\t['%s']", element, token_name);
189 sprintf(s, "%d", element);
194 void DumpTile(int x, int y)
199 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
205 printf_line("-", 79);
206 printf("Field Info: SCREEN(%d, %d), LEVEL(%d, %d)\n", sx, sy, x, y);
207 printf_line("-", 79);
209 if (!IN_LEV_FIELD(x, y))
211 printf("(not in level field)\n");
217 printf(" Feld: %d\t['%s']\n", Feld[x][y],
218 element_info[Feld[x][y]].token_name);
219 printf(" Back: %s\n", print_if_not_empty(Back[x][y]));
220 printf(" Store: %s\n", print_if_not_empty(Store[x][y]));
221 printf(" Store2: %s\n", print_if_not_empty(Store2[x][y]));
222 printf(" StorePlayer: %s\n", print_if_not_empty(StorePlayer[x][y]));
223 printf(" MovPos: %d\n", MovPos[x][y]);
224 printf(" MovDir: %d\n", MovDir[x][y]);
225 printf(" MovDelay: %d\n", MovDelay[x][y]);
226 printf(" ChangeDelay: %d\n", ChangeDelay[x][y]);
227 printf(" CustomValue: %d\n", CustomValue[x][y]);
228 printf(" GfxElement: %d\n", GfxElement[x][y]);
229 printf(" GfxAction: %d\n", GfxAction[x][y]);
230 printf(" GfxFrame: %d\n", GfxFrame[x][y]);
234 void SetDrawtoField(int mode)
236 if (mode == DRAW_FIELDBUFFER)
242 BX2 = SCR_FIELDX + 1;
243 BY2 = SCR_FIELDY + 1;
245 drawto_field = fieldbuffer;
247 else /* DRAW_BACKBUFFER */
253 BX2 = SCR_FIELDX - 1;
254 BY2 = SCR_FIELDY - 1;
256 drawto_field = backbuffer;
260 static void RedrawPlayfield_RND()
262 if (game.envelope_active)
265 DrawLevel(REDRAW_ALL);
269 void RedrawPlayfield()
271 if (game_status != GAME_MODE_PLAYING)
274 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
275 RedrawPlayfield_EM(TRUE);
276 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
277 RedrawPlayfield_SP(TRUE);
278 else if (level.game_engine_type == GAME_ENGINE_TYPE_RND)
279 RedrawPlayfield_RND();
281 BlitScreenToBitmap(backbuffer);
283 BlitBitmap(drawto, window, gfx.sx, gfx.sy, gfx.sxsize, gfx.sysize,
287 void DrawMaskedBorder_Rect(int x, int y, int width, int height)
289 Bitmap *bitmap = graphic_info[IMG_GLOBAL_BORDER].bitmap;
291 BlitBitmapMasked(bitmap, backbuffer, x, y, width, height, x, y);
294 void DrawMaskedBorder_FIELD()
296 if (global.border_status >= GAME_MODE_TITLE &&
297 global.border_status <= GAME_MODE_PLAYING &&
298 border.draw_masked[global.border_status])
299 DrawMaskedBorder_Rect(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
302 void DrawMaskedBorder_DOOR_1()
304 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
305 (global.border_status != GAME_MODE_EDITOR ||
306 border.draw_masked[GFX_SPECIAL_ARG_EDITOR]))
307 DrawMaskedBorder_Rect(DX, DY, DXSIZE, DYSIZE);
310 void DrawMaskedBorder_DOOR_2()
312 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
313 global.border_status != GAME_MODE_EDITOR)
314 DrawMaskedBorder_Rect(VX, VY, VXSIZE, VYSIZE);
317 void DrawMaskedBorder_DOOR_3()
319 /* currently not available */
322 void DrawMaskedBorder_ALL()
324 DrawMaskedBorder_FIELD();
325 DrawMaskedBorder_DOOR_1();
326 DrawMaskedBorder_DOOR_2();
327 DrawMaskedBorder_DOOR_3();
330 void DrawMaskedBorder(int redraw_mask)
332 /* never draw masked screen borders on borderless screens */
333 if (effectiveGameStatus() == GAME_MODE_LOADING ||
334 effectiveGameStatus() == GAME_MODE_TITLE)
337 /* never draw masked screen borders when displaying request outside door */
338 if (effectiveGameStatus() == GAME_MODE_PSEUDO_DOOR &&
339 global.use_envelope_request)
342 if (redraw_mask & REDRAW_ALL)
343 DrawMaskedBorder_ALL();
346 if (redraw_mask & REDRAW_FIELD)
347 DrawMaskedBorder_FIELD();
348 if (redraw_mask & REDRAW_DOOR_1)
349 DrawMaskedBorder_DOOR_1();
350 if (redraw_mask & REDRAW_DOOR_2)
351 DrawMaskedBorder_DOOR_2();
352 if (redraw_mask & REDRAW_DOOR_3)
353 DrawMaskedBorder_DOOR_3();
357 void BlitScreenToBitmap_RND(Bitmap *target_bitmap)
359 DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
360 int fx = FX, fy = FY;
361 int full_lev_fieldx = lev_fieldx + (BorderElement != EL_EMPTY ? 2 : 0);
362 int full_lev_fieldy = lev_fieldy + (BorderElement != EL_EMPTY ? 2 : 0);
364 int dx = (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
365 int dy = (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
366 int dx_var = dx * TILESIZE_VAR / TILESIZE;
367 int dy_var = dy * TILESIZE_VAR / TILESIZE;
370 ffx = (scroll_x - SBX_Left) * TILEX_VAR + dx_var;
371 ffy = (scroll_y - SBY_Upper) * TILEY_VAR + dy_var;
373 if (EVEN(SCR_FIELDX))
375 if (ffx < SBX_Right * TILEX_VAR + TILEX_VAR / 2 + TILEX_VAR)
376 fx += dx_var - MIN(ffx, TILEX_VAR / 2) + TILEX_VAR;
378 fx += (dx_var > 0 ? TILEX_VAR : 0);
385 if (EVEN(SCR_FIELDY))
387 if (ffy < SBY_Lower * TILEY_VAR + TILEY_VAR / 2 + TILEY_VAR)
388 fy += dy_var - MIN(ffy, TILEY_VAR / 2) + TILEY_VAR;
390 fy += (dy_var > 0 ? TILEY_VAR : 0);
397 if (full_lev_fieldx <= SCR_FIELDX)
399 if (EVEN(SCR_FIELDX))
400 fx = 2 * TILEX_VAR - (ODD(lev_fieldx) ? TILEX_VAR / 2 : 0);
402 fx = 2 * TILEX_VAR - (EVEN(lev_fieldx) ? TILEX_VAR / 2 : 0);
405 if (full_lev_fieldy <= SCR_FIELDY)
407 if (EVEN(SCR_FIELDY))
408 fy = 2 * TILEY_VAR - (ODD(lev_fieldy) ? TILEY_VAR / 2 : 0);
410 fy = 2 * TILEY_VAR - (EVEN(lev_fieldy) ? TILEY_VAR / 2 : 0);
413 BlitBitmap(buffer, target_bitmap, fx, fy, SXSIZE, SYSIZE, SX, SY);
416 void BlitScreenToBitmap(Bitmap *target_bitmap)
418 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
419 BlitScreenToBitmap_EM(target_bitmap);
420 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
421 BlitScreenToBitmap_SP(target_bitmap);
422 else if (level.game_engine_type == GAME_ENGINE_TYPE_RND)
423 BlitScreenToBitmap_RND(target_bitmap);
426 void BackToFront_OLD()
428 DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
431 /* !!! TEST ONLY !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
432 /* (force full redraw) */
433 if (game_status == GAME_MODE_PLAYING)
434 redraw_mask |= REDRAW_FIELD;
437 if (redraw_mask == REDRAW_NONE)
442 if (redraw_mask & REDRAW_ALL)
443 printf("[REDRAW_ALL]");
444 if (redraw_mask & REDRAW_FIELD)
445 printf("[REDRAW_FIELD]");
446 if (redraw_mask & REDRAW_DOOR_1)
447 printf("[REDRAW_DOOR_1]");
448 if (redraw_mask & REDRAW_DOOR_2)
449 printf("[REDRAW_DOOR_2]");
450 if (redraw_mask & REDRAW_FROM_BACKBUFFER)
451 printf("[REDRAW_FROM_BACKBUFFER]");
452 printf(" [%d]\n", FrameCounter);
455 if (global.fps_slowdown && game_status == GAME_MODE_PLAYING)
457 static boolean last_frame_skipped = FALSE;
458 boolean skip_even_when_not_scrolling = TRUE;
459 boolean just_scrolling = (ScreenMovDir != 0);
460 boolean verbose = FALSE;
462 if (global.fps_slowdown_factor > 1 &&
463 (FrameCounter % global.fps_slowdown_factor) &&
464 (just_scrolling || skip_even_when_not_scrolling))
466 redraw_mask &= ~REDRAW_MAIN;
468 last_frame_skipped = TRUE;
471 printf("FRAME SKIPPED\n");
475 if (last_frame_skipped)
476 redraw_mask |= REDRAW_FIELD;
478 last_frame_skipped = FALSE;
481 printf("frame not skipped\n");
485 /* synchronize X11 graphics at this point; if we would synchronize the
486 display immediately after the buffer switching (after the XFlush),
487 this could mean that we have to wait for the graphics to complete,
488 although we could go on doing calculations for the next frame */
492 /* never draw masked border to backbuffer when using playfield buffer */
493 if (game_status != GAME_MODE_PLAYING ||
494 redraw_mask & REDRAW_FROM_BACKBUFFER ||
495 buffer == backbuffer)
496 DrawMaskedBorder(redraw_mask);
498 DrawMaskedBorder(redraw_mask & REDRAW_DOORS);
500 if (redraw_mask & REDRAW_ALL)
502 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
504 redraw_mask = REDRAW_NONE;
507 if (redraw_mask & REDRAW_FIELD)
509 if (game_status != GAME_MODE_PLAYING ||
510 redraw_mask & REDRAW_FROM_BACKBUFFER)
512 BlitBitmap(backbuffer, window,
513 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
517 BlitScreenToBitmap_RND(window);
520 redraw_mask &= ~REDRAW_MAIN;
523 if (redraw_mask & REDRAW_DOORS)
525 if (redraw_mask & REDRAW_DOOR_1)
526 BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
528 if (redraw_mask & REDRAW_DOOR_2)
529 BlitBitmap(backbuffer, window, VX, VY, VXSIZE, VYSIZE, VX, VY);
531 if (redraw_mask & REDRAW_DOOR_3)
532 BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
534 redraw_mask &= ~REDRAW_DOORS;
537 if (redraw_mask & REDRAW_MICROLEVEL)
539 BlitBitmap(backbuffer, window, SX, SY + 10 * TILEY, SXSIZE, 7 * TILEY,
540 SX, SY + 10 * TILEY);
542 redraw_mask &= ~REDRAW_MICROLEVEL;
545 if (redraw_mask & REDRAW_FPS) /* display frames per second */
550 sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
551 if (!global.fps_slowdown)
554 sprintf(text, "%04.1f fps%s", global.frames_per_second, info1);
556 DrawTextExt(window, SX + SXSIZE + SX, 0, text, FONT_TEXT_2, BLIT_OPAQUE);
559 redraw_mask = REDRAW_NONE;
564 if (redraw_mask == REDRAW_NONE)
567 // draw masked border to all viewports, if defined
568 DrawMaskedBorder(redraw_mask);
570 // blit backbuffer to visible screen
571 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
573 redraw_mask = REDRAW_NONE;
576 static void FadeCrossSaveBackbuffer()
578 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
581 static void FadeExt(int fade_mask, int fade_mode, int fade_type)
583 static int fade_type_skip = FADE_TYPE_NONE;
584 void (*draw_border_function)(void) = NULL;
585 Bitmap *bitmap = (fade_mode & FADE_TYPE_TRANSFORM ? bitmap_db_cross : NULL);
586 int x, y, width, height;
587 int fade_delay, post_delay;
589 if (fade_type == FADE_TYPE_FADE_OUT)
591 if (fade_type_skip != FADE_TYPE_NONE)
593 /* skip all fade operations until specified fade operation */
594 if (fade_type & fade_type_skip)
595 fade_type_skip = FADE_TYPE_NONE;
600 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
602 FadeCrossSaveBackbuffer();
608 redraw_mask |= fade_mask;
610 if (fade_type == FADE_TYPE_SKIP)
612 fade_type_skip = fade_mode;
617 fade_delay = fading.fade_delay;
618 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
620 if (fade_type_skip != FADE_TYPE_NONE)
622 /* skip all fade operations until specified fade operation */
623 if (fade_type & fade_type_skip)
624 fade_type_skip = FADE_TYPE_NONE;
629 if (global.autoplay_leveldir)
634 if (fade_mask == REDRAW_FIELD)
639 height = FULL_SYSIZE;
641 if (border.draw_masked_when_fading)
642 draw_border_function = DrawMaskedBorder_FIELD; /* update when fading */
644 DrawMaskedBorder_FIELD(); /* draw once */
646 else /* REDRAW_ALL */
654 if (!setup.fade_screens ||
656 fading.fade_mode == FADE_MODE_NONE)
658 if (fade_mode == FADE_MODE_FADE_OUT)
661 BlitBitmap(backbuffer, window, x, y, width, height, x, y);
663 redraw_mask &= ~fade_mask;
668 FadeRectangle(bitmap, x, y, width, height, fade_mode, fade_delay, post_delay,
669 draw_border_function);
671 redraw_mask &= ~fade_mask;
674 void FadeIn(int fade_mask)
676 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
677 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_IN);
679 FadeExt(fade_mask, FADE_MODE_FADE_IN, FADE_TYPE_FADE_IN);
682 void FadeOut(int fade_mask)
684 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
685 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_OUT);
687 FadeExt(fade_mask, FADE_MODE_FADE_OUT, FADE_TYPE_FADE_OUT);
689 global.border_status = game_status;
692 static void FadeSetLeaveNext(struct TitleFadingInfo fading_leave, boolean set)
694 static struct TitleFadingInfo fading_leave_stored;
697 fading_leave_stored = fading_leave;
699 fading = fading_leave_stored;
702 void FadeSetEnterMenu()
704 fading = menu.enter_menu;
706 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
709 void FadeSetLeaveMenu()
711 fading = menu.leave_menu;
713 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
716 void FadeSetEnterScreen()
718 fading = menu.enter_screen[game_status];
720 FadeSetLeaveNext(menu.leave_screen[game_status], TRUE); /* store */
723 void FadeSetNextScreen()
725 fading = menu.next_screen;
727 // (do not overwrite fade mode set by FadeSetEnterScreen)
728 // FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
731 void FadeSetLeaveScreen()
733 FadeSetLeaveNext(menu.leave_screen[game_status], FALSE); /* recall */
736 void FadeSetFromType(int type)
738 if (type & TYPE_ENTER_SCREEN)
739 FadeSetEnterScreen();
740 else if (type & TYPE_ENTER)
742 else if (type & TYPE_LEAVE)
746 void FadeSetDisabled()
748 static struct TitleFadingInfo fading_none = { FADE_MODE_NONE, -1, -1, -1 };
750 fading = fading_none;
753 void FadeSkipNextFadeIn()
755 FadeExt(0, FADE_MODE_SKIP_FADE_IN, FADE_TYPE_SKIP);
758 void FadeSkipNextFadeOut()
760 FadeExt(0, FADE_MODE_SKIP_FADE_OUT, FADE_TYPE_SKIP);
763 void SetWindowBackgroundImageIfDefined(int graphic)
765 if (graphic_info[graphic].bitmap)
766 SetWindowBackgroundBitmap(graphic_info[graphic].bitmap);
769 void SetMainBackgroundImageIfDefined(int graphic)
771 if (graphic_info[graphic].bitmap)
772 SetMainBackgroundBitmap(graphic_info[graphic].bitmap);
775 void SetDoorBackgroundImageIfDefined(int graphic)
777 if (graphic_info[graphic].bitmap)
778 SetDoorBackgroundBitmap(graphic_info[graphic].bitmap);
781 void SetWindowBackgroundImage(int graphic)
783 SetWindowBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
784 graphic_info[graphic].bitmap ?
785 graphic_info[graphic].bitmap :
786 graphic_info[IMG_BACKGROUND].bitmap);
789 void SetMainBackgroundImage(int graphic)
791 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
792 graphic_info[graphic].bitmap ?
793 graphic_info[graphic].bitmap :
794 graphic_info[IMG_BACKGROUND].bitmap);
797 void SetDoorBackgroundImage(int graphic)
799 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
800 graphic_info[graphic].bitmap ?
801 graphic_info[graphic].bitmap :
802 graphic_info[IMG_BACKGROUND].bitmap);
805 void SetPanelBackground()
807 struct GraphicInfo *gfx = &graphic_info[IMG_BACKGROUND_PANEL];
809 BlitBitmapTiled(gfx->bitmap, bitmap_db_panel, gfx->src_x, gfx->src_y,
810 gfx->width, gfx->height, 0, 0, DXSIZE, DYSIZE);
812 SetDoorBackgroundBitmap(bitmap_db_panel);
815 void DrawBackground(int x, int y, int width, int height)
817 /* "drawto" might still point to playfield buffer here (hall of fame) */
818 ClearRectangleOnBackground(backbuffer, x, y, width, height);
820 if (IN_GFX_FIELD_FULL(x, y))
821 redraw_mask |= REDRAW_FIELD;
822 else if (IN_GFX_DOOR_1(x, y))
823 redraw_mask |= REDRAW_DOOR_1;
824 else if (IN_GFX_DOOR_2(x, y))
825 redraw_mask |= REDRAW_DOOR_2;
826 else if (IN_GFX_DOOR_3(x, y))
827 redraw_mask |= REDRAW_DOOR_3;
830 void DrawBackgroundForFont(int x, int y, int width, int height, int font_nr)
832 struct FontBitmapInfo *font = getFontBitmapInfo(font_nr);
834 if (font->bitmap == NULL)
837 DrawBackground(x, y, width, height);
840 void DrawBackgroundForGraphic(int x, int y, int width, int height, int graphic)
842 struct GraphicInfo *g = &graphic_info[graphic];
844 if (g->bitmap == NULL)
847 DrawBackground(x, y, width, height);
852 /* !!! "drawto" might still point to playfield buffer here (see above) !!! */
853 /* (when entering hall of fame after playing) */
854 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
856 /* !!! maybe this should be done before clearing the background !!! */
857 if (game_status == GAME_MODE_PLAYING)
859 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
860 SetDrawtoField(DRAW_FIELDBUFFER);
863 SetDrawtoField(DRAW_BACKBUFFER);
866 void MarkTileDirty(int x, int y)
868 redraw_mask |= REDRAW_FIELD;
871 void SetBorderElement()
875 BorderElement = EL_EMPTY;
877 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
879 for (x = 0; x < lev_fieldx; x++)
881 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
882 BorderElement = EL_STEELWALL;
884 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
890 void FloodFillLevel(int from_x, int from_y, int fill_element,
891 short field[MAX_LEV_FIELDX][MAX_LEV_FIELDY],
892 int max_fieldx, int max_fieldy)
896 static int check[4][2] = { { -1, 0 }, { 0, -1 }, { 1, 0 }, { 0, 1 } };
897 static int safety = 0;
899 /* check if starting field still has the desired content */
900 if (field[from_x][from_y] == fill_element)
905 if (safety > max_fieldx * max_fieldy)
906 Error(ERR_EXIT, "Something went wrong in 'FloodFill()'. Please debug.");
908 old_element = field[from_x][from_y];
909 field[from_x][from_y] = fill_element;
911 for (i = 0; i < 4; i++)
913 x = from_x + check[i][0];
914 y = from_y + check[i][1];
916 if (IN_FIELD(x, y, max_fieldx, max_fieldy) && field[x][y] == old_element)
917 FloodFillLevel(x, y, fill_element, field, max_fieldx, max_fieldy);
923 void SetRandomAnimationValue(int x, int y)
925 gfx.anim_random_frame = GfxRandom[x][y];
928 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
930 /* animation synchronized with global frame counter, not move position */
931 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
932 sync_frame = FrameCounter;
934 return getAnimationFrame(graphic_info[graphic].anim_frames,
935 graphic_info[graphic].anim_delay,
936 graphic_info[graphic].anim_mode,
937 graphic_info[graphic].anim_start_frame,
941 void getSizedGraphicSourceExt(int graphic, int frame, int tilesize,
942 Bitmap **bitmap, int *x, int *y,
943 boolean get_backside)
945 struct GraphicInfo *g = &graphic_info[graphic];
946 Bitmap *src_bitmap = g->bitmap;
947 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
948 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
949 int tilesize_capped = MIN(MAX(1, tilesize), TILESIZE);
951 // if no in-game graphics defined, always use standard graphic size
952 if (g->bitmaps[IMG_BITMAP_GAME] == NULL)
955 if (tilesize == gfx.standard_tile_size)
956 src_bitmap = g->bitmaps[IMG_BITMAP_STANDARD];
957 else if (tilesize == game.tile_size)
958 src_bitmap = g->bitmaps[IMG_BITMAP_GAME];
960 src_bitmap = g->bitmaps[IMG_BITMAP_1x1 - log_2(tilesize_capped)];
962 if (g->offset_y == 0) /* frames are ordered horizontally */
964 int max_width = g->anim_frames_per_line * g->width;
965 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
967 src_x = pos % max_width;
968 src_y = src_y % g->height + pos / max_width * g->height;
970 else if (g->offset_x == 0) /* frames are ordered vertically */
972 int max_height = g->anim_frames_per_line * g->height;
973 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
975 src_x = src_x % g->width + pos / max_height * g->width;
976 src_y = pos % max_height;
978 else /* frames are ordered diagonally */
980 src_x = src_x + frame * g->offset_x;
981 src_y = src_y + frame * g->offset_y;
984 *bitmap = src_bitmap;
985 *x = src_x * tilesize / TILESIZE;
986 *y = src_y * tilesize / TILESIZE;
989 void getFixedGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
990 int *x, int *y, boolean get_backside)
992 getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y,
996 void getSizedGraphicSource(int graphic, int frame, int tilesize,
997 Bitmap **bitmap, int *x, int *y)
999 getSizedGraphicSourceExt(graphic, frame, tilesize, bitmap, x, y, FALSE);
1002 void getFixedGraphicSource(int graphic, int frame,
1003 Bitmap **bitmap, int *x, int *y)
1005 getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y, FALSE);
1008 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1010 getSizedGraphicSource(graphic, 0, MINI_TILESIZE, bitmap, x, y);
1013 inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1014 int *x, int *y, boolean get_backside)
1016 struct GraphicInfo *g = &graphic_info[graphic];
1017 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
1018 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
1020 if (TILESIZE_VAR != TILESIZE)
1021 return getSizedGraphicSourceExt(graphic, frame, TILESIZE_VAR, bitmap, x, y,
1024 *bitmap = g->bitmap;
1026 if (g->offset_y == 0) /* frames are ordered horizontally */
1028 int max_width = g->anim_frames_per_line * g->width;
1029 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
1031 *x = pos % max_width;
1032 *y = src_y % g->height + pos / max_width * g->height;
1034 else if (g->offset_x == 0) /* frames are ordered vertically */
1036 int max_height = g->anim_frames_per_line * g->height;
1037 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
1039 *x = src_x % g->width + pos / max_height * g->width;
1040 *y = pos % max_height;
1042 else /* frames are ordered diagonally */
1044 *x = src_x + frame * g->offset_x;
1045 *y = src_y + frame * g->offset_y;
1049 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
1051 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
1054 void DrawGraphic(int x, int y, int graphic, int frame)
1057 if (!IN_SCR_FIELD(x, y))
1059 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1060 printf("DrawGraphic(): This should never happen!\n");
1065 DrawGraphicExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR, graphic,
1068 MarkTileDirty(x, y);
1071 void DrawFixedGraphic(int x, int y, int graphic, int frame)
1074 if (!IN_SCR_FIELD(x, y))
1076 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1077 printf("DrawGraphic(): This should never happen!\n");
1082 DrawFixedGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic,
1084 MarkTileDirty(x, y);
1087 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1093 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1095 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX_VAR, TILEY_VAR, x, y);
1098 void DrawFixedGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1104 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1105 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
1108 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
1111 if (!IN_SCR_FIELD(x, y))
1113 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1114 printf("DrawGraphicThruMask(): This should never happen!\n");
1119 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
1122 MarkTileDirty(x, y);
1125 void DrawFixedGraphicThruMask(int x, int y, int graphic, int frame)
1128 if (!IN_SCR_FIELD(x, y))
1130 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1131 printf("DrawGraphicThruMask(): This should never happen!\n");
1136 DrawFixedGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
1138 MarkTileDirty(x, y);
1141 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
1147 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1149 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX_VAR, TILEY_VAR,
1153 void DrawFixedGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y,
1154 int graphic, int frame)
1156 struct GraphicInfo *g = &graphic_info[graphic];
1160 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1162 BlitBitmapMasked(src_bitmap, d, src_x, src_y, g->width, g->height,
1166 void DrawSizedGraphic(int x, int y, int graphic, int frame, int tilesize)
1168 DrawSizedGraphicExt(drawto, SX + x * tilesize, SY + y * tilesize, graphic,
1170 MarkTileDirty(x / tilesize, y / tilesize);
1173 void DrawSizedGraphicExt(DrawBuffer *d, int x, int y, int graphic, int frame,
1179 getSizedGraphicSource(graphic, frame, tilesize, &src_bitmap, &src_x, &src_y);
1180 BlitBitmap(src_bitmap, d, src_x, src_y, tilesize, tilesize, x, y);
1183 void DrawMiniGraphic(int x, int y, int graphic)
1185 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
1186 MarkTileDirty(x / 2, y / 2);
1189 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
1194 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1195 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
1198 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
1199 int graphic, int frame,
1200 int cut_mode, int mask_mode)
1205 int width = TILEX, height = TILEY;
1208 if (dx || dy) /* shifted graphic */
1210 if (x < BX1) /* object enters playfield from the left */
1217 else if (x > BX2) /* object enters playfield from the right */
1223 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
1229 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
1231 else if (dx) /* general horizontal movement */
1232 MarkTileDirty(x + SIGN(dx), y);
1234 if (y < BY1) /* object enters playfield from the top */
1236 if (cut_mode==CUT_BELOW) /* object completely above top border */
1244 else if (y > BY2) /* object enters playfield from the bottom */
1250 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
1256 else if (dy > 0 && cut_mode == CUT_ABOVE)
1258 if (y == BY2) /* object completely above bottom border */
1264 MarkTileDirty(x, y + 1);
1265 } /* object leaves playfield to the bottom */
1266 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1268 else if (dy) /* general vertical movement */
1269 MarkTileDirty(x, y + SIGN(dy));
1273 if (!IN_SCR_FIELD(x, y))
1275 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1276 printf("DrawGraphicShifted(): This should never happen!\n");
1281 width = width * TILESIZE_VAR / TILESIZE;
1282 height = height * TILESIZE_VAR / TILESIZE;
1283 cx = cx * TILESIZE_VAR / TILESIZE;
1284 cy = cy * TILESIZE_VAR / TILESIZE;
1285 dx = dx * TILESIZE_VAR / TILESIZE;
1286 dy = dy * TILESIZE_VAR / TILESIZE;
1288 if (width > 0 && height > 0)
1290 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1295 dst_x = FX + x * TILEX_VAR + dx;
1296 dst_y = FY + y * TILEY_VAR + dy;
1298 if (mask_mode == USE_MASKING)
1299 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1302 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1305 MarkTileDirty(x, y);
1309 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
1310 int graphic, int frame,
1311 int cut_mode, int mask_mode)
1316 int width = TILEX_VAR, height = TILEY_VAR;
1319 int x2 = x + SIGN(dx);
1320 int y2 = y + SIGN(dy);
1322 /* movement with two-tile animations must be sync'ed with movement position,
1323 not with current GfxFrame (which can be higher when using slow movement) */
1324 int anim_pos = (dx ? ABS(dx) : ABS(dy));
1325 int anim_frames = graphic_info[graphic].anim_frames;
1327 /* (we also need anim_delay here for movement animations with less frames) */
1328 int anim_delay = graphic_info[graphic].anim_delay;
1329 int sync_frame = anim_pos * anim_frames * anim_delay / TILESIZE;
1331 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
1332 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
1334 /* re-calculate animation frame for two-tile movement animation */
1335 frame = getGraphicAnimationFrame(graphic, sync_frame);
1337 /* check if movement start graphic inside screen area and should be drawn */
1338 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
1340 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
1342 dst_x = FX + x1 * TILEX_VAR;
1343 dst_y = FY + y1 * TILEY_VAR;
1345 if (mask_mode == USE_MASKING)
1346 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1349 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1352 MarkTileDirty(x1, y1);
1355 /* check if movement end graphic inside screen area and should be drawn */
1356 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
1358 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
1360 dst_x = FX + x2 * TILEX_VAR;
1361 dst_y = FY + y2 * TILEY_VAR;
1363 if (mask_mode == USE_MASKING)
1364 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1367 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1370 MarkTileDirty(x2, y2);
1374 static void DrawGraphicShifted(int x, int y, int dx, int dy,
1375 int graphic, int frame,
1376 int cut_mode, int mask_mode)
1380 DrawGraphic(x, y, graphic, frame);
1385 if (graphic_info[graphic].double_movement) /* EM style movement images */
1386 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1388 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1391 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1392 int frame, int cut_mode)
1394 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
1397 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1398 int cut_mode, int mask_mode)
1400 int lx = LEVELX(x), ly = LEVELY(y);
1404 if (IN_LEV_FIELD(lx, ly))
1406 SetRandomAnimationValue(lx, ly);
1408 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
1409 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1411 /* do not use double (EM style) movement graphic when not moving */
1412 if (graphic_info[graphic].double_movement && !dx && !dy)
1414 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
1415 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1418 else /* border element */
1420 graphic = el2img(element);
1421 frame = getGraphicAnimationFrame(graphic, -1);
1424 if (element == EL_EXPANDABLE_WALL)
1426 boolean left_stopped = FALSE, right_stopped = FALSE;
1428 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1429 left_stopped = TRUE;
1430 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1431 right_stopped = TRUE;
1433 if (left_stopped && right_stopped)
1435 else if (left_stopped)
1437 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1438 frame = graphic_info[graphic].anim_frames - 1;
1440 else if (right_stopped)
1442 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1443 frame = graphic_info[graphic].anim_frames - 1;
1448 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1449 else if (mask_mode == USE_MASKING)
1450 DrawGraphicThruMask(x, y, graphic, frame);
1452 DrawGraphic(x, y, graphic, frame);
1455 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1456 int cut_mode, int mask_mode)
1458 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1459 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1460 cut_mode, mask_mode);
1463 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1466 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1469 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1472 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1475 void DrawLevelElementThruMask(int x, int y, int element)
1477 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1480 void DrawLevelFieldThruMask(int x, int y)
1482 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1485 /* !!! implementation of quicksand is totally broken !!! */
1486 #define IS_CRUMBLED_TILE(x, y, e) \
1487 (GFX_CRUMBLED(e) && (!IN_LEV_FIELD(x, y) || \
1488 !IS_MOVING(x, y) || \
1489 (e) == EL_QUICKSAND_EMPTYING || \
1490 (e) == EL_QUICKSAND_FAST_EMPTYING))
1492 static void DrawLevelFieldCrumbledInnerCorners(int x, int y, int dx, int dy,
1497 int width, height, cx, cy;
1498 int sx = SCREENX(x), sy = SCREENY(y);
1499 int crumbled_border_size = graphic_info[graphic].border_size;
1502 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1504 for (i = 1; i < 4; i++)
1506 int dxx = (i & 1 ? dx : 0);
1507 int dyy = (i & 2 ? dy : 0);
1510 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1513 /* check if neighbour field is of same crumble type */
1514 boolean same = (IS_CRUMBLED_TILE(xx, yy, element) &&
1515 graphic_info[graphic].class ==
1516 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class);
1518 /* return if check prevents inner corner */
1519 if (same == (dxx == dx && dyy == dy))
1523 /* if we reach this point, we have an inner corner */
1525 getGraphicSource(graphic, 1, &src_bitmap, &src_x, &src_y);
1527 width = crumbled_border_size * TILESIZE_VAR / TILESIZE;
1528 height = crumbled_border_size * TILESIZE_VAR / TILESIZE;
1529 cx = (dx > 0 ? TILESIZE_VAR - width : 0);
1530 cy = (dy > 0 ? TILESIZE_VAR - height : 0);
1532 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1533 width, height, FX + sx * TILEX_VAR + cx, FY + sy * TILEY_VAR + cy);
1536 static void DrawLevelFieldCrumbledBorders(int x, int y, int graphic, int frame,
1541 int width, height, bx, by, cx, cy;
1542 int sx = SCREENX(x), sy = SCREENY(y);
1543 int crumbled_border_size = graphic_info[graphic].border_size;
1544 int crumbled_border_size_var = crumbled_border_size * TILESIZE_VAR / TILESIZE;
1545 int crumbled_border_pos_var = TILESIZE_VAR - crumbled_border_size_var;
1548 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1550 /* draw simple, sloppy, non-corner-accurate crumbled border */
1552 width = (dir == 1 || dir == 2 ? crumbled_border_size_var : TILESIZE_VAR);
1553 height = (dir == 0 || dir == 3 ? crumbled_border_size_var : TILESIZE_VAR);
1554 cx = (dir == 2 ? crumbled_border_pos_var : 0);
1555 cy = (dir == 3 ? crumbled_border_pos_var : 0);
1557 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy, width, height,
1558 FX + sx * TILEX_VAR + cx,
1559 FY + sy * TILEY_VAR + cy);
1561 /* (remaining middle border part must be at least as big as corner part) */
1562 if (!(graphic_info[graphic].style & STYLE_ACCURATE_BORDERS) ||
1563 crumbled_border_size >= TILESIZE / 3)
1566 /* correct corners of crumbled border, if needed */
1568 for (i = -1; i <= 1; i += 2)
1570 int xx = x + (dir == 0 || dir == 3 ? i : 0);
1571 int yy = y + (dir == 1 || dir == 2 ? i : 0);
1572 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1575 /* check if neighbour field is of same crumble type */
1576 if (IS_CRUMBLED_TILE(xx, yy, element) &&
1577 graphic_info[graphic].class ==
1578 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1580 /* no crumbled corner, but continued crumbled border */
1582 int c1 = (dir == 2 || dir == 3 ? crumbled_border_pos_var : 0);
1583 int c2 = (i == 1 ? crumbled_border_pos_var : 0);
1584 int b1 = (i == 1 ? crumbled_border_size_var :
1585 TILESIZE_VAR - 2 * crumbled_border_size_var);
1587 width = crumbled_border_size_var;
1588 height = crumbled_border_size_var;
1590 if (dir == 1 || dir == 2)
1605 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
1607 FX + sx * TILEX_VAR + cx,
1608 FY + sy * TILEY_VAR + cy);
1613 static void DrawLevelFieldCrumbledExt(int x, int y, int graphic, int frame)
1615 int sx = SCREENX(x), sy = SCREENY(y);
1618 static int xy[4][2] =
1626 if (!IN_LEV_FIELD(x, y))
1629 element = TILE_GFX_ELEMENT(x, y);
1631 /* crumble field itself */
1632 if (IS_CRUMBLED_TILE(x, y, element))
1634 if (!IN_SCR_FIELD(sx, sy))
1637 for (i = 0; i < 4; i++)
1639 int xx = x + xy[i][0];
1640 int yy = y + xy[i][1];
1642 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1645 /* check if neighbour field is of same crumble type */
1646 if (IS_CRUMBLED_TILE(xx, yy, element) &&
1647 graphic_info[graphic].class ==
1648 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1651 DrawLevelFieldCrumbledBorders(x, y, graphic, frame, i);
1654 if ((graphic_info[graphic].style & STYLE_INNER_CORNERS) &&
1655 graphic_info[graphic].anim_frames == 2)
1657 for (i = 0; i < 4; i++)
1659 int dx = (i & 1 ? +1 : -1);
1660 int dy = (i & 2 ? +1 : -1);
1662 DrawLevelFieldCrumbledInnerCorners(x, y, dx, dy, graphic);
1666 MarkTileDirty(sx, sy);
1668 else /* center field not crumbled -- crumble neighbour fields */
1670 for (i = 0; i < 4; i++)
1672 int xx = x + xy[i][0];
1673 int yy = y + xy[i][1];
1674 int sxx = sx + xy[i][0];
1675 int syy = sy + xy[i][1];
1677 if (!IN_LEV_FIELD(xx, yy) ||
1678 !IN_SCR_FIELD(sxx, syy))
1681 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
1684 element = TILE_GFX_ELEMENT(xx, yy);
1686 if (!IS_CRUMBLED_TILE(xx, yy, element))
1689 graphic = el_act2crm(element, ACTION_DEFAULT);
1691 DrawLevelFieldCrumbledBorders(xx, yy, graphic, 0, 3 - i);
1693 MarkTileDirty(sxx, syy);
1698 void DrawLevelFieldCrumbled(int x, int y)
1702 if (!IN_LEV_FIELD(x, y))
1705 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1706 GfxElement[x][y] != EL_UNDEFINED &&
1707 GFX_CRUMBLED(GfxElement[x][y]))
1709 DrawLevelFieldCrumbledDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
1714 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
1716 DrawLevelFieldCrumbledExt(x, y, graphic, 0);
1719 void DrawLevelFieldCrumbledDigging(int x, int y, int direction,
1722 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1723 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1724 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1725 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1726 int sx = SCREENX(x), sy = SCREENY(y);
1728 DrawGraphic(sx, sy, graphic1, frame1);
1729 DrawLevelFieldCrumbledExt(x, y, graphic2, frame2);
1732 void DrawLevelFieldCrumbledNeighbours(int x, int y)
1734 int sx = SCREENX(x), sy = SCREENY(y);
1735 static int xy[4][2] =
1744 for (i = 0; i < 4; i++)
1746 int xx = x + xy[i][0];
1747 int yy = y + xy[i][1];
1748 int sxx = sx + xy[i][0];
1749 int syy = sy + xy[i][1];
1751 if (!IN_LEV_FIELD(xx, yy) ||
1752 !IN_SCR_FIELD(sxx, syy) ||
1753 !GFX_CRUMBLED(Feld[xx][yy]) ||
1757 DrawLevelField(xx, yy);
1761 static int getBorderElement(int x, int y)
1765 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1766 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1767 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1768 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1769 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1770 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1771 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1773 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1774 int steel_position = (x == -1 && y == -1 ? 0 :
1775 x == lev_fieldx && y == -1 ? 1 :
1776 x == -1 && y == lev_fieldy ? 2 :
1777 x == lev_fieldx && y == lev_fieldy ? 3 :
1778 x == -1 || x == lev_fieldx ? 4 :
1779 y == -1 || y == lev_fieldy ? 5 : 6);
1781 return border[steel_position][steel_type];
1784 void DrawScreenElement(int x, int y, int element)
1786 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1787 DrawLevelFieldCrumbled(LEVELX(x), LEVELY(y));
1790 void DrawLevelElement(int x, int y, int element)
1792 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1793 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1796 void DrawScreenField(int x, int y)
1798 int lx = LEVELX(x), ly = LEVELY(y);
1799 int element, content;
1801 if (!IN_LEV_FIELD(lx, ly))
1803 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1806 element = getBorderElement(lx, ly);
1808 DrawScreenElement(x, y, element);
1813 element = Feld[lx][ly];
1814 content = Store[lx][ly];
1816 if (IS_MOVING(lx, ly))
1818 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1819 boolean cut_mode = NO_CUTTING;
1821 if (element == EL_QUICKSAND_EMPTYING ||
1822 element == EL_QUICKSAND_FAST_EMPTYING ||
1823 element == EL_MAGIC_WALL_EMPTYING ||
1824 element == EL_BD_MAGIC_WALL_EMPTYING ||
1825 element == EL_DC_MAGIC_WALL_EMPTYING ||
1826 element == EL_AMOEBA_DROPPING)
1827 cut_mode = CUT_ABOVE;
1828 else if (element == EL_QUICKSAND_FILLING ||
1829 element == EL_QUICKSAND_FAST_FILLING ||
1830 element == EL_MAGIC_WALL_FILLING ||
1831 element == EL_BD_MAGIC_WALL_FILLING ||
1832 element == EL_DC_MAGIC_WALL_FILLING)
1833 cut_mode = CUT_BELOW;
1835 if (cut_mode == CUT_ABOVE)
1836 DrawScreenElement(x, y, element);
1838 DrawScreenElement(x, y, EL_EMPTY);
1841 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1842 else if (cut_mode == NO_CUTTING)
1843 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1846 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1848 if (cut_mode == CUT_BELOW &&
1849 IN_LEV_FIELD(lx, ly + 1) && IN_SCR_FIELD(x, y + 1))
1850 DrawLevelElement(lx, ly + 1, element);
1853 if (content == EL_ACID)
1855 int dir = MovDir[lx][ly];
1856 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
1857 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
1859 DrawLevelElementThruMask(newlx, newly, EL_ACID);
1862 else if (IS_BLOCKED(lx, ly))
1867 boolean cut_mode = NO_CUTTING;
1868 int element_old, content_old;
1870 Blocked2Moving(lx, ly, &oldx, &oldy);
1873 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1874 MovDir[oldx][oldy] == MV_RIGHT);
1876 element_old = Feld[oldx][oldy];
1877 content_old = Store[oldx][oldy];
1879 if (element_old == EL_QUICKSAND_EMPTYING ||
1880 element_old == EL_QUICKSAND_FAST_EMPTYING ||
1881 element_old == EL_MAGIC_WALL_EMPTYING ||
1882 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1883 element_old == EL_DC_MAGIC_WALL_EMPTYING ||
1884 element_old == EL_AMOEBA_DROPPING)
1885 cut_mode = CUT_ABOVE;
1887 DrawScreenElement(x, y, EL_EMPTY);
1890 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1892 else if (cut_mode == NO_CUTTING)
1893 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1896 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1899 else if (IS_DRAWABLE(element))
1900 DrawScreenElement(x, y, element);
1902 DrawScreenElement(x, y, EL_EMPTY);
1905 void DrawLevelField(int x, int y)
1907 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1908 DrawScreenField(SCREENX(x), SCREENY(y));
1909 else if (IS_MOVING(x, y))
1913 Moving2Blocked(x, y, &newx, &newy);
1914 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1915 DrawScreenField(SCREENX(newx), SCREENY(newy));
1917 else if (IS_BLOCKED(x, y))
1921 Blocked2Moving(x, y, &oldx, &oldy);
1922 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1923 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1927 void DrawSizedElement(int x, int y, int element, int tilesize)
1931 graphic = el2edimg(element);
1932 DrawSizedGraphic(x, y, graphic, 0, tilesize);
1935 void DrawMiniElement(int x, int y, int element)
1939 graphic = el2edimg(element);
1940 DrawMiniGraphic(x, y, graphic);
1943 void DrawSizedElementOrWall(int sx, int sy, int scroll_x, int scroll_y,
1946 int x = sx + scroll_x, y = sy + scroll_y;
1948 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1949 DrawSizedElement(sx, sy, EL_EMPTY, tilesize);
1950 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1951 DrawSizedElement(sx, sy, Feld[x][y], tilesize);
1953 DrawSizedGraphic(sx, sy, el2edimg(getBorderElement(x, y)), 0, tilesize);
1956 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1958 int x = sx + scroll_x, y = sy + scroll_y;
1960 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1961 DrawMiniElement(sx, sy, EL_EMPTY);
1962 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1963 DrawMiniElement(sx, sy, Feld[x][y]);
1965 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1968 void DrawEnvelopeBackgroundTiles(int graphic, int startx, int starty,
1969 int x, int y, int xsize, int ysize,
1970 int tile_width, int tile_height)
1974 int dst_x = startx + x * tile_width;
1975 int dst_y = starty + y * tile_height;
1976 int width = graphic_info[graphic].width;
1977 int height = graphic_info[graphic].height;
1978 int inner_width_raw = MAX(width - 2 * tile_width, tile_width);
1979 int inner_height_raw = MAX(height - 2 * tile_height, tile_height);
1980 int inner_width = inner_width_raw - (inner_width_raw % tile_width);
1981 int inner_height = inner_height_raw - (inner_height_raw % tile_height);
1982 int inner_sx = (width >= 3 * tile_width ? tile_width : 0);
1983 int inner_sy = (height >= 3 * tile_height ? tile_height : 0);
1984 boolean draw_masked = graphic_info[graphic].draw_masked;
1986 getFixedGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1988 if (src_bitmap == NULL || width < tile_width || height < tile_height)
1990 ClearRectangle(drawto, dst_x, dst_y, tile_width, tile_height);
1994 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - tile_width :
1995 inner_sx + (x - 1) * tile_width % inner_width);
1996 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - tile_height :
1997 inner_sy + (y - 1) * tile_height % inner_height);
2000 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
2003 BlitBitmap(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
2007 void DrawEnvelopeBackground(int graphic, int startx, int starty,
2008 int x, int y, int xsize, int ysize, int font_nr)
2010 int font_width = getFontWidth(font_nr);
2011 int font_height = getFontHeight(font_nr);
2013 DrawEnvelopeBackgroundTiles(graphic, startx, starty, x, y, xsize, ysize,
2014 font_width, font_height);
2017 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
2019 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2020 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2021 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2022 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2023 boolean no_delay = (tape.warp_forward);
2024 unsigned int anim_delay = 0;
2025 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
2026 int anim_delay_value = (no_delay ? 0 : frame_delay_value) / 2;
2027 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
2028 int font_width = getFontWidth(font_nr);
2029 int font_height = getFontHeight(font_nr);
2030 int max_xsize = level.envelope[envelope_nr].xsize;
2031 int max_ysize = level.envelope[envelope_nr].ysize;
2032 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
2033 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
2034 int xend = max_xsize;
2035 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
2036 int xstep = (xstart < xend ? 1 : 0);
2037 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2039 int end = MAX(xend - xstart, yend - ystart);
2042 for (i = start; i <= end; i++)
2044 int last_frame = end; // last frame of this "for" loop
2045 int x = xstart + i * xstep;
2046 int y = ystart + i * ystep;
2047 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2048 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2049 int sx = SX + (SXSIZE - xsize * font_width) / 2;
2050 int sy = SY + (SYSIZE - ysize * font_height) / 2;
2053 SetDrawtoField(DRAW_FIELDBUFFER);
2055 BlitScreenToBitmap(backbuffer);
2057 SetDrawtoField(DRAW_BACKBUFFER);
2059 for (yy = 0; yy < ysize; yy++)
2060 for (xx = 0; xx < xsize; xx++)
2061 DrawEnvelopeBackground(graphic, sx, sy, xx, yy, xsize, ysize, font_nr);
2063 DrawTextBuffer(sx + font_width, sy + font_height,
2064 level.envelope[envelope_nr].text, font_nr, max_xsize,
2065 xsize - 2, ysize - 2, 0, mask_mode,
2066 level.envelope[envelope_nr].autowrap,
2067 level.envelope[envelope_nr].centered, FALSE);
2069 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2072 SkipUntilDelayReached(&anim_delay, anim_delay_value, &i, last_frame);
2076 void ShowEnvelope(int envelope_nr)
2078 int element = EL_ENVELOPE_1 + envelope_nr;
2079 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2080 int sound_opening = element_info[element].sound[ACTION_OPENING];
2081 int sound_closing = element_info[element].sound[ACTION_CLOSING];
2082 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2083 boolean no_delay = (tape.warp_forward);
2084 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
2085 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
2086 int anim_mode = graphic_info[graphic].anim_mode;
2087 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2088 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2090 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
2092 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2094 if (anim_mode == ANIM_DEFAULT)
2095 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
2097 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
2100 Delay(wait_delay_value);
2102 WaitForEventToContinue();
2104 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2106 if (anim_mode != ANIM_NONE)
2107 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
2109 if (anim_mode == ANIM_DEFAULT)
2110 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
2112 game.envelope_active = FALSE;
2114 SetDrawtoField(DRAW_FIELDBUFFER);
2116 redraw_mask |= REDRAW_FIELD;
2120 static void setRequestCenterPosition(int *x, int *y)
2122 int sx_center = (request.x != -1 ? request.x : SX + SXSIZE / 2);
2123 int sy_center = (request.y != -1 ? request.y : SY + SYSIZE / 2);
2129 static void setRequestPosition(int *x, int *y, boolean add_border_size)
2131 int border_size = request.border_size;
2132 int sx_center, sy_center;
2135 setRequestCenterPosition(&sx_center, &sy_center);
2137 sx = sx_center - request.width / 2;
2138 sy = sy_center - request.height / 2;
2140 if (add_border_size)
2150 void DrawEnvelopeRequest(char *text)
2152 char *text_final = text;
2153 char *text_door_style = NULL;
2154 int graphic = IMG_BACKGROUND_REQUEST;
2155 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2156 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2157 int font_nr = FONT_REQUEST;
2158 int font_width = getFontWidth(font_nr);
2159 int font_height = getFontHeight(font_nr);
2160 int border_size = request.border_size;
2161 int line_spacing = request.line_spacing;
2162 int line_height = font_height + line_spacing;
2163 int text_width = request.width - 2 * border_size;
2164 int text_height = request.height - 2 * border_size;
2165 int line_length = text_width / font_width;
2166 int max_lines = text_height / line_height;
2167 int width = request.width;
2168 int height = request.height;
2169 int tile_size = request.step_offset;
2170 int x_steps = width / tile_size;
2171 int y_steps = height / tile_size;
2175 if (request.wrap_single_words)
2177 char *src_text_ptr, *dst_text_ptr;
2179 text_door_style = checked_malloc(2 * strlen(text) + 1);
2181 src_text_ptr = text;
2182 dst_text_ptr = text_door_style;
2184 while (*src_text_ptr)
2186 if (*src_text_ptr == ' ' ||
2187 *src_text_ptr == '?' ||
2188 *src_text_ptr == '!')
2189 *dst_text_ptr++ = '\n';
2191 if (*src_text_ptr != ' ')
2192 *dst_text_ptr++ = *src_text_ptr;
2197 *dst_text_ptr = '\0';
2199 text_final = text_door_style;
2202 setRequestPosition(&sx, &sy, FALSE);
2204 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
2206 for (y = 0; y < y_steps; y++)
2207 for (x = 0; x < x_steps; x++)
2208 DrawEnvelopeBackgroundTiles(graphic, sx, sy,
2209 x, y, x_steps, y_steps,
2210 tile_size, tile_size);
2212 DrawTextBuffer(sx + border_size, sy + border_size, text_final, font_nr,
2213 line_length, -1, max_lines, line_spacing, mask_mode,
2214 request.autowrap, request.centered, FALSE);
2216 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2217 RedrawGadget(tool_gadget[i]);
2219 // store readily prepared envelope request for later use when animating
2220 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2222 if (text_door_style)
2223 free(text_door_style);
2226 void AnimateEnvelopeRequest(int anim_mode, int action)
2228 int graphic = IMG_BACKGROUND_REQUEST;
2229 boolean draw_masked = graphic_info[graphic].draw_masked;
2230 int delay_value_normal = request.step_delay;
2231 int delay_value_fast = delay_value_normal / 2;
2232 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2233 boolean no_delay = (tape.warp_forward);
2234 int delay_value = (ffwd_delay ? delay_value_fast : delay_value_normal);
2235 int anim_delay_value = (no_delay ? 0 : delay_value + 500 * 0) / 2;
2236 unsigned int anim_delay = 0;
2238 int width = request.width;
2239 int height = request.height;
2240 int tile_size = request.step_offset;
2241 int max_xsize = width / tile_size;
2242 int max_ysize = height / tile_size;
2243 int max_xsize_inner = max_xsize - 2;
2244 int max_ysize_inner = max_ysize - 2;
2246 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize_inner : 0);
2247 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize_inner : 0);
2248 int xend = max_xsize_inner;
2249 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize_inner : 0);
2250 int xstep = (xstart < xend ? 1 : 0);
2251 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2253 int end = MAX(xend - xstart, yend - ystart);
2256 if (setup.quick_doors)
2264 if (action == ACTION_OPENING)
2265 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2266 else if (action == ACTION_CLOSING)
2267 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2270 for (i = start; i <= end; i++)
2272 int last_frame = end; // last frame of this "for" loop
2273 int x = xstart + i * xstep;
2274 int y = ystart + i * ystep;
2275 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2276 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2277 int xsize_size_left = (xsize - 1) * tile_size;
2278 int ysize_size_top = (ysize - 1) * tile_size;
2279 int max_xsize_pos = (max_xsize - 1) * tile_size;
2280 int max_ysize_pos = (max_ysize - 1) * tile_size;
2281 int sx_center, sy_center;
2286 setRequestCenterPosition(&sx_center, &sy_center);
2288 src_x = sx_center - width / 2;
2289 src_y = sy_center - height / 2;
2290 dst_x = sx_center - xsize * tile_size / 2;
2291 dst_y = sy_center - ysize * tile_size / 2;
2293 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2295 for (yy = 0; yy < 2; yy++)
2297 for (xx = 0; xx < 2; xx++)
2299 int src_xx = src_x + xx * max_xsize_pos;
2300 int src_yy = src_y + yy * max_ysize_pos;
2301 int dst_xx = dst_x + xx * xsize_size_left;
2302 int dst_yy = dst_y + yy * ysize_size_top;
2303 int xx_size = (xx ? tile_size : xsize_size_left);
2304 int yy_size = (yy ? tile_size : ysize_size_top);
2307 BlitBitmapMasked(bitmap_db_cross, backbuffer,
2308 src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
2310 BlitBitmap(bitmap_db_cross, backbuffer,
2311 src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
2315 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2320 SkipUntilDelayReached(&anim_delay, anim_delay_value, &i, last_frame);
2325 void ShowEnvelopeRequest(char *text, unsigned int req_state, int action)
2327 int last_game_status = game_status; /* save current game status */
2328 int graphic = IMG_BACKGROUND_REQUEST;
2329 int sound_opening = SND_REQUEST_OPENING;
2330 int sound_closing = SND_REQUEST_CLOSING;
2331 int anim_mode = graphic_info[graphic].anim_mode;
2332 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2333 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2335 if (game_status == GAME_MODE_PLAYING)
2336 BlitScreenToBitmap(backbuffer);
2338 SetDrawtoField(DRAW_BACKBUFFER);
2340 // SetDrawBackgroundMask(REDRAW_NONE);
2342 if (action == ACTION_OPENING)
2344 BlitBitmap(backbuffer, bitmap_db_store, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2346 if (req_state & REQ_ASK)
2348 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2349 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2351 else if (req_state & REQ_CONFIRM)
2353 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2355 else if (req_state & REQ_PLAYER)
2357 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2358 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2359 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2360 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2363 DrawEnvelopeRequest(text);
2365 if (game_status != GAME_MODE_MAIN)
2369 /* force DOOR font inside door area */
2370 game_status = GAME_MODE_PSEUDO_DOOR;
2372 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
2374 if (action == ACTION_OPENING)
2376 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2378 if (anim_mode == ANIM_DEFAULT)
2379 AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_OPENING);
2381 AnimateEnvelopeRequest(main_anim_mode, ACTION_OPENING);
2385 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2387 if (anim_mode != ANIM_NONE)
2388 AnimateEnvelopeRequest(main_anim_mode, ACTION_CLOSING);
2390 if (anim_mode == ANIM_DEFAULT)
2391 AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_CLOSING);
2394 game.envelope_active = FALSE;
2396 game_status = last_game_status; /* restore current game status */
2398 if (action == ACTION_CLOSING)
2400 if (game_status != GAME_MODE_MAIN)
2403 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2406 // SetDrawBackgroundMask(last_draw_background_mask);
2408 redraw_mask |= REDRAW_FIELD;
2410 if (game_status == GAME_MODE_MAIN)
2415 if (action == ACTION_CLOSING &&
2416 game_status == GAME_MODE_PLAYING &&
2417 level.game_engine_type == GAME_ENGINE_TYPE_RND)
2418 SetDrawtoField(DRAW_FIELDBUFFER);
2421 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
2425 int graphic = el2preimg(element);
2427 getSizedGraphicSource(graphic, 0, tilesize, &src_bitmap, &src_x, &src_y);
2428 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
2431 void DrawLevel(int draw_background_mask)
2435 SetMainBackgroundImage(IMG_BACKGROUND_PLAYING);
2436 SetDrawBackgroundMask(draw_background_mask);
2440 for (x = BX1; x <= BX2; x++)
2441 for (y = BY1; y <= BY2; y++)
2442 DrawScreenField(x, y);
2444 redraw_mask |= REDRAW_FIELD;
2447 void DrawSizedLevel(int size_x, int size_y, int scroll_x, int scroll_y,
2452 for (x = 0; x < size_x; x++)
2453 for (y = 0; y < size_y; y++)
2454 DrawSizedElementOrWall(x, y, scroll_x, scroll_y, tilesize);
2456 redraw_mask |= REDRAW_FIELD;
2459 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
2463 for (x = 0; x < size_x; x++)
2464 for (y = 0; y < size_y; y++)
2465 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
2467 redraw_mask |= REDRAW_FIELD;
2470 static void DrawPreviewLevelPlayfieldExt(int from_x, int from_y)
2472 boolean show_level_border = (BorderElement != EL_EMPTY);
2473 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2474 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2475 int tile_size = preview.tile_size;
2476 int preview_width = preview.xsize * tile_size;
2477 int preview_height = preview.ysize * tile_size;
2478 int real_preview_xsize = MIN(level_xsize, preview.xsize);
2479 int real_preview_ysize = MIN(level_ysize, preview.ysize);
2480 int real_preview_width = real_preview_xsize * tile_size;
2481 int real_preview_height = real_preview_ysize * tile_size;
2482 int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
2483 int dst_y = SY + ALIGNED_YPOS(preview.y, preview_height, preview.valign);
2486 if (!IN_GFX_FIELD_FULL(dst_x, dst_y + preview_height - 1))
2489 DrawBackground(dst_x, dst_y, preview_width, preview_height);
2491 dst_x += (preview_width - real_preview_width) / 2;
2492 dst_y += (preview_height - real_preview_height) / 2;
2494 for (x = 0; x < real_preview_xsize; x++)
2496 for (y = 0; y < real_preview_ysize; y++)
2498 int lx = from_x + x + (show_level_border ? -1 : 0);
2499 int ly = from_y + y + (show_level_border ? -1 : 0);
2500 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
2501 getBorderElement(lx, ly));
2503 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
2504 element, tile_size);
2508 redraw_mask |= REDRAW_MICROLEVEL;
2511 #define MICROLABEL_EMPTY 0
2512 #define MICROLABEL_LEVEL_NAME 1
2513 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
2514 #define MICROLABEL_LEVEL_AUTHOR 3
2515 #define MICROLABEL_IMPORTED_FROM_HEAD 4
2516 #define MICROLABEL_IMPORTED_FROM 5
2517 #define MICROLABEL_IMPORTED_BY_HEAD 6
2518 #define MICROLABEL_IMPORTED_BY 7
2520 static int getMaxTextLength(struct TextPosInfo *pos, int font_nr)
2522 int max_text_width = SXSIZE;
2523 int font_width = getFontWidth(font_nr);
2525 if (pos->align == ALIGN_CENTER)
2526 max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
2527 else if (pos->align == ALIGN_RIGHT)
2528 max_text_width = pos->x;
2530 max_text_width = SXSIZE - pos->x;
2532 return max_text_width / font_width;
2535 static void DrawPreviewLevelLabelExt(int mode)
2537 struct TextPosInfo *pos = &menu.main.text.level_info_2;
2538 char label_text[MAX_OUTPUT_LINESIZE + 1];
2539 int max_len_label_text;
2540 int font_nr = pos->font;
2543 if (!IN_GFX_FIELD_FULL(pos->x, pos->y + getFontHeight(pos->font)))
2546 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
2547 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
2548 mode == MICROLABEL_IMPORTED_BY_HEAD)
2549 font_nr = pos->font_alt;
2551 max_len_label_text = getMaxTextLength(pos, font_nr);
2553 if (pos->size != -1)
2554 max_len_label_text = pos->size;
2556 for (i = 0; i < max_len_label_text; i++)
2557 label_text[i] = ' ';
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);
2564 (mode == MICROLABEL_LEVEL_NAME ? level.name :
2565 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
2566 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
2567 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
2568 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
2569 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
2570 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
2571 max_len_label_text);
2572 label_text[max_len_label_text] = '\0';
2574 if (strlen(label_text) > 0)
2575 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2577 redraw_mask |= REDRAW_MICROLEVEL;
2580 static void DrawPreviewLevelExt(boolean restart)
2582 static unsigned int scroll_delay = 0;
2583 static unsigned int label_delay = 0;
2584 static int from_x, from_y, scroll_direction;
2585 static int label_state, label_counter;
2586 unsigned int scroll_delay_value = preview.step_delay;
2587 boolean show_level_border = (BorderElement != EL_EMPTY);
2588 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2589 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2590 int last_game_status = game_status; /* save current game status */
2597 if (preview.anim_mode == ANIM_CENTERED)
2599 if (level_xsize > preview.xsize)
2600 from_x = (level_xsize - preview.xsize) / 2;
2601 if (level_ysize > preview.ysize)
2602 from_y = (level_ysize - preview.ysize) / 2;
2605 from_x += preview.xoffset;
2606 from_y += preview.yoffset;
2608 scroll_direction = MV_RIGHT;
2612 DrawPreviewLevelPlayfieldExt(from_x, from_y);
2613 DrawPreviewLevelLabelExt(label_state);
2615 /* initialize delay counters */
2616 DelayReached(&scroll_delay, 0);
2617 DelayReached(&label_delay, 0);
2619 if (leveldir_current->name)
2621 struct TextPosInfo *pos = &menu.main.text.level_info_1;
2622 char label_text[MAX_OUTPUT_LINESIZE + 1];
2623 int font_nr = pos->font;
2624 int max_len_label_text = getMaxTextLength(pos, font_nr);
2626 if (pos->size != -1)
2627 max_len_label_text = pos->size;
2629 strncpy(label_text, leveldir_current->name, max_len_label_text);
2630 label_text[max_len_label_text] = '\0';
2632 if (IN_GFX_FIELD_FULL(pos->x, pos->y + getFontHeight(pos->font)))
2633 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2636 game_status = last_game_status; /* restore current game status */
2641 /* scroll preview level, if needed */
2642 if (preview.anim_mode != ANIM_NONE &&
2643 (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
2644 DelayReached(&scroll_delay, scroll_delay_value))
2646 switch (scroll_direction)
2651 from_x -= preview.step_offset;
2652 from_x = (from_x < 0 ? 0 : from_x);
2655 scroll_direction = MV_UP;
2659 if (from_x < level_xsize - preview.xsize)
2661 from_x += preview.step_offset;
2662 from_x = (from_x > level_xsize - preview.xsize ?
2663 level_xsize - preview.xsize : from_x);
2666 scroll_direction = MV_DOWN;
2672 from_y -= preview.step_offset;
2673 from_y = (from_y < 0 ? 0 : from_y);
2676 scroll_direction = MV_RIGHT;
2680 if (from_y < level_ysize - preview.ysize)
2682 from_y += preview.step_offset;
2683 from_y = (from_y > level_ysize - preview.ysize ?
2684 level_ysize - preview.ysize : from_y);
2687 scroll_direction = MV_LEFT;
2694 DrawPreviewLevelPlayfieldExt(from_x, from_y);
2697 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
2698 /* redraw micro level label, if needed */
2699 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
2700 !strEqual(level.author, ANONYMOUS_NAME) &&
2701 !strEqual(level.author, leveldir_current->name) &&
2702 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
2704 int max_label_counter = 23;
2706 if (leveldir_current->imported_from != NULL &&
2707 strlen(leveldir_current->imported_from) > 0)
2708 max_label_counter += 14;
2709 if (leveldir_current->imported_by != NULL &&
2710 strlen(leveldir_current->imported_by) > 0)
2711 max_label_counter += 14;
2713 label_counter = (label_counter + 1) % max_label_counter;
2714 label_state = (label_counter >= 0 && label_counter <= 7 ?
2715 MICROLABEL_LEVEL_NAME :
2716 label_counter >= 9 && label_counter <= 12 ?
2717 MICROLABEL_LEVEL_AUTHOR_HEAD :
2718 label_counter >= 14 && label_counter <= 21 ?
2719 MICROLABEL_LEVEL_AUTHOR :
2720 label_counter >= 23 && label_counter <= 26 ?
2721 MICROLABEL_IMPORTED_FROM_HEAD :
2722 label_counter >= 28 && label_counter <= 35 ?
2723 MICROLABEL_IMPORTED_FROM :
2724 label_counter >= 37 && label_counter <= 40 ?
2725 MICROLABEL_IMPORTED_BY_HEAD :
2726 label_counter >= 42 && label_counter <= 49 ?
2727 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
2729 if (leveldir_current->imported_from == NULL &&
2730 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
2731 label_state == MICROLABEL_IMPORTED_FROM))
2732 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
2733 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
2735 DrawPreviewLevelLabelExt(label_state);
2738 game_status = last_game_status; /* restore current game status */
2741 void DrawPreviewLevelInitial()
2743 DrawPreviewLevelExt(TRUE);
2746 void DrawPreviewLevelAnimation()
2748 DrawPreviewLevelExt(FALSE);
2751 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
2752 int graphic, int sync_frame, int mask_mode)
2754 int frame = getGraphicAnimationFrame(graphic, sync_frame);
2756 if (mask_mode == USE_MASKING)
2757 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
2759 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
2762 inline void DrawFixedGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
2763 int graphic, int sync_frame,
2766 int frame = getGraphicAnimationFrame(graphic, sync_frame);
2768 if (mask_mode == USE_MASKING)
2769 DrawFixedGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
2771 DrawFixedGraphicExt(dst_bitmap, x, y, graphic, frame);
2774 inline void DrawGraphicAnimation(int x, int y, int graphic)
2776 int lx = LEVELX(x), ly = LEVELY(y);
2778 if (!IN_SCR_FIELD(x, y))
2781 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
2782 graphic, GfxFrame[lx][ly], NO_MASKING);
2784 MarkTileDirty(x, y);
2787 inline void DrawFixedGraphicAnimation(int x, int y, int graphic)
2789 int lx = LEVELX(x), ly = LEVELY(y);
2791 if (!IN_SCR_FIELD(x, y))
2794 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
2795 graphic, GfxFrame[lx][ly], NO_MASKING);
2796 MarkTileDirty(x, y);
2799 void DrawLevelGraphicAnimation(int x, int y, int graphic)
2801 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2804 void DrawLevelElementAnimation(int x, int y, int element)
2806 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2808 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2811 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
2813 int sx = SCREENX(x), sy = SCREENY(y);
2815 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2818 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2821 DrawGraphicAnimation(sx, sy, graphic);
2824 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
2825 DrawLevelFieldCrumbled(x, y);
2827 if (GFX_CRUMBLED(Feld[x][y]))
2828 DrawLevelFieldCrumbled(x, y);
2832 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
2834 int sx = SCREENX(x), sy = SCREENY(y);
2837 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2840 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2842 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2845 DrawGraphicAnimation(sx, sy, graphic);
2847 if (GFX_CRUMBLED(element))
2848 DrawLevelFieldCrumbled(x, y);
2851 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
2853 if (player->use_murphy)
2855 /* this works only because currently only one player can be "murphy" ... */
2856 static int last_horizontal_dir = MV_LEFT;
2857 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
2859 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2860 last_horizontal_dir = move_dir;
2862 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
2864 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
2866 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
2872 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
2875 static boolean equalGraphics(int graphic1, int graphic2)
2877 struct GraphicInfo *g1 = &graphic_info[graphic1];
2878 struct GraphicInfo *g2 = &graphic_info[graphic2];
2880 return (g1->bitmap == g2->bitmap &&
2881 g1->src_x == g2->src_x &&
2882 g1->src_y == g2->src_y &&
2883 g1->anim_frames == g2->anim_frames &&
2884 g1->anim_delay == g2->anim_delay &&
2885 g1->anim_mode == g2->anim_mode);
2888 void DrawAllPlayers()
2892 for (i = 0; i < MAX_PLAYERS; i++)
2893 if (stored_player[i].active)
2894 DrawPlayer(&stored_player[i]);
2897 void DrawPlayerField(int x, int y)
2899 if (!IS_PLAYER(x, y))
2902 DrawPlayer(PLAYERINFO(x, y));
2905 #define DRAW_PLAYER_OVER_PUSHED_ELEMENT 1
2907 void DrawPlayer(struct PlayerInfo *player)
2909 int jx = player->jx;
2910 int jy = player->jy;
2911 int move_dir = player->MovDir;
2912 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
2913 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
2914 int last_jx = (player->is_moving ? jx - dx : jx);
2915 int last_jy = (player->is_moving ? jy - dy : jy);
2916 int next_jx = jx + dx;
2917 int next_jy = jy + dy;
2918 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
2919 boolean player_is_opaque = FALSE;
2920 int sx = SCREENX(jx), sy = SCREENY(jy);
2921 int sxx = 0, syy = 0;
2922 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
2924 int action = ACTION_DEFAULT;
2925 int last_player_graphic = getPlayerGraphic(player, move_dir);
2926 int last_player_frame = player->Frame;
2929 /* GfxElement[][] is set to the element the player is digging or collecting;
2930 remove also for off-screen player if the player is not moving anymore */
2931 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
2932 GfxElement[jx][jy] = EL_UNDEFINED;
2934 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
2938 if (!IN_LEV_FIELD(jx, jy))
2940 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
2941 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
2942 printf("DrawPlayerField(): This should never happen!\n");
2947 if (element == EL_EXPLOSION)
2950 action = (player->is_pushing ? ACTION_PUSHING :
2951 player->is_digging ? ACTION_DIGGING :
2952 player->is_collecting ? ACTION_COLLECTING :
2953 player->is_moving ? ACTION_MOVING :
2954 player->is_snapping ? ACTION_SNAPPING :
2955 player->is_dropping ? ACTION_DROPPING :
2956 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
2958 if (player->is_waiting)
2959 move_dir = player->dir_waiting;
2961 InitPlayerGfxAnimation(player, action, move_dir);
2963 /* ----------------------------------------------------------------------- */
2964 /* draw things in the field the player is leaving, if needed */
2965 /* ----------------------------------------------------------------------- */
2967 if (player->is_moving)
2969 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
2971 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
2973 if (last_element == EL_DYNAMITE_ACTIVE ||
2974 last_element == EL_EM_DYNAMITE_ACTIVE ||
2975 last_element == EL_SP_DISK_RED_ACTIVE)
2976 DrawDynamite(last_jx, last_jy);
2978 DrawLevelFieldThruMask(last_jx, last_jy);
2980 else if (last_element == EL_DYNAMITE_ACTIVE ||
2981 last_element == EL_EM_DYNAMITE_ACTIVE ||
2982 last_element == EL_SP_DISK_RED_ACTIVE)
2983 DrawDynamite(last_jx, last_jy);
2985 /* !!! this is not enough to prevent flickering of players which are
2986 moving next to each others without a free tile between them -- this
2987 can only be solved by drawing all players layer by layer (first the
2988 background, then the foreground etc.) !!! => TODO */
2989 else if (!IS_PLAYER(last_jx, last_jy))
2990 DrawLevelField(last_jx, last_jy);
2993 DrawLevelField(last_jx, last_jy);
2996 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
2997 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
3000 if (!IN_SCR_FIELD(sx, sy))
3003 /* ----------------------------------------------------------------------- */
3004 /* draw things behind the player, if needed */
3005 /* ----------------------------------------------------------------------- */
3008 DrawLevelElement(jx, jy, Back[jx][jy]);
3009 else if (IS_ACTIVE_BOMB(element))
3010 DrawLevelElement(jx, jy, EL_EMPTY);
3013 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
3015 int old_element = GfxElement[jx][jy];
3016 int old_graphic = el_act_dir2img(old_element, action, move_dir);
3017 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
3019 if (GFX_CRUMBLED(old_element))
3020 DrawLevelFieldCrumbledDigging(jx, jy, move_dir, player->StepFrame);
3022 DrawGraphic(sx, sy, old_graphic, frame);
3024 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
3025 player_is_opaque = TRUE;
3029 GfxElement[jx][jy] = EL_UNDEFINED;
3031 /* make sure that pushed elements are drawn with correct frame rate */
3032 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
3034 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
3035 GfxFrame[jx][jy] = player->StepFrame;
3037 DrawLevelField(jx, jy);
3041 #if !DRAW_PLAYER_OVER_PUSHED_ELEMENT
3042 /* ----------------------------------------------------------------------- */
3043 /* draw player himself */
3044 /* ----------------------------------------------------------------------- */
3046 graphic = getPlayerGraphic(player, move_dir);
3048 /* in the case of changed player action or direction, prevent the current
3049 animation frame from being restarted for identical animations */
3050 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
3051 player->Frame = last_player_frame;
3053 frame = getGraphicAnimationFrame(graphic, player->Frame);
3057 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3058 sxx = player->GfxPos;
3060 syy = player->GfxPos;
3063 if (player_is_opaque)
3064 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
3066 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3068 if (SHIELD_ON(player))
3070 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
3071 IMG_SHIELD_NORMAL_ACTIVE);
3072 int frame = getGraphicAnimationFrame(graphic, -1);
3074 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3078 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
3081 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3082 sxx = player->GfxPos;
3084 syy = player->GfxPos;
3088 /* ----------------------------------------------------------------------- */
3089 /* draw things the player is pushing, if needed */
3090 /* ----------------------------------------------------------------------- */
3092 if (player->is_pushing && player->is_moving)
3094 int px = SCREENX(jx), py = SCREENY(jy);
3095 int pxx = (TILEX - ABS(sxx)) * dx;
3096 int pyy = (TILEY - ABS(syy)) * dy;
3097 int gfx_frame = GfxFrame[jx][jy];
3103 if (!IS_MOVING(jx, jy)) /* push movement already finished */
3105 element = Feld[next_jx][next_jy];
3106 gfx_frame = GfxFrame[next_jx][next_jy];
3109 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
3111 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
3112 frame = getGraphicAnimationFrame(graphic, sync_frame);
3114 /* draw background element under pushed element (like the Sokoban field) */
3115 if (game.use_masked_pushing && IS_MOVING(jx, jy))
3117 /* this allows transparent pushing animation over non-black background */
3120 DrawLevelElement(jx, jy, Back[jx][jy]);
3122 DrawLevelElement(jx, jy, EL_EMPTY);
3124 if (Back[next_jx][next_jy])
3125 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3127 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
3129 else if (Back[next_jx][next_jy])
3130 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3133 /* do not draw (EM style) pushing animation when pushing is finished */
3134 /* (two-tile animations usually do not contain start and end frame) */
3135 if (graphic_info[graphic].double_movement && !IS_MOVING(jx, jy))
3136 DrawLevelElement(next_jx, next_jy, Feld[next_jx][next_jy]);
3138 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3140 /* masked drawing is needed for EMC style (double) movement graphics */
3141 /* !!! (ONLY WHEN DRAWING PUSHED ELEMENT OVER THE PLAYER) !!! */
3142 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3146 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
3147 /* ----------------------------------------------------------------------- */
3148 /* draw player himself */
3149 /* ----------------------------------------------------------------------- */
3151 graphic = getPlayerGraphic(player, move_dir);
3153 /* in the case of changed player action or direction, prevent the current
3154 animation frame from being restarted for identical animations */
3155 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
3156 player->Frame = last_player_frame;
3158 frame = getGraphicAnimationFrame(graphic, player->Frame);
3162 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3163 sxx = player->GfxPos;
3165 syy = player->GfxPos;
3168 if (player_is_opaque)
3169 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
3171 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3173 if (SHIELD_ON(player))
3175 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
3176 IMG_SHIELD_NORMAL_ACTIVE);
3177 int frame = getGraphicAnimationFrame(graphic, -1);
3179 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3183 /* ----------------------------------------------------------------------- */
3184 /* draw things in front of player (active dynamite or dynabombs) */
3185 /* ----------------------------------------------------------------------- */
3187 if (IS_ACTIVE_BOMB(element))
3189 graphic = el2img(element);
3190 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
3192 if (game.emulation == EMU_SUPAPLEX)
3193 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
3195 DrawGraphicThruMask(sx, sy, graphic, frame);
3198 if (player_is_moving && last_element == EL_EXPLOSION)
3200 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
3201 GfxElement[last_jx][last_jy] : EL_EMPTY);
3202 int graphic = el_act2img(element, ACTION_EXPLODING);
3203 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
3204 int phase = ExplodePhase[last_jx][last_jy] - 1;
3205 int frame = getGraphicAnimationFrame(graphic, phase - delay);
3208 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
3211 /* ----------------------------------------------------------------------- */
3212 /* draw elements the player is just walking/passing through/under */
3213 /* ----------------------------------------------------------------------- */
3215 if (player_is_moving)
3217 /* handle the field the player is leaving ... */
3218 if (IS_ACCESSIBLE_INSIDE(last_element))
3219 DrawLevelField(last_jx, last_jy);
3220 else if (IS_ACCESSIBLE_UNDER(last_element))
3221 DrawLevelFieldThruMask(last_jx, last_jy);
3224 /* do not redraw accessible elements if the player is just pushing them */
3225 if (!player_is_moving || !player->is_pushing)
3227 /* ... and the field the player is entering */
3228 if (IS_ACCESSIBLE_INSIDE(element))
3229 DrawLevelField(jx, jy);
3230 else if (IS_ACCESSIBLE_UNDER(element))
3231 DrawLevelFieldThruMask(jx, jy);
3234 MarkTileDirty(sx, sy);
3237 /* ------------------------------------------------------------------------- */
3239 void WaitForEventToContinue()
3241 boolean still_wait = TRUE;
3243 /* simulate releasing mouse button over last gadget, if still pressed */
3245 HandleGadgets(-1, -1, 0);
3247 button_status = MB_RELEASED;
3261 case EVENT_BUTTONPRESS:
3262 case EVENT_KEYPRESS:
3266 case EVENT_KEYRELEASE:
3267 ClearPlayerAction();
3271 HandleOtherEvents(&event);
3275 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3282 /* don't eat all CPU time */
3287 #define MAX_REQUEST_LINES 13
3288 #define MAX_REQUEST_LINE_FONT1_LEN 7
3289 #define MAX_REQUEST_LINE_FONT2_LEN 10
3291 static int RequestHandleEvents(unsigned int req_state)
3293 int last_game_status = game_status; /* save current game status */
3297 button_status = MB_RELEASED;
3299 request_gadget_id = -1;
3308 while (NextValidEvent(&event))
3312 case EVENT_BUTTONPRESS:
3313 case EVENT_BUTTONRELEASE:
3314 case EVENT_MOTIONNOTIFY:
3316 if (event.type == EVENT_MOTIONNOTIFY)
3321 motion_status = TRUE;
3322 mx = ((MotionEvent *) &event)->x;
3323 my = ((MotionEvent *) &event)->y;
3327 motion_status = FALSE;
3328 mx = ((ButtonEvent *) &event)->x;
3329 my = ((ButtonEvent *) &event)->y;
3330 if (event.type == EVENT_BUTTONPRESS)
3331 button_status = ((ButtonEvent *) &event)->button;
3333 button_status = MB_RELEASED;
3336 /* this sets 'request_gadget_id' */
3337 HandleGadgets(mx, my, button_status);
3339 switch (request_gadget_id)
3341 case TOOL_CTRL_ID_YES:
3344 case TOOL_CTRL_ID_NO:
3347 case TOOL_CTRL_ID_CONFIRM:
3348 result = TRUE | FALSE;
3351 case TOOL_CTRL_ID_PLAYER_1:
3354 case TOOL_CTRL_ID_PLAYER_2:
3357 case TOOL_CTRL_ID_PLAYER_3:
3360 case TOOL_CTRL_ID_PLAYER_4:
3371 case EVENT_KEYPRESS:
3372 switch (GetEventKey((KeyEvent *)&event, TRUE))
3375 if (req_state & REQ_CONFIRM)
3380 #if defined(TARGET_SDL2)
3387 #if defined(TARGET_SDL2)
3397 if (req_state & REQ_PLAYER)
3401 case EVENT_KEYRELEASE:
3402 ClearPlayerAction();
3406 HandleOtherEvents(&event);
3411 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3413 int joy = AnyJoystick();
3415 if (joy & JOY_BUTTON_1)
3417 else if (joy & JOY_BUTTON_2)
3421 if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd)
3423 HandleGameActions();
3429 if (!PendingEvent()) /* delay only if no pending events */
3433 game_status = GAME_MODE_PSEUDO_DOOR;
3437 game_status = last_game_status; /* restore current game status */
3443 static boolean RequestDoor(char *text, unsigned int req_state)
3445 unsigned int old_door_state;
3446 int last_game_status = game_status; /* save current game status */
3447 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
3448 int font_nr = FONT_TEXT_2;
3453 if (maxWordLengthInString(text) > MAX_REQUEST_LINE_FONT1_LEN)
3455 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
3456 font_nr = FONT_TEXT_1;
3459 if (game_status == GAME_MODE_PLAYING)
3460 BlitScreenToBitmap(backbuffer);
3462 /* disable deactivated drawing when quick-loading level tape recording */
3463 if (tape.playing && tape.deactivate_display)
3464 TapeDeactivateDisplayOff(TRUE);
3466 SetMouseCursor(CURSOR_DEFAULT);
3468 #if defined(NETWORK_AVALIABLE)
3469 /* pause network game while waiting for request to answer */
3470 if (options.network &&
3471 game_status == GAME_MODE_PLAYING &&
3472 req_state & REQUEST_WAIT_FOR_INPUT)
3473 SendToServer_PausePlaying();
3476 old_door_state = GetDoorState();
3478 /* simulate releasing mouse button over last gadget, if still pressed */
3480 HandleGadgets(-1, -1, 0);
3484 /* draw released gadget before proceeding */
3487 if (old_door_state & DOOR_OPEN_1)
3489 CloseDoor(DOOR_CLOSE_1);
3491 /* save old door content */
3492 BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
3493 0 * DXSIZE, 0, DXSIZE, DYSIZE, 1 * DXSIZE, 0);
3496 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
3497 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3499 /* clear door drawing field */
3500 DrawBackground(DX, DY, DXSIZE, DYSIZE);
3502 /* force DOOR font inside door area */
3503 game_status = GAME_MODE_PSEUDO_DOOR;
3505 /* write text for request */
3506 for (text_ptr = text, ty = 0; ty < MAX_REQUEST_LINES; ty++)
3508 char text_line[max_request_line_len + 1];
3514 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
3516 tc = *(text_ptr + tx);
3517 // if (!tc || tc == ' ')
3518 if (!tc || tc == ' ' || tc == '?' || tc == '!')
3522 if ((tc == '?' || tc == '!') && tl == 0)
3532 strncpy(text_line, text_ptr, tl);
3535 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
3536 DY + 8 + ty * (getFontHeight(font_nr) + 2),
3537 text_line, font_nr);
3539 text_ptr += tl + (tc == ' ' ? 1 : 0);
3540 // text_ptr += tl + (tc == ' ' || tc == '?' || tc == '!' ? 1 : 0);
3543 game_status = last_game_status; /* restore current game status */
3545 if (req_state & REQ_ASK)
3547 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
3548 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
3550 else if (req_state & REQ_CONFIRM)
3552 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
3554 else if (req_state & REQ_PLAYER)
3556 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
3557 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
3558 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
3559 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
3562 /* copy request gadgets to door backbuffer */
3563 BlitBitmap(drawto, bitmap_db_door_1, DX, DY, DXSIZE, DYSIZE, 0, 0);
3565 OpenDoor(DOOR_OPEN_1);
3567 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
3569 if (game_status == GAME_MODE_PLAYING)
3571 SetPanelBackground();
3572 SetDrawBackgroundMask(REDRAW_DOOR_1);
3576 SetDrawBackgroundMask(REDRAW_FIELD);
3582 if (game_status != GAME_MODE_MAIN)
3585 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3587 // ---------- handle request buttons ----------
3588 result = RequestHandleEvents(req_state);
3590 if (game_status != GAME_MODE_MAIN)
3595 if (!(req_state & REQ_STAY_OPEN))
3597 CloseDoor(DOOR_CLOSE_1);
3599 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
3600 (req_state & REQ_REOPEN))
3601 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
3606 if (game_status == GAME_MODE_PLAYING)
3608 SetPanelBackground();
3609 SetDrawBackgroundMask(REDRAW_DOOR_1);
3613 SetDrawBackgroundMask(REDRAW_FIELD);
3616 #if defined(NETWORK_AVALIABLE)
3617 /* continue network game after request */
3618 if (options.network &&
3619 game_status == GAME_MODE_PLAYING &&
3620 req_state & REQUEST_WAIT_FOR_INPUT)
3621 SendToServer_ContinuePlaying();
3624 /* restore deactivated drawing when quick-loading level tape recording */
3625 if (tape.playing && tape.deactivate_display)
3626 TapeDeactivateDisplayOn();
3631 static boolean RequestEnvelope(char *text, unsigned int req_state)
3635 if (game_status == GAME_MODE_PLAYING)
3636 BlitScreenToBitmap(backbuffer);
3638 /* disable deactivated drawing when quick-loading level tape recording */
3639 if (tape.playing && tape.deactivate_display)
3640 TapeDeactivateDisplayOff(TRUE);
3642 SetMouseCursor(CURSOR_DEFAULT);
3644 #if defined(NETWORK_AVALIABLE)
3645 /* pause network game while waiting for request to answer */
3646 if (options.network &&
3647 game_status == GAME_MODE_PLAYING &&
3648 req_state & REQUEST_WAIT_FOR_INPUT)
3649 SendToServer_PausePlaying();
3652 /* simulate releasing mouse button over last gadget, if still pressed */
3654 HandleGadgets(-1, -1, 0);
3658 // (replace with setting corresponding request background)
3659 // SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
3660 // SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3662 /* clear door drawing field */
3663 // DrawBackground(DX, DY, DXSIZE, DYSIZE);
3665 ShowEnvelopeRequest(text, req_state, ACTION_OPENING);
3667 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
3669 if (game_status == GAME_MODE_PLAYING)
3671 SetPanelBackground();
3672 SetDrawBackgroundMask(REDRAW_DOOR_1);
3676 SetDrawBackgroundMask(REDRAW_FIELD);
3682 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3684 // ---------- handle request buttons ----------
3685 result = RequestHandleEvents(req_state);
3687 if (game_status != GAME_MODE_MAIN)
3692 ShowEnvelopeRequest(text, req_state, ACTION_CLOSING);
3696 if (game_status == GAME_MODE_PLAYING)
3698 SetPanelBackground();
3699 SetDrawBackgroundMask(REDRAW_DOOR_1);
3703 SetDrawBackgroundMask(REDRAW_FIELD);
3706 #if defined(NETWORK_AVALIABLE)
3707 /* continue network game after request */
3708 if (options.network &&
3709 game_status == GAME_MODE_PLAYING &&
3710 req_state & REQUEST_WAIT_FOR_INPUT)
3711 SendToServer_ContinuePlaying();
3714 /* restore deactivated drawing when quick-loading level tape recording */
3715 if (tape.playing && tape.deactivate_display)
3716 TapeDeactivateDisplayOn();
3721 boolean Request(char *text, unsigned int req_state)
3723 if (global.use_envelope_request)
3724 return RequestEnvelope(text, req_state);
3726 return RequestDoor(text, req_state);
3729 static int compareDoorPartOrderInfo(const void *object1, const void *object2)
3731 const struct DoorPartOrderInfo *dpo1 = (struct DoorPartOrderInfo *)object1;
3732 const struct DoorPartOrderInfo *dpo2 = (struct DoorPartOrderInfo *)object2;
3735 if (dpo1->sort_priority != dpo2->sort_priority)
3736 compare_result = dpo1->sort_priority - dpo2->sort_priority;
3738 compare_result = dpo1->nr - dpo2->nr;
3740 return compare_result;
3743 void InitGraphicCompatibilityInfo_Doors()
3749 struct DoorInfo *door;
3753 { DOOR_1, IMG_DOOR_1_GFX_PART_1, IMG_DOOR_1_GFX_PART_8, &door_1 },
3754 { DOOR_2, IMG_DOOR_2_GFX_PART_1, IMG_DOOR_2_GFX_PART_8, &door_2 },
3756 { -1, -1, -1, NULL }
3758 struct Rect door_rect_list[] =
3760 { DX, DY, DXSIZE, DYSIZE },
3761 { VX, VY, VXSIZE, VYSIZE }
3765 for (i = 0; doors[i].door_token != -1; i++)
3767 int door_token = doors[i].door_token;
3768 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
3769 int part_1 = doors[i].part_1;
3770 int part_8 = doors[i].part_8;
3771 int part_2 = part_1 + 1;
3772 int part_3 = part_1 + 2;
3773 struct DoorInfo *door = doors[i].door;
3774 struct Rect *door_rect = &door_rect_list[door_index];
3775 boolean door_gfx_redefined = FALSE;
3777 /* check if any door part graphic definitions have been redefined */
3779 for (j = 0; door_part_controls[j].door_token != -1; j++)
3781 struct DoorPartControlInfo *dpc = &door_part_controls[j];
3782 struct FileInfo *fi = getImageListEntryFromImageID(dpc->graphic);
3784 if (dpc->door_token == door_token && fi->redefined)
3785 door_gfx_redefined = TRUE;
3788 /* check for old-style door graphic/animation modifications */
3790 if (!door_gfx_redefined)
3792 if (door->anim_mode & ANIM_STATIC_PANEL)
3794 door->panel.step_xoffset = 0;
3795 door->panel.step_yoffset = 0;
3798 if (door->anim_mode & (ANIM_HORIZONTAL | ANIM_VERTICAL))
3800 struct GraphicInfo *g_part_1 = &graphic_info[part_1];
3801 struct GraphicInfo *g_part_2 = &graphic_info[part_2];
3802 int num_door_steps, num_panel_steps;
3804 /* remove door part graphics other than the two default wings */
3806 for (j = 0; door_part_controls[j].door_token != -1; j++)
3808 struct DoorPartControlInfo *dpc = &door_part_controls[j];
3809 struct GraphicInfo *g = &graphic_info[dpc->graphic];
3811 if (dpc->graphic >= part_3 &&
3812 dpc->graphic <= part_8)
3816 /* set graphics and screen positions of the default wings */
3818 g_part_1->width = door_rect->width;
3819 g_part_1->height = door_rect->height;
3820 g_part_2->width = door_rect->width;
3821 g_part_2->height = door_rect->height;
3822 g_part_2->src_x = door_rect->width;
3823 g_part_2->src_y = g_part_1->src_y;
3825 door->part_2.x = door->part_1.x;
3826 door->part_2.y = door->part_1.y;
3828 if (door->width != -1)
3830 g_part_1->width = door->width;
3831 g_part_2->width = door->width;
3833 // special treatment for graphics and screen position of right wing
3834 g_part_2->src_x += door_rect->width - door->width;
3835 door->part_2.x += door_rect->width - door->width;
3838 if (door->height != -1)
3840 g_part_1->height = door->height;
3841 g_part_2->height = door->height;
3843 // special treatment for graphics and screen position of bottom wing
3844 g_part_2->src_y += door_rect->height - door->height;
3845 door->part_2.y += door_rect->height - door->height;
3848 /* set animation delays for the default wings and panels */
3850 door->part_1.step_delay = door->step_delay;
3851 door->part_2.step_delay = door->step_delay;
3852 door->panel.step_delay = door->step_delay;
3854 /* set animation draw order for the default wings */
3856 door->part_1.sort_priority = 2; /* draw left wing over ... */
3857 door->part_2.sort_priority = 1; /* ... right wing */
3859 /* set animation draw offset for the default wings */
3861 if (door->anim_mode & ANIM_HORIZONTAL)
3863 door->part_1.step_xoffset = door->step_offset;
3864 door->part_1.step_yoffset = 0;
3865 door->part_2.step_xoffset = door->step_offset * -1;
3866 door->part_2.step_yoffset = 0;
3868 num_door_steps = g_part_1->width / door->step_offset;
3870 else // ANIM_VERTICAL
3872 door->part_1.step_xoffset = 0;
3873 door->part_1.step_yoffset = door->step_offset;
3874 door->part_2.step_xoffset = 0;
3875 door->part_2.step_yoffset = door->step_offset * -1;
3877 num_door_steps = g_part_1->height / door->step_offset;
3880 /* set animation draw offset for the default panels */
3882 if (door->step_offset > 1)
3884 num_panel_steps = 2 * door_rect->height / door->step_offset;
3885 door->panel.start_step = num_panel_steps - num_door_steps;
3886 door->panel.start_step_closing = door->panel.start_step;
3890 num_panel_steps = door_rect->height / door->step_offset;
3891 door->panel.start_step = num_panel_steps - num_door_steps / 2;
3892 door->panel.start_step_closing = door->panel.start_step;
3893 door->panel.step_delay *= 2;
3904 for (i = 0; door_part_controls[i].door_token != -1; i++)
3906 struct DoorPartControlInfo *dpc = &door_part_controls[i];
3907 struct DoorPartOrderInfo *dpo = &door_part_order[i];
3909 /* initialize "start_step_opening" and "start_step_closing", if needed */
3910 if (dpc->pos->start_step_opening == 0 &&
3911 dpc->pos->start_step_closing == 0)
3913 // dpc->pos->start_step_opening = dpc->pos->start_step;
3914 dpc->pos->start_step_closing = dpc->pos->start_step;
3917 /* fill structure for door part draw order (sorted below) */
3919 dpo->sort_priority = dpc->pos->sort_priority;
3922 /* sort door part controls according to sort_priority and graphic number */
3923 qsort(door_part_order, MAX_DOOR_PARTS,
3924 sizeof(struct DoorPartOrderInfo), compareDoorPartOrderInfo);
3927 unsigned int OpenDoor(unsigned int door_state)
3929 if (door_state & DOOR_COPY_BACK)
3931 if (door_state & DOOR_OPEN_1)
3932 BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
3933 1 * DXSIZE, 0, DXSIZE, DYSIZE, 0 * DXSIZE, 0);
3935 if (door_state & DOOR_OPEN_2)
3936 BlitBitmap(bitmap_db_door_2, bitmap_db_door_2,
3937 1 * VXSIZE, 0, VXSIZE, VYSIZE, 0 * VXSIZE, 0);
3939 door_state &= ~DOOR_COPY_BACK;
3942 return MoveDoor(door_state);
3945 unsigned int CloseDoor(unsigned int door_state)
3947 unsigned int old_door_state = GetDoorState();
3949 if (!(door_state & DOOR_NO_COPY_BACK))
3951 if (old_door_state & DOOR_OPEN_1)
3952 BlitBitmap(backbuffer, bitmap_db_door_1,
3953 DX, DY, DXSIZE, DYSIZE, 0, 0);
3955 if (old_door_state & DOOR_OPEN_2)
3956 BlitBitmap(backbuffer, bitmap_db_door_2,
3957 VX, VY, VXSIZE, VYSIZE, 0, 0);
3959 door_state &= ~DOOR_NO_COPY_BACK;
3962 return MoveDoor(door_state);
3965 unsigned int GetDoorState()
3967 return MoveDoor(DOOR_GET_STATE);
3970 unsigned int SetDoorState(unsigned int door_state)
3972 return MoveDoor(door_state | DOOR_SET_STATE);
3975 int euclid(int a, int b)
3977 return (b ? euclid(b, a % b) : a);
3980 unsigned int MoveDoor(unsigned int door_state)
3982 struct Rect door_rect_list[] =
3984 { DX, DY, DXSIZE, DYSIZE },
3985 { VX, VY, VXSIZE, VYSIZE }
3987 static int door1 = DOOR_OPEN_1;
3988 static int door2 = DOOR_CLOSE_2;
3989 unsigned int door_delay = 0;
3990 unsigned int door_delay_value;
3993 if (door_state == DOOR_GET_STATE)
3994 return (door1 | door2);
3996 if (door_state & DOOR_SET_STATE)
3998 if (door_state & DOOR_ACTION_1)
3999 door1 = door_state & DOOR_ACTION_1;
4000 if (door_state & DOOR_ACTION_2)
4001 door2 = door_state & DOOR_ACTION_2;
4003 return (door1 | door2);
4006 if (!(door_state & DOOR_FORCE_REDRAW))
4008 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
4009 door_state &= ~DOOR_OPEN_1;
4010 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
4011 door_state &= ~DOOR_CLOSE_1;
4012 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
4013 door_state &= ~DOOR_OPEN_2;
4014 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
4015 door_state &= ~DOOR_CLOSE_2;
4018 if (global.autoplay_leveldir)
4020 door_state |= DOOR_NO_DELAY;
4021 door_state &= ~DOOR_CLOSE_ALL;
4024 if (game_status == GAME_MODE_EDITOR)
4025 door_state |= DOOR_NO_DELAY;
4027 if (door_state & DOOR_ACTION)
4029 boolean door_panel_drawn[NUM_DOORS];
4030 boolean panel_has_doors[NUM_DOORS];
4031 boolean door_part_skip[MAX_DOOR_PARTS];
4032 boolean door_part_done[MAX_DOOR_PARTS];
4033 boolean door_part_done_all;
4034 int num_steps[MAX_DOOR_PARTS];
4035 int max_move_delay = 0; // delay for complete animations of all doors
4036 int max_step_delay = 0; // delay (ms) between two animation frames
4037 int num_move_steps = 0; // number of animation steps for all doors
4038 int max_move_delay_doors_only = 0; // delay for doors only (no panel)
4039 int num_move_steps_doors_only = 0; // steps for doors only (no panel)
4040 int current_move_delay = 0;
4044 for (i = 0; i < NUM_DOORS; i++)
4045 panel_has_doors[i] = FALSE;
4047 for (i = 0; i < MAX_DOOR_PARTS; i++)
4049 struct DoorPartControlInfo *dpc = &door_part_controls[i];
4050 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4051 int door_token = dpc->door_token;
4053 door_part_done[i] = FALSE;
4054 door_part_skip[i] = (!(door_state & door_token) ||
4058 for (i = 0; i < MAX_DOOR_PARTS; i++)
4060 int nr = door_part_order[i].nr;
4061 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
4062 struct DoorPartPosInfo *pos = dpc->pos;
4063 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4064 int door_token = dpc->door_token;
4065 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
4066 boolean is_panel = DOOR_PART_IS_PANEL(nr);
4067 int step_xoffset = ABS(pos->step_xoffset);
4068 int step_yoffset = ABS(pos->step_yoffset);
4069 int step_delay = pos->step_delay;
4070 int current_door_state = door_state & door_token;
4071 boolean door_opening = ((current_door_state & DOOR_OPEN) != 0);
4072 boolean door_closing = ((current_door_state & DOOR_CLOSE) != 0);
4073 boolean part_opening = (is_panel ? door_closing : door_opening);
4074 int start_step = (part_opening ? pos->start_step_opening :
4075 pos->start_step_closing);
4076 float move_xsize = (step_xoffset ? g->width : 0);
4077 float move_ysize = (step_yoffset ? g->height : 0);
4078 int move_xsteps = (step_xoffset ? ceil(move_xsize / step_xoffset) : 0);
4079 int move_ysteps = (step_yoffset ? ceil(move_ysize / step_yoffset) : 0);
4080 int move_steps = (move_xsteps && move_ysteps ?
4081 MIN(move_xsteps, move_ysteps) :
4082 move_xsteps ? move_xsteps : move_ysteps) - start_step;
4083 int move_delay = move_steps * step_delay;
4085 if (door_part_skip[nr])
4088 max_move_delay = MAX(max_move_delay, move_delay);
4089 max_step_delay = (max_step_delay == 0 ? step_delay :
4090 euclid(max_step_delay, step_delay));
4091 num_steps[nr] = move_steps;
4095 max_move_delay_doors_only = MAX(max_move_delay_doors_only, move_delay);
4097 panel_has_doors[door_index] = TRUE;
4101 max_step_delay = MAX(1, max_step_delay); // prevent division by zero
4103 num_move_steps = max_move_delay / max_step_delay;
4104 num_move_steps_doors_only = max_move_delay_doors_only / max_step_delay;
4106 door_delay_value = max_step_delay;
4108 if ((door_state & DOOR_NO_DELAY) || setup.quick_doors)
4110 start = num_move_steps - 1;
4114 /* opening door sound has priority over simultaneously closing door */
4115 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
4116 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
4117 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
4118 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
4121 for (k = start; k < num_move_steps; k++)
4123 int last_frame = num_move_steps - 1; // last frame of this "for" loop
4125 door_part_done_all = TRUE;
4127 for (i = 0; i < NUM_DOORS; i++)
4128 door_panel_drawn[i] = FALSE;
4130 for (i = 0; i < MAX_DOOR_PARTS; i++)
4132 int nr = door_part_order[i].nr;
4133 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
4134 struct DoorPartPosInfo *pos = dpc->pos;
4135 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4136 int door_token = dpc->door_token;
4137 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
4138 boolean is_panel = DOOR_PART_IS_PANEL(nr);
4139 boolean is_panel_and_door_has_closed = FALSE;
4140 struct Rect *door_rect = &door_rect_list[door_index];
4141 Bitmap *bitmap_db_door = (door_token == DOOR_1 ? bitmap_db_door_1 :
4143 Bitmap *bitmap = (is_panel ? bitmap_db_door : g->bitmap);
4144 int current_door_state = door_state & door_token;
4145 boolean door_opening = ((current_door_state & DOOR_OPEN) != 0);
4146 boolean door_closing = !door_opening;
4147 boolean part_opening = (is_panel ? door_closing : door_opening);
4148 boolean part_closing = !part_opening;
4149 int start_step = (part_opening ? pos->start_step_opening :
4150 pos->start_step_closing);
4151 int step_delay = pos->step_delay;
4152 int step_factor = step_delay / max_step_delay;
4153 int k1 = (step_factor ? k / step_factor + 1 : k);
4154 int k2 = (part_opening ? k1 + start_step : num_steps[nr] - k1);
4155 int kk = MAX(0, k2);
4158 int src_x, src_y, src_xx, src_yy;
4159 int dst_x, dst_y, dst_xx, dst_yy;
4162 if (door_part_skip[nr])
4165 if (!(door_state & door_token))
4173 int k2_door = (door_opening ? k : num_move_steps_doors_only - k - 1);
4174 int kk_door = MAX(0, k2_door);
4175 int sync_frame = kk_door * door_delay_value;
4176 int frame = getGraphicAnimationFrame(dpc->graphic, sync_frame);
4178 getGraphicSource(dpc->graphic, frame, &bitmap, &g_src_x, &g_src_y);
4183 if (!door_panel_drawn[door_index])
4185 ClearRectangle(drawto, door_rect->x, door_rect->y,
4186 door_rect->width, door_rect->height);
4188 door_panel_drawn[door_index] = TRUE;
4191 // draw opening or closing door parts
4193 if (pos->step_xoffset < 0) // door part on right side
4196 dst_xx = pos->x + ABS(kk * pos->step_xoffset);
4199 if (dst_xx + width > door_rect->width)
4200 width = door_rect->width - dst_xx;
4202 else // door part on left side
4205 dst_xx = pos->x - kk * pos->step_xoffset;
4209 src_xx = ABS(dst_xx);
4213 width = g->width - src_xx;
4215 // printf("::: k == %d [%d] \n", k, start_step);
4218 if (pos->step_yoffset < 0) // door part on bottom side
4221 dst_yy = pos->y + ABS(kk * pos->step_yoffset);
4224 if (dst_yy + height > door_rect->height)
4225 height = door_rect->height - dst_yy;
4227 else // door part on top side
4230 dst_yy = pos->y - kk * pos->step_yoffset;
4234 src_yy = ABS(dst_yy);
4238 height = g->height - src_yy;
4241 src_x = g_src_x + src_xx;
4242 src_y = g_src_y + src_yy;
4244 dst_x = door_rect->x + dst_xx;
4245 dst_y = door_rect->y + dst_yy;
4247 is_panel_and_door_has_closed =
4250 panel_has_doors[door_index] &&
4251 k >= num_move_steps_doors_only - 1);
4253 if (width >= 0 && width <= g->width &&
4254 height >= 0 && height <= g->height &&
4255 !is_panel_and_door_has_closed)
4257 if (is_panel || !pos->draw_masked)
4258 BlitBitmap(bitmap, drawto, src_x, src_y, width, height,
4261 BlitBitmapMasked(bitmap, drawto, src_x, src_y, width, height,
4265 redraw_mask |= REDRAW_DOOR_FROM_TOKEN(door_token);
4267 if ((part_opening && (width < 0 || height < 0)) ||
4268 (part_closing && (width >= g->width && height >= g->height)))
4269 door_part_done[nr] = TRUE;
4271 // continue door part animations, but not panel after door has closed
4272 if (!door_part_done[nr] && !is_panel_and_door_has_closed)
4273 door_part_done_all = FALSE;
4276 if (!(door_state & DOOR_NO_DELAY))
4280 if (game_status == GAME_MODE_MAIN)
4283 SkipUntilDelayReached(&door_delay, door_delay_value, &k, last_frame);
4285 current_move_delay += max_step_delay;
4288 if (door_part_done_all)
4293 if (door_state & DOOR_ACTION_1)
4294 door1 = door_state & DOOR_ACTION_1;
4295 if (door_state & DOOR_ACTION_2)
4296 door2 = door_state & DOOR_ACTION_2;
4298 return (door1 | door2);
4301 void DrawSpecialEditorDoor()
4303 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
4304 int top_border_width = gfx1->width;
4305 int top_border_height = gfx1->height;
4306 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
4307 int ex = EX - outer_border;
4308 int ey = EY - outer_border;
4309 int vy = VY - outer_border;
4310 int exsize = EXSIZE + 2 * outer_border;
4312 /* draw bigger level editor toolbox window */
4313 BlitBitmap(gfx1->bitmap, drawto, gfx1->src_x, gfx1->src_y,
4314 top_border_width, top_border_height, ex, ey - top_border_height);
4315 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto, ex, vy,
4316 exsize, EYSIZE - VYSIZE + outer_border, ex, ey);
4318 redraw_mask |= REDRAW_ALL;
4321 void UndrawSpecialEditorDoor()
4323 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
4324 int top_border_width = gfx1->width;
4325 int top_border_height = gfx1->height;
4326 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
4327 int ex = EX - outer_border;
4328 int ey = EY - outer_border;
4329 int ey_top = ey - top_border_height;
4330 int exsize = EXSIZE + 2 * outer_border;
4331 int eysize = EYSIZE + 2 * outer_border;
4333 /* draw normal tape recorder window */
4334 if (graphic_info[IMG_GLOBAL_BORDER].bitmap)
4336 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
4337 ex, ey_top, top_border_width, top_border_height,
4339 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
4340 ex, ey, exsize, eysize, ex, ey);
4344 // if screen background is set to "[NONE]", clear editor toolbox window
4345 ClearRectangle(drawto, ex, ey_top, top_border_width, top_border_height);
4346 ClearRectangle(drawto, ex, ey, exsize, eysize);
4349 redraw_mask |= REDRAW_ALL;
4353 /* ---------- new tool button stuff ---------------------------------------- */
4358 struct TextPosInfo *pos;
4361 } toolbutton_info[NUM_TOOL_BUTTONS] =
4364 IMG_REQUEST_BUTTON_GFX_YES, &request.button.yes,
4365 TOOL_CTRL_ID_YES, "yes"
4368 IMG_REQUEST_BUTTON_GFX_NO, &request.button.no,
4369 TOOL_CTRL_ID_NO, "no"
4372 IMG_REQUEST_BUTTON_GFX_CONFIRM, &request.button.confirm,
4373 TOOL_CTRL_ID_CONFIRM, "confirm"
4376 IMG_REQUEST_BUTTON_GFX_PLAYER_1, &request.button.player_1,
4377 TOOL_CTRL_ID_PLAYER_1, "player 1"
4380 IMG_REQUEST_BUTTON_GFX_PLAYER_2, &request.button.player_2,
4381 TOOL_CTRL_ID_PLAYER_2, "player 2"
4384 IMG_REQUEST_BUTTON_GFX_PLAYER_3, &request.button.player_3,
4385 TOOL_CTRL_ID_PLAYER_3, "player 3"
4388 IMG_REQUEST_BUTTON_GFX_PLAYER_4, &request.button.player_4,
4389 TOOL_CTRL_ID_PLAYER_4, "player 4"
4393 void CreateToolButtons()
4397 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4399 struct GraphicInfo *gfx = &graphic_info[toolbutton_info[i].graphic];
4400 struct TextPosInfo *pos = toolbutton_info[i].pos;
4401 struct GadgetInfo *gi;
4402 Bitmap *deco_bitmap = None;
4403 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
4404 unsigned int event_mask = GD_EVENT_RELEASED;
4407 int gd_x = gfx->src_x;
4408 int gd_y = gfx->src_y;
4409 int gd_xp = gfx->src_x + gfx->pressed_xoffset;
4410 int gd_yp = gfx->src_y + gfx->pressed_yoffset;
4413 if (global.use_envelope_request)
4414 setRequestPosition(&dx, &dy, TRUE);
4416 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
4418 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
4420 getSizedGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr), 0,
4421 pos->size, &deco_bitmap, &deco_x, &deco_y);
4422 deco_xpos = (gfx->width - pos->size) / 2;
4423 deco_ypos = (gfx->height - pos->size) / 2;
4426 gi = CreateGadget(GDI_CUSTOM_ID, id,
4427 GDI_INFO_TEXT, toolbutton_info[i].infotext,
4428 GDI_X, dx + GDI_ACTIVE_POS(pos->x),
4429 GDI_Y, dy + GDI_ACTIVE_POS(pos->y),
4430 GDI_WIDTH, gfx->width,
4431 GDI_HEIGHT, gfx->height,
4432 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
4433 GDI_STATE, GD_BUTTON_UNPRESSED,
4434 GDI_DESIGN_UNPRESSED, gfx->bitmap, gd_x, gd_y,
4435 GDI_DESIGN_PRESSED, gfx->bitmap, gd_xp, gd_yp,
4436 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
4437 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
4438 GDI_DECORATION_SIZE, pos->size, pos->size,
4439 GDI_DECORATION_SHIFTING, 1, 1,
4440 GDI_DIRECT_DRAW, FALSE,
4441 GDI_EVENT_MASK, event_mask,
4442 GDI_CALLBACK_ACTION, HandleToolButtons,
4446 Error(ERR_EXIT, "cannot create gadget");
4448 tool_gadget[id] = gi;
4452 void FreeToolButtons()
4456 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4457 FreeGadget(tool_gadget[i]);
4460 static void UnmapToolButtons()
4464 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4465 UnmapGadget(tool_gadget[i]);
4468 static void HandleToolButtons(struct GadgetInfo *gi)
4470 request_gadget_id = gi->custom_id;
4473 static struct Mapping_EM_to_RND_object
4476 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
4477 boolean is_backside; /* backside of moving element */
4483 em_object_mapping_list[] =
4486 Xblank, TRUE, FALSE,
4490 Yacid_splash_eB, FALSE, FALSE,
4491 EL_ACID_SPLASH_RIGHT, -1, -1
4494 Yacid_splash_wB, FALSE, FALSE,
4495 EL_ACID_SPLASH_LEFT, -1, -1
4498 #ifdef EM_ENGINE_BAD_ROLL
4500 Xstone_force_e, FALSE, FALSE,
4501 EL_ROCK, -1, MV_BIT_RIGHT
4504 Xstone_force_w, FALSE, FALSE,
4505 EL_ROCK, -1, MV_BIT_LEFT
4508 Xnut_force_e, FALSE, FALSE,
4509 EL_NUT, -1, MV_BIT_RIGHT
4512 Xnut_force_w, FALSE, FALSE,
4513 EL_NUT, -1, MV_BIT_LEFT
4516 Xspring_force_e, FALSE, FALSE,
4517 EL_SPRING, -1, MV_BIT_RIGHT
4520 Xspring_force_w, FALSE, FALSE,
4521 EL_SPRING, -1, MV_BIT_LEFT
4524 Xemerald_force_e, FALSE, FALSE,
4525 EL_EMERALD, -1, MV_BIT_RIGHT
4528 Xemerald_force_w, FALSE, FALSE,
4529 EL_EMERALD, -1, MV_BIT_LEFT
4532 Xdiamond_force_e, FALSE, FALSE,
4533 EL_DIAMOND, -1, MV_BIT_RIGHT
4536 Xdiamond_force_w, FALSE, FALSE,
4537 EL_DIAMOND, -1, MV_BIT_LEFT
4540 Xbomb_force_e, FALSE, FALSE,
4541 EL_BOMB, -1, MV_BIT_RIGHT
4544 Xbomb_force_w, FALSE, FALSE,
4545 EL_BOMB, -1, MV_BIT_LEFT
4547 #endif /* EM_ENGINE_BAD_ROLL */
4550 Xstone, TRUE, FALSE,
4554 Xstone_pause, FALSE, FALSE,
4558 Xstone_fall, FALSE, FALSE,
4562 Ystone_s, FALSE, FALSE,
4563 EL_ROCK, ACTION_FALLING, -1
4566 Ystone_sB, FALSE, TRUE,
4567 EL_ROCK, ACTION_FALLING, -1
4570 Ystone_e, FALSE, FALSE,
4571 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
4574 Ystone_eB, FALSE, TRUE,
4575 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
4578 Ystone_w, FALSE, FALSE,
4579 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
4582 Ystone_wB, FALSE, TRUE,
4583 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
4590 Xnut_pause, FALSE, FALSE,
4594 Xnut_fall, FALSE, FALSE,
4598 Ynut_s, FALSE, FALSE,
4599 EL_NUT, ACTION_FALLING, -1
4602 Ynut_sB, FALSE, TRUE,
4603 EL_NUT, ACTION_FALLING, -1
4606 Ynut_e, FALSE, FALSE,
4607 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
4610 Ynut_eB, FALSE, TRUE,
4611 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
4614 Ynut_w, FALSE, FALSE,
4615 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
4618 Ynut_wB, FALSE, TRUE,
4619 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
4622 Xbug_n, TRUE, FALSE,
4626 Xbug_e, TRUE, FALSE,
4627 EL_BUG_RIGHT, -1, -1
4630 Xbug_s, TRUE, FALSE,
4634 Xbug_w, TRUE, FALSE,
4638 Xbug_gon, FALSE, FALSE,
4642 Xbug_goe, FALSE, FALSE,
4643 EL_BUG_RIGHT, -1, -1
4646 Xbug_gos, FALSE, FALSE,
4650 Xbug_gow, FALSE, FALSE,
4654 Ybug_n, FALSE, FALSE,
4655 EL_BUG, ACTION_MOVING, MV_BIT_UP
4658 Ybug_nB, FALSE, TRUE,
4659 EL_BUG, ACTION_MOVING, MV_BIT_UP
4662 Ybug_e, FALSE, FALSE,
4663 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
4666 Ybug_eB, FALSE, TRUE,
4667 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
4670 Ybug_s, FALSE, FALSE,
4671 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
4674 Ybug_sB, FALSE, TRUE,
4675 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
4678 Ybug_w, FALSE, FALSE,
4679 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
4682 Ybug_wB, FALSE, TRUE,
4683 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
4686 Ybug_w_n, FALSE, FALSE,
4687 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
4690 Ybug_n_e, FALSE, FALSE,
4691 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
4694 Ybug_e_s, FALSE, FALSE,
4695 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
4698 Ybug_s_w, FALSE, FALSE,
4699 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
4702 Ybug_e_n, FALSE, FALSE,
4703 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
4706 Ybug_s_e, FALSE, FALSE,
4707 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
4710 Ybug_w_s, FALSE, FALSE,
4711 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
4714 Ybug_n_w, FALSE, FALSE,
4715 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
4718 Ybug_stone, FALSE, FALSE,
4719 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
4722 Ybug_spring, FALSE, FALSE,
4723 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
4726 Xtank_n, TRUE, FALSE,
4727 EL_SPACESHIP_UP, -1, -1
4730 Xtank_e, TRUE, FALSE,
4731 EL_SPACESHIP_RIGHT, -1, -1
4734 Xtank_s, TRUE, FALSE,
4735 EL_SPACESHIP_DOWN, -1, -1
4738 Xtank_w, TRUE, FALSE,
4739 EL_SPACESHIP_LEFT, -1, -1
4742 Xtank_gon, FALSE, FALSE,
4743 EL_SPACESHIP_UP, -1, -1
4746 Xtank_goe, FALSE, FALSE,
4747 EL_SPACESHIP_RIGHT, -1, -1
4750 Xtank_gos, FALSE, FALSE,
4751 EL_SPACESHIP_DOWN, -1, -1
4754 Xtank_gow, FALSE, FALSE,
4755 EL_SPACESHIP_LEFT, -1, -1
4758 Ytank_n, FALSE, FALSE,
4759 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
4762 Ytank_nB, FALSE, TRUE,
4763 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
4766 Ytank_e, FALSE, FALSE,
4767 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
4770 Ytank_eB, FALSE, TRUE,
4771 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
4774 Ytank_s, FALSE, FALSE,
4775 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
4778 Ytank_sB, FALSE, TRUE,
4779 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
4782 Ytank_w, FALSE, FALSE,
4783 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
4786 Ytank_wB, FALSE, TRUE,
4787 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
4790 Ytank_w_n, FALSE, FALSE,
4791 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
4794 Ytank_n_e, FALSE, FALSE,
4795 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
4798 Ytank_e_s, FALSE, FALSE,
4799 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
4802 Ytank_s_w, FALSE, FALSE,
4803 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
4806 Ytank_e_n, FALSE, FALSE,
4807 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
4810 Ytank_s_e, FALSE, FALSE,
4811 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
4814 Ytank_w_s, FALSE, FALSE,
4815 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
4818 Ytank_n_w, FALSE, FALSE,
4819 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
4822 Ytank_stone, FALSE, FALSE,
4823 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
4826 Ytank_spring, FALSE, FALSE,
4827 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
4830 Xandroid, TRUE, FALSE,
4831 EL_EMC_ANDROID, ACTION_ACTIVE, -1
4834 Xandroid_1_n, FALSE, FALSE,
4835 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
4838 Xandroid_2_n, FALSE, FALSE,
4839 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
4842 Xandroid_1_e, FALSE, FALSE,
4843 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
4846 Xandroid_2_e, FALSE, FALSE,
4847 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
4850 Xandroid_1_w, FALSE, FALSE,
4851 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
4854 Xandroid_2_w, FALSE, FALSE,
4855 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
4858 Xandroid_1_s, FALSE, FALSE,
4859 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
4862 Xandroid_2_s, FALSE, FALSE,
4863 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
4866 Yandroid_n, FALSE, FALSE,
4867 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
4870 Yandroid_nB, FALSE, TRUE,
4871 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
4874 Yandroid_ne, FALSE, FALSE,
4875 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
4878 Yandroid_neB, FALSE, TRUE,
4879 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
4882 Yandroid_e, FALSE, FALSE,
4883 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
4886 Yandroid_eB, FALSE, TRUE,
4887 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
4890 Yandroid_se, FALSE, FALSE,
4891 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
4894 Yandroid_seB, FALSE, TRUE,
4895 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
4898 Yandroid_s, FALSE, FALSE,
4899 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
4902 Yandroid_sB, FALSE, TRUE,
4903 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
4906 Yandroid_sw, FALSE, FALSE,
4907 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
4910 Yandroid_swB, FALSE, TRUE,
4911 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
4914 Yandroid_w, FALSE, FALSE,
4915 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
4918 Yandroid_wB, FALSE, TRUE,
4919 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
4922 Yandroid_nw, FALSE, FALSE,
4923 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
4926 Yandroid_nwB, FALSE, TRUE,
4927 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
4930 Xspring, TRUE, FALSE,
4934 Xspring_pause, FALSE, FALSE,
4938 Xspring_e, FALSE, FALSE,
4942 Xspring_w, FALSE, FALSE,
4946 Xspring_fall, FALSE, FALSE,
4950 Yspring_s, FALSE, FALSE,
4951 EL_SPRING, ACTION_FALLING, -1
4954 Yspring_sB, FALSE, TRUE,
4955 EL_SPRING, ACTION_FALLING, -1
4958 Yspring_e, FALSE, FALSE,
4959 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
4962 Yspring_eB, FALSE, TRUE,
4963 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
4966 Yspring_w, FALSE, FALSE,
4967 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
4970 Yspring_wB, FALSE, TRUE,
4971 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
4974 Yspring_kill_e, FALSE, FALSE,
4975 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
4978 Yspring_kill_eB, FALSE, TRUE,
4979 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
4982 Yspring_kill_w, FALSE, FALSE,
4983 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
4986 Yspring_kill_wB, FALSE, TRUE,
4987 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
4990 Xeater_n, TRUE, FALSE,
4991 EL_YAMYAM_UP, -1, -1
4994 Xeater_e, TRUE, FALSE,
4995 EL_YAMYAM_RIGHT, -1, -1
4998 Xeater_w, TRUE, FALSE,
4999 EL_YAMYAM_LEFT, -1, -1
5002 Xeater_s, TRUE, FALSE,
5003 EL_YAMYAM_DOWN, -1, -1
5006 Yeater_n, FALSE, FALSE,
5007 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
5010 Yeater_nB, FALSE, TRUE,
5011 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
5014 Yeater_e, FALSE, FALSE,
5015 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
5018 Yeater_eB, FALSE, TRUE,
5019 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
5022 Yeater_s, FALSE, FALSE,
5023 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
5026 Yeater_sB, FALSE, TRUE,
5027 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
5030 Yeater_w, FALSE, FALSE,
5031 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
5034 Yeater_wB, FALSE, TRUE,
5035 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
5038 Yeater_stone, FALSE, FALSE,
5039 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
5042 Yeater_spring, FALSE, FALSE,
5043 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
5046 Xalien, TRUE, FALSE,
5050 Xalien_pause, FALSE, FALSE,
5054 Yalien_n, FALSE, FALSE,
5055 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
5058 Yalien_nB, FALSE, TRUE,
5059 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
5062 Yalien_e, FALSE, FALSE,
5063 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
5066 Yalien_eB, FALSE, TRUE,
5067 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
5070 Yalien_s, FALSE, FALSE,
5071 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
5074 Yalien_sB, FALSE, TRUE,
5075 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
5078 Yalien_w, FALSE, FALSE,
5079 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
5082 Yalien_wB, FALSE, TRUE,
5083 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
5086 Yalien_stone, FALSE, FALSE,
5087 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
5090 Yalien_spring, FALSE, FALSE,
5091 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
5094 Xemerald, TRUE, FALSE,
5098 Xemerald_pause, FALSE, FALSE,
5102 Xemerald_fall, FALSE, FALSE,
5106 Xemerald_shine, FALSE, FALSE,
5107 EL_EMERALD, ACTION_TWINKLING, -1
5110 Yemerald_s, FALSE, FALSE,
5111 EL_EMERALD, ACTION_FALLING, -1
5114 Yemerald_sB, FALSE, TRUE,
5115 EL_EMERALD, ACTION_FALLING, -1
5118 Yemerald_e, FALSE, FALSE,
5119 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
5122 Yemerald_eB, FALSE, TRUE,
5123 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
5126 Yemerald_w, FALSE, FALSE,
5127 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
5130 Yemerald_wB, FALSE, TRUE,
5131 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
5134 Yemerald_eat, FALSE, FALSE,
5135 EL_EMERALD, ACTION_COLLECTING, -1
5138 Yemerald_stone, FALSE, FALSE,
5139 EL_NUT, ACTION_BREAKING, -1
5142 Xdiamond, TRUE, FALSE,
5146 Xdiamond_pause, FALSE, FALSE,
5150 Xdiamond_fall, FALSE, FALSE,
5154 Xdiamond_shine, FALSE, FALSE,
5155 EL_DIAMOND, ACTION_TWINKLING, -1
5158 Ydiamond_s, FALSE, FALSE,
5159 EL_DIAMOND, ACTION_FALLING, -1
5162 Ydiamond_sB, FALSE, TRUE,
5163 EL_DIAMOND, ACTION_FALLING, -1
5166 Ydiamond_e, FALSE, FALSE,
5167 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
5170 Ydiamond_eB, FALSE, TRUE,
5171 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
5174 Ydiamond_w, FALSE, FALSE,
5175 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
5178 Ydiamond_wB, FALSE, TRUE,
5179 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
5182 Ydiamond_eat, FALSE, FALSE,
5183 EL_DIAMOND, ACTION_COLLECTING, -1
5186 Ydiamond_stone, FALSE, FALSE,
5187 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
5190 Xdrip_fall, TRUE, FALSE,
5191 EL_AMOEBA_DROP, -1, -1
5194 Xdrip_stretch, FALSE, FALSE,
5195 EL_AMOEBA_DROP, ACTION_FALLING, -1
5198 Xdrip_stretchB, FALSE, TRUE,
5199 EL_AMOEBA_DROP, ACTION_FALLING, -1
5202 Xdrip_eat, FALSE, FALSE,
5203 EL_AMOEBA_DROP, ACTION_GROWING, -1
5206 Ydrip_s1, FALSE, FALSE,
5207 EL_AMOEBA_DROP, ACTION_FALLING, -1
5210 Ydrip_s1B, FALSE, TRUE,
5211 EL_AMOEBA_DROP, ACTION_FALLING, -1
5214 Ydrip_s2, FALSE, FALSE,
5215 EL_AMOEBA_DROP, ACTION_FALLING, -1
5218 Ydrip_s2B, FALSE, TRUE,
5219 EL_AMOEBA_DROP, ACTION_FALLING, -1
5226 Xbomb_pause, FALSE, FALSE,
5230 Xbomb_fall, FALSE, FALSE,
5234 Ybomb_s, FALSE, FALSE,
5235 EL_BOMB, ACTION_FALLING, -1
5238 Ybomb_sB, FALSE, TRUE,
5239 EL_BOMB, ACTION_FALLING, -1
5242 Ybomb_e, FALSE, FALSE,
5243 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
5246 Ybomb_eB, FALSE, TRUE,
5247 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
5250 Ybomb_w, FALSE, FALSE,
5251 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
5254 Ybomb_wB, FALSE, TRUE,
5255 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
5258 Ybomb_eat, FALSE, FALSE,
5259 EL_BOMB, ACTION_ACTIVATING, -1
5262 Xballoon, TRUE, FALSE,
5266 Yballoon_n, FALSE, FALSE,
5267 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
5270 Yballoon_nB, FALSE, TRUE,
5271 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
5274 Yballoon_e, FALSE, FALSE,
5275 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
5278 Yballoon_eB, FALSE, TRUE,
5279 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
5282 Yballoon_s, FALSE, FALSE,
5283 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
5286 Yballoon_sB, FALSE, TRUE,
5287 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
5290 Yballoon_w, FALSE, FALSE,
5291 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
5294 Yballoon_wB, FALSE, TRUE,
5295 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
5298 Xgrass, TRUE, FALSE,
5299 EL_EMC_GRASS, -1, -1
5302 Ygrass_nB, FALSE, FALSE,
5303 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
5306 Ygrass_eB, FALSE, FALSE,
5307 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
5310 Ygrass_sB, FALSE, FALSE,
5311 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
5314 Ygrass_wB, FALSE, FALSE,
5315 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
5322 Ydirt_nB, FALSE, FALSE,
5323 EL_SAND, ACTION_DIGGING, MV_BIT_UP
5326 Ydirt_eB, FALSE, FALSE,
5327 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
5330 Ydirt_sB, FALSE, FALSE,
5331 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
5334 Ydirt_wB, FALSE, FALSE,
5335 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
5338 Xacid_ne, TRUE, FALSE,
5339 EL_ACID_POOL_TOPRIGHT, -1, -1
5342 Xacid_se, TRUE, FALSE,
5343 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
5346 Xacid_s, TRUE, FALSE,
5347 EL_ACID_POOL_BOTTOM, -1, -1
5350 Xacid_sw, TRUE, FALSE,
5351 EL_ACID_POOL_BOTTOMLEFT, -1, -1
5354 Xacid_nw, TRUE, FALSE,
5355 EL_ACID_POOL_TOPLEFT, -1, -1
5358 Xacid_1, TRUE, FALSE,
5362 Xacid_2, FALSE, FALSE,
5366 Xacid_3, FALSE, FALSE,
5370 Xacid_4, FALSE, FALSE,
5374 Xacid_5, FALSE, FALSE,
5378 Xacid_6, FALSE, FALSE,
5382 Xacid_7, FALSE, FALSE,
5386 Xacid_8, FALSE, FALSE,
5390 Xball_1, TRUE, FALSE,
5391 EL_EMC_MAGIC_BALL, -1, -1
5394 Xball_1B, FALSE, FALSE,
5395 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5398 Xball_2, FALSE, FALSE,
5399 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5402 Xball_2B, FALSE, FALSE,
5403 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5406 Yball_eat, FALSE, FALSE,
5407 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
5410 Ykey_1_eat, FALSE, FALSE,
5411 EL_EM_KEY_1, ACTION_COLLECTING, -1
5414 Ykey_2_eat, FALSE, FALSE,
5415 EL_EM_KEY_2, ACTION_COLLECTING, -1
5418 Ykey_3_eat, FALSE, FALSE,
5419 EL_EM_KEY_3, ACTION_COLLECTING, -1
5422 Ykey_4_eat, FALSE, FALSE,
5423 EL_EM_KEY_4, ACTION_COLLECTING, -1
5426 Ykey_5_eat, FALSE, FALSE,
5427 EL_EMC_KEY_5, ACTION_COLLECTING, -1
5430 Ykey_6_eat, FALSE, FALSE,
5431 EL_EMC_KEY_6, ACTION_COLLECTING, -1
5434 Ykey_7_eat, FALSE, FALSE,
5435 EL_EMC_KEY_7, ACTION_COLLECTING, -1
5438 Ykey_8_eat, FALSE, FALSE,
5439 EL_EMC_KEY_8, ACTION_COLLECTING, -1
5442 Ylenses_eat, FALSE, FALSE,
5443 EL_EMC_LENSES, ACTION_COLLECTING, -1
5446 Ymagnify_eat, FALSE, FALSE,
5447 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
5450 Ygrass_eat, FALSE, FALSE,
5451 EL_EMC_GRASS, ACTION_SNAPPING, -1
5454 Ydirt_eat, FALSE, FALSE,
5455 EL_SAND, ACTION_SNAPPING, -1
5458 Xgrow_ns, TRUE, FALSE,
5459 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
5462 Ygrow_ns_eat, FALSE, FALSE,
5463 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
5466 Xgrow_ew, TRUE, FALSE,
5467 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
5470 Ygrow_ew_eat, FALSE, FALSE,
5471 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
5474 Xwonderwall, TRUE, FALSE,
5475 EL_MAGIC_WALL, -1, -1
5478 XwonderwallB, FALSE, FALSE,
5479 EL_MAGIC_WALL, ACTION_ACTIVE, -1
5482 Xamoeba_1, TRUE, FALSE,
5483 EL_AMOEBA_DRY, ACTION_OTHER, -1
5486 Xamoeba_2, FALSE, FALSE,
5487 EL_AMOEBA_DRY, ACTION_OTHER, -1
5490 Xamoeba_3, FALSE, FALSE,
5491 EL_AMOEBA_DRY, ACTION_OTHER, -1
5494 Xamoeba_4, FALSE, FALSE,
5495 EL_AMOEBA_DRY, ACTION_OTHER, -1
5498 Xamoeba_5, TRUE, FALSE,
5499 EL_AMOEBA_WET, ACTION_OTHER, -1
5502 Xamoeba_6, FALSE, FALSE,
5503 EL_AMOEBA_WET, ACTION_OTHER, -1
5506 Xamoeba_7, FALSE, FALSE,
5507 EL_AMOEBA_WET, ACTION_OTHER, -1
5510 Xamoeba_8, FALSE, FALSE,
5511 EL_AMOEBA_WET, ACTION_OTHER, -1
5514 Xdoor_1, TRUE, FALSE,
5515 EL_EM_GATE_1, -1, -1
5518 Xdoor_2, TRUE, FALSE,
5519 EL_EM_GATE_2, -1, -1
5522 Xdoor_3, TRUE, FALSE,
5523 EL_EM_GATE_3, -1, -1
5526 Xdoor_4, TRUE, FALSE,
5527 EL_EM_GATE_4, -1, -1
5530 Xdoor_5, TRUE, FALSE,
5531 EL_EMC_GATE_5, -1, -1
5534 Xdoor_6, TRUE, FALSE,
5535 EL_EMC_GATE_6, -1, -1
5538 Xdoor_7, TRUE, FALSE,
5539 EL_EMC_GATE_7, -1, -1
5542 Xdoor_8, TRUE, FALSE,
5543 EL_EMC_GATE_8, -1, -1
5546 Xkey_1, TRUE, FALSE,
5550 Xkey_2, TRUE, FALSE,
5554 Xkey_3, TRUE, FALSE,
5558 Xkey_4, TRUE, FALSE,
5562 Xkey_5, TRUE, FALSE,
5563 EL_EMC_KEY_5, -1, -1
5566 Xkey_6, TRUE, FALSE,
5567 EL_EMC_KEY_6, -1, -1
5570 Xkey_7, TRUE, FALSE,
5571 EL_EMC_KEY_7, -1, -1
5574 Xkey_8, TRUE, FALSE,
5575 EL_EMC_KEY_8, -1, -1
5578 Xwind_n, TRUE, FALSE,
5579 EL_BALLOON_SWITCH_UP, -1, -1
5582 Xwind_e, TRUE, FALSE,
5583 EL_BALLOON_SWITCH_RIGHT, -1, -1
5586 Xwind_s, TRUE, FALSE,
5587 EL_BALLOON_SWITCH_DOWN, -1, -1
5590 Xwind_w, TRUE, FALSE,
5591 EL_BALLOON_SWITCH_LEFT, -1, -1
5594 Xwind_nesw, TRUE, FALSE,
5595 EL_BALLOON_SWITCH_ANY, -1, -1
5598 Xwind_stop, TRUE, FALSE,
5599 EL_BALLOON_SWITCH_NONE, -1, -1
5603 EL_EM_EXIT_CLOSED, -1, -1
5606 Xexit_1, TRUE, FALSE,
5607 EL_EM_EXIT_OPEN, -1, -1
5610 Xexit_2, FALSE, FALSE,
5611 EL_EM_EXIT_OPEN, -1, -1
5614 Xexit_3, FALSE, FALSE,
5615 EL_EM_EXIT_OPEN, -1, -1
5618 Xdynamite, TRUE, FALSE,
5619 EL_EM_DYNAMITE, -1, -1
5622 Ydynamite_eat, FALSE, FALSE,
5623 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
5626 Xdynamite_1, TRUE, FALSE,
5627 EL_EM_DYNAMITE_ACTIVE, -1, -1
5630 Xdynamite_2, FALSE, FALSE,
5631 EL_EM_DYNAMITE_ACTIVE, -1, -1
5634 Xdynamite_3, FALSE, FALSE,
5635 EL_EM_DYNAMITE_ACTIVE, -1, -1
5638 Xdynamite_4, FALSE, FALSE,
5639 EL_EM_DYNAMITE_ACTIVE, -1, -1
5642 Xbumper, TRUE, FALSE,
5643 EL_EMC_SPRING_BUMPER, -1, -1
5646 XbumperB, FALSE, FALSE,
5647 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
5650 Xwheel, TRUE, FALSE,
5651 EL_ROBOT_WHEEL, -1, -1
5654 XwheelB, FALSE, FALSE,
5655 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
5658 Xswitch, TRUE, FALSE,
5659 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
5662 XswitchB, FALSE, FALSE,
5663 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
5667 EL_QUICKSAND_EMPTY, -1, -1
5670 Xsand_stone, TRUE, FALSE,
5671 EL_QUICKSAND_FULL, -1, -1
5674 Xsand_stonein_1, FALSE, TRUE,
5675 EL_ROCK, ACTION_FILLING, -1
5678 Xsand_stonein_2, FALSE, TRUE,
5679 EL_ROCK, ACTION_FILLING, -1
5682 Xsand_stonein_3, FALSE, TRUE,
5683 EL_ROCK, ACTION_FILLING, -1
5686 Xsand_stonein_4, FALSE, TRUE,
5687 EL_ROCK, ACTION_FILLING, -1
5690 Xsand_stonesand_1, FALSE, FALSE,
5691 EL_QUICKSAND_EMPTYING, -1, -1
5694 Xsand_stonesand_2, FALSE, FALSE,
5695 EL_QUICKSAND_EMPTYING, -1, -1
5698 Xsand_stonesand_3, FALSE, FALSE,
5699 EL_QUICKSAND_EMPTYING, -1, -1
5702 Xsand_stonesand_4, FALSE, FALSE,
5703 EL_QUICKSAND_EMPTYING, -1, -1
5706 Xsand_stonesand_quickout_1, FALSE, FALSE,
5707 EL_QUICKSAND_EMPTYING, -1, -1
5710 Xsand_stonesand_quickout_2, FALSE, FALSE,
5711 EL_QUICKSAND_EMPTYING, -1, -1
5714 Xsand_stoneout_1, FALSE, FALSE,
5715 EL_ROCK, ACTION_EMPTYING, -1
5718 Xsand_stoneout_2, FALSE, FALSE,
5719 EL_ROCK, ACTION_EMPTYING, -1
5722 Xsand_sandstone_1, FALSE, FALSE,
5723 EL_QUICKSAND_FILLING, -1, -1
5726 Xsand_sandstone_2, FALSE, FALSE,
5727 EL_QUICKSAND_FILLING, -1, -1
5730 Xsand_sandstone_3, FALSE, FALSE,
5731 EL_QUICKSAND_FILLING, -1, -1
5734 Xsand_sandstone_4, FALSE, FALSE,
5735 EL_QUICKSAND_FILLING, -1, -1
5738 Xplant, TRUE, FALSE,
5739 EL_EMC_PLANT, -1, -1
5742 Yplant, FALSE, FALSE,
5743 EL_EMC_PLANT, -1, -1
5746 Xlenses, TRUE, FALSE,
5747 EL_EMC_LENSES, -1, -1
5750 Xmagnify, TRUE, FALSE,
5751 EL_EMC_MAGNIFIER, -1, -1
5754 Xdripper, TRUE, FALSE,
5755 EL_EMC_DRIPPER, -1, -1
5758 XdripperB, FALSE, FALSE,
5759 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
5762 Xfake_blank, TRUE, FALSE,
5763 EL_INVISIBLE_WALL, -1, -1
5766 Xfake_blankB, FALSE, FALSE,
5767 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
5770 Xfake_grass, TRUE, FALSE,
5771 EL_EMC_FAKE_GRASS, -1, -1
5774 Xfake_grassB, FALSE, FALSE,
5775 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
5778 Xfake_door_1, TRUE, FALSE,
5779 EL_EM_GATE_1_GRAY, -1, -1
5782 Xfake_door_2, TRUE, FALSE,
5783 EL_EM_GATE_2_GRAY, -1, -1
5786 Xfake_door_3, TRUE, FALSE,
5787 EL_EM_GATE_3_GRAY, -1, -1
5790 Xfake_door_4, TRUE, FALSE,
5791 EL_EM_GATE_4_GRAY, -1, -1
5794 Xfake_door_5, TRUE, FALSE,
5795 EL_EMC_GATE_5_GRAY, -1, -1
5798 Xfake_door_6, TRUE, FALSE,
5799 EL_EMC_GATE_6_GRAY, -1, -1
5802 Xfake_door_7, TRUE, FALSE,
5803 EL_EMC_GATE_7_GRAY, -1, -1
5806 Xfake_door_8, TRUE, FALSE,
5807 EL_EMC_GATE_8_GRAY, -1, -1
5810 Xfake_acid_1, TRUE, FALSE,
5811 EL_EMC_FAKE_ACID, -1, -1
5814 Xfake_acid_2, FALSE, FALSE,
5815 EL_EMC_FAKE_ACID, -1, -1
5818 Xfake_acid_3, FALSE, FALSE,
5819 EL_EMC_FAKE_ACID, -1, -1
5822 Xfake_acid_4, FALSE, FALSE,
5823 EL_EMC_FAKE_ACID, -1, -1
5826 Xfake_acid_5, FALSE, FALSE,
5827 EL_EMC_FAKE_ACID, -1, -1
5830 Xfake_acid_6, FALSE, FALSE,
5831 EL_EMC_FAKE_ACID, -1, -1
5834 Xfake_acid_7, FALSE, FALSE,
5835 EL_EMC_FAKE_ACID, -1, -1
5838 Xfake_acid_8, FALSE, FALSE,
5839 EL_EMC_FAKE_ACID, -1, -1
5842 Xsteel_1, TRUE, FALSE,
5843 EL_STEELWALL, -1, -1
5846 Xsteel_2, TRUE, FALSE,
5847 EL_EMC_STEELWALL_2, -1, -1
5850 Xsteel_3, TRUE, FALSE,
5851 EL_EMC_STEELWALL_3, -1, -1
5854 Xsteel_4, TRUE, FALSE,
5855 EL_EMC_STEELWALL_4, -1, -1
5858 Xwall_1, TRUE, FALSE,
5862 Xwall_2, TRUE, FALSE,
5863 EL_EMC_WALL_14, -1, -1
5866 Xwall_3, TRUE, FALSE,
5867 EL_EMC_WALL_15, -1, -1
5870 Xwall_4, TRUE, FALSE,
5871 EL_EMC_WALL_16, -1, -1
5874 Xround_wall_1, TRUE, FALSE,
5875 EL_WALL_SLIPPERY, -1, -1
5878 Xround_wall_2, TRUE, FALSE,
5879 EL_EMC_WALL_SLIPPERY_2, -1, -1
5882 Xround_wall_3, TRUE, FALSE,
5883 EL_EMC_WALL_SLIPPERY_3, -1, -1
5886 Xround_wall_4, TRUE, FALSE,
5887 EL_EMC_WALL_SLIPPERY_4, -1, -1
5890 Xdecor_1, TRUE, FALSE,
5891 EL_EMC_WALL_8, -1, -1
5894 Xdecor_2, TRUE, FALSE,
5895 EL_EMC_WALL_6, -1, -1
5898 Xdecor_3, TRUE, FALSE,
5899 EL_EMC_WALL_4, -1, -1
5902 Xdecor_4, TRUE, FALSE,
5903 EL_EMC_WALL_7, -1, -1
5906 Xdecor_5, TRUE, FALSE,
5907 EL_EMC_WALL_5, -1, -1
5910 Xdecor_6, TRUE, FALSE,
5911 EL_EMC_WALL_9, -1, -1
5914 Xdecor_7, TRUE, FALSE,
5915 EL_EMC_WALL_10, -1, -1
5918 Xdecor_8, TRUE, FALSE,
5919 EL_EMC_WALL_1, -1, -1
5922 Xdecor_9, TRUE, FALSE,
5923 EL_EMC_WALL_2, -1, -1
5926 Xdecor_10, TRUE, FALSE,
5927 EL_EMC_WALL_3, -1, -1
5930 Xdecor_11, TRUE, FALSE,
5931 EL_EMC_WALL_11, -1, -1
5934 Xdecor_12, TRUE, FALSE,
5935 EL_EMC_WALL_12, -1, -1
5938 Xalpha_0, TRUE, FALSE,
5939 EL_CHAR('0'), -1, -1
5942 Xalpha_1, TRUE, FALSE,
5943 EL_CHAR('1'), -1, -1
5946 Xalpha_2, TRUE, FALSE,
5947 EL_CHAR('2'), -1, -1
5950 Xalpha_3, TRUE, FALSE,
5951 EL_CHAR('3'), -1, -1
5954 Xalpha_4, TRUE, FALSE,
5955 EL_CHAR('4'), -1, -1
5958 Xalpha_5, TRUE, FALSE,
5959 EL_CHAR('5'), -1, -1
5962 Xalpha_6, TRUE, FALSE,
5963 EL_CHAR('6'), -1, -1
5966 Xalpha_7, TRUE, FALSE,
5967 EL_CHAR('7'), -1, -1
5970 Xalpha_8, TRUE, FALSE,
5971 EL_CHAR('8'), -1, -1
5974 Xalpha_9, TRUE, FALSE,
5975 EL_CHAR('9'), -1, -1
5978 Xalpha_excla, TRUE, FALSE,
5979 EL_CHAR('!'), -1, -1
5982 Xalpha_quote, TRUE, FALSE,
5983 EL_CHAR('"'), -1, -1
5986 Xalpha_comma, TRUE, FALSE,
5987 EL_CHAR(','), -1, -1
5990 Xalpha_minus, TRUE, FALSE,
5991 EL_CHAR('-'), -1, -1
5994 Xalpha_perio, TRUE, FALSE,
5995 EL_CHAR('.'), -1, -1
5998 Xalpha_colon, TRUE, FALSE,
5999 EL_CHAR(':'), -1, -1
6002 Xalpha_quest, TRUE, FALSE,
6003 EL_CHAR('?'), -1, -1
6006 Xalpha_a, TRUE, FALSE,
6007 EL_CHAR('A'), -1, -1
6010 Xalpha_b, TRUE, FALSE,
6011 EL_CHAR('B'), -1, -1
6014 Xalpha_c, TRUE, FALSE,
6015 EL_CHAR('C'), -1, -1
6018 Xalpha_d, TRUE, FALSE,
6019 EL_CHAR('D'), -1, -1
6022 Xalpha_e, TRUE, FALSE,
6023 EL_CHAR('E'), -1, -1
6026 Xalpha_f, TRUE, FALSE,
6027 EL_CHAR('F'), -1, -1
6030 Xalpha_g, TRUE, FALSE,
6031 EL_CHAR('G'), -1, -1
6034 Xalpha_h, TRUE, FALSE,
6035 EL_CHAR('H'), -1, -1
6038 Xalpha_i, TRUE, FALSE,
6039 EL_CHAR('I'), -1, -1
6042 Xalpha_j, TRUE, FALSE,
6043 EL_CHAR('J'), -1, -1
6046 Xalpha_k, TRUE, FALSE,
6047 EL_CHAR('K'), -1, -1
6050 Xalpha_l, TRUE, FALSE,
6051 EL_CHAR('L'), -1, -1
6054 Xalpha_m, TRUE, FALSE,
6055 EL_CHAR('M'), -1, -1
6058 Xalpha_n, TRUE, FALSE,
6059 EL_CHAR('N'), -1, -1
6062 Xalpha_o, TRUE, FALSE,
6063 EL_CHAR('O'), -1, -1
6066 Xalpha_p, TRUE, FALSE,
6067 EL_CHAR('P'), -1, -1
6070 Xalpha_q, TRUE, FALSE,
6071 EL_CHAR('Q'), -1, -1
6074 Xalpha_r, TRUE, FALSE,
6075 EL_CHAR('R'), -1, -1
6078 Xalpha_s, TRUE, FALSE,
6079 EL_CHAR('S'), -1, -1
6082 Xalpha_t, TRUE, FALSE,
6083 EL_CHAR('T'), -1, -1
6086 Xalpha_u, TRUE, FALSE,
6087 EL_CHAR('U'), -1, -1
6090 Xalpha_v, TRUE, FALSE,
6091 EL_CHAR('V'), -1, -1
6094 Xalpha_w, TRUE, FALSE,
6095 EL_CHAR('W'), -1, -1
6098 Xalpha_x, TRUE, FALSE,
6099 EL_CHAR('X'), -1, -1
6102 Xalpha_y, TRUE, FALSE,
6103 EL_CHAR('Y'), -1, -1
6106 Xalpha_z, TRUE, FALSE,
6107 EL_CHAR('Z'), -1, -1
6110 Xalpha_arrow_e, TRUE, FALSE,
6111 EL_CHAR('>'), -1, -1
6114 Xalpha_arrow_w, TRUE, FALSE,
6115 EL_CHAR('<'), -1, -1
6118 Xalpha_copyr, TRUE, FALSE,
6119 EL_CHAR(CHAR_BYTE_COPYRIGHT), -1, -1
6123 Xboom_bug, FALSE, FALSE,
6124 EL_BUG, ACTION_EXPLODING, -1
6127 Xboom_bomb, FALSE, FALSE,
6128 EL_BOMB, ACTION_EXPLODING, -1
6131 Xboom_android, FALSE, FALSE,
6132 EL_EMC_ANDROID, ACTION_OTHER, -1
6135 Xboom_1, FALSE, FALSE,
6136 EL_DEFAULT, ACTION_EXPLODING, -1
6139 Xboom_2, FALSE, FALSE,
6140 EL_DEFAULT, ACTION_EXPLODING, -1
6143 Znormal, FALSE, FALSE,
6147 Zdynamite, FALSE, FALSE,
6151 Zplayer, FALSE, FALSE,
6155 ZBORDER, FALSE, FALSE,
6165 static struct Mapping_EM_to_RND_player
6174 em_player_mapping_list[] =
6178 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
6182 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
6186 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
6190 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
6194 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
6198 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
6202 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
6206 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
6210 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
6214 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
6218 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
6222 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
6226 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
6230 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
6234 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
6238 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
6242 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
6246 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
6250 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
6254 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
6258 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
6262 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
6266 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
6270 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
6274 EL_PLAYER_1, ACTION_DEFAULT, -1,
6278 EL_PLAYER_2, ACTION_DEFAULT, -1,
6282 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
6286 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
6290 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
6294 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
6298 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
6302 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
6306 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
6310 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
6314 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
6318 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
6322 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
6326 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
6330 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
6334 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
6338 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
6342 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
6346 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
6350 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
6354 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
6358 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
6362 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
6366 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
6370 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
6374 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
6378 EL_PLAYER_3, ACTION_DEFAULT, -1,
6382 EL_PLAYER_4, ACTION_DEFAULT, -1,
6391 int map_element_RND_to_EM(int element_rnd)
6393 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
6394 static boolean mapping_initialized = FALSE;
6396 if (!mapping_initialized)
6400 /* return "Xalpha_quest" for all undefined elements in mapping array */
6401 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
6402 mapping_RND_to_EM[i] = Xalpha_quest;
6404 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6405 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
6406 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
6407 em_object_mapping_list[i].element_em;
6409 mapping_initialized = TRUE;
6412 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
6413 return mapping_RND_to_EM[element_rnd];
6415 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
6420 int map_element_EM_to_RND(int element_em)
6422 static unsigned short mapping_EM_to_RND[TILE_MAX];
6423 static boolean mapping_initialized = FALSE;
6425 if (!mapping_initialized)
6429 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
6430 for (i = 0; i < TILE_MAX; i++)
6431 mapping_EM_to_RND[i] = EL_UNKNOWN;
6433 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6434 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
6435 em_object_mapping_list[i].element_rnd;
6437 mapping_initialized = TRUE;
6440 if (element_em >= 0 && element_em < TILE_MAX)
6441 return mapping_EM_to_RND[element_em];
6443 Error(ERR_WARN, "invalid EM level element %d", element_em);
6448 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
6450 struct LevelInfo_EM *level_em = level->native_em_level;
6451 struct LEVEL *lev = level_em->lev;
6454 for (i = 0; i < TILE_MAX; i++)
6455 lev->android_array[i] = Xblank;
6457 for (i = 0; i < level->num_android_clone_elements; i++)
6459 int element_rnd = level->android_clone_element[i];
6460 int element_em = map_element_RND_to_EM(element_rnd);
6462 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
6463 if (em_object_mapping_list[j].element_rnd == element_rnd)
6464 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
6468 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
6470 struct LevelInfo_EM *level_em = level->native_em_level;
6471 struct LEVEL *lev = level_em->lev;
6474 level->num_android_clone_elements = 0;
6476 for (i = 0; i < TILE_MAX; i++)
6478 int element_em = lev->android_array[i];
6480 boolean element_found = FALSE;
6482 if (element_em == Xblank)
6485 element_rnd = map_element_EM_to_RND(element_em);
6487 for (j = 0; j < level->num_android_clone_elements; j++)
6488 if (level->android_clone_element[j] == element_rnd)
6489 element_found = TRUE;
6493 level->android_clone_element[level->num_android_clone_elements++] =
6496 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
6501 if (level->num_android_clone_elements == 0)
6503 level->num_android_clone_elements = 1;
6504 level->android_clone_element[0] = EL_EMPTY;
6508 int map_direction_RND_to_EM(int direction)
6510 return (direction == MV_UP ? 0 :
6511 direction == MV_RIGHT ? 1 :
6512 direction == MV_DOWN ? 2 :
6513 direction == MV_LEFT ? 3 :
6517 int map_direction_EM_to_RND(int direction)
6519 return (direction == 0 ? MV_UP :
6520 direction == 1 ? MV_RIGHT :
6521 direction == 2 ? MV_DOWN :
6522 direction == 3 ? MV_LEFT :
6526 int map_element_RND_to_SP(int element_rnd)
6528 int element_sp = 0x20; /* map unknown elements to yellow "hardware" */
6530 if (element_rnd >= EL_SP_START &&
6531 element_rnd <= EL_SP_END)
6532 element_sp = element_rnd - EL_SP_START;
6533 else if (element_rnd == EL_EMPTY_SPACE)
6535 else if (element_rnd == EL_INVISIBLE_WALL)
6541 int map_element_SP_to_RND(int element_sp)
6543 int element_rnd = EL_UNKNOWN;
6545 if (element_sp >= 0x00 &&
6547 element_rnd = EL_SP_START + element_sp;
6548 else if (element_sp == 0x28)
6549 element_rnd = EL_INVISIBLE_WALL;
6554 int map_action_SP_to_RND(int action_sp)
6558 case actActive: return ACTION_ACTIVE;
6559 case actImpact: return ACTION_IMPACT;
6560 case actExploding: return ACTION_EXPLODING;
6561 case actDigging: return ACTION_DIGGING;
6562 case actSnapping: return ACTION_SNAPPING;
6563 case actCollecting: return ACTION_COLLECTING;
6564 case actPassing: return ACTION_PASSING;
6565 case actPushing: return ACTION_PUSHING;
6566 case actDropping: return ACTION_DROPPING;
6568 default: return ACTION_DEFAULT;
6572 int get_next_element(int element)
6576 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
6577 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
6578 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
6579 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
6580 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
6581 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
6582 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
6583 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
6584 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
6585 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
6586 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
6588 default: return element;
6592 int el_act_dir2img(int element, int action, int direction)
6594 element = GFX_ELEMENT(element);
6595 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
6597 /* direction_graphic[][] == graphic[] for undefined direction graphics */
6598 return element_info[element].direction_graphic[action][direction];
6601 static int el_act_dir2crm(int element, int action, int direction)
6603 element = GFX_ELEMENT(element);
6604 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
6606 /* direction_graphic[][] == graphic[] for undefined direction graphics */
6607 return element_info[element].direction_crumbled[action][direction];
6610 int el_act2img(int element, int action)
6612 element = GFX_ELEMENT(element);
6614 return element_info[element].graphic[action];
6617 int el_act2crm(int element, int action)
6619 element = GFX_ELEMENT(element);
6621 return element_info[element].crumbled[action];
6624 int el_dir2img(int element, int direction)
6626 element = GFX_ELEMENT(element);
6628 return el_act_dir2img(element, ACTION_DEFAULT, direction);
6631 int el2baseimg(int element)
6633 return element_info[element].graphic[ACTION_DEFAULT];
6636 int el2img(int element)
6638 element = GFX_ELEMENT(element);
6640 return element_info[element].graphic[ACTION_DEFAULT];
6643 int el2edimg(int element)
6645 element = GFX_ELEMENT(element);
6647 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
6650 int el2preimg(int element)
6652 element = GFX_ELEMENT(element);
6654 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
6657 int el2panelimg(int element)
6659 element = GFX_ELEMENT(element);
6661 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL];
6664 int font2baseimg(int font_nr)
6666 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
6669 int getBeltNrFromBeltElement(int element)
6671 return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
6672 element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
6673 element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
6676 int getBeltNrFromBeltActiveElement(int element)
6678 return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
6679 element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
6680 element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
6683 int getBeltNrFromBeltSwitchElement(int element)
6685 return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
6686 element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
6687 element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
6690 int getBeltDirNrFromBeltElement(int element)
6692 static int belt_base_element[4] =
6694 EL_CONVEYOR_BELT_1_LEFT,
6695 EL_CONVEYOR_BELT_2_LEFT,
6696 EL_CONVEYOR_BELT_3_LEFT,
6697 EL_CONVEYOR_BELT_4_LEFT
6700 int belt_nr = getBeltNrFromBeltElement(element);
6701 int belt_dir_nr = element - belt_base_element[belt_nr];
6703 return (belt_dir_nr % 3);
6706 int getBeltDirNrFromBeltSwitchElement(int element)
6708 static int belt_base_element[4] =
6710 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
6711 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
6712 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
6713 EL_CONVEYOR_BELT_4_SWITCH_LEFT
6716 int belt_nr = getBeltNrFromBeltSwitchElement(element);
6717 int belt_dir_nr = element - belt_base_element[belt_nr];
6719 return (belt_dir_nr % 3);
6722 int getBeltDirFromBeltElement(int element)
6724 static int belt_move_dir[3] =
6731 int belt_dir_nr = getBeltDirNrFromBeltElement(element);
6733 return belt_move_dir[belt_dir_nr];
6736 int getBeltDirFromBeltSwitchElement(int element)
6738 static int belt_move_dir[3] =
6745 int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
6747 return belt_move_dir[belt_dir_nr];
6750 int getBeltElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
6752 static int belt_base_element[4] =
6754 EL_CONVEYOR_BELT_1_LEFT,
6755 EL_CONVEYOR_BELT_2_LEFT,
6756 EL_CONVEYOR_BELT_3_LEFT,
6757 EL_CONVEYOR_BELT_4_LEFT
6760 return belt_base_element[belt_nr] + belt_dir_nr;
6763 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
6765 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
6767 return getBeltElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
6770 int getBeltSwitchElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
6772 static int belt_base_element[4] =
6774 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
6775 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
6776 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
6777 EL_CONVEYOR_BELT_4_SWITCH_LEFT
6780 return belt_base_element[belt_nr] + belt_dir_nr;
6783 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
6785 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
6787 return getBeltSwitchElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
6790 boolean getTeamMode_EM()
6792 return game.team_mode;
6795 int getGameFrameDelay_EM(int native_em_game_frame_delay)
6797 int game_frame_delay_value;
6799 game_frame_delay_value =
6800 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
6801 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
6804 if (tape.playing && tape.warp_forward && !tape.pausing)
6805 game_frame_delay_value = 0;
6807 return game_frame_delay_value;
6810 unsigned int InitRND(int seed)
6812 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
6813 return InitEngineRandom_EM(seed);
6814 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
6815 return InitEngineRandom_SP(seed);
6817 return InitEngineRandom_RND(seed);
6820 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
6821 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
6823 inline static int get_effective_element_EM(int tile, int frame_em)
6825 int element = object_mapping[tile].element_rnd;
6826 int action = object_mapping[tile].action;
6827 boolean is_backside = object_mapping[tile].is_backside;
6828 boolean action_removing = (action == ACTION_DIGGING ||
6829 action == ACTION_SNAPPING ||
6830 action == ACTION_COLLECTING);
6836 case Yacid_splash_eB:
6837 case Yacid_splash_wB:
6838 return (frame_em > 5 ? EL_EMPTY : element);
6844 else /* frame_em == 7 */
6848 case Yacid_splash_eB:
6849 case Yacid_splash_wB:
6852 case Yemerald_stone:
6855 case Ydiamond_stone:
6859 case Xdrip_stretchB:
6878 case Xsand_stonein_1:
6879 case Xsand_stonein_2:
6880 case Xsand_stonein_3:
6881 case Xsand_stonein_4:
6885 return (is_backside || action_removing ? EL_EMPTY : element);
6890 inline static boolean check_linear_animation_EM(int tile)
6894 case Xsand_stonesand_1:
6895 case Xsand_stonesand_quickout_1:
6896 case Xsand_sandstone_1:
6897 case Xsand_stonein_1:
6898 case Xsand_stoneout_1:
6917 case Yacid_splash_eB:
6918 case Yacid_splash_wB:
6919 case Yemerald_stone:
6926 inline static void set_crumbled_graphics_EM(struct GraphicInfo_EM *g_em,
6927 boolean has_crumbled_graphics,
6928 int crumbled, int sync_frame)
6930 /* if element can be crumbled, but certain action graphics are just empty
6931 space (like instantly snapping sand to empty space in 1 frame), do not
6932 treat these empty space graphics as crumbled graphics in EMC engine */
6933 if (crumbled == IMG_EMPTY_SPACE)
6934 has_crumbled_graphics = FALSE;
6936 if (has_crumbled_graphics)
6938 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
6939 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
6940 g_crumbled->anim_delay,
6941 g_crumbled->anim_mode,
6942 g_crumbled->anim_start_frame,
6945 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
6946 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
6948 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
6950 g_em->has_crumbled_graphics = TRUE;
6954 g_em->crumbled_bitmap = NULL;
6955 g_em->crumbled_src_x = 0;
6956 g_em->crumbled_src_y = 0;
6957 g_em->crumbled_border_size = 0;
6959 g_em->has_crumbled_graphics = FALSE;
6963 void ResetGfxAnimation_EM(int x, int y, int tile)
6968 void SetGfxAnimation_EM(struct GraphicInfo_EM *g_em,
6969 int tile, int frame_em, int x, int y)
6971 int action = object_mapping[tile].action;
6972 int direction = object_mapping[tile].direction;
6973 int effective_element = get_effective_element_EM(tile, frame_em);
6974 int graphic = (direction == MV_NONE ?
6975 el_act2img(effective_element, action) :
6976 el_act_dir2img(effective_element, action, direction));
6977 struct GraphicInfo *g = &graphic_info[graphic];
6979 boolean action_removing = (action == ACTION_DIGGING ||
6980 action == ACTION_SNAPPING ||
6981 action == ACTION_COLLECTING);
6982 boolean action_moving = (action == ACTION_FALLING ||
6983 action == ACTION_MOVING ||
6984 action == ACTION_PUSHING ||
6985 action == ACTION_EATING ||
6986 action == ACTION_FILLING ||
6987 action == ACTION_EMPTYING);
6988 boolean action_falling = (action == ACTION_FALLING ||
6989 action == ACTION_FILLING ||
6990 action == ACTION_EMPTYING);
6992 /* special case: graphic uses "2nd movement tile" and has defined
6993 7 frames for movement animation (or less) => use default graphic
6994 for last (8th) frame which ends the movement animation */
6995 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
6997 action = ACTION_DEFAULT; /* (keep action_* unchanged for now) */
6998 graphic = (direction == MV_NONE ?
6999 el_act2img(effective_element, action) :
7000 el_act_dir2img(effective_element, action, direction));
7002 g = &graphic_info[graphic];
7005 if ((action_removing || check_linear_animation_EM(tile)) && frame_em == 0)
7009 else if (action_moving)
7011 boolean is_backside = object_mapping[tile].is_backside;
7015 int direction = object_mapping[tile].direction;
7016 int move_dir = (action_falling ? MV_DOWN : direction);
7021 /* !!! TEST !!! NEW !!! DOES NOT WORK RIGHT YET !!! */
7022 if (g->double_movement && frame_em == 0)
7026 if (move_dir == MV_LEFT)
7027 GfxFrame[x - 1][y] = GfxFrame[x][y];
7028 else if (move_dir == MV_RIGHT)
7029 GfxFrame[x + 1][y] = GfxFrame[x][y];
7030 else if (move_dir == MV_UP)
7031 GfxFrame[x][y - 1] = GfxFrame[x][y];
7032 else if (move_dir == MV_DOWN)
7033 GfxFrame[x][y + 1] = GfxFrame[x][y];
7040 /* special case: animation for Xsand_stonesand_quickout_1/2 twice as fast */
7041 if (tile == Xsand_stonesand_quickout_1 ||
7042 tile == Xsand_stonesand_quickout_2)
7046 if (graphic_info[graphic].anim_global_sync)
7047 sync_frame = FrameCounter;
7048 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
7049 sync_frame = GfxFrame[x][y];
7051 sync_frame = 0; /* playfield border (pseudo steel) */
7053 SetRandomAnimationValue(x, y);
7055 int frame = getAnimationFrame(g->anim_frames,
7058 g->anim_start_frame,
7061 g_em->unique_identifier =
7062 (graphic << 16) | ((frame % 8) << 12) | (g_em->width << 6) | g_em->height;
7065 void getGraphicSourceObjectExt_EM(struct GraphicInfo_EM *g_em,
7066 int tile, int frame_em, int x, int y)
7068 int action = object_mapping[tile].action;
7069 int direction = object_mapping[tile].direction;
7070 boolean is_backside = object_mapping[tile].is_backside;
7071 int effective_element = get_effective_element_EM(tile, frame_em);
7072 int effective_action = action;
7073 int graphic = (direction == MV_NONE ?
7074 el_act2img(effective_element, effective_action) :
7075 el_act_dir2img(effective_element, effective_action,
7077 int crumbled = (direction == MV_NONE ?
7078 el_act2crm(effective_element, effective_action) :
7079 el_act_dir2crm(effective_element, effective_action,
7081 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7082 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7083 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7084 struct GraphicInfo *g = &graphic_info[graphic];
7087 /* special case: graphic uses "2nd movement tile" and has defined
7088 7 frames for movement animation (or less) => use default graphic
7089 for last (8th) frame which ends the movement animation */
7090 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
7092 effective_action = ACTION_DEFAULT;
7093 graphic = (direction == MV_NONE ?
7094 el_act2img(effective_element, effective_action) :
7095 el_act_dir2img(effective_element, effective_action,
7097 crumbled = (direction == MV_NONE ?
7098 el_act2crm(effective_element, effective_action) :
7099 el_act_dir2crm(effective_element, effective_action,
7102 g = &graphic_info[graphic];
7105 if (graphic_info[graphic].anim_global_sync)
7106 sync_frame = FrameCounter;
7107 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
7108 sync_frame = GfxFrame[x][y];
7110 sync_frame = 0; /* playfield border (pseudo steel) */
7112 SetRandomAnimationValue(x, y);
7114 int frame = getAnimationFrame(g->anim_frames,
7117 g->anim_start_frame,
7120 getGraphicSourceExt(graphic, frame, &g_em->bitmap, &g_em->src_x, &g_em->src_y,
7121 g->double_movement && is_backside);
7123 /* (updating the "crumbled" graphic definitions is probably not really needed,
7124 as animations for crumbled graphics can't be longer than one EMC cycle) */
7125 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
7129 void getGraphicSourcePlayerExt_EM(struct GraphicInfo_EM *g_em,
7130 int player_nr, int anim, int frame_em)
7132 int element = player_mapping[player_nr][anim].element_rnd;
7133 int action = player_mapping[player_nr][anim].action;
7134 int direction = player_mapping[player_nr][anim].direction;
7135 int graphic = (direction == MV_NONE ?
7136 el_act2img(element, action) :
7137 el_act_dir2img(element, action, direction));
7138 struct GraphicInfo *g = &graphic_info[graphic];
7141 InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
7143 stored_player[player_nr].StepFrame = frame_em;
7145 sync_frame = stored_player[player_nr].Frame;
7147 int frame = getAnimationFrame(g->anim_frames,
7150 g->anim_start_frame,
7153 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
7154 &g_em->src_x, &g_em->src_y, FALSE);
7157 void InitGraphicInfo_EM(void)
7162 int num_em_gfx_errors = 0;
7164 if (graphic_info_em_object[0][0].bitmap == NULL)
7166 /* EM graphics not yet initialized in em_open_all() */
7171 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
7174 /* always start with reliable default values */
7175 for (i = 0; i < TILE_MAX; i++)
7177 object_mapping[i].element_rnd = EL_UNKNOWN;
7178 object_mapping[i].is_backside = FALSE;
7179 object_mapping[i].action = ACTION_DEFAULT;
7180 object_mapping[i].direction = MV_NONE;
7183 /* always start with reliable default values */
7184 for (p = 0; p < MAX_PLAYERS; p++)
7186 for (i = 0; i < SPR_MAX; i++)
7188 player_mapping[p][i].element_rnd = EL_UNKNOWN;
7189 player_mapping[p][i].action = ACTION_DEFAULT;
7190 player_mapping[p][i].direction = MV_NONE;
7194 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
7196 int e = em_object_mapping_list[i].element_em;
7198 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
7199 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
7201 if (em_object_mapping_list[i].action != -1)
7202 object_mapping[e].action = em_object_mapping_list[i].action;
7204 if (em_object_mapping_list[i].direction != -1)
7205 object_mapping[e].direction =
7206 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
7209 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
7211 int a = em_player_mapping_list[i].action_em;
7212 int p = em_player_mapping_list[i].player_nr;
7214 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
7216 if (em_player_mapping_list[i].action != -1)
7217 player_mapping[p][a].action = em_player_mapping_list[i].action;
7219 if (em_player_mapping_list[i].direction != -1)
7220 player_mapping[p][a].direction =
7221 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
7224 for (i = 0; i < TILE_MAX; i++)
7226 int element = object_mapping[i].element_rnd;
7227 int action = object_mapping[i].action;
7228 int direction = object_mapping[i].direction;
7229 boolean is_backside = object_mapping[i].is_backside;
7230 boolean action_exploding = ((action == ACTION_EXPLODING ||
7231 action == ACTION_SMASHED_BY_ROCK ||
7232 action == ACTION_SMASHED_BY_SPRING) &&
7233 element != EL_DIAMOND);
7234 boolean action_active = (action == ACTION_ACTIVE);
7235 boolean action_other = (action == ACTION_OTHER);
7237 for (j = 0; j < 8; j++)
7239 int effective_element = get_effective_element_EM(i, j);
7240 int effective_action = (j < 7 ? action :
7241 i == Xdrip_stretch ? action :
7242 i == Xdrip_stretchB ? action :
7243 i == Ydrip_s1 ? action :
7244 i == Ydrip_s1B ? action :
7245 i == Xball_1B ? action :
7246 i == Xball_2 ? action :
7247 i == Xball_2B ? action :
7248 i == Yball_eat ? action :
7249 i == Ykey_1_eat ? action :
7250 i == Ykey_2_eat ? action :
7251 i == Ykey_3_eat ? action :
7252 i == Ykey_4_eat ? action :
7253 i == Ykey_5_eat ? action :
7254 i == Ykey_6_eat ? action :
7255 i == Ykey_7_eat ? action :
7256 i == Ykey_8_eat ? action :
7257 i == Ylenses_eat ? action :
7258 i == Ymagnify_eat ? action :
7259 i == Ygrass_eat ? action :
7260 i == Ydirt_eat ? action :
7261 i == Xsand_stonein_1 ? action :
7262 i == Xsand_stonein_2 ? action :
7263 i == Xsand_stonein_3 ? action :
7264 i == Xsand_stonein_4 ? action :
7265 i == Xsand_stoneout_1 ? action :
7266 i == Xsand_stoneout_2 ? action :
7267 i == Xboom_android ? ACTION_EXPLODING :
7268 action_exploding ? ACTION_EXPLODING :
7269 action_active ? action :
7270 action_other ? action :
7272 int graphic = (el_act_dir2img(effective_element, effective_action,
7274 int crumbled = (el_act_dir2crm(effective_element, effective_action,
7276 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7277 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7278 boolean has_action_graphics = (graphic != base_graphic);
7279 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7280 struct GraphicInfo *g = &graphic_info[graphic];
7281 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7284 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
7285 boolean special_animation = (action != ACTION_DEFAULT &&
7286 g->anim_frames == 3 &&
7287 g->anim_delay == 2 &&
7288 g->anim_mode & ANIM_LINEAR);
7289 int sync_frame = (i == Xdrip_stretch ? 7 :
7290 i == Xdrip_stretchB ? 7 :
7291 i == Ydrip_s2 ? j + 8 :
7292 i == Ydrip_s2B ? j + 8 :
7301 i == Xfake_acid_1 ? 0 :
7302 i == Xfake_acid_2 ? 10 :
7303 i == Xfake_acid_3 ? 20 :
7304 i == Xfake_acid_4 ? 30 :
7305 i == Xfake_acid_5 ? 40 :
7306 i == Xfake_acid_6 ? 50 :
7307 i == Xfake_acid_7 ? 60 :
7308 i == Xfake_acid_8 ? 70 :
7310 i == Xball_2B ? j + 8 :
7311 i == Yball_eat ? j + 1 :
7312 i == Ykey_1_eat ? j + 1 :
7313 i == Ykey_2_eat ? j + 1 :
7314 i == Ykey_3_eat ? j + 1 :
7315 i == Ykey_4_eat ? j + 1 :
7316 i == Ykey_5_eat ? j + 1 :
7317 i == Ykey_6_eat ? j + 1 :
7318 i == Ykey_7_eat ? j + 1 :
7319 i == Ykey_8_eat ? j + 1 :
7320 i == Ylenses_eat ? j + 1 :
7321 i == Ymagnify_eat ? j + 1 :
7322 i == Ygrass_eat ? j + 1 :
7323 i == Ydirt_eat ? j + 1 :
7324 i == Xamoeba_1 ? 0 :
7325 i == Xamoeba_2 ? 1 :
7326 i == Xamoeba_3 ? 2 :
7327 i == Xamoeba_4 ? 3 :
7328 i == Xamoeba_5 ? 0 :
7329 i == Xamoeba_6 ? 1 :
7330 i == Xamoeba_7 ? 2 :
7331 i == Xamoeba_8 ? 3 :
7332 i == Xexit_2 ? j + 8 :
7333 i == Xexit_3 ? j + 16 :
7334 i == Xdynamite_1 ? 0 :
7335 i == Xdynamite_2 ? 8 :
7336 i == Xdynamite_3 ? 16 :
7337 i == Xdynamite_4 ? 24 :
7338 i == Xsand_stonein_1 ? j + 1 :
7339 i == Xsand_stonein_2 ? j + 9 :
7340 i == Xsand_stonein_3 ? j + 17 :
7341 i == Xsand_stonein_4 ? j + 25 :
7342 i == Xsand_stoneout_1 && j == 0 ? 0 :
7343 i == Xsand_stoneout_1 && j == 1 ? 0 :
7344 i == Xsand_stoneout_1 && j == 2 ? 1 :
7345 i == Xsand_stoneout_1 && j == 3 ? 2 :
7346 i == Xsand_stoneout_1 && j == 4 ? 2 :
7347 i == Xsand_stoneout_1 && j == 5 ? 3 :
7348 i == Xsand_stoneout_1 && j == 6 ? 4 :
7349 i == Xsand_stoneout_1 && j == 7 ? 4 :
7350 i == Xsand_stoneout_2 && j == 0 ? 5 :
7351 i == Xsand_stoneout_2 && j == 1 ? 6 :
7352 i == Xsand_stoneout_2 && j == 2 ? 7 :
7353 i == Xsand_stoneout_2 && j == 3 ? 8 :
7354 i == Xsand_stoneout_2 && j == 4 ? 9 :
7355 i == Xsand_stoneout_2 && j == 5 ? 11 :
7356 i == Xsand_stoneout_2 && j == 6 ? 13 :
7357 i == Xsand_stoneout_2 && j == 7 ? 15 :
7358 i == Xboom_bug && j == 1 ? 2 :
7359 i == Xboom_bug && j == 2 ? 2 :
7360 i == Xboom_bug && j == 3 ? 4 :
7361 i == Xboom_bug && j == 4 ? 4 :
7362 i == Xboom_bug && j == 5 ? 2 :
7363 i == Xboom_bug && j == 6 ? 2 :
7364 i == Xboom_bug && j == 7 ? 0 :
7365 i == Xboom_bomb && j == 1 ? 2 :
7366 i == Xboom_bomb && j == 2 ? 2 :
7367 i == Xboom_bomb && j == 3 ? 4 :
7368 i == Xboom_bomb && j == 4 ? 4 :
7369 i == Xboom_bomb && j == 5 ? 2 :
7370 i == Xboom_bomb && j == 6 ? 2 :
7371 i == Xboom_bomb && j == 7 ? 0 :
7372 i == Xboom_android && j == 7 ? 6 :
7373 i == Xboom_1 && j == 1 ? 2 :
7374 i == Xboom_1 && j == 2 ? 2 :
7375 i == Xboom_1 && j == 3 ? 4 :
7376 i == Xboom_1 && j == 4 ? 4 :
7377 i == Xboom_1 && j == 5 ? 6 :
7378 i == Xboom_1 && j == 6 ? 6 :
7379 i == Xboom_1 && j == 7 ? 8 :
7380 i == Xboom_2 && j == 0 ? 8 :
7381 i == Xboom_2 && j == 1 ? 8 :
7382 i == Xboom_2 && j == 2 ? 10 :
7383 i == Xboom_2 && j == 3 ? 10 :
7384 i == Xboom_2 && j == 4 ? 10 :
7385 i == Xboom_2 && j == 5 ? 12 :
7386 i == Xboom_2 && j == 6 ? 12 :
7387 i == Xboom_2 && j == 7 ? 12 :
7388 special_animation && j == 4 ? 3 :
7389 effective_action != action ? 0 :
7393 Bitmap *debug_bitmap = g_em->bitmap;
7394 int debug_src_x = g_em->src_x;
7395 int debug_src_y = g_em->src_y;
7398 int frame = getAnimationFrame(g->anim_frames,
7401 g->anim_start_frame,
7404 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
7405 g->double_movement && is_backside);
7407 g_em->bitmap = src_bitmap;
7408 g_em->src_x = src_x;
7409 g_em->src_y = src_y;
7410 g_em->src_offset_x = 0;
7411 g_em->src_offset_y = 0;
7412 g_em->dst_offset_x = 0;
7413 g_em->dst_offset_y = 0;
7414 g_em->width = TILEX;
7415 g_em->height = TILEY;
7417 g_em->preserve_background = FALSE;
7419 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
7422 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
7423 effective_action == ACTION_MOVING ||
7424 effective_action == ACTION_PUSHING ||
7425 effective_action == ACTION_EATING)) ||
7426 (!has_action_graphics && (effective_action == ACTION_FILLING ||
7427 effective_action == ACTION_EMPTYING)))
7430 (effective_action == ACTION_FALLING ||
7431 effective_action == ACTION_FILLING ||
7432 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
7433 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
7434 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
7435 int num_steps = (i == Ydrip_s1 ? 16 :
7436 i == Ydrip_s1B ? 16 :
7437 i == Ydrip_s2 ? 16 :
7438 i == Ydrip_s2B ? 16 :
7439 i == Xsand_stonein_1 ? 32 :
7440 i == Xsand_stonein_2 ? 32 :
7441 i == Xsand_stonein_3 ? 32 :
7442 i == Xsand_stonein_4 ? 32 :
7443 i == Xsand_stoneout_1 ? 16 :
7444 i == Xsand_stoneout_2 ? 16 : 8);
7445 int cx = ABS(dx) * (TILEX / num_steps);
7446 int cy = ABS(dy) * (TILEY / num_steps);
7447 int step_frame = (i == Ydrip_s2 ? j + 8 :
7448 i == Ydrip_s2B ? j + 8 :
7449 i == Xsand_stonein_2 ? j + 8 :
7450 i == Xsand_stonein_3 ? j + 16 :
7451 i == Xsand_stonein_4 ? j + 24 :
7452 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
7453 int step = (is_backside ? step_frame : num_steps - step_frame);
7455 if (is_backside) /* tile where movement starts */
7457 if (dx < 0 || dy < 0)
7459 g_em->src_offset_x = cx * step;
7460 g_em->src_offset_y = cy * step;
7464 g_em->dst_offset_x = cx * step;
7465 g_em->dst_offset_y = cy * step;
7468 else /* tile where movement ends */
7470 if (dx < 0 || dy < 0)
7472 g_em->dst_offset_x = cx * step;
7473 g_em->dst_offset_y = cy * step;
7477 g_em->src_offset_x = cx * step;
7478 g_em->src_offset_y = cy * step;
7482 g_em->width = TILEX - cx * step;
7483 g_em->height = TILEY - cy * step;
7486 /* create unique graphic identifier to decide if tile must be redrawn */
7487 /* bit 31 - 16 (16 bit): EM style graphic
7488 bit 15 - 12 ( 4 bit): EM style frame
7489 bit 11 - 6 ( 6 bit): graphic width
7490 bit 5 - 0 ( 6 bit): graphic height */
7491 g_em->unique_identifier =
7492 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
7496 /* skip check for EMC elements not contained in original EMC artwork */
7497 if (element == EL_EMC_FAKE_ACID)
7500 if (g_em->bitmap != debug_bitmap ||
7501 g_em->src_x != debug_src_x ||
7502 g_em->src_y != debug_src_y ||
7503 g_em->src_offset_x != 0 ||
7504 g_em->src_offset_y != 0 ||
7505 g_em->dst_offset_x != 0 ||
7506 g_em->dst_offset_y != 0 ||
7507 g_em->width != TILEX ||
7508 g_em->height != TILEY)
7510 static int last_i = -1;
7518 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
7519 i, element, element_info[element].token_name,
7520 element_action_info[effective_action].suffix, direction);
7522 if (element != effective_element)
7523 printf(" [%d ('%s')]",
7525 element_info[effective_element].token_name);
7529 if (g_em->bitmap != debug_bitmap)
7530 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
7531 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
7533 if (g_em->src_x != debug_src_x ||
7534 g_em->src_y != debug_src_y)
7535 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
7536 j, (is_backside ? 'B' : 'F'),
7537 g_em->src_x, g_em->src_y,
7538 g_em->src_x / 32, g_em->src_y / 32,
7539 debug_src_x, debug_src_y,
7540 debug_src_x / 32, debug_src_y / 32);
7542 if (g_em->src_offset_x != 0 ||
7543 g_em->src_offset_y != 0 ||
7544 g_em->dst_offset_x != 0 ||
7545 g_em->dst_offset_y != 0)
7546 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
7548 g_em->src_offset_x, g_em->src_offset_y,
7549 g_em->dst_offset_x, g_em->dst_offset_y);
7551 if (g_em->width != TILEX ||
7552 g_em->height != TILEY)
7553 printf(" %d (%d): size %d,%d should be %d,%d\n",
7555 g_em->width, g_em->height, TILEX, TILEY);
7557 num_em_gfx_errors++;
7564 for (i = 0; i < TILE_MAX; i++)
7566 for (j = 0; j < 8; j++)
7568 int element = object_mapping[i].element_rnd;
7569 int action = object_mapping[i].action;
7570 int direction = object_mapping[i].direction;
7571 boolean is_backside = object_mapping[i].is_backside;
7572 int graphic_action = el_act_dir2img(element, action, direction);
7573 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
7575 if ((action == ACTION_SMASHED_BY_ROCK ||
7576 action == ACTION_SMASHED_BY_SPRING ||
7577 action == ACTION_EATING) &&
7578 graphic_action == graphic_default)
7580 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
7581 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
7582 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
7583 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
7586 /* no separate animation for "smashed by rock" -- use rock instead */
7587 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7588 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
7590 g_em->bitmap = g_xx->bitmap;
7591 g_em->src_x = g_xx->src_x;
7592 g_em->src_y = g_xx->src_y;
7593 g_em->src_offset_x = g_xx->src_offset_x;
7594 g_em->src_offset_y = g_xx->src_offset_y;
7595 g_em->dst_offset_x = g_xx->dst_offset_x;
7596 g_em->dst_offset_y = g_xx->dst_offset_y;
7597 g_em->width = g_xx->width;
7598 g_em->height = g_xx->height;
7599 g_em->unique_identifier = g_xx->unique_identifier;
7602 g_em->preserve_background = TRUE;
7607 for (p = 0; p < MAX_PLAYERS; p++)
7609 for (i = 0; i < SPR_MAX; i++)
7611 int element = player_mapping[p][i].element_rnd;
7612 int action = player_mapping[p][i].action;
7613 int direction = player_mapping[p][i].direction;
7615 for (j = 0; j < 8; j++)
7617 int effective_element = element;
7618 int effective_action = action;
7619 int graphic = (direction == MV_NONE ?
7620 el_act2img(effective_element, effective_action) :
7621 el_act_dir2img(effective_element, effective_action,
7623 struct GraphicInfo *g = &graphic_info[graphic];
7624 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
7630 Bitmap *debug_bitmap = g_em->bitmap;
7631 int debug_src_x = g_em->src_x;
7632 int debug_src_y = g_em->src_y;
7635 int frame = getAnimationFrame(g->anim_frames,
7638 g->anim_start_frame,
7641 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
7643 g_em->bitmap = src_bitmap;
7644 g_em->src_x = src_x;
7645 g_em->src_y = src_y;
7646 g_em->src_offset_x = 0;
7647 g_em->src_offset_y = 0;
7648 g_em->dst_offset_x = 0;
7649 g_em->dst_offset_y = 0;
7650 g_em->width = TILEX;
7651 g_em->height = TILEY;
7655 /* skip check for EMC elements not contained in original EMC artwork */
7656 if (element == EL_PLAYER_3 ||
7657 element == EL_PLAYER_4)
7660 if (g_em->bitmap != debug_bitmap ||
7661 g_em->src_x != debug_src_x ||
7662 g_em->src_y != debug_src_y)
7664 static int last_i = -1;
7672 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
7673 p, i, element, element_info[element].token_name,
7674 element_action_info[effective_action].suffix, direction);
7676 if (element != effective_element)
7677 printf(" [%d ('%s')]",
7679 element_info[effective_element].token_name);
7683 if (g_em->bitmap != debug_bitmap)
7684 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
7685 j, (int)(g_em->bitmap), (int)(debug_bitmap));
7687 if (g_em->src_x != debug_src_x ||
7688 g_em->src_y != debug_src_y)
7689 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
7691 g_em->src_x, g_em->src_y,
7692 g_em->src_x / 32, g_em->src_y / 32,
7693 debug_src_x, debug_src_y,
7694 debug_src_x / 32, debug_src_y / 32);
7696 num_em_gfx_errors++;
7706 printf("::: [%d errors found]\n", num_em_gfx_errors);
7712 void CheckSaveEngineSnapshot_EM(byte action[MAX_PLAYERS], int frame,
7713 boolean any_player_moving,
7714 boolean any_player_snapping,
7715 boolean any_player_dropping)
7717 static boolean player_was_waiting = TRUE;
7719 if (frame == 0 && !any_player_dropping)
7721 if (!player_was_waiting)
7723 if (!SaveEngineSnapshotToList())
7726 player_was_waiting = TRUE;
7729 else if (any_player_moving || any_player_snapping || any_player_dropping)
7731 player_was_waiting = FALSE;
7735 void CheckSaveEngineSnapshot_SP(boolean murphy_is_waiting,
7736 boolean murphy_is_dropping)
7738 static boolean player_was_waiting = TRUE;
7740 if (murphy_is_waiting)
7742 if (!player_was_waiting)
7744 if (!SaveEngineSnapshotToList())
7747 player_was_waiting = TRUE;
7752 player_was_waiting = FALSE;
7756 void CheckSingleStepMode_EM(byte action[MAX_PLAYERS], int frame,
7757 boolean any_player_moving,
7758 boolean any_player_snapping,
7759 boolean any_player_dropping)
7761 if (tape.single_step && tape.recording && !tape.pausing)
7762 if (frame == 0 && !any_player_dropping)
7763 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
7765 CheckSaveEngineSnapshot_EM(action, frame, any_player_moving,
7766 any_player_snapping, any_player_dropping);
7769 void CheckSingleStepMode_SP(boolean murphy_is_waiting,
7770 boolean murphy_is_dropping)
7772 if (tape.single_step && tape.recording && !tape.pausing)
7773 if (murphy_is_waiting)
7774 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
7776 CheckSaveEngineSnapshot_SP(murphy_is_waiting, murphy_is_dropping);
7779 void getGraphicSource_SP(struct GraphicInfo_SP *g_sp,
7780 int graphic, int sync_frame, int x, int y)
7782 int frame = getGraphicAnimationFrame(graphic, sync_frame);
7784 getGraphicSource(graphic, frame, &g_sp->bitmap, &g_sp->src_x, &g_sp->src_y);
7787 boolean isNextAnimationFrame_SP(int graphic, int sync_frame)
7789 return (IS_NEXT_FRAME(sync_frame, graphic));
7792 int getGraphicInfo_Delay(int graphic)
7794 return graphic_info[graphic].anim_delay;
7797 void PlayMenuSoundExt(int sound)
7799 if (sound == SND_UNDEFINED)
7802 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
7803 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
7806 if (IS_LOOP_SOUND(sound))
7807 PlaySoundLoop(sound);
7812 void PlayMenuSound()
7814 PlayMenuSoundExt(menu.sound[game_status]);
7817 void PlayMenuSoundStereo(int sound, int stereo_position)
7819 if (sound == SND_UNDEFINED)
7822 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
7823 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
7826 if (IS_LOOP_SOUND(sound))
7827 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
7829 PlaySoundStereo(sound, stereo_position);
7832 void PlayMenuSoundIfLoopExt(int sound)
7834 if (sound == SND_UNDEFINED)
7837 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
7838 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
7841 if (IS_LOOP_SOUND(sound))
7842 PlaySoundLoop(sound);
7845 void PlayMenuSoundIfLoop()
7847 PlayMenuSoundIfLoopExt(menu.sound[game_status]);
7850 void PlayMenuMusicExt(int music)
7852 if (music == MUS_UNDEFINED)
7855 if (!setup.sound_music)
7861 void PlayMenuMusic()
7863 PlayMenuMusicExt(menu.music[game_status]);
7866 void PlaySoundActivating()
7869 PlaySound(SND_MENU_ITEM_ACTIVATING);
7873 void PlaySoundSelecting()
7876 PlaySound(SND_MENU_ITEM_SELECTING);
7880 void ToggleFullscreenOrChangeWindowScalingIfNeeded()
7882 boolean change_fullscreen = (setup.fullscreen !=
7883 video.fullscreen_enabled);
7884 boolean change_fullscreen_mode = (video.fullscreen_enabled &&
7885 !strEqual(setup.fullscreen_mode,
7886 video.fullscreen_mode_current));
7887 boolean change_window_scaling_percent = (!video.fullscreen_enabled &&
7888 setup.window_scaling_percent !=
7889 video.window_scaling_percent);
7891 if (change_window_scaling_percent && video.fullscreen_enabled)
7894 if (!change_window_scaling_percent && !video.fullscreen_available)
7897 #if defined(TARGET_SDL2)
7898 if (change_window_scaling_percent)
7900 SDLSetWindowScaling(setup.window_scaling_percent);
7904 else if (change_fullscreen)
7906 SDLSetWindowFullscreen(setup.fullscreen);
7908 /* set setup value according to successfully changed fullscreen mode */
7909 setup.fullscreen = video.fullscreen_enabled;
7915 if (change_fullscreen ||
7916 change_fullscreen_mode ||
7917 change_window_scaling_percent)
7919 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
7921 /* save backbuffer content which gets lost when toggling fullscreen mode */
7922 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
7924 if (change_fullscreen_mode)
7926 /* keep fullscreen, but change fullscreen mode (screen resolution) */
7927 video.fullscreen_enabled = FALSE; /* force new fullscreen mode */
7930 if (change_window_scaling_percent)
7932 /* keep window mode, but change window scaling */
7933 video.fullscreen_enabled = TRUE; /* force new window scaling */
7936 /* toggle fullscreen */
7937 ChangeVideoModeIfNeeded(setup.fullscreen);
7939 /* set setup value according to successfully changed fullscreen mode */
7940 setup.fullscreen = video.fullscreen_enabled;
7942 /* restore backbuffer content from temporary backbuffer backup bitmap */
7943 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
7945 FreeBitmap(tmp_backbuffer);
7947 /* update visible window/screen */
7948 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
7952 void ChangeViewportPropertiesIfNeeded()
7954 int gfx_game_mode = game_status;
7955 int gfx_game_mode2 = (game_status == GAME_MODE_EDITOR ? GAME_MODE_DEFAULT :
7957 struct RectWithBorder *vp_playfield = &viewport.playfield[gfx_game_mode];
7958 struct RectWithBorder *vp_door_1 = &viewport.door_1[gfx_game_mode];
7959 struct RectWithBorder *vp_door_2 = &viewport.door_2[gfx_game_mode2];
7960 struct RectWithBorder *vp_door_3 = &viewport.door_2[GAME_MODE_EDITOR];
7961 int border_size = vp_playfield->border_size;
7962 int new_sx = vp_playfield->x + border_size;
7963 int new_sy = vp_playfield->y + border_size;
7964 int new_sxsize = vp_playfield->width - 2 * border_size;
7965 int new_sysize = vp_playfield->height - 2 * border_size;
7966 int new_real_sx = vp_playfield->x;
7967 int new_real_sy = vp_playfield->y;
7968 int new_full_sxsize = vp_playfield->width;
7969 int new_full_sysize = vp_playfield->height;
7970 int new_dx = vp_door_1->x;
7971 int new_dy = vp_door_1->y;
7972 int new_dxsize = vp_door_1->width;
7973 int new_dysize = vp_door_1->height;
7974 int new_vx = vp_door_2->x;
7975 int new_vy = vp_door_2->y;
7976 int new_vxsize = vp_door_2->width;
7977 int new_vysize = vp_door_2->height;
7978 int new_ex = vp_door_3->x;
7979 int new_ey = vp_door_3->y;
7980 int new_exsize = vp_door_3->width;
7981 int new_eysize = vp_door_3->height;
7982 int new_tilesize_var =
7983 (setup.small_game_graphics ? MINI_TILESIZE : game.tile_size);
7985 int tilesize = (gfx_game_mode == GAME_MODE_PLAYING ? new_tilesize_var :
7986 gfx_game_mode == GAME_MODE_EDITOR ? MINI_TILESIZE : TILESIZE);
7987 int new_scr_fieldx = new_sxsize / tilesize;
7988 int new_scr_fieldy = new_sysize / tilesize;
7989 int new_scr_fieldx_buffers = new_sxsize / new_tilesize_var;
7990 int new_scr_fieldy_buffers = new_sysize / new_tilesize_var;
7991 boolean init_gfx_buffers = FALSE;
7992 boolean init_video_buffer = FALSE;
7993 boolean init_gadgets_and_toons = FALSE;
7994 boolean init_em_graphics = FALSE;
7995 boolean drawing_area_changed = FALSE;
7997 if (viewport.window.width != WIN_XSIZE ||
7998 viewport.window.height != WIN_YSIZE)
8000 WIN_XSIZE = viewport.window.width;
8001 WIN_YSIZE = viewport.window.height;
8003 init_video_buffer = TRUE;
8004 init_gfx_buffers = TRUE;
8006 // printf("::: video: init_video_buffer, init_gfx_buffers\n");
8009 if (new_scr_fieldx != SCR_FIELDX ||
8010 new_scr_fieldy != SCR_FIELDY)
8012 /* this always toggles between MAIN and GAME when using small tile size */
8014 SCR_FIELDX = new_scr_fieldx;
8015 SCR_FIELDY = new_scr_fieldy;
8017 // printf("::: new_scr_fieldx != SCR_FIELDX ...\n");
8028 new_sxsize != SXSIZE ||
8029 new_sysize != SYSIZE ||
8030 new_dxsize != DXSIZE ||
8031 new_dysize != DYSIZE ||
8032 new_vxsize != VXSIZE ||
8033 new_vysize != VYSIZE ||
8034 new_exsize != EXSIZE ||
8035 new_eysize != EYSIZE ||
8036 new_real_sx != REAL_SX ||
8037 new_real_sy != REAL_SY ||
8038 new_full_sxsize != FULL_SXSIZE ||
8039 new_full_sysize != FULL_SYSIZE ||
8040 new_tilesize_var != TILESIZE_VAR
8043 if (new_tilesize_var != TILESIZE_VAR)
8045 // printf("::: new_tilesize_var != TILESIZE_VAR\n");
8047 // changing tile size invalidates scroll values of engine snapshots
8048 FreeEngineSnapshotSingle();
8050 // changing tile size requires update of graphic mapping for EM engine
8051 init_em_graphics = TRUE;
8056 new_sxsize != SXSIZE ||
8057 new_sysize != SYSIZE ||
8058 new_real_sx != REAL_SX ||
8059 new_real_sy != REAL_SY ||
8060 new_full_sxsize != FULL_SXSIZE ||
8061 new_full_sysize != FULL_SYSIZE)
8063 if (!init_video_buffer)
8064 drawing_area_changed = TRUE;
8075 SXSIZE = new_sxsize;
8076 SYSIZE = new_sysize;
8077 DXSIZE = new_dxsize;
8078 DYSIZE = new_dysize;
8079 VXSIZE = new_vxsize;
8080 VYSIZE = new_vysize;
8081 EXSIZE = new_exsize;
8082 EYSIZE = new_eysize;
8083 REAL_SX = new_real_sx;
8084 REAL_SY = new_real_sy;
8085 FULL_SXSIZE = new_full_sxsize;
8086 FULL_SYSIZE = new_full_sysize;
8087 TILESIZE_VAR = new_tilesize_var;
8089 init_gfx_buffers = TRUE;
8090 init_gadgets_and_toons = TRUE;
8092 // printf("::: viewports: init_gfx_buffers\n");
8093 // printf("::: viewports: init_gadgets_and_toons\n");
8096 if (init_gfx_buffers)
8098 // printf("::: init_gfx_buffers\n");
8100 SCR_FIELDX = new_scr_fieldx_buffers;
8101 SCR_FIELDY = new_scr_fieldy_buffers;
8105 SCR_FIELDX = new_scr_fieldx;
8106 SCR_FIELDY = new_scr_fieldy;
8108 gfx.drawing_area_changed = drawing_area_changed;
8110 SetDrawDeactivationMask(REDRAW_NONE);
8111 SetDrawBackgroundMask(REDRAW_FIELD);
8114 if (init_video_buffer)
8116 // printf("::: init_video_buffer\n");
8118 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
8121 if (init_gadgets_and_toons)
8123 // printf("::: init_gadgets_and_toons\n");
8129 if (init_em_graphics)
8131 InitGraphicInfo_EM();