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 int fx = FX, fy = FY;
360 int full_lev_fieldx = lev_fieldx + (BorderElement != EL_EMPTY ? 2 : 0);
361 int full_lev_fieldy = lev_fieldy + (BorderElement != EL_EMPTY ? 2 : 0);
363 int dx = (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
364 int dy = (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
365 int dx_var = dx * TILESIZE_VAR / TILESIZE;
366 int dy_var = dy * TILESIZE_VAR / TILESIZE;
369 ffx = (scroll_x - SBX_Left) * TILEX_VAR + dx_var;
370 ffy = (scroll_y - SBY_Upper) * TILEY_VAR + dy_var;
372 if (EVEN(SCR_FIELDX))
374 if (ffx < SBX_Right * TILEX_VAR + TILEX_VAR / 2 + TILEX_VAR)
375 fx += dx_var - MIN(ffx, TILEX_VAR / 2) + TILEX_VAR;
377 fx += (dx_var > 0 ? TILEX_VAR : 0);
384 if (EVEN(SCR_FIELDY))
386 if (ffy < SBY_Lower * TILEY_VAR + TILEY_VAR / 2 + TILEY_VAR)
387 fy += dy_var - MIN(ffy, TILEY_VAR / 2) + TILEY_VAR;
389 fy += (dy_var > 0 ? TILEY_VAR : 0);
396 if (full_lev_fieldx <= SCR_FIELDX)
398 if (EVEN(SCR_FIELDX))
399 fx = 2 * TILEX_VAR - (ODD(lev_fieldx) ? TILEX_VAR / 2 : 0);
401 fx = 2 * TILEX_VAR - (EVEN(lev_fieldx) ? TILEX_VAR / 2 : 0);
404 if (full_lev_fieldy <= SCR_FIELDY)
406 if (EVEN(SCR_FIELDY))
407 fy = 2 * TILEY_VAR - (ODD(lev_fieldy) ? TILEY_VAR / 2 : 0);
409 fy = 2 * TILEY_VAR - (EVEN(lev_fieldy) ? TILEY_VAR / 2 : 0);
412 BlitBitmap(drawto_field, target_bitmap, fx, fy, SXSIZE, SYSIZE, SX, SY);
415 void BlitScreenToBitmap(Bitmap *target_bitmap)
417 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
418 BlitScreenToBitmap_EM(target_bitmap);
419 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
420 BlitScreenToBitmap_SP(target_bitmap);
421 else if (level.game_engine_type == GAME_ENGINE_TYPE_RND)
422 BlitScreenToBitmap_RND(target_bitmap);
425 void BackToFront_OLD()
427 DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
430 /* !!! TEST ONLY !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
431 /* (force full redraw) */
432 if (game_status == GAME_MODE_PLAYING)
433 redraw_mask |= REDRAW_FIELD;
436 if (redraw_mask == REDRAW_NONE)
441 if (redraw_mask & REDRAW_ALL)
442 printf("[REDRAW_ALL]");
443 if (redraw_mask & REDRAW_FIELD)
444 printf("[REDRAW_FIELD]");
445 if (redraw_mask & REDRAW_DOOR_1)
446 printf("[REDRAW_DOOR_1]");
447 if (redraw_mask & REDRAW_DOOR_2)
448 printf("[REDRAW_DOOR_2]");
449 if (redraw_mask & REDRAW_FROM_BACKBUFFER)
450 printf("[REDRAW_FROM_BACKBUFFER]");
451 printf(" [%d]\n", FrameCounter);
454 if (global.fps_slowdown && game_status == GAME_MODE_PLAYING)
456 static boolean last_frame_skipped = FALSE;
457 boolean skip_even_when_not_scrolling = TRUE;
458 boolean just_scrolling = (ScreenMovDir != 0);
459 boolean verbose = FALSE;
461 if (global.fps_slowdown_factor > 1 &&
462 (FrameCounter % global.fps_slowdown_factor) &&
463 (just_scrolling || skip_even_when_not_scrolling))
465 redraw_mask &= ~REDRAW_MAIN;
467 last_frame_skipped = TRUE;
470 printf("FRAME SKIPPED\n");
474 if (last_frame_skipped)
475 redraw_mask |= REDRAW_FIELD;
477 last_frame_skipped = FALSE;
480 printf("frame not skipped\n");
484 /* synchronize X11 graphics at this point; if we would synchronize the
485 display immediately after the buffer switching (after the XFlush),
486 this could mean that we have to wait for the graphics to complete,
487 although we could go on doing calculations for the next frame */
491 /* never draw masked border to backbuffer when using playfield buffer */
492 if (game_status != GAME_MODE_PLAYING ||
493 redraw_mask & REDRAW_FROM_BACKBUFFER ||
494 buffer == backbuffer)
495 DrawMaskedBorder(redraw_mask);
497 DrawMaskedBorder(redraw_mask & REDRAW_DOORS);
499 if (redraw_mask & REDRAW_ALL)
501 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
503 redraw_mask = REDRAW_NONE;
506 if (redraw_mask & REDRAW_FIELD)
508 if (game_status != GAME_MODE_PLAYING ||
509 redraw_mask & REDRAW_FROM_BACKBUFFER)
511 BlitBitmap(backbuffer, window,
512 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
516 BlitScreenToBitmap_RND(window);
519 redraw_mask &= ~REDRAW_MAIN;
522 if (redraw_mask & REDRAW_DOORS)
524 if (redraw_mask & REDRAW_DOOR_1)
525 BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
527 if (redraw_mask & REDRAW_DOOR_2)
528 BlitBitmap(backbuffer, window, VX, VY, VXSIZE, VYSIZE, VX, VY);
530 if (redraw_mask & REDRAW_DOOR_3)
531 BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
533 redraw_mask &= ~REDRAW_DOORS;
536 if (redraw_mask & REDRAW_MICROLEVEL)
538 BlitBitmap(backbuffer, window, SX, SY + 10 * TILEY, SXSIZE, 7 * TILEY,
539 SX, SY + 10 * TILEY);
541 redraw_mask &= ~REDRAW_MICROLEVEL;
544 if (redraw_mask & REDRAW_FPS) /* display frames per second */
549 sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
550 if (!global.fps_slowdown)
553 sprintf(text, "%04.1f fps%s", global.frames_per_second, info1);
555 DrawTextExt(window, SX + SXSIZE + SX, 0, text, FONT_TEXT_2, BLIT_OPAQUE);
558 redraw_mask = REDRAW_NONE;
563 if (redraw_mask == REDRAW_NONE)
566 // draw masked border to all viewports, if defined
567 DrawMaskedBorder(redraw_mask);
569 // blit backbuffer to visible screen
570 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
572 redraw_mask = REDRAW_NONE;
575 static void FadeCrossSaveBackbuffer()
577 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
580 static void FadeExt(int fade_mask, int fade_mode, int fade_type)
582 static int fade_type_skip = FADE_TYPE_NONE;
583 void (*draw_border_function)(void) = NULL;
584 Bitmap *bitmap = (fade_mode & FADE_TYPE_TRANSFORM ? bitmap_db_cross : NULL);
585 int x, y, width, height;
586 int fade_delay, post_delay;
588 if (fade_type == FADE_TYPE_FADE_OUT)
590 if (fade_type_skip != FADE_TYPE_NONE)
592 /* skip all fade operations until specified fade operation */
593 if (fade_type & fade_type_skip)
594 fade_type_skip = FADE_TYPE_NONE;
599 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
601 FadeCrossSaveBackbuffer();
607 redraw_mask |= fade_mask;
609 if (fade_type == FADE_TYPE_SKIP)
611 fade_type_skip = fade_mode;
616 fade_delay = fading.fade_delay;
617 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
619 if (fade_type_skip != FADE_TYPE_NONE)
621 /* skip all fade operations until specified fade operation */
622 if (fade_type & fade_type_skip)
623 fade_type_skip = FADE_TYPE_NONE;
628 if (global.autoplay_leveldir)
633 if (fade_mask == REDRAW_FIELD)
638 height = FULL_SYSIZE;
640 if (border.draw_masked_when_fading)
641 draw_border_function = DrawMaskedBorder_FIELD; /* update when fading */
643 DrawMaskedBorder_FIELD(); /* draw once */
645 else /* REDRAW_ALL */
653 if (!setup.fade_screens ||
655 fading.fade_mode == FADE_MODE_NONE)
657 if (fade_mode == FADE_MODE_FADE_OUT)
660 BlitBitmap(backbuffer, window, x, y, width, height, x, y);
662 redraw_mask &= ~fade_mask;
667 FadeRectangle(bitmap, x, y, width, height, fade_mode, fade_delay, post_delay,
668 draw_border_function);
670 redraw_mask &= ~fade_mask;
673 void FadeIn(int fade_mask)
675 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
676 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_IN);
678 FadeExt(fade_mask, FADE_MODE_FADE_IN, FADE_TYPE_FADE_IN);
681 void FadeOut(int fade_mask)
683 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
684 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_OUT);
686 FadeExt(fade_mask, FADE_MODE_FADE_OUT, FADE_TYPE_FADE_OUT);
688 global.border_status = game_status;
691 static void FadeSetLeaveNext(struct TitleFadingInfo fading_leave, boolean set)
693 static struct TitleFadingInfo fading_leave_stored;
696 fading_leave_stored = fading_leave;
698 fading = fading_leave_stored;
701 void FadeSetEnterMenu()
703 fading = menu.enter_menu;
705 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
708 void FadeSetLeaveMenu()
710 fading = menu.leave_menu;
712 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
715 void FadeSetEnterScreen()
717 fading = menu.enter_screen[game_status];
719 FadeSetLeaveNext(menu.leave_screen[game_status], TRUE); /* store */
722 void FadeSetNextScreen()
724 fading = menu.next_screen;
726 // (do not overwrite fade mode set by FadeSetEnterScreen)
727 // FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
730 void FadeSetLeaveScreen()
732 FadeSetLeaveNext(menu.leave_screen[game_status], FALSE); /* recall */
735 void FadeSetFromType(int type)
737 if (type & TYPE_ENTER_SCREEN)
738 FadeSetEnterScreen();
739 else if (type & TYPE_ENTER)
741 else if (type & TYPE_LEAVE)
745 void FadeSetDisabled()
747 static struct TitleFadingInfo fading_none = { FADE_MODE_NONE, -1, -1, -1 };
749 fading = fading_none;
752 void FadeSkipNextFadeIn()
754 FadeExt(0, FADE_MODE_SKIP_FADE_IN, FADE_TYPE_SKIP);
757 void FadeSkipNextFadeOut()
759 FadeExt(0, FADE_MODE_SKIP_FADE_OUT, FADE_TYPE_SKIP);
762 void SetWindowBackgroundImageIfDefined(int graphic)
764 if (graphic_info[graphic].bitmap)
765 SetWindowBackgroundBitmap(graphic_info[graphic].bitmap);
768 void SetMainBackgroundImageIfDefined(int graphic)
770 if (graphic_info[graphic].bitmap)
771 SetMainBackgroundBitmap(graphic_info[graphic].bitmap);
774 void SetDoorBackgroundImageIfDefined(int graphic)
776 if (graphic_info[graphic].bitmap)
777 SetDoorBackgroundBitmap(graphic_info[graphic].bitmap);
780 void SetWindowBackgroundImage(int graphic)
782 SetWindowBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
783 graphic_info[graphic].bitmap ?
784 graphic_info[graphic].bitmap :
785 graphic_info[IMG_BACKGROUND].bitmap);
788 void SetMainBackgroundImage(int graphic)
790 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
791 graphic_info[graphic].bitmap ?
792 graphic_info[graphic].bitmap :
793 graphic_info[IMG_BACKGROUND].bitmap);
796 void SetDoorBackgroundImage(int graphic)
798 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
799 graphic_info[graphic].bitmap ?
800 graphic_info[graphic].bitmap :
801 graphic_info[IMG_BACKGROUND].bitmap);
804 void SetPanelBackground()
806 struct GraphicInfo *gfx = &graphic_info[IMG_BACKGROUND_PANEL];
808 BlitBitmapTiled(gfx->bitmap, bitmap_db_panel, gfx->src_x, gfx->src_y,
809 gfx->width, gfx->height, 0, 0, DXSIZE, DYSIZE);
811 SetDoorBackgroundBitmap(bitmap_db_panel);
814 void DrawBackground(int x, int y, int width, int height)
816 /* "drawto" might still point to playfield buffer here (hall of fame) */
817 ClearRectangleOnBackground(backbuffer, x, y, width, height);
819 if (IN_GFX_FIELD_FULL(x, y))
820 redraw_mask |= REDRAW_FIELD;
821 else if (IN_GFX_DOOR_1(x, y))
822 redraw_mask |= REDRAW_DOOR_1;
823 else if (IN_GFX_DOOR_2(x, y))
824 redraw_mask |= REDRAW_DOOR_2;
825 else if (IN_GFX_DOOR_3(x, y))
826 redraw_mask |= REDRAW_DOOR_3;
829 void DrawBackgroundForFont(int x, int y, int width, int height, int font_nr)
831 struct FontBitmapInfo *font = getFontBitmapInfo(font_nr);
833 if (font->bitmap == NULL)
836 DrawBackground(x, y, width, height);
839 void DrawBackgroundForGraphic(int x, int y, int width, int height, int graphic)
841 struct GraphicInfo *g = &graphic_info[graphic];
843 if (g->bitmap == NULL)
846 DrawBackground(x, y, width, height);
851 /* !!! "drawto" might still point to playfield buffer here (see above) !!! */
852 /* (when entering hall of fame after playing) */
853 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
855 /* !!! maybe this should be done before clearing the background !!! */
856 if (game_status == GAME_MODE_PLAYING)
858 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
859 SetDrawtoField(DRAW_FIELDBUFFER);
862 SetDrawtoField(DRAW_BACKBUFFER);
865 void MarkTileDirty(int x, int y)
867 redraw_mask |= REDRAW_FIELD;
870 void SetBorderElement()
874 BorderElement = EL_EMPTY;
876 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
878 for (x = 0; x < lev_fieldx; x++)
880 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
881 BorderElement = EL_STEELWALL;
883 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
889 void FloodFillLevel(int from_x, int from_y, int fill_element,
890 short field[MAX_LEV_FIELDX][MAX_LEV_FIELDY],
891 int max_fieldx, int max_fieldy)
895 static int check[4][2] = { { -1, 0 }, { 0, -1 }, { 1, 0 }, { 0, 1 } };
896 static int safety = 0;
898 /* check if starting field still has the desired content */
899 if (field[from_x][from_y] == fill_element)
904 if (safety > max_fieldx * max_fieldy)
905 Error(ERR_EXIT, "Something went wrong in 'FloodFill()'. Please debug.");
907 old_element = field[from_x][from_y];
908 field[from_x][from_y] = fill_element;
910 for (i = 0; i < 4; i++)
912 x = from_x + check[i][0];
913 y = from_y + check[i][1];
915 if (IN_FIELD(x, y, max_fieldx, max_fieldy) && field[x][y] == old_element)
916 FloodFillLevel(x, y, fill_element, field, max_fieldx, max_fieldy);
922 void SetRandomAnimationValue(int x, int y)
924 gfx.anim_random_frame = GfxRandom[x][y];
927 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
929 /* animation synchronized with global frame counter, not move position */
930 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
931 sync_frame = FrameCounter;
933 return getAnimationFrame(graphic_info[graphic].anim_frames,
934 graphic_info[graphic].anim_delay,
935 graphic_info[graphic].anim_mode,
936 graphic_info[graphic].anim_start_frame,
940 void getSizedGraphicSourceExt(int graphic, int frame, int tilesize,
941 Bitmap **bitmap, int *x, int *y,
942 boolean get_backside)
944 struct GraphicInfo *g = &graphic_info[graphic];
945 Bitmap *src_bitmap = g->bitmap;
946 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
947 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
948 int tilesize_capped = MIN(MAX(1, tilesize), TILESIZE);
950 // if no in-game graphics defined, always use standard graphic size
951 if (g->bitmaps[IMG_BITMAP_GAME] == NULL)
954 if (tilesize == gfx.standard_tile_size)
955 src_bitmap = g->bitmaps[IMG_BITMAP_STANDARD];
956 else if (tilesize == game.tile_size)
957 src_bitmap = g->bitmaps[IMG_BITMAP_GAME];
959 src_bitmap = g->bitmaps[IMG_BITMAP_1x1 - log_2(tilesize_capped)];
961 if (g->offset_y == 0) /* frames are ordered horizontally */
963 int max_width = g->anim_frames_per_line * g->width;
964 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
966 src_x = pos % max_width;
967 src_y = src_y % g->height + pos / max_width * g->height;
969 else if (g->offset_x == 0) /* frames are ordered vertically */
971 int max_height = g->anim_frames_per_line * g->height;
972 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
974 src_x = src_x % g->width + pos / max_height * g->width;
975 src_y = pos % max_height;
977 else /* frames are ordered diagonally */
979 src_x = src_x + frame * g->offset_x;
980 src_y = src_y + frame * g->offset_y;
983 *bitmap = src_bitmap;
984 *x = src_x * tilesize / TILESIZE;
985 *y = src_y * tilesize / TILESIZE;
988 void getFixedGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
989 int *x, int *y, boolean get_backside)
991 getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y,
995 void getSizedGraphicSource(int graphic, int frame, int tilesize,
996 Bitmap **bitmap, int *x, int *y)
998 getSizedGraphicSourceExt(graphic, frame, tilesize, bitmap, x, y, FALSE);
1001 void getFixedGraphicSource(int graphic, int frame,
1002 Bitmap **bitmap, int *x, int *y)
1004 getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y, FALSE);
1007 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1009 getSizedGraphicSource(graphic, 0, MINI_TILESIZE, bitmap, x, y);
1012 inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1013 int *x, int *y, boolean get_backside)
1015 struct GraphicInfo *g = &graphic_info[graphic];
1016 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
1017 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
1019 if (TILESIZE_VAR != TILESIZE)
1020 return getSizedGraphicSourceExt(graphic, frame, TILESIZE_VAR, bitmap, x, y,
1023 *bitmap = g->bitmap;
1025 if (g->offset_y == 0) /* frames are ordered horizontally */
1027 int max_width = g->anim_frames_per_line * g->width;
1028 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
1030 *x = pos % max_width;
1031 *y = src_y % g->height + pos / max_width * g->height;
1033 else if (g->offset_x == 0) /* frames are ordered vertically */
1035 int max_height = g->anim_frames_per_line * g->height;
1036 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
1038 *x = src_x % g->width + pos / max_height * g->width;
1039 *y = pos % max_height;
1041 else /* frames are ordered diagonally */
1043 *x = src_x + frame * g->offset_x;
1044 *y = src_y + frame * g->offset_y;
1048 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
1050 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
1053 void DrawGraphic(int x, int y, int graphic, int frame)
1056 if (!IN_SCR_FIELD(x, y))
1058 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1059 printf("DrawGraphic(): This should never happen!\n");
1064 DrawGraphicExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR, graphic,
1067 MarkTileDirty(x, y);
1070 void DrawFixedGraphic(int x, int y, int graphic, int frame)
1073 if (!IN_SCR_FIELD(x, y))
1075 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1076 printf("DrawGraphic(): This should never happen!\n");
1081 DrawFixedGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic,
1083 MarkTileDirty(x, y);
1086 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1092 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1094 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX_VAR, TILEY_VAR, x, y);
1097 void DrawFixedGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1103 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1104 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
1107 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
1110 if (!IN_SCR_FIELD(x, y))
1112 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1113 printf("DrawGraphicThruMask(): This should never happen!\n");
1118 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
1121 MarkTileDirty(x, y);
1124 void DrawFixedGraphicThruMask(int x, int y, int graphic, int frame)
1127 if (!IN_SCR_FIELD(x, y))
1129 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1130 printf("DrawGraphicThruMask(): This should never happen!\n");
1135 DrawFixedGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
1137 MarkTileDirty(x, y);
1140 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
1146 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1148 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX_VAR, TILEY_VAR,
1152 void DrawFixedGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y,
1153 int graphic, int frame)
1155 struct GraphicInfo *g = &graphic_info[graphic];
1159 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1161 BlitBitmapMasked(src_bitmap, d, src_x, src_y, g->width, g->height,
1165 void DrawSizedGraphic(int x, int y, int graphic, int frame, int tilesize)
1167 DrawSizedGraphicExt(drawto, SX + x * tilesize, SY + y * tilesize, graphic,
1169 MarkTileDirty(x / tilesize, y / tilesize);
1172 void DrawSizedGraphicExt(DrawBuffer *d, int x, int y, int graphic, int frame,
1178 getSizedGraphicSource(graphic, frame, tilesize, &src_bitmap, &src_x, &src_y);
1179 BlitBitmap(src_bitmap, d, src_x, src_y, tilesize, tilesize, x, y);
1182 void DrawMiniGraphic(int x, int y, int graphic)
1184 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
1185 MarkTileDirty(x / 2, y / 2);
1188 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
1193 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1194 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
1197 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
1198 int graphic, int frame,
1199 int cut_mode, int mask_mode)
1204 int width = TILEX, height = TILEY;
1207 if (dx || dy) /* shifted graphic */
1209 if (x < BX1) /* object enters playfield from the left */
1216 else if (x > BX2) /* object enters playfield from the right */
1222 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
1228 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
1230 else if (dx) /* general horizontal movement */
1231 MarkTileDirty(x + SIGN(dx), y);
1233 if (y < BY1) /* object enters playfield from the top */
1235 if (cut_mode==CUT_BELOW) /* object completely above top border */
1243 else if (y > BY2) /* object enters playfield from the bottom */
1249 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
1255 else if (dy > 0 && cut_mode == CUT_ABOVE)
1257 if (y == BY2) /* object completely above bottom border */
1263 MarkTileDirty(x, y + 1);
1264 } /* object leaves playfield to the bottom */
1265 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1267 else if (dy) /* general vertical movement */
1268 MarkTileDirty(x, y + SIGN(dy));
1272 if (!IN_SCR_FIELD(x, y))
1274 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1275 printf("DrawGraphicShifted(): This should never happen!\n");
1280 width = width * TILESIZE_VAR / TILESIZE;
1281 height = height * TILESIZE_VAR / TILESIZE;
1282 cx = cx * TILESIZE_VAR / TILESIZE;
1283 cy = cy * TILESIZE_VAR / TILESIZE;
1284 dx = dx * TILESIZE_VAR / TILESIZE;
1285 dy = dy * TILESIZE_VAR / TILESIZE;
1287 if (width > 0 && height > 0)
1289 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1294 dst_x = FX + x * TILEX_VAR + dx;
1295 dst_y = FY + y * TILEY_VAR + dy;
1297 if (mask_mode == USE_MASKING)
1298 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1301 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1304 MarkTileDirty(x, y);
1308 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
1309 int graphic, int frame,
1310 int cut_mode, int mask_mode)
1315 int width = TILEX_VAR, height = TILEY_VAR;
1318 int x2 = x + SIGN(dx);
1319 int y2 = y + SIGN(dy);
1321 /* movement with two-tile animations must be sync'ed with movement position,
1322 not with current GfxFrame (which can be higher when using slow movement) */
1323 int anim_pos = (dx ? ABS(dx) : ABS(dy));
1324 int anim_frames = graphic_info[graphic].anim_frames;
1326 /* (we also need anim_delay here for movement animations with less frames) */
1327 int anim_delay = graphic_info[graphic].anim_delay;
1328 int sync_frame = anim_pos * anim_frames * anim_delay / TILESIZE;
1330 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
1331 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
1333 /* re-calculate animation frame for two-tile movement animation */
1334 frame = getGraphicAnimationFrame(graphic, sync_frame);
1336 /* check if movement start graphic inside screen area and should be drawn */
1337 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
1339 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
1341 dst_x = FX + x1 * TILEX_VAR;
1342 dst_y = FY + y1 * TILEY_VAR;
1344 if (mask_mode == USE_MASKING)
1345 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1348 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1351 MarkTileDirty(x1, y1);
1354 /* check if movement end graphic inside screen area and should be drawn */
1355 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
1357 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
1359 dst_x = FX + x2 * TILEX_VAR;
1360 dst_y = FY + y2 * TILEY_VAR;
1362 if (mask_mode == USE_MASKING)
1363 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1366 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1369 MarkTileDirty(x2, y2);
1373 static void DrawGraphicShifted(int x, int y, int dx, int dy,
1374 int graphic, int frame,
1375 int cut_mode, int mask_mode)
1379 DrawGraphic(x, y, graphic, frame);
1384 if (graphic_info[graphic].double_movement) /* EM style movement images */
1385 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1387 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1390 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1391 int frame, int cut_mode)
1393 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
1396 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1397 int cut_mode, int mask_mode)
1399 int lx = LEVELX(x), ly = LEVELY(y);
1403 if (IN_LEV_FIELD(lx, ly))
1405 SetRandomAnimationValue(lx, ly);
1407 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
1408 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1410 /* do not use double (EM style) movement graphic when not moving */
1411 if (graphic_info[graphic].double_movement && !dx && !dy)
1413 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
1414 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1417 else /* border element */
1419 graphic = el2img(element);
1420 frame = getGraphicAnimationFrame(graphic, -1);
1423 if (element == EL_EXPANDABLE_WALL)
1425 boolean left_stopped = FALSE, right_stopped = FALSE;
1427 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1428 left_stopped = TRUE;
1429 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1430 right_stopped = TRUE;
1432 if (left_stopped && right_stopped)
1434 else if (left_stopped)
1436 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1437 frame = graphic_info[graphic].anim_frames - 1;
1439 else if (right_stopped)
1441 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1442 frame = graphic_info[graphic].anim_frames - 1;
1447 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1448 else if (mask_mode == USE_MASKING)
1449 DrawGraphicThruMask(x, y, graphic, frame);
1451 DrawGraphic(x, y, graphic, frame);
1454 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1455 int cut_mode, int mask_mode)
1457 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1458 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1459 cut_mode, mask_mode);
1462 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1465 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1468 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1471 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1474 void DrawLevelElementThruMask(int x, int y, int element)
1476 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1479 void DrawLevelFieldThruMask(int x, int y)
1481 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1484 /* !!! implementation of quicksand is totally broken !!! */
1485 #define IS_CRUMBLED_TILE(x, y, e) \
1486 (GFX_CRUMBLED(e) && (!IN_LEV_FIELD(x, y) || \
1487 !IS_MOVING(x, y) || \
1488 (e) == EL_QUICKSAND_EMPTYING || \
1489 (e) == EL_QUICKSAND_FAST_EMPTYING))
1491 static void DrawLevelFieldCrumbledInnerCorners(int x, int y, int dx, int dy,
1496 int width, height, cx, cy;
1497 int sx = SCREENX(x), sy = SCREENY(y);
1498 int crumbled_border_size = graphic_info[graphic].border_size;
1501 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1503 for (i = 1; i < 4; i++)
1505 int dxx = (i & 1 ? dx : 0);
1506 int dyy = (i & 2 ? dy : 0);
1509 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1512 /* check if neighbour field is of same crumble type */
1513 boolean same = (IS_CRUMBLED_TILE(xx, yy, element) &&
1514 graphic_info[graphic].class ==
1515 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class);
1517 /* return if check prevents inner corner */
1518 if (same == (dxx == dx && dyy == dy))
1522 /* if we reach this point, we have an inner corner */
1524 getGraphicSource(graphic, 1, &src_bitmap, &src_x, &src_y);
1526 width = crumbled_border_size * TILESIZE_VAR / TILESIZE;
1527 height = crumbled_border_size * TILESIZE_VAR / TILESIZE;
1528 cx = (dx > 0 ? TILESIZE_VAR - width : 0);
1529 cy = (dy > 0 ? TILESIZE_VAR - height : 0);
1531 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1532 width, height, FX + sx * TILEX_VAR + cx, FY + sy * TILEY_VAR + cy);
1535 static void DrawLevelFieldCrumbledBorders(int x, int y, int graphic, int frame,
1540 int width, height, bx, by, cx, cy;
1541 int sx = SCREENX(x), sy = SCREENY(y);
1542 int crumbled_border_size = graphic_info[graphic].border_size;
1543 int crumbled_border_size_var = crumbled_border_size * TILESIZE_VAR / TILESIZE;
1544 int crumbled_border_pos_var = TILESIZE_VAR - crumbled_border_size_var;
1547 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1549 /* draw simple, sloppy, non-corner-accurate crumbled border */
1551 width = (dir == 1 || dir == 2 ? crumbled_border_size_var : TILESIZE_VAR);
1552 height = (dir == 0 || dir == 3 ? crumbled_border_size_var : TILESIZE_VAR);
1553 cx = (dir == 2 ? crumbled_border_pos_var : 0);
1554 cy = (dir == 3 ? crumbled_border_pos_var : 0);
1556 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy, width, height,
1557 FX + sx * TILEX_VAR + cx,
1558 FY + sy * TILEY_VAR + cy);
1560 /* (remaining middle border part must be at least as big as corner part) */
1561 if (!(graphic_info[graphic].style & STYLE_ACCURATE_BORDERS) ||
1562 crumbled_border_size >= TILESIZE / 3)
1565 /* correct corners of crumbled border, if needed */
1567 for (i = -1; i <= 1; i += 2)
1569 int xx = x + (dir == 0 || dir == 3 ? i : 0);
1570 int yy = y + (dir == 1 || dir == 2 ? i : 0);
1571 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1574 /* check if neighbour field is of same crumble type */
1575 if (IS_CRUMBLED_TILE(xx, yy, element) &&
1576 graphic_info[graphic].class ==
1577 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1579 /* no crumbled corner, but continued crumbled border */
1581 int c1 = (dir == 2 || dir == 3 ? crumbled_border_pos_var : 0);
1582 int c2 = (i == 1 ? crumbled_border_pos_var : 0);
1583 int b1 = (i == 1 ? crumbled_border_size_var :
1584 TILESIZE_VAR - 2 * crumbled_border_size_var);
1586 width = crumbled_border_size_var;
1587 height = crumbled_border_size_var;
1589 if (dir == 1 || dir == 2)
1604 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
1606 FX + sx * TILEX_VAR + cx,
1607 FY + sy * TILEY_VAR + cy);
1612 static void DrawLevelFieldCrumbledExt(int x, int y, int graphic, int frame)
1614 int sx = SCREENX(x), sy = SCREENY(y);
1617 static int xy[4][2] =
1625 if (!IN_LEV_FIELD(x, y))
1628 element = TILE_GFX_ELEMENT(x, y);
1630 /* crumble field itself */
1631 if (IS_CRUMBLED_TILE(x, y, element))
1633 if (!IN_SCR_FIELD(sx, sy))
1636 for (i = 0; i < 4; i++)
1638 int xx = x + xy[i][0];
1639 int yy = y + xy[i][1];
1641 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1644 /* check if neighbour field is of same crumble type */
1645 if (IS_CRUMBLED_TILE(xx, yy, element) &&
1646 graphic_info[graphic].class ==
1647 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1650 DrawLevelFieldCrumbledBorders(x, y, graphic, frame, i);
1653 if ((graphic_info[graphic].style & STYLE_INNER_CORNERS) &&
1654 graphic_info[graphic].anim_frames == 2)
1656 for (i = 0; i < 4; i++)
1658 int dx = (i & 1 ? +1 : -1);
1659 int dy = (i & 2 ? +1 : -1);
1661 DrawLevelFieldCrumbledInnerCorners(x, y, dx, dy, graphic);
1665 MarkTileDirty(sx, sy);
1667 else /* center field not crumbled -- crumble neighbour fields */
1669 for (i = 0; i < 4; i++)
1671 int xx = x + xy[i][0];
1672 int yy = y + xy[i][1];
1673 int sxx = sx + xy[i][0];
1674 int syy = sy + xy[i][1];
1676 if (!IN_LEV_FIELD(xx, yy) ||
1677 !IN_SCR_FIELD(sxx, syy))
1680 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
1683 element = TILE_GFX_ELEMENT(xx, yy);
1685 if (!IS_CRUMBLED_TILE(xx, yy, element))
1688 graphic = el_act2crm(element, ACTION_DEFAULT);
1690 DrawLevelFieldCrumbledBorders(xx, yy, graphic, 0, 3 - i);
1692 MarkTileDirty(sxx, syy);
1697 void DrawLevelFieldCrumbled(int x, int y)
1701 if (!IN_LEV_FIELD(x, y))
1704 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1705 GfxElement[x][y] != EL_UNDEFINED &&
1706 GFX_CRUMBLED(GfxElement[x][y]))
1708 DrawLevelFieldCrumbledDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
1713 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
1715 DrawLevelFieldCrumbledExt(x, y, graphic, 0);
1718 void DrawLevelFieldCrumbledDigging(int x, int y, int direction,
1721 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1722 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1723 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1724 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1725 int sx = SCREENX(x), sy = SCREENY(y);
1727 DrawGraphic(sx, sy, graphic1, frame1);
1728 DrawLevelFieldCrumbledExt(x, y, graphic2, frame2);
1731 void DrawLevelFieldCrumbledNeighbours(int x, int y)
1733 int sx = SCREENX(x), sy = SCREENY(y);
1734 static int xy[4][2] =
1743 for (i = 0; i < 4; i++)
1745 int xx = x + xy[i][0];
1746 int yy = y + xy[i][1];
1747 int sxx = sx + xy[i][0];
1748 int syy = sy + xy[i][1];
1750 if (!IN_LEV_FIELD(xx, yy) ||
1751 !IN_SCR_FIELD(sxx, syy) ||
1752 !GFX_CRUMBLED(Feld[xx][yy]) ||
1756 DrawLevelField(xx, yy);
1760 static int getBorderElement(int x, int y)
1764 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1765 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1766 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1767 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1768 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1769 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1770 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1772 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1773 int steel_position = (x == -1 && y == -1 ? 0 :
1774 x == lev_fieldx && y == -1 ? 1 :
1775 x == -1 && y == lev_fieldy ? 2 :
1776 x == lev_fieldx && y == lev_fieldy ? 3 :
1777 x == -1 || x == lev_fieldx ? 4 :
1778 y == -1 || y == lev_fieldy ? 5 : 6);
1780 return border[steel_position][steel_type];
1783 void DrawScreenElement(int x, int y, int element)
1785 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1786 DrawLevelFieldCrumbled(LEVELX(x), LEVELY(y));
1789 void DrawLevelElement(int x, int y, int element)
1791 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1792 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1795 void DrawScreenField(int x, int y)
1797 int lx = LEVELX(x), ly = LEVELY(y);
1798 int element, content;
1800 if (!IN_LEV_FIELD(lx, ly))
1802 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1805 element = getBorderElement(lx, ly);
1807 DrawScreenElement(x, y, element);
1812 element = Feld[lx][ly];
1813 content = Store[lx][ly];
1815 if (IS_MOVING(lx, ly))
1817 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1818 boolean cut_mode = NO_CUTTING;
1820 if (element == EL_QUICKSAND_EMPTYING ||
1821 element == EL_QUICKSAND_FAST_EMPTYING ||
1822 element == EL_MAGIC_WALL_EMPTYING ||
1823 element == EL_BD_MAGIC_WALL_EMPTYING ||
1824 element == EL_DC_MAGIC_WALL_EMPTYING ||
1825 element == EL_AMOEBA_DROPPING)
1826 cut_mode = CUT_ABOVE;
1827 else if (element == EL_QUICKSAND_FILLING ||
1828 element == EL_QUICKSAND_FAST_FILLING ||
1829 element == EL_MAGIC_WALL_FILLING ||
1830 element == EL_BD_MAGIC_WALL_FILLING ||
1831 element == EL_DC_MAGIC_WALL_FILLING)
1832 cut_mode = CUT_BELOW;
1834 if (cut_mode == CUT_ABOVE)
1835 DrawScreenElement(x, y, element);
1837 DrawScreenElement(x, y, EL_EMPTY);
1840 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1841 else if (cut_mode == NO_CUTTING)
1842 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1845 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1847 if (cut_mode == CUT_BELOW &&
1848 IN_LEV_FIELD(lx, ly + 1) && IN_SCR_FIELD(x, y + 1))
1849 DrawLevelElement(lx, ly + 1, element);
1852 if (content == EL_ACID)
1854 int dir = MovDir[lx][ly];
1855 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
1856 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
1858 DrawLevelElementThruMask(newlx, newly, EL_ACID);
1861 else if (IS_BLOCKED(lx, ly))
1866 boolean cut_mode = NO_CUTTING;
1867 int element_old, content_old;
1869 Blocked2Moving(lx, ly, &oldx, &oldy);
1872 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1873 MovDir[oldx][oldy] == MV_RIGHT);
1875 element_old = Feld[oldx][oldy];
1876 content_old = Store[oldx][oldy];
1878 if (element_old == EL_QUICKSAND_EMPTYING ||
1879 element_old == EL_QUICKSAND_FAST_EMPTYING ||
1880 element_old == EL_MAGIC_WALL_EMPTYING ||
1881 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1882 element_old == EL_DC_MAGIC_WALL_EMPTYING ||
1883 element_old == EL_AMOEBA_DROPPING)
1884 cut_mode = CUT_ABOVE;
1886 DrawScreenElement(x, y, EL_EMPTY);
1889 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1891 else if (cut_mode == NO_CUTTING)
1892 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1895 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1898 else if (IS_DRAWABLE(element))
1899 DrawScreenElement(x, y, element);
1901 DrawScreenElement(x, y, EL_EMPTY);
1904 void DrawLevelField(int x, int y)
1906 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1907 DrawScreenField(SCREENX(x), SCREENY(y));
1908 else if (IS_MOVING(x, y))
1912 Moving2Blocked(x, y, &newx, &newy);
1913 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1914 DrawScreenField(SCREENX(newx), SCREENY(newy));
1916 else if (IS_BLOCKED(x, y))
1920 Blocked2Moving(x, y, &oldx, &oldy);
1921 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1922 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1926 void DrawSizedElement(int x, int y, int element, int tilesize)
1930 graphic = el2edimg(element);
1931 DrawSizedGraphic(x, y, graphic, 0, tilesize);
1934 void DrawMiniElement(int x, int y, int element)
1938 graphic = el2edimg(element);
1939 DrawMiniGraphic(x, y, graphic);
1942 void DrawSizedElementOrWall(int sx, int sy, int scroll_x, int scroll_y,
1945 int x = sx + scroll_x, y = sy + scroll_y;
1947 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1948 DrawSizedElement(sx, sy, EL_EMPTY, tilesize);
1949 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1950 DrawSizedElement(sx, sy, Feld[x][y], tilesize);
1952 DrawSizedGraphic(sx, sy, el2edimg(getBorderElement(x, y)), 0, tilesize);
1955 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1957 int x = sx + scroll_x, y = sy + scroll_y;
1959 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1960 DrawMiniElement(sx, sy, EL_EMPTY);
1961 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1962 DrawMiniElement(sx, sy, Feld[x][y]);
1964 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1967 void DrawEnvelopeBackgroundTiles(int graphic, int startx, int starty,
1968 int x, int y, int xsize, int ysize,
1969 int tile_width, int tile_height)
1973 int dst_x = startx + x * tile_width;
1974 int dst_y = starty + y * tile_height;
1975 int width = graphic_info[graphic].width;
1976 int height = graphic_info[graphic].height;
1977 int inner_width_raw = MAX(width - 2 * tile_width, tile_width);
1978 int inner_height_raw = MAX(height - 2 * tile_height, tile_height);
1979 int inner_width = inner_width_raw - (inner_width_raw % tile_width);
1980 int inner_height = inner_height_raw - (inner_height_raw % tile_height);
1981 int inner_sx = (width >= 3 * tile_width ? tile_width : 0);
1982 int inner_sy = (height >= 3 * tile_height ? tile_height : 0);
1983 boolean draw_masked = graphic_info[graphic].draw_masked;
1985 getFixedGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1987 if (src_bitmap == NULL || width < tile_width || height < tile_height)
1989 ClearRectangle(drawto, dst_x, dst_y, tile_width, tile_height);
1993 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - tile_width :
1994 inner_sx + (x - 1) * tile_width % inner_width);
1995 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - tile_height :
1996 inner_sy + (y - 1) * tile_height % inner_height);
1999 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
2002 BlitBitmap(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
2006 void DrawEnvelopeBackground(int graphic, int startx, int starty,
2007 int x, int y, int xsize, int ysize, int font_nr)
2009 int font_width = getFontWidth(font_nr);
2010 int font_height = getFontHeight(font_nr);
2012 DrawEnvelopeBackgroundTiles(graphic, startx, starty, x, y, xsize, ysize,
2013 font_width, font_height);
2016 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
2018 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2019 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2020 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2021 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2022 boolean no_delay = (tape.warp_forward);
2023 unsigned int anim_delay = 0;
2024 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
2025 int anim_delay_value = (no_delay ? 0 : frame_delay_value) / 2;
2026 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
2027 int font_width = getFontWidth(font_nr);
2028 int font_height = getFontHeight(font_nr);
2029 int max_xsize = level.envelope[envelope_nr].xsize;
2030 int max_ysize = level.envelope[envelope_nr].ysize;
2031 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
2032 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
2033 int xend = max_xsize;
2034 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
2035 int xstep = (xstart < xend ? 1 : 0);
2036 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2038 int end = MAX(xend - xstart, yend - ystart);
2041 for (i = start; i <= end; i++)
2043 int last_frame = end; // last frame of this "for" loop
2044 int x = xstart + i * xstep;
2045 int y = ystart + i * ystep;
2046 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2047 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2048 int sx = SX + (SXSIZE - xsize * font_width) / 2;
2049 int sy = SY + (SYSIZE - ysize * font_height) / 2;
2052 SetDrawtoField(DRAW_FIELDBUFFER);
2054 BlitScreenToBitmap(backbuffer);
2056 SetDrawtoField(DRAW_BACKBUFFER);
2058 for (yy = 0; yy < ysize; yy++)
2059 for (xx = 0; xx < xsize; xx++)
2060 DrawEnvelopeBackground(graphic, sx, sy, xx, yy, xsize, ysize, font_nr);
2062 DrawTextBuffer(sx + font_width, sy + font_height,
2063 level.envelope[envelope_nr].text, font_nr, max_xsize,
2064 xsize - 2, ysize - 2, 0, mask_mode,
2065 level.envelope[envelope_nr].autowrap,
2066 level.envelope[envelope_nr].centered, FALSE);
2068 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2071 SkipUntilDelayReached(&anim_delay, anim_delay_value, &i, last_frame);
2075 void ShowEnvelope(int envelope_nr)
2077 int element = EL_ENVELOPE_1 + envelope_nr;
2078 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2079 int sound_opening = element_info[element].sound[ACTION_OPENING];
2080 int sound_closing = element_info[element].sound[ACTION_CLOSING];
2081 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2082 boolean no_delay = (tape.warp_forward);
2083 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
2084 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
2085 int anim_mode = graphic_info[graphic].anim_mode;
2086 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2087 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2089 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
2091 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2093 if (anim_mode == ANIM_DEFAULT)
2094 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
2096 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
2099 Delay(wait_delay_value);
2101 WaitForEventToContinue();
2103 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2105 if (anim_mode != ANIM_NONE)
2106 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
2108 if (anim_mode == ANIM_DEFAULT)
2109 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
2111 game.envelope_active = FALSE;
2113 SetDrawtoField(DRAW_FIELDBUFFER);
2115 redraw_mask |= REDRAW_FIELD;
2119 static void setRequestCenterPosition(int *x, int *y)
2121 int sx_center = (request.x != -1 ? request.x : SX + SXSIZE / 2);
2122 int sy_center = (request.y != -1 ? request.y : SY + SYSIZE / 2);
2128 static void setRequestPosition(int *x, int *y, boolean add_border_size)
2130 int border_size = request.border_size;
2131 int sx_center, sy_center;
2134 setRequestCenterPosition(&sx_center, &sy_center);
2136 sx = sx_center - request.width / 2;
2137 sy = sy_center - request.height / 2;
2139 if (add_border_size)
2149 void DrawEnvelopeRequest(char *text)
2151 char *text_final = text;
2152 char *text_door_style = NULL;
2153 int graphic = IMG_BACKGROUND_REQUEST;
2154 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2155 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2156 int font_nr = FONT_REQUEST;
2157 int font_width = getFontWidth(font_nr);
2158 int font_height = getFontHeight(font_nr);
2159 int border_size = request.border_size;
2160 int line_spacing = request.line_spacing;
2161 int line_height = font_height + line_spacing;
2162 int text_width = request.width - 2 * border_size;
2163 int text_height = request.height - 2 * border_size;
2164 int line_length = text_width / font_width;
2165 int max_lines = text_height / line_height;
2166 int width = request.width;
2167 int height = request.height;
2168 int tile_size = request.step_offset;
2169 int x_steps = width / tile_size;
2170 int y_steps = height / tile_size;
2174 if (request.wrap_single_words)
2176 char *src_text_ptr, *dst_text_ptr;
2178 text_door_style = checked_malloc(2 * strlen(text) + 1);
2180 src_text_ptr = text;
2181 dst_text_ptr = text_door_style;
2183 while (*src_text_ptr)
2185 if (*src_text_ptr == ' ' ||
2186 *src_text_ptr == '?' ||
2187 *src_text_ptr == '!')
2188 *dst_text_ptr++ = '\n';
2190 if (*src_text_ptr != ' ')
2191 *dst_text_ptr++ = *src_text_ptr;
2196 *dst_text_ptr = '\0';
2198 text_final = text_door_style;
2201 setRequestPosition(&sx, &sy, FALSE);
2203 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
2205 for (y = 0; y < y_steps; y++)
2206 for (x = 0; x < x_steps; x++)
2207 DrawEnvelopeBackgroundTiles(graphic, sx, sy,
2208 x, y, x_steps, y_steps,
2209 tile_size, tile_size);
2211 DrawTextBuffer(sx + border_size, sy + border_size, text_final, font_nr,
2212 line_length, -1, max_lines, line_spacing, mask_mode,
2213 request.autowrap, request.centered, FALSE);
2215 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2216 RedrawGadget(tool_gadget[i]);
2218 // store readily prepared envelope request for later use when animating
2219 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2221 if (text_door_style)
2222 free(text_door_style);
2225 void AnimateEnvelopeRequest(int anim_mode, int action)
2227 int graphic = IMG_BACKGROUND_REQUEST;
2228 boolean draw_masked = graphic_info[graphic].draw_masked;
2229 int delay_value_normal = request.step_delay;
2230 int delay_value_fast = delay_value_normal / 2;
2231 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2232 boolean no_delay = (tape.warp_forward);
2233 int delay_value = (ffwd_delay ? delay_value_fast : delay_value_normal);
2234 int anim_delay_value = (no_delay ? 0 : delay_value + 500 * 0) / 2;
2235 unsigned int anim_delay = 0;
2237 int width = request.width;
2238 int height = request.height;
2239 int tile_size = request.step_offset;
2240 int max_xsize = width / tile_size;
2241 int max_ysize = height / tile_size;
2242 int max_xsize_inner = max_xsize - 2;
2243 int max_ysize_inner = max_ysize - 2;
2245 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize_inner : 0);
2246 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize_inner : 0);
2247 int xend = max_xsize_inner;
2248 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize_inner : 0);
2249 int xstep = (xstart < xend ? 1 : 0);
2250 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2252 int end = MAX(xend - xstart, yend - ystart);
2255 if (setup.quick_doors)
2263 if (action == ACTION_OPENING)
2264 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2265 else if (action == ACTION_CLOSING)
2266 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2269 for (i = start; i <= end; i++)
2271 int last_frame = end; // last frame of this "for" loop
2272 int x = xstart + i * xstep;
2273 int y = ystart + i * ystep;
2274 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2275 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2276 int xsize_size_left = (xsize - 1) * tile_size;
2277 int ysize_size_top = (ysize - 1) * tile_size;
2278 int max_xsize_pos = (max_xsize - 1) * tile_size;
2279 int max_ysize_pos = (max_ysize - 1) * tile_size;
2280 int sx_center, sy_center;
2285 setRequestCenterPosition(&sx_center, &sy_center);
2287 src_x = sx_center - width / 2;
2288 src_y = sy_center - height / 2;
2289 dst_x = sx_center - xsize * tile_size / 2;
2290 dst_y = sy_center - ysize * tile_size / 2;
2292 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2294 for (yy = 0; yy < 2; yy++)
2296 for (xx = 0; xx < 2; xx++)
2298 int src_xx = src_x + xx * max_xsize_pos;
2299 int src_yy = src_y + yy * max_ysize_pos;
2300 int dst_xx = dst_x + xx * xsize_size_left;
2301 int dst_yy = dst_y + yy * ysize_size_top;
2302 int xx_size = (xx ? tile_size : xsize_size_left);
2303 int yy_size = (yy ? tile_size : ysize_size_top);
2306 BlitBitmapMasked(bitmap_db_cross, backbuffer,
2307 src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
2309 BlitBitmap(bitmap_db_cross, backbuffer,
2310 src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
2314 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2319 SkipUntilDelayReached(&anim_delay, anim_delay_value, &i, last_frame);
2324 void ShowEnvelopeRequest(char *text, unsigned int req_state, int action)
2326 int last_game_status = game_status; /* save current game status */
2327 int graphic = IMG_BACKGROUND_REQUEST;
2328 int sound_opening = SND_REQUEST_OPENING;
2329 int sound_closing = SND_REQUEST_CLOSING;
2330 int anim_mode = graphic_info[graphic].anim_mode;
2331 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2332 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2334 if (game_status == GAME_MODE_PLAYING)
2335 BlitScreenToBitmap(backbuffer);
2337 SetDrawtoField(DRAW_BACKBUFFER);
2339 // SetDrawBackgroundMask(REDRAW_NONE);
2341 if (action == ACTION_OPENING)
2343 BlitBitmap(backbuffer, bitmap_db_store, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2345 if (req_state & REQ_ASK)
2347 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2348 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2350 else if (req_state & REQ_CONFIRM)
2352 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2354 else if (req_state & REQ_PLAYER)
2356 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2357 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2358 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2359 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2362 DrawEnvelopeRequest(text);
2364 if (game_status != GAME_MODE_MAIN)
2368 /* force DOOR font inside door area */
2369 game_status = GAME_MODE_PSEUDO_DOOR;
2371 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
2373 if (action == ACTION_OPENING)
2375 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2377 if (anim_mode == ANIM_DEFAULT)
2378 AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_OPENING);
2380 AnimateEnvelopeRequest(main_anim_mode, ACTION_OPENING);
2384 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2386 if (anim_mode != ANIM_NONE)
2387 AnimateEnvelopeRequest(main_anim_mode, ACTION_CLOSING);
2389 if (anim_mode == ANIM_DEFAULT)
2390 AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_CLOSING);
2393 game.envelope_active = FALSE;
2395 game_status = last_game_status; /* restore current game status */
2397 if (action == ACTION_CLOSING)
2399 if (game_status != GAME_MODE_MAIN)
2402 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2405 // SetDrawBackgroundMask(last_draw_background_mask);
2407 redraw_mask |= REDRAW_FIELD;
2409 if (game_status == GAME_MODE_MAIN)
2414 if (action == ACTION_CLOSING &&
2415 game_status == GAME_MODE_PLAYING &&
2416 level.game_engine_type == GAME_ENGINE_TYPE_RND)
2417 SetDrawtoField(DRAW_FIELDBUFFER);
2420 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
2424 int graphic = el2preimg(element);
2426 getSizedGraphicSource(graphic, 0, tilesize, &src_bitmap, &src_x, &src_y);
2427 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
2430 void DrawLevel(int draw_background_mask)
2434 SetMainBackgroundImage(IMG_BACKGROUND_PLAYING);
2435 SetDrawBackgroundMask(draw_background_mask);
2439 for (x = BX1; x <= BX2; x++)
2440 for (y = BY1; y <= BY2; y++)
2441 DrawScreenField(x, y);
2443 redraw_mask |= REDRAW_FIELD;
2446 void DrawSizedLevel(int size_x, int size_y, int scroll_x, int scroll_y,
2451 for (x = 0; x < size_x; x++)
2452 for (y = 0; y < size_y; y++)
2453 DrawSizedElementOrWall(x, y, scroll_x, scroll_y, tilesize);
2455 redraw_mask |= REDRAW_FIELD;
2458 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
2462 for (x = 0; x < size_x; x++)
2463 for (y = 0; y < size_y; y++)
2464 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
2466 redraw_mask |= REDRAW_FIELD;
2469 static void DrawPreviewLevelPlayfieldExt(int from_x, int from_y)
2471 boolean show_level_border = (BorderElement != EL_EMPTY);
2472 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2473 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2474 int tile_size = preview.tile_size;
2475 int preview_width = preview.xsize * tile_size;
2476 int preview_height = preview.ysize * tile_size;
2477 int real_preview_xsize = MIN(level_xsize, preview.xsize);
2478 int real_preview_ysize = MIN(level_ysize, preview.ysize);
2479 int real_preview_width = real_preview_xsize * tile_size;
2480 int real_preview_height = real_preview_ysize * tile_size;
2481 int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
2482 int dst_y = SY + ALIGNED_YPOS(preview.y, preview_height, preview.valign);
2485 if (!IN_GFX_FIELD_FULL(dst_x, dst_y + preview_height - 1))
2488 DrawBackground(dst_x, dst_y, preview_width, preview_height);
2490 dst_x += (preview_width - real_preview_width) / 2;
2491 dst_y += (preview_height - real_preview_height) / 2;
2493 for (x = 0; x < real_preview_xsize; x++)
2495 for (y = 0; y < real_preview_ysize; y++)
2497 int lx = from_x + x + (show_level_border ? -1 : 0);
2498 int ly = from_y + y + (show_level_border ? -1 : 0);
2499 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
2500 getBorderElement(lx, ly));
2502 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
2503 element, tile_size);
2507 redraw_mask |= REDRAW_MICROLEVEL;
2510 #define MICROLABEL_EMPTY 0
2511 #define MICROLABEL_LEVEL_NAME 1
2512 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
2513 #define MICROLABEL_LEVEL_AUTHOR 3
2514 #define MICROLABEL_IMPORTED_FROM_HEAD 4
2515 #define MICROLABEL_IMPORTED_FROM 5
2516 #define MICROLABEL_IMPORTED_BY_HEAD 6
2517 #define MICROLABEL_IMPORTED_BY 7
2519 static int getMaxTextLength(struct TextPosInfo *pos, int font_nr)
2521 int max_text_width = SXSIZE;
2522 int font_width = getFontWidth(font_nr);
2524 if (pos->align == ALIGN_CENTER)
2525 max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
2526 else if (pos->align == ALIGN_RIGHT)
2527 max_text_width = pos->x;
2529 max_text_width = SXSIZE - pos->x;
2531 return max_text_width / font_width;
2534 static void DrawPreviewLevelLabelExt(int mode)
2536 struct TextPosInfo *pos = &menu.main.text.level_info_2;
2537 char label_text[MAX_OUTPUT_LINESIZE + 1];
2538 int max_len_label_text;
2539 int font_nr = pos->font;
2542 if (!IN_GFX_FIELD_FULL(pos->x, pos->y + getFontHeight(pos->font)))
2545 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
2546 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
2547 mode == MICROLABEL_IMPORTED_BY_HEAD)
2548 font_nr = pos->font_alt;
2550 max_len_label_text = getMaxTextLength(pos, font_nr);
2552 if (pos->size != -1)
2553 max_len_label_text = pos->size;
2555 for (i = 0; i < max_len_label_text; i++)
2556 label_text[i] = ' ';
2557 label_text[max_len_label_text] = '\0';
2559 if (strlen(label_text) > 0)
2560 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2563 (mode == MICROLABEL_LEVEL_NAME ? level.name :
2564 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
2565 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
2566 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
2567 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
2568 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
2569 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
2570 max_len_label_text);
2571 label_text[max_len_label_text] = '\0';
2573 if (strlen(label_text) > 0)
2574 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2576 redraw_mask |= REDRAW_MICROLEVEL;
2579 static void DrawPreviewLevelExt(boolean restart)
2581 static unsigned int scroll_delay = 0;
2582 static unsigned int label_delay = 0;
2583 static int from_x, from_y, scroll_direction;
2584 static int label_state, label_counter;
2585 unsigned int scroll_delay_value = preview.step_delay;
2586 boolean show_level_border = (BorderElement != EL_EMPTY);
2587 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2588 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2589 int last_game_status = game_status; /* save current game status */
2596 if (preview.anim_mode == ANIM_CENTERED)
2598 if (level_xsize > preview.xsize)
2599 from_x = (level_xsize - preview.xsize) / 2;
2600 if (level_ysize > preview.ysize)
2601 from_y = (level_ysize - preview.ysize) / 2;
2604 from_x += preview.xoffset;
2605 from_y += preview.yoffset;
2607 scroll_direction = MV_RIGHT;
2611 DrawPreviewLevelPlayfieldExt(from_x, from_y);
2612 DrawPreviewLevelLabelExt(label_state);
2614 /* initialize delay counters */
2615 DelayReached(&scroll_delay, 0);
2616 DelayReached(&label_delay, 0);
2618 if (leveldir_current->name)
2620 struct TextPosInfo *pos = &menu.main.text.level_info_1;
2621 char label_text[MAX_OUTPUT_LINESIZE + 1];
2622 int font_nr = pos->font;
2623 int max_len_label_text = getMaxTextLength(pos, font_nr);
2625 if (pos->size != -1)
2626 max_len_label_text = pos->size;
2628 strncpy(label_text, leveldir_current->name, max_len_label_text);
2629 label_text[max_len_label_text] = '\0';
2631 if (IN_GFX_FIELD_FULL(pos->x, pos->y + getFontHeight(pos->font)))
2632 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2635 game_status = last_game_status; /* restore current game status */
2640 /* scroll preview level, if needed */
2641 if (preview.anim_mode != ANIM_NONE &&
2642 (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
2643 DelayReached(&scroll_delay, scroll_delay_value))
2645 switch (scroll_direction)
2650 from_x -= preview.step_offset;
2651 from_x = (from_x < 0 ? 0 : from_x);
2654 scroll_direction = MV_UP;
2658 if (from_x < level_xsize - preview.xsize)
2660 from_x += preview.step_offset;
2661 from_x = (from_x > level_xsize - preview.xsize ?
2662 level_xsize - preview.xsize : from_x);
2665 scroll_direction = MV_DOWN;
2671 from_y -= preview.step_offset;
2672 from_y = (from_y < 0 ? 0 : from_y);
2675 scroll_direction = MV_RIGHT;
2679 if (from_y < level_ysize - preview.ysize)
2681 from_y += preview.step_offset;
2682 from_y = (from_y > level_ysize - preview.ysize ?
2683 level_ysize - preview.ysize : from_y);
2686 scroll_direction = MV_LEFT;
2693 DrawPreviewLevelPlayfieldExt(from_x, from_y);
2696 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
2697 /* redraw micro level label, if needed */
2698 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
2699 !strEqual(level.author, ANONYMOUS_NAME) &&
2700 !strEqual(level.author, leveldir_current->name) &&
2701 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
2703 int max_label_counter = 23;
2705 if (leveldir_current->imported_from != NULL &&
2706 strlen(leveldir_current->imported_from) > 0)
2707 max_label_counter += 14;
2708 if (leveldir_current->imported_by != NULL &&
2709 strlen(leveldir_current->imported_by) > 0)
2710 max_label_counter += 14;
2712 label_counter = (label_counter + 1) % max_label_counter;
2713 label_state = (label_counter >= 0 && label_counter <= 7 ?
2714 MICROLABEL_LEVEL_NAME :
2715 label_counter >= 9 && label_counter <= 12 ?
2716 MICROLABEL_LEVEL_AUTHOR_HEAD :
2717 label_counter >= 14 && label_counter <= 21 ?
2718 MICROLABEL_LEVEL_AUTHOR :
2719 label_counter >= 23 && label_counter <= 26 ?
2720 MICROLABEL_IMPORTED_FROM_HEAD :
2721 label_counter >= 28 && label_counter <= 35 ?
2722 MICROLABEL_IMPORTED_FROM :
2723 label_counter >= 37 && label_counter <= 40 ?
2724 MICROLABEL_IMPORTED_BY_HEAD :
2725 label_counter >= 42 && label_counter <= 49 ?
2726 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
2728 if (leveldir_current->imported_from == NULL &&
2729 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
2730 label_state == MICROLABEL_IMPORTED_FROM))
2731 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
2732 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
2734 DrawPreviewLevelLabelExt(label_state);
2737 game_status = last_game_status; /* restore current game status */
2740 void DrawPreviewLevelInitial()
2742 DrawPreviewLevelExt(TRUE);
2745 void DrawPreviewLevelAnimation()
2747 DrawPreviewLevelExt(FALSE);
2750 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
2751 int graphic, int sync_frame, int mask_mode)
2753 int frame = getGraphicAnimationFrame(graphic, sync_frame);
2755 if (mask_mode == USE_MASKING)
2756 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
2758 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
2761 inline void DrawFixedGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
2762 int graphic, int sync_frame,
2765 int frame = getGraphicAnimationFrame(graphic, sync_frame);
2767 if (mask_mode == USE_MASKING)
2768 DrawFixedGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
2770 DrawFixedGraphicExt(dst_bitmap, x, y, graphic, frame);
2773 inline void DrawGraphicAnimation(int x, int y, int graphic)
2775 int lx = LEVELX(x), ly = LEVELY(y);
2777 if (!IN_SCR_FIELD(x, y))
2780 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
2781 graphic, GfxFrame[lx][ly], NO_MASKING);
2783 MarkTileDirty(x, y);
2786 inline void DrawFixedGraphicAnimation(int x, int y, int graphic)
2788 int lx = LEVELX(x), ly = LEVELY(y);
2790 if (!IN_SCR_FIELD(x, y))
2793 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
2794 graphic, GfxFrame[lx][ly], NO_MASKING);
2795 MarkTileDirty(x, y);
2798 void DrawLevelGraphicAnimation(int x, int y, int graphic)
2800 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2803 void DrawLevelElementAnimation(int x, int y, int element)
2805 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2807 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2810 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
2812 int sx = SCREENX(x), sy = SCREENY(y);
2814 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2817 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2820 DrawGraphicAnimation(sx, sy, graphic);
2823 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
2824 DrawLevelFieldCrumbled(x, y);
2826 if (GFX_CRUMBLED(Feld[x][y]))
2827 DrawLevelFieldCrumbled(x, y);
2831 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
2833 int sx = SCREENX(x), sy = SCREENY(y);
2836 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2839 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2841 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2844 DrawGraphicAnimation(sx, sy, graphic);
2846 if (GFX_CRUMBLED(element))
2847 DrawLevelFieldCrumbled(x, y);
2850 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
2852 if (player->use_murphy)
2854 /* this works only because currently only one player can be "murphy" ... */
2855 static int last_horizontal_dir = MV_LEFT;
2856 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
2858 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2859 last_horizontal_dir = move_dir;
2861 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
2863 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
2865 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
2871 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
2874 static boolean equalGraphics(int graphic1, int graphic2)
2876 struct GraphicInfo *g1 = &graphic_info[graphic1];
2877 struct GraphicInfo *g2 = &graphic_info[graphic2];
2879 return (g1->bitmap == g2->bitmap &&
2880 g1->src_x == g2->src_x &&
2881 g1->src_y == g2->src_y &&
2882 g1->anim_frames == g2->anim_frames &&
2883 g1->anim_delay == g2->anim_delay &&
2884 g1->anim_mode == g2->anim_mode);
2887 void DrawAllPlayers()
2891 for (i = 0; i < MAX_PLAYERS; i++)
2892 if (stored_player[i].active)
2893 DrawPlayer(&stored_player[i]);
2896 void DrawPlayerField(int x, int y)
2898 if (!IS_PLAYER(x, y))
2901 DrawPlayer(PLAYERINFO(x, y));
2904 #define DRAW_PLAYER_OVER_PUSHED_ELEMENT 1
2906 void DrawPlayer(struct PlayerInfo *player)
2908 int jx = player->jx;
2909 int jy = player->jy;
2910 int move_dir = player->MovDir;
2911 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
2912 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
2913 int last_jx = (player->is_moving ? jx - dx : jx);
2914 int last_jy = (player->is_moving ? jy - dy : jy);
2915 int next_jx = jx + dx;
2916 int next_jy = jy + dy;
2917 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
2918 boolean player_is_opaque = FALSE;
2919 int sx = SCREENX(jx), sy = SCREENY(jy);
2920 int sxx = 0, syy = 0;
2921 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
2923 int action = ACTION_DEFAULT;
2924 int last_player_graphic = getPlayerGraphic(player, move_dir);
2925 int last_player_frame = player->Frame;
2928 /* GfxElement[][] is set to the element the player is digging or collecting;
2929 remove also for off-screen player if the player is not moving anymore */
2930 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
2931 GfxElement[jx][jy] = EL_UNDEFINED;
2933 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
2937 if (!IN_LEV_FIELD(jx, jy))
2939 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
2940 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
2941 printf("DrawPlayerField(): This should never happen!\n");
2946 if (element == EL_EXPLOSION)
2949 action = (player->is_pushing ? ACTION_PUSHING :
2950 player->is_digging ? ACTION_DIGGING :
2951 player->is_collecting ? ACTION_COLLECTING :
2952 player->is_moving ? ACTION_MOVING :
2953 player->is_snapping ? ACTION_SNAPPING :
2954 player->is_dropping ? ACTION_DROPPING :
2955 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
2957 if (player->is_waiting)
2958 move_dir = player->dir_waiting;
2960 InitPlayerGfxAnimation(player, action, move_dir);
2962 /* ----------------------------------------------------------------------- */
2963 /* draw things in the field the player is leaving, if needed */
2964 /* ----------------------------------------------------------------------- */
2966 if (player->is_moving)
2968 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
2970 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
2972 if (last_element == EL_DYNAMITE_ACTIVE ||
2973 last_element == EL_EM_DYNAMITE_ACTIVE ||
2974 last_element == EL_SP_DISK_RED_ACTIVE)
2975 DrawDynamite(last_jx, last_jy);
2977 DrawLevelFieldThruMask(last_jx, last_jy);
2979 else if (last_element == EL_DYNAMITE_ACTIVE ||
2980 last_element == EL_EM_DYNAMITE_ACTIVE ||
2981 last_element == EL_SP_DISK_RED_ACTIVE)
2982 DrawDynamite(last_jx, last_jy);
2984 /* !!! this is not enough to prevent flickering of players which are
2985 moving next to each others without a free tile between them -- this
2986 can only be solved by drawing all players layer by layer (first the
2987 background, then the foreground etc.) !!! => TODO */
2988 else if (!IS_PLAYER(last_jx, last_jy))
2989 DrawLevelField(last_jx, last_jy);
2992 DrawLevelField(last_jx, last_jy);
2995 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
2996 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
2999 if (!IN_SCR_FIELD(sx, sy))
3002 /* ----------------------------------------------------------------------- */
3003 /* draw things behind the player, if needed */
3004 /* ----------------------------------------------------------------------- */
3007 DrawLevelElement(jx, jy, Back[jx][jy]);
3008 else if (IS_ACTIVE_BOMB(element))
3009 DrawLevelElement(jx, jy, EL_EMPTY);
3012 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
3014 int old_element = GfxElement[jx][jy];
3015 int old_graphic = el_act_dir2img(old_element, action, move_dir);
3016 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
3018 if (GFX_CRUMBLED(old_element))
3019 DrawLevelFieldCrumbledDigging(jx, jy, move_dir, player->StepFrame);
3021 DrawGraphic(sx, sy, old_graphic, frame);
3023 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
3024 player_is_opaque = TRUE;
3028 GfxElement[jx][jy] = EL_UNDEFINED;
3030 /* make sure that pushed elements are drawn with correct frame rate */
3031 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
3033 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
3034 GfxFrame[jx][jy] = player->StepFrame;
3036 DrawLevelField(jx, jy);
3040 #if !DRAW_PLAYER_OVER_PUSHED_ELEMENT
3041 /* ----------------------------------------------------------------------- */
3042 /* draw player himself */
3043 /* ----------------------------------------------------------------------- */
3045 graphic = getPlayerGraphic(player, move_dir);
3047 /* in the case of changed player action or direction, prevent the current
3048 animation frame from being restarted for identical animations */
3049 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
3050 player->Frame = last_player_frame;
3052 frame = getGraphicAnimationFrame(graphic, player->Frame);
3056 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3057 sxx = player->GfxPos;
3059 syy = player->GfxPos;
3062 if (player_is_opaque)
3063 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
3065 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3067 if (SHIELD_ON(player))
3069 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
3070 IMG_SHIELD_NORMAL_ACTIVE);
3071 int frame = getGraphicAnimationFrame(graphic, -1);
3073 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3077 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
3080 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3081 sxx = player->GfxPos;
3083 syy = player->GfxPos;
3087 /* ----------------------------------------------------------------------- */
3088 /* draw things the player is pushing, if needed */
3089 /* ----------------------------------------------------------------------- */
3091 if (player->is_pushing && player->is_moving)
3093 int px = SCREENX(jx), py = SCREENY(jy);
3094 int pxx = (TILEX - ABS(sxx)) * dx;
3095 int pyy = (TILEY - ABS(syy)) * dy;
3096 int gfx_frame = GfxFrame[jx][jy];
3102 if (!IS_MOVING(jx, jy)) /* push movement already finished */
3104 element = Feld[next_jx][next_jy];
3105 gfx_frame = GfxFrame[next_jx][next_jy];
3108 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
3110 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
3111 frame = getGraphicAnimationFrame(graphic, sync_frame);
3113 /* draw background element under pushed element (like the Sokoban field) */
3114 if (game.use_masked_pushing && IS_MOVING(jx, jy))
3116 /* this allows transparent pushing animation over non-black background */
3119 DrawLevelElement(jx, jy, Back[jx][jy]);
3121 DrawLevelElement(jx, jy, EL_EMPTY);
3123 if (Back[next_jx][next_jy])
3124 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3126 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
3128 else if (Back[next_jx][next_jy])
3129 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3132 /* do not draw (EM style) pushing animation when pushing is finished */
3133 /* (two-tile animations usually do not contain start and end frame) */
3134 if (graphic_info[graphic].double_movement && !IS_MOVING(jx, jy))
3135 DrawLevelElement(next_jx, next_jy, Feld[next_jx][next_jy]);
3137 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3139 /* masked drawing is needed for EMC style (double) movement graphics */
3140 /* !!! (ONLY WHEN DRAWING PUSHED ELEMENT OVER THE PLAYER) !!! */
3141 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3145 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
3146 /* ----------------------------------------------------------------------- */
3147 /* draw player himself */
3148 /* ----------------------------------------------------------------------- */
3150 graphic = getPlayerGraphic(player, move_dir);
3152 /* in the case of changed player action or direction, prevent the current
3153 animation frame from being restarted for identical animations */
3154 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
3155 player->Frame = last_player_frame;
3157 frame = getGraphicAnimationFrame(graphic, player->Frame);
3161 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3162 sxx = player->GfxPos;
3164 syy = player->GfxPos;
3167 if (player_is_opaque)
3168 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
3170 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3172 if (SHIELD_ON(player))
3174 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
3175 IMG_SHIELD_NORMAL_ACTIVE);
3176 int frame = getGraphicAnimationFrame(graphic, -1);
3178 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3182 /* ----------------------------------------------------------------------- */
3183 /* draw things in front of player (active dynamite or dynabombs) */
3184 /* ----------------------------------------------------------------------- */
3186 if (IS_ACTIVE_BOMB(element))
3188 graphic = el2img(element);
3189 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
3191 if (game.emulation == EMU_SUPAPLEX)
3192 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
3194 DrawGraphicThruMask(sx, sy, graphic, frame);
3197 if (player_is_moving && last_element == EL_EXPLOSION)
3199 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
3200 GfxElement[last_jx][last_jy] : EL_EMPTY);
3201 int graphic = el_act2img(element, ACTION_EXPLODING);
3202 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
3203 int phase = ExplodePhase[last_jx][last_jy] - 1;
3204 int frame = getGraphicAnimationFrame(graphic, phase - delay);
3207 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
3210 /* ----------------------------------------------------------------------- */
3211 /* draw elements the player is just walking/passing through/under */
3212 /* ----------------------------------------------------------------------- */
3214 if (player_is_moving)
3216 /* handle the field the player is leaving ... */
3217 if (IS_ACCESSIBLE_INSIDE(last_element))
3218 DrawLevelField(last_jx, last_jy);
3219 else if (IS_ACCESSIBLE_UNDER(last_element))
3220 DrawLevelFieldThruMask(last_jx, last_jy);
3223 /* do not redraw accessible elements if the player is just pushing them */
3224 if (!player_is_moving || !player->is_pushing)
3226 /* ... and the field the player is entering */
3227 if (IS_ACCESSIBLE_INSIDE(element))
3228 DrawLevelField(jx, jy);
3229 else if (IS_ACCESSIBLE_UNDER(element))
3230 DrawLevelFieldThruMask(jx, jy);
3233 MarkTileDirty(sx, sy);
3236 /* ------------------------------------------------------------------------- */
3238 void WaitForEventToContinue()
3240 boolean still_wait = TRUE;
3242 /* simulate releasing mouse button over last gadget, if still pressed */
3244 HandleGadgets(-1, -1, 0);
3246 button_status = MB_RELEASED;
3260 case EVENT_BUTTONPRESS:
3261 case EVENT_KEYPRESS:
3265 case EVENT_KEYRELEASE:
3266 ClearPlayerAction();
3270 HandleOtherEvents(&event);
3274 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3281 /* don't eat all CPU time */
3286 #define MAX_REQUEST_LINES 13
3287 #define MAX_REQUEST_LINE_FONT1_LEN 7
3288 #define MAX_REQUEST_LINE_FONT2_LEN 10
3290 static int RequestHandleEvents(unsigned int req_state)
3292 boolean level_solved = (game_status == GAME_MODE_PLAYING &&
3293 local_player->LevelSolved_GameEnd);
3294 int last_game_status = game_status; /* save current game status */
3295 int width = request.width;
3296 int height = request.height;
3300 setRequestPosition(&sx, &sy, FALSE);
3302 button_status = MB_RELEASED;
3304 request_gadget_id = -1;
3311 SetDrawtoField(DRAW_FIELDBUFFER);
3313 HandleGameActions();
3315 SetDrawtoField(DRAW_BACKBUFFER);
3317 if (global.use_envelope_request)
3319 /* copy current state of request area to middle of playfield area */
3320 BlitBitmap(bitmap_db_cross, drawto, sx, sy, width, height, sx, sy);
3328 while (NextValidEvent(&event))
3332 case EVENT_BUTTONPRESS:
3333 case EVENT_BUTTONRELEASE:
3334 case EVENT_MOTIONNOTIFY:
3338 if (event.type == EVENT_MOTIONNOTIFY)
3343 motion_status = TRUE;
3344 mx = ((MotionEvent *) &event)->x;
3345 my = ((MotionEvent *) &event)->y;
3349 motion_status = FALSE;
3350 mx = ((ButtonEvent *) &event)->x;
3351 my = ((ButtonEvent *) &event)->y;
3352 if (event.type == EVENT_BUTTONPRESS)
3353 button_status = ((ButtonEvent *) &event)->button;
3355 button_status = MB_RELEASED;
3358 /* this sets 'request_gadget_id' */
3359 HandleGadgets(mx, my, button_status);
3361 switch (request_gadget_id)
3363 case TOOL_CTRL_ID_YES:
3366 case TOOL_CTRL_ID_NO:
3369 case TOOL_CTRL_ID_CONFIRM:
3370 result = TRUE | FALSE;
3373 case TOOL_CTRL_ID_PLAYER_1:
3376 case TOOL_CTRL_ID_PLAYER_2:
3379 case TOOL_CTRL_ID_PLAYER_3:
3382 case TOOL_CTRL_ID_PLAYER_4:
3393 case EVENT_KEYPRESS:
3394 switch (GetEventKey((KeyEvent *)&event, TRUE))
3397 if (req_state & REQ_CONFIRM)
3402 #if defined(TARGET_SDL2)
3409 #if defined(TARGET_SDL2)
3419 if (req_state & REQ_PLAYER)
3423 case EVENT_KEYRELEASE:
3424 ClearPlayerAction();
3428 HandleOtherEvents(&event);
3433 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3435 int joy = AnyJoystick();
3437 if (joy & JOY_BUTTON_1)
3439 else if (joy & JOY_BUTTON_2)
3445 if (global.use_envelope_request)
3447 /* copy back current state of pressed buttons inside request area */
3448 BlitBitmap(drawto, bitmap_db_cross, sx, sy, width, height, sx, sy);
3455 if (!PendingEvent()) /* delay only if no pending events */
3459 game_status = GAME_MODE_PSEUDO_DOOR;
3463 game_status = last_game_status; /* restore current game status */
3469 static boolean RequestDoor(char *text, unsigned int req_state)
3471 unsigned int old_door_state;
3472 int last_game_status = game_status; /* save current game status */
3473 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
3474 int font_nr = FONT_TEXT_2;
3479 if (maxWordLengthInString(text) > MAX_REQUEST_LINE_FONT1_LEN)
3481 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
3482 font_nr = FONT_TEXT_1;
3485 if (game_status == GAME_MODE_PLAYING)
3486 BlitScreenToBitmap(backbuffer);
3488 /* disable deactivated drawing when quick-loading level tape recording */
3489 if (tape.playing && tape.deactivate_display)
3490 TapeDeactivateDisplayOff(TRUE);
3492 SetMouseCursor(CURSOR_DEFAULT);
3494 #if defined(NETWORK_AVALIABLE)
3495 /* pause network game while waiting for request to answer */
3496 if (options.network &&
3497 game_status == GAME_MODE_PLAYING &&
3498 req_state & REQUEST_WAIT_FOR_INPUT)
3499 SendToServer_PausePlaying();
3502 old_door_state = GetDoorState();
3504 /* simulate releasing mouse button over last gadget, if still pressed */
3506 HandleGadgets(-1, -1, 0);
3510 /* draw released gadget before proceeding */
3513 if (old_door_state & DOOR_OPEN_1)
3515 CloseDoor(DOOR_CLOSE_1);
3517 /* save old door content */
3518 BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
3519 0 * DXSIZE, 0, DXSIZE, DYSIZE, 1 * DXSIZE, 0);
3522 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
3523 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3525 /* clear door drawing field */
3526 DrawBackground(DX, DY, DXSIZE, DYSIZE);
3528 /* force DOOR font inside door area */
3529 game_status = GAME_MODE_PSEUDO_DOOR;
3531 /* write text for request */
3532 for (text_ptr = text, ty = 0; ty < MAX_REQUEST_LINES; ty++)
3534 char text_line[max_request_line_len + 1];
3540 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
3542 tc = *(text_ptr + tx);
3543 // if (!tc || tc == ' ')
3544 if (!tc || tc == ' ' || tc == '?' || tc == '!')
3548 if ((tc == '?' || tc == '!') && tl == 0)
3558 strncpy(text_line, text_ptr, tl);
3561 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
3562 DY + 8 + ty * (getFontHeight(font_nr) + 2),
3563 text_line, font_nr);
3565 text_ptr += tl + (tc == ' ' ? 1 : 0);
3566 // text_ptr += tl + (tc == ' ' || tc == '?' || tc == '!' ? 1 : 0);
3569 game_status = last_game_status; /* restore current game status */
3571 if (req_state & REQ_ASK)
3573 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
3574 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
3576 else if (req_state & REQ_CONFIRM)
3578 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
3580 else if (req_state & REQ_PLAYER)
3582 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
3583 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
3584 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
3585 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
3588 /* copy request gadgets to door backbuffer */
3589 BlitBitmap(drawto, bitmap_db_door_1, DX, DY, DXSIZE, DYSIZE, 0, 0);
3591 OpenDoor(DOOR_OPEN_1);
3593 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
3595 if (game_status == GAME_MODE_PLAYING)
3597 SetPanelBackground();
3598 SetDrawBackgroundMask(REDRAW_DOOR_1);
3602 SetDrawBackgroundMask(REDRAW_FIELD);
3608 if (game_status != GAME_MODE_MAIN)
3611 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3613 // ---------- handle request buttons ----------
3614 result = RequestHandleEvents(req_state);
3616 if (game_status != GAME_MODE_MAIN)
3621 if (!(req_state & REQ_STAY_OPEN))
3623 CloseDoor(DOOR_CLOSE_1);
3625 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
3626 (req_state & REQ_REOPEN))
3627 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
3632 if (game_status == GAME_MODE_PLAYING)
3634 SetPanelBackground();
3635 SetDrawBackgroundMask(REDRAW_DOOR_1);
3639 SetDrawBackgroundMask(REDRAW_FIELD);
3642 #if defined(NETWORK_AVALIABLE)
3643 /* continue network game after request */
3644 if (options.network &&
3645 game_status == GAME_MODE_PLAYING &&
3646 req_state & REQUEST_WAIT_FOR_INPUT)
3647 SendToServer_ContinuePlaying();
3650 /* restore deactivated drawing when quick-loading level tape recording */
3651 if (tape.playing && tape.deactivate_display)
3652 TapeDeactivateDisplayOn();
3657 static boolean RequestEnvelope(char *text, unsigned int req_state)
3661 if (game_status == GAME_MODE_PLAYING)
3662 BlitScreenToBitmap(backbuffer);
3664 /* disable deactivated drawing when quick-loading level tape recording */
3665 if (tape.playing && tape.deactivate_display)
3666 TapeDeactivateDisplayOff(TRUE);
3668 SetMouseCursor(CURSOR_DEFAULT);
3670 #if defined(NETWORK_AVALIABLE)
3671 /* pause network game while waiting for request to answer */
3672 if (options.network &&
3673 game_status == GAME_MODE_PLAYING &&
3674 req_state & REQUEST_WAIT_FOR_INPUT)
3675 SendToServer_PausePlaying();
3678 /* simulate releasing mouse button over last gadget, if still pressed */
3680 HandleGadgets(-1, -1, 0);
3684 // (replace with setting corresponding request background)
3685 // SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
3686 // SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3688 /* clear door drawing field */
3689 // DrawBackground(DX, DY, DXSIZE, DYSIZE);
3691 ShowEnvelopeRequest(text, req_state, ACTION_OPENING);
3693 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
3695 if (game_status == GAME_MODE_PLAYING)
3697 SetPanelBackground();
3698 SetDrawBackgroundMask(REDRAW_DOOR_1);
3702 SetDrawBackgroundMask(REDRAW_FIELD);
3708 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3710 // ---------- handle request buttons ----------
3711 result = RequestHandleEvents(req_state);
3713 if (game_status != GAME_MODE_MAIN)
3718 ShowEnvelopeRequest(text, req_state, ACTION_CLOSING);
3722 if (game_status == GAME_MODE_PLAYING)
3724 SetPanelBackground();
3725 SetDrawBackgroundMask(REDRAW_DOOR_1);
3729 SetDrawBackgroundMask(REDRAW_FIELD);
3732 #if defined(NETWORK_AVALIABLE)
3733 /* continue network game after request */
3734 if (options.network &&
3735 game_status == GAME_MODE_PLAYING &&
3736 req_state & REQUEST_WAIT_FOR_INPUT)
3737 SendToServer_ContinuePlaying();
3740 /* restore deactivated drawing when quick-loading level tape recording */
3741 if (tape.playing && tape.deactivate_display)
3742 TapeDeactivateDisplayOn();
3747 boolean Request(char *text, unsigned int req_state)
3749 if (global.use_envelope_request)
3750 return RequestEnvelope(text, req_state);
3752 return RequestDoor(text, req_state);
3755 static int compareDoorPartOrderInfo(const void *object1, const void *object2)
3757 const struct DoorPartOrderInfo *dpo1 = (struct DoorPartOrderInfo *)object1;
3758 const struct DoorPartOrderInfo *dpo2 = (struct DoorPartOrderInfo *)object2;
3761 if (dpo1->sort_priority != dpo2->sort_priority)
3762 compare_result = dpo1->sort_priority - dpo2->sort_priority;
3764 compare_result = dpo1->nr - dpo2->nr;
3766 return compare_result;
3769 void InitGraphicCompatibilityInfo_Doors()
3775 struct DoorInfo *door;
3779 { DOOR_1, IMG_DOOR_1_GFX_PART_1, IMG_DOOR_1_GFX_PART_8, &door_1 },
3780 { DOOR_2, IMG_DOOR_2_GFX_PART_1, IMG_DOOR_2_GFX_PART_8, &door_2 },
3782 { -1, -1, -1, NULL }
3784 struct Rect door_rect_list[] =
3786 { DX, DY, DXSIZE, DYSIZE },
3787 { VX, VY, VXSIZE, VYSIZE }
3791 for (i = 0; doors[i].door_token != -1; i++)
3793 int door_token = doors[i].door_token;
3794 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
3795 int part_1 = doors[i].part_1;
3796 int part_8 = doors[i].part_8;
3797 int part_2 = part_1 + 1;
3798 int part_3 = part_1 + 2;
3799 struct DoorInfo *door = doors[i].door;
3800 struct Rect *door_rect = &door_rect_list[door_index];
3801 boolean door_gfx_redefined = FALSE;
3803 /* check if any door part graphic definitions have been redefined */
3805 for (j = 0; door_part_controls[j].door_token != -1; j++)
3807 struct DoorPartControlInfo *dpc = &door_part_controls[j];
3808 struct FileInfo *fi = getImageListEntryFromImageID(dpc->graphic);
3810 if (dpc->door_token == door_token && fi->redefined)
3811 door_gfx_redefined = TRUE;
3814 /* check for old-style door graphic/animation modifications */
3816 if (!door_gfx_redefined)
3818 if (door->anim_mode & ANIM_STATIC_PANEL)
3820 door->panel.step_xoffset = 0;
3821 door->panel.step_yoffset = 0;
3824 if (door->anim_mode & (ANIM_HORIZONTAL | ANIM_VERTICAL))
3826 struct GraphicInfo *g_part_1 = &graphic_info[part_1];
3827 struct GraphicInfo *g_part_2 = &graphic_info[part_2];
3828 int num_door_steps, num_panel_steps;
3830 /* remove door part graphics other than the two default wings */
3832 for (j = 0; door_part_controls[j].door_token != -1; j++)
3834 struct DoorPartControlInfo *dpc = &door_part_controls[j];
3835 struct GraphicInfo *g = &graphic_info[dpc->graphic];
3837 if (dpc->graphic >= part_3 &&
3838 dpc->graphic <= part_8)
3842 /* set graphics and screen positions of the default wings */
3844 g_part_1->width = door_rect->width;
3845 g_part_1->height = door_rect->height;
3846 g_part_2->width = door_rect->width;
3847 g_part_2->height = door_rect->height;
3848 g_part_2->src_x = door_rect->width;
3849 g_part_2->src_y = g_part_1->src_y;
3851 door->part_2.x = door->part_1.x;
3852 door->part_2.y = door->part_1.y;
3854 if (door->width != -1)
3856 g_part_1->width = door->width;
3857 g_part_2->width = door->width;
3859 // special treatment for graphics and screen position of right wing
3860 g_part_2->src_x += door_rect->width - door->width;
3861 door->part_2.x += door_rect->width - door->width;
3864 if (door->height != -1)
3866 g_part_1->height = door->height;
3867 g_part_2->height = door->height;
3869 // special treatment for graphics and screen position of bottom wing
3870 g_part_2->src_y += door_rect->height - door->height;
3871 door->part_2.y += door_rect->height - door->height;
3874 /* set animation delays for the default wings and panels */
3876 door->part_1.step_delay = door->step_delay;
3877 door->part_2.step_delay = door->step_delay;
3878 door->panel.step_delay = door->step_delay;
3880 /* set animation draw order for the default wings */
3882 door->part_1.sort_priority = 2; /* draw left wing over ... */
3883 door->part_2.sort_priority = 1; /* ... right wing */
3885 /* set animation draw offset for the default wings */
3887 if (door->anim_mode & ANIM_HORIZONTAL)
3889 door->part_1.step_xoffset = door->step_offset;
3890 door->part_1.step_yoffset = 0;
3891 door->part_2.step_xoffset = door->step_offset * -1;
3892 door->part_2.step_yoffset = 0;
3894 num_door_steps = g_part_1->width / door->step_offset;
3896 else // ANIM_VERTICAL
3898 door->part_1.step_xoffset = 0;
3899 door->part_1.step_yoffset = door->step_offset;
3900 door->part_2.step_xoffset = 0;
3901 door->part_2.step_yoffset = door->step_offset * -1;
3903 num_door_steps = g_part_1->height / door->step_offset;
3906 /* set animation draw offset for the default panels */
3908 if (door->step_offset > 1)
3910 num_panel_steps = 2 * door_rect->height / door->step_offset;
3911 door->panel.start_step = num_panel_steps - num_door_steps;
3912 door->panel.start_step_closing = door->panel.start_step;
3916 num_panel_steps = door_rect->height / door->step_offset;
3917 door->panel.start_step = num_panel_steps - num_door_steps / 2;
3918 door->panel.start_step_closing = door->panel.start_step;
3919 door->panel.step_delay *= 2;
3930 for (i = 0; door_part_controls[i].door_token != -1; i++)
3932 struct DoorPartControlInfo *dpc = &door_part_controls[i];
3933 struct DoorPartOrderInfo *dpo = &door_part_order[i];
3935 /* initialize "start_step_opening" and "start_step_closing", if needed */
3936 if (dpc->pos->start_step_opening == 0 &&
3937 dpc->pos->start_step_closing == 0)
3939 // dpc->pos->start_step_opening = dpc->pos->start_step;
3940 dpc->pos->start_step_closing = dpc->pos->start_step;
3943 /* fill structure for door part draw order (sorted below) */
3945 dpo->sort_priority = dpc->pos->sort_priority;
3948 /* sort door part controls according to sort_priority and graphic number */
3949 qsort(door_part_order, MAX_DOOR_PARTS,
3950 sizeof(struct DoorPartOrderInfo), compareDoorPartOrderInfo);
3953 unsigned int OpenDoor(unsigned int door_state)
3955 if (door_state & DOOR_COPY_BACK)
3957 if (door_state & DOOR_OPEN_1)
3958 BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
3959 1 * DXSIZE, 0, DXSIZE, DYSIZE, 0 * DXSIZE, 0);
3961 if (door_state & DOOR_OPEN_2)
3962 BlitBitmap(bitmap_db_door_2, bitmap_db_door_2,
3963 1 * VXSIZE, 0, VXSIZE, VYSIZE, 0 * VXSIZE, 0);
3965 door_state &= ~DOOR_COPY_BACK;
3968 return MoveDoor(door_state);
3971 unsigned int CloseDoor(unsigned int door_state)
3973 unsigned int old_door_state = GetDoorState();
3975 if (!(door_state & DOOR_NO_COPY_BACK))
3977 if (old_door_state & DOOR_OPEN_1)
3978 BlitBitmap(backbuffer, bitmap_db_door_1,
3979 DX, DY, DXSIZE, DYSIZE, 0, 0);
3981 if (old_door_state & DOOR_OPEN_2)
3982 BlitBitmap(backbuffer, bitmap_db_door_2,
3983 VX, VY, VXSIZE, VYSIZE, 0, 0);
3985 door_state &= ~DOOR_NO_COPY_BACK;
3988 return MoveDoor(door_state);
3991 unsigned int GetDoorState()
3993 return MoveDoor(DOOR_GET_STATE);
3996 unsigned int SetDoorState(unsigned int door_state)
3998 return MoveDoor(door_state | DOOR_SET_STATE);
4001 int euclid(int a, int b)
4003 return (b ? euclid(b, a % b) : a);
4006 unsigned int MoveDoor(unsigned int door_state)
4008 struct Rect door_rect_list[] =
4010 { DX, DY, DXSIZE, DYSIZE },
4011 { VX, VY, VXSIZE, VYSIZE }
4013 static int door1 = DOOR_OPEN_1;
4014 static int door2 = DOOR_CLOSE_2;
4015 unsigned int door_delay = 0;
4016 unsigned int door_delay_value;
4019 if (door_state == DOOR_GET_STATE)
4020 return (door1 | door2);
4022 if (door_state & DOOR_SET_STATE)
4024 if (door_state & DOOR_ACTION_1)
4025 door1 = door_state & DOOR_ACTION_1;
4026 if (door_state & DOOR_ACTION_2)
4027 door2 = door_state & DOOR_ACTION_2;
4029 return (door1 | door2);
4032 if (!(door_state & DOOR_FORCE_REDRAW))
4034 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
4035 door_state &= ~DOOR_OPEN_1;
4036 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
4037 door_state &= ~DOOR_CLOSE_1;
4038 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
4039 door_state &= ~DOOR_OPEN_2;
4040 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
4041 door_state &= ~DOOR_CLOSE_2;
4044 if (global.autoplay_leveldir)
4046 door_state |= DOOR_NO_DELAY;
4047 door_state &= ~DOOR_CLOSE_ALL;
4050 if (game_status == GAME_MODE_EDITOR)
4051 door_state |= DOOR_NO_DELAY;
4053 if (door_state & DOOR_ACTION)
4055 boolean door_panel_drawn[NUM_DOORS];
4056 boolean panel_has_doors[NUM_DOORS];
4057 boolean door_part_skip[MAX_DOOR_PARTS];
4058 boolean door_part_done[MAX_DOOR_PARTS];
4059 boolean door_part_done_all;
4060 int num_steps[MAX_DOOR_PARTS];
4061 int max_move_delay = 0; // delay for complete animations of all doors
4062 int max_step_delay = 0; // delay (ms) between two animation frames
4063 int num_move_steps = 0; // number of animation steps for all doors
4064 int max_move_delay_doors_only = 0; // delay for doors only (no panel)
4065 int num_move_steps_doors_only = 0; // steps for doors only (no panel)
4066 int current_move_delay = 0;
4070 for (i = 0; i < NUM_DOORS; i++)
4071 panel_has_doors[i] = FALSE;
4073 for (i = 0; i < MAX_DOOR_PARTS; i++)
4075 struct DoorPartControlInfo *dpc = &door_part_controls[i];
4076 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4077 int door_token = dpc->door_token;
4079 door_part_done[i] = FALSE;
4080 door_part_skip[i] = (!(door_state & door_token) ||
4084 for (i = 0; i < MAX_DOOR_PARTS; i++)
4086 int nr = door_part_order[i].nr;
4087 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
4088 struct DoorPartPosInfo *pos = dpc->pos;
4089 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4090 int door_token = dpc->door_token;
4091 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
4092 boolean is_panel = DOOR_PART_IS_PANEL(nr);
4093 int step_xoffset = ABS(pos->step_xoffset);
4094 int step_yoffset = ABS(pos->step_yoffset);
4095 int step_delay = pos->step_delay;
4096 int current_door_state = door_state & door_token;
4097 boolean door_opening = ((current_door_state & DOOR_OPEN) != 0);
4098 boolean door_closing = ((current_door_state & DOOR_CLOSE) != 0);
4099 boolean part_opening = (is_panel ? door_closing : door_opening);
4100 int start_step = (part_opening ? pos->start_step_opening :
4101 pos->start_step_closing);
4102 float move_xsize = (step_xoffset ? g->width : 0);
4103 float move_ysize = (step_yoffset ? g->height : 0);
4104 int move_xsteps = (step_xoffset ? ceil(move_xsize / step_xoffset) : 0);
4105 int move_ysteps = (step_yoffset ? ceil(move_ysize / step_yoffset) : 0);
4106 int move_steps = (move_xsteps && move_ysteps ?
4107 MIN(move_xsteps, move_ysteps) :
4108 move_xsteps ? move_xsteps : move_ysteps) - start_step;
4109 int move_delay = move_steps * step_delay;
4111 if (door_part_skip[nr])
4114 max_move_delay = MAX(max_move_delay, move_delay);
4115 max_step_delay = (max_step_delay == 0 ? step_delay :
4116 euclid(max_step_delay, step_delay));
4117 num_steps[nr] = move_steps;
4121 max_move_delay_doors_only = MAX(max_move_delay_doors_only, move_delay);
4123 panel_has_doors[door_index] = TRUE;
4127 max_step_delay = MAX(1, max_step_delay); // prevent division by zero
4129 num_move_steps = max_move_delay / max_step_delay;
4130 num_move_steps_doors_only = max_move_delay_doors_only / max_step_delay;
4132 door_delay_value = max_step_delay;
4134 if ((door_state & DOOR_NO_DELAY) || setup.quick_doors)
4136 start = num_move_steps - 1;
4140 /* opening door sound has priority over simultaneously closing door */
4141 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
4142 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
4143 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
4144 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
4147 for (k = start; k < num_move_steps; k++)
4149 int last_frame = num_move_steps - 1; // last frame of this "for" loop
4151 door_part_done_all = TRUE;
4153 for (i = 0; i < NUM_DOORS; i++)
4154 door_panel_drawn[i] = FALSE;
4156 for (i = 0; i < MAX_DOOR_PARTS; i++)
4158 int nr = door_part_order[i].nr;
4159 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
4160 struct DoorPartPosInfo *pos = dpc->pos;
4161 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4162 int door_token = dpc->door_token;
4163 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
4164 boolean is_panel = DOOR_PART_IS_PANEL(nr);
4165 boolean is_panel_and_door_has_closed = FALSE;
4166 struct Rect *door_rect = &door_rect_list[door_index];
4167 Bitmap *bitmap_db_door = (door_token == DOOR_1 ? bitmap_db_door_1 :
4169 Bitmap *bitmap = (is_panel ? bitmap_db_door : g->bitmap);
4170 int current_door_state = door_state & door_token;
4171 boolean door_opening = ((current_door_state & DOOR_OPEN) != 0);
4172 boolean door_closing = !door_opening;
4173 boolean part_opening = (is_panel ? door_closing : door_opening);
4174 boolean part_closing = !part_opening;
4175 int start_step = (part_opening ? pos->start_step_opening :
4176 pos->start_step_closing);
4177 int step_delay = pos->step_delay;
4178 int step_factor = step_delay / max_step_delay;
4179 int k1 = (step_factor ? k / step_factor + 1 : k);
4180 int k2 = (part_opening ? k1 + start_step : num_steps[nr] - k1);
4181 int kk = MAX(0, k2);
4184 int src_x, src_y, src_xx, src_yy;
4185 int dst_x, dst_y, dst_xx, dst_yy;
4188 if (door_part_skip[nr])
4191 if (!(door_state & door_token))
4199 int k2_door = (door_opening ? k : num_move_steps_doors_only - k - 1);
4200 int kk_door = MAX(0, k2_door);
4201 int sync_frame = kk_door * door_delay_value;
4202 int frame = getGraphicAnimationFrame(dpc->graphic, sync_frame);
4204 getGraphicSource(dpc->graphic, frame, &bitmap, &g_src_x, &g_src_y);
4209 if (!door_panel_drawn[door_index])
4211 ClearRectangle(drawto, door_rect->x, door_rect->y,
4212 door_rect->width, door_rect->height);
4214 door_panel_drawn[door_index] = TRUE;
4217 // draw opening or closing door parts
4219 if (pos->step_xoffset < 0) // door part on right side
4222 dst_xx = pos->x + ABS(kk * pos->step_xoffset);
4225 if (dst_xx + width > door_rect->width)
4226 width = door_rect->width - dst_xx;
4228 else // door part on left side
4231 dst_xx = pos->x - kk * pos->step_xoffset;
4235 src_xx = ABS(dst_xx);
4239 width = g->width - src_xx;
4241 // printf("::: k == %d [%d] \n", k, start_step);
4244 if (pos->step_yoffset < 0) // door part on bottom side
4247 dst_yy = pos->y + ABS(kk * pos->step_yoffset);
4250 if (dst_yy + height > door_rect->height)
4251 height = door_rect->height - dst_yy;
4253 else // door part on top side
4256 dst_yy = pos->y - kk * pos->step_yoffset;
4260 src_yy = ABS(dst_yy);
4264 height = g->height - src_yy;
4267 src_x = g_src_x + src_xx;
4268 src_y = g_src_y + src_yy;
4270 dst_x = door_rect->x + dst_xx;
4271 dst_y = door_rect->y + dst_yy;
4273 is_panel_and_door_has_closed =
4276 panel_has_doors[door_index] &&
4277 k >= num_move_steps_doors_only - 1);
4279 if (width >= 0 && width <= g->width &&
4280 height >= 0 && height <= g->height &&
4281 !is_panel_and_door_has_closed)
4283 if (is_panel || !pos->draw_masked)
4284 BlitBitmap(bitmap, drawto, src_x, src_y, width, height,
4287 BlitBitmapMasked(bitmap, drawto, src_x, src_y, width, height,
4291 redraw_mask |= REDRAW_DOOR_FROM_TOKEN(door_token);
4293 if ((part_opening && (width < 0 || height < 0)) ||
4294 (part_closing && (width >= g->width && height >= g->height)))
4295 door_part_done[nr] = TRUE;
4297 // continue door part animations, but not panel after door has closed
4298 if (!door_part_done[nr] && !is_panel_and_door_has_closed)
4299 door_part_done_all = FALSE;
4302 if (!(door_state & DOOR_NO_DELAY))
4306 if (game_status == GAME_MODE_MAIN)
4309 SkipUntilDelayReached(&door_delay, door_delay_value, &k, last_frame);
4311 current_move_delay += max_step_delay;
4314 if (door_part_done_all)
4319 if (door_state & DOOR_ACTION_1)
4320 door1 = door_state & DOOR_ACTION_1;
4321 if (door_state & DOOR_ACTION_2)
4322 door2 = door_state & DOOR_ACTION_2;
4324 return (door1 | door2);
4327 void DrawSpecialEditorDoor()
4329 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
4330 int top_border_width = gfx1->width;
4331 int top_border_height = gfx1->height;
4332 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
4333 int ex = EX - outer_border;
4334 int ey = EY - outer_border;
4335 int vy = VY - outer_border;
4336 int exsize = EXSIZE + 2 * outer_border;
4338 /* draw bigger level editor toolbox window */
4339 BlitBitmap(gfx1->bitmap, drawto, gfx1->src_x, gfx1->src_y,
4340 top_border_width, top_border_height, ex, ey - top_border_height);
4341 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto, ex, vy,
4342 exsize, EYSIZE - VYSIZE + outer_border, ex, ey);
4344 redraw_mask |= REDRAW_ALL;
4347 void UndrawSpecialEditorDoor()
4349 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
4350 int top_border_width = gfx1->width;
4351 int top_border_height = gfx1->height;
4352 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
4353 int ex = EX - outer_border;
4354 int ey = EY - outer_border;
4355 int ey_top = ey - top_border_height;
4356 int exsize = EXSIZE + 2 * outer_border;
4357 int eysize = EYSIZE + 2 * outer_border;
4359 /* draw normal tape recorder window */
4360 if (graphic_info[IMG_GLOBAL_BORDER].bitmap)
4362 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
4363 ex, ey_top, top_border_width, top_border_height,
4365 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
4366 ex, ey, exsize, eysize, ex, ey);
4370 // if screen background is set to "[NONE]", clear editor toolbox window
4371 ClearRectangle(drawto, ex, ey_top, top_border_width, top_border_height);
4372 ClearRectangle(drawto, ex, ey, exsize, eysize);
4375 redraw_mask |= REDRAW_ALL;
4379 /* ---------- new tool button stuff ---------------------------------------- */
4384 struct TextPosInfo *pos;
4387 } toolbutton_info[NUM_TOOL_BUTTONS] =
4390 IMG_REQUEST_BUTTON_GFX_YES, &request.button.yes,
4391 TOOL_CTRL_ID_YES, "yes"
4394 IMG_REQUEST_BUTTON_GFX_NO, &request.button.no,
4395 TOOL_CTRL_ID_NO, "no"
4398 IMG_REQUEST_BUTTON_GFX_CONFIRM, &request.button.confirm,
4399 TOOL_CTRL_ID_CONFIRM, "confirm"
4402 IMG_REQUEST_BUTTON_GFX_PLAYER_1, &request.button.player_1,
4403 TOOL_CTRL_ID_PLAYER_1, "player 1"
4406 IMG_REQUEST_BUTTON_GFX_PLAYER_2, &request.button.player_2,
4407 TOOL_CTRL_ID_PLAYER_2, "player 2"
4410 IMG_REQUEST_BUTTON_GFX_PLAYER_3, &request.button.player_3,
4411 TOOL_CTRL_ID_PLAYER_3, "player 3"
4414 IMG_REQUEST_BUTTON_GFX_PLAYER_4, &request.button.player_4,
4415 TOOL_CTRL_ID_PLAYER_4, "player 4"
4419 void CreateToolButtons()
4423 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4425 struct GraphicInfo *gfx = &graphic_info[toolbutton_info[i].graphic];
4426 struct TextPosInfo *pos = toolbutton_info[i].pos;
4427 struct GadgetInfo *gi;
4428 Bitmap *deco_bitmap = None;
4429 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
4430 unsigned int event_mask = GD_EVENT_RELEASED;
4433 int gd_x = gfx->src_x;
4434 int gd_y = gfx->src_y;
4435 int gd_xp = gfx->src_x + gfx->pressed_xoffset;
4436 int gd_yp = gfx->src_y + gfx->pressed_yoffset;
4439 if (global.use_envelope_request)
4440 setRequestPosition(&dx, &dy, TRUE);
4442 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
4444 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
4446 getSizedGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr), 0,
4447 pos->size, &deco_bitmap, &deco_x, &deco_y);
4448 deco_xpos = (gfx->width - pos->size) / 2;
4449 deco_ypos = (gfx->height - pos->size) / 2;
4452 gi = CreateGadget(GDI_CUSTOM_ID, id,
4453 GDI_INFO_TEXT, toolbutton_info[i].infotext,
4454 GDI_X, dx + GDI_ACTIVE_POS(pos->x),
4455 GDI_Y, dy + GDI_ACTIVE_POS(pos->y),
4456 GDI_WIDTH, gfx->width,
4457 GDI_HEIGHT, gfx->height,
4458 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
4459 GDI_STATE, GD_BUTTON_UNPRESSED,
4460 GDI_DESIGN_UNPRESSED, gfx->bitmap, gd_x, gd_y,
4461 GDI_DESIGN_PRESSED, gfx->bitmap, gd_xp, gd_yp,
4462 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
4463 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
4464 GDI_DECORATION_SIZE, pos->size, pos->size,
4465 GDI_DECORATION_SHIFTING, 1, 1,
4466 GDI_DIRECT_DRAW, FALSE,
4467 GDI_EVENT_MASK, event_mask,
4468 GDI_CALLBACK_ACTION, HandleToolButtons,
4472 Error(ERR_EXIT, "cannot create gadget");
4474 tool_gadget[id] = gi;
4478 void FreeToolButtons()
4482 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4483 FreeGadget(tool_gadget[i]);
4486 static void UnmapToolButtons()
4490 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4491 UnmapGadget(tool_gadget[i]);
4494 static void HandleToolButtons(struct GadgetInfo *gi)
4496 request_gadget_id = gi->custom_id;
4499 static struct Mapping_EM_to_RND_object
4502 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
4503 boolean is_backside; /* backside of moving element */
4509 em_object_mapping_list[] =
4512 Xblank, TRUE, FALSE,
4516 Yacid_splash_eB, FALSE, FALSE,
4517 EL_ACID_SPLASH_RIGHT, -1, -1
4520 Yacid_splash_wB, FALSE, FALSE,
4521 EL_ACID_SPLASH_LEFT, -1, -1
4524 #ifdef EM_ENGINE_BAD_ROLL
4526 Xstone_force_e, FALSE, FALSE,
4527 EL_ROCK, -1, MV_BIT_RIGHT
4530 Xstone_force_w, FALSE, FALSE,
4531 EL_ROCK, -1, MV_BIT_LEFT
4534 Xnut_force_e, FALSE, FALSE,
4535 EL_NUT, -1, MV_BIT_RIGHT
4538 Xnut_force_w, FALSE, FALSE,
4539 EL_NUT, -1, MV_BIT_LEFT
4542 Xspring_force_e, FALSE, FALSE,
4543 EL_SPRING, -1, MV_BIT_RIGHT
4546 Xspring_force_w, FALSE, FALSE,
4547 EL_SPRING, -1, MV_BIT_LEFT
4550 Xemerald_force_e, FALSE, FALSE,
4551 EL_EMERALD, -1, MV_BIT_RIGHT
4554 Xemerald_force_w, FALSE, FALSE,
4555 EL_EMERALD, -1, MV_BIT_LEFT
4558 Xdiamond_force_e, FALSE, FALSE,
4559 EL_DIAMOND, -1, MV_BIT_RIGHT
4562 Xdiamond_force_w, FALSE, FALSE,
4563 EL_DIAMOND, -1, MV_BIT_LEFT
4566 Xbomb_force_e, FALSE, FALSE,
4567 EL_BOMB, -1, MV_BIT_RIGHT
4570 Xbomb_force_w, FALSE, FALSE,
4571 EL_BOMB, -1, MV_BIT_LEFT
4573 #endif /* EM_ENGINE_BAD_ROLL */
4576 Xstone, TRUE, FALSE,
4580 Xstone_pause, FALSE, FALSE,
4584 Xstone_fall, FALSE, FALSE,
4588 Ystone_s, FALSE, FALSE,
4589 EL_ROCK, ACTION_FALLING, -1
4592 Ystone_sB, FALSE, TRUE,
4593 EL_ROCK, ACTION_FALLING, -1
4596 Ystone_e, FALSE, FALSE,
4597 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
4600 Ystone_eB, FALSE, TRUE,
4601 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
4604 Ystone_w, FALSE, FALSE,
4605 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
4608 Ystone_wB, FALSE, TRUE,
4609 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
4616 Xnut_pause, FALSE, FALSE,
4620 Xnut_fall, FALSE, FALSE,
4624 Ynut_s, FALSE, FALSE,
4625 EL_NUT, ACTION_FALLING, -1
4628 Ynut_sB, FALSE, TRUE,
4629 EL_NUT, ACTION_FALLING, -1
4632 Ynut_e, FALSE, FALSE,
4633 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
4636 Ynut_eB, FALSE, TRUE,
4637 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
4640 Ynut_w, FALSE, FALSE,
4641 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
4644 Ynut_wB, FALSE, TRUE,
4645 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
4648 Xbug_n, TRUE, FALSE,
4652 Xbug_e, TRUE, FALSE,
4653 EL_BUG_RIGHT, -1, -1
4656 Xbug_s, TRUE, FALSE,
4660 Xbug_w, TRUE, FALSE,
4664 Xbug_gon, FALSE, FALSE,
4668 Xbug_goe, FALSE, FALSE,
4669 EL_BUG_RIGHT, -1, -1
4672 Xbug_gos, FALSE, FALSE,
4676 Xbug_gow, FALSE, FALSE,
4680 Ybug_n, FALSE, FALSE,
4681 EL_BUG, ACTION_MOVING, MV_BIT_UP
4684 Ybug_nB, FALSE, TRUE,
4685 EL_BUG, ACTION_MOVING, MV_BIT_UP
4688 Ybug_e, FALSE, FALSE,
4689 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
4692 Ybug_eB, FALSE, TRUE,
4693 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
4696 Ybug_s, FALSE, FALSE,
4697 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
4700 Ybug_sB, FALSE, TRUE,
4701 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
4704 Ybug_w, FALSE, FALSE,
4705 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
4708 Ybug_wB, FALSE, TRUE,
4709 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
4712 Ybug_w_n, FALSE, FALSE,
4713 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
4716 Ybug_n_e, FALSE, FALSE,
4717 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
4720 Ybug_e_s, FALSE, FALSE,
4721 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
4724 Ybug_s_w, FALSE, FALSE,
4725 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
4728 Ybug_e_n, FALSE, FALSE,
4729 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
4732 Ybug_s_e, FALSE, FALSE,
4733 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
4736 Ybug_w_s, FALSE, FALSE,
4737 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
4740 Ybug_n_w, FALSE, FALSE,
4741 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
4744 Ybug_stone, FALSE, FALSE,
4745 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
4748 Ybug_spring, FALSE, FALSE,
4749 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
4752 Xtank_n, TRUE, FALSE,
4753 EL_SPACESHIP_UP, -1, -1
4756 Xtank_e, TRUE, FALSE,
4757 EL_SPACESHIP_RIGHT, -1, -1
4760 Xtank_s, TRUE, FALSE,
4761 EL_SPACESHIP_DOWN, -1, -1
4764 Xtank_w, TRUE, FALSE,
4765 EL_SPACESHIP_LEFT, -1, -1
4768 Xtank_gon, FALSE, FALSE,
4769 EL_SPACESHIP_UP, -1, -1
4772 Xtank_goe, FALSE, FALSE,
4773 EL_SPACESHIP_RIGHT, -1, -1
4776 Xtank_gos, FALSE, FALSE,
4777 EL_SPACESHIP_DOWN, -1, -1
4780 Xtank_gow, FALSE, FALSE,
4781 EL_SPACESHIP_LEFT, -1, -1
4784 Ytank_n, FALSE, FALSE,
4785 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
4788 Ytank_nB, FALSE, TRUE,
4789 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
4792 Ytank_e, FALSE, FALSE,
4793 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
4796 Ytank_eB, FALSE, TRUE,
4797 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
4800 Ytank_s, FALSE, FALSE,
4801 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
4804 Ytank_sB, FALSE, TRUE,
4805 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
4808 Ytank_w, FALSE, FALSE,
4809 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
4812 Ytank_wB, FALSE, TRUE,
4813 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
4816 Ytank_w_n, FALSE, FALSE,
4817 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
4820 Ytank_n_e, FALSE, FALSE,
4821 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
4824 Ytank_e_s, FALSE, FALSE,
4825 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
4828 Ytank_s_w, FALSE, FALSE,
4829 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
4832 Ytank_e_n, FALSE, FALSE,
4833 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
4836 Ytank_s_e, FALSE, FALSE,
4837 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
4840 Ytank_w_s, FALSE, FALSE,
4841 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
4844 Ytank_n_w, FALSE, FALSE,
4845 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
4848 Ytank_stone, FALSE, FALSE,
4849 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
4852 Ytank_spring, FALSE, FALSE,
4853 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
4856 Xandroid, TRUE, FALSE,
4857 EL_EMC_ANDROID, ACTION_ACTIVE, -1
4860 Xandroid_1_n, FALSE, FALSE,
4861 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
4864 Xandroid_2_n, FALSE, FALSE,
4865 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
4868 Xandroid_1_e, FALSE, FALSE,
4869 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
4872 Xandroid_2_e, FALSE, FALSE,
4873 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
4876 Xandroid_1_w, FALSE, FALSE,
4877 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
4880 Xandroid_2_w, FALSE, FALSE,
4881 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
4884 Xandroid_1_s, FALSE, FALSE,
4885 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
4888 Xandroid_2_s, FALSE, FALSE,
4889 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
4892 Yandroid_n, FALSE, FALSE,
4893 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
4896 Yandroid_nB, FALSE, TRUE,
4897 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
4900 Yandroid_ne, FALSE, FALSE,
4901 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
4904 Yandroid_neB, FALSE, TRUE,
4905 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
4908 Yandroid_e, FALSE, FALSE,
4909 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
4912 Yandroid_eB, FALSE, TRUE,
4913 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
4916 Yandroid_se, FALSE, FALSE,
4917 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
4920 Yandroid_seB, FALSE, TRUE,
4921 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
4924 Yandroid_s, FALSE, FALSE,
4925 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
4928 Yandroid_sB, FALSE, TRUE,
4929 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
4932 Yandroid_sw, FALSE, FALSE,
4933 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
4936 Yandroid_swB, FALSE, TRUE,
4937 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
4940 Yandroid_w, FALSE, FALSE,
4941 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
4944 Yandroid_wB, FALSE, TRUE,
4945 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
4948 Yandroid_nw, FALSE, FALSE,
4949 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
4952 Yandroid_nwB, FALSE, TRUE,
4953 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
4956 Xspring, TRUE, FALSE,
4960 Xspring_pause, FALSE, FALSE,
4964 Xspring_e, FALSE, FALSE,
4968 Xspring_w, FALSE, FALSE,
4972 Xspring_fall, FALSE, FALSE,
4976 Yspring_s, FALSE, FALSE,
4977 EL_SPRING, ACTION_FALLING, -1
4980 Yspring_sB, FALSE, TRUE,
4981 EL_SPRING, ACTION_FALLING, -1
4984 Yspring_e, FALSE, FALSE,
4985 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
4988 Yspring_eB, FALSE, TRUE,
4989 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
4992 Yspring_w, FALSE, FALSE,
4993 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
4996 Yspring_wB, FALSE, TRUE,
4997 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
5000 Yspring_kill_e, FALSE, FALSE,
5001 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
5004 Yspring_kill_eB, FALSE, TRUE,
5005 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
5008 Yspring_kill_w, FALSE, FALSE,
5009 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
5012 Yspring_kill_wB, FALSE, TRUE,
5013 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
5016 Xeater_n, TRUE, FALSE,
5017 EL_YAMYAM_UP, -1, -1
5020 Xeater_e, TRUE, FALSE,
5021 EL_YAMYAM_RIGHT, -1, -1
5024 Xeater_w, TRUE, FALSE,
5025 EL_YAMYAM_LEFT, -1, -1
5028 Xeater_s, TRUE, FALSE,
5029 EL_YAMYAM_DOWN, -1, -1
5032 Yeater_n, FALSE, FALSE,
5033 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
5036 Yeater_nB, FALSE, TRUE,
5037 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
5040 Yeater_e, FALSE, FALSE,
5041 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
5044 Yeater_eB, FALSE, TRUE,
5045 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
5048 Yeater_s, FALSE, FALSE,
5049 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
5052 Yeater_sB, FALSE, TRUE,
5053 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
5056 Yeater_w, FALSE, FALSE,
5057 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
5060 Yeater_wB, FALSE, TRUE,
5061 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
5064 Yeater_stone, FALSE, FALSE,
5065 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
5068 Yeater_spring, FALSE, FALSE,
5069 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
5072 Xalien, TRUE, FALSE,
5076 Xalien_pause, FALSE, FALSE,
5080 Yalien_n, FALSE, FALSE,
5081 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
5084 Yalien_nB, FALSE, TRUE,
5085 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
5088 Yalien_e, FALSE, FALSE,
5089 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
5092 Yalien_eB, FALSE, TRUE,
5093 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
5096 Yalien_s, FALSE, FALSE,
5097 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
5100 Yalien_sB, FALSE, TRUE,
5101 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
5104 Yalien_w, FALSE, FALSE,
5105 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
5108 Yalien_wB, FALSE, TRUE,
5109 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
5112 Yalien_stone, FALSE, FALSE,
5113 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
5116 Yalien_spring, FALSE, FALSE,
5117 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
5120 Xemerald, TRUE, FALSE,
5124 Xemerald_pause, FALSE, FALSE,
5128 Xemerald_fall, FALSE, FALSE,
5132 Xemerald_shine, FALSE, FALSE,
5133 EL_EMERALD, ACTION_TWINKLING, -1
5136 Yemerald_s, FALSE, FALSE,
5137 EL_EMERALD, ACTION_FALLING, -1
5140 Yemerald_sB, FALSE, TRUE,
5141 EL_EMERALD, ACTION_FALLING, -1
5144 Yemerald_e, FALSE, FALSE,
5145 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
5148 Yemerald_eB, FALSE, TRUE,
5149 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
5152 Yemerald_w, FALSE, FALSE,
5153 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
5156 Yemerald_wB, FALSE, TRUE,
5157 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
5160 Yemerald_eat, FALSE, FALSE,
5161 EL_EMERALD, ACTION_COLLECTING, -1
5164 Yemerald_stone, FALSE, FALSE,
5165 EL_NUT, ACTION_BREAKING, -1
5168 Xdiamond, TRUE, FALSE,
5172 Xdiamond_pause, FALSE, FALSE,
5176 Xdiamond_fall, FALSE, FALSE,
5180 Xdiamond_shine, FALSE, FALSE,
5181 EL_DIAMOND, ACTION_TWINKLING, -1
5184 Ydiamond_s, FALSE, FALSE,
5185 EL_DIAMOND, ACTION_FALLING, -1
5188 Ydiamond_sB, FALSE, TRUE,
5189 EL_DIAMOND, ACTION_FALLING, -1
5192 Ydiamond_e, FALSE, FALSE,
5193 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
5196 Ydiamond_eB, FALSE, TRUE,
5197 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
5200 Ydiamond_w, FALSE, FALSE,
5201 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
5204 Ydiamond_wB, FALSE, TRUE,
5205 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
5208 Ydiamond_eat, FALSE, FALSE,
5209 EL_DIAMOND, ACTION_COLLECTING, -1
5212 Ydiamond_stone, FALSE, FALSE,
5213 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
5216 Xdrip_fall, TRUE, FALSE,
5217 EL_AMOEBA_DROP, -1, -1
5220 Xdrip_stretch, FALSE, FALSE,
5221 EL_AMOEBA_DROP, ACTION_FALLING, -1
5224 Xdrip_stretchB, FALSE, TRUE,
5225 EL_AMOEBA_DROP, ACTION_FALLING, -1
5228 Xdrip_eat, FALSE, FALSE,
5229 EL_AMOEBA_DROP, ACTION_GROWING, -1
5232 Ydrip_s1, FALSE, FALSE,
5233 EL_AMOEBA_DROP, ACTION_FALLING, -1
5236 Ydrip_s1B, FALSE, TRUE,
5237 EL_AMOEBA_DROP, ACTION_FALLING, -1
5240 Ydrip_s2, FALSE, FALSE,
5241 EL_AMOEBA_DROP, ACTION_FALLING, -1
5244 Ydrip_s2B, FALSE, TRUE,
5245 EL_AMOEBA_DROP, ACTION_FALLING, -1
5252 Xbomb_pause, FALSE, FALSE,
5256 Xbomb_fall, FALSE, FALSE,
5260 Ybomb_s, FALSE, FALSE,
5261 EL_BOMB, ACTION_FALLING, -1
5264 Ybomb_sB, FALSE, TRUE,
5265 EL_BOMB, ACTION_FALLING, -1
5268 Ybomb_e, FALSE, FALSE,
5269 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
5272 Ybomb_eB, FALSE, TRUE,
5273 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
5276 Ybomb_w, FALSE, FALSE,
5277 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
5280 Ybomb_wB, FALSE, TRUE,
5281 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
5284 Ybomb_eat, FALSE, FALSE,
5285 EL_BOMB, ACTION_ACTIVATING, -1
5288 Xballoon, TRUE, FALSE,
5292 Yballoon_n, FALSE, FALSE,
5293 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
5296 Yballoon_nB, FALSE, TRUE,
5297 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
5300 Yballoon_e, FALSE, FALSE,
5301 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
5304 Yballoon_eB, FALSE, TRUE,
5305 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
5308 Yballoon_s, FALSE, FALSE,
5309 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
5312 Yballoon_sB, FALSE, TRUE,
5313 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
5316 Yballoon_w, FALSE, FALSE,
5317 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
5320 Yballoon_wB, FALSE, TRUE,
5321 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
5324 Xgrass, TRUE, FALSE,
5325 EL_EMC_GRASS, -1, -1
5328 Ygrass_nB, FALSE, FALSE,
5329 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
5332 Ygrass_eB, FALSE, FALSE,
5333 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
5336 Ygrass_sB, FALSE, FALSE,
5337 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
5340 Ygrass_wB, FALSE, FALSE,
5341 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
5348 Ydirt_nB, FALSE, FALSE,
5349 EL_SAND, ACTION_DIGGING, MV_BIT_UP
5352 Ydirt_eB, FALSE, FALSE,
5353 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
5356 Ydirt_sB, FALSE, FALSE,
5357 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
5360 Ydirt_wB, FALSE, FALSE,
5361 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
5364 Xacid_ne, TRUE, FALSE,
5365 EL_ACID_POOL_TOPRIGHT, -1, -1
5368 Xacid_se, TRUE, FALSE,
5369 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
5372 Xacid_s, TRUE, FALSE,
5373 EL_ACID_POOL_BOTTOM, -1, -1
5376 Xacid_sw, TRUE, FALSE,
5377 EL_ACID_POOL_BOTTOMLEFT, -1, -1
5380 Xacid_nw, TRUE, FALSE,
5381 EL_ACID_POOL_TOPLEFT, -1, -1
5384 Xacid_1, TRUE, FALSE,
5388 Xacid_2, FALSE, FALSE,
5392 Xacid_3, FALSE, FALSE,
5396 Xacid_4, FALSE, FALSE,
5400 Xacid_5, FALSE, FALSE,
5404 Xacid_6, FALSE, FALSE,
5408 Xacid_7, FALSE, FALSE,
5412 Xacid_8, FALSE, FALSE,
5416 Xball_1, TRUE, FALSE,
5417 EL_EMC_MAGIC_BALL, -1, -1
5420 Xball_1B, FALSE, FALSE,
5421 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5424 Xball_2, FALSE, FALSE,
5425 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5428 Xball_2B, FALSE, FALSE,
5429 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5432 Yball_eat, FALSE, FALSE,
5433 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
5436 Ykey_1_eat, FALSE, FALSE,
5437 EL_EM_KEY_1, ACTION_COLLECTING, -1
5440 Ykey_2_eat, FALSE, FALSE,
5441 EL_EM_KEY_2, ACTION_COLLECTING, -1
5444 Ykey_3_eat, FALSE, FALSE,
5445 EL_EM_KEY_3, ACTION_COLLECTING, -1
5448 Ykey_4_eat, FALSE, FALSE,
5449 EL_EM_KEY_4, ACTION_COLLECTING, -1
5452 Ykey_5_eat, FALSE, FALSE,
5453 EL_EMC_KEY_5, ACTION_COLLECTING, -1
5456 Ykey_6_eat, FALSE, FALSE,
5457 EL_EMC_KEY_6, ACTION_COLLECTING, -1
5460 Ykey_7_eat, FALSE, FALSE,
5461 EL_EMC_KEY_7, ACTION_COLLECTING, -1
5464 Ykey_8_eat, FALSE, FALSE,
5465 EL_EMC_KEY_8, ACTION_COLLECTING, -1
5468 Ylenses_eat, FALSE, FALSE,
5469 EL_EMC_LENSES, ACTION_COLLECTING, -1
5472 Ymagnify_eat, FALSE, FALSE,
5473 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
5476 Ygrass_eat, FALSE, FALSE,
5477 EL_EMC_GRASS, ACTION_SNAPPING, -1
5480 Ydirt_eat, FALSE, FALSE,
5481 EL_SAND, ACTION_SNAPPING, -1
5484 Xgrow_ns, TRUE, FALSE,
5485 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
5488 Ygrow_ns_eat, FALSE, FALSE,
5489 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
5492 Xgrow_ew, TRUE, FALSE,
5493 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
5496 Ygrow_ew_eat, FALSE, FALSE,
5497 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
5500 Xwonderwall, TRUE, FALSE,
5501 EL_MAGIC_WALL, -1, -1
5504 XwonderwallB, FALSE, FALSE,
5505 EL_MAGIC_WALL, ACTION_ACTIVE, -1
5508 Xamoeba_1, TRUE, FALSE,
5509 EL_AMOEBA_DRY, ACTION_OTHER, -1
5512 Xamoeba_2, FALSE, FALSE,
5513 EL_AMOEBA_DRY, ACTION_OTHER, -1
5516 Xamoeba_3, FALSE, FALSE,
5517 EL_AMOEBA_DRY, ACTION_OTHER, -1
5520 Xamoeba_4, FALSE, FALSE,
5521 EL_AMOEBA_DRY, ACTION_OTHER, -1
5524 Xamoeba_5, TRUE, FALSE,
5525 EL_AMOEBA_WET, ACTION_OTHER, -1
5528 Xamoeba_6, FALSE, FALSE,
5529 EL_AMOEBA_WET, ACTION_OTHER, -1
5532 Xamoeba_7, FALSE, FALSE,
5533 EL_AMOEBA_WET, ACTION_OTHER, -1
5536 Xamoeba_8, FALSE, FALSE,
5537 EL_AMOEBA_WET, ACTION_OTHER, -1
5540 Xdoor_1, TRUE, FALSE,
5541 EL_EM_GATE_1, -1, -1
5544 Xdoor_2, TRUE, FALSE,
5545 EL_EM_GATE_2, -1, -1
5548 Xdoor_3, TRUE, FALSE,
5549 EL_EM_GATE_3, -1, -1
5552 Xdoor_4, TRUE, FALSE,
5553 EL_EM_GATE_4, -1, -1
5556 Xdoor_5, TRUE, FALSE,
5557 EL_EMC_GATE_5, -1, -1
5560 Xdoor_6, TRUE, FALSE,
5561 EL_EMC_GATE_6, -1, -1
5564 Xdoor_7, TRUE, FALSE,
5565 EL_EMC_GATE_7, -1, -1
5568 Xdoor_8, TRUE, FALSE,
5569 EL_EMC_GATE_8, -1, -1
5572 Xkey_1, TRUE, FALSE,
5576 Xkey_2, TRUE, FALSE,
5580 Xkey_3, TRUE, FALSE,
5584 Xkey_4, TRUE, FALSE,
5588 Xkey_5, TRUE, FALSE,
5589 EL_EMC_KEY_5, -1, -1
5592 Xkey_6, TRUE, FALSE,
5593 EL_EMC_KEY_6, -1, -1
5596 Xkey_7, TRUE, FALSE,
5597 EL_EMC_KEY_7, -1, -1
5600 Xkey_8, TRUE, FALSE,
5601 EL_EMC_KEY_8, -1, -1
5604 Xwind_n, TRUE, FALSE,
5605 EL_BALLOON_SWITCH_UP, -1, -1
5608 Xwind_e, TRUE, FALSE,
5609 EL_BALLOON_SWITCH_RIGHT, -1, -1
5612 Xwind_s, TRUE, FALSE,
5613 EL_BALLOON_SWITCH_DOWN, -1, -1
5616 Xwind_w, TRUE, FALSE,
5617 EL_BALLOON_SWITCH_LEFT, -1, -1
5620 Xwind_nesw, TRUE, FALSE,
5621 EL_BALLOON_SWITCH_ANY, -1, -1
5624 Xwind_stop, TRUE, FALSE,
5625 EL_BALLOON_SWITCH_NONE, -1, -1
5629 EL_EM_EXIT_CLOSED, -1, -1
5632 Xexit_1, TRUE, FALSE,
5633 EL_EM_EXIT_OPEN, -1, -1
5636 Xexit_2, FALSE, FALSE,
5637 EL_EM_EXIT_OPEN, -1, -1
5640 Xexit_3, FALSE, FALSE,
5641 EL_EM_EXIT_OPEN, -1, -1
5644 Xdynamite, TRUE, FALSE,
5645 EL_EM_DYNAMITE, -1, -1
5648 Ydynamite_eat, FALSE, FALSE,
5649 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
5652 Xdynamite_1, TRUE, FALSE,
5653 EL_EM_DYNAMITE_ACTIVE, -1, -1
5656 Xdynamite_2, FALSE, FALSE,
5657 EL_EM_DYNAMITE_ACTIVE, -1, -1
5660 Xdynamite_3, FALSE, FALSE,
5661 EL_EM_DYNAMITE_ACTIVE, -1, -1
5664 Xdynamite_4, FALSE, FALSE,
5665 EL_EM_DYNAMITE_ACTIVE, -1, -1
5668 Xbumper, TRUE, FALSE,
5669 EL_EMC_SPRING_BUMPER, -1, -1
5672 XbumperB, FALSE, FALSE,
5673 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
5676 Xwheel, TRUE, FALSE,
5677 EL_ROBOT_WHEEL, -1, -1
5680 XwheelB, FALSE, FALSE,
5681 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
5684 Xswitch, TRUE, FALSE,
5685 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
5688 XswitchB, FALSE, FALSE,
5689 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
5693 EL_QUICKSAND_EMPTY, -1, -1
5696 Xsand_stone, TRUE, FALSE,
5697 EL_QUICKSAND_FULL, -1, -1
5700 Xsand_stonein_1, FALSE, TRUE,
5701 EL_ROCK, ACTION_FILLING, -1
5704 Xsand_stonein_2, FALSE, TRUE,
5705 EL_ROCK, ACTION_FILLING, -1
5708 Xsand_stonein_3, FALSE, TRUE,
5709 EL_ROCK, ACTION_FILLING, -1
5712 Xsand_stonein_4, FALSE, TRUE,
5713 EL_ROCK, ACTION_FILLING, -1
5716 Xsand_stonesand_1, FALSE, FALSE,
5717 EL_QUICKSAND_EMPTYING, -1, -1
5720 Xsand_stonesand_2, FALSE, FALSE,
5721 EL_QUICKSAND_EMPTYING, -1, -1
5724 Xsand_stonesand_3, FALSE, FALSE,
5725 EL_QUICKSAND_EMPTYING, -1, -1
5728 Xsand_stonesand_4, FALSE, FALSE,
5729 EL_QUICKSAND_EMPTYING, -1, -1
5732 Xsand_stonesand_quickout_1, FALSE, FALSE,
5733 EL_QUICKSAND_EMPTYING, -1, -1
5736 Xsand_stonesand_quickout_2, FALSE, FALSE,
5737 EL_QUICKSAND_EMPTYING, -1, -1
5740 Xsand_stoneout_1, FALSE, FALSE,
5741 EL_ROCK, ACTION_EMPTYING, -1
5744 Xsand_stoneout_2, FALSE, FALSE,
5745 EL_ROCK, ACTION_EMPTYING, -1
5748 Xsand_sandstone_1, FALSE, FALSE,
5749 EL_QUICKSAND_FILLING, -1, -1
5752 Xsand_sandstone_2, FALSE, FALSE,
5753 EL_QUICKSAND_FILLING, -1, -1
5756 Xsand_sandstone_3, FALSE, FALSE,
5757 EL_QUICKSAND_FILLING, -1, -1
5760 Xsand_sandstone_4, FALSE, FALSE,
5761 EL_QUICKSAND_FILLING, -1, -1
5764 Xplant, TRUE, FALSE,
5765 EL_EMC_PLANT, -1, -1
5768 Yplant, FALSE, FALSE,
5769 EL_EMC_PLANT, -1, -1
5772 Xlenses, TRUE, FALSE,
5773 EL_EMC_LENSES, -1, -1
5776 Xmagnify, TRUE, FALSE,
5777 EL_EMC_MAGNIFIER, -1, -1
5780 Xdripper, TRUE, FALSE,
5781 EL_EMC_DRIPPER, -1, -1
5784 XdripperB, FALSE, FALSE,
5785 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
5788 Xfake_blank, TRUE, FALSE,
5789 EL_INVISIBLE_WALL, -1, -1
5792 Xfake_blankB, FALSE, FALSE,
5793 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
5796 Xfake_grass, TRUE, FALSE,
5797 EL_EMC_FAKE_GRASS, -1, -1
5800 Xfake_grassB, FALSE, FALSE,
5801 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
5804 Xfake_door_1, TRUE, FALSE,
5805 EL_EM_GATE_1_GRAY, -1, -1
5808 Xfake_door_2, TRUE, FALSE,
5809 EL_EM_GATE_2_GRAY, -1, -1
5812 Xfake_door_3, TRUE, FALSE,
5813 EL_EM_GATE_3_GRAY, -1, -1
5816 Xfake_door_4, TRUE, FALSE,
5817 EL_EM_GATE_4_GRAY, -1, -1
5820 Xfake_door_5, TRUE, FALSE,
5821 EL_EMC_GATE_5_GRAY, -1, -1
5824 Xfake_door_6, TRUE, FALSE,
5825 EL_EMC_GATE_6_GRAY, -1, -1
5828 Xfake_door_7, TRUE, FALSE,
5829 EL_EMC_GATE_7_GRAY, -1, -1
5832 Xfake_door_8, TRUE, FALSE,
5833 EL_EMC_GATE_8_GRAY, -1, -1
5836 Xfake_acid_1, TRUE, FALSE,
5837 EL_EMC_FAKE_ACID, -1, -1
5840 Xfake_acid_2, FALSE, FALSE,
5841 EL_EMC_FAKE_ACID, -1, -1
5844 Xfake_acid_3, FALSE, FALSE,
5845 EL_EMC_FAKE_ACID, -1, -1
5848 Xfake_acid_4, FALSE, FALSE,
5849 EL_EMC_FAKE_ACID, -1, -1
5852 Xfake_acid_5, FALSE, FALSE,
5853 EL_EMC_FAKE_ACID, -1, -1
5856 Xfake_acid_6, FALSE, FALSE,
5857 EL_EMC_FAKE_ACID, -1, -1
5860 Xfake_acid_7, FALSE, FALSE,
5861 EL_EMC_FAKE_ACID, -1, -1
5864 Xfake_acid_8, FALSE, FALSE,
5865 EL_EMC_FAKE_ACID, -1, -1
5868 Xsteel_1, TRUE, FALSE,
5869 EL_STEELWALL, -1, -1
5872 Xsteel_2, TRUE, FALSE,
5873 EL_EMC_STEELWALL_2, -1, -1
5876 Xsteel_3, TRUE, FALSE,
5877 EL_EMC_STEELWALL_3, -1, -1
5880 Xsteel_4, TRUE, FALSE,
5881 EL_EMC_STEELWALL_4, -1, -1
5884 Xwall_1, TRUE, FALSE,
5888 Xwall_2, TRUE, FALSE,
5889 EL_EMC_WALL_14, -1, -1
5892 Xwall_3, TRUE, FALSE,
5893 EL_EMC_WALL_15, -1, -1
5896 Xwall_4, TRUE, FALSE,
5897 EL_EMC_WALL_16, -1, -1
5900 Xround_wall_1, TRUE, FALSE,
5901 EL_WALL_SLIPPERY, -1, -1
5904 Xround_wall_2, TRUE, FALSE,
5905 EL_EMC_WALL_SLIPPERY_2, -1, -1
5908 Xround_wall_3, TRUE, FALSE,
5909 EL_EMC_WALL_SLIPPERY_3, -1, -1
5912 Xround_wall_4, TRUE, FALSE,
5913 EL_EMC_WALL_SLIPPERY_4, -1, -1
5916 Xdecor_1, TRUE, FALSE,
5917 EL_EMC_WALL_8, -1, -1
5920 Xdecor_2, TRUE, FALSE,
5921 EL_EMC_WALL_6, -1, -1
5924 Xdecor_3, TRUE, FALSE,
5925 EL_EMC_WALL_4, -1, -1
5928 Xdecor_4, TRUE, FALSE,
5929 EL_EMC_WALL_7, -1, -1
5932 Xdecor_5, TRUE, FALSE,
5933 EL_EMC_WALL_5, -1, -1
5936 Xdecor_6, TRUE, FALSE,
5937 EL_EMC_WALL_9, -1, -1
5940 Xdecor_7, TRUE, FALSE,
5941 EL_EMC_WALL_10, -1, -1
5944 Xdecor_8, TRUE, FALSE,
5945 EL_EMC_WALL_1, -1, -1
5948 Xdecor_9, TRUE, FALSE,
5949 EL_EMC_WALL_2, -1, -1
5952 Xdecor_10, TRUE, FALSE,
5953 EL_EMC_WALL_3, -1, -1
5956 Xdecor_11, TRUE, FALSE,
5957 EL_EMC_WALL_11, -1, -1
5960 Xdecor_12, TRUE, FALSE,
5961 EL_EMC_WALL_12, -1, -1
5964 Xalpha_0, TRUE, FALSE,
5965 EL_CHAR('0'), -1, -1
5968 Xalpha_1, TRUE, FALSE,
5969 EL_CHAR('1'), -1, -1
5972 Xalpha_2, TRUE, FALSE,
5973 EL_CHAR('2'), -1, -1
5976 Xalpha_3, TRUE, FALSE,
5977 EL_CHAR('3'), -1, -1
5980 Xalpha_4, TRUE, FALSE,
5981 EL_CHAR('4'), -1, -1
5984 Xalpha_5, TRUE, FALSE,
5985 EL_CHAR('5'), -1, -1
5988 Xalpha_6, TRUE, FALSE,
5989 EL_CHAR('6'), -1, -1
5992 Xalpha_7, TRUE, FALSE,
5993 EL_CHAR('7'), -1, -1
5996 Xalpha_8, TRUE, FALSE,
5997 EL_CHAR('8'), -1, -1
6000 Xalpha_9, TRUE, FALSE,
6001 EL_CHAR('9'), -1, -1
6004 Xalpha_excla, TRUE, FALSE,
6005 EL_CHAR('!'), -1, -1
6008 Xalpha_quote, TRUE, FALSE,
6009 EL_CHAR('"'), -1, -1
6012 Xalpha_comma, TRUE, FALSE,
6013 EL_CHAR(','), -1, -1
6016 Xalpha_minus, TRUE, FALSE,
6017 EL_CHAR('-'), -1, -1
6020 Xalpha_perio, TRUE, FALSE,
6021 EL_CHAR('.'), -1, -1
6024 Xalpha_colon, TRUE, FALSE,
6025 EL_CHAR(':'), -1, -1
6028 Xalpha_quest, TRUE, FALSE,
6029 EL_CHAR('?'), -1, -1
6032 Xalpha_a, TRUE, FALSE,
6033 EL_CHAR('A'), -1, -1
6036 Xalpha_b, TRUE, FALSE,
6037 EL_CHAR('B'), -1, -1
6040 Xalpha_c, TRUE, FALSE,
6041 EL_CHAR('C'), -1, -1
6044 Xalpha_d, TRUE, FALSE,
6045 EL_CHAR('D'), -1, -1
6048 Xalpha_e, TRUE, FALSE,
6049 EL_CHAR('E'), -1, -1
6052 Xalpha_f, TRUE, FALSE,
6053 EL_CHAR('F'), -1, -1
6056 Xalpha_g, TRUE, FALSE,
6057 EL_CHAR('G'), -1, -1
6060 Xalpha_h, TRUE, FALSE,
6061 EL_CHAR('H'), -1, -1
6064 Xalpha_i, TRUE, FALSE,
6065 EL_CHAR('I'), -1, -1
6068 Xalpha_j, TRUE, FALSE,
6069 EL_CHAR('J'), -1, -1
6072 Xalpha_k, TRUE, FALSE,
6073 EL_CHAR('K'), -1, -1
6076 Xalpha_l, TRUE, FALSE,
6077 EL_CHAR('L'), -1, -1
6080 Xalpha_m, TRUE, FALSE,
6081 EL_CHAR('M'), -1, -1
6084 Xalpha_n, TRUE, FALSE,
6085 EL_CHAR('N'), -1, -1
6088 Xalpha_o, TRUE, FALSE,
6089 EL_CHAR('O'), -1, -1
6092 Xalpha_p, TRUE, FALSE,
6093 EL_CHAR('P'), -1, -1
6096 Xalpha_q, TRUE, FALSE,
6097 EL_CHAR('Q'), -1, -1
6100 Xalpha_r, TRUE, FALSE,
6101 EL_CHAR('R'), -1, -1
6104 Xalpha_s, TRUE, FALSE,
6105 EL_CHAR('S'), -1, -1
6108 Xalpha_t, TRUE, FALSE,
6109 EL_CHAR('T'), -1, -1
6112 Xalpha_u, TRUE, FALSE,
6113 EL_CHAR('U'), -1, -1
6116 Xalpha_v, TRUE, FALSE,
6117 EL_CHAR('V'), -1, -1
6120 Xalpha_w, TRUE, FALSE,
6121 EL_CHAR('W'), -1, -1
6124 Xalpha_x, TRUE, FALSE,
6125 EL_CHAR('X'), -1, -1
6128 Xalpha_y, TRUE, FALSE,
6129 EL_CHAR('Y'), -1, -1
6132 Xalpha_z, TRUE, FALSE,
6133 EL_CHAR('Z'), -1, -1
6136 Xalpha_arrow_e, TRUE, FALSE,
6137 EL_CHAR('>'), -1, -1
6140 Xalpha_arrow_w, TRUE, FALSE,
6141 EL_CHAR('<'), -1, -1
6144 Xalpha_copyr, TRUE, FALSE,
6145 EL_CHAR(CHAR_BYTE_COPYRIGHT), -1, -1
6149 Xboom_bug, FALSE, FALSE,
6150 EL_BUG, ACTION_EXPLODING, -1
6153 Xboom_bomb, FALSE, FALSE,
6154 EL_BOMB, ACTION_EXPLODING, -1
6157 Xboom_android, FALSE, FALSE,
6158 EL_EMC_ANDROID, ACTION_OTHER, -1
6161 Xboom_1, FALSE, FALSE,
6162 EL_DEFAULT, ACTION_EXPLODING, -1
6165 Xboom_2, FALSE, FALSE,
6166 EL_DEFAULT, ACTION_EXPLODING, -1
6169 Znormal, FALSE, FALSE,
6173 Zdynamite, FALSE, FALSE,
6177 Zplayer, FALSE, FALSE,
6181 ZBORDER, FALSE, FALSE,
6191 static struct Mapping_EM_to_RND_player
6200 em_player_mapping_list[] =
6204 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
6208 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
6212 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
6216 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
6220 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
6224 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
6228 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
6232 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
6236 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
6240 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
6244 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
6248 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
6252 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
6256 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
6260 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
6264 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
6268 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
6272 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
6276 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
6280 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
6284 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
6288 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
6292 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
6296 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
6300 EL_PLAYER_1, ACTION_DEFAULT, -1,
6304 EL_PLAYER_2, ACTION_DEFAULT, -1,
6308 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
6312 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
6316 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
6320 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
6324 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
6328 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
6332 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
6336 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
6340 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
6344 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
6348 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
6352 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
6356 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
6360 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
6364 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
6368 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
6372 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
6376 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
6380 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
6384 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
6388 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
6392 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
6396 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
6400 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
6404 EL_PLAYER_3, ACTION_DEFAULT, -1,
6408 EL_PLAYER_4, ACTION_DEFAULT, -1,
6417 int map_element_RND_to_EM(int element_rnd)
6419 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
6420 static boolean mapping_initialized = FALSE;
6422 if (!mapping_initialized)
6426 /* return "Xalpha_quest" for all undefined elements in mapping array */
6427 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
6428 mapping_RND_to_EM[i] = Xalpha_quest;
6430 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6431 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
6432 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
6433 em_object_mapping_list[i].element_em;
6435 mapping_initialized = TRUE;
6438 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
6439 return mapping_RND_to_EM[element_rnd];
6441 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
6446 int map_element_EM_to_RND(int element_em)
6448 static unsigned short mapping_EM_to_RND[TILE_MAX];
6449 static boolean mapping_initialized = FALSE;
6451 if (!mapping_initialized)
6455 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
6456 for (i = 0; i < TILE_MAX; i++)
6457 mapping_EM_to_RND[i] = EL_UNKNOWN;
6459 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6460 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
6461 em_object_mapping_list[i].element_rnd;
6463 mapping_initialized = TRUE;
6466 if (element_em >= 0 && element_em < TILE_MAX)
6467 return mapping_EM_to_RND[element_em];
6469 Error(ERR_WARN, "invalid EM level element %d", element_em);
6474 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
6476 struct LevelInfo_EM *level_em = level->native_em_level;
6477 struct LEVEL *lev = level_em->lev;
6480 for (i = 0; i < TILE_MAX; i++)
6481 lev->android_array[i] = Xblank;
6483 for (i = 0; i < level->num_android_clone_elements; i++)
6485 int element_rnd = level->android_clone_element[i];
6486 int element_em = map_element_RND_to_EM(element_rnd);
6488 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
6489 if (em_object_mapping_list[j].element_rnd == element_rnd)
6490 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
6494 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
6496 struct LevelInfo_EM *level_em = level->native_em_level;
6497 struct LEVEL *lev = level_em->lev;
6500 level->num_android_clone_elements = 0;
6502 for (i = 0; i < TILE_MAX; i++)
6504 int element_em = lev->android_array[i];
6506 boolean element_found = FALSE;
6508 if (element_em == Xblank)
6511 element_rnd = map_element_EM_to_RND(element_em);
6513 for (j = 0; j < level->num_android_clone_elements; j++)
6514 if (level->android_clone_element[j] == element_rnd)
6515 element_found = TRUE;
6519 level->android_clone_element[level->num_android_clone_elements++] =
6522 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
6527 if (level->num_android_clone_elements == 0)
6529 level->num_android_clone_elements = 1;
6530 level->android_clone_element[0] = EL_EMPTY;
6534 int map_direction_RND_to_EM(int direction)
6536 return (direction == MV_UP ? 0 :
6537 direction == MV_RIGHT ? 1 :
6538 direction == MV_DOWN ? 2 :
6539 direction == MV_LEFT ? 3 :
6543 int map_direction_EM_to_RND(int direction)
6545 return (direction == 0 ? MV_UP :
6546 direction == 1 ? MV_RIGHT :
6547 direction == 2 ? MV_DOWN :
6548 direction == 3 ? MV_LEFT :
6552 int map_element_RND_to_SP(int element_rnd)
6554 int element_sp = 0x20; /* map unknown elements to yellow "hardware" */
6556 if (element_rnd >= EL_SP_START &&
6557 element_rnd <= EL_SP_END)
6558 element_sp = element_rnd - EL_SP_START;
6559 else if (element_rnd == EL_EMPTY_SPACE)
6561 else if (element_rnd == EL_INVISIBLE_WALL)
6567 int map_element_SP_to_RND(int element_sp)
6569 int element_rnd = EL_UNKNOWN;
6571 if (element_sp >= 0x00 &&
6573 element_rnd = EL_SP_START + element_sp;
6574 else if (element_sp == 0x28)
6575 element_rnd = EL_INVISIBLE_WALL;
6580 int map_action_SP_to_RND(int action_sp)
6584 case actActive: return ACTION_ACTIVE;
6585 case actImpact: return ACTION_IMPACT;
6586 case actExploding: return ACTION_EXPLODING;
6587 case actDigging: return ACTION_DIGGING;
6588 case actSnapping: return ACTION_SNAPPING;
6589 case actCollecting: return ACTION_COLLECTING;
6590 case actPassing: return ACTION_PASSING;
6591 case actPushing: return ACTION_PUSHING;
6592 case actDropping: return ACTION_DROPPING;
6594 default: return ACTION_DEFAULT;
6598 int get_next_element(int element)
6602 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
6603 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
6604 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
6605 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
6606 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
6607 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
6608 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
6609 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
6610 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
6611 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
6612 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
6614 default: return element;
6618 int el_act_dir2img(int element, int action, int direction)
6620 element = GFX_ELEMENT(element);
6621 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
6623 /* direction_graphic[][] == graphic[] for undefined direction graphics */
6624 return element_info[element].direction_graphic[action][direction];
6627 static int el_act_dir2crm(int element, int action, int direction)
6629 element = GFX_ELEMENT(element);
6630 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
6632 /* direction_graphic[][] == graphic[] for undefined direction graphics */
6633 return element_info[element].direction_crumbled[action][direction];
6636 int el_act2img(int element, int action)
6638 element = GFX_ELEMENT(element);
6640 return element_info[element].graphic[action];
6643 int el_act2crm(int element, int action)
6645 element = GFX_ELEMENT(element);
6647 return element_info[element].crumbled[action];
6650 int el_dir2img(int element, int direction)
6652 element = GFX_ELEMENT(element);
6654 return el_act_dir2img(element, ACTION_DEFAULT, direction);
6657 int el2baseimg(int element)
6659 return element_info[element].graphic[ACTION_DEFAULT];
6662 int el2img(int element)
6664 element = GFX_ELEMENT(element);
6666 return element_info[element].graphic[ACTION_DEFAULT];
6669 int el2edimg(int element)
6671 element = GFX_ELEMENT(element);
6673 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
6676 int el2preimg(int element)
6678 element = GFX_ELEMENT(element);
6680 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
6683 int el2panelimg(int element)
6685 element = GFX_ELEMENT(element);
6687 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL];
6690 int font2baseimg(int font_nr)
6692 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
6695 int getBeltNrFromBeltElement(int element)
6697 return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
6698 element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
6699 element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
6702 int getBeltNrFromBeltActiveElement(int element)
6704 return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
6705 element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
6706 element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
6709 int getBeltNrFromBeltSwitchElement(int element)
6711 return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
6712 element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
6713 element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
6716 int getBeltDirNrFromBeltElement(int element)
6718 static int belt_base_element[4] =
6720 EL_CONVEYOR_BELT_1_LEFT,
6721 EL_CONVEYOR_BELT_2_LEFT,
6722 EL_CONVEYOR_BELT_3_LEFT,
6723 EL_CONVEYOR_BELT_4_LEFT
6726 int belt_nr = getBeltNrFromBeltElement(element);
6727 int belt_dir_nr = element - belt_base_element[belt_nr];
6729 return (belt_dir_nr % 3);
6732 int getBeltDirNrFromBeltSwitchElement(int element)
6734 static int belt_base_element[4] =
6736 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
6737 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
6738 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
6739 EL_CONVEYOR_BELT_4_SWITCH_LEFT
6742 int belt_nr = getBeltNrFromBeltSwitchElement(element);
6743 int belt_dir_nr = element - belt_base_element[belt_nr];
6745 return (belt_dir_nr % 3);
6748 int getBeltDirFromBeltElement(int element)
6750 static int belt_move_dir[3] =
6757 int belt_dir_nr = getBeltDirNrFromBeltElement(element);
6759 return belt_move_dir[belt_dir_nr];
6762 int getBeltDirFromBeltSwitchElement(int element)
6764 static int belt_move_dir[3] =
6771 int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
6773 return belt_move_dir[belt_dir_nr];
6776 int getBeltElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
6778 static int belt_base_element[4] =
6780 EL_CONVEYOR_BELT_1_LEFT,
6781 EL_CONVEYOR_BELT_2_LEFT,
6782 EL_CONVEYOR_BELT_3_LEFT,
6783 EL_CONVEYOR_BELT_4_LEFT
6786 return belt_base_element[belt_nr] + belt_dir_nr;
6789 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
6791 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
6793 return getBeltElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
6796 int getBeltSwitchElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
6798 static int belt_base_element[4] =
6800 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
6801 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
6802 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
6803 EL_CONVEYOR_BELT_4_SWITCH_LEFT
6806 return belt_base_element[belt_nr] + belt_dir_nr;
6809 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
6811 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
6813 return getBeltSwitchElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
6816 boolean getTeamMode_EM()
6818 return game.team_mode;
6821 int getGameFrameDelay_EM(int native_em_game_frame_delay)
6823 int game_frame_delay_value;
6825 game_frame_delay_value =
6826 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
6827 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
6830 if (tape.playing && tape.warp_forward && !tape.pausing)
6831 game_frame_delay_value = 0;
6833 return game_frame_delay_value;
6836 unsigned int InitRND(int seed)
6838 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
6839 return InitEngineRandom_EM(seed);
6840 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
6841 return InitEngineRandom_SP(seed);
6843 return InitEngineRandom_RND(seed);
6846 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
6847 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
6849 inline static int get_effective_element_EM(int tile, int frame_em)
6851 int element = object_mapping[tile].element_rnd;
6852 int action = object_mapping[tile].action;
6853 boolean is_backside = object_mapping[tile].is_backside;
6854 boolean action_removing = (action == ACTION_DIGGING ||
6855 action == ACTION_SNAPPING ||
6856 action == ACTION_COLLECTING);
6862 case Yacid_splash_eB:
6863 case Yacid_splash_wB:
6864 return (frame_em > 5 ? EL_EMPTY : element);
6870 else /* frame_em == 7 */
6874 case Yacid_splash_eB:
6875 case Yacid_splash_wB:
6878 case Yemerald_stone:
6881 case Ydiamond_stone:
6885 case Xdrip_stretchB:
6904 case Xsand_stonein_1:
6905 case Xsand_stonein_2:
6906 case Xsand_stonein_3:
6907 case Xsand_stonein_4:
6911 return (is_backside || action_removing ? EL_EMPTY : element);
6916 inline static boolean check_linear_animation_EM(int tile)
6920 case Xsand_stonesand_1:
6921 case Xsand_stonesand_quickout_1:
6922 case Xsand_sandstone_1:
6923 case Xsand_stonein_1:
6924 case Xsand_stoneout_1:
6943 case Yacid_splash_eB:
6944 case Yacid_splash_wB:
6945 case Yemerald_stone:
6952 inline static void set_crumbled_graphics_EM(struct GraphicInfo_EM *g_em,
6953 boolean has_crumbled_graphics,
6954 int crumbled, int sync_frame)
6956 /* if element can be crumbled, but certain action graphics are just empty
6957 space (like instantly snapping sand to empty space in 1 frame), do not
6958 treat these empty space graphics as crumbled graphics in EMC engine */
6959 if (crumbled == IMG_EMPTY_SPACE)
6960 has_crumbled_graphics = FALSE;
6962 if (has_crumbled_graphics)
6964 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
6965 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
6966 g_crumbled->anim_delay,
6967 g_crumbled->anim_mode,
6968 g_crumbled->anim_start_frame,
6971 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
6972 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
6974 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
6976 g_em->has_crumbled_graphics = TRUE;
6980 g_em->crumbled_bitmap = NULL;
6981 g_em->crumbled_src_x = 0;
6982 g_em->crumbled_src_y = 0;
6983 g_em->crumbled_border_size = 0;
6985 g_em->has_crumbled_graphics = FALSE;
6989 void ResetGfxAnimation_EM(int x, int y, int tile)
6994 void SetGfxAnimation_EM(struct GraphicInfo_EM *g_em,
6995 int tile, int frame_em, int x, int y)
6997 int action = object_mapping[tile].action;
6998 int direction = object_mapping[tile].direction;
6999 int effective_element = get_effective_element_EM(tile, frame_em);
7000 int graphic = (direction == MV_NONE ?
7001 el_act2img(effective_element, action) :
7002 el_act_dir2img(effective_element, action, direction));
7003 struct GraphicInfo *g = &graphic_info[graphic];
7005 boolean action_removing = (action == ACTION_DIGGING ||
7006 action == ACTION_SNAPPING ||
7007 action == ACTION_COLLECTING);
7008 boolean action_moving = (action == ACTION_FALLING ||
7009 action == ACTION_MOVING ||
7010 action == ACTION_PUSHING ||
7011 action == ACTION_EATING ||
7012 action == ACTION_FILLING ||
7013 action == ACTION_EMPTYING);
7014 boolean action_falling = (action == ACTION_FALLING ||
7015 action == ACTION_FILLING ||
7016 action == ACTION_EMPTYING);
7018 /* special case: graphic uses "2nd movement tile" and has defined
7019 7 frames for movement animation (or less) => use default graphic
7020 for last (8th) frame which ends the movement animation */
7021 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
7023 action = ACTION_DEFAULT; /* (keep action_* unchanged for now) */
7024 graphic = (direction == MV_NONE ?
7025 el_act2img(effective_element, action) :
7026 el_act_dir2img(effective_element, action, direction));
7028 g = &graphic_info[graphic];
7031 if ((action_removing || check_linear_animation_EM(tile)) && frame_em == 0)
7035 else if (action_moving)
7037 boolean is_backside = object_mapping[tile].is_backside;
7041 int direction = object_mapping[tile].direction;
7042 int move_dir = (action_falling ? MV_DOWN : direction);
7047 /* !!! TEST !!! NEW !!! DOES NOT WORK RIGHT YET !!! */
7048 if (g->double_movement && frame_em == 0)
7052 if (move_dir == MV_LEFT)
7053 GfxFrame[x - 1][y] = GfxFrame[x][y];
7054 else if (move_dir == MV_RIGHT)
7055 GfxFrame[x + 1][y] = GfxFrame[x][y];
7056 else if (move_dir == MV_UP)
7057 GfxFrame[x][y - 1] = GfxFrame[x][y];
7058 else if (move_dir == MV_DOWN)
7059 GfxFrame[x][y + 1] = GfxFrame[x][y];
7066 /* special case: animation for Xsand_stonesand_quickout_1/2 twice as fast */
7067 if (tile == Xsand_stonesand_quickout_1 ||
7068 tile == Xsand_stonesand_quickout_2)
7072 if (graphic_info[graphic].anim_global_sync)
7073 sync_frame = FrameCounter;
7074 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
7075 sync_frame = GfxFrame[x][y];
7077 sync_frame = 0; /* playfield border (pseudo steel) */
7079 SetRandomAnimationValue(x, y);
7081 int frame = getAnimationFrame(g->anim_frames,
7084 g->anim_start_frame,
7087 g_em->unique_identifier =
7088 (graphic << 16) | ((frame % 8) << 12) | (g_em->width << 6) | g_em->height;
7091 void getGraphicSourceObjectExt_EM(struct GraphicInfo_EM *g_em,
7092 int tile, int frame_em, int x, int y)
7094 int action = object_mapping[tile].action;
7095 int direction = object_mapping[tile].direction;
7096 boolean is_backside = object_mapping[tile].is_backside;
7097 int effective_element = get_effective_element_EM(tile, frame_em);
7098 int effective_action = action;
7099 int graphic = (direction == MV_NONE ?
7100 el_act2img(effective_element, effective_action) :
7101 el_act_dir2img(effective_element, effective_action,
7103 int crumbled = (direction == MV_NONE ?
7104 el_act2crm(effective_element, effective_action) :
7105 el_act_dir2crm(effective_element, effective_action,
7107 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7108 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7109 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7110 struct GraphicInfo *g = &graphic_info[graphic];
7113 /* special case: graphic uses "2nd movement tile" and has defined
7114 7 frames for movement animation (or less) => use default graphic
7115 for last (8th) frame which ends the movement animation */
7116 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
7118 effective_action = ACTION_DEFAULT;
7119 graphic = (direction == MV_NONE ?
7120 el_act2img(effective_element, effective_action) :
7121 el_act_dir2img(effective_element, effective_action,
7123 crumbled = (direction == MV_NONE ?
7124 el_act2crm(effective_element, effective_action) :
7125 el_act_dir2crm(effective_element, effective_action,
7128 g = &graphic_info[graphic];
7131 if (graphic_info[graphic].anim_global_sync)
7132 sync_frame = FrameCounter;
7133 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
7134 sync_frame = GfxFrame[x][y];
7136 sync_frame = 0; /* playfield border (pseudo steel) */
7138 SetRandomAnimationValue(x, y);
7140 int frame = getAnimationFrame(g->anim_frames,
7143 g->anim_start_frame,
7146 getGraphicSourceExt(graphic, frame, &g_em->bitmap, &g_em->src_x, &g_em->src_y,
7147 g->double_movement && is_backside);
7149 /* (updating the "crumbled" graphic definitions is probably not really needed,
7150 as animations for crumbled graphics can't be longer than one EMC cycle) */
7151 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
7155 void getGraphicSourcePlayerExt_EM(struct GraphicInfo_EM *g_em,
7156 int player_nr, int anim, int frame_em)
7158 int element = player_mapping[player_nr][anim].element_rnd;
7159 int action = player_mapping[player_nr][anim].action;
7160 int direction = player_mapping[player_nr][anim].direction;
7161 int graphic = (direction == MV_NONE ?
7162 el_act2img(element, action) :
7163 el_act_dir2img(element, action, direction));
7164 struct GraphicInfo *g = &graphic_info[graphic];
7167 InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
7169 stored_player[player_nr].StepFrame = frame_em;
7171 sync_frame = stored_player[player_nr].Frame;
7173 int frame = getAnimationFrame(g->anim_frames,
7176 g->anim_start_frame,
7179 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
7180 &g_em->src_x, &g_em->src_y, FALSE);
7183 void InitGraphicInfo_EM(void)
7188 int num_em_gfx_errors = 0;
7190 if (graphic_info_em_object[0][0].bitmap == NULL)
7192 /* EM graphics not yet initialized in em_open_all() */
7197 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
7200 /* always start with reliable default values */
7201 for (i = 0; i < TILE_MAX; i++)
7203 object_mapping[i].element_rnd = EL_UNKNOWN;
7204 object_mapping[i].is_backside = FALSE;
7205 object_mapping[i].action = ACTION_DEFAULT;
7206 object_mapping[i].direction = MV_NONE;
7209 /* always start with reliable default values */
7210 for (p = 0; p < MAX_PLAYERS; p++)
7212 for (i = 0; i < SPR_MAX; i++)
7214 player_mapping[p][i].element_rnd = EL_UNKNOWN;
7215 player_mapping[p][i].action = ACTION_DEFAULT;
7216 player_mapping[p][i].direction = MV_NONE;
7220 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
7222 int e = em_object_mapping_list[i].element_em;
7224 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
7225 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
7227 if (em_object_mapping_list[i].action != -1)
7228 object_mapping[e].action = em_object_mapping_list[i].action;
7230 if (em_object_mapping_list[i].direction != -1)
7231 object_mapping[e].direction =
7232 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
7235 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
7237 int a = em_player_mapping_list[i].action_em;
7238 int p = em_player_mapping_list[i].player_nr;
7240 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
7242 if (em_player_mapping_list[i].action != -1)
7243 player_mapping[p][a].action = em_player_mapping_list[i].action;
7245 if (em_player_mapping_list[i].direction != -1)
7246 player_mapping[p][a].direction =
7247 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
7250 for (i = 0; i < TILE_MAX; i++)
7252 int element = object_mapping[i].element_rnd;
7253 int action = object_mapping[i].action;
7254 int direction = object_mapping[i].direction;
7255 boolean is_backside = object_mapping[i].is_backside;
7256 boolean action_exploding = ((action == ACTION_EXPLODING ||
7257 action == ACTION_SMASHED_BY_ROCK ||
7258 action == ACTION_SMASHED_BY_SPRING) &&
7259 element != EL_DIAMOND);
7260 boolean action_active = (action == ACTION_ACTIVE);
7261 boolean action_other = (action == ACTION_OTHER);
7263 for (j = 0; j < 8; j++)
7265 int effective_element = get_effective_element_EM(i, j);
7266 int effective_action = (j < 7 ? action :
7267 i == Xdrip_stretch ? action :
7268 i == Xdrip_stretchB ? action :
7269 i == Ydrip_s1 ? action :
7270 i == Ydrip_s1B ? action :
7271 i == Xball_1B ? action :
7272 i == Xball_2 ? action :
7273 i == Xball_2B ? action :
7274 i == Yball_eat ? action :
7275 i == Ykey_1_eat ? action :
7276 i == Ykey_2_eat ? action :
7277 i == Ykey_3_eat ? action :
7278 i == Ykey_4_eat ? action :
7279 i == Ykey_5_eat ? action :
7280 i == Ykey_6_eat ? action :
7281 i == Ykey_7_eat ? action :
7282 i == Ykey_8_eat ? action :
7283 i == Ylenses_eat ? action :
7284 i == Ymagnify_eat ? action :
7285 i == Ygrass_eat ? action :
7286 i == Ydirt_eat ? action :
7287 i == Xsand_stonein_1 ? action :
7288 i == Xsand_stonein_2 ? action :
7289 i == Xsand_stonein_3 ? action :
7290 i == Xsand_stonein_4 ? action :
7291 i == Xsand_stoneout_1 ? action :
7292 i == Xsand_stoneout_2 ? action :
7293 i == Xboom_android ? ACTION_EXPLODING :
7294 action_exploding ? ACTION_EXPLODING :
7295 action_active ? action :
7296 action_other ? action :
7298 int graphic = (el_act_dir2img(effective_element, effective_action,
7300 int crumbled = (el_act_dir2crm(effective_element, effective_action,
7302 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7303 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7304 boolean has_action_graphics = (graphic != base_graphic);
7305 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7306 struct GraphicInfo *g = &graphic_info[graphic];
7307 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7310 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
7311 boolean special_animation = (action != ACTION_DEFAULT &&
7312 g->anim_frames == 3 &&
7313 g->anim_delay == 2 &&
7314 g->anim_mode & ANIM_LINEAR);
7315 int sync_frame = (i == Xdrip_stretch ? 7 :
7316 i == Xdrip_stretchB ? 7 :
7317 i == Ydrip_s2 ? j + 8 :
7318 i == Ydrip_s2B ? j + 8 :
7327 i == Xfake_acid_1 ? 0 :
7328 i == Xfake_acid_2 ? 10 :
7329 i == Xfake_acid_3 ? 20 :
7330 i == Xfake_acid_4 ? 30 :
7331 i == Xfake_acid_5 ? 40 :
7332 i == Xfake_acid_6 ? 50 :
7333 i == Xfake_acid_7 ? 60 :
7334 i == Xfake_acid_8 ? 70 :
7336 i == Xball_2B ? j + 8 :
7337 i == Yball_eat ? j + 1 :
7338 i == Ykey_1_eat ? j + 1 :
7339 i == Ykey_2_eat ? j + 1 :
7340 i == Ykey_3_eat ? j + 1 :
7341 i == Ykey_4_eat ? j + 1 :
7342 i == Ykey_5_eat ? j + 1 :
7343 i == Ykey_6_eat ? j + 1 :
7344 i == Ykey_7_eat ? j + 1 :
7345 i == Ykey_8_eat ? j + 1 :
7346 i == Ylenses_eat ? j + 1 :
7347 i == Ymagnify_eat ? j + 1 :
7348 i == Ygrass_eat ? j + 1 :
7349 i == Ydirt_eat ? j + 1 :
7350 i == Xamoeba_1 ? 0 :
7351 i == Xamoeba_2 ? 1 :
7352 i == Xamoeba_3 ? 2 :
7353 i == Xamoeba_4 ? 3 :
7354 i == Xamoeba_5 ? 0 :
7355 i == Xamoeba_6 ? 1 :
7356 i == Xamoeba_7 ? 2 :
7357 i == Xamoeba_8 ? 3 :
7358 i == Xexit_2 ? j + 8 :
7359 i == Xexit_3 ? j + 16 :
7360 i == Xdynamite_1 ? 0 :
7361 i == Xdynamite_2 ? 8 :
7362 i == Xdynamite_3 ? 16 :
7363 i == Xdynamite_4 ? 24 :
7364 i == Xsand_stonein_1 ? j + 1 :
7365 i == Xsand_stonein_2 ? j + 9 :
7366 i == Xsand_stonein_3 ? j + 17 :
7367 i == Xsand_stonein_4 ? j + 25 :
7368 i == Xsand_stoneout_1 && j == 0 ? 0 :
7369 i == Xsand_stoneout_1 && j == 1 ? 0 :
7370 i == Xsand_stoneout_1 && j == 2 ? 1 :
7371 i == Xsand_stoneout_1 && j == 3 ? 2 :
7372 i == Xsand_stoneout_1 && j == 4 ? 2 :
7373 i == Xsand_stoneout_1 && j == 5 ? 3 :
7374 i == Xsand_stoneout_1 && j == 6 ? 4 :
7375 i == Xsand_stoneout_1 && j == 7 ? 4 :
7376 i == Xsand_stoneout_2 && j == 0 ? 5 :
7377 i == Xsand_stoneout_2 && j == 1 ? 6 :
7378 i == Xsand_stoneout_2 && j == 2 ? 7 :
7379 i == Xsand_stoneout_2 && j == 3 ? 8 :
7380 i == Xsand_stoneout_2 && j == 4 ? 9 :
7381 i == Xsand_stoneout_2 && j == 5 ? 11 :
7382 i == Xsand_stoneout_2 && j == 6 ? 13 :
7383 i == Xsand_stoneout_2 && j == 7 ? 15 :
7384 i == Xboom_bug && j == 1 ? 2 :
7385 i == Xboom_bug && j == 2 ? 2 :
7386 i == Xboom_bug && j == 3 ? 4 :
7387 i == Xboom_bug && j == 4 ? 4 :
7388 i == Xboom_bug && j == 5 ? 2 :
7389 i == Xboom_bug && j == 6 ? 2 :
7390 i == Xboom_bug && j == 7 ? 0 :
7391 i == Xboom_bomb && j == 1 ? 2 :
7392 i == Xboom_bomb && j == 2 ? 2 :
7393 i == Xboom_bomb && j == 3 ? 4 :
7394 i == Xboom_bomb && j == 4 ? 4 :
7395 i == Xboom_bomb && j == 5 ? 2 :
7396 i == Xboom_bomb && j == 6 ? 2 :
7397 i == Xboom_bomb && j == 7 ? 0 :
7398 i == Xboom_android && j == 7 ? 6 :
7399 i == Xboom_1 && j == 1 ? 2 :
7400 i == Xboom_1 && j == 2 ? 2 :
7401 i == Xboom_1 && j == 3 ? 4 :
7402 i == Xboom_1 && j == 4 ? 4 :
7403 i == Xboom_1 && j == 5 ? 6 :
7404 i == Xboom_1 && j == 6 ? 6 :
7405 i == Xboom_1 && j == 7 ? 8 :
7406 i == Xboom_2 && j == 0 ? 8 :
7407 i == Xboom_2 && j == 1 ? 8 :
7408 i == Xboom_2 && j == 2 ? 10 :
7409 i == Xboom_2 && j == 3 ? 10 :
7410 i == Xboom_2 && j == 4 ? 10 :
7411 i == Xboom_2 && j == 5 ? 12 :
7412 i == Xboom_2 && j == 6 ? 12 :
7413 i == Xboom_2 && j == 7 ? 12 :
7414 special_animation && j == 4 ? 3 :
7415 effective_action != action ? 0 :
7419 Bitmap *debug_bitmap = g_em->bitmap;
7420 int debug_src_x = g_em->src_x;
7421 int debug_src_y = g_em->src_y;
7424 int frame = getAnimationFrame(g->anim_frames,
7427 g->anim_start_frame,
7430 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
7431 g->double_movement && is_backside);
7433 g_em->bitmap = src_bitmap;
7434 g_em->src_x = src_x;
7435 g_em->src_y = src_y;
7436 g_em->src_offset_x = 0;
7437 g_em->src_offset_y = 0;
7438 g_em->dst_offset_x = 0;
7439 g_em->dst_offset_y = 0;
7440 g_em->width = TILEX;
7441 g_em->height = TILEY;
7443 g_em->preserve_background = FALSE;
7445 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
7448 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
7449 effective_action == ACTION_MOVING ||
7450 effective_action == ACTION_PUSHING ||
7451 effective_action == ACTION_EATING)) ||
7452 (!has_action_graphics && (effective_action == ACTION_FILLING ||
7453 effective_action == ACTION_EMPTYING)))
7456 (effective_action == ACTION_FALLING ||
7457 effective_action == ACTION_FILLING ||
7458 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
7459 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
7460 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
7461 int num_steps = (i == Ydrip_s1 ? 16 :
7462 i == Ydrip_s1B ? 16 :
7463 i == Ydrip_s2 ? 16 :
7464 i == Ydrip_s2B ? 16 :
7465 i == Xsand_stonein_1 ? 32 :
7466 i == Xsand_stonein_2 ? 32 :
7467 i == Xsand_stonein_3 ? 32 :
7468 i == Xsand_stonein_4 ? 32 :
7469 i == Xsand_stoneout_1 ? 16 :
7470 i == Xsand_stoneout_2 ? 16 : 8);
7471 int cx = ABS(dx) * (TILEX / num_steps);
7472 int cy = ABS(dy) * (TILEY / num_steps);
7473 int step_frame = (i == Ydrip_s2 ? j + 8 :
7474 i == Ydrip_s2B ? j + 8 :
7475 i == Xsand_stonein_2 ? j + 8 :
7476 i == Xsand_stonein_3 ? j + 16 :
7477 i == Xsand_stonein_4 ? j + 24 :
7478 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
7479 int step = (is_backside ? step_frame : num_steps - step_frame);
7481 if (is_backside) /* tile where movement starts */
7483 if (dx < 0 || dy < 0)
7485 g_em->src_offset_x = cx * step;
7486 g_em->src_offset_y = cy * step;
7490 g_em->dst_offset_x = cx * step;
7491 g_em->dst_offset_y = cy * step;
7494 else /* tile where movement ends */
7496 if (dx < 0 || dy < 0)
7498 g_em->dst_offset_x = cx * step;
7499 g_em->dst_offset_y = cy * step;
7503 g_em->src_offset_x = cx * step;
7504 g_em->src_offset_y = cy * step;
7508 g_em->width = TILEX - cx * step;
7509 g_em->height = TILEY - cy * step;
7512 /* create unique graphic identifier to decide if tile must be redrawn */
7513 /* bit 31 - 16 (16 bit): EM style graphic
7514 bit 15 - 12 ( 4 bit): EM style frame
7515 bit 11 - 6 ( 6 bit): graphic width
7516 bit 5 - 0 ( 6 bit): graphic height */
7517 g_em->unique_identifier =
7518 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
7522 /* skip check for EMC elements not contained in original EMC artwork */
7523 if (element == EL_EMC_FAKE_ACID)
7526 if (g_em->bitmap != debug_bitmap ||
7527 g_em->src_x != debug_src_x ||
7528 g_em->src_y != debug_src_y ||
7529 g_em->src_offset_x != 0 ||
7530 g_em->src_offset_y != 0 ||
7531 g_em->dst_offset_x != 0 ||
7532 g_em->dst_offset_y != 0 ||
7533 g_em->width != TILEX ||
7534 g_em->height != TILEY)
7536 static int last_i = -1;
7544 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
7545 i, element, element_info[element].token_name,
7546 element_action_info[effective_action].suffix, direction);
7548 if (element != effective_element)
7549 printf(" [%d ('%s')]",
7551 element_info[effective_element].token_name);
7555 if (g_em->bitmap != debug_bitmap)
7556 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
7557 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
7559 if (g_em->src_x != debug_src_x ||
7560 g_em->src_y != debug_src_y)
7561 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
7562 j, (is_backside ? 'B' : 'F'),
7563 g_em->src_x, g_em->src_y,
7564 g_em->src_x / 32, g_em->src_y / 32,
7565 debug_src_x, debug_src_y,
7566 debug_src_x / 32, debug_src_y / 32);
7568 if (g_em->src_offset_x != 0 ||
7569 g_em->src_offset_y != 0 ||
7570 g_em->dst_offset_x != 0 ||
7571 g_em->dst_offset_y != 0)
7572 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
7574 g_em->src_offset_x, g_em->src_offset_y,
7575 g_em->dst_offset_x, g_em->dst_offset_y);
7577 if (g_em->width != TILEX ||
7578 g_em->height != TILEY)
7579 printf(" %d (%d): size %d,%d should be %d,%d\n",
7581 g_em->width, g_em->height, TILEX, TILEY);
7583 num_em_gfx_errors++;
7590 for (i = 0; i < TILE_MAX; i++)
7592 for (j = 0; j < 8; j++)
7594 int element = object_mapping[i].element_rnd;
7595 int action = object_mapping[i].action;
7596 int direction = object_mapping[i].direction;
7597 boolean is_backside = object_mapping[i].is_backside;
7598 int graphic_action = el_act_dir2img(element, action, direction);
7599 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
7601 if ((action == ACTION_SMASHED_BY_ROCK ||
7602 action == ACTION_SMASHED_BY_SPRING ||
7603 action == ACTION_EATING) &&
7604 graphic_action == graphic_default)
7606 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
7607 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
7608 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
7609 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
7612 /* no separate animation for "smashed by rock" -- use rock instead */
7613 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7614 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
7616 g_em->bitmap = g_xx->bitmap;
7617 g_em->src_x = g_xx->src_x;
7618 g_em->src_y = g_xx->src_y;
7619 g_em->src_offset_x = g_xx->src_offset_x;
7620 g_em->src_offset_y = g_xx->src_offset_y;
7621 g_em->dst_offset_x = g_xx->dst_offset_x;
7622 g_em->dst_offset_y = g_xx->dst_offset_y;
7623 g_em->width = g_xx->width;
7624 g_em->height = g_xx->height;
7625 g_em->unique_identifier = g_xx->unique_identifier;
7628 g_em->preserve_background = TRUE;
7633 for (p = 0; p < MAX_PLAYERS; p++)
7635 for (i = 0; i < SPR_MAX; i++)
7637 int element = player_mapping[p][i].element_rnd;
7638 int action = player_mapping[p][i].action;
7639 int direction = player_mapping[p][i].direction;
7641 for (j = 0; j < 8; j++)
7643 int effective_element = element;
7644 int effective_action = action;
7645 int graphic = (direction == MV_NONE ?
7646 el_act2img(effective_element, effective_action) :
7647 el_act_dir2img(effective_element, effective_action,
7649 struct GraphicInfo *g = &graphic_info[graphic];
7650 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
7656 Bitmap *debug_bitmap = g_em->bitmap;
7657 int debug_src_x = g_em->src_x;
7658 int debug_src_y = g_em->src_y;
7661 int frame = getAnimationFrame(g->anim_frames,
7664 g->anim_start_frame,
7667 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
7669 g_em->bitmap = src_bitmap;
7670 g_em->src_x = src_x;
7671 g_em->src_y = src_y;
7672 g_em->src_offset_x = 0;
7673 g_em->src_offset_y = 0;
7674 g_em->dst_offset_x = 0;
7675 g_em->dst_offset_y = 0;
7676 g_em->width = TILEX;
7677 g_em->height = TILEY;
7681 /* skip check for EMC elements not contained in original EMC artwork */
7682 if (element == EL_PLAYER_3 ||
7683 element == EL_PLAYER_4)
7686 if (g_em->bitmap != debug_bitmap ||
7687 g_em->src_x != debug_src_x ||
7688 g_em->src_y != debug_src_y)
7690 static int last_i = -1;
7698 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
7699 p, i, element, element_info[element].token_name,
7700 element_action_info[effective_action].suffix, direction);
7702 if (element != effective_element)
7703 printf(" [%d ('%s')]",
7705 element_info[effective_element].token_name);
7709 if (g_em->bitmap != debug_bitmap)
7710 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
7711 j, (int)(g_em->bitmap), (int)(debug_bitmap));
7713 if (g_em->src_x != debug_src_x ||
7714 g_em->src_y != debug_src_y)
7715 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
7717 g_em->src_x, g_em->src_y,
7718 g_em->src_x / 32, g_em->src_y / 32,
7719 debug_src_x, debug_src_y,
7720 debug_src_x / 32, debug_src_y / 32);
7722 num_em_gfx_errors++;
7732 printf("::: [%d errors found]\n", num_em_gfx_errors);
7738 void CheckSaveEngineSnapshot_EM(byte action[MAX_PLAYERS], int frame,
7739 boolean any_player_moving,
7740 boolean any_player_snapping,
7741 boolean any_player_dropping)
7743 static boolean player_was_waiting = TRUE;
7745 if (frame == 0 && !any_player_dropping)
7747 if (!player_was_waiting)
7749 if (!SaveEngineSnapshotToList())
7752 player_was_waiting = TRUE;
7755 else if (any_player_moving || any_player_snapping || any_player_dropping)
7757 player_was_waiting = FALSE;
7761 void CheckSaveEngineSnapshot_SP(boolean murphy_is_waiting,
7762 boolean murphy_is_dropping)
7764 static boolean player_was_waiting = TRUE;
7766 if (murphy_is_waiting)
7768 if (!player_was_waiting)
7770 if (!SaveEngineSnapshotToList())
7773 player_was_waiting = TRUE;
7778 player_was_waiting = FALSE;
7782 void CheckSingleStepMode_EM(byte action[MAX_PLAYERS], int frame,
7783 boolean any_player_moving,
7784 boolean any_player_snapping,
7785 boolean any_player_dropping)
7787 if (tape.single_step && tape.recording && !tape.pausing)
7788 if (frame == 0 && !any_player_dropping)
7789 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
7791 CheckSaveEngineSnapshot_EM(action, frame, any_player_moving,
7792 any_player_snapping, any_player_dropping);
7795 void CheckSingleStepMode_SP(boolean murphy_is_waiting,
7796 boolean murphy_is_dropping)
7798 if (tape.single_step && tape.recording && !tape.pausing)
7799 if (murphy_is_waiting)
7800 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
7802 CheckSaveEngineSnapshot_SP(murphy_is_waiting, murphy_is_dropping);
7805 void getGraphicSource_SP(struct GraphicInfo_SP *g_sp,
7806 int graphic, int sync_frame, int x, int y)
7808 int frame = getGraphicAnimationFrame(graphic, sync_frame);
7810 getGraphicSource(graphic, frame, &g_sp->bitmap, &g_sp->src_x, &g_sp->src_y);
7813 boolean isNextAnimationFrame_SP(int graphic, int sync_frame)
7815 return (IS_NEXT_FRAME(sync_frame, graphic));
7818 int getGraphicInfo_Delay(int graphic)
7820 return graphic_info[graphic].anim_delay;
7823 void PlayMenuSoundExt(int sound)
7825 if (sound == SND_UNDEFINED)
7828 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
7829 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
7832 if (IS_LOOP_SOUND(sound))
7833 PlaySoundLoop(sound);
7838 void PlayMenuSound()
7840 PlayMenuSoundExt(menu.sound[game_status]);
7843 void PlayMenuSoundStereo(int sound, int stereo_position)
7845 if (sound == SND_UNDEFINED)
7848 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
7849 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
7852 if (IS_LOOP_SOUND(sound))
7853 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
7855 PlaySoundStereo(sound, stereo_position);
7858 void PlayMenuSoundIfLoopExt(int sound)
7860 if (sound == SND_UNDEFINED)
7863 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
7864 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
7867 if (IS_LOOP_SOUND(sound))
7868 PlaySoundLoop(sound);
7871 void PlayMenuSoundIfLoop()
7873 PlayMenuSoundIfLoopExt(menu.sound[game_status]);
7876 void PlayMenuMusicExt(int music)
7878 if (music == MUS_UNDEFINED)
7881 if (!setup.sound_music)
7887 void PlayMenuMusic()
7889 PlayMenuMusicExt(menu.music[game_status]);
7892 void PlaySoundActivating()
7895 PlaySound(SND_MENU_ITEM_ACTIVATING);
7899 void PlaySoundSelecting()
7902 PlaySound(SND_MENU_ITEM_SELECTING);
7906 void ToggleFullscreenOrChangeWindowScalingIfNeeded()
7908 boolean change_fullscreen = (setup.fullscreen !=
7909 video.fullscreen_enabled);
7910 boolean change_fullscreen_mode = (video.fullscreen_enabled &&
7911 !strEqual(setup.fullscreen_mode,
7912 video.fullscreen_mode_current));
7913 boolean change_window_scaling_percent = (!video.fullscreen_enabled &&
7914 setup.window_scaling_percent !=
7915 video.window_scaling_percent);
7917 if (change_window_scaling_percent && video.fullscreen_enabled)
7920 if (!change_window_scaling_percent && !video.fullscreen_available)
7923 #if defined(TARGET_SDL2)
7924 if (change_window_scaling_percent)
7926 SDLSetWindowScaling(setup.window_scaling_percent);
7930 else if (change_fullscreen)
7932 SDLSetWindowFullscreen(setup.fullscreen);
7934 /* set setup value according to successfully changed fullscreen mode */
7935 setup.fullscreen = video.fullscreen_enabled;
7941 if (change_fullscreen ||
7942 change_fullscreen_mode ||
7943 change_window_scaling_percent)
7945 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
7947 /* save backbuffer content which gets lost when toggling fullscreen mode */
7948 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
7950 if (change_fullscreen_mode)
7952 /* keep fullscreen, but change fullscreen mode (screen resolution) */
7953 video.fullscreen_enabled = FALSE; /* force new fullscreen mode */
7956 if (change_window_scaling_percent)
7958 /* keep window mode, but change window scaling */
7959 video.fullscreen_enabled = TRUE; /* force new window scaling */
7962 /* toggle fullscreen */
7963 ChangeVideoModeIfNeeded(setup.fullscreen);
7965 /* set setup value according to successfully changed fullscreen mode */
7966 setup.fullscreen = video.fullscreen_enabled;
7968 /* restore backbuffer content from temporary backbuffer backup bitmap */
7969 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
7971 FreeBitmap(tmp_backbuffer);
7973 /* update visible window/screen */
7974 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
7978 void ChangeViewportPropertiesIfNeeded()
7980 int gfx_game_mode = game_status;
7981 int gfx_game_mode2 = (game_status == GAME_MODE_EDITOR ? GAME_MODE_DEFAULT :
7983 struct RectWithBorder *vp_playfield = &viewport.playfield[gfx_game_mode];
7984 struct RectWithBorder *vp_door_1 = &viewport.door_1[gfx_game_mode];
7985 struct RectWithBorder *vp_door_2 = &viewport.door_2[gfx_game_mode2];
7986 struct RectWithBorder *vp_door_3 = &viewport.door_2[GAME_MODE_EDITOR];
7987 int border_size = vp_playfield->border_size;
7988 int new_sx = vp_playfield->x + border_size;
7989 int new_sy = vp_playfield->y + border_size;
7990 int new_sxsize = vp_playfield->width - 2 * border_size;
7991 int new_sysize = vp_playfield->height - 2 * border_size;
7992 int new_real_sx = vp_playfield->x;
7993 int new_real_sy = vp_playfield->y;
7994 int new_full_sxsize = vp_playfield->width;
7995 int new_full_sysize = vp_playfield->height;
7996 int new_dx = vp_door_1->x;
7997 int new_dy = vp_door_1->y;
7998 int new_dxsize = vp_door_1->width;
7999 int new_dysize = vp_door_1->height;
8000 int new_vx = vp_door_2->x;
8001 int new_vy = vp_door_2->y;
8002 int new_vxsize = vp_door_2->width;
8003 int new_vysize = vp_door_2->height;
8004 int new_ex = vp_door_3->x;
8005 int new_ey = vp_door_3->y;
8006 int new_exsize = vp_door_3->width;
8007 int new_eysize = vp_door_3->height;
8008 int new_tilesize_var =
8009 (setup.small_game_graphics ? MINI_TILESIZE : game.tile_size);
8011 int tilesize = (gfx_game_mode == GAME_MODE_PLAYING ? new_tilesize_var :
8012 gfx_game_mode == GAME_MODE_EDITOR ? MINI_TILESIZE : TILESIZE);
8013 int new_scr_fieldx = new_sxsize / tilesize;
8014 int new_scr_fieldy = new_sysize / tilesize;
8015 int new_scr_fieldx_buffers = new_sxsize / new_tilesize_var;
8016 int new_scr_fieldy_buffers = new_sysize / new_tilesize_var;
8017 boolean init_gfx_buffers = FALSE;
8018 boolean init_video_buffer = FALSE;
8019 boolean init_gadgets_and_toons = FALSE;
8020 boolean init_em_graphics = FALSE;
8021 boolean drawing_area_changed = FALSE;
8023 if (viewport.window.width != WIN_XSIZE ||
8024 viewport.window.height != WIN_YSIZE)
8026 WIN_XSIZE = viewport.window.width;
8027 WIN_YSIZE = viewport.window.height;
8029 init_video_buffer = TRUE;
8030 init_gfx_buffers = TRUE;
8032 // printf("::: video: init_video_buffer, init_gfx_buffers\n");
8035 if (new_scr_fieldx != SCR_FIELDX ||
8036 new_scr_fieldy != SCR_FIELDY)
8038 /* this always toggles between MAIN and GAME when using small tile size */
8040 SCR_FIELDX = new_scr_fieldx;
8041 SCR_FIELDY = new_scr_fieldy;
8043 // printf("::: new_scr_fieldx != SCR_FIELDX ...\n");
8054 new_sxsize != SXSIZE ||
8055 new_sysize != SYSIZE ||
8056 new_dxsize != DXSIZE ||
8057 new_dysize != DYSIZE ||
8058 new_vxsize != VXSIZE ||
8059 new_vysize != VYSIZE ||
8060 new_exsize != EXSIZE ||
8061 new_eysize != EYSIZE ||
8062 new_real_sx != REAL_SX ||
8063 new_real_sy != REAL_SY ||
8064 new_full_sxsize != FULL_SXSIZE ||
8065 new_full_sysize != FULL_SYSIZE ||
8066 new_tilesize_var != TILESIZE_VAR
8069 if (new_tilesize_var != TILESIZE_VAR)
8071 // printf("::: new_tilesize_var != TILESIZE_VAR\n");
8073 // changing tile size invalidates scroll values of engine snapshots
8074 FreeEngineSnapshotSingle();
8076 // changing tile size requires update of graphic mapping for EM engine
8077 init_em_graphics = TRUE;
8082 new_sxsize != SXSIZE ||
8083 new_sysize != SYSIZE ||
8084 new_real_sx != REAL_SX ||
8085 new_real_sy != REAL_SY ||
8086 new_full_sxsize != FULL_SXSIZE ||
8087 new_full_sysize != FULL_SYSIZE)
8089 if (!init_video_buffer)
8090 drawing_area_changed = TRUE;
8101 SXSIZE = new_sxsize;
8102 SYSIZE = new_sysize;
8103 DXSIZE = new_dxsize;
8104 DYSIZE = new_dysize;
8105 VXSIZE = new_vxsize;
8106 VYSIZE = new_vysize;
8107 EXSIZE = new_exsize;
8108 EYSIZE = new_eysize;
8109 REAL_SX = new_real_sx;
8110 REAL_SY = new_real_sy;
8111 FULL_SXSIZE = new_full_sxsize;
8112 FULL_SYSIZE = new_full_sysize;
8113 TILESIZE_VAR = new_tilesize_var;
8115 init_gfx_buffers = TRUE;
8116 init_gadgets_and_toons = TRUE;
8118 // printf("::: viewports: init_gfx_buffers\n");
8119 // printf("::: viewports: init_gadgets_and_toons\n");
8122 if (init_gfx_buffers)
8124 // printf("::: init_gfx_buffers\n");
8126 SCR_FIELDX = new_scr_fieldx_buffers;
8127 SCR_FIELDY = new_scr_fieldy_buffers;
8131 SCR_FIELDX = new_scr_fieldx;
8132 SCR_FIELDY = new_scr_fieldy;
8134 gfx.drawing_area_changed = drawing_area_changed;
8136 SetDrawDeactivationMask(REDRAW_NONE);
8137 SetDrawBackgroundMask(REDRAW_FIELD);
8140 if (init_video_buffer)
8142 // printf("::: init_video_buffer\n");
8144 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
8147 if (init_gadgets_and_toons)
8149 // printf("::: init_gadgets_and_toons\n");
8155 if (init_em_graphics)
8157 InitGraphicInfo_EM();