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 boolean level_solved = (game_status == GAME_MODE_PLAYING &&
3294 local_player->LevelSolved_GameEnd);
3295 int last_game_status = game_status; /* save current game status */
3296 int width = request.width;
3297 int height = request.height;
3301 setRequestPosition(&sx, &sy, FALSE);
3303 button_status = MB_RELEASED;
3305 request_gadget_id = -1;
3312 SetDrawtoField(DRAW_FIELDBUFFER);
3314 HandleGameActions();
3316 SetDrawtoField(DRAW_BACKBUFFER);
3318 if (global.use_envelope_request)
3320 /* copy current state of request area to middle of playfield area */
3321 BlitBitmap(bitmap_db_cross, drawto, sx, sy, width, height, sx, sy);
3329 while (NextValidEvent(&event))
3333 case EVENT_BUTTONPRESS:
3334 case EVENT_BUTTONRELEASE:
3335 case EVENT_MOTIONNOTIFY:
3339 if (event.type == EVENT_MOTIONNOTIFY)
3344 motion_status = TRUE;
3345 mx = ((MotionEvent *) &event)->x;
3346 my = ((MotionEvent *) &event)->y;
3350 motion_status = FALSE;
3351 mx = ((ButtonEvent *) &event)->x;
3352 my = ((ButtonEvent *) &event)->y;
3353 if (event.type == EVENT_BUTTONPRESS)
3354 button_status = ((ButtonEvent *) &event)->button;
3356 button_status = MB_RELEASED;
3359 /* this sets 'request_gadget_id' */
3360 HandleGadgets(mx, my, button_status);
3362 switch (request_gadget_id)
3364 case TOOL_CTRL_ID_YES:
3367 case TOOL_CTRL_ID_NO:
3370 case TOOL_CTRL_ID_CONFIRM:
3371 result = TRUE | FALSE;
3374 case TOOL_CTRL_ID_PLAYER_1:
3377 case TOOL_CTRL_ID_PLAYER_2:
3380 case TOOL_CTRL_ID_PLAYER_3:
3383 case TOOL_CTRL_ID_PLAYER_4:
3394 case EVENT_KEYPRESS:
3395 switch (GetEventKey((KeyEvent *)&event, TRUE))
3398 if (req_state & REQ_CONFIRM)
3403 #if defined(TARGET_SDL2)
3410 #if defined(TARGET_SDL2)
3420 if (req_state & REQ_PLAYER)
3424 case EVENT_KEYRELEASE:
3425 ClearPlayerAction();
3429 HandleOtherEvents(&event);
3434 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3436 int joy = AnyJoystick();
3438 if (joy & JOY_BUTTON_1)
3440 else if (joy & JOY_BUTTON_2)
3446 if (global.use_envelope_request)
3448 /* copy back current state of pressed buttons inside request area */
3449 BlitBitmap(drawto, bitmap_db_cross, sx, sy, width, height, sx, sy);
3456 if (!PendingEvent()) /* delay only if no pending events */
3460 game_status = GAME_MODE_PSEUDO_DOOR;
3464 game_status = last_game_status; /* restore current game status */
3470 static boolean RequestDoor(char *text, unsigned int req_state)
3472 unsigned int old_door_state;
3473 int last_game_status = game_status; /* save current game status */
3474 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
3475 int font_nr = FONT_TEXT_2;
3480 if (maxWordLengthInString(text) > MAX_REQUEST_LINE_FONT1_LEN)
3482 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
3483 font_nr = FONT_TEXT_1;
3486 if (game_status == GAME_MODE_PLAYING)
3487 BlitScreenToBitmap(backbuffer);
3489 /* disable deactivated drawing when quick-loading level tape recording */
3490 if (tape.playing && tape.deactivate_display)
3491 TapeDeactivateDisplayOff(TRUE);
3493 SetMouseCursor(CURSOR_DEFAULT);
3495 #if defined(NETWORK_AVALIABLE)
3496 /* pause network game while waiting for request to answer */
3497 if (options.network &&
3498 game_status == GAME_MODE_PLAYING &&
3499 req_state & REQUEST_WAIT_FOR_INPUT)
3500 SendToServer_PausePlaying();
3503 old_door_state = GetDoorState();
3505 /* simulate releasing mouse button over last gadget, if still pressed */
3507 HandleGadgets(-1, -1, 0);
3511 /* draw released gadget before proceeding */
3514 if (old_door_state & DOOR_OPEN_1)
3516 CloseDoor(DOOR_CLOSE_1);
3518 /* save old door content */
3519 BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
3520 0 * DXSIZE, 0, DXSIZE, DYSIZE, 1 * DXSIZE, 0);
3523 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
3524 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3526 /* clear door drawing field */
3527 DrawBackground(DX, DY, DXSIZE, DYSIZE);
3529 /* force DOOR font inside door area */
3530 game_status = GAME_MODE_PSEUDO_DOOR;
3532 /* write text for request */
3533 for (text_ptr = text, ty = 0; ty < MAX_REQUEST_LINES; ty++)
3535 char text_line[max_request_line_len + 1];
3541 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
3543 tc = *(text_ptr + tx);
3544 // if (!tc || tc == ' ')
3545 if (!tc || tc == ' ' || tc == '?' || tc == '!')
3549 if ((tc == '?' || tc == '!') && tl == 0)
3559 strncpy(text_line, text_ptr, tl);
3562 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
3563 DY + 8 + ty * (getFontHeight(font_nr) + 2),
3564 text_line, font_nr);
3566 text_ptr += tl + (tc == ' ' ? 1 : 0);
3567 // text_ptr += tl + (tc == ' ' || tc == '?' || tc == '!' ? 1 : 0);
3570 game_status = last_game_status; /* restore current game status */
3572 if (req_state & REQ_ASK)
3574 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
3575 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
3577 else if (req_state & REQ_CONFIRM)
3579 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
3581 else if (req_state & REQ_PLAYER)
3583 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
3584 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
3585 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
3586 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
3589 /* copy request gadgets to door backbuffer */
3590 BlitBitmap(drawto, bitmap_db_door_1, DX, DY, DXSIZE, DYSIZE, 0, 0);
3592 OpenDoor(DOOR_OPEN_1);
3594 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
3596 if (game_status == GAME_MODE_PLAYING)
3598 SetPanelBackground();
3599 SetDrawBackgroundMask(REDRAW_DOOR_1);
3603 SetDrawBackgroundMask(REDRAW_FIELD);
3609 if (game_status != GAME_MODE_MAIN)
3612 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3614 // ---------- handle request buttons ----------
3615 result = RequestHandleEvents(req_state);
3617 if (game_status != GAME_MODE_MAIN)
3622 if (!(req_state & REQ_STAY_OPEN))
3624 CloseDoor(DOOR_CLOSE_1);
3626 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
3627 (req_state & REQ_REOPEN))
3628 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
3633 if (game_status == GAME_MODE_PLAYING)
3635 SetPanelBackground();
3636 SetDrawBackgroundMask(REDRAW_DOOR_1);
3640 SetDrawBackgroundMask(REDRAW_FIELD);
3643 #if defined(NETWORK_AVALIABLE)
3644 /* continue network game after request */
3645 if (options.network &&
3646 game_status == GAME_MODE_PLAYING &&
3647 req_state & REQUEST_WAIT_FOR_INPUT)
3648 SendToServer_ContinuePlaying();
3651 /* restore deactivated drawing when quick-loading level tape recording */
3652 if (tape.playing && tape.deactivate_display)
3653 TapeDeactivateDisplayOn();
3658 static boolean RequestEnvelope(char *text, unsigned int req_state)
3662 if (game_status == GAME_MODE_PLAYING)
3663 BlitScreenToBitmap(backbuffer);
3665 /* disable deactivated drawing when quick-loading level tape recording */
3666 if (tape.playing && tape.deactivate_display)
3667 TapeDeactivateDisplayOff(TRUE);
3669 SetMouseCursor(CURSOR_DEFAULT);
3671 #if defined(NETWORK_AVALIABLE)
3672 /* pause network game while waiting for request to answer */
3673 if (options.network &&
3674 game_status == GAME_MODE_PLAYING &&
3675 req_state & REQUEST_WAIT_FOR_INPUT)
3676 SendToServer_PausePlaying();
3679 /* simulate releasing mouse button over last gadget, if still pressed */
3681 HandleGadgets(-1, -1, 0);
3685 // (replace with setting corresponding request background)
3686 // SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
3687 // SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3689 /* clear door drawing field */
3690 // DrawBackground(DX, DY, DXSIZE, DYSIZE);
3692 ShowEnvelopeRequest(text, req_state, ACTION_OPENING);
3694 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
3696 if (game_status == GAME_MODE_PLAYING)
3698 SetPanelBackground();
3699 SetDrawBackgroundMask(REDRAW_DOOR_1);
3703 SetDrawBackgroundMask(REDRAW_FIELD);
3709 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3711 // ---------- handle request buttons ----------
3712 result = RequestHandleEvents(req_state);
3714 if (game_status != GAME_MODE_MAIN)
3719 ShowEnvelopeRequest(text, req_state, ACTION_CLOSING);
3723 if (game_status == GAME_MODE_PLAYING)
3725 SetPanelBackground();
3726 SetDrawBackgroundMask(REDRAW_DOOR_1);
3730 SetDrawBackgroundMask(REDRAW_FIELD);
3733 #if defined(NETWORK_AVALIABLE)
3734 /* continue network game after request */
3735 if (options.network &&
3736 game_status == GAME_MODE_PLAYING &&
3737 req_state & REQUEST_WAIT_FOR_INPUT)
3738 SendToServer_ContinuePlaying();
3741 /* restore deactivated drawing when quick-loading level tape recording */
3742 if (tape.playing && tape.deactivate_display)
3743 TapeDeactivateDisplayOn();
3748 boolean Request(char *text, unsigned int req_state)
3750 if (global.use_envelope_request)
3751 return RequestEnvelope(text, req_state);
3753 return RequestDoor(text, req_state);
3756 static int compareDoorPartOrderInfo(const void *object1, const void *object2)
3758 const struct DoorPartOrderInfo *dpo1 = (struct DoorPartOrderInfo *)object1;
3759 const struct DoorPartOrderInfo *dpo2 = (struct DoorPartOrderInfo *)object2;
3762 if (dpo1->sort_priority != dpo2->sort_priority)
3763 compare_result = dpo1->sort_priority - dpo2->sort_priority;
3765 compare_result = dpo1->nr - dpo2->nr;
3767 return compare_result;
3770 void InitGraphicCompatibilityInfo_Doors()
3776 struct DoorInfo *door;
3780 { DOOR_1, IMG_DOOR_1_GFX_PART_1, IMG_DOOR_1_GFX_PART_8, &door_1 },
3781 { DOOR_2, IMG_DOOR_2_GFX_PART_1, IMG_DOOR_2_GFX_PART_8, &door_2 },
3783 { -1, -1, -1, NULL }
3785 struct Rect door_rect_list[] =
3787 { DX, DY, DXSIZE, DYSIZE },
3788 { VX, VY, VXSIZE, VYSIZE }
3792 for (i = 0; doors[i].door_token != -1; i++)
3794 int door_token = doors[i].door_token;
3795 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
3796 int part_1 = doors[i].part_1;
3797 int part_8 = doors[i].part_8;
3798 int part_2 = part_1 + 1;
3799 int part_3 = part_1 + 2;
3800 struct DoorInfo *door = doors[i].door;
3801 struct Rect *door_rect = &door_rect_list[door_index];
3802 boolean door_gfx_redefined = FALSE;
3804 /* check if any door part graphic definitions have been redefined */
3806 for (j = 0; door_part_controls[j].door_token != -1; j++)
3808 struct DoorPartControlInfo *dpc = &door_part_controls[j];
3809 struct FileInfo *fi = getImageListEntryFromImageID(dpc->graphic);
3811 if (dpc->door_token == door_token && fi->redefined)
3812 door_gfx_redefined = TRUE;
3815 /* check for old-style door graphic/animation modifications */
3817 if (!door_gfx_redefined)
3819 if (door->anim_mode & ANIM_STATIC_PANEL)
3821 door->panel.step_xoffset = 0;
3822 door->panel.step_yoffset = 0;
3825 if (door->anim_mode & (ANIM_HORIZONTAL | ANIM_VERTICAL))
3827 struct GraphicInfo *g_part_1 = &graphic_info[part_1];
3828 struct GraphicInfo *g_part_2 = &graphic_info[part_2];
3829 int num_door_steps, num_panel_steps;
3831 /* remove door part graphics other than the two default wings */
3833 for (j = 0; door_part_controls[j].door_token != -1; j++)
3835 struct DoorPartControlInfo *dpc = &door_part_controls[j];
3836 struct GraphicInfo *g = &graphic_info[dpc->graphic];
3838 if (dpc->graphic >= part_3 &&
3839 dpc->graphic <= part_8)
3843 /* set graphics and screen positions of the default wings */
3845 g_part_1->width = door_rect->width;
3846 g_part_1->height = door_rect->height;
3847 g_part_2->width = door_rect->width;
3848 g_part_2->height = door_rect->height;
3849 g_part_2->src_x = door_rect->width;
3850 g_part_2->src_y = g_part_1->src_y;
3852 door->part_2.x = door->part_1.x;
3853 door->part_2.y = door->part_1.y;
3855 if (door->width != -1)
3857 g_part_1->width = door->width;
3858 g_part_2->width = door->width;
3860 // special treatment for graphics and screen position of right wing
3861 g_part_2->src_x += door_rect->width - door->width;
3862 door->part_2.x += door_rect->width - door->width;
3865 if (door->height != -1)
3867 g_part_1->height = door->height;
3868 g_part_2->height = door->height;
3870 // special treatment for graphics and screen position of bottom wing
3871 g_part_2->src_y += door_rect->height - door->height;
3872 door->part_2.y += door_rect->height - door->height;
3875 /* set animation delays for the default wings and panels */
3877 door->part_1.step_delay = door->step_delay;
3878 door->part_2.step_delay = door->step_delay;
3879 door->panel.step_delay = door->step_delay;
3881 /* set animation draw order for the default wings */
3883 door->part_1.sort_priority = 2; /* draw left wing over ... */
3884 door->part_2.sort_priority = 1; /* ... right wing */
3886 /* set animation draw offset for the default wings */
3888 if (door->anim_mode & ANIM_HORIZONTAL)
3890 door->part_1.step_xoffset = door->step_offset;
3891 door->part_1.step_yoffset = 0;
3892 door->part_2.step_xoffset = door->step_offset * -1;
3893 door->part_2.step_yoffset = 0;
3895 num_door_steps = g_part_1->width / door->step_offset;
3897 else // ANIM_VERTICAL
3899 door->part_1.step_xoffset = 0;
3900 door->part_1.step_yoffset = door->step_offset;
3901 door->part_2.step_xoffset = 0;
3902 door->part_2.step_yoffset = door->step_offset * -1;
3904 num_door_steps = g_part_1->height / door->step_offset;
3907 /* set animation draw offset for the default panels */
3909 if (door->step_offset > 1)
3911 num_panel_steps = 2 * door_rect->height / door->step_offset;
3912 door->panel.start_step = num_panel_steps - num_door_steps;
3913 door->panel.start_step_closing = door->panel.start_step;
3917 num_panel_steps = door_rect->height / door->step_offset;
3918 door->panel.start_step = num_panel_steps - num_door_steps / 2;
3919 door->panel.start_step_closing = door->panel.start_step;
3920 door->panel.step_delay *= 2;
3931 for (i = 0; door_part_controls[i].door_token != -1; i++)
3933 struct DoorPartControlInfo *dpc = &door_part_controls[i];
3934 struct DoorPartOrderInfo *dpo = &door_part_order[i];
3936 /* initialize "start_step_opening" and "start_step_closing", if needed */
3937 if (dpc->pos->start_step_opening == 0 &&
3938 dpc->pos->start_step_closing == 0)
3940 // dpc->pos->start_step_opening = dpc->pos->start_step;
3941 dpc->pos->start_step_closing = dpc->pos->start_step;
3944 /* fill structure for door part draw order (sorted below) */
3946 dpo->sort_priority = dpc->pos->sort_priority;
3949 /* sort door part controls according to sort_priority and graphic number */
3950 qsort(door_part_order, MAX_DOOR_PARTS,
3951 sizeof(struct DoorPartOrderInfo), compareDoorPartOrderInfo);
3954 unsigned int OpenDoor(unsigned int door_state)
3956 if (door_state & DOOR_COPY_BACK)
3958 if (door_state & DOOR_OPEN_1)
3959 BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
3960 1 * DXSIZE, 0, DXSIZE, DYSIZE, 0 * DXSIZE, 0);
3962 if (door_state & DOOR_OPEN_2)
3963 BlitBitmap(bitmap_db_door_2, bitmap_db_door_2,
3964 1 * VXSIZE, 0, VXSIZE, VYSIZE, 0 * VXSIZE, 0);
3966 door_state &= ~DOOR_COPY_BACK;
3969 return MoveDoor(door_state);
3972 unsigned int CloseDoor(unsigned int door_state)
3974 unsigned int old_door_state = GetDoorState();
3976 if (!(door_state & DOOR_NO_COPY_BACK))
3978 if (old_door_state & DOOR_OPEN_1)
3979 BlitBitmap(backbuffer, bitmap_db_door_1,
3980 DX, DY, DXSIZE, DYSIZE, 0, 0);
3982 if (old_door_state & DOOR_OPEN_2)
3983 BlitBitmap(backbuffer, bitmap_db_door_2,
3984 VX, VY, VXSIZE, VYSIZE, 0, 0);
3986 door_state &= ~DOOR_NO_COPY_BACK;
3989 return MoveDoor(door_state);
3992 unsigned int GetDoorState()
3994 return MoveDoor(DOOR_GET_STATE);
3997 unsigned int SetDoorState(unsigned int door_state)
3999 return MoveDoor(door_state | DOOR_SET_STATE);
4002 int euclid(int a, int b)
4004 return (b ? euclid(b, a % b) : a);
4007 unsigned int MoveDoor(unsigned int door_state)
4009 struct Rect door_rect_list[] =
4011 { DX, DY, DXSIZE, DYSIZE },
4012 { VX, VY, VXSIZE, VYSIZE }
4014 static int door1 = DOOR_OPEN_1;
4015 static int door2 = DOOR_CLOSE_2;
4016 unsigned int door_delay = 0;
4017 unsigned int door_delay_value;
4020 if (door_state == DOOR_GET_STATE)
4021 return (door1 | door2);
4023 if (door_state & DOOR_SET_STATE)
4025 if (door_state & DOOR_ACTION_1)
4026 door1 = door_state & DOOR_ACTION_1;
4027 if (door_state & DOOR_ACTION_2)
4028 door2 = door_state & DOOR_ACTION_2;
4030 return (door1 | door2);
4033 if (!(door_state & DOOR_FORCE_REDRAW))
4035 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
4036 door_state &= ~DOOR_OPEN_1;
4037 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
4038 door_state &= ~DOOR_CLOSE_1;
4039 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
4040 door_state &= ~DOOR_OPEN_2;
4041 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
4042 door_state &= ~DOOR_CLOSE_2;
4045 if (global.autoplay_leveldir)
4047 door_state |= DOOR_NO_DELAY;
4048 door_state &= ~DOOR_CLOSE_ALL;
4051 if (game_status == GAME_MODE_EDITOR)
4052 door_state |= DOOR_NO_DELAY;
4054 if (door_state & DOOR_ACTION)
4056 boolean door_panel_drawn[NUM_DOORS];
4057 boolean panel_has_doors[NUM_DOORS];
4058 boolean door_part_skip[MAX_DOOR_PARTS];
4059 boolean door_part_done[MAX_DOOR_PARTS];
4060 boolean door_part_done_all;
4061 int num_steps[MAX_DOOR_PARTS];
4062 int max_move_delay = 0; // delay for complete animations of all doors
4063 int max_step_delay = 0; // delay (ms) between two animation frames
4064 int num_move_steps = 0; // number of animation steps for all doors
4065 int max_move_delay_doors_only = 0; // delay for doors only (no panel)
4066 int num_move_steps_doors_only = 0; // steps for doors only (no panel)
4067 int current_move_delay = 0;
4071 for (i = 0; i < NUM_DOORS; i++)
4072 panel_has_doors[i] = FALSE;
4074 for (i = 0; i < MAX_DOOR_PARTS; i++)
4076 struct DoorPartControlInfo *dpc = &door_part_controls[i];
4077 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4078 int door_token = dpc->door_token;
4080 door_part_done[i] = FALSE;
4081 door_part_skip[i] = (!(door_state & door_token) ||
4085 for (i = 0; i < MAX_DOOR_PARTS; i++)
4087 int nr = door_part_order[i].nr;
4088 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
4089 struct DoorPartPosInfo *pos = dpc->pos;
4090 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4091 int door_token = dpc->door_token;
4092 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
4093 boolean is_panel = DOOR_PART_IS_PANEL(nr);
4094 int step_xoffset = ABS(pos->step_xoffset);
4095 int step_yoffset = ABS(pos->step_yoffset);
4096 int step_delay = pos->step_delay;
4097 int current_door_state = door_state & door_token;
4098 boolean door_opening = ((current_door_state & DOOR_OPEN) != 0);
4099 boolean door_closing = ((current_door_state & DOOR_CLOSE) != 0);
4100 boolean part_opening = (is_panel ? door_closing : door_opening);
4101 int start_step = (part_opening ? pos->start_step_opening :
4102 pos->start_step_closing);
4103 float move_xsize = (step_xoffset ? g->width : 0);
4104 float move_ysize = (step_yoffset ? g->height : 0);
4105 int move_xsteps = (step_xoffset ? ceil(move_xsize / step_xoffset) : 0);
4106 int move_ysteps = (step_yoffset ? ceil(move_ysize / step_yoffset) : 0);
4107 int move_steps = (move_xsteps && move_ysteps ?
4108 MIN(move_xsteps, move_ysteps) :
4109 move_xsteps ? move_xsteps : move_ysteps) - start_step;
4110 int move_delay = move_steps * step_delay;
4112 if (door_part_skip[nr])
4115 max_move_delay = MAX(max_move_delay, move_delay);
4116 max_step_delay = (max_step_delay == 0 ? step_delay :
4117 euclid(max_step_delay, step_delay));
4118 num_steps[nr] = move_steps;
4122 max_move_delay_doors_only = MAX(max_move_delay_doors_only, move_delay);
4124 panel_has_doors[door_index] = TRUE;
4128 max_step_delay = MAX(1, max_step_delay); // prevent division by zero
4130 num_move_steps = max_move_delay / max_step_delay;
4131 num_move_steps_doors_only = max_move_delay_doors_only / max_step_delay;
4133 door_delay_value = max_step_delay;
4135 if ((door_state & DOOR_NO_DELAY) || setup.quick_doors)
4137 start = num_move_steps - 1;
4141 /* opening door sound has priority over simultaneously closing door */
4142 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
4143 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
4144 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
4145 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
4148 for (k = start; k < num_move_steps; k++)
4150 int last_frame = num_move_steps - 1; // last frame of this "for" loop
4152 door_part_done_all = TRUE;
4154 for (i = 0; i < NUM_DOORS; i++)
4155 door_panel_drawn[i] = FALSE;
4157 for (i = 0; i < MAX_DOOR_PARTS; i++)
4159 int nr = door_part_order[i].nr;
4160 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
4161 struct DoorPartPosInfo *pos = dpc->pos;
4162 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4163 int door_token = dpc->door_token;
4164 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
4165 boolean is_panel = DOOR_PART_IS_PANEL(nr);
4166 boolean is_panel_and_door_has_closed = FALSE;
4167 struct Rect *door_rect = &door_rect_list[door_index];
4168 Bitmap *bitmap_db_door = (door_token == DOOR_1 ? bitmap_db_door_1 :
4170 Bitmap *bitmap = (is_panel ? bitmap_db_door : g->bitmap);
4171 int current_door_state = door_state & door_token;
4172 boolean door_opening = ((current_door_state & DOOR_OPEN) != 0);
4173 boolean door_closing = !door_opening;
4174 boolean part_opening = (is_panel ? door_closing : door_opening);
4175 boolean part_closing = !part_opening;
4176 int start_step = (part_opening ? pos->start_step_opening :
4177 pos->start_step_closing);
4178 int step_delay = pos->step_delay;
4179 int step_factor = step_delay / max_step_delay;
4180 int k1 = (step_factor ? k / step_factor + 1 : k);
4181 int k2 = (part_opening ? k1 + start_step : num_steps[nr] - k1);
4182 int kk = MAX(0, k2);
4185 int src_x, src_y, src_xx, src_yy;
4186 int dst_x, dst_y, dst_xx, dst_yy;
4189 if (door_part_skip[nr])
4192 if (!(door_state & door_token))
4200 int k2_door = (door_opening ? k : num_move_steps_doors_only - k - 1);
4201 int kk_door = MAX(0, k2_door);
4202 int sync_frame = kk_door * door_delay_value;
4203 int frame = getGraphicAnimationFrame(dpc->graphic, sync_frame);
4205 getGraphicSource(dpc->graphic, frame, &bitmap, &g_src_x, &g_src_y);
4210 if (!door_panel_drawn[door_index])
4212 ClearRectangle(drawto, door_rect->x, door_rect->y,
4213 door_rect->width, door_rect->height);
4215 door_panel_drawn[door_index] = TRUE;
4218 // draw opening or closing door parts
4220 if (pos->step_xoffset < 0) // door part on right side
4223 dst_xx = pos->x + ABS(kk * pos->step_xoffset);
4226 if (dst_xx + width > door_rect->width)
4227 width = door_rect->width - dst_xx;
4229 else // door part on left side
4232 dst_xx = pos->x - kk * pos->step_xoffset;
4236 src_xx = ABS(dst_xx);
4240 width = g->width - src_xx;
4242 // printf("::: k == %d [%d] \n", k, start_step);
4245 if (pos->step_yoffset < 0) // door part on bottom side
4248 dst_yy = pos->y + ABS(kk * pos->step_yoffset);
4251 if (dst_yy + height > door_rect->height)
4252 height = door_rect->height - dst_yy;
4254 else // door part on top side
4257 dst_yy = pos->y - kk * pos->step_yoffset;
4261 src_yy = ABS(dst_yy);
4265 height = g->height - src_yy;
4268 src_x = g_src_x + src_xx;
4269 src_y = g_src_y + src_yy;
4271 dst_x = door_rect->x + dst_xx;
4272 dst_y = door_rect->y + dst_yy;
4274 is_panel_and_door_has_closed =
4277 panel_has_doors[door_index] &&
4278 k >= num_move_steps_doors_only - 1);
4280 if (width >= 0 && width <= g->width &&
4281 height >= 0 && height <= g->height &&
4282 !is_panel_and_door_has_closed)
4284 if (is_panel || !pos->draw_masked)
4285 BlitBitmap(bitmap, drawto, src_x, src_y, width, height,
4288 BlitBitmapMasked(bitmap, drawto, src_x, src_y, width, height,
4292 redraw_mask |= REDRAW_DOOR_FROM_TOKEN(door_token);
4294 if ((part_opening && (width < 0 || height < 0)) ||
4295 (part_closing && (width >= g->width && height >= g->height)))
4296 door_part_done[nr] = TRUE;
4298 // continue door part animations, but not panel after door has closed
4299 if (!door_part_done[nr] && !is_panel_and_door_has_closed)
4300 door_part_done_all = FALSE;
4303 if (!(door_state & DOOR_NO_DELAY))
4307 if (game_status == GAME_MODE_MAIN)
4310 SkipUntilDelayReached(&door_delay, door_delay_value, &k, last_frame);
4312 current_move_delay += max_step_delay;
4315 if (door_part_done_all)
4320 if (door_state & DOOR_ACTION_1)
4321 door1 = door_state & DOOR_ACTION_1;
4322 if (door_state & DOOR_ACTION_2)
4323 door2 = door_state & DOOR_ACTION_2;
4325 return (door1 | door2);
4328 void DrawSpecialEditorDoor()
4330 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
4331 int top_border_width = gfx1->width;
4332 int top_border_height = gfx1->height;
4333 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
4334 int ex = EX - outer_border;
4335 int ey = EY - outer_border;
4336 int vy = VY - outer_border;
4337 int exsize = EXSIZE + 2 * outer_border;
4339 /* draw bigger level editor toolbox window */
4340 BlitBitmap(gfx1->bitmap, drawto, gfx1->src_x, gfx1->src_y,
4341 top_border_width, top_border_height, ex, ey - top_border_height);
4342 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto, ex, vy,
4343 exsize, EYSIZE - VYSIZE + outer_border, ex, ey);
4345 redraw_mask |= REDRAW_ALL;
4348 void UndrawSpecialEditorDoor()
4350 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
4351 int top_border_width = gfx1->width;
4352 int top_border_height = gfx1->height;
4353 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
4354 int ex = EX - outer_border;
4355 int ey = EY - outer_border;
4356 int ey_top = ey - top_border_height;
4357 int exsize = EXSIZE + 2 * outer_border;
4358 int eysize = EYSIZE + 2 * outer_border;
4360 /* draw normal tape recorder window */
4361 if (graphic_info[IMG_GLOBAL_BORDER].bitmap)
4363 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
4364 ex, ey_top, top_border_width, top_border_height,
4366 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
4367 ex, ey, exsize, eysize, ex, ey);
4371 // if screen background is set to "[NONE]", clear editor toolbox window
4372 ClearRectangle(drawto, ex, ey_top, top_border_width, top_border_height);
4373 ClearRectangle(drawto, ex, ey, exsize, eysize);
4376 redraw_mask |= REDRAW_ALL;
4380 /* ---------- new tool button stuff ---------------------------------------- */
4385 struct TextPosInfo *pos;
4388 } toolbutton_info[NUM_TOOL_BUTTONS] =
4391 IMG_REQUEST_BUTTON_GFX_YES, &request.button.yes,
4392 TOOL_CTRL_ID_YES, "yes"
4395 IMG_REQUEST_BUTTON_GFX_NO, &request.button.no,
4396 TOOL_CTRL_ID_NO, "no"
4399 IMG_REQUEST_BUTTON_GFX_CONFIRM, &request.button.confirm,
4400 TOOL_CTRL_ID_CONFIRM, "confirm"
4403 IMG_REQUEST_BUTTON_GFX_PLAYER_1, &request.button.player_1,
4404 TOOL_CTRL_ID_PLAYER_1, "player 1"
4407 IMG_REQUEST_BUTTON_GFX_PLAYER_2, &request.button.player_2,
4408 TOOL_CTRL_ID_PLAYER_2, "player 2"
4411 IMG_REQUEST_BUTTON_GFX_PLAYER_3, &request.button.player_3,
4412 TOOL_CTRL_ID_PLAYER_3, "player 3"
4415 IMG_REQUEST_BUTTON_GFX_PLAYER_4, &request.button.player_4,
4416 TOOL_CTRL_ID_PLAYER_4, "player 4"
4420 void CreateToolButtons()
4424 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4426 struct GraphicInfo *gfx = &graphic_info[toolbutton_info[i].graphic];
4427 struct TextPosInfo *pos = toolbutton_info[i].pos;
4428 struct GadgetInfo *gi;
4429 Bitmap *deco_bitmap = None;
4430 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
4431 unsigned int event_mask = GD_EVENT_RELEASED;
4434 int gd_x = gfx->src_x;
4435 int gd_y = gfx->src_y;
4436 int gd_xp = gfx->src_x + gfx->pressed_xoffset;
4437 int gd_yp = gfx->src_y + gfx->pressed_yoffset;
4440 if (global.use_envelope_request)
4441 setRequestPosition(&dx, &dy, TRUE);
4443 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
4445 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
4447 getSizedGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr), 0,
4448 pos->size, &deco_bitmap, &deco_x, &deco_y);
4449 deco_xpos = (gfx->width - pos->size) / 2;
4450 deco_ypos = (gfx->height - pos->size) / 2;
4453 gi = CreateGadget(GDI_CUSTOM_ID, id,
4454 GDI_INFO_TEXT, toolbutton_info[i].infotext,
4455 GDI_X, dx + GDI_ACTIVE_POS(pos->x),
4456 GDI_Y, dy + GDI_ACTIVE_POS(pos->y),
4457 GDI_WIDTH, gfx->width,
4458 GDI_HEIGHT, gfx->height,
4459 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
4460 GDI_STATE, GD_BUTTON_UNPRESSED,
4461 GDI_DESIGN_UNPRESSED, gfx->bitmap, gd_x, gd_y,
4462 GDI_DESIGN_PRESSED, gfx->bitmap, gd_xp, gd_yp,
4463 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
4464 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
4465 GDI_DECORATION_SIZE, pos->size, pos->size,
4466 GDI_DECORATION_SHIFTING, 1, 1,
4467 GDI_DIRECT_DRAW, FALSE,
4468 GDI_EVENT_MASK, event_mask,
4469 GDI_CALLBACK_ACTION, HandleToolButtons,
4473 Error(ERR_EXIT, "cannot create gadget");
4475 tool_gadget[id] = gi;
4479 void FreeToolButtons()
4483 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4484 FreeGadget(tool_gadget[i]);
4487 static void UnmapToolButtons()
4491 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4492 UnmapGadget(tool_gadget[i]);
4495 static void HandleToolButtons(struct GadgetInfo *gi)
4497 request_gadget_id = gi->custom_id;
4500 static struct Mapping_EM_to_RND_object
4503 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
4504 boolean is_backside; /* backside of moving element */
4510 em_object_mapping_list[] =
4513 Xblank, TRUE, FALSE,
4517 Yacid_splash_eB, FALSE, FALSE,
4518 EL_ACID_SPLASH_RIGHT, -1, -1
4521 Yacid_splash_wB, FALSE, FALSE,
4522 EL_ACID_SPLASH_LEFT, -1, -1
4525 #ifdef EM_ENGINE_BAD_ROLL
4527 Xstone_force_e, FALSE, FALSE,
4528 EL_ROCK, -1, MV_BIT_RIGHT
4531 Xstone_force_w, FALSE, FALSE,
4532 EL_ROCK, -1, MV_BIT_LEFT
4535 Xnut_force_e, FALSE, FALSE,
4536 EL_NUT, -1, MV_BIT_RIGHT
4539 Xnut_force_w, FALSE, FALSE,
4540 EL_NUT, -1, MV_BIT_LEFT
4543 Xspring_force_e, FALSE, FALSE,
4544 EL_SPRING, -1, MV_BIT_RIGHT
4547 Xspring_force_w, FALSE, FALSE,
4548 EL_SPRING, -1, MV_BIT_LEFT
4551 Xemerald_force_e, FALSE, FALSE,
4552 EL_EMERALD, -1, MV_BIT_RIGHT
4555 Xemerald_force_w, FALSE, FALSE,
4556 EL_EMERALD, -1, MV_BIT_LEFT
4559 Xdiamond_force_e, FALSE, FALSE,
4560 EL_DIAMOND, -1, MV_BIT_RIGHT
4563 Xdiamond_force_w, FALSE, FALSE,
4564 EL_DIAMOND, -1, MV_BIT_LEFT
4567 Xbomb_force_e, FALSE, FALSE,
4568 EL_BOMB, -1, MV_BIT_RIGHT
4571 Xbomb_force_w, FALSE, FALSE,
4572 EL_BOMB, -1, MV_BIT_LEFT
4574 #endif /* EM_ENGINE_BAD_ROLL */
4577 Xstone, TRUE, FALSE,
4581 Xstone_pause, FALSE, FALSE,
4585 Xstone_fall, FALSE, FALSE,
4589 Ystone_s, FALSE, FALSE,
4590 EL_ROCK, ACTION_FALLING, -1
4593 Ystone_sB, FALSE, TRUE,
4594 EL_ROCK, ACTION_FALLING, -1
4597 Ystone_e, FALSE, FALSE,
4598 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
4601 Ystone_eB, FALSE, TRUE,
4602 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
4605 Ystone_w, FALSE, FALSE,
4606 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
4609 Ystone_wB, FALSE, TRUE,
4610 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
4617 Xnut_pause, FALSE, FALSE,
4621 Xnut_fall, FALSE, FALSE,
4625 Ynut_s, FALSE, FALSE,
4626 EL_NUT, ACTION_FALLING, -1
4629 Ynut_sB, FALSE, TRUE,
4630 EL_NUT, ACTION_FALLING, -1
4633 Ynut_e, FALSE, FALSE,
4634 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
4637 Ynut_eB, FALSE, TRUE,
4638 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
4641 Ynut_w, FALSE, FALSE,
4642 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
4645 Ynut_wB, FALSE, TRUE,
4646 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
4649 Xbug_n, TRUE, FALSE,
4653 Xbug_e, TRUE, FALSE,
4654 EL_BUG_RIGHT, -1, -1
4657 Xbug_s, TRUE, FALSE,
4661 Xbug_w, TRUE, FALSE,
4665 Xbug_gon, FALSE, FALSE,
4669 Xbug_goe, FALSE, FALSE,
4670 EL_BUG_RIGHT, -1, -1
4673 Xbug_gos, FALSE, FALSE,
4677 Xbug_gow, FALSE, FALSE,
4681 Ybug_n, FALSE, FALSE,
4682 EL_BUG, ACTION_MOVING, MV_BIT_UP
4685 Ybug_nB, FALSE, TRUE,
4686 EL_BUG, ACTION_MOVING, MV_BIT_UP
4689 Ybug_e, FALSE, FALSE,
4690 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
4693 Ybug_eB, FALSE, TRUE,
4694 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
4697 Ybug_s, FALSE, FALSE,
4698 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
4701 Ybug_sB, FALSE, TRUE,
4702 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
4705 Ybug_w, FALSE, FALSE,
4706 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
4709 Ybug_wB, FALSE, TRUE,
4710 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
4713 Ybug_w_n, FALSE, FALSE,
4714 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
4717 Ybug_n_e, FALSE, FALSE,
4718 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
4721 Ybug_e_s, FALSE, FALSE,
4722 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
4725 Ybug_s_w, FALSE, FALSE,
4726 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
4729 Ybug_e_n, FALSE, FALSE,
4730 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
4733 Ybug_s_e, FALSE, FALSE,
4734 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
4737 Ybug_w_s, FALSE, FALSE,
4738 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
4741 Ybug_n_w, FALSE, FALSE,
4742 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
4745 Ybug_stone, FALSE, FALSE,
4746 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
4749 Ybug_spring, FALSE, FALSE,
4750 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
4753 Xtank_n, TRUE, FALSE,
4754 EL_SPACESHIP_UP, -1, -1
4757 Xtank_e, TRUE, FALSE,
4758 EL_SPACESHIP_RIGHT, -1, -1
4761 Xtank_s, TRUE, FALSE,
4762 EL_SPACESHIP_DOWN, -1, -1
4765 Xtank_w, TRUE, FALSE,
4766 EL_SPACESHIP_LEFT, -1, -1
4769 Xtank_gon, FALSE, FALSE,
4770 EL_SPACESHIP_UP, -1, -1
4773 Xtank_goe, FALSE, FALSE,
4774 EL_SPACESHIP_RIGHT, -1, -1
4777 Xtank_gos, FALSE, FALSE,
4778 EL_SPACESHIP_DOWN, -1, -1
4781 Xtank_gow, FALSE, FALSE,
4782 EL_SPACESHIP_LEFT, -1, -1
4785 Ytank_n, FALSE, FALSE,
4786 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
4789 Ytank_nB, FALSE, TRUE,
4790 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
4793 Ytank_e, FALSE, FALSE,
4794 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
4797 Ytank_eB, FALSE, TRUE,
4798 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
4801 Ytank_s, FALSE, FALSE,
4802 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
4805 Ytank_sB, FALSE, TRUE,
4806 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
4809 Ytank_w, FALSE, FALSE,
4810 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
4813 Ytank_wB, FALSE, TRUE,
4814 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
4817 Ytank_w_n, FALSE, FALSE,
4818 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
4821 Ytank_n_e, FALSE, FALSE,
4822 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
4825 Ytank_e_s, FALSE, FALSE,
4826 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
4829 Ytank_s_w, FALSE, FALSE,
4830 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
4833 Ytank_e_n, FALSE, FALSE,
4834 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
4837 Ytank_s_e, FALSE, FALSE,
4838 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
4841 Ytank_w_s, FALSE, FALSE,
4842 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
4845 Ytank_n_w, FALSE, FALSE,
4846 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
4849 Ytank_stone, FALSE, FALSE,
4850 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
4853 Ytank_spring, FALSE, FALSE,
4854 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
4857 Xandroid, TRUE, FALSE,
4858 EL_EMC_ANDROID, ACTION_ACTIVE, -1
4861 Xandroid_1_n, FALSE, FALSE,
4862 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
4865 Xandroid_2_n, FALSE, FALSE,
4866 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
4869 Xandroid_1_e, FALSE, FALSE,
4870 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
4873 Xandroid_2_e, FALSE, FALSE,
4874 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
4877 Xandroid_1_w, FALSE, FALSE,
4878 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
4881 Xandroid_2_w, FALSE, FALSE,
4882 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
4885 Xandroid_1_s, FALSE, FALSE,
4886 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
4889 Xandroid_2_s, FALSE, FALSE,
4890 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
4893 Yandroid_n, FALSE, FALSE,
4894 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
4897 Yandroid_nB, FALSE, TRUE,
4898 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
4901 Yandroid_ne, FALSE, FALSE,
4902 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
4905 Yandroid_neB, FALSE, TRUE,
4906 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
4909 Yandroid_e, FALSE, FALSE,
4910 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
4913 Yandroid_eB, FALSE, TRUE,
4914 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
4917 Yandroid_se, FALSE, FALSE,
4918 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
4921 Yandroid_seB, FALSE, TRUE,
4922 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
4925 Yandroid_s, FALSE, FALSE,
4926 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
4929 Yandroid_sB, FALSE, TRUE,
4930 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
4933 Yandroid_sw, FALSE, FALSE,
4934 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
4937 Yandroid_swB, FALSE, TRUE,
4938 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
4941 Yandroid_w, FALSE, FALSE,
4942 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
4945 Yandroid_wB, FALSE, TRUE,
4946 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
4949 Yandroid_nw, FALSE, FALSE,
4950 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
4953 Yandroid_nwB, FALSE, TRUE,
4954 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
4957 Xspring, TRUE, FALSE,
4961 Xspring_pause, FALSE, FALSE,
4965 Xspring_e, FALSE, FALSE,
4969 Xspring_w, FALSE, FALSE,
4973 Xspring_fall, FALSE, FALSE,
4977 Yspring_s, FALSE, FALSE,
4978 EL_SPRING, ACTION_FALLING, -1
4981 Yspring_sB, FALSE, TRUE,
4982 EL_SPRING, ACTION_FALLING, -1
4985 Yspring_e, FALSE, FALSE,
4986 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
4989 Yspring_eB, FALSE, TRUE,
4990 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
4993 Yspring_w, FALSE, FALSE,
4994 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
4997 Yspring_wB, FALSE, TRUE,
4998 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
5001 Yspring_kill_e, FALSE, FALSE,
5002 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
5005 Yspring_kill_eB, FALSE, TRUE,
5006 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
5009 Yspring_kill_w, FALSE, FALSE,
5010 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
5013 Yspring_kill_wB, FALSE, TRUE,
5014 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
5017 Xeater_n, TRUE, FALSE,
5018 EL_YAMYAM_UP, -1, -1
5021 Xeater_e, TRUE, FALSE,
5022 EL_YAMYAM_RIGHT, -1, -1
5025 Xeater_w, TRUE, FALSE,
5026 EL_YAMYAM_LEFT, -1, -1
5029 Xeater_s, TRUE, FALSE,
5030 EL_YAMYAM_DOWN, -1, -1
5033 Yeater_n, FALSE, FALSE,
5034 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
5037 Yeater_nB, FALSE, TRUE,
5038 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
5041 Yeater_e, FALSE, FALSE,
5042 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
5045 Yeater_eB, FALSE, TRUE,
5046 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
5049 Yeater_s, FALSE, FALSE,
5050 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
5053 Yeater_sB, FALSE, TRUE,
5054 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
5057 Yeater_w, FALSE, FALSE,
5058 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
5061 Yeater_wB, FALSE, TRUE,
5062 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
5065 Yeater_stone, FALSE, FALSE,
5066 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
5069 Yeater_spring, FALSE, FALSE,
5070 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
5073 Xalien, TRUE, FALSE,
5077 Xalien_pause, FALSE, FALSE,
5081 Yalien_n, FALSE, FALSE,
5082 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
5085 Yalien_nB, FALSE, TRUE,
5086 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
5089 Yalien_e, FALSE, FALSE,
5090 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
5093 Yalien_eB, FALSE, TRUE,
5094 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
5097 Yalien_s, FALSE, FALSE,
5098 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
5101 Yalien_sB, FALSE, TRUE,
5102 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
5105 Yalien_w, FALSE, FALSE,
5106 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
5109 Yalien_wB, FALSE, TRUE,
5110 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
5113 Yalien_stone, FALSE, FALSE,
5114 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
5117 Yalien_spring, FALSE, FALSE,
5118 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
5121 Xemerald, TRUE, FALSE,
5125 Xemerald_pause, FALSE, FALSE,
5129 Xemerald_fall, FALSE, FALSE,
5133 Xemerald_shine, FALSE, FALSE,
5134 EL_EMERALD, ACTION_TWINKLING, -1
5137 Yemerald_s, FALSE, FALSE,
5138 EL_EMERALD, ACTION_FALLING, -1
5141 Yemerald_sB, FALSE, TRUE,
5142 EL_EMERALD, ACTION_FALLING, -1
5145 Yemerald_e, FALSE, FALSE,
5146 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
5149 Yemerald_eB, FALSE, TRUE,
5150 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
5153 Yemerald_w, FALSE, FALSE,
5154 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
5157 Yemerald_wB, FALSE, TRUE,
5158 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
5161 Yemerald_eat, FALSE, FALSE,
5162 EL_EMERALD, ACTION_COLLECTING, -1
5165 Yemerald_stone, FALSE, FALSE,
5166 EL_NUT, ACTION_BREAKING, -1
5169 Xdiamond, TRUE, FALSE,
5173 Xdiamond_pause, FALSE, FALSE,
5177 Xdiamond_fall, FALSE, FALSE,
5181 Xdiamond_shine, FALSE, FALSE,
5182 EL_DIAMOND, ACTION_TWINKLING, -1
5185 Ydiamond_s, FALSE, FALSE,
5186 EL_DIAMOND, ACTION_FALLING, -1
5189 Ydiamond_sB, FALSE, TRUE,
5190 EL_DIAMOND, ACTION_FALLING, -1
5193 Ydiamond_e, FALSE, FALSE,
5194 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
5197 Ydiamond_eB, FALSE, TRUE,
5198 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
5201 Ydiamond_w, FALSE, FALSE,
5202 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
5205 Ydiamond_wB, FALSE, TRUE,
5206 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
5209 Ydiamond_eat, FALSE, FALSE,
5210 EL_DIAMOND, ACTION_COLLECTING, -1
5213 Ydiamond_stone, FALSE, FALSE,
5214 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
5217 Xdrip_fall, TRUE, FALSE,
5218 EL_AMOEBA_DROP, -1, -1
5221 Xdrip_stretch, FALSE, FALSE,
5222 EL_AMOEBA_DROP, ACTION_FALLING, -1
5225 Xdrip_stretchB, FALSE, TRUE,
5226 EL_AMOEBA_DROP, ACTION_FALLING, -1
5229 Xdrip_eat, FALSE, FALSE,
5230 EL_AMOEBA_DROP, ACTION_GROWING, -1
5233 Ydrip_s1, FALSE, FALSE,
5234 EL_AMOEBA_DROP, ACTION_FALLING, -1
5237 Ydrip_s1B, FALSE, TRUE,
5238 EL_AMOEBA_DROP, ACTION_FALLING, -1
5241 Ydrip_s2, FALSE, FALSE,
5242 EL_AMOEBA_DROP, ACTION_FALLING, -1
5245 Ydrip_s2B, FALSE, TRUE,
5246 EL_AMOEBA_DROP, ACTION_FALLING, -1
5253 Xbomb_pause, FALSE, FALSE,
5257 Xbomb_fall, FALSE, FALSE,
5261 Ybomb_s, FALSE, FALSE,
5262 EL_BOMB, ACTION_FALLING, -1
5265 Ybomb_sB, FALSE, TRUE,
5266 EL_BOMB, ACTION_FALLING, -1
5269 Ybomb_e, FALSE, FALSE,
5270 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
5273 Ybomb_eB, FALSE, TRUE,
5274 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
5277 Ybomb_w, FALSE, FALSE,
5278 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
5281 Ybomb_wB, FALSE, TRUE,
5282 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
5285 Ybomb_eat, FALSE, FALSE,
5286 EL_BOMB, ACTION_ACTIVATING, -1
5289 Xballoon, TRUE, FALSE,
5293 Yballoon_n, FALSE, FALSE,
5294 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
5297 Yballoon_nB, FALSE, TRUE,
5298 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
5301 Yballoon_e, FALSE, FALSE,
5302 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
5305 Yballoon_eB, FALSE, TRUE,
5306 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
5309 Yballoon_s, FALSE, FALSE,
5310 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
5313 Yballoon_sB, FALSE, TRUE,
5314 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
5317 Yballoon_w, FALSE, FALSE,
5318 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
5321 Yballoon_wB, FALSE, TRUE,
5322 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
5325 Xgrass, TRUE, FALSE,
5326 EL_EMC_GRASS, -1, -1
5329 Ygrass_nB, FALSE, FALSE,
5330 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
5333 Ygrass_eB, FALSE, FALSE,
5334 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
5337 Ygrass_sB, FALSE, FALSE,
5338 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
5341 Ygrass_wB, FALSE, FALSE,
5342 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
5349 Ydirt_nB, FALSE, FALSE,
5350 EL_SAND, ACTION_DIGGING, MV_BIT_UP
5353 Ydirt_eB, FALSE, FALSE,
5354 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
5357 Ydirt_sB, FALSE, FALSE,
5358 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
5361 Ydirt_wB, FALSE, FALSE,
5362 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
5365 Xacid_ne, TRUE, FALSE,
5366 EL_ACID_POOL_TOPRIGHT, -1, -1
5369 Xacid_se, TRUE, FALSE,
5370 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
5373 Xacid_s, TRUE, FALSE,
5374 EL_ACID_POOL_BOTTOM, -1, -1
5377 Xacid_sw, TRUE, FALSE,
5378 EL_ACID_POOL_BOTTOMLEFT, -1, -1
5381 Xacid_nw, TRUE, FALSE,
5382 EL_ACID_POOL_TOPLEFT, -1, -1
5385 Xacid_1, TRUE, FALSE,
5389 Xacid_2, FALSE, FALSE,
5393 Xacid_3, FALSE, FALSE,
5397 Xacid_4, FALSE, FALSE,
5401 Xacid_5, FALSE, FALSE,
5405 Xacid_6, FALSE, FALSE,
5409 Xacid_7, FALSE, FALSE,
5413 Xacid_8, FALSE, FALSE,
5417 Xball_1, TRUE, FALSE,
5418 EL_EMC_MAGIC_BALL, -1, -1
5421 Xball_1B, FALSE, FALSE,
5422 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5425 Xball_2, FALSE, FALSE,
5426 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5429 Xball_2B, FALSE, FALSE,
5430 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5433 Yball_eat, FALSE, FALSE,
5434 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
5437 Ykey_1_eat, FALSE, FALSE,
5438 EL_EM_KEY_1, ACTION_COLLECTING, -1
5441 Ykey_2_eat, FALSE, FALSE,
5442 EL_EM_KEY_2, ACTION_COLLECTING, -1
5445 Ykey_3_eat, FALSE, FALSE,
5446 EL_EM_KEY_3, ACTION_COLLECTING, -1
5449 Ykey_4_eat, FALSE, FALSE,
5450 EL_EM_KEY_4, ACTION_COLLECTING, -1
5453 Ykey_5_eat, FALSE, FALSE,
5454 EL_EMC_KEY_5, ACTION_COLLECTING, -1
5457 Ykey_6_eat, FALSE, FALSE,
5458 EL_EMC_KEY_6, ACTION_COLLECTING, -1
5461 Ykey_7_eat, FALSE, FALSE,
5462 EL_EMC_KEY_7, ACTION_COLLECTING, -1
5465 Ykey_8_eat, FALSE, FALSE,
5466 EL_EMC_KEY_8, ACTION_COLLECTING, -1
5469 Ylenses_eat, FALSE, FALSE,
5470 EL_EMC_LENSES, ACTION_COLLECTING, -1
5473 Ymagnify_eat, FALSE, FALSE,
5474 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
5477 Ygrass_eat, FALSE, FALSE,
5478 EL_EMC_GRASS, ACTION_SNAPPING, -1
5481 Ydirt_eat, FALSE, FALSE,
5482 EL_SAND, ACTION_SNAPPING, -1
5485 Xgrow_ns, TRUE, FALSE,
5486 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
5489 Ygrow_ns_eat, FALSE, FALSE,
5490 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
5493 Xgrow_ew, TRUE, FALSE,
5494 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
5497 Ygrow_ew_eat, FALSE, FALSE,
5498 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
5501 Xwonderwall, TRUE, FALSE,
5502 EL_MAGIC_WALL, -1, -1
5505 XwonderwallB, FALSE, FALSE,
5506 EL_MAGIC_WALL, ACTION_ACTIVE, -1
5509 Xamoeba_1, TRUE, FALSE,
5510 EL_AMOEBA_DRY, ACTION_OTHER, -1
5513 Xamoeba_2, FALSE, FALSE,
5514 EL_AMOEBA_DRY, ACTION_OTHER, -1
5517 Xamoeba_3, FALSE, FALSE,
5518 EL_AMOEBA_DRY, ACTION_OTHER, -1
5521 Xamoeba_4, FALSE, FALSE,
5522 EL_AMOEBA_DRY, ACTION_OTHER, -1
5525 Xamoeba_5, TRUE, FALSE,
5526 EL_AMOEBA_WET, ACTION_OTHER, -1
5529 Xamoeba_6, FALSE, FALSE,
5530 EL_AMOEBA_WET, ACTION_OTHER, -1
5533 Xamoeba_7, FALSE, FALSE,
5534 EL_AMOEBA_WET, ACTION_OTHER, -1
5537 Xamoeba_8, FALSE, FALSE,
5538 EL_AMOEBA_WET, ACTION_OTHER, -1
5541 Xdoor_1, TRUE, FALSE,
5542 EL_EM_GATE_1, -1, -1
5545 Xdoor_2, TRUE, FALSE,
5546 EL_EM_GATE_2, -1, -1
5549 Xdoor_3, TRUE, FALSE,
5550 EL_EM_GATE_3, -1, -1
5553 Xdoor_4, TRUE, FALSE,
5554 EL_EM_GATE_4, -1, -1
5557 Xdoor_5, TRUE, FALSE,
5558 EL_EMC_GATE_5, -1, -1
5561 Xdoor_6, TRUE, FALSE,
5562 EL_EMC_GATE_6, -1, -1
5565 Xdoor_7, TRUE, FALSE,
5566 EL_EMC_GATE_7, -1, -1
5569 Xdoor_8, TRUE, FALSE,
5570 EL_EMC_GATE_8, -1, -1
5573 Xkey_1, TRUE, FALSE,
5577 Xkey_2, TRUE, FALSE,
5581 Xkey_3, TRUE, FALSE,
5585 Xkey_4, TRUE, FALSE,
5589 Xkey_5, TRUE, FALSE,
5590 EL_EMC_KEY_5, -1, -1
5593 Xkey_6, TRUE, FALSE,
5594 EL_EMC_KEY_6, -1, -1
5597 Xkey_7, TRUE, FALSE,
5598 EL_EMC_KEY_7, -1, -1
5601 Xkey_8, TRUE, FALSE,
5602 EL_EMC_KEY_8, -1, -1
5605 Xwind_n, TRUE, FALSE,
5606 EL_BALLOON_SWITCH_UP, -1, -1
5609 Xwind_e, TRUE, FALSE,
5610 EL_BALLOON_SWITCH_RIGHT, -1, -1
5613 Xwind_s, TRUE, FALSE,
5614 EL_BALLOON_SWITCH_DOWN, -1, -1
5617 Xwind_w, TRUE, FALSE,
5618 EL_BALLOON_SWITCH_LEFT, -1, -1
5621 Xwind_nesw, TRUE, FALSE,
5622 EL_BALLOON_SWITCH_ANY, -1, -1
5625 Xwind_stop, TRUE, FALSE,
5626 EL_BALLOON_SWITCH_NONE, -1, -1
5630 EL_EM_EXIT_CLOSED, -1, -1
5633 Xexit_1, TRUE, FALSE,
5634 EL_EM_EXIT_OPEN, -1, -1
5637 Xexit_2, FALSE, FALSE,
5638 EL_EM_EXIT_OPEN, -1, -1
5641 Xexit_3, FALSE, FALSE,
5642 EL_EM_EXIT_OPEN, -1, -1
5645 Xdynamite, TRUE, FALSE,
5646 EL_EM_DYNAMITE, -1, -1
5649 Ydynamite_eat, FALSE, FALSE,
5650 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
5653 Xdynamite_1, TRUE, FALSE,
5654 EL_EM_DYNAMITE_ACTIVE, -1, -1
5657 Xdynamite_2, FALSE, FALSE,
5658 EL_EM_DYNAMITE_ACTIVE, -1, -1
5661 Xdynamite_3, FALSE, FALSE,
5662 EL_EM_DYNAMITE_ACTIVE, -1, -1
5665 Xdynamite_4, FALSE, FALSE,
5666 EL_EM_DYNAMITE_ACTIVE, -1, -1
5669 Xbumper, TRUE, FALSE,
5670 EL_EMC_SPRING_BUMPER, -1, -1
5673 XbumperB, FALSE, FALSE,
5674 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
5677 Xwheel, TRUE, FALSE,
5678 EL_ROBOT_WHEEL, -1, -1
5681 XwheelB, FALSE, FALSE,
5682 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
5685 Xswitch, TRUE, FALSE,
5686 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
5689 XswitchB, FALSE, FALSE,
5690 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
5694 EL_QUICKSAND_EMPTY, -1, -1
5697 Xsand_stone, TRUE, FALSE,
5698 EL_QUICKSAND_FULL, -1, -1
5701 Xsand_stonein_1, FALSE, TRUE,
5702 EL_ROCK, ACTION_FILLING, -1
5705 Xsand_stonein_2, FALSE, TRUE,
5706 EL_ROCK, ACTION_FILLING, -1
5709 Xsand_stonein_3, FALSE, TRUE,
5710 EL_ROCK, ACTION_FILLING, -1
5713 Xsand_stonein_4, FALSE, TRUE,
5714 EL_ROCK, ACTION_FILLING, -1
5717 Xsand_stonesand_1, FALSE, FALSE,
5718 EL_QUICKSAND_EMPTYING, -1, -1
5721 Xsand_stonesand_2, FALSE, FALSE,
5722 EL_QUICKSAND_EMPTYING, -1, -1
5725 Xsand_stonesand_3, FALSE, FALSE,
5726 EL_QUICKSAND_EMPTYING, -1, -1
5729 Xsand_stonesand_4, FALSE, FALSE,
5730 EL_QUICKSAND_EMPTYING, -1, -1
5733 Xsand_stonesand_quickout_1, FALSE, FALSE,
5734 EL_QUICKSAND_EMPTYING, -1, -1
5737 Xsand_stonesand_quickout_2, FALSE, FALSE,
5738 EL_QUICKSAND_EMPTYING, -1, -1
5741 Xsand_stoneout_1, FALSE, FALSE,
5742 EL_ROCK, ACTION_EMPTYING, -1
5745 Xsand_stoneout_2, FALSE, FALSE,
5746 EL_ROCK, ACTION_EMPTYING, -1
5749 Xsand_sandstone_1, FALSE, FALSE,
5750 EL_QUICKSAND_FILLING, -1, -1
5753 Xsand_sandstone_2, FALSE, FALSE,
5754 EL_QUICKSAND_FILLING, -1, -1
5757 Xsand_sandstone_3, FALSE, FALSE,
5758 EL_QUICKSAND_FILLING, -1, -1
5761 Xsand_sandstone_4, FALSE, FALSE,
5762 EL_QUICKSAND_FILLING, -1, -1
5765 Xplant, TRUE, FALSE,
5766 EL_EMC_PLANT, -1, -1
5769 Yplant, FALSE, FALSE,
5770 EL_EMC_PLANT, -1, -1
5773 Xlenses, TRUE, FALSE,
5774 EL_EMC_LENSES, -1, -1
5777 Xmagnify, TRUE, FALSE,
5778 EL_EMC_MAGNIFIER, -1, -1
5781 Xdripper, TRUE, FALSE,
5782 EL_EMC_DRIPPER, -1, -1
5785 XdripperB, FALSE, FALSE,
5786 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
5789 Xfake_blank, TRUE, FALSE,
5790 EL_INVISIBLE_WALL, -1, -1
5793 Xfake_blankB, FALSE, FALSE,
5794 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
5797 Xfake_grass, TRUE, FALSE,
5798 EL_EMC_FAKE_GRASS, -1, -1
5801 Xfake_grassB, FALSE, FALSE,
5802 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
5805 Xfake_door_1, TRUE, FALSE,
5806 EL_EM_GATE_1_GRAY, -1, -1
5809 Xfake_door_2, TRUE, FALSE,
5810 EL_EM_GATE_2_GRAY, -1, -1
5813 Xfake_door_3, TRUE, FALSE,
5814 EL_EM_GATE_3_GRAY, -1, -1
5817 Xfake_door_4, TRUE, FALSE,
5818 EL_EM_GATE_4_GRAY, -1, -1
5821 Xfake_door_5, TRUE, FALSE,
5822 EL_EMC_GATE_5_GRAY, -1, -1
5825 Xfake_door_6, TRUE, FALSE,
5826 EL_EMC_GATE_6_GRAY, -1, -1
5829 Xfake_door_7, TRUE, FALSE,
5830 EL_EMC_GATE_7_GRAY, -1, -1
5833 Xfake_door_8, TRUE, FALSE,
5834 EL_EMC_GATE_8_GRAY, -1, -1
5837 Xfake_acid_1, TRUE, FALSE,
5838 EL_EMC_FAKE_ACID, -1, -1
5841 Xfake_acid_2, FALSE, FALSE,
5842 EL_EMC_FAKE_ACID, -1, -1
5845 Xfake_acid_3, FALSE, FALSE,
5846 EL_EMC_FAKE_ACID, -1, -1
5849 Xfake_acid_4, FALSE, FALSE,
5850 EL_EMC_FAKE_ACID, -1, -1
5853 Xfake_acid_5, FALSE, FALSE,
5854 EL_EMC_FAKE_ACID, -1, -1
5857 Xfake_acid_6, FALSE, FALSE,
5858 EL_EMC_FAKE_ACID, -1, -1
5861 Xfake_acid_7, FALSE, FALSE,
5862 EL_EMC_FAKE_ACID, -1, -1
5865 Xfake_acid_8, FALSE, FALSE,
5866 EL_EMC_FAKE_ACID, -1, -1
5869 Xsteel_1, TRUE, FALSE,
5870 EL_STEELWALL, -1, -1
5873 Xsteel_2, TRUE, FALSE,
5874 EL_EMC_STEELWALL_2, -1, -1
5877 Xsteel_3, TRUE, FALSE,
5878 EL_EMC_STEELWALL_3, -1, -1
5881 Xsteel_4, TRUE, FALSE,
5882 EL_EMC_STEELWALL_4, -1, -1
5885 Xwall_1, TRUE, FALSE,
5889 Xwall_2, TRUE, FALSE,
5890 EL_EMC_WALL_14, -1, -1
5893 Xwall_3, TRUE, FALSE,
5894 EL_EMC_WALL_15, -1, -1
5897 Xwall_4, TRUE, FALSE,
5898 EL_EMC_WALL_16, -1, -1
5901 Xround_wall_1, TRUE, FALSE,
5902 EL_WALL_SLIPPERY, -1, -1
5905 Xround_wall_2, TRUE, FALSE,
5906 EL_EMC_WALL_SLIPPERY_2, -1, -1
5909 Xround_wall_3, TRUE, FALSE,
5910 EL_EMC_WALL_SLIPPERY_3, -1, -1
5913 Xround_wall_4, TRUE, FALSE,
5914 EL_EMC_WALL_SLIPPERY_4, -1, -1
5917 Xdecor_1, TRUE, FALSE,
5918 EL_EMC_WALL_8, -1, -1
5921 Xdecor_2, TRUE, FALSE,
5922 EL_EMC_WALL_6, -1, -1
5925 Xdecor_3, TRUE, FALSE,
5926 EL_EMC_WALL_4, -1, -1
5929 Xdecor_4, TRUE, FALSE,
5930 EL_EMC_WALL_7, -1, -1
5933 Xdecor_5, TRUE, FALSE,
5934 EL_EMC_WALL_5, -1, -1
5937 Xdecor_6, TRUE, FALSE,
5938 EL_EMC_WALL_9, -1, -1
5941 Xdecor_7, TRUE, FALSE,
5942 EL_EMC_WALL_10, -1, -1
5945 Xdecor_8, TRUE, FALSE,
5946 EL_EMC_WALL_1, -1, -1
5949 Xdecor_9, TRUE, FALSE,
5950 EL_EMC_WALL_2, -1, -1
5953 Xdecor_10, TRUE, FALSE,
5954 EL_EMC_WALL_3, -1, -1
5957 Xdecor_11, TRUE, FALSE,
5958 EL_EMC_WALL_11, -1, -1
5961 Xdecor_12, TRUE, FALSE,
5962 EL_EMC_WALL_12, -1, -1
5965 Xalpha_0, TRUE, FALSE,
5966 EL_CHAR('0'), -1, -1
5969 Xalpha_1, TRUE, FALSE,
5970 EL_CHAR('1'), -1, -1
5973 Xalpha_2, TRUE, FALSE,
5974 EL_CHAR('2'), -1, -1
5977 Xalpha_3, TRUE, FALSE,
5978 EL_CHAR('3'), -1, -1
5981 Xalpha_4, TRUE, FALSE,
5982 EL_CHAR('4'), -1, -1
5985 Xalpha_5, TRUE, FALSE,
5986 EL_CHAR('5'), -1, -1
5989 Xalpha_6, TRUE, FALSE,
5990 EL_CHAR('6'), -1, -1
5993 Xalpha_7, TRUE, FALSE,
5994 EL_CHAR('7'), -1, -1
5997 Xalpha_8, TRUE, FALSE,
5998 EL_CHAR('8'), -1, -1
6001 Xalpha_9, TRUE, FALSE,
6002 EL_CHAR('9'), -1, -1
6005 Xalpha_excla, TRUE, FALSE,
6006 EL_CHAR('!'), -1, -1
6009 Xalpha_quote, TRUE, FALSE,
6010 EL_CHAR('"'), -1, -1
6013 Xalpha_comma, TRUE, FALSE,
6014 EL_CHAR(','), -1, -1
6017 Xalpha_minus, TRUE, FALSE,
6018 EL_CHAR('-'), -1, -1
6021 Xalpha_perio, TRUE, FALSE,
6022 EL_CHAR('.'), -1, -1
6025 Xalpha_colon, TRUE, FALSE,
6026 EL_CHAR(':'), -1, -1
6029 Xalpha_quest, TRUE, FALSE,
6030 EL_CHAR('?'), -1, -1
6033 Xalpha_a, TRUE, FALSE,
6034 EL_CHAR('A'), -1, -1
6037 Xalpha_b, TRUE, FALSE,
6038 EL_CHAR('B'), -1, -1
6041 Xalpha_c, TRUE, FALSE,
6042 EL_CHAR('C'), -1, -1
6045 Xalpha_d, TRUE, FALSE,
6046 EL_CHAR('D'), -1, -1
6049 Xalpha_e, TRUE, FALSE,
6050 EL_CHAR('E'), -1, -1
6053 Xalpha_f, TRUE, FALSE,
6054 EL_CHAR('F'), -1, -1
6057 Xalpha_g, TRUE, FALSE,
6058 EL_CHAR('G'), -1, -1
6061 Xalpha_h, TRUE, FALSE,
6062 EL_CHAR('H'), -1, -1
6065 Xalpha_i, TRUE, FALSE,
6066 EL_CHAR('I'), -1, -1
6069 Xalpha_j, TRUE, FALSE,
6070 EL_CHAR('J'), -1, -1
6073 Xalpha_k, TRUE, FALSE,
6074 EL_CHAR('K'), -1, -1
6077 Xalpha_l, TRUE, FALSE,
6078 EL_CHAR('L'), -1, -1
6081 Xalpha_m, TRUE, FALSE,
6082 EL_CHAR('M'), -1, -1
6085 Xalpha_n, TRUE, FALSE,
6086 EL_CHAR('N'), -1, -1
6089 Xalpha_o, TRUE, FALSE,
6090 EL_CHAR('O'), -1, -1
6093 Xalpha_p, TRUE, FALSE,
6094 EL_CHAR('P'), -1, -1
6097 Xalpha_q, TRUE, FALSE,
6098 EL_CHAR('Q'), -1, -1
6101 Xalpha_r, TRUE, FALSE,
6102 EL_CHAR('R'), -1, -1
6105 Xalpha_s, TRUE, FALSE,
6106 EL_CHAR('S'), -1, -1
6109 Xalpha_t, TRUE, FALSE,
6110 EL_CHAR('T'), -1, -1
6113 Xalpha_u, TRUE, FALSE,
6114 EL_CHAR('U'), -1, -1
6117 Xalpha_v, TRUE, FALSE,
6118 EL_CHAR('V'), -1, -1
6121 Xalpha_w, TRUE, FALSE,
6122 EL_CHAR('W'), -1, -1
6125 Xalpha_x, TRUE, FALSE,
6126 EL_CHAR('X'), -1, -1
6129 Xalpha_y, TRUE, FALSE,
6130 EL_CHAR('Y'), -1, -1
6133 Xalpha_z, TRUE, FALSE,
6134 EL_CHAR('Z'), -1, -1
6137 Xalpha_arrow_e, TRUE, FALSE,
6138 EL_CHAR('>'), -1, -1
6141 Xalpha_arrow_w, TRUE, FALSE,
6142 EL_CHAR('<'), -1, -1
6145 Xalpha_copyr, TRUE, FALSE,
6146 EL_CHAR(CHAR_BYTE_COPYRIGHT), -1, -1
6150 Xboom_bug, FALSE, FALSE,
6151 EL_BUG, ACTION_EXPLODING, -1
6154 Xboom_bomb, FALSE, FALSE,
6155 EL_BOMB, ACTION_EXPLODING, -1
6158 Xboom_android, FALSE, FALSE,
6159 EL_EMC_ANDROID, ACTION_OTHER, -1
6162 Xboom_1, FALSE, FALSE,
6163 EL_DEFAULT, ACTION_EXPLODING, -1
6166 Xboom_2, FALSE, FALSE,
6167 EL_DEFAULT, ACTION_EXPLODING, -1
6170 Znormal, FALSE, FALSE,
6174 Zdynamite, FALSE, FALSE,
6178 Zplayer, FALSE, FALSE,
6182 ZBORDER, FALSE, FALSE,
6192 static struct Mapping_EM_to_RND_player
6201 em_player_mapping_list[] =
6205 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
6209 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
6213 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
6217 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
6221 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
6225 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
6229 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
6233 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
6237 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
6241 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
6245 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
6249 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
6253 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
6257 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
6261 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
6265 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
6269 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
6273 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
6277 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
6281 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
6285 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
6289 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
6293 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
6297 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
6301 EL_PLAYER_1, ACTION_DEFAULT, -1,
6305 EL_PLAYER_2, ACTION_DEFAULT, -1,
6309 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
6313 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
6317 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
6321 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
6325 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
6329 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
6333 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
6337 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
6341 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
6345 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
6349 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
6353 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
6357 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
6361 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
6365 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
6369 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
6373 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
6377 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
6381 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
6385 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
6389 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
6393 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
6397 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
6401 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
6405 EL_PLAYER_3, ACTION_DEFAULT, -1,
6409 EL_PLAYER_4, ACTION_DEFAULT, -1,
6418 int map_element_RND_to_EM(int element_rnd)
6420 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
6421 static boolean mapping_initialized = FALSE;
6423 if (!mapping_initialized)
6427 /* return "Xalpha_quest" for all undefined elements in mapping array */
6428 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
6429 mapping_RND_to_EM[i] = Xalpha_quest;
6431 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6432 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
6433 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
6434 em_object_mapping_list[i].element_em;
6436 mapping_initialized = TRUE;
6439 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
6440 return mapping_RND_to_EM[element_rnd];
6442 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
6447 int map_element_EM_to_RND(int element_em)
6449 static unsigned short mapping_EM_to_RND[TILE_MAX];
6450 static boolean mapping_initialized = FALSE;
6452 if (!mapping_initialized)
6456 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
6457 for (i = 0; i < TILE_MAX; i++)
6458 mapping_EM_to_RND[i] = EL_UNKNOWN;
6460 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6461 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
6462 em_object_mapping_list[i].element_rnd;
6464 mapping_initialized = TRUE;
6467 if (element_em >= 0 && element_em < TILE_MAX)
6468 return mapping_EM_to_RND[element_em];
6470 Error(ERR_WARN, "invalid EM level element %d", element_em);
6475 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
6477 struct LevelInfo_EM *level_em = level->native_em_level;
6478 struct LEVEL *lev = level_em->lev;
6481 for (i = 0; i < TILE_MAX; i++)
6482 lev->android_array[i] = Xblank;
6484 for (i = 0; i < level->num_android_clone_elements; i++)
6486 int element_rnd = level->android_clone_element[i];
6487 int element_em = map_element_RND_to_EM(element_rnd);
6489 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
6490 if (em_object_mapping_list[j].element_rnd == element_rnd)
6491 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
6495 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
6497 struct LevelInfo_EM *level_em = level->native_em_level;
6498 struct LEVEL *lev = level_em->lev;
6501 level->num_android_clone_elements = 0;
6503 for (i = 0; i < TILE_MAX; i++)
6505 int element_em = lev->android_array[i];
6507 boolean element_found = FALSE;
6509 if (element_em == Xblank)
6512 element_rnd = map_element_EM_to_RND(element_em);
6514 for (j = 0; j < level->num_android_clone_elements; j++)
6515 if (level->android_clone_element[j] == element_rnd)
6516 element_found = TRUE;
6520 level->android_clone_element[level->num_android_clone_elements++] =
6523 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
6528 if (level->num_android_clone_elements == 0)
6530 level->num_android_clone_elements = 1;
6531 level->android_clone_element[0] = EL_EMPTY;
6535 int map_direction_RND_to_EM(int direction)
6537 return (direction == MV_UP ? 0 :
6538 direction == MV_RIGHT ? 1 :
6539 direction == MV_DOWN ? 2 :
6540 direction == MV_LEFT ? 3 :
6544 int map_direction_EM_to_RND(int direction)
6546 return (direction == 0 ? MV_UP :
6547 direction == 1 ? MV_RIGHT :
6548 direction == 2 ? MV_DOWN :
6549 direction == 3 ? MV_LEFT :
6553 int map_element_RND_to_SP(int element_rnd)
6555 int element_sp = 0x20; /* map unknown elements to yellow "hardware" */
6557 if (element_rnd >= EL_SP_START &&
6558 element_rnd <= EL_SP_END)
6559 element_sp = element_rnd - EL_SP_START;
6560 else if (element_rnd == EL_EMPTY_SPACE)
6562 else if (element_rnd == EL_INVISIBLE_WALL)
6568 int map_element_SP_to_RND(int element_sp)
6570 int element_rnd = EL_UNKNOWN;
6572 if (element_sp >= 0x00 &&
6574 element_rnd = EL_SP_START + element_sp;
6575 else if (element_sp == 0x28)
6576 element_rnd = EL_INVISIBLE_WALL;
6581 int map_action_SP_to_RND(int action_sp)
6585 case actActive: return ACTION_ACTIVE;
6586 case actImpact: return ACTION_IMPACT;
6587 case actExploding: return ACTION_EXPLODING;
6588 case actDigging: return ACTION_DIGGING;
6589 case actSnapping: return ACTION_SNAPPING;
6590 case actCollecting: return ACTION_COLLECTING;
6591 case actPassing: return ACTION_PASSING;
6592 case actPushing: return ACTION_PUSHING;
6593 case actDropping: return ACTION_DROPPING;
6595 default: return ACTION_DEFAULT;
6599 int get_next_element(int element)
6603 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
6604 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
6605 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
6606 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
6607 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
6608 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
6609 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
6610 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
6611 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
6612 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
6613 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
6615 default: return element;
6619 int el_act_dir2img(int element, int action, int direction)
6621 element = GFX_ELEMENT(element);
6622 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
6624 /* direction_graphic[][] == graphic[] for undefined direction graphics */
6625 return element_info[element].direction_graphic[action][direction];
6628 static int el_act_dir2crm(int element, int action, int direction)
6630 element = GFX_ELEMENT(element);
6631 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
6633 /* direction_graphic[][] == graphic[] for undefined direction graphics */
6634 return element_info[element].direction_crumbled[action][direction];
6637 int el_act2img(int element, int action)
6639 element = GFX_ELEMENT(element);
6641 return element_info[element].graphic[action];
6644 int el_act2crm(int element, int action)
6646 element = GFX_ELEMENT(element);
6648 return element_info[element].crumbled[action];
6651 int el_dir2img(int element, int direction)
6653 element = GFX_ELEMENT(element);
6655 return el_act_dir2img(element, ACTION_DEFAULT, direction);
6658 int el2baseimg(int element)
6660 return element_info[element].graphic[ACTION_DEFAULT];
6663 int el2img(int element)
6665 element = GFX_ELEMENT(element);
6667 return element_info[element].graphic[ACTION_DEFAULT];
6670 int el2edimg(int element)
6672 element = GFX_ELEMENT(element);
6674 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
6677 int el2preimg(int element)
6679 element = GFX_ELEMENT(element);
6681 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
6684 int el2panelimg(int element)
6686 element = GFX_ELEMENT(element);
6688 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL];
6691 int font2baseimg(int font_nr)
6693 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
6696 int getBeltNrFromBeltElement(int element)
6698 return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
6699 element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
6700 element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
6703 int getBeltNrFromBeltActiveElement(int element)
6705 return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
6706 element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
6707 element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
6710 int getBeltNrFromBeltSwitchElement(int element)
6712 return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
6713 element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
6714 element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
6717 int getBeltDirNrFromBeltElement(int element)
6719 static int belt_base_element[4] =
6721 EL_CONVEYOR_BELT_1_LEFT,
6722 EL_CONVEYOR_BELT_2_LEFT,
6723 EL_CONVEYOR_BELT_3_LEFT,
6724 EL_CONVEYOR_BELT_4_LEFT
6727 int belt_nr = getBeltNrFromBeltElement(element);
6728 int belt_dir_nr = element - belt_base_element[belt_nr];
6730 return (belt_dir_nr % 3);
6733 int getBeltDirNrFromBeltSwitchElement(int element)
6735 static int belt_base_element[4] =
6737 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
6738 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
6739 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
6740 EL_CONVEYOR_BELT_4_SWITCH_LEFT
6743 int belt_nr = getBeltNrFromBeltSwitchElement(element);
6744 int belt_dir_nr = element - belt_base_element[belt_nr];
6746 return (belt_dir_nr % 3);
6749 int getBeltDirFromBeltElement(int element)
6751 static int belt_move_dir[3] =
6758 int belt_dir_nr = getBeltDirNrFromBeltElement(element);
6760 return belt_move_dir[belt_dir_nr];
6763 int getBeltDirFromBeltSwitchElement(int element)
6765 static int belt_move_dir[3] =
6772 int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
6774 return belt_move_dir[belt_dir_nr];
6777 int getBeltElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
6779 static int belt_base_element[4] =
6781 EL_CONVEYOR_BELT_1_LEFT,
6782 EL_CONVEYOR_BELT_2_LEFT,
6783 EL_CONVEYOR_BELT_3_LEFT,
6784 EL_CONVEYOR_BELT_4_LEFT
6787 return belt_base_element[belt_nr] + belt_dir_nr;
6790 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
6792 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
6794 return getBeltElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
6797 int getBeltSwitchElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
6799 static int belt_base_element[4] =
6801 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
6802 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
6803 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
6804 EL_CONVEYOR_BELT_4_SWITCH_LEFT
6807 return belt_base_element[belt_nr] + belt_dir_nr;
6810 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
6812 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
6814 return getBeltSwitchElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
6817 boolean getTeamMode_EM()
6819 return game.team_mode;
6822 int getGameFrameDelay_EM(int native_em_game_frame_delay)
6824 int game_frame_delay_value;
6826 game_frame_delay_value =
6827 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
6828 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
6831 if (tape.playing && tape.warp_forward && !tape.pausing)
6832 game_frame_delay_value = 0;
6834 return game_frame_delay_value;
6837 unsigned int InitRND(int seed)
6839 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
6840 return InitEngineRandom_EM(seed);
6841 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
6842 return InitEngineRandom_SP(seed);
6844 return InitEngineRandom_RND(seed);
6847 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
6848 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
6850 inline static int get_effective_element_EM(int tile, int frame_em)
6852 int element = object_mapping[tile].element_rnd;
6853 int action = object_mapping[tile].action;
6854 boolean is_backside = object_mapping[tile].is_backside;
6855 boolean action_removing = (action == ACTION_DIGGING ||
6856 action == ACTION_SNAPPING ||
6857 action == ACTION_COLLECTING);
6863 case Yacid_splash_eB:
6864 case Yacid_splash_wB:
6865 return (frame_em > 5 ? EL_EMPTY : element);
6871 else /* frame_em == 7 */
6875 case Yacid_splash_eB:
6876 case Yacid_splash_wB:
6879 case Yemerald_stone:
6882 case Ydiamond_stone:
6886 case Xdrip_stretchB:
6905 case Xsand_stonein_1:
6906 case Xsand_stonein_2:
6907 case Xsand_stonein_3:
6908 case Xsand_stonein_4:
6912 return (is_backside || action_removing ? EL_EMPTY : element);
6917 inline static boolean check_linear_animation_EM(int tile)
6921 case Xsand_stonesand_1:
6922 case Xsand_stonesand_quickout_1:
6923 case Xsand_sandstone_1:
6924 case Xsand_stonein_1:
6925 case Xsand_stoneout_1:
6944 case Yacid_splash_eB:
6945 case Yacid_splash_wB:
6946 case Yemerald_stone:
6953 inline static void set_crumbled_graphics_EM(struct GraphicInfo_EM *g_em,
6954 boolean has_crumbled_graphics,
6955 int crumbled, int sync_frame)
6957 /* if element can be crumbled, but certain action graphics are just empty
6958 space (like instantly snapping sand to empty space in 1 frame), do not
6959 treat these empty space graphics as crumbled graphics in EMC engine */
6960 if (crumbled == IMG_EMPTY_SPACE)
6961 has_crumbled_graphics = FALSE;
6963 if (has_crumbled_graphics)
6965 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
6966 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
6967 g_crumbled->anim_delay,
6968 g_crumbled->anim_mode,
6969 g_crumbled->anim_start_frame,
6972 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
6973 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
6975 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
6977 g_em->has_crumbled_graphics = TRUE;
6981 g_em->crumbled_bitmap = NULL;
6982 g_em->crumbled_src_x = 0;
6983 g_em->crumbled_src_y = 0;
6984 g_em->crumbled_border_size = 0;
6986 g_em->has_crumbled_graphics = FALSE;
6990 void ResetGfxAnimation_EM(int x, int y, int tile)
6995 void SetGfxAnimation_EM(struct GraphicInfo_EM *g_em,
6996 int tile, int frame_em, int x, int y)
6998 int action = object_mapping[tile].action;
6999 int direction = object_mapping[tile].direction;
7000 int effective_element = get_effective_element_EM(tile, frame_em);
7001 int graphic = (direction == MV_NONE ?
7002 el_act2img(effective_element, action) :
7003 el_act_dir2img(effective_element, action, direction));
7004 struct GraphicInfo *g = &graphic_info[graphic];
7006 boolean action_removing = (action == ACTION_DIGGING ||
7007 action == ACTION_SNAPPING ||
7008 action == ACTION_COLLECTING);
7009 boolean action_moving = (action == ACTION_FALLING ||
7010 action == ACTION_MOVING ||
7011 action == ACTION_PUSHING ||
7012 action == ACTION_EATING ||
7013 action == ACTION_FILLING ||
7014 action == ACTION_EMPTYING);
7015 boolean action_falling = (action == ACTION_FALLING ||
7016 action == ACTION_FILLING ||
7017 action == ACTION_EMPTYING);
7019 /* special case: graphic uses "2nd movement tile" and has defined
7020 7 frames for movement animation (or less) => use default graphic
7021 for last (8th) frame which ends the movement animation */
7022 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
7024 action = ACTION_DEFAULT; /* (keep action_* unchanged for now) */
7025 graphic = (direction == MV_NONE ?
7026 el_act2img(effective_element, action) :
7027 el_act_dir2img(effective_element, action, direction));
7029 g = &graphic_info[graphic];
7032 if ((action_removing || check_linear_animation_EM(tile)) && frame_em == 0)
7036 else if (action_moving)
7038 boolean is_backside = object_mapping[tile].is_backside;
7042 int direction = object_mapping[tile].direction;
7043 int move_dir = (action_falling ? MV_DOWN : direction);
7048 /* !!! TEST !!! NEW !!! DOES NOT WORK RIGHT YET !!! */
7049 if (g->double_movement && frame_em == 0)
7053 if (move_dir == MV_LEFT)
7054 GfxFrame[x - 1][y] = GfxFrame[x][y];
7055 else if (move_dir == MV_RIGHT)
7056 GfxFrame[x + 1][y] = GfxFrame[x][y];
7057 else if (move_dir == MV_UP)
7058 GfxFrame[x][y - 1] = GfxFrame[x][y];
7059 else if (move_dir == MV_DOWN)
7060 GfxFrame[x][y + 1] = GfxFrame[x][y];
7067 /* special case: animation for Xsand_stonesand_quickout_1/2 twice as fast */
7068 if (tile == Xsand_stonesand_quickout_1 ||
7069 tile == Xsand_stonesand_quickout_2)
7073 if (graphic_info[graphic].anim_global_sync)
7074 sync_frame = FrameCounter;
7075 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
7076 sync_frame = GfxFrame[x][y];
7078 sync_frame = 0; /* playfield border (pseudo steel) */
7080 SetRandomAnimationValue(x, y);
7082 int frame = getAnimationFrame(g->anim_frames,
7085 g->anim_start_frame,
7088 g_em->unique_identifier =
7089 (graphic << 16) | ((frame % 8) << 12) | (g_em->width << 6) | g_em->height;
7092 void getGraphicSourceObjectExt_EM(struct GraphicInfo_EM *g_em,
7093 int tile, int frame_em, int x, int y)
7095 int action = object_mapping[tile].action;
7096 int direction = object_mapping[tile].direction;
7097 boolean is_backside = object_mapping[tile].is_backside;
7098 int effective_element = get_effective_element_EM(tile, frame_em);
7099 int effective_action = action;
7100 int graphic = (direction == MV_NONE ?
7101 el_act2img(effective_element, effective_action) :
7102 el_act_dir2img(effective_element, effective_action,
7104 int crumbled = (direction == MV_NONE ?
7105 el_act2crm(effective_element, effective_action) :
7106 el_act_dir2crm(effective_element, effective_action,
7108 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7109 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7110 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7111 struct GraphicInfo *g = &graphic_info[graphic];
7114 /* special case: graphic uses "2nd movement tile" and has defined
7115 7 frames for movement animation (or less) => use default graphic
7116 for last (8th) frame which ends the movement animation */
7117 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
7119 effective_action = ACTION_DEFAULT;
7120 graphic = (direction == MV_NONE ?
7121 el_act2img(effective_element, effective_action) :
7122 el_act_dir2img(effective_element, effective_action,
7124 crumbled = (direction == MV_NONE ?
7125 el_act2crm(effective_element, effective_action) :
7126 el_act_dir2crm(effective_element, effective_action,
7129 g = &graphic_info[graphic];
7132 if (graphic_info[graphic].anim_global_sync)
7133 sync_frame = FrameCounter;
7134 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
7135 sync_frame = GfxFrame[x][y];
7137 sync_frame = 0; /* playfield border (pseudo steel) */
7139 SetRandomAnimationValue(x, y);
7141 int frame = getAnimationFrame(g->anim_frames,
7144 g->anim_start_frame,
7147 getGraphicSourceExt(graphic, frame, &g_em->bitmap, &g_em->src_x, &g_em->src_y,
7148 g->double_movement && is_backside);
7150 /* (updating the "crumbled" graphic definitions is probably not really needed,
7151 as animations for crumbled graphics can't be longer than one EMC cycle) */
7152 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
7156 void getGraphicSourcePlayerExt_EM(struct GraphicInfo_EM *g_em,
7157 int player_nr, int anim, int frame_em)
7159 int element = player_mapping[player_nr][anim].element_rnd;
7160 int action = player_mapping[player_nr][anim].action;
7161 int direction = player_mapping[player_nr][anim].direction;
7162 int graphic = (direction == MV_NONE ?
7163 el_act2img(element, action) :
7164 el_act_dir2img(element, action, direction));
7165 struct GraphicInfo *g = &graphic_info[graphic];
7168 InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
7170 stored_player[player_nr].StepFrame = frame_em;
7172 sync_frame = stored_player[player_nr].Frame;
7174 int frame = getAnimationFrame(g->anim_frames,
7177 g->anim_start_frame,
7180 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
7181 &g_em->src_x, &g_em->src_y, FALSE);
7184 void InitGraphicInfo_EM(void)
7189 int num_em_gfx_errors = 0;
7191 if (graphic_info_em_object[0][0].bitmap == NULL)
7193 /* EM graphics not yet initialized in em_open_all() */
7198 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
7201 /* always start with reliable default values */
7202 for (i = 0; i < TILE_MAX; i++)
7204 object_mapping[i].element_rnd = EL_UNKNOWN;
7205 object_mapping[i].is_backside = FALSE;
7206 object_mapping[i].action = ACTION_DEFAULT;
7207 object_mapping[i].direction = MV_NONE;
7210 /* always start with reliable default values */
7211 for (p = 0; p < MAX_PLAYERS; p++)
7213 for (i = 0; i < SPR_MAX; i++)
7215 player_mapping[p][i].element_rnd = EL_UNKNOWN;
7216 player_mapping[p][i].action = ACTION_DEFAULT;
7217 player_mapping[p][i].direction = MV_NONE;
7221 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
7223 int e = em_object_mapping_list[i].element_em;
7225 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
7226 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
7228 if (em_object_mapping_list[i].action != -1)
7229 object_mapping[e].action = em_object_mapping_list[i].action;
7231 if (em_object_mapping_list[i].direction != -1)
7232 object_mapping[e].direction =
7233 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
7236 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
7238 int a = em_player_mapping_list[i].action_em;
7239 int p = em_player_mapping_list[i].player_nr;
7241 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
7243 if (em_player_mapping_list[i].action != -1)
7244 player_mapping[p][a].action = em_player_mapping_list[i].action;
7246 if (em_player_mapping_list[i].direction != -1)
7247 player_mapping[p][a].direction =
7248 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
7251 for (i = 0; i < TILE_MAX; i++)
7253 int element = object_mapping[i].element_rnd;
7254 int action = object_mapping[i].action;
7255 int direction = object_mapping[i].direction;
7256 boolean is_backside = object_mapping[i].is_backside;
7257 boolean action_exploding = ((action == ACTION_EXPLODING ||
7258 action == ACTION_SMASHED_BY_ROCK ||
7259 action == ACTION_SMASHED_BY_SPRING) &&
7260 element != EL_DIAMOND);
7261 boolean action_active = (action == ACTION_ACTIVE);
7262 boolean action_other = (action == ACTION_OTHER);
7264 for (j = 0; j < 8; j++)
7266 int effective_element = get_effective_element_EM(i, j);
7267 int effective_action = (j < 7 ? action :
7268 i == Xdrip_stretch ? action :
7269 i == Xdrip_stretchB ? action :
7270 i == Ydrip_s1 ? action :
7271 i == Ydrip_s1B ? action :
7272 i == Xball_1B ? action :
7273 i == Xball_2 ? action :
7274 i == Xball_2B ? action :
7275 i == Yball_eat ? action :
7276 i == Ykey_1_eat ? action :
7277 i == Ykey_2_eat ? action :
7278 i == Ykey_3_eat ? action :
7279 i == Ykey_4_eat ? action :
7280 i == Ykey_5_eat ? action :
7281 i == Ykey_6_eat ? action :
7282 i == Ykey_7_eat ? action :
7283 i == Ykey_8_eat ? action :
7284 i == Ylenses_eat ? action :
7285 i == Ymagnify_eat ? action :
7286 i == Ygrass_eat ? action :
7287 i == Ydirt_eat ? action :
7288 i == Xsand_stonein_1 ? action :
7289 i == Xsand_stonein_2 ? action :
7290 i == Xsand_stonein_3 ? action :
7291 i == Xsand_stonein_4 ? action :
7292 i == Xsand_stoneout_1 ? action :
7293 i == Xsand_stoneout_2 ? action :
7294 i == Xboom_android ? ACTION_EXPLODING :
7295 action_exploding ? ACTION_EXPLODING :
7296 action_active ? action :
7297 action_other ? action :
7299 int graphic = (el_act_dir2img(effective_element, effective_action,
7301 int crumbled = (el_act_dir2crm(effective_element, effective_action,
7303 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7304 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7305 boolean has_action_graphics = (graphic != base_graphic);
7306 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7307 struct GraphicInfo *g = &graphic_info[graphic];
7308 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7311 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
7312 boolean special_animation = (action != ACTION_DEFAULT &&
7313 g->anim_frames == 3 &&
7314 g->anim_delay == 2 &&
7315 g->anim_mode & ANIM_LINEAR);
7316 int sync_frame = (i == Xdrip_stretch ? 7 :
7317 i == Xdrip_stretchB ? 7 :
7318 i == Ydrip_s2 ? j + 8 :
7319 i == Ydrip_s2B ? j + 8 :
7328 i == Xfake_acid_1 ? 0 :
7329 i == Xfake_acid_2 ? 10 :
7330 i == Xfake_acid_3 ? 20 :
7331 i == Xfake_acid_4 ? 30 :
7332 i == Xfake_acid_5 ? 40 :
7333 i == Xfake_acid_6 ? 50 :
7334 i == Xfake_acid_7 ? 60 :
7335 i == Xfake_acid_8 ? 70 :
7337 i == Xball_2B ? j + 8 :
7338 i == Yball_eat ? j + 1 :
7339 i == Ykey_1_eat ? j + 1 :
7340 i == Ykey_2_eat ? j + 1 :
7341 i == Ykey_3_eat ? j + 1 :
7342 i == Ykey_4_eat ? j + 1 :
7343 i == Ykey_5_eat ? j + 1 :
7344 i == Ykey_6_eat ? j + 1 :
7345 i == Ykey_7_eat ? j + 1 :
7346 i == Ykey_8_eat ? j + 1 :
7347 i == Ylenses_eat ? j + 1 :
7348 i == Ymagnify_eat ? j + 1 :
7349 i == Ygrass_eat ? j + 1 :
7350 i == Ydirt_eat ? j + 1 :
7351 i == Xamoeba_1 ? 0 :
7352 i == Xamoeba_2 ? 1 :
7353 i == Xamoeba_3 ? 2 :
7354 i == Xamoeba_4 ? 3 :
7355 i == Xamoeba_5 ? 0 :
7356 i == Xamoeba_6 ? 1 :
7357 i == Xamoeba_7 ? 2 :
7358 i == Xamoeba_8 ? 3 :
7359 i == Xexit_2 ? j + 8 :
7360 i == Xexit_3 ? j + 16 :
7361 i == Xdynamite_1 ? 0 :
7362 i == Xdynamite_2 ? 8 :
7363 i == Xdynamite_3 ? 16 :
7364 i == Xdynamite_4 ? 24 :
7365 i == Xsand_stonein_1 ? j + 1 :
7366 i == Xsand_stonein_2 ? j + 9 :
7367 i == Xsand_stonein_3 ? j + 17 :
7368 i == Xsand_stonein_4 ? j + 25 :
7369 i == Xsand_stoneout_1 && j == 0 ? 0 :
7370 i == Xsand_stoneout_1 && j == 1 ? 0 :
7371 i == Xsand_stoneout_1 && j == 2 ? 1 :
7372 i == Xsand_stoneout_1 && j == 3 ? 2 :
7373 i == Xsand_stoneout_1 && j == 4 ? 2 :
7374 i == Xsand_stoneout_1 && j == 5 ? 3 :
7375 i == Xsand_stoneout_1 && j == 6 ? 4 :
7376 i == Xsand_stoneout_1 && j == 7 ? 4 :
7377 i == Xsand_stoneout_2 && j == 0 ? 5 :
7378 i == Xsand_stoneout_2 && j == 1 ? 6 :
7379 i == Xsand_stoneout_2 && j == 2 ? 7 :
7380 i == Xsand_stoneout_2 && j == 3 ? 8 :
7381 i == Xsand_stoneout_2 && j == 4 ? 9 :
7382 i == Xsand_stoneout_2 && j == 5 ? 11 :
7383 i == Xsand_stoneout_2 && j == 6 ? 13 :
7384 i == Xsand_stoneout_2 && j == 7 ? 15 :
7385 i == Xboom_bug && j == 1 ? 2 :
7386 i == Xboom_bug && j == 2 ? 2 :
7387 i == Xboom_bug && j == 3 ? 4 :
7388 i == Xboom_bug && j == 4 ? 4 :
7389 i == Xboom_bug && j == 5 ? 2 :
7390 i == Xboom_bug && j == 6 ? 2 :
7391 i == Xboom_bug && j == 7 ? 0 :
7392 i == Xboom_bomb && j == 1 ? 2 :
7393 i == Xboom_bomb && j == 2 ? 2 :
7394 i == Xboom_bomb && j == 3 ? 4 :
7395 i == Xboom_bomb && j == 4 ? 4 :
7396 i == Xboom_bomb && j == 5 ? 2 :
7397 i == Xboom_bomb && j == 6 ? 2 :
7398 i == Xboom_bomb && j == 7 ? 0 :
7399 i == Xboom_android && j == 7 ? 6 :
7400 i == Xboom_1 && j == 1 ? 2 :
7401 i == Xboom_1 && j == 2 ? 2 :
7402 i == Xboom_1 && j == 3 ? 4 :
7403 i == Xboom_1 && j == 4 ? 4 :
7404 i == Xboom_1 && j == 5 ? 6 :
7405 i == Xboom_1 && j == 6 ? 6 :
7406 i == Xboom_1 && j == 7 ? 8 :
7407 i == Xboom_2 && j == 0 ? 8 :
7408 i == Xboom_2 && j == 1 ? 8 :
7409 i == Xboom_2 && j == 2 ? 10 :
7410 i == Xboom_2 && j == 3 ? 10 :
7411 i == Xboom_2 && j == 4 ? 10 :
7412 i == Xboom_2 && j == 5 ? 12 :
7413 i == Xboom_2 && j == 6 ? 12 :
7414 i == Xboom_2 && j == 7 ? 12 :
7415 special_animation && j == 4 ? 3 :
7416 effective_action != action ? 0 :
7420 Bitmap *debug_bitmap = g_em->bitmap;
7421 int debug_src_x = g_em->src_x;
7422 int debug_src_y = g_em->src_y;
7425 int frame = getAnimationFrame(g->anim_frames,
7428 g->anim_start_frame,
7431 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
7432 g->double_movement && is_backside);
7434 g_em->bitmap = src_bitmap;
7435 g_em->src_x = src_x;
7436 g_em->src_y = src_y;
7437 g_em->src_offset_x = 0;
7438 g_em->src_offset_y = 0;
7439 g_em->dst_offset_x = 0;
7440 g_em->dst_offset_y = 0;
7441 g_em->width = TILEX;
7442 g_em->height = TILEY;
7444 g_em->preserve_background = FALSE;
7446 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
7449 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
7450 effective_action == ACTION_MOVING ||
7451 effective_action == ACTION_PUSHING ||
7452 effective_action == ACTION_EATING)) ||
7453 (!has_action_graphics && (effective_action == ACTION_FILLING ||
7454 effective_action == ACTION_EMPTYING)))
7457 (effective_action == ACTION_FALLING ||
7458 effective_action == ACTION_FILLING ||
7459 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
7460 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
7461 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
7462 int num_steps = (i == Ydrip_s1 ? 16 :
7463 i == Ydrip_s1B ? 16 :
7464 i == Ydrip_s2 ? 16 :
7465 i == Ydrip_s2B ? 16 :
7466 i == Xsand_stonein_1 ? 32 :
7467 i == Xsand_stonein_2 ? 32 :
7468 i == Xsand_stonein_3 ? 32 :
7469 i == Xsand_stonein_4 ? 32 :
7470 i == Xsand_stoneout_1 ? 16 :
7471 i == Xsand_stoneout_2 ? 16 : 8);
7472 int cx = ABS(dx) * (TILEX / num_steps);
7473 int cy = ABS(dy) * (TILEY / num_steps);
7474 int step_frame = (i == Ydrip_s2 ? j + 8 :
7475 i == Ydrip_s2B ? j + 8 :
7476 i == Xsand_stonein_2 ? j + 8 :
7477 i == Xsand_stonein_3 ? j + 16 :
7478 i == Xsand_stonein_4 ? j + 24 :
7479 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
7480 int step = (is_backside ? step_frame : num_steps - step_frame);
7482 if (is_backside) /* tile where movement starts */
7484 if (dx < 0 || dy < 0)
7486 g_em->src_offset_x = cx * step;
7487 g_em->src_offset_y = cy * step;
7491 g_em->dst_offset_x = cx * step;
7492 g_em->dst_offset_y = cy * step;
7495 else /* tile where movement ends */
7497 if (dx < 0 || dy < 0)
7499 g_em->dst_offset_x = cx * step;
7500 g_em->dst_offset_y = cy * step;
7504 g_em->src_offset_x = cx * step;
7505 g_em->src_offset_y = cy * step;
7509 g_em->width = TILEX - cx * step;
7510 g_em->height = TILEY - cy * step;
7513 /* create unique graphic identifier to decide if tile must be redrawn */
7514 /* bit 31 - 16 (16 bit): EM style graphic
7515 bit 15 - 12 ( 4 bit): EM style frame
7516 bit 11 - 6 ( 6 bit): graphic width
7517 bit 5 - 0 ( 6 bit): graphic height */
7518 g_em->unique_identifier =
7519 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
7523 /* skip check for EMC elements not contained in original EMC artwork */
7524 if (element == EL_EMC_FAKE_ACID)
7527 if (g_em->bitmap != debug_bitmap ||
7528 g_em->src_x != debug_src_x ||
7529 g_em->src_y != debug_src_y ||
7530 g_em->src_offset_x != 0 ||
7531 g_em->src_offset_y != 0 ||
7532 g_em->dst_offset_x != 0 ||
7533 g_em->dst_offset_y != 0 ||
7534 g_em->width != TILEX ||
7535 g_em->height != TILEY)
7537 static int last_i = -1;
7545 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
7546 i, element, element_info[element].token_name,
7547 element_action_info[effective_action].suffix, direction);
7549 if (element != effective_element)
7550 printf(" [%d ('%s')]",
7552 element_info[effective_element].token_name);
7556 if (g_em->bitmap != debug_bitmap)
7557 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
7558 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
7560 if (g_em->src_x != debug_src_x ||
7561 g_em->src_y != debug_src_y)
7562 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
7563 j, (is_backside ? 'B' : 'F'),
7564 g_em->src_x, g_em->src_y,
7565 g_em->src_x / 32, g_em->src_y / 32,
7566 debug_src_x, debug_src_y,
7567 debug_src_x / 32, debug_src_y / 32);
7569 if (g_em->src_offset_x != 0 ||
7570 g_em->src_offset_y != 0 ||
7571 g_em->dst_offset_x != 0 ||
7572 g_em->dst_offset_y != 0)
7573 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
7575 g_em->src_offset_x, g_em->src_offset_y,
7576 g_em->dst_offset_x, g_em->dst_offset_y);
7578 if (g_em->width != TILEX ||
7579 g_em->height != TILEY)
7580 printf(" %d (%d): size %d,%d should be %d,%d\n",
7582 g_em->width, g_em->height, TILEX, TILEY);
7584 num_em_gfx_errors++;
7591 for (i = 0; i < TILE_MAX; i++)
7593 for (j = 0; j < 8; j++)
7595 int element = object_mapping[i].element_rnd;
7596 int action = object_mapping[i].action;
7597 int direction = object_mapping[i].direction;
7598 boolean is_backside = object_mapping[i].is_backside;
7599 int graphic_action = el_act_dir2img(element, action, direction);
7600 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
7602 if ((action == ACTION_SMASHED_BY_ROCK ||
7603 action == ACTION_SMASHED_BY_SPRING ||
7604 action == ACTION_EATING) &&
7605 graphic_action == graphic_default)
7607 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
7608 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
7609 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
7610 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
7613 /* no separate animation for "smashed by rock" -- use rock instead */
7614 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7615 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
7617 g_em->bitmap = g_xx->bitmap;
7618 g_em->src_x = g_xx->src_x;
7619 g_em->src_y = g_xx->src_y;
7620 g_em->src_offset_x = g_xx->src_offset_x;
7621 g_em->src_offset_y = g_xx->src_offset_y;
7622 g_em->dst_offset_x = g_xx->dst_offset_x;
7623 g_em->dst_offset_y = g_xx->dst_offset_y;
7624 g_em->width = g_xx->width;
7625 g_em->height = g_xx->height;
7626 g_em->unique_identifier = g_xx->unique_identifier;
7629 g_em->preserve_background = TRUE;
7634 for (p = 0; p < MAX_PLAYERS; p++)
7636 for (i = 0; i < SPR_MAX; i++)
7638 int element = player_mapping[p][i].element_rnd;
7639 int action = player_mapping[p][i].action;
7640 int direction = player_mapping[p][i].direction;
7642 for (j = 0; j < 8; j++)
7644 int effective_element = element;
7645 int effective_action = action;
7646 int graphic = (direction == MV_NONE ?
7647 el_act2img(effective_element, effective_action) :
7648 el_act_dir2img(effective_element, effective_action,
7650 struct GraphicInfo *g = &graphic_info[graphic];
7651 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
7657 Bitmap *debug_bitmap = g_em->bitmap;
7658 int debug_src_x = g_em->src_x;
7659 int debug_src_y = g_em->src_y;
7662 int frame = getAnimationFrame(g->anim_frames,
7665 g->anim_start_frame,
7668 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
7670 g_em->bitmap = src_bitmap;
7671 g_em->src_x = src_x;
7672 g_em->src_y = src_y;
7673 g_em->src_offset_x = 0;
7674 g_em->src_offset_y = 0;
7675 g_em->dst_offset_x = 0;
7676 g_em->dst_offset_y = 0;
7677 g_em->width = TILEX;
7678 g_em->height = TILEY;
7682 /* skip check for EMC elements not contained in original EMC artwork */
7683 if (element == EL_PLAYER_3 ||
7684 element == EL_PLAYER_4)
7687 if (g_em->bitmap != debug_bitmap ||
7688 g_em->src_x != debug_src_x ||
7689 g_em->src_y != debug_src_y)
7691 static int last_i = -1;
7699 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
7700 p, i, element, element_info[element].token_name,
7701 element_action_info[effective_action].suffix, direction);
7703 if (element != effective_element)
7704 printf(" [%d ('%s')]",
7706 element_info[effective_element].token_name);
7710 if (g_em->bitmap != debug_bitmap)
7711 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
7712 j, (int)(g_em->bitmap), (int)(debug_bitmap));
7714 if (g_em->src_x != debug_src_x ||
7715 g_em->src_y != debug_src_y)
7716 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
7718 g_em->src_x, g_em->src_y,
7719 g_em->src_x / 32, g_em->src_y / 32,
7720 debug_src_x, debug_src_y,
7721 debug_src_x / 32, debug_src_y / 32);
7723 num_em_gfx_errors++;
7733 printf("::: [%d errors found]\n", num_em_gfx_errors);
7739 void CheckSaveEngineSnapshot_EM(byte action[MAX_PLAYERS], int frame,
7740 boolean any_player_moving,
7741 boolean any_player_snapping,
7742 boolean any_player_dropping)
7744 static boolean player_was_waiting = TRUE;
7746 if (frame == 0 && !any_player_dropping)
7748 if (!player_was_waiting)
7750 if (!SaveEngineSnapshotToList())
7753 player_was_waiting = TRUE;
7756 else if (any_player_moving || any_player_snapping || any_player_dropping)
7758 player_was_waiting = FALSE;
7762 void CheckSaveEngineSnapshot_SP(boolean murphy_is_waiting,
7763 boolean murphy_is_dropping)
7765 static boolean player_was_waiting = TRUE;
7767 if (murphy_is_waiting)
7769 if (!player_was_waiting)
7771 if (!SaveEngineSnapshotToList())
7774 player_was_waiting = TRUE;
7779 player_was_waiting = FALSE;
7783 void CheckSingleStepMode_EM(byte action[MAX_PLAYERS], int frame,
7784 boolean any_player_moving,
7785 boolean any_player_snapping,
7786 boolean any_player_dropping)
7788 if (tape.single_step && tape.recording && !tape.pausing)
7789 if (frame == 0 && !any_player_dropping)
7790 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
7792 CheckSaveEngineSnapshot_EM(action, frame, any_player_moving,
7793 any_player_snapping, any_player_dropping);
7796 void CheckSingleStepMode_SP(boolean murphy_is_waiting,
7797 boolean murphy_is_dropping)
7799 if (tape.single_step && tape.recording && !tape.pausing)
7800 if (murphy_is_waiting)
7801 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
7803 CheckSaveEngineSnapshot_SP(murphy_is_waiting, murphy_is_dropping);
7806 void getGraphicSource_SP(struct GraphicInfo_SP *g_sp,
7807 int graphic, int sync_frame, int x, int y)
7809 int frame = getGraphicAnimationFrame(graphic, sync_frame);
7811 getGraphicSource(graphic, frame, &g_sp->bitmap, &g_sp->src_x, &g_sp->src_y);
7814 boolean isNextAnimationFrame_SP(int graphic, int sync_frame)
7816 return (IS_NEXT_FRAME(sync_frame, graphic));
7819 int getGraphicInfo_Delay(int graphic)
7821 return graphic_info[graphic].anim_delay;
7824 void PlayMenuSoundExt(int sound)
7826 if (sound == SND_UNDEFINED)
7829 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
7830 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
7833 if (IS_LOOP_SOUND(sound))
7834 PlaySoundLoop(sound);
7839 void PlayMenuSound()
7841 PlayMenuSoundExt(menu.sound[game_status]);
7844 void PlayMenuSoundStereo(int sound, int stereo_position)
7846 if (sound == SND_UNDEFINED)
7849 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
7850 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
7853 if (IS_LOOP_SOUND(sound))
7854 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
7856 PlaySoundStereo(sound, stereo_position);
7859 void PlayMenuSoundIfLoopExt(int sound)
7861 if (sound == SND_UNDEFINED)
7864 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
7865 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
7868 if (IS_LOOP_SOUND(sound))
7869 PlaySoundLoop(sound);
7872 void PlayMenuSoundIfLoop()
7874 PlayMenuSoundIfLoopExt(menu.sound[game_status]);
7877 void PlayMenuMusicExt(int music)
7879 if (music == MUS_UNDEFINED)
7882 if (!setup.sound_music)
7888 void PlayMenuMusic()
7890 PlayMenuMusicExt(menu.music[game_status]);
7893 void PlaySoundActivating()
7896 PlaySound(SND_MENU_ITEM_ACTIVATING);
7900 void PlaySoundSelecting()
7903 PlaySound(SND_MENU_ITEM_SELECTING);
7907 void ToggleFullscreenOrChangeWindowScalingIfNeeded()
7909 boolean change_fullscreen = (setup.fullscreen !=
7910 video.fullscreen_enabled);
7911 boolean change_fullscreen_mode = (video.fullscreen_enabled &&
7912 !strEqual(setup.fullscreen_mode,
7913 video.fullscreen_mode_current));
7914 boolean change_window_scaling_percent = (!video.fullscreen_enabled &&
7915 setup.window_scaling_percent !=
7916 video.window_scaling_percent);
7918 if (change_window_scaling_percent && video.fullscreen_enabled)
7921 if (!change_window_scaling_percent && !video.fullscreen_available)
7924 #if defined(TARGET_SDL2)
7925 if (change_window_scaling_percent)
7927 SDLSetWindowScaling(setup.window_scaling_percent);
7931 else if (change_fullscreen)
7933 SDLSetWindowFullscreen(setup.fullscreen);
7935 /* set setup value according to successfully changed fullscreen mode */
7936 setup.fullscreen = video.fullscreen_enabled;
7942 if (change_fullscreen ||
7943 change_fullscreen_mode ||
7944 change_window_scaling_percent)
7946 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
7948 /* save backbuffer content which gets lost when toggling fullscreen mode */
7949 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
7951 if (change_fullscreen_mode)
7953 /* keep fullscreen, but change fullscreen mode (screen resolution) */
7954 video.fullscreen_enabled = FALSE; /* force new fullscreen mode */
7957 if (change_window_scaling_percent)
7959 /* keep window mode, but change window scaling */
7960 video.fullscreen_enabled = TRUE; /* force new window scaling */
7963 /* toggle fullscreen */
7964 ChangeVideoModeIfNeeded(setup.fullscreen);
7966 /* set setup value according to successfully changed fullscreen mode */
7967 setup.fullscreen = video.fullscreen_enabled;
7969 /* restore backbuffer content from temporary backbuffer backup bitmap */
7970 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
7972 FreeBitmap(tmp_backbuffer);
7974 /* update visible window/screen */
7975 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
7979 void ChangeViewportPropertiesIfNeeded()
7981 int gfx_game_mode = game_status;
7982 int gfx_game_mode2 = (game_status == GAME_MODE_EDITOR ? GAME_MODE_DEFAULT :
7984 struct RectWithBorder *vp_playfield = &viewport.playfield[gfx_game_mode];
7985 struct RectWithBorder *vp_door_1 = &viewport.door_1[gfx_game_mode];
7986 struct RectWithBorder *vp_door_2 = &viewport.door_2[gfx_game_mode2];
7987 struct RectWithBorder *vp_door_3 = &viewport.door_2[GAME_MODE_EDITOR];
7988 int border_size = vp_playfield->border_size;
7989 int new_sx = vp_playfield->x + border_size;
7990 int new_sy = vp_playfield->y + border_size;
7991 int new_sxsize = vp_playfield->width - 2 * border_size;
7992 int new_sysize = vp_playfield->height - 2 * border_size;
7993 int new_real_sx = vp_playfield->x;
7994 int new_real_sy = vp_playfield->y;
7995 int new_full_sxsize = vp_playfield->width;
7996 int new_full_sysize = vp_playfield->height;
7997 int new_dx = vp_door_1->x;
7998 int new_dy = vp_door_1->y;
7999 int new_dxsize = vp_door_1->width;
8000 int new_dysize = vp_door_1->height;
8001 int new_vx = vp_door_2->x;
8002 int new_vy = vp_door_2->y;
8003 int new_vxsize = vp_door_2->width;
8004 int new_vysize = vp_door_2->height;
8005 int new_ex = vp_door_3->x;
8006 int new_ey = vp_door_3->y;
8007 int new_exsize = vp_door_3->width;
8008 int new_eysize = vp_door_3->height;
8009 int new_tilesize_var =
8010 (setup.small_game_graphics ? MINI_TILESIZE : game.tile_size);
8012 int tilesize = (gfx_game_mode == GAME_MODE_PLAYING ? new_tilesize_var :
8013 gfx_game_mode == GAME_MODE_EDITOR ? MINI_TILESIZE : TILESIZE);
8014 int new_scr_fieldx = new_sxsize / tilesize;
8015 int new_scr_fieldy = new_sysize / tilesize;
8016 int new_scr_fieldx_buffers = new_sxsize / new_tilesize_var;
8017 int new_scr_fieldy_buffers = new_sysize / new_tilesize_var;
8018 boolean init_gfx_buffers = FALSE;
8019 boolean init_video_buffer = FALSE;
8020 boolean init_gadgets_and_toons = FALSE;
8021 boolean init_em_graphics = FALSE;
8022 boolean drawing_area_changed = FALSE;
8024 if (viewport.window.width != WIN_XSIZE ||
8025 viewport.window.height != WIN_YSIZE)
8027 WIN_XSIZE = viewport.window.width;
8028 WIN_YSIZE = viewport.window.height;
8030 init_video_buffer = TRUE;
8031 init_gfx_buffers = TRUE;
8033 // printf("::: video: init_video_buffer, init_gfx_buffers\n");
8036 if (new_scr_fieldx != SCR_FIELDX ||
8037 new_scr_fieldy != SCR_FIELDY)
8039 /* this always toggles between MAIN and GAME when using small tile size */
8041 SCR_FIELDX = new_scr_fieldx;
8042 SCR_FIELDY = new_scr_fieldy;
8044 // printf("::: new_scr_fieldx != SCR_FIELDX ...\n");
8055 new_sxsize != SXSIZE ||
8056 new_sysize != SYSIZE ||
8057 new_dxsize != DXSIZE ||
8058 new_dysize != DYSIZE ||
8059 new_vxsize != VXSIZE ||
8060 new_vysize != VYSIZE ||
8061 new_exsize != EXSIZE ||
8062 new_eysize != EYSIZE ||
8063 new_real_sx != REAL_SX ||
8064 new_real_sy != REAL_SY ||
8065 new_full_sxsize != FULL_SXSIZE ||
8066 new_full_sysize != FULL_SYSIZE ||
8067 new_tilesize_var != TILESIZE_VAR
8070 if (new_tilesize_var != TILESIZE_VAR)
8072 // printf("::: new_tilesize_var != TILESIZE_VAR\n");
8074 // changing tile size invalidates scroll values of engine snapshots
8075 FreeEngineSnapshotSingle();
8077 // changing tile size requires update of graphic mapping for EM engine
8078 init_em_graphics = TRUE;
8083 new_sxsize != SXSIZE ||
8084 new_sysize != SYSIZE ||
8085 new_real_sx != REAL_SX ||
8086 new_real_sy != REAL_SY ||
8087 new_full_sxsize != FULL_SXSIZE ||
8088 new_full_sysize != FULL_SYSIZE)
8090 if (!init_video_buffer)
8091 drawing_area_changed = TRUE;
8102 SXSIZE = new_sxsize;
8103 SYSIZE = new_sysize;
8104 DXSIZE = new_dxsize;
8105 DYSIZE = new_dysize;
8106 VXSIZE = new_vxsize;
8107 VYSIZE = new_vysize;
8108 EXSIZE = new_exsize;
8109 EYSIZE = new_eysize;
8110 REAL_SX = new_real_sx;
8111 REAL_SY = new_real_sy;
8112 FULL_SXSIZE = new_full_sxsize;
8113 FULL_SYSIZE = new_full_sysize;
8114 TILESIZE_VAR = new_tilesize_var;
8116 init_gfx_buffers = TRUE;
8117 init_gadgets_and_toons = TRUE;
8119 // printf("::: viewports: init_gfx_buffers\n");
8120 // printf("::: viewports: init_gadgets_and_toons\n");
8123 if (init_gfx_buffers)
8125 // printf("::: init_gfx_buffers\n");
8127 SCR_FIELDX = new_scr_fieldx_buffers;
8128 SCR_FIELDY = new_scr_fieldy_buffers;
8132 SCR_FIELDX = new_scr_fieldx;
8133 SCR_FIELDY = new_scr_fieldy;
8135 gfx.drawing_area_changed = drawing_area_changed;
8137 SetDrawDeactivationMask(REDRAW_NONE);
8138 SetDrawBackgroundMask(REDRAW_FIELD);
8141 if (init_video_buffer)
8143 // printf("::: init_video_buffer\n");
8145 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
8148 if (init_gadgets_and_toons)
8150 // printf("::: init_gadgets_and_toons\n");
8156 if (init_em_graphics)
8158 InitGraphicInfo_EM();