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 FALSE
28 #define DEBUG_FRAME_TIME FALSE
30 /* tool button identifiers */
31 #define TOOL_CTRL_ID_YES 0
32 #define TOOL_CTRL_ID_NO 1
33 #define TOOL_CTRL_ID_CONFIRM 2
34 #define TOOL_CTRL_ID_PLAYER_1 3
35 #define TOOL_CTRL_ID_PLAYER_2 4
36 #define TOOL_CTRL_ID_PLAYER_3 5
37 #define TOOL_CTRL_ID_PLAYER_4 6
39 #define NUM_TOOL_BUTTONS 7
41 /* constants for number of doors and door parts */
43 #define NUM_PANELS NUM_DOORS
44 // #define NUM_PANELS 0
45 #define MAX_PARTS_PER_DOOR 8
46 #define MAX_DOOR_PARTS (NUM_DOORS * MAX_PARTS_PER_DOOR + NUM_PANELS)
47 #define DOOR_PART_IS_PANEL(i) ((i) >= NUM_DOORS * MAX_PARTS_PER_DOOR)
50 struct DoorPartOrderInfo
56 static struct DoorPartOrderInfo door_part_order[MAX_DOOR_PARTS];
58 struct DoorPartControlInfo
62 struct DoorPartPosInfo *pos;
65 static struct DoorPartControlInfo door_part_controls[] =
69 IMG_GFX_DOOR_1_PART_1,
74 IMG_GFX_DOOR_1_PART_2,
79 IMG_GFX_DOOR_1_PART_3,
84 IMG_GFX_DOOR_1_PART_4,
89 IMG_GFX_DOOR_1_PART_5,
94 IMG_GFX_DOOR_1_PART_6,
99 IMG_GFX_DOOR_1_PART_7,
104 IMG_GFX_DOOR_1_PART_8,
110 IMG_GFX_DOOR_2_PART_1,
115 IMG_GFX_DOOR_2_PART_2,
120 IMG_GFX_DOOR_2_PART_3,
125 IMG_GFX_DOOR_2_PART_4,
130 IMG_GFX_DOOR_2_PART_5,
135 IMG_GFX_DOOR_2_PART_6,
140 IMG_GFX_DOOR_2_PART_7,
145 IMG_GFX_DOOR_2_PART_8,
151 IMG_BACKGROUND_PANEL,
168 /* forward declaration for internal use */
169 static void UnmapToolButtons();
170 static void HandleToolButtons(struct GadgetInfo *);
171 static int el_act_dir2crm(int, int, int);
172 static int el_act2crm(int, int);
174 static struct GadgetInfo *tool_gadget[NUM_TOOL_BUTTONS];
175 static int request_gadget_id = -1;
177 static char *print_if_not_empty(int element)
179 static char *s = NULL;
180 char *token_name = element_info[element].token_name;
185 s = checked_malloc(strlen(token_name) + 10 + 1);
187 if (element != EL_EMPTY)
188 sprintf(s, "%d\t['%s']", element, token_name);
190 sprintf(s, "%d", element);
195 void DumpTile(int x, int y)
200 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
206 printf_line("-", 79);
207 printf("Field Info: SCREEN(%d, %d), LEVEL(%d, %d)\n", sx, sy, x, y);
208 printf_line("-", 79);
210 if (!IN_LEV_FIELD(x, y))
212 printf("(not in level field)\n");
218 printf(" Feld: %d\t['%s']\n", Feld[x][y],
219 element_info[Feld[x][y]].token_name);
220 printf(" Back: %s\n", print_if_not_empty(Back[x][y]));
221 printf(" Store: %s\n", print_if_not_empty(Store[x][y]));
222 printf(" Store2: %s\n", print_if_not_empty(Store2[x][y]));
223 printf(" StorePlayer: %s\n", print_if_not_empty(StorePlayer[x][y]));
224 printf(" MovPos: %d\n", MovPos[x][y]);
225 printf(" MovDir: %d\n", MovDir[x][y]);
226 printf(" MovDelay: %d\n", MovDelay[x][y]);
227 printf(" ChangeDelay: %d\n", ChangeDelay[x][y]);
228 printf(" CustomValue: %d\n", CustomValue[x][y]);
229 printf(" GfxElement: %d\n", GfxElement[x][y]);
230 printf(" GfxAction: %d\n", GfxAction[x][y]);
231 printf(" GfxFrame: %d [%d]\n", GfxFrame[x][y], FrameCounter);
235 void SetDrawtoField(int mode)
237 if (mode == DRAW_TO_FIELDBUFFER)
243 BX2 = SCR_FIELDX + 1;
244 BY2 = SCR_FIELDY + 1;
246 drawto_field = fieldbuffer;
248 else /* DRAW_TO_BACKBUFFER */
254 BX2 = SCR_FIELDX - 1;
255 BY2 = SCR_FIELDY - 1;
257 drawto_field = backbuffer;
261 static void RedrawPlayfield_RND()
263 if (game.envelope_active)
266 DrawLevel(REDRAW_ALL);
270 void RedrawPlayfield()
272 if (game_status != GAME_MODE_PLAYING)
275 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
276 RedrawPlayfield_EM(TRUE);
277 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
278 RedrawPlayfield_SP(TRUE);
279 else if (level.game_engine_type == GAME_ENGINE_TYPE_RND)
280 RedrawPlayfield_RND();
282 BlitScreenToBitmap(backbuffer);
284 BlitBitmap(drawto, window, gfx.sx, gfx.sy, gfx.sxsize, gfx.sysize,
288 static void DrawMaskedBorderExt_Rect(int x, int y, int width, int height,
291 Bitmap *src_bitmap = getGlobalBorderBitmapFromStatus(global.border_status);
292 Bitmap *dst_bitmap = gfx.masked_border_bitmap_ptr;
294 if (x == -1 && y == -1)
297 if (draw_target == DRAW_TO_SCREEN)
298 BlitToScreenMasked(src_bitmap, x, y, width, height, x, y);
300 BlitBitmapMasked(src_bitmap, dst_bitmap, x, y, width, height, x, y);
303 static void DrawMaskedBorderExt_FIELD(int draw_target)
305 if (global.border_status >= GAME_MODE_MAIN &&
306 global.border_status <= GAME_MODE_PLAYING &&
307 border.draw_masked[global.border_status])
308 DrawMaskedBorderExt_Rect(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
312 static void DrawMaskedBorderExt_DOOR_1(int draw_target)
314 // when drawing to backbuffer, never draw border over open doors
315 if (draw_target == DRAW_TO_BACKBUFFER &&
316 (GetDoorState() & DOOR_OPEN_1))
319 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
320 (global.border_status != GAME_MODE_EDITOR ||
321 border.draw_masked[GFX_SPECIAL_ARG_EDITOR]))
322 DrawMaskedBorderExt_Rect(DX, DY, DXSIZE, DYSIZE, draw_target);
325 static void DrawMaskedBorderExt_DOOR_2(int draw_target)
327 // when drawing to backbuffer, never draw border over open doors
328 if (draw_target == DRAW_TO_BACKBUFFER &&
329 (GetDoorState() & DOOR_OPEN_2))
332 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
333 global.border_status != GAME_MODE_EDITOR)
334 DrawMaskedBorderExt_Rect(VX, VY, VXSIZE, VYSIZE, draw_target);
337 static void DrawMaskedBorderExt_DOOR_3(int draw_target)
339 /* currently not available */
342 static void DrawMaskedBorderExt_ALL(int draw_target)
344 DrawMaskedBorderExt_FIELD(draw_target);
345 DrawMaskedBorderExt_DOOR_1(draw_target);
346 DrawMaskedBorderExt_DOOR_2(draw_target);
347 DrawMaskedBorderExt_DOOR_3(draw_target);
350 static void DrawMaskedBorderExt(int redraw_mask, int draw_target)
352 /* never draw masked screen borders on borderless screens */
353 if (global.border_status == GAME_MODE_LOADING ||
354 global.border_status == GAME_MODE_TITLE)
357 if (redraw_mask & REDRAW_ALL)
358 DrawMaskedBorderExt_ALL(draw_target);
361 if (redraw_mask & REDRAW_FIELD)
362 DrawMaskedBorderExt_FIELD(draw_target);
363 if (redraw_mask & REDRAW_DOOR_1)
364 DrawMaskedBorderExt_DOOR_1(draw_target);
365 if (redraw_mask & REDRAW_DOOR_2)
366 DrawMaskedBorderExt_DOOR_2(draw_target);
367 if (redraw_mask & REDRAW_DOOR_3)
368 DrawMaskedBorderExt_DOOR_3(draw_target);
372 void DrawMaskedBorder_FIELD()
374 DrawMaskedBorderExt_FIELD(DRAW_TO_BACKBUFFER);
377 void DrawMaskedBorder(int redraw_mask)
379 DrawMaskedBorderExt(redraw_mask, DRAW_TO_BACKBUFFER);
382 void DrawMaskedBorderToTarget(int draw_target)
384 if (draw_target == DRAW_TO_BACKBUFFER ||
385 draw_target == DRAW_TO_SCREEN)
387 DrawMaskedBorderExt(REDRAW_ALL, draw_target);
391 int last_border_status = global.border_status;
393 if (draw_target == DRAW_TO_FADE_SOURCE)
395 global.border_status = gfx.fade_border_source_status;
396 gfx.masked_border_bitmap_ptr = gfx.fade_bitmap_source;
398 else if (draw_target == DRAW_TO_FADE_TARGET)
400 global.border_status = gfx.fade_border_target_status;
401 gfx.masked_border_bitmap_ptr = gfx.fade_bitmap_target;
404 DrawMaskedBorderExt(REDRAW_ALL, draw_target);
406 global.border_status = last_border_status;
407 gfx.masked_border_bitmap_ptr = backbuffer;
411 void BlitScreenToBitmap_RND(Bitmap *target_bitmap)
413 int fx = FX, fy = FY;
414 int full_lev_fieldx = lev_fieldx + (BorderElement != EL_EMPTY ? 2 : 0);
415 int full_lev_fieldy = lev_fieldy + (BorderElement != EL_EMPTY ? 2 : 0);
417 int dx = (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
418 int dy = (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
419 int dx_var = dx * TILESIZE_VAR / TILESIZE;
420 int dy_var = dy * TILESIZE_VAR / TILESIZE;
423 ffx = (scroll_x - SBX_Left) * TILEX_VAR + dx_var;
424 ffy = (scroll_y - SBY_Upper) * TILEY_VAR + dy_var;
426 if (EVEN(SCR_FIELDX))
428 if (ffx < SBX_Right * TILEX_VAR + TILEX_VAR / 2 + TILEX_VAR)
429 fx += dx_var - MIN(ffx, TILEX_VAR / 2) + TILEX_VAR;
431 fx += (dx_var > 0 ? TILEX_VAR : 0);
438 if (EVEN(SCR_FIELDY))
440 if (ffy < SBY_Lower * TILEY_VAR + TILEY_VAR / 2 + TILEY_VAR)
441 fy += dy_var - MIN(ffy, TILEY_VAR / 2) + TILEY_VAR;
443 fy += (dy_var > 0 ? TILEY_VAR : 0);
450 if (full_lev_fieldx <= SCR_FIELDX)
452 if (EVEN(SCR_FIELDX))
453 fx = 2 * TILEX_VAR - (ODD(lev_fieldx) ? TILEX_VAR / 2 : 0);
455 fx = 2 * TILEX_VAR - (EVEN(lev_fieldx) ? TILEX_VAR / 2 : 0);
458 if (full_lev_fieldy <= SCR_FIELDY)
460 if (EVEN(SCR_FIELDY))
461 fy = 2 * TILEY_VAR - (ODD(lev_fieldy) ? TILEY_VAR / 2 : 0);
463 fy = 2 * TILEY_VAR - (EVEN(lev_fieldy) ? TILEY_VAR / 2 : 0);
466 BlitBitmap(drawto_field, target_bitmap, fx, fy, SXSIZE, SYSIZE, SX, SY);
469 void BlitScreenToBitmap(Bitmap *target_bitmap)
471 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
472 BlitScreenToBitmap_EM(target_bitmap);
473 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
474 BlitScreenToBitmap_SP(target_bitmap);
475 else if (level.game_engine_type == GAME_ENGINE_TYPE_RND)
476 BlitScreenToBitmap_RND(target_bitmap);
478 redraw_mask |= REDRAW_FIELD;
481 void DrawFramesPerSecond()
484 int font_nr = FONT_TEXT_2;
485 int font_width = getFontWidth(font_nr);
487 sprintf(text, "%04.1f fps", global.frames_per_second);
489 DrawTextExt(backbuffer, WIN_XSIZE - font_width * strlen(text), 0, text,
490 font_nr, BLIT_OPAQUE);
494 static void PrintFrameTimeDebugging()
496 static unsigned int last_counter = 0;
497 unsigned int counter = Counter();
498 int diff_1 = counter - last_counter;
499 int diff_2 = diff_1 - GAME_FRAME_DELAY;
501 int diff_2_cut = MIN(ABS(diff_2), diff_2_max);
502 char diff_bar[2 * diff_2_max + 5];
506 diff_bar[pos++] = (diff_2 < -diff_2_max ? '<' : ' ');
508 for (i = 0; i < diff_2_max; i++)
509 diff_bar[pos++] = (diff_2 >= 0 ? ' ' :
510 i >= diff_2_max - diff_2_cut ? '-' : ' ');
512 diff_bar[pos++] = '|';
514 for (i = 0; i < diff_2_max; i++)
515 diff_bar[pos++] = (diff_2 <= 0 ? ' ' : i < diff_2_cut ? '+' : ' ');
517 diff_bar[pos++] = (diff_2 > diff_2_max ? '>' : ' ');
519 diff_bar[pos++] = '\0';
521 Error(ERR_INFO, "%06d [%02d] [%c%02d] %s",
524 (diff_2 < 0 ? '-' : diff_2 > 0 ? '+' : ' '), ABS(diff_2),
527 last_counter = counter;
531 static int unifiedRedrawMask(int mask)
533 if (mask & REDRAW_ALL)
536 if (mask & REDRAW_FIELD && mask & REDRAW_DOORS)
542 static boolean equalRedrawMasks(int mask_1, int mask_2)
544 return unifiedRedrawMask(mask_1) == unifiedRedrawMask(mask_2);
549 static int last_redraw_mask = REDRAW_NONE;
551 // force screen redraw in every frame to continue drawing global animations
552 // (but always use the last redraw mask to prevent unwanted side effects)
553 if (redraw_mask == REDRAW_NONE)
554 redraw_mask = last_redraw_mask;
556 last_redraw_mask = redraw_mask;
559 // masked border now drawn immediately when blitting backbuffer to window
561 // draw masked border to all viewports, if defined
562 DrawMaskedBorder(redraw_mask);
565 // draw frames per second (only if debug mode is enabled)
566 if (redraw_mask & REDRAW_FPS)
567 DrawFramesPerSecond();
569 // remove playfield redraw before potentially merging with doors redraw
570 if (DrawingDeactivated(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE))
571 redraw_mask &= ~REDRAW_FIELD;
573 // redraw complete window if both playfield and (some) doors need redraw
574 if (redraw_mask & REDRAW_FIELD && redraw_mask & REDRAW_DOORS)
575 redraw_mask = REDRAW_ALL;
577 /* although redrawing the whole window would be fine for normal gameplay,
578 being able to only redraw the playfield is required for deactivating
579 certain drawing areas (mainly playfield) to work, which is needed for
580 warp-forward to be fast enough (by skipping redraw of most frames) */
582 if (redraw_mask & REDRAW_ALL)
584 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
586 else if (redraw_mask & REDRAW_FIELD)
588 BlitBitmap(backbuffer, window,
589 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
591 else if (redraw_mask & REDRAW_DOORS)
593 // merge door areas to prevent calling screen redraw more than once
599 if (redraw_mask & REDRAW_DOOR_1)
603 x2 = MAX(x2, DX + DXSIZE);
604 y2 = MAX(y2, DY + DYSIZE);
607 if (redraw_mask & REDRAW_DOOR_2)
611 x2 = MAX(x2, VX + VXSIZE);
612 y2 = MAX(y2, VY + VYSIZE);
615 if (redraw_mask & REDRAW_DOOR_3)
619 x2 = MAX(x2, EX + EXSIZE);
620 y2 = MAX(y2, EY + EYSIZE);
623 BlitBitmap(backbuffer, window, x1, y1, x2 - x1, y2 - y1, x1, y1);
626 redraw_mask = REDRAW_NONE;
629 PrintFrameTimeDebugging();
633 void BackToFront_WithFrameDelay(unsigned int frame_delay_value)
635 unsigned int frame_delay_value_old = GetVideoFrameDelay();
637 SetVideoFrameDelay(frame_delay_value);
641 SetVideoFrameDelay(frame_delay_value_old);
644 static int fade_type_skip = FADE_TYPE_NONE;
646 static void FadeExt(int fade_mask, int fade_mode, int fade_type)
648 void (*draw_border_function)(void) = NULL;
649 int x, y, width, height;
650 int fade_delay, post_delay;
652 if (fade_type == FADE_TYPE_FADE_OUT)
654 if (fade_type_skip != FADE_TYPE_NONE)
656 /* skip all fade operations until specified fade operation */
657 if (fade_type & fade_type_skip)
658 fade_type_skip = FADE_TYPE_NONE;
663 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
667 redraw_mask |= fade_mask;
669 if (fade_type == FADE_TYPE_SKIP)
671 fade_type_skip = fade_mode;
676 fade_delay = fading.fade_delay;
677 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
679 if (fade_type_skip != FADE_TYPE_NONE)
681 /* skip all fade operations until specified fade operation */
682 if (fade_type & fade_type_skip)
683 fade_type_skip = FADE_TYPE_NONE;
688 if (global.autoplay_leveldir)
693 if (fade_mask == REDRAW_FIELD)
698 height = FADE_SYSIZE;
700 if (border.draw_masked_when_fading)
701 draw_border_function = DrawMaskedBorder_FIELD; /* update when fading */
703 DrawMaskedBorder_FIELD(); /* draw once */
705 else /* REDRAW_ALL */
713 if (!setup.fade_screens ||
715 fading.fade_mode == FADE_MODE_NONE)
717 if (fade_mode == FADE_MODE_FADE_OUT)
720 BlitBitmap(backbuffer, window, x, y, width, height, x, y);
722 redraw_mask &= ~fade_mask;
727 FadeRectangle(x, y, width, height, fade_mode, fade_delay, post_delay,
728 draw_border_function);
730 redraw_mask &= ~fade_mask;
733 static void SetScreenStates_BeforeFadingIn()
735 // temporarily set screen mode for animations to screen after fading in
736 global.anim_status = global.anim_status_next;
738 // store backbuffer with all animations that will be started after fading in
739 if (fade_type_skip != FADE_MODE_SKIP_FADE_IN)
740 PrepareFadeBitmap(DRAW_TO_FADE_TARGET);
742 // set screen mode for animations back to fading
743 global.anim_status = GAME_MODE_PSEUDO_FADING;
746 static void SetScreenStates_AfterFadingIn()
748 // store new source screen (to use correct masked border for fading)
749 gfx.fade_border_source_status = global.border_status;
751 global.anim_status = global.anim_status_next;
754 static void SetScreenStates_BeforeFadingOut()
756 // store new target screen (to use correct masked border for fading)
757 gfx.fade_border_target_status = game_status;
759 // set screen mode for animations to fading
760 global.anim_status = GAME_MODE_PSEUDO_FADING;
762 // store backbuffer with all animations that will be stopped for fading out
763 if (fade_type_skip != FADE_MODE_SKIP_FADE_OUT)
764 PrepareFadeBitmap(DRAW_TO_FADE_SOURCE);
767 static void SetScreenStates_AfterFadingOut()
769 global.border_status = game_status;
772 void FadeIn(int fade_mask)
774 SetScreenStates_BeforeFadingIn();
777 DrawMaskedBorder(REDRAW_ALL);
780 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
781 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_IN);
783 FadeExt(fade_mask, FADE_MODE_FADE_IN, FADE_TYPE_FADE_IN);
787 FADE_SXSIZE = FULL_SXSIZE;
788 FADE_SYSIZE = FULL_SYSIZE;
790 SetScreenStates_AfterFadingIn();
792 // force update of global animation status in case of rapid screen changes
793 redraw_mask = REDRAW_ALL;
797 void FadeOut(int fade_mask)
799 // update screen if areas covered by "fade_mask" and "redraw_mask" differ
800 if (!equalRedrawMasks(fade_mask, redraw_mask))
803 SetScreenStates_BeforeFadingOut();
806 DrawMaskedBorder(REDRAW_ALL);
809 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
810 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_OUT);
812 FadeExt(fade_mask, FADE_MODE_FADE_OUT, FADE_TYPE_FADE_OUT);
814 SetScreenStates_AfterFadingOut();
817 static void FadeSetLeaveNext(struct TitleFadingInfo fading_leave, boolean set)
819 static struct TitleFadingInfo fading_leave_stored;
822 fading_leave_stored = fading_leave;
824 fading = fading_leave_stored;
827 void FadeSetEnterMenu()
829 fading = menu.enter_menu;
831 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
834 void FadeSetLeaveMenu()
836 fading = menu.leave_menu;
838 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
841 void FadeSetEnterScreen()
843 fading = menu.enter_screen[game_status];
845 FadeSetLeaveNext(menu.leave_screen[game_status], TRUE); /* store */
848 void FadeSetNextScreen()
850 fading = menu.next_screen[game_status];
852 // (do not overwrite fade mode set by FadeSetEnterScreen)
853 // FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
856 void FadeSetLeaveScreen()
858 FadeSetLeaveNext(menu.leave_screen[game_status], FALSE); /* recall */
861 void FadeSetFromType(int type)
863 if (type & TYPE_ENTER_SCREEN)
864 FadeSetEnterScreen();
865 else if (type & TYPE_ENTER)
867 else if (type & TYPE_LEAVE)
871 void FadeSetDisabled()
873 static struct TitleFadingInfo fading_none = { FADE_MODE_NONE, -1, -1, -1 };
875 fading = fading_none;
878 void FadeSkipNextFadeIn()
880 FadeExt(0, FADE_MODE_SKIP_FADE_IN, FADE_TYPE_SKIP);
883 void FadeSkipNextFadeOut()
885 FadeExt(0, FADE_MODE_SKIP_FADE_OUT, FADE_TYPE_SKIP);
888 Bitmap *getBitmapFromGraphicOrDefault(int graphic, int default_graphic)
890 boolean redefined = getImageListEntryFromImageID(graphic)->redefined;
892 return (graphic == IMG_UNDEFINED ? NULL :
893 graphic_info[graphic].bitmap != NULL || redefined ?
894 graphic_info[graphic].bitmap :
895 graphic_info[default_graphic].bitmap);
898 Bitmap *getBackgroundBitmap(int graphic)
900 return getBitmapFromGraphicOrDefault(graphic, IMG_BACKGROUND);
903 Bitmap *getGlobalBorderBitmap(int graphic)
905 return getBitmapFromGraphicOrDefault(graphic, IMG_GLOBAL_BORDER);
908 Bitmap *getGlobalBorderBitmapFromStatus(int status)
911 (status == GAME_MODE_MAIN ||
912 status == GAME_MODE_PSEUDO_TYPENAME ? IMG_GLOBAL_BORDER_MAIN :
913 status == GAME_MODE_SCORES ? IMG_GLOBAL_BORDER_SCORES :
914 status == GAME_MODE_EDITOR ? IMG_GLOBAL_BORDER_EDITOR :
915 status == GAME_MODE_PLAYING ? IMG_GLOBAL_BORDER_PLAYING :
918 return getGlobalBorderBitmap(graphic);
921 void SetWindowBackgroundImageIfDefined(int graphic)
923 if (graphic_info[graphic].bitmap)
924 SetWindowBackgroundBitmap(graphic_info[graphic].bitmap);
927 void SetMainBackgroundImageIfDefined(int graphic)
929 if (graphic_info[graphic].bitmap)
930 SetMainBackgroundBitmap(graphic_info[graphic].bitmap);
933 void SetDoorBackgroundImageIfDefined(int graphic)
935 if (graphic_info[graphic].bitmap)
936 SetDoorBackgroundBitmap(graphic_info[graphic].bitmap);
939 void SetWindowBackgroundImage(int graphic)
941 SetWindowBackgroundBitmap(getBackgroundBitmap(graphic));
944 void SetMainBackgroundImage(int graphic)
946 SetMainBackgroundBitmap(getBackgroundBitmap(graphic));
949 void SetDoorBackgroundImage(int graphic)
951 SetDoorBackgroundBitmap(getBackgroundBitmap(graphic));
954 void SetPanelBackground()
956 struct GraphicInfo *gfx = &graphic_info[IMG_BACKGROUND_PANEL];
958 BlitBitmapTiled(gfx->bitmap, bitmap_db_panel, gfx->src_x, gfx->src_y,
959 gfx->width, gfx->height, 0, 0, DXSIZE, DYSIZE);
961 SetDoorBackgroundBitmap(bitmap_db_panel);
964 void DrawBackground(int x, int y, int width, int height)
966 /* "drawto" might still point to playfield buffer here (hall of fame) */
967 ClearRectangleOnBackground(backbuffer, x, y, width, height);
969 if (IN_GFX_FIELD_FULL(x, y))
970 redraw_mask |= REDRAW_FIELD;
971 else if (IN_GFX_DOOR_1(x, y))
972 redraw_mask |= REDRAW_DOOR_1;
973 else if (IN_GFX_DOOR_2(x, y))
974 redraw_mask |= REDRAW_DOOR_2;
975 else if (IN_GFX_DOOR_3(x, y))
976 redraw_mask |= REDRAW_DOOR_3;
979 void DrawBackgroundForFont(int x, int y, int width, int height, int font_nr)
981 struct FontBitmapInfo *font = getFontBitmapInfo(font_nr);
983 if (font->bitmap == NULL)
986 DrawBackground(x, y, width, height);
989 void DrawBackgroundForGraphic(int x, int y, int width, int height, int graphic)
991 struct GraphicInfo *g = &graphic_info[graphic];
993 if (g->bitmap == NULL)
996 DrawBackground(x, y, width, height);
999 static int game_status_last = -1;
1000 static Bitmap *global_border_bitmap_last = NULL;
1001 static Bitmap *global_border_bitmap = NULL;
1002 static int real_sx_last = -1, real_sy_last = -1;
1003 static int full_sxsize_last = -1, full_sysize_last = -1;
1004 static int dx_last = -1, dy_last = -1;
1005 static int dxsize_last = -1, dysize_last = -1;
1006 static int vx_last = -1, vy_last = -1;
1007 static int vxsize_last = -1, vysize_last = -1;
1009 boolean CheckIfGlobalBorderHasChanged()
1011 // if game status has not changed, global border has not changed either
1012 if (game_status == game_status_last)
1015 // determine and store new global border bitmap for current game status
1016 global_border_bitmap = getGlobalBorderBitmapFromStatus(game_status);
1018 return (global_border_bitmap_last != global_border_bitmap);
1021 boolean CheckIfGlobalBorderRedrawIsNeeded()
1023 // if game status has not changed, nothing has to be redrawn
1024 if (game_status == game_status_last)
1027 // redraw if last screen was title screen
1028 if (game_status_last == GAME_MODE_TITLE)
1031 // redraw if global screen border has changed
1032 if (CheckIfGlobalBorderHasChanged())
1035 // redraw if position or size of playfield area has changed
1036 if (real_sx_last != REAL_SX || real_sy_last != REAL_SY ||
1037 full_sxsize_last != FULL_SXSIZE || full_sysize_last != FULL_SYSIZE)
1040 // redraw if position or size of door area has changed
1041 if (dx_last != DX || dy_last != DY ||
1042 dxsize_last != DXSIZE || dysize_last != DYSIZE)
1045 // redraw if position or size of tape area has changed
1046 if (vx_last != VX || vy_last != VY ||
1047 vxsize_last != VXSIZE || vysize_last != VYSIZE)
1053 void RedrawGlobalBorderFromBitmap(Bitmap *bitmap)
1056 BlitBitmap(bitmap, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
1058 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
1061 void RedrawGlobalBorder()
1063 Bitmap *bitmap = getGlobalBorderBitmapFromStatus(game_status);
1065 RedrawGlobalBorderFromBitmap(bitmap);
1067 redraw_mask = REDRAW_ALL;
1070 static void RedrawGlobalBorderIfNeeded()
1072 if (game_status == game_status_last)
1075 // copy current draw buffer to later copy back areas that have not changed
1076 if (game_status_last != GAME_MODE_TITLE)
1077 BlitBitmap(backbuffer, bitmap_db_store_1, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
1079 if (CheckIfGlobalBorderRedrawIsNeeded())
1081 // redraw global screen border (or clear, if defined to be empty)
1082 RedrawGlobalBorderFromBitmap(global_border_bitmap);
1084 // copy previous playfield and door areas, if they are defined on both
1085 // previous and current screen and if they still have the same size
1087 if (real_sx_last != -1 && real_sy_last != -1 &&
1088 REAL_SX != -1 && REAL_SY != -1 &&
1089 full_sxsize_last == FULL_SXSIZE && full_sysize_last == FULL_SYSIZE)
1090 BlitBitmap(bitmap_db_store_1, backbuffer,
1091 real_sx_last, real_sy_last, FULL_SXSIZE, FULL_SYSIZE,
1094 if (dx_last != -1 && dy_last != -1 &&
1095 DX != -1 && DY != -1 &&
1096 dxsize_last == DXSIZE && dysize_last == DYSIZE)
1097 BlitBitmap(bitmap_db_store_1, backbuffer,
1098 dx_last, dy_last, DXSIZE, DYSIZE, DX, DY);
1100 if (vx_last != -1 && vy_last != -1 &&
1101 VX != -1 && VY != -1 &&
1102 vxsize_last == VXSIZE && vysize_last == VYSIZE)
1103 BlitBitmap(bitmap_db_store_1, backbuffer,
1104 vx_last, vy_last, VXSIZE, VYSIZE, VX, VY);
1106 redraw_mask = REDRAW_ALL;
1109 game_status_last = game_status;
1111 global_border_bitmap_last = global_border_bitmap;
1113 real_sx_last = REAL_SX;
1114 real_sy_last = REAL_SY;
1115 full_sxsize_last = FULL_SXSIZE;
1116 full_sysize_last = FULL_SYSIZE;
1119 dxsize_last = DXSIZE;
1120 dysize_last = DYSIZE;
1123 vxsize_last = VXSIZE;
1124 vysize_last = VYSIZE;
1129 RedrawGlobalBorderIfNeeded();
1131 /* !!! "drawto" might still point to playfield buffer here (see above) !!! */
1132 /* (when entering hall of fame after playing) */
1133 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
1135 /* !!! maybe this should be done before clearing the background !!! */
1136 if (game_status == GAME_MODE_PLAYING)
1138 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
1139 SetDrawtoField(DRAW_TO_FIELDBUFFER);
1143 SetDrawtoField(DRAW_TO_BACKBUFFER);
1147 void MarkTileDirty(int x, int y)
1149 redraw_mask |= REDRAW_FIELD;
1152 void SetBorderElement()
1156 BorderElement = EL_EMPTY;
1158 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
1160 for (x = 0; x < lev_fieldx; x++)
1162 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
1163 BorderElement = EL_STEELWALL;
1165 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
1171 void FloodFillLevel(int from_x, int from_y, int fill_element,
1172 short field[MAX_LEV_FIELDX][MAX_LEV_FIELDY],
1173 int max_fieldx, int max_fieldy)
1177 static int check[4][2] = { { -1, 0 }, { 0, -1 }, { 1, 0 }, { 0, 1 } };
1178 static int safety = 0;
1180 /* check if starting field still has the desired content */
1181 if (field[from_x][from_y] == fill_element)
1186 if (safety > max_fieldx * max_fieldy)
1187 Error(ERR_EXIT, "Something went wrong in 'FloodFill()'. Please debug.");
1189 old_element = field[from_x][from_y];
1190 field[from_x][from_y] = fill_element;
1192 for (i = 0; i < 4; i++)
1194 x = from_x + check[i][0];
1195 y = from_y + check[i][1];
1197 if (IN_FIELD(x, y, max_fieldx, max_fieldy) && field[x][y] == old_element)
1198 FloodFillLevel(x, y, fill_element, field, max_fieldx, max_fieldy);
1204 void SetRandomAnimationValue(int x, int y)
1206 gfx.anim_random_frame = GfxRandom[x][y];
1209 int getGraphicAnimationFrame(int graphic, int sync_frame)
1211 /* animation synchronized with global frame counter, not move position */
1212 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
1213 sync_frame = FrameCounter;
1215 return getAnimationFrame(graphic_info[graphic].anim_frames,
1216 graphic_info[graphic].anim_delay,
1217 graphic_info[graphic].anim_mode,
1218 graphic_info[graphic].anim_start_frame,
1222 void getGraphicSourceBitmap(int graphic, int tilesize, Bitmap **bitmap)
1224 struct GraphicInfo *g = &graphic_info[graphic];
1225 int tilesize_capped = MIN(MAX(1, tilesize), TILESIZE);
1227 if (tilesize == gfx.standard_tile_size)
1228 *bitmap = g->bitmaps[IMG_BITMAP_STANDARD];
1229 else if (tilesize == game.tile_size)
1230 *bitmap = g->bitmaps[IMG_BITMAP_GAME];
1232 *bitmap = g->bitmaps[IMG_BITMAP_1x1 - log_2(tilesize_capped)];
1235 void getGraphicSourceXY(int graphic, int frame, int *x, int *y,
1236 boolean get_backside)
1238 struct GraphicInfo *g = &graphic_info[graphic];
1239 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
1240 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
1242 if (g->offset_y == 0) /* frames are ordered horizontally */
1244 int max_width = g->anim_frames_per_line * g->width;
1245 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
1247 *x = pos % max_width;
1248 *y = src_y % g->height + pos / max_width * g->height;
1250 else if (g->offset_x == 0) /* frames are ordered vertically */
1252 int max_height = g->anim_frames_per_line * g->height;
1253 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
1255 *x = src_x % g->width + pos / max_height * g->width;
1256 *y = pos % max_height;
1258 else /* frames are ordered diagonally */
1260 *x = src_x + frame * g->offset_x;
1261 *y = src_y + frame * g->offset_y;
1265 void getSizedGraphicSourceExt(int graphic, int frame, int tilesize,
1266 Bitmap **bitmap, int *x, int *y,
1267 boolean get_backside)
1269 struct GraphicInfo *g = &graphic_info[graphic];
1271 // if no in-game graphics defined, always use standard graphic size
1272 if (g->bitmaps[IMG_BITMAP_GAME] == NULL)
1273 tilesize = TILESIZE;
1275 getGraphicSourceBitmap(graphic, tilesize, bitmap);
1276 getGraphicSourceXY(graphic, frame, x, y, get_backside);
1278 *x = *x * tilesize / g->tile_size;
1279 *y = *y * tilesize / g->tile_size;
1282 void getFixedGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1283 int *x, int *y, boolean get_backside)
1285 getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y,
1289 void getSizedGraphicSource(int graphic, int frame, int tilesize,
1290 Bitmap **bitmap, int *x, int *y)
1292 getSizedGraphicSourceExt(graphic, frame, tilesize, bitmap, x, y, FALSE);
1295 void getFixedGraphicSource(int graphic, int frame,
1296 Bitmap **bitmap, int *x, int *y)
1298 getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y, FALSE);
1301 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1303 getSizedGraphicSource(graphic, 0, MINI_TILESIZE, bitmap, x, y);
1306 inline static void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1307 int *x, int *y, boolean get_backside)
1309 getSizedGraphicSourceExt(graphic, frame, TILESIZE_VAR, bitmap, x, y,
1313 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
1315 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
1318 void DrawGraphic(int x, int y, int graphic, int frame)
1321 if (!IN_SCR_FIELD(x, y))
1323 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1324 printf("DrawGraphic(): This should never happen!\n");
1329 DrawGraphicExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR, graphic,
1332 MarkTileDirty(x, y);
1335 void DrawFixedGraphic(int x, int y, int graphic, int frame)
1338 if (!IN_SCR_FIELD(x, y))
1340 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1341 printf("DrawGraphic(): This should never happen!\n");
1346 DrawFixedGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic,
1348 MarkTileDirty(x, y);
1351 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1357 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1359 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX_VAR, TILEY_VAR, x, y);
1362 void DrawFixedGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1368 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1369 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
1372 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
1375 if (!IN_SCR_FIELD(x, y))
1377 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1378 printf("DrawGraphicThruMask(): This should never happen!\n");
1383 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
1386 MarkTileDirty(x, y);
1389 void DrawFixedGraphicThruMask(int x, int y, int graphic, int frame)
1392 if (!IN_SCR_FIELD(x, y))
1394 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1395 printf("DrawGraphicThruMask(): This should never happen!\n");
1400 DrawFixedGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
1402 MarkTileDirty(x, y);
1405 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
1411 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1413 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX_VAR, TILEY_VAR,
1417 void DrawFixedGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y,
1418 int graphic, int frame)
1423 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1425 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY,
1429 void DrawSizedGraphic(int x, int y, int graphic, int frame, int tilesize)
1431 DrawSizedGraphicExt(drawto, SX + x * tilesize, SY + y * tilesize, graphic,
1433 MarkTileDirty(x / tilesize, y / tilesize);
1436 void DrawSizedGraphicExt(DrawBuffer *d, int x, int y, int graphic, int frame,
1442 getSizedGraphicSource(graphic, frame, tilesize, &src_bitmap, &src_x, &src_y);
1443 BlitBitmap(src_bitmap, d, src_x, src_y, tilesize, tilesize, x, y);
1446 void DrawMiniGraphic(int x, int y, int graphic)
1448 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
1449 MarkTileDirty(x / 2, y / 2);
1452 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
1457 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1458 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
1461 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
1462 int graphic, int frame,
1463 int cut_mode, int mask_mode)
1468 int width = TILEX, height = TILEY;
1471 if (dx || dy) /* shifted graphic */
1473 if (x < BX1) /* object enters playfield from the left */
1480 else if (x > BX2) /* object enters playfield from the right */
1486 else if (x == BX1 && dx < 0) /* object leaves playfield to the left */
1492 else if (x == BX2 && dx > 0) /* object leaves playfield to the right */
1494 else if (dx) /* general horizontal movement */
1495 MarkTileDirty(x + SIGN(dx), y);
1497 if (y < BY1) /* object enters playfield from the top */
1499 if (cut_mode == CUT_BELOW) /* object completely above top border */
1507 else if (y > BY2) /* object enters playfield from the bottom */
1513 else if (y == BY1 && dy < 0) /* object leaves playfield to the top */
1519 else if (dy > 0 && cut_mode == CUT_ABOVE)
1521 if (y == BY2) /* object completely above bottom border */
1527 MarkTileDirty(x, y + 1);
1528 } /* object leaves playfield to the bottom */
1529 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1531 else if (dy) /* general vertical movement */
1532 MarkTileDirty(x, y + SIGN(dy));
1536 if (!IN_SCR_FIELD(x, y))
1538 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1539 printf("DrawGraphicShifted(): This should never happen!\n");
1544 width = width * TILESIZE_VAR / TILESIZE;
1545 height = height * TILESIZE_VAR / TILESIZE;
1546 cx = cx * TILESIZE_VAR / TILESIZE;
1547 cy = cy * TILESIZE_VAR / TILESIZE;
1548 dx = dx * TILESIZE_VAR / TILESIZE;
1549 dy = dy * TILESIZE_VAR / TILESIZE;
1551 if (width > 0 && height > 0)
1553 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1558 dst_x = FX + x * TILEX_VAR + dx;
1559 dst_y = FY + y * TILEY_VAR + dy;
1561 if (mask_mode == USE_MASKING)
1562 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1565 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1568 MarkTileDirty(x, y);
1572 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
1573 int graphic, int frame,
1574 int cut_mode, int mask_mode)
1579 int width = TILEX_VAR, height = TILEY_VAR;
1582 int x2 = x + SIGN(dx);
1583 int y2 = y + SIGN(dy);
1585 /* movement with two-tile animations must be sync'ed with movement position,
1586 not with current GfxFrame (which can be higher when using slow movement) */
1587 int anim_pos = (dx ? ABS(dx) : ABS(dy));
1588 int anim_frames = graphic_info[graphic].anim_frames;
1590 /* (we also need anim_delay here for movement animations with less frames) */
1591 int anim_delay = graphic_info[graphic].anim_delay;
1592 int sync_frame = anim_pos * anim_frames * anim_delay / TILESIZE;
1594 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
1595 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
1597 /* re-calculate animation frame for two-tile movement animation */
1598 frame = getGraphicAnimationFrame(graphic, sync_frame);
1600 /* check if movement start graphic inside screen area and should be drawn */
1601 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
1603 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
1605 dst_x = FX + x1 * TILEX_VAR;
1606 dst_y = FY + y1 * TILEY_VAR;
1608 if (mask_mode == USE_MASKING)
1609 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1612 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1615 MarkTileDirty(x1, y1);
1618 /* check if movement end graphic inside screen area and should be drawn */
1619 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
1621 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
1623 dst_x = FX + x2 * TILEX_VAR;
1624 dst_y = FY + y2 * TILEY_VAR;
1626 if (mask_mode == USE_MASKING)
1627 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1630 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1633 MarkTileDirty(x2, y2);
1637 static void DrawGraphicShifted(int x, int y, int dx, int dy,
1638 int graphic, int frame,
1639 int cut_mode, int mask_mode)
1643 DrawGraphic(x, y, graphic, frame);
1648 if (graphic_info[graphic].double_movement) /* EM style movement images */
1649 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1651 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1654 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1655 int frame, int cut_mode)
1657 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
1660 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1661 int cut_mode, int mask_mode)
1663 int lx = LEVELX(x), ly = LEVELY(y);
1667 if (IN_LEV_FIELD(lx, ly))
1669 SetRandomAnimationValue(lx, ly);
1671 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
1672 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1674 /* do not use double (EM style) movement graphic when not moving */
1675 if (graphic_info[graphic].double_movement && !dx && !dy)
1677 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
1678 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1681 else /* border element */
1683 graphic = el2img(element);
1684 frame = getGraphicAnimationFrame(graphic, -1);
1687 if (element == EL_EXPANDABLE_WALL)
1689 boolean left_stopped = FALSE, right_stopped = FALSE;
1691 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1692 left_stopped = TRUE;
1693 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1694 right_stopped = TRUE;
1696 if (left_stopped && right_stopped)
1698 else if (left_stopped)
1700 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1701 frame = graphic_info[graphic].anim_frames - 1;
1703 else if (right_stopped)
1705 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1706 frame = graphic_info[graphic].anim_frames - 1;
1711 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1712 else if (mask_mode == USE_MASKING)
1713 DrawGraphicThruMask(x, y, graphic, frame);
1715 DrawGraphic(x, y, graphic, frame);
1718 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1719 int cut_mode, int mask_mode)
1721 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1722 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1723 cut_mode, mask_mode);
1726 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1729 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1732 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1735 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1738 void DrawLevelElementThruMask(int x, int y, int element)
1740 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1743 void DrawLevelFieldThruMask(int x, int y)
1745 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1748 /* !!! implementation of quicksand is totally broken !!! */
1749 #define IS_CRUMBLED_TILE(x, y, e) \
1750 (GFX_CRUMBLED(e) && (!IN_LEV_FIELD(x, y) || \
1751 !IS_MOVING(x, y) || \
1752 (e) == EL_QUICKSAND_EMPTYING || \
1753 (e) == EL_QUICKSAND_FAST_EMPTYING))
1755 static void DrawLevelFieldCrumbledInnerCorners(int x, int y, int dx, int dy,
1760 int width, height, cx, cy;
1761 int sx = SCREENX(x), sy = SCREENY(y);
1762 int crumbled_border_size = graphic_info[graphic].border_size;
1763 int crumbled_tile_size = graphic_info[graphic].tile_size;
1764 int crumbled_border_size_var =
1765 crumbled_border_size * TILESIZE_VAR / crumbled_tile_size;
1768 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1770 for (i = 1; i < 4; i++)
1772 int dxx = (i & 1 ? dx : 0);
1773 int dyy = (i & 2 ? dy : 0);
1776 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1779 /* check if neighbour field is of same crumble type */
1780 boolean same = (IS_CRUMBLED_TILE(xx, yy, element) &&
1781 graphic_info[graphic].class ==
1782 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class);
1784 /* return if check prevents inner corner */
1785 if (same == (dxx == dx && dyy == dy))
1789 /* if we reach this point, we have an inner corner */
1791 getGraphicSource(graphic, 1, &src_bitmap, &src_x, &src_y);
1793 width = crumbled_border_size_var;
1794 height = crumbled_border_size_var;
1795 cx = (dx > 0 ? TILESIZE_VAR - width : 0);
1796 cy = (dy > 0 ? TILESIZE_VAR - height : 0);
1798 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1799 width, height, FX + sx * TILEX_VAR + cx, FY + sy * TILEY_VAR + cy);
1802 static void DrawLevelFieldCrumbledBorders(int x, int y, int graphic, int frame,
1807 int width, height, bx, by, cx, cy;
1808 int sx = SCREENX(x), sy = SCREENY(y);
1809 int crumbled_border_size = graphic_info[graphic].border_size;
1810 int crumbled_tile_size = graphic_info[graphic].tile_size;
1811 int crumbled_border_size_var =
1812 crumbled_border_size * TILESIZE_VAR / crumbled_tile_size;
1813 int crumbled_border_pos_var = TILESIZE_VAR - crumbled_border_size_var;
1816 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1818 /* draw simple, sloppy, non-corner-accurate crumbled border */
1820 width = (dir == 1 || dir == 2 ? crumbled_border_size_var : TILESIZE_VAR);
1821 height = (dir == 0 || dir == 3 ? crumbled_border_size_var : TILESIZE_VAR);
1822 cx = (dir == 2 ? crumbled_border_pos_var : 0);
1823 cy = (dir == 3 ? crumbled_border_pos_var : 0);
1825 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy, width, height,
1826 FX + sx * TILEX_VAR + cx,
1827 FY + sy * TILEY_VAR + cy);
1829 /* (remaining middle border part must be at least as big as corner part) */
1830 if (!(graphic_info[graphic].style & STYLE_ACCURATE_BORDERS) ||
1831 crumbled_border_size_var >= TILESIZE_VAR / 3)
1834 /* correct corners of crumbled border, if needed */
1836 for (i = -1; i <= 1; i += 2)
1838 int xx = x + (dir == 0 || dir == 3 ? i : 0);
1839 int yy = y + (dir == 1 || dir == 2 ? i : 0);
1840 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1843 /* check if neighbour field is of same crumble type */
1844 if (IS_CRUMBLED_TILE(xx, yy, element) &&
1845 graphic_info[graphic].class ==
1846 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1848 /* no crumbled corner, but continued crumbled border */
1850 int c1 = (dir == 2 || dir == 3 ? crumbled_border_pos_var : 0);
1851 int c2 = (i == 1 ? crumbled_border_pos_var : 0);
1852 int b1 = (i == 1 ? crumbled_border_size_var :
1853 TILESIZE_VAR - 2 * crumbled_border_size_var);
1855 width = crumbled_border_size_var;
1856 height = crumbled_border_size_var;
1858 if (dir == 1 || dir == 2)
1873 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
1875 FX + sx * TILEX_VAR + cx,
1876 FY + sy * TILEY_VAR + cy);
1881 static void DrawLevelFieldCrumbledExt(int x, int y, int graphic, int frame)
1883 int sx = SCREENX(x), sy = SCREENY(y);
1886 static int xy[4][2] =
1894 if (!IN_LEV_FIELD(x, y))
1897 element = TILE_GFX_ELEMENT(x, y);
1899 /* crumble field itself */
1900 if (IS_CRUMBLED_TILE(x, y, element))
1902 if (!IN_SCR_FIELD(sx, sy))
1905 for (i = 0; i < 4; i++)
1907 int xx = x + xy[i][0];
1908 int yy = y + xy[i][1];
1910 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1913 /* check if neighbour field is of same crumble type */
1914 if (IS_CRUMBLED_TILE(xx, yy, element) &&
1915 graphic_info[graphic].class ==
1916 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1919 DrawLevelFieldCrumbledBorders(x, y, graphic, frame, i);
1922 if ((graphic_info[graphic].style & STYLE_INNER_CORNERS) &&
1923 graphic_info[graphic].anim_frames == 2)
1925 for (i = 0; i < 4; i++)
1927 int dx = (i & 1 ? +1 : -1);
1928 int dy = (i & 2 ? +1 : -1);
1930 DrawLevelFieldCrumbledInnerCorners(x, y, dx, dy, graphic);
1934 MarkTileDirty(sx, sy);
1936 else /* center field not crumbled -- crumble neighbour fields */
1938 for (i = 0; i < 4; i++)
1940 int xx = x + xy[i][0];
1941 int yy = y + xy[i][1];
1942 int sxx = sx + xy[i][0];
1943 int syy = sy + xy[i][1];
1945 if (!IN_LEV_FIELD(xx, yy) ||
1946 !IN_SCR_FIELD(sxx, syy))
1949 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
1952 element = TILE_GFX_ELEMENT(xx, yy);
1954 if (!IS_CRUMBLED_TILE(xx, yy, element))
1957 graphic = el_act2crm(element, ACTION_DEFAULT);
1959 DrawLevelFieldCrumbledBorders(xx, yy, graphic, 0, 3 - i);
1961 MarkTileDirty(sxx, syy);
1966 void DrawLevelFieldCrumbled(int x, int y)
1970 if (!IN_LEV_FIELD(x, y))
1973 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1974 GfxElement[x][y] != EL_UNDEFINED &&
1975 GFX_CRUMBLED(GfxElement[x][y]))
1977 DrawLevelFieldCrumbledDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
1982 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
1984 DrawLevelFieldCrumbledExt(x, y, graphic, 0);
1987 void DrawLevelFieldCrumbledDigging(int x, int y, int direction,
1990 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1991 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1992 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1993 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1994 int sx = SCREENX(x), sy = SCREENY(y);
1996 DrawGraphic(sx, sy, graphic1, frame1);
1997 DrawLevelFieldCrumbledExt(x, y, graphic2, frame2);
2000 void DrawLevelFieldCrumbledNeighbours(int x, int y)
2002 int sx = SCREENX(x), sy = SCREENY(y);
2003 static int xy[4][2] =
2012 for (i = 0; i < 4; i++)
2014 int xx = x + xy[i][0];
2015 int yy = y + xy[i][1];
2016 int sxx = sx + xy[i][0];
2017 int syy = sy + xy[i][1];
2019 if (!IN_LEV_FIELD(xx, yy) ||
2020 !IN_SCR_FIELD(sxx, syy) ||
2021 !GFX_CRUMBLED(Feld[xx][yy]) ||
2025 DrawLevelField(xx, yy);
2029 static int getBorderElement(int x, int y)
2033 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
2034 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
2035 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
2036 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
2037 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
2038 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
2039 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
2041 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
2042 int steel_position = (x == -1 && y == -1 ? 0 :
2043 x == lev_fieldx && y == -1 ? 1 :
2044 x == -1 && y == lev_fieldy ? 2 :
2045 x == lev_fieldx && y == lev_fieldy ? 3 :
2046 x == -1 || x == lev_fieldx ? 4 :
2047 y == -1 || y == lev_fieldy ? 5 : 6);
2049 return border[steel_position][steel_type];
2052 void DrawScreenElement(int x, int y, int element)
2054 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
2055 DrawLevelFieldCrumbled(LEVELX(x), LEVELY(y));
2058 void DrawLevelElement(int x, int y, int element)
2060 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2061 DrawScreenElement(SCREENX(x), SCREENY(y), element);
2064 void DrawScreenField(int x, int y)
2066 int lx = LEVELX(x), ly = LEVELY(y);
2067 int element, content;
2069 if (!IN_LEV_FIELD(lx, ly))
2071 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
2074 element = getBorderElement(lx, ly);
2076 DrawScreenElement(x, y, element);
2081 element = Feld[lx][ly];
2082 content = Store[lx][ly];
2084 if (IS_MOVING(lx, ly))
2086 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
2087 boolean cut_mode = NO_CUTTING;
2089 if (element == EL_QUICKSAND_EMPTYING ||
2090 element == EL_QUICKSAND_FAST_EMPTYING ||
2091 element == EL_MAGIC_WALL_EMPTYING ||
2092 element == EL_BD_MAGIC_WALL_EMPTYING ||
2093 element == EL_DC_MAGIC_WALL_EMPTYING ||
2094 element == EL_AMOEBA_DROPPING)
2095 cut_mode = CUT_ABOVE;
2096 else if (element == EL_QUICKSAND_FILLING ||
2097 element == EL_QUICKSAND_FAST_FILLING ||
2098 element == EL_MAGIC_WALL_FILLING ||
2099 element == EL_BD_MAGIC_WALL_FILLING ||
2100 element == EL_DC_MAGIC_WALL_FILLING)
2101 cut_mode = CUT_BELOW;
2103 if (cut_mode == CUT_ABOVE)
2104 DrawScreenElement(x, y, element);
2106 DrawScreenElement(x, y, EL_EMPTY);
2109 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
2110 else if (cut_mode == NO_CUTTING)
2111 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
2114 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
2116 if (cut_mode == CUT_BELOW &&
2117 IN_LEV_FIELD(lx, ly + 1) && IN_SCR_FIELD(x, y + 1))
2118 DrawLevelElement(lx, ly + 1, element);
2121 if (content == EL_ACID)
2123 int dir = MovDir[lx][ly];
2124 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
2125 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
2127 DrawLevelElementThruMask(newlx, newly, EL_ACID);
2130 else if (IS_BLOCKED(lx, ly))
2135 boolean cut_mode = NO_CUTTING;
2136 int element_old, content_old;
2138 Blocked2Moving(lx, ly, &oldx, &oldy);
2141 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
2142 MovDir[oldx][oldy] == MV_RIGHT);
2144 element_old = Feld[oldx][oldy];
2145 content_old = Store[oldx][oldy];
2147 if (element_old == EL_QUICKSAND_EMPTYING ||
2148 element_old == EL_QUICKSAND_FAST_EMPTYING ||
2149 element_old == EL_MAGIC_WALL_EMPTYING ||
2150 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
2151 element_old == EL_DC_MAGIC_WALL_EMPTYING ||
2152 element_old == EL_AMOEBA_DROPPING)
2153 cut_mode = CUT_ABOVE;
2155 DrawScreenElement(x, y, EL_EMPTY);
2158 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
2160 else if (cut_mode == NO_CUTTING)
2161 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
2164 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
2167 else if (IS_DRAWABLE(element))
2168 DrawScreenElement(x, y, element);
2170 DrawScreenElement(x, y, EL_EMPTY);
2173 void DrawLevelField(int x, int y)
2175 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2176 DrawScreenField(SCREENX(x), SCREENY(y));
2177 else if (IS_MOVING(x, y))
2181 Moving2Blocked(x, y, &newx, &newy);
2182 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
2183 DrawScreenField(SCREENX(newx), SCREENY(newy));
2185 else if (IS_BLOCKED(x, y))
2189 Blocked2Moving(x, y, &oldx, &oldy);
2190 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
2191 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
2195 void DrawSizedElement(int x, int y, int element, int tilesize)
2199 graphic = el2edimg(element);
2200 DrawSizedGraphic(x, y, graphic, 0, tilesize);
2203 void DrawMiniElement(int x, int y, int element)
2207 graphic = el2edimg(element);
2208 DrawMiniGraphic(x, y, graphic);
2211 void DrawSizedElementOrWall(int sx, int sy, int scroll_x, int scroll_y,
2214 int x = sx + scroll_x, y = sy + scroll_y;
2216 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
2217 DrawSizedElement(sx, sy, EL_EMPTY, tilesize);
2218 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
2219 DrawSizedElement(sx, sy, Feld[x][y], tilesize);
2221 DrawSizedGraphic(sx, sy, el2edimg(getBorderElement(x, y)), 0, tilesize);
2224 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
2226 int x = sx + scroll_x, y = sy + scroll_y;
2228 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
2229 DrawMiniElement(sx, sy, EL_EMPTY);
2230 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
2231 DrawMiniElement(sx, sy, Feld[x][y]);
2233 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
2236 void DrawEnvelopeBackgroundTiles(int graphic, int startx, int starty,
2237 int x, int y, int xsize, int ysize,
2238 int tile_width, int tile_height)
2242 int dst_x = startx + x * tile_width;
2243 int dst_y = starty + y * tile_height;
2244 int width = graphic_info[graphic].width;
2245 int height = graphic_info[graphic].height;
2246 int inner_width_raw = MAX(width - 2 * tile_width, tile_width);
2247 int inner_height_raw = MAX(height - 2 * tile_height, tile_height);
2248 int inner_width = inner_width_raw - (inner_width_raw % tile_width);
2249 int inner_height = inner_height_raw - (inner_height_raw % tile_height);
2250 int inner_sx = (width >= 3 * tile_width ? tile_width : 0);
2251 int inner_sy = (height >= 3 * tile_height ? tile_height : 0);
2252 boolean draw_masked = graphic_info[graphic].draw_masked;
2254 getFixedGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
2256 if (src_bitmap == NULL || width < tile_width || height < tile_height)
2258 ClearRectangle(drawto, dst_x, dst_y, tile_width, tile_height);
2262 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - tile_width :
2263 inner_sx + (x - 1) * tile_width % inner_width);
2264 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - tile_height :
2265 inner_sy + (y - 1) * tile_height % inner_height);
2268 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
2271 BlitBitmap(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
2275 void DrawEnvelopeBackground(int graphic, int startx, int starty,
2276 int x, int y, int xsize, int ysize, int font_nr)
2278 int font_width = getFontWidth(font_nr);
2279 int font_height = getFontHeight(font_nr);
2281 DrawEnvelopeBackgroundTiles(graphic, startx, starty, x, y, xsize, ysize,
2282 font_width, font_height);
2285 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
2287 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2288 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2289 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2290 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2291 boolean no_delay = (tape.warp_forward);
2292 unsigned int anim_delay = 0;
2293 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
2294 int anim_delay_value = (no_delay ? 0 : frame_delay_value) / 2;
2295 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
2296 int font_width = getFontWidth(font_nr);
2297 int font_height = getFontHeight(font_nr);
2298 int max_xsize = level.envelope[envelope_nr].xsize;
2299 int max_ysize = level.envelope[envelope_nr].ysize;
2300 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
2301 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
2302 int xend = max_xsize;
2303 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
2304 int xstep = (xstart < xend ? 1 : 0);
2305 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2307 int end = MAX(xend - xstart, yend - ystart);
2310 for (i = start; i <= end; i++)
2312 int last_frame = end; // last frame of this "for" loop
2313 int x = xstart + i * xstep;
2314 int y = ystart + i * ystep;
2315 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2316 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2317 int sx = SX + (SXSIZE - xsize * font_width) / 2;
2318 int sy = SY + (SYSIZE - ysize * font_height) / 2;
2321 SetDrawtoField(DRAW_TO_FIELDBUFFER);
2323 BlitScreenToBitmap(backbuffer);
2325 SetDrawtoField(DRAW_TO_BACKBUFFER);
2327 for (yy = 0; yy < ysize; yy++)
2328 for (xx = 0; xx < xsize; xx++)
2329 DrawEnvelopeBackground(graphic, sx, sy, xx, yy, xsize, ysize, font_nr);
2331 DrawTextBuffer(sx + font_width, sy + font_height,
2332 level.envelope[envelope_nr].text, font_nr, max_xsize,
2333 xsize - 2, ysize - 2, 0, mask_mode,
2334 level.envelope[envelope_nr].autowrap,
2335 level.envelope[envelope_nr].centered, FALSE);
2337 redraw_mask |= REDRAW_FIELD;
2340 SkipUntilDelayReached(&anim_delay, anim_delay_value, &i, last_frame);
2344 void ShowEnvelope(int envelope_nr)
2346 int element = EL_ENVELOPE_1 + envelope_nr;
2347 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2348 int sound_opening = element_info[element].sound[ACTION_OPENING];
2349 int sound_closing = element_info[element].sound[ACTION_CLOSING];
2350 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2351 boolean no_delay = (tape.warp_forward);
2352 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
2353 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
2354 int anim_mode = graphic_info[graphic].anim_mode;
2355 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2356 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2358 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
2360 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2362 if (anim_mode == ANIM_DEFAULT)
2363 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
2365 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
2368 Delay(wait_delay_value);
2370 WaitForEventToContinue();
2372 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2374 if (anim_mode != ANIM_NONE)
2375 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
2377 if (anim_mode == ANIM_DEFAULT)
2378 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
2380 game.envelope_active = FALSE;
2382 SetDrawtoField(DRAW_TO_FIELDBUFFER);
2384 redraw_mask |= REDRAW_FIELD;
2388 static void setRequestBasePosition(int *x, int *y)
2390 int sx_base, sy_base;
2392 if (request.x != -1)
2393 sx_base = request.x;
2394 else if (request.align == ALIGN_LEFT)
2396 else if (request.align == ALIGN_RIGHT)
2397 sx_base = SX + SXSIZE;
2399 sx_base = SX + SXSIZE / 2;
2401 if (request.y != -1)
2402 sy_base = request.y;
2403 else if (request.valign == VALIGN_TOP)
2405 else if (request.valign == VALIGN_BOTTOM)
2406 sy_base = SY + SYSIZE;
2408 sy_base = SY + SYSIZE / 2;
2414 static void setRequestPositionExt(int *x, int *y, int width, int height,
2415 boolean add_border_size)
2417 int border_size = request.border_size;
2418 int sx_base, sy_base;
2421 setRequestBasePosition(&sx_base, &sy_base);
2423 if (request.align == ALIGN_LEFT)
2425 else if (request.align == ALIGN_RIGHT)
2426 sx = sx_base - width;
2428 sx = sx_base - width / 2;
2430 if (request.valign == VALIGN_TOP)
2432 else if (request.valign == VALIGN_BOTTOM)
2433 sy = sy_base - height;
2435 sy = sy_base - height / 2;
2437 sx = MAX(0, MIN(sx, WIN_XSIZE - width));
2438 sy = MAX(0, MIN(sy, WIN_YSIZE - height));
2440 if (add_border_size)
2450 static void setRequestPosition(int *x, int *y, boolean add_border_size)
2452 setRequestPositionExt(x, y, request.width, request.height, add_border_size);
2455 void DrawEnvelopeRequest(char *text)
2457 char *text_final = text;
2458 char *text_door_style = NULL;
2459 int graphic = IMG_BACKGROUND_REQUEST;
2460 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2461 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2462 int font_nr = FONT_REQUEST;
2463 int font_width = getFontWidth(font_nr);
2464 int font_height = getFontHeight(font_nr);
2465 int border_size = request.border_size;
2466 int line_spacing = request.line_spacing;
2467 int line_height = font_height + line_spacing;
2468 int max_text_width = request.width - 2 * border_size;
2469 int max_text_height = request.height - 2 * border_size;
2470 int line_length = max_text_width / font_width;
2471 int max_lines = max_text_height / line_height;
2472 int text_width = line_length * font_width;
2473 int width = request.width;
2474 int height = request.height;
2475 int tile_size = MAX(request.step_offset, 1);
2476 int x_steps = width / tile_size;
2477 int y_steps = height / tile_size;
2478 int sx_offset = border_size;
2479 int sy_offset = border_size;
2483 if (request.centered)
2484 sx_offset = (request.width - text_width) / 2;
2486 if (request.wrap_single_words && !request.autowrap)
2488 char *src_text_ptr, *dst_text_ptr;
2490 text_door_style = checked_malloc(2 * strlen(text) + 1);
2492 src_text_ptr = text;
2493 dst_text_ptr = text_door_style;
2495 while (*src_text_ptr)
2497 if (*src_text_ptr == ' ' ||
2498 *src_text_ptr == '?' ||
2499 *src_text_ptr == '!')
2500 *dst_text_ptr++ = '\n';
2502 if (*src_text_ptr != ' ')
2503 *dst_text_ptr++ = *src_text_ptr;
2508 *dst_text_ptr = '\0';
2510 text_final = text_door_style;
2513 setRequestPosition(&sx, &sy, FALSE);
2515 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
2517 for (y = 0; y < y_steps; y++)
2518 for (x = 0; x < x_steps; x++)
2519 DrawEnvelopeBackgroundTiles(graphic, sx, sy,
2520 x, y, x_steps, y_steps,
2521 tile_size, tile_size);
2523 /* force DOOR font inside door area */
2524 SetFontStatus(GAME_MODE_PSEUDO_DOOR);
2526 DrawTextBuffer(sx + sx_offset, sy + sy_offset, text_final, font_nr,
2527 line_length, -1, max_lines, line_spacing, mask_mode,
2528 request.autowrap, request.centered, FALSE);
2532 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2533 RedrawGadget(tool_gadget[i]);
2535 // store readily prepared envelope request for later use when animating
2536 BlitBitmap(backbuffer, bitmap_db_store_2, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2538 if (text_door_style)
2539 free(text_door_style);
2542 void AnimateEnvelopeRequest(int anim_mode, int action)
2544 int graphic = IMG_BACKGROUND_REQUEST;
2545 boolean draw_masked = graphic_info[graphic].draw_masked;
2546 int delay_value_normal = request.step_delay;
2547 int delay_value_fast = delay_value_normal / 2;
2548 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2549 boolean no_delay = (tape.warp_forward);
2550 int delay_value = (ffwd_delay ? delay_value_fast : delay_value_normal);
2551 int anim_delay_value = (no_delay ? 0 : delay_value + 500 * 0) / 2;
2552 unsigned int anim_delay = 0;
2554 int tile_size = MAX(request.step_offset, 1);
2555 int max_xsize = request.width / tile_size;
2556 int max_ysize = request.height / tile_size;
2557 int max_xsize_inner = max_xsize - 2;
2558 int max_ysize_inner = max_ysize - 2;
2560 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize_inner : 0);
2561 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize_inner : 0);
2562 int xend = max_xsize_inner;
2563 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize_inner : 0);
2564 int xstep = (xstart < xend ? 1 : 0);
2565 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2567 int end = MAX(xend - xstart, yend - ystart);
2570 if (setup.quick_doors)
2577 for (i = start; i <= end; i++)
2579 int last_frame = end; // last frame of this "for" loop
2580 int x = xstart + i * xstep;
2581 int y = ystart + i * ystep;
2582 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2583 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2584 int xsize_size_left = (xsize - 1) * tile_size;
2585 int ysize_size_top = (ysize - 1) * tile_size;
2586 int max_xsize_pos = (max_xsize - 1) * tile_size;
2587 int max_ysize_pos = (max_ysize - 1) * tile_size;
2588 int width = xsize * tile_size;
2589 int height = ysize * tile_size;
2594 setRequestPosition(&src_x, &src_y, FALSE);
2595 setRequestPositionExt(&dst_x, &dst_y, width, height, FALSE);
2597 BlitBitmap(bitmap_db_store_1, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2599 for (yy = 0; yy < 2; yy++)
2601 for (xx = 0; xx < 2; xx++)
2603 int src_xx = src_x + xx * max_xsize_pos;
2604 int src_yy = src_y + yy * max_ysize_pos;
2605 int dst_xx = dst_x + xx * xsize_size_left;
2606 int dst_yy = dst_y + yy * ysize_size_top;
2607 int xx_size = (xx ? tile_size : xsize_size_left);
2608 int yy_size = (yy ? tile_size : ysize_size_top);
2611 BlitBitmapMasked(bitmap_db_store_2, backbuffer,
2612 src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
2614 BlitBitmap(bitmap_db_store_2, backbuffer,
2615 src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
2619 redraw_mask |= REDRAW_FIELD;
2623 SkipUntilDelayReached(&anim_delay, anim_delay_value, &i, last_frame);
2627 void ShowEnvelopeRequest(char *text, unsigned int req_state, int action)
2629 int graphic = IMG_BACKGROUND_REQUEST;
2630 int sound_opening = SND_REQUEST_OPENING;
2631 int sound_closing = SND_REQUEST_CLOSING;
2632 int anim_mode_1 = request.anim_mode; /* (higher priority) */
2633 int anim_mode_2 = graphic_info[graphic].anim_mode; /* (lower priority) */
2634 int anim_mode = (anim_mode_1 != ANIM_DEFAULT ? anim_mode_1 : anim_mode_2);
2635 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2636 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2638 if (game_status == GAME_MODE_PLAYING)
2639 BlitScreenToBitmap(backbuffer);
2641 SetDrawtoField(DRAW_TO_BACKBUFFER);
2643 // SetDrawBackgroundMask(REDRAW_NONE);
2645 if (action == ACTION_OPENING)
2647 BlitBitmap(backbuffer, bitmap_db_store_1, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2649 if (req_state & REQ_ASK)
2651 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2652 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2654 else if (req_state & REQ_CONFIRM)
2656 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2658 else if (req_state & REQ_PLAYER)
2660 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2661 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2662 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2663 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2666 DrawEnvelopeRequest(text);
2669 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
2671 if (action == ACTION_OPENING)
2673 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2675 if (anim_mode == ANIM_DEFAULT)
2676 AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_OPENING);
2678 AnimateEnvelopeRequest(main_anim_mode, ACTION_OPENING);
2682 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2684 if (anim_mode != ANIM_NONE)
2685 AnimateEnvelopeRequest(main_anim_mode, ACTION_CLOSING);
2687 if (anim_mode == ANIM_DEFAULT)
2688 AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_CLOSING);
2691 game.envelope_active = FALSE;
2693 if (action == ACTION_CLOSING)
2694 BlitBitmap(bitmap_db_store_1, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2696 // SetDrawBackgroundMask(last_draw_background_mask);
2698 redraw_mask |= REDRAW_FIELD;
2702 if (action == ACTION_CLOSING &&
2703 game_status == GAME_MODE_PLAYING &&
2704 level.game_engine_type == GAME_ENGINE_TYPE_RND)
2705 SetDrawtoField(DRAW_TO_FIELDBUFFER);
2708 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
2712 int graphic = el2preimg(element);
2714 getSizedGraphicSource(graphic, 0, tilesize, &src_bitmap, &src_x, &src_y);
2715 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
2718 void DrawLevel(int draw_background_mask)
2722 SetMainBackgroundImage(IMG_BACKGROUND_PLAYING);
2723 SetDrawBackgroundMask(draw_background_mask);
2727 for (x = BX1; x <= BX2; x++)
2728 for (y = BY1; y <= BY2; y++)
2729 DrawScreenField(x, y);
2731 redraw_mask |= REDRAW_FIELD;
2734 void DrawSizedLevel(int size_x, int size_y, int scroll_x, int scroll_y,
2739 for (x = 0; x < size_x; x++)
2740 for (y = 0; y < size_y; y++)
2741 DrawSizedElementOrWall(x, y, scroll_x, scroll_y, tilesize);
2743 redraw_mask |= REDRAW_FIELD;
2746 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
2750 for (x = 0; x < size_x; x++)
2751 for (y = 0; y < size_y; y++)
2752 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
2754 redraw_mask |= REDRAW_FIELD;
2757 static void DrawPreviewLevelPlayfieldExt(int from_x, int from_y)
2759 boolean show_level_border = (BorderElement != EL_EMPTY);
2760 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2761 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2762 int tile_size = preview.tile_size;
2763 int preview_width = preview.xsize * tile_size;
2764 int preview_height = preview.ysize * tile_size;
2765 int real_preview_xsize = MIN(level_xsize, preview.xsize);
2766 int real_preview_ysize = MIN(level_ysize, preview.ysize);
2767 int real_preview_width = real_preview_xsize * tile_size;
2768 int real_preview_height = real_preview_ysize * tile_size;
2769 int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
2770 int dst_y = SY + ALIGNED_YPOS(preview.y, preview_height, preview.valign);
2773 if (!IN_GFX_FIELD_FULL(dst_x, dst_y + preview_height - 1))
2776 DrawBackground(dst_x, dst_y, preview_width, preview_height);
2778 dst_x += (preview_width - real_preview_width) / 2;
2779 dst_y += (preview_height - real_preview_height) / 2;
2781 for (x = 0; x < real_preview_xsize; x++)
2783 for (y = 0; y < real_preview_ysize; y++)
2785 int lx = from_x + x + (show_level_border ? -1 : 0);
2786 int ly = from_y + y + (show_level_border ? -1 : 0);
2787 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
2788 getBorderElement(lx, ly));
2790 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
2791 element, tile_size);
2795 redraw_mask |= REDRAW_FIELD;
2798 #define MICROLABEL_EMPTY 0
2799 #define MICROLABEL_LEVEL_NAME 1
2800 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
2801 #define MICROLABEL_LEVEL_AUTHOR 3
2802 #define MICROLABEL_IMPORTED_FROM_HEAD 4
2803 #define MICROLABEL_IMPORTED_FROM 5
2804 #define MICROLABEL_IMPORTED_BY_HEAD 6
2805 #define MICROLABEL_IMPORTED_BY 7
2807 static int getMaxTextLength(struct TextPosInfo *pos, int font_nr)
2809 int max_text_width = SXSIZE;
2810 int font_width = getFontWidth(font_nr);
2812 if (pos->align == ALIGN_CENTER)
2813 max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
2814 else if (pos->align == ALIGN_RIGHT)
2815 max_text_width = pos->x;
2817 max_text_width = SXSIZE - pos->x;
2819 return max_text_width / font_width;
2822 static void DrawPreviewLevelLabelExt(int mode)
2824 struct TextPosInfo *pos = &menu.main.text.level_info_2;
2825 char label_text[MAX_OUTPUT_LINESIZE + 1];
2826 int max_len_label_text;
2827 int font_nr = pos->font;
2830 if (!IN_GFX_FIELD_FULL(pos->x, pos->y + getFontHeight(pos->font)))
2833 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
2834 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
2835 mode == MICROLABEL_IMPORTED_BY_HEAD)
2836 font_nr = pos->font_alt;
2838 max_len_label_text = getMaxTextLength(pos, font_nr);
2840 if (pos->size != -1)
2841 max_len_label_text = pos->size;
2843 for (i = 0; i < max_len_label_text; i++)
2844 label_text[i] = ' ';
2845 label_text[max_len_label_text] = '\0';
2847 if (strlen(label_text) > 0)
2848 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2851 (mode == MICROLABEL_LEVEL_NAME ? level.name :
2852 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
2853 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
2854 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
2855 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
2856 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
2857 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
2858 max_len_label_text);
2859 label_text[max_len_label_text] = '\0';
2861 if (strlen(label_text) > 0)
2862 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2864 redraw_mask |= REDRAW_FIELD;
2867 static void DrawPreviewLevelExt(boolean restart)
2869 static unsigned int scroll_delay = 0;
2870 static unsigned int label_delay = 0;
2871 static int from_x, from_y, scroll_direction;
2872 static int label_state, label_counter;
2873 unsigned int scroll_delay_value = preview.step_delay;
2874 boolean show_level_border = (BorderElement != EL_EMPTY);
2875 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2876 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2883 if (preview.anim_mode == ANIM_CENTERED)
2885 if (level_xsize > preview.xsize)
2886 from_x = (level_xsize - preview.xsize) / 2;
2887 if (level_ysize > preview.ysize)
2888 from_y = (level_ysize - preview.ysize) / 2;
2891 from_x += preview.xoffset;
2892 from_y += preview.yoffset;
2894 scroll_direction = MV_RIGHT;
2898 DrawPreviewLevelPlayfieldExt(from_x, from_y);
2899 DrawPreviewLevelLabelExt(label_state);
2901 /* initialize delay counters */
2902 DelayReached(&scroll_delay, 0);
2903 DelayReached(&label_delay, 0);
2905 if (leveldir_current->name)
2907 struct TextPosInfo *pos = &menu.main.text.level_info_1;
2908 char label_text[MAX_OUTPUT_LINESIZE + 1];
2909 int font_nr = pos->font;
2910 int max_len_label_text = getMaxTextLength(pos, font_nr);
2912 if (pos->size != -1)
2913 max_len_label_text = pos->size;
2915 strncpy(label_text, leveldir_current->name, max_len_label_text);
2916 label_text[max_len_label_text] = '\0';
2918 if (IN_GFX_FIELD_FULL(pos->x, pos->y + getFontHeight(pos->font)))
2919 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2925 /* scroll preview level, if needed */
2926 if (preview.anim_mode != ANIM_NONE &&
2927 (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
2928 DelayReached(&scroll_delay, scroll_delay_value))
2930 switch (scroll_direction)
2935 from_x -= preview.step_offset;
2936 from_x = (from_x < 0 ? 0 : from_x);
2939 scroll_direction = MV_UP;
2943 if (from_x < level_xsize - preview.xsize)
2945 from_x += preview.step_offset;
2946 from_x = (from_x > level_xsize - preview.xsize ?
2947 level_xsize - preview.xsize : from_x);
2950 scroll_direction = MV_DOWN;
2956 from_y -= preview.step_offset;
2957 from_y = (from_y < 0 ? 0 : from_y);
2960 scroll_direction = MV_RIGHT;
2964 if (from_y < level_ysize - preview.ysize)
2966 from_y += preview.step_offset;
2967 from_y = (from_y > level_ysize - preview.ysize ?
2968 level_ysize - preview.ysize : from_y);
2971 scroll_direction = MV_LEFT;
2978 DrawPreviewLevelPlayfieldExt(from_x, from_y);
2981 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
2982 /* redraw micro level label, if needed */
2983 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
2984 !strEqual(level.author, ANONYMOUS_NAME) &&
2985 !strEqual(level.author, leveldir_current->name) &&
2986 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
2988 int max_label_counter = 23;
2990 if (leveldir_current->imported_from != NULL &&
2991 strlen(leveldir_current->imported_from) > 0)
2992 max_label_counter += 14;
2993 if (leveldir_current->imported_by != NULL &&
2994 strlen(leveldir_current->imported_by) > 0)
2995 max_label_counter += 14;
2997 label_counter = (label_counter + 1) % max_label_counter;
2998 label_state = (label_counter >= 0 && label_counter <= 7 ?
2999 MICROLABEL_LEVEL_NAME :
3000 label_counter >= 9 && label_counter <= 12 ?
3001 MICROLABEL_LEVEL_AUTHOR_HEAD :
3002 label_counter >= 14 && label_counter <= 21 ?
3003 MICROLABEL_LEVEL_AUTHOR :
3004 label_counter >= 23 && label_counter <= 26 ?
3005 MICROLABEL_IMPORTED_FROM_HEAD :
3006 label_counter >= 28 && label_counter <= 35 ?
3007 MICROLABEL_IMPORTED_FROM :
3008 label_counter >= 37 && label_counter <= 40 ?
3009 MICROLABEL_IMPORTED_BY_HEAD :
3010 label_counter >= 42 && label_counter <= 49 ?
3011 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
3013 if (leveldir_current->imported_from == NULL &&
3014 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
3015 label_state == MICROLABEL_IMPORTED_FROM))
3016 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
3017 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
3019 DrawPreviewLevelLabelExt(label_state);
3023 void DrawPreviewLevelInitial()
3025 DrawPreviewLevelExt(TRUE);
3028 void DrawPreviewLevelAnimation()
3030 DrawPreviewLevelExt(FALSE);
3033 inline static void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
3034 int graphic, int sync_frame,
3037 int frame = getGraphicAnimationFrame(graphic, sync_frame);
3039 if (mask_mode == USE_MASKING)
3040 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
3042 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
3045 void DrawFixedGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
3046 int graphic, int sync_frame, int mask_mode)
3048 int frame = getGraphicAnimationFrame(graphic, sync_frame);
3050 if (mask_mode == USE_MASKING)
3051 DrawFixedGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
3053 DrawFixedGraphicExt(dst_bitmap, x, y, graphic, frame);
3056 inline static void DrawGraphicAnimation(int x, int y, int graphic)
3058 int lx = LEVELX(x), ly = LEVELY(y);
3060 if (!IN_SCR_FIELD(x, y))
3063 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
3064 graphic, GfxFrame[lx][ly], NO_MASKING);
3066 MarkTileDirty(x, y);
3069 void DrawFixedGraphicAnimation(int x, int y, int graphic)
3071 int lx = LEVELX(x), ly = LEVELY(y);
3073 if (!IN_SCR_FIELD(x, y))
3076 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
3077 graphic, GfxFrame[lx][ly], NO_MASKING);
3078 MarkTileDirty(x, y);
3081 void DrawLevelGraphicAnimation(int x, int y, int graphic)
3083 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
3086 void DrawLevelElementAnimation(int x, int y, int element)
3088 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
3090 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
3093 void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
3095 int sx = SCREENX(x), sy = SCREENY(y);
3097 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
3100 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
3103 DrawGraphicAnimation(sx, sy, graphic);
3106 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
3107 DrawLevelFieldCrumbled(x, y);
3109 if (GFX_CRUMBLED(Feld[x][y]))
3110 DrawLevelFieldCrumbled(x, y);
3114 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
3116 int sx = SCREENX(x), sy = SCREENY(y);
3119 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
3122 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
3124 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
3127 DrawGraphicAnimation(sx, sy, graphic);
3129 if (GFX_CRUMBLED(element))
3130 DrawLevelFieldCrumbled(x, y);
3133 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
3135 if (player->use_murphy)
3137 /* this works only because currently only one player can be "murphy" ... */
3138 static int last_horizontal_dir = MV_LEFT;
3139 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
3141 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3142 last_horizontal_dir = move_dir;
3144 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
3146 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
3148 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
3154 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
3157 static boolean equalGraphics(int graphic1, int graphic2)
3159 struct GraphicInfo *g1 = &graphic_info[graphic1];
3160 struct GraphicInfo *g2 = &graphic_info[graphic2];
3162 return (g1->bitmap == g2->bitmap &&
3163 g1->src_x == g2->src_x &&
3164 g1->src_y == g2->src_y &&
3165 g1->anim_frames == g2->anim_frames &&
3166 g1->anim_delay == g2->anim_delay &&
3167 g1->anim_mode == g2->anim_mode);
3170 void DrawAllPlayers()
3174 for (i = 0; i < MAX_PLAYERS; i++)
3175 if (stored_player[i].active)
3176 DrawPlayer(&stored_player[i]);
3179 void DrawPlayerField(int x, int y)
3181 if (!IS_PLAYER(x, y))
3184 DrawPlayer(PLAYERINFO(x, y));
3187 #define DRAW_PLAYER_OVER_PUSHED_ELEMENT 1
3189 void DrawPlayer(struct PlayerInfo *player)
3191 int jx = player->jx;
3192 int jy = player->jy;
3193 int move_dir = player->MovDir;
3194 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
3195 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
3196 int last_jx = (player->is_moving ? jx - dx : jx);
3197 int last_jy = (player->is_moving ? jy - dy : jy);
3198 int next_jx = jx + dx;
3199 int next_jy = jy + dy;
3200 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
3201 boolean player_is_opaque = FALSE;
3202 int sx = SCREENX(jx), sy = SCREENY(jy);
3203 int sxx = 0, syy = 0;
3204 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
3206 int action = ACTION_DEFAULT;
3207 int last_player_graphic = getPlayerGraphic(player, move_dir);
3208 int last_player_frame = player->Frame;
3211 /* GfxElement[][] is set to the element the player is digging or collecting;
3212 remove also for off-screen player if the player is not moving anymore */
3213 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
3214 GfxElement[jx][jy] = EL_UNDEFINED;
3216 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
3220 if (!IN_LEV_FIELD(jx, jy))
3222 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
3223 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
3224 printf("DrawPlayerField(): This should never happen!\n");
3229 if (element == EL_EXPLOSION)
3232 action = (player->is_pushing ? ACTION_PUSHING :
3233 player->is_digging ? ACTION_DIGGING :
3234 player->is_collecting ? ACTION_COLLECTING :
3235 player->is_moving ? ACTION_MOVING :
3236 player->is_snapping ? ACTION_SNAPPING :
3237 player->is_dropping ? ACTION_DROPPING :
3238 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
3240 if (player->is_waiting)
3241 move_dir = player->dir_waiting;
3243 InitPlayerGfxAnimation(player, action, move_dir);
3245 /* ----------------------------------------------------------------------- */
3246 /* draw things in the field the player is leaving, if needed */
3247 /* ----------------------------------------------------------------------- */
3249 if (player->is_moving)
3251 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
3253 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
3255 if (last_element == EL_DYNAMITE_ACTIVE ||
3256 last_element == EL_EM_DYNAMITE_ACTIVE ||
3257 last_element == EL_SP_DISK_RED_ACTIVE)
3258 DrawDynamite(last_jx, last_jy);
3260 DrawLevelFieldThruMask(last_jx, last_jy);
3262 else if (last_element == EL_DYNAMITE_ACTIVE ||
3263 last_element == EL_EM_DYNAMITE_ACTIVE ||
3264 last_element == EL_SP_DISK_RED_ACTIVE)
3265 DrawDynamite(last_jx, last_jy);
3267 /* !!! this is not enough to prevent flickering of players which are
3268 moving next to each others without a free tile between them -- this
3269 can only be solved by drawing all players layer by layer (first the
3270 background, then the foreground etc.) !!! => TODO */
3271 else if (!IS_PLAYER(last_jx, last_jy))
3272 DrawLevelField(last_jx, last_jy);
3275 DrawLevelField(last_jx, last_jy);
3278 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
3279 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
3282 if (!IN_SCR_FIELD(sx, sy))
3285 /* ----------------------------------------------------------------------- */
3286 /* draw things behind the player, if needed */
3287 /* ----------------------------------------------------------------------- */
3290 DrawLevelElement(jx, jy, Back[jx][jy]);
3291 else if (IS_ACTIVE_BOMB(element))
3292 DrawLevelElement(jx, jy, EL_EMPTY);
3295 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
3297 int old_element = GfxElement[jx][jy];
3298 int old_graphic = el_act_dir2img(old_element, action, move_dir);
3299 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
3301 if (GFX_CRUMBLED(old_element))
3302 DrawLevelFieldCrumbledDigging(jx, jy, move_dir, player->StepFrame);
3304 DrawGraphic(sx, sy, old_graphic, frame);
3306 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
3307 player_is_opaque = TRUE;
3311 GfxElement[jx][jy] = EL_UNDEFINED;
3313 /* make sure that pushed elements are drawn with correct frame rate */
3314 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
3316 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
3317 GfxFrame[jx][jy] = player->StepFrame;
3319 DrawLevelField(jx, jy);
3323 #if !DRAW_PLAYER_OVER_PUSHED_ELEMENT
3324 /* ----------------------------------------------------------------------- */
3325 /* draw player himself */
3326 /* ----------------------------------------------------------------------- */
3328 graphic = getPlayerGraphic(player, move_dir);
3330 /* in the case of changed player action or direction, prevent the current
3331 animation frame from being restarted for identical animations */
3332 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
3333 player->Frame = last_player_frame;
3335 frame = getGraphicAnimationFrame(graphic, player->Frame);
3339 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3340 sxx = player->GfxPos;
3342 syy = player->GfxPos;
3345 if (player_is_opaque)
3346 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
3348 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3350 if (SHIELD_ON(player))
3352 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
3353 IMG_SHIELD_NORMAL_ACTIVE);
3354 int frame = getGraphicAnimationFrame(graphic, -1);
3356 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3360 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
3363 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3364 sxx = player->GfxPos;
3366 syy = player->GfxPos;
3370 /* ----------------------------------------------------------------------- */
3371 /* draw things the player is pushing, if needed */
3372 /* ----------------------------------------------------------------------- */
3374 if (player->is_pushing && player->is_moving)
3376 int px = SCREENX(jx), py = SCREENY(jy);
3377 int pxx = (TILEX - ABS(sxx)) * dx;
3378 int pyy = (TILEY - ABS(syy)) * dy;
3379 int gfx_frame = GfxFrame[jx][jy];
3385 if (!IS_MOVING(jx, jy)) /* push movement already finished */
3387 element = Feld[next_jx][next_jy];
3388 gfx_frame = GfxFrame[next_jx][next_jy];
3391 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
3393 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
3394 frame = getGraphicAnimationFrame(graphic, sync_frame);
3396 /* draw background element under pushed element (like the Sokoban field) */
3397 if (game.use_masked_pushing && IS_MOVING(jx, jy))
3399 /* this allows transparent pushing animation over non-black background */
3402 DrawLevelElement(jx, jy, Back[jx][jy]);
3404 DrawLevelElement(jx, jy, EL_EMPTY);
3406 if (Back[next_jx][next_jy])
3407 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3409 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
3411 else if (Back[next_jx][next_jy])
3412 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3415 /* do not draw (EM style) pushing animation when pushing is finished */
3416 /* (two-tile animations usually do not contain start and end frame) */
3417 if (graphic_info[graphic].double_movement && !IS_MOVING(jx, jy))
3418 DrawLevelElement(next_jx, next_jy, Feld[next_jx][next_jy]);
3420 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3422 /* masked drawing is needed for EMC style (double) movement graphics */
3423 /* !!! (ONLY WHEN DRAWING PUSHED ELEMENT OVER THE PLAYER) !!! */
3424 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3428 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
3429 /* ----------------------------------------------------------------------- */
3430 /* draw player himself */
3431 /* ----------------------------------------------------------------------- */
3433 graphic = getPlayerGraphic(player, move_dir);
3435 /* in the case of changed player action or direction, prevent the current
3436 animation frame from being restarted for identical animations */
3437 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
3438 player->Frame = last_player_frame;
3440 frame = getGraphicAnimationFrame(graphic, player->Frame);
3444 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3445 sxx = player->GfxPos;
3447 syy = player->GfxPos;
3450 if (player_is_opaque)
3451 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
3453 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3455 if (SHIELD_ON(player))
3457 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
3458 IMG_SHIELD_NORMAL_ACTIVE);
3459 int frame = getGraphicAnimationFrame(graphic, -1);
3461 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3465 /* ----------------------------------------------------------------------- */
3466 /* draw things in front of player (active dynamite or dynabombs) */
3467 /* ----------------------------------------------------------------------- */
3469 if (IS_ACTIVE_BOMB(element))
3471 graphic = el2img(element);
3472 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
3474 if (game.emulation == EMU_SUPAPLEX)
3475 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
3477 DrawGraphicThruMask(sx, sy, graphic, frame);
3480 if (player_is_moving && last_element == EL_EXPLOSION)
3482 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
3483 GfxElement[last_jx][last_jy] : EL_EMPTY);
3484 int graphic = el_act2img(element, ACTION_EXPLODING);
3485 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
3486 int phase = ExplodePhase[last_jx][last_jy] - 1;
3487 int frame = getGraphicAnimationFrame(graphic, phase - delay);
3490 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
3493 /* ----------------------------------------------------------------------- */
3494 /* draw elements the player is just walking/passing through/under */
3495 /* ----------------------------------------------------------------------- */
3497 if (player_is_moving)
3499 /* handle the field the player is leaving ... */
3500 if (IS_ACCESSIBLE_INSIDE(last_element))
3501 DrawLevelField(last_jx, last_jy);
3502 else if (IS_ACCESSIBLE_UNDER(last_element))
3503 DrawLevelFieldThruMask(last_jx, last_jy);
3506 /* do not redraw accessible elements if the player is just pushing them */
3507 if (!player_is_moving || !player->is_pushing)
3509 /* ... and the field the player is entering */
3510 if (IS_ACCESSIBLE_INSIDE(element))
3511 DrawLevelField(jx, jy);
3512 else if (IS_ACCESSIBLE_UNDER(element))
3513 DrawLevelFieldThruMask(jx, jy);
3516 MarkTileDirty(sx, sy);
3519 /* ------------------------------------------------------------------------- */
3521 void WaitForEventToContinue()
3523 boolean still_wait = TRUE;
3525 /* simulate releasing mouse button over last gadget, if still pressed */
3527 HandleGadgets(-1, -1, 0);
3529 button_status = MB_RELEASED;
3543 case EVENT_BUTTONPRESS:
3544 case EVENT_KEYPRESS:
3548 case EVENT_KEYRELEASE:
3549 ClearPlayerAction();
3553 HandleOtherEvents(&event);
3557 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3566 #define MAX_REQUEST_LINES 13
3567 #define MAX_REQUEST_LINE_FONT1_LEN 7
3568 #define MAX_REQUEST_LINE_FONT2_LEN 10
3570 static int RequestHandleEvents(unsigned int req_state)
3572 boolean level_solved = (game_status == GAME_MODE_PLAYING &&
3573 local_player->LevelSolved_GameEnd);
3574 int width = request.width;
3575 int height = request.height;
3579 setRequestPosition(&sx, &sy, FALSE);
3581 button_status = MB_RELEASED;
3583 request_gadget_id = -1;
3590 SetDrawtoField(DRAW_TO_FIELDBUFFER);
3592 HandleGameActions();
3594 SetDrawtoField(DRAW_TO_BACKBUFFER);
3596 if (global.use_envelope_request)
3598 /* copy current state of request area to middle of playfield area */
3599 BlitBitmap(bitmap_db_store_2, drawto, sx, sy, width, height, sx, sy);
3607 while (NextValidEvent(&event))
3611 case EVENT_BUTTONPRESS:
3612 case EVENT_BUTTONRELEASE:
3613 case EVENT_MOTIONNOTIFY:
3617 if (event.type == EVENT_MOTIONNOTIFY)
3622 motion_status = TRUE;
3623 mx = ((MotionEvent *) &event)->x;
3624 my = ((MotionEvent *) &event)->y;
3628 motion_status = FALSE;
3629 mx = ((ButtonEvent *) &event)->x;
3630 my = ((ButtonEvent *) &event)->y;
3631 if (event.type == EVENT_BUTTONPRESS)
3632 button_status = ((ButtonEvent *) &event)->button;
3634 button_status = MB_RELEASED;
3637 /* this sets 'request_gadget_id' */
3638 HandleGadgets(mx, my, button_status);
3640 switch (request_gadget_id)
3642 case TOOL_CTRL_ID_YES:
3645 case TOOL_CTRL_ID_NO:
3648 case TOOL_CTRL_ID_CONFIRM:
3649 result = TRUE | FALSE;
3652 case TOOL_CTRL_ID_PLAYER_1:
3655 case TOOL_CTRL_ID_PLAYER_2:
3658 case TOOL_CTRL_ID_PLAYER_3:
3661 case TOOL_CTRL_ID_PLAYER_4:
3672 case EVENT_KEYPRESS:
3674 Key key = GetEventKey((KeyEvent *)&event, TRUE);
3679 if (req_state & REQ_CONFIRM)
3684 #if defined(TARGET_SDL2)
3691 #if defined(TARGET_SDL2)
3698 HandleKeysDebug(key);
3702 if (req_state & REQ_PLAYER)
3708 case EVENT_KEYRELEASE:
3709 ClearPlayerAction();
3713 HandleOtherEvents(&event);
3718 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3720 int joy = AnyJoystick();
3722 if (joy & JOY_BUTTON_1)
3724 else if (joy & JOY_BUTTON_2)
3730 if (global.use_envelope_request)
3732 /* copy back current state of pressed buttons inside request area */
3733 BlitBitmap(drawto, bitmap_db_store_2, sx, sy, width, height, sx, sy);
3743 static boolean RequestDoor(char *text, unsigned int req_state)
3745 unsigned int old_door_state;
3746 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
3747 int font_nr = FONT_TEXT_2;
3752 if (maxWordLengthInString(text) > MAX_REQUEST_LINE_FONT1_LEN)
3754 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
3755 font_nr = FONT_TEXT_1;
3758 if (game_status == GAME_MODE_PLAYING)
3759 BlitScreenToBitmap(backbuffer);
3761 /* disable deactivated drawing when quick-loading level tape recording */
3762 if (tape.playing && tape.deactivate_display)
3763 TapeDeactivateDisplayOff(TRUE);
3765 SetMouseCursor(CURSOR_DEFAULT);
3767 #if defined(NETWORK_AVALIABLE)
3768 /* pause network game while waiting for request to answer */
3769 if (options.network &&
3770 game_status == GAME_MODE_PLAYING &&
3771 req_state & REQUEST_WAIT_FOR_INPUT)
3772 SendToServer_PausePlaying();
3775 old_door_state = GetDoorState();
3777 /* simulate releasing mouse button over last gadget, if still pressed */
3779 HandleGadgets(-1, -1, 0);
3783 /* draw released gadget before proceeding */
3786 if (old_door_state & DOOR_OPEN_1)
3788 CloseDoor(DOOR_CLOSE_1);
3790 /* save old door content */
3791 BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
3792 0 * DXSIZE, 0, DXSIZE, DYSIZE, 1 * DXSIZE, 0);
3795 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
3796 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3798 /* clear door drawing field */
3799 DrawBackground(DX, DY, DXSIZE, DYSIZE);
3801 /* force DOOR font inside door area */
3802 SetFontStatus(GAME_MODE_PSEUDO_DOOR);
3804 /* write text for request */
3805 for (text_ptr = text, ty = 0; ty < MAX_REQUEST_LINES; ty++)
3807 char text_line[max_request_line_len + 1];
3813 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
3815 tc = *(text_ptr + tx);
3816 // if (!tc || tc == ' ')
3817 if (!tc || tc == ' ' || tc == '?' || tc == '!')
3821 if ((tc == '?' || tc == '!') && tl == 0)
3831 strncpy(text_line, text_ptr, tl);
3834 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
3835 DY + 8 + ty * (getFontHeight(font_nr) + 2),
3836 text_line, font_nr);
3838 text_ptr += tl + (tc == ' ' ? 1 : 0);
3839 // text_ptr += tl + (tc == ' ' || tc == '?' || tc == '!' ? 1 : 0);
3844 if (req_state & REQ_ASK)
3846 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
3847 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
3849 else if (req_state & REQ_CONFIRM)
3851 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
3853 else if (req_state & REQ_PLAYER)
3855 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
3856 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
3857 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
3858 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
3861 /* copy request gadgets to door backbuffer */
3862 BlitBitmap(drawto, bitmap_db_door_1, DX, DY, DXSIZE, DYSIZE, 0, 0);
3864 OpenDoor(DOOR_OPEN_1);
3866 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
3868 if (game_status == GAME_MODE_PLAYING)
3870 SetPanelBackground();
3871 SetDrawBackgroundMask(REDRAW_DOOR_1);
3875 SetDrawBackgroundMask(REDRAW_FIELD);
3881 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3883 // ---------- handle request buttons ----------
3884 result = RequestHandleEvents(req_state);
3888 if (!(req_state & REQ_STAY_OPEN))
3890 CloseDoor(DOOR_CLOSE_1);
3892 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
3893 (req_state & REQ_REOPEN))
3894 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
3899 if (game_status == GAME_MODE_PLAYING)
3901 SetPanelBackground();
3902 SetDrawBackgroundMask(REDRAW_DOOR_1);
3906 SetDrawBackgroundMask(REDRAW_FIELD);
3909 #if defined(NETWORK_AVALIABLE)
3910 /* continue network game after request */
3911 if (options.network &&
3912 game_status == GAME_MODE_PLAYING &&
3913 req_state & REQUEST_WAIT_FOR_INPUT)
3914 SendToServer_ContinuePlaying();
3917 /* restore deactivated drawing when quick-loading level tape recording */
3918 if (tape.playing && tape.deactivate_display)
3919 TapeDeactivateDisplayOn();
3924 static boolean RequestEnvelope(char *text, unsigned int req_state)
3928 if (game_status == GAME_MODE_PLAYING)
3929 BlitScreenToBitmap(backbuffer);
3931 /* disable deactivated drawing when quick-loading level tape recording */
3932 if (tape.playing && tape.deactivate_display)
3933 TapeDeactivateDisplayOff(TRUE);
3935 SetMouseCursor(CURSOR_DEFAULT);
3937 #if defined(NETWORK_AVALIABLE)
3938 /* pause network game while waiting for request to answer */
3939 if (options.network &&
3940 game_status == GAME_MODE_PLAYING &&
3941 req_state & REQUEST_WAIT_FOR_INPUT)
3942 SendToServer_PausePlaying();
3945 /* simulate releasing mouse button over last gadget, if still pressed */
3947 HandleGadgets(-1, -1, 0);
3951 // (replace with setting corresponding request background)
3952 // SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
3953 // SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3955 /* clear door drawing field */
3956 // DrawBackground(DX, DY, DXSIZE, DYSIZE);
3958 ShowEnvelopeRequest(text, req_state, ACTION_OPENING);
3960 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
3962 if (game_status == GAME_MODE_PLAYING)
3964 SetPanelBackground();
3965 SetDrawBackgroundMask(REDRAW_DOOR_1);
3969 SetDrawBackgroundMask(REDRAW_FIELD);
3975 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3977 // ---------- handle request buttons ----------
3978 result = RequestHandleEvents(req_state);
3982 ShowEnvelopeRequest(text, req_state, ACTION_CLOSING);
3986 if (game_status == GAME_MODE_PLAYING)
3988 SetPanelBackground();
3989 SetDrawBackgroundMask(REDRAW_DOOR_1);
3993 SetDrawBackgroundMask(REDRAW_FIELD);
3996 #if defined(NETWORK_AVALIABLE)
3997 /* continue network game after request */
3998 if (options.network &&
3999 game_status == GAME_MODE_PLAYING &&
4000 req_state & REQUEST_WAIT_FOR_INPUT)
4001 SendToServer_ContinuePlaying();
4004 /* restore deactivated drawing when quick-loading level tape recording */
4005 if (tape.playing && tape.deactivate_display)
4006 TapeDeactivateDisplayOn();
4011 boolean Request(char *text, unsigned int req_state)
4013 if (global.use_envelope_request)
4014 return RequestEnvelope(text, req_state);
4016 return RequestDoor(text, req_state);
4019 static int compareDoorPartOrderInfo(const void *object1, const void *object2)
4021 const struct DoorPartOrderInfo *dpo1 = (struct DoorPartOrderInfo *)object1;
4022 const struct DoorPartOrderInfo *dpo2 = (struct DoorPartOrderInfo *)object2;
4025 if (dpo1->sort_priority != dpo2->sort_priority)
4026 compare_result = dpo1->sort_priority - dpo2->sort_priority;
4028 compare_result = dpo1->nr - dpo2->nr;
4030 return compare_result;
4033 void InitGraphicCompatibilityInfo_Doors()
4039 struct DoorInfo *door;
4043 { DOOR_1, IMG_GFX_DOOR_1_PART_1, IMG_GFX_DOOR_1_PART_8, &door_1 },
4044 { DOOR_2, IMG_GFX_DOOR_2_PART_1, IMG_GFX_DOOR_2_PART_8, &door_2 },
4046 { -1, -1, -1, NULL }
4048 struct Rect door_rect_list[] =
4050 { DX, DY, DXSIZE, DYSIZE },
4051 { VX, VY, VXSIZE, VYSIZE }
4055 for (i = 0; doors[i].door_token != -1; i++)
4057 int door_token = doors[i].door_token;
4058 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
4059 int part_1 = doors[i].part_1;
4060 int part_8 = doors[i].part_8;
4061 int part_2 = part_1 + 1;
4062 int part_3 = part_1 + 2;
4063 struct DoorInfo *door = doors[i].door;
4064 struct Rect *door_rect = &door_rect_list[door_index];
4065 boolean door_gfx_redefined = FALSE;
4067 /* check if any door part graphic definitions have been redefined */
4069 for (j = 0; door_part_controls[j].door_token != -1; j++)
4071 struct DoorPartControlInfo *dpc = &door_part_controls[j];
4072 struct FileInfo *fi = getImageListEntryFromImageID(dpc->graphic);
4074 if (dpc->door_token == door_token && fi->redefined)
4075 door_gfx_redefined = TRUE;
4078 /* check for old-style door graphic/animation modifications */
4080 if (!door_gfx_redefined)
4082 if (door->anim_mode & ANIM_STATIC_PANEL)
4084 door->panel.step_xoffset = 0;
4085 door->panel.step_yoffset = 0;
4088 if (door->anim_mode & (ANIM_HORIZONTAL | ANIM_VERTICAL))
4090 struct GraphicInfo *g_part_1 = &graphic_info[part_1];
4091 struct GraphicInfo *g_part_2 = &graphic_info[part_2];
4092 int num_door_steps, num_panel_steps;
4094 /* remove door part graphics other than the two default wings */
4096 for (j = 0; door_part_controls[j].door_token != -1; j++)
4098 struct DoorPartControlInfo *dpc = &door_part_controls[j];
4099 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4101 if (dpc->graphic >= part_3 &&
4102 dpc->graphic <= part_8)
4106 /* set graphics and screen positions of the default wings */
4108 g_part_1->width = door_rect->width;
4109 g_part_1->height = door_rect->height;
4110 g_part_2->width = door_rect->width;
4111 g_part_2->height = door_rect->height;
4112 g_part_2->src_x = door_rect->width;
4113 g_part_2->src_y = g_part_1->src_y;
4115 door->part_2.x = door->part_1.x;
4116 door->part_2.y = door->part_1.y;
4118 if (door->width != -1)
4120 g_part_1->width = door->width;
4121 g_part_2->width = door->width;
4123 // special treatment for graphics and screen position of right wing
4124 g_part_2->src_x += door_rect->width - door->width;
4125 door->part_2.x += door_rect->width - door->width;
4128 if (door->height != -1)
4130 g_part_1->height = door->height;
4131 g_part_2->height = door->height;
4133 // special treatment for graphics and screen position of bottom wing
4134 g_part_2->src_y += door_rect->height - door->height;
4135 door->part_2.y += door_rect->height - door->height;
4138 /* set animation delays for the default wings and panels */
4140 door->part_1.step_delay = door->step_delay;
4141 door->part_2.step_delay = door->step_delay;
4142 door->panel.step_delay = door->step_delay;
4144 /* set animation draw order for the default wings */
4146 door->part_1.sort_priority = 2; /* draw left wing over ... */
4147 door->part_2.sort_priority = 1; /* ... right wing */
4149 /* set animation draw offset for the default wings */
4151 if (door->anim_mode & ANIM_HORIZONTAL)
4153 door->part_1.step_xoffset = door->step_offset;
4154 door->part_1.step_yoffset = 0;
4155 door->part_2.step_xoffset = door->step_offset * -1;
4156 door->part_2.step_yoffset = 0;
4158 num_door_steps = g_part_1->width / door->step_offset;
4160 else // ANIM_VERTICAL
4162 door->part_1.step_xoffset = 0;
4163 door->part_1.step_yoffset = door->step_offset;
4164 door->part_2.step_xoffset = 0;
4165 door->part_2.step_yoffset = door->step_offset * -1;
4167 num_door_steps = g_part_1->height / door->step_offset;
4170 /* set animation draw offset for the default panels */
4172 if (door->step_offset > 1)
4174 num_panel_steps = 2 * door_rect->height / door->step_offset;
4175 door->panel.start_step = num_panel_steps - num_door_steps;
4176 door->panel.start_step_closing = door->panel.start_step;
4180 num_panel_steps = door_rect->height / door->step_offset;
4181 door->panel.start_step = num_panel_steps - num_door_steps / 2;
4182 door->panel.start_step_closing = door->panel.start_step;
4183 door->panel.step_delay *= 2;
4194 for (i = 0; door_part_controls[i].door_token != -1; i++)
4196 struct DoorPartControlInfo *dpc = &door_part_controls[i];
4197 struct DoorPartOrderInfo *dpo = &door_part_order[i];
4199 /* initialize "start_step_opening" and "start_step_closing", if needed */
4200 if (dpc->pos->start_step_opening == 0 &&
4201 dpc->pos->start_step_closing == 0)
4203 // dpc->pos->start_step_opening = dpc->pos->start_step;
4204 dpc->pos->start_step_closing = dpc->pos->start_step;
4207 /* fill structure for door part draw order (sorted below) */
4209 dpo->sort_priority = dpc->pos->sort_priority;
4212 /* sort door part controls according to sort_priority and graphic number */
4213 qsort(door_part_order, MAX_DOOR_PARTS,
4214 sizeof(struct DoorPartOrderInfo), compareDoorPartOrderInfo);
4217 unsigned int OpenDoor(unsigned int door_state)
4219 if (door_state & DOOR_COPY_BACK)
4221 if (door_state & DOOR_OPEN_1)
4222 BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
4223 1 * DXSIZE, 0, DXSIZE, DYSIZE, 0 * DXSIZE, 0);
4225 if (door_state & DOOR_OPEN_2)
4226 BlitBitmap(bitmap_db_door_2, bitmap_db_door_2,
4227 1 * VXSIZE, 0, VXSIZE, VYSIZE, 0 * VXSIZE, 0);
4229 door_state &= ~DOOR_COPY_BACK;
4232 return MoveDoor(door_state);
4235 unsigned int CloseDoor(unsigned int door_state)
4237 unsigned int old_door_state = GetDoorState();
4239 if (!(door_state & DOOR_NO_COPY_BACK))
4241 if (old_door_state & DOOR_OPEN_1)
4242 BlitBitmap(backbuffer, bitmap_db_door_1,
4243 DX, DY, DXSIZE, DYSIZE, 0, 0);
4245 if (old_door_state & DOOR_OPEN_2)
4246 BlitBitmap(backbuffer, bitmap_db_door_2,
4247 VX, VY, VXSIZE, VYSIZE, 0, 0);
4249 door_state &= ~DOOR_NO_COPY_BACK;
4252 return MoveDoor(door_state);
4255 unsigned int GetDoorState()
4257 return MoveDoor(DOOR_GET_STATE);
4260 unsigned int SetDoorState(unsigned int door_state)
4262 return MoveDoor(door_state | DOOR_SET_STATE);
4265 int euclid(int a, int b)
4267 return (b ? euclid(b, a % b) : a);
4270 unsigned int MoveDoor(unsigned int door_state)
4272 struct Rect door_rect_list[] =
4274 { DX, DY, DXSIZE, DYSIZE },
4275 { VX, VY, VXSIZE, VYSIZE }
4277 static int door1 = DOOR_CLOSE_1;
4278 static int door2 = DOOR_CLOSE_2;
4279 unsigned int door_delay = 0;
4280 unsigned int door_delay_value;
4283 if (door_state == DOOR_GET_STATE)
4284 return (door1 | door2);
4286 if (door_state & DOOR_SET_STATE)
4288 if (door_state & DOOR_ACTION_1)
4289 door1 = door_state & DOOR_ACTION_1;
4290 if (door_state & DOOR_ACTION_2)
4291 door2 = door_state & DOOR_ACTION_2;
4293 return (door1 | door2);
4296 if (!(door_state & DOOR_FORCE_REDRAW))
4298 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
4299 door_state &= ~DOOR_OPEN_1;
4300 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
4301 door_state &= ~DOOR_CLOSE_1;
4302 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
4303 door_state &= ~DOOR_OPEN_2;
4304 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
4305 door_state &= ~DOOR_CLOSE_2;
4308 if (global.autoplay_leveldir)
4310 door_state |= DOOR_NO_DELAY;
4311 door_state &= ~DOOR_CLOSE_ALL;
4314 if (game_status == GAME_MODE_EDITOR)
4315 door_state |= DOOR_NO_DELAY;
4317 if (door_state & DOOR_ACTION)
4319 boolean door_panel_drawn[NUM_DOORS];
4320 boolean panel_has_doors[NUM_DOORS];
4321 boolean door_part_skip[MAX_DOOR_PARTS];
4322 boolean door_part_done[MAX_DOOR_PARTS];
4323 boolean door_part_done_all;
4324 int num_steps[MAX_DOOR_PARTS];
4325 int max_move_delay = 0; // delay for complete animations of all doors
4326 int max_step_delay = 0; // delay (ms) between two animation frames
4327 int num_move_steps = 0; // number of animation steps for all doors
4328 int max_move_delay_doors_only = 0; // delay for doors only (no panel)
4329 int num_move_steps_doors_only = 0; // steps for doors only (no panel)
4330 int current_move_delay = 0;
4334 for (i = 0; i < NUM_DOORS; i++)
4335 panel_has_doors[i] = FALSE;
4337 for (i = 0; i < MAX_DOOR_PARTS; i++)
4339 struct DoorPartControlInfo *dpc = &door_part_controls[i];
4340 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4341 int door_token = dpc->door_token;
4343 door_part_done[i] = FALSE;
4344 door_part_skip[i] = (!(door_state & door_token) ||
4348 for (i = 0; i < MAX_DOOR_PARTS; i++)
4350 int nr = door_part_order[i].nr;
4351 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
4352 struct DoorPartPosInfo *pos = dpc->pos;
4353 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4354 int door_token = dpc->door_token;
4355 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
4356 boolean is_panel = DOOR_PART_IS_PANEL(nr);
4357 int step_xoffset = ABS(pos->step_xoffset);
4358 int step_yoffset = ABS(pos->step_yoffset);
4359 int step_delay = pos->step_delay;
4360 int current_door_state = door_state & door_token;
4361 boolean door_opening = ((current_door_state & DOOR_OPEN) != 0);
4362 boolean door_closing = ((current_door_state & DOOR_CLOSE) != 0);
4363 boolean part_opening = (is_panel ? door_closing : door_opening);
4364 int start_step = (part_opening ? pos->start_step_opening :
4365 pos->start_step_closing);
4366 float move_xsize = (step_xoffset ? g->width : 0);
4367 float move_ysize = (step_yoffset ? g->height : 0);
4368 int move_xsteps = (step_xoffset ? ceil(move_xsize / step_xoffset) : 0);
4369 int move_ysteps = (step_yoffset ? ceil(move_ysize / step_yoffset) : 0);
4370 int move_steps = (move_xsteps && move_ysteps ?
4371 MIN(move_xsteps, move_ysteps) :
4372 move_xsteps ? move_xsteps : move_ysteps) - start_step;
4373 int move_delay = move_steps * step_delay;
4375 if (door_part_skip[nr])
4378 max_move_delay = MAX(max_move_delay, move_delay);
4379 max_step_delay = (max_step_delay == 0 ? step_delay :
4380 euclid(max_step_delay, step_delay));
4381 num_steps[nr] = move_steps;
4385 max_move_delay_doors_only = MAX(max_move_delay_doors_only, move_delay);
4387 panel_has_doors[door_index] = TRUE;
4391 max_step_delay = MAX(1, max_step_delay); // prevent division by zero
4393 num_move_steps = max_move_delay / max_step_delay;
4394 num_move_steps_doors_only = max_move_delay_doors_only / max_step_delay;
4396 door_delay_value = max_step_delay;
4398 if ((door_state & DOOR_NO_DELAY) || setup.quick_doors)
4400 start = num_move_steps - 1;
4404 /* opening door sound has priority over simultaneously closing door */
4405 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
4406 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
4407 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
4408 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
4411 for (k = start; k < num_move_steps; k++)
4413 int last_frame = num_move_steps - 1; // last frame of this "for" loop
4415 door_part_done_all = TRUE;
4417 for (i = 0; i < NUM_DOORS; i++)
4418 door_panel_drawn[i] = FALSE;
4420 for (i = 0; i < MAX_DOOR_PARTS; i++)
4422 int nr = door_part_order[i].nr;
4423 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
4424 struct DoorPartPosInfo *pos = dpc->pos;
4425 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4426 int door_token = dpc->door_token;
4427 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
4428 boolean is_panel = DOOR_PART_IS_PANEL(nr);
4429 boolean is_panel_and_door_has_closed = FALSE;
4430 struct Rect *door_rect = &door_rect_list[door_index];
4431 Bitmap *bitmap_db_door = (door_token == DOOR_1 ? bitmap_db_door_1 :
4433 Bitmap *bitmap = (is_panel ? bitmap_db_door : g->bitmap);
4434 int current_door_state = door_state & door_token;
4435 boolean door_opening = ((current_door_state & DOOR_OPEN) != 0);
4436 boolean door_closing = !door_opening;
4437 boolean part_opening = (is_panel ? door_closing : door_opening);
4438 boolean part_closing = !part_opening;
4439 int start_step = (part_opening ? pos->start_step_opening :
4440 pos->start_step_closing);
4441 int step_delay = pos->step_delay;
4442 int step_factor = step_delay / max_step_delay;
4443 int k1 = (step_factor ? k / step_factor + 1 : k);
4444 int k2 = (part_opening ? k1 + start_step : num_steps[nr] - k1);
4445 int kk = MAX(0, k2);
4448 int src_x, src_y, src_xx, src_yy;
4449 int dst_x, dst_y, dst_xx, dst_yy;
4452 if (door_part_skip[nr])
4455 if (!(door_state & door_token))
4463 int k2_door = (door_opening ? k : num_move_steps_doors_only - k - 1);
4464 int kk_door = MAX(0, k2_door);
4465 int sync_frame = kk_door * door_delay_value;
4466 int frame = getGraphicAnimationFrame(dpc->graphic, sync_frame);
4468 getFixedGraphicSource(dpc->graphic, frame, &bitmap,
4469 &g_src_x, &g_src_y);
4474 if (!door_panel_drawn[door_index])
4476 ClearRectangle(drawto, door_rect->x, door_rect->y,
4477 door_rect->width, door_rect->height);
4479 door_panel_drawn[door_index] = TRUE;
4482 // draw opening or closing door parts
4484 if (pos->step_xoffset < 0) // door part on right side
4487 dst_xx = pos->x + ABS(kk * pos->step_xoffset);
4490 if (dst_xx + width > door_rect->width)
4491 width = door_rect->width - dst_xx;
4493 else // door part on left side
4496 dst_xx = pos->x - kk * pos->step_xoffset;
4500 src_xx = ABS(dst_xx);
4504 width = g->width - src_xx;
4506 if (width > door_rect->width)
4507 width = door_rect->width;
4509 // printf("::: k == %d [%d] \n", k, start_step);
4512 if (pos->step_yoffset < 0) // door part on bottom side
4515 dst_yy = pos->y + ABS(kk * pos->step_yoffset);
4518 if (dst_yy + height > door_rect->height)
4519 height = door_rect->height - dst_yy;
4521 else // door part on top side
4524 dst_yy = pos->y - kk * pos->step_yoffset;
4528 src_yy = ABS(dst_yy);
4532 height = g->height - src_yy;
4535 src_x = g_src_x + src_xx;
4536 src_y = g_src_y + src_yy;
4538 dst_x = door_rect->x + dst_xx;
4539 dst_y = door_rect->y + dst_yy;
4541 is_panel_and_door_has_closed =
4544 panel_has_doors[door_index] &&
4545 k >= num_move_steps_doors_only - 1);
4547 if (width >= 0 && width <= g->width &&
4548 height >= 0 && height <= g->height &&
4549 !is_panel_and_door_has_closed)
4551 if (is_panel || !pos->draw_masked)
4552 BlitBitmap(bitmap, drawto, src_x, src_y, width, height,
4555 BlitBitmapMasked(bitmap, drawto, src_x, src_y, width, height,
4559 redraw_mask |= REDRAW_DOOR_FROM_TOKEN(door_token);
4561 if ((part_opening && (width < 0 || height < 0)) ||
4562 (part_closing && (width >= g->width && height >= g->height)))
4563 door_part_done[nr] = TRUE;
4565 // continue door part animations, but not panel after door has closed
4566 if (!door_part_done[nr] && !is_panel_and_door_has_closed)
4567 door_part_done_all = FALSE;
4570 if (!(door_state & DOOR_NO_DELAY))
4574 SkipUntilDelayReached(&door_delay, door_delay_value, &k, last_frame);
4576 current_move_delay += max_step_delay;
4579 if (door_part_done_all)
4584 if (door_state & DOOR_ACTION_1)
4585 door1 = door_state & DOOR_ACTION_1;
4586 if (door_state & DOOR_ACTION_2)
4587 door2 = door_state & DOOR_ACTION_2;
4589 // draw masked border over door area
4590 DrawMaskedBorder(REDRAW_DOOR_1);
4591 DrawMaskedBorder(REDRAW_DOOR_2);
4593 return (door1 | door2);
4596 static boolean useSpecialEditorDoor()
4598 int graphic = IMG_GLOBAL_BORDER_EDITOR;
4599 boolean redefined = getImageListEntryFromImageID(graphic)->redefined;
4601 // do not draw special editor door if editor border defined or redefined
4602 if (graphic_info[graphic].bitmap != NULL || redefined)
4605 // do not draw special editor door if global border defined to be empty
4606 if (graphic_info[IMG_GLOBAL_BORDER].bitmap == NULL)
4609 // do not draw special editor door if viewport definitions do not match
4613 EY + EYSIZE != VY + VYSIZE)
4619 void DrawSpecialEditorDoor()
4621 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
4622 int top_border_width = gfx1->width;
4623 int top_border_height = gfx1->height;
4624 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
4625 int ex = EX - outer_border;
4626 int ey = EY - outer_border;
4627 int vy = VY - outer_border;
4628 int exsize = EXSIZE + 2 * outer_border;
4630 if (!useSpecialEditorDoor())
4633 /* draw bigger level editor toolbox window */
4634 BlitBitmap(gfx1->bitmap, drawto, gfx1->src_x, gfx1->src_y,
4635 top_border_width, top_border_height, ex, ey - top_border_height);
4636 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto, ex, vy,
4637 exsize, EYSIZE - VYSIZE + outer_border, ex, ey);
4639 redraw_mask |= REDRAW_ALL;
4642 void UndrawSpecialEditorDoor()
4644 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
4645 int top_border_width = gfx1->width;
4646 int top_border_height = gfx1->height;
4647 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
4648 int ex = EX - outer_border;
4649 int ey = EY - outer_border;
4650 int ey_top = ey - top_border_height;
4651 int exsize = EXSIZE + 2 * outer_border;
4652 int eysize = EYSIZE + 2 * outer_border;
4654 if (!useSpecialEditorDoor())
4657 /* draw normal tape recorder window */
4658 if (graphic_info[IMG_GLOBAL_BORDER].bitmap)
4660 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
4661 ex, ey_top, top_border_width, top_border_height,
4663 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
4664 ex, ey, exsize, eysize, ex, ey);
4668 // if screen background is set to "[NONE]", clear editor toolbox window
4669 ClearRectangle(drawto, ex, ey_top, top_border_width, top_border_height);
4670 ClearRectangle(drawto, ex, ey, exsize, eysize);
4673 redraw_mask |= REDRAW_ALL;
4677 /* ---------- new tool button stuff ---------------------------------------- */
4682 struct TextPosInfo *pos;
4685 } toolbutton_info[NUM_TOOL_BUTTONS] =
4688 IMG_GFX_REQUEST_BUTTON_YES, &request.button.yes,
4689 TOOL_CTRL_ID_YES, "yes"
4692 IMG_GFX_REQUEST_BUTTON_NO, &request.button.no,
4693 TOOL_CTRL_ID_NO, "no"
4696 IMG_GFX_REQUEST_BUTTON_CONFIRM, &request.button.confirm,
4697 TOOL_CTRL_ID_CONFIRM, "confirm"
4700 IMG_GFX_REQUEST_BUTTON_PLAYER_1, &request.button.player_1,
4701 TOOL_CTRL_ID_PLAYER_1, "player 1"
4704 IMG_GFX_REQUEST_BUTTON_PLAYER_2, &request.button.player_2,
4705 TOOL_CTRL_ID_PLAYER_2, "player 2"
4708 IMG_GFX_REQUEST_BUTTON_PLAYER_3, &request.button.player_3,
4709 TOOL_CTRL_ID_PLAYER_3, "player 3"
4712 IMG_GFX_REQUEST_BUTTON_PLAYER_4, &request.button.player_4,
4713 TOOL_CTRL_ID_PLAYER_4, "player 4"
4717 void CreateToolButtons()
4721 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4723 struct GraphicInfo *gfx = &graphic_info[toolbutton_info[i].graphic];
4724 struct TextPosInfo *pos = toolbutton_info[i].pos;
4725 struct GadgetInfo *gi;
4726 Bitmap *deco_bitmap = None;
4727 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
4728 unsigned int event_mask = GD_EVENT_RELEASED;
4731 int gd_x = gfx->src_x;
4732 int gd_y = gfx->src_y;
4733 int gd_xp = gfx->src_x + gfx->pressed_xoffset;
4734 int gd_yp = gfx->src_y + gfx->pressed_yoffset;
4737 if (global.use_envelope_request)
4738 setRequestPosition(&dx, &dy, TRUE);
4740 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
4742 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
4744 getSizedGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr), 0,
4745 pos->size, &deco_bitmap, &deco_x, &deco_y);
4746 deco_xpos = (gfx->width - pos->size) / 2;
4747 deco_ypos = (gfx->height - pos->size) / 2;
4750 gi = CreateGadget(GDI_CUSTOM_ID, id,
4751 GDI_INFO_TEXT, toolbutton_info[i].infotext,
4752 GDI_X, dx + GDI_ACTIVE_POS(pos->x),
4753 GDI_Y, dy + GDI_ACTIVE_POS(pos->y),
4754 GDI_WIDTH, gfx->width,
4755 GDI_HEIGHT, gfx->height,
4756 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
4757 GDI_STATE, GD_BUTTON_UNPRESSED,
4758 GDI_DESIGN_UNPRESSED, gfx->bitmap, gd_x, gd_y,
4759 GDI_DESIGN_PRESSED, gfx->bitmap, gd_xp, gd_yp,
4760 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
4761 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
4762 GDI_DECORATION_SIZE, pos->size, pos->size,
4763 GDI_DECORATION_SHIFTING, 1, 1,
4764 GDI_DIRECT_DRAW, FALSE,
4765 GDI_EVENT_MASK, event_mask,
4766 GDI_CALLBACK_ACTION, HandleToolButtons,
4770 Error(ERR_EXIT, "cannot create gadget");
4772 tool_gadget[id] = gi;
4776 void FreeToolButtons()
4780 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4781 FreeGadget(tool_gadget[i]);
4784 static void UnmapToolButtons()
4788 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4789 UnmapGadget(tool_gadget[i]);
4792 static void HandleToolButtons(struct GadgetInfo *gi)
4794 request_gadget_id = gi->custom_id;
4797 static struct Mapping_EM_to_RND_object
4800 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
4801 boolean is_backside; /* backside of moving element */
4807 em_object_mapping_list[] =
4810 Xblank, TRUE, FALSE,
4814 Yacid_splash_eB, FALSE, FALSE,
4815 EL_ACID_SPLASH_RIGHT, -1, -1
4818 Yacid_splash_wB, FALSE, FALSE,
4819 EL_ACID_SPLASH_LEFT, -1, -1
4822 #ifdef EM_ENGINE_BAD_ROLL
4824 Xstone_force_e, FALSE, FALSE,
4825 EL_ROCK, -1, MV_BIT_RIGHT
4828 Xstone_force_w, FALSE, FALSE,
4829 EL_ROCK, -1, MV_BIT_LEFT
4832 Xnut_force_e, FALSE, FALSE,
4833 EL_NUT, -1, MV_BIT_RIGHT
4836 Xnut_force_w, FALSE, FALSE,
4837 EL_NUT, -1, MV_BIT_LEFT
4840 Xspring_force_e, FALSE, FALSE,
4841 EL_SPRING, -1, MV_BIT_RIGHT
4844 Xspring_force_w, FALSE, FALSE,
4845 EL_SPRING, -1, MV_BIT_LEFT
4848 Xemerald_force_e, FALSE, FALSE,
4849 EL_EMERALD, -1, MV_BIT_RIGHT
4852 Xemerald_force_w, FALSE, FALSE,
4853 EL_EMERALD, -1, MV_BIT_LEFT
4856 Xdiamond_force_e, FALSE, FALSE,
4857 EL_DIAMOND, -1, MV_BIT_RIGHT
4860 Xdiamond_force_w, FALSE, FALSE,
4861 EL_DIAMOND, -1, MV_BIT_LEFT
4864 Xbomb_force_e, FALSE, FALSE,
4865 EL_BOMB, -1, MV_BIT_RIGHT
4868 Xbomb_force_w, FALSE, FALSE,
4869 EL_BOMB, -1, MV_BIT_LEFT
4871 #endif /* EM_ENGINE_BAD_ROLL */
4874 Xstone, TRUE, FALSE,
4878 Xstone_pause, FALSE, FALSE,
4882 Xstone_fall, FALSE, FALSE,
4886 Ystone_s, FALSE, FALSE,
4887 EL_ROCK, ACTION_FALLING, -1
4890 Ystone_sB, FALSE, TRUE,
4891 EL_ROCK, ACTION_FALLING, -1
4894 Ystone_e, FALSE, FALSE,
4895 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
4898 Ystone_eB, FALSE, TRUE,
4899 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
4902 Ystone_w, FALSE, FALSE,
4903 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
4906 Ystone_wB, FALSE, TRUE,
4907 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
4914 Xnut_pause, FALSE, FALSE,
4918 Xnut_fall, FALSE, FALSE,
4922 Ynut_s, FALSE, FALSE,
4923 EL_NUT, ACTION_FALLING, -1
4926 Ynut_sB, FALSE, TRUE,
4927 EL_NUT, ACTION_FALLING, -1
4930 Ynut_e, FALSE, FALSE,
4931 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
4934 Ynut_eB, FALSE, TRUE,
4935 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
4938 Ynut_w, FALSE, FALSE,
4939 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
4942 Ynut_wB, FALSE, TRUE,
4943 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
4946 Xbug_n, TRUE, FALSE,
4950 Xbug_e, TRUE, FALSE,
4951 EL_BUG_RIGHT, -1, -1
4954 Xbug_s, TRUE, FALSE,
4958 Xbug_w, TRUE, FALSE,
4962 Xbug_gon, FALSE, FALSE,
4966 Xbug_goe, FALSE, FALSE,
4967 EL_BUG_RIGHT, -1, -1
4970 Xbug_gos, FALSE, FALSE,
4974 Xbug_gow, FALSE, FALSE,
4978 Ybug_n, FALSE, FALSE,
4979 EL_BUG, ACTION_MOVING, MV_BIT_UP
4982 Ybug_nB, FALSE, TRUE,
4983 EL_BUG, ACTION_MOVING, MV_BIT_UP
4986 Ybug_e, FALSE, FALSE,
4987 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
4990 Ybug_eB, FALSE, TRUE,
4991 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
4994 Ybug_s, FALSE, FALSE,
4995 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
4998 Ybug_sB, FALSE, TRUE,
4999 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
5002 Ybug_w, FALSE, FALSE,
5003 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
5006 Ybug_wB, FALSE, TRUE,
5007 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
5010 Ybug_w_n, FALSE, FALSE,
5011 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
5014 Ybug_n_e, FALSE, FALSE,
5015 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
5018 Ybug_e_s, FALSE, FALSE,
5019 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
5022 Ybug_s_w, FALSE, FALSE,
5023 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
5026 Ybug_e_n, FALSE, FALSE,
5027 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
5030 Ybug_s_e, FALSE, FALSE,
5031 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
5034 Ybug_w_s, FALSE, FALSE,
5035 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
5038 Ybug_n_w, FALSE, FALSE,
5039 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
5042 Ybug_stone, FALSE, FALSE,
5043 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
5046 Ybug_spring, FALSE, FALSE,
5047 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
5050 Xtank_n, TRUE, FALSE,
5051 EL_SPACESHIP_UP, -1, -1
5054 Xtank_e, TRUE, FALSE,
5055 EL_SPACESHIP_RIGHT, -1, -1
5058 Xtank_s, TRUE, FALSE,
5059 EL_SPACESHIP_DOWN, -1, -1
5062 Xtank_w, TRUE, FALSE,
5063 EL_SPACESHIP_LEFT, -1, -1
5066 Xtank_gon, FALSE, FALSE,
5067 EL_SPACESHIP_UP, -1, -1
5070 Xtank_goe, FALSE, FALSE,
5071 EL_SPACESHIP_RIGHT, -1, -1
5074 Xtank_gos, FALSE, FALSE,
5075 EL_SPACESHIP_DOWN, -1, -1
5078 Xtank_gow, FALSE, FALSE,
5079 EL_SPACESHIP_LEFT, -1, -1
5082 Ytank_n, FALSE, FALSE,
5083 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
5086 Ytank_nB, FALSE, TRUE,
5087 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
5090 Ytank_e, FALSE, FALSE,
5091 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
5094 Ytank_eB, FALSE, TRUE,
5095 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
5098 Ytank_s, FALSE, FALSE,
5099 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
5102 Ytank_sB, FALSE, TRUE,
5103 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
5106 Ytank_w, FALSE, FALSE,
5107 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
5110 Ytank_wB, FALSE, TRUE,
5111 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
5114 Ytank_w_n, FALSE, FALSE,
5115 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
5118 Ytank_n_e, FALSE, FALSE,
5119 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
5122 Ytank_e_s, FALSE, FALSE,
5123 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
5126 Ytank_s_w, FALSE, FALSE,
5127 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
5130 Ytank_e_n, FALSE, FALSE,
5131 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
5134 Ytank_s_e, FALSE, FALSE,
5135 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
5138 Ytank_w_s, FALSE, FALSE,
5139 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
5142 Ytank_n_w, FALSE, FALSE,
5143 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
5146 Ytank_stone, FALSE, FALSE,
5147 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
5150 Ytank_spring, FALSE, FALSE,
5151 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
5154 Xandroid, TRUE, FALSE,
5155 EL_EMC_ANDROID, ACTION_ACTIVE, -1
5158 Xandroid_1_n, FALSE, FALSE,
5159 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
5162 Xandroid_2_n, FALSE, FALSE,
5163 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
5166 Xandroid_1_e, FALSE, FALSE,
5167 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
5170 Xandroid_2_e, FALSE, FALSE,
5171 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
5174 Xandroid_1_w, FALSE, FALSE,
5175 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
5178 Xandroid_2_w, FALSE, FALSE,
5179 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
5182 Xandroid_1_s, FALSE, FALSE,
5183 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
5186 Xandroid_2_s, FALSE, FALSE,
5187 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
5190 Yandroid_n, FALSE, FALSE,
5191 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
5194 Yandroid_nB, FALSE, TRUE,
5195 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
5198 Yandroid_ne, FALSE, FALSE,
5199 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
5202 Yandroid_neB, FALSE, TRUE,
5203 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
5206 Yandroid_e, FALSE, FALSE,
5207 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
5210 Yandroid_eB, FALSE, TRUE,
5211 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
5214 Yandroid_se, FALSE, FALSE,
5215 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
5218 Yandroid_seB, FALSE, TRUE,
5219 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
5222 Yandroid_s, FALSE, FALSE,
5223 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
5226 Yandroid_sB, FALSE, TRUE,
5227 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
5230 Yandroid_sw, FALSE, FALSE,
5231 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
5234 Yandroid_swB, FALSE, TRUE,
5235 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
5238 Yandroid_w, FALSE, FALSE,
5239 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
5242 Yandroid_wB, FALSE, TRUE,
5243 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
5246 Yandroid_nw, FALSE, FALSE,
5247 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
5250 Yandroid_nwB, FALSE, TRUE,
5251 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
5254 Xspring, TRUE, FALSE,
5258 Xspring_pause, FALSE, FALSE,
5262 Xspring_e, FALSE, FALSE,
5266 Xspring_w, FALSE, FALSE,
5270 Xspring_fall, FALSE, FALSE,
5274 Yspring_s, FALSE, FALSE,
5275 EL_SPRING, ACTION_FALLING, -1
5278 Yspring_sB, FALSE, TRUE,
5279 EL_SPRING, ACTION_FALLING, -1
5282 Yspring_e, FALSE, FALSE,
5283 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
5286 Yspring_eB, FALSE, TRUE,
5287 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
5290 Yspring_w, FALSE, FALSE,
5291 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
5294 Yspring_wB, FALSE, TRUE,
5295 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
5298 Yspring_kill_e, FALSE, FALSE,
5299 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
5302 Yspring_kill_eB, FALSE, TRUE,
5303 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
5306 Yspring_kill_w, FALSE, FALSE,
5307 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
5310 Yspring_kill_wB, FALSE, TRUE,
5311 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
5314 Xeater_n, TRUE, FALSE,
5315 EL_YAMYAM_UP, -1, -1
5318 Xeater_e, TRUE, FALSE,
5319 EL_YAMYAM_RIGHT, -1, -1
5322 Xeater_w, TRUE, FALSE,
5323 EL_YAMYAM_LEFT, -1, -1
5326 Xeater_s, TRUE, FALSE,
5327 EL_YAMYAM_DOWN, -1, -1
5330 Yeater_n, FALSE, FALSE,
5331 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
5334 Yeater_nB, FALSE, TRUE,
5335 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
5338 Yeater_e, FALSE, FALSE,
5339 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
5342 Yeater_eB, FALSE, TRUE,
5343 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
5346 Yeater_s, FALSE, FALSE,
5347 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
5350 Yeater_sB, FALSE, TRUE,
5351 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
5354 Yeater_w, FALSE, FALSE,
5355 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
5358 Yeater_wB, FALSE, TRUE,
5359 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
5362 Yeater_stone, FALSE, FALSE,
5363 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
5366 Yeater_spring, FALSE, FALSE,
5367 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
5370 Xalien, TRUE, FALSE,
5374 Xalien_pause, FALSE, FALSE,
5378 Yalien_n, FALSE, FALSE,
5379 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
5382 Yalien_nB, FALSE, TRUE,
5383 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
5386 Yalien_e, FALSE, FALSE,
5387 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
5390 Yalien_eB, FALSE, TRUE,
5391 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
5394 Yalien_s, FALSE, FALSE,
5395 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
5398 Yalien_sB, FALSE, TRUE,
5399 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
5402 Yalien_w, FALSE, FALSE,
5403 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
5406 Yalien_wB, FALSE, TRUE,
5407 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
5410 Yalien_stone, FALSE, FALSE,
5411 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
5414 Yalien_spring, FALSE, FALSE,
5415 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
5418 Xemerald, TRUE, FALSE,
5422 Xemerald_pause, FALSE, FALSE,
5426 Xemerald_fall, FALSE, FALSE,
5430 Xemerald_shine, FALSE, FALSE,
5431 EL_EMERALD, ACTION_TWINKLING, -1
5434 Yemerald_s, FALSE, FALSE,
5435 EL_EMERALD, ACTION_FALLING, -1
5438 Yemerald_sB, FALSE, TRUE,
5439 EL_EMERALD, ACTION_FALLING, -1
5442 Yemerald_e, FALSE, FALSE,
5443 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
5446 Yemerald_eB, FALSE, TRUE,
5447 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
5450 Yemerald_w, FALSE, FALSE,
5451 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
5454 Yemerald_wB, FALSE, TRUE,
5455 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
5458 Yemerald_eat, FALSE, FALSE,
5459 EL_EMERALD, ACTION_COLLECTING, -1
5462 Yemerald_stone, FALSE, FALSE,
5463 EL_NUT, ACTION_BREAKING, -1
5466 Xdiamond, TRUE, FALSE,
5470 Xdiamond_pause, FALSE, FALSE,
5474 Xdiamond_fall, FALSE, FALSE,
5478 Xdiamond_shine, FALSE, FALSE,
5479 EL_DIAMOND, ACTION_TWINKLING, -1
5482 Ydiamond_s, FALSE, FALSE,
5483 EL_DIAMOND, ACTION_FALLING, -1
5486 Ydiamond_sB, FALSE, TRUE,
5487 EL_DIAMOND, ACTION_FALLING, -1
5490 Ydiamond_e, FALSE, FALSE,
5491 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
5494 Ydiamond_eB, FALSE, TRUE,
5495 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
5498 Ydiamond_w, FALSE, FALSE,
5499 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
5502 Ydiamond_wB, FALSE, TRUE,
5503 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
5506 Ydiamond_eat, FALSE, FALSE,
5507 EL_DIAMOND, ACTION_COLLECTING, -1
5510 Ydiamond_stone, FALSE, FALSE,
5511 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
5514 Xdrip_fall, TRUE, FALSE,
5515 EL_AMOEBA_DROP, -1, -1
5518 Xdrip_stretch, FALSE, FALSE,
5519 EL_AMOEBA_DROP, ACTION_FALLING, -1
5522 Xdrip_stretchB, FALSE, TRUE,
5523 EL_AMOEBA_DROP, ACTION_FALLING, -1
5526 Xdrip_eat, FALSE, FALSE,
5527 EL_AMOEBA_DROP, ACTION_GROWING, -1
5530 Ydrip_s1, FALSE, FALSE,
5531 EL_AMOEBA_DROP, ACTION_FALLING, -1
5534 Ydrip_s1B, FALSE, TRUE,
5535 EL_AMOEBA_DROP, ACTION_FALLING, -1
5538 Ydrip_s2, FALSE, FALSE,
5539 EL_AMOEBA_DROP, ACTION_FALLING, -1
5542 Ydrip_s2B, FALSE, TRUE,
5543 EL_AMOEBA_DROP, ACTION_FALLING, -1
5550 Xbomb_pause, FALSE, FALSE,
5554 Xbomb_fall, FALSE, FALSE,
5558 Ybomb_s, FALSE, FALSE,
5559 EL_BOMB, ACTION_FALLING, -1
5562 Ybomb_sB, FALSE, TRUE,
5563 EL_BOMB, ACTION_FALLING, -1
5566 Ybomb_e, FALSE, FALSE,
5567 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
5570 Ybomb_eB, FALSE, TRUE,
5571 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
5574 Ybomb_w, FALSE, FALSE,
5575 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
5578 Ybomb_wB, FALSE, TRUE,
5579 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
5582 Ybomb_eat, FALSE, FALSE,
5583 EL_BOMB, ACTION_ACTIVATING, -1
5586 Xballoon, TRUE, FALSE,
5590 Yballoon_n, FALSE, FALSE,
5591 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
5594 Yballoon_nB, FALSE, TRUE,
5595 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
5598 Yballoon_e, FALSE, FALSE,
5599 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
5602 Yballoon_eB, FALSE, TRUE,
5603 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
5606 Yballoon_s, FALSE, FALSE,
5607 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
5610 Yballoon_sB, FALSE, TRUE,
5611 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
5614 Yballoon_w, FALSE, FALSE,
5615 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
5618 Yballoon_wB, FALSE, TRUE,
5619 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
5622 Xgrass, TRUE, FALSE,
5623 EL_EMC_GRASS, -1, -1
5626 Ygrass_nB, FALSE, FALSE,
5627 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
5630 Ygrass_eB, FALSE, FALSE,
5631 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
5634 Ygrass_sB, FALSE, FALSE,
5635 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
5638 Ygrass_wB, FALSE, FALSE,
5639 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
5646 Ydirt_nB, FALSE, FALSE,
5647 EL_SAND, ACTION_DIGGING, MV_BIT_UP
5650 Ydirt_eB, FALSE, FALSE,
5651 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
5654 Ydirt_sB, FALSE, FALSE,
5655 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
5658 Ydirt_wB, FALSE, FALSE,
5659 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
5662 Xacid_ne, TRUE, FALSE,
5663 EL_ACID_POOL_TOPRIGHT, -1, -1
5666 Xacid_se, TRUE, FALSE,
5667 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
5670 Xacid_s, TRUE, FALSE,
5671 EL_ACID_POOL_BOTTOM, -1, -1
5674 Xacid_sw, TRUE, FALSE,
5675 EL_ACID_POOL_BOTTOMLEFT, -1, -1
5678 Xacid_nw, TRUE, FALSE,
5679 EL_ACID_POOL_TOPLEFT, -1, -1
5682 Xacid_1, TRUE, FALSE,
5686 Xacid_2, FALSE, FALSE,
5690 Xacid_3, FALSE, FALSE,
5694 Xacid_4, FALSE, FALSE,
5698 Xacid_5, FALSE, FALSE,
5702 Xacid_6, FALSE, FALSE,
5706 Xacid_7, FALSE, FALSE,
5710 Xacid_8, FALSE, FALSE,
5714 Xball_1, TRUE, FALSE,
5715 EL_EMC_MAGIC_BALL, -1, -1
5718 Xball_1B, FALSE, FALSE,
5719 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5722 Xball_2, FALSE, FALSE,
5723 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5726 Xball_2B, FALSE, FALSE,
5727 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5730 Yball_eat, FALSE, FALSE,
5731 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
5734 Ykey_1_eat, FALSE, FALSE,
5735 EL_EM_KEY_1, ACTION_COLLECTING, -1
5738 Ykey_2_eat, FALSE, FALSE,
5739 EL_EM_KEY_2, ACTION_COLLECTING, -1
5742 Ykey_3_eat, FALSE, FALSE,
5743 EL_EM_KEY_3, ACTION_COLLECTING, -1
5746 Ykey_4_eat, FALSE, FALSE,
5747 EL_EM_KEY_4, ACTION_COLLECTING, -1
5750 Ykey_5_eat, FALSE, FALSE,
5751 EL_EMC_KEY_5, ACTION_COLLECTING, -1
5754 Ykey_6_eat, FALSE, FALSE,
5755 EL_EMC_KEY_6, ACTION_COLLECTING, -1
5758 Ykey_7_eat, FALSE, FALSE,
5759 EL_EMC_KEY_7, ACTION_COLLECTING, -1
5762 Ykey_8_eat, FALSE, FALSE,
5763 EL_EMC_KEY_8, ACTION_COLLECTING, -1
5766 Ylenses_eat, FALSE, FALSE,
5767 EL_EMC_LENSES, ACTION_COLLECTING, -1
5770 Ymagnify_eat, FALSE, FALSE,
5771 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
5774 Ygrass_eat, FALSE, FALSE,
5775 EL_EMC_GRASS, ACTION_SNAPPING, -1
5778 Ydirt_eat, FALSE, FALSE,
5779 EL_SAND, ACTION_SNAPPING, -1
5782 Xgrow_ns, TRUE, FALSE,
5783 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
5786 Ygrow_ns_eat, FALSE, FALSE,
5787 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
5790 Xgrow_ew, TRUE, FALSE,
5791 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
5794 Ygrow_ew_eat, FALSE, FALSE,
5795 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
5798 Xwonderwall, TRUE, FALSE,
5799 EL_MAGIC_WALL, -1, -1
5802 XwonderwallB, FALSE, FALSE,
5803 EL_MAGIC_WALL, ACTION_ACTIVE, -1
5806 Xamoeba_1, TRUE, FALSE,
5807 EL_AMOEBA_DRY, ACTION_OTHER, -1
5810 Xamoeba_2, FALSE, FALSE,
5811 EL_AMOEBA_DRY, ACTION_OTHER, -1
5814 Xamoeba_3, FALSE, FALSE,
5815 EL_AMOEBA_DRY, ACTION_OTHER, -1
5818 Xamoeba_4, FALSE, FALSE,
5819 EL_AMOEBA_DRY, ACTION_OTHER, -1
5822 Xamoeba_5, TRUE, FALSE,
5823 EL_AMOEBA_WET, ACTION_OTHER, -1
5826 Xamoeba_6, FALSE, FALSE,
5827 EL_AMOEBA_WET, ACTION_OTHER, -1
5830 Xamoeba_7, FALSE, FALSE,
5831 EL_AMOEBA_WET, ACTION_OTHER, -1
5834 Xamoeba_8, FALSE, FALSE,
5835 EL_AMOEBA_WET, ACTION_OTHER, -1
5838 Xdoor_1, TRUE, FALSE,
5839 EL_EM_GATE_1, -1, -1
5842 Xdoor_2, TRUE, FALSE,
5843 EL_EM_GATE_2, -1, -1
5846 Xdoor_3, TRUE, FALSE,
5847 EL_EM_GATE_3, -1, -1
5850 Xdoor_4, TRUE, FALSE,
5851 EL_EM_GATE_4, -1, -1
5854 Xdoor_5, TRUE, FALSE,
5855 EL_EMC_GATE_5, -1, -1
5858 Xdoor_6, TRUE, FALSE,
5859 EL_EMC_GATE_6, -1, -1
5862 Xdoor_7, TRUE, FALSE,
5863 EL_EMC_GATE_7, -1, -1
5866 Xdoor_8, TRUE, FALSE,
5867 EL_EMC_GATE_8, -1, -1
5870 Xkey_1, TRUE, FALSE,
5874 Xkey_2, TRUE, FALSE,
5878 Xkey_3, TRUE, FALSE,
5882 Xkey_4, TRUE, FALSE,
5886 Xkey_5, TRUE, FALSE,
5887 EL_EMC_KEY_5, -1, -1
5890 Xkey_6, TRUE, FALSE,
5891 EL_EMC_KEY_6, -1, -1
5894 Xkey_7, TRUE, FALSE,
5895 EL_EMC_KEY_7, -1, -1
5898 Xkey_8, TRUE, FALSE,
5899 EL_EMC_KEY_8, -1, -1
5902 Xwind_n, TRUE, FALSE,
5903 EL_BALLOON_SWITCH_UP, -1, -1
5906 Xwind_e, TRUE, FALSE,
5907 EL_BALLOON_SWITCH_RIGHT, -1, -1
5910 Xwind_s, TRUE, FALSE,
5911 EL_BALLOON_SWITCH_DOWN, -1, -1
5914 Xwind_w, TRUE, FALSE,
5915 EL_BALLOON_SWITCH_LEFT, -1, -1
5918 Xwind_nesw, TRUE, FALSE,
5919 EL_BALLOON_SWITCH_ANY, -1, -1
5922 Xwind_stop, TRUE, FALSE,
5923 EL_BALLOON_SWITCH_NONE, -1, -1
5927 EL_EM_EXIT_CLOSED, -1, -1
5930 Xexit_1, TRUE, FALSE,
5931 EL_EM_EXIT_OPEN, -1, -1
5934 Xexit_2, FALSE, FALSE,
5935 EL_EM_EXIT_OPEN, -1, -1
5938 Xexit_3, FALSE, FALSE,
5939 EL_EM_EXIT_OPEN, -1, -1
5942 Xdynamite, TRUE, FALSE,
5943 EL_EM_DYNAMITE, -1, -1
5946 Ydynamite_eat, FALSE, FALSE,
5947 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
5950 Xdynamite_1, TRUE, FALSE,
5951 EL_EM_DYNAMITE_ACTIVE, -1, -1
5954 Xdynamite_2, FALSE, FALSE,
5955 EL_EM_DYNAMITE_ACTIVE, -1, -1
5958 Xdynamite_3, FALSE, FALSE,
5959 EL_EM_DYNAMITE_ACTIVE, -1, -1
5962 Xdynamite_4, FALSE, FALSE,
5963 EL_EM_DYNAMITE_ACTIVE, -1, -1
5966 Xbumper, TRUE, FALSE,
5967 EL_EMC_SPRING_BUMPER, -1, -1
5970 XbumperB, FALSE, FALSE,
5971 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
5974 Xwheel, TRUE, FALSE,
5975 EL_ROBOT_WHEEL, -1, -1
5978 XwheelB, FALSE, FALSE,
5979 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
5982 Xswitch, TRUE, FALSE,
5983 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
5986 XswitchB, FALSE, FALSE,
5987 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
5991 EL_QUICKSAND_EMPTY, -1, -1
5994 Xsand_stone, TRUE, FALSE,
5995 EL_QUICKSAND_FULL, -1, -1
5998 Xsand_stonein_1, FALSE, TRUE,
5999 EL_ROCK, ACTION_FILLING, -1
6002 Xsand_stonein_2, FALSE, TRUE,
6003 EL_ROCK, ACTION_FILLING, -1
6006 Xsand_stonein_3, FALSE, TRUE,
6007 EL_ROCK, ACTION_FILLING, -1
6010 Xsand_stonein_4, FALSE, TRUE,
6011 EL_ROCK, ACTION_FILLING, -1
6014 Xsand_stonesand_1, FALSE, FALSE,
6015 EL_QUICKSAND_EMPTYING, -1, -1
6018 Xsand_stonesand_2, FALSE, FALSE,
6019 EL_QUICKSAND_EMPTYING, -1, -1
6022 Xsand_stonesand_3, FALSE, FALSE,
6023 EL_QUICKSAND_EMPTYING, -1, -1
6026 Xsand_stonesand_4, FALSE, FALSE,
6027 EL_QUICKSAND_EMPTYING, -1, -1
6030 Xsand_stonesand_quickout_1, FALSE, FALSE,
6031 EL_QUICKSAND_EMPTYING, -1, -1
6034 Xsand_stonesand_quickout_2, FALSE, FALSE,
6035 EL_QUICKSAND_EMPTYING, -1, -1
6038 Xsand_stoneout_1, FALSE, FALSE,
6039 EL_ROCK, ACTION_EMPTYING, -1
6042 Xsand_stoneout_2, FALSE, FALSE,
6043 EL_ROCK, ACTION_EMPTYING, -1
6046 Xsand_sandstone_1, FALSE, FALSE,
6047 EL_QUICKSAND_FILLING, -1, -1
6050 Xsand_sandstone_2, FALSE, FALSE,
6051 EL_QUICKSAND_FILLING, -1, -1
6054 Xsand_sandstone_3, FALSE, FALSE,
6055 EL_QUICKSAND_FILLING, -1, -1
6058 Xsand_sandstone_4, FALSE, FALSE,
6059 EL_QUICKSAND_FILLING, -1, -1
6062 Xplant, TRUE, FALSE,
6063 EL_EMC_PLANT, -1, -1
6066 Yplant, FALSE, FALSE,
6067 EL_EMC_PLANT, -1, -1
6070 Xlenses, TRUE, FALSE,
6071 EL_EMC_LENSES, -1, -1
6074 Xmagnify, TRUE, FALSE,
6075 EL_EMC_MAGNIFIER, -1, -1
6078 Xdripper, TRUE, FALSE,
6079 EL_EMC_DRIPPER, -1, -1
6082 XdripperB, FALSE, FALSE,
6083 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
6086 Xfake_blank, TRUE, FALSE,
6087 EL_INVISIBLE_WALL, -1, -1
6090 Xfake_blankB, FALSE, FALSE,
6091 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
6094 Xfake_grass, TRUE, FALSE,
6095 EL_EMC_FAKE_GRASS, -1, -1
6098 Xfake_grassB, FALSE, FALSE,
6099 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
6102 Xfake_door_1, TRUE, FALSE,
6103 EL_EM_GATE_1_GRAY, -1, -1
6106 Xfake_door_2, TRUE, FALSE,
6107 EL_EM_GATE_2_GRAY, -1, -1
6110 Xfake_door_3, TRUE, FALSE,
6111 EL_EM_GATE_3_GRAY, -1, -1
6114 Xfake_door_4, TRUE, FALSE,
6115 EL_EM_GATE_4_GRAY, -1, -1
6118 Xfake_door_5, TRUE, FALSE,
6119 EL_EMC_GATE_5_GRAY, -1, -1
6122 Xfake_door_6, TRUE, FALSE,
6123 EL_EMC_GATE_6_GRAY, -1, -1
6126 Xfake_door_7, TRUE, FALSE,
6127 EL_EMC_GATE_7_GRAY, -1, -1
6130 Xfake_door_8, TRUE, FALSE,
6131 EL_EMC_GATE_8_GRAY, -1, -1
6134 Xfake_acid_1, TRUE, FALSE,
6135 EL_EMC_FAKE_ACID, -1, -1
6138 Xfake_acid_2, FALSE, FALSE,
6139 EL_EMC_FAKE_ACID, -1, -1
6142 Xfake_acid_3, FALSE, FALSE,
6143 EL_EMC_FAKE_ACID, -1, -1
6146 Xfake_acid_4, FALSE, FALSE,
6147 EL_EMC_FAKE_ACID, -1, -1
6150 Xfake_acid_5, FALSE, FALSE,
6151 EL_EMC_FAKE_ACID, -1, -1
6154 Xfake_acid_6, FALSE, FALSE,
6155 EL_EMC_FAKE_ACID, -1, -1
6158 Xfake_acid_7, FALSE, FALSE,
6159 EL_EMC_FAKE_ACID, -1, -1
6162 Xfake_acid_8, FALSE, FALSE,
6163 EL_EMC_FAKE_ACID, -1, -1
6166 Xsteel_1, TRUE, FALSE,
6167 EL_STEELWALL, -1, -1
6170 Xsteel_2, TRUE, FALSE,
6171 EL_EMC_STEELWALL_2, -1, -1
6174 Xsteel_3, TRUE, FALSE,
6175 EL_EMC_STEELWALL_3, -1, -1
6178 Xsteel_4, TRUE, FALSE,
6179 EL_EMC_STEELWALL_4, -1, -1
6182 Xwall_1, TRUE, FALSE,
6186 Xwall_2, TRUE, FALSE,
6187 EL_EMC_WALL_14, -1, -1
6190 Xwall_3, TRUE, FALSE,
6191 EL_EMC_WALL_15, -1, -1
6194 Xwall_4, TRUE, FALSE,
6195 EL_EMC_WALL_16, -1, -1
6198 Xround_wall_1, TRUE, FALSE,
6199 EL_WALL_SLIPPERY, -1, -1
6202 Xround_wall_2, TRUE, FALSE,
6203 EL_EMC_WALL_SLIPPERY_2, -1, -1
6206 Xround_wall_3, TRUE, FALSE,
6207 EL_EMC_WALL_SLIPPERY_3, -1, -1
6210 Xround_wall_4, TRUE, FALSE,
6211 EL_EMC_WALL_SLIPPERY_4, -1, -1
6214 Xdecor_1, TRUE, FALSE,
6215 EL_EMC_WALL_8, -1, -1
6218 Xdecor_2, TRUE, FALSE,
6219 EL_EMC_WALL_6, -1, -1
6222 Xdecor_3, TRUE, FALSE,
6223 EL_EMC_WALL_4, -1, -1
6226 Xdecor_4, TRUE, FALSE,
6227 EL_EMC_WALL_7, -1, -1
6230 Xdecor_5, TRUE, FALSE,
6231 EL_EMC_WALL_5, -1, -1
6234 Xdecor_6, TRUE, FALSE,
6235 EL_EMC_WALL_9, -1, -1
6238 Xdecor_7, TRUE, FALSE,
6239 EL_EMC_WALL_10, -1, -1
6242 Xdecor_8, TRUE, FALSE,
6243 EL_EMC_WALL_1, -1, -1
6246 Xdecor_9, TRUE, FALSE,
6247 EL_EMC_WALL_2, -1, -1
6250 Xdecor_10, TRUE, FALSE,
6251 EL_EMC_WALL_3, -1, -1
6254 Xdecor_11, TRUE, FALSE,
6255 EL_EMC_WALL_11, -1, -1
6258 Xdecor_12, TRUE, FALSE,
6259 EL_EMC_WALL_12, -1, -1
6262 Xalpha_0, TRUE, FALSE,
6263 EL_CHAR('0'), -1, -1
6266 Xalpha_1, TRUE, FALSE,
6267 EL_CHAR('1'), -1, -1
6270 Xalpha_2, TRUE, FALSE,
6271 EL_CHAR('2'), -1, -1
6274 Xalpha_3, TRUE, FALSE,
6275 EL_CHAR('3'), -1, -1
6278 Xalpha_4, TRUE, FALSE,
6279 EL_CHAR('4'), -1, -1
6282 Xalpha_5, TRUE, FALSE,
6283 EL_CHAR('5'), -1, -1
6286 Xalpha_6, TRUE, FALSE,
6287 EL_CHAR('6'), -1, -1
6290 Xalpha_7, TRUE, FALSE,
6291 EL_CHAR('7'), -1, -1
6294 Xalpha_8, TRUE, FALSE,
6295 EL_CHAR('8'), -1, -1
6298 Xalpha_9, TRUE, FALSE,
6299 EL_CHAR('9'), -1, -1
6302 Xalpha_excla, TRUE, FALSE,
6303 EL_CHAR('!'), -1, -1
6306 Xalpha_quote, TRUE, FALSE,
6307 EL_CHAR('"'), -1, -1
6310 Xalpha_comma, TRUE, FALSE,
6311 EL_CHAR(','), -1, -1
6314 Xalpha_minus, TRUE, FALSE,
6315 EL_CHAR('-'), -1, -1
6318 Xalpha_perio, TRUE, FALSE,
6319 EL_CHAR('.'), -1, -1
6322 Xalpha_colon, TRUE, FALSE,
6323 EL_CHAR(':'), -1, -1
6326 Xalpha_quest, TRUE, FALSE,
6327 EL_CHAR('?'), -1, -1
6330 Xalpha_a, TRUE, FALSE,
6331 EL_CHAR('A'), -1, -1
6334 Xalpha_b, TRUE, FALSE,
6335 EL_CHAR('B'), -1, -1
6338 Xalpha_c, TRUE, FALSE,
6339 EL_CHAR('C'), -1, -1
6342 Xalpha_d, TRUE, FALSE,
6343 EL_CHAR('D'), -1, -1
6346 Xalpha_e, TRUE, FALSE,
6347 EL_CHAR('E'), -1, -1
6350 Xalpha_f, TRUE, FALSE,
6351 EL_CHAR('F'), -1, -1
6354 Xalpha_g, TRUE, FALSE,
6355 EL_CHAR('G'), -1, -1
6358 Xalpha_h, TRUE, FALSE,
6359 EL_CHAR('H'), -1, -1
6362 Xalpha_i, TRUE, FALSE,
6363 EL_CHAR('I'), -1, -1
6366 Xalpha_j, TRUE, FALSE,
6367 EL_CHAR('J'), -1, -1
6370 Xalpha_k, TRUE, FALSE,
6371 EL_CHAR('K'), -1, -1
6374 Xalpha_l, TRUE, FALSE,
6375 EL_CHAR('L'), -1, -1
6378 Xalpha_m, TRUE, FALSE,
6379 EL_CHAR('M'), -1, -1
6382 Xalpha_n, TRUE, FALSE,
6383 EL_CHAR('N'), -1, -1
6386 Xalpha_o, TRUE, FALSE,
6387 EL_CHAR('O'), -1, -1
6390 Xalpha_p, TRUE, FALSE,
6391 EL_CHAR('P'), -1, -1
6394 Xalpha_q, TRUE, FALSE,
6395 EL_CHAR('Q'), -1, -1
6398 Xalpha_r, TRUE, FALSE,
6399 EL_CHAR('R'), -1, -1
6402 Xalpha_s, TRUE, FALSE,
6403 EL_CHAR('S'), -1, -1
6406 Xalpha_t, TRUE, FALSE,
6407 EL_CHAR('T'), -1, -1
6410 Xalpha_u, TRUE, FALSE,
6411 EL_CHAR('U'), -1, -1
6414 Xalpha_v, TRUE, FALSE,
6415 EL_CHAR('V'), -1, -1
6418 Xalpha_w, TRUE, FALSE,
6419 EL_CHAR('W'), -1, -1
6422 Xalpha_x, TRUE, FALSE,
6423 EL_CHAR('X'), -1, -1
6426 Xalpha_y, TRUE, FALSE,
6427 EL_CHAR('Y'), -1, -1
6430 Xalpha_z, TRUE, FALSE,
6431 EL_CHAR('Z'), -1, -1
6434 Xalpha_arrow_e, TRUE, FALSE,
6435 EL_CHAR('>'), -1, -1
6438 Xalpha_arrow_w, TRUE, FALSE,
6439 EL_CHAR('<'), -1, -1
6442 Xalpha_copyr, TRUE, FALSE,
6443 EL_CHAR(CHAR_BYTE_COPYRIGHT), -1, -1
6447 Xboom_bug, FALSE, FALSE,
6448 EL_BUG, ACTION_EXPLODING, -1
6451 Xboom_bomb, FALSE, FALSE,
6452 EL_BOMB, ACTION_EXPLODING, -1
6455 Xboom_android, FALSE, FALSE,
6456 EL_EMC_ANDROID, ACTION_OTHER, -1
6459 Xboom_1, FALSE, FALSE,
6460 EL_DEFAULT, ACTION_EXPLODING, -1
6463 Xboom_2, FALSE, FALSE,
6464 EL_DEFAULT, ACTION_EXPLODING, -1
6467 Znormal, FALSE, FALSE,
6471 Zdynamite, FALSE, FALSE,
6475 Zplayer, FALSE, FALSE,
6479 ZBORDER, FALSE, FALSE,
6489 static struct Mapping_EM_to_RND_player
6498 em_player_mapping_list[] =
6502 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
6506 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
6510 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
6514 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
6518 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
6522 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
6526 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
6530 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
6534 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
6538 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
6542 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
6546 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
6550 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
6554 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
6558 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
6562 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
6566 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
6570 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
6574 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
6578 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
6582 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
6586 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
6590 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
6594 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
6598 EL_PLAYER_1, ACTION_DEFAULT, -1,
6602 EL_PLAYER_2, ACTION_DEFAULT, -1,
6606 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
6610 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
6614 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
6618 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
6622 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
6626 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
6630 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
6634 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
6638 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
6642 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
6646 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
6650 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
6654 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
6658 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
6662 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
6666 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
6670 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
6674 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
6678 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
6682 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
6686 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
6690 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
6694 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
6698 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
6702 EL_PLAYER_3, ACTION_DEFAULT, -1,
6706 EL_PLAYER_4, ACTION_DEFAULT, -1,
6715 int map_element_RND_to_EM(int element_rnd)
6717 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
6718 static boolean mapping_initialized = FALSE;
6720 if (!mapping_initialized)
6724 /* return "Xalpha_quest" for all undefined elements in mapping array */
6725 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
6726 mapping_RND_to_EM[i] = Xalpha_quest;
6728 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6729 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
6730 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
6731 em_object_mapping_list[i].element_em;
6733 mapping_initialized = TRUE;
6736 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
6737 return mapping_RND_to_EM[element_rnd];
6739 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
6744 int map_element_EM_to_RND(int element_em)
6746 static unsigned short mapping_EM_to_RND[TILE_MAX];
6747 static boolean mapping_initialized = FALSE;
6749 if (!mapping_initialized)
6753 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
6754 for (i = 0; i < TILE_MAX; i++)
6755 mapping_EM_to_RND[i] = EL_UNKNOWN;
6757 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6758 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
6759 em_object_mapping_list[i].element_rnd;
6761 mapping_initialized = TRUE;
6764 if (element_em >= 0 && element_em < TILE_MAX)
6765 return mapping_EM_to_RND[element_em];
6767 Error(ERR_WARN, "invalid EM level element %d", element_em);
6772 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
6774 struct LevelInfo_EM *level_em = level->native_em_level;
6775 struct LEVEL *lev = level_em->lev;
6778 for (i = 0; i < TILE_MAX; i++)
6779 lev->android_array[i] = Xblank;
6781 for (i = 0; i < level->num_android_clone_elements; i++)
6783 int element_rnd = level->android_clone_element[i];
6784 int element_em = map_element_RND_to_EM(element_rnd);
6786 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
6787 if (em_object_mapping_list[j].element_rnd == element_rnd)
6788 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
6792 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
6794 struct LevelInfo_EM *level_em = level->native_em_level;
6795 struct LEVEL *lev = level_em->lev;
6798 level->num_android_clone_elements = 0;
6800 for (i = 0; i < TILE_MAX; i++)
6802 int element_em = lev->android_array[i];
6804 boolean element_found = FALSE;
6806 if (element_em == Xblank)
6809 element_rnd = map_element_EM_to_RND(element_em);
6811 for (j = 0; j < level->num_android_clone_elements; j++)
6812 if (level->android_clone_element[j] == element_rnd)
6813 element_found = TRUE;
6817 level->android_clone_element[level->num_android_clone_elements++] =
6820 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
6825 if (level->num_android_clone_elements == 0)
6827 level->num_android_clone_elements = 1;
6828 level->android_clone_element[0] = EL_EMPTY;
6832 int map_direction_RND_to_EM(int direction)
6834 return (direction == MV_UP ? 0 :
6835 direction == MV_RIGHT ? 1 :
6836 direction == MV_DOWN ? 2 :
6837 direction == MV_LEFT ? 3 :
6841 int map_direction_EM_to_RND(int direction)
6843 return (direction == 0 ? MV_UP :
6844 direction == 1 ? MV_RIGHT :
6845 direction == 2 ? MV_DOWN :
6846 direction == 3 ? MV_LEFT :
6850 int map_element_RND_to_SP(int element_rnd)
6852 int element_sp = 0x20; /* map unknown elements to yellow "hardware" */
6854 if (element_rnd >= EL_SP_START &&
6855 element_rnd <= EL_SP_END)
6856 element_sp = element_rnd - EL_SP_START;
6857 else if (element_rnd == EL_EMPTY_SPACE)
6859 else if (element_rnd == EL_INVISIBLE_WALL)
6865 int map_element_SP_to_RND(int element_sp)
6867 int element_rnd = EL_UNKNOWN;
6869 if (element_sp >= 0x00 &&
6871 element_rnd = EL_SP_START + element_sp;
6872 else if (element_sp == 0x28)
6873 element_rnd = EL_INVISIBLE_WALL;
6878 int map_action_SP_to_RND(int action_sp)
6882 case actActive: return ACTION_ACTIVE;
6883 case actImpact: return ACTION_IMPACT;
6884 case actExploding: return ACTION_EXPLODING;
6885 case actDigging: return ACTION_DIGGING;
6886 case actSnapping: return ACTION_SNAPPING;
6887 case actCollecting: return ACTION_COLLECTING;
6888 case actPassing: return ACTION_PASSING;
6889 case actPushing: return ACTION_PUSHING;
6890 case actDropping: return ACTION_DROPPING;
6892 default: return ACTION_DEFAULT;
6896 int get_next_element(int element)
6900 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
6901 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
6902 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
6903 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
6904 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
6905 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
6906 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
6907 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
6908 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
6909 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
6910 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
6912 default: return element;
6916 int el_act_dir2img(int element, int action, int direction)
6918 element = GFX_ELEMENT(element);
6919 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
6921 /* direction_graphic[][] == graphic[] for undefined direction graphics */
6922 return element_info[element].direction_graphic[action][direction];
6925 static int el_act_dir2crm(int element, int action, int direction)
6927 element = GFX_ELEMENT(element);
6928 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
6930 /* direction_graphic[][] == graphic[] for undefined direction graphics */
6931 return element_info[element].direction_crumbled[action][direction];
6934 int el_act2img(int element, int action)
6936 element = GFX_ELEMENT(element);
6938 return element_info[element].graphic[action];
6941 int el_act2crm(int element, int action)
6943 element = GFX_ELEMENT(element);
6945 return element_info[element].crumbled[action];
6948 int el_dir2img(int element, int direction)
6950 element = GFX_ELEMENT(element);
6952 return el_act_dir2img(element, ACTION_DEFAULT, direction);
6955 int el2baseimg(int element)
6957 return element_info[element].graphic[ACTION_DEFAULT];
6960 int el2img(int element)
6962 element = GFX_ELEMENT(element);
6964 return element_info[element].graphic[ACTION_DEFAULT];
6967 int el2edimg(int element)
6969 element = GFX_ELEMENT(element);
6971 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
6974 int el2preimg(int element)
6976 element = GFX_ELEMENT(element);
6978 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
6981 int el2panelimg(int element)
6983 element = GFX_ELEMENT(element);
6985 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL];
6988 int font2baseimg(int font_nr)
6990 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
6993 int getBeltNrFromBeltElement(int element)
6995 return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
6996 element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
6997 element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
7000 int getBeltNrFromBeltActiveElement(int element)
7002 return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
7003 element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
7004 element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
7007 int getBeltNrFromBeltSwitchElement(int element)
7009 return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
7010 element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
7011 element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
7014 int getBeltDirNrFromBeltElement(int element)
7016 static int belt_base_element[4] =
7018 EL_CONVEYOR_BELT_1_LEFT,
7019 EL_CONVEYOR_BELT_2_LEFT,
7020 EL_CONVEYOR_BELT_3_LEFT,
7021 EL_CONVEYOR_BELT_4_LEFT
7024 int belt_nr = getBeltNrFromBeltElement(element);
7025 int belt_dir_nr = element - belt_base_element[belt_nr];
7027 return (belt_dir_nr % 3);
7030 int getBeltDirNrFromBeltSwitchElement(int element)
7032 static int belt_base_element[4] =
7034 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
7035 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
7036 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
7037 EL_CONVEYOR_BELT_4_SWITCH_LEFT
7040 int belt_nr = getBeltNrFromBeltSwitchElement(element);
7041 int belt_dir_nr = element - belt_base_element[belt_nr];
7043 return (belt_dir_nr % 3);
7046 int getBeltDirFromBeltElement(int element)
7048 static int belt_move_dir[3] =
7055 int belt_dir_nr = getBeltDirNrFromBeltElement(element);
7057 return belt_move_dir[belt_dir_nr];
7060 int getBeltDirFromBeltSwitchElement(int element)
7062 static int belt_move_dir[3] =
7069 int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
7071 return belt_move_dir[belt_dir_nr];
7074 int getBeltElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
7076 static int belt_base_element[4] =
7078 EL_CONVEYOR_BELT_1_LEFT,
7079 EL_CONVEYOR_BELT_2_LEFT,
7080 EL_CONVEYOR_BELT_3_LEFT,
7081 EL_CONVEYOR_BELT_4_LEFT
7084 return belt_base_element[belt_nr] + belt_dir_nr;
7087 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
7089 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
7091 return getBeltElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
7094 int getBeltSwitchElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
7096 static int belt_base_element[4] =
7098 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
7099 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
7100 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
7101 EL_CONVEYOR_BELT_4_SWITCH_LEFT
7104 return belt_base_element[belt_nr] + belt_dir_nr;
7107 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
7109 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
7111 return getBeltSwitchElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
7114 boolean getTeamMode_EM()
7116 return game.team_mode;
7119 int getGameFrameDelay_EM(int native_em_game_frame_delay)
7121 int game_frame_delay_value;
7123 game_frame_delay_value =
7124 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
7125 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
7128 if (tape.playing && tape.warp_forward && !tape.pausing)
7129 game_frame_delay_value = 0;
7131 return game_frame_delay_value;
7134 unsigned int InitRND(int seed)
7136 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
7137 return InitEngineRandom_EM(seed);
7138 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
7139 return InitEngineRandom_SP(seed);
7141 return InitEngineRandom_RND(seed);
7144 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
7145 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
7147 inline static int get_effective_element_EM(int tile, int frame_em)
7149 int element = object_mapping[tile].element_rnd;
7150 int action = object_mapping[tile].action;
7151 boolean is_backside = object_mapping[tile].is_backside;
7152 boolean action_removing = (action == ACTION_DIGGING ||
7153 action == ACTION_SNAPPING ||
7154 action == ACTION_COLLECTING);
7160 case Yacid_splash_eB:
7161 case Yacid_splash_wB:
7162 return (frame_em > 5 ? EL_EMPTY : element);
7168 else /* frame_em == 7 */
7172 case Yacid_splash_eB:
7173 case Yacid_splash_wB:
7176 case Yemerald_stone:
7179 case Ydiamond_stone:
7183 case Xdrip_stretchB:
7202 case Xsand_stonein_1:
7203 case Xsand_stonein_2:
7204 case Xsand_stonein_3:
7205 case Xsand_stonein_4:
7209 return (is_backside || action_removing ? EL_EMPTY : element);
7214 inline static boolean check_linear_animation_EM(int tile)
7218 case Xsand_stonesand_1:
7219 case Xsand_stonesand_quickout_1:
7220 case Xsand_sandstone_1:
7221 case Xsand_stonein_1:
7222 case Xsand_stoneout_1:
7241 case Yacid_splash_eB:
7242 case Yacid_splash_wB:
7243 case Yemerald_stone:
7250 inline static void set_crumbled_graphics_EM(struct GraphicInfo_EM *g_em,
7251 boolean has_crumbled_graphics,
7252 int crumbled, int sync_frame)
7254 /* if element can be crumbled, but certain action graphics are just empty
7255 space (like instantly snapping sand to empty space in 1 frame), do not
7256 treat these empty space graphics as crumbled graphics in EMC engine */
7257 if (crumbled == IMG_EMPTY_SPACE)
7258 has_crumbled_graphics = FALSE;
7260 if (has_crumbled_graphics)
7262 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
7263 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
7264 g_crumbled->anim_delay,
7265 g_crumbled->anim_mode,
7266 g_crumbled->anim_start_frame,
7269 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
7270 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
7272 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
7273 g_em->crumbled_tile_size = graphic_info[crumbled].tile_size;
7275 g_em->has_crumbled_graphics = TRUE;
7279 g_em->crumbled_bitmap = NULL;
7280 g_em->crumbled_src_x = 0;
7281 g_em->crumbled_src_y = 0;
7282 g_em->crumbled_border_size = 0;
7283 g_em->crumbled_tile_size = 0;
7285 g_em->has_crumbled_graphics = FALSE;
7289 void ResetGfxAnimation_EM(int x, int y, int tile)
7294 void SetGfxAnimation_EM(struct GraphicInfo_EM *g_em,
7295 int tile, int frame_em, int x, int y)
7297 int action = object_mapping[tile].action;
7298 int direction = object_mapping[tile].direction;
7299 int effective_element = get_effective_element_EM(tile, frame_em);
7300 int graphic = (direction == MV_NONE ?
7301 el_act2img(effective_element, action) :
7302 el_act_dir2img(effective_element, action, direction));
7303 struct GraphicInfo *g = &graphic_info[graphic];
7305 boolean action_removing = (action == ACTION_DIGGING ||
7306 action == ACTION_SNAPPING ||
7307 action == ACTION_COLLECTING);
7308 boolean action_moving = (action == ACTION_FALLING ||
7309 action == ACTION_MOVING ||
7310 action == ACTION_PUSHING ||
7311 action == ACTION_EATING ||
7312 action == ACTION_FILLING ||
7313 action == ACTION_EMPTYING);
7314 boolean action_falling = (action == ACTION_FALLING ||
7315 action == ACTION_FILLING ||
7316 action == ACTION_EMPTYING);
7318 /* special case: graphic uses "2nd movement tile" and has defined
7319 7 frames for movement animation (or less) => use default graphic
7320 for last (8th) frame which ends the movement animation */
7321 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
7323 action = ACTION_DEFAULT; /* (keep action_* unchanged for now) */
7324 graphic = (direction == MV_NONE ?
7325 el_act2img(effective_element, action) :
7326 el_act_dir2img(effective_element, action, direction));
7328 g = &graphic_info[graphic];
7331 if ((action_removing || check_linear_animation_EM(tile)) && frame_em == 0)
7335 else if (action_moving)
7337 boolean is_backside = object_mapping[tile].is_backside;
7341 int direction = object_mapping[tile].direction;
7342 int move_dir = (action_falling ? MV_DOWN : direction);
7347 /* !!! TEST !!! NEW !!! DOES NOT WORK RIGHT YET !!! */
7348 if (g->double_movement && frame_em == 0)
7352 if (move_dir == MV_LEFT)
7353 GfxFrame[x - 1][y] = GfxFrame[x][y];
7354 else if (move_dir == MV_RIGHT)
7355 GfxFrame[x + 1][y] = GfxFrame[x][y];
7356 else if (move_dir == MV_UP)
7357 GfxFrame[x][y - 1] = GfxFrame[x][y];
7358 else if (move_dir == MV_DOWN)
7359 GfxFrame[x][y + 1] = GfxFrame[x][y];
7366 /* special case: animation for Xsand_stonesand_quickout_1/2 twice as fast */
7367 if (tile == Xsand_stonesand_quickout_1 ||
7368 tile == Xsand_stonesand_quickout_2)
7372 if (graphic_info[graphic].anim_global_sync)
7373 sync_frame = FrameCounter;
7374 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
7375 sync_frame = GfxFrame[x][y];
7377 sync_frame = 0; /* playfield border (pseudo steel) */
7379 SetRandomAnimationValue(x, y);
7381 int frame = getAnimationFrame(g->anim_frames,
7384 g->anim_start_frame,
7387 g_em->unique_identifier =
7388 (graphic << 16) | ((frame % 8) << 12) | (g_em->width << 6) | g_em->height;
7391 void getGraphicSourceObjectExt_EM(struct GraphicInfo_EM *g_em,
7392 int tile, int frame_em, int x, int y)
7394 int action = object_mapping[tile].action;
7395 int direction = object_mapping[tile].direction;
7396 boolean is_backside = object_mapping[tile].is_backside;
7397 int effective_element = get_effective_element_EM(tile, frame_em);
7398 int effective_action = action;
7399 int graphic = (direction == MV_NONE ?
7400 el_act2img(effective_element, effective_action) :
7401 el_act_dir2img(effective_element, effective_action,
7403 int crumbled = (direction == MV_NONE ?
7404 el_act2crm(effective_element, effective_action) :
7405 el_act_dir2crm(effective_element, effective_action,
7407 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7408 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7409 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7410 struct GraphicInfo *g = &graphic_info[graphic];
7413 /* special case: graphic uses "2nd movement tile" and has defined
7414 7 frames for movement animation (or less) => use default graphic
7415 for last (8th) frame which ends the movement animation */
7416 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
7418 effective_action = ACTION_DEFAULT;
7419 graphic = (direction == MV_NONE ?
7420 el_act2img(effective_element, effective_action) :
7421 el_act_dir2img(effective_element, effective_action,
7423 crumbled = (direction == MV_NONE ?
7424 el_act2crm(effective_element, effective_action) :
7425 el_act_dir2crm(effective_element, effective_action,
7428 g = &graphic_info[graphic];
7431 if (graphic_info[graphic].anim_global_sync)
7432 sync_frame = FrameCounter;
7433 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
7434 sync_frame = GfxFrame[x][y];
7436 sync_frame = 0; /* playfield border (pseudo steel) */
7438 SetRandomAnimationValue(x, y);
7440 int frame = getAnimationFrame(g->anim_frames,
7443 g->anim_start_frame,
7446 getGraphicSourceExt(graphic, frame, &g_em->bitmap, &g_em->src_x, &g_em->src_y,
7447 g->double_movement && is_backside);
7449 /* (updating the "crumbled" graphic definitions is probably not really needed,
7450 as animations for crumbled graphics can't be longer than one EMC cycle) */
7451 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
7455 void getGraphicSourcePlayerExt_EM(struct GraphicInfo_EM *g_em,
7456 int player_nr, int anim, int frame_em)
7458 int element = player_mapping[player_nr][anim].element_rnd;
7459 int action = player_mapping[player_nr][anim].action;
7460 int direction = player_mapping[player_nr][anim].direction;
7461 int graphic = (direction == MV_NONE ?
7462 el_act2img(element, action) :
7463 el_act_dir2img(element, action, direction));
7464 struct GraphicInfo *g = &graphic_info[graphic];
7467 InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
7469 stored_player[player_nr].StepFrame = frame_em;
7471 sync_frame = stored_player[player_nr].Frame;
7473 int frame = getAnimationFrame(g->anim_frames,
7476 g->anim_start_frame,
7479 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
7480 &g_em->src_x, &g_em->src_y, FALSE);
7483 void InitGraphicInfo_EM(void)
7488 int num_em_gfx_errors = 0;
7490 if (graphic_info_em_object[0][0].bitmap == NULL)
7492 /* EM graphics not yet initialized in em_open_all() */
7497 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
7500 /* always start with reliable default values */
7501 for (i = 0; i < TILE_MAX; i++)
7503 object_mapping[i].element_rnd = EL_UNKNOWN;
7504 object_mapping[i].is_backside = FALSE;
7505 object_mapping[i].action = ACTION_DEFAULT;
7506 object_mapping[i].direction = MV_NONE;
7509 /* always start with reliable default values */
7510 for (p = 0; p < MAX_PLAYERS; p++)
7512 for (i = 0; i < SPR_MAX; i++)
7514 player_mapping[p][i].element_rnd = EL_UNKNOWN;
7515 player_mapping[p][i].action = ACTION_DEFAULT;
7516 player_mapping[p][i].direction = MV_NONE;
7520 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
7522 int e = em_object_mapping_list[i].element_em;
7524 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
7525 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
7527 if (em_object_mapping_list[i].action != -1)
7528 object_mapping[e].action = em_object_mapping_list[i].action;
7530 if (em_object_mapping_list[i].direction != -1)
7531 object_mapping[e].direction =
7532 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
7535 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
7537 int a = em_player_mapping_list[i].action_em;
7538 int p = em_player_mapping_list[i].player_nr;
7540 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
7542 if (em_player_mapping_list[i].action != -1)
7543 player_mapping[p][a].action = em_player_mapping_list[i].action;
7545 if (em_player_mapping_list[i].direction != -1)
7546 player_mapping[p][a].direction =
7547 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
7550 for (i = 0; i < TILE_MAX; i++)
7552 int element = object_mapping[i].element_rnd;
7553 int action = object_mapping[i].action;
7554 int direction = object_mapping[i].direction;
7555 boolean is_backside = object_mapping[i].is_backside;
7556 boolean action_exploding = ((action == ACTION_EXPLODING ||
7557 action == ACTION_SMASHED_BY_ROCK ||
7558 action == ACTION_SMASHED_BY_SPRING) &&
7559 element != EL_DIAMOND);
7560 boolean action_active = (action == ACTION_ACTIVE);
7561 boolean action_other = (action == ACTION_OTHER);
7563 for (j = 0; j < 8; j++)
7565 int effective_element = get_effective_element_EM(i, j);
7566 int effective_action = (j < 7 ? action :
7567 i == Xdrip_stretch ? action :
7568 i == Xdrip_stretchB ? action :
7569 i == Ydrip_s1 ? action :
7570 i == Ydrip_s1B ? action :
7571 i == Xball_1B ? action :
7572 i == Xball_2 ? action :
7573 i == Xball_2B ? action :
7574 i == Yball_eat ? action :
7575 i == Ykey_1_eat ? action :
7576 i == Ykey_2_eat ? action :
7577 i == Ykey_3_eat ? action :
7578 i == Ykey_4_eat ? action :
7579 i == Ykey_5_eat ? action :
7580 i == Ykey_6_eat ? action :
7581 i == Ykey_7_eat ? action :
7582 i == Ykey_8_eat ? action :
7583 i == Ylenses_eat ? action :
7584 i == Ymagnify_eat ? action :
7585 i == Ygrass_eat ? action :
7586 i == Ydirt_eat ? action :
7587 i == Xsand_stonein_1 ? action :
7588 i == Xsand_stonein_2 ? action :
7589 i == Xsand_stonein_3 ? action :
7590 i == Xsand_stonein_4 ? action :
7591 i == Xsand_stoneout_1 ? action :
7592 i == Xsand_stoneout_2 ? action :
7593 i == Xboom_android ? ACTION_EXPLODING :
7594 action_exploding ? ACTION_EXPLODING :
7595 action_active ? action :
7596 action_other ? action :
7598 int graphic = (el_act_dir2img(effective_element, effective_action,
7600 int crumbled = (el_act_dir2crm(effective_element, effective_action,
7602 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7603 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7604 boolean has_action_graphics = (graphic != base_graphic);
7605 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7606 struct GraphicInfo *g = &graphic_info[graphic];
7607 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7610 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
7611 boolean special_animation = (action != ACTION_DEFAULT &&
7612 g->anim_frames == 3 &&
7613 g->anim_delay == 2 &&
7614 g->anim_mode & ANIM_LINEAR);
7615 int sync_frame = (i == Xdrip_stretch ? 7 :
7616 i == Xdrip_stretchB ? 7 :
7617 i == Ydrip_s2 ? j + 8 :
7618 i == Ydrip_s2B ? j + 8 :
7627 i == Xfake_acid_1 ? 0 :
7628 i == Xfake_acid_2 ? 10 :
7629 i == Xfake_acid_3 ? 20 :
7630 i == Xfake_acid_4 ? 30 :
7631 i == Xfake_acid_5 ? 40 :
7632 i == Xfake_acid_6 ? 50 :
7633 i == Xfake_acid_7 ? 60 :
7634 i == Xfake_acid_8 ? 70 :
7636 i == Xball_2B ? j + 8 :
7637 i == Yball_eat ? j + 1 :
7638 i == Ykey_1_eat ? j + 1 :
7639 i == Ykey_2_eat ? j + 1 :
7640 i == Ykey_3_eat ? j + 1 :
7641 i == Ykey_4_eat ? j + 1 :
7642 i == Ykey_5_eat ? j + 1 :
7643 i == Ykey_6_eat ? j + 1 :
7644 i == Ykey_7_eat ? j + 1 :
7645 i == Ykey_8_eat ? j + 1 :
7646 i == Ylenses_eat ? j + 1 :
7647 i == Ymagnify_eat ? j + 1 :
7648 i == Ygrass_eat ? j + 1 :
7649 i == Ydirt_eat ? j + 1 :
7650 i == Xamoeba_1 ? 0 :
7651 i == Xamoeba_2 ? 1 :
7652 i == Xamoeba_3 ? 2 :
7653 i == Xamoeba_4 ? 3 :
7654 i == Xamoeba_5 ? 0 :
7655 i == Xamoeba_6 ? 1 :
7656 i == Xamoeba_7 ? 2 :
7657 i == Xamoeba_8 ? 3 :
7658 i == Xexit_2 ? j + 8 :
7659 i == Xexit_3 ? j + 16 :
7660 i == Xdynamite_1 ? 0 :
7661 i == Xdynamite_2 ? 8 :
7662 i == Xdynamite_3 ? 16 :
7663 i == Xdynamite_4 ? 24 :
7664 i == Xsand_stonein_1 ? j + 1 :
7665 i == Xsand_stonein_2 ? j + 9 :
7666 i == Xsand_stonein_3 ? j + 17 :
7667 i == Xsand_stonein_4 ? j + 25 :
7668 i == Xsand_stoneout_1 && j == 0 ? 0 :
7669 i == Xsand_stoneout_1 && j == 1 ? 0 :
7670 i == Xsand_stoneout_1 && j == 2 ? 1 :
7671 i == Xsand_stoneout_1 && j == 3 ? 2 :
7672 i == Xsand_stoneout_1 && j == 4 ? 2 :
7673 i == Xsand_stoneout_1 && j == 5 ? 3 :
7674 i == Xsand_stoneout_1 && j == 6 ? 4 :
7675 i == Xsand_stoneout_1 && j == 7 ? 4 :
7676 i == Xsand_stoneout_2 && j == 0 ? 5 :
7677 i == Xsand_stoneout_2 && j == 1 ? 6 :
7678 i == Xsand_stoneout_2 && j == 2 ? 7 :
7679 i == Xsand_stoneout_2 && j == 3 ? 8 :
7680 i == Xsand_stoneout_2 && j == 4 ? 9 :
7681 i == Xsand_stoneout_2 && j == 5 ? 11 :
7682 i == Xsand_stoneout_2 && j == 6 ? 13 :
7683 i == Xsand_stoneout_2 && j == 7 ? 15 :
7684 i == Xboom_bug && j == 1 ? 2 :
7685 i == Xboom_bug && j == 2 ? 2 :
7686 i == Xboom_bug && j == 3 ? 4 :
7687 i == Xboom_bug && j == 4 ? 4 :
7688 i == Xboom_bug && j == 5 ? 2 :
7689 i == Xboom_bug && j == 6 ? 2 :
7690 i == Xboom_bug && j == 7 ? 0 :
7691 i == Xboom_bomb && j == 1 ? 2 :
7692 i == Xboom_bomb && j == 2 ? 2 :
7693 i == Xboom_bomb && j == 3 ? 4 :
7694 i == Xboom_bomb && j == 4 ? 4 :
7695 i == Xboom_bomb && j == 5 ? 2 :
7696 i == Xboom_bomb && j == 6 ? 2 :
7697 i == Xboom_bomb && j == 7 ? 0 :
7698 i == Xboom_android && j == 7 ? 6 :
7699 i == Xboom_1 && j == 1 ? 2 :
7700 i == Xboom_1 && j == 2 ? 2 :
7701 i == Xboom_1 && j == 3 ? 4 :
7702 i == Xboom_1 && j == 4 ? 4 :
7703 i == Xboom_1 && j == 5 ? 6 :
7704 i == Xboom_1 && j == 6 ? 6 :
7705 i == Xboom_1 && j == 7 ? 8 :
7706 i == Xboom_2 && j == 0 ? 8 :
7707 i == Xboom_2 && j == 1 ? 8 :
7708 i == Xboom_2 && j == 2 ? 10 :
7709 i == Xboom_2 && j == 3 ? 10 :
7710 i == Xboom_2 && j == 4 ? 10 :
7711 i == Xboom_2 && j == 5 ? 12 :
7712 i == Xboom_2 && j == 6 ? 12 :
7713 i == Xboom_2 && j == 7 ? 12 :
7714 special_animation && j == 4 ? 3 :
7715 effective_action != action ? 0 :
7719 Bitmap *debug_bitmap = g_em->bitmap;
7720 int debug_src_x = g_em->src_x;
7721 int debug_src_y = g_em->src_y;
7724 int frame = getAnimationFrame(g->anim_frames,
7727 g->anim_start_frame,
7730 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
7731 g->double_movement && is_backside);
7733 g_em->bitmap = src_bitmap;
7734 g_em->src_x = src_x;
7735 g_em->src_y = src_y;
7736 g_em->src_offset_x = 0;
7737 g_em->src_offset_y = 0;
7738 g_em->dst_offset_x = 0;
7739 g_em->dst_offset_y = 0;
7740 g_em->width = TILEX;
7741 g_em->height = TILEY;
7743 g_em->preserve_background = FALSE;
7745 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
7748 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
7749 effective_action == ACTION_MOVING ||
7750 effective_action == ACTION_PUSHING ||
7751 effective_action == ACTION_EATING)) ||
7752 (!has_action_graphics && (effective_action == ACTION_FILLING ||
7753 effective_action == ACTION_EMPTYING)))
7756 (effective_action == ACTION_FALLING ||
7757 effective_action == ACTION_FILLING ||
7758 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
7759 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
7760 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
7761 int num_steps = (i == Ydrip_s1 ? 16 :
7762 i == Ydrip_s1B ? 16 :
7763 i == Ydrip_s2 ? 16 :
7764 i == Ydrip_s2B ? 16 :
7765 i == Xsand_stonein_1 ? 32 :
7766 i == Xsand_stonein_2 ? 32 :
7767 i == Xsand_stonein_3 ? 32 :
7768 i == Xsand_stonein_4 ? 32 :
7769 i == Xsand_stoneout_1 ? 16 :
7770 i == Xsand_stoneout_2 ? 16 : 8);
7771 int cx = ABS(dx) * (TILEX / num_steps);
7772 int cy = ABS(dy) * (TILEY / num_steps);
7773 int step_frame = (i == Ydrip_s2 ? j + 8 :
7774 i == Ydrip_s2B ? j + 8 :
7775 i == Xsand_stonein_2 ? j + 8 :
7776 i == Xsand_stonein_3 ? j + 16 :
7777 i == Xsand_stonein_4 ? j + 24 :
7778 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
7779 int step = (is_backside ? step_frame : num_steps - step_frame);
7781 if (is_backside) /* tile where movement starts */
7783 if (dx < 0 || dy < 0)
7785 g_em->src_offset_x = cx * step;
7786 g_em->src_offset_y = cy * step;
7790 g_em->dst_offset_x = cx * step;
7791 g_em->dst_offset_y = cy * step;
7794 else /* tile where movement ends */
7796 if (dx < 0 || dy < 0)
7798 g_em->dst_offset_x = cx * step;
7799 g_em->dst_offset_y = cy * step;
7803 g_em->src_offset_x = cx * step;
7804 g_em->src_offset_y = cy * step;
7808 g_em->width = TILEX - cx * step;
7809 g_em->height = TILEY - cy * step;
7812 /* create unique graphic identifier to decide if tile must be redrawn */
7813 /* bit 31 - 16 (16 bit): EM style graphic
7814 bit 15 - 12 ( 4 bit): EM style frame
7815 bit 11 - 6 ( 6 bit): graphic width
7816 bit 5 - 0 ( 6 bit): graphic height */
7817 g_em->unique_identifier =
7818 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
7822 /* skip check for EMC elements not contained in original EMC artwork */
7823 if (element == EL_EMC_FAKE_ACID)
7826 if (g_em->bitmap != debug_bitmap ||
7827 g_em->src_x != debug_src_x ||
7828 g_em->src_y != debug_src_y ||
7829 g_em->src_offset_x != 0 ||
7830 g_em->src_offset_y != 0 ||
7831 g_em->dst_offset_x != 0 ||
7832 g_em->dst_offset_y != 0 ||
7833 g_em->width != TILEX ||
7834 g_em->height != TILEY)
7836 static int last_i = -1;
7844 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
7845 i, element, element_info[element].token_name,
7846 element_action_info[effective_action].suffix, direction);
7848 if (element != effective_element)
7849 printf(" [%d ('%s')]",
7851 element_info[effective_element].token_name);
7855 if (g_em->bitmap != debug_bitmap)
7856 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
7857 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
7859 if (g_em->src_x != debug_src_x ||
7860 g_em->src_y != debug_src_y)
7861 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
7862 j, (is_backside ? 'B' : 'F'),
7863 g_em->src_x, g_em->src_y,
7864 g_em->src_x / 32, g_em->src_y / 32,
7865 debug_src_x, debug_src_y,
7866 debug_src_x / 32, debug_src_y / 32);
7868 if (g_em->src_offset_x != 0 ||
7869 g_em->src_offset_y != 0 ||
7870 g_em->dst_offset_x != 0 ||
7871 g_em->dst_offset_y != 0)
7872 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
7874 g_em->src_offset_x, g_em->src_offset_y,
7875 g_em->dst_offset_x, g_em->dst_offset_y);
7877 if (g_em->width != TILEX ||
7878 g_em->height != TILEY)
7879 printf(" %d (%d): size %d,%d should be %d,%d\n",
7881 g_em->width, g_em->height, TILEX, TILEY);
7883 num_em_gfx_errors++;
7890 for (i = 0; i < TILE_MAX; i++)
7892 for (j = 0; j < 8; j++)
7894 int element = object_mapping[i].element_rnd;
7895 int action = object_mapping[i].action;
7896 int direction = object_mapping[i].direction;
7897 boolean is_backside = object_mapping[i].is_backside;
7898 int graphic_action = el_act_dir2img(element, action, direction);
7899 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
7901 if ((action == ACTION_SMASHED_BY_ROCK ||
7902 action == ACTION_SMASHED_BY_SPRING ||
7903 action == ACTION_EATING) &&
7904 graphic_action == graphic_default)
7906 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
7907 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
7908 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
7909 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
7912 /* no separate animation for "smashed by rock" -- use rock instead */
7913 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7914 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
7916 g_em->bitmap = g_xx->bitmap;
7917 g_em->src_x = g_xx->src_x;
7918 g_em->src_y = g_xx->src_y;
7919 g_em->src_offset_x = g_xx->src_offset_x;
7920 g_em->src_offset_y = g_xx->src_offset_y;
7921 g_em->dst_offset_x = g_xx->dst_offset_x;
7922 g_em->dst_offset_y = g_xx->dst_offset_y;
7923 g_em->width = g_xx->width;
7924 g_em->height = g_xx->height;
7925 g_em->unique_identifier = g_xx->unique_identifier;
7928 g_em->preserve_background = TRUE;
7933 for (p = 0; p < MAX_PLAYERS; p++)
7935 for (i = 0; i < SPR_MAX; i++)
7937 int element = player_mapping[p][i].element_rnd;
7938 int action = player_mapping[p][i].action;
7939 int direction = player_mapping[p][i].direction;
7941 for (j = 0; j < 8; j++)
7943 int effective_element = element;
7944 int effective_action = action;
7945 int graphic = (direction == MV_NONE ?
7946 el_act2img(effective_element, effective_action) :
7947 el_act_dir2img(effective_element, effective_action,
7949 struct GraphicInfo *g = &graphic_info[graphic];
7950 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
7956 Bitmap *debug_bitmap = g_em->bitmap;
7957 int debug_src_x = g_em->src_x;
7958 int debug_src_y = g_em->src_y;
7961 int frame = getAnimationFrame(g->anim_frames,
7964 g->anim_start_frame,
7967 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
7969 g_em->bitmap = src_bitmap;
7970 g_em->src_x = src_x;
7971 g_em->src_y = src_y;
7972 g_em->src_offset_x = 0;
7973 g_em->src_offset_y = 0;
7974 g_em->dst_offset_x = 0;
7975 g_em->dst_offset_y = 0;
7976 g_em->width = TILEX;
7977 g_em->height = TILEY;
7981 /* skip check for EMC elements not contained in original EMC artwork */
7982 if (element == EL_PLAYER_3 ||
7983 element == EL_PLAYER_4)
7986 if (g_em->bitmap != debug_bitmap ||
7987 g_em->src_x != debug_src_x ||
7988 g_em->src_y != debug_src_y)
7990 static int last_i = -1;
7998 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
7999 p, i, element, element_info[element].token_name,
8000 element_action_info[effective_action].suffix, direction);
8002 if (element != effective_element)
8003 printf(" [%d ('%s')]",
8005 element_info[effective_element].token_name);
8009 if (g_em->bitmap != debug_bitmap)
8010 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
8011 j, (int)(g_em->bitmap), (int)(debug_bitmap));
8013 if (g_em->src_x != debug_src_x ||
8014 g_em->src_y != debug_src_y)
8015 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
8017 g_em->src_x, g_em->src_y,
8018 g_em->src_x / 32, g_em->src_y / 32,
8019 debug_src_x, debug_src_y,
8020 debug_src_x / 32, debug_src_y / 32);
8022 num_em_gfx_errors++;
8032 printf("::: [%d errors found]\n", num_em_gfx_errors);
8038 void CheckSaveEngineSnapshot_EM(byte action[MAX_PLAYERS], int frame,
8039 boolean any_player_moving,
8040 boolean any_player_snapping,
8041 boolean any_player_dropping)
8043 if (frame == 0 && !any_player_dropping)
8045 if (!local_player->was_waiting)
8047 if (!CheckSaveEngineSnapshotToList())
8050 local_player->was_waiting = TRUE;
8053 else if (any_player_moving || any_player_snapping || any_player_dropping)
8055 local_player->was_waiting = FALSE;
8059 void CheckSaveEngineSnapshot_SP(boolean murphy_is_waiting,
8060 boolean murphy_is_dropping)
8062 if (murphy_is_waiting)
8064 if (!local_player->was_waiting)
8066 if (!CheckSaveEngineSnapshotToList())
8069 local_player->was_waiting = TRUE;
8074 local_player->was_waiting = FALSE;
8078 void CheckSingleStepMode_EM(byte action[MAX_PLAYERS], int frame,
8079 boolean any_player_moving,
8080 boolean any_player_snapping,
8081 boolean any_player_dropping)
8083 if (tape.single_step && tape.recording && !tape.pausing)
8084 if (frame == 0 && !any_player_dropping)
8085 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
8087 CheckSaveEngineSnapshot_EM(action, frame, any_player_moving,
8088 any_player_snapping, any_player_dropping);
8091 void CheckSingleStepMode_SP(boolean murphy_is_waiting,
8092 boolean murphy_is_dropping)
8094 if (tape.single_step && tape.recording && !tape.pausing)
8095 if (murphy_is_waiting)
8096 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
8098 CheckSaveEngineSnapshot_SP(murphy_is_waiting, murphy_is_dropping);
8101 void getGraphicSource_SP(struct GraphicInfo_SP *g_sp,
8102 int graphic, int sync_frame, int x, int y)
8104 int frame = getGraphicAnimationFrame(graphic, sync_frame);
8106 getGraphicSource(graphic, frame, &g_sp->bitmap, &g_sp->src_x, &g_sp->src_y);
8109 boolean isNextAnimationFrame_SP(int graphic, int sync_frame)
8111 return (IS_NEXT_FRAME(sync_frame, graphic));
8114 int getGraphicInfo_Delay(int graphic)
8116 return graphic_info[graphic].anim_delay;
8119 void PlayMenuSoundExt(int sound)
8121 if (sound == SND_UNDEFINED)
8124 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8125 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8128 if (IS_LOOP_SOUND(sound))
8129 PlaySoundLoop(sound);
8134 void PlayMenuSound()
8136 PlayMenuSoundExt(menu.sound[game_status]);
8139 void PlayMenuSoundStereo(int sound, int stereo_position)
8141 if (sound == SND_UNDEFINED)
8144 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8145 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8148 if (IS_LOOP_SOUND(sound))
8149 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
8151 PlaySoundStereo(sound, stereo_position);
8154 void PlayMenuSoundIfLoopExt(int sound)
8156 if (sound == SND_UNDEFINED)
8159 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8160 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8163 if (IS_LOOP_SOUND(sound))
8164 PlaySoundLoop(sound);
8167 void PlayMenuSoundIfLoop()
8169 PlayMenuSoundIfLoopExt(menu.sound[game_status]);
8172 void PlayMenuMusicExt(int music)
8174 if (music == MUS_UNDEFINED)
8177 if (!setup.sound_music)
8183 void PlayMenuMusic()
8185 PlayMenuMusicExt(menu.music[game_status]);
8188 void PlaySoundActivating()
8191 PlaySound(SND_MENU_ITEM_ACTIVATING);
8195 void PlaySoundSelecting()
8198 PlaySound(SND_MENU_ITEM_SELECTING);
8202 void ToggleFullscreenOrChangeWindowScalingIfNeeded()
8204 boolean change_fullscreen = (setup.fullscreen !=
8205 video.fullscreen_enabled);
8206 boolean change_window_scaling_percent = (!video.fullscreen_enabled &&
8207 setup.window_scaling_percent !=
8208 video.window_scaling_percent);
8210 if (change_window_scaling_percent && video.fullscreen_enabled)
8213 if (!change_window_scaling_percent && !video.fullscreen_available)
8216 #if defined(TARGET_SDL2)
8217 if (change_window_scaling_percent)
8219 SDLSetWindowScaling(setup.window_scaling_percent);
8223 else if (change_fullscreen)
8225 SDLSetWindowFullscreen(setup.fullscreen);
8227 /* set setup value according to successfully changed fullscreen mode */
8228 setup.fullscreen = video.fullscreen_enabled;
8234 if (change_fullscreen ||
8235 change_window_scaling_percent)
8237 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
8239 /* save backbuffer content which gets lost when toggling fullscreen mode */
8240 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8242 if (change_window_scaling_percent)
8244 /* keep window mode, but change window scaling */
8245 video.fullscreen_enabled = TRUE; /* force new window scaling */
8248 /* toggle fullscreen */
8249 ChangeVideoModeIfNeeded(setup.fullscreen);
8251 /* set setup value according to successfully changed fullscreen mode */
8252 setup.fullscreen = video.fullscreen_enabled;
8254 /* restore backbuffer content from temporary backbuffer backup bitmap */
8255 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8257 FreeBitmap(tmp_backbuffer);
8259 /* update visible window/screen */
8260 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8264 void JoinRectangles(int *x, int *y, int *width, int *height,
8265 int x2, int y2, int width2, int height2)
8267 // do not join with "off-screen" rectangle
8268 if (x2 == -1 || y2 == -1)
8273 *width = MAX(*width, width2);
8274 *height = MAX(*height, height2);
8277 void SetAnimStatus(int anim_status_new)
8279 if (anim_status_new == GAME_MODE_MAIN)
8280 anim_status_new = GAME_MODE_PSEUDO_MAINONLY;
8282 global.anim_status_next = anim_status_new;
8284 // directly set screen modes that are entered without fading
8285 if ((global.anim_status == GAME_MODE_PSEUDO_MAINONLY &&
8286 global.anim_status_next == GAME_MODE_PSEUDO_TYPENAME) ||
8287 (global.anim_status == GAME_MODE_PSEUDO_TYPENAME &&
8288 global.anim_status_next == GAME_MODE_PSEUDO_MAINONLY))
8289 global.anim_status = global.anim_status_next;
8292 void SetGameStatus(int game_status_new)
8294 game_status = game_status_new;
8296 SetAnimStatus(game_status_new);
8299 void SetFontStatus(int game_status_new)
8301 static int last_game_status = -1;
8303 if (game_status_new != -1)
8305 // set game status for font use after storing last game status
8306 last_game_status = game_status;
8307 game_status = game_status_new;
8311 // reset game status after font use from last stored game status
8312 game_status = last_game_status;
8316 void ResetFontStatus()
8321 void ChangeViewportPropertiesIfNeeded()
8323 int gfx_game_mode = game_status;
8324 int gfx_game_mode2 = (game_status == GAME_MODE_EDITOR ? GAME_MODE_DEFAULT :
8326 struct RectWithBorder *vp_window = &viewport.window[gfx_game_mode];
8327 struct RectWithBorder *vp_playfield = &viewport.playfield[gfx_game_mode];
8328 struct RectWithBorder *vp_door_1 = &viewport.door_1[gfx_game_mode];
8329 struct RectWithBorder *vp_door_2 = &viewport.door_2[gfx_game_mode2];
8330 struct RectWithBorder *vp_door_3 = &viewport.door_2[GAME_MODE_EDITOR];
8331 int new_win_xsize = vp_window->width;
8332 int new_win_ysize = vp_window->height;
8333 int border_size = vp_playfield->border_size;
8334 int new_sx = vp_playfield->x + border_size;
8335 int new_sy = vp_playfield->y + border_size;
8336 int new_sxsize = vp_playfield->width - 2 * border_size;
8337 int new_sysize = vp_playfield->height - 2 * border_size;
8338 int new_real_sx = vp_playfield->x;
8339 int new_real_sy = vp_playfield->y;
8340 int new_full_sxsize = vp_playfield->width;
8341 int new_full_sysize = vp_playfield->height;
8342 int new_dx = vp_door_1->x;
8343 int new_dy = vp_door_1->y;
8344 int new_dxsize = vp_door_1->width;
8345 int new_dysize = vp_door_1->height;
8346 int new_vx = vp_door_2->x;
8347 int new_vy = vp_door_2->y;
8348 int new_vxsize = vp_door_2->width;
8349 int new_vysize = vp_door_2->height;
8350 int new_ex = vp_door_3->x;
8351 int new_ey = vp_door_3->y;
8352 int new_exsize = vp_door_3->width;
8353 int new_eysize = vp_door_3->height;
8354 int new_tilesize_var =
8355 (setup.small_game_graphics ? MINI_TILESIZE : game.tile_size);
8357 int tilesize = (gfx_game_mode == GAME_MODE_PLAYING ? new_tilesize_var :
8358 gfx_game_mode == GAME_MODE_EDITOR ? MINI_TILESIZE : TILESIZE);
8359 int new_scr_fieldx = new_sxsize / tilesize;
8360 int new_scr_fieldy = new_sysize / tilesize;
8361 int new_scr_fieldx_buffers = new_sxsize / new_tilesize_var;
8362 int new_scr_fieldy_buffers = new_sysize / new_tilesize_var;
8363 boolean init_gfx_buffers = FALSE;
8364 boolean init_video_buffer = FALSE;
8365 boolean init_gadgets_and_anims = FALSE;
8366 boolean init_em_graphics = FALSE;
8368 if (new_win_xsize != WIN_XSIZE ||
8369 new_win_ysize != WIN_YSIZE)
8371 WIN_XSIZE = new_win_xsize;
8372 WIN_YSIZE = new_win_ysize;
8374 init_video_buffer = TRUE;
8375 init_gfx_buffers = TRUE;
8376 init_gadgets_and_anims = TRUE;
8378 // printf("::: video: init_video_buffer, init_gfx_buffers\n");
8381 if (new_scr_fieldx != SCR_FIELDX ||
8382 new_scr_fieldy != SCR_FIELDY)
8384 /* this always toggles between MAIN and GAME when using small tile size */
8386 SCR_FIELDX = new_scr_fieldx;
8387 SCR_FIELDY = new_scr_fieldy;
8389 // printf("::: new_scr_fieldx != SCR_FIELDX ...\n");
8400 new_sxsize != SXSIZE ||
8401 new_sysize != SYSIZE ||
8402 new_dxsize != DXSIZE ||
8403 new_dysize != DYSIZE ||
8404 new_vxsize != VXSIZE ||
8405 new_vysize != VYSIZE ||
8406 new_exsize != EXSIZE ||
8407 new_eysize != EYSIZE ||
8408 new_real_sx != REAL_SX ||
8409 new_real_sy != REAL_SY ||
8410 new_full_sxsize != FULL_SXSIZE ||
8411 new_full_sysize != FULL_SYSIZE ||
8412 new_tilesize_var != TILESIZE_VAR
8415 // ------------------------------------------------------------------------
8416 // determine next fading area for changed viewport definitions
8417 // ------------------------------------------------------------------------
8419 // start with current playfield area (default fading area)
8422 FADE_SXSIZE = FULL_SXSIZE;
8423 FADE_SYSIZE = FULL_SYSIZE;
8425 // add new playfield area if position or size has changed
8426 if (new_real_sx != REAL_SX || new_real_sy != REAL_SY ||
8427 new_full_sxsize != FULL_SXSIZE || new_full_sysize != FULL_SYSIZE)
8429 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
8430 new_real_sx, new_real_sy, new_full_sxsize,new_full_sysize);
8433 // add current and new door 1 area if position or size has changed
8434 if (new_dx != DX || new_dy != DY ||
8435 new_dxsize != DXSIZE || new_dysize != DYSIZE)
8437 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
8438 DX, DY, DXSIZE, DYSIZE);
8439 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
8440 new_dx, new_dy, new_dxsize, new_dysize);
8443 // add current and new door 2 area if position or size has changed
8444 if (new_dx != VX || new_dy != VY ||
8445 new_dxsize != VXSIZE || new_dysize != VYSIZE)
8447 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
8448 VX, VY, VXSIZE, VYSIZE);
8449 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
8450 new_vx, new_vy, new_vxsize, new_vysize);
8453 // ------------------------------------------------------------------------
8454 // handle changed tile size
8455 // ------------------------------------------------------------------------
8457 if (new_tilesize_var != TILESIZE_VAR)
8459 // printf("::: new_tilesize_var != TILESIZE_VAR\n");
8461 // changing tile size invalidates scroll values of engine snapshots
8462 FreeEngineSnapshotSingle();
8464 // changing tile size requires update of graphic mapping for EM engine
8465 init_em_graphics = TRUE;
8476 SXSIZE = new_sxsize;
8477 SYSIZE = new_sysize;
8478 DXSIZE = new_dxsize;
8479 DYSIZE = new_dysize;
8480 VXSIZE = new_vxsize;
8481 VYSIZE = new_vysize;
8482 EXSIZE = new_exsize;
8483 EYSIZE = new_eysize;
8484 REAL_SX = new_real_sx;
8485 REAL_SY = new_real_sy;
8486 FULL_SXSIZE = new_full_sxsize;
8487 FULL_SYSIZE = new_full_sysize;
8488 TILESIZE_VAR = new_tilesize_var;
8490 init_gfx_buffers = TRUE;
8491 init_gadgets_and_anims = TRUE;
8493 // printf("::: viewports: init_gfx_buffers\n");
8494 // printf("::: viewports: init_gadgets_and_anims\n");
8497 if (init_gfx_buffers)
8499 // printf("::: init_gfx_buffers\n");
8501 SCR_FIELDX = new_scr_fieldx_buffers;
8502 SCR_FIELDY = new_scr_fieldy_buffers;
8506 SCR_FIELDX = new_scr_fieldx;
8507 SCR_FIELDY = new_scr_fieldy;
8509 SetDrawDeactivationMask(REDRAW_NONE);
8510 SetDrawBackgroundMask(REDRAW_FIELD);
8513 if (init_video_buffer)
8515 // printf("::: init_video_buffer\n");
8517 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
8518 InitImageTextures();
8521 if (init_gadgets_and_anims)
8523 // printf("::: init_gadgets_and_anims\n");
8526 InitGlobalAnimations();
8529 if (init_em_graphics)
8531 InitGraphicInfo_EM();