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 if (redraw_mask & REDRAW_ALL)
338 DrawMaskedBorder_ALL();
341 if (redraw_mask & REDRAW_FIELD)
342 DrawMaskedBorder_FIELD();
343 if (redraw_mask & REDRAW_DOOR_1)
344 DrawMaskedBorder_DOOR_1();
345 if (redraw_mask & REDRAW_DOOR_2)
346 DrawMaskedBorder_DOOR_2();
347 if (redraw_mask & REDRAW_DOOR_3)
348 DrawMaskedBorder_DOOR_3();
352 void BlitScreenToBitmap_RND(Bitmap *target_bitmap)
354 int fx = FX, fy = FY;
355 int full_lev_fieldx = lev_fieldx + (BorderElement != EL_EMPTY ? 2 : 0);
356 int full_lev_fieldy = lev_fieldy + (BorderElement != EL_EMPTY ? 2 : 0);
358 int dx = (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
359 int dy = (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
360 int dx_var = dx * TILESIZE_VAR / TILESIZE;
361 int dy_var = dy * TILESIZE_VAR / TILESIZE;
364 ffx = (scroll_x - SBX_Left) * TILEX_VAR + dx_var;
365 ffy = (scroll_y - SBY_Upper) * TILEY_VAR + dy_var;
367 if (EVEN(SCR_FIELDX))
369 if (ffx < SBX_Right * TILEX_VAR + TILEX_VAR / 2 + TILEX_VAR)
370 fx += dx_var - MIN(ffx, TILEX_VAR / 2) + TILEX_VAR;
372 fx += (dx_var > 0 ? TILEX_VAR : 0);
379 if (EVEN(SCR_FIELDY))
381 if (ffy < SBY_Lower * TILEY_VAR + TILEY_VAR / 2 + TILEY_VAR)
382 fy += dy_var - MIN(ffy, TILEY_VAR / 2) + TILEY_VAR;
384 fy += (dy_var > 0 ? TILEY_VAR : 0);
391 if (full_lev_fieldx <= SCR_FIELDX)
393 if (EVEN(SCR_FIELDX))
394 fx = 2 * TILEX_VAR - (ODD(lev_fieldx) ? TILEX_VAR / 2 : 0);
396 fx = 2 * TILEX_VAR - (EVEN(lev_fieldx) ? TILEX_VAR / 2 : 0);
399 if (full_lev_fieldy <= SCR_FIELDY)
401 if (EVEN(SCR_FIELDY))
402 fy = 2 * TILEY_VAR - (ODD(lev_fieldy) ? TILEY_VAR / 2 : 0);
404 fy = 2 * TILEY_VAR - (EVEN(lev_fieldy) ? TILEY_VAR / 2 : 0);
407 BlitBitmap(drawto_field, target_bitmap, fx, fy, SXSIZE, SYSIZE, SX, SY);
410 void BlitScreenToBitmap(Bitmap *target_bitmap)
412 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
413 BlitScreenToBitmap_EM(target_bitmap);
414 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
415 BlitScreenToBitmap_SP(target_bitmap);
416 else if (level.game_engine_type == GAME_ENGINE_TYPE_RND)
417 BlitScreenToBitmap_RND(target_bitmap);
419 redraw_mask |= REDRAW_FIELD;
422 void BackToFront_OLD()
424 DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
427 /* !!! TEST ONLY !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
428 /* (force full redraw) */
429 if (game_status == GAME_MODE_PLAYING)
430 redraw_mask |= REDRAW_FIELD;
433 if (redraw_mask == REDRAW_NONE)
438 if (redraw_mask & REDRAW_ALL)
439 printf("[REDRAW_ALL]");
440 if (redraw_mask & REDRAW_FIELD)
441 printf("[REDRAW_FIELD]");
442 if (redraw_mask & REDRAW_DOOR_1)
443 printf("[REDRAW_DOOR_1]");
444 if (redraw_mask & REDRAW_DOOR_2)
445 printf("[REDRAW_DOOR_2]");
446 if (redraw_mask & REDRAW_FROM_BACKBUFFER)
447 printf("[REDRAW_FROM_BACKBUFFER]");
448 printf(" [%d]\n", FrameCounter);
451 if (global.fps_slowdown && game_status == GAME_MODE_PLAYING)
453 static boolean last_frame_skipped = FALSE;
454 boolean skip_even_when_not_scrolling = TRUE;
455 boolean just_scrolling = (ScreenMovDir != 0);
456 boolean verbose = FALSE;
458 if (global.fps_slowdown_factor > 1 &&
459 (FrameCounter % global.fps_slowdown_factor) &&
460 (just_scrolling || skip_even_when_not_scrolling))
462 redraw_mask &= ~REDRAW_MAIN;
464 last_frame_skipped = TRUE;
467 printf("FRAME SKIPPED\n");
471 if (last_frame_skipped)
472 redraw_mask |= REDRAW_FIELD;
474 last_frame_skipped = FALSE;
477 printf("frame not skipped\n");
481 /* synchronize X11 graphics at this point; if we would synchronize the
482 display immediately after the buffer switching (after the XFlush),
483 this could mean that we have to wait for the graphics to complete,
484 although we could go on doing calculations for the next frame */
488 /* never draw masked border to backbuffer when using playfield buffer */
489 if (game_status != GAME_MODE_PLAYING ||
490 redraw_mask & REDRAW_FROM_BACKBUFFER ||
491 buffer == backbuffer)
492 DrawMaskedBorder(redraw_mask);
494 DrawMaskedBorder(redraw_mask & REDRAW_DOORS);
496 if (redraw_mask & REDRAW_ALL)
498 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
500 redraw_mask = REDRAW_NONE;
503 if (redraw_mask & REDRAW_FIELD)
505 if (game_status != GAME_MODE_PLAYING ||
506 redraw_mask & REDRAW_FROM_BACKBUFFER)
508 BlitBitmap(backbuffer, window,
509 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
513 BlitScreenToBitmap_RND(window);
516 redraw_mask &= ~REDRAW_MAIN;
519 if (redraw_mask & REDRAW_DOORS)
521 if (redraw_mask & REDRAW_DOOR_1)
522 BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
524 if (redraw_mask & REDRAW_DOOR_2)
525 BlitBitmap(backbuffer, window, VX, VY, VXSIZE, VYSIZE, VX, VY);
527 if (redraw_mask & REDRAW_DOOR_3)
528 BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
530 redraw_mask &= ~REDRAW_DOORS;
533 if (redraw_mask & REDRAW_MICROLEVEL)
535 BlitBitmap(backbuffer, window, SX, SY + 10 * TILEY, SXSIZE, 7 * TILEY,
536 SX, SY + 10 * TILEY);
538 redraw_mask &= ~REDRAW_MICROLEVEL;
541 if (redraw_mask & REDRAW_FPS) /* display frames per second */
546 sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
547 if (!global.fps_slowdown)
550 sprintf(text, "%04.1f fps%s", global.frames_per_second, info1);
552 DrawTextExt(window, SX + SXSIZE + SX, 0, text, FONT_TEXT_2, BLIT_OPAQUE);
555 redraw_mask = REDRAW_NONE;
560 if (redraw_mask == REDRAW_NONE)
563 // draw masked border to all viewports, if defined
564 DrawMaskedBorder(redraw_mask);
566 // blit backbuffer to visible screen
567 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
569 redraw_mask = REDRAW_NONE;
572 static void FadeCrossSaveBackbuffer()
574 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
577 static void FadeExt(int fade_mask, int fade_mode, int fade_type)
579 static int fade_type_skip = FADE_TYPE_NONE;
580 void (*draw_border_function)(void) = NULL;
581 Bitmap *bitmap = (fade_mode & FADE_TYPE_TRANSFORM ? bitmap_db_cross : NULL);
582 int x, y, width, height;
583 int fade_delay, post_delay;
585 if (fade_type == FADE_TYPE_FADE_OUT)
587 if (fade_type_skip != FADE_TYPE_NONE)
589 /* skip all fade operations until specified fade operation */
590 if (fade_type & fade_type_skip)
591 fade_type_skip = FADE_TYPE_NONE;
596 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
598 FadeCrossSaveBackbuffer();
604 redraw_mask |= fade_mask;
606 if (fade_type == FADE_TYPE_SKIP)
608 fade_type_skip = fade_mode;
613 fade_delay = fading.fade_delay;
614 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
616 if (fade_type_skip != FADE_TYPE_NONE)
618 /* skip all fade operations until specified fade operation */
619 if (fade_type & fade_type_skip)
620 fade_type_skip = FADE_TYPE_NONE;
625 if (global.autoplay_leveldir)
630 if (fade_mask == REDRAW_FIELD)
635 height = FULL_SYSIZE;
637 if (border.draw_masked_when_fading)
638 draw_border_function = DrawMaskedBorder_FIELD; /* update when fading */
640 DrawMaskedBorder_FIELD(); /* draw once */
642 else /* REDRAW_ALL */
650 if (!setup.fade_screens ||
652 fading.fade_mode == FADE_MODE_NONE)
654 if (fade_mode == FADE_MODE_FADE_OUT)
657 BlitBitmap(backbuffer, window, x, y, width, height, x, y);
659 redraw_mask &= ~fade_mask;
664 FadeRectangle(bitmap, x, y, width, height, fade_mode, fade_delay, post_delay,
665 draw_border_function);
667 redraw_mask &= ~fade_mask;
670 void FadeIn(int fade_mask)
672 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
673 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_IN);
675 FadeExt(fade_mask, FADE_MODE_FADE_IN, FADE_TYPE_FADE_IN);
678 void FadeOut(int fade_mask)
680 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
681 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_OUT);
683 FadeExt(fade_mask, FADE_MODE_FADE_OUT, FADE_TYPE_FADE_OUT);
685 global.border_status = game_status;
688 static void FadeSetLeaveNext(struct TitleFadingInfo fading_leave, boolean set)
690 static struct TitleFadingInfo fading_leave_stored;
693 fading_leave_stored = fading_leave;
695 fading = fading_leave_stored;
698 void FadeSetEnterMenu()
700 fading = menu.enter_menu;
702 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
705 void FadeSetLeaveMenu()
707 fading = menu.leave_menu;
709 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
712 void FadeSetEnterScreen()
714 fading = menu.enter_screen[game_status];
716 FadeSetLeaveNext(menu.leave_screen[game_status], TRUE); /* store */
719 void FadeSetNextScreen()
721 fading = menu.next_screen;
723 // (do not overwrite fade mode set by FadeSetEnterScreen)
724 // FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
727 void FadeSetLeaveScreen()
729 FadeSetLeaveNext(menu.leave_screen[game_status], FALSE); /* recall */
732 void FadeSetFromType(int type)
734 if (type & TYPE_ENTER_SCREEN)
735 FadeSetEnterScreen();
736 else if (type & TYPE_ENTER)
738 else if (type & TYPE_LEAVE)
742 void FadeSetDisabled()
744 static struct TitleFadingInfo fading_none = { FADE_MODE_NONE, -1, -1, -1 };
746 fading = fading_none;
749 void FadeSkipNextFadeIn()
751 FadeExt(0, FADE_MODE_SKIP_FADE_IN, FADE_TYPE_SKIP);
754 void FadeSkipNextFadeOut()
756 FadeExt(0, FADE_MODE_SKIP_FADE_OUT, FADE_TYPE_SKIP);
759 void SetWindowBackgroundImageIfDefined(int graphic)
761 if (graphic_info[graphic].bitmap)
762 SetWindowBackgroundBitmap(graphic_info[graphic].bitmap);
765 void SetMainBackgroundImageIfDefined(int graphic)
767 if (graphic_info[graphic].bitmap)
768 SetMainBackgroundBitmap(graphic_info[graphic].bitmap);
771 void SetDoorBackgroundImageIfDefined(int graphic)
773 if (graphic_info[graphic].bitmap)
774 SetDoorBackgroundBitmap(graphic_info[graphic].bitmap);
777 void SetWindowBackgroundImage(int graphic)
779 SetWindowBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
780 graphic_info[graphic].bitmap ?
781 graphic_info[graphic].bitmap :
782 graphic_info[IMG_BACKGROUND].bitmap);
785 void SetMainBackgroundImage(int graphic)
787 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
788 graphic_info[graphic].bitmap ?
789 graphic_info[graphic].bitmap :
790 graphic_info[IMG_BACKGROUND].bitmap);
793 void SetDoorBackgroundImage(int graphic)
795 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
796 graphic_info[graphic].bitmap ?
797 graphic_info[graphic].bitmap :
798 graphic_info[IMG_BACKGROUND].bitmap);
801 void SetPanelBackground()
803 struct GraphicInfo *gfx = &graphic_info[IMG_BACKGROUND_PANEL];
805 BlitBitmapTiled(gfx->bitmap, bitmap_db_panel, gfx->src_x, gfx->src_y,
806 gfx->width, gfx->height, 0, 0, DXSIZE, DYSIZE);
808 SetDoorBackgroundBitmap(bitmap_db_panel);
811 void DrawBackground(int x, int y, int width, int height)
813 /* "drawto" might still point to playfield buffer here (hall of fame) */
814 ClearRectangleOnBackground(backbuffer, x, y, width, height);
816 if (IN_GFX_FIELD_FULL(x, y))
817 redraw_mask |= REDRAW_FIELD;
818 else if (IN_GFX_DOOR_1(x, y))
819 redraw_mask |= REDRAW_DOOR_1;
820 else if (IN_GFX_DOOR_2(x, y))
821 redraw_mask |= REDRAW_DOOR_2;
822 else if (IN_GFX_DOOR_3(x, y))
823 redraw_mask |= REDRAW_DOOR_3;
826 void DrawBackgroundForFont(int x, int y, int width, int height, int font_nr)
828 struct FontBitmapInfo *font = getFontBitmapInfo(font_nr);
830 if (font->bitmap == NULL)
833 DrawBackground(x, y, width, height);
836 void DrawBackgroundForGraphic(int x, int y, int width, int height, int graphic)
838 struct GraphicInfo *g = &graphic_info[graphic];
840 if (g->bitmap == NULL)
843 DrawBackground(x, y, width, height);
848 /* !!! "drawto" might still point to playfield buffer here (see above) !!! */
849 /* (when entering hall of fame after playing) */
850 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
852 /* !!! maybe this should be done before clearing the background !!! */
853 if (game_status == GAME_MODE_PLAYING)
855 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
856 SetDrawtoField(DRAW_FIELDBUFFER);
860 SetDrawtoField(DRAW_BACKBUFFER);
864 void MarkTileDirty(int x, int y)
866 redraw_mask |= REDRAW_FIELD;
869 void SetBorderElement()
873 BorderElement = EL_EMPTY;
875 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
877 for (x = 0; x < lev_fieldx; x++)
879 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
880 BorderElement = EL_STEELWALL;
882 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
888 void FloodFillLevel(int from_x, int from_y, int fill_element,
889 short field[MAX_LEV_FIELDX][MAX_LEV_FIELDY],
890 int max_fieldx, int max_fieldy)
894 static int check[4][2] = { { -1, 0 }, { 0, -1 }, { 1, 0 }, { 0, 1 } };
895 static int safety = 0;
897 /* check if starting field still has the desired content */
898 if (field[from_x][from_y] == fill_element)
903 if (safety > max_fieldx * max_fieldy)
904 Error(ERR_EXIT, "Something went wrong in 'FloodFill()'. Please debug.");
906 old_element = field[from_x][from_y];
907 field[from_x][from_y] = fill_element;
909 for (i = 0; i < 4; i++)
911 x = from_x + check[i][0];
912 y = from_y + check[i][1];
914 if (IN_FIELD(x, y, max_fieldx, max_fieldy) && field[x][y] == old_element)
915 FloodFillLevel(x, y, fill_element, field, max_fieldx, max_fieldy);
921 void SetRandomAnimationValue(int x, int y)
923 gfx.anim_random_frame = GfxRandom[x][y];
926 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
928 /* animation synchronized with global frame counter, not move position */
929 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
930 sync_frame = FrameCounter;
932 return getAnimationFrame(graphic_info[graphic].anim_frames,
933 graphic_info[graphic].anim_delay,
934 graphic_info[graphic].anim_mode,
935 graphic_info[graphic].anim_start_frame,
939 void getSizedGraphicSourceExt(int graphic, int frame, int tilesize,
940 Bitmap **bitmap, int *x, int *y,
941 boolean get_backside)
943 struct GraphicInfo *g = &graphic_info[graphic];
944 Bitmap *src_bitmap = g->bitmap;
945 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
946 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
947 int tilesize_capped = MIN(MAX(1, tilesize), TILESIZE);
949 // if no in-game graphics defined, always use standard graphic size
950 if (g->bitmaps[IMG_BITMAP_GAME] == NULL)
953 if (tilesize == gfx.standard_tile_size)
954 src_bitmap = g->bitmaps[IMG_BITMAP_STANDARD];
955 else if (tilesize == game.tile_size)
956 src_bitmap = g->bitmaps[IMG_BITMAP_GAME];
958 src_bitmap = g->bitmaps[IMG_BITMAP_1x1 - log_2(tilesize_capped)];
960 if (g->offset_y == 0) /* frames are ordered horizontally */
962 int max_width = g->anim_frames_per_line * g->width;
963 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
965 src_x = pos % max_width;
966 src_y = src_y % g->height + pos / max_width * g->height;
968 else if (g->offset_x == 0) /* frames are ordered vertically */
970 int max_height = g->anim_frames_per_line * g->height;
971 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
973 src_x = src_x % g->width + pos / max_height * g->width;
974 src_y = pos % max_height;
976 else /* frames are ordered diagonally */
978 src_x = src_x + frame * g->offset_x;
979 src_y = src_y + frame * g->offset_y;
982 *bitmap = src_bitmap;
983 *x = src_x * tilesize / TILESIZE;
984 *y = src_y * tilesize / TILESIZE;
987 void getFixedGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
988 int *x, int *y, boolean get_backside)
990 getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y,
994 void getSizedGraphicSource(int graphic, int frame, int tilesize,
995 Bitmap **bitmap, int *x, int *y)
997 getSizedGraphicSourceExt(graphic, frame, tilesize, bitmap, x, y, FALSE);
1000 void getFixedGraphicSource(int graphic, int frame,
1001 Bitmap **bitmap, int *x, int *y)
1003 getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y, FALSE);
1006 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1008 getSizedGraphicSource(graphic, 0, MINI_TILESIZE, bitmap, x, y);
1011 inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1012 int *x, int *y, boolean get_backside)
1014 struct GraphicInfo *g = &graphic_info[graphic];
1015 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
1016 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
1018 if (TILESIZE_VAR != TILESIZE)
1019 return getSizedGraphicSourceExt(graphic, frame, TILESIZE_VAR, bitmap, x, y,
1022 *bitmap = g->bitmap;
1024 if (g->offset_y == 0) /* frames are ordered horizontally */
1026 int max_width = g->anim_frames_per_line * g->width;
1027 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
1029 *x = pos % max_width;
1030 *y = src_y % g->height + pos / max_width * g->height;
1032 else if (g->offset_x == 0) /* frames are ordered vertically */
1034 int max_height = g->anim_frames_per_line * g->height;
1035 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
1037 *x = src_x % g->width + pos / max_height * g->width;
1038 *y = pos % max_height;
1040 else /* frames are ordered diagonally */
1042 *x = src_x + frame * g->offset_x;
1043 *y = src_y + frame * g->offset_y;
1047 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
1049 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
1052 void DrawGraphic(int x, int y, int graphic, int frame)
1055 if (!IN_SCR_FIELD(x, y))
1057 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1058 printf("DrawGraphic(): This should never happen!\n");
1063 DrawGraphicExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR, graphic,
1066 MarkTileDirty(x, y);
1069 void DrawFixedGraphic(int x, int y, int graphic, int frame)
1072 if (!IN_SCR_FIELD(x, y))
1074 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1075 printf("DrawGraphic(): This should never happen!\n");
1080 DrawFixedGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic,
1082 MarkTileDirty(x, y);
1085 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1091 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1093 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX_VAR, TILEY_VAR, x, y);
1096 void DrawFixedGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1102 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1103 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
1106 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
1109 if (!IN_SCR_FIELD(x, y))
1111 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1112 printf("DrawGraphicThruMask(): This should never happen!\n");
1117 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
1120 MarkTileDirty(x, y);
1123 void DrawFixedGraphicThruMask(int x, int y, int graphic, int frame)
1126 if (!IN_SCR_FIELD(x, y))
1128 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1129 printf("DrawGraphicThruMask(): This should never happen!\n");
1134 DrawFixedGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
1136 MarkTileDirty(x, y);
1139 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
1145 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1147 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX_VAR, TILEY_VAR,
1151 void DrawFixedGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y,
1152 int graphic, int frame)
1154 struct GraphicInfo *g = &graphic_info[graphic];
1158 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1160 BlitBitmapMasked(src_bitmap, d, src_x, src_y, g->width, g->height,
1164 void DrawSizedGraphic(int x, int y, int graphic, int frame, int tilesize)
1166 DrawSizedGraphicExt(drawto, SX + x * tilesize, SY + y * tilesize, graphic,
1168 MarkTileDirty(x / tilesize, y / tilesize);
1171 void DrawSizedGraphicExt(DrawBuffer *d, int x, int y, int graphic, int frame,
1177 getSizedGraphicSource(graphic, frame, tilesize, &src_bitmap, &src_x, &src_y);
1178 BlitBitmap(src_bitmap, d, src_x, src_y, tilesize, tilesize, x, y);
1181 void DrawMiniGraphic(int x, int y, int graphic)
1183 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
1184 MarkTileDirty(x / 2, y / 2);
1187 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
1192 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1193 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
1196 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
1197 int graphic, int frame,
1198 int cut_mode, int mask_mode)
1203 int width = TILEX, height = TILEY;
1206 if (dx || dy) /* shifted graphic */
1208 if (x < BX1) /* object enters playfield from the left */
1215 else if (x > BX2) /* object enters playfield from the right */
1221 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
1227 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
1229 else if (dx) /* general horizontal movement */
1230 MarkTileDirty(x + SIGN(dx), y);
1232 if (y < BY1) /* object enters playfield from the top */
1234 if (cut_mode==CUT_BELOW) /* object completely above top border */
1242 else if (y > BY2) /* object enters playfield from the bottom */
1248 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
1254 else if (dy > 0 && cut_mode == CUT_ABOVE)
1256 if (y == BY2) /* object completely above bottom border */
1262 MarkTileDirty(x, y + 1);
1263 } /* object leaves playfield to the bottom */
1264 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1266 else if (dy) /* general vertical movement */
1267 MarkTileDirty(x, y + SIGN(dy));
1271 if (!IN_SCR_FIELD(x, y))
1273 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1274 printf("DrawGraphicShifted(): This should never happen!\n");
1279 width = width * TILESIZE_VAR / TILESIZE;
1280 height = height * TILESIZE_VAR / TILESIZE;
1281 cx = cx * TILESIZE_VAR / TILESIZE;
1282 cy = cy * TILESIZE_VAR / TILESIZE;
1283 dx = dx * TILESIZE_VAR / TILESIZE;
1284 dy = dy * TILESIZE_VAR / TILESIZE;
1286 if (width > 0 && height > 0)
1288 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1293 dst_x = FX + x * TILEX_VAR + dx;
1294 dst_y = FY + y * TILEY_VAR + dy;
1296 if (mask_mode == USE_MASKING)
1297 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1300 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1303 MarkTileDirty(x, y);
1307 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
1308 int graphic, int frame,
1309 int cut_mode, int mask_mode)
1314 int width = TILEX_VAR, height = TILEY_VAR;
1317 int x2 = x + SIGN(dx);
1318 int y2 = y + SIGN(dy);
1320 /* movement with two-tile animations must be sync'ed with movement position,
1321 not with current GfxFrame (which can be higher when using slow movement) */
1322 int anim_pos = (dx ? ABS(dx) : ABS(dy));
1323 int anim_frames = graphic_info[graphic].anim_frames;
1325 /* (we also need anim_delay here for movement animations with less frames) */
1326 int anim_delay = graphic_info[graphic].anim_delay;
1327 int sync_frame = anim_pos * anim_frames * anim_delay / TILESIZE;
1329 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
1330 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
1332 /* re-calculate animation frame for two-tile movement animation */
1333 frame = getGraphicAnimationFrame(graphic, sync_frame);
1335 /* check if movement start graphic inside screen area and should be drawn */
1336 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
1338 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
1340 dst_x = FX + x1 * TILEX_VAR;
1341 dst_y = FY + y1 * TILEY_VAR;
1343 if (mask_mode == USE_MASKING)
1344 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1347 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1350 MarkTileDirty(x1, y1);
1353 /* check if movement end graphic inside screen area and should be drawn */
1354 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
1356 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
1358 dst_x = FX + x2 * TILEX_VAR;
1359 dst_y = FY + y2 * TILEY_VAR;
1361 if (mask_mode == USE_MASKING)
1362 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1365 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1368 MarkTileDirty(x2, y2);
1372 static void DrawGraphicShifted(int x, int y, int dx, int dy,
1373 int graphic, int frame,
1374 int cut_mode, int mask_mode)
1378 DrawGraphic(x, y, graphic, frame);
1383 if (graphic_info[graphic].double_movement) /* EM style movement images */
1384 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1386 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1389 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1390 int frame, int cut_mode)
1392 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
1395 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1396 int cut_mode, int mask_mode)
1398 int lx = LEVELX(x), ly = LEVELY(y);
1402 if (IN_LEV_FIELD(lx, ly))
1404 SetRandomAnimationValue(lx, ly);
1406 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
1407 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1409 /* do not use double (EM style) movement graphic when not moving */
1410 if (graphic_info[graphic].double_movement && !dx && !dy)
1412 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
1413 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1416 else /* border element */
1418 graphic = el2img(element);
1419 frame = getGraphicAnimationFrame(graphic, -1);
1422 if (element == EL_EXPANDABLE_WALL)
1424 boolean left_stopped = FALSE, right_stopped = FALSE;
1426 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1427 left_stopped = TRUE;
1428 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1429 right_stopped = TRUE;
1431 if (left_stopped && right_stopped)
1433 else if (left_stopped)
1435 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1436 frame = graphic_info[graphic].anim_frames - 1;
1438 else if (right_stopped)
1440 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1441 frame = graphic_info[graphic].anim_frames - 1;
1446 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1447 else if (mask_mode == USE_MASKING)
1448 DrawGraphicThruMask(x, y, graphic, frame);
1450 DrawGraphic(x, y, graphic, frame);
1453 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1454 int cut_mode, int mask_mode)
1456 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1457 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1458 cut_mode, mask_mode);
1461 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1464 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1467 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1470 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1473 void DrawLevelElementThruMask(int x, int y, int element)
1475 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1478 void DrawLevelFieldThruMask(int x, int y)
1480 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1483 /* !!! implementation of quicksand is totally broken !!! */
1484 #define IS_CRUMBLED_TILE(x, y, e) \
1485 (GFX_CRUMBLED(e) && (!IN_LEV_FIELD(x, y) || \
1486 !IS_MOVING(x, y) || \
1487 (e) == EL_QUICKSAND_EMPTYING || \
1488 (e) == EL_QUICKSAND_FAST_EMPTYING))
1490 static void DrawLevelFieldCrumbledInnerCorners(int x, int y, int dx, int dy,
1495 int width, height, cx, cy;
1496 int sx = SCREENX(x), sy = SCREENY(y);
1497 int crumbled_border_size = graphic_info[graphic].border_size;
1500 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1502 for (i = 1; i < 4; i++)
1504 int dxx = (i & 1 ? dx : 0);
1505 int dyy = (i & 2 ? dy : 0);
1508 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1511 /* check if neighbour field is of same crumble type */
1512 boolean same = (IS_CRUMBLED_TILE(xx, yy, element) &&
1513 graphic_info[graphic].class ==
1514 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class);
1516 /* return if check prevents inner corner */
1517 if (same == (dxx == dx && dyy == dy))
1521 /* if we reach this point, we have an inner corner */
1523 getGraphicSource(graphic, 1, &src_bitmap, &src_x, &src_y);
1525 width = crumbled_border_size * TILESIZE_VAR / TILESIZE;
1526 height = crumbled_border_size * TILESIZE_VAR / TILESIZE;
1527 cx = (dx > 0 ? TILESIZE_VAR - width : 0);
1528 cy = (dy > 0 ? TILESIZE_VAR - height : 0);
1530 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1531 width, height, FX + sx * TILEX_VAR + cx, FY + sy * TILEY_VAR + cy);
1534 static void DrawLevelFieldCrumbledBorders(int x, int y, int graphic, int frame,
1539 int width, height, bx, by, cx, cy;
1540 int sx = SCREENX(x), sy = SCREENY(y);
1541 int crumbled_border_size = graphic_info[graphic].border_size;
1542 int crumbled_border_size_var = crumbled_border_size * TILESIZE_VAR / TILESIZE;
1543 int crumbled_border_pos_var = TILESIZE_VAR - crumbled_border_size_var;
1546 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1548 /* draw simple, sloppy, non-corner-accurate crumbled border */
1550 width = (dir == 1 || dir == 2 ? crumbled_border_size_var : TILESIZE_VAR);
1551 height = (dir == 0 || dir == 3 ? crumbled_border_size_var : TILESIZE_VAR);
1552 cx = (dir == 2 ? crumbled_border_pos_var : 0);
1553 cy = (dir == 3 ? crumbled_border_pos_var : 0);
1555 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy, width, height,
1556 FX + sx * TILEX_VAR + cx,
1557 FY + sy * TILEY_VAR + cy);
1559 /* (remaining middle border part must be at least as big as corner part) */
1560 if (!(graphic_info[graphic].style & STYLE_ACCURATE_BORDERS) ||
1561 crumbled_border_size >= TILESIZE / 3)
1564 /* correct corners of crumbled border, if needed */
1566 for (i = -1; i <= 1; i += 2)
1568 int xx = x + (dir == 0 || dir == 3 ? i : 0);
1569 int yy = y + (dir == 1 || dir == 2 ? i : 0);
1570 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1573 /* check if neighbour field is of same crumble type */
1574 if (IS_CRUMBLED_TILE(xx, yy, element) &&
1575 graphic_info[graphic].class ==
1576 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1578 /* no crumbled corner, but continued crumbled border */
1580 int c1 = (dir == 2 || dir == 3 ? crumbled_border_pos_var : 0);
1581 int c2 = (i == 1 ? crumbled_border_pos_var : 0);
1582 int b1 = (i == 1 ? crumbled_border_size_var :
1583 TILESIZE_VAR - 2 * crumbled_border_size_var);
1585 width = crumbled_border_size_var;
1586 height = crumbled_border_size_var;
1588 if (dir == 1 || dir == 2)
1603 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
1605 FX + sx * TILEX_VAR + cx,
1606 FY + sy * TILEY_VAR + cy);
1611 static void DrawLevelFieldCrumbledExt(int x, int y, int graphic, int frame)
1613 int sx = SCREENX(x), sy = SCREENY(y);
1616 static int xy[4][2] =
1624 if (!IN_LEV_FIELD(x, y))
1627 element = TILE_GFX_ELEMENT(x, y);
1629 /* crumble field itself */
1630 if (IS_CRUMBLED_TILE(x, y, element))
1632 if (!IN_SCR_FIELD(sx, sy))
1635 for (i = 0; i < 4; i++)
1637 int xx = x + xy[i][0];
1638 int yy = y + xy[i][1];
1640 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1643 /* check if neighbour field is of same crumble type */
1644 if (IS_CRUMBLED_TILE(xx, yy, element) &&
1645 graphic_info[graphic].class ==
1646 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1649 DrawLevelFieldCrumbledBorders(x, y, graphic, frame, i);
1652 if ((graphic_info[graphic].style & STYLE_INNER_CORNERS) &&
1653 graphic_info[graphic].anim_frames == 2)
1655 for (i = 0; i < 4; i++)
1657 int dx = (i & 1 ? +1 : -1);
1658 int dy = (i & 2 ? +1 : -1);
1660 DrawLevelFieldCrumbledInnerCorners(x, y, dx, dy, graphic);
1664 MarkTileDirty(sx, sy);
1666 else /* center field not crumbled -- crumble neighbour fields */
1668 for (i = 0; i < 4; i++)
1670 int xx = x + xy[i][0];
1671 int yy = y + xy[i][1];
1672 int sxx = sx + xy[i][0];
1673 int syy = sy + xy[i][1];
1675 if (!IN_LEV_FIELD(xx, yy) ||
1676 !IN_SCR_FIELD(sxx, syy))
1679 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
1682 element = TILE_GFX_ELEMENT(xx, yy);
1684 if (!IS_CRUMBLED_TILE(xx, yy, element))
1687 graphic = el_act2crm(element, ACTION_DEFAULT);
1689 DrawLevelFieldCrumbledBorders(xx, yy, graphic, 0, 3 - i);
1691 MarkTileDirty(sxx, syy);
1696 void DrawLevelFieldCrumbled(int x, int y)
1700 if (!IN_LEV_FIELD(x, y))
1703 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1704 GfxElement[x][y] != EL_UNDEFINED &&
1705 GFX_CRUMBLED(GfxElement[x][y]))
1707 DrawLevelFieldCrumbledDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
1712 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
1714 DrawLevelFieldCrumbledExt(x, y, graphic, 0);
1717 void DrawLevelFieldCrumbledDigging(int x, int y, int direction,
1720 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1721 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1722 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1723 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1724 int sx = SCREENX(x), sy = SCREENY(y);
1726 DrawGraphic(sx, sy, graphic1, frame1);
1727 DrawLevelFieldCrumbledExt(x, y, graphic2, frame2);
1730 void DrawLevelFieldCrumbledNeighbours(int x, int y)
1732 int sx = SCREENX(x), sy = SCREENY(y);
1733 static int xy[4][2] =
1742 for (i = 0; i < 4; i++)
1744 int xx = x + xy[i][0];
1745 int yy = y + xy[i][1];
1746 int sxx = sx + xy[i][0];
1747 int syy = sy + xy[i][1];
1749 if (!IN_LEV_FIELD(xx, yy) ||
1750 !IN_SCR_FIELD(sxx, syy) ||
1751 !GFX_CRUMBLED(Feld[xx][yy]) ||
1755 DrawLevelField(xx, yy);
1759 static int getBorderElement(int x, int y)
1763 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1764 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1765 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1766 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1767 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1768 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1769 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1771 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1772 int steel_position = (x == -1 && y == -1 ? 0 :
1773 x == lev_fieldx && y == -1 ? 1 :
1774 x == -1 && y == lev_fieldy ? 2 :
1775 x == lev_fieldx && y == lev_fieldy ? 3 :
1776 x == -1 || x == lev_fieldx ? 4 :
1777 y == -1 || y == lev_fieldy ? 5 : 6);
1779 return border[steel_position][steel_type];
1782 void DrawScreenElement(int x, int y, int element)
1784 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1785 DrawLevelFieldCrumbled(LEVELX(x), LEVELY(y));
1788 void DrawLevelElement(int x, int y, int element)
1790 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1791 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1794 void DrawScreenField(int x, int y)
1796 int lx = LEVELX(x), ly = LEVELY(y);
1797 int element, content;
1799 if (!IN_LEV_FIELD(lx, ly))
1801 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1804 element = getBorderElement(lx, ly);
1806 DrawScreenElement(x, y, element);
1811 element = Feld[lx][ly];
1812 content = Store[lx][ly];
1814 if (IS_MOVING(lx, ly))
1816 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1817 boolean cut_mode = NO_CUTTING;
1819 if (element == EL_QUICKSAND_EMPTYING ||
1820 element == EL_QUICKSAND_FAST_EMPTYING ||
1821 element == EL_MAGIC_WALL_EMPTYING ||
1822 element == EL_BD_MAGIC_WALL_EMPTYING ||
1823 element == EL_DC_MAGIC_WALL_EMPTYING ||
1824 element == EL_AMOEBA_DROPPING)
1825 cut_mode = CUT_ABOVE;
1826 else if (element == EL_QUICKSAND_FILLING ||
1827 element == EL_QUICKSAND_FAST_FILLING ||
1828 element == EL_MAGIC_WALL_FILLING ||
1829 element == EL_BD_MAGIC_WALL_FILLING ||
1830 element == EL_DC_MAGIC_WALL_FILLING)
1831 cut_mode = CUT_BELOW;
1833 if (cut_mode == CUT_ABOVE)
1834 DrawScreenElement(x, y, element);
1836 DrawScreenElement(x, y, EL_EMPTY);
1839 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1840 else if (cut_mode == NO_CUTTING)
1841 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1844 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1846 if (cut_mode == CUT_BELOW &&
1847 IN_LEV_FIELD(lx, ly + 1) && IN_SCR_FIELD(x, y + 1))
1848 DrawLevelElement(lx, ly + 1, element);
1851 if (content == EL_ACID)
1853 int dir = MovDir[lx][ly];
1854 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
1855 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
1857 DrawLevelElementThruMask(newlx, newly, EL_ACID);
1860 else if (IS_BLOCKED(lx, ly))
1865 boolean cut_mode = NO_CUTTING;
1866 int element_old, content_old;
1868 Blocked2Moving(lx, ly, &oldx, &oldy);
1871 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1872 MovDir[oldx][oldy] == MV_RIGHT);
1874 element_old = Feld[oldx][oldy];
1875 content_old = Store[oldx][oldy];
1877 if (element_old == EL_QUICKSAND_EMPTYING ||
1878 element_old == EL_QUICKSAND_FAST_EMPTYING ||
1879 element_old == EL_MAGIC_WALL_EMPTYING ||
1880 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1881 element_old == EL_DC_MAGIC_WALL_EMPTYING ||
1882 element_old == EL_AMOEBA_DROPPING)
1883 cut_mode = CUT_ABOVE;
1885 DrawScreenElement(x, y, EL_EMPTY);
1888 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1890 else if (cut_mode == NO_CUTTING)
1891 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1894 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1897 else if (IS_DRAWABLE(element))
1898 DrawScreenElement(x, y, element);
1900 DrawScreenElement(x, y, EL_EMPTY);
1903 void DrawLevelField(int x, int y)
1905 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1906 DrawScreenField(SCREENX(x), SCREENY(y));
1907 else if (IS_MOVING(x, y))
1911 Moving2Blocked(x, y, &newx, &newy);
1912 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1913 DrawScreenField(SCREENX(newx), SCREENY(newy));
1915 else if (IS_BLOCKED(x, y))
1919 Blocked2Moving(x, y, &oldx, &oldy);
1920 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1921 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1925 void DrawSizedElement(int x, int y, int element, int tilesize)
1929 graphic = el2edimg(element);
1930 DrawSizedGraphic(x, y, graphic, 0, tilesize);
1933 void DrawMiniElement(int x, int y, int element)
1937 graphic = el2edimg(element);
1938 DrawMiniGraphic(x, y, graphic);
1941 void DrawSizedElementOrWall(int sx, int sy, int scroll_x, int scroll_y,
1944 int x = sx + scroll_x, y = sy + scroll_y;
1946 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1947 DrawSizedElement(sx, sy, EL_EMPTY, tilesize);
1948 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1949 DrawSizedElement(sx, sy, Feld[x][y], tilesize);
1951 DrawSizedGraphic(sx, sy, el2edimg(getBorderElement(x, y)), 0, tilesize);
1954 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1956 int x = sx + scroll_x, y = sy + scroll_y;
1958 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1959 DrawMiniElement(sx, sy, EL_EMPTY);
1960 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1961 DrawMiniElement(sx, sy, Feld[x][y]);
1963 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1966 void DrawEnvelopeBackgroundTiles(int graphic, int startx, int starty,
1967 int x, int y, int xsize, int ysize,
1968 int tile_width, int tile_height)
1972 int dst_x = startx + x * tile_width;
1973 int dst_y = starty + y * tile_height;
1974 int width = graphic_info[graphic].width;
1975 int height = graphic_info[graphic].height;
1976 int inner_width_raw = MAX(width - 2 * tile_width, tile_width);
1977 int inner_height_raw = MAX(height - 2 * tile_height, tile_height);
1978 int inner_width = inner_width_raw - (inner_width_raw % tile_width);
1979 int inner_height = inner_height_raw - (inner_height_raw % tile_height);
1980 int inner_sx = (width >= 3 * tile_width ? tile_width : 0);
1981 int inner_sy = (height >= 3 * tile_height ? tile_height : 0);
1982 boolean draw_masked = graphic_info[graphic].draw_masked;
1984 getFixedGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1986 if (src_bitmap == NULL || width < tile_width || height < tile_height)
1988 ClearRectangle(drawto, dst_x, dst_y, tile_width, tile_height);
1992 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - tile_width :
1993 inner_sx + (x - 1) * tile_width % inner_width);
1994 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - tile_height :
1995 inner_sy + (y - 1) * tile_height % inner_height);
1998 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
2001 BlitBitmap(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
2005 void DrawEnvelopeBackground(int graphic, int startx, int starty,
2006 int x, int y, int xsize, int ysize, int font_nr)
2008 int font_width = getFontWidth(font_nr);
2009 int font_height = getFontHeight(font_nr);
2011 DrawEnvelopeBackgroundTiles(graphic, startx, starty, x, y, xsize, ysize,
2012 font_width, font_height);
2015 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
2017 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2018 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2019 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2020 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2021 boolean no_delay = (tape.warp_forward);
2022 unsigned int anim_delay = 0;
2023 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
2024 int anim_delay_value = (no_delay ? 0 : frame_delay_value) / 2;
2025 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
2026 int font_width = getFontWidth(font_nr);
2027 int font_height = getFontHeight(font_nr);
2028 int max_xsize = level.envelope[envelope_nr].xsize;
2029 int max_ysize = level.envelope[envelope_nr].ysize;
2030 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
2031 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
2032 int xend = max_xsize;
2033 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
2034 int xstep = (xstart < xend ? 1 : 0);
2035 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2037 int end = MAX(xend - xstart, yend - ystart);
2040 for (i = start; i <= end; i++)
2042 int last_frame = end; // last frame of this "for" loop
2043 int x = xstart + i * xstep;
2044 int y = ystart + i * ystep;
2045 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2046 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2047 int sx = SX + (SXSIZE - xsize * font_width) / 2;
2048 int sy = SY + (SYSIZE - ysize * font_height) / 2;
2051 SetDrawtoField(DRAW_FIELDBUFFER);
2053 BlitScreenToBitmap(backbuffer);
2055 SetDrawtoField(DRAW_BACKBUFFER);
2057 for (yy = 0; yy < ysize; yy++)
2058 for (xx = 0; xx < xsize; xx++)
2059 DrawEnvelopeBackground(graphic, sx, sy, xx, yy, xsize, ysize, font_nr);
2061 DrawTextBuffer(sx + font_width, sy + font_height,
2062 level.envelope[envelope_nr].text, font_nr, max_xsize,
2063 xsize - 2, ysize - 2, 0, mask_mode,
2064 level.envelope[envelope_nr].autowrap,
2065 level.envelope[envelope_nr].centered, FALSE);
2067 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2070 SkipUntilDelayReached(&anim_delay, anim_delay_value, &i, last_frame);
2074 void ShowEnvelope(int envelope_nr)
2076 int element = EL_ENVELOPE_1 + envelope_nr;
2077 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2078 int sound_opening = element_info[element].sound[ACTION_OPENING];
2079 int sound_closing = element_info[element].sound[ACTION_CLOSING];
2080 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2081 boolean no_delay = (tape.warp_forward);
2082 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
2083 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
2084 int anim_mode = graphic_info[graphic].anim_mode;
2085 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2086 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2088 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
2090 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2092 if (anim_mode == ANIM_DEFAULT)
2093 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
2095 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
2098 Delay(wait_delay_value);
2100 WaitForEventToContinue();
2102 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2104 if (anim_mode != ANIM_NONE)
2105 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
2107 if (anim_mode == ANIM_DEFAULT)
2108 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
2110 game.envelope_active = FALSE;
2112 SetDrawtoField(DRAW_FIELDBUFFER);
2114 redraw_mask |= REDRAW_FIELD;
2118 static void setRequestCenterPosition(int *x, int *y)
2120 int sx_center = (request.x != -1 ? request.x : SX + SXSIZE / 2);
2121 int sy_center = (request.y != -1 ? request.y : SY + SYSIZE / 2);
2127 static void setRequestPosition(int *x, int *y, boolean add_border_size)
2129 int border_size = request.border_size;
2130 int sx_center, sy_center;
2133 setRequestCenterPosition(&sx_center, &sy_center);
2135 sx = sx_center - request.width / 2;
2136 sy = sy_center - request.height / 2;
2138 if (add_border_size)
2148 void DrawEnvelopeRequest(char *text)
2150 char *text_final = text;
2151 char *text_door_style = NULL;
2152 int graphic = IMG_BACKGROUND_REQUEST;
2153 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2154 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2155 int font_nr = FONT_REQUEST;
2156 int font_width = getFontWidth(font_nr);
2157 int font_height = getFontHeight(font_nr);
2158 int border_size = request.border_size;
2159 int line_spacing = request.line_spacing;
2160 int line_height = font_height + line_spacing;
2161 int text_width = request.width - 2 * border_size;
2162 int text_height = request.height - 2 * border_size;
2163 int line_length = text_width / font_width;
2164 int max_lines = text_height / line_height;
2165 int width = request.width;
2166 int height = request.height;
2167 int tile_size = request.step_offset;
2168 int x_steps = width / tile_size;
2169 int y_steps = height / tile_size;
2173 if (request.wrap_single_words)
2175 char *src_text_ptr, *dst_text_ptr;
2177 text_door_style = checked_malloc(2 * strlen(text) + 1);
2179 src_text_ptr = text;
2180 dst_text_ptr = text_door_style;
2182 while (*src_text_ptr)
2184 if (*src_text_ptr == ' ' ||
2185 *src_text_ptr == '?' ||
2186 *src_text_ptr == '!')
2187 *dst_text_ptr++ = '\n';
2189 if (*src_text_ptr != ' ')
2190 *dst_text_ptr++ = *src_text_ptr;
2195 *dst_text_ptr = '\0';
2197 text_final = text_door_style;
2200 setRequestPosition(&sx, &sy, FALSE);
2202 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
2204 for (y = 0; y < y_steps; y++)
2205 for (x = 0; x < x_steps; x++)
2206 DrawEnvelopeBackgroundTiles(graphic, sx, sy,
2207 x, y, x_steps, y_steps,
2208 tile_size, tile_size);
2210 DrawTextBuffer(sx + border_size, sy + border_size, text_final, font_nr,
2211 line_length, -1, max_lines, line_spacing, mask_mode,
2212 request.autowrap, request.centered, FALSE);
2214 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2215 RedrawGadget(tool_gadget[i]);
2217 // store readily prepared envelope request for later use when animating
2218 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2220 if (text_door_style)
2221 free(text_door_style);
2224 void AnimateEnvelopeRequest(int anim_mode, int action)
2226 int graphic = IMG_BACKGROUND_REQUEST;
2227 boolean draw_masked = graphic_info[graphic].draw_masked;
2228 int delay_value_normal = request.step_delay;
2229 int delay_value_fast = delay_value_normal / 2;
2230 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2231 boolean no_delay = (tape.warp_forward);
2232 int delay_value = (ffwd_delay ? delay_value_fast : delay_value_normal);
2233 int anim_delay_value = (no_delay ? 0 : delay_value + 500 * 0) / 2;
2234 unsigned int anim_delay = 0;
2236 int width = request.width;
2237 int height = request.height;
2238 int tile_size = request.step_offset;
2239 int max_xsize = width / tile_size;
2240 int max_ysize = height / tile_size;
2241 int max_xsize_inner = max_xsize - 2;
2242 int max_ysize_inner = max_ysize - 2;
2244 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize_inner : 0);
2245 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize_inner : 0);
2246 int xend = max_xsize_inner;
2247 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize_inner : 0);
2248 int xstep = (xstart < xend ? 1 : 0);
2249 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2251 int end = MAX(xend - xstart, yend - ystart);
2254 if (setup.quick_doors)
2262 if (action == ACTION_OPENING)
2263 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2264 else if (action == ACTION_CLOSING)
2265 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2268 for (i = start; i <= end; i++)
2270 int last_frame = end; // last frame of this "for" loop
2271 int x = xstart + i * xstep;
2272 int y = ystart + i * ystep;
2273 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2274 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2275 int xsize_size_left = (xsize - 1) * tile_size;
2276 int ysize_size_top = (ysize - 1) * tile_size;
2277 int max_xsize_pos = (max_xsize - 1) * tile_size;
2278 int max_ysize_pos = (max_ysize - 1) * tile_size;
2279 int sx_center, sy_center;
2284 setRequestCenterPosition(&sx_center, &sy_center);
2286 src_x = sx_center - width / 2;
2287 src_y = sy_center - height / 2;
2288 dst_x = sx_center - xsize * tile_size / 2;
2289 dst_y = sy_center - ysize * tile_size / 2;
2291 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2293 for (yy = 0; yy < 2; yy++)
2295 for (xx = 0; xx < 2; xx++)
2297 int src_xx = src_x + xx * max_xsize_pos;
2298 int src_yy = src_y + yy * max_ysize_pos;
2299 int dst_xx = dst_x + xx * xsize_size_left;
2300 int dst_yy = dst_y + yy * ysize_size_top;
2301 int xx_size = (xx ? tile_size : xsize_size_left);
2302 int yy_size = (yy ? tile_size : ysize_size_top);
2305 BlitBitmapMasked(bitmap_db_cross, backbuffer,
2306 src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
2308 BlitBitmap(bitmap_db_cross, backbuffer,
2309 src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
2313 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2318 SkipUntilDelayReached(&anim_delay, anim_delay_value, &i, last_frame);
2322 void ShowEnvelopeRequest(char *text, unsigned int req_state, int action)
2324 int last_game_status = game_status; /* save current game status */
2325 int graphic = IMG_BACKGROUND_REQUEST;
2326 int sound_opening = SND_REQUEST_OPENING;
2327 int sound_closing = SND_REQUEST_CLOSING;
2328 int anim_mode = graphic_info[graphic].anim_mode;
2329 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2330 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2332 if (game_status == GAME_MODE_PLAYING)
2333 BlitScreenToBitmap(backbuffer);
2335 SetDrawtoField(DRAW_BACKBUFFER);
2337 // SetDrawBackgroundMask(REDRAW_NONE);
2339 if (action == ACTION_OPENING)
2341 BlitBitmap(backbuffer, bitmap_db_store, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2343 if (req_state & REQ_ASK)
2345 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2346 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2348 else if (req_state & REQ_CONFIRM)
2350 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2352 else if (req_state & REQ_PLAYER)
2354 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2355 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2356 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2357 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2360 DrawEnvelopeRequest(text);
2362 if (game_status != GAME_MODE_MAIN)
2366 /* force DOOR font inside door area */
2367 game_status = GAME_MODE_PSEUDO_DOOR;
2369 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
2371 if (action == ACTION_OPENING)
2373 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2375 if (anim_mode == ANIM_DEFAULT)
2376 AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_OPENING);
2378 AnimateEnvelopeRequest(main_anim_mode, ACTION_OPENING);
2382 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2384 if (anim_mode != ANIM_NONE)
2385 AnimateEnvelopeRequest(main_anim_mode, ACTION_CLOSING);
2387 if (anim_mode == ANIM_DEFAULT)
2388 AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_CLOSING);
2391 game.envelope_active = FALSE;
2393 game_status = last_game_status; /* restore current game status */
2395 if (action == ACTION_CLOSING)
2397 if (game_status != GAME_MODE_MAIN)
2400 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2403 // SetDrawBackgroundMask(last_draw_background_mask);
2405 redraw_mask |= REDRAW_FIELD;
2407 if (game_status == GAME_MODE_MAIN)
2412 if (action == ACTION_CLOSING &&
2413 game_status == GAME_MODE_PLAYING &&
2414 level.game_engine_type == GAME_ENGINE_TYPE_RND)
2415 SetDrawtoField(DRAW_FIELDBUFFER);
2418 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
2422 int graphic = el2preimg(element);
2424 getSizedGraphicSource(graphic, 0, tilesize, &src_bitmap, &src_x, &src_y);
2425 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
2428 void DrawLevel(int draw_background_mask)
2432 SetMainBackgroundImage(IMG_BACKGROUND_PLAYING);
2433 SetDrawBackgroundMask(draw_background_mask);
2437 for (x = BX1; x <= BX2; x++)
2438 for (y = BY1; y <= BY2; y++)
2439 DrawScreenField(x, y);
2441 redraw_mask |= REDRAW_FIELD;
2444 void DrawSizedLevel(int size_x, int size_y, int scroll_x, int scroll_y,
2449 for (x = 0; x < size_x; x++)
2450 for (y = 0; y < size_y; y++)
2451 DrawSizedElementOrWall(x, y, scroll_x, scroll_y, tilesize);
2453 redraw_mask |= REDRAW_FIELD;
2456 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
2460 for (x = 0; x < size_x; x++)
2461 for (y = 0; y < size_y; y++)
2462 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
2464 redraw_mask |= REDRAW_FIELD;
2467 static void DrawPreviewLevelPlayfieldExt(int from_x, int from_y)
2469 boolean show_level_border = (BorderElement != EL_EMPTY);
2470 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2471 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2472 int tile_size = preview.tile_size;
2473 int preview_width = preview.xsize * tile_size;
2474 int preview_height = preview.ysize * tile_size;
2475 int real_preview_xsize = MIN(level_xsize, preview.xsize);
2476 int real_preview_ysize = MIN(level_ysize, preview.ysize);
2477 int real_preview_width = real_preview_xsize * tile_size;
2478 int real_preview_height = real_preview_ysize * tile_size;
2479 int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
2480 int dst_y = SY + ALIGNED_YPOS(preview.y, preview_height, preview.valign);
2483 if (!IN_GFX_FIELD_FULL(dst_x, dst_y + preview_height - 1))
2486 DrawBackground(dst_x, dst_y, preview_width, preview_height);
2488 dst_x += (preview_width - real_preview_width) / 2;
2489 dst_y += (preview_height - real_preview_height) / 2;
2491 for (x = 0; x < real_preview_xsize; x++)
2493 for (y = 0; y < real_preview_ysize; y++)
2495 int lx = from_x + x + (show_level_border ? -1 : 0);
2496 int ly = from_y + y + (show_level_border ? -1 : 0);
2497 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
2498 getBorderElement(lx, ly));
2500 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
2501 element, tile_size);
2505 redraw_mask |= REDRAW_MICROLEVEL;
2508 #define MICROLABEL_EMPTY 0
2509 #define MICROLABEL_LEVEL_NAME 1
2510 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
2511 #define MICROLABEL_LEVEL_AUTHOR 3
2512 #define MICROLABEL_IMPORTED_FROM_HEAD 4
2513 #define MICROLABEL_IMPORTED_FROM 5
2514 #define MICROLABEL_IMPORTED_BY_HEAD 6
2515 #define MICROLABEL_IMPORTED_BY 7
2517 static int getMaxTextLength(struct TextPosInfo *pos, int font_nr)
2519 int max_text_width = SXSIZE;
2520 int font_width = getFontWidth(font_nr);
2522 if (pos->align == ALIGN_CENTER)
2523 max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
2524 else if (pos->align == ALIGN_RIGHT)
2525 max_text_width = pos->x;
2527 max_text_width = SXSIZE - pos->x;
2529 return max_text_width / font_width;
2532 static void DrawPreviewLevelLabelExt(int mode)
2534 struct TextPosInfo *pos = &menu.main.text.level_info_2;
2535 char label_text[MAX_OUTPUT_LINESIZE + 1];
2536 int max_len_label_text;
2537 int font_nr = pos->font;
2540 if (!IN_GFX_FIELD_FULL(pos->x, pos->y + getFontHeight(pos->font)))
2543 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
2544 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
2545 mode == MICROLABEL_IMPORTED_BY_HEAD)
2546 font_nr = pos->font_alt;
2548 max_len_label_text = getMaxTextLength(pos, font_nr);
2550 if (pos->size != -1)
2551 max_len_label_text = pos->size;
2553 for (i = 0; i < max_len_label_text; i++)
2554 label_text[i] = ' ';
2555 label_text[max_len_label_text] = '\0';
2557 if (strlen(label_text) > 0)
2558 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2561 (mode == MICROLABEL_LEVEL_NAME ? level.name :
2562 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
2563 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
2564 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
2565 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
2566 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
2567 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
2568 max_len_label_text);
2569 label_text[max_len_label_text] = '\0';
2571 if (strlen(label_text) > 0)
2572 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2574 redraw_mask |= REDRAW_MICROLEVEL;
2577 static void DrawPreviewLevelExt(boolean restart)
2579 static unsigned int scroll_delay = 0;
2580 static unsigned int label_delay = 0;
2581 static int from_x, from_y, scroll_direction;
2582 static int label_state, label_counter;
2583 unsigned int scroll_delay_value = preview.step_delay;
2584 boolean show_level_border = (BorderElement != EL_EMPTY);
2585 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2586 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2587 int last_game_status = game_status; /* save current game status */
2594 if (preview.anim_mode == ANIM_CENTERED)
2596 if (level_xsize > preview.xsize)
2597 from_x = (level_xsize - preview.xsize) / 2;
2598 if (level_ysize > preview.ysize)
2599 from_y = (level_ysize - preview.ysize) / 2;
2602 from_x += preview.xoffset;
2603 from_y += preview.yoffset;
2605 scroll_direction = MV_RIGHT;
2609 DrawPreviewLevelPlayfieldExt(from_x, from_y);
2610 DrawPreviewLevelLabelExt(label_state);
2612 /* initialize delay counters */
2613 DelayReached(&scroll_delay, 0);
2614 DelayReached(&label_delay, 0);
2616 if (leveldir_current->name)
2618 struct TextPosInfo *pos = &menu.main.text.level_info_1;
2619 char label_text[MAX_OUTPUT_LINESIZE + 1];
2620 int font_nr = pos->font;
2621 int max_len_label_text = getMaxTextLength(pos, font_nr);
2623 if (pos->size != -1)
2624 max_len_label_text = pos->size;
2626 strncpy(label_text, leveldir_current->name, max_len_label_text);
2627 label_text[max_len_label_text] = '\0';
2629 if (IN_GFX_FIELD_FULL(pos->x, pos->y + getFontHeight(pos->font)))
2630 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2633 game_status = last_game_status; /* restore current game status */
2638 /* scroll preview level, if needed */
2639 if (preview.anim_mode != ANIM_NONE &&
2640 (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
2641 DelayReached(&scroll_delay, scroll_delay_value))
2643 switch (scroll_direction)
2648 from_x -= preview.step_offset;
2649 from_x = (from_x < 0 ? 0 : from_x);
2652 scroll_direction = MV_UP;
2656 if (from_x < level_xsize - preview.xsize)
2658 from_x += preview.step_offset;
2659 from_x = (from_x > level_xsize - preview.xsize ?
2660 level_xsize - preview.xsize : from_x);
2663 scroll_direction = MV_DOWN;
2669 from_y -= preview.step_offset;
2670 from_y = (from_y < 0 ? 0 : from_y);
2673 scroll_direction = MV_RIGHT;
2677 if (from_y < level_ysize - preview.ysize)
2679 from_y += preview.step_offset;
2680 from_y = (from_y > level_ysize - preview.ysize ?
2681 level_ysize - preview.ysize : from_y);
2684 scroll_direction = MV_LEFT;
2691 DrawPreviewLevelPlayfieldExt(from_x, from_y);
2694 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
2695 /* redraw micro level label, if needed */
2696 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
2697 !strEqual(level.author, ANONYMOUS_NAME) &&
2698 !strEqual(level.author, leveldir_current->name) &&
2699 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
2701 int max_label_counter = 23;
2703 if (leveldir_current->imported_from != NULL &&
2704 strlen(leveldir_current->imported_from) > 0)
2705 max_label_counter += 14;
2706 if (leveldir_current->imported_by != NULL &&
2707 strlen(leveldir_current->imported_by) > 0)
2708 max_label_counter += 14;
2710 label_counter = (label_counter + 1) % max_label_counter;
2711 label_state = (label_counter >= 0 && label_counter <= 7 ?
2712 MICROLABEL_LEVEL_NAME :
2713 label_counter >= 9 && label_counter <= 12 ?
2714 MICROLABEL_LEVEL_AUTHOR_HEAD :
2715 label_counter >= 14 && label_counter <= 21 ?
2716 MICROLABEL_LEVEL_AUTHOR :
2717 label_counter >= 23 && label_counter <= 26 ?
2718 MICROLABEL_IMPORTED_FROM_HEAD :
2719 label_counter >= 28 && label_counter <= 35 ?
2720 MICROLABEL_IMPORTED_FROM :
2721 label_counter >= 37 && label_counter <= 40 ?
2722 MICROLABEL_IMPORTED_BY_HEAD :
2723 label_counter >= 42 && label_counter <= 49 ?
2724 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
2726 if (leveldir_current->imported_from == NULL &&
2727 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
2728 label_state == MICROLABEL_IMPORTED_FROM))
2729 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
2730 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
2732 DrawPreviewLevelLabelExt(label_state);
2735 game_status = last_game_status; /* restore current game status */
2738 void DrawPreviewLevelInitial()
2740 DrawPreviewLevelExt(TRUE);
2743 void DrawPreviewLevelAnimation()
2745 DrawPreviewLevelExt(FALSE);
2748 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
2749 int graphic, int sync_frame, int mask_mode)
2751 int frame = getGraphicAnimationFrame(graphic, sync_frame);
2753 if (mask_mode == USE_MASKING)
2754 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
2756 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
2759 inline void DrawFixedGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
2760 int graphic, int sync_frame,
2763 int frame = getGraphicAnimationFrame(graphic, sync_frame);
2765 if (mask_mode == USE_MASKING)
2766 DrawFixedGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
2768 DrawFixedGraphicExt(dst_bitmap, x, y, graphic, frame);
2771 inline void DrawGraphicAnimation(int x, int y, int graphic)
2773 int lx = LEVELX(x), ly = LEVELY(y);
2775 if (!IN_SCR_FIELD(x, y))
2778 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
2779 graphic, GfxFrame[lx][ly], NO_MASKING);
2781 MarkTileDirty(x, y);
2784 inline void DrawFixedGraphicAnimation(int x, int y, int graphic)
2786 int lx = LEVELX(x), ly = LEVELY(y);
2788 if (!IN_SCR_FIELD(x, y))
2791 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
2792 graphic, GfxFrame[lx][ly], NO_MASKING);
2793 MarkTileDirty(x, y);
2796 void DrawLevelGraphicAnimation(int x, int y, int graphic)
2798 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2801 void DrawLevelElementAnimation(int x, int y, int element)
2803 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2805 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2808 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
2810 int sx = SCREENX(x), sy = SCREENY(y);
2812 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2815 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2818 DrawGraphicAnimation(sx, sy, graphic);
2821 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
2822 DrawLevelFieldCrumbled(x, y);
2824 if (GFX_CRUMBLED(Feld[x][y]))
2825 DrawLevelFieldCrumbled(x, y);
2829 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
2831 int sx = SCREENX(x), sy = SCREENY(y);
2834 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2837 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2839 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2842 DrawGraphicAnimation(sx, sy, graphic);
2844 if (GFX_CRUMBLED(element))
2845 DrawLevelFieldCrumbled(x, y);
2848 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
2850 if (player->use_murphy)
2852 /* this works only because currently only one player can be "murphy" ... */
2853 static int last_horizontal_dir = MV_LEFT;
2854 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
2856 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2857 last_horizontal_dir = move_dir;
2859 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
2861 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
2863 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
2869 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
2872 static boolean equalGraphics(int graphic1, int graphic2)
2874 struct GraphicInfo *g1 = &graphic_info[graphic1];
2875 struct GraphicInfo *g2 = &graphic_info[graphic2];
2877 return (g1->bitmap == g2->bitmap &&
2878 g1->src_x == g2->src_x &&
2879 g1->src_y == g2->src_y &&
2880 g1->anim_frames == g2->anim_frames &&
2881 g1->anim_delay == g2->anim_delay &&
2882 g1->anim_mode == g2->anim_mode);
2885 void DrawAllPlayers()
2889 for (i = 0; i < MAX_PLAYERS; i++)
2890 if (stored_player[i].active)
2891 DrawPlayer(&stored_player[i]);
2894 void DrawPlayerField(int x, int y)
2896 if (!IS_PLAYER(x, y))
2899 DrawPlayer(PLAYERINFO(x, y));
2902 #define DRAW_PLAYER_OVER_PUSHED_ELEMENT 1
2904 void DrawPlayer(struct PlayerInfo *player)
2906 int jx = player->jx;
2907 int jy = player->jy;
2908 int move_dir = player->MovDir;
2909 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
2910 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
2911 int last_jx = (player->is_moving ? jx - dx : jx);
2912 int last_jy = (player->is_moving ? jy - dy : jy);
2913 int next_jx = jx + dx;
2914 int next_jy = jy + dy;
2915 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
2916 boolean player_is_opaque = FALSE;
2917 int sx = SCREENX(jx), sy = SCREENY(jy);
2918 int sxx = 0, syy = 0;
2919 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
2921 int action = ACTION_DEFAULT;
2922 int last_player_graphic = getPlayerGraphic(player, move_dir);
2923 int last_player_frame = player->Frame;
2926 /* GfxElement[][] is set to the element the player is digging or collecting;
2927 remove also for off-screen player if the player is not moving anymore */
2928 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
2929 GfxElement[jx][jy] = EL_UNDEFINED;
2931 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
2935 if (!IN_LEV_FIELD(jx, jy))
2937 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
2938 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
2939 printf("DrawPlayerField(): This should never happen!\n");
2944 if (element == EL_EXPLOSION)
2947 action = (player->is_pushing ? ACTION_PUSHING :
2948 player->is_digging ? ACTION_DIGGING :
2949 player->is_collecting ? ACTION_COLLECTING :
2950 player->is_moving ? ACTION_MOVING :
2951 player->is_snapping ? ACTION_SNAPPING :
2952 player->is_dropping ? ACTION_DROPPING :
2953 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
2955 if (player->is_waiting)
2956 move_dir = player->dir_waiting;
2958 InitPlayerGfxAnimation(player, action, move_dir);
2960 /* ----------------------------------------------------------------------- */
2961 /* draw things in the field the player is leaving, if needed */
2962 /* ----------------------------------------------------------------------- */
2964 if (player->is_moving)
2966 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
2968 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
2970 if (last_element == EL_DYNAMITE_ACTIVE ||
2971 last_element == EL_EM_DYNAMITE_ACTIVE ||
2972 last_element == EL_SP_DISK_RED_ACTIVE)
2973 DrawDynamite(last_jx, last_jy);
2975 DrawLevelFieldThruMask(last_jx, last_jy);
2977 else if (last_element == EL_DYNAMITE_ACTIVE ||
2978 last_element == EL_EM_DYNAMITE_ACTIVE ||
2979 last_element == EL_SP_DISK_RED_ACTIVE)
2980 DrawDynamite(last_jx, last_jy);
2982 /* !!! this is not enough to prevent flickering of players which are
2983 moving next to each others without a free tile between them -- this
2984 can only be solved by drawing all players layer by layer (first the
2985 background, then the foreground etc.) !!! => TODO */
2986 else if (!IS_PLAYER(last_jx, last_jy))
2987 DrawLevelField(last_jx, last_jy);
2990 DrawLevelField(last_jx, last_jy);
2993 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
2994 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
2997 if (!IN_SCR_FIELD(sx, sy))
3000 /* ----------------------------------------------------------------------- */
3001 /* draw things behind the player, if needed */
3002 /* ----------------------------------------------------------------------- */
3005 DrawLevelElement(jx, jy, Back[jx][jy]);
3006 else if (IS_ACTIVE_BOMB(element))
3007 DrawLevelElement(jx, jy, EL_EMPTY);
3010 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
3012 int old_element = GfxElement[jx][jy];
3013 int old_graphic = el_act_dir2img(old_element, action, move_dir);
3014 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
3016 if (GFX_CRUMBLED(old_element))
3017 DrawLevelFieldCrumbledDigging(jx, jy, move_dir, player->StepFrame);
3019 DrawGraphic(sx, sy, old_graphic, frame);
3021 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
3022 player_is_opaque = TRUE;
3026 GfxElement[jx][jy] = EL_UNDEFINED;
3028 /* make sure that pushed elements are drawn with correct frame rate */
3029 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
3031 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
3032 GfxFrame[jx][jy] = player->StepFrame;
3034 DrawLevelField(jx, jy);
3038 #if !DRAW_PLAYER_OVER_PUSHED_ELEMENT
3039 /* ----------------------------------------------------------------------- */
3040 /* draw player himself */
3041 /* ----------------------------------------------------------------------- */
3043 graphic = getPlayerGraphic(player, move_dir);
3045 /* in the case of changed player action or direction, prevent the current
3046 animation frame from being restarted for identical animations */
3047 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
3048 player->Frame = last_player_frame;
3050 frame = getGraphicAnimationFrame(graphic, player->Frame);
3054 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3055 sxx = player->GfxPos;
3057 syy = player->GfxPos;
3060 if (player_is_opaque)
3061 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
3063 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3065 if (SHIELD_ON(player))
3067 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
3068 IMG_SHIELD_NORMAL_ACTIVE);
3069 int frame = getGraphicAnimationFrame(graphic, -1);
3071 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3075 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
3078 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3079 sxx = player->GfxPos;
3081 syy = player->GfxPos;
3085 /* ----------------------------------------------------------------------- */
3086 /* draw things the player is pushing, if needed */
3087 /* ----------------------------------------------------------------------- */
3089 if (player->is_pushing && player->is_moving)
3091 int px = SCREENX(jx), py = SCREENY(jy);
3092 int pxx = (TILEX - ABS(sxx)) * dx;
3093 int pyy = (TILEY - ABS(syy)) * dy;
3094 int gfx_frame = GfxFrame[jx][jy];
3100 if (!IS_MOVING(jx, jy)) /* push movement already finished */
3102 element = Feld[next_jx][next_jy];
3103 gfx_frame = GfxFrame[next_jx][next_jy];
3106 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
3108 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
3109 frame = getGraphicAnimationFrame(graphic, sync_frame);
3111 /* draw background element under pushed element (like the Sokoban field) */
3112 if (game.use_masked_pushing && IS_MOVING(jx, jy))
3114 /* this allows transparent pushing animation over non-black background */
3117 DrawLevelElement(jx, jy, Back[jx][jy]);
3119 DrawLevelElement(jx, jy, EL_EMPTY);
3121 if (Back[next_jx][next_jy])
3122 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3124 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
3126 else if (Back[next_jx][next_jy])
3127 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3130 /* do not draw (EM style) pushing animation when pushing is finished */
3131 /* (two-tile animations usually do not contain start and end frame) */
3132 if (graphic_info[graphic].double_movement && !IS_MOVING(jx, jy))
3133 DrawLevelElement(next_jx, next_jy, Feld[next_jx][next_jy]);
3135 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3137 /* masked drawing is needed for EMC style (double) movement graphics */
3138 /* !!! (ONLY WHEN DRAWING PUSHED ELEMENT OVER THE PLAYER) !!! */
3139 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3143 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
3144 /* ----------------------------------------------------------------------- */
3145 /* draw player himself */
3146 /* ----------------------------------------------------------------------- */
3148 graphic = getPlayerGraphic(player, move_dir);
3150 /* in the case of changed player action or direction, prevent the current
3151 animation frame from being restarted for identical animations */
3152 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
3153 player->Frame = last_player_frame;
3155 frame = getGraphicAnimationFrame(graphic, player->Frame);
3159 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3160 sxx = player->GfxPos;
3162 syy = player->GfxPos;
3165 if (player_is_opaque)
3166 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
3168 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3170 if (SHIELD_ON(player))
3172 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
3173 IMG_SHIELD_NORMAL_ACTIVE);
3174 int frame = getGraphicAnimationFrame(graphic, -1);
3176 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3180 /* ----------------------------------------------------------------------- */
3181 /* draw things in front of player (active dynamite or dynabombs) */
3182 /* ----------------------------------------------------------------------- */
3184 if (IS_ACTIVE_BOMB(element))
3186 graphic = el2img(element);
3187 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
3189 if (game.emulation == EMU_SUPAPLEX)
3190 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
3192 DrawGraphicThruMask(sx, sy, graphic, frame);
3195 if (player_is_moving && last_element == EL_EXPLOSION)
3197 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
3198 GfxElement[last_jx][last_jy] : EL_EMPTY);
3199 int graphic = el_act2img(element, ACTION_EXPLODING);
3200 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
3201 int phase = ExplodePhase[last_jx][last_jy] - 1;
3202 int frame = getGraphicAnimationFrame(graphic, phase - delay);
3205 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
3208 /* ----------------------------------------------------------------------- */
3209 /* draw elements the player is just walking/passing through/under */
3210 /* ----------------------------------------------------------------------- */
3212 if (player_is_moving)
3214 /* handle the field the player is leaving ... */
3215 if (IS_ACCESSIBLE_INSIDE(last_element))
3216 DrawLevelField(last_jx, last_jy);
3217 else if (IS_ACCESSIBLE_UNDER(last_element))
3218 DrawLevelFieldThruMask(last_jx, last_jy);
3221 /* do not redraw accessible elements if the player is just pushing them */
3222 if (!player_is_moving || !player->is_pushing)
3224 /* ... and the field the player is entering */
3225 if (IS_ACCESSIBLE_INSIDE(element))
3226 DrawLevelField(jx, jy);
3227 else if (IS_ACCESSIBLE_UNDER(element))
3228 DrawLevelFieldThruMask(jx, jy);
3231 MarkTileDirty(sx, sy);
3234 /* ------------------------------------------------------------------------- */
3236 void WaitForEventToContinue()
3238 boolean still_wait = TRUE;
3240 /* simulate releasing mouse button over last gadget, if still pressed */
3242 HandleGadgets(-1, -1, 0);
3244 button_status = MB_RELEASED;
3258 case EVENT_BUTTONPRESS:
3259 case EVENT_KEYPRESS:
3263 case EVENT_KEYRELEASE:
3264 ClearPlayerAction();
3268 HandleOtherEvents(&event);
3272 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3279 /* don't eat all CPU time */
3284 #define MAX_REQUEST_LINES 13
3285 #define MAX_REQUEST_LINE_FONT1_LEN 7
3286 #define MAX_REQUEST_LINE_FONT2_LEN 10
3288 static int RequestHandleEvents(unsigned int req_state)
3290 boolean level_solved = (game_status == GAME_MODE_PLAYING &&
3291 local_player->LevelSolved_GameEnd);
3292 int last_game_status = game_status; /* save current game status */
3293 int width = request.width;
3294 int height = request.height;
3298 setRequestPosition(&sx, &sy, FALSE);
3300 button_status = MB_RELEASED;
3302 request_gadget_id = -1;
3309 SetDrawtoField(DRAW_FIELDBUFFER);
3311 HandleGameActions();
3313 SetDrawtoField(DRAW_BACKBUFFER);
3315 if (global.use_envelope_request)
3317 /* copy current state of request area to middle of playfield area */
3318 BlitBitmap(bitmap_db_cross, drawto, sx, sy, width, height, sx, sy);
3326 while (NextValidEvent(&event))
3330 case EVENT_BUTTONPRESS:
3331 case EVENT_BUTTONRELEASE:
3332 case EVENT_MOTIONNOTIFY:
3336 if (event.type == EVENT_MOTIONNOTIFY)
3341 motion_status = TRUE;
3342 mx = ((MotionEvent *) &event)->x;
3343 my = ((MotionEvent *) &event)->y;
3347 motion_status = FALSE;
3348 mx = ((ButtonEvent *) &event)->x;
3349 my = ((ButtonEvent *) &event)->y;
3350 if (event.type == EVENT_BUTTONPRESS)
3351 button_status = ((ButtonEvent *) &event)->button;
3353 button_status = MB_RELEASED;
3356 /* this sets 'request_gadget_id' */
3357 HandleGadgets(mx, my, button_status);
3359 switch (request_gadget_id)
3361 case TOOL_CTRL_ID_YES:
3364 case TOOL_CTRL_ID_NO:
3367 case TOOL_CTRL_ID_CONFIRM:
3368 result = TRUE | FALSE;
3371 case TOOL_CTRL_ID_PLAYER_1:
3374 case TOOL_CTRL_ID_PLAYER_2:
3377 case TOOL_CTRL_ID_PLAYER_3:
3380 case TOOL_CTRL_ID_PLAYER_4:
3391 case EVENT_KEYPRESS:
3392 switch (GetEventKey((KeyEvent *)&event, TRUE))
3395 if (req_state & REQ_CONFIRM)
3400 #if defined(TARGET_SDL2)
3407 #if defined(TARGET_SDL2)
3417 if (req_state & REQ_PLAYER)
3421 case EVENT_KEYRELEASE:
3422 ClearPlayerAction();
3426 HandleOtherEvents(&event);
3431 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3433 int joy = AnyJoystick();
3435 if (joy & JOY_BUTTON_1)
3437 else if (joy & JOY_BUTTON_2)
3443 if (global.use_envelope_request)
3445 /* copy back current state of pressed buttons inside request area */
3446 BlitBitmap(drawto, bitmap_db_cross, sx, sy, width, height, sx, sy);
3453 if (!PendingEvent()) /* delay only if no pending events */
3457 game_status = GAME_MODE_PSEUDO_DOOR;
3461 game_status = last_game_status; /* restore current game status */
3467 static boolean RequestDoor(char *text, unsigned int req_state)
3469 unsigned int old_door_state;
3470 int last_game_status = game_status; /* save current game status */
3471 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
3472 int font_nr = FONT_TEXT_2;
3477 if (maxWordLengthInString(text) > MAX_REQUEST_LINE_FONT1_LEN)
3479 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
3480 font_nr = FONT_TEXT_1;
3483 if (game_status == GAME_MODE_PLAYING)
3484 BlitScreenToBitmap(backbuffer);
3486 /* disable deactivated drawing when quick-loading level tape recording */
3487 if (tape.playing && tape.deactivate_display)
3488 TapeDeactivateDisplayOff(TRUE);
3490 SetMouseCursor(CURSOR_DEFAULT);
3492 #if defined(NETWORK_AVALIABLE)
3493 /* pause network game while waiting for request to answer */
3494 if (options.network &&
3495 game_status == GAME_MODE_PLAYING &&
3496 req_state & REQUEST_WAIT_FOR_INPUT)
3497 SendToServer_PausePlaying();
3500 old_door_state = GetDoorState();
3502 /* simulate releasing mouse button over last gadget, if still pressed */
3504 HandleGadgets(-1, -1, 0);
3508 /* draw released gadget before proceeding */
3511 if (old_door_state & DOOR_OPEN_1)
3513 CloseDoor(DOOR_CLOSE_1);
3515 /* save old door content */
3516 BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
3517 0 * DXSIZE, 0, DXSIZE, DYSIZE, 1 * DXSIZE, 0);
3520 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
3521 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3523 /* clear door drawing field */
3524 DrawBackground(DX, DY, DXSIZE, DYSIZE);
3526 /* force DOOR font inside door area */
3527 game_status = GAME_MODE_PSEUDO_DOOR;
3529 /* write text for request */
3530 for (text_ptr = text, ty = 0; ty < MAX_REQUEST_LINES; ty++)
3532 char text_line[max_request_line_len + 1];
3538 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
3540 tc = *(text_ptr + tx);
3541 // if (!tc || tc == ' ')
3542 if (!tc || tc == ' ' || tc == '?' || tc == '!')
3546 if ((tc == '?' || tc == '!') && tl == 0)
3556 strncpy(text_line, text_ptr, tl);
3559 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
3560 DY + 8 + ty * (getFontHeight(font_nr) + 2),
3561 text_line, font_nr);
3563 text_ptr += tl + (tc == ' ' ? 1 : 0);
3564 // text_ptr += tl + (tc == ' ' || tc == '?' || tc == '!' ? 1 : 0);
3567 game_status = last_game_status; /* restore current game status */
3569 if (req_state & REQ_ASK)
3571 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
3572 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
3574 else if (req_state & REQ_CONFIRM)
3576 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
3578 else if (req_state & REQ_PLAYER)
3580 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
3581 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
3582 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
3583 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
3586 /* copy request gadgets to door backbuffer */
3587 BlitBitmap(drawto, bitmap_db_door_1, DX, DY, DXSIZE, DYSIZE, 0, 0);
3589 OpenDoor(DOOR_OPEN_1);
3591 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
3593 if (game_status == GAME_MODE_PLAYING)
3595 SetPanelBackground();
3596 SetDrawBackgroundMask(REDRAW_DOOR_1);
3600 SetDrawBackgroundMask(REDRAW_FIELD);
3606 if (game_status != GAME_MODE_MAIN)
3609 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3611 // ---------- handle request buttons ----------
3612 result = RequestHandleEvents(req_state);
3614 if (game_status != GAME_MODE_MAIN)
3619 if (!(req_state & REQ_STAY_OPEN))
3621 CloseDoor(DOOR_CLOSE_1);
3623 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
3624 (req_state & REQ_REOPEN))
3625 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
3630 if (game_status == GAME_MODE_PLAYING)
3632 SetPanelBackground();
3633 SetDrawBackgroundMask(REDRAW_DOOR_1);
3637 SetDrawBackgroundMask(REDRAW_FIELD);
3640 #if defined(NETWORK_AVALIABLE)
3641 /* continue network game after request */
3642 if (options.network &&
3643 game_status == GAME_MODE_PLAYING &&
3644 req_state & REQUEST_WAIT_FOR_INPUT)
3645 SendToServer_ContinuePlaying();
3648 /* restore deactivated drawing when quick-loading level tape recording */
3649 if (tape.playing && tape.deactivate_display)
3650 TapeDeactivateDisplayOn();
3655 static boolean RequestEnvelope(char *text, unsigned int req_state)
3659 if (game_status == GAME_MODE_PLAYING)
3660 BlitScreenToBitmap(backbuffer);
3662 /* disable deactivated drawing when quick-loading level tape recording */
3663 if (tape.playing && tape.deactivate_display)
3664 TapeDeactivateDisplayOff(TRUE);
3666 SetMouseCursor(CURSOR_DEFAULT);
3668 #if defined(NETWORK_AVALIABLE)
3669 /* pause network game while waiting for request to answer */
3670 if (options.network &&
3671 game_status == GAME_MODE_PLAYING &&
3672 req_state & REQUEST_WAIT_FOR_INPUT)
3673 SendToServer_PausePlaying();
3676 /* simulate releasing mouse button over last gadget, if still pressed */
3678 HandleGadgets(-1, -1, 0);
3682 // (replace with setting corresponding request background)
3683 // SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
3684 // SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3686 /* clear door drawing field */
3687 // DrawBackground(DX, DY, DXSIZE, DYSIZE);
3689 ShowEnvelopeRequest(text, req_state, ACTION_OPENING);
3691 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
3693 if (game_status == GAME_MODE_PLAYING)
3695 SetPanelBackground();
3696 SetDrawBackgroundMask(REDRAW_DOOR_1);
3700 SetDrawBackgroundMask(REDRAW_FIELD);
3706 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3708 // ---------- handle request buttons ----------
3709 result = RequestHandleEvents(req_state);
3711 if (game_status != GAME_MODE_MAIN)
3716 ShowEnvelopeRequest(text, req_state, ACTION_CLOSING);
3720 if (game_status == GAME_MODE_PLAYING)
3722 SetPanelBackground();
3723 SetDrawBackgroundMask(REDRAW_DOOR_1);
3727 SetDrawBackgroundMask(REDRAW_FIELD);
3730 #if defined(NETWORK_AVALIABLE)
3731 /* continue network game after request */
3732 if (options.network &&
3733 game_status == GAME_MODE_PLAYING &&
3734 req_state & REQUEST_WAIT_FOR_INPUT)
3735 SendToServer_ContinuePlaying();
3738 /* restore deactivated drawing when quick-loading level tape recording */
3739 if (tape.playing && tape.deactivate_display)
3740 TapeDeactivateDisplayOn();
3745 boolean Request(char *text, unsigned int req_state)
3747 if (global.use_envelope_request)
3748 return RequestEnvelope(text, req_state);
3750 return RequestDoor(text, req_state);
3753 static int compareDoorPartOrderInfo(const void *object1, const void *object2)
3755 const struct DoorPartOrderInfo *dpo1 = (struct DoorPartOrderInfo *)object1;
3756 const struct DoorPartOrderInfo *dpo2 = (struct DoorPartOrderInfo *)object2;
3759 if (dpo1->sort_priority != dpo2->sort_priority)
3760 compare_result = dpo1->sort_priority - dpo2->sort_priority;
3762 compare_result = dpo1->nr - dpo2->nr;
3764 return compare_result;
3767 void InitGraphicCompatibilityInfo_Doors()
3773 struct DoorInfo *door;
3777 { DOOR_1, IMG_DOOR_1_GFX_PART_1, IMG_DOOR_1_GFX_PART_8, &door_1 },
3778 { DOOR_2, IMG_DOOR_2_GFX_PART_1, IMG_DOOR_2_GFX_PART_8, &door_2 },
3780 { -1, -1, -1, NULL }
3782 struct Rect door_rect_list[] =
3784 { DX, DY, DXSIZE, DYSIZE },
3785 { VX, VY, VXSIZE, VYSIZE }
3789 for (i = 0; doors[i].door_token != -1; i++)
3791 int door_token = doors[i].door_token;
3792 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
3793 int part_1 = doors[i].part_1;
3794 int part_8 = doors[i].part_8;
3795 int part_2 = part_1 + 1;
3796 int part_3 = part_1 + 2;
3797 struct DoorInfo *door = doors[i].door;
3798 struct Rect *door_rect = &door_rect_list[door_index];
3799 boolean door_gfx_redefined = FALSE;
3801 /* check if any door part graphic definitions have been redefined */
3803 for (j = 0; door_part_controls[j].door_token != -1; j++)
3805 struct DoorPartControlInfo *dpc = &door_part_controls[j];
3806 struct FileInfo *fi = getImageListEntryFromImageID(dpc->graphic);
3808 if (dpc->door_token == door_token && fi->redefined)
3809 door_gfx_redefined = TRUE;
3812 /* check for old-style door graphic/animation modifications */
3814 if (!door_gfx_redefined)
3816 if (door->anim_mode & ANIM_STATIC_PANEL)
3818 door->panel.step_xoffset = 0;
3819 door->panel.step_yoffset = 0;
3822 if (door->anim_mode & (ANIM_HORIZONTAL | ANIM_VERTICAL))
3824 struct GraphicInfo *g_part_1 = &graphic_info[part_1];
3825 struct GraphicInfo *g_part_2 = &graphic_info[part_2];
3826 int num_door_steps, num_panel_steps;
3828 /* remove door part graphics other than the two default wings */
3830 for (j = 0; door_part_controls[j].door_token != -1; j++)
3832 struct DoorPartControlInfo *dpc = &door_part_controls[j];
3833 struct GraphicInfo *g = &graphic_info[dpc->graphic];
3835 if (dpc->graphic >= part_3 &&
3836 dpc->graphic <= part_8)
3840 /* set graphics and screen positions of the default wings */
3842 g_part_1->width = door_rect->width;
3843 g_part_1->height = door_rect->height;
3844 g_part_2->width = door_rect->width;
3845 g_part_2->height = door_rect->height;
3846 g_part_2->src_x = door_rect->width;
3847 g_part_2->src_y = g_part_1->src_y;
3849 door->part_2.x = door->part_1.x;
3850 door->part_2.y = door->part_1.y;
3852 if (door->width != -1)
3854 g_part_1->width = door->width;
3855 g_part_2->width = door->width;
3857 // special treatment for graphics and screen position of right wing
3858 g_part_2->src_x += door_rect->width - door->width;
3859 door->part_2.x += door_rect->width - door->width;
3862 if (door->height != -1)
3864 g_part_1->height = door->height;
3865 g_part_2->height = door->height;
3867 // special treatment for graphics and screen position of bottom wing
3868 g_part_2->src_y += door_rect->height - door->height;
3869 door->part_2.y += door_rect->height - door->height;
3872 /* set animation delays for the default wings and panels */
3874 door->part_1.step_delay = door->step_delay;
3875 door->part_2.step_delay = door->step_delay;
3876 door->panel.step_delay = door->step_delay;
3878 /* set animation draw order for the default wings */
3880 door->part_1.sort_priority = 2; /* draw left wing over ... */
3881 door->part_2.sort_priority = 1; /* ... right wing */
3883 /* set animation draw offset for the default wings */
3885 if (door->anim_mode & ANIM_HORIZONTAL)
3887 door->part_1.step_xoffset = door->step_offset;
3888 door->part_1.step_yoffset = 0;
3889 door->part_2.step_xoffset = door->step_offset * -1;
3890 door->part_2.step_yoffset = 0;
3892 num_door_steps = g_part_1->width / door->step_offset;
3894 else // ANIM_VERTICAL
3896 door->part_1.step_xoffset = 0;
3897 door->part_1.step_yoffset = door->step_offset;
3898 door->part_2.step_xoffset = 0;
3899 door->part_2.step_yoffset = door->step_offset * -1;
3901 num_door_steps = g_part_1->height / door->step_offset;
3904 /* set animation draw offset for the default panels */
3906 if (door->step_offset > 1)
3908 num_panel_steps = 2 * door_rect->height / door->step_offset;
3909 door->panel.start_step = num_panel_steps - num_door_steps;
3910 door->panel.start_step_closing = door->panel.start_step;
3914 num_panel_steps = door_rect->height / door->step_offset;
3915 door->panel.start_step = num_panel_steps - num_door_steps / 2;
3916 door->panel.start_step_closing = door->panel.start_step;
3917 door->panel.step_delay *= 2;
3928 for (i = 0; door_part_controls[i].door_token != -1; i++)
3930 struct DoorPartControlInfo *dpc = &door_part_controls[i];
3931 struct DoorPartOrderInfo *dpo = &door_part_order[i];
3933 /* initialize "start_step_opening" and "start_step_closing", if needed */
3934 if (dpc->pos->start_step_opening == 0 &&
3935 dpc->pos->start_step_closing == 0)
3937 // dpc->pos->start_step_opening = dpc->pos->start_step;
3938 dpc->pos->start_step_closing = dpc->pos->start_step;
3941 /* fill structure for door part draw order (sorted below) */
3943 dpo->sort_priority = dpc->pos->sort_priority;
3946 /* sort door part controls according to sort_priority and graphic number */
3947 qsort(door_part_order, MAX_DOOR_PARTS,
3948 sizeof(struct DoorPartOrderInfo), compareDoorPartOrderInfo);
3951 unsigned int OpenDoor(unsigned int door_state)
3953 if (door_state & DOOR_COPY_BACK)
3955 if (door_state & DOOR_OPEN_1)
3956 BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
3957 1 * DXSIZE, 0, DXSIZE, DYSIZE, 0 * DXSIZE, 0);
3959 if (door_state & DOOR_OPEN_2)
3960 BlitBitmap(bitmap_db_door_2, bitmap_db_door_2,
3961 1 * VXSIZE, 0, VXSIZE, VYSIZE, 0 * VXSIZE, 0);
3963 door_state &= ~DOOR_COPY_BACK;
3966 return MoveDoor(door_state);
3969 unsigned int CloseDoor(unsigned int door_state)
3971 unsigned int old_door_state = GetDoorState();
3973 if (!(door_state & DOOR_NO_COPY_BACK))
3975 if (old_door_state & DOOR_OPEN_1)
3976 BlitBitmap(backbuffer, bitmap_db_door_1,
3977 DX, DY, DXSIZE, DYSIZE, 0, 0);
3979 if (old_door_state & DOOR_OPEN_2)
3980 BlitBitmap(backbuffer, bitmap_db_door_2,
3981 VX, VY, VXSIZE, VYSIZE, 0, 0);
3983 door_state &= ~DOOR_NO_COPY_BACK;
3986 return MoveDoor(door_state);
3989 unsigned int GetDoorState()
3991 return MoveDoor(DOOR_GET_STATE);
3994 unsigned int SetDoorState(unsigned int door_state)
3996 return MoveDoor(door_state | DOOR_SET_STATE);
3999 int euclid(int a, int b)
4001 return (b ? euclid(b, a % b) : a);
4004 unsigned int MoveDoor(unsigned int door_state)
4006 struct Rect door_rect_list[] =
4008 { DX, DY, DXSIZE, DYSIZE },
4009 { VX, VY, VXSIZE, VYSIZE }
4011 static int door1 = DOOR_OPEN_1;
4012 static int door2 = DOOR_CLOSE_2;
4013 unsigned int door_delay = 0;
4014 unsigned int door_delay_value;
4017 if (door_state == DOOR_GET_STATE)
4018 return (door1 | door2);
4020 if (door_state & DOOR_SET_STATE)
4022 if (door_state & DOOR_ACTION_1)
4023 door1 = door_state & DOOR_ACTION_1;
4024 if (door_state & DOOR_ACTION_2)
4025 door2 = door_state & DOOR_ACTION_2;
4027 return (door1 | door2);
4030 if (!(door_state & DOOR_FORCE_REDRAW))
4032 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
4033 door_state &= ~DOOR_OPEN_1;
4034 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
4035 door_state &= ~DOOR_CLOSE_1;
4036 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
4037 door_state &= ~DOOR_OPEN_2;
4038 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
4039 door_state &= ~DOOR_CLOSE_2;
4042 if (global.autoplay_leveldir)
4044 door_state |= DOOR_NO_DELAY;
4045 door_state &= ~DOOR_CLOSE_ALL;
4048 if (game_status == GAME_MODE_EDITOR)
4049 door_state |= DOOR_NO_DELAY;
4051 if (door_state & DOOR_ACTION)
4053 boolean door_panel_drawn[NUM_DOORS];
4054 boolean panel_has_doors[NUM_DOORS];
4055 boolean door_part_skip[MAX_DOOR_PARTS];
4056 boolean door_part_done[MAX_DOOR_PARTS];
4057 boolean door_part_done_all;
4058 int num_steps[MAX_DOOR_PARTS];
4059 int max_move_delay = 0; // delay for complete animations of all doors
4060 int max_step_delay = 0; // delay (ms) between two animation frames
4061 int num_move_steps = 0; // number of animation steps for all doors
4062 int max_move_delay_doors_only = 0; // delay for doors only (no panel)
4063 int num_move_steps_doors_only = 0; // steps for doors only (no panel)
4064 int current_move_delay = 0;
4068 for (i = 0; i < NUM_DOORS; i++)
4069 panel_has_doors[i] = FALSE;
4071 for (i = 0; i < MAX_DOOR_PARTS; i++)
4073 struct DoorPartControlInfo *dpc = &door_part_controls[i];
4074 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4075 int door_token = dpc->door_token;
4077 door_part_done[i] = FALSE;
4078 door_part_skip[i] = (!(door_state & door_token) ||
4082 for (i = 0; i < MAX_DOOR_PARTS; i++)
4084 int nr = door_part_order[i].nr;
4085 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
4086 struct DoorPartPosInfo *pos = dpc->pos;
4087 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4088 int door_token = dpc->door_token;
4089 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
4090 boolean is_panel = DOOR_PART_IS_PANEL(nr);
4091 int step_xoffset = ABS(pos->step_xoffset);
4092 int step_yoffset = ABS(pos->step_yoffset);
4093 int step_delay = pos->step_delay;
4094 int current_door_state = door_state & door_token;
4095 boolean door_opening = ((current_door_state & DOOR_OPEN) != 0);
4096 boolean door_closing = ((current_door_state & DOOR_CLOSE) != 0);
4097 boolean part_opening = (is_panel ? door_closing : door_opening);
4098 int start_step = (part_opening ? pos->start_step_opening :
4099 pos->start_step_closing);
4100 float move_xsize = (step_xoffset ? g->width : 0);
4101 float move_ysize = (step_yoffset ? g->height : 0);
4102 int move_xsteps = (step_xoffset ? ceil(move_xsize / step_xoffset) : 0);
4103 int move_ysteps = (step_yoffset ? ceil(move_ysize / step_yoffset) : 0);
4104 int move_steps = (move_xsteps && move_ysteps ?
4105 MIN(move_xsteps, move_ysteps) :
4106 move_xsteps ? move_xsteps : move_ysteps) - start_step;
4107 int move_delay = move_steps * step_delay;
4109 if (door_part_skip[nr])
4112 max_move_delay = MAX(max_move_delay, move_delay);
4113 max_step_delay = (max_step_delay == 0 ? step_delay :
4114 euclid(max_step_delay, step_delay));
4115 num_steps[nr] = move_steps;
4119 max_move_delay_doors_only = MAX(max_move_delay_doors_only, move_delay);
4121 panel_has_doors[door_index] = TRUE;
4125 max_step_delay = MAX(1, max_step_delay); // prevent division by zero
4127 num_move_steps = max_move_delay / max_step_delay;
4128 num_move_steps_doors_only = max_move_delay_doors_only / max_step_delay;
4130 door_delay_value = max_step_delay;
4132 if ((door_state & DOOR_NO_DELAY) || setup.quick_doors)
4134 start = num_move_steps - 1;
4138 /* opening door sound has priority over simultaneously closing door */
4139 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
4140 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
4141 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
4142 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
4145 for (k = start; k < num_move_steps; k++)
4147 int last_frame = num_move_steps - 1; // last frame of this "for" loop
4149 door_part_done_all = TRUE;
4151 for (i = 0; i < NUM_DOORS; i++)
4152 door_panel_drawn[i] = FALSE;
4154 for (i = 0; i < MAX_DOOR_PARTS; i++)
4156 int nr = door_part_order[i].nr;
4157 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
4158 struct DoorPartPosInfo *pos = dpc->pos;
4159 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4160 int door_token = dpc->door_token;
4161 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
4162 boolean is_panel = DOOR_PART_IS_PANEL(nr);
4163 boolean is_panel_and_door_has_closed = FALSE;
4164 struct Rect *door_rect = &door_rect_list[door_index];
4165 Bitmap *bitmap_db_door = (door_token == DOOR_1 ? bitmap_db_door_1 :
4167 Bitmap *bitmap = (is_panel ? bitmap_db_door : g->bitmap);
4168 int current_door_state = door_state & door_token;
4169 boolean door_opening = ((current_door_state & DOOR_OPEN) != 0);
4170 boolean door_closing = !door_opening;
4171 boolean part_opening = (is_panel ? door_closing : door_opening);
4172 boolean part_closing = !part_opening;
4173 int start_step = (part_opening ? pos->start_step_opening :
4174 pos->start_step_closing);
4175 int step_delay = pos->step_delay;
4176 int step_factor = step_delay / max_step_delay;
4177 int k1 = (step_factor ? k / step_factor + 1 : k);
4178 int k2 = (part_opening ? k1 + start_step : num_steps[nr] - k1);
4179 int kk = MAX(0, k2);
4182 int src_x, src_y, src_xx, src_yy;
4183 int dst_x, dst_y, dst_xx, dst_yy;
4186 if (door_part_skip[nr])
4189 if (!(door_state & door_token))
4197 int k2_door = (door_opening ? k : num_move_steps_doors_only - k - 1);
4198 int kk_door = MAX(0, k2_door);
4199 int sync_frame = kk_door * door_delay_value;
4200 int frame = getGraphicAnimationFrame(dpc->graphic, sync_frame);
4202 getGraphicSource(dpc->graphic, frame, &bitmap, &g_src_x, &g_src_y);
4207 if (!door_panel_drawn[door_index])
4209 ClearRectangle(drawto, door_rect->x, door_rect->y,
4210 door_rect->width, door_rect->height);
4212 door_panel_drawn[door_index] = TRUE;
4215 // draw opening or closing door parts
4217 if (pos->step_xoffset < 0) // door part on right side
4220 dst_xx = pos->x + ABS(kk * pos->step_xoffset);
4223 if (dst_xx + width > door_rect->width)
4224 width = door_rect->width - dst_xx;
4226 else // door part on left side
4229 dst_xx = pos->x - kk * pos->step_xoffset;
4233 src_xx = ABS(dst_xx);
4237 width = g->width - src_xx;
4239 // printf("::: k == %d [%d] \n", k, start_step);
4242 if (pos->step_yoffset < 0) // door part on bottom side
4245 dst_yy = pos->y + ABS(kk * pos->step_yoffset);
4248 if (dst_yy + height > door_rect->height)
4249 height = door_rect->height - dst_yy;
4251 else // door part on top side
4254 dst_yy = pos->y - kk * pos->step_yoffset;
4258 src_yy = ABS(dst_yy);
4262 height = g->height - src_yy;
4265 src_x = g_src_x + src_xx;
4266 src_y = g_src_y + src_yy;
4268 dst_x = door_rect->x + dst_xx;
4269 dst_y = door_rect->y + dst_yy;
4271 is_panel_and_door_has_closed =
4274 panel_has_doors[door_index] &&
4275 k >= num_move_steps_doors_only - 1);
4277 if (width >= 0 && width <= g->width &&
4278 height >= 0 && height <= g->height &&
4279 !is_panel_and_door_has_closed)
4281 if (is_panel || !pos->draw_masked)
4282 BlitBitmap(bitmap, drawto, src_x, src_y, width, height,
4285 BlitBitmapMasked(bitmap, drawto, src_x, src_y, width, height,
4289 redraw_mask |= REDRAW_DOOR_FROM_TOKEN(door_token);
4291 if ((part_opening && (width < 0 || height < 0)) ||
4292 (part_closing && (width >= g->width && height >= g->height)))
4293 door_part_done[nr] = TRUE;
4295 // continue door part animations, but not panel after door has closed
4296 if (!door_part_done[nr] && !is_panel_and_door_has_closed)
4297 door_part_done_all = FALSE;
4300 if (!(door_state & DOOR_NO_DELAY))
4304 if (game_status == GAME_MODE_MAIN)
4307 SkipUntilDelayReached(&door_delay, door_delay_value, &k, last_frame);
4309 current_move_delay += max_step_delay;
4312 if (door_part_done_all)
4317 if (door_state & DOOR_ACTION_1)
4318 door1 = door_state & DOOR_ACTION_1;
4319 if (door_state & DOOR_ACTION_2)
4320 door2 = door_state & DOOR_ACTION_2;
4322 return (door1 | door2);
4325 void DrawSpecialEditorDoor()
4327 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
4328 int top_border_width = gfx1->width;
4329 int top_border_height = gfx1->height;
4330 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
4331 int ex = EX - outer_border;
4332 int ey = EY - outer_border;
4333 int vy = VY - outer_border;
4334 int exsize = EXSIZE + 2 * outer_border;
4336 /* draw bigger level editor toolbox window */
4337 BlitBitmap(gfx1->bitmap, drawto, gfx1->src_x, gfx1->src_y,
4338 top_border_width, top_border_height, ex, ey - top_border_height);
4339 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto, ex, vy,
4340 exsize, EYSIZE - VYSIZE + outer_border, ex, ey);
4342 redraw_mask |= REDRAW_ALL;
4345 void UndrawSpecialEditorDoor()
4347 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
4348 int top_border_width = gfx1->width;
4349 int top_border_height = gfx1->height;
4350 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
4351 int ex = EX - outer_border;
4352 int ey = EY - outer_border;
4353 int ey_top = ey - top_border_height;
4354 int exsize = EXSIZE + 2 * outer_border;
4355 int eysize = EYSIZE + 2 * outer_border;
4357 /* draw normal tape recorder window */
4358 if (graphic_info[IMG_GLOBAL_BORDER].bitmap)
4360 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
4361 ex, ey_top, top_border_width, top_border_height,
4363 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
4364 ex, ey, exsize, eysize, ex, ey);
4368 // if screen background is set to "[NONE]", clear editor toolbox window
4369 ClearRectangle(drawto, ex, ey_top, top_border_width, top_border_height);
4370 ClearRectangle(drawto, ex, ey, exsize, eysize);
4373 redraw_mask |= REDRAW_ALL;
4377 /* ---------- new tool button stuff ---------------------------------------- */
4382 struct TextPosInfo *pos;
4385 } toolbutton_info[NUM_TOOL_BUTTONS] =
4388 IMG_REQUEST_BUTTON_GFX_YES, &request.button.yes,
4389 TOOL_CTRL_ID_YES, "yes"
4392 IMG_REQUEST_BUTTON_GFX_NO, &request.button.no,
4393 TOOL_CTRL_ID_NO, "no"
4396 IMG_REQUEST_BUTTON_GFX_CONFIRM, &request.button.confirm,
4397 TOOL_CTRL_ID_CONFIRM, "confirm"
4400 IMG_REQUEST_BUTTON_GFX_PLAYER_1, &request.button.player_1,
4401 TOOL_CTRL_ID_PLAYER_1, "player 1"
4404 IMG_REQUEST_BUTTON_GFX_PLAYER_2, &request.button.player_2,
4405 TOOL_CTRL_ID_PLAYER_2, "player 2"
4408 IMG_REQUEST_BUTTON_GFX_PLAYER_3, &request.button.player_3,
4409 TOOL_CTRL_ID_PLAYER_3, "player 3"
4412 IMG_REQUEST_BUTTON_GFX_PLAYER_4, &request.button.player_4,
4413 TOOL_CTRL_ID_PLAYER_4, "player 4"
4417 void CreateToolButtons()
4421 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4423 struct GraphicInfo *gfx = &graphic_info[toolbutton_info[i].graphic];
4424 struct TextPosInfo *pos = toolbutton_info[i].pos;
4425 struct GadgetInfo *gi;
4426 Bitmap *deco_bitmap = None;
4427 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
4428 unsigned int event_mask = GD_EVENT_RELEASED;
4431 int gd_x = gfx->src_x;
4432 int gd_y = gfx->src_y;
4433 int gd_xp = gfx->src_x + gfx->pressed_xoffset;
4434 int gd_yp = gfx->src_y + gfx->pressed_yoffset;
4437 if (global.use_envelope_request)
4438 setRequestPosition(&dx, &dy, TRUE);
4440 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
4442 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
4444 getSizedGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr), 0,
4445 pos->size, &deco_bitmap, &deco_x, &deco_y);
4446 deco_xpos = (gfx->width - pos->size) / 2;
4447 deco_ypos = (gfx->height - pos->size) / 2;
4450 gi = CreateGadget(GDI_CUSTOM_ID, id,
4451 GDI_INFO_TEXT, toolbutton_info[i].infotext,
4452 GDI_X, dx + GDI_ACTIVE_POS(pos->x),
4453 GDI_Y, dy + GDI_ACTIVE_POS(pos->y),
4454 GDI_WIDTH, gfx->width,
4455 GDI_HEIGHT, gfx->height,
4456 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
4457 GDI_STATE, GD_BUTTON_UNPRESSED,
4458 GDI_DESIGN_UNPRESSED, gfx->bitmap, gd_x, gd_y,
4459 GDI_DESIGN_PRESSED, gfx->bitmap, gd_xp, gd_yp,
4460 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
4461 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
4462 GDI_DECORATION_SIZE, pos->size, pos->size,
4463 GDI_DECORATION_SHIFTING, 1, 1,
4464 GDI_DIRECT_DRAW, FALSE,
4465 GDI_EVENT_MASK, event_mask,
4466 GDI_CALLBACK_ACTION, HandleToolButtons,
4470 Error(ERR_EXIT, "cannot create gadget");
4472 tool_gadget[id] = gi;
4476 void FreeToolButtons()
4480 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4481 FreeGadget(tool_gadget[i]);
4484 static void UnmapToolButtons()
4488 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4489 UnmapGadget(tool_gadget[i]);
4492 static void HandleToolButtons(struct GadgetInfo *gi)
4494 request_gadget_id = gi->custom_id;
4497 static struct Mapping_EM_to_RND_object
4500 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
4501 boolean is_backside; /* backside of moving element */
4507 em_object_mapping_list[] =
4510 Xblank, TRUE, FALSE,
4514 Yacid_splash_eB, FALSE, FALSE,
4515 EL_ACID_SPLASH_RIGHT, -1, -1
4518 Yacid_splash_wB, FALSE, FALSE,
4519 EL_ACID_SPLASH_LEFT, -1, -1
4522 #ifdef EM_ENGINE_BAD_ROLL
4524 Xstone_force_e, FALSE, FALSE,
4525 EL_ROCK, -1, MV_BIT_RIGHT
4528 Xstone_force_w, FALSE, FALSE,
4529 EL_ROCK, -1, MV_BIT_LEFT
4532 Xnut_force_e, FALSE, FALSE,
4533 EL_NUT, -1, MV_BIT_RIGHT
4536 Xnut_force_w, FALSE, FALSE,
4537 EL_NUT, -1, MV_BIT_LEFT
4540 Xspring_force_e, FALSE, FALSE,
4541 EL_SPRING, -1, MV_BIT_RIGHT
4544 Xspring_force_w, FALSE, FALSE,
4545 EL_SPRING, -1, MV_BIT_LEFT
4548 Xemerald_force_e, FALSE, FALSE,
4549 EL_EMERALD, -1, MV_BIT_RIGHT
4552 Xemerald_force_w, FALSE, FALSE,
4553 EL_EMERALD, -1, MV_BIT_LEFT
4556 Xdiamond_force_e, FALSE, FALSE,
4557 EL_DIAMOND, -1, MV_BIT_RIGHT
4560 Xdiamond_force_w, FALSE, FALSE,
4561 EL_DIAMOND, -1, MV_BIT_LEFT
4564 Xbomb_force_e, FALSE, FALSE,
4565 EL_BOMB, -1, MV_BIT_RIGHT
4568 Xbomb_force_w, FALSE, FALSE,
4569 EL_BOMB, -1, MV_BIT_LEFT
4571 #endif /* EM_ENGINE_BAD_ROLL */
4574 Xstone, TRUE, FALSE,
4578 Xstone_pause, FALSE, FALSE,
4582 Xstone_fall, FALSE, FALSE,
4586 Ystone_s, FALSE, FALSE,
4587 EL_ROCK, ACTION_FALLING, -1
4590 Ystone_sB, FALSE, TRUE,
4591 EL_ROCK, ACTION_FALLING, -1
4594 Ystone_e, FALSE, FALSE,
4595 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
4598 Ystone_eB, FALSE, TRUE,
4599 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
4602 Ystone_w, FALSE, FALSE,
4603 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
4606 Ystone_wB, FALSE, TRUE,
4607 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
4614 Xnut_pause, FALSE, FALSE,
4618 Xnut_fall, FALSE, FALSE,
4622 Ynut_s, FALSE, FALSE,
4623 EL_NUT, ACTION_FALLING, -1
4626 Ynut_sB, FALSE, TRUE,
4627 EL_NUT, ACTION_FALLING, -1
4630 Ynut_e, FALSE, FALSE,
4631 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
4634 Ynut_eB, FALSE, TRUE,
4635 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
4638 Ynut_w, FALSE, FALSE,
4639 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
4642 Ynut_wB, FALSE, TRUE,
4643 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
4646 Xbug_n, TRUE, FALSE,
4650 Xbug_e, TRUE, FALSE,
4651 EL_BUG_RIGHT, -1, -1
4654 Xbug_s, TRUE, FALSE,
4658 Xbug_w, TRUE, FALSE,
4662 Xbug_gon, FALSE, FALSE,
4666 Xbug_goe, FALSE, FALSE,
4667 EL_BUG_RIGHT, -1, -1
4670 Xbug_gos, FALSE, FALSE,
4674 Xbug_gow, FALSE, FALSE,
4678 Ybug_n, FALSE, FALSE,
4679 EL_BUG, ACTION_MOVING, MV_BIT_UP
4682 Ybug_nB, FALSE, TRUE,
4683 EL_BUG, ACTION_MOVING, MV_BIT_UP
4686 Ybug_e, FALSE, FALSE,
4687 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
4690 Ybug_eB, FALSE, TRUE,
4691 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
4694 Ybug_s, FALSE, FALSE,
4695 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
4698 Ybug_sB, FALSE, TRUE,
4699 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
4702 Ybug_w, FALSE, FALSE,
4703 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
4706 Ybug_wB, FALSE, TRUE,
4707 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
4710 Ybug_w_n, FALSE, FALSE,
4711 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
4714 Ybug_n_e, FALSE, FALSE,
4715 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
4718 Ybug_e_s, FALSE, FALSE,
4719 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
4722 Ybug_s_w, FALSE, FALSE,
4723 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
4726 Ybug_e_n, FALSE, FALSE,
4727 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
4730 Ybug_s_e, FALSE, FALSE,
4731 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
4734 Ybug_w_s, FALSE, FALSE,
4735 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
4738 Ybug_n_w, FALSE, FALSE,
4739 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
4742 Ybug_stone, FALSE, FALSE,
4743 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
4746 Ybug_spring, FALSE, FALSE,
4747 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
4750 Xtank_n, TRUE, FALSE,
4751 EL_SPACESHIP_UP, -1, -1
4754 Xtank_e, TRUE, FALSE,
4755 EL_SPACESHIP_RIGHT, -1, -1
4758 Xtank_s, TRUE, FALSE,
4759 EL_SPACESHIP_DOWN, -1, -1
4762 Xtank_w, TRUE, FALSE,
4763 EL_SPACESHIP_LEFT, -1, -1
4766 Xtank_gon, FALSE, FALSE,
4767 EL_SPACESHIP_UP, -1, -1
4770 Xtank_goe, FALSE, FALSE,
4771 EL_SPACESHIP_RIGHT, -1, -1
4774 Xtank_gos, FALSE, FALSE,
4775 EL_SPACESHIP_DOWN, -1, -1
4778 Xtank_gow, FALSE, FALSE,
4779 EL_SPACESHIP_LEFT, -1, -1
4782 Ytank_n, FALSE, FALSE,
4783 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
4786 Ytank_nB, FALSE, TRUE,
4787 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
4790 Ytank_e, FALSE, FALSE,
4791 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
4794 Ytank_eB, FALSE, TRUE,
4795 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
4798 Ytank_s, FALSE, FALSE,
4799 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
4802 Ytank_sB, FALSE, TRUE,
4803 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
4806 Ytank_w, FALSE, FALSE,
4807 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
4810 Ytank_wB, FALSE, TRUE,
4811 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
4814 Ytank_w_n, FALSE, FALSE,
4815 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
4818 Ytank_n_e, FALSE, FALSE,
4819 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
4822 Ytank_e_s, FALSE, FALSE,
4823 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
4826 Ytank_s_w, FALSE, FALSE,
4827 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
4830 Ytank_e_n, FALSE, FALSE,
4831 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
4834 Ytank_s_e, FALSE, FALSE,
4835 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
4838 Ytank_w_s, FALSE, FALSE,
4839 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
4842 Ytank_n_w, FALSE, FALSE,
4843 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
4846 Ytank_stone, FALSE, FALSE,
4847 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
4850 Ytank_spring, FALSE, FALSE,
4851 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
4854 Xandroid, TRUE, FALSE,
4855 EL_EMC_ANDROID, ACTION_ACTIVE, -1
4858 Xandroid_1_n, FALSE, FALSE,
4859 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
4862 Xandroid_2_n, FALSE, FALSE,
4863 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
4866 Xandroid_1_e, FALSE, FALSE,
4867 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
4870 Xandroid_2_e, FALSE, FALSE,
4871 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
4874 Xandroid_1_w, FALSE, FALSE,
4875 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
4878 Xandroid_2_w, FALSE, FALSE,
4879 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
4882 Xandroid_1_s, FALSE, FALSE,
4883 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
4886 Xandroid_2_s, FALSE, FALSE,
4887 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
4890 Yandroid_n, FALSE, FALSE,
4891 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
4894 Yandroid_nB, FALSE, TRUE,
4895 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
4898 Yandroid_ne, FALSE, FALSE,
4899 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
4902 Yandroid_neB, FALSE, TRUE,
4903 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
4906 Yandroid_e, FALSE, FALSE,
4907 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
4910 Yandroid_eB, FALSE, TRUE,
4911 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
4914 Yandroid_se, FALSE, FALSE,
4915 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
4918 Yandroid_seB, FALSE, TRUE,
4919 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
4922 Yandroid_s, FALSE, FALSE,
4923 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
4926 Yandroid_sB, FALSE, TRUE,
4927 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
4930 Yandroid_sw, FALSE, FALSE,
4931 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
4934 Yandroid_swB, FALSE, TRUE,
4935 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
4938 Yandroid_w, FALSE, FALSE,
4939 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
4942 Yandroid_wB, FALSE, TRUE,
4943 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
4946 Yandroid_nw, FALSE, FALSE,
4947 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
4950 Yandroid_nwB, FALSE, TRUE,
4951 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
4954 Xspring, TRUE, FALSE,
4958 Xspring_pause, FALSE, FALSE,
4962 Xspring_e, FALSE, FALSE,
4966 Xspring_w, FALSE, FALSE,
4970 Xspring_fall, FALSE, FALSE,
4974 Yspring_s, FALSE, FALSE,
4975 EL_SPRING, ACTION_FALLING, -1
4978 Yspring_sB, FALSE, TRUE,
4979 EL_SPRING, ACTION_FALLING, -1
4982 Yspring_e, FALSE, FALSE,
4983 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
4986 Yspring_eB, FALSE, TRUE,
4987 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
4990 Yspring_w, FALSE, FALSE,
4991 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
4994 Yspring_wB, FALSE, TRUE,
4995 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
4998 Yspring_kill_e, FALSE, FALSE,
4999 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
5002 Yspring_kill_eB, FALSE, TRUE,
5003 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
5006 Yspring_kill_w, FALSE, FALSE,
5007 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
5010 Yspring_kill_wB, FALSE, TRUE,
5011 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
5014 Xeater_n, TRUE, FALSE,
5015 EL_YAMYAM_UP, -1, -1
5018 Xeater_e, TRUE, FALSE,
5019 EL_YAMYAM_RIGHT, -1, -1
5022 Xeater_w, TRUE, FALSE,
5023 EL_YAMYAM_LEFT, -1, -1
5026 Xeater_s, TRUE, FALSE,
5027 EL_YAMYAM_DOWN, -1, -1
5030 Yeater_n, FALSE, FALSE,
5031 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
5034 Yeater_nB, FALSE, TRUE,
5035 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
5038 Yeater_e, FALSE, FALSE,
5039 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
5042 Yeater_eB, FALSE, TRUE,
5043 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
5046 Yeater_s, FALSE, FALSE,
5047 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
5050 Yeater_sB, FALSE, TRUE,
5051 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
5054 Yeater_w, FALSE, FALSE,
5055 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
5058 Yeater_wB, FALSE, TRUE,
5059 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
5062 Yeater_stone, FALSE, FALSE,
5063 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
5066 Yeater_spring, FALSE, FALSE,
5067 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
5070 Xalien, TRUE, FALSE,
5074 Xalien_pause, FALSE, FALSE,
5078 Yalien_n, FALSE, FALSE,
5079 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
5082 Yalien_nB, FALSE, TRUE,
5083 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
5086 Yalien_e, FALSE, FALSE,
5087 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
5090 Yalien_eB, FALSE, TRUE,
5091 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
5094 Yalien_s, FALSE, FALSE,
5095 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
5098 Yalien_sB, FALSE, TRUE,
5099 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
5102 Yalien_w, FALSE, FALSE,
5103 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
5106 Yalien_wB, FALSE, TRUE,
5107 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
5110 Yalien_stone, FALSE, FALSE,
5111 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
5114 Yalien_spring, FALSE, FALSE,
5115 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
5118 Xemerald, TRUE, FALSE,
5122 Xemerald_pause, FALSE, FALSE,
5126 Xemerald_fall, FALSE, FALSE,
5130 Xemerald_shine, FALSE, FALSE,
5131 EL_EMERALD, ACTION_TWINKLING, -1
5134 Yemerald_s, FALSE, FALSE,
5135 EL_EMERALD, ACTION_FALLING, -1
5138 Yemerald_sB, FALSE, TRUE,
5139 EL_EMERALD, ACTION_FALLING, -1
5142 Yemerald_e, FALSE, FALSE,
5143 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
5146 Yemerald_eB, FALSE, TRUE,
5147 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
5150 Yemerald_w, FALSE, FALSE,
5151 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
5154 Yemerald_wB, FALSE, TRUE,
5155 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
5158 Yemerald_eat, FALSE, FALSE,
5159 EL_EMERALD, ACTION_COLLECTING, -1
5162 Yemerald_stone, FALSE, FALSE,
5163 EL_NUT, ACTION_BREAKING, -1
5166 Xdiamond, TRUE, FALSE,
5170 Xdiamond_pause, FALSE, FALSE,
5174 Xdiamond_fall, FALSE, FALSE,
5178 Xdiamond_shine, FALSE, FALSE,
5179 EL_DIAMOND, ACTION_TWINKLING, -1
5182 Ydiamond_s, FALSE, FALSE,
5183 EL_DIAMOND, ACTION_FALLING, -1
5186 Ydiamond_sB, FALSE, TRUE,
5187 EL_DIAMOND, ACTION_FALLING, -1
5190 Ydiamond_e, FALSE, FALSE,
5191 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
5194 Ydiamond_eB, FALSE, TRUE,
5195 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
5198 Ydiamond_w, FALSE, FALSE,
5199 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
5202 Ydiamond_wB, FALSE, TRUE,
5203 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
5206 Ydiamond_eat, FALSE, FALSE,
5207 EL_DIAMOND, ACTION_COLLECTING, -1
5210 Ydiamond_stone, FALSE, FALSE,
5211 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
5214 Xdrip_fall, TRUE, FALSE,
5215 EL_AMOEBA_DROP, -1, -1
5218 Xdrip_stretch, FALSE, FALSE,
5219 EL_AMOEBA_DROP, ACTION_FALLING, -1
5222 Xdrip_stretchB, FALSE, TRUE,
5223 EL_AMOEBA_DROP, ACTION_FALLING, -1
5226 Xdrip_eat, FALSE, FALSE,
5227 EL_AMOEBA_DROP, ACTION_GROWING, -1
5230 Ydrip_s1, FALSE, FALSE,
5231 EL_AMOEBA_DROP, ACTION_FALLING, -1
5234 Ydrip_s1B, FALSE, TRUE,
5235 EL_AMOEBA_DROP, ACTION_FALLING, -1
5238 Ydrip_s2, FALSE, FALSE,
5239 EL_AMOEBA_DROP, ACTION_FALLING, -1
5242 Ydrip_s2B, FALSE, TRUE,
5243 EL_AMOEBA_DROP, ACTION_FALLING, -1
5250 Xbomb_pause, FALSE, FALSE,
5254 Xbomb_fall, FALSE, FALSE,
5258 Ybomb_s, FALSE, FALSE,
5259 EL_BOMB, ACTION_FALLING, -1
5262 Ybomb_sB, FALSE, TRUE,
5263 EL_BOMB, ACTION_FALLING, -1
5266 Ybomb_e, FALSE, FALSE,
5267 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
5270 Ybomb_eB, FALSE, TRUE,
5271 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
5274 Ybomb_w, FALSE, FALSE,
5275 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
5278 Ybomb_wB, FALSE, TRUE,
5279 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
5282 Ybomb_eat, FALSE, FALSE,
5283 EL_BOMB, ACTION_ACTIVATING, -1
5286 Xballoon, TRUE, FALSE,
5290 Yballoon_n, FALSE, FALSE,
5291 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
5294 Yballoon_nB, FALSE, TRUE,
5295 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
5298 Yballoon_e, FALSE, FALSE,
5299 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
5302 Yballoon_eB, FALSE, TRUE,
5303 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
5306 Yballoon_s, FALSE, FALSE,
5307 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
5310 Yballoon_sB, FALSE, TRUE,
5311 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
5314 Yballoon_w, FALSE, FALSE,
5315 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
5318 Yballoon_wB, FALSE, TRUE,
5319 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
5322 Xgrass, TRUE, FALSE,
5323 EL_EMC_GRASS, -1, -1
5326 Ygrass_nB, FALSE, FALSE,
5327 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
5330 Ygrass_eB, FALSE, FALSE,
5331 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
5334 Ygrass_sB, FALSE, FALSE,
5335 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
5338 Ygrass_wB, FALSE, FALSE,
5339 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
5346 Ydirt_nB, FALSE, FALSE,
5347 EL_SAND, ACTION_DIGGING, MV_BIT_UP
5350 Ydirt_eB, FALSE, FALSE,
5351 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
5354 Ydirt_sB, FALSE, FALSE,
5355 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
5358 Ydirt_wB, FALSE, FALSE,
5359 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
5362 Xacid_ne, TRUE, FALSE,
5363 EL_ACID_POOL_TOPRIGHT, -1, -1
5366 Xacid_se, TRUE, FALSE,
5367 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
5370 Xacid_s, TRUE, FALSE,
5371 EL_ACID_POOL_BOTTOM, -1, -1
5374 Xacid_sw, TRUE, FALSE,
5375 EL_ACID_POOL_BOTTOMLEFT, -1, -1
5378 Xacid_nw, TRUE, FALSE,
5379 EL_ACID_POOL_TOPLEFT, -1, -1
5382 Xacid_1, TRUE, FALSE,
5386 Xacid_2, FALSE, FALSE,
5390 Xacid_3, FALSE, FALSE,
5394 Xacid_4, FALSE, FALSE,
5398 Xacid_5, FALSE, FALSE,
5402 Xacid_6, FALSE, FALSE,
5406 Xacid_7, FALSE, FALSE,
5410 Xacid_8, FALSE, FALSE,
5414 Xball_1, TRUE, FALSE,
5415 EL_EMC_MAGIC_BALL, -1, -1
5418 Xball_1B, FALSE, FALSE,
5419 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5422 Xball_2, FALSE, FALSE,
5423 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5426 Xball_2B, FALSE, FALSE,
5427 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5430 Yball_eat, FALSE, FALSE,
5431 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
5434 Ykey_1_eat, FALSE, FALSE,
5435 EL_EM_KEY_1, ACTION_COLLECTING, -1
5438 Ykey_2_eat, FALSE, FALSE,
5439 EL_EM_KEY_2, ACTION_COLLECTING, -1
5442 Ykey_3_eat, FALSE, FALSE,
5443 EL_EM_KEY_3, ACTION_COLLECTING, -1
5446 Ykey_4_eat, FALSE, FALSE,
5447 EL_EM_KEY_4, ACTION_COLLECTING, -1
5450 Ykey_5_eat, FALSE, FALSE,
5451 EL_EMC_KEY_5, ACTION_COLLECTING, -1
5454 Ykey_6_eat, FALSE, FALSE,
5455 EL_EMC_KEY_6, ACTION_COLLECTING, -1
5458 Ykey_7_eat, FALSE, FALSE,
5459 EL_EMC_KEY_7, ACTION_COLLECTING, -1
5462 Ykey_8_eat, FALSE, FALSE,
5463 EL_EMC_KEY_8, ACTION_COLLECTING, -1
5466 Ylenses_eat, FALSE, FALSE,
5467 EL_EMC_LENSES, ACTION_COLLECTING, -1
5470 Ymagnify_eat, FALSE, FALSE,
5471 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
5474 Ygrass_eat, FALSE, FALSE,
5475 EL_EMC_GRASS, ACTION_SNAPPING, -1
5478 Ydirt_eat, FALSE, FALSE,
5479 EL_SAND, ACTION_SNAPPING, -1
5482 Xgrow_ns, TRUE, FALSE,
5483 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
5486 Ygrow_ns_eat, FALSE, FALSE,
5487 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
5490 Xgrow_ew, TRUE, FALSE,
5491 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
5494 Ygrow_ew_eat, FALSE, FALSE,
5495 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
5498 Xwonderwall, TRUE, FALSE,
5499 EL_MAGIC_WALL, -1, -1
5502 XwonderwallB, FALSE, FALSE,
5503 EL_MAGIC_WALL, ACTION_ACTIVE, -1
5506 Xamoeba_1, TRUE, FALSE,
5507 EL_AMOEBA_DRY, ACTION_OTHER, -1
5510 Xamoeba_2, FALSE, FALSE,
5511 EL_AMOEBA_DRY, ACTION_OTHER, -1
5514 Xamoeba_3, FALSE, FALSE,
5515 EL_AMOEBA_DRY, ACTION_OTHER, -1
5518 Xamoeba_4, FALSE, FALSE,
5519 EL_AMOEBA_DRY, ACTION_OTHER, -1
5522 Xamoeba_5, TRUE, FALSE,
5523 EL_AMOEBA_WET, ACTION_OTHER, -1
5526 Xamoeba_6, FALSE, FALSE,
5527 EL_AMOEBA_WET, ACTION_OTHER, -1
5530 Xamoeba_7, FALSE, FALSE,
5531 EL_AMOEBA_WET, ACTION_OTHER, -1
5534 Xamoeba_8, FALSE, FALSE,
5535 EL_AMOEBA_WET, ACTION_OTHER, -1
5538 Xdoor_1, TRUE, FALSE,
5539 EL_EM_GATE_1, -1, -1
5542 Xdoor_2, TRUE, FALSE,
5543 EL_EM_GATE_2, -1, -1
5546 Xdoor_3, TRUE, FALSE,
5547 EL_EM_GATE_3, -1, -1
5550 Xdoor_4, TRUE, FALSE,
5551 EL_EM_GATE_4, -1, -1
5554 Xdoor_5, TRUE, FALSE,
5555 EL_EMC_GATE_5, -1, -1
5558 Xdoor_6, TRUE, FALSE,
5559 EL_EMC_GATE_6, -1, -1
5562 Xdoor_7, TRUE, FALSE,
5563 EL_EMC_GATE_7, -1, -1
5566 Xdoor_8, TRUE, FALSE,
5567 EL_EMC_GATE_8, -1, -1
5570 Xkey_1, TRUE, FALSE,
5574 Xkey_2, TRUE, FALSE,
5578 Xkey_3, TRUE, FALSE,
5582 Xkey_4, TRUE, FALSE,
5586 Xkey_5, TRUE, FALSE,
5587 EL_EMC_KEY_5, -1, -1
5590 Xkey_6, TRUE, FALSE,
5591 EL_EMC_KEY_6, -1, -1
5594 Xkey_7, TRUE, FALSE,
5595 EL_EMC_KEY_7, -1, -1
5598 Xkey_8, TRUE, FALSE,
5599 EL_EMC_KEY_8, -1, -1
5602 Xwind_n, TRUE, FALSE,
5603 EL_BALLOON_SWITCH_UP, -1, -1
5606 Xwind_e, TRUE, FALSE,
5607 EL_BALLOON_SWITCH_RIGHT, -1, -1
5610 Xwind_s, TRUE, FALSE,
5611 EL_BALLOON_SWITCH_DOWN, -1, -1
5614 Xwind_w, TRUE, FALSE,
5615 EL_BALLOON_SWITCH_LEFT, -1, -1
5618 Xwind_nesw, TRUE, FALSE,
5619 EL_BALLOON_SWITCH_ANY, -1, -1
5622 Xwind_stop, TRUE, FALSE,
5623 EL_BALLOON_SWITCH_NONE, -1, -1
5627 EL_EM_EXIT_CLOSED, -1, -1
5630 Xexit_1, TRUE, FALSE,
5631 EL_EM_EXIT_OPEN, -1, -1
5634 Xexit_2, FALSE, FALSE,
5635 EL_EM_EXIT_OPEN, -1, -1
5638 Xexit_3, FALSE, FALSE,
5639 EL_EM_EXIT_OPEN, -1, -1
5642 Xdynamite, TRUE, FALSE,
5643 EL_EM_DYNAMITE, -1, -1
5646 Ydynamite_eat, FALSE, FALSE,
5647 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
5650 Xdynamite_1, TRUE, FALSE,
5651 EL_EM_DYNAMITE_ACTIVE, -1, -1
5654 Xdynamite_2, FALSE, FALSE,
5655 EL_EM_DYNAMITE_ACTIVE, -1, -1
5658 Xdynamite_3, FALSE, FALSE,
5659 EL_EM_DYNAMITE_ACTIVE, -1, -1
5662 Xdynamite_4, FALSE, FALSE,
5663 EL_EM_DYNAMITE_ACTIVE, -1, -1
5666 Xbumper, TRUE, FALSE,
5667 EL_EMC_SPRING_BUMPER, -1, -1
5670 XbumperB, FALSE, FALSE,
5671 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
5674 Xwheel, TRUE, FALSE,
5675 EL_ROBOT_WHEEL, -1, -1
5678 XwheelB, FALSE, FALSE,
5679 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
5682 Xswitch, TRUE, FALSE,
5683 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
5686 XswitchB, FALSE, FALSE,
5687 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
5691 EL_QUICKSAND_EMPTY, -1, -1
5694 Xsand_stone, TRUE, FALSE,
5695 EL_QUICKSAND_FULL, -1, -1
5698 Xsand_stonein_1, FALSE, TRUE,
5699 EL_ROCK, ACTION_FILLING, -1
5702 Xsand_stonein_2, FALSE, TRUE,
5703 EL_ROCK, ACTION_FILLING, -1
5706 Xsand_stonein_3, FALSE, TRUE,
5707 EL_ROCK, ACTION_FILLING, -1
5710 Xsand_stonein_4, FALSE, TRUE,
5711 EL_ROCK, ACTION_FILLING, -1
5714 Xsand_stonesand_1, FALSE, FALSE,
5715 EL_QUICKSAND_EMPTYING, -1, -1
5718 Xsand_stonesand_2, FALSE, FALSE,
5719 EL_QUICKSAND_EMPTYING, -1, -1
5722 Xsand_stonesand_3, FALSE, FALSE,
5723 EL_QUICKSAND_EMPTYING, -1, -1
5726 Xsand_stonesand_4, FALSE, FALSE,
5727 EL_QUICKSAND_EMPTYING, -1, -1
5730 Xsand_stonesand_quickout_1, FALSE, FALSE,
5731 EL_QUICKSAND_EMPTYING, -1, -1
5734 Xsand_stonesand_quickout_2, FALSE, FALSE,
5735 EL_QUICKSAND_EMPTYING, -1, -1
5738 Xsand_stoneout_1, FALSE, FALSE,
5739 EL_ROCK, ACTION_EMPTYING, -1
5742 Xsand_stoneout_2, FALSE, FALSE,
5743 EL_ROCK, ACTION_EMPTYING, -1
5746 Xsand_sandstone_1, FALSE, FALSE,
5747 EL_QUICKSAND_FILLING, -1, -1
5750 Xsand_sandstone_2, FALSE, FALSE,
5751 EL_QUICKSAND_FILLING, -1, -1
5754 Xsand_sandstone_3, FALSE, FALSE,
5755 EL_QUICKSAND_FILLING, -1, -1
5758 Xsand_sandstone_4, FALSE, FALSE,
5759 EL_QUICKSAND_FILLING, -1, -1
5762 Xplant, TRUE, FALSE,
5763 EL_EMC_PLANT, -1, -1
5766 Yplant, FALSE, FALSE,
5767 EL_EMC_PLANT, -1, -1
5770 Xlenses, TRUE, FALSE,
5771 EL_EMC_LENSES, -1, -1
5774 Xmagnify, TRUE, FALSE,
5775 EL_EMC_MAGNIFIER, -1, -1
5778 Xdripper, TRUE, FALSE,
5779 EL_EMC_DRIPPER, -1, -1
5782 XdripperB, FALSE, FALSE,
5783 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
5786 Xfake_blank, TRUE, FALSE,
5787 EL_INVISIBLE_WALL, -1, -1
5790 Xfake_blankB, FALSE, FALSE,
5791 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
5794 Xfake_grass, TRUE, FALSE,
5795 EL_EMC_FAKE_GRASS, -1, -1
5798 Xfake_grassB, FALSE, FALSE,
5799 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
5802 Xfake_door_1, TRUE, FALSE,
5803 EL_EM_GATE_1_GRAY, -1, -1
5806 Xfake_door_2, TRUE, FALSE,
5807 EL_EM_GATE_2_GRAY, -1, -1
5810 Xfake_door_3, TRUE, FALSE,
5811 EL_EM_GATE_3_GRAY, -1, -1
5814 Xfake_door_4, TRUE, FALSE,
5815 EL_EM_GATE_4_GRAY, -1, -1
5818 Xfake_door_5, TRUE, FALSE,
5819 EL_EMC_GATE_5_GRAY, -1, -1
5822 Xfake_door_6, TRUE, FALSE,
5823 EL_EMC_GATE_6_GRAY, -1, -1
5826 Xfake_door_7, TRUE, FALSE,
5827 EL_EMC_GATE_7_GRAY, -1, -1
5830 Xfake_door_8, TRUE, FALSE,
5831 EL_EMC_GATE_8_GRAY, -1, -1
5834 Xfake_acid_1, TRUE, FALSE,
5835 EL_EMC_FAKE_ACID, -1, -1
5838 Xfake_acid_2, FALSE, FALSE,
5839 EL_EMC_FAKE_ACID, -1, -1
5842 Xfake_acid_3, FALSE, FALSE,
5843 EL_EMC_FAKE_ACID, -1, -1
5846 Xfake_acid_4, FALSE, FALSE,
5847 EL_EMC_FAKE_ACID, -1, -1
5850 Xfake_acid_5, FALSE, FALSE,
5851 EL_EMC_FAKE_ACID, -1, -1
5854 Xfake_acid_6, FALSE, FALSE,
5855 EL_EMC_FAKE_ACID, -1, -1
5858 Xfake_acid_7, FALSE, FALSE,
5859 EL_EMC_FAKE_ACID, -1, -1
5862 Xfake_acid_8, FALSE, FALSE,
5863 EL_EMC_FAKE_ACID, -1, -1
5866 Xsteel_1, TRUE, FALSE,
5867 EL_STEELWALL, -1, -1
5870 Xsteel_2, TRUE, FALSE,
5871 EL_EMC_STEELWALL_2, -1, -1
5874 Xsteel_3, TRUE, FALSE,
5875 EL_EMC_STEELWALL_3, -1, -1
5878 Xsteel_4, TRUE, FALSE,
5879 EL_EMC_STEELWALL_4, -1, -1
5882 Xwall_1, TRUE, FALSE,
5886 Xwall_2, TRUE, FALSE,
5887 EL_EMC_WALL_14, -1, -1
5890 Xwall_3, TRUE, FALSE,
5891 EL_EMC_WALL_15, -1, -1
5894 Xwall_4, TRUE, FALSE,
5895 EL_EMC_WALL_16, -1, -1
5898 Xround_wall_1, TRUE, FALSE,
5899 EL_WALL_SLIPPERY, -1, -1
5902 Xround_wall_2, TRUE, FALSE,
5903 EL_EMC_WALL_SLIPPERY_2, -1, -1
5906 Xround_wall_3, TRUE, FALSE,
5907 EL_EMC_WALL_SLIPPERY_3, -1, -1
5910 Xround_wall_4, TRUE, FALSE,
5911 EL_EMC_WALL_SLIPPERY_4, -1, -1
5914 Xdecor_1, TRUE, FALSE,
5915 EL_EMC_WALL_8, -1, -1
5918 Xdecor_2, TRUE, FALSE,
5919 EL_EMC_WALL_6, -1, -1
5922 Xdecor_3, TRUE, FALSE,
5923 EL_EMC_WALL_4, -1, -1
5926 Xdecor_4, TRUE, FALSE,
5927 EL_EMC_WALL_7, -1, -1
5930 Xdecor_5, TRUE, FALSE,
5931 EL_EMC_WALL_5, -1, -1
5934 Xdecor_6, TRUE, FALSE,
5935 EL_EMC_WALL_9, -1, -1
5938 Xdecor_7, TRUE, FALSE,
5939 EL_EMC_WALL_10, -1, -1
5942 Xdecor_8, TRUE, FALSE,
5943 EL_EMC_WALL_1, -1, -1
5946 Xdecor_9, TRUE, FALSE,
5947 EL_EMC_WALL_2, -1, -1
5950 Xdecor_10, TRUE, FALSE,
5951 EL_EMC_WALL_3, -1, -1
5954 Xdecor_11, TRUE, FALSE,
5955 EL_EMC_WALL_11, -1, -1
5958 Xdecor_12, TRUE, FALSE,
5959 EL_EMC_WALL_12, -1, -1
5962 Xalpha_0, TRUE, FALSE,
5963 EL_CHAR('0'), -1, -1
5966 Xalpha_1, TRUE, FALSE,
5967 EL_CHAR('1'), -1, -1
5970 Xalpha_2, TRUE, FALSE,
5971 EL_CHAR('2'), -1, -1
5974 Xalpha_3, TRUE, FALSE,
5975 EL_CHAR('3'), -1, -1
5978 Xalpha_4, TRUE, FALSE,
5979 EL_CHAR('4'), -1, -1
5982 Xalpha_5, TRUE, FALSE,
5983 EL_CHAR('5'), -1, -1
5986 Xalpha_6, TRUE, FALSE,
5987 EL_CHAR('6'), -1, -1
5990 Xalpha_7, TRUE, FALSE,
5991 EL_CHAR('7'), -1, -1
5994 Xalpha_8, TRUE, FALSE,
5995 EL_CHAR('8'), -1, -1
5998 Xalpha_9, TRUE, FALSE,
5999 EL_CHAR('9'), -1, -1
6002 Xalpha_excla, TRUE, FALSE,
6003 EL_CHAR('!'), -1, -1
6006 Xalpha_quote, TRUE, FALSE,
6007 EL_CHAR('"'), -1, -1
6010 Xalpha_comma, TRUE, FALSE,
6011 EL_CHAR(','), -1, -1
6014 Xalpha_minus, TRUE, FALSE,
6015 EL_CHAR('-'), -1, -1
6018 Xalpha_perio, TRUE, FALSE,
6019 EL_CHAR('.'), -1, -1
6022 Xalpha_colon, TRUE, FALSE,
6023 EL_CHAR(':'), -1, -1
6026 Xalpha_quest, TRUE, FALSE,
6027 EL_CHAR('?'), -1, -1
6030 Xalpha_a, TRUE, FALSE,
6031 EL_CHAR('A'), -1, -1
6034 Xalpha_b, TRUE, FALSE,
6035 EL_CHAR('B'), -1, -1
6038 Xalpha_c, TRUE, FALSE,
6039 EL_CHAR('C'), -1, -1
6042 Xalpha_d, TRUE, FALSE,
6043 EL_CHAR('D'), -1, -1
6046 Xalpha_e, TRUE, FALSE,
6047 EL_CHAR('E'), -1, -1
6050 Xalpha_f, TRUE, FALSE,
6051 EL_CHAR('F'), -1, -1
6054 Xalpha_g, TRUE, FALSE,
6055 EL_CHAR('G'), -1, -1
6058 Xalpha_h, TRUE, FALSE,
6059 EL_CHAR('H'), -1, -1
6062 Xalpha_i, TRUE, FALSE,
6063 EL_CHAR('I'), -1, -1
6066 Xalpha_j, TRUE, FALSE,
6067 EL_CHAR('J'), -1, -1
6070 Xalpha_k, TRUE, FALSE,
6071 EL_CHAR('K'), -1, -1
6074 Xalpha_l, TRUE, FALSE,
6075 EL_CHAR('L'), -1, -1
6078 Xalpha_m, TRUE, FALSE,
6079 EL_CHAR('M'), -1, -1
6082 Xalpha_n, TRUE, FALSE,
6083 EL_CHAR('N'), -1, -1
6086 Xalpha_o, TRUE, FALSE,
6087 EL_CHAR('O'), -1, -1
6090 Xalpha_p, TRUE, FALSE,
6091 EL_CHAR('P'), -1, -1
6094 Xalpha_q, TRUE, FALSE,
6095 EL_CHAR('Q'), -1, -1
6098 Xalpha_r, TRUE, FALSE,
6099 EL_CHAR('R'), -1, -1
6102 Xalpha_s, TRUE, FALSE,
6103 EL_CHAR('S'), -1, -1
6106 Xalpha_t, TRUE, FALSE,
6107 EL_CHAR('T'), -1, -1
6110 Xalpha_u, TRUE, FALSE,
6111 EL_CHAR('U'), -1, -1
6114 Xalpha_v, TRUE, FALSE,
6115 EL_CHAR('V'), -1, -1
6118 Xalpha_w, TRUE, FALSE,
6119 EL_CHAR('W'), -1, -1
6122 Xalpha_x, TRUE, FALSE,
6123 EL_CHAR('X'), -1, -1
6126 Xalpha_y, TRUE, FALSE,
6127 EL_CHAR('Y'), -1, -1
6130 Xalpha_z, TRUE, FALSE,
6131 EL_CHAR('Z'), -1, -1
6134 Xalpha_arrow_e, TRUE, FALSE,
6135 EL_CHAR('>'), -1, -1
6138 Xalpha_arrow_w, TRUE, FALSE,
6139 EL_CHAR('<'), -1, -1
6142 Xalpha_copyr, TRUE, FALSE,
6143 EL_CHAR(CHAR_BYTE_COPYRIGHT), -1, -1
6147 Xboom_bug, FALSE, FALSE,
6148 EL_BUG, ACTION_EXPLODING, -1
6151 Xboom_bomb, FALSE, FALSE,
6152 EL_BOMB, ACTION_EXPLODING, -1
6155 Xboom_android, FALSE, FALSE,
6156 EL_EMC_ANDROID, ACTION_OTHER, -1
6159 Xboom_1, FALSE, FALSE,
6160 EL_DEFAULT, ACTION_EXPLODING, -1
6163 Xboom_2, FALSE, FALSE,
6164 EL_DEFAULT, ACTION_EXPLODING, -1
6167 Znormal, FALSE, FALSE,
6171 Zdynamite, FALSE, FALSE,
6175 Zplayer, FALSE, FALSE,
6179 ZBORDER, FALSE, FALSE,
6189 static struct Mapping_EM_to_RND_player
6198 em_player_mapping_list[] =
6202 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
6206 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
6210 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
6214 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
6218 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
6222 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
6226 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
6230 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
6234 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
6238 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
6242 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
6246 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
6250 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
6254 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
6258 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
6262 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
6266 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
6270 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
6274 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
6278 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
6282 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
6286 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
6290 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
6294 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
6298 EL_PLAYER_1, ACTION_DEFAULT, -1,
6302 EL_PLAYER_2, ACTION_DEFAULT, -1,
6306 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
6310 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
6314 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
6318 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
6322 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
6326 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
6330 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
6334 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
6338 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
6342 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
6346 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
6350 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
6354 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
6358 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
6362 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
6366 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
6370 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
6374 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
6378 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
6382 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
6386 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
6390 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
6394 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
6398 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
6402 EL_PLAYER_3, ACTION_DEFAULT, -1,
6406 EL_PLAYER_4, ACTION_DEFAULT, -1,
6415 int map_element_RND_to_EM(int element_rnd)
6417 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
6418 static boolean mapping_initialized = FALSE;
6420 if (!mapping_initialized)
6424 /* return "Xalpha_quest" for all undefined elements in mapping array */
6425 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
6426 mapping_RND_to_EM[i] = Xalpha_quest;
6428 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6429 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
6430 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
6431 em_object_mapping_list[i].element_em;
6433 mapping_initialized = TRUE;
6436 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
6437 return mapping_RND_to_EM[element_rnd];
6439 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
6444 int map_element_EM_to_RND(int element_em)
6446 static unsigned short mapping_EM_to_RND[TILE_MAX];
6447 static boolean mapping_initialized = FALSE;
6449 if (!mapping_initialized)
6453 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
6454 for (i = 0; i < TILE_MAX; i++)
6455 mapping_EM_to_RND[i] = EL_UNKNOWN;
6457 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6458 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
6459 em_object_mapping_list[i].element_rnd;
6461 mapping_initialized = TRUE;
6464 if (element_em >= 0 && element_em < TILE_MAX)
6465 return mapping_EM_to_RND[element_em];
6467 Error(ERR_WARN, "invalid EM level element %d", element_em);
6472 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
6474 struct LevelInfo_EM *level_em = level->native_em_level;
6475 struct LEVEL *lev = level_em->lev;
6478 for (i = 0; i < TILE_MAX; i++)
6479 lev->android_array[i] = Xblank;
6481 for (i = 0; i < level->num_android_clone_elements; i++)
6483 int element_rnd = level->android_clone_element[i];
6484 int element_em = map_element_RND_to_EM(element_rnd);
6486 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
6487 if (em_object_mapping_list[j].element_rnd == element_rnd)
6488 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
6492 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
6494 struct LevelInfo_EM *level_em = level->native_em_level;
6495 struct LEVEL *lev = level_em->lev;
6498 level->num_android_clone_elements = 0;
6500 for (i = 0; i < TILE_MAX; i++)
6502 int element_em = lev->android_array[i];
6504 boolean element_found = FALSE;
6506 if (element_em == Xblank)
6509 element_rnd = map_element_EM_to_RND(element_em);
6511 for (j = 0; j < level->num_android_clone_elements; j++)
6512 if (level->android_clone_element[j] == element_rnd)
6513 element_found = TRUE;
6517 level->android_clone_element[level->num_android_clone_elements++] =
6520 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
6525 if (level->num_android_clone_elements == 0)
6527 level->num_android_clone_elements = 1;
6528 level->android_clone_element[0] = EL_EMPTY;
6532 int map_direction_RND_to_EM(int direction)
6534 return (direction == MV_UP ? 0 :
6535 direction == MV_RIGHT ? 1 :
6536 direction == MV_DOWN ? 2 :
6537 direction == MV_LEFT ? 3 :
6541 int map_direction_EM_to_RND(int direction)
6543 return (direction == 0 ? MV_UP :
6544 direction == 1 ? MV_RIGHT :
6545 direction == 2 ? MV_DOWN :
6546 direction == 3 ? MV_LEFT :
6550 int map_element_RND_to_SP(int element_rnd)
6552 int element_sp = 0x20; /* map unknown elements to yellow "hardware" */
6554 if (element_rnd >= EL_SP_START &&
6555 element_rnd <= EL_SP_END)
6556 element_sp = element_rnd - EL_SP_START;
6557 else if (element_rnd == EL_EMPTY_SPACE)
6559 else if (element_rnd == EL_INVISIBLE_WALL)
6565 int map_element_SP_to_RND(int element_sp)
6567 int element_rnd = EL_UNKNOWN;
6569 if (element_sp >= 0x00 &&
6571 element_rnd = EL_SP_START + element_sp;
6572 else if (element_sp == 0x28)
6573 element_rnd = EL_INVISIBLE_WALL;
6578 int map_action_SP_to_RND(int action_sp)
6582 case actActive: return ACTION_ACTIVE;
6583 case actImpact: return ACTION_IMPACT;
6584 case actExploding: return ACTION_EXPLODING;
6585 case actDigging: return ACTION_DIGGING;
6586 case actSnapping: return ACTION_SNAPPING;
6587 case actCollecting: return ACTION_COLLECTING;
6588 case actPassing: return ACTION_PASSING;
6589 case actPushing: return ACTION_PUSHING;
6590 case actDropping: return ACTION_DROPPING;
6592 default: return ACTION_DEFAULT;
6596 int get_next_element(int element)
6600 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
6601 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
6602 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
6603 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
6604 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
6605 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
6606 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
6607 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
6608 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
6609 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
6610 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
6612 default: return element;
6616 int el_act_dir2img(int element, int action, int direction)
6618 element = GFX_ELEMENT(element);
6619 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
6621 /* direction_graphic[][] == graphic[] for undefined direction graphics */
6622 return element_info[element].direction_graphic[action][direction];
6625 static int el_act_dir2crm(int element, int action, int direction)
6627 element = GFX_ELEMENT(element);
6628 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
6630 /* direction_graphic[][] == graphic[] for undefined direction graphics */
6631 return element_info[element].direction_crumbled[action][direction];
6634 int el_act2img(int element, int action)
6636 element = GFX_ELEMENT(element);
6638 return element_info[element].graphic[action];
6641 int el_act2crm(int element, int action)
6643 element = GFX_ELEMENT(element);
6645 return element_info[element].crumbled[action];
6648 int el_dir2img(int element, int direction)
6650 element = GFX_ELEMENT(element);
6652 return el_act_dir2img(element, ACTION_DEFAULT, direction);
6655 int el2baseimg(int element)
6657 return element_info[element].graphic[ACTION_DEFAULT];
6660 int el2img(int element)
6662 element = GFX_ELEMENT(element);
6664 return element_info[element].graphic[ACTION_DEFAULT];
6667 int el2edimg(int element)
6669 element = GFX_ELEMENT(element);
6671 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
6674 int el2preimg(int element)
6676 element = GFX_ELEMENT(element);
6678 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
6681 int el2panelimg(int element)
6683 element = GFX_ELEMENT(element);
6685 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL];
6688 int font2baseimg(int font_nr)
6690 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
6693 int getBeltNrFromBeltElement(int element)
6695 return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
6696 element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
6697 element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
6700 int getBeltNrFromBeltActiveElement(int element)
6702 return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
6703 element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
6704 element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
6707 int getBeltNrFromBeltSwitchElement(int element)
6709 return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
6710 element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
6711 element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
6714 int getBeltDirNrFromBeltElement(int element)
6716 static int belt_base_element[4] =
6718 EL_CONVEYOR_BELT_1_LEFT,
6719 EL_CONVEYOR_BELT_2_LEFT,
6720 EL_CONVEYOR_BELT_3_LEFT,
6721 EL_CONVEYOR_BELT_4_LEFT
6724 int belt_nr = getBeltNrFromBeltElement(element);
6725 int belt_dir_nr = element - belt_base_element[belt_nr];
6727 return (belt_dir_nr % 3);
6730 int getBeltDirNrFromBeltSwitchElement(int element)
6732 static int belt_base_element[4] =
6734 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
6735 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
6736 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
6737 EL_CONVEYOR_BELT_4_SWITCH_LEFT
6740 int belt_nr = getBeltNrFromBeltSwitchElement(element);
6741 int belt_dir_nr = element - belt_base_element[belt_nr];
6743 return (belt_dir_nr % 3);
6746 int getBeltDirFromBeltElement(int element)
6748 static int belt_move_dir[3] =
6755 int belt_dir_nr = getBeltDirNrFromBeltElement(element);
6757 return belt_move_dir[belt_dir_nr];
6760 int getBeltDirFromBeltSwitchElement(int element)
6762 static int belt_move_dir[3] =
6769 int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
6771 return belt_move_dir[belt_dir_nr];
6774 int getBeltElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
6776 static int belt_base_element[4] =
6778 EL_CONVEYOR_BELT_1_LEFT,
6779 EL_CONVEYOR_BELT_2_LEFT,
6780 EL_CONVEYOR_BELT_3_LEFT,
6781 EL_CONVEYOR_BELT_4_LEFT
6784 return belt_base_element[belt_nr] + belt_dir_nr;
6787 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
6789 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
6791 return getBeltElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
6794 int getBeltSwitchElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
6796 static int belt_base_element[4] =
6798 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
6799 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
6800 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
6801 EL_CONVEYOR_BELT_4_SWITCH_LEFT
6804 return belt_base_element[belt_nr] + belt_dir_nr;
6807 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
6809 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
6811 return getBeltSwitchElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
6814 boolean getTeamMode_EM()
6816 return game.team_mode;
6819 int getGameFrameDelay_EM(int native_em_game_frame_delay)
6821 int game_frame_delay_value;
6823 game_frame_delay_value =
6824 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
6825 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
6828 if (tape.playing && tape.warp_forward && !tape.pausing)
6829 game_frame_delay_value = 0;
6831 return game_frame_delay_value;
6834 unsigned int InitRND(int seed)
6836 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
6837 return InitEngineRandom_EM(seed);
6838 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
6839 return InitEngineRandom_SP(seed);
6841 return InitEngineRandom_RND(seed);
6844 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
6845 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
6847 inline static int get_effective_element_EM(int tile, int frame_em)
6849 int element = object_mapping[tile].element_rnd;
6850 int action = object_mapping[tile].action;
6851 boolean is_backside = object_mapping[tile].is_backside;
6852 boolean action_removing = (action == ACTION_DIGGING ||
6853 action == ACTION_SNAPPING ||
6854 action == ACTION_COLLECTING);
6860 case Yacid_splash_eB:
6861 case Yacid_splash_wB:
6862 return (frame_em > 5 ? EL_EMPTY : element);
6868 else /* frame_em == 7 */
6872 case Yacid_splash_eB:
6873 case Yacid_splash_wB:
6876 case Yemerald_stone:
6879 case Ydiamond_stone:
6883 case Xdrip_stretchB:
6902 case Xsand_stonein_1:
6903 case Xsand_stonein_2:
6904 case Xsand_stonein_3:
6905 case Xsand_stonein_4:
6909 return (is_backside || action_removing ? EL_EMPTY : element);
6914 inline static boolean check_linear_animation_EM(int tile)
6918 case Xsand_stonesand_1:
6919 case Xsand_stonesand_quickout_1:
6920 case Xsand_sandstone_1:
6921 case Xsand_stonein_1:
6922 case Xsand_stoneout_1:
6941 case Yacid_splash_eB:
6942 case Yacid_splash_wB:
6943 case Yemerald_stone:
6950 inline static void set_crumbled_graphics_EM(struct GraphicInfo_EM *g_em,
6951 boolean has_crumbled_graphics,
6952 int crumbled, int sync_frame)
6954 /* if element can be crumbled, but certain action graphics are just empty
6955 space (like instantly snapping sand to empty space in 1 frame), do not
6956 treat these empty space graphics as crumbled graphics in EMC engine */
6957 if (crumbled == IMG_EMPTY_SPACE)
6958 has_crumbled_graphics = FALSE;
6960 if (has_crumbled_graphics)
6962 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
6963 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
6964 g_crumbled->anim_delay,
6965 g_crumbled->anim_mode,
6966 g_crumbled->anim_start_frame,
6969 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
6970 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
6972 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
6974 g_em->has_crumbled_graphics = TRUE;
6978 g_em->crumbled_bitmap = NULL;
6979 g_em->crumbled_src_x = 0;
6980 g_em->crumbled_src_y = 0;
6981 g_em->crumbled_border_size = 0;
6983 g_em->has_crumbled_graphics = FALSE;
6987 void ResetGfxAnimation_EM(int x, int y, int tile)
6992 void SetGfxAnimation_EM(struct GraphicInfo_EM *g_em,
6993 int tile, int frame_em, int x, int y)
6995 int action = object_mapping[tile].action;
6996 int direction = object_mapping[tile].direction;
6997 int effective_element = get_effective_element_EM(tile, frame_em);
6998 int graphic = (direction == MV_NONE ?
6999 el_act2img(effective_element, action) :
7000 el_act_dir2img(effective_element, action, direction));
7001 struct GraphicInfo *g = &graphic_info[graphic];
7003 boolean action_removing = (action == ACTION_DIGGING ||
7004 action == ACTION_SNAPPING ||
7005 action == ACTION_COLLECTING);
7006 boolean action_moving = (action == ACTION_FALLING ||
7007 action == ACTION_MOVING ||
7008 action == ACTION_PUSHING ||
7009 action == ACTION_EATING ||
7010 action == ACTION_FILLING ||
7011 action == ACTION_EMPTYING);
7012 boolean action_falling = (action == ACTION_FALLING ||
7013 action == ACTION_FILLING ||
7014 action == ACTION_EMPTYING);
7016 /* special case: graphic uses "2nd movement tile" and has defined
7017 7 frames for movement animation (or less) => use default graphic
7018 for last (8th) frame which ends the movement animation */
7019 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
7021 action = ACTION_DEFAULT; /* (keep action_* unchanged for now) */
7022 graphic = (direction == MV_NONE ?
7023 el_act2img(effective_element, action) :
7024 el_act_dir2img(effective_element, action, direction));
7026 g = &graphic_info[graphic];
7029 if ((action_removing || check_linear_animation_EM(tile)) && frame_em == 0)
7033 else if (action_moving)
7035 boolean is_backside = object_mapping[tile].is_backside;
7039 int direction = object_mapping[tile].direction;
7040 int move_dir = (action_falling ? MV_DOWN : direction);
7045 /* !!! TEST !!! NEW !!! DOES NOT WORK RIGHT YET !!! */
7046 if (g->double_movement && frame_em == 0)
7050 if (move_dir == MV_LEFT)
7051 GfxFrame[x - 1][y] = GfxFrame[x][y];
7052 else if (move_dir == MV_RIGHT)
7053 GfxFrame[x + 1][y] = GfxFrame[x][y];
7054 else if (move_dir == MV_UP)
7055 GfxFrame[x][y - 1] = GfxFrame[x][y];
7056 else if (move_dir == MV_DOWN)
7057 GfxFrame[x][y + 1] = GfxFrame[x][y];
7064 /* special case: animation for Xsand_stonesand_quickout_1/2 twice as fast */
7065 if (tile == Xsand_stonesand_quickout_1 ||
7066 tile == Xsand_stonesand_quickout_2)
7070 if (graphic_info[graphic].anim_global_sync)
7071 sync_frame = FrameCounter;
7072 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
7073 sync_frame = GfxFrame[x][y];
7075 sync_frame = 0; /* playfield border (pseudo steel) */
7077 SetRandomAnimationValue(x, y);
7079 int frame = getAnimationFrame(g->anim_frames,
7082 g->anim_start_frame,
7085 g_em->unique_identifier =
7086 (graphic << 16) | ((frame % 8) << 12) | (g_em->width << 6) | g_em->height;
7089 void getGraphicSourceObjectExt_EM(struct GraphicInfo_EM *g_em,
7090 int tile, int frame_em, int x, int y)
7092 int action = object_mapping[tile].action;
7093 int direction = object_mapping[tile].direction;
7094 boolean is_backside = object_mapping[tile].is_backside;
7095 int effective_element = get_effective_element_EM(tile, frame_em);
7096 int effective_action = action;
7097 int graphic = (direction == MV_NONE ?
7098 el_act2img(effective_element, effective_action) :
7099 el_act_dir2img(effective_element, effective_action,
7101 int crumbled = (direction == MV_NONE ?
7102 el_act2crm(effective_element, effective_action) :
7103 el_act_dir2crm(effective_element, effective_action,
7105 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7106 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7107 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7108 struct GraphicInfo *g = &graphic_info[graphic];
7111 /* special case: graphic uses "2nd movement tile" and has defined
7112 7 frames for movement animation (or less) => use default graphic
7113 for last (8th) frame which ends the movement animation */
7114 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
7116 effective_action = ACTION_DEFAULT;
7117 graphic = (direction == MV_NONE ?
7118 el_act2img(effective_element, effective_action) :
7119 el_act_dir2img(effective_element, effective_action,
7121 crumbled = (direction == MV_NONE ?
7122 el_act2crm(effective_element, effective_action) :
7123 el_act_dir2crm(effective_element, effective_action,
7126 g = &graphic_info[graphic];
7129 if (graphic_info[graphic].anim_global_sync)
7130 sync_frame = FrameCounter;
7131 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
7132 sync_frame = GfxFrame[x][y];
7134 sync_frame = 0; /* playfield border (pseudo steel) */
7136 SetRandomAnimationValue(x, y);
7138 int frame = getAnimationFrame(g->anim_frames,
7141 g->anim_start_frame,
7144 getGraphicSourceExt(graphic, frame, &g_em->bitmap, &g_em->src_x, &g_em->src_y,
7145 g->double_movement && is_backside);
7147 /* (updating the "crumbled" graphic definitions is probably not really needed,
7148 as animations for crumbled graphics can't be longer than one EMC cycle) */
7149 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
7153 void getGraphicSourcePlayerExt_EM(struct GraphicInfo_EM *g_em,
7154 int player_nr, int anim, int frame_em)
7156 int element = player_mapping[player_nr][anim].element_rnd;
7157 int action = player_mapping[player_nr][anim].action;
7158 int direction = player_mapping[player_nr][anim].direction;
7159 int graphic = (direction == MV_NONE ?
7160 el_act2img(element, action) :
7161 el_act_dir2img(element, action, direction));
7162 struct GraphicInfo *g = &graphic_info[graphic];
7165 InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
7167 stored_player[player_nr].StepFrame = frame_em;
7169 sync_frame = stored_player[player_nr].Frame;
7171 int frame = getAnimationFrame(g->anim_frames,
7174 g->anim_start_frame,
7177 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
7178 &g_em->src_x, &g_em->src_y, FALSE);
7181 void InitGraphicInfo_EM(void)
7186 int num_em_gfx_errors = 0;
7188 if (graphic_info_em_object[0][0].bitmap == NULL)
7190 /* EM graphics not yet initialized in em_open_all() */
7195 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
7198 /* always start with reliable default values */
7199 for (i = 0; i < TILE_MAX; i++)
7201 object_mapping[i].element_rnd = EL_UNKNOWN;
7202 object_mapping[i].is_backside = FALSE;
7203 object_mapping[i].action = ACTION_DEFAULT;
7204 object_mapping[i].direction = MV_NONE;
7207 /* always start with reliable default values */
7208 for (p = 0; p < MAX_PLAYERS; p++)
7210 for (i = 0; i < SPR_MAX; i++)
7212 player_mapping[p][i].element_rnd = EL_UNKNOWN;
7213 player_mapping[p][i].action = ACTION_DEFAULT;
7214 player_mapping[p][i].direction = MV_NONE;
7218 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
7220 int e = em_object_mapping_list[i].element_em;
7222 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
7223 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
7225 if (em_object_mapping_list[i].action != -1)
7226 object_mapping[e].action = em_object_mapping_list[i].action;
7228 if (em_object_mapping_list[i].direction != -1)
7229 object_mapping[e].direction =
7230 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
7233 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
7235 int a = em_player_mapping_list[i].action_em;
7236 int p = em_player_mapping_list[i].player_nr;
7238 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
7240 if (em_player_mapping_list[i].action != -1)
7241 player_mapping[p][a].action = em_player_mapping_list[i].action;
7243 if (em_player_mapping_list[i].direction != -1)
7244 player_mapping[p][a].direction =
7245 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
7248 for (i = 0; i < TILE_MAX; i++)
7250 int element = object_mapping[i].element_rnd;
7251 int action = object_mapping[i].action;
7252 int direction = object_mapping[i].direction;
7253 boolean is_backside = object_mapping[i].is_backside;
7254 boolean action_exploding = ((action == ACTION_EXPLODING ||
7255 action == ACTION_SMASHED_BY_ROCK ||
7256 action == ACTION_SMASHED_BY_SPRING) &&
7257 element != EL_DIAMOND);
7258 boolean action_active = (action == ACTION_ACTIVE);
7259 boolean action_other = (action == ACTION_OTHER);
7261 for (j = 0; j < 8; j++)
7263 int effective_element = get_effective_element_EM(i, j);
7264 int effective_action = (j < 7 ? action :
7265 i == Xdrip_stretch ? action :
7266 i == Xdrip_stretchB ? action :
7267 i == Ydrip_s1 ? action :
7268 i == Ydrip_s1B ? action :
7269 i == Xball_1B ? action :
7270 i == Xball_2 ? action :
7271 i == Xball_2B ? action :
7272 i == Yball_eat ? action :
7273 i == Ykey_1_eat ? action :
7274 i == Ykey_2_eat ? action :
7275 i == Ykey_3_eat ? action :
7276 i == Ykey_4_eat ? action :
7277 i == Ykey_5_eat ? action :
7278 i == Ykey_6_eat ? action :
7279 i == Ykey_7_eat ? action :
7280 i == Ykey_8_eat ? action :
7281 i == Ylenses_eat ? action :
7282 i == Ymagnify_eat ? action :
7283 i == Ygrass_eat ? action :
7284 i == Ydirt_eat ? action :
7285 i == Xsand_stonein_1 ? action :
7286 i == Xsand_stonein_2 ? action :
7287 i == Xsand_stonein_3 ? action :
7288 i == Xsand_stonein_4 ? action :
7289 i == Xsand_stoneout_1 ? action :
7290 i == Xsand_stoneout_2 ? action :
7291 i == Xboom_android ? ACTION_EXPLODING :
7292 action_exploding ? ACTION_EXPLODING :
7293 action_active ? action :
7294 action_other ? action :
7296 int graphic = (el_act_dir2img(effective_element, effective_action,
7298 int crumbled = (el_act_dir2crm(effective_element, effective_action,
7300 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7301 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7302 boolean has_action_graphics = (graphic != base_graphic);
7303 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7304 struct GraphicInfo *g = &graphic_info[graphic];
7305 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7308 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
7309 boolean special_animation = (action != ACTION_DEFAULT &&
7310 g->anim_frames == 3 &&
7311 g->anim_delay == 2 &&
7312 g->anim_mode & ANIM_LINEAR);
7313 int sync_frame = (i == Xdrip_stretch ? 7 :
7314 i == Xdrip_stretchB ? 7 :
7315 i == Ydrip_s2 ? j + 8 :
7316 i == Ydrip_s2B ? j + 8 :
7325 i == Xfake_acid_1 ? 0 :
7326 i == Xfake_acid_2 ? 10 :
7327 i == Xfake_acid_3 ? 20 :
7328 i == Xfake_acid_4 ? 30 :
7329 i == Xfake_acid_5 ? 40 :
7330 i == Xfake_acid_6 ? 50 :
7331 i == Xfake_acid_7 ? 60 :
7332 i == Xfake_acid_8 ? 70 :
7334 i == Xball_2B ? j + 8 :
7335 i == Yball_eat ? j + 1 :
7336 i == Ykey_1_eat ? j + 1 :
7337 i == Ykey_2_eat ? j + 1 :
7338 i == Ykey_3_eat ? j + 1 :
7339 i == Ykey_4_eat ? j + 1 :
7340 i == Ykey_5_eat ? j + 1 :
7341 i == Ykey_6_eat ? j + 1 :
7342 i == Ykey_7_eat ? j + 1 :
7343 i == Ykey_8_eat ? j + 1 :
7344 i == Ylenses_eat ? j + 1 :
7345 i == Ymagnify_eat ? j + 1 :
7346 i == Ygrass_eat ? j + 1 :
7347 i == Ydirt_eat ? j + 1 :
7348 i == Xamoeba_1 ? 0 :
7349 i == Xamoeba_2 ? 1 :
7350 i == Xamoeba_3 ? 2 :
7351 i == Xamoeba_4 ? 3 :
7352 i == Xamoeba_5 ? 0 :
7353 i == Xamoeba_6 ? 1 :
7354 i == Xamoeba_7 ? 2 :
7355 i == Xamoeba_8 ? 3 :
7356 i == Xexit_2 ? j + 8 :
7357 i == Xexit_3 ? j + 16 :
7358 i == Xdynamite_1 ? 0 :
7359 i == Xdynamite_2 ? 8 :
7360 i == Xdynamite_3 ? 16 :
7361 i == Xdynamite_4 ? 24 :
7362 i == Xsand_stonein_1 ? j + 1 :
7363 i == Xsand_stonein_2 ? j + 9 :
7364 i == Xsand_stonein_3 ? j + 17 :
7365 i == Xsand_stonein_4 ? j + 25 :
7366 i == Xsand_stoneout_1 && j == 0 ? 0 :
7367 i == Xsand_stoneout_1 && j == 1 ? 0 :
7368 i == Xsand_stoneout_1 && j == 2 ? 1 :
7369 i == Xsand_stoneout_1 && j == 3 ? 2 :
7370 i == Xsand_stoneout_1 && j == 4 ? 2 :
7371 i == Xsand_stoneout_1 && j == 5 ? 3 :
7372 i == Xsand_stoneout_1 && j == 6 ? 4 :
7373 i == Xsand_stoneout_1 && j == 7 ? 4 :
7374 i == Xsand_stoneout_2 && j == 0 ? 5 :
7375 i == Xsand_stoneout_2 && j == 1 ? 6 :
7376 i == Xsand_stoneout_2 && j == 2 ? 7 :
7377 i == Xsand_stoneout_2 && j == 3 ? 8 :
7378 i == Xsand_stoneout_2 && j == 4 ? 9 :
7379 i == Xsand_stoneout_2 && j == 5 ? 11 :
7380 i == Xsand_stoneout_2 && j == 6 ? 13 :
7381 i == Xsand_stoneout_2 && j == 7 ? 15 :
7382 i == Xboom_bug && j == 1 ? 2 :
7383 i == Xboom_bug && j == 2 ? 2 :
7384 i == Xboom_bug && j == 3 ? 4 :
7385 i == Xboom_bug && j == 4 ? 4 :
7386 i == Xboom_bug && j == 5 ? 2 :
7387 i == Xboom_bug && j == 6 ? 2 :
7388 i == Xboom_bug && j == 7 ? 0 :
7389 i == Xboom_bomb && j == 1 ? 2 :
7390 i == Xboom_bomb && j == 2 ? 2 :
7391 i == Xboom_bomb && j == 3 ? 4 :
7392 i == Xboom_bomb && j == 4 ? 4 :
7393 i == Xboom_bomb && j == 5 ? 2 :
7394 i == Xboom_bomb && j == 6 ? 2 :
7395 i == Xboom_bomb && j == 7 ? 0 :
7396 i == Xboom_android && j == 7 ? 6 :
7397 i == Xboom_1 && j == 1 ? 2 :
7398 i == Xboom_1 && j == 2 ? 2 :
7399 i == Xboom_1 && j == 3 ? 4 :
7400 i == Xboom_1 && j == 4 ? 4 :
7401 i == Xboom_1 && j == 5 ? 6 :
7402 i == Xboom_1 && j == 6 ? 6 :
7403 i == Xboom_1 && j == 7 ? 8 :
7404 i == Xboom_2 && j == 0 ? 8 :
7405 i == Xboom_2 && j == 1 ? 8 :
7406 i == Xboom_2 && j == 2 ? 10 :
7407 i == Xboom_2 && j == 3 ? 10 :
7408 i == Xboom_2 && j == 4 ? 10 :
7409 i == Xboom_2 && j == 5 ? 12 :
7410 i == Xboom_2 && j == 6 ? 12 :
7411 i == Xboom_2 && j == 7 ? 12 :
7412 special_animation && j == 4 ? 3 :
7413 effective_action != action ? 0 :
7417 Bitmap *debug_bitmap = g_em->bitmap;
7418 int debug_src_x = g_em->src_x;
7419 int debug_src_y = g_em->src_y;
7422 int frame = getAnimationFrame(g->anim_frames,
7425 g->anim_start_frame,
7428 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
7429 g->double_movement && is_backside);
7431 g_em->bitmap = src_bitmap;
7432 g_em->src_x = src_x;
7433 g_em->src_y = src_y;
7434 g_em->src_offset_x = 0;
7435 g_em->src_offset_y = 0;
7436 g_em->dst_offset_x = 0;
7437 g_em->dst_offset_y = 0;
7438 g_em->width = TILEX;
7439 g_em->height = TILEY;
7441 g_em->preserve_background = FALSE;
7443 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
7446 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
7447 effective_action == ACTION_MOVING ||
7448 effective_action == ACTION_PUSHING ||
7449 effective_action == ACTION_EATING)) ||
7450 (!has_action_graphics && (effective_action == ACTION_FILLING ||
7451 effective_action == ACTION_EMPTYING)))
7454 (effective_action == ACTION_FALLING ||
7455 effective_action == ACTION_FILLING ||
7456 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
7457 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
7458 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
7459 int num_steps = (i == Ydrip_s1 ? 16 :
7460 i == Ydrip_s1B ? 16 :
7461 i == Ydrip_s2 ? 16 :
7462 i == Ydrip_s2B ? 16 :
7463 i == Xsand_stonein_1 ? 32 :
7464 i == Xsand_stonein_2 ? 32 :
7465 i == Xsand_stonein_3 ? 32 :
7466 i == Xsand_stonein_4 ? 32 :
7467 i == Xsand_stoneout_1 ? 16 :
7468 i == Xsand_stoneout_2 ? 16 : 8);
7469 int cx = ABS(dx) * (TILEX / num_steps);
7470 int cy = ABS(dy) * (TILEY / num_steps);
7471 int step_frame = (i == Ydrip_s2 ? j + 8 :
7472 i == Ydrip_s2B ? j + 8 :
7473 i == Xsand_stonein_2 ? j + 8 :
7474 i == Xsand_stonein_3 ? j + 16 :
7475 i == Xsand_stonein_4 ? j + 24 :
7476 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
7477 int step = (is_backside ? step_frame : num_steps - step_frame);
7479 if (is_backside) /* tile where movement starts */
7481 if (dx < 0 || dy < 0)
7483 g_em->src_offset_x = cx * step;
7484 g_em->src_offset_y = cy * step;
7488 g_em->dst_offset_x = cx * step;
7489 g_em->dst_offset_y = cy * step;
7492 else /* tile where movement ends */
7494 if (dx < 0 || dy < 0)
7496 g_em->dst_offset_x = cx * step;
7497 g_em->dst_offset_y = cy * step;
7501 g_em->src_offset_x = cx * step;
7502 g_em->src_offset_y = cy * step;
7506 g_em->width = TILEX - cx * step;
7507 g_em->height = TILEY - cy * step;
7510 /* create unique graphic identifier to decide if tile must be redrawn */
7511 /* bit 31 - 16 (16 bit): EM style graphic
7512 bit 15 - 12 ( 4 bit): EM style frame
7513 bit 11 - 6 ( 6 bit): graphic width
7514 bit 5 - 0 ( 6 bit): graphic height */
7515 g_em->unique_identifier =
7516 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
7520 /* skip check for EMC elements not contained in original EMC artwork */
7521 if (element == EL_EMC_FAKE_ACID)
7524 if (g_em->bitmap != debug_bitmap ||
7525 g_em->src_x != debug_src_x ||
7526 g_em->src_y != debug_src_y ||
7527 g_em->src_offset_x != 0 ||
7528 g_em->src_offset_y != 0 ||
7529 g_em->dst_offset_x != 0 ||
7530 g_em->dst_offset_y != 0 ||
7531 g_em->width != TILEX ||
7532 g_em->height != TILEY)
7534 static int last_i = -1;
7542 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
7543 i, element, element_info[element].token_name,
7544 element_action_info[effective_action].suffix, direction);
7546 if (element != effective_element)
7547 printf(" [%d ('%s')]",
7549 element_info[effective_element].token_name);
7553 if (g_em->bitmap != debug_bitmap)
7554 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
7555 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
7557 if (g_em->src_x != debug_src_x ||
7558 g_em->src_y != debug_src_y)
7559 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
7560 j, (is_backside ? 'B' : 'F'),
7561 g_em->src_x, g_em->src_y,
7562 g_em->src_x / 32, g_em->src_y / 32,
7563 debug_src_x, debug_src_y,
7564 debug_src_x / 32, debug_src_y / 32);
7566 if (g_em->src_offset_x != 0 ||
7567 g_em->src_offset_y != 0 ||
7568 g_em->dst_offset_x != 0 ||
7569 g_em->dst_offset_y != 0)
7570 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
7572 g_em->src_offset_x, g_em->src_offset_y,
7573 g_em->dst_offset_x, g_em->dst_offset_y);
7575 if (g_em->width != TILEX ||
7576 g_em->height != TILEY)
7577 printf(" %d (%d): size %d,%d should be %d,%d\n",
7579 g_em->width, g_em->height, TILEX, TILEY);
7581 num_em_gfx_errors++;
7588 for (i = 0; i < TILE_MAX; i++)
7590 for (j = 0; j < 8; j++)
7592 int element = object_mapping[i].element_rnd;
7593 int action = object_mapping[i].action;
7594 int direction = object_mapping[i].direction;
7595 boolean is_backside = object_mapping[i].is_backside;
7596 int graphic_action = el_act_dir2img(element, action, direction);
7597 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
7599 if ((action == ACTION_SMASHED_BY_ROCK ||
7600 action == ACTION_SMASHED_BY_SPRING ||
7601 action == ACTION_EATING) &&
7602 graphic_action == graphic_default)
7604 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
7605 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
7606 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
7607 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
7610 /* no separate animation for "smashed by rock" -- use rock instead */
7611 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7612 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
7614 g_em->bitmap = g_xx->bitmap;
7615 g_em->src_x = g_xx->src_x;
7616 g_em->src_y = g_xx->src_y;
7617 g_em->src_offset_x = g_xx->src_offset_x;
7618 g_em->src_offset_y = g_xx->src_offset_y;
7619 g_em->dst_offset_x = g_xx->dst_offset_x;
7620 g_em->dst_offset_y = g_xx->dst_offset_y;
7621 g_em->width = g_xx->width;
7622 g_em->height = g_xx->height;
7623 g_em->unique_identifier = g_xx->unique_identifier;
7626 g_em->preserve_background = TRUE;
7631 for (p = 0; p < MAX_PLAYERS; p++)
7633 for (i = 0; i < SPR_MAX; i++)
7635 int element = player_mapping[p][i].element_rnd;
7636 int action = player_mapping[p][i].action;
7637 int direction = player_mapping[p][i].direction;
7639 for (j = 0; j < 8; j++)
7641 int effective_element = element;
7642 int effective_action = action;
7643 int graphic = (direction == MV_NONE ?
7644 el_act2img(effective_element, effective_action) :
7645 el_act_dir2img(effective_element, effective_action,
7647 struct GraphicInfo *g = &graphic_info[graphic];
7648 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
7654 Bitmap *debug_bitmap = g_em->bitmap;
7655 int debug_src_x = g_em->src_x;
7656 int debug_src_y = g_em->src_y;
7659 int frame = getAnimationFrame(g->anim_frames,
7662 g->anim_start_frame,
7665 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
7667 g_em->bitmap = src_bitmap;
7668 g_em->src_x = src_x;
7669 g_em->src_y = src_y;
7670 g_em->src_offset_x = 0;
7671 g_em->src_offset_y = 0;
7672 g_em->dst_offset_x = 0;
7673 g_em->dst_offset_y = 0;
7674 g_em->width = TILEX;
7675 g_em->height = TILEY;
7679 /* skip check for EMC elements not contained in original EMC artwork */
7680 if (element == EL_PLAYER_3 ||
7681 element == EL_PLAYER_4)
7684 if (g_em->bitmap != debug_bitmap ||
7685 g_em->src_x != debug_src_x ||
7686 g_em->src_y != debug_src_y)
7688 static int last_i = -1;
7696 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
7697 p, i, element, element_info[element].token_name,
7698 element_action_info[effective_action].suffix, direction);
7700 if (element != effective_element)
7701 printf(" [%d ('%s')]",
7703 element_info[effective_element].token_name);
7707 if (g_em->bitmap != debug_bitmap)
7708 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
7709 j, (int)(g_em->bitmap), (int)(debug_bitmap));
7711 if (g_em->src_x != debug_src_x ||
7712 g_em->src_y != debug_src_y)
7713 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
7715 g_em->src_x, g_em->src_y,
7716 g_em->src_x / 32, g_em->src_y / 32,
7717 debug_src_x, debug_src_y,
7718 debug_src_x / 32, debug_src_y / 32);
7720 num_em_gfx_errors++;
7730 printf("::: [%d errors found]\n", num_em_gfx_errors);
7736 void CheckSaveEngineSnapshot_EM(byte action[MAX_PLAYERS], int frame,
7737 boolean any_player_moving,
7738 boolean any_player_snapping,
7739 boolean any_player_dropping)
7741 static boolean player_was_waiting = TRUE;
7743 if (frame == 0 && !any_player_dropping)
7745 if (!player_was_waiting)
7747 if (!SaveEngineSnapshotToList())
7750 player_was_waiting = TRUE;
7753 else if (any_player_moving || any_player_snapping || any_player_dropping)
7755 player_was_waiting = FALSE;
7759 void CheckSaveEngineSnapshot_SP(boolean murphy_is_waiting,
7760 boolean murphy_is_dropping)
7762 static boolean player_was_waiting = TRUE;
7764 if (murphy_is_waiting)
7766 if (!player_was_waiting)
7768 if (!SaveEngineSnapshotToList())
7771 player_was_waiting = TRUE;
7776 player_was_waiting = FALSE;
7780 void CheckSingleStepMode_EM(byte action[MAX_PLAYERS], int frame,
7781 boolean any_player_moving,
7782 boolean any_player_snapping,
7783 boolean any_player_dropping)
7785 if (tape.single_step && tape.recording && !tape.pausing)
7786 if (frame == 0 && !any_player_dropping)
7787 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
7789 CheckSaveEngineSnapshot_EM(action, frame, any_player_moving,
7790 any_player_snapping, any_player_dropping);
7793 void CheckSingleStepMode_SP(boolean murphy_is_waiting,
7794 boolean murphy_is_dropping)
7796 if (tape.single_step && tape.recording && !tape.pausing)
7797 if (murphy_is_waiting)
7798 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
7800 CheckSaveEngineSnapshot_SP(murphy_is_waiting, murphy_is_dropping);
7803 void getGraphicSource_SP(struct GraphicInfo_SP *g_sp,
7804 int graphic, int sync_frame, int x, int y)
7806 int frame = getGraphicAnimationFrame(graphic, sync_frame);
7808 getGraphicSource(graphic, frame, &g_sp->bitmap, &g_sp->src_x, &g_sp->src_y);
7811 boolean isNextAnimationFrame_SP(int graphic, int sync_frame)
7813 return (IS_NEXT_FRAME(sync_frame, graphic));
7816 int getGraphicInfo_Delay(int graphic)
7818 return graphic_info[graphic].anim_delay;
7821 void PlayMenuSoundExt(int sound)
7823 if (sound == SND_UNDEFINED)
7826 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
7827 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
7830 if (IS_LOOP_SOUND(sound))
7831 PlaySoundLoop(sound);
7836 void PlayMenuSound()
7838 PlayMenuSoundExt(menu.sound[game_status]);
7841 void PlayMenuSoundStereo(int sound, int stereo_position)
7843 if (sound == SND_UNDEFINED)
7846 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
7847 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
7850 if (IS_LOOP_SOUND(sound))
7851 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
7853 PlaySoundStereo(sound, stereo_position);
7856 void PlayMenuSoundIfLoopExt(int sound)
7858 if (sound == SND_UNDEFINED)
7861 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
7862 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
7865 if (IS_LOOP_SOUND(sound))
7866 PlaySoundLoop(sound);
7869 void PlayMenuSoundIfLoop()
7871 PlayMenuSoundIfLoopExt(menu.sound[game_status]);
7874 void PlayMenuMusicExt(int music)
7876 if (music == MUS_UNDEFINED)
7879 if (!setup.sound_music)
7885 void PlayMenuMusic()
7887 PlayMenuMusicExt(menu.music[game_status]);
7890 void PlaySoundActivating()
7893 PlaySound(SND_MENU_ITEM_ACTIVATING);
7897 void PlaySoundSelecting()
7900 PlaySound(SND_MENU_ITEM_SELECTING);
7904 void ToggleFullscreenOrChangeWindowScalingIfNeeded()
7906 boolean change_fullscreen = (setup.fullscreen !=
7907 video.fullscreen_enabled);
7908 boolean change_fullscreen_mode = (video.fullscreen_enabled &&
7909 !strEqual(setup.fullscreen_mode,
7910 video.fullscreen_mode_current));
7911 boolean change_window_scaling_percent = (!video.fullscreen_enabled &&
7912 setup.window_scaling_percent !=
7913 video.window_scaling_percent);
7915 if (change_window_scaling_percent && video.fullscreen_enabled)
7918 if (!change_window_scaling_percent && !video.fullscreen_available)
7921 #if defined(TARGET_SDL2)
7922 if (change_window_scaling_percent)
7924 SDLSetWindowScaling(setup.window_scaling_percent);
7928 else if (change_fullscreen)
7930 SDLSetWindowFullscreen(setup.fullscreen);
7932 /* set setup value according to successfully changed fullscreen mode */
7933 setup.fullscreen = video.fullscreen_enabled;
7939 if (change_fullscreen ||
7940 change_fullscreen_mode ||
7941 change_window_scaling_percent)
7943 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
7945 /* save backbuffer content which gets lost when toggling fullscreen mode */
7946 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
7948 if (change_fullscreen_mode)
7950 /* keep fullscreen, but change fullscreen mode (screen resolution) */
7951 video.fullscreen_enabled = FALSE; /* force new fullscreen mode */
7954 if (change_window_scaling_percent)
7956 /* keep window mode, but change window scaling */
7957 video.fullscreen_enabled = TRUE; /* force new window scaling */
7960 /* toggle fullscreen */
7961 ChangeVideoModeIfNeeded(setup.fullscreen);
7963 /* set setup value according to successfully changed fullscreen mode */
7964 setup.fullscreen = video.fullscreen_enabled;
7966 /* restore backbuffer content from temporary backbuffer backup bitmap */
7967 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
7969 FreeBitmap(tmp_backbuffer);
7971 /* update visible window/screen */
7972 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
7976 void ChangeViewportPropertiesIfNeeded()
7978 int gfx_game_mode = game_status;
7979 int gfx_game_mode2 = (game_status == GAME_MODE_EDITOR ? GAME_MODE_DEFAULT :
7981 struct RectWithBorder *vp_playfield = &viewport.playfield[gfx_game_mode];
7982 struct RectWithBorder *vp_door_1 = &viewport.door_1[gfx_game_mode];
7983 struct RectWithBorder *vp_door_2 = &viewport.door_2[gfx_game_mode2];
7984 struct RectWithBorder *vp_door_3 = &viewport.door_2[GAME_MODE_EDITOR];
7985 int border_size = vp_playfield->border_size;
7986 int new_sx = vp_playfield->x + border_size;
7987 int new_sy = vp_playfield->y + border_size;
7988 int new_sxsize = vp_playfield->width - 2 * border_size;
7989 int new_sysize = vp_playfield->height - 2 * border_size;
7990 int new_real_sx = vp_playfield->x;
7991 int new_real_sy = vp_playfield->y;
7992 int new_full_sxsize = vp_playfield->width;
7993 int new_full_sysize = vp_playfield->height;
7994 int new_dx = vp_door_1->x;
7995 int new_dy = vp_door_1->y;
7996 int new_dxsize = vp_door_1->width;
7997 int new_dysize = vp_door_1->height;
7998 int new_vx = vp_door_2->x;
7999 int new_vy = vp_door_2->y;
8000 int new_vxsize = vp_door_2->width;
8001 int new_vysize = vp_door_2->height;
8002 int new_ex = vp_door_3->x;
8003 int new_ey = vp_door_3->y;
8004 int new_exsize = vp_door_3->width;
8005 int new_eysize = vp_door_3->height;
8006 int new_tilesize_var =
8007 (setup.small_game_graphics ? MINI_TILESIZE : game.tile_size);
8009 int tilesize = (gfx_game_mode == GAME_MODE_PLAYING ? new_tilesize_var :
8010 gfx_game_mode == GAME_MODE_EDITOR ? MINI_TILESIZE : TILESIZE);
8011 int new_scr_fieldx = new_sxsize / tilesize;
8012 int new_scr_fieldy = new_sysize / tilesize;
8013 int new_scr_fieldx_buffers = new_sxsize / new_tilesize_var;
8014 int new_scr_fieldy_buffers = new_sysize / new_tilesize_var;
8015 boolean init_gfx_buffers = FALSE;
8016 boolean init_video_buffer = FALSE;
8017 boolean init_gadgets_and_toons = FALSE;
8018 boolean init_em_graphics = FALSE;
8019 boolean drawing_area_changed = FALSE;
8021 if (viewport.window.width != WIN_XSIZE ||
8022 viewport.window.height != WIN_YSIZE)
8024 WIN_XSIZE = viewport.window.width;
8025 WIN_YSIZE = viewport.window.height;
8027 init_video_buffer = TRUE;
8028 init_gfx_buffers = TRUE;
8030 // printf("::: video: init_video_buffer, init_gfx_buffers\n");
8033 if (new_scr_fieldx != SCR_FIELDX ||
8034 new_scr_fieldy != SCR_FIELDY)
8036 /* this always toggles between MAIN and GAME when using small tile size */
8038 SCR_FIELDX = new_scr_fieldx;
8039 SCR_FIELDY = new_scr_fieldy;
8041 // printf("::: new_scr_fieldx != SCR_FIELDX ...\n");
8052 new_sxsize != SXSIZE ||
8053 new_sysize != SYSIZE ||
8054 new_dxsize != DXSIZE ||
8055 new_dysize != DYSIZE ||
8056 new_vxsize != VXSIZE ||
8057 new_vysize != VYSIZE ||
8058 new_exsize != EXSIZE ||
8059 new_eysize != EYSIZE ||
8060 new_real_sx != REAL_SX ||
8061 new_real_sy != REAL_SY ||
8062 new_full_sxsize != FULL_SXSIZE ||
8063 new_full_sysize != FULL_SYSIZE ||
8064 new_tilesize_var != TILESIZE_VAR
8067 if (new_tilesize_var != TILESIZE_VAR)
8069 // printf("::: new_tilesize_var != TILESIZE_VAR\n");
8071 // changing tile size invalidates scroll values of engine snapshots
8072 FreeEngineSnapshotSingle();
8074 // changing tile size requires update of graphic mapping for EM engine
8075 init_em_graphics = TRUE;
8080 new_sxsize != SXSIZE ||
8081 new_sysize != SYSIZE ||
8082 new_real_sx != REAL_SX ||
8083 new_real_sy != REAL_SY ||
8084 new_full_sxsize != FULL_SXSIZE ||
8085 new_full_sysize != FULL_SYSIZE)
8087 if (!init_video_buffer)
8088 drawing_area_changed = TRUE;
8099 SXSIZE = new_sxsize;
8100 SYSIZE = new_sysize;
8101 DXSIZE = new_dxsize;
8102 DYSIZE = new_dysize;
8103 VXSIZE = new_vxsize;
8104 VYSIZE = new_vysize;
8105 EXSIZE = new_exsize;
8106 EYSIZE = new_eysize;
8107 REAL_SX = new_real_sx;
8108 REAL_SY = new_real_sy;
8109 FULL_SXSIZE = new_full_sxsize;
8110 FULL_SYSIZE = new_full_sysize;
8111 TILESIZE_VAR = new_tilesize_var;
8113 init_gfx_buffers = TRUE;
8114 init_gadgets_and_toons = TRUE;
8116 // printf("::: viewports: init_gfx_buffers\n");
8117 // printf("::: viewports: init_gadgets_and_toons\n");
8120 if (init_gfx_buffers)
8122 // printf("::: init_gfx_buffers\n");
8124 SCR_FIELDX = new_scr_fieldx_buffers;
8125 SCR_FIELDY = new_scr_fieldy_buffers;
8129 SCR_FIELDX = new_scr_fieldx;
8130 SCR_FIELDY = new_scr_fieldy;
8132 gfx.drawing_area_changed = drawing_area_changed;
8134 SetDrawDeactivationMask(REDRAW_NONE);
8135 SetDrawBackgroundMask(REDRAW_FIELD);
8138 if (init_video_buffer)
8140 // printf("::: init_video_buffer\n");
8142 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
8145 if (init_gadgets_and_toons)
8147 // printf("::: init_gadgets_and_toons\n");
8153 if (init_em_graphics)
8155 InitGraphicInfo_EM();