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 if (IS_CRUMBLED_TILE(x, y, element)) /* crumble field itself */
1901 if (!IN_SCR_FIELD(sx, sy))
1904 /* crumble field borders towards direct neighbour fields */
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 /* crumble inner field corners towards corner neighbour fields */
1923 if ((graphic_info[graphic].style & STYLE_INNER_CORNERS) &&
1924 graphic_info[graphic].anim_frames == 2)
1926 for (i = 0; i < 4; i++)
1928 int dx = (i & 1 ? +1 : -1);
1929 int dy = (i & 2 ? +1 : -1);
1931 DrawLevelFieldCrumbledInnerCorners(x, y, dx, dy, graphic);
1935 MarkTileDirty(sx, sy);
1937 else /* center field is not crumbled -- crumble neighbour fields */
1939 /* crumble field borders of direct neighbour fields */
1940 for (i = 0; i < 4; i++)
1942 int xx = x + xy[i][0];
1943 int yy = y + xy[i][1];
1944 int sxx = sx + xy[i][0];
1945 int syy = sy + xy[i][1];
1947 if (!IN_LEV_FIELD(xx, yy) ||
1948 !IN_SCR_FIELD(sxx, syy))
1951 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
1954 element = TILE_GFX_ELEMENT(xx, yy);
1956 if (!IS_CRUMBLED_TILE(xx, yy, element))
1959 graphic = el_act2crm(element, ACTION_DEFAULT);
1961 DrawLevelFieldCrumbledBorders(xx, yy, graphic, 0, 3 - i);
1963 MarkTileDirty(sxx, syy);
1966 /* crumble inner field corners of corner neighbour fields */
1967 for (i = 0; i < 4; i++)
1969 int dx = (i & 1 ? +1 : -1);
1970 int dy = (i & 2 ? +1 : -1);
1976 if (!IN_LEV_FIELD(xx, yy) ||
1977 !IN_SCR_FIELD(sxx, syy))
1980 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
1983 element = TILE_GFX_ELEMENT(xx, yy);
1985 if (!IS_CRUMBLED_TILE(xx, yy, element))
1988 graphic = el_act2crm(element, ACTION_DEFAULT);
1990 if ((graphic_info[graphic].style & STYLE_INNER_CORNERS) &&
1991 graphic_info[graphic].anim_frames == 2)
1992 DrawLevelFieldCrumbledInnerCorners(xx, yy, -dx, -dy, graphic);
1994 MarkTileDirty(sxx, syy);
1999 void DrawLevelFieldCrumbled(int x, int y)
2003 if (!IN_LEV_FIELD(x, y))
2006 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
2007 GfxElement[x][y] != EL_UNDEFINED &&
2008 GFX_CRUMBLED(GfxElement[x][y]))
2010 DrawLevelFieldCrumbledDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
2015 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
2017 DrawLevelFieldCrumbledExt(x, y, graphic, 0);
2020 void DrawLevelFieldCrumbledDigging(int x, int y, int direction,
2023 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
2024 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
2025 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
2026 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
2027 int sx = SCREENX(x), sy = SCREENY(y);
2029 DrawGraphic(sx, sy, graphic1, frame1);
2030 DrawLevelFieldCrumbledExt(x, y, graphic2, frame2);
2033 void DrawLevelFieldCrumbledNeighbours(int x, int y)
2035 int sx = SCREENX(x), sy = SCREENY(y);
2036 static int xy[4][2] =
2045 /* crumble direct neighbour fields (required for field borders) */
2046 for (i = 0; i < 4; i++)
2048 int xx = x + xy[i][0];
2049 int yy = y + xy[i][1];
2050 int sxx = sx + xy[i][0];
2051 int syy = sy + xy[i][1];
2053 if (!IN_LEV_FIELD(xx, yy) ||
2054 !IN_SCR_FIELD(sxx, syy) ||
2055 !GFX_CRUMBLED(Feld[xx][yy]) ||
2059 DrawLevelField(xx, yy);
2062 /* crumble corner neighbour fields (required for inner field corners) */
2063 for (i = 0; i < 4; i++)
2065 int dx = (i & 1 ? +1 : -1);
2066 int dy = (i & 2 ? +1 : -1);
2072 if (!IN_LEV_FIELD(xx, yy) ||
2073 !IN_SCR_FIELD(sxx, syy) ||
2074 !GFX_CRUMBLED(Feld[xx][yy]) ||
2078 int element = TILE_GFX_ELEMENT(xx, yy);
2079 int graphic = el_act2crm(element, ACTION_DEFAULT);
2081 if ((graphic_info[graphic].style & STYLE_INNER_CORNERS) &&
2082 graphic_info[graphic].anim_frames == 2)
2083 DrawLevelField(xx, yy);
2087 static int getBorderElement(int x, int y)
2091 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
2092 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
2093 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
2094 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
2095 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
2096 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
2097 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
2099 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
2100 int steel_position = (x == -1 && y == -1 ? 0 :
2101 x == lev_fieldx && y == -1 ? 1 :
2102 x == -1 && y == lev_fieldy ? 2 :
2103 x == lev_fieldx && y == lev_fieldy ? 3 :
2104 x == -1 || x == lev_fieldx ? 4 :
2105 y == -1 || y == lev_fieldy ? 5 : 6);
2107 return border[steel_position][steel_type];
2110 void DrawScreenElement(int x, int y, int element)
2112 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
2113 DrawLevelFieldCrumbled(LEVELX(x), LEVELY(y));
2116 void DrawLevelElement(int x, int y, int element)
2118 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2119 DrawScreenElement(SCREENX(x), SCREENY(y), element);
2122 void DrawScreenField(int x, int y)
2124 int lx = LEVELX(x), ly = LEVELY(y);
2125 int element, content;
2127 if (!IN_LEV_FIELD(lx, ly))
2129 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
2132 element = getBorderElement(lx, ly);
2134 DrawScreenElement(x, y, element);
2139 element = Feld[lx][ly];
2140 content = Store[lx][ly];
2142 if (IS_MOVING(lx, ly))
2144 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
2145 boolean cut_mode = NO_CUTTING;
2147 if (element == EL_QUICKSAND_EMPTYING ||
2148 element == EL_QUICKSAND_FAST_EMPTYING ||
2149 element == EL_MAGIC_WALL_EMPTYING ||
2150 element == EL_BD_MAGIC_WALL_EMPTYING ||
2151 element == EL_DC_MAGIC_WALL_EMPTYING ||
2152 element == EL_AMOEBA_DROPPING)
2153 cut_mode = CUT_ABOVE;
2154 else if (element == EL_QUICKSAND_FILLING ||
2155 element == EL_QUICKSAND_FAST_FILLING ||
2156 element == EL_MAGIC_WALL_FILLING ||
2157 element == EL_BD_MAGIC_WALL_FILLING ||
2158 element == EL_DC_MAGIC_WALL_FILLING)
2159 cut_mode = CUT_BELOW;
2161 if (cut_mode == CUT_ABOVE)
2162 DrawScreenElement(x, y, element);
2164 DrawScreenElement(x, y, EL_EMPTY);
2167 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
2168 else if (cut_mode == NO_CUTTING)
2169 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
2172 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
2174 if (cut_mode == CUT_BELOW &&
2175 IN_LEV_FIELD(lx, ly + 1) && IN_SCR_FIELD(x, y + 1))
2176 DrawLevelElement(lx, ly + 1, element);
2179 if (content == EL_ACID)
2181 int dir = MovDir[lx][ly];
2182 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
2183 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
2185 DrawLevelElementThruMask(newlx, newly, EL_ACID);
2188 else if (IS_BLOCKED(lx, ly))
2193 boolean cut_mode = NO_CUTTING;
2194 int element_old, content_old;
2196 Blocked2Moving(lx, ly, &oldx, &oldy);
2199 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
2200 MovDir[oldx][oldy] == MV_RIGHT);
2202 element_old = Feld[oldx][oldy];
2203 content_old = Store[oldx][oldy];
2205 if (element_old == EL_QUICKSAND_EMPTYING ||
2206 element_old == EL_QUICKSAND_FAST_EMPTYING ||
2207 element_old == EL_MAGIC_WALL_EMPTYING ||
2208 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
2209 element_old == EL_DC_MAGIC_WALL_EMPTYING ||
2210 element_old == EL_AMOEBA_DROPPING)
2211 cut_mode = CUT_ABOVE;
2213 DrawScreenElement(x, y, EL_EMPTY);
2216 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
2218 else if (cut_mode == NO_CUTTING)
2219 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
2222 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
2225 else if (IS_DRAWABLE(element))
2226 DrawScreenElement(x, y, element);
2228 DrawScreenElement(x, y, EL_EMPTY);
2231 void DrawLevelField(int x, int y)
2233 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2234 DrawScreenField(SCREENX(x), SCREENY(y));
2235 else if (IS_MOVING(x, y))
2239 Moving2Blocked(x, y, &newx, &newy);
2240 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
2241 DrawScreenField(SCREENX(newx), SCREENY(newy));
2243 else if (IS_BLOCKED(x, y))
2247 Blocked2Moving(x, y, &oldx, &oldy);
2248 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
2249 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
2253 void DrawSizedElement(int x, int y, int element, int tilesize)
2257 graphic = el2edimg(element);
2258 DrawSizedGraphic(x, y, graphic, 0, tilesize);
2261 void DrawMiniElement(int x, int y, int element)
2265 graphic = el2edimg(element);
2266 DrawMiniGraphic(x, y, graphic);
2269 void DrawSizedElementOrWall(int sx, int sy, int scroll_x, int scroll_y,
2272 int x = sx + scroll_x, y = sy + scroll_y;
2274 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
2275 DrawSizedElement(sx, sy, EL_EMPTY, tilesize);
2276 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
2277 DrawSizedElement(sx, sy, Feld[x][y], tilesize);
2279 DrawSizedGraphic(sx, sy, el2edimg(getBorderElement(x, y)), 0, tilesize);
2282 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
2284 int x = sx + scroll_x, y = sy + scroll_y;
2286 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
2287 DrawMiniElement(sx, sy, EL_EMPTY);
2288 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
2289 DrawMiniElement(sx, sy, Feld[x][y]);
2291 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
2294 void DrawEnvelopeBackgroundTiles(int graphic, int startx, int starty,
2295 int x, int y, int xsize, int ysize,
2296 int tile_width, int tile_height)
2300 int dst_x = startx + x * tile_width;
2301 int dst_y = starty + y * tile_height;
2302 int width = graphic_info[graphic].width;
2303 int height = graphic_info[graphic].height;
2304 int inner_width_raw = MAX(width - 2 * tile_width, tile_width);
2305 int inner_height_raw = MAX(height - 2 * tile_height, tile_height);
2306 int inner_width = inner_width_raw - (inner_width_raw % tile_width);
2307 int inner_height = inner_height_raw - (inner_height_raw % tile_height);
2308 int inner_sx = (width >= 3 * tile_width ? tile_width : 0);
2309 int inner_sy = (height >= 3 * tile_height ? tile_height : 0);
2310 boolean draw_masked = graphic_info[graphic].draw_masked;
2312 getFixedGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
2314 if (src_bitmap == NULL || width < tile_width || height < tile_height)
2316 ClearRectangle(drawto, dst_x, dst_y, tile_width, tile_height);
2320 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - tile_width :
2321 inner_sx + (x - 1) * tile_width % inner_width);
2322 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - tile_height :
2323 inner_sy + (y - 1) * tile_height % inner_height);
2326 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
2329 BlitBitmap(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
2333 void DrawEnvelopeBackground(int graphic, int startx, int starty,
2334 int x, int y, int xsize, int ysize, int font_nr)
2336 int font_width = getFontWidth(font_nr);
2337 int font_height = getFontHeight(font_nr);
2339 DrawEnvelopeBackgroundTiles(graphic, startx, starty, x, y, xsize, ysize,
2340 font_width, font_height);
2343 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
2345 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2346 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2347 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2348 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2349 boolean no_delay = (tape.warp_forward);
2350 unsigned int anim_delay = 0;
2351 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
2352 int anim_delay_value = (no_delay ? 0 : frame_delay_value) / 2;
2353 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
2354 int font_width = getFontWidth(font_nr);
2355 int font_height = getFontHeight(font_nr);
2356 int max_xsize = level.envelope[envelope_nr].xsize;
2357 int max_ysize = level.envelope[envelope_nr].ysize;
2358 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
2359 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
2360 int xend = max_xsize;
2361 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
2362 int xstep = (xstart < xend ? 1 : 0);
2363 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2365 int end = MAX(xend - xstart, yend - ystart);
2368 for (i = start; i <= end; i++)
2370 int last_frame = end; // last frame of this "for" loop
2371 int x = xstart + i * xstep;
2372 int y = ystart + i * ystep;
2373 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2374 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2375 int sx = SX + (SXSIZE - xsize * font_width) / 2;
2376 int sy = SY + (SYSIZE - ysize * font_height) / 2;
2379 SetDrawtoField(DRAW_TO_FIELDBUFFER);
2381 BlitScreenToBitmap(backbuffer);
2383 SetDrawtoField(DRAW_TO_BACKBUFFER);
2385 for (yy = 0; yy < ysize; yy++)
2386 for (xx = 0; xx < xsize; xx++)
2387 DrawEnvelopeBackground(graphic, sx, sy, xx, yy, xsize, ysize, font_nr);
2389 DrawTextBuffer(sx + font_width, sy + font_height,
2390 level.envelope[envelope_nr].text, font_nr, max_xsize,
2391 xsize - 2, ysize - 2, 0, mask_mode,
2392 level.envelope[envelope_nr].autowrap,
2393 level.envelope[envelope_nr].centered, FALSE);
2395 redraw_mask |= REDRAW_FIELD;
2398 SkipUntilDelayReached(&anim_delay, anim_delay_value, &i, last_frame);
2402 void ShowEnvelope(int envelope_nr)
2404 int element = EL_ENVELOPE_1 + envelope_nr;
2405 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2406 int sound_opening = element_info[element].sound[ACTION_OPENING];
2407 int sound_closing = element_info[element].sound[ACTION_CLOSING];
2408 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2409 boolean no_delay = (tape.warp_forward);
2410 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
2411 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
2412 int anim_mode = graphic_info[graphic].anim_mode;
2413 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2414 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2416 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
2418 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2420 if (anim_mode == ANIM_DEFAULT)
2421 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
2423 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
2426 Delay(wait_delay_value);
2428 WaitForEventToContinue();
2430 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2432 if (anim_mode != ANIM_NONE)
2433 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
2435 if (anim_mode == ANIM_DEFAULT)
2436 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
2438 game.envelope_active = FALSE;
2440 SetDrawtoField(DRAW_TO_FIELDBUFFER);
2442 redraw_mask |= REDRAW_FIELD;
2446 static void setRequestBasePosition(int *x, int *y)
2448 int sx_base, sy_base;
2450 if (request.x != -1)
2451 sx_base = request.x;
2452 else if (request.align == ALIGN_LEFT)
2454 else if (request.align == ALIGN_RIGHT)
2455 sx_base = SX + SXSIZE;
2457 sx_base = SX + SXSIZE / 2;
2459 if (request.y != -1)
2460 sy_base = request.y;
2461 else if (request.valign == VALIGN_TOP)
2463 else if (request.valign == VALIGN_BOTTOM)
2464 sy_base = SY + SYSIZE;
2466 sy_base = SY + SYSIZE / 2;
2472 static void setRequestPositionExt(int *x, int *y, int width, int height,
2473 boolean add_border_size)
2475 int border_size = request.border_size;
2476 int sx_base, sy_base;
2479 setRequestBasePosition(&sx_base, &sy_base);
2481 if (request.align == ALIGN_LEFT)
2483 else if (request.align == ALIGN_RIGHT)
2484 sx = sx_base - width;
2486 sx = sx_base - width / 2;
2488 if (request.valign == VALIGN_TOP)
2490 else if (request.valign == VALIGN_BOTTOM)
2491 sy = sy_base - height;
2493 sy = sy_base - height / 2;
2495 sx = MAX(0, MIN(sx, WIN_XSIZE - width));
2496 sy = MAX(0, MIN(sy, WIN_YSIZE - height));
2498 if (add_border_size)
2508 static void setRequestPosition(int *x, int *y, boolean add_border_size)
2510 setRequestPositionExt(x, y, request.width, request.height, add_border_size);
2513 void DrawEnvelopeRequest(char *text)
2515 char *text_final = text;
2516 char *text_door_style = NULL;
2517 int graphic = IMG_BACKGROUND_REQUEST;
2518 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2519 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2520 int font_nr = FONT_REQUEST;
2521 int font_width = getFontWidth(font_nr);
2522 int font_height = getFontHeight(font_nr);
2523 int border_size = request.border_size;
2524 int line_spacing = request.line_spacing;
2525 int line_height = font_height + line_spacing;
2526 int max_text_width = request.width - 2 * border_size;
2527 int max_text_height = request.height - 2 * border_size;
2528 int line_length = max_text_width / font_width;
2529 int max_lines = max_text_height / line_height;
2530 int text_width = line_length * font_width;
2531 int width = request.width;
2532 int height = request.height;
2533 int tile_size = MAX(request.step_offset, 1);
2534 int x_steps = width / tile_size;
2535 int y_steps = height / tile_size;
2536 int sx_offset = border_size;
2537 int sy_offset = border_size;
2541 if (request.centered)
2542 sx_offset = (request.width - text_width) / 2;
2544 if (request.wrap_single_words && !request.autowrap)
2546 char *src_text_ptr, *dst_text_ptr;
2548 text_door_style = checked_malloc(2 * strlen(text) + 1);
2550 src_text_ptr = text;
2551 dst_text_ptr = text_door_style;
2553 while (*src_text_ptr)
2555 if (*src_text_ptr == ' ' ||
2556 *src_text_ptr == '?' ||
2557 *src_text_ptr == '!')
2558 *dst_text_ptr++ = '\n';
2560 if (*src_text_ptr != ' ')
2561 *dst_text_ptr++ = *src_text_ptr;
2566 *dst_text_ptr = '\0';
2568 text_final = text_door_style;
2571 setRequestPosition(&sx, &sy, FALSE);
2573 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
2575 for (y = 0; y < y_steps; y++)
2576 for (x = 0; x < x_steps; x++)
2577 DrawEnvelopeBackgroundTiles(graphic, sx, sy,
2578 x, y, x_steps, y_steps,
2579 tile_size, tile_size);
2581 /* force DOOR font inside door area */
2582 SetFontStatus(GAME_MODE_PSEUDO_DOOR);
2584 DrawTextBuffer(sx + sx_offset, sy + sy_offset, text_final, font_nr,
2585 line_length, -1, max_lines, line_spacing, mask_mode,
2586 request.autowrap, request.centered, FALSE);
2590 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2591 RedrawGadget(tool_gadget[i]);
2593 // store readily prepared envelope request for later use when animating
2594 BlitBitmap(backbuffer, bitmap_db_store_2, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2596 if (text_door_style)
2597 free(text_door_style);
2600 void AnimateEnvelopeRequest(int anim_mode, int action)
2602 int graphic = IMG_BACKGROUND_REQUEST;
2603 boolean draw_masked = graphic_info[graphic].draw_masked;
2604 int delay_value_normal = request.step_delay;
2605 int delay_value_fast = delay_value_normal / 2;
2606 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2607 boolean no_delay = (tape.warp_forward);
2608 int delay_value = (ffwd_delay ? delay_value_fast : delay_value_normal);
2609 int anim_delay_value = (no_delay ? 0 : delay_value + 500 * 0) / 2;
2610 unsigned int anim_delay = 0;
2612 int tile_size = MAX(request.step_offset, 1);
2613 int max_xsize = request.width / tile_size;
2614 int max_ysize = request.height / tile_size;
2615 int max_xsize_inner = max_xsize - 2;
2616 int max_ysize_inner = max_ysize - 2;
2618 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize_inner : 0);
2619 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize_inner : 0);
2620 int xend = max_xsize_inner;
2621 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize_inner : 0);
2622 int xstep = (xstart < xend ? 1 : 0);
2623 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2625 int end = MAX(xend - xstart, yend - ystart);
2628 if (setup.quick_doors)
2635 for (i = start; i <= end; i++)
2637 int last_frame = end; // last frame of this "for" loop
2638 int x = xstart + i * xstep;
2639 int y = ystart + i * ystep;
2640 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2641 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2642 int xsize_size_left = (xsize - 1) * tile_size;
2643 int ysize_size_top = (ysize - 1) * tile_size;
2644 int max_xsize_pos = (max_xsize - 1) * tile_size;
2645 int max_ysize_pos = (max_ysize - 1) * tile_size;
2646 int width = xsize * tile_size;
2647 int height = ysize * tile_size;
2652 setRequestPosition(&src_x, &src_y, FALSE);
2653 setRequestPositionExt(&dst_x, &dst_y, width, height, FALSE);
2655 BlitBitmap(bitmap_db_store_1, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2657 for (yy = 0; yy < 2; yy++)
2659 for (xx = 0; xx < 2; xx++)
2661 int src_xx = src_x + xx * max_xsize_pos;
2662 int src_yy = src_y + yy * max_ysize_pos;
2663 int dst_xx = dst_x + xx * xsize_size_left;
2664 int dst_yy = dst_y + yy * ysize_size_top;
2665 int xx_size = (xx ? tile_size : xsize_size_left);
2666 int yy_size = (yy ? tile_size : ysize_size_top);
2669 BlitBitmapMasked(bitmap_db_store_2, backbuffer,
2670 src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
2672 BlitBitmap(bitmap_db_store_2, backbuffer,
2673 src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
2677 redraw_mask |= REDRAW_FIELD;
2681 SkipUntilDelayReached(&anim_delay, anim_delay_value, &i, last_frame);
2685 void ShowEnvelopeRequest(char *text, unsigned int req_state, int action)
2687 int graphic = IMG_BACKGROUND_REQUEST;
2688 int sound_opening = SND_REQUEST_OPENING;
2689 int sound_closing = SND_REQUEST_CLOSING;
2690 int anim_mode_1 = request.anim_mode; /* (higher priority) */
2691 int anim_mode_2 = graphic_info[graphic].anim_mode; /* (lower priority) */
2692 int anim_mode = (anim_mode_1 != ANIM_DEFAULT ? anim_mode_1 : anim_mode_2);
2693 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2694 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2696 if (game_status == GAME_MODE_PLAYING)
2697 BlitScreenToBitmap(backbuffer);
2699 SetDrawtoField(DRAW_TO_BACKBUFFER);
2701 // SetDrawBackgroundMask(REDRAW_NONE);
2703 if (action == ACTION_OPENING)
2705 BlitBitmap(backbuffer, bitmap_db_store_1, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2707 if (req_state & REQ_ASK)
2709 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2710 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2712 else if (req_state & REQ_CONFIRM)
2714 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2716 else if (req_state & REQ_PLAYER)
2718 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2719 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2720 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2721 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2724 DrawEnvelopeRequest(text);
2727 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
2729 if (action == ACTION_OPENING)
2731 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2733 if (anim_mode == ANIM_DEFAULT)
2734 AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_OPENING);
2736 AnimateEnvelopeRequest(main_anim_mode, ACTION_OPENING);
2740 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2742 if (anim_mode != ANIM_NONE)
2743 AnimateEnvelopeRequest(main_anim_mode, ACTION_CLOSING);
2745 if (anim_mode == ANIM_DEFAULT)
2746 AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_CLOSING);
2749 game.envelope_active = FALSE;
2751 if (action == ACTION_CLOSING)
2752 BlitBitmap(bitmap_db_store_1, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2754 // SetDrawBackgroundMask(last_draw_background_mask);
2756 redraw_mask |= REDRAW_FIELD;
2760 if (action == ACTION_CLOSING &&
2761 game_status == GAME_MODE_PLAYING &&
2762 level.game_engine_type == GAME_ENGINE_TYPE_RND)
2763 SetDrawtoField(DRAW_TO_FIELDBUFFER);
2766 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
2770 int graphic = el2preimg(element);
2772 getSizedGraphicSource(graphic, 0, tilesize, &src_bitmap, &src_x, &src_y);
2773 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
2776 void DrawLevel(int draw_background_mask)
2780 SetMainBackgroundImage(IMG_BACKGROUND_PLAYING);
2781 SetDrawBackgroundMask(draw_background_mask);
2785 for (x = BX1; x <= BX2; x++)
2786 for (y = BY1; y <= BY2; y++)
2787 DrawScreenField(x, y);
2789 redraw_mask |= REDRAW_FIELD;
2792 void DrawSizedLevel(int size_x, int size_y, int scroll_x, int scroll_y,
2797 for (x = 0; x < size_x; x++)
2798 for (y = 0; y < size_y; y++)
2799 DrawSizedElementOrWall(x, y, scroll_x, scroll_y, tilesize);
2801 redraw_mask |= REDRAW_FIELD;
2804 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
2808 for (x = 0; x < size_x; x++)
2809 for (y = 0; y < size_y; y++)
2810 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
2812 redraw_mask |= REDRAW_FIELD;
2815 static void DrawPreviewLevelPlayfieldExt(int from_x, int from_y)
2817 boolean show_level_border = (BorderElement != EL_EMPTY);
2818 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2819 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2820 int tile_size = preview.tile_size;
2821 int preview_width = preview.xsize * tile_size;
2822 int preview_height = preview.ysize * tile_size;
2823 int real_preview_xsize = MIN(level_xsize, preview.xsize);
2824 int real_preview_ysize = MIN(level_ysize, preview.ysize);
2825 int real_preview_width = real_preview_xsize * tile_size;
2826 int real_preview_height = real_preview_ysize * tile_size;
2827 int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
2828 int dst_y = SY + ALIGNED_YPOS(preview.y, preview_height, preview.valign);
2831 if (!IN_GFX_FIELD_FULL(dst_x, dst_y + preview_height - 1))
2834 DrawBackground(dst_x, dst_y, preview_width, preview_height);
2836 dst_x += (preview_width - real_preview_width) / 2;
2837 dst_y += (preview_height - real_preview_height) / 2;
2839 for (x = 0; x < real_preview_xsize; x++)
2841 for (y = 0; y < real_preview_ysize; y++)
2843 int lx = from_x + x + (show_level_border ? -1 : 0);
2844 int ly = from_y + y + (show_level_border ? -1 : 0);
2845 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
2846 getBorderElement(lx, ly));
2848 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
2849 element, tile_size);
2853 redraw_mask |= REDRAW_FIELD;
2856 #define MICROLABEL_EMPTY 0
2857 #define MICROLABEL_LEVEL_NAME 1
2858 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
2859 #define MICROLABEL_LEVEL_AUTHOR 3
2860 #define MICROLABEL_IMPORTED_FROM_HEAD 4
2861 #define MICROLABEL_IMPORTED_FROM 5
2862 #define MICROLABEL_IMPORTED_BY_HEAD 6
2863 #define MICROLABEL_IMPORTED_BY 7
2865 static int getMaxTextLength(struct TextPosInfo *pos, int font_nr)
2867 int max_text_width = SXSIZE;
2868 int font_width = getFontWidth(font_nr);
2870 if (pos->align == ALIGN_CENTER)
2871 max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
2872 else if (pos->align == ALIGN_RIGHT)
2873 max_text_width = pos->x;
2875 max_text_width = SXSIZE - pos->x;
2877 return max_text_width / font_width;
2880 static void DrawPreviewLevelLabelExt(int mode)
2882 struct TextPosInfo *pos = &menu.main.text.level_info_2;
2883 char label_text[MAX_OUTPUT_LINESIZE + 1];
2884 int max_len_label_text;
2885 int font_nr = pos->font;
2888 if (!IN_GFX_FIELD_FULL(pos->x, pos->y + getFontHeight(pos->font)))
2891 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
2892 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
2893 mode == MICROLABEL_IMPORTED_BY_HEAD)
2894 font_nr = pos->font_alt;
2896 max_len_label_text = getMaxTextLength(pos, font_nr);
2898 if (pos->size != -1)
2899 max_len_label_text = pos->size;
2901 for (i = 0; i < max_len_label_text; i++)
2902 label_text[i] = ' ';
2903 label_text[max_len_label_text] = '\0';
2905 if (strlen(label_text) > 0)
2906 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2909 (mode == MICROLABEL_LEVEL_NAME ? level.name :
2910 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
2911 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
2912 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
2913 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
2914 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
2915 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
2916 max_len_label_text);
2917 label_text[max_len_label_text] = '\0';
2919 if (strlen(label_text) > 0)
2920 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2922 redraw_mask |= REDRAW_FIELD;
2925 static void DrawPreviewLevelExt(boolean restart)
2927 static unsigned int scroll_delay = 0;
2928 static unsigned int label_delay = 0;
2929 static int from_x, from_y, scroll_direction;
2930 static int label_state, label_counter;
2931 unsigned int scroll_delay_value = preview.step_delay;
2932 boolean show_level_border = (BorderElement != EL_EMPTY);
2933 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2934 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2941 if (preview.anim_mode == ANIM_CENTERED)
2943 if (level_xsize > preview.xsize)
2944 from_x = (level_xsize - preview.xsize) / 2;
2945 if (level_ysize > preview.ysize)
2946 from_y = (level_ysize - preview.ysize) / 2;
2949 from_x += preview.xoffset;
2950 from_y += preview.yoffset;
2952 scroll_direction = MV_RIGHT;
2956 DrawPreviewLevelPlayfieldExt(from_x, from_y);
2957 DrawPreviewLevelLabelExt(label_state);
2959 /* initialize delay counters */
2960 DelayReached(&scroll_delay, 0);
2961 DelayReached(&label_delay, 0);
2963 if (leveldir_current->name)
2965 struct TextPosInfo *pos = &menu.main.text.level_info_1;
2966 char label_text[MAX_OUTPUT_LINESIZE + 1];
2967 int font_nr = pos->font;
2968 int max_len_label_text = getMaxTextLength(pos, font_nr);
2970 if (pos->size != -1)
2971 max_len_label_text = pos->size;
2973 strncpy(label_text, leveldir_current->name, max_len_label_text);
2974 label_text[max_len_label_text] = '\0';
2976 if (IN_GFX_FIELD_FULL(pos->x, pos->y + getFontHeight(pos->font)))
2977 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2983 /* scroll preview level, if needed */
2984 if (preview.anim_mode != ANIM_NONE &&
2985 (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
2986 DelayReached(&scroll_delay, scroll_delay_value))
2988 switch (scroll_direction)
2993 from_x -= preview.step_offset;
2994 from_x = (from_x < 0 ? 0 : from_x);
2997 scroll_direction = MV_UP;
3001 if (from_x < level_xsize - preview.xsize)
3003 from_x += preview.step_offset;
3004 from_x = (from_x > level_xsize - preview.xsize ?
3005 level_xsize - preview.xsize : from_x);
3008 scroll_direction = MV_DOWN;
3014 from_y -= preview.step_offset;
3015 from_y = (from_y < 0 ? 0 : from_y);
3018 scroll_direction = MV_RIGHT;
3022 if (from_y < level_ysize - preview.ysize)
3024 from_y += preview.step_offset;
3025 from_y = (from_y > level_ysize - preview.ysize ?
3026 level_ysize - preview.ysize : from_y);
3029 scroll_direction = MV_LEFT;
3036 DrawPreviewLevelPlayfieldExt(from_x, from_y);
3039 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
3040 /* redraw micro level label, if needed */
3041 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
3042 !strEqual(level.author, ANONYMOUS_NAME) &&
3043 !strEqual(level.author, leveldir_current->name) &&
3044 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
3046 int max_label_counter = 23;
3048 if (leveldir_current->imported_from != NULL &&
3049 strlen(leveldir_current->imported_from) > 0)
3050 max_label_counter += 14;
3051 if (leveldir_current->imported_by != NULL &&
3052 strlen(leveldir_current->imported_by) > 0)
3053 max_label_counter += 14;
3055 label_counter = (label_counter + 1) % max_label_counter;
3056 label_state = (label_counter >= 0 && label_counter <= 7 ?
3057 MICROLABEL_LEVEL_NAME :
3058 label_counter >= 9 && label_counter <= 12 ?
3059 MICROLABEL_LEVEL_AUTHOR_HEAD :
3060 label_counter >= 14 && label_counter <= 21 ?
3061 MICROLABEL_LEVEL_AUTHOR :
3062 label_counter >= 23 && label_counter <= 26 ?
3063 MICROLABEL_IMPORTED_FROM_HEAD :
3064 label_counter >= 28 && label_counter <= 35 ?
3065 MICROLABEL_IMPORTED_FROM :
3066 label_counter >= 37 && label_counter <= 40 ?
3067 MICROLABEL_IMPORTED_BY_HEAD :
3068 label_counter >= 42 && label_counter <= 49 ?
3069 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
3071 if (leveldir_current->imported_from == NULL &&
3072 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
3073 label_state == MICROLABEL_IMPORTED_FROM))
3074 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
3075 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
3077 DrawPreviewLevelLabelExt(label_state);
3081 void DrawPreviewLevelInitial()
3083 DrawPreviewLevelExt(TRUE);
3086 void DrawPreviewLevelAnimation()
3088 DrawPreviewLevelExt(FALSE);
3091 inline static void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
3092 int graphic, int sync_frame,
3095 int frame = getGraphicAnimationFrame(graphic, sync_frame);
3097 if (mask_mode == USE_MASKING)
3098 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
3100 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
3103 void DrawFixedGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
3104 int graphic, int sync_frame, int mask_mode)
3106 int frame = getGraphicAnimationFrame(graphic, sync_frame);
3108 if (mask_mode == USE_MASKING)
3109 DrawFixedGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
3111 DrawFixedGraphicExt(dst_bitmap, x, y, graphic, frame);
3114 inline static void DrawGraphicAnimation(int x, int y, int graphic)
3116 int lx = LEVELX(x), ly = LEVELY(y);
3118 if (!IN_SCR_FIELD(x, y))
3121 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
3122 graphic, GfxFrame[lx][ly], NO_MASKING);
3124 MarkTileDirty(x, y);
3127 void DrawFixedGraphicAnimation(int x, int y, int graphic)
3129 int lx = LEVELX(x), ly = LEVELY(y);
3131 if (!IN_SCR_FIELD(x, y))
3134 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
3135 graphic, GfxFrame[lx][ly], NO_MASKING);
3136 MarkTileDirty(x, y);
3139 void DrawLevelGraphicAnimation(int x, int y, int graphic)
3141 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
3144 void DrawLevelElementAnimation(int x, int y, int element)
3146 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
3148 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
3151 void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
3153 int sx = SCREENX(x), sy = SCREENY(y);
3155 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
3158 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
3161 DrawGraphicAnimation(sx, sy, graphic);
3164 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
3165 DrawLevelFieldCrumbled(x, y);
3167 if (GFX_CRUMBLED(Feld[x][y]))
3168 DrawLevelFieldCrumbled(x, y);
3172 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
3174 int sx = SCREENX(x), sy = SCREENY(y);
3177 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
3180 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
3182 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
3185 DrawGraphicAnimation(sx, sy, graphic);
3187 if (GFX_CRUMBLED(element))
3188 DrawLevelFieldCrumbled(x, y);
3191 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
3193 if (player->use_murphy)
3195 /* this works only because currently only one player can be "murphy" ... */
3196 static int last_horizontal_dir = MV_LEFT;
3197 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
3199 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3200 last_horizontal_dir = move_dir;
3202 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
3204 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
3206 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
3212 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
3215 static boolean equalGraphics(int graphic1, int graphic2)
3217 struct GraphicInfo *g1 = &graphic_info[graphic1];
3218 struct GraphicInfo *g2 = &graphic_info[graphic2];
3220 return (g1->bitmap == g2->bitmap &&
3221 g1->src_x == g2->src_x &&
3222 g1->src_y == g2->src_y &&
3223 g1->anim_frames == g2->anim_frames &&
3224 g1->anim_delay == g2->anim_delay &&
3225 g1->anim_mode == g2->anim_mode);
3228 void DrawAllPlayers()
3232 for (i = 0; i < MAX_PLAYERS; i++)
3233 if (stored_player[i].active)
3234 DrawPlayer(&stored_player[i]);
3237 void DrawPlayerField(int x, int y)
3239 if (!IS_PLAYER(x, y))
3242 DrawPlayer(PLAYERINFO(x, y));
3245 #define DRAW_PLAYER_OVER_PUSHED_ELEMENT 1
3247 void DrawPlayer(struct PlayerInfo *player)
3249 int jx = player->jx;
3250 int jy = player->jy;
3251 int move_dir = player->MovDir;
3252 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
3253 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
3254 int last_jx = (player->is_moving ? jx - dx : jx);
3255 int last_jy = (player->is_moving ? jy - dy : jy);
3256 int next_jx = jx + dx;
3257 int next_jy = jy + dy;
3258 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
3259 boolean player_is_opaque = FALSE;
3260 int sx = SCREENX(jx), sy = SCREENY(jy);
3261 int sxx = 0, syy = 0;
3262 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
3264 int action = ACTION_DEFAULT;
3265 int last_player_graphic = getPlayerGraphic(player, move_dir);
3266 int last_player_frame = player->Frame;
3269 /* GfxElement[][] is set to the element the player is digging or collecting;
3270 remove also for off-screen player if the player is not moving anymore */
3271 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
3272 GfxElement[jx][jy] = EL_UNDEFINED;
3274 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
3278 if (!IN_LEV_FIELD(jx, jy))
3280 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
3281 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
3282 printf("DrawPlayerField(): This should never happen!\n");
3287 if (element == EL_EXPLOSION)
3290 action = (player->is_pushing ? ACTION_PUSHING :
3291 player->is_digging ? ACTION_DIGGING :
3292 player->is_collecting ? ACTION_COLLECTING :
3293 player->is_moving ? ACTION_MOVING :
3294 player->is_snapping ? ACTION_SNAPPING :
3295 player->is_dropping ? ACTION_DROPPING :
3296 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
3298 if (player->is_waiting)
3299 move_dir = player->dir_waiting;
3301 InitPlayerGfxAnimation(player, action, move_dir);
3303 /* ----------------------------------------------------------------------- */
3304 /* draw things in the field the player is leaving, if needed */
3305 /* ----------------------------------------------------------------------- */
3307 if (player->is_moving)
3309 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
3311 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
3313 if (last_element == EL_DYNAMITE_ACTIVE ||
3314 last_element == EL_EM_DYNAMITE_ACTIVE ||
3315 last_element == EL_SP_DISK_RED_ACTIVE)
3316 DrawDynamite(last_jx, last_jy);
3318 DrawLevelFieldThruMask(last_jx, last_jy);
3320 else if (last_element == EL_DYNAMITE_ACTIVE ||
3321 last_element == EL_EM_DYNAMITE_ACTIVE ||
3322 last_element == EL_SP_DISK_RED_ACTIVE)
3323 DrawDynamite(last_jx, last_jy);
3325 /* !!! this is not enough to prevent flickering of players which are
3326 moving next to each others without a free tile between them -- this
3327 can only be solved by drawing all players layer by layer (first the
3328 background, then the foreground etc.) !!! => TODO */
3329 else if (!IS_PLAYER(last_jx, last_jy))
3330 DrawLevelField(last_jx, last_jy);
3333 DrawLevelField(last_jx, last_jy);
3336 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
3337 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
3340 if (!IN_SCR_FIELD(sx, sy))
3343 /* ----------------------------------------------------------------------- */
3344 /* draw things behind the player, if needed */
3345 /* ----------------------------------------------------------------------- */
3348 DrawLevelElement(jx, jy, Back[jx][jy]);
3349 else if (IS_ACTIVE_BOMB(element))
3350 DrawLevelElement(jx, jy, EL_EMPTY);
3353 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
3355 int old_element = GfxElement[jx][jy];
3356 int old_graphic = el_act_dir2img(old_element, action, move_dir);
3357 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
3359 if (GFX_CRUMBLED(old_element))
3360 DrawLevelFieldCrumbledDigging(jx, jy, move_dir, player->StepFrame);
3362 DrawGraphic(sx, sy, old_graphic, frame);
3364 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
3365 player_is_opaque = TRUE;
3369 GfxElement[jx][jy] = EL_UNDEFINED;
3371 /* make sure that pushed elements are drawn with correct frame rate */
3372 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
3374 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
3375 GfxFrame[jx][jy] = player->StepFrame;
3377 DrawLevelField(jx, jy);
3381 #if !DRAW_PLAYER_OVER_PUSHED_ELEMENT
3382 /* ----------------------------------------------------------------------- */
3383 /* draw player himself */
3384 /* ----------------------------------------------------------------------- */
3386 graphic = getPlayerGraphic(player, move_dir);
3388 /* in the case of changed player action or direction, prevent the current
3389 animation frame from being restarted for identical animations */
3390 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
3391 player->Frame = last_player_frame;
3393 frame = getGraphicAnimationFrame(graphic, player->Frame);
3397 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3398 sxx = player->GfxPos;
3400 syy = player->GfxPos;
3403 if (player_is_opaque)
3404 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
3406 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3408 if (SHIELD_ON(player))
3410 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
3411 IMG_SHIELD_NORMAL_ACTIVE);
3412 int frame = getGraphicAnimationFrame(graphic, -1);
3414 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3418 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
3421 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3422 sxx = player->GfxPos;
3424 syy = player->GfxPos;
3428 /* ----------------------------------------------------------------------- */
3429 /* draw things the player is pushing, if needed */
3430 /* ----------------------------------------------------------------------- */
3432 if (player->is_pushing && player->is_moving)
3434 int px = SCREENX(jx), py = SCREENY(jy);
3435 int pxx = (TILEX - ABS(sxx)) * dx;
3436 int pyy = (TILEY - ABS(syy)) * dy;
3437 int gfx_frame = GfxFrame[jx][jy];
3443 if (!IS_MOVING(jx, jy)) /* push movement already finished */
3445 element = Feld[next_jx][next_jy];
3446 gfx_frame = GfxFrame[next_jx][next_jy];
3449 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
3451 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
3452 frame = getGraphicAnimationFrame(graphic, sync_frame);
3454 /* draw background element under pushed element (like the Sokoban field) */
3455 if (game.use_masked_pushing && IS_MOVING(jx, jy))
3457 /* this allows transparent pushing animation over non-black background */
3460 DrawLevelElement(jx, jy, Back[jx][jy]);
3462 DrawLevelElement(jx, jy, EL_EMPTY);
3464 if (Back[next_jx][next_jy])
3465 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3467 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
3469 else if (Back[next_jx][next_jy])
3470 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3473 /* do not draw (EM style) pushing animation when pushing is finished */
3474 /* (two-tile animations usually do not contain start and end frame) */
3475 if (graphic_info[graphic].double_movement && !IS_MOVING(jx, jy))
3476 DrawLevelElement(next_jx, next_jy, Feld[next_jx][next_jy]);
3478 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3480 /* masked drawing is needed for EMC style (double) movement graphics */
3481 /* !!! (ONLY WHEN DRAWING PUSHED ELEMENT OVER THE PLAYER) !!! */
3482 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3486 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
3487 /* ----------------------------------------------------------------------- */
3488 /* draw player himself */
3489 /* ----------------------------------------------------------------------- */
3491 graphic = getPlayerGraphic(player, move_dir);
3493 /* in the case of changed player action or direction, prevent the current
3494 animation frame from being restarted for identical animations */
3495 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
3496 player->Frame = last_player_frame;
3498 frame = getGraphicAnimationFrame(graphic, player->Frame);
3502 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3503 sxx = player->GfxPos;
3505 syy = player->GfxPos;
3508 if (player_is_opaque)
3509 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
3511 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3513 if (SHIELD_ON(player))
3515 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
3516 IMG_SHIELD_NORMAL_ACTIVE);
3517 int frame = getGraphicAnimationFrame(graphic, -1);
3519 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3523 /* ----------------------------------------------------------------------- */
3524 /* draw things in front of player (active dynamite or dynabombs) */
3525 /* ----------------------------------------------------------------------- */
3527 if (IS_ACTIVE_BOMB(element))
3529 graphic = el2img(element);
3530 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
3532 if (game.emulation == EMU_SUPAPLEX)
3533 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
3535 DrawGraphicThruMask(sx, sy, graphic, frame);
3538 if (player_is_moving && last_element == EL_EXPLOSION)
3540 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
3541 GfxElement[last_jx][last_jy] : EL_EMPTY);
3542 int graphic = el_act2img(element, ACTION_EXPLODING);
3543 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
3544 int phase = ExplodePhase[last_jx][last_jy] - 1;
3545 int frame = getGraphicAnimationFrame(graphic, phase - delay);
3548 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
3551 /* ----------------------------------------------------------------------- */
3552 /* draw elements the player is just walking/passing through/under */
3553 /* ----------------------------------------------------------------------- */
3555 if (player_is_moving)
3557 /* handle the field the player is leaving ... */
3558 if (IS_ACCESSIBLE_INSIDE(last_element))
3559 DrawLevelField(last_jx, last_jy);
3560 else if (IS_ACCESSIBLE_UNDER(last_element))
3561 DrawLevelFieldThruMask(last_jx, last_jy);
3564 /* do not redraw accessible elements if the player is just pushing them */
3565 if (!player_is_moving || !player->is_pushing)
3567 /* ... and the field the player is entering */
3568 if (IS_ACCESSIBLE_INSIDE(element))
3569 DrawLevelField(jx, jy);
3570 else if (IS_ACCESSIBLE_UNDER(element))
3571 DrawLevelFieldThruMask(jx, jy);
3574 MarkTileDirty(sx, sy);
3577 /* ------------------------------------------------------------------------- */
3579 void WaitForEventToContinue()
3581 boolean still_wait = TRUE;
3583 /* simulate releasing mouse button over last gadget, if still pressed */
3585 HandleGadgets(-1, -1, 0);
3587 button_status = MB_RELEASED;
3601 case EVENT_BUTTONPRESS:
3602 case EVENT_KEYPRESS:
3606 case EVENT_KEYRELEASE:
3607 ClearPlayerAction();
3611 HandleOtherEvents(&event);
3615 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3624 #define MAX_REQUEST_LINES 13
3625 #define MAX_REQUEST_LINE_FONT1_LEN 7
3626 #define MAX_REQUEST_LINE_FONT2_LEN 10
3628 static int RequestHandleEvents(unsigned int req_state)
3630 boolean level_solved = (game_status == GAME_MODE_PLAYING &&
3631 local_player->LevelSolved_GameEnd);
3632 int width = request.width;
3633 int height = request.height;
3637 setRequestPosition(&sx, &sy, FALSE);
3639 button_status = MB_RELEASED;
3641 request_gadget_id = -1;
3648 SetDrawtoField(DRAW_TO_FIELDBUFFER);
3650 HandleGameActions();
3652 SetDrawtoField(DRAW_TO_BACKBUFFER);
3654 if (global.use_envelope_request)
3656 /* copy current state of request area to middle of playfield area */
3657 BlitBitmap(bitmap_db_store_2, drawto, sx, sy, width, height, sx, sy);
3665 while (NextValidEvent(&event))
3669 case EVENT_BUTTONPRESS:
3670 case EVENT_BUTTONRELEASE:
3671 case EVENT_MOTIONNOTIFY:
3675 if (event.type == EVENT_MOTIONNOTIFY)
3680 motion_status = TRUE;
3681 mx = ((MotionEvent *) &event)->x;
3682 my = ((MotionEvent *) &event)->y;
3686 motion_status = FALSE;
3687 mx = ((ButtonEvent *) &event)->x;
3688 my = ((ButtonEvent *) &event)->y;
3689 if (event.type == EVENT_BUTTONPRESS)
3690 button_status = ((ButtonEvent *) &event)->button;
3692 button_status = MB_RELEASED;
3695 /* this sets 'request_gadget_id' */
3696 HandleGadgets(mx, my, button_status);
3698 switch (request_gadget_id)
3700 case TOOL_CTRL_ID_YES:
3703 case TOOL_CTRL_ID_NO:
3706 case TOOL_CTRL_ID_CONFIRM:
3707 result = TRUE | FALSE;
3710 case TOOL_CTRL_ID_PLAYER_1:
3713 case TOOL_CTRL_ID_PLAYER_2:
3716 case TOOL_CTRL_ID_PLAYER_3:
3719 case TOOL_CTRL_ID_PLAYER_4:
3730 case EVENT_KEYPRESS:
3732 Key key = GetEventKey((KeyEvent *)&event, TRUE);
3737 if (req_state & REQ_CONFIRM)
3742 #if defined(TARGET_SDL2)
3749 #if defined(TARGET_SDL2)
3756 HandleKeysDebug(key);
3760 if (req_state & REQ_PLAYER)
3766 case EVENT_KEYRELEASE:
3767 ClearPlayerAction();
3771 HandleOtherEvents(&event);
3776 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3778 int joy = AnyJoystick();
3780 if (joy & JOY_BUTTON_1)
3782 else if (joy & JOY_BUTTON_2)
3788 if (global.use_envelope_request)
3790 /* copy back current state of pressed buttons inside request area */
3791 BlitBitmap(drawto, bitmap_db_store_2, sx, sy, width, height, sx, sy);
3801 static boolean RequestDoor(char *text, unsigned int req_state)
3803 unsigned int old_door_state;
3804 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
3805 int font_nr = FONT_TEXT_2;
3810 if (maxWordLengthInString(text) > MAX_REQUEST_LINE_FONT1_LEN)
3812 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
3813 font_nr = FONT_TEXT_1;
3816 if (game_status == GAME_MODE_PLAYING)
3817 BlitScreenToBitmap(backbuffer);
3819 /* disable deactivated drawing when quick-loading level tape recording */
3820 if (tape.playing && tape.deactivate_display)
3821 TapeDeactivateDisplayOff(TRUE);
3823 SetMouseCursor(CURSOR_DEFAULT);
3825 #if defined(NETWORK_AVALIABLE)
3826 /* pause network game while waiting for request to answer */
3827 if (options.network &&
3828 game_status == GAME_MODE_PLAYING &&
3829 req_state & REQUEST_WAIT_FOR_INPUT)
3830 SendToServer_PausePlaying();
3833 old_door_state = GetDoorState();
3835 /* simulate releasing mouse button over last gadget, if still pressed */
3837 HandleGadgets(-1, -1, 0);
3841 /* draw released gadget before proceeding */
3844 if (old_door_state & DOOR_OPEN_1)
3846 CloseDoor(DOOR_CLOSE_1);
3848 /* save old door content */
3849 BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
3850 0 * DXSIZE, 0, DXSIZE, DYSIZE, 1 * DXSIZE, 0);
3853 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
3854 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3856 /* clear door drawing field */
3857 DrawBackground(DX, DY, DXSIZE, DYSIZE);
3859 /* force DOOR font inside door area */
3860 SetFontStatus(GAME_MODE_PSEUDO_DOOR);
3862 /* write text for request */
3863 for (text_ptr = text, ty = 0; ty < MAX_REQUEST_LINES; ty++)
3865 char text_line[max_request_line_len + 1];
3871 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
3873 tc = *(text_ptr + tx);
3874 // if (!tc || tc == ' ')
3875 if (!tc || tc == ' ' || tc == '?' || tc == '!')
3879 if ((tc == '?' || tc == '!') && tl == 0)
3889 strncpy(text_line, text_ptr, tl);
3892 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
3893 DY + 8 + ty * (getFontHeight(font_nr) + 2),
3894 text_line, font_nr);
3896 text_ptr += tl + (tc == ' ' ? 1 : 0);
3897 // text_ptr += tl + (tc == ' ' || tc == '?' || tc == '!' ? 1 : 0);
3902 if (req_state & REQ_ASK)
3904 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
3905 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
3907 else if (req_state & REQ_CONFIRM)
3909 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
3911 else if (req_state & REQ_PLAYER)
3913 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
3914 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
3915 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
3916 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
3919 /* copy request gadgets to door backbuffer */
3920 BlitBitmap(drawto, bitmap_db_door_1, DX, DY, DXSIZE, DYSIZE, 0, 0);
3922 OpenDoor(DOOR_OPEN_1);
3924 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
3926 if (game_status == GAME_MODE_PLAYING)
3928 SetPanelBackground();
3929 SetDrawBackgroundMask(REDRAW_DOOR_1);
3933 SetDrawBackgroundMask(REDRAW_FIELD);
3939 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3941 // ---------- handle request buttons ----------
3942 result = RequestHandleEvents(req_state);
3946 if (!(req_state & REQ_STAY_OPEN))
3948 CloseDoor(DOOR_CLOSE_1);
3950 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
3951 (req_state & REQ_REOPEN))
3952 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
3957 if (game_status == GAME_MODE_PLAYING)
3959 SetPanelBackground();
3960 SetDrawBackgroundMask(REDRAW_DOOR_1);
3964 SetDrawBackgroundMask(REDRAW_FIELD);
3967 #if defined(NETWORK_AVALIABLE)
3968 /* continue network game after request */
3969 if (options.network &&
3970 game_status == GAME_MODE_PLAYING &&
3971 req_state & REQUEST_WAIT_FOR_INPUT)
3972 SendToServer_ContinuePlaying();
3975 /* restore deactivated drawing when quick-loading level tape recording */
3976 if (tape.playing && tape.deactivate_display)
3977 TapeDeactivateDisplayOn();
3982 static boolean RequestEnvelope(char *text, unsigned int req_state)
3986 if (game_status == GAME_MODE_PLAYING)
3987 BlitScreenToBitmap(backbuffer);
3989 /* disable deactivated drawing when quick-loading level tape recording */
3990 if (tape.playing && tape.deactivate_display)
3991 TapeDeactivateDisplayOff(TRUE);
3993 SetMouseCursor(CURSOR_DEFAULT);
3995 #if defined(NETWORK_AVALIABLE)
3996 /* pause network game while waiting for request to answer */
3997 if (options.network &&
3998 game_status == GAME_MODE_PLAYING &&
3999 req_state & REQUEST_WAIT_FOR_INPUT)
4000 SendToServer_PausePlaying();
4003 /* simulate releasing mouse button over last gadget, if still pressed */
4005 HandleGadgets(-1, -1, 0);
4009 // (replace with setting corresponding request background)
4010 // SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
4011 // SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4013 /* clear door drawing field */
4014 // DrawBackground(DX, DY, DXSIZE, DYSIZE);
4016 ShowEnvelopeRequest(text, req_state, ACTION_OPENING);
4018 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
4020 if (game_status == GAME_MODE_PLAYING)
4022 SetPanelBackground();
4023 SetDrawBackgroundMask(REDRAW_DOOR_1);
4027 SetDrawBackgroundMask(REDRAW_FIELD);
4033 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4035 // ---------- handle request buttons ----------
4036 result = RequestHandleEvents(req_state);
4040 ShowEnvelopeRequest(text, req_state, ACTION_CLOSING);
4044 if (game_status == GAME_MODE_PLAYING)
4046 SetPanelBackground();
4047 SetDrawBackgroundMask(REDRAW_DOOR_1);
4051 SetDrawBackgroundMask(REDRAW_FIELD);
4054 #if defined(NETWORK_AVALIABLE)
4055 /* continue network game after request */
4056 if (options.network &&
4057 game_status == GAME_MODE_PLAYING &&
4058 req_state & REQUEST_WAIT_FOR_INPUT)
4059 SendToServer_ContinuePlaying();
4062 /* restore deactivated drawing when quick-loading level tape recording */
4063 if (tape.playing && tape.deactivate_display)
4064 TapeDeactivateDisplayOn();
4069 boolean Request(char *text, unsigned int req_state)
4071 if (global.use_envelope_request)
4072 return RequestEnvelope(text, req_state);
4074 return RequestDoor(text, req_state);
4077 static int compareDoorPartOrderInfo(const void *object1, const void *object2)
4079 const struct DoorPartOrderInfo *dpo1 = (struct DoorPartOrderInfo *)object1;
4080 const struct DoorPartOrderInfo *dpo2 = (struct DoorPartOrderInfo *)object2;
4083 if (dpo1->sort_priority != dpo2->sort_priority)
4084 compare_result = dpo1->sort_priority - dpo2->sort_priority;
4086 compare_result = dpo1->nr - dpo2->nr;
4088 return compare_result;
4091 void InitGraphicCompatibilityInfo_Doors()
4097 struct DoorInfo *door;
4101 { DOOR_1, IMG_GFX_DOOR_1_PART_1, IMG_GFX_DOOR_1_PART_8, &door_1 },
4102 { DOOR_2, IMG_GFX_DOOR_2_PART_1, IMG_GFX_DOOR_2_PART_8, &door_2 },
4104 { -1, -1, -1, NULL }
4106 struct Rect door_rect_list[] =
4108 { DX, DY, DXSIZE, DYSIZE },
4109 { VX, VY, VXSIZE, VYSIZE }
4113 for (i = 0; doors[i].door_token != -1; i++)
4115 int door_token = doors[i].door_token;
4116 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
4117 int part_1 = doors[i].part_1;
4118 int part_8 = doors[i].part_8;
4119 int part_2 = part_1 + 1;
4120 int part_3 = part_1 + 2;
4121 struct DoorInfo *door = doors[i].door;
4122 struct Rect *door_rect = &door_rect_list[door_index];
4123 boolean door_gfx_redefined = FALSE;
4125 /* check if any door part graphic definitions have been redefined */
4127 for (j = 0; door_part_controls[j].door_token != -1; j++)
4129 struct DoorPartControlInfo *dpc = &door_part_controls[j];
4130 struct FileInfo *fi = getImageListEntryFromImageID(dpc->graphic);
4132 if (dpc->door_token == door_token && fi->redefined)
4133 door_gfx_redefined = TRUE;
4136 /* check for old-style door graphic/animation modifications */
4138 if (!door_gfx_redefined)
4140 if (door->anim_mode & ANIM_STATIC_PANEL)
4142 door->panel.step_xoffset = 0;
4143 door->panel.step_yoffset = 0;
4146 if (door->anim_mode & (ANIM_HORIZONTAL | ANIM_VERTICAL))
4148 struct GraphicInfo *g_part_1 = &graphic_info[part_1];
4149 struct GraphicInfo *g_part_2 = &graphic_info[part_2];
4150 int num_door_steps, num_panel_steps;
4152 /* remove door part graphics other than the two default wings */
4154 for (j = 0; door_part_controls[j].door_token != -1; j++)
4156 struct DoorPartControlInfo *dpc = &door_part_controls[j];
4157 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4159 if (dpc->graphic >= part_3 &&
4160 dpc->graphic <= part_8)
4164 /* set graphics and screen positions of the default wings */
4166 g_part_1->width = door_rect->width;
4167 g_part_1->height = door_rect->height;
4168 g_part_2->width = door_rect->width;
4169 g_part_2->height = door_rect->height;
4170 g_part_2->src_x = door_rect->width;
4171 g_part_2->src_y = g_part_1->src_y;
4173 door->part_2.x = door->part_1.x;
4174 door->part_2.y = door->part_1.y;
4176 if (door->width != -1)
4178 g_part_1->width = door->width;
4179 g_part_2->width = door->width;
4181 // special treatment for graphics and screen position of right wing
4182 g_part_2->src_x += door_rect->width - door->width;
4183 door->part_2.x += door_rect->width - door->width;
4186 if (door->height != -1)
4188 g_part_1->height = door->height;
4189 g_part_2->height = door->height;
4191 // special treatment for graphics and screen position of bottom wing
4192 g_part_2->src_y += door_rect->height - door->height;
4193 door->part_2.y += door_rect->height - door->height;
4196 /* set animation delays for the default wings and panels */
4198 door->part_1.step_delay = door->step_delay;
4199 door->part_2.step_delay = door->step_delay;
4200 door->panel.step_delay = door->step_delay;
4202 /* set animation draw order for the default wings */
4204 door->part_1.sort_priority = 2; /* draw left wing over ... */
4205 door->part_2.sort_priority = 1; /* ... right wing */
4207 /* set animation draw offset for the default wings */
4209 if (door->anim_mode & ANIM_HORIZONTAL)
4211 door->part_1.step_xoffset = door->step_offset;
4212 door->part_1.step_yoffset = 0;
4213 door->part_2.step_xoffset = door->step_offset * -1;
4214 door->part_2.step_yoffset = 0;
4216 num_door_steps = g_part_1->width / door->step_offset;
4218 else // ANIM_VERTICAL
4220 door->part_1.step_xoffset = 0;
4221 door->part_1.step_yoffset = door->step_offset;
4222 door->part_2.step_xoffset = 0;
4223 door->part_2.step_yoffset = door->step_offset * -1;
4225 num_door_steps = g_part_1->height / door->step_offset;
4228 /* set animation draw offset for the default panels */
4230 if (door->step_offset > 1)
4232 num_panel_steps = 2 * door_rect->height / door->step_offset;
4233 door->panel.start_step = num_panel_steps - num_door_steps;
4234 door->panel.start_step_closing = door->panel.start_step;
4238 num_panel_steps = door_rect->height / door->step_offset;
4239 door->panel.start_step = num_panel_steps - num_door_steps / 2;
4240 door->panel.start_step_closing = door->panel.start_step;
4241 door->panel.step_delay *= 2;
4252 for (i = 0; door_part_controls[i].door_token != -1; i++)
4254 struct DoorPartControlInfo *dpc = &door_part_controls[i];
4255 struct DoorPartOrderInfo *dpo = &door_part_order[i];
4257 /* initialize "start_step_opening" and "start_step_closing", if needed */
4258 if (dpc->pos->start_step_opening == 0 &&
4259 dpc->pos->start_step_closing == 0)
4261 // dpc->pos->start_step_opening = dpc->pos->start_step;
4262 dpc->pos->start_step_closing = dpc->pos->start_step;
4265 /* fill structure for door part draw order (sorted below) */
4267 dpo->sort_priority = dpc->pos->sort_priority;
4270 /* sort door part controls according to sort_priority and graphic number */
4271 qsort(door_part_order, MAX_DOOR_PARTS,
4272 sizeof(struct DoorPartOrderInfo), compareDoorPartOrderInfo);
4275 unsigned int OpenDoor(unsigned int door_state)
4277 if (door_state & DOOR_COPY_BACK)
4279 if (door_state & DOOR_OPEN_1)
4280 BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
4281 1 * DXSIZE, 0, DXSIZE, DYSIZE, 0 * DXSIZE, 0);
4283 if (door_state & DOOR_OPEN_2)
4284 BlitBitmap(bitmap_db_door_2, bitmap_db_door_2,
4285 1 * VXSIZE, 0, VXSIZE, VYSIZE, 0 * VXSIZE, 0);
4287 door_state &= ~DOOR_COPY_BACK;
4290 return MoveDoor(door_state);
4293 unsigned int CloseDoor(unsigned int door_state)
4295 unsigned int old_door_state = GetDoorState();
4297 if (!(door_state & DOOR_NO_COPY_BACK))
4299 if (old_door_state & DOOR_OPEN_1)
4300 BlitBitmap(backbuffer, bitmap_db_door_1,
4301 DX, DY, DXSIZE, DYSIZE, 0, 0);
4303 if (old_door_state & DOOR_OPEN_2)
4304 BlitBitmap(backbuffer, bitmap_db_door_2,
4305 VX, VY, VXSIZE, VYSIZE, 0, 0);
4307 door_state &= ~DOOR_NO_COPY_BACK;
4310 return MoveDoor(door_state);
4313 unsigned int GetDoorState()
4315 return MoveDoor(DOOR_GET_STATE);
4318 unsigned int SetDoorState(unsigned int door_state)
4320 return MoveDoor(door_state | DOOR_SET_STATE);
4323 int euclid(int a, int b)
4325 return (b ? euclid(b, a % b) : a);
4328 unsigned int MoveDoor(unsigned int door_state)
4330 struct Rect door_rect_list[] =
4332 { DX, DY, DXSIZE, DYSIZE },
4333 { VX, VY, VXSIZE, VYSIZE }
4335 static int door1 = DOOR_CLOSE_1;
4336 static int door2 = DOOR_CLOSE_2;
4337 unsigned int door_delay = 0;
4338 unsigned int door_delay_value;
4341 if (door_state == DOOR_GET_STATE)
4342 return (door1 | door2);
4344 if (door_state & DOOR_SET_STATE)
4346 if (door_state & DOOR_ACTION_1)
4347 door1 = door_state & DOOR_ACTION_1;
4348 if (door_state & DOOR_ACTION_2)
4349 door2 = door_state & DOOR_ACTION_2;
4351 return (door1 | door2);
4354 if (!(door_state & DOOR_FORCE_REDRAW))
4356 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
4357 door_state &= ~DOOR_OPEN_1;
4358 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
4359 door_state &= ~DOOR_CLOSE_1;
4360 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
4361 door_state &= ~DOOR_OPEN_2;
4362 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
4363 door_state &= ~DOOR_CLOSE_2;
4366 if (global.autoplay_leveldir)
4368 door_state |= DOOR_NO_DELAY;
4369 door_state &= ~DOOR_CLOSE_ALL;
4372 if (game_status == GAME_MODE_EDITOR)
4373 door_state |= DOOR_NO_DELAY;
4375 if (door_state & DOOR_ACTION)
4377 boolean door_panel_drawn[NUM_DOORS];
4378 boolean panel_has_doors[NUM_DOORS];
4379 boolean door_part_skip[MAX_DOOR_PARTS];
4380 boolean door_part_done[MAX_DOOR_PARTS];
4381 boolean door_part_done_all;
4382 int num_steps[MAX_DOOR_PARTS];
4383 int max_move_delay = 0; // delay for complete animations of all doors
4384 int max_step_delay = 0; // delay (ms) between two animation frames
4385 int num_move_steps = 0; // number of animation steps for all doors
4386 int max_move_delay_doors_only = 0; // delay for doors only (no panel)
4387 int num_move_steps_doors_only = 0; // steps for doors only (no panel)
4388 int current_move_delay = 0;
4392 for (i = 0; i < NUM_DOORS; i++)
4393 panel_has_doors[i] = FALSE;
4395 for (i = 0; i < MAX_DOOR_PARTS; i++)
4397 struct DoorPartControlInfo *dpc = &door_part_controls[i];
4398 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4399 int door_token = dpc->door_token;
4401 door_part_done[i] = FALSE;
4402 door_part_skip[i] = (!(door_state & door_token) ||
4406 for (i = 0; i < MAX_DOOR_PARTS; i++)
4408 int nr = door_part_order[i].nr;
4409 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
4410 struct DoorPartPosInfo *pos = dpc->pos;
4411 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4412 int door_token = dpc->door_token;
4413 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
4414 boolean is_panel = DOOR_PART_IS_PANEL(nr);
4415 int step_xoffset = ABS(pos->step_xoffset);
4416 int step_yoffset = ABS(pos->step_yoffset);
4417 int step_delay = pos->step_delay;
4418 int current_door_state = door_state & door_token;
4419 boolean door_opening = ((current_door_state & DOOR_OPEN) != 0);
4420 boolean door_closing = ((current_door_state & DOOR_CLOSE) != 0);
4421 boolean part_opening = (is_panel ? door_closing : door_opening);
4422 int start_step = (part_opening ? pos->start_step_opening :
4423 pos->start_step_closing);
4424 float move_xsize = (step_xoffset ? g->width : 0);
4425 float move_ysize = (step_yoffset ? g->height : 0);
4426 int move_xsteps = (step_xoffset ? ceil(move_xsize / step_xoffset) : 0);
4427 int move_ysteps = (step_yoffset ? ceil(move_ysize / step_yoffset) : 0);
4428 int move_steps = (move_xsteps && move_ysteps ?
4429 MIN(move_xsteps, move_ysteps) :
4430 move_xsteps ? move_xsteps : move_ysteps) - start_step;
4431 int move_delay = move_steps * step_delay;
4433 if (door_part_skip[nr])
4436 max_move_delay = MAX(max_move_delay, move_delay);
4437 max_step_delay = (max_step_delay == 0 ? step_delay :
4438 euclid(max_step_delay, step_delay));
4439 num_steps[nr] = move_steps;
4443 max_move_delay_doors_only = MAX(max_move_delay_doors_only, move_delay);
4445 panel_has_doors[door_index] = TRUE;
4449 max_step_delay = MAX(1, max_step_delay); // prevent division by zero
4451 num_move_steps = max_move_delay / max_step_delay;
4452 num_move_steps_doors_only = max_move_delay_doors_only / max_step_delay;
4454 door_delay_value = max_step_delay;
4456 if ((door_state & DOOR_NO_DELAY) || setup.quick_doors)
4458 start = num_move_steps - 1;
4462 /* opening door sound has priority over simultaneously closing door */
4463 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
4464 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
4465 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
4466 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
4469 for (k = start; k < num_move_steps; k++)
4471 int last_frame = num_move_steps - 1; // last frame of this "for" loop
4473 door_part_done_all = TRUE;
4475 for (i = 0; i < NUM_DOORS; i++)
4476 door_panel_drawn[i] = FALSE;
4478 for (i = 0; i < MAX_DOOR_PARTS; i++)
4480 int nr = door_part_order[i].nr;
4481 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
4482 struct DoorPartPosInfo *pos = dpc->pos;
4483 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4484 int door_token = dpc->door_token;
4485 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
4486 boolean is_panel = DOOR_PART_IS_PANEL(nr);
4487 boolean is_panel_and_door_has_closed = FALSE;
4488 struct Rect *door_rect = &door_rect_list[door_index];
4489 Bitmap *bitmap_db_door = (door_token == DOOR_1 ? bitmap_db_door_1 :
4491 Bitmap *bitmap = (is_panel ? bitmap_db_door : g->bitmap);
4492 int current_door_state = door_state & door_token;
4493 boolean door_opening = ((current_door_state & DOOR_OPEN) != 0);
4494 boolean door_closing = !door_opening;
4495 boolean part_opening = (is_panel ? door_closing : door_opening);
4496 boolean part_closing = !part_opening;
4497 int start_step = (part_opening ? pos->start_step_opening :
4498 pos->start_step_closing);
4499 int step_delay = pos->step_delay;
4500 int step_factor = step_delay / max_step_delay;
4501 int k1 = (step_factor ? k / step_factor + 1 : k);
4502 int k2 = (part_opening ? k1 + start_step : num_steps[nr] - k1);
4503 int kk = MAX(0, k2);
4506 int src_x, src_y, src_xx, src_yy;
4507 int dst_x, dst_y, dst_xx, dst_yy;
4510 if (door_part_skip[nr])
4513 if (!(door_state & door_token))
4521 int k2_door = (door_opening ? k : num_move_steps_doors_only - k - 1);
4522 int kk_door = MAX(0, k2_door);
4523 int sync_frame = kk_door * door_delay_value;
4524 int frame = getGraphicAnimationFrame(dpc->graphic, sync_frame);
4526 getFixedGraphicSource(dpc->graphic, frame, &bitmap,
4527 &g_src_x, &g_src_y);
4532 if (!door_panel_drawn[door_index])
4534 ClearRectangle(drawto, door_rect->x, door_rect->y,
4535 door_rect->width, door_rect->height);
4537 door_panel_drawn[door_index] = TRUE;
4540 // draw opening or closing door parts
4542 if (pos->step_xoffset < 0) // door part on right side
4545 dst_xx = pos->x + ABS(kk * pos->step_xoffset);
4548 if (dst_xx + width > door_rect->width)
4549 width = door_rect->width - dst_xx;
4551 else // door part on left side
4554 dst_xx = pos->x - kk * pos->step_xoffset;
4558 src_xx = ABS(dst_xx);
4562 width = g->width - src_xx;
4564 if (width > door_rect->width)
4565 width = door_rect->width;
4567 // printf("::: k == %d [%d] \n", k, start_step);
4570 if (pos->step_yoffset < 0) // door part on bottom side
4573 dst_yy = pos->y + ABS(kk * pos->step_yoffset);
4576 if (dst_yy + height > door_rect->height)
4577 height = door_rect->height - dst_yy;
4579 else // door part on top side
4582 dst_yy = pos->y - kk * pos->step_yoffset;
4586 src_yy = ABS(dst_yy);
4590 height = g->height - src_yy;
4593 src_x = g_src_x + src_xx;
4594 src_y = g_src_y + src_yy;
4596 dst_x = door_rect->x + dst_xx;
4597 dst_y = door_rect->y + dst_yy;
4599 is_panel_and_door_has_closed =
4602 panel_has_doors[door_index] &&
4603 k >= num_move_steps_doors_only - 1);
4605 if (width >= 0 && width <= g->width &&
4606 height >= 0 && height <= g->height &&
4607 !is_panel_and_door_has_closed)
4609 if (is_panel || !pos->draw_masked)
4610 BlitBitmap(bitmap, drawto, src_x, src_y, width, height,
4613 BlitBitmapMasked(bitmap, drawto, src_x, src_y, width, height,
4617 redraw_mask |= REDRAW_DOOR_FROM_TOKEN(door_token);
4619 if ((part_opening && (width < 0 || height < 0)) ||
4620 (part_closing && (width >= g->width && height >= g->height)))
4621 door_part_done[nr] = TRUE;
4623 // continue door part animations, but not panel after door has closed
4624 if (!door_part_done[nr] && !is_panel_and_door_has_closed)
4625 door_part_done_all = FALSE;
4628 if (!(door_state & DOOR_NO_DELAY))
4632 SkipUntilDelayReached(&door_delay, door_delay_value, &k, last_frame);
4634 current_move_delay += max_step_delay;
4637 if (door_part_done_all)
4642 if (door_state & DOOR_ACTION_1)
4643 door1 = door_state & DOOR_ACTION_1;
4644 if (door_state & DOOR_ACTION_2)
4645 door2 = door_state & DOOR_ACTION_2;
4647 // draw masked border over door area
4648 DrawMaskedBorder(REDRAW_DOOR_1);
4649 DrawMaskedBorder(REDRAW_DOOR_2);
4651 return (door1 | door2);
4654 static boolean useSpecialEditorDoor()
4656 int graphic = IMG_GLOBAL_BORDER_EDITOR;
4657 boolean redefined = getImageListEntryFromImageID(graphic)->redefined;
4659 // do not draw special editor door if editor border defined or redefined
4660 if (graphic_info[graphic].bitmap != NULL || redefined)
4663 // do not draw special editor door if global border defined to be empty
4664 if (graphic_info[IMG_GLOBAL_BORDER].bitmap == NULL)
4667 // do not draw special editor door if viewport definitions do not match
4671 EY + EYSIZE != VY + VYSIZE)
4677 void DrawSpecialEditorDoor()
4679 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
4680 int top_border_width = gfx1->width;
4681 int top_border_height = gfx1->height;
4682 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
4683 int ex = EX - outer_border;
4684 int ey = EY - outer_border;
4685 int vy = VY - outer_border;
4686 int exsize = EXSIZE + 2 * outer_border;
4688 if (!useSpecialEditorDoor())
4691 /* draw bigger level editor toolbox window */
4692 BlitBitmap(gfx1->bitmap, drawto, gfx1->src_x, gfx1->src_y,
4693 top_border_width, top_border_height, ex, ey - top_border_height);
4694 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto, ex, vy,
4695 exsize, EYSIZE - VYSIZE + outer_border, ex, ey);
4697 redraw_mask |= REDRAW_ALL;
4700 void UndrawSpecialEditorDoor()
4702 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
4703 int top_border_width = gfx1->width;
4704 int top_border_height = gfx1->height;
4705 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
4706 int ex = EX - outer_border;
4707 int ey = EY - outer_border;
4708 int ey_top = ey - top_border_height;
4709 int exsize = EXSIZE + 2 * outer_border;
4710 int eysize = EYSIZE + 2 * outer_border;
4712 if (!useSpecialEditorDoor())
4715 /* draw normal tape recorder window */
4716 if (graphic_info[IMG_GLOBAL_BORDER].bitmap)
4718 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
4719 ex, ey_top, top_border_width, top_border_height,
4721 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
4722 ex, ey, exsize, eysize, ex, ey);
4726 // if screen background is set to "[NONE]", clear editor toolbox window
4727 ClearRectangle(drawto, ex, ey_top, top_border_width, top_border_height);
4728 ClearRectangle(drawto, ex, ey, exsize, eysize);
4731 redraw_mask |= REDRAW_ALL;
4735 /* ---------- new tool button stuff ---------------------------------------- */
4740 struct TextPosInfo *pos;
4743 } toolbutton_info[NUM_TOOL_BUTTONS] =
4746 IMG_GFX_REQUEST_BUTTON_YES, &request.button.yes,
4747 TOOL_CTRL_ID_YES, "yes"
4750 IMG_GFX_REQUEST_BUTTON_NO, &request.button.no,
4751 TOOL_CTRL_ID_NO, "no"
4754 IMG_GFX_REQUEST_BUTTON_CONFIRM, &request.button.confirm,
4755 TOOL_CTRL_ID_CONFIRM, "confirm"
4758 IMG_GFX_REQUEST_BUTTON_PLAYER_1, &request.button.player_1,
4759 TOOL_CTRL_ID_PLAYER_1, "player 1"
4762 IMG_GFX_REQUEST_BUTTON_PLAYER_2, &request.button.player_2,
4763 TOOL_CTRL_ID_PLAYER_2, "player 2"
4766 IMG_GFX_REQUEST_BUTTON_PLAYER_3, &request.button.player_3,
4767 TOOL_CTRL_ID_PLAYER_3, "player 3"
4770 IMG_GFX_REQUEST_BUTTON_PLAYER_4, &request.button.player_4,
4771 TOOL_CTRL_ID_PLAYER_4, "player 4"
4775 void CreateToolButtons()
4779 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4781 struct GraphicInfo *gfx = &graphic_info[toolbutton_info[i].graphic];
4782 struct TextPosInfo *pos = toolbutton_info[i].pos;
4783 struct GadgetInfo *gi;
4784 Bitmap *deco_bitmap = None;
4785 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
4786 unsigned int event_mask = GD_EVENT_RELEASED;
4789 int gd_x = gfx->src_x;
4790 int gd_y = gfx->src_y;
4791 int gd_xp = gfx->src_x + gfx->pressed_xoffset;
4792 int gd_yp = gfx->src_y + gfx->pressed_yoffset;
4795 if (global.use_envelope_request)
4796 setRequestPosition(&dx, &dy, TRUE);
4798 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
4800 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
4802 getSizedGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr), 0,
4803 pos->size, &deco_bitmap, &deco_x, &deco_y);
4804 deco_xpos = (gfx->width - pos->size) / 2;
4805 deco_ypos = (gfx->height - pos->size) / 2;
4808 gi = CreateGadget(GDI_CUSTOM_ID, id,
4809 GDI_INFO_TEXT, toolbutton_info[i].infotext,
4810 GDI_X, dx + GDI_ACTIVE_POS(pos->x),
4811 GDI_Y, dy + GDI_ACTIVE_POS(pos->y),
4812 GDI_WIDTH, gfx->width,
4813 GDI_HEIGHT, gfx->height,
4814 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
4815 GDI_STATE, GD_BUTTON_UNPRESSED,
4816 GDI_DESIGN_UNPRESSED, gfx->bitmap, gd_x, gd_y,
4817 GDI_DESIGN_PRESSED, gfx->bitmap, gd_xp, gd_yp,
4818 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
4819 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
4820 GDI_DECORATION_SIZE, pos->size, pos->size,
4821 GDI_DECORATION_SHIFTING, 1, 1,
4822 GDI_DIRECT_DRAW, FALSE,
4823 GDI_EVENT_MASK, event_mask,
4824 GDI_CALLBACK_ACTION, HandleToolButtons,
4828 Error(ERR_EXIT, "cannot create gadget");
4830 tool_gadget[id] = gi;
4834 void FreeToolButtons()
4838 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4839 FreeGadget(tool_gadget[i]);
4842 static void UnmapToolButtons()
4846 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4847 UnmapGadget(tool_gadget[i]);
4850 static void HandleToolButtons(struct GadgetInfo *gi)
4852 request_gadget_id = gi->custom_id;
4855 static struct Mapping_EM_to_RND_object
4858 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
4859 boolean is_backside; /* backside of moving element */
4865 em_object_mapping_list[] =
4868 Xblank, TRUE, FALSE,
4872 Yacid_splash_eB, FALSE, FALSE,
4873 EL_ACID_SPLASH_RIGHT, -1, -1
4876 Yacid_splash_wB, FALSE, FALSE,
4877 EL_ACID_SPLASH_LEFT, -1, -1
4880 #ifdef EM_ENGINE_BAD_ROLL
4882 Xstone_force_e, FALSE, FALSE,
4883 EL_ROCK, -1, MV_BIT_RIGHT
4886 Xstone_force_w, FALSE, FALSE,
4887 EL_ROCK, -1, MV_BIT_LEFT
4890 Xnut_force_e, FALSE, FALSE,
4891 EL_NUT, -1, MV_BIT_RIGHT
4894 Xnut_force_w, FALSE, FALSE,
4895 EL_NUT, -1, MV_BIT_LEFT
4898 Xspring_force_e, FALSE, FALSE,
4899 EL_SPRING, -1, MV_BIT_RIGHT
4902 Xspring_force_w, FALSE, FALSE,
4903 EL_SPRING, -1, MV_BIT_LEFT
4906 Xemerald_force_e, FALSE, FALSE,
4907 EL_EMERALD, -1, MV_BIT_RIGHT
4910 Xemerald_force_w, FALSE, FALSE,
4911 EL_EMERALD, -1, MV_BIT_LEFT
4914 Xdiamond_force_e, FALSE, FALSE,
4915 EL_DIAMOND, -1, MV_BIT_RIGHT
4918 Xdiamond_force_w, FALSE, FALSE,
4919 EL_DIAMOND, -1, MV_BIT_LEFT
4922 Xbomb_force_e, FALSE, FALSE,
4923 EL_BOMB, -1, MV_BIT_RIGHT
4926 Xbomb_force_w, FALSE, FALSE,
4927 EL_BOMB, -1, MV_BIT_LEFT
4929 #endif /* EM_ENGINE_BAD_ROLL */
4932 Xstone, TRUE, FALSE,
4936 Xstone_pause, FALSE, FALSE,
4940 Xstone_fall, FALSE, FALSE,
4944 Ystone_s, FALSE, FALSE,
4945 EL_ROCK, ACTION_FALLING, -1
4948 Ystone_sB, FALSE, TRUE,
4949 EL_ROCK, ACTION_FALLING, -1
4952 Ystone_e, FALSE, FALSE,
4953 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
4956 Ystone_eB, FALSE, TRUE,
4957 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
4960 Ystone_w, FALSE, FALSE,
4961 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
4964 Ystone_wB, FALSE, TRUE,
4965 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
4972 Xnut_pause, FALSE, FALSE,
4976 Xnut_fall, FALSE, FALSE,
4980 Ynut_s, FALSE, FALSE,
4981 EL_NUT, ACTION_FALLING, -1
4984 Ynut_sB, FALSE, TRUE,
4985 EL_NUT, ACTION_FALLING, -1
4988 Ynut_e, FALSE, FALSE,
4989 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
4992 Ynut_eB, FALSE, TRUE,
4993 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
4996 Ynut_w, FALSE, FALSE,
4997 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
5000 Ynut_wB, FALSE, TRUE,
5001 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
5004 Xbug_n, TRUE, FALSE,
5008 Xbug_e, TRUE, FALSE,
5009 EL_BUG_RIGHT, -1, -1
5012 Xbug_s, TRUE, FALSE,
5016 Xbug_w, TRUE, FALSE,
5020 Xbug_gon, FALSE, FALSE,
5024 Xbug_goe, FALSE, FALSE,
5025 EL_BUG_RIGHT, -1, -1
5028 Xbug_gos, FALSE, FALSE,
5032 Xbug_gow, FALSE, FALSE,
5036 Ybug_n, FALSE, FALSE,
5037 EL_BUG, ACTION_MOVING, MV_BIT_UP
5040 Ybug_nB, FALSE, TRUE,
5041 EL_BUG, ACTION_MOVING, MV_BIT_UP
5044 Ybug_e, FALSE, FALSE,
5045 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
5048 Ybug_eB, FALSE, TRUE,
5049 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
5052 Ybug_s, FALSE, FALSE,
5053 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
5056 Ybug_sB, FALSE, TRUE,
5057 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
5060 Ybug_w, FALSE, FALSE,
5061 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
5064 Ybug_wB, FALSE, TRUE,
5065 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
5068 Ybug_w_n, FALSE, FALSE,
5069 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
5072 Ybug_n_e, FALSE, FALSE,
5073 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
5076 Ybug_e_s, FALSE, FALSE,
5077 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
5080 Ybug_s_w, FALSE, FALSE,
5081 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
5084 Ybug_e_n, FALSE, FALSE,
5085 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
5088 Ybug_s_e, FALSE, FALSE,
5089 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
5092 Ybug_w_s, FALSE, FALSE,
5093 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
5096 Ybug_n_w, FALSE, FALSE,
5097 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
5100 Ybug_stone, FALSE, FALSE,
5101 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
5104 Ybug_spring, FALSE, FALSE,
5105 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
5108 Xtank_n, TRUE, FALSE,
5109 EL_SPACESHIP_UP, -1, -1
5112 Xtank_e, TRUE, FALSE,
5113 EL_SPACESHIP_RIGHT, -1, -1
5116 Xtank_s, TRUE, FALSE,
5117 EL_SPACESHIP_DOWN, -1, -1
5120 Xtank_w, TRUE, FALSE,
5121 EL_SPACESHIP_LEFT, -1, -1
5124 Xtank_gon, FALSE, FALSE,
5125 EL_SPACESHIP_UP, -1, -1
5128 Xtank_goe, FALSE, FALSE,
5129 EL_SPACESHIP_RIGHT, -1, -1
5132 Xtank_gos, FALSE, FALSE,
5133 EL_SPACESHIP_DOWN, -1, -1
5136 Xtank_gow, FALSE, FALSE,
5137 EL_SPACESHIP_LEFT, -1, -1
5140 Ytank_n, FALSE, FALSE,
5141 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
5144 Ytank_nB, FALSE, TRUE,
5145 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
5148 Ytank_e, FALSE, FALSE,
5149 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
5152 Ytank_eB, FALSE, TRUE,
5153 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
5156 Ytank_s, FALSE, FALSE,
5157 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
5160 Ytank_sB, FALSE, TRUE,
5161 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
5164 Ytank_w, FALSE, FALSE,
5165 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
5168 Ytank_wB, FALSE, TRUE,
5169 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
5172 Ytank_w_n, FALSE, FALSE,
5173 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
5176 Ytank_n_e, FALSE, FALSE,
5177 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
5180 Ytank_e_s, FALSE, FALSE,
5181 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
5184 Ytank_s_w, FALSE, FALSE,
5185 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
5188 Ytank_e_n, FALSE, FALSE,
5189 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
5192 Ytank_s_e, FALSE, FALSE,
5193 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
5196 Ytank_w_s, FALSE, FALSE,
5197 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
5200 Ytank_n_w, FALSE, FALSE,
5201 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
5204 Ytank_stone, FALSE, FALSE,
5205 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
5208 Ytank_spring, FALSE, FALSE,
5209 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
5212 Xandroid, TRUE, FALSE,
5213 EL_EMC_ANDROID, ACTION_ACTIVE, -1
5216 Xandroid_1_n, FALSE, FALSE,
5217 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
5220 Xandroid_2_n, FALSE, FALSE,
5221 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
5224 Xandroid_1_e, FALSE, FALSE,
5225 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
5228 Xandroid_2_e, FALSE, FALSE,
5229 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
5232 Xandroid_1_w, FALSE, FALSE,
5233 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
5236 Xandroid_2_w, FALSE, FALSE,
5237 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
5240 Xandroid_1_s, FALSE, FALSE,
5241 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
5244 Xandroid_2_s, FALSE, FALSE,
5245 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
5248 Yandroid_n, FALSE, FALSE,
5249 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
5252 Yandroid_nB, FALSE, TRUE,
5253 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
5256 Yandroid_ne, FALSE, FALSE,
5257 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
5260 Yandroid_neB, FALSE, TRUE,
5261 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
5264 Yandroid_e, FALSE, FALSE,
5265 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
5268 Yandroid_eB, FALSE, TRUE,
5269 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
5272 Yandroid_se, FALSE, FALSE,
5273 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
5276 Yandroid_seB, FALSE, TRUE,
5277 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
5280 Yandroid_s, FALSE, FALSE,
5281 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
5284 Yandroid_sB, FALSE, TRUE,
5285 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
5288 Yandroid_sw, FALSE, FALSE,
5289 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
5292 Yandroid_swB, FALSE, TRUE,
5293 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
5296 Yandroid_w, FALSE, FALSE,
5297 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
5300 Yandroid_wB, FALSE, TRUE,
5301 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
5304 Yandroid_nw, FALSE, FALSE,
5305 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
5308 Yandroid_nwB, FALSE, TRUE,
5309 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
5312 Xspring, TRUE, FALSE,
5316 Xspring_pause, FALSE, FALSE,
5320 Xspring_e, FALSE, FALSE,
5324 Xspring_w, FALSE, FALSE,
5328 Xspring_fall, FALSE, FALSE,
5332 Yspring_s, FALSE, FALSE,
5333 EL_SPRING, ACTION_FALLING, -1
5336 Yspring_sB, FALSE, TRUE,
5337 EL_SPRING, ACTION_FALLING, -1
5340 Yspring_e, FALSE, FALSE,
5341 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
5344 Yspring_eB, FALSE, TRUE,
5345 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
5348 Yspring_w, FALSE, FALSE,
5349 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
5352 Yspring_wB, FALSE, TRUE,
5353 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
5356 Yspring_kill_e, FALSE, FALSE,
5357 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
5360 Yspring_kill_eB, FALSE, TRUE,
5361 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
5364 Yspring_kill_w, FALSE, FALSE,
5365 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
5368 Yspring_kill_wB, FALSE, TRUE,
5369 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
5372 Xeater_n, TRUE, FALSE,
5373 EL_YAMYAM_UP, -1, -1
5376 Xeater_e, TRUE, FALSE,
5377 EL_YAMYAM_RIGHT, -1, -1
5380 Xeater_w, TRUE, FALSE,
5381 EL_YAMYAM_LEFT, -1, -1
5384 Xeater_s, TRUE, FALSE,
5385 EL_YAMYAM_DOWN, -1, -1
5388 Yeater_n, FALSE, FALSE,
5389 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
5392 Yeater_nB, FALSE, TRUE,
5393 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
5396 Yeater_e, FALSE, FALSE,
5397 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
5400 Yeater_eB, FALSE, TRUE,
5401 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
5404 Yeater_s, FALSE, FALSE,
5405 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
5408 Yeater_sB, FALSE, TRUE,
5409 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
5412 Yeater_w, FALSE, FALSE,
5413 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
5416 Yeater_wB, FALSE, TRUE,
5417 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
5420 Yeater_stone, FALSE, FALSE,
5421 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
5424 Yeater_spring, FALSE, FALSE,
5425 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
5428 Xalien, TRUE, FALSE,
5432 Xalien_pause, FALSE, FALSE,
5436 Yalien_n, FALSE, FALSE,
5437 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
5440 Yalien_nB, FALSE, TRUE,
5441 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
5444 Yalien_e, FALSE, FALSE,
5445 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
5448 Yalien_eB, FALSE, TRUE,
5449 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
5452 Yalien_s, FALSE, FALSE,
5453 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
5456 Yalien_sB, FALSE, TRUE,
5457 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
5460 Yalien_w, FALSE, FALSE,
5461 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
5464 Yalien_wB, FALSE, TRUE,
5465 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
5468 Yalien_stone, FALSE, FALSE,
5469 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
5472 Yalien_spring, FALSE, FALSE,
5473 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
5476 Xemerald, TRUE, FALSE,
5480 Xemerald_pause, FALSE, FALSE,
5484 Xemerald_fall, FALSE, FALSE,
5488 Xemerald_shine, FALSE, FALSE,
5489 EL_EMERALD, ACTION_TWINKLING, -1
5492 Yemerald_s, FALSE, FALSE,
5493 EL_EMERALD, ACTION_FALLING, -1
5496 Yemerald_sB, FALSE, TRUE,
5497 EL_EMERALD, ACTION_FALLING, -1
5500 Yemerald_e, FALSE, FALSE,
5501 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
5504 Yemerald_eB, FALSE, TRUE,
5505 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
5508 Yemerald_w, FALSE, FALSE,
5509 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
5512 Yemerald_wB, FALSE, TRUE,
5513 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
5516 Yemerald_eat, FALSE, FALSE,
5517 EL_EMERALD, ACTION_COLLECTING, -1
5520 Yemerald_stone, FALSE, FALSE,
5521 EL_NUT, ACTION_BREAKING, -1
5524 Xdiamond, TRUE, FALSE,
5528 Xdiamond_pause, FALSE, FALSE,
5532 Xdiamond_fall, FALSE, FALSE,
5536 Xdiamond_shine, FALSE, FALSE,
5537 EL_DIAMOND, ACTION_TWINKLING, -1
5540 Ydiamond_s, FALSE, FALSE,
5541 EL_DIAMOND, ACTION_FALLING, -1
5544 Ydiamond_sB, FALSE, TRUE,
5545 EL_DIAMOND, ACTION_FALLING, -1
5548 Ydiamond_e, FALSE, FALSE,
5549 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
5552 Ydiamond_eB, FALSE, TRUE,
5553 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
5556 Ydiamond_w, FALSE, FALSE,
5557 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
5560 Ydiamond_wB, FALSE, TRUE,
5561 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
5564 Ydiamond_eat, FALSE, FALSE,
5565 EL_DIAMOND, ACTION_COLLECTING, -1
5568 Ydiamond_stone, FALSE, FALSE,
5569 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
5572 Xdrip_fall, TRUE, FALSE,
5573 EL_AMOEBA_DROP, -1, -1
5576 Xdrip_stretch, FALSE, FALSE,
5577 EL_AMOEBA_DROP, ACTION_FALLING, -1
5580 Xdrip_stretchB, FALSE, TRUE,
5581 EL_AMOEBA_DROP, ACTION_FALLING, -1
5584 Xdrip_eat, FALSE, FALSE,
5585 EL_AMOEBA_DROP, ACTION_GROWING, -1
5588 Ydrip_s1, FALSE, FALSE,
5589 EL_AMOEBA_DROP, ACTION_FALLING, -1
5592 Ydrip_s1B, FALSE, TRUE,
5593 EL_AMOEBA_DROP, ACTION_FALLING, -1
5596 Ydrip_s2, FALSE, FALSE,
5597 EL_AMOEBA_DROP, ACTION_FALLING, -1
5600 Ydrip_s2B, FALSE, TRUE,
5601 EL_AMOEBA_DROP, ACTION_FALLING, -1
5608 Xbomb_pause, FALSE, FALSE,
5612 Xbomb_fall, FALSE, FALSE,
5616 Ybomb_s, FALSE, FALSE,
5617 EL_BOMB, ACTION_FALLING, -1
5620 Ybomb_sB, FALSE, TRUE,
5621 EL_BOMB, ACTION_FALLING, -1
5624 Ybomb_e, FALSE, FALSE,
5625 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
5628 Ybomb_eB, FALSE, TRUE,
5629 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
5632 Ybomb_w, FALSE, FALSE,
5633 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
5636 Ybomb_wB, FALSE, TRUE,
5637 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
5640 Ybomb_eat, FALSE, FALSE,
5641 EL_BOMB, ACTION_ACTIVATING, -1
5644 Xballoon, TRUE, FALSE,
5648 Yballoon_n, FALSE, FALSE,
5649 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
5652 Yballoon_nB, FALSE, TRUE,
5653 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
5656 Yballoon_e, FALSE, FALSE,
5657 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
5660 Yballoon_eB, FALSE, TRUE,
5661 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
5664 Yballoon_s, FALSE, FALSE,
5665 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
5668 Yballoon_sB, FALSE, TRUE,
5669 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
5672 Yballoon_w, FALSE, FALSE,
5673 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
5676 Yballoon_wB, FALSE, TRUE,
5677 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
5680 Xgrass, TRUE, FALSE,
5681 EL_EMC_GRASS, -1, -1
5684 Ygrass_nB, FALSE, FALSE,
5685 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
5688 Ygrass_eB, FALSE, FALSE,
5689 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
5692 Ygrass_sB, FALSE, FALSE,
5693 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
5696 Ygrass_wB, FALSE, FALSE,
5697 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
5704 Ydirt_nB, FALSE, FALSE,
5705 EL_SAND, ACTION_DIGGING, MV_BIT_UP
5708 Ydirt_eB, FALSE, FALSE,
5709 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
5712 Ydirt_sB, FALSE, FALSE,
5713 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
5716 Ydirt_wB, FALSE, FALSE,
5717 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
5720 Xacid_ne, TRUE, FALSE,
5721 EL_ACID_POOL_TOPRIGHT, -1, -1
5724 Xacid_se, TRUE, FALSE,
5725 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
5728 Xacid_s, TRUE, FALSE,
5729 EL_ACID_POOL_BOTTOM, -1, -1
5732 Xacid_sw, TRUE, FALSE,
5733 EL_ACID_POOL_BOTTOMLEFT, -1, -1
5736 Xacid_nw, TRUE, FALSE,
5737 EL_ACID_POOL_TOPLEFT, -1, -1
5740 Xacid_1, TRUE, FALSE,
5744 Xacid_2, FALSE, FALSE,
5748 Xacid_3, FALSE, FALSE,
5752 Xacid_4, FALSE, FALSE,
5756 Xacid_5, FALSE, FALSE,
5760 Xacid_6, FALSE, FALSE,
5764 Xacid_7, FALSE, FALSE,
5768 Xacid_8, FALSE, FALSE,
5772 Xball_1, TRUE, FALSE,
5773 EL_EMC_MAGIC_BALL, -1, -1
5776 Xball_1B, FALSE, FALSE,
5777 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5780 Xball_2, FALSE, FALSE,
5781 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5784 Xball_2B, FALSE, FALSE,
5785 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5788 Yball_eat, FALSE, FALSE,
5789 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
5792 Ykey_1_eat, FALSE, FALSE,
5793 EL_EM_KEY_1, ACTION_COLLECTING, -1
5796 Ykey_2_eat, FALSE, FALSE,
5797 EL_EM_KEY_2, ACTION_COLLECTING, -1
5800 Ykey_3_eat, FALSE, FALSE,
5801 EL_EM_KEY_3, ACTION_COLLECTING, -1
5804 Ykey_4_eat, FALSE, FALSE,
5805 EL_EM_KEY_4, ACTION_COLLECTING, -1
5808 Ykey_5_eat, FALSE, FALSE,
5809 EL_EMC_KEY_5, ACTION_COLLECTING, -1
5812 Ykey_6_eat, FALSE, FALSE,
5813 EL_EMC_KEY_6, ACTION_COLLECTING, -1
5816 Ykey_7_eat, FALSE, FALSE,
5817 EL_EMC_KEY_7, ACTION_COLLECTING, -1
5820 Ykey_8_eat, FALSE, FALSE,
5821 EL_EMC_KEY_8, ACTION_COLLECTING, -1
5824 Ylenses_eat, FALSE, FALSE,
5825 EL_EMC_LENSES, ACTION_COLLECTING, -1
5828 Ymagnify_eat, FALSE, FALSE,
5829 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
5832 Ygrass_eat, FALSE, FALSE,
5833 EL_EMC_GRASS, ACTION_SNAPPING, -1
5836 Ydirt_eat, FALSE, FALSE,
5837 EL_SAND, ACTION_SNAPPING, -1
5840 Xgrow_ns, TRUE, FALSE,
5841 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
5844 Ygrow_ns_eat, FALSE, FALSE,
5845 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
5848 Xgrow_ew, TRUE, FALSE,
5849 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
5852 Ygrow_ew_eat, FALSE, FALSE,
5853 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
5856 Xwonderwall, TRUE, FALSE,
5857 EL_MAGIC_WALL, -1, -1
5860 XwonderwallB, FALSE, FALSE,
5861 EL_MAGIC_WALL, ACTION_ACTIVE, -1
5864 Xamoeba_1, TRUE, FALSE,
5865 EL_AMOEBA_DRY, ACTION_OTHER, -1
5868 Xamoeba_2, FALSE, FALSE,
5869 EL_AMOEBA_DRY, ACTION_OTHER, -1
5872 Xamoeba_3, FALSE, FALSE,
5873 EL_AMOEBA_DRY, ACTION_OTHER, -1
5876 Xamoeba_4, FALSE, FALSE,
5877 EL_AMOEBA_DRY, ACTION_OTHER, -1
5880 Xamoeba_5, TRUE, FALSE,
5881 EL_AMOEBA_WET, ACTION_OTHER, -1
5884 Xamoeba_6, FALSE, FALSE,
5885 EL_AMOEBA_WET, ACTION_OTHER, -1
5888 Xamoeba_7, FALSE, FALSE,
5889 EL_AMOEBA_WET, ACTION_OTHER, -1
5892 Xamoeba_8, FALSE, FALSE,
5893 EL_AMOEBA_WET, ACTION_OTHER, -1
5896 Xdoor_1, TRUE, FALSE,
5897 EL_EM_GATE_1, -1, -1
5900 Xdoor_2, TRUE, FALSE,
5901 EL_EM_GATE_2, -1, -1
5904 Xdoor_3, TRUE, FALSE,
5905 EL_EM_GATE_3, -1, -1
5908 Xdoor_4, TRUE, FALSE,
5909 EL_EM_GATE_4, -1, -1
5912 Xdoor_5, TRUE, FALSE,
5913 EL_EMC_GATE_5, -1, -1
5916 Xdoor_6, TRUE, FALSE,
5917 EL_EMC_GATE_6, -1, -1
5920 Xdoor_7, TRUE, FALSE,
5921 EL_EMC_GATE_7, -1, -1
5924 Xdoor_8, TRUE, FALSE,
5925 EL_EMC_GATE_8, -1, -1
5928 Xkey_1, TRUE, FALSE,
5932 Xkey_2, TRUE, FALSE,
5936 Xkey_3, TRUE, FALSE,
5940 Xkey_4, TRUE, FALSE,
5944 Xkey_5, TRUE, FALSE,
5945 EL_EMC_KEY_5, -1, -1
5948 Xkey_6, TRUE, FALSE,
5949 EL_EMC_KEY_6, -1, -1
5952 Xkey_7, TRUE, FALSE,
5953 EL_EMC_KEY_7, -1, -1
5956 Xkey_8, TRUE, FALSE,
5957 EL_EMC_KEY_8, -1, -1
5960 Xwind_n, TRUE, FALSE,
5961 EL_BALLOON_SWITCH_UP, -1, -1
5964 Xwind_e, TRUE, FALSE,
5965 EL_BALLOON_SWITCH_RIGHT, -1, -1
5968 Xwind_s, TRUE, FALSE,
5969 EL_BALLOON_SWITCH_DOWN, -1, -1
5972 Xwind_w, TRUE, FALSE,
5973 EL_BALLOON_SWITCH_LEFT, -1, -1
5976 Xwind_nesw, TRUE, FALSE,
5977 EL_BALLOON_SWITCH_ANY, -1, -1
5980 Xwind_stop, TRUE, FALSE,
5981 EL_BALLOON_SWITCH_NONE, -1, -1
5985 EL_EM_EXIT_CLOSED, -1, -1
5988 Xexit_1, TRUE, FALSE,
5989 EL_EM_EXIT_OPEN, -1, -1
5992 Xexit_2, FALSE, FALSE,
5993 EL_EM_EXIT_OPEN, -1, -1
5996 Xexit_3, FALSE, FALSE,
5997 EL_EM_EXIT_OPEN, -1, -1
6000 Xdynamite, TRUE, FALSE,
6001 EL_EM_DYNAMITE, -1, -1
6004 Ydynamite_eat, FALSE, FALSE,
6005 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
6008 Xdynamite_1, TRUE, FALSE,
6009 EL_EM_DYNAMITE_ACTIVE, -1, -1
6012 Xdynamite_2, FALSE, FALSE,
6013 EL_EM_DYNAMITE_ACTIVE, -1, -1
6016 Xdynamite_3, FALSE, FALSE,
6017 EL_EM_DYNAMITE_ACTIVE, -1, -1
6020 Xdynamite_4, FALSE, FALSE,
6021 EL_EM_DYNAMITE_ACTIVE, -1, -1
6024 Xbumper, TRUE, FALSE,
6025 EL_EMC_SPRING_BUMPER, -1, -1
6028 XbumperB, FALSE, FALSE,
6029 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
6032 Xwheel, TRUE, FALSE,
6033 EL_ROBOT_WHEEL, -1, -1
6036 XwheelB, FALSE, FALSE,
6037 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
6040 Xswitch, TRUE, FALSE,
6041 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
6044 XswitchB, FALSE, FALSE,
6045 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
6049 EL_QUICKSAND_EMPTY, -1, -1
6052 Xsand_stone, TRUE, FALSE,
6053 EL_QUICKSAND_FULL, -1, -1
6056 Xsand_stonein_1, FALSE, TRUE,
6057 EL_ROCK, ACTION_FILLING, -1
6060 Xsand_stonein_2, FALSE, TRUE,
6061 EL_ROCK, ACTION_FILLING, -1
6064 Xsand_stonein_3, FALSE, TRUE,
6065 EL_ROCK, ACTION_FILLING, -1
6068 Xsand_stonein_4, FALSE, TRUE,
6069 EL_ROCK, ACTION_FILLING, -1
6072 Xsand_stonesand_1, FALSE, FALSE,
6073 EL_QUICKSAND_EMPTYING, -1, -1
6076 Xsand_stonesand_2, FALSE, FALSE,
6077 EL_QUICKSAND_EMPTYING, -1, -1
6080 Xsand_stonesand_3, FALSE, FALSE,
6081 EL_QUICKSAND_EMPTYING, -1, -1
6084 Xsand_stonesand_4, FALSE, FALSE,
6085 EL_QUICKSAND_EMPTYING, -1, -1
6088 Xsand_stonesand_quickout_1, FALSE, FALSE,
6089 EL_QUICKSAND_EMPTYING, -1, -1
6092 Xsand_stonesand_quickout_2, FALSE, FALSE,
6093 EL_QUICKSAND_EMPTYING, -1, -1
6096 Xsand_stoneout_1, FALSE, FALSE,
6097 EL_ROCK, ACTION_EMPTYING, -1
6100 Xsand_stoneout_2, FALSE, FALSE,
6101 EL_ROCK, ACTION_EMPTYING, -1
6104 Xsand_sandstone_1, FALSE, FALSE,
6105 EL_QUICKSAND_FILLING, -1, -1
6108 Xsand_sandstone_2, FALSE, FALSE,
6109 EL_QUICKSAND_FILLING, -1, -1
6112 Xsand_sandstone_3, FALSE, FALSE,
6113 EL_QUICKSAND_FILLING, -1, -1
6116 Xsand_sandstone_4, FALSE, FALSE,
6117 EL_QUICKSAND_FILLING, -1, -1
6120 Xplant, TRUE, FALSE,
6121 EL_EMC_PLANT, -1, -1
6124 Yplant, FALSE, FALSE,
6125 EL_EMC_PLANT, -1, -1
6128 Xlenses, TRUE, FALSE,
6129 EL_EMC_LENSES, -1, -1
6132 Xmagnify, TRUE, FALSE,
6133 EL_EMC_MAGNIFIER, -1, -1
6136 Xdripper, TRUE, FALSE,
6137 EL_EMC_DRIPPER, -1, -1
6140 XdripperB, FALSE, FALSE,
6141 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
6144 Xfake_blank, TRUE, FALSE,
6145 EL_INVISIBLE_WALL, -1, -1
6148 Xfake_blankB, FALSE, FALSE,
6149 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
6152 Xfake_grass, TRUE, FALSE,
6153 EL_EMC_FAKE_GRASS, -1, -1
6156 Xfake_grassB, FALSE, FALSE,
6157 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
6160 Xfake_door_1, TRUE, FALSE,
6161 EL_EM_GATE_1_GRAY, -1, -1
6164 Xfake_door_2, TRUE, FALSE,
6165 EL_EM_GATE_2_GRAY, -1, -1
6168 Xfake_door_3, TRUE, FALSE,
6169 EL_EM_GATE_3_GRAY, -1, -1
6172 Xfake_door_4, TRUE, FALSE,
6173 EL_EM_GATE_4_GRAY, -1, -1
6176 Xfake_door_5, TRUE, FALSE,
6177 EL_EMC_GATE_5_GRAY, -1, -1
6180 Xfake_door_6, TRUE, FALSE,
6181 EL_EMC_GATE_6_GRAY, -1, -1
6184 Xfake_door_7, TRUE, FALSE,
6185 EL_EMC_GATE_7_GRAY, -1, -1
6188 Xfake_door_8, TRUE, FALSE,
6189 EL_EMC_GATE_8_GRAY, -1, -1
6192 Xfake_acid_1, TRUE, FALSE,
6193 EL_EMC_FAKE_ACID, -1, -1
6196 Xfake_acid_2, FALSE, FALSE,
6197 EL_EMC_FAKE_ACID, -1, -1
6200 Xfake_acid_3, FALSE, FALSE,
6201 EL_EMC_FAKE_ACID, -1, -1
6204 Xfake_acid_4, FALSE, FALSE,
6205 EL_EMC_FAKE_ACID, -1, -1
6208 Xfake_acid_5, FALSE, FALSE,
6209 EL_EMC_FAKE_ACID, -1, -1
6212 Xfake_acid_6, FALSE, FALSE,
6213 EL_EMC_FAKE_ACID, -1, -1
6216 Xfake_acid_7, FALSE, FALSE,
6217 EL_EMC_FAKE_ACID, -1, -1
6220 Xfake_acid_8, FALSE, FALSE,
6221 EL_EMC_FAKE_ACID, -1, -1
6224 Xsteel_1, TRUE, FALSE,
6225 EL_STEELWALL, -1, -1
6228 Xsteel_2, TRUE, FALSE,
6229 EL_EMC_STEELWALL_2, -1, -1
6232 Xsteel_3, TRUE, FALSE,
6233 EL_EMC_STEELWALL_3, -1, -1
6236 Xsteel_4, TRUE, FALSE,
6237 EL_EMC_STEELWALL_4, -1, -1
6240 Xwall_1, TRUE, FALSE,
6244 Xwall_2, TRUE, FALSE,
6245 EL_EMC_WALL_14, -1, -1
6248 Xwall_3, TRUE, FALSE,
6249 EL_EMC_WALL_15, -1, -1
6252 Xwall_4, TRUE, FALSE,
6253 EL_EMC_WALL_16, -1, -1
6256 Xround_wall_1, TRUE, FALSE,
6257 EL_WALL_SLIPPERY, -1, -1
6260 Xround_wall_2, TRUE, FALSE,
6261 EL_EMC_WALL_SLIPPERY_2, -1, -1
6264 Xround_wall_3, TRUE, FALSE,
6265 EL_EMC_WALL_SLIPPERY_3, -1, -1
6268 Xround_wall_4, TRUE, FALSE,
6269 EL_EMC_WALL_SLIPPERY_4, -1, -1
6272 Xdecor_1, TRUE, FALSE,
6273 EL_EMC_WALL_8, -1, -1
6276 Xdecor_2, TRUE, FALSE,
6277 EL_EMC_WALL_6, -1, -1
6280 Xdecor_3, TRUE, FALSE,
6281 EL_EMC_WALL_4, -1, -1
6284 Xdecor_4, TRUE, FALSE,
6285 EL_EMC_WALL_7, -1, -1
6288 Xdecor_5, TRUE, FALSE,
6289 EL_EMC_WALL_5, -1, -1
6292 Xdecor_6, TRUE, FALSE,
6293 EL_EMC_WALL_9, -1, -1
6296 Xdecor_7, TRUE, FALSE,
6297 EL_EMC_WALL_10, -1, -1
6300 Xdecor_8, TRUE, FALSE,
6301 EL_EMC_WALL_1, -1, -1
6304 Xdecor_9, TRUE, FALSE,
6305 EL_EMC_WALL_2, -1, -1
6308 Xdecor_10, TRUE, FALSE,
6309 EL_EMC_WALL_3, -1, -1
6312 Xdecor_11, TRUE, FALSE,
6313 EL_EMC_WALL_11, -1, -1
6316 Xdecor_12, TRUE, FALSE,
6317 EL_EMC_WALL_12, -1, -1
6320 Xalpha_0, TRUE, FALSE,
6321 EL_CHAR('0'), -1, -1
6324 Xalpha_1, TRUE, FALSE,
6325 EL_CHAR('1'), -1, -1
6328 Xalpha_2, TRUE, FALSE,
6329 EL_CHAR('2'), -1, -1
6332 Xalpha_3, TRUE, FALSE,
6333 EL_CHAR('3'), -1, -1
6336 Xalpha_4, TRUE, FALSE,
6337 EL_CHAR('4'), -1, -1
6340 Xalpha_5, TRUE, FALSE,
6341 EL_CHAR('5'), -1, -1
6344 Xalpha_6, TRUE, FALSE,
6345 EL_CHAR('6'), -1, -1
6348 Xalpha_7, TRUE, FALSE,
6349 EL_CHAR('7'), -1, -1
6352 Xalpha_8, TRUE, FALSE,
6353 EL_CHAR('8'), -1, -1
6356 Xalpha_9, TRUE, FALSE,
6357 EL_CHAR('9'), -1, -1
6360 Xalpha_excla, TRUE, FALSE,
6361 EL_CHAR('!'), -1, -1
6364 Xalpha_quote, TRUE, FALSE,
6365 EL_CHAR('"'), -1, -1
6368 Xalpha_comma, TRUE, FALSE,
6369 EL_CHAR(','), -1, -1
6372 Xalpha_minus, TRUE, FALSE,
6373 EL_CHAR('-'), -1, -1
6376 Xalpha_perio, TRUE, FALSE,
6377 EL_CHAR('.'), -1, -1
6380 Xalpha_colon, TRUE, FALSE,
6381 EL_CHAR(':'), -1, -1
6384 Xalpha_quest, TRUE, FALSE,
6385 EL_CHAR('?'), -1, -1
6388 Xalpha_a, TRUE, FALSE,
6389 EL_CHAR('A'), -1, -1
6392 Xalpha_b, TRUE, FALSE,
6393 EL_CHAR('B'), -1, -1
6396 Xalpha_c, TRUE, FALSE,
6397 EL_CHAR('C'), -1, -1
6400 Xalpha_d, TRUE, FALSE,
6401 EL_CHAR('D'), -1, -1
6404 Xalpha_e, TRUE, FALSE,
6405 EL_CHAR('E'), -1, -1
6408 Xalpha_f, TRUE, FALSE,
6409 EL_CHAR('F'), -1, -1
6412 Xalpha_g, TRUE, FALSE,
6413 EL_CHAR('G'), -1, -1
6416 Xalpha_h, TRUE, FALSE,
6417 EL_CHAR('H'), -1, -1
6420 Xalpha_i, TRUE, FALSE,
6421 EL_CHAR('I'), -1, -1
6424 Xalpha_j, TRUE, FALSE,
6425 EL_CHAR('J'), -1, -1
6428 Xalpha_k, TRUE, FALSE,
6429 EL_CHAR('K'), -1, -1
6432 Xalpha_l, TRUE, FALSE,
6433 EL_CHAR('L'), -1, -1
6436 Xalpha_m, TRUE, FALSE,
6437 EL_CHAR('M'), -1, -1
6440 Xalpha_n, TRUE, FALSE,
6441 EL_CHAR('N'), -1, -1
6444 Xalpha_o, TRUE, FALSE,
6445 EL_CHAR('O'), -1, -1
6448 Xalpha_p, TRUE, FALSE,
6449 EL_CHAR('P'), -1, -1
6452 Xalpha_q, TRUE, FALSE,
6453 EL_CHAR('Q'), -1, -1
6456 Xalpha_r, TRUE, FALSE,
6457 EL_CHAR('R'), -1, -1
6460 Xalpha_s, TRUE, FALSE,
6461 EL_CHAR('S'), -1, -1
6464 Xalpha_t, TRUE, FALSE,
6465 EL_CHAR('T'), -1, -1
6468 Xalpha_u, TRUE, FALSE,
6469 EL_CHAR('U'), -1, -1
6472 Xalpha_v, TRUE, FALSE,
6473 EL_CHAR('V'), -1, -1
6476 Xalpha_w, TRUE, FALSE,
6477 EL_CHAR('W'), -1, -1
6480 Xalpha_x, TRUE, FALSE,
6481 EL_CHAR('X'), -1, -1
6484 Xalpha_y, TRUE, FALSE,
6485 EL_CHAR('Y'), -1, -1
6488 Xalpha_z, TRUE, FALSE,
6489 EL_CHAR('Z'), -1, -1
6492 Xalpha_arrow_e, TRUE, FALSE,
6493 EL_CHAR('>'), -1, -1
6496 Xalpha_arrow_w, TRUE, FALSE,
6497 EL_CHAR('<'), -1, -1
6500 Xalpha_copyr, TRUE, FALSE,
6501 EL_CHAR(CHAR_BYTE_COPYRIGHT), -1, -1
6505 Xboom_bug, FALSE, FALSE,
6506 EL_BUG, ACTION_EXPLODING, -1
6509 Xboom_bomb, FALSE, FALSE,
6510 EL_BOMB, ACTION_EXPLODING, -1
6513 Xboom_android, FALSE, FALSE,
6514 EL_EMC_ANDROID, ACTION_OTHER, -1
6517 Xboom_1, FALSE, FALSE,
6518 EL_DEFAULT, ACTION_EXPLODING, -1
6521 Xboom_2, FALSE, FALSE,
6522 EL_DEFAULT, ACTION_EXPLODING, -1
6525 Znormal, FALSE, FALSE,
6529 Zdynamite, FALSE, FALSE,
6533 Zplayer, FALSE, FALSE,
6537 ZBORDER, FALSE, FALSE,
6547 static struct Mapping_EM_to_RND_player
6556 em_player_mapping_list[] =
6560 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
6564 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
6568 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
6572 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
6576 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
6580 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
6584 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
6588 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
6592 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
6596 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
6600 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
6604 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
6608 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
6612 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
6616 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
6620 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
6624 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
6628 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
6632 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
6636 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
6640 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
6644 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
6648 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
6652 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
6656 EL_PLAYER_1, ACTION_DEFAULT, -1,
6660 EL_PLAYER_2, ACTION_DEFAULT, -1,
6664 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
6668 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
6672 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
6676 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
6680 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
6684 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
6688 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
6692 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
6696 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
6700 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
6704 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
6708 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
6712 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
6716 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
6720 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
6724 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
6728 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
6732 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
6736 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
6740 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
6744 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
6748 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
6752 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
6756 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
6760 EL_PLAYER_3, ACTION_DEFAULT, -1,
6764 EL_PLAYER_4, ACTION_DEFAULT, -1,
6773 int map_element_RND_to_EM(int element_rnd)
6775 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
6776 static boolean mapping_initialized = FALSE;
6778 if (!mapping_initialized)
6782 /* return "Xalpha_quest" for all undefined elements in mapping array */
6783 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
6784 mapping_RND_to_EM[i] = Xalpha_quest;
6786 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6787 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
6788 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
6789 em_object_mapping_list[i].element_em;
6791 mapping_initialized = TRUE;
6794 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
6795 return mapping_RND_to_EM[element_rnd];
6797 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
6802 int map_element_EM_to_RND(int element_em)
6804 static unsigned short mapping_EM_to_RND[TILE_MAX];
6805 static boolean mapping_initialized = FALSE;
6807 if (!mapping_initialized)
6811 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
6812 for (i = 0; i < TILE_MAX; i++)
6813 mapping_EM_to_RND[i] = EL_UNKNOWN;
6815 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6816 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
6817 em_object_mapping_list[i].element_rnd;
6819 mapping_initialized = TRUE;
6822 if (element_em >= 0 && element_em < TILE_MAX)
6823 return mapping_EM_to_RND[element_em];
6825 Error(ERR_WARN, "invalid EM level element %d", element_em);
6830 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
6832 struct LevelInfo_EM *level_em = level->native_em_level;
6833 struct LEVEL *lev = level_em->lev;
6836 for (i = 0; i < TILE_MAX; i++)
6837 lev->android_array[i] = Xblank;
6839 for (i = 0; i < level->num_android_clone_elements; i++)
6841 int element_rnd = level->android_clone_element[i];
6842 int element_em = map_element_RND_to_EM(element_rnd);
6844 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
6845 if (em_object_mapping_list[j].element_rnd == element_rnd)
6846 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
6850 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
6852 struct LevelInfo_EM *level_em = level->native_em_level;
6853 struct LEVEL *lev = level_em->lev;
6856 level->num_android_clone_elements = 0;
6858 for (i = 0; i < TILE_MAX; i++)
6860 int element_em = lev->android_array[i];
6862 boolean element_found = FALSE;
6864 if (element_em == Xblank)
6867 element_rnd = map_element_EM_to_RND(element_em);
6869 for (j = 0; j < level->num_android_clone_elements; j++)
6870 if (level->android_clone_element[j] == element_rnd)
6871 element_found = TRUE;
6875 level->android_clone_element[level->num_android_clone_elements++] =
6878 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
6883 if (level->num_android_clone_elements == 0)
6885 level->num_android_clone_elements = 1;
6886 level->android_clone_element[0] = EL_EMPTY;
6890 int map_direction_RND_to_EM(int direction)
6892 return (direction == MV_UP ? 0 :
6893 direction == MV_RIGHT ? 1 :
6894 direction == MV_DOWN ? 2 :
6895 direction == MV_LEFT ? 3 :
6899 int map_direction_EM_to_RND(int direction)
6901 return (direction == 0 ? MV_UP :
6902 direction == 1 ? MV_RIGHT :
6903 direction == 2 ? MV_DOWN :
6904 direction == 3 ? MV_LEFT :
6908 int map_element_RND_to_SP(int element_rnd)
6910 int element_sp = 0x20; /* map unknown elements to yellow "hardware" */
6912 if (element_rnd >= EL_SP_START &&
6913 element_rnd <= EL_SP_END)
6914 element_sp = element_rnd - EL_SP_START;
6915 else if (element_rnd == EL_EMPTY_SPACE)
6917 else if (element_rnd == EL_INVISIBLE_WALL)
6923 int map_element_SP_to_RND(int element_sp)
6925 int element_rnd = EL_UNKNOWN;
6927 if (element_sp >= 0x00 &&
6929 element_rnd = EL_SP_START + element_sp;
6930 else if (element_sp == 0x28)
6931 element_rnd = EL_INVISIBLE_WALL;
6936 int map_action_SP_to_RND(int action_sp)
6940 case actActive: return ACTION_ACTIVE;
6941 case actImpact: return ACTION_IMPACT;
6942 case actExploding: return ACTION_EXPLODING;
6943 case actDigging: return ACTION_DIGGING;
6944 case actSnapping: return ACTION_SNAPPING;
6945 case actCollecting: return ACTION_COLLECTING;
6946 case actPassing: return ACTION_PASSING;
6947 case actPushing: return ACTION_PUSHING;
6948 case actDropping: return ACTION_DROPPING;
6950 default: return ACTION_DEFAULT;
6954 int get_next_element(int element)
6958 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
6959 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
6960 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
6961 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
6962 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
6963 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
6964 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
6965 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
6966 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
6967 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
6968 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
6970 default: return element;
6974 int el_act_dir2img(int element, int action, int direction)
6976 element = GFX_ELEMENT(element);
6977 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
6979 /* direction_graphic[][] == graphic[] for undefined direction graphics */
6980 return element_info[element].direction_graphic[action][direction];
6983 static int el_act_dir2crm(int element, int action, int direction)
6985 element = GFX_ELEMENT(element);
6986 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
6988 /* direction_graphic[][] == graphic[] for undefined direction graphics */
6989 return element_info[element].direction_crumbled[action][direction];
6992 int el_act2img(int element, int action)
6994 element = GFX_ELEMENT(element);
6996 return element_info[element].graphic[action];
6999 int el_act2crm(int element, int action)
7001 element = GFX_ELEMENT(element);
7003 return element_info[element].crumbled[action];
7006 int el_dir2img(int element, int direction)
7008 element = GFX_ELEMENT(element);
7010 return el_act_dir2img(element, ACTION_DEFAULT, direction);
7013 int el2baseimg(int element)
7015 return element_info[element].graphic[ACTION_DEFAULT];
7018 int el2img(int element)
7020 element = GFX_ELEMENT(element);
7022 return element_info[element].graphic[ACTION_DEFAULT];
7025 int el2edimg(int element)
7027 element = GFX_ELEMENT(element);
7029 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
7032 int el2preimg(int element)
7034 element = GFX_ELEMENT(element);
7036 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
7039 int el2panelimg(int element)
7041 element = GFX_ELEMENT(element);
7043 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL];
7046 int font2baseimg(int font_nr)
7048 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
7051 int getBeltNrFromBeltElement(int element)
7053 return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
7054 element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
7055 element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
7058 int getBeltNrFromBeltActiveElement(int element)
7060 return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
7061 element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
7062 element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
7065 int getBeltNrFromBeltSwitchElement(int element)
7067 return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
7068 element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
7069 element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
7072 int getBeltDirNrFromBeltElement(int element)
7074 static int belt_base_element[4] =
7076 EL_CONVEYOR_BELT_1_LEFT,
7077 EL_CONVEYOR_BELT_2_LEFT,
7078 EL_CONVEYOR_BELT_3_LEFT,
7079 EL_CONVEYOR_BELT_4_LEFT
7082 int belt_nr = getBeltNrFromBeltElement(element);
7083 int belt_dir_nr = element - belt_base_element[belt_nr];
7085 return (belt_dir_nr % 3);
7088 int getBeltDirNrFromBeltSwitchElement(int element)
7090 static int belt_base_element[4] =
7092 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
7093 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
7094 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
7095 EL_CONVEYOR_BELT_4_SWITCH_LEFT
7098 int belt_nr = getBeltNrFromBeltSwitchElement(element);
7099 int belt_dir_nr = element - belt_base_element[belt_nr];
7101 return (belt_dir_nr % 3);
7104 int getBeltDirFromBeltElement(int element)
7106 static int belt_move_dir[3] =
7113 int belt_dir_nr = getBeltDirNrFromBeltElement(element);
7115 return belt_move_dir[belt_dir_nr];
7118 int getBeltDirFromBeltSwitchElement(int element)
7120 static int belt_move_dir[3] =
7127 int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
7129 return belt_move_dir[belt_dir_nr];
7132 int getBeltElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
7134 static int belt_base_element[4] =
7136 EL_CONVEYOR_BELT_1_LEFT,
7137 EL_CONVEYOR_BELT_2_LEFT,
7138 EL_CONVEYOR_BELT_3_LEFT,
7139 EL_CONVEYOR_BELT_4_LEFT
7142 return belt_base_element[belt_nr] + belt_dir_nr;
7145 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
7147 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
7149 return getBeltElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
7152 int getBeltSwitchElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
7154 static int belt_base_element[4] =
7156 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
7157 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
7158 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
7159 EL_CONVEYOR_BELT_4_SWITCH_LEFT
7162 return belt_base_element[belt_nr] + belt_dir_nr;
7165 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
7167 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
7169 return getBeltSwitchElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
7172 boolean getTeamMode_EM()
7174 return game.team_mode;
7177 int getGameFrameDelay_EM(int native_em_game_frame_delay)
7179 int game_frame_delay_value;
7181 game_frame_delay_value =
7182 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
7183 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
7186 if (tape.playing && tape.warp_forward && !tape.pausing)
7187 game_frame_delay_value = 0;
7189 return game_frame_delay_value;
7192 unsigned int InitRND(int seed)
7194 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
7195 return InitEngineRandom_EM(seed);
7196 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
7197 return InitEngineRandom_SP(seed);
7199 return InitEngineRandom_RND(seed);
7202 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
7203 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
7205 inline static int get_effective_element_EM(int tile, int frame_em)
7207 int element = object_mapping[tile].element_rnd;
7208 int action = object_mapping[tile].action;
7209 boolean is_backside = object_mapping[tile].is_backside;
7210 boolean action_removing = (action == ACTION_DIGGING ||
7211 action == ACTION_SNAPPING ||
7212 action == ACTION_COLLECTING);
7218 case Yacid_splash_eB:
7219 case Yacid_splash_wB:
7220 return (frame_em > 5 ? EL_EMPTY : element);
7226 else /* frame_em == 7 */
7230 case Yacid_splash_eB:
7231 case Yacid_splash_wB:
7234 case Yemerald_stone:
7237 case Ydiamond_stone:
7241 case Xdrip_stretchB:
7260 case Xsand_stonein_1:
7261 case Xsand_stonein_2:
7262 case Xsand_stonein_3:
7263 case Xsand_stonein_4:
7267 return (is_backside || action_removing ? EL_EMPTY : element);
7272 inline static boolean check_linear_animation_EM(int tile)
7276 case Xsand_stonesand_1:
7277 case Xsand_stonesand_quickout_1:
7278 case Xsand_sandstone_1:
7279 case Xsand_stonein_1:
7280 case Xsand_stoneout_1:
7299 case Yacid_splash_eB:
7300 case Yacid_splash_wB:
7301 case Yemerald_stone:
7308 inline static void set_crumbled_graphics_EM(struct GraphicInfo_EM *g_em,
7309 boolean has_crumbled_graphics,
7310 int crumbled, int sync_frame)
7312 /* if element can be crumbled, but certain action graphics are just empty
7313 space (like instantly snapping sand to empty space in 1 frame), do not
7314 treat these empty space graphics as crumbled graphics in EMC engine */
7315 if (crumbled == IMG_EMPTY_SPACE)
7316 has_crumbled_graphics = FALSE;
7318 if (has_crumbled_graphics)
7320 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
7321 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
7322 g_crumbled->anim_delay,
7323 g_crumbled->anim_mode,
7324 g_crumbled->anim_start_frame,
7327 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
7328 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
7330 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
7331 g_em->crumbled_tile_size = graphic_info[crumbled].tile_size;
7333 g_em->has_crumbled_graphics = TRUE;
7337 g_em->crumbled_bitmap = NULL;
7338 g_em->crumbled_src_x = 0;
7339 g_em->crumbled_src_y = 0;
7340 g_em->crumbled_border_size = 0;
7341 g_em->crumbled_tile_size = 0;
7343 g_em->has_crumbled_graphics = FALSE;
7347 void ResetGfxAnimation_EM(int x, int y, int tile)
7352 void SetGfxAnimation_EM(struct GraphicInfo_EM *g_em,
7353 int tile, int frame_em, int x, int y)
7355 int action = object_mapping[tile].action;
7356 int direction = object_mapping[tile].direction;
7357 int effective_element = get_effective_element_EM(tile, frame_em);
7358 int graphic = (direction == MV_NONE ?
7359 el_act2img(effective_element, action) :
7360 el_act_dir2img(effective_element, action, direction));
7361 struct GraphicInfo *g = &graphic_info[graphic];
7363 boolean action_removing = (action == ACTION_DIGGING ||
7364 action == ACTION_SNAPPING ||
7365 action == ACTION_COLLECTING);
7366 boolean action_moving = (action == ACTION_FALLING ||
7367 action == ACTION_MOVING ||
7368 action == ACTION_PUSHING ||
7369 action == ACTION_EATING ||
7370 action == ACTION_FILLING ||
7371 action == ACTION_EMPTYING);
7372 boolean action_falling = (action == ACTION_FALLING ||
7373 action == ACTION_FILLING ||
7374 action == ACTION_EMPTYING);
7376 /* special case: graphic uses "2nd movement tile" and has defined
7377 7 frames for movement animation (or less) => use default graphic
7378 for last (8th) frame which ends the movement animation */
7379 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
7381 action = ACTION_DEFAULT; /* (keep action_* unchanged for now) */
7382 graphic = (direction == MV_NONE ?
7383 el_act2img(effective_element, action) :
7384 el_act_dir2img(effective_element, action, direction));
7386 g = &graphic_info[graphic];
7389 if ((action_removing || check_linear_animation_EM(tile)) && frame_em == 0)
7393 else if (action_moving)
7395 boolean is_backside = object_mapping[tile].is_backside;
7399 int direction = object_mapping[tile].direction;
7400 int move_dir = (action_falling ? MV_DOWN : direction);
7405 /* !!! TEST !!! NEW !!! DOES NOT WORK RIGHT YET !!! */
7406 if (g->double_movement && frame_em == 0)
7410 if (move_dir == MV_LEFT)
7411 GfxFrame[x - 1][y] = GfxFrame[x][y];
7412 else if (move_dir == MV_RIGHT)
7413 GfxFrame[x + 1][y] = GfxFrame[x][y];
7414 else if (move_dir == MV_UP)
7415 GfxFrame[x][y - 1] = GfxFrame[x][y];
7416 else if (move_dir == MV_DOWN)
7417 GfxFrame[x][y + 1] = GfxFrame[x][y];
7424 /* special case: animation for Xsand_stonesand_quickout_1/2 twice as fast */
7425 if (tile == Xsand_stonesand_quickout_1 ||
7426 tile == Xsand_stonesand_quickout_2)
7430 if (graphic_info[graphic].anim_global_sync)
7431 sync_frame = FrameCounter;
7432 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
7433 sync_frame = GfxFrame[x][y];
7435 sync_frame = 0; /* playfield border (pseudo steel) */
7437 SetRandomAnimationValue(x, y);
7439 int frame = getAnimationFrame(g->anim_frames,
7442 g->anim_start_frame,
7445 g_em->unique_identifier =
7446 (graphic << 16) | ((frame % 8) << 12) | (g_em->width << 6) | g_em->height;
7449 void getGraphicSourceObjectExt_EM(struct GraphicInfo_EM *g_em,
7450 int tile, int frame_em, int x, int y)
7452 int action = object_mapping[tile].action;
7453 int direction = object_mapping[tile].direction;
7454 boolean is_backside = object_mapping[tile].is_backside;
7455 int effective_element = get_effective_element_EM(tile, frame_em);
7456 int effective_action = action;
7457 int graphic = (direction == MV_NONE ?
7458 el_act2img(effective_element, effective_action) :
7459 el_act_dir2img(effective_element, effective_action,
7461 int crumbled = (direction == MV_NONE ?
7462 el_act2crm(effective_element, effective_action) :
7463 el_act_dir2crm(effective_element, effective_action,
7465 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7466 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7467 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7468 struct GraphicInfo *g = &graphic_info[graphic];
7471 /* special case: graphic uses "2nd movement tile" and has defined
7472 7 frames for movement animation (or less) => use default graphic
7473 for last (8th) frame which ends the movement animation */
7474 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
7476 effective_action = ACTION_DEFAULT;
7477 graphic = (direction == MV_NONE ?
7478 el_act2img(effective_element, effective_action) :
7479 el_act_dir2img(effective_element, effective_action,
7481 crumbled = (direction == MV_NONE ?
7482 el_act2crm(effective_element, effective_action) :
7483 el_act_dir2crm(effective_element, effective_action,
7486 g = &graphic_info[graphic];
7489 if (graphic_info[graphic].anim_global_sync)
7490 sync_frame = FrameCounter;
7491 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
7492 sync_frame = GfxFrame[x][y];
7494 sync_frame = 0; /* playfield border (pseudo steel) */
7496 SetRandomAnimationValue(x, y);
7498 int frame = getAnimationFrame(g->anim_frames,
7501 g->anim_start_frame,
7504 getGraphicSourceExt(graphic, frame, &g_em->bitmap, &g_em->src_x, &g_em->src_y,
7505 g->double_movement && is_backside);
7507 /* (updating the "crumbled" graphic definitions is probably not really needed,
7508 as animations for crumbled graphics can't be longer than one EMC cycle) */
7509 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
7513 void getGraphicSourcePlayerExt_EM(struct GraphicInfo_EM *g_em,
7514 int player_nr, int anim, int frame_em)
7516 int element = player_mapping[player_nr][anim].element_rnd;
7517 int action = player_mapping[player_nr][anim].action;
7518 int direction = player_mapping[player_nr][anim].direction;
7519 int graphic = (direction == MV_NONE ?
7520 el_act2img(element, action) :
7521 el_act_dir2img(element, action, direction));
7522 struct GraphicInfo *g = &graphic_info[graphic];
7525 InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
7527 stored_player[player_nr].StepFrame = frame_em;
7529 sync_frame = stored_player[player_nr].Frame;
7531 int frame = getAnimationFrame(g->anim_frames,
7534 g->anim_start_frame,
7537 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
7538 &g_em->src_x, &g_em->src_y, FALSE);
7541 void InitGraphicInfo_EM(void)
7546 int num_em_gfx_errors = 0;
7548 if (graphic_info_em_object[0][0].bitmap == NULL)
7550 /* EM graphics not yet initialized in em_open_all() */
7555 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
7558 /* always start with reliable default values */
7559 for (i = 0; i < TILE_MAX; i++)
7561 object_mapping[i].element_rnd = EL_UNKNOWN;
7562 object_mapping[i].is_backside = FALSE;
7563 object_mapping[i].action = ACTION_DEFAULT;
7564 object_mapping[i].direction = MV_NONE;
7567 /* always start with reliable default values */
7568 for (p = 0; p < MAX_PLAYERS; p++)
7570 for (i = 0; i < SPR_MAX; i++)
7572 player_mapping[p][i].element_rnd = EL_UNKNOWN;
7573 player_mapping[p][i].action = ACTION_DEFAULT;
7574 player_mapping[p][i].direction = MV_NONE;
7578 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
7580 int e = em_object_mapping_list[i].element_em;
7582 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
7583 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
7585 if (em_object_mapping_list[i].action != -1)
7586 object_mapping[e].action = em_object_mapping_list[i].action;
7588 if (em_object_mapping_list[i].direction != -1)
7589 object_mapping[e].direction =
7590 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
7593 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
7595 int a = em_player_mapping_list[i].action_em;
7596 int p = em_player_mapping_list[i].player_nr;
7598 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
7600 if (em_player_mapping_list[i].action != -1)
7601 player_mapping[p][a].action = em_player_mapping_list[i].action;
7603 if (em_player_mapping_list[i].direction != -1)
7604 player_mapping[p][a].direction =
7605 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
7608 for (i = 0; i < TILE_MAX; i++)
7610 int element = object_mapping[i].element_rnd;
7611 int action = object_mapping[i].action;
7612 int direction = object_mapping[i].direction;
7613 boolean is_backside = object_mapping[i].is_backside;
7614 boolean action_exploding = ((action == ACTION_EXPLODING ||
7615 action == ACTION_SMASHED_BY_ROCK ||
7616 action == ACTION_SMASHED_BY_SPRING) &&
7617 element != EL_DIAMOND);
7618 boolean action_active = (action == ACTION_ACTIVE);
7619 boolean action_other = (action == ACTION_OTHER);
7621 for (j = 0; j < 8; j++)
7623 int effective_element = get_effective_element_EM(i, j);
7624 int effective_action = (j < 7 ? action :
7625 i == Xdrip_stretch ? action :
7626 i == Xdrip_stretchB ? action :
7627 i == Ydrip_s1 ? action :
7628 i == Ydrip_s1B ? action :
7629 i == Xball_1B ? action :
7630 i == Xball_2 ? action :
7631 i == Xball_2B ? action :
7632 i == Yball_eat ? action :
7633 i == Ykey_1_eat ? action :
7634 i == Ykey_2_eat ? action :
7635 i == Ykey_3_eat ? action :
7636 i == Ykey_4_eat ? action :
7637 i == Ykey_5_eat ? action :
7638 i == Ykey_6_eat ? action :
7639 i == Ykey_7_eat ? action :
7640 i == Ykey_8_eat ? action :
7641 i == Ylenses_eat ? action :
7642 i == Ymagnify_eat ? action :
7643 i == Ygrass_eat ? action :
7644 i == Ydirt_eat ? action :
7645 i == Xsand_stonein_1 ? action :
7646 i == Xsand_stonein_2 ? action :
7647 i == Xsand_stonein_3 ? action :
7648 i == Xsand_stonein_4 ? action :
7649 i == Xsand_stoneout_1 ? action :
7650 i == Xsand_stoneout_2 ? action :
7651 i == Xboom_android ? ACTION_EXPLODING :
7652 action_exploding ? ACTION_EXPLODING :
7653 action_active ? action :
7654 action_other ? action :
7656 int graphic = (el_act_dir2img(effective_element, effective_action,
7658 int crumbled = (el_act_dir2crm(effective_element, effective_action,
7660 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7661 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7662 boolean has_action_graphics = (graphic != base_graphic);
7663 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7664 struct GraphicInfo *g = &graphic_info[graphic];
7665 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7668 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
7669 boolean special_animation = (action != ACTION_DEFAULT &&
7670 g->anim_frames == 3 &&
7671 g->anim_delay == 2 &&
7672 g->anim_mode & ANIM_LINEAR);
7673 int sync_frame = (i == Xdrip_stretch ? 7 :
7674 i == Xdrip_stretchB ? 7 :
7675 i == Ydrip_s2 ? j + 8 :
7676 i == Ydrip_s2B ? j + 8 :
7685 i == Xfake_acid_1 ? 0 :
7686 i == Xfake_acid_2 ? 10 :
7687 i == Xfake_acid_3 ? 20 :
7688 i == Xfake_acid_4 ? 30 :
7689 i == Xfake_acid_5 ? 40 :
7690 i == Xfake_acid_6 ? 50 :
7691 i == Xfake_acid_7 ? 60 :
7692 i == Xfake_acid_8 ? 70 :
7694 i == Xball_2B ? j + 8 :
7695 i == Yball_eat ? j + 1 :
7696 i == Ykey_1_eat ? j + 1 :
7697 i == Ykey_2_eat ? j + 1 :
7698 i == Ykey_3_eat ? j + 1 :
7699 i == Ykey_4_eat ? j + 1 :
7700 i == Ykey_5_eat ? j + 1 :
7701 i == Ykey_6_eat ? j + 1 :
7702 i == Ykey_7_eat ? j + 1 :
7703 i == Ykey_8_eat ? j + 1 :
7704 i == Ylenses_eat ? j + 1 :
7705 i == Ymagnify_eat ? j + 1 :
7706 i == Ygrass_eat ? j + 1 :
7707 i == Ydirt_eat ? j + 1 :
7708 i == Xamoeba_1 ? 0 :
7709 i == Xamoeba_2 ? 1 :
7710 i == Xamoeba_3 ? 2 :
7711 i == Xamoeba_4 ? 3 :
7712 i == Xamoeba_5 ? 0 :
7713 i == Xamoeba_6 ? 1 :
7714 i == Xamoeba_7 ? 2 :
7715 i == Xamoeba_8 ? 3 :
7716 i == Xexit_2 ? j + 8 :
7717 i == Xexit_3 ? j + 16 :
7718 i == Xdynamite_1 ? 0 :
7719 i == Xdynamite_2 ? 8 :
7720 i == Xdynamite_3 ? 16 :
7721 i == Xdynamite_4 ? 24 :
7722 i == Xsand_stonein_1 ? j + 1 :
7723 i == Xsand_stonein_2 ? j + 9 :
7724 i == Xsand_stonein_3 ? j + 17 :
7725 i == Xsand_stonein_4 ? j + 25 :
7726 i == Xsand_stoneout_1 && j == 0 ? 0 :
7727 i == Xsand_stoneout_1 && j == 1 ? 0 :
7728 i == Xsand_stoneout_1 && j == 2 ? 1 :
7729 i == Xsand_stoneout_1 && j == 3 ? 2 :
7730 i == Xsand_stoneout_1 && j == 4 ? 2 :
7731 i == Xsand_stoneout_1 && j == 5 ? 3 :
7732 i == Xsand_stoneout_1 && j == 6 ? 4 :
7733 i == Xsand_stoneout_1 && j == 7 ? 4 :
7734 i == Xsand_stoneout_2 && j == 0 ? 5 :
7735 i == Xsand_stoneout_2 && j == 1 ? 6 :
7736 i == Xsand_stoneout_2 && j == 2 ? 7 :
7737 i == Xsand_stoneout_2 && j == 3 ? 8 :
7738 i == Xsand_stoneout_2 && j == 4 ? 9 :
7739 i == Xsand_stoneout_2 && j == 5 ? 11 :
7740 i == Xsand_stoneout_2 && j == 6 ? 13 :
7741 i == Xsand_stoneout_2 && j == 7 ? 15 :
7742 i == Xboom_bug && j == 1 ? 2 :
7743 i == Xboom_bug && j == 2 ? 2 :
7744 i == Xboom_bug && j == 3 ? 4 :
7745 i == Xboom_bug && j == 4 ? 4 :
7746 i == Xboom_bug && j == 5 ? 2 :
7747 i == Xboom_bug && j == 6 ? 2 :
7748 i == Xboom_bug && j == 7 ? 0 :
7749 i == Xboom_bomb && j == 1 ? 2 :
7750 i == Xboom_bomb && j == 2 ? 2 :
7751 i == Xboom_bomb && j == 3 ? 4 :
7752 i == Xboom_bomb && j == 4 ? 4 :
7753 i == Xboom_bomb && j == 5 ? 2 :
7754 i == Xboom_bomb && j == 6 ? 2 :
7755 i == Xboom_bomb && j == 7 ? 0 :
7756 i == Xboom_android && j == 7 ? 6 :
7757 i == Xboom_1 && j == 1 ? 2 :
7758 i == Xboom_1 && j == 2 ? 2 :
7759 i == Xboom_1 && j == 3 ? 4 :
7760 i == Xboom_1 && j == 4 ? 4 :
7761 i == Xboom_1 && j == 5 ? 6 :
7762 i == Xboom_1 && j == 6 ? 6 :
7763 i == Xboom_1 && j == 7 ? 8 :
7764 i == Xboom_2 && j == 0 ? 8 :
7765 i == Xboom_2 && j == 1 ? 8 :
7766 i == Xboom_2 && j == 2 ? 10 :
7767 i == Xboom_2 && j == 3 ? 10 :
7768 i == Xboom_2 && j == 4 ? 10 :
7769 i == Xboom_2 && j == 5 ? 12 :
7770 i == Xboom_2 && j == 6 ? 12 :
7771 i == Xboom_2 && j == 7 ? 12 :
7772 special_animation && j == 4 ? 3 :
7773 effective_action != action ? 0 :
7777 Bitmap *debug_bitmap = g_em->bitmap;
7778 int debug_src_x = g_em->src_x;
7779 int debug_src_y = g_em->src_y;
7782 int frame = getAnimationFrame(g->anim_frames,
7785 g->anim_start_frame,
7788 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
7789 g->double_movement && is_backside);
7791 g_em->bitmap = src_bitmap;
7792 g_em->src_x = src_x;
7793 g_em->src_y = src_y;
7794 g_em->src_offset_x = 0;
7795 g_em->src_offset_y = 0;
7796 g_em->dst_offset_x = 0;
7797 g_em->dst_offset_y = 0;
7798 g_em->width = TILEX;
7799 g_em->height = TILEY;
7801 g_em->preserve_background = FALSE;
7803 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
7806 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
7807 effective_action == ACTION_MOVING ||
7808 effective_action == ACTION_PUSHING ||
7809 effective_action == ACTION_EATING)) ||
7810 (!has_action_graphics && (effective_action == ACTION_FILLING ||
7811 effective_action == ACTION_EMPTYING)))
7814 (effective_action == ACTION_FALLING ||
7815 effective_action == ACTION_FILLING ||
7816 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
7817 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
7818 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
7819 int num_steps = (i == Ydrip_s1 ? 16 :
7820 i == Ydrip_s1B ? 16 :
7821 i == Ydrip_s2 ? 16 :
7822 i == Ydrip_s2B ? 16 :
7823 i == Xsand_stonein_1 ? 32 :
7824 i == Xsand_stonein_2 ? 32 :
7825 i == Xsand_stonein_3 ? 32 :
7826 i == Xsand_stonein_4 ? 32 :
7827 i == Xsand_stoneout_1 ? 16 :
7828 i == Xsand_stoneout_2 ? 16 : 8);
7829 int cx = ABS(dx) * (TILEX / num_steps);
7830 int cy = ABS(dy) * (TILEY / num_steps);
7831 int step_frame = (i == Ydrip_s2 ? j + 8 :
7832 i == Ydrip_s2B ? j + 8 :
7833 i == Xsand_stonein_2 ? j + 8 :
7834 i == Xsand_stonein_3 ? j + 16 :
7835 i == Xsand_stonein_4 ? j + 24 :
7836 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
7837 int step = (is_backside ? step_frame : num_steps - step_frame);
7839 if (is_backside) /* tile where movement starts */
7841 if (dx < 0 || dy < 0)
7843 g_em->src_offset_x = cx * step;
7844 g_em->src_offset_y = cy * step;
7848 g_em->dst_offset_x = cx * step;
7849 g_em->dst_offset_y = cy * step;
7852 else /* tile where movement ends */
7854 if (dx < 0 || dy < 0)
7856 g_em->dst_offset_x = cx * step;
7857 g_em->dst_offset_y = cy * step;
7861 g_em->src_offset_x = cx * step;
7862 g_em->src_offset_y = cy * step;
7866 g_em->width = TILEX - cx * step;
7867 g_em->height = TILEY - cy * step;
7870 /* create unique graphic identifier to decide if tile must be redrawn */
7871 /* bit 31 - 16 (16 bit): EM style graphic
7872 bit 15 - 12 ( 4 bit): EM style frame
7873 bit 11 - 6 ( 6 bit): graphic width
7874 bit 5 - 0 ( 6 bit): graphic height */
7875 g_em->unique_identifier =
7876 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
7880 /* skip check for EMC elements not contained in original EMC artwork */
7881 if (element == EL_EMC_FAKE_ACID)
7884 if (g_em->bitmap != debug_bitmap ||
7885 g_em->src_x != debug_src_x ||
7886 g_em->src_y != debug_src_y ||
7887 g_em->src_offset_x != 0 ||
7888 g_em->src_offset_y != 0 ||
7889 g_em->dst_offset_x != 0 ||
7890 g_em->dst_offset_y != 0 ||
7891 g_em->width != TILEX ||
7892 g_em->height != TILEY)
7894 static int last_i = -1;
7902 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
7903 i, element, element_info[element].token_name,
7904 element_action_info[effective_action].suffix, direction);
7906 if (element != effective_element)
7907 printf(" [%d ('%s')]",
7909 element_info[effective_element].token_name);
7913 if (g_em->bitmap != debug_bitmap)
7914 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
7915 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
7917 if (g_em->src_x != debug_src_x ||
7918 g_em->src_y != debug_src_y)
7919 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
7920 j, (is_backside ? 'B' : 'F'),
7921 g_em->src_x, g_em->src_y,
7922 g_em->src_x / 32, g_em->src_y / 32,
7923 debug_src_x, debug_src_y,
7924 debug_src_x / 32, debug_src_y / 32);
7926 if (g_em->src_offset_x != 0 ||
7927 g_em->src_offset_y != 0 ||
7928 g_em->dst_offset_x != 0 ||
7929 g_em->dst_offset_y != 0)
7930 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
7932 g_em->src_offset_x, g_em->src_offset_y,
7933 g_em->dst_offset_x, g_em->dst_offset_y);
7935 if (g_em->width != TILEX ||
7936 g_em->height != TILEY)
7937 printf(" %d (%d): size %d,%d should be %d,%d\n",
7939 g_em->width, g_em->height, TILEX, TILEY);
7941 num_em_gfx_errors++;
7948 for (i = 0; i < TILE_MAX; i++)
7950 for (j = 0; j < 8; j++)
7952 int element = object_mapping[i].element_rnd;
7953 int action = object_mapping[i].action;
7954 int direction = object_mapping[i].direction;
7955 boolean is_backside = object_mapping[i].is_backside;
7956 int graphic_action = el_act_dir2img(element, action, direction);
7957 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
7959 if ((action == ACTION_SMASHED_BY_ROCK ||
7960 action == ACTION_SMASHED_BY_SPRING ||
7961 action == ACTION_EATING) &&
7962 graphic_action == graphic_default)
7964 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
7965 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
7966 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
7967 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
7970 /* no separate animation for "smashed by rock" -- use rock instead */
7971 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7972 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
7974 g_em->bitmap = g_xx->bitmap;
7975 g_em->src_x = g_xx->src_x;
7976 g_em->src_y = g_xx->src_y;
7977 g_em->src_offset_x = g_xx->src_offset_x;
7978 g_em->src_offset_y = g_xx->src_offset_y;
7979 g_em->dst_offset_x = g_xx->dst_offset_x;
7980 g_em->dst_offset_y = g_xx->dst_offset_y;
7981 g_em->width = g_xx->width;
7982 g_em->height = g_xx->height;
7983 g_em->unique_identifier = g_xx->unique_identifier;
7986 g_em->preserve_background = TRUE;
7991 for (p = 0; p < MAX_PLAYERS; p++)
7993 for (i = 0; i < SPR_MAX; i++)
7995 int element = player_mapping[p][i].element_rnd;
7996 int action = player_mapping[p][i].action;
7997 int direction = player_mapping[p][i].direction;
7999 for (j = 0; j < 8; j++)
8001 int effective_element = element;
8002 int effective_action = action;
8003 int graphic = (direction == MV_NONE ?
8004 el_act2img(effective_element, effective_action) :
8005 el_act_dir2img(effective_element, effective_action,
8007 struct GraphicInfo *g = &graphic_info[graphic];
8008 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
8014 Bitmap *debug_bitmap = g_em->bitmap;
8015 int debug_src_x = g_em->src_x;
8016 int debug_src_y = g_em->src_y;
8019 int frame = getAnimationFrame(g->anim_frames,
8022 g->anim_start_frame,
8025 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
8027 g_em->bitmap = src_bitmap;
8028 g_em->src_x = src_x;
8029 g_em->src_y = src_y;
8030 g_em->src_offset_x = 0;
8031 g_em->src_offset_y = 0;
8032 g_em->dst_offset_x = 0;
8033 g_em->dst_offset_y = 0;
8034 g_em->width = TILEX;
8035 g_em->height = TILEY;
8039 /* skip check for EMC elements not contained in original EMC artwork */
8040 if (element == EL_PLAYER_3 ||
8041 element == EL_PLAYER_4)
8044 if (g_em->bitmap != debug_bitmap ||
8045 g_em->src_x != debug_src_x ||
8046 g_em->src_y != debug_src_y)
8048 static int last_i = -1;
8056 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
8057 p, i, element, element_info[element].token_name,
8058 element_action_info[effective_action].suffix, direction);
8060 if (element != effective_element)
8061 printf(" [%d ('%s')]",
8063 element_info[effective_element].token_name);
8067 if (g_em->bitmap != debug_bitmap)
8068 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
8069 j, (int)(g_em->bitmap), (int)(debug_bitmap));
8071 if (g_em->src_x != debug_src_x ||
8072 g_em->src_y != debug_src_y)
8073 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
8075 g_em->src_x, g_em->src_y,
8076 g_em->src_x / 32, g_em->src_y / 32,
8077 debug_src_x, debug_src_y,
8078 debug_src_x / 32, debug_src_y / 32);
8080 num_em_gfx_errors++;
8090 printf("::: [%d errors found]\n", num_em_gfx_errors);
8096 void CheckSaveEngineSnapshot_EM(byte action[MAX_PLAYERS], int frame,
8097 boolean any_player_moving,
8098 boolean any_player_snapping,
8099 boolean any_player_dropping)
8101 if (frame == 0 && !any_player_dropping)
8103 if (!local_player->was_waiting)
8105 if (!CheckSaveEngineSnapshotToList())
8108 local_player->was_waiting = TRUE;
8111 else if (any_player_moving || any_player_snapping || any_player_dropping)
8113 local_player->was_waiting = FALSE;
8117 void CheckSaveEngineSnapshot_SP(boolean murphy_is_waiting,
8118 boolean murphy_is_dropping)
8120 if (murphy_is_waiting)
8122 if (!local_player->was_waiting)
8124 if (!CheckSaveEngineSnapshotToList())
8127 local_player->was_waiting = TRUE;
8132 local_player->was_waiting = FALSE;
8136 void CheckSingleStepMode_EM(byte action[MAX_PLAYERS], int frame,
8137 boolean any_player_moving,
8138 boolean any_player_snapping,
8139 boolean any_player_dropping)
8141 if (tape.single_step && tape.recording && !tape.pausing)
8142 if (frame == 0 && !any_player_dropping)
8143 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
8145 CheckSaveEngineSnapshot_EM(action, frame, any_player_moving,
8146 any_player_snapping, any_player_dropping);
8149 void CheckSingleStepMode_SP(boolean murphy_is_waiting,
8150 boolean murphy_is_dropping)
8152 if (tape.single_step && tape.recording && !tape.pausing)
8153 if (murphy_is_waiting)
8154 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
8156 CheckSaveEngineSnapshot_SP(murphy_is_waiting, murphy_is_dropping);
8159 void getGraphicSource_SP(struct GraphicInfo_SP *g_sp,
8160 int graphic, int sync_frame, int x, int y)
8162 int frame = getGraphicAnimationFrame(graphic, sync_frame);
8164 getGraphicSource(graphic, frame, &g_sp->bitmap, &g_sp->src_x, &g_sp->src_y);
8167 boolean isNextAnimationFrame_SP(int graphic, int sync_frame)
8169 return (IS_NEXT_FRAME(sync_frame, graphic));
8172 int getGraphicInfo_Delay(int graphic)
8174 return graphic_info[graphic].anim_delay;
8177 void PlayMenuSoundExt(int sound)
8179 if (sound == SND_UNDEFINED)
8182 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8183 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8186 if (IS_LOOP_SOUND(sound))
8187 PlaySoundLoop(sound);
8192 void PlayMenuSound()
8194 PlayMenuSoundExt(menu.sound[game_status]);
8197 void PlayMenuSoundStereo(int sound, int stereo_position)
8199 if (sound == SND_UNDEFINED)
8202 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8203 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8206 if (IS_LOOP_SOUND(sound))
8207 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
8209 PlaySoundStereo(sound, stereo_position);
8212 void PlayMenuSoundIfLoopExt(int sound)
8214 if (sound == SND_UNDEFINED)
8217 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8218 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8221 if (IS_LOOP_SOUND(sound))
8222 PlaySoundLoop(sound);
8225 void PlayMenuSoundIfLoop()
8227 PlayMenuSoundIfLoopExt(menu.sound[game_status]);
8230 void PlayMenuMusicExt(int music)
8232 if (music == MUS_UNDEFINED)
8235 if (!setup.sound_music)
8241 void PlayMenuMusic()
8243 PlayMenuMusicExt(menu.music[game_status]);
8246 void PlaySoundActivating()
8249 PlaySound(SND_MENU_ITEM_ACTIVATING);
8253 void PlaySoundSelecting()
8256 PlaySound(SND_MENU_ITEM_SELECTING);
8260 void ToggleFullscreenOrChangeWindowScalingIfNeeded()
8262 boolean change_fullscreen = (setup.fullscreen !=
8263 video.fullscreen_enabled);
8264 boolean change_window_scaling_percent = (!video.fullscreen_enabled &&
8265 setup.window_scaling_percent !=
8266 video.window_scaling_percent);
8268 if (change_window_scaling_percent && video.fullscreen_enabled)
8271 if (!change_window_scaling_percent && !video.fullscreen_available)
8274 #if defined(TARGET_SDL2)
8275 if (change_window_scaling_percent)
8277 SDLSetWindowScaling(setup.window_scaling_percent);
8281 else if (change_fullscreen)
8283 SDLSetWindowFullscreen(setup.fullscreen);
8285 /* set setup value according to successfully changed fullscreen mode */
8286 setup.fullscreen = video.fullscreen_enabled;
8292 if (change_fullscreen ||
8293 change_window_scaling_percent)
8295 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
8297 /* save backbuffer content which gets lost when toggling fullscreen mode */
8298 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8300 if (change_window_scaling_percent)
8302 /* keep window mode, but change window scaling */
8303 video.fullscreen_enabled = TRUE; /* force new window scaling */
8306 /* toggle fullscreen */
8307 ChangeVideoModeIfNeeded(setup.fullscreen);
8309 /* set setup value according to successfully changed fullscreen mode */
8310 setup.fullscreen = video.fullscreen_enabled;
8312 /* restore backbuffer content from temporary backbuffer backup bitmap */
8313 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8315 FreeBitmap(tmp_backbuffer);
8317 /* update visible window/screen */
8318 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8322 void JoinRectangles(int *x, int *y, int *width, int *height,
8323 int x2, int y2, int width2, int height2)
8325 // do not join with "off-screen" rectangle
8326 if (x2 == -1 || y2 == -1)
8331 *width = MAX(*width, width2);
8332 *height = MAX(*height, height2);
8335 void SetAnimStatus(int anim_status_new)
8337 if (anim_status_new == GAME_MODE_MAIN)
8338 anim_status_new = GAME_MODE_PSEUDO_MAINONLY;
8340 global.anim_status_next = anim_status_new;
8342 // directly set screen modes that are entered without fading
8343 if ((global.anim_status == GAME_MODE_PSEUDO_MAINONLY &&
8344 global.anim_status_next == GAME_MODE_PSEUDO_TYPENAME) ||
8345 (global.anim_status == GAME_MODE_PSEUDO_TYPENAME &&
8346 global.anim_status_next == GAME_MODE_PSEUDO_MAINONLY))
8347 global.anim_status = global.anim_status_next;
8350 void SetGameStatus(int game_status_new)
8352 game_status = game_status_new;
8354 SetAnimStatus(game_status_new);
8357 void SetFontStatus(int game_status_new)
8359 static int last_game_status = -1;
8361 if (game_status_new != -1)
8363 // set game status for font use after storing last game status
8364 last_game_status = game_status;
8365 game_status = game_status_new;
8369 // reset game status after font use from last stored game status
8370 game_status = last_game_status;
8374 void ResetFontStatus()
8379 void ChangeViewportPropertiesIfNeeded()
8381 int gfx_game_mode = game_status;
8382 int gfx_game_mode2 = (game_status == GAME_MODE_EDITOR ? GAME_MODE_DEFAULT :
8384 struct RectWithBorder *vp_window = &viewport.window[gfx_game_mode];
8385 struct RectWithBorder *vp_playfield = &viewport.playfield[gfx_game_mode];
8386 struct RectWithBorder *vp_door_1 = &viewport.door_1[gfx_game_mode];
8387 struct RectWithBorder *vp_door_2 = &viewport.door_2[gfx_game_mode2];
8388 struct RectWithBorder *vp_door_3 = &viewport.door_2[GAME_MODE_EDITOR];
8389 int new_win_xsize = vp_window->width;
8390 int new_win_ysize = vp_window->height;
8391 int border_size = vp_playfield->border_size;
8392 int new_sx = vp_playfield->x + border_size;
8393 int new_sy = vp_playfield->y + border_size;
8394 int new_sxsize = vp_playfield->width - 2 * border_size;
8395 int new_sysize = vp_playfield->height - 2 * border_size;
8396 int new_real_sx = vp_playfield->x;
8397 int new_real_sy = vp_playfield->y;
8398 int new_full_sxsize = vp_playfield->width;
8399 int new_full_sysize = vp_playfield->height;
8400 int new_dx = vp_door_1->x;
8401 int new_dy = vp_door_1->y;
8402 int new_dxsize = vp_door_1->width;
8403 int new_dysize = vp_door_1->height;
8404 int new_vx = vp_door_2->x;
8405 int new_vy = vp_door_2->y;
8406 int new_vxsize = vp_door_2->width;
8407 int new_vysize = vp_door_2->height;
8408 int new_ex = vp_door_3->x;
8409 int new_ey = vp_door_3->y;
8410 int new_exsize = vp_door_3->width;
8411 int new_eysize = vp_door_3->height;
8412 int new_tilesize_var =
8413 (setup.small_game_graphics ? MINI_TILESIZE : game.tile_size);
8415 int tilesize = (gfx_game_mode == GAME_MODE_PLAYING ? new_tilesize_var :
8416 gfx_game_mode == GAME_MODE_EDITOR ? MINI_TILESIZE : TILESIZE);
8417 int new_scr_fieldx = new_sxsize / tilesize;
8418 int new_scr_fieldy = new_sysize / tilesize;
8419 int new_scr_fieldx_buffers = new_sxsize / new_tilesize_var;
8420 int new_scr_fieldy_buffers = new_sysize / new_tilesize_var;
8421 boolean init_gfx_buffers = FALSE;
8422 boolean init_video_buffer = FALSE;
8423 boolean init_gadgets_and_anims = FALSE;
8424 boolean init_em_graphics = FALSE;
8426 if (new_win_xsize != WIN_XSIZE ||
8427 new_win_ysize != WIN_YSIZE)
8429 WIN_XSIZE = new_win_xsize;
8430 WIN_YSIZE = new_win_ysize;
8432 init_video_buffer = TRUE;
8433 init_gfx_buffers = TRUE;
8434 init_gadgets_and_anims = TRUE;
8436 // printf("::: video: init_video_buffer, init_gfx_buffers\n");
8439 if (new_scr_fieldx != SCR_FIELDX ||
8440 new_scr_fieldy != SCR_FIELDY)
8442 /* this always toggles between MAIN and GAME when using small tile size */
8444 SCR_FIELDX = new_scr_fieldx;
8445 SCR_FIELDY = new_scr_fieldy;
8447 // printf("::: new_scr_fieldx != SCR_FIELDX ...\n");
8458 new_sxsize != SXSIZE ||
8459 new_sysize != SYSIZE ||
8460 new_dxsize != DXSIZE ||
8461 new_dysize != DYSIZE ||
8462 new_vxsize != VXSIZE ||
8463 new_vysize != VYSIZE ||
8464 new_exsize != EXSIZE ||
8465 new_eysize != EYSIZE ||
8466 new_real_sx != REAL_SX ||
8467 new_real_sy != REAL_SY ||
8468 new_full_sxsize != FULL_SXSIZE ||
8469 new_full_sysize != FULL_SYSIZE ||
8470 new_tilesize_var != TILESIZE_VAR
8473 // ------------------------------------------------------------------------
8474 // determine next fading area for changed viewport definitions
8475 // ------------------------------------------------------------------------
8477 // start with current playfield area (default fading area)
8480 FADE_SXSIZE = FULL_SXSIZE;
8481 FADE_SYSIZE = FULL_SYSIZE;
8483 // add new playfield area if position or size has changed
8484 if (new_real_sx != REAL_SX || new_real_sy != REAL_SY ||
8485 new_full_sxsize != FULL_SXSIZE || new_full_sysize != FULL_SYSIZE)
8487 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
8488 new_real_sx, new_real_sy, new_full_sxsize,new_full_sysize);
8491 // add current and new door 1 area if position or size has changed
8492 if (new_dx != DX || new_dy != DY ||
8493 new_dxsize != DXSIZE || new_dysize != DYSIZE)
8495 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
8496 DX, DY, DXSIZE, DYSIZE);
8497 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
8498 new_dx, new_dy, new_dxsize, new_dysize);
8501 // add current and new door 2 area if position or size has changed
8502 if (new_dx != VX || new_dy != VY ||
8503 new_dxsize != VXSIZE || new_dysize != VYSIZE)
8505 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
8506 VX, VY, VXSIZE, VYSIZE);
8507 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
8508 new_vx, new_vy, new_vxsize, new_vysize);
8511 // ------------------------------------------------------------------------
8512 // handle changed tile size
8513 // ------------------------------------------------------------------------
8515 if (new_tilesize_var != TILESIZE_VAR)
8517 // printf("::: new_tilesize_var != TILESIZE_VAR\n");
8519 // changing tile size invalidates scroll values of engine snapshots
8520 FreeEngineSnapshotSingle();
8522 // changing tile size requires update of graphic mapping for EM engine
8523 init_em_graphics = TRUE;
8534 SXSIZE = new_sxsize;
8535 SYSIZE = new_sysize;
8536 DXSIZE = new_dxsize;
8537 DYSIZE = new_dysize;
8538 VXSIZE = new_vxsize;
8539 VYSIZE = new_vysize;
8540 EXSIZE = new_exsize;
8541 EYSIZE = new_eysize;
8542 REAL_SX = new_real_sx;
8543 REAL_SY = new_real_sy;
8544 FULL_SXSIZE = new_full_sxsize;
8545 FULL_SYSIZE = new_full_sysize;
8546 TILESIZE_VAR = new_tilesize_var;
8548 init_gfx_buffers = TRUE;
8549 init_gadgets_and_anims = TRUE;
8551 // printf("::: viewports: init_gfx_buffers\n");
8552 // printf("::: viewports: init_gadgets_and_anims\n");
8555 if (init_gfx_buffers)
8557 // printf("::: init_gfx_buffers\n");
8559 SCR_FIELDX = new_scr_fieldx_buffers;
8560 SCR_FIELDY = new_scr_fieldy_buffers;
8564 SCR_FIELDX = new_scr_fieldx;
8565 SCR_FIELDY = new_scr_fieldy;
8567 SetDrawDeactivationMask(REDRAW_NONE);
8568 SetDrawBackgroundMask(REDRAW_FIELD);
8571 if (init_video_buffer)
8573 // printf("::: init_video_buffer\n");
8575 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
8576 InitImageTextures();
8579 if (init_gadgets_and_anims)
8581 // printf("::: init_gadgets_and_anims\n");
8584 InitGlobalAnimations();
8587 if (init_em_graphics)
8589 InitGraphicInfo_EM();