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 getSizedGraphicSourceExt(int graphic, int frame, int tilesize,
1223 Bitmap **bitmap, int *x, int *y,
1224 boolean get_backside)
1226 struct GraphicInfo *g = &graphic_info[graphic];
1227 Bitmap *src_bitmap = g->bitmap;
1228 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
1229 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
1230 int tilesize_capped = MIN(MAX(1, tilesize), TILESIZE);
1232 // if no in-game graphics defined, always use standard graphic size
1233 if (g->bitmaps[IMG_BITMAP_GAME] == NULL)
1234 tilesize = TILESIZE;
1236 if (tilesize == gfx.standard_tile_size)
1237 src_bitmap = g->bitmaps[IMG_BITMAP_STANDARD];
1238 else if (tilesize == game.tile_size)
1239 src_bitmap = g->bitmaps[IMG_BITMAP_GAME];
1241 src_bitmap = g->bitmaps[IMG_BITMAP_1x1 - log_2(tilesize_capped)];
1243 if (g->offset_y == 0) /* frames are ordered horizontally */
1245 int max_width = g->anim_frames_per_line * g->width;
1246 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
1248 src_x = pos % max_width;
1249 src_y = src_y % g->height + pos / max_width * g->height;
1251 else if (g->offset_x == 0) /* frames are ordered vertically */
1253 int max_height = g->anim_frames_per_line * g->height;
1254 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
1256 src_x = src_x % g->width + pos / max_height * g->width;
1257 src_y = pos % max_height;
1259 else /* frames are ordered diagonally */
1261 src_x = src_x + frame * g->offset_x;
1262 src_y = src_y + frame * g->offset_y;
1265 *bitmap = src_bitmap;
1266 *x = src_x * tilesize / g->tile_size;
1267 *y = src_y * tilesize / g->tile_size;
1270 void getFixedGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1271 int *x, int *y, boolean get_backside)
1273 getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y,
1277 void getSizedGraphicSource(int graphic, int frame, int tilesize,
1278 Bitmap **bitmap, int *x, int *y)
1280 getSizedGraphicSourceExt(graphic, frame, tilesize, bitmap, x, y, FALSE);
1283 void getFixedGraphicSource(int graphic, int frame,
1284 Bitmap **bitmap, int *x, int *y)
1286 getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y, FALSE);
1289 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1291 getSizedGraphicSource(graphic, 0, MINI_TILESIZE, bitmap, x, y);
1294 inline static void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1295 int *x, int *y, boolean get_backside)
1297 struct GraphicInfo *g = &graphic_info[graphic];
1298 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
1299 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
1301 if (TILESIZE_VAR != TILESIZE)
1302 return getSizedGraphicSourceExt(graphic, frame, TILESIZE_VAR, bitmap, x, y,
1305 *bitmap = g->bitmap;
1307 if (g->offset_y == 0) /* frames are ordered horizontally */
1309 int max_width = g->anim_frames_per_line * g->width;
1310 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
1312 *x = pos % max_width;
1313 *y = src_y % g->height + pos / max_width * g->height;
1315 else if (g->offset_x == 0) /* frames are ordered vertically */
1317 int max_height = g->anim_frames_per_line * g->height;
1318 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
1320 *x = src_x % g->width + pos / max_height * g->width;
1321 *y = pos % max_height;
1323 else /* frames are ordered diagonally */
1325 *x = src_x + frame * g->offset_x;
1326 *y = src_y + frame * g->offset_y;
1329 *x = *x * TILESIZE_VAR / g->tile_size;
1330 *y = *y * TILESIZE_VAR / g->tile_size;
1333 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
1335 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
1338 void DrawGraphic(int x, int y, int graphic, int frame)
1341 if (!IN_SCR_FIELD(x, y))
1343 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1344 printf("DrawGraphic(): This should never happen!\n");
1349 DrawGraphicExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR, graphic,
1352 MarkTileDirty(x, y);
1355 void DrawFixedGraphic(int x, int y, int graphic, int frame)
1358 if (!IN_SCR_FIELD(x, y))
1360 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1361 printf("DrawGraphic(): This should never happen!\n");
1366 DrawFixedGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic,
1368 MarkTileDirty(x, y);
1371 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1377 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1379 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX_VAR, TILEY_VAR, x, y);
1382 void DrawFixedGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1388 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1389 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
1392 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
1395 if (!IN_SCR_FIELD(x, y))
1397 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1398 printf("DrawGraphicThruMask(): This should never happen!\n");
1403 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
1406 MarkTileDirty(x, y);
1409 void DrawFixedGraphicThruMask(int x, int y, int graphic, int frame)
1412 if (!IN_SCR_FIELD(x, y))
1414 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1415 printf("DrawGraphicThruMask(): This should never happen!\n");
1420 DrawFixedGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
1422 MarkTileDirty(x, y);
1425 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
1431 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1433 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX_VAR, TILEY_VAR,
1437 void DrawFixedGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y,
1438 int graphic, int frame)
1443 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1445 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY,
1449 void DrawSizedGraphic(int x, int y, int graphic, int frame, int tilesize)
1451 DrawSizedGraphicExt(drawto, SX + x * tilesize, SY + y * tilesize, graphic,
1453 MarkTileDirty(x / tilesize, y / tilesize);
1456 void DrawSizedGraphicExt(DrawBuffer *d, int x, int y, int graphic, int frame,
1462 getSizedGraphicSource(graphic, frame, tilesize, &src_bitmap, &src_x, &src_y);
1463 BlitBitmap(src_bitmap, d, src_x, src_y, tilesize, tilesize, x, y);
1466 void DrawMiniGraphic(int x, int y, int graphic)
1468 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
1469 MarkTileDirty(x / 2, y / 2);
1472 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
1477 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1478 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
1481 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
1482 int graphic, int frame,
1483 int cut_mode, int mask_mode)
1488 int width = TILEX, height = TILEY;
1491 if (dx || dy) /* shifted graphic */
1493 if (x < BX1) /* object enters playfield from the left */
1500 else if (x > BX2) /* object enters playfield from the right */
1506 else if (x == BX1 && dx < 0) /* object leaves playfield to the left */
1512 else if (x == BX2 && dx > 0) /* object leaves playfield to the right */
1514 else if (dx) /* general horizontal movement */
1515 MarkTileDirty(x + SIGN(dx), y);
1517 if (y < BY1) /* object enters playfield from the top */
1519 if (cut_mode == CUT_BELOW) /* object completely above top border */
1527 else if (y > BY2) /* object enters playfield from the bottom */
1533 else if (y == BY1 && dy < 0) /* object leaves playfield to the top */
1539 else if (dy > 0 && cut_mode == CUT_ABOVE)
1541 if (y == BY2) /* object completely above bottom border */
1547 MarkTileDirty(x, y + 1);
1548 } /* object leaves playfield to the bottom */
1549 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1551 else if (dy) /* general vertical movement */
1552 MarkTileDirty(x, y + SIGN(dy));
1556 if (!IN_SCR_FIELD(x, y))
1558 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1559 printf("DrawGraphicShifted(): This should never happen!\n");
1564 width = width * TILESIZE_VAR / TILESIZE;
1565 height = height * TILESIZE_VAR / TILESIZE;
1566 cx = cx * TILESIZE_VAR / TILESIZE;
1567 cy = cy * TILESIZE_VAR / TILESIZE;
1568 dx = dx * TILESIZE_VAR / TILESIZE;
1569 dy = dy * TILESIZE_VAR / TILESIZE;
1571 if (width > 0 && height > 0)
1573 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1578 dst_x = FX + x * TILEX_VAR + dx;
1579 dst_y = FY + y * TILEY_VAR + dy;
1581 if (mask_mode == USE_MASKING)
1582 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1585 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1588 MarkTileDirty(x, y);
1592 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
1593 int graphic, int frame,
1594 int cut_mode, int mask_mode)
1599 int width = TILEX_VAR, height = TILEY_VAR;
1602 int x2 = x + SIGN(dx);
1603 int y2 = y + SIGN(dy);
1605 /* movement with two-tile animations must be sync'ed with movement position,
1606 not with current GfxFrame (which can be higher when using slow movement) */
1607 int anim_pos = (dx ? ABS(dx) : ABS(dy));
1608 int anim_frames = graphic_info[graphic].anim_frames;
1610 /* (we also need anim_delay here for movement animations with less frames) */
1611 int anim_delay = graphic_info[graphic].anim_delay;
1612 int sync_frame = anim_pos * anim_frames * anim_delay / TILESIZE;
1614 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
1615 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
1617 /* re-calculate animation frame for two-tile movement animation */
1618 frame = getGraphicAnimationFrame(graphic, sync_frame);
1620 /* check if movement start graphic inside screen area and should be drawn */
1621 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
1623 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
1625 dst_x = FX + x1 * TILEX_VAR;
1626 dst_y = FY + y1 * TILEY_VAR;
1628 if (mask_mode == USE_MASKING)
1629 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1632 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1635 MarkTileDirty(x1, y1);
1638 /* check if movement end graphic inside screen area and should be drawn */
1639 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
1641 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
1643 dst_x = FX + x2 * TILEX_VAR;
1644 dst_y = FY + y2 * TILEY_VAR;
1646 if (mask_mode == USE_MASKING)
1647 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1650 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1653 MarkTileDirty(x2, y2);
1657 static void DrawGraphicShifted(int x, int y, int dx, int dy,
1658 int graphic, int frame,
1659 int cut_mode, int mask_mode)
1663 DrawGraphic(x, y, graphic, frame);
1668 if (graphic_info[graphic].double_movement) /* EM style movement images */
1669 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1671 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1674 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1675 int frame, int cut_mode)
1677 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
1680 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1681 int cut_mode, int mask_mode)
1683 int lx = LEVELX(x), ly = LEVELY(y);
1687 if (IN_LEV_FIELD(lx, ly))
1689 SetRandomAnimationValue(lx, ly);
1691 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
1692 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1694 /* do not use double (EM style) movement graphic when not moving */
1695 if (graphic_info[graphic].double_movement && !dx && !dy)
1697 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
1698 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1701 else /* border element */
1703 graphic = el2img(element);
1704 frame = getGraphicAnimationFrame(graphic, -1);
1707 if (element == EL_EXPANDABLE_WALL)
1709 boolean left_stopped = FALSE, right_stopped = FALSE;
1711 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1712 left_stopped = TRUE;
1713 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1714 right_stopped = TRUE;
1716 if (left_stopped && right_stopped)
1718 else if (left_stopped)
1720 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1721 frame = graphic_info[graphic].anim_frames - 1;
1723 else if (right_stopped)
1725 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1726 frame = graphic_info[graphic].anim_frames - 1;
1731 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1732 else if (mask_mode == USE_MASKING)
1733 DrawGraphicThruMask(x, y, graphic, frame);
1735 DrawGraphic(x, y, graphic, frame);
1738 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1739 int cut_mode, int mask_mode)
1741 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1742 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1743 cut_mode, mask_mode);
1746 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1749 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1752 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1755 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1758 void DrawLevelElementThruMask(int x, int y, int element)
1760 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1763 void DrawLevelFieldThruMask(int x, int y)
1765 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1768 /* !!! implementation of quicksand is totally broken !!! */
1769 #define IS_CRUMBLED_TILE(x, y, e) \
1770 (GFX_CRUMBLED(e) && (!IN_LEV_FIELD(x, y) || \
1771 !IS_MOVING(x, y) || \
1772 (e) == EL_QUICKSAND_EMPTYING || \
1773 (e) == EL_QUICKSAND_FAST_EMPTYING))
1775 static void DrawLevelFieldCrumbledInnerCorners(int x, int y, int dx, int dy,
1780 int width, height, cx, cy;
1781 int sx = SCREENX(x), sy = SCREENY(y);
1782 int crumbled_border_size = graphic_info[graphic].border_size;
1785 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1787 for (i = 1; i < 4; i++)
1789 int dxx = (i & 1 ? dx : 0);
1790 int dyy = (i & 2 ? dy : 0);
1793 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1796 /* check if neighbour field is of same crumble type */
1797 boolean same = (IS_CRUMBLED_TILE(xx, yy, element) &&
1798 graphic_info[graphic].class ==
1799 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class);
1801 /* return if check prevents inner corner */
1802 if (same == (dxx == dx && dyy == dy))
1806 /* if we reach this point, we have an inner corner */
1808 getGraphicSource(graphic, 1, &src_bitmap, &src_x, &src_y);
1810 width = crumbled_border_size * TILESIZE_VAR / TILESIZE;
1811 height = crumbled_border_size * TILESIZE_VAR / TILESIZE;
1812 cx = (dx > 0 ? TILESIZE_VAR - width : 0);
1813 cy = (dy > 0 ? TILESIZE_VAR - height : 0);
1815 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1816 width, height, FX + sx * TILEX_VAR + cx, FY + sy * TILEY_VAR + cy);
1819 static void DrawLevelFieldCrumbledBorders(int x, int y, int graphic, int frame,
1824 int width, height, bx, by, cx, cy;
1825 int sx = SCREENX(x), sy = SCREENY(y);
1826 int crumbled_border_size = graphic_info[graphic].border_size;
1827 int crumbled_border_size_var = crumbled_border_size * TILESIZE_VAR / TILESIZE;
1828 int crumbled_border_pos_var = TILESIZE_VAR - crumbled_border_size_var;
1831 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1833 /* draw simple, sloppy, non-corner-accurate crumbled border */
1835 width = (dir == 1 || dir == 2 ? crumbled_border_size_var : TILESIZE_VAR);
1836 height = (dir == 0 || dir == 3 ? crumbled_border_size_var : TILESIZE_VAR);
1837 cx = (dir == 2 ? crumbled_border_pos_var : 0);
1838 cy = (dir == 3 ? crumbled_border_pos_var : 0);
1840 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy, width, height,
1841 FX + sx * TILEX_VAR + cx,
1842 FY + sy * TILEY_VAR + cy);
1844 /* (remaining middle border part must be at least as big as corner part) */
1845 if (!(graphic_info[graphic].style & STYLE_ACCURATE_BORDERS) ||
1846 crumbled_border_size >= TILESIZE / 3)
1849 /* correct corners of crumbled border, if needed */
1851 for (i = -1; i <= 1; i += 2)
1853 int xx = x + (dir == 0 || dir == 3 ? i : 0);
1854 int yy = y + (dir == 1 || dir == 2 ? i : 0);
1855 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1858 /* check if neighbour field is of same crumble type */
1859 if (IS_CRUMBLED_TILE(xx, yy, element) &&
1860 graphic_info[graphic].class ==
1861 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1863 /* no crumbled corner, but continued crumbled border */
1865 int c1 = (dir == 2 || dir == 3 ? crumbled_border_pos_var : 0);
1866 int c2 = (i == 1 ? crumbled_border_pos_var : 0);
1867 int b1 = (i == 1 ? crumbled_border_size_var :
1868 TILESIZE_VAR - 2 * crumbled_border_size_var);
1870 width = crumbled_border_size_var;
1871 height = crumbled_border_size_var;
1873 if (dir == 1 || dir == 2)
1888 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
1890 FX + sx * TILEX_VAR + cx,
1891 FY + sy * TILEY_VAR + cy);
1896 static void DrawLevelFieldCrumbledExt(int x, int y, int graphic, int frame)
1898 int sx = SCREENX(x), sy = SCREENY(y);
1901 static int xy[4][2] =
1909 if (!IN_LEV_FIELD(x, y))
1912 element = TILE_GFX_ELEMENT(x, y);
1914 /* crumble field itself */
1915 if (IS_CRUMBLED_TILE(x, y, element))
1917 if (!IN_SCR_FIELD(sx, sy))
1920 for (i = 0; i < 4; i++)
1922 int xx = x + xy[i][0];
1923 int yy = y + xy[i][1];
1925 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1928 /* check if neighbour field is of same crumble type */
1929 if (IS_CRUMBLED_TILE(xx, yy, element) &&
1930 graphic_info[graphic].class ==
1931 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1934 DrawLevelFieldCrumbledBorders(x, y, graphic, frame, i);
1937 if ((graphic_info[graphic].style & STYLE_INNER_CORNERS) &&
1938 graphic_info[graphic].anim_frames == 2)
1940 for (i = 0; i < 4; i++)
1942 int dx = (i & 1 ? +1 : -1);
1943 int dy = (i & 2 ? +1 : -1);
1945 DrawLevelFieldCrumbledInnerCorners(x, y, dx, dy, graphic);
1949 MarkTileDirty(sx, sy);
1951 else /* center field not crumbled -- crumble neighbour fields */
1953 for (i = 0; i < 4; i++)
1955 int xx = x + xy[i][0];
1956 int yy = y + xy[i][1];
1957 int sxx = sx + xy[i][0];
1958 int syy = sy + xy[i][1];
1960 if (!IN_LEV_FIELD(xx, yy) ||
1961 !IN_SCR_FIELD(sxx, syy))
1964 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
1967 element = TILE_GFX_ELEMENT(xx, yy);
1969 if (!IS_CRUMBLED_TILE(xx, yy, element))
1972 graphic = el_act2crm(element, ACTION_DEFAULT);
1974 DrawLevelFieldCrumbledBorders(xx, yy, graphic, 0, 3 - i);
1976 MarkTileDirty(sxx, syy);
1981 void DrawLevelFieldCrumbled(int x, int y)
1985 if (!IN_LEV_FIELD(x, y))
1988 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1989 GfxElement[x][y] != EL_UNDEFINED &&
1990 GFX_CRUMBLED(GfxElement[x][y]))
1992 DrawLevelFieldCrumbledDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
1997 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
1999 DrawLevelFieldCrumbledExt(x, y, graphic, 0);
2002 void DrawLevelFieldCrumbledDigging(int x, int y, int direction,
2005 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
2006 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
2007 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
2008 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
2009 int sx = SCREENX(x), sy = SCREENY(y);
2011 DrawGraphic(sx, sy, graphic1, frame1);
2012 DrawLevelFieldCrumbledExt(x, y, graphic2, frame2);
2015 void DrawLevelFieldCrumbledNeighbours(int x, int y)
2017 int sx = SCREENX(x), sy = SCREENY(y);
2018 static int xy[4][2] =
2027 for (i = 0; i < 4; i++)
2029 int xx = x + xy[i][0];
2030 int yy = y + xy[i][1];
2031 int sxx = sx + xy[i][0];
2032 int syy = sy + xy[i][1];
2034 if (!IN_LEV_FIELD(xx, yy) ||
2035 !IN_SCR_FIELD(sxx, syy) ||
2036 !GFX_CRUMBLED(Feld[xx][yy]) ||
2040 DrawLevelField(xx, yy);
2044 static int getBorderElement(int x, int y)
2048 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
2049 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
2050 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
2051 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
2052 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
2053 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
2054 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
2056 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
2057 int steel_position = (x == -1 && y == -1 ? 0 :
2058 x == lev_fieldx && y == -1 ? 1 :
2059 x == -1 && y == lev_fieldy ? 2 :
2060 x == lev_fieldx && y == lev_fieldy ? 3 :
2061 x == -1 || x == lev_fieldx ? 4 :
2062 y == -1 || y == lev_fieldy ? 5 : 6);
2064 return border[steel_position][steel_type];
2067 void DrawScreenElement(int x, int y, int element)
2069 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
2070 DrawLevelFieldCrumbled(LEVELX(x), LEVELY(y));
2073 void DrawLevelElement(int x, int y, int element)
2075 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2076 DrawScreenElement(SCREENX(x), SCREENY(y), element);
2079 void DrawScreenField(int x, int y)
2081 int lx = LEVELX(x), ly = LEVELY(y);
2082 int element, content;
2084 if (!IN_LEV_FIELD(lx, ly))
2086 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
2089 element = getBorderElement(lx, ly);
2091 DrawScreenElement(x, y, element);
2096 element = Feld[lx][ly];
2097 content = Store[lx][ly];
2099 if (IS_MOVING(lx, ly))
2101 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
2102 boolean cut_mode = NO_CUTTING;
2104 if (element == EL_QUICKSAND_EMPTYING ||
2105 element == EL_QUICKSAND_FAST_EMPTYING ||
2106 element == EL_MAGIC_WALL_EMPTYING ||
2107 element == EL_BD_MAGIC_WALL_EMPTYING ||
2108 element == EL_DC_MAGIC_WALL_EMPTYING ||
2109 element == EL_AMOEBA_DROPPING)
2110 cut_mode = CUT_ABOVE;
2111 else if (element == EL_QUICKSAND_FILLING ||
2112 element == EL_QUICKSAND_FAST_FILLING ||
2113 element == EL_MAGIC_WALL_FILLING ||
2114 element == EL_BD_MAGIC_WALL_FILLING ||
2115 element == EL_DC_MAGIC_WALL_FILLING)
2116 cut_mode = CUT_BELOW;
2118 if (cut_mode == CUT_ABOVE)
2119 DrawScreenElement(x, y, element);
2121 DrawScreenElement(x, y, EL_EMPTY);
2124 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
2125 else if (cut_mode == NO_CUTTING)
2126 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
2129 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
2131 if (cut_mode == CUT_BELOW &&
2132 IN_LEV_FIELD(lx, ly + 1) && IN_SCR_FIELD(x, y + 1))
2133 DrawLevelElement(lx, ly + 1, element);
2136 if (content == EL_ACID)
2138 int dir = MovDir[lx][ly];
2139 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
2140 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
2142 DrawLevelElementThruMask(newlx, newly, EL_ACID);
2145 else if (IS_BLOCKED(lx, ly))
2150 boolean cut_mode = NO_CUTTING;
2151 int element_old, content_old;
2153 Blocked2Moving(lx, ly, &oldx, &oldy);
2156 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
2157 MovDir[oldx][oldy] == MV_RIGHT);
2159 element_old = Feld[oldx][oldy];
2160 content_old = Store[oldx][oldy];
2162 if (element_old == EL_QUICKSAND_EMPTYING ||
2163 element_old == EL_QUICKSAND_FAST_EMPTYING ||
2164 element_old == EL_MAGIC_WALL_EMPTYING ||
2165 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
2166 element_old == EL_DC_MAGIC_WALL_EMPTYING ||
2167 element_old == EL_AMOEBA_DROPPING)
2168 cut_mode = CUT_ABOVE;
2170 DrawScreenElement(x, y, EL_EMPTY);
2173 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
2175 else if (cut_mode == NO_CUTTING)
2176 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
2179 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
2182 else if (IS_DRAWABLE(element))
2183 DrawScreenElement(x, y, element);
2185 DrawScreenElement(x, y, EL_EMPTY);
2188 void DrawLevelField(int x, int y)
2190 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2191 DrawScreenField(SCREENX(x), SCREENY(y));
2192 else if (IS_MOVING(x, y))
2196 Moving2Blocked(x, y, &newx, &newy);
2197 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
2198 DrawScreenField(SCREENX(newx), SCREENY(newy));
2200 else if (IS_BLOCKED(x, y))
2204 Blocked2Moving(x, y, &oldx, &oldy);
2205 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
2206 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
2210 void DrawSizedElement(int x, int y, int element, int tilesize)
2214 graphic = el2edimg(element);
2215 DrawSizedGraphic(x, y, graphic, 0, tilesize);
2218 void DrawMiniElement(int x, int y, int element)
2222 graphic = el2edimg(element);
2223 DrawMiniGraphic(x, y, graphic);
2226 void DrawSizedElementOrWall(int sx, int sy, int scroll_x, int scroll_y,
2229 int x = sx + scroll_x, y = sy + scroll_y;
2231 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
2232 DrawSizedElement(sx, sy, EL_EMPTY, tilesize);
2233 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
2234 DrawSizedElement(sx, sy, Feld[x][y], tilesize);
2236 DrawSizedGraphic(sx, sy, el2edimg(getBorderElement(x, y)), 0, tilesize);
2239 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
2241 int x = sx + scroll_x, y = sy + scroll_y;
2243 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
2244 DrawMiniElement(sx, sy, EL_EMPTY);
2245 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
2246 DrawMiniElement(sx, sy, Feld[x][y]);
2248 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
2251 void DrawEnvelopeBackgroundTiles(int graphic, int startx, int starty,
2252 int x, int y, int xsize, int ysize,
2253 int tile_width, int tile_height)
2257 int dst_x = startx + x * tile_width;
2258 int dst_y = starty + y * tile_height;
2259 int width = graphic_info[graphic].width;
2260 int height = graphic_info[graphic].height;
2261 int inner_width_raw = MAX(width - 2 * tile_width, tile_width);
2262 int inner_height_raw = MAX(height - 2 * tile_height, tile_height);
2263 int inner_width = inner_width_raw - (inner_width_raw % tile_width);
2264 int inner_height = inner_height_raw - (inner_height_raw % tile_height);
2265 int inner_sx = (width >= 3 * tile_width ? tile_width : 0);
2266 int inner_sy = (height >= 3 * tile_height ? tile_height : 0);
2267 boolean draw_masked = graphic_info[graphic].draw_masked;
2269 getFixedGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
2271 if (src_bitmap == NULL || width < tile_width || height < tile_height)
2273 ClearRectangle(drawto, dst_x, dst_y, tile_width, tile_height);
2277 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - tile_width :
2278 inner_sx + (x - 1) * tile_width % inner_width);
2279 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - tile_height :
2280 inner_sy + (y - 1) * tile_height % inner_height);
2283 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
2286 BlitBitmap(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
2290 void DrawEnvelopeBackground(int graphic, int startx, int starty,
2291 int x, int y, int xsize, int ysize, int font_nr)
2293 int font_width = getFontWidth(font_nr);
2294 int font_height = getFontHeight(font_nr);
2296 DrawEnvelopeBackgroundTiles(graphic, startx, starty, x, y, xsize, ysize,
2297 font_width, font_height);
2300 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
2302 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2303 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2304 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2305 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2306 boolean no_delay = (tape.warp_forward);
2307 unsigned int anim_delay = 0;
2308 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
2309 int anim_delay_value = (no_delay ? 0 : frame_delay_value) / 2;
2310 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
2311 int font_width = getFontWidth(font_nr);
2312 int font_height = getFontHeight(font_nr);
2313 int max_xsize = level.envelope[envelope_nr].xsize;
2314 int max_ysize = level.envelope[envelope_nr].ysize;
2315 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
2316 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
2317 int xend = max_xsize;
2318 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
2319 int xstep = (xstart < xend ? 1 : 0);
2320 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2322 int end = MAX(xend - xstart, yend - ystart);
2325 for (i = start; i <= end; i++)
2327 int last_frame = end; // last frame of this "for" loop
2328 int x = xstart + i * xstep;
2329 int y = ystart + i * ystep;
2330 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2331 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2332 int sx = SX + (SXSIZE - xsize * font_width) / 2;
2333 int sy = SY + (SYSIZE - ysize * font_height) / 2;
2336 SetDrawtoField(DRAW_TO_FIELDBUFFER);
2338 BlitScreenToBitmap(backbuffer);
2340 SetDrawtoField(DRAW_TO_BACKBUFFER);
2342 for (yy = 0; yy < ysize; yy++)
2343 for (xx = 0; xx < xsize; xx++)
2344 DrawEnvelopeBackground(graphic, sx, sy, xx, yy, xsize, ysize, font_nr);
2346 DrawTextBuffer(sx + font_width, sy + font_height,
2347 level.envelope[envelope_nr].text, font_nr, max_xsize,
2348 xsize - 2, ysize - 2, 0, mask_mode,
2349 level.envelope[envelope_nr].autowrap,
2350 level.envelope[envelope_nr].centered, FALSE);
2352 redraw_mask |= REDRAW_FIELD;
2355 SkipUntilDelayReached(&anim_delay, anim_delay_value, &i, last_frame);
2359 void ShowEnvelope(int envelope_nr)
2361 int element = EL_ENVELOPE_1 + envelope_nr;
2362 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2363 int sound_opening = element_info[element].sound[ACTION_OPENING];
2364 int sound_closing = element_info[element].sound[ACTION_CLOSING];
2365 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2366 boolean no_delay = (tape.warp_forward);
2367 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
2368 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
2369 int anim_mode = graphic_info[graphic].anim_mode;
2370 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2371 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2373 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
2375 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2377 if (anim_mode == ANIM_DEFAULT)
2378 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
2380 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
2383 Delay(wait_delay_value);
2385 WaitForEventToContinue();
2387 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2389 if (anim_mode != ANIM_NONE)
2390 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
2392 if (anim_mode == ANIM_DEFAULT)
2393 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
2395 game.envelope_active = FALSE;
2397 SetDrawtoField(DRAW_TO_FIELDBUFFER);
2399 redraw_mask |= REDRAW_FIELD;
2403 static void setRequestBasePosition(int *x, int *y)
2405 int sx_base, sy_base;
2407 if (request.x != -1)
2408 sx_base = request.x;
2409 else if (request.align == ALIGN_LEFT)
2411 else if (request.align == ALIGN_RIGHT)
2412 sx_base = SX + SXSIZE;
2414 sx_base = SX + SXSIZE / 2;
2416 if (request.y != -1)
2417 sy_base = request.y;
2418 else if (request.valign == VALIGN_TOP)
2420 else if (request.valign == VALIGN_BOTTOM)
2421 sy_base = SY + SYSIZE;
2423 sy_base = SY + SYSIZE / 2;
2429 static void setRequestPositionExt(int *x, int *y, int width, int height,
2430 boolean add_border_size)
2432 int border_size = request.border_size;
2433 int sx_base, sy_base;
2436 setRequestBasePosition(&sx_base, &sy_base);
2438 if (request.align == ALIGN_LEFT)
2440 else if (request.align == ALIGN_RIGHT)
2441 sx = sx_base - width;
2443 sx = sx_base - width / 2;
2445 if (request.valign == VALIGN_TOP)
2447 else if (request.valign == VALIGN_BOTTOM)
2448 sy = sy_base - height;
2450 sy = sy_base - height / 2;
2452 sx = MAX(0, MIN(sx, WIN_XSIZE - width));
2453 sy = MAX(0, MIN(sy, WIN_YSIZE - height));
2455 if (add_border_size)
2465 static void setRequestPosition(int *x, int *y, boolean add_border_size)
2467 setRequestPositionExt(x, y, request.width, request.height, add_border_size);
2470 void DrawEnvelopeRequest(char *text)
2472 char *text_final = text;
2473 char *text_door_style = NULL;
2474 int graphic = IMG_BACKGROUND_REQUEST;
2475 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2476 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2477 int font_nr = FONT_REQUEST;
2478 int font_width = getFontWidth(font_nr);
2479 int font_height = getFontHeight(font_nr);
2480 int border_size = request.border_size;
2481 int line_spacing = request.line_spacing;
2482 int line_height = font_height + line_spacing;
2483 int max_text_width = request.width - 2 * border_size;
2484 int max_text_height = request.height - 2 * border_size;
2485 int line_length = max_text_width / font_width;
2486 int max_lines = max_text_height / line_height;
2487 int text_width = line_length * font_width;
2488 int width = request.width;
2489 int height = request.height;
2490 int tile_size = MAX(request.step_offset, 1);
2491 int x_steps = width / tile_size;
2492 int y_steps = height / tile_size;
2493 int sx_offset = border_size;
2494 int sy_offset = border_size;
2498 if (request.centered)
2499 sx_offset = (request.width - text_width) / 2;
2501 if (request.wrap_single_words && !request.autowrap)
2503 char *src_text_ptr, *dst_text_ptr;
2505 text_door_style = checked_malloc(2 * strlen(text) + 1);
2507 src_text_ptr = text;
2508 dst_text_ptr = text_door_style;
2510 while (*src_text_ptr)
2512 if (*src_text_ptr == ' ' ||
2513 *src_text_ptr == '?' ||
2514 *src_text_ptr == '!')
2515 *dst_text_ptr++ = '\n';
2517 if (*src_text_ptr != ' ')
2518 *dst_text_ptr++ = *src_text_ptr;
2523 *dst_text_ptr = '\0';
2525 text_final = text_door_style;
2528 setRequestPosition(&sx, &sy, FALSE);
2530 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
2532 for (y = 0; y < y_steps; y++)
2533 for (x = 0; x < x_steps; x++)
2534 DrawEnvelopeBackgroundTiles(graphic, sx, sy,
2535 x, y, x_steps, y_steps,
2536 tile_size, tile_size);
2538 /* force DOOR font inside door area */
2539 SetFontStatus(GAME_MODE_PSEUDO_DOOR);
2541 DrawTextBuffer(sx + sx_offset, sy + sy_offset, text_final, font_nr,
2542 line_length, -1, max_lines, line_spacing, mask_mode,
2543 request.autowrap, request.centered, FALSE);
2547 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2548 RedrawGadget(tool_gadget[i]);
2550 // store readily prepared envelope request for later use when animating
2551 BlitBitmap(backbuffer, bitmap_db_store_2, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2553 if (text_door_style)
2554 free(text_door_style);
2557 void AnimateEnvelopeRequest(int anim_mode, int action)
2559 int graphic = IMG_BACKGROUND_REQUEST;
2560 boolean draw_masked = graphic_info[graphic].draw_masked;
2561 int delay_value_normal = request.step_delay;
2562 int delay_value_fast = delay_value_normal / 2;
2563 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2564 boolean no_delay = (tape.warp_forward);
2565 int delay_value = (ffwd_delay ? delay_value_fast : delay_value_normal);
2566 int anim_delay_value = (no_delay ? 0 : delay_value + 500 * 0) / 2;
2567 unsigned int anim_delay = 0;
2569 int tile_size = MAX(request.step_offset, 1);
2570 int max_xsize = request.width / tile_size;
2571 int max_ysize = request.height / tile_size;
2572 int max_xsize_inner = max_xsize - 2;
2573 int max_ysize_inner = max_ysize - 2;
2575 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize_inner : 0);
2576 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize_inner : 0);
2577 int xend = max_xsize_inner;
2578 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize_inner : 0);
2579 int xstep = (xstart < xend ? 1 : 0);
2580 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2582 int end = MAX(xend - xstart, yend - ystart);
2585 if (setup.quick_doors)
2592 for (i = start; i <= end; i++)
2594 int last_frame = end; // last frame of this "for" loop
2595 int x = xstart + i * xstep;
2596 int y = ystart + i * ystep;
2597 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2598 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2599 int xsize_size_left = (xsize - 1) * tile_size;
2600 int ysize_size_top = (ysize - 1) * tile_size;
2601 int max_xsize_pos = (max_xsize - 1) * tile_size;
2602 int max_ysize_pos = (max_ysize - 1) * tile_size;
2603 int width = xsize * tile_size;
2604 int height = ysize * tile_size;
2609 setRequestPosition(&src_x, &src_y, FALSE);
2610 setRequestPositionExt(&dst_x, &dst_y, width, height, FALSE);
2612 BlitBitmap(bitmap_db_store_1, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2614 for (yy = 0; yy < 2; yy++)
2616 for (xx = 0; xx < 2; xx++)
2618 int src_xx = src_x + xx * max_xsize_pos;
2619 int src_yy = src_y + yy * max_ysize_pos;
2620 int dst_xx = dst_x + xx * xsize_size_left;
2621 int dst_yy = dst_y + yy * ysize_size_top;
2622 int xx_size = (xx ? tile_size : xsize_size_left);
2623 int yy_size = (yy ? tile_size : ysize_size_top);
2626 BlitBitmapMasked(bitmap_db_store_2, backbuffer,
2627 src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
2629 BlitBitmap(bitmap_db_store_2, backbuffer,
2630 src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
2634 redraw_mask |= REDRAW_FIELD;
2638 SkipUntilDelayReached(&anim_delay, anim_delay_value, &i, last_frame);
2642 void ShowEnvelopeRequest(char *text, unsigned int req_state, int action)
2644 int graphic = IMG_BACKGROUND_REQUEST;
2645 int sound_opening = SND_REQUEST_OPENING;
2646 int sound_closing = SND_REQUEST_CLOSING;
2647 int anim_mode_1 = request.anim_mode; /* (higher priority) */
2648 int anim_mode_2 = graphic_info[graphic].anim_mode; /* (lower priority) */
2649 int anim_mode = (anim_mode_1 != ANIM_DEFAULT ? anim_mode_1 : anim_mode_2);
2650 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2651 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2653 if (game_status == GAME_MODE_PLAYING)
2654 BlitScreenToBitmap(backbuffer);
2656 SetDrawtoField(DRAW_TO_BACKBUFFER);
2658 // SetDrawBackgroundMask(REDRAW_NONE);
2660 if (action == ACTION_OPENING)
2662 BlitBitmap(backbuffer, bitmap_db_store_1, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2664 if (req_state & REQ_ASK)
2666 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2667 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2669 else if (req_state & REQ_CONFIRM)
2671 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2673 else if (req_state & REQ_PLAYER)
2675 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2676 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2677 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2678 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2681 DrawEnvelopeRequest(text);
2684 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
2686 if (action == ACTION_OPENING)
2688 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2690 if (anim_mode == ANIM_DEFAULT)
2691 AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_OPENING);
2693 AnimateEnvelopeRequest(main_anim_mode, ACTION_OPENING);
2697 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2699 if (anim_mode != ANIM_NONE)
2700 AnimateEnvelopeRequest(main_anim_mode, ACTION_CLOSING);
2702 if (anim_mode == ANIM_DEFAULT)
2703 AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_CLOSING);
2706 game.envelope_active = FALSE;
2708 if (action == ACTION_CLOSING)
2709 BlitBitmap(bitmap_db_store_1, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2711 // SetDrawBackgroundMask(last_draw_background_mask);
2713 redraw_mask |= REDRAW_FIELD;
2717 if (action == ACTION_CLOSING &&
2718 game_status == GAME_MODE_PLAYING &&
2719 level.game_engine_type == GAME_ENGINE_TYPE_RND)
2720 SetDrawtoField(DRAW_TO_FIELDBUFFER);
2723 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
2727 int graphic = el2preimg(element);
2729 getSizedGraphicSource(graphic, 0, tilesize, &src_bitmap, &src_x, &src_y);
2730 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
2733 void DrawLevel(int draw_background_mask)
2737 SetMainBackgroundImage(IMG_BACKGROUND_PLAYING);
2738 SetDrawBackgroundMask(draw_background_mask);
2742 for (x = BX1; x <= BX2; x++)
2743 for (y = BY1; y <= BY2; y++)
2744 DrawScreenField(x, y);
2746 redraw_mask |= REDRAW_FIELD;
2749 void DrawSizedLevel(int size_x, int size_y, int scroll_x, int scroll_y,
2754 for (x = 0; x < size_x; x++)
2755 for (y = 0; y < size_y; y++)
2756 DrawSizedElementOrWall(x, y, scroll_x, scroll_y, tilesize);
2758 redraw_mask |= REDRAW_FIELD;
2761 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
2765 for (x = 0; x < size_x; x++)
2766 for (y = 0; y < size_y; y++)
2767 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
2769 redraw_mask |= REDRAW_FIELD;
2772 static void DrawPreviewLevelPlayfieldExt(int from_x, int from_y)
2774 boolean show_level_border = (BorderElement != EL_EMPTY);
2775 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2776 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2777 int tile_size = preview.tile_size;
2778 int preview_width = preview.xsize * tile_size;
2779 int preview_height = preview.ysize * tile_size;
2780 int real_preview_xsize = MIN(level_xsize, preview.xsize);
2781 int real_preview_ysize = MIN(level_ysize, preview.ysize);
2782 int real_preview_width = real_preview_xsize * tile_size;
2783 int real_preview_height = real_preview_ysize * tile_size;
2784 int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
2785 int dst_y = SY + ALIGNED_YPOS(preview.y, preview_height, preview.valign);
2788 if (!IN_GFX_FIELD_FULL(dst_x, dst_y + preview_height - 1))
2791 DrawBackground(dst_x, dst_y, preview_width, preview_height);
2793 dst_x += (preview_width - real_preview_width) / 2;
2794 dst_y += (preview_height - real_preview_height) / 2;
2796 for (x = 0; x < real_preview_xsize; x++)
2798 for (y = 0; y < real_preview_ysize; y++)
2800 int lx = from_x + x + (show_level_border ? -1 : 0);
2801 int ly = from_y + y + (show_level_border ? -1 : 0);
2802 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
2803 getBorderElement(lx, ly));
2805 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
2806 element, tile_size);
2810 redraw_mask |= REDRAW_FIELD;
2813 #define MICROLABEL_EMPTY 0
2814 #define MICROLABEL_LEVEL_NAME 1
2815 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
2816 #define MICROLABEL_LEVEL_AUTHOR 3
2817 #define MICROLABEL_IMPORTED_FROM_HEAD 4
2818 #define MICROLABEL_IMPORTED_FROM 5
2819 #define MICROLABEL_IMPORTED_BY_HEAD 6
2820 #define MICROLABEL_IMPORTED_BY 7
2822 static int getMaxTextLength(struct TextPosInfo *pos, int font_nr)
2824 int max_text_width = SXSIZE;
2825 int font_width = getFontWidth(font_nr);
2827 if (pos->align == ALIGN_CENTER)
2828 max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
2829 else if (pos->align == ALIGN_RIGHT)
2830 max_text_width = pos->x;
2832 max_text_width = SXSIZE - pos->x;
2834 return max_text_width / font_width;
2837 static void DrawPreviewLevelLabelExt(int mode)
2839 struct TextPosInfo *pos = &menu.main.text.level_info_2;
2840 char label_text[MAX_OUTPUT_LINESIZE + 1];
2841 int max_len_label_text;
2842 int font_nr = pos->font;
2845 if (!IN_GFX_FIELD_FULL(pos->x, pos->y + getFontHeight(pos->font)))
2848 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
2849 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
2850 mode == MICROLABEL_IMPORTED_BY_HEAD)
2851 font_nr = pos->font_alt;
2853 max_len_label_text = getMaxTextLength(pos, font_nr);
2855 if (pos->size != -1)
2856 max_len_label_text = pos->size;
2858 for (i = 0; i < max_len_label_text; i++)
2859 label_text[i] = ' ';
2860 label_text[max_len_label_text] = '\0';
2862 if (strlen(label_text) > 0)
2863 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2866 (mode == MICROLABEL_LEVEL_NAME ? level.name :
2867 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
2868 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
2869 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
2870 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
2871 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
2872 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
2873 max_len_label_text);
2874 label_text[max_len_label_text] = '\0';
2876 if (strlen(label_text) > 0)
2877 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2879 redraw_mask |= REDRAW_FIELD;
2882 static void DrawPreviewLevelExt(boolean restart)
2884 static unsigned int scroll_delay = 0;
2885 static unsigned int label_delay = 0;
2886 static int from_x, from_y, scroll_direction;
2887 static int label_state, label_counter;
2888 unsigned int scroll_delay_value = preview.step_delay;
2889 boolean show_level_border = (BorderElement != EL_EMPTY);
2890 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2891 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2898 if (preview.anim_mode == ANIM_CENTERED)
2900 if (level_xsize > preview.xsize)
2901 from_x = (level_xsize - preview.xsize) / 2;
2902 if (level_ysize > preview.ysize)
2903 from_y = (level_ysize - preview.ysize) / 2;
2906 from_x += preview.xoffset;
2907 from_y += preview.yoffset;
2909 scroll_direction = MV_RIGHT;
2913 DrawPreviewLevelPlayfieldExt(from_x, from_y);
2914 DrawPreviewLevelLabelExt(label_state);
2916 /* initialize delay counters */
2917 DelayReached(&scroll_delay, 0);
2918 DelayReached(&label_delay, 0);
2920 if (leveldir_current->name)
2922 struct TextPosInfo *pos = &menu.main.text.level_info_1;
2923 char label_text[MAX_OUTPUT_LINESIZE + 1];
2924 int font_nr = pos->font;
2925 int max_len_label_text = getMaxTextLength(pos, font_nr);
2927 if (pos->size != -1)
2928 max_len_label_text = pos->size;
2930 strncpy(label_text, leveldir_current->name, max_len_label_text);
2931 label_text[max_len_label_text] = '\0';
2933 if (IN_GFX_FIELD_FULL(pos->x, pos->y + getFontHeight(pos->font)))
2934 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2940 /* scroll preview level, if needed */
2941 if (preview.anim_mode != ANIM_NONE &&
2942 (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
2943 DelayReached(&scroll_delay, scroll_delay_value))
2945 switch (scroll_direction)
2950 from_x -= preview.step_offset;
2951 from_x = (from_x < 0 ? 0 : from_x);
2954 scroll_direction = MV_UP;
2958 if (from_x < level_xsize - preview.xsize)
2960 from_x += preview.step_offset;
2961 from_x = (from_x > level_xsize - preview.xsize ?
2962 level_xsize - preview.xsize : from_x);
2965 scroll_direction = MV_DOWN;
2971 from_y -= preview.step_offset;
2972 from_y = (from_y < 0 ? 0 : from_y);
2975 scroll_direction = MV_RIGHT;
2979 if (from_y < level_ysize - preview.ysize)
2981 from_y += preview.step_offset;
2982 from_y = (from_y > level_ysize - preview.ysize ?
2983 level_ysize - preview.ysize : from_y);
2986 scroll_direction = MV_LEFT;
2993 DrawPreviewLevelPlayfieldExt(from_x, from_y);
2996 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
2997 /* redraw micro level label, if needed */
2998 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
2999 !strEqual(level.author, ANONYMOUS_NAME) &&
3000 !strEqual(level.author, leveldir_current->name) &&
3001 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
3003 int max_label_counter = 23;
3005 if (leveldir_current->imported_from != NULL &&
3006 strlen(leveldir_current->imported_from) > 0)
3007 max_label_counter += 14;
3008 if (leveldir_current->imported_by != NULL &&
3009 strlen(leveldir_current->imported_by) > 0)
3010 max_label_counter += 14;
3012 label_counter = (label_counter + 1) % max_label_counter;
3013 label_state = (label_counter >= 0 && label_counter <= 7 ?
3014 MICROLABEL_LEVEL_NAME :
3015 label_counter >= 9 && label_counter <= 12 ?
3016 MICROLABEL_LEVEL_AUTHOR_HEAD :
3017 label_counter >= 14 && label_counter <= 21 ?
3018 MICROLABEL_LEVEL_AUTHOR :
3019 label_counter >= 23 && label_counter <= 26 ?
3020 MICROLABEL_IMPORTED_FROM_HEAD :
3021 label_counter >= 28 && label_counter <= 35 ?
3022 MICROLABEL_IMPORTED_FROM :
3023 label_counter >= 37 && label_counter <= 40 ?
3024 MICROLABEL_IMPORTED_BY_HEAD :
3025 label_counter >= 42 && label_counter <= 49 ?
3026 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
3028 if (leveldir_current->imported_from == NULL &&
3029 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
3030 label_state == MICROLABEL_IMPORTED_FROM))
3031 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
3032 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
3034 DrawPreviewLevelLabelExt(label_state);
3038 void DrawPreviewLevelInitial()
3040 DrawPreviewLevelExt(TRUE);
3043 void DrawPreviewLevelAnimation()
3045 DrawPreviewLevelExt(FALSE);
3048 inline static void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
3049 int graphic, int sync_frame,
3052 int frame = getGraphicAnimationFrame(graphic, sync_frame);
3054 if (mask_mode == USE_MASKING)
3055 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
3057 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
3060 void DrawFixedGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
3061 int graphic, int sync_frame, int mask_mode)
3063 int frame = getGraphicAnimationFrame(graphic, sync_frame);
3065 if (mask_mode == USE_MASKING)
3066 DrawFixedGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
3068 DrawFixedGraphicExt(dst_bitmap, x, y, graphic, frame);
3071 inline static void DrawGraphicAnimation(int x, int y, int graphic)
3073 int lx = LEVELX(x), ly = LEVELY(y);
3075 if (!IN_SCR_FIELD(x, y))
3078 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
3079 graphic, GfxFrame[lx][ly], NO_MASKING);
3081 MarkTileDirty(x, y);
3084 void DrawFixedGraphicAnimation(int x, int y, int graphic)
3086 int lx = LEVELX(x), ly = LEVELY(y);
3088 if (!IN_SCR_FIELD(x, y))
3091 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
3092 graphic, GfxFrame[lx][ly], NO_MASKING);
3093 MarkTileDirty(x, y);
3096 void DrawLevelGraphicAnimation(int x, int y, int graphic)
3098 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
3101 void DrawLevelElementAnimation(int x, int y, int element)
3103 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
3105 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
3108 void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
3110 int sx = SCREENX(x), sy = SCREENY(y);
3112 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
3115 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
3118 DrawGraphicAnimation(sx, sy, graphic);
3121 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
3122 DrawLevelFieldCrumbled(x, y);
3124 if (GFX_CRUMBLED(Feld[x][y]))
3125 DrawLevelFieldCrumbled(x, y);
3129 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
3131 int sx = SCREENX(x), sy = SCREENY(y);
3134 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
3137 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
3139 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
3142 DrawGraphicAnimation(sx, sy, graphic);
3144 if (GFX_CRUMBLED(element))
3145 DrawLevelFieldCrumbled(x, y);
3148 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
3150 if (player->use_murphy)
3152 /* this works only because currently only one player can be "murphy" ... */
3153 static int last_horizontal_dir = MV_LEFT;
3154 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
3156 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3157 last_horizontal_dir = move_dir;
3159 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
3161 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
3163 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
3169 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
3172 static boolean equalGraphics(int graphic1, int graphic2)
3174 struct GraphicInfo *g1 = &graphic_info[graphic1];
3175 struct GraphicInfo *g2 = &graphic_info[graphic2];
3177 return (g1->bitmap == g2->bitmap &&
3178 g1->src_x == g2->src_x &&
3179 g1->src_y == g2->src_y &&
3180 g1->anim_frames == g2->anim_frames &&
3181 g1->anim_delay == g2->anim_delay &&
3182 g1->anim_mode == g2->anim_mode);
3185 void DrawAllPlayers()
3189 for (i = 0; i < MAX_PLAYERS; i++)
3190 if (stored_player[i].active)
3191 DrawPlayer(&stored_player[i]);
3194 void DrawPlayerField(int x, int y)
3196 if (!IS_PLAYER(x, y))
3199 DrawPlayer(PLAYERINFO(x, y));
3202 #define DRAW_PLAYER_OVER_PUSHED_ELEMENT 1
3204 void DrawPlayer(struct PlayerInfo *player)
3206 int jx = player->jx;
3207 int jy = player->jy;
3208 int move_dir = player->MovDir;
3209 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
3210 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
3211 int last_jx = (player->is_moving ? jx - dx : jx);
3212 int last_jy = (player->is_moving ? jy - dy : jy);
3213 int next_jx = jx + dx;
3214 int next_jy = jy + dy;
3215 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
3216 boolean player_is_opaque = FALSE;
3217 int sx = SCREENX(jx), sy = SCREENY(jy);
3218 int sxx = 0, syy = 0;
3219 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
3221 int action = ACTION_DEFAULT;
3222 int last_player_graphic = getPlayerGraphic(player, move_dir);
3223 int last_player_frame = player->Frame;
3226 /* GfxElement[][] is set to the element the player is digging or collecting;
3227 remove also for off-screen player if the player is not moving anymore */
3228 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
3229 GfxElement[jx][jy] = EL_UNDEFINED;
3231 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
3235 if (!IN_LEV_FIELD(jx, jy))
3237 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
3238 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
3239 printf("DrawPlayerField(): This should never happen!\n");
3244 if (element == EL_EXPLOSION)
3247 action = (player->is_pushing ? ACTION_PUSHING :
3248 player->is_digging ? ACTION_DIGGING :
3249 player->is_collecting ? ACTION_COLLECTING :
3250 player->is_moving ? ACTION_MOVING :
3251 player->is_snapping ? ACTION_SNAPPING :
3252 player->is_dropping ? ACTION_DROPPING :
3253 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
3255 if (player->is_waiting)
3256 move_dir = player->dir_waiting;
3258 InitPlayerGfxAnimation(player, action, move_dir);
3260 /* ----------------------------------------------------------------------- */
3261 /* draw things in the field the player is leaving, if needed */
3262 /* ----------------------------------------------------------------------- */
3264 if (player->is_moving)
3266 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
3268 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
3270 if (last_element == EL_DYNAMITE_ACTIVE ||
3271 last_element == EL_EM_DYNAMITE_ACTIVE ||
3272 last_element == EL_SP_DISK_RED_ACTIVE)
3273 DrawDynamite(last_jx, last_jy);
3275 DrawLevelFieldThruMask(last_jx, last_jy);
3277 else if (last_element == EL_DYNAMITE_ACTIVE ||
3278 last_element == EL_EM_DYNAMITE_ACTIVE ||
3279 last_element == EL_SP_DISK_RED_ACTIVE)
3280 DrawDynamite(last_jx, last_jy);
3282 /* !!! this is not enough to prevent flickering of players which are
3283 moving next to each others without a free tile between them -- this
3284 can only be solved by drawing all players layer by layer (first the
3285 background, then the foreground etc.) !!! => TODO */
3286 else if (!IS_PLAYER(last_jx, last_jy))
3287 DrawLevelField(last_jx, last_jy);
3290 DrawLevelField(last_jx, last_jy);
3293 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
3294 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
3297 if (!IN_SCR_FIELD(sx, sy))
3300 /* ----------------------------------------------------------------------- */
3301 /* draw things behind the player, if needed */
3302 /* ----------------------------------------------------------------------- */
3305 DrawLevelElement(jx, jy, Back[jx][jy]);
3306 else if (IS_ACTIVE_BOMB(element))
3307 DrawLevelElement(jx, jy, EL_EMPTY);
3310 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
3312 int old_element = GfxElement[jx][jy];
3313 int old_graphic = el_act_dir2img(old_element, action, move_dir);
3314 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
3316 if (GFX_CRUMBLED(old_element))
3317 DrawLevelFieldCrumbledDigging(jx, jy, move_dir, player->StepFrame);
3319 DrawGraphic(sx, sy, old_graphic, frame);
3321 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
3322 player_is_opaque = TRUE;
3326 GfxElement[jx][jy] = EL_UNDEFINED;
3328 /* make sure that pushed elements are drawn with correct frame rate */
3329 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
3331 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
3332 GfxFrame[jx][jy] = player->StepFrame;
3334 DrawLevelField(jx, jy);
3338 #if !DRAW_PLAYER_OVER_PUSHED_ELEMENT
3339 /* ----------------------------------------------------------------------- */
3340 /* draw player himself */
3341 /* ----------------------------------------------------------------------- */
3343 graphic = getPlayerGraphic(player, move_dir);
3345 /* in the case of changed player action or direction, prevent the current
3346 animation frame from being restarted for identical animations */
3347 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
3348 player->Frame = last_player_frame;
3350 frame = getGraphicAnimationFrame(graphic, player->Frame);
3354 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3355 sxx = player->GfxPos;
3357 syy = player->GfxPos;
3360 if (player_is_opaque)
3361 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
3363 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3365 if (SHIELD_ON(player))
3367 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
3368 IMG_SHIELD_NORMAL_ACTIVE);
3369 int frame = getGraphicAnimationFrame(graphic, -1);
3371 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3375 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
3378 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3379 sxx = player->GfxPos;
3381 syy = player->GfxPos;
3385 /* ----------------------------------------------------------------------- */
3386 /* draw things the player is pushing, if needed */
3387 /* ----------------------------------------------------------------------- */
3389 if (player->is_pushing && player->is_moving)
3391 int px = SCREENX(jx), py = SCREENY(jy);
3392 int pxx = (TILEX - ABS(sxx)) * dx;
3393 int pyy = (TILEY - ABS(syy)) * dy;
3394 int gfx_frame = GfxFrame[jx][jy];
3400 if (!IS_MOVING(jx, jy)) /* push movement already finished */
3402 element = Feld[next_jx][next_jy];
3403 gfx_frame = GfxFrame[next_jx][next_jy];
3406 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
3408 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
3409 frame = getGraphicAnimationFrame(graphic, sync_frame);
3411 /* draw background element under pushed element (like the Sokoban field) */
3412 if (game.use_masked_pushing && IS_MOVING(jx, jy))
3414 /* this allows transparent pushing animation over non-black background */
3417 DrawLevelElement(jx, jy, Back[jx][jy]);
3419 DrawLevelElement(jx, jy, EL_EMPTY);
3421 if (Back[next_jx][next_jy])
3422 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3424 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
3426 else if (Back[next_jx][next_jy])
3427 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3430 /* do not draw (EM style) pushing animation when pushing is finished */
3431 /* (two-tile animations usually do not contain start and end frame) */
3432 if (graphic_info[graphic].double_movement && !IS_MOVING(jx, jy))
3433 DrawLevelElement(next_jx, next_jy, Feld[next_jx][next_jy]);
3435 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3437 /* masked drawing is needed for EMC style (double) movement graphics */
3438 /* !!! (ONLY WHEN DRAWING PUSHED ELEMENT OVER THE PLAYER) !!! */
3439 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3443 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
3444 /* ----------------------------------------------------------------------- */
3445 /* draw player himself */
3446 /* ----------------------------------------------------------------------- */
3448 graphic = getPlayerGraphic(player, move_dir);
3450 /* in the case of changed player action or direction, prevent the current
3451 animation frame from being restarted for identical animations */
3452 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
3453 player->Frame = last_player_frame;
3455 frame = getGraphicAnimationFrame(graphic, player->Frame);
3459 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3460 sxx = player->GfxPos;
3462 syy = player->GfxPos;
3465 if (player_is_opaque)
3466 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
3468 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3470 if (SHIELD_ON(player))
3472 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
3473 IMG_SHIELD_NORMAL_ACTIVE);
3474 int frame = getGraphicAnimationFrame(graphic, -1);
3476 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3480 /* ----------------------------------------------------------------------- */
3481 /* draw things in front of player (active dynamite or dynabombs) */
3482 /* ----------------------------------------------------------------------- */
3484 if (IS_ACTIVE_BOMB(element))
3486 graphic = el2img(element);
3487 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
3489 if (game.emulation == EMU_SUPAPLEX)
3490 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
3492 DrawGraphicThruMask(sx, sy, graphic, frame);
3495 if (player_is_moving && last_element == EL_EXPLOSION)
3497 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
3498 GfxElement[last_jx][last_jy] : EL_EMPTY);
3499 int graphic = el_act2img(element, ACTION_EXPLODING);
3500 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
3501 int phase = ExplodePhase[last_jx][last_jy] - 1;
3502 int frame = getGraphicAnimationFrame(graphic, phase - delay);
3505 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
3508 /* ----------------------------------------------------------------------- */
3509 /* draw elements the player is just walking/passing through/under */
3510 /* ----------------------------------------------------------------------- */
3512 if (player_is_moving)
3514 /* handle the field the player is leaving ... */
3515 if (IS_ACCESSIBLE_INSIDE(last_element))
3516 DrawLevelField(last_jx, last_jy);
3517 else if (IS_ACCESSIBLE_UNDER(last_element))
3518 DrawLevelFieldThruMask(last_jx, last_jy);
3521 /* do not redraw accessible elements if the player is just pushing them */
3522 if (!player_is_moving || !player->is_pushing)
3524 /* ... and the field the player is entering */
3525 if (IS_ACCESSIBLE_INSIDE(element))
3526 DrawLevelField(jx, jy);
3527 else if (IS_ACCESSIBLE_UNDER(element))
3528 DrawLevelFieldThruMask(jx, jy);
3531 MarkTileDirty(sx, sy);
3534 /* ------------------------------------------------------------------------- */
3536 void WaitForEventToContinue()
3538 boolean still_wait = TRUE;
3540 /* simulate releasing mouse button over last gadget, if still pressed */
3542 HandleGadgets(-1, -1, 0);
3544 button_status = MB_RELEASED;
3558 case EVENT_BUTTONPRESS:
3559 case EVENT_KEYPRESS:
3563 case EVENT_KEYRELEASE:
3564 ClearPlayerAction();
3568 HandleOtherEvents(&event);
3572 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3581 #define MAX_REQUEST_LINES 13
3582 #define MAX_REQUEST_LINE_FONT1_LEN 7
3583 #define MAX_REQUEST_LINE_FONT2_LEN 10
3585 static int RequestHandleEvents(unsigned int req_state)
3587 boolean level_solved = (game_status == GAME_MODE_PLAYING &&
3588 local_player->LevelSolved_GameEnd);
3589 int width = request.width;
3590 int height = request.height;
3594 setRequestPosition(&sx, &sy, FALSE);
3596 button_status = MB_RELEASED;
3598 request_gadget_id = -1;
3605 SetDrawtoField(DRAW_TO_FIELDBUFFER);
3607 HandleGameActions();
3609 SetDrawtoField(DRAW_TO_BACKBUFFER);
3611 if (global.use_envelope_request)
3613 /* copy current state of request area to middle of playfield area */
3614 BlitBitmap(bitmap_db_store_2, drawto, sx, sy, width, height, sx, sy);
3622 while (NextValidEvent(&event))
3626 case EVENT_BUTTONPRESS:
3627 case EVENT_BUTTONRELEASE:
3628 case EVENT_MOTIONNOTIFY:
3632 if (event.type == EVENT_MOTIONNOTIFY)
3637 motion_status = TRUE;
3638 mx = ((MotionEvent *) &event)->x;
3639 my = ((MotionEvent *) &event)->y;
3643 motion_status = FALSE;
3644 mx = ((ButtonEvent *) &event)->x;
3645 my = ((ButtonEvent *) &event)->y;
3646 if (event.type == EVENT_BUTTONPRESS)
3647 button_status = ((ButtonEvent *) &event)->button;
3649 button_status = MB_RELEASED;
3652 /* this sets 'request_gadget_id' */
3653 HandleGadgets(mx, my, button_status);
3655 switch (request_gadget_id)
3657 case TOOL_CTRL_ID_YES:
3660 case TOOL_CTRL_ID_NO:
3663 case TOOL_CTRL_ID_CONFIRM:
3664 result = TRUE | FALSE;
3667 case TOOL_CTRL_ID_PLAYER_1:
3670 case TOOL_CTRL_ID_PLAYER_2:
3673 case TOOL_CTRL_ID_PLAYER_3:
3676 case TOOL_CTRL_ID_PLAYER_4:
3687 case EVENT_KEYPRESS:
3688 switch (GetEventKey((KeyEvent *)&event, TRUE))
3691 if (req_state & REQ_CONFIRM)
3696 #if defined(TARGET_SDL2)
3703 #if defined(TARGET_SDL2)
3713 if (req_state & REQ_PLAYER)
3717 case EVENT_KEYRELEASE:
3718 ClearPlayerAction();
3722 HandleOtherEvents(&event);
3727 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3729 int joy = AnyJoystick();
3731 if (joy & JOY_BUTTON_1)
3733 else if (joy & JOY_BUTTON_2)
3739 if (global.use_envelope_request)
3741 /* copy back current state of pressed buttons inside request area */
3742 BlitBitmap(drawto, bitmap_db_store_2, sx, sy, width, height, sx, sy);
3752 static boolean RequestDoor(char *text, unsigned int req_state)
3754 unsigned int old_door_state;
3755 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
3756 int font_nr = FONT_TEXT_2;
3761 if (maxWordLengthInString(text) > MAX_REQUEST_LINE_FONT1_LEN)
3763 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
3764 font_nr = FONT_TEXT_1;
3767 if (game_status == GAME_MODE_PLAYING)
3768 BlitScreenToBitmap(backbuffer);
3770 /* disable deactivated drawing when quick-loading level tape recording */
3771 if (tape.playing && tape.deactivate_display)
3772 TapeDeactivateDisplayOff(TRUE);
3774 SetMouseCursor(CURSOR_DEFAULT);
3776 #if defined(NETWORK_AVALIABLE)
3777 /* pause network game while waiting for request to answer */
3778 if (options.network &&
3779 game_status == GAME_MODE_PLAYING &&
3780 req_state & REQUEST_WAIT_FOR_INPUT)
3781 SendToServer_PausePlaying();
3784 old_door_state = GetDoorState();
3786 /* simulate releasing mouse button over last gadget, if still pressed */
3788 HandleGadgets(-1, -1, 0);
3792 /* draw released gadget before proceeding */
3795 if (old_door_state & DOOR_OPEN_1)
3797 CloseDoor(DOOR_CLOSE_1);
3799 /* save old door content */
3800 BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
3801 0 * DXSIZE, 0, DXSIZE, DYSIZE, 1 * DXSIZE, 0);
3804 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
3805 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3807 /* clear door drawing field */
3808 DrawBackground(DX, DY, DXSIZE, DYSIZE);
3810 /* force DOOR font inside door area */
3811 SetFontStatus(GAME_MODE_PSEUDO_DOOR);
3813 /* write text for request */
3814 for (text_ptr = text, ty = 0; ty < MAX_REQUEST_LINES; ty++)
3816 char text_line[max_request_line_len + 1];
3822 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
3824 tc = *(text_ptr + tx);
3825 // if (!tc || tc == ' ')
3826 if (!tc || tc == ' ' || tc == '?' || tc == '!')
3830 if ((tc == '?' || tc == '!') && tl == 0)
3840 strncpy(text_line, text_ptr, tl);
3843 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
3844 DY + 8 + ty * (getFontHeight(font_nr) + 2),
3845 text_line, font_nr);
3847 text_ptr += tl + (tc == ' ' ? 1 : 0);
3848 // text_ptr += tl + (tc == ' ' || tc == '?' || tc == '!' ? 1 : 0);
3853 if (req_state & REQ_ASK)
3855 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
3856 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
3858 else if (req_state & REQ_CONFIRM)
3860 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
3862 else if (req_state & REQ_PLAYER)
3864 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
3865 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
3866 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
3867 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
3870 /* copy request gadgets to door backbuffer */
3871 BlitBitmap(drawto, bitmap_db_door_1, DX, DY, DXSIZE, DYSIZE, 0, 0);
3873 OpenDoor(DOOR_OPEN_1);
3875 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
3877 if (game_status == GAME_MODE_PLAYING)
3879 SetPanelBackground();
3880 SetDrawBackgroundMask(REDRAW_DOOR_1);
3884 SetDrawBackgroundMask(REDRAW_FIELD);
3890 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3892 // ---------- handle request buttons ----------
3893 result = RequestHandleEvents(req_state);
3897 if (!(req_state & REQ_STAY_OPEN))
3899 CloseDoor(DOOR_CLOSE_1);
3901 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
3902 (req_state & REQ_REOPEN))
3903 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
3908 if (game_status == GAME_MODE_PLAYING)
3910 SetPanelBackground();
3911 SetDrawBackgroundMask(REDRAW_DOOR_1);
3915 SetDrawBackgroundMask(REDRAW_FIELD);
3918 #if defined(NETWORK_AVALIABLE)
3919 /* continue network game after request */
3920 if (options.network &&
3921 game_status == GAME_MODE_PLAYING &&
3922 req_state & REQUEST_WAIT_FOR_INPUT)
3923 SendToServer_ContinuePlaying();
3926 /* restore deactivated drawing when quick-loading level tape recording */
3927 if (tape.playing && tape.deactivate_display)
3928 TapeDeactivateDisplayOn();
3933 static boolean RequestEnvelope(char *text, unsigned int req_state)
3937 if (game_status == GAME_MODE_PLAYING)
3938 BlitScreenToBitmap(backbuffer);
3940 /* disable deactivated drawing when quick-loading level tape recording */
3941 if (tape.playing && tape.deactivate_display)
3942 TapeDeactivateDisplayOff(TRUE);
3944 SetMouseCursor(CURSOR_DEFAULT);
3946 #if defined(NETWORK_AVALIABLE)
3947 /* pause network game while waiting for request to answer */
3948 if (options.network &&
3949 game_status == GAME_MODE_PLAYING &&
3950 req_state & REQUEST_WAIT_FOR_INPUT)
3951 SendToServer_PausePlaying();
3954 /* simulate releasing mouse button over last gadget, if still pressed */
3956 HandleGadgets(-1, -1, 0);
3960 // (replace with setting corresponding request background)
3961 // SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
3962 // SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3964 /* clear door drawing field */
3965 // DrawBackground(DX, DY, DXSIZE, DYSIZE);
3967 ShowEnvelopeRequest(text, req_state, ACTION_OPENING);
3969 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
3971 if (game_status == GAME_MODE_PLAYING)
3973 SetPanelBackground();
3974 SetDrawBackgroundMask(REDRAW_DOOR_1);
3978 SetDrawBackgroundMask(REDRAW_FIELD);
3984 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3986 // ---------- handle request buttons ----------
3987 result = RequestHandleEvents(req_state);
3991 ShowEnvelopeRequest(text, req_state, ACTION_CLOSING);
3995 if (game_status == GAME_MODE_PLAYING)
3997 SetPanelBackground();
3998 SetDrawBackgroundMask(REDRAW_DOOR_1);
4002 SetDrawBackgroundMask(REDRAW_FIELD);
4005 #if defined(NETWORK_AVALIABLE)
4006 /* continue network game after request */
4007 if (options.network &&
4008 game_status == GAME_MODE_PLAYING &&
4009 req_state & REQUEST_WAIT_FOR_INPUT)
4010 SendToServer_ContinuePlaying();
4013 /* restore deactivated drawing when quick-loading level tape recording */
4014 if (tape.playing && tape.deactivate_display)
4015 TapeDeactivateDisplayOn();
4020 boolean Request(char *text, unsigned int req_state)
4022 if (global.use_envelope_request)
4023 return RequestEnvelope(text, req_state);
4025 return RequestDoor(text, req_state);
4028 static int compareDoorPartOrderInfo(const void *object1, const void *object2)
4030 const struct DoorPartOrderInfo *dpo1 = (struct DoorPartOrderInfo *)object1;
4031 const struct DoorPartOrderInfo *dpo2 = (struct DoorPartOrderInfo *)object2;
4034 if (dpo1->sort_priority != dpo2->sort_priority)
4035 compare_result = dpo1->sort_priority - dpo2->sort_priority;
4037 compare_result = dpo1->nr - dpo2->nr;
4039 return compare_result;
4042 void InitGraphicCompatibilityInfo_Doors()
4048 struct DoorInfo *door;
4052 { DOOR_1, IMG_GFX_DOOR_1_PART_1, IMG_GFX_DOOR_1_PART_8, &door_1 },
4053 { DOOR_2, IMG_GFX_DOOR_2_PART_1, IMG_GFX_DOOR_2_PART_8, &door_2 },
4055 { -1, -1, -1, NULL }
4057 struct Rect door_rect_list[] =
4059 { DX, DY, DXSIZE, DYSIZE },
4060 { VX, VY, VXSIZE, VYSIZE }
4064 for (i = 0; doors[i].door_token != -1; i++)
4066 int door_token = doors[i].door_token;
4067 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
4068 int part_1 = doors[i].part_1;
4069 int part_8 = doors[i].part_8;
4070 int part_2 = part_1 + 1;
4071 int part_3 = part_1 + 2;
4072 struct DoorInfo *door = doors[i].door;
4073 struct Rect *door_rect = &door_rect_list[door_index];
4074 boolean door_gfx_redefined = FALSE;
4076 /* check if any door part graphic definitions have been redefined */
4078 for (j = 0; door_part_controls[j].door_token != -1; j++)
4080 struct DoorPartControlInfo *dpc = &door_part_controls[j];
4081 struct FileInfo *fi = getImageListEntryFromImageID(dpc->graphic);
4083 if (dpc->door_token == door_token && fi->redefined)
4084 door_gfx_redefined = TRUE;
4087 /* check for old-style door graphic/animation modifications */
4089 if (!door_gfx_redefined)
4091 if (door->anim_mode & ANIM_STATIC_PANEL)
4093 door->panel.step_xoffset = 0;
4094 door->panel.step_yoffset = 0;
4097 if (door->anim_mode & (ANIM_HORIZONTAL | ANIM_VERTICAL))
4099 struct GraphicInfo *g_part_1 = &graphic_info[part_1];
4100 struct GraphicInfo *g_part_2 = &graphic_info[part_2];
4101 int num_door_steps, num_panel_steps;
4103 /* remove door part graphics other than the two default wings */
4105 for (j = 0; door_part_controls[j].door_token != -1; j++)
4107 struct DoorPartControlInfo *dpc = &door_part_controls[j];
4108 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4110 if (dpc->graphic >= part_3 &&
4111 dpc->graphic <= part_8)
4115 /* set graphics and screen positions of the default wings */
4117 g_part_1->width = door_rect->width;
4118 g_part_1->height = door_rect->height;
4119 g_part_2->width = door_rect->width;
4120 g_part_2->height = door_rect->height;
4121 g_part_2->src_x = door_rect->width;
4122 g_part_2->src_y = g_part_1->src_y;
4124 door->part_2.x = door->part_1.x;
4125 door->part_2.y = door->part_1.y;
4127 if (door->width != -1)
4129 g_part_1->width = door->width;
4130 g_part_2->width = door->width;
4132 // special treatment for graphics and screen position of right wing
4133 g_part_2->src_x += door_rect->width - door->width;
4134 door->part_2.x += door_rect->width - door->width;
4137 if (door->height != -1)
4139 g_part_1->height = door->height;
4140 g_part_2->height = door->height;
4142 // special treatment for graphics and screen position of bottom wing
4143 g_part_2->src_y += door_rect->height - door->height;
4144 door->part_2.y += door_rect->height - door->height;
4147 /* set animation delays for the default wings and panels */
4149 door->part_1.step_delay = door->step_delay;
4150 door->part_2.step_delay = door->step_delay;
4151 door->panel.step_delay = door->step_delay;
4153 /* set animation draw order for the default wings */
4155 door->part_1.sort_priority = 2; /* draw left wing over ... */
4156 door->part_2.sort_priority = 1; /* ... right wing */
4158 /* set animation draw offset for the default wings */
4160 if (door->anim_mode & ANIM_HORIZONTAL)
4162 door->part_1.step_xoffset = door->step_offset;
4163 door->part_1.step_yoffset = 0;
4164 door->part_2.step_xoffset = door->step_offset * -1;
4165 door->part_2.step_yoffset = 0;
4167 num_door_steps = g_part_1->width / door->step_offset;
4169 else // ANIM_VERTICAL
4171 door->part_1.step_xoffset = 0;
4172 door->part_1.step_yoffset = door->step_offset;
4173 door->part_2.step_xoffset = 0;
4174 door->part_2.step_yoffset = door->step_offset * -1;
4176 num_door_steps = g_part_1->height / door->step_offset;
4179 /* set animation draw offset for the default panels */
4181 if (door->step_offset > 1)
4183 num_panel_steps = 2 * door_rect->height / door->step_offset;
4184 door->panel.start_step = num_panel_steps - num_door_steps;
4185 door->panel.start_step_closing = door->panel.start_step;
4189 num_panel_steps = door_rect->height / door->step_offset;
4190 door->panel.start_step = num_panel_steps - num_door_steps / 2;
4191 door->panel.start_step_closing = door->panel.start_step;
4192 door->panel.step_delay *= 2;
4203 for (i = 0; door_part_controls[i].door_token != -1; i++)
4205 struct DoorPartControlInfo *dpc = &door_part_controls[i];
4206 struct DoorPartOrderInfo *dpo = &door_part_order[i];
4208 /* initialize "start_step_opening" and "start_step_closing", if needed */
4209 if (dpc->pos->start_step_opening == 0 &&
4210 dpc->pos->start_step_closing == 0)
4212 // dpc->pos->start_step_opening = dpc->pos->start_step;
4213 dpc->pos->start_step_closing = dpc->pos->start_step;
4216 /* fill structure for door part draw order (sorted below) */
4218 dpo->sort_priority = dpc->pos->sort_priority;
4221 /* sort door part controls according to sort_priority and graphic number */
4222 qsort(door_part_order, MAX_DOOR_PARTS,
4223 sizeof(struct DoorPartOrderInfo), compareDoorPartOrderInfo);
4226 unsigned int OpenDoor(unsigned int door_state)
4228 if (door_state & DOOR_COPY_BACK)
4230 if (door_state & DOOR_OPEN_1)
4231 BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
4232 1 * DXSIZE, 0, DXSIZE, DYSIZE, 0 * DXSIZE, 0);
4234 if (door_state & DOOR_OPEN_2)
4235 BlitBitmap(bitmap_db_door_2, bitmap_db_door_2,
4236 1 * VXSIZE, 0, VXSIZE, VYSIZE, 0 * VXSIZE, 0);
4238 door_state &= ~DOOR_COPY_BACK;
4241 return MoveDoor(door_state);
4244 unsigned int CloseDoor(unsigned int door_state)
4246 unsigned int old_door_state = GetDoorState();
4248 if (!(door_state & DOOR_NO_COPY_BACK))
4250 if (old_door_state & DOOR_OPEN_1)
4251 BlitBitmap(backbuffer, bitmap_db_door_1,
4252 DX, DY, DXSIZE, DYSIZE, 0, 0);
4254 if (old_door_state & DOOR_OPEN_2)
4255 BlitBitmap(backbuffer, bitmap_db_door_2,
4256 VX, VY, VXSIZE, VYSIZE, 0, 0);
4258 door_state &= ~DOOR_NO_COPY_BACK;
4261 return MoveDoor(door_state);
4264 unsigned int GetDoorState()
4266 return MoveDoor(DOOR_GET_STATE);
4269 unsigned int SetDoorState(unsigned int door_state)
4271 return MoveDoor(door_state | DOOR_SET_STATE);
4274 int euclid(int a, int b)
4276 return (b ? euclid(b, a % b) : a);
4279 unsigned int MoveDoor(unsigned int door_state)
4281 struct Rect door_rect_list[] =
4283 { DX, DY, DXSIZE, DYSIZE },
4284 { VX, VY, VXSIZE, VYSIZE }
4286 static int door1 = DOOR_CLOSE_1;
4287 static int door2 = DOOR_CLOSE_2;
4288 unsigned int door_delay = 0;
4289 unsigned int door_delay_value;
4292 if (door_state == DOOR_GET_STATE)
4293 return (door1 | door2);
4295 if (door_state & DOOR_SET_STATE)
4297 if (door_state & DOOR_ACTION_1)
4298 door1 = door_state & DOOR_ACTION_1;
4299 if (door_state & DOOR_ACTION_2)
4300 door2 = door_state & DOOR_ACTION_2;
4302 return (door1 | door2);
4305 if (!(door_state & DOOR_FORCE_REDRAW))
4307 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
4308 door_state &= ~DOOR_OPEN_1;
4309 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
4310 door_state &= ~DOOR_CLOSE_1;
4311 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
4312 door_state &= ~DOOR_OPEN_2;
4313 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
4314 door_state &= ~DOOR_CLOSE_2;
4317 if (global.autoplay_leveldir)
4319 door_state |= DOOR_NO_DELAY;
4320 door_state &= ~DOOR_CLOSE_ALL;
4323 if (game_status == GAME_MODE_EDITOR)
4324 door_state |= DOOR_NO_DELAY;
4326 if (door_state & DOOR_ACTION)
4328 boolean door_panel_drawn[NUM_DOORS];
4329 boolean panel_has_doors[NUM_DOORS];
4330 boolean door_part_skip[MAX_DOOR_PARTS];
4331 boolean door_part_done[MAX_DOOR_PARTS];
4332 boolean door_part_done_all;
4333 int num_steps[MAX_DOOR_PARTS];
4334 int max_move_delay = 0; // delay for complete animations of all doors
4335 int max_step_delay = 0; // delay (ms) between two animation frames
4336 int num_move_steps = 0; // number of animation steps for all doors
4337 int max_move_delay_doors_only = 0; // delay for doors only (no panel)
4338 int num_move_steps_doors_only = 0; // steps for doors only (no panel)
4339 int current_move_delay = 0;
4343 for (i = 0; i < NUM_DOORS; i++)
4344 panel_has_doors[i] = FALSE;
4346 for (i = 0; i < MAX_DOOR_PARTS; i++)
4348 struct DoorPartControlInfo *dpc = &door_part_controls[i];
4349 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4350 int door_token = dpc->door_token;
4352 door_part_done[i] = FALSE;
4353 door_part_skip[i] = (!(door_state & door_token) ||
4357 for (i = 0; i < MAX_DOOR_PARTS; i++)
4359 int nr = door_part_order[i].nr;
4360 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
4361 struct DoorPartPosInfo *pos = dpc->pos;
4362 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4363 int door_token = dpc->door_token;
4364 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
4365 boolean is_panel = DOOR_PART_IS_PANEL(nr);
4366 int step_xoffset = ABS(pos->step_xoffset);
4367 int step_yoffset = ABS(pos->step_yoffset);
4368 int step_delay = pos->step_delay;
4369 int current_door_state = door_state & door_token;
4370 boolean door_opening = ((current_door_state & DOOR_OPEN) != 0);
4371 boolean door_closing = ((current_door_state & DOOR_CLOSE) != 0);
4372 boolean part_opening = (is_panel ? door_closing : door_opening);
4373 int start_step = (part_opening ? pos->start_step_opening :
4374 pos->start_step_closing);
4375 float move_xsize = (step_xoffset ? g->width : 0);
4376 float move_ysize = (step_yoffset ? g->height : 0);
4377 int move_xsteps = (step_xoffset ? ceil(move_xsize / step_xoffset) : 0);
4378 int move_ysteps = (step_yoffset ? ceil(move_ysize / step_yoffset) : 0);
4379 int move_steps = (move_xsteps && move_ysteps ?
4380 MIN(move_xsteps, move_ysteps) :
4381 move_xsteps ? move_xsteps : move_ysteps) - start_step;
4382 int move_delay = move_steps * step_delay;
4384 if (door_part_skip[nr])
4387 max_move_delay = MAX(max_move_delay, move_delay);
4388 max_step_delay = (max_step_delay == 0 ? step_delay :
4389 euclid(max_step_delay, step_delay));
4390 num_steps[nr] = move_steps;
4394 max_move_delay_doors_only = MAX(max_move_delay_doors_only, move_delay);
4396 panel_has_doors[door_index] = TRUE;
4400 max_step_delay = MAX(1, max_step_delay); // prevent division by zero
4402 num_move_steps = max_move_delay / max_step_delay;
4403 num_move_steps_doors_only = max_move_delay_doors_only / max_step_delay;
4405 door_delay_value = max_step_delay;
4407 if ((door_state & DOOR_NO_DELAY) || setup.quick_doors)
4409 start = num_move_steps - 1;
4413 /* opening door sound has priority over simultaneously closing door */
4414 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
4415 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
4416 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
4417 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
4420 for (k = start; k < num_move_steps; k++)
4422 int last_frame = num_move_steps - 1; // last frame of this "for" loop
4424 door_part_done_all = TRUE;
4426 for (i = 0; i < NUM_DOORS; i++)
4427 door_panel_drawn[i] = FALSE;
4429 for (i = 0; i < MAX_DOOR_PARTS; i++)
4431 int nr = door_part_order[i].nr;
4432 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
4433 struct DoorPartPosInfo *pos = dpc->pos;
4434 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4435 int door_token = dpc->door_token;
4436 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
4437 boolean is_panel = DOOR_PART_IS_PANEL(nr);
4438 boolean is_panel_and_door_has_closed = FALSE;
4439 struct Rect *door_rect = &door_rect_list[door_index];
4440 Bitmap *bitmap_db_door = (door_token == DOOR_1 ? bitmap_db_door_1 :
4442 Bitmap *bitmap = (is_panel ? bitmap_db_door : g->bitmap);
4443 int current_door_state = door_state & door_token;
4444 boolean door_opening = ((current_door_state & DOOR_OPEN) != 0);
4445 boolean door_closing = !door_opening;
4446 boolean part_opening = (is_panel ? door_closing : door_opening);
4447 boolean part_closing = !part_opening;
4448 int start_step = (part_opening ? pos->start_step_opening :
4449 pos->start_step_closing);
4450 int step_delay = pos->step_delay;
4451 int step_factor = step_delay / max_step_delay;
4452 int k1 = (step_factor ? k / step_factor + 1 : k);
4453 int k2 = (part_opening ? k1 + start_step : num_steps[nr] - k1);
4454 int kk = MAX(0, k2);
4457 int src_x, src_y, src_xx, src_yy;
4458 int dst_x, dst_y, dst_xx, dst_yy;
4461 if (door_part_skip[nr])
4464 if (!(door_state & door_token))
4472 int k2_door = (door_opening ? k : num_move_steps_doors_only - k - 1);
4473 int kk_door = MAX(0, k2_door);
4474 int sync_frame = kk_door * door_delay_value;
4475 int frame = getGraphicAnimationFrame(dpc->graphic, sync_frame);
4477 getGraphicSource(dpc->graphic, frame, &bitmap, &g_src_x, &g_src_y);
4482 if (!door_panel_drawn[door_index])
4484 ClearRectangle(drawto, door_rect->x, door_rect->y,
4485 door_rect->width, door_rect->height);
4487 door_panel_drawn[door_index] = TRUE;
4490 // draw opening or closing door parts
4492 if (pos->step_xoffset < 0) // door part on right side
4495 dst_xx = pos->x + ABS(kk * pos->step_xoffset);
4498 if (dst_xx + width > door_rect->width)
4499 width = door_rect->width - dst_xx;
4501 else // door part on left side
4504 dst_xx = pos->x - kk * pos->step_xoffset;
4508 src_xx = ABS(dst_xx);
4512 width = g->width - src_xx;
4514 if (width > door_rect->width)
4515 width = door_rect->width;
4517 // printf("::: k == %d [%d] \n", k, start_step);
4520 if (pos->step_yoffset < 0) // door part on bottom side
4523 dst_yy = pos->y + ABS(kk * pos->step_yoffset);
4526 if (dst_yy + height > door_rect->height)
4527 height = door_rect->height - dst_yy;
4529 else // door part on top side
4532 dst_yy = pos->y - kk * pos->step_yoffset;
4536 src_yy = ABS(dst_yy);
4540 height = g->height - src_yy;
4543 src_x = g_src_x + src_xx;
4544 src_y = g_src_y + src_yy;
4546 dst_x = door_rect->x + dst_xx;
4547 dst_y = door_rect->y + dst_yy;
4549 is_panel_and_door_has_closed =
4552 panel_has_doors[door_index] &&
4553 k >= num_move_steps_doors_only - 1);
4555 if (width >= 0 && width <= g->width &&
4556 height >= 0 && height <= g->height &&
4557 !is_panel_and_door_has_closed)
4559 if (is_panel || !pos->draw_masked)
4560 BlitBitmap(bitmap, drawto, src_x, src_y, width, height,
4563 BlitBitmapMasked(bitmap, drawto, src_x, src_y, width, height,
4567 redraw_mask |= REDRAW_DOOR_FROM_TOKEN(door_token);
4569 if ((part_opening && (width < 0 || height < 0)) ||
4570 (part_closing && (width >= g->width && height >= g->height)))
4571 door_part_done[nr] = TRUE;
4573 // continue door part animations, but not panel after door has closed
4574 if (!door_part_done[nr] && !is_panel_and_door_has_closed)
4575 door_part_done_all = FALSE;
4578 if (!(door_state & DOOR_NO_DELAY))
4582 SkipUntilDelayReached(&door_delay, door_delay_value, &k, last_frame);
4584 current_move_delay += max_step_delay;
4587 if (door_part_done_all)
4592 if (door_state & DOOR_ACTION_1)
4593 door1 = door_state & DOOR_ACTION_1;
4594 if (door_state & DOOR_ACTION_2)
4595 door2 = door_state & DOOR_ACTION_2;
4597 // draw masked border over door area
4598 DrawMaskedBorder(REDRAW_DOOR_1);
4599 DrawMaskedBorder(REDRAW_DOOR_2);
4601 return (door1 | door2);
4604 static boolean useSpecialEditorDoor()
4606 int graphic = IMG_GLOBAL_BORDER_EDITOR;
4607 boolean redefined = getImageListEntryFromImageID(graphic)->redefined;
4609 // do not draw special editor door if editor border defined or redefined
4610 if (graphic_info[graphic].bitmap != NULL || redefined)
4613 // do not draw special editor door if global border defined to be empty
4614 if (graphic_info[IMG_GLOBAL_BORDER].bitmap == NULL)
4617 // do not draw special editor door if viewport definitions do not match
4621 EY + EYSIZE != VY + VYSIZE)
4627 void DrawSpecialEditorDoor()
4629 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
4630 int top_border_width = gfx1->width;
4631 int top_border_height = gfx1->height;
4632 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
4633 int ex = EX - outer_border;
4634 int ey = EY - outer_border;
4635 int vy = VY - outer_border;
4636 int exsize = EXSIZE + 2 * outer_border;
4638 if (!useSpecialEditorDoor())
4641 /* draw bigger level editor toolbox window */
4642 BlitBitmap(gfx1->bitmap, drawto, gfx1->src_x, gfx1->src_y,
4643 top_border_width, top_border_height, ex, ey - top_border_height);
4644 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto, ex, vy,
4645 exsize, EYSIZE - VYSIZE + outer_border, ex, ey);
4647 redraw_mask |= REDRAW_ALL;
4650 void UndrawSpecialEditorDoor()
4652 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
4653 int top_border_width = gfx1->width;
4654 int top_border_height = gfx1->height;
4655 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
4656 int ex = EX - outer_border;
4657 int ey = EY - outer_border;
4658 int ey_top = ey - top_border_height;
4659 int exsize = EXSIZE + 2 * outer_border;
4660 int eysize = EYSIZE + 2 * outer_border;
4662 if (!useSpecialEditorDoor())
4665 /* draw normal tape recorder window */
4666 if (graphic_info[IMG_GLOBAL_BORDER].bitmap)
4668 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
4669 ex, ey_top, top_border_width, top_border_height,
4671 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
4672 ex, ey, exsize, eysize, ex, ey);
4676 // if screen background is set to "[NONE]", clear editor toolbox window
4677 ClearRectangle(drawto, ex, ey_top, top_border_width, top_border_height);
4678 ClearRectangle(drawto, ex, ey, exsize, eysize);
4681 redraw_mask |= REDRAW_ALL;
4685 /* ---------- new tool button stuff ---------------------------------------- */
4690 struct TextPosInfo *pos;
4693 } toolbutton_info[NUM_TOOL_BUTTONS] =
4696 IMG_GFX_REQUEST_BUTTON_YES, &request.button.yes,
4697 TOOL_CTRL_ID_YES, "yes"
4700 IMG_GFX_REQUEST_BUTTON_NO, &request.button.no,
4701 TOOL_CTRL_ID_NO, "no"
4704 IMG_GFX_REQUEST_BUTTON_CONFIRM, &request.button.confirm,
4705 TOOL_CTRL_ID_CONFIRM, "confirm"
4708 IMG_GFX_REQUEST_BUTTON_PLAYER_1, &request.button.player_1,
4709 TOOL_CTRL_ID_PLAYER_1, "player 1"
4712 IMG_GFX_REQUEST_BUTTON_PLAYER_2, &request.button.player_2,
4713 TOOL_CTRL_ID_PLAYER_2, "player 2"
4716 IMG_GFX_REQUEST_BUTTON_PLAYER_3, &request.button.player_3,
4717 TOOL_CTRL_ID_PLAYER_3, "player 3"
4720 IMG_GFX_REQUEST_BUTTON_PLAYER_4, &request.button.player_4,
4721 TOOL_CTRL_ID_PLAYER_4, "player 4"
4725 void CreateToolButtons()
4729 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4731 struct GraphicInfo *gfx = &graphic_info[toolbutton_info[i].graphic];
4732 struct TextPosInfo *pos = toolbutton_info[i].pos;
4733 struct GadgetInfo *gi;
4734 Bitmap *deco_bitmap = None;
4735 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
4736 unsigned int event_mask = GD_EVENT_RELEASED;
4739 int gd_x = gfx->src_x;
4740 int gd_y = gfx->src_y;
4741 int gd_xp = gfx->src_x + gfx->pressed_xoffset;
4742 int gd_yp = gfx->src_y + gfx->pressed_yoffset;
4745 if (global.use_envelope_request)
4746 setRequestPosition(&dx, &dy, TRUE);
4748 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
4750 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
4752 getSizedGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr), 0,
4753 pos->size, &deco_bitmap, &deco_x, &deco_y);
4754 deco_xpos = (gfx->width - pos->size) / 2;
4755 deco_ypos = (gfx->height - pos->size) / 2;
4758 gi = CreateGadget(GDI_CUSTOM_ID, id,
4759 GDI_INFO_TEXT, toolbutton_info[i].infotext,
4760 GDI_X, dx + GDI_ACTIVE_POS(pos->x),
4761 GDI_Y, dy + GDI_ACTIVE_POS(pos->y),
4762 GDI_WIDTH, gfx->width,
4763 GDI_HEIGHT, gfx->height,
4764 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
4765 GDI_STATE, GD_BUTTON_UNPRESSED,
4766 GDI_DESIGN_UNPRESSED, gfx->bitmap, gd_x, gd_y,
4767 GDI_DESIGN_PRESSED, gfx->bitmap, gd_xp, gd_yp,
4768 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
4769 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
4770 GDI_DECORATION_SIZE, pos->size, pos->size,
4771 GDI_DECORATION_SHIFTING, 1, 1,
4772 GDI_DIRECT_DRAW, FALSE,
4773 GDI_EVENT_MASK, event_mask,
4774 GDI_CALLBACK_ACTION, HandleToolButtons,
4778 Error(ERR_EXIT, "cannot create gadget");
4780 tool_gadget[id] = gi;
4784 void FreeToolButtons()
4788 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4789 FreeGadget(tool_gadget[i]);
4792 static void UnmapToolButtons()
4796 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4797 UnmapGadget(tool_gadget[i]);
4800 static void HandleToolButtons(struct GadgetInfo *gi)
4802 request_gadget_id = gi->custom_id;
4805 static struct Mapping_EM_to_RND_object
4808 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
4809 boolean is_backside; /* backside of moving element */
4815 em_object_mapping_list[] =
4818 Xblank, TRUE, FALSE,
4822 Yacid_splash_eB, FALSE, FALSE,
4823 EL_ACID_SPLASH_RIGHT, -1, -1
4826 Yacid_splash_wB, FALSE, FALSE,
4827 EL_ACID_SPLASH_LEFT, -1, -1
4830 #ifdef EM_ENGINE_BAD_ROLL
4832 Xstone_force_e, FALSE, FALSE,
4833 EL_ROCK, -1, MV_BIT_RIGHT
4836 Xstone_force_w, FALSE, FALSE,
4837 EL_ROCK, -1, MV_BIT_LEFT
4840 Xnut_force_e, FALSE, FALSE,
4841 EL_NUT, -1, MV_BIT_RIGHT
4844 Xnut_force_w, FALSE, FALSE,
4845 EL_NUT, -1, MV_BIT_LEFT
4848 Xspring_force_e, FALSE, FALSE,
4849 EL_SPRING, -1, MV_BIT_RIGHT
4852 Xspring_force_w, FALSE, FALSE,
4853 EL_SPRING, -1, MV_BIT_LEFT
4856 Xemerald_force_e, FALSE, FALSE,
4857 EL_EMERALD, -1, MV_BIT_RIGHT
4860 Xemerald_force_w, FALSE, FALSE,
4861 EL_EMERALD, -1, MV_BIT_LEFT
4864 Xdiamond_force_e, FALSE, FALSE,
4865 EL_DIAMOND, -1, MV_BIT_RIGHT
4868 Xdiamond_force_w, FALSE, FALSE,
4869 EL_DIAMOND, -1, MV_BIT_LEFT
4872 Xbomb_force_e, FALSE, FALSE,
4873 EL_BOMB, -1, MV_BIT_RIGHT
4876 Xbomb_force_w, FALSE, FALSE,
4877 EL_BOMB, -1, MV_BIT_LEFT
4879 #endif /* EM_ENGINE_BAD_ROLL */
4882 Xstone, TRUE, FALSE,
4886 Xstone_pause, FALSE, FALSE,
4890 Xstone_fall, FALSE, FALSE,
4894 Ystone_s, FALSE, FALSE,
4895 EL_ROCK, ACTION_FALLING, -1
4898 Ystone_sB, FALSE, TRUE,
4899 EL_ROCK, ACTION_FALLING, -1
4902 Ystone_e, FALSE, FALSE,
4903 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
4906 Ystone_eB, FALSE, TRUE,
4907 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
4910 Ystone_w, FALSE, FALSE,
4911 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
4914 Ystone_wB, FALSE, TRUE,
4915 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
4922 Xnut_pause, FALSE, FALSE,
4926 Xnut_fall, FALSE, FALSE,
4930 Ynut_s, FALSE, FALSE,
4931 EL_NUT, ACTION_FALLING, -1
4934 Ynut_sB, FALSE, TRUE,
4935 EL_NUT, ACTION_FALLING, -1
4938 Ynut_e, FALSE, FALSE,
4939 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
4942 Ynut_eB, FALSE, TRUE,
4943 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
4946 Ynut_w, FALSE, FALSE,
4947 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
4950 Ynut_wB, FALSE, TRUE,
4951 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
4954 Xbug_n, TRUE, FALSE,
4958 Xbug_e, TRUE, FALSE,
4959 EL_BUG_RIGHT, -1, -1
4962 Xbug_s, TRUE, FALSE,
4966 Xbug_w, TRUE, FALSE,
4970 Xbug_gon, FALSE, FALSE,
4974 Xbug_goe, FALSE, FALSE,
4975 EL_BUG_RIGHT, -1, -1
4978 Xbug_gos, FALSE, FALSE,
4982 Xbug_gow, FALSE, FALSE,
4986 Ybug_n, FALSE, FALSE,
4987 EL_BUG, ACTION_MOVING, MV_BIT_UP
4990 Ybug_nB, FALSE, TRUE,
4991 EL_BUG, ACTION_MOVING, MV_BIT_UP
4994 Ybug_e, FALSE, FALSE,
4995 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
4998 Ybug_eB, FALSE, TRUE,
4999 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
5002 Ybug_s, FALSE, FALSE,
5003 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
5006 Ybug_sB, FALSE, TRUE,
5007 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
5010 Ybug_w, FALSE, FALSE,
5011 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
5014 Ybug_wB, FALSE, TRUE,
5015 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
5018 Ybug_w_n, FALSE, FALSE,
5019 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
5022 Ybug_n_e, FALSE, FALSE,
5023 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
5026 Ybug_e_s, FALSE, FALSE,
5027 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
5030 Ybug_s_w, FALSE, FALSE,
5031 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
5034 Ybug_e_n, FALSE, FALSE,
5035 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
5038 Ybug_s_e, FALSE, FALSE,
5039 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
5042 Ybug_w_s, FALSE, FALSE,
5043 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
5046 Ybug_n_w, FALSE, FALSE,
5047 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
5050 Ybug_stone, FALSE, FALSE,
5051 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
5054 Ybug_spring, FALSE, FALSE,
5055 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
5058 Xtank_n, TRUE, FALSE,
5059 EL_SPACESHIP_UP, -1, -1
5062 Xtank_e, TRUE, FALSE,
5063 EL_SPACESHIP_RIGHT, -1, -1
5066 Xtank_s, TRUE, FALSE,
5067 EL_SPACESHIP_DOWN, -1, -1
5070 Xtank_w, TRUE, FALSE,
5071 EL_SPACESHIP_LEFT, -1, -1
5074 Xtank_gon, FALSE, FALSE,
5075 EL_SPACESHIP_UP, -1, -1
5078 Xtank_goe, FALSE, FALSE,
5079 EL_SPACESHIP_RIGHT, -1, -1
5082 Xtank_gos, FALSE, FALSE,
5083 EL_SPACESHIP_DOWN, -1, -1
5086 Xtank_gow, FALSE, FALSE,
5087 EL_SPACESHIP_LEFT, -1, -1
5090 Ytank_n, FALSE, FALSE,
5091 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
5094 Ytank_nB, FALSE, TRUE,
5095 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
5098 Ytank_e, FALSE, FALSE,
5099 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
5102 Ytank_eB, FALSE, TRUE,
5103 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
5106 Ytank_s, FALSE, FALSE,
5107 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
5110 Ytank_sB, FALSE, TRUE,
5111 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
5114 Ytank_w, FALSE, FALSE,
5115 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
5118 Ytank_wB, FALSE, TRUE,
5119 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
5122 Ytank_w_n, FALSE, FALSE,
5123 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
5126 Ytank_n_e, FALSE, FALSE,
5127 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
5130 Ytank_e_s, FALSE, FALSE,
5131 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
5134 Ytank_s_w, FALSE, FALSE,
5135 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
5138 Ytank_e_n, FALSE, FALSE,
5139 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
5142 Ytank_s_e, FALSE, FALSE,
5143 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
5146 Ytank_w_s, FALSE, FALSE,
5147 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
5150 Ytank_n_w, FALSE, FALSE,
5151 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
5154 Ytank_stone, FALSE, FALSE,
5155 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
5158 Ytank_spring, FALSE, FALSE,
5159 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
5162 Xandroid, TRUE, FALSE,
5163 EL_EMC_ANDROID, ACTION_ACTIVE, -1
5166 Xandroid_1_n, FALSE, FALSE,
5167 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
5170 Xandroid_2_n, FALSE, FALSE,
5171 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
5174 Xandroid_1_e, FALSE, FALSE,
5175 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
5178 Xandroid_2_e, FALSE, FALSE,
5179 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
5182 Xandroid_1_w, FALSE, FALSE,
5183 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
5186 Xandroid_2_w, FALSE, FALSE,
5187 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
5190 Xandroid_1_s, FALSE, FALSE,
5191 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
5194 Xandroid_2_s, FALSE, FALSE,
5195 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
5198 Yandroid_n, FALSE, FALSE,
5199 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
5202 Yandroid_nB, FALSE, TRUE,
5203 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
5206 Yandroid_ne, FALSE, FALSE,
5207 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
5210 Yandroid_neB, FALSE, TRUE,
5211 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
5214 Yandroid_e, FALSE, FALSE,
5215 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
5218 Yandroid_eB, FALSE, TRUE,
5219 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
5222 Yandroid_se, FALSE, FALSE,
5223 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
5226 Yandroid_seB, FALSE, TRUE,
5227 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
5230 Yandroid_s, FALSE, FALSE,
5231 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
5234 Yandroid_sB, FALSE, TRUE,
5235 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
5238 Yandroid_sw, FALSE, FALSE,
5239 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
5242 Yandroid_swB, FALSE, TRUE,
5243 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
5246 Yandroid_w, FALSE, FALSE,
5247 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
5250 Yandroid_wB, FALSE, TRUE,
5251 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
5254 Yandroid_nw, FALSE, FALSE,
5255 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
5258 Yandroid_nwB, FALSE, TRUE,
5259 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
5262 Xspring, TRUE, FALSE,
5266 Xspring_pause, FALSE, FALSE,
5270 Xspring_e, FALSE, FALSE,
5274 Xspring_w, FALSE, FALSE,
5278 Xspring_fall, FALSE, FALSE,
5282 Yspring_s, FALSE, FALSE,
5283 EL_SPRING, ACTION_FALLING, -1
5286 Yspring_sB, FALSE, TRUE,
5287 EL_SPRING, ACTION_FALLING, -1
5290 Yspring_e, FALSE, FALSE,
5291 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
5294 Yspring_eB, FALSE, TRUE,
5295 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
5298 Yspring_w, FALSE, FALSE,
5299 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
5302 Yspring_wB, FALSE, TRUE,
5303 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
5306 Yspring_kill_e, FALSE, FALSE,
5307 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
5310 Yspring_kill_eB, FALSE, TRUE,
5311 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
5314 Yspring_kill_w, FALSE, FALSE,
5315 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
5318 Yspring_kill_wB, FALSE, TRUE,
5319 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
5322 Xeater_n, TRUE, FALSE,
5323 EL_YAMYAM_UP, -1, -1
5326 Xeater_e, TRUE, FALSE,
5327 EL_YAMYAM_RIGHT, -1, -1
5330 Xeater_w, TRUE, FALSE,
5331 EL_YAMYAM_LEFT, -1, -1
5334 Xeater_s, TRUE, FALSE,
5335 EL_YAMYAM_DOWN, -1, -1
5338 Yeater_n, FALSE, FALSE,
5339 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
5342 Yeater_nB, FALSE, TRUE,
5343 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
5346 Yeater_e, FALSE, FALSE,
5347 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
5350 Yeater_eB, FALSE, TRUE,
5351 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
5354 Yeater_s, FALSE, FALSE,
5355 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
5358 Yeater_sB, FALSE, TRUE,
5359 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
5362 Yeater_w, FALSE, FALSE,
5363 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
5366 Yeater_wB, FALSE, TRUE,
5367 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
5370 Yeater_stone, FALSE, FALSE,
5371 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
5374 Yeater_spring, FALSE, FALSE,
5375 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
5378 Xalien, TRUE, FALSE,
5382 Xalien_pause, FALSE, FALSE,
5386 Yalien_n, FALSE, FALSE,
5387 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
5390 Yalien_nB, FALSE, TRUE,
5391 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
5394 Yalien_e, FALSE, FALSE,
5395 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
5398 Yalien_eB, FALSE, TRUE,
5399 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
5402 Yalien_s, FALSE, FALSE,
5403 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
5406 Yalien_sB, FALSE, TRUE,
5407 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
5410 Yalien_w, FALSE, FALSE,
5411 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
5414 Yalien_wB, FALSE, TRUE,
5415 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
5418 Yalien_stone, FALSE, FALSE,
5419 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
5422 Yalien_spring, FALSE, FALSE,
5423 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
5426 Xemerald, TRUE, FALSE,
5430 Xemerald_pause, FALSE, FALSE,
5434 Xemerald_fall, FALSE, FALSE,
5438 Xemerald_shine, FALSE, FALSE,
5439 EL_EMERALD, ACTION_TWINKLING, -1
5442 Yemerald_s, FALSE, FALSE,
5443 EL_EMERALD, ACTION_FALLING, -1
5446 Yemerald_sB, FALSE, TRUE,
5447 EL_EMERALD, ACTION_FALLING, -1
5450 Yemerald_e, FALSE, FALSE,
5451 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
5454 Yemerald_eB, FALSE, TRUE,
5455 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
5458 Yemerald_w, FALSE, FALSE,
5459 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
5462 Yemerald_wB, FALSE, TRUE,
5463 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
5466 Yemerald_eat, FALSE, FALSE,
5467 EL_EMERALD, ACTION_COLLECTING, -1
5470 Yemerald_stone, FALSE, FALSE,
5471 EL_NUT, ACTION_BREAKING, -1
5474 Xdiamond, TRUE, FALSE,
5478 Xdiamond_pause, FALSE, FALSE,
5482 Xdiamond_fall, FALSE, FALSE,
5486 Xdiamond_shine, FALSE, FALSE,
5487 EL_DIAMOND, ACTION_TWINKLING, -1
5490 Ydiamond_s, FALSE, FALSE,
5491 EL_DIAMOND, ACTION_FALLING, -1
5494 Ydiamond_sB, FALSE, TRUE,
5495 EL_DIAMOND, ACTION_FALLING, -1
5498 Ydiamond_e, FALSE, FALSE,
5499 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
5502 Ydiamond_eB, FALSE, TRUE,
5503 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
5506 Ydiamond_w, FALSE, FALSE,
5507 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
5510 Ydiamond_wB, FALSE, TRUE,
5511 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
5514 Ydiamond_eat, FALSE, FALSE,
5515 EL_DIAMOND, ACTION_COLLECTING, -1
5518 Ydiamond_stone, FALSE, FALSE,
5519 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
5522 Xdrip_fall, TRUE, FALSE,
5523 EL_AMOEBA_DROP, -1, -1
5526 Xdrip_stretch, FALSE, FALSE,
5527 EL_AMOEBA_DROP, ACTION_FALLING, -1
5530 Xdrip_stretchB, FALSE, TRUE,
5531 EL_AMOEBA_DROP, ACTION_FALLING, -1
5534 Xdrip_eat, FALSE, FALSE,
5535 EL_AMOEBA_DROP, ACTION_GROWING, -1
5538 Ydrip_s1, FALSE, FALSE,
5539 EL_AMOEBA_DROP, ACTION_FALLING, -1
5542 Ydrip_s1B, FALSE, TRUE,
5543 EL_AMOEBA_DROP, ACTION_FALLING, -1
5546 Ydrip_s2, FALSE, FALSE,
5547 EL_AMOEBA_DROP, ACTION_FALLING, -1
5550 Ydrip_s2B, FALSE, TRUE,
5551 EL_AMOEBA_DROP, ACTION_FALLING, -1
5558 Xbomb_pause, FALSE, FALSE,
5562 Xbomb_fall, FALSE, FALSE,
5566 Ybomb_s, FALSE, FALSE,
5567 EL_BOMB, ACTION_FALLING, -1
5570 Ybomb_sB, FALSE, TRUE,
5571 EL_BOMB, ACTION_FALLING, -1
5574 Ybomb_e, FALSE, FALSE,
5575 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
5578 Ybomb_eB, FALSE, TRUE,
5579 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
5582 Ybomb_w, FALSE, FALSE,
5583 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
5586 Ybomb_wB, FALSE, TRUE,
5587 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
5590 Ybomb_eat, FALSE, FALSE,
5591 EL_BOMB, ACTION_ACTIVATING, -1
5594 Xballoon, TRUE, FALSE,
5598 Yballoon_n, FALSE, FALSE,
5599 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
5602 Yballoon_nB, FALSE, TRUE,
5603 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
5606 Yballoon_e, FALSE, FALSE,
5607 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
5610 Yballoon_eB, FALSE, TRUE,
5611 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
5614 Yballoon_s, FALSE, FALSE,
5615 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
5618 Yballoon_sB, FALSE, TRUE,
5619 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
5622 Yballoon_w, FALSE, FALSE,
5623 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
5626 Yballoon_wB, FALSE, TRUE,
5627 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
5630 Xgrass, TRUE, FALSE,
5631 EL_EMC_GRASS, -1, -1
5634 Ygrass_nB, FALSE, FALSE,
5635 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
5638 Ygrass_eB, FALSE, FALSE,
5639 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
5642 Ygrass_sB, FALSE, FALSE,
5643 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
5646 Ygrass_wB, FALSE, FALSE,
5647 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
5654 Ydirt_nB, FALSE, FALSE,
5655 EL_SAND, ACTION_DIGGING, MV_BIT_UP
5658 Ydirt_eB, FALSE, FALSE,
5659 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
5662 Ydirt_sB, FALSE, FALSE,
5663 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
5666 Ydirt_wB, FALSE, FALSE,
5667 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
5670 Xacid_ne, TRUE, FALSE,
5671 EL_ACID_POOL_TOPRIGHT, -1, -1
5674 Xacid_se, TRUE, FALSE,
5675 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
5678 Xacid_s, TRUE, FALSE,
5679 EL_ACID_POOL_BOTTOM, -1, -1
5682 Xacid_sw, TRUE, FALSE,
5683 EL_ACID_POOL_BOTTOMLEFT, -1, -1
5686 Xacid_nw, TRUE, FALSE,
5687 EL_ACID_POOL_TOPLEFT, -1, -1
5690 Xacid_1, TRUE, FALSE,
5694 Xacid_2, FALSE, FALSE,
5698 Xacid_3, FALSE, FALSE,
5702 Xacid_4, FALSE, FALSE,
5706 Xacid_5, FALSE, FALSE,
5710 Xacid_6, FALSE, FALSE,
5714 Xacid_7, FALSE, FALSE,
5718 Xacid_8, FALSE, FALSE,
5722 Xball_1, TRUE, FALSE,
5723 EL_EMC_MAGIC_BALL, -1, -1
5726 Xball_1B, FALSE, FALSE,
5727 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5730 Xball_2, FALSE, FALSE,
5731 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5734 Xball_2B, FALSE, FALSE,
5735 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5738 Yball_eat, FALSE, FALSE,
5739 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
5742 Ykey_1_eat, FALSE, FALSE,
5743 EL_EM_KEY_1, ACTION_COLLECTING, -1
5746 Ykey_2_eat, FALSE, FALSE,
5747 EL_EM_KEY_2, ACTION_COLLECTING, -1
5750 Ykey_3_eat, FALSE, FALSE,
5751 EL_EM_KEY_3, ACTION_COLLECTING, -1
5754 Ykey_4_eat, FALSE, FALSE,
5755 EL_EM_KEY_4, ACTION_COLLECTING, -1
5758 Ykey_5_eat, FALSE, FALSE,
5759 EL_EMC_KEY_5, ACTION_COLLECTING, -1
5762 Ykey_6_eat, FALSE, FALSE,
5763 EL_EMC_KEY_6, ACTION_COLLECTING, -1
5766 Ykey_7_eat, FALSE, FALSE,
5767 EL_EMC_KEY_7, ACTION_COLLECTING, -1
5770 Ykey_8_eat, FALSE, FALSE,
5771 EL_EMC_KEY_8, ACTION_COLLECTING, -1
5774 Ylenses_eat, FALSE, FALSE,
5775 EL_EMC_LENSES, ACTION_COLLECTING, -1
5778 Ymagnify_eat, FALSE, FALSE,
5779 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
5782 Ygrass_eat, FALSE, FALSE,
5783 EL_EMC_GRASS, ACTION_SNAPPING, -1
5786 Ydirt_eat, FALSE, FALSE,
5787 EL_SAND, ACTION_SNAPPING, -1
5790 Xgrow_ns, TRUE, FALSE,
5791 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
5794 Ygrow_ns_eat, FALSE, FALSE,
5795 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
5798 Xgrow_ew, TRUE, FALSE,
5799 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
5802 Ygrow_ew_eat, FALSE, FALSE,
5803 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
5806 Xwonderwall, TRUE, FALSE,
5807 EL_MAGIC_WALL, -1, -1
5810 XwonderwallB, FALSE, FALSE,
5811 EL_MAGIC_WALL, ACTION_ACTIVE, -1
5814 Xamoeba_1, TRUE, FALSE,
5815 EL_AMOEBA_DRY, ACTION_OTHER, -1
5818 Xamoeba_2, FALSE, FALSE,
5819 EL_AMOEBA_DRY, ACTION_OTHER, -1
5822 Xamoeba_3, FALSE, FALSE,
5823 EL_AMOEBA_DRY, ACTION_OTHER, -1
5826 Xamoeba_4, FALSE, FALSE,
5827 EL_AMOEBA_DRY, ACTION_OTHER, -1
5830 Xamoeba_5, TRUE, FALSE,
5831 EL_AMOEBA_WET, ACTION_OTHER, -1
5834 Xamoeba_6, FALSE, FALSE,
5835 EL_AMOEBA_WET, ACTION_OTHER, -1
5838 Xamoeba_7, FALSE, FALSE,
5839 EL_AMOEBA_WET, ACTION_OTHER, -1
5842 Xamoeba_8, FALSE, FALSE,
5843 EL_AMOEBA_WET, ACTION_OTHER, -1
5846 Xdoor_1, TRUE, FALSE,
5847 EL_EM_GATE_1, -1, -1
5850 Xdoor_2, TRUE, FALSE,
5851 EL_EM_GATE_2, -1, -1
5854 Xdoor_3, TRUE, FALSE,
5855 EL_EM_GATE_3, -1, -1
5858 Xdoor_4, TRUE, FALSE,
5859 EL_EM_GATE_4, -1, -1
5862 Xdoor_5, TRUE, FALSE,
5863 EL_EMC_GATE_5, -1, -1
5866 Xdoor_6, TRUE, FALSE,
5867 EL_EMC_GATE_6, -1, -1
5870 Xdoor_7, TRUE, FALSE,
5871 EL_EMC_GATE_7, -1, -1
5874 Xdoor_8, TRUE, FALSE,
5875 EL_EMC_GATE_8, -1, -1
5878 Xkey_1, TRUE, FALSE,
5882 Xkey_2, TRUE, FALSE,
5886 Xkey_3, TRUE, FALSE,
5890 Xkey_4, TRUE, FALSE,
5894 Xkey_5, TRUE, FALSE,
5895 EL_EMC_KEY_5, -1, -1
5898 Xkey_6, TRUE, FALSE,
5899 EL_EMC_KEY_6, -1, -1
5902 Xkey_7, TRUE, FALSE,
5903 EL_EMC_KEY_7, -1, -1
5906 Xkey_8, TRUE, FALSE,
5907 EL_EMC_KEY_8, -1, -1
5910 Xwind_n, TRUE, FALSE,
5911 EL_BALLOON_SWITCH_UP, -1, -1
5914 Xwind_e, TRUE, FALSE,
5915 EL_BALLOON_SWITCH_RIGHT, -1, -1
5918 Xwind_s, TRUE, FALSE,
5919 EL_BALLOON_SWITCH_DOWN, -1, -1
5922 Xwind_w, TRUE, FALSE,
5923 EL_BALLOON_SWITCH_LEFT, -1, -1
5926 Xwind_nesw, TRUE, FALSE,
5927 EL_BALLOON_SWITCH_ANY, -1, -1
5930 Xwind_stop, TRUE, FALSE,
5931 EL_BALLOON_SWITCH_NONE, -1, -1
5935 EL_EM_EXIT_CLOSED, -1, -1
5938 Xexit_1, TRUE, FALSE,
5939 EL_EM_EXIT_OPEN, -1, -1
5942 Xexit_2, FALSE, FALSE,
5943 EL_EM_EXIT_OPEN, -1, -1
5946 Xexit_3, FALSE, FALSE,
5947 EL_EM_EXIT_OPEN, -1, -1
5950 Xdynamite, TRUE, FALSE,
5951 EL_EM_DYNAMITE, -1, -1
5954 Ydynamite_eat, FALSE, FALSE,
5955 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
5958 Xdynamite_1, TRUE, FALSE,
5959 EL_EM_DYNAMITE_ACTIVE, -1, -1
5962 Xdynamite_2, FALSE, FALSE,
5963 EL_EM_DYNAMITE_ACTIVE, -1, -1
5966 Xdynamite_3, FALSE, FALSE,
5967 EL_EM_DYNAMITE_ACTIVE, -1, -1
5970 Xdynamite_4, FALSE, FALSE,
5971 EL_EM_DYNAMITE_ACTIVE, -1, -1
5974 Xbumper, TRUE, FALSE,
5975 EL_EMC_SPRING_BUMPER, -1, -1
5978 XbumperB, FALSE, FALSE,
5979 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
5982 Xwheel, TRUE, FALSE,
5983 EL_ROBOT_WHEEL, -1, -1
5986 XwheelB, FALSE, FALSE,
5987 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
5990 Xswitch, TRUE, FALSE,
5991 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
5994 XswitchB, FALSE, FALSE,
5995 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
5999 EL_QUICKSAND_EMPTY, -1, -1
6002 Xsand_stone, TRUE, FALSE,
6003 EL_QUICKSAND_FULL, -1, -1
6006 Xsand_stonein_1, FALSE, TRUE,
6007 EL_ROCK, ACTION_FILLING, -1
6010 Xsand_stonein_2, FALSE, TRUE,
6011 EL_ROCK, ACTION_FILLING, -1
6014 Xsand_stonein_3, FALSE, TRUE,
6015 EL_ROCK, ACTION_FILLING, -1
6018 Xsand_stonein_4, FALSE, TRUE,
6019 EL_ROCK, ACTION_FILLING, -1
6022 Xsand_stonesand_1, FALSE, FALSE,
6023 EL_QUICKSAND_EMPTYING, -1, -1
6026 Xsand_stonesand_2, FALSE, FALSE,
6027 EL_QUICKSAND_EMPTYING, -1, -1
6030 Xsand_stonesand_3, FALSE, FALSE,
6031 EL_QUICKSAND_EMPTYING, -1, -1
6034 Xsand_stonesand_4, FALSE, FALSE,
6035 EL_QUICKSAND_EMPTYING, -1, -1
6038 Xsand_stonesand_quickout_1, FALSE, FALSE,
6039 EL_QUICKSAND_EMPTYING, -1, -1
6042 Xsand_stonesand_quickout_2, FALSE, FALSE,
6043 EL_QUICKSAND_EMPTYING, -1, -1
6046 Xsand_stoneout_1, FALSE, FALSE,
6047 EL_ROCK, ACTION_EMPTYING, -1
6050 Xsand_stoneout_2, FALSE, FALSE,
6051 EL_ROCK, ACTION_EMPTYING, -1
6054 Xsand_sandstone_1, FALSE, FALSE,
6055 EL_QUICKSAND_FILLING, -1, -1
6058 Xsand_sandstone_2, FALSE, FALSE,
6059 EL_QUICKSAND_FILLING, -1, -1
6062 Xsand_sandstone_3, FALSE, FALSE,
6063 EL_QUICKSAND_FILLING, -1, -1
6066 Xsand_sandstone_4, FALSE, FALSE,
6067 EL_QUICKSAND_FILLING, -1, -1
6070 Xplant, TRUE, FALSE,
6071 EL_EMC_PLANT, -1, -1
6074 Yplant, FALSE, FALSE,
6075 EL_EMC_PLANT, -1, -1
6078 Xlenses, TRUE, FALSE,
6079 EL_EMC_LENSES, -1, -1
6082 Xmagnify, TRUE, FALSE,
6083 EL_EMC_MAGNIFIER, -1, -1
6086 Xdripper, TRUE, FALSE,
6087 EL_EMC_DRIPPER, -1, -1
6090 XdripperB, FALSE, FALSE,
6091 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
6094 Xfake_blank, TRUE, FALSE,
6095 EL_INVISIBLE_WALL, -1, -1
6098 Xfake_blankB, FALSE, FALSE,
6099 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
6102 Xfake_grass, TRUE, FALSE,
6103 EL_EMC_FAKE_GRASS, -1, -1
6106 Xfake_grassB, FALSE, FALSE,
6107 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
6110 Xfake_door_1, TRUE, FALSE,
6111 EL_EM_GATE_1_GRAY, -1, -1
6114 Xfake_door_2, TRUE, FALSE,
6115 EL_EM_GATE_2_GRAY, -1, -1
6118 Xfake_door_3, TRUE, FALSE,
6119 EL_EM_GATE_3_GRAY, -1, -1
6122 Xfake_door_4, TRUE, FALSE,
6123 EL_EM_GATE_4_GRAY, -1, -1
6126 Xfake_door_5, TRUE, FALSE,
6127 EL_EMC_GATE_5_GRAY, -1, -1
6130 Xfake_door_6, TRUE, FALSE,
6131 EL_EMC_GATE_6_GRAY, -1, -1
6134 Xfake_door_7, TRUE, FALSE,
6135 EL_EMC_GATE_7_GRAY, -1, -1
6138 Xfake_door_8, TRUE, FALSE,
6139 EL_EMC_GATE_8_GRAY, -1, -1
6142 Xfake_acid_1, TRUE, FALSE,
6143 EL_EMC_FAKE_ACID, -1, -1
6146 Xfake_acid_2, FALSE, FALSE,
6147 EL_EMC_FAKE_ACID, -1, -1
6150 Xfake_acid_3, FALSE, FALSE,
6151 EL_EMC_FAKE_ACID, -1, -1
6154 Xfake_acid_4, FALSE, FALSE,
6155 EL_EMC_FAKE_ACID, -1, -1
6158 Xfake_acid_5, FALSE, FALSE,
6159 EL_EMC_FAKE_ACID, -1, -1
6162 Xfake_acid_6, FALSE, FALSE,
6163 EL_EMC_FAKE_ACID, -1, -1
6166 Xfake_acid_7, FALSE, FALSE,
6167 EL_EMC_FAKE_ACID, -1, -1
6170 Xfake_acid_8, FALSE, FALSE,
6171 EL_EMC_FAKE_ACID, -1, -1
6174 Xsteel_1, TRUE, FALSE,
6175 EL_STEELWALL, -1, -1
6178 Xsteel_2, TRUE, FALSE,
6179 EL_EMC_STEELWALL_2, -1, -1
6182 Xsteel_3, TRUE, FALSE,
6183 EL_EMC_STEELWALL_3, -1, -1
6186 Xsteel_4, TRUE, FALSE,
6187 EL_EMC_STEELWALL_4, -1, -1
6190 Xwall_1, TRUE, FALSE,
6194 Xwall_2, TRUE, FALSE,
6195 EL_EMC_WALL_14, -1, -1
6198 Xwall_3, TRUE, FALSE,
6199 EL_EMC_WALL_15, -1, -1
6202 Xwall_4, TRUE, FALSE,
6203 EL_EMC_WALL_16, -1, -1
6206 Xround_wall_1, TRUE, FALSE,
6207 EL_WALL_SLIPPERY, -1, -1
6210 Xround_wall_2, TRUE, FALSE,
6211 EL_EMC_WALL_SLIPPERY_2, -1, -1
6214 Xround_wall_3, TRUE, FALSE,
6215 EL_EMC_WALL_SLIPPERY_3, -1, -1
6218 Xround_wall_4, TRUE, FALSE,
6219 EL_EMC_WALL_SLIPPERY_4, -1, -1
6222 Xdecor_1, TRUE, FALSE,
6223 EL_EMC_WALL_8, -1, -1
6226 Xdecor_2, TRUE, FALSE,
6227 EL_EMC_WALL_6, -1, -1
6230 Xdecor_3, TRUE, FALSE,
6231 EL_EMC_WALL_4, -1, -1
6234 Xdecor_4, TRUE, FALSE,
6235 EL_EMC_WALL_7, -1, -1
6238 Xdecor_5, TRUE, FALSE,
6239 EL_EMC_WALL_5, -1, -1
6242 Xdecor_6, TRUE, FALSE,
6243 EL_EMC_WALL_9, -1, -1
6246 Xdecor_7, TRUE, FALSE,
6247 EL_EMC_WALL_10, -1, -1
6250 Xdecor_8, TRUE, FALSE,
6251 EL_EMC_WALL_1, -1, -1
6254 Xdecor_9, TRUE, FALSE,
6255 EL_EMC_WALL_2, -1, -1
6258 Xdecor_10, TRUE, FALSE,
6259 EL_EMC_WALL_3, -1, -1
6262 Xdecor_11, TRUE, FALSE,
6263 EL_EMC_WALL_11, -1, -1
6266 Xdecor_12, TRUE, FALSE,
6267 EL_EMC_WALL_12, -1, -1
6270 Xalpha_0, TRUE, FALSE,
6271 EL_CHAR('0'), -1, -1
6274 Xalpha_1, TRUE, FALSE,
6275 EL_CHAR('1'), -1, -1
6278 Xalpha_2, TRUE, FALSE,
6279 EL_CHAR('2'), -1, -1
6282 Xalpha_3, TRUE, FALSE,
6283 EL_CHAR('3'), -1, -1
6286 Xalpha_4, TRUE, FALSE,
6287 EL_CHAR('4'), -1, -1
6290 Xalpha_5, TRUE, FALSE,
6291 EL_CHAR('5'), -1, -1
6294 Xalpha_6, TRUE, FALSE,
6295 EL_CHAR('6'), -1, -1
6298 Xalpha_7, TRUE, FALSE,
6299 EL_CHAR('7'), -1, -1
6302 Xalpha_8, TRUE, FALSE,
6303 EL_CHAR('8'), -1, -1
6306 Xalpha_9, TRUE, FALSE,
6307 EL_CHAR('9'), -1, -1
6310 Xalpha_excla, TRUE, FALSE,
6311 EL_CHAR('!'), -1, -1
6314 Xalpha_quote, TRUE, FALSE,
6315 EL_CHAR('"'), -1, -1
6318 Xalpha_comma, TRUE, FALSE,
6319 EL_CHAR(','), -1, -1
6322 Xalpha_minus, TRUE, FALSE,
6323 EL_CHAR('-'), -1, -1
6326 Xalpha_perio, TRUE, FALSE,
6327 EL_CHAR('.'), -1, -1
6330 Xalpha_colon, TRUE, FALSE,
6331 EL_CHAR(':'), -1, -1
6334 Xalpha_quest, TRUE, FALSE,
6335 EL_CHAR('?'), -1, -1
6338 Xalpha_a, TRUE, FALSE,
6339 EL_CHAR('A'), -1, -1
6342 Xalpha_b, TRUE, FALSE,
6343 EL_CHAR('B'), -1, -1
6346 Xalpha_c, TRUE, FALSE,
6347 EL_CHAR('C'), -1, -1
6350 Xalpha_d, TRUE, FALSE,
6351 EL_CHAR('D'), -1, -1
6354 Xalpha_e, TRUE, FALSE,
6355 EL_CHAR('E'), -1, -1
6358 Xalpha_f, TRUE, FALSE,
6359 EL_CHAR('F'), -1, -1
6362 Xalpha_g, TRUE, FALSE,
6363 EL_CHAR('G'), -1, -1
6366 Xalpha_h, TRUE, FALSE,
6367 EL_CHAR('H'), -1, -1
6370 Xalpha_i, TRUE, FALSE,
6371 EL_CHAR('I'), -1, -1
6374 Xalpha_j, TRUE, FALSE,
6375 EL_CHAR('J'), -1, -1
6378 Xalpha_k, TRUE, FALSE,
6379 EL_CHAR('K'), -1, -1
6382 Xalpha_l, TRUE, FALSE,
6383 EL_CHAR('L'), -1, -1
6386 Xalpha_m, TRUE, FALSE,
6387 EL_CHAR('M'), -1, -1
6390 Xalpha_n, TRUE, FALSE,
6391 EL_CHAR('N'), -1, -1
6394 Xalpha_o, TRUE, FALSE,
6395 EL_CHAR('O'), -1, -1
6398 Xalpha_p, TRUE, FALSE,
6399 EL_CHAR('P'), -1, -1
6402 Xalpha_q, TRUE, FALSE,
6403 EL_CHAR('Q'), -1, -1
6406 Xalpha_r, TRUE, FALSE,
6407 EL_CHAR('R'), -1, -1
6410 Xalpha_s, TRUE, FALSE,
6411 EL_CHAR('S'), -1, -1
6414 Xalpha_t, TRUE, FALSE,
6415 EL_CHAR('T'), -1, -1
6418 Xalpha_u, TRUE, FALSE,
6419 EL_CHAR('U'), -1, -1
6422 Xalpha_v, TRUE, FALSE,
6423 EL_CHAR('V'), -1, -1
6426 Xalpha_w, TRUE, FALSE,
6427 EL_CHAR('W'), -1, -1
6430 Xalpha_x, TRUE, FALSE,
6431 EL_CHAR('X'), -1, -1
6434 Xalpha_y, TRUE, FALSE,
6435 EL_CHAR('Y'), -1, -1
6438 Xalpha_z, TRUE, FALSE,
6439 EL_CHAR('Z'), -1, -1
6442 Xalpha_arrow_e, TRUE, FALSE,
6443 EL_CHAR('>'), -1, -1
6446 Xalpha_arrow_w, TRUE, FALSE,
6447 EL_CHAR('<'), -1, -1
6450 Xalpha_copyr, TRUE, FALSE,
6451 EL_CHAR(CHAR_BYTE_COPYRIGHT), -1, -1
6455 Xboom_bug, FALSE, FALSE,
6456 EL_BUG, ACTION_EXPLODING, -1
6459 Xboom_bomb, FALSE, FALSE,
6460 EL_BOMB, ACTION_EXPLODING, -1
6463 Xboom_android, FALSE, FALSE,
6464 EL_EMC_ANDROID, ACTION_OTHER, -1
6467 Xboom_1, FALSE, FALSE,
6468 EL_DEFAULT, ACTION_EXPLODING, -1
6471 Xboom_2, FALSE, FALSE,
6472 EL_DEFAULT, ACTION_EXPLODING, -1
6475 Znormal, FALSE, FALSE,
6479 Zdynamite, FALSE, FALSE,
6483 Zplayer, FALSE, FALSE,
6487 ZBORDER, FALSE, FALSE,
6497 static struct Mapping_EM_to_RND_player
6506 em_player_mapping_list[] =
6510 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
6514 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
6518 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
6522 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
6526 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
6530 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
6534 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
6538 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
6542 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
6546 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
6550 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
6554 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
6558 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
6562 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
6566 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
6570 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
6574 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
6578 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
6582 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
6586 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
6590 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
6594 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
6598 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
6602 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
6606 EL_PLAYER_1, ACTION_DEFAULT, -1,
6610 EL_PLAYER_2, ACTION_DEFAULT, -1,
6614 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
6618 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
6622 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
6626 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
6630 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
6634 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
6638 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
6642 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
6646 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
6650 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
6654 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
6658 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
6662 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
6666 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
6670 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
6674 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
6678 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
6682 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
6686 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
6690 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
6694 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
6698 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
6702 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
6706 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
6710 EL_PLAYER_3, ACTION_DEFAULT, -1,
6714 EL_PLAYER_4, ACTION_DEFAULT, -1,
6723 int map_element_RND_to_EM(int element_rnd)
6725 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
6726 static boolean mapping_initialized = FALSE;
6728 if (!mapping_initialized)
6732 /* return "Xalpha_quest" for all undefined elements in mapping array */
6733 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
6734 mapping_RND_to_EM[i] = Xalpha_quest;
6736 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6737 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
6738 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
6739 em_object_mapping_list[i].element_em;
6741 mapping_initialized = TRUE;
6744 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
6745 return mapping_RND_to_EM[element_rnd];
6747 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
6752 int map_element_EM_to_RND(int element_em)
6754 static unsigned short mapping_EM_to_RND[TILE_MAX];
6755 static boolean mapping_initialized = FALSE;
6757 if (!mapping_initialized)
6761 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
6762 for (i = 0; i < TILE_MAX; i++)
6763 mapping_EM_to_RND[i] = EL_UNKNOWN;
6765 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6766 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
6767 em_object_mapping_list[i].element_rnd;
6769 mapping_initialized = TRUE;
6772 if (element_em >= 0 && element_em < TILE_MAX)
6773 return mapping_EM_to_RND[element_em];
6775 Error(ERR_WARN, "invalid EM level element %d", element_em);
6780 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
6782 struct LevelInfo_EM *level_em = level->native_em_level;
6783 struct LEVEL *lev = level_em->lev;
6786 for (i = 0; i < TILE_MAX; i++)
6787 lev->android_array[i] = Xblank;
6789 for (i = 0; i < level->num_android_clone_elements; i++)
6791 int element_rnd = level->android_clone_element[i];
6792 int element_em = map_element_RND_to_EM(element_rnd);
6794 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
6795 if (em_object_mapping_list[j].element_rnd == element_rnd)
6796 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
6800 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
6802 struct LevelInfo_EM *level_em = level->native_em_level;
6803 struct LEVEL *lev = level_em->lev;
6806 level->num_android_clone_elements = 0;
6808 for (i = 0; i < TILE_MAX; i++)
6810 int element_em = lev->android_array[i];
6812 boolean element_found = FALSE;
6814 if (element_em == Xblank)
6817 element_rnd = map_element_EM_to_RND(element_em);
6819 for (j = 0; j < level->num_android_clone_elements; j++)
6820 if (level->android_clone_element[j] == element_rnd)
6821 element_found = TRUE;
6825 level->android_clone_element[level->num_android_clone_elements++] =
6828 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
6833 if (level->num_android_clone_elements == 0)
6835 level->num_android_clone_elements = 1;
6836 level->android_clone_element[0] = EL_EMPTY;
6840 int map_direction_RND_to_EM(int direction)
6842 return (direction == MV_UP ? 0 :
6843 direction == MV_RIGHT ? 1 :
6844 direction == MV_DOWN ? 2 :
6845 direction == MV_LEFT ? 3 :
6849 int map_direction_EM_to_RND(int direction)
6851 return (direction == 0 ? MV_UP :
6852 direction == 1 ? MV_RIGHT :
6853 direction == 2 ? MV_DOWN :
6854 direction == 3 ? MV_LEFT :
6858 int map_element_RND_to_SP(int element_rnd)
6860 int element_sp = 0x20; /* map unknown elements to yellow "hardware" */
6862 if (element_rnd >= EL_SP_START &&
6863 element_rnd <= EL_SP_END)
6864 element_sp = element_rnd - EL_SP_START;
6865 else if (element_rnd == EL_EMPTY_SPACE)
6867 else if (element_rnd == EL_INVISIBLE_WALL)
6873 int map_element_SP_to_RND(int element_sp)
6875 int element_rnd = EL_UNKNOWN;
6877 if (element_sp >= 0x00 &&
6879 element_rnd = EL_SP_START + element_sp;
6880 else if (element_sp == 0x28)
6881 element_rnd = EL_INVISIBLE_WALL;
6886 int map_action_SP_to_RND(int action_sp)
6890 case actActive: return ACTION_ACTIVE;
6891 case actImpact: return ACTION_IMPACT;
6892 case actExploding: return ACTION_EXPLODING;
6893 case actDigging: return ACTION_DIGGING;
6894 case actSnapping: return ACTION_SNAPPING;
6895 case actCollecting: return ACTION_COLLECTING;
6896 case actPassing: return ACTION_PASSING;
6897 case actPushing: return ACTION_PUSHING;
6898 case actDropping: return ACTION_DROPPING;
6900 default: return ACTION_DEFAULT;
6904 int get_next_element(int element)
6908 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
6909 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
6910 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
6911 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
6912 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
6913 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
6914 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
6915 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
6916 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
6917 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
6918 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
6920 default: return element;
6924 int el_act_dir2img(int element, int action, int direction)
6926 element = GFX_ELEMENT(element);
6927 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
6929 /* direction_graphic[][] == graphic[] for undefined direction graphics */
6930 return element_info[element].direction_graphic[action][direction];
6933 static int el_act_dir2crm(int element, int action, int direction)
6935 element = GFX_ELEMENT(element);
6936 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
6938 /* direction_graphic[][] == graphic[] for undefined direction graphics */
6939 return element_info[element].direction_crumbled[action][direction];
6942 int el_act2img(int element, int action)
6944 element = GFX_ELEMENT(element);
6946 return element_info[element].graphic[action];
6949 int el_act2crm(int element, int action)
6951 element = GFX_ELEMENT(element);
6953 return element_info[element].crumbled[action];
6956 int el_dir2img(int element, int direction)
6958 element = GFX_ELEMENT(element);
6960 return el_act_dir2img(element, ACTION_DEFAULT, direction);
6963 int el2baseimg(int element)
6965 return element_info[element].graphic[ACTION_DEFAULT];
6968 int el2img(int element)
6970 element = GFX_ELEMENT(element);
6972 return element_info[element].graphic[ACTION_DEFAULT];
6975 int el2edimg(int element)
6977 element = GFX_ELEMENT(element);
6979 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
6982 int el2preimg(int element)
6984 element = GFX_ELEMENT(element);
6986 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
6989 int el2panelimg(int element)
6991 element = GFX_ELEMENT(element);
6993 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL];
6996 int font2baseimg(int font_nr)
6998 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
7001 int getBeltNrFromBeltElement(int element)
7003 return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
7004 element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
7005 element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
7008 int getBeltNrFromBeltActiveElement(int element)
7010 return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
7011 element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
7012 element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
7015 int getBeltNrFromBeltSwitchElement(int element)
7017 return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
7018 element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
7019 element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
7022 int getBeltDirNrFromBeltElement(int element)
7024 static int belt_base_element[4] =
7026 EL_CONVEYOR_BELT_1_LEFT,
7027 EL_CONVEYOR_BELT_2_LEFT,
7028 EL_CONVEYOR_BELT_3_LEFT,
7029 EL_CONVEYOR_BELT_4_LEFT
7032 int belt_nr = getBeltNrFromBeltElement(element);
7033 int belt_dir_nr = element - belt_base_element[belt_nr];
7035 return (belt_dir_nr % 3);
7038 int getBeltDirNrFromBeltSwitchElement(int element)
7040 static int belt_base_element[4] =
7042 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
7043 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
7044 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
7045 EL_CONVEYOR_BELT_4_SWITCH_LEFT
7048 int belt_nr = getBeltNrFromBeltSwitchElement(element);
7049 int belt_dir_nr = element - belt_base_element[belt_nr];
7051 return (belt_dir_nr % 3);
7054 int getBeltDirFromBeltElement(int element)
7056 static int belt_move_dir[3] =
7063 int belt_dir_nr = getBeltDirNrFromBeltElement(element);
7065 return belt_move_dir[belt_dir_nr];
7068 int getBeltDirFromBeltSwitchElement(int element)
7070 static int belt_move_dir[3] =
7077 int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
7079 return belt_move_dir[belt_dir_nr];
7082 int getBeltElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
7084 static int belt_base_element[4] =
7086 EL_CONVEYOR_BELT_1_LEFT,
7087 EL_CONVEYOR_BELT_2_LEFT,
7088 EL_CONVEYOR_BELT_3_LEFT,
7089 EL_CONVEYOR_BELT_4_LEFT
7092 return belt_base_element[belt_nr] + belt_dir_nr;
7095 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
7097 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
7099 return getBeltElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
7102 int getBeltSwitchElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
7104 static int belt_base_element[4] =
7106 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
7107 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
7108 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
7109 EL_CONVEYOR_BELT_4_SWITCH_LEFT
7112 return belt_base_element[belt_nr] + belt_dir_nr;
7115 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
7117 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
7119 return getBeltSwitchElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
7122 boolean getTeamMode_EM()
7124 return game.team_mode;
7127 int getGameFrameDelay_EM(int native_em_game_frame_delay)
7129 int game_frame_delay_value;
7131 game_frame_delay_value =
7132 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
7133 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
7136 if (tape.playing && tape.warp_forward && !tape.pausing)
7137 game_frame_delay_value = 0;
7139 return game_frame_delay_value;
7142 unsigned int InitRND(int seed)
7144 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
7145 return InitEngineRandom_EM(seed);
7146 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
7147 return InitEngineRandom_SP(seed);
7149 return InitEngineRandom_RND(seed);
7152 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
7153 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
7155 inline static int get_effective_element_EM(int tile, int frame_em)
7157 int element = object_mapping[tile].element_rnd;
7158 int action = object_mapping[tile].action;
7159 boolean is_backside = object_mapping[tile].is_backside;
7160 boolean action_removing = (action == ACTION_DIGGING ||
7161 action == ACTION_SNAPPING ||
7162 action == ACTION_COLLECTING);
7168 case Yacid_splash_eB:
7169 case Yacid_splash_wB:
7170 return (frame_em > 5 ? EL_EMPTY : element);
7176 else /* frame_em == 7 */
7180 case Yacid_splash_eB:
7181 case Yacid_splash_wB:
7184 case Yemerald_stone:
7187 case Ydiamond_stone:
7191 case Xdrip_stretchB:
7210 case Xsand_stonein_1:
7211 case Xsand_stonein_2:
7212 case Xsand_stonein_3:
7213 case Xsand_stonein_4:
7217 return (is_backside || action_removing ? EL_EMPTY : element);
7222 inline static boolean check_linear_animation_EM(int tile)
7226 case Xsand_stonesand_1:
7227 case Xsand_stonesand_quickout_1:
7228 case Xsand_sandstone_1:
7229 case Xsand_stonein_1:
7230 case Xsand_stoneout_1:
7249 case Yacid_splash_eB:
7250 case Yacid_splash_wB:
7251 case Yemerald_stone:
7258 inline static void set_crumbled_graphics_EM(struct GraphicInfo_EM *g_em,
7259 boolean has_crumbled_graphics,
7260 int crumbled, int sync_frame)
7262 /* if element can be crumbled, but certain action graphics are just empty
7263 space (like instantly snapping sand to empty space in 1 frame), do not
7264 treat these empty space graphics as crumbled graphics in EMC engine */
7265 if (crumbled == IMG_EMPTY_SPACE)
7266 has_crumbled_graphics = FALSE;
7268 if (has_crumbled_graphics)
7270 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
7271 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
7272 g_crumbled->anim_delay,
7273 g_crumbled->anim_mode,
7274 g_crumbled->anim_start_frame,
7277 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
7278 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
7280 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
7282 g_em->has_crumbled_graphics = TRUE;
7286 g_em->crumbled_bitmap = NULL;
7287 g_em->crumbled_src_x = 0;
7288 g_em->crumbled_src_y = 0;
7289 g_em->crumbled_border_size = 0;
7291 g_em->has_crumbled_graphics = FALSE;
7295 void ResetGfxAnimation_EM(int x, int y, int tile)
7300 void SetGfxAnimation_EM(struct GraphicInfo_EM *g_em,
7301 int tile, int frame_em, int x, int y)
7303 int action = object_mapping[tile].action;
7304 int direction = object_mapping[tile].direction;
7305 int effective_element = get_effective_element_EM(tile, frame_em);
7306 int graphic = (direction == MV_NONE ?
7307 el_act2img(effective_element, action) :
7308 el_act_dir2img(effective_element, action, direction));
7309 struct GraphicInfo *g = &graphic_info[graphic];
7311 boolean action_removing = (action == ACTION_DIGGING ||
7312 action == ACTION_SNAPPING ||
7313 action == ACTION_COLLECTING);
7314 boolean action_moving = (action == ACTION_FALLING ||
7315 action == ACTION_MOVING ||
7316 action == ACTION_PUSHING ||
7317 action == ACTION_EATING ||
7318 action == ACTION_FILLING ||
7319 action == ACTION_EMPTYING);
7320 boolean action_falling = (action == ACTION_FALLING ||
7321 action == ACTION_FILLING ||
7322 action == ACTION_EMPTYING);
7324 /* special case: graphic uses "2nd movement tile" and has defined
7325 7 frames for movement animation (or less) => use default graphic
7326 for last (8th) frame which ends the movement animation */
7327 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
7329 action = ACTION_DEFAULT; /* (keep action_* unchanged for now) */
7330 graphic = (direction == MV_NONE ?
7331 el_act2img(effective_element, action) :
7332 el_act_dir2img(effective_element, action, direction));
7334 g = &graphic_info[graphic];
7337 if ((action_removing || check_linear_animation_EM(tile)) && frame_em == 0)
7341 else if (action_moving)
7343 boolean is_backside = object_mapping[tile].is_backside;
7347 int direction = object_mapping[tile].direction;
7348 int move_dir = (action_falling ? MV_DOWN : direction);
7353 /* !!! TEST !!! NEW !!! DOES NOT WORK RIGHT YET !!! */
7354 if (g->double_movement && frame_em == 0)
7358 if (move_dir == MV_LEFT)
7359 GfxFrame[x - 1][y] = GfxFrame[x][y];
7360 else if (move_dir == MV_RIGHT)
7361 GfxFrame[x + 1][y] = GfxFrame[x][y];
7362 else if (move_dir == MV_UP)
7363 GfxFrame[x][y - 1] = GfxFrame[x][y];
7364 else if (move_dir == MV_DOWN)
7365 GfxFrame[x][y + 1] = GfxFrame[x][y];
7372 /* special case: animation for Xsand_stonesand_quickout_1/2 twice as fast */
7373 if (tile == Xsand_stonesand_quickout_1 ||
7374 tile == Xsand_stonesand_quickout_2)
7378 if (graphic_info[graphic].anim_global_sync)
7379 sync_frame = FrameCounter;
7380 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
7381 sync_frame = GfxFrame[x][y];
7383 sync_frame = 0; /* playfield border (pseudo steel) */
7385 SetRandomAnimationValue(x, y);
7387 int frame = getAnimationFrame(g->anim_frames,
7390 g->anim_start_frame,
7393 g_em->unique_identifier =
7394 (graphic << 16) | ((frame % 8) << 12) | (g_em->width << 6) | g_em->height;
7397 void getGraphicSourceObjectExt_EM(struct GraphicInfo_EM *g_em,
7398 int tile, int frame_em, int x, int y)
7400 int action = object_mapping[tile].action;
7401 int direction = object_mapping[tile].direction;
7402 boolean is_backside = object_mapping[tile].is_backside;
7403 int effective_element = get_effective_element_EM(tile, frame_em);
7404 int effective_action = action;
7405 int graphic = (direction == MV_NONE ?
7406 el_act2img(effective_element, effective_action) :
7407 el_act_dir2img(effective_element, effective_action,
7409 int crumbled = (direction == MV_NONE ?
7410 el_act2crm(effective_element, effective_action) :
7411 el_act_dir2crm(effective_element, effective_action,
7413 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7414 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7415 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7416 struct GraphicInfo *g = &graphic_info[graphic];
7419 /* special case: graphic uses "2nd movement tile" and has defined
7420 7 frames for movement animation (or less) => use default graphic
7421 for last (8th) frame which ends the movement animation */
7422 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
7424 effective_action = ACTION_DEFAULT;
7425 graphic = (direction == MV_NONE ?
7426 el_act2img(effective_element, effective_action) :
7427 el_act_dir2img(effective_element, effective_action,
7429 crumbled = (direction == MV_NONE ?
7430 el_act2crm(effective_element, effective_action) :
7431 el_act_dir2crm(effective_element, effective_action,
7434 g = &graphic_info[graphic];
7437 if (graphic_info[graphic].anim_global_sync)
7438 sync_frame = FrameCounter;
7439 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
7440 sync_frame = GfxFrame[x][y];
7442 sync_frame = 0; /* playfield border (pseudo steel) */
7444 SetRandomAnimationValue(x, y);
7446 int frame = getAnimationFrame(g->anim_frames,
7449 g->anim_start_frame,
7452 getGraphicSourceExt(graphic, frame, &g_em->bitmap, &g_em->src_x, &g_em->src_y,
7453 g->double_movement && is_backside);
7455 /* (updating the "crumbled" graphic definitions is probably not really needed,
7456 as animations for crumbled graphics can't be longer than one EMC cycle) */
7457 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
7461 void getGraphicSourcePlayerExt_EM(struct GraphicInfo_EM *g_em,
7462 int player_nr, int anim, int frame_em)
7464 int element = player_mapping[player_nr][anim].element_rnd;
7465 int action = player_mapping[player_nr][anim].action;
7466 int direction = player_mapping[player_nr][anim].direction;
7467 int graphic = (direction == MV_NONE ?
7468 el_act2img(element, action) :
7469 el_act_dir2img(element, action, direction));
7470 struct GraphicInfo *g = &graphic_info[graphic];
7473 InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
7475 stored_player[player_nr].StepFrame = frame_em;
7477 sync_frame = stored_player[player_nr].Frame;
7479 int frame = getAnimationFrame(g->anim_frames,
7482 g->anim_start_frame,
7485 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
7486 &g_em->src_x, &g_em->src_y, FALSE);
7489 void InitGraphicInfo_EM(void)
7494 int num_em_gfx_errors = 0;
7496 if (graphic_info_em_object[0][0].bitmap == NULL)
7498 /* EM graphics not yet initialized in em_open_all() */
7503 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
7506 /* always start with reliable default values */
7507 for (i = 0; i < TILE_MAX; i++)
7509 object_mapping[i].element_rnd = EL_UNKNOWN;
7510 object_mapping[i].is_backside = FALSE;
7511 object_mapping[i].action = ACTION_DEFAULT;
7512 object_mapping[i].direction = MV_NONE;
7515 /* always start with reliable default values */
7516 for (p = 0; p < MAX_PLAYERS; p++)
7518 for (i = 0; i < SPR_MAX; i++)
7520 player_mapping[p][i].element_rnd = EL_UNKNOWN;
7521 player_mapping[p][i].action = ACTION_DEFAULT;
7522 player_mapping[p][i].direction = MV_NONE;
7526 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
7528 int e = em_object_mapping_list[i].element_em;
7530 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
7531 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
7533 if (em_object_mapping_list[i].action != -1)
7534 object_mapping[e].action = em_object_mapping_list[i].action;
7536 if (em_object_mapping_list[i].direction != -1)
7537 object_mapping[e].direction =
7538 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
7541 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
7543 int a = em_player_mapping_list[i].action_em;
7544 int p = em_player_mapping_list[i].player_nr;
7546 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
7548 if (em_player_mapping_list[i].action != -1)
7549 player_mapping[p][a].action = em_player_mapping_list[i].action;
7551 if (em_player_mapping_list[i].direction != -1)
7552 player_mapping[p][a].direction =
7553 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
7556 for (i = 0; i < TILE_MAX; i++)
7558 int element = object_mapping[i].element_rnd;
7559 int action = object_mapping[i].action;
7560 int direction = object_mapping[i].direction;
7561 boolean is_backside = object_mapping[i].is_backside;
7562 boolean action_exploding = ((action == ACTION_EXPLODING ||
7563 action == ACTION_SMASHED_BY_ROCK ||
7564 action == ACTION_SMASHED_BY_SPRING) &&
7565 element != EL_DIAMOND);
7566 boolean action_active = (action == ACTION_ACTIVE);
7567 boolean action_other = (action == ACTION_OTHER);
7569 for (j = 0; j < 8; j++)
7571 int effective_element = get_effective_element_EM(i, j);
7572 int effective_action = (j < 7 ? action :
7573 i == Xdrip_stretch ? action :
7574 i == Xdrip_stretchB ? action :
7575 i == Ydrip_s1 ? action :
7576 i == Ydrip_s1B ? action :
7577 i == Xball_1B ? action :
7578 i == Xball_2 ? action :
7579 i == Xball_2B ? action :
7580 i == Yball_eat ? action :
7581 i == Ykey_1_eat ? action :
7582 i == Ykey_2_eat ? action :
7583 i == Ykey_3_eat ? action :
7584 i == Ykey_4_eat ? action :
7585 i == Ykey_5_eat ? action :
7586 i == Ykey_6_eat ? action :
7587 i == Ykey_7_eat ? action :
7588 i == Ykey_8_eat ? action :
7589 i == Ylenses_eat ? action :
7590 i == Ymagnify_eat ? action :
7591 i == Ygrass_eat ? action :
7592 i == Ydirt_eat ? action :
7593 i == Xsand_stonein_1 ? action :
7594 i == Xsand_stonein_2 ? action :
7595 i == Xsand_stonein_3 ? action :
7596 i == Xsand_stonein_4 ? action :
7597 i == Xsand_stoneout_1 ? action :
7598 i == Xsand_stoneout_2 ? action :
7599 i == Xboom_android ? ACTION_EXPLODING :
7600 action_exploding ? ACTION_EXPLODING :
7601 action_active ? action :
7602 action_other ? action :
7604 int graphic = (el_act_dir2img(effective_element, effective_action,
7606 int crumbled = (el_act_dir2crm(effective_element, effective_action,
7608 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7609 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7610 boolean has_action_graphics = (graphic != base_graphic);
7611 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7612 struct GraphicInfo *g = &graphic_info[graphic];
7613 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7616 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
7617 boolean special_animation = (action != ACTION_DEFAULT &&
7618 g->anim_frames == 3 &&
7619 g->anim_delay == 2 &&
7620 g->anim_mode & ANIM_LINEAR);
7621 int sync_frame = (i == Xdrip_stretch ? 7 :
7622 i == Xdrip_stretchB ? 7 :
7623 i == Ydrip_s2 ? j + 8 :
7624 i == Ydrip_s2B ? j + 8 :
7633 i == Xfake_acid_1 ? 0 :
7634 i == Xfake_acid_2 ? 10 :
7635 i == Xfake_acid_3 ? 20 :
7636 i == Xfake_acid_4 ? 30 :
7637 i == Xfake_acid_5 ? 40 :
7638 i == Xfake_acid_6 ? 50 :
7639 i == Xfake_acid_7 ? 60 :
7640 i == Xfake_acid_8 ? 70 :
7642 i == Xball_2B ? j + 8 :
7643 i == Yball_eat ? j + 1 :
7644 i == Ykey_1_eat ? j + 1 :
7645 i == Ykey_2_eat ? j + 1 :
7646 i == Ykey_3_eat ? j + 1 :
7647 i == Ykey_4_eat ? j + 1 :
7648 i == Ykey_5_eat ? j + 1 :
7649 i == Ykey_6_eat ? j + 1 :
7650 i == Ykey_7_eat ? j + 1 :
7651 i == Ykey_8_eat ? j + 1 :
7652 i == Ylenses_eat ? j + 1 :
7653 i == Ymagnify_eat ? j + 1 :
7654 i == Ygrass_eat ? j + 1 :
7655 i == Ydirt_eat ? j + 1 :
7656 i == Xamoeba_1 ? 0 :
7657 i == Xamoeba_2 ? 1 :
7658 i == Xamoeba_3 ? 2 :
7659 i == Xamoeba_4 ? 3 :
7660 i == Xamoeba_5 ? 0 :
7661 i == Xamoeba_6 ? 1 :
7662 i == Xamoeba_7 ? 2 :
7663 i == Xamoeba_8 ? 3 :
7664 i == Xexit_2 ? j + 8 :
7665 i == Xexit_3 ? j + 16 :
7666 i == Xdynamite_1 ? 0 :
7667 i == Xdynamite_2 ? 8 :
7668 i == Xdynamite_3 ? 16 :
7669 i == Xdynamite_4 ? 24 :
7670 i == Xsand_stonein_1 ? j + 1 :
7671 i == Xsand_stonein_2 ? j + 9 :
7672 i == Xsand_stonein_3 ? j + 17 :
7673 i == Xsand_stonein_4 ? j + 25 :
7674 i == Xsand_stoneout_1 && j == 0 ? 0 :
7675 i == Xsand_stoneout_1 && j == 1 ? 0 :
7676 i == Xsand_stoneout_1 && j == 2 ? 1 :
7677 i == Xsand_stoneout_1 && j == 3 ? 2 :
7678 i == Xsand_stoneout_1 && j == 4 ? 2 :
7679 i == Xsand_stoneout_1 && j == 5 ? 3 :
7680 i == Xsand_stoneout_1 && j == 6 ? 4 :
7681 i == Xsand_stoneout_1 && j == 7 ? 4 :
7682 i == Xsand_stoneout_2 && j == 0 ? 5 :
7683 i == Xsand_stoneout_2 && j == 1 ? 6 :
7684 i == Xsand_stoneout_2 && j == 2 ? 7 :
7685 i == Xsand_stoneout_2 && j == 3 ? 8 :
7686 i == Xsand_stoneout_2 && j == 4 ? 9 :
7687 i == Xsand_stoneout_2 && j == 5 ? 11 :
7688 i == Xsand_stoneout_2 && j == 6 ? 13 :
7689 i == Xsand_stoneout_2 && j == 7 ? 15 :
7690 i == Xboom_bug && j == 1 ? 2 :
7691 i == Xboom_bug && j == 2 ? 2 :
7692 i == Xboom_bug && j == 3 ? 4 :
7693 i == Xboom_bug && j == 4 ? 4 :
7694 i == Xboom_bug && j == 5 ? 2 :
7695 i == Xboom_bug && j == 6 ? 2 :
7696 i == Xboom_bug && j == 7 ? 0 :
7697 i == Xboom_bomb && j == 1 ? 2 :
7698 i == Xboom_bomb && j == 2 ? 2 :
7699 i == Xboom_bomb && j == 3 ? 4 :
7700 i == Xboom_bomb && j == 4 ? 4 :
7701 i == Xboom_bomb && j == 5 ? 2 :
7702 i == Xboom_bomb && j == 6 ? 2 :
7703 i == Xboom_bomb && j == 7 ? 0 :
7704 i == Xboom_android && j == 7 ? 6 :
7705 i == Xboom_1 && j == 1 ? 2 :
7706 i == Xboom_1 && j == 2 ? 2 :
7707 i == Xboom_1 && j == 3 ? 4 :
7708 i == Xboom_1 && j == 4 ? 4 :
7709 i == Xboom_1 && j == 5 ? 6 :
7710 i == Xboom_1 && j == 6 ? 6 :
7711 i == Xboom_1 && j == 7 ? 8 :
7712 i == Xboom_2 && j == 0 ? 8 :
7713 i == Xboom_2 && j == 1 ? 8 :
7714 i == Xboom_2 && j == 2 ? 10 :
7715 i == Xboom_2 && j == 3 ? 10 :
7716 i == Xboom_2 && j == 4 ? 10 :
7717 i == Xboom_2 && j == 5 ? 12 :
7718 i == Xboom_2 && j == 6 ? 12 :
7719 i == Xboom_2 && j == 7 ? 12 :
7720 special_animation && j == 4 ? 3 :
7721 effective_action != action ? 0 :
7725 Bitmap *debug_bitmap = g_em->bitmap;
7726 int debug_src_x = g_em->src_x;
7727 int debug_src_y = g_em->src_y;
7730 int frame = getAnimationFrame(g->anim_frames,
7733 g->anim_start_frame,
7736 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
7737 g->double_movement && is_backside);
7739 g_em->bitmap = src_bitmap;
7740 g_em->src_x = src_x;
7741 g_em->src_y = src_y;
7742 g_em->src_offset_x = 0;
7743 g_em->src_offset_y = 0;
7744 g_em->dst_offset_x = 0;
7745 g_em->dst_offset_y = 0;
7746 g_em->width = TILEX;
7747 g_em->height = TILEY;
7749 g_em->preserve_background = FALSE;
7751 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
7754 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
7755 effective_action == ACTION_MOVING ||
7756 effective_action == ACTION_PUSHING ||
7757 effective_action == ACTION_EATING)) ||
7758 (!has_action_graphics && (effective_action == ACTION_FILLING ||
7759 effective_action == ACTION_EMPTYING)))
7762 (effective_action == ACTION_FALLING ||
7763 effective_action == ACTION_FILLING ||
7764 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
7765 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
7766 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
7767 int num_steps = (i == Ydrip_s1 ? 16 :
7768 i == Ydrip_s1B ? 16 :
7769 i == Ydrip_s2 ? 16 :
7770 i == Ydrip_s2B ? 16 :
7771 i == Xsand_stonein_1 ? 32 :
7772 i == Xsand_stonein_2 ? 32 :
7773 i == Xsand_stonein_3 ? 32 :
7774 i == Xsand_stonein_4 ? 32 :
7775 i == Xsand_stoneout_1 ? 16 :
7776 i == Xsand_stoneout_2 ? 16 : 8);
7777 int cx = ABS(dx) * (TILEX / num_steps);
7778 int cy = ABS(dy) * (TILEY / num_steps);
7779 int step_frame = (i == Ydrip_s2 ? j + 8 :
7780 i == Ydrip_s2B ? j + 8 :
7781 i == Xsand_stonein_2 ? j + 8 :
7782 i == Xsand_stonein_3 ? j + 16 :
7783 i == Xsand_stonein_4 ? j + 24 :
7784 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
7785 int step = (is_backside ? step_frame : num_steps - step_frame);
7787 if (is_backside) /* tile where movement starts */
7789 if (dx < 0 || dy < 0)
7791 g_em->src_offset_x = cx * step;
7792 g_em->src_offset_y = cy * step;
7796 g_em->dst_offset_x = cx * step;
7797 g_em->dst_offset_y = cy * step;
7800 else /* tile where movement ends */
7802 if (dx < 0 || dy < 0)
7804 g_em->dst_offset_x = cx * step;
7805 g_em->dst_offset_y = cy * step;
7809 g_em->src_offset_x = cx * step;
7810 g_em->src_offset_y = cy * step;
7814 g_em->width = TILEX - cx * step;
7815 g_em->height = TILEY - cy * step;
7818 /* create unique graphic identifier to decide if tile must be redrawn */
7819 /* bit 31 - 16 (16 bit): EM style graphic
7820 bit 15 - 12 ( 4 bit): EM style frame
7821 bit 11 - 6 ( 6 bit): graphic width
7822 bit 5 - 0 ( 6 bit): graphic height */
7823 g_em->unique_identifier =
7824 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
7828 /* skip check for EMC elements not contained in original EMC artwork */
7829 if (element == EL_EMC_FAKE_ACID)
7832 if (g_em->bitmap != debug_bitmap ||
7833 g_em->src_x != debug_src_x ||
7834 g_em->src_y != debug_src_y ||
7835 g_em->src_offset_x != 0 ||
7836 g_em->src_offset_y != 0 ||
7837 g_em->dst_offset_x != 0 ||
7838 g_em->dst_offset_y != 0 ||
7839 g_em->width != TILEX ||
7840 g_em->height != TILEY)
7842 static int last_i = -1;
7850 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
7851 i, element, element_info[element].token_name,
7852 element_action_info[effective_action].suffix, direction);
7854 if (element != effective_element)
7855 printf(" [%d ('%s')]",
7857 element_info[effective_element].token_name);
7861 if (g_em->bitmap != debug_bitmap)
7862 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
7863 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
7865 if (g_em->src_x != debug_src_x ||
7866 g_em->src_y != debug_src_y)
7867 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
7868 j, (is_backside ? 'B' : 'F'),
7869 g_em->src_x, g_em->src_y,
7870 g_em->src_x / 32, g_em->src_y / 32,
7871 debug_src_x, debug_src_y,
7872 debug_src_x / 32, debug_src_y / 32);
7874 if (g_em->src_offset_x != 0 ||
7875 g_em->src_offset_y != 0 ||
7876 g_em->dst_offset_x != 0 ||
7877 g_em->dst_offset_y != 0)
7878 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
7880 g_em->src_offset_x, g_em->src_offset_y,
7881 g_em->dst_offset_x, g_em->dst_offset_y);
7883 if (g_em->width != TILEX ||
7884 g_em->height != TILEY)
7885 printf(" %d (%d): size %d,%d should be %d,%d\n",
7887 g_em->width, g_em->height, TILEX, TILEY);
7889 num_em_gfx_errors++;
7896 for (i = 0; i < TILE_MAX; i++)
7898 for (j = 0; j < 8; j++)
7900 int element = object_mapping[i].element_rnd;
7901 int action = object_mapping[i].action;
7902 int direction = object_mapping[i].direction;
7903 boolean is_backside = object_mapping[i].is_backside;
7904 int graphic_action = el_act_dir2img(element, action, direction);
7905 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
7907 if ((action == ACTION_SMASHED_BY_ROCK ||
7908 action == ACTION_SMASHED_BY_SPRING ||
7909 action == ACTION_EATING) &&
7910 graphic_action == graphic_default)
7912 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
7913 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
7914 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
7915 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
7918 /* no separate animation for "smashed by rock" -- use rock instead */
7919 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7920 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
7922 g_em->bitmap = g_xx->bitmap;
7923 g_em->src_x = g_xx->src_x;
7924 g_em->src_y = g_xx->src_y;
7925 g_em->src_offset_x = g_xx->src_offset_x;
7926 g_em->src_offset_y = g_xx->src_offset_y;
7927 g_em->dst_offset_x = g_xx->dst_offset_x;
7928 g_em->dst_offset_y = g_xx->dst_offset_y;
7929 g_em->width = g_xx->width;
7930 g_em->height = g_xx->height;
7931 g_em->unique_identifier = g_xx->unique_identifier;
7934 g_em->preserve_background = TRUE;
7939 for (p = 0; p < MAX_PLAYERS; p++)
7941 for (i = 0; i < SPR_MAX; i++)
7943 int element = player_mapping[p][i].element_rnd;
7944 int action = player_mapping[p][i].action;
7945 int direction = player_mapping[p][i].direction;
7947 for (j = 0; j < 8; j++)
7949 int effective_element = element;
7950 int effective_action = action;
7951 int graphic = (direction == MV_NONE ?
7952 el_act2img(effective_element, effective_action) :
7953 el_act_dir2img(effective_element, effective_action,
7955 struct GraphicInfo *g = &graphic_info[graphic];
7956 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
7962 Bitmap *debug_bitmap = g_em->bitmap;
7963 int debug_src_x = g_em->src_x;
7964 int debug_src_y = g_em->src_y;
7967 int frame = getAnimationFrame(g->anim_frames,
7970 g->anim_start_frame,
7973 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
7975 g_em->bitmap = src_bitmap;
7976 g_em->src_x = src_x;
7977 g_em->src_y = src_y;
7978 g_em->src_offset_x = 0;
7979 g_em->src_offset_y = 0;
7980 g_em->dst_offset_x = 0;
7981 g_em->dst_offset_y = 0;
7982 g_em->width = TILEX;
7983 g_em->height = TILEY;
7987 /* skip check for EMC elements not contained in original EMC artwork */
7988 if (element == EL_PLAYER_3 ||
7989 element == EL_PLAYER_4)
7992 if (g_em->bitmap != debug_bitmap ||
7993 g_em->src_x != debug_src_x ||
7994 g_em->src_y != debug_src_y)
7996 static int last_i = -1;
8004 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
8005 p, i, element, element_info[element].token_name,
8006 element_action_info[effective_action].suffix, direction);
8008 if (element != effective_element)
8009 printf(" [%d ('%s')]",
8011 element_info[effective_element].token_name);
8015 if (g_em->bitmap != debug_bitmap)
8016 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
8017 j, (int)(g_em->bitmap), (int)(debug_bitmap));
8019 if (g_em->src_x != debug_src_x ||
8020 g_em->src_y != debug_src_y)
8021 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
8023 g_em->src_x, g_em->src_y,
8024 g_em->src_x / 32, g_em->src_y / 32,
8025 debug_src_x, debug_src_y,
8026 debug_src_x / 32, debug_src_y / 32);
8028 num_em_gfx_errors++;
8038 printf("::: [%d errors found]\n", num_em_gfx_errors);
8044 void CheckSaveEngineSnapshot_EM(byte action[MAX_PLAYERS], int frame,
8045 boolean any_player_moving,
8046 boolean any_player_snapping,
8047 boolean any_player_dropping)
8049 static boolean player_was_waiting = TRUE;
8051 if (frame == 0 && !any_player_dropping)
8053 if (!player_was_waiting)
8055 if (!SaveEngineSnapshotToList())
8058 player_was_waiting = TRUE;
8061 else if (any_player_moving || any_player_snapping || any_player_dropping)
8063 player_was_waiting = FALSE;
8067 void CheckSaveEngineSnapshot_SP(boolean murphy_is_waiting,
8068 boolean murphy_is_dropping)
8070 static boolean player_was_waiting = TRUE;
8072 if (murphy_is_waiting)
8074 if (!player_was_waiting)
8076 if (!SaveEngineSnapshotToList())
8079 player_was_waiting = TRUE;
8084 player_was_waiting = FALSE;
8088 void CheckSingleStepMode_EM(byte action[MAX_PLAYERS], int frame,
8089 boolean any_player_moving,
8090 boolean any_player_snapping,
8091 boolean any_player_dropping)
8093 if (tape.single_step && tape.recording && !tape.pausing)
8094 if (frame == 0 && !any_player_dropping)
8095 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
8097 CheckSaveEngineSnapshot_EM(action, frame, any_player_moving,
8098 any_player_snapping, any_player_dropping);
8101 void CheckSingleStepMode_SP(boolean murphy_is_waiting,
8102 boolean murphy_is_dropping)
8104 if (tape.single_step && tape.recording && !tape.pausing)
8105 if (murphy_is_waiting)
8106 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
8108 CheckSaveEngineSnapshot_SP(murphy_is_waiting, murphy_is_dropping);
8111 void getGraphicSource_SP(struct GraphicInfo_SP *g_sp,
8112 int graphic, int sync_frame, int x, int y)
8114 int frame = getGraphicAnimationFrame(graphic, sync_frame);
8116 getGraphicSource(graphic, frame, &g_sp->bitmap, &g_sp->src_x, &g_sp->src_y);
8119 boolean isNextAnimationFrame_SP(int graphic, int sync_frame)
8121 return (IS_NEXT_FRAME(sync_frame, graphic));
8124 int getGraphicInfo_Delay(int graphic)
8126 return graphic_info[graphic].anim_delay;
8129 void PlayMenuSoundExt(int sound)
8131 if (sound == SND_UNDEFINED)
8134 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8135 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8138 if (IS_LOOP_SOUND(sound))
8139 PlaySoundLoop(sound);
8144 void PlayMenuSound()
8146 PlayMenuSoundExt(menu.sound[game_status]);
8149 void PlayMenuSoundStereo(int sound, int stereo_position)
8151 if (sound == SND_UNDEFINED)
8154 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8155 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8158 if (IS_LOOP_SOUND(sound))
8159 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
8161 PlaySoundStereo(sound, stereo_position);
8164 void PlayMenuSoundIfLoopExt(int sound)
8166 if (sound == SND_UNDEFINED)
8169 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8170 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8173 if (IS_LOOP_SOUND(sound))
8174 PlaySoundLoop(sound);
8177 void PlayMenuSoundIfLoop()
8179 PlayMenuSoundIfLoopExt(menu.sound[game_status]);
8182 void PlayMenuMusicExt(int music)
8184 if (music == MUS_UNDEFINED)
8187 if (!setup.sound_music)
8193 void PlayMenuMusic()
8195 PlayMenuMusicExt(menu.music[game_status]);
8198 void PlaySoundActivating()
8201 PlaySound(SND_MENU_ITEM_ACTIVATING);
8205 void PlaySoundSelecting()
8208 PlaySound(SND_MENU_ITEM_SELECTING);
8212 void ToggleFullscreenOrChangeWindowScalingIfNeeded()
8214 boolean change_fullscreen = (setup.fullscreen !=
8215 video.fullscreen_enabled);
8216 boolean change_window_scaling_percent = (!video.fullscreen_enabled &&
8217 setup.window_scaling_percent !=
8218 video.window_scaling_percent);
8220 if (change_window_scaling_percent && video.fullscreen_enabled)
8223 if (!change_window_scaling_percent && !video.fullscreen_available)
8226 #if defined(TARGET_SDL2)
8227 if (change_window_scaling_percent)
8229 SDLSetWindowScaling(setup.window_scaling_percent);
8233 else if (change_fullscreen)
8235 SDLSetWindowFullscreen(setup.fullscreen);
8237 /* set setup value according to successfully changed fullscreen mode */
8238 setup.fullscreen = video.fullscreen_enabled;
8244 if (change_fullscreen ||
8245 change_window_scaling_percent)
8247 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
8249 /* save backbuffer content which gets lost when toggling fullscreen mode */
8250 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8252 if (change_window_scaling_percent)
8254 /* keep window mode, but change window scaling */
8255 video.fullscreen_enabled = TRUE; /* force new window scaling */
8258 /* toggle fullscreen */
8259 ChangeVideoModeIfNeeded(setup.fullscreen);
8261 /* set setup value according to successfully changed fullscreen mode */
8262 setup.fullscreen = video.fullscreen_enabled;
8264 /* restore backbuffer content from temporary backbuffer backup bitmap */
8265 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8267 FreeBitmap(tmp_backbuffer);
8269 /* update visible window/screen */
8270 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8274 void JoinRectangles(int *x, int *y, int *width, int *height,
8275 int x2, int y2, int width2, int height2)
8277 // do not join with "off-screen" rectangle
8278 if (x2 == -1 || y2 == -1)
8283 *width = MAX(*width, width2);
8284 *height = MAX(*height, height2);
8287 void SetAnimStatus(int anim_status_new)
8289 if (anim_status_new == GAME_MODE_MAIN)
8290 anim_status_new = GAME_MODE_PSEUDO_MAINONLY;
8292 global.anim_status_next = anim_status_new;
8294 // directly set screen modes that are entered without fading
8295 if ((global.anim_status == GAME_MODE_PSEUDO_MAINONLY &&
8296 global.anim_status_next == GAME_MODE_PSEUDO_TYPENAME) ||
8297 (global.anim_status == GAME_MODE_PSEUDO_TYPENAME &&
8298 global.anim_status_next == GAME_MODE_PSEUDO_MAINONLY))
8299 global.anim_status = global.anim_status_next;
8302 void SetGameStatus(int game_status_new)
8304 game_status = game_status_new;
8306 SetAnimStatus(game_status_new);
8309 void SetFontStatus(int game_status_new)
8311 static int last_game_status = -1;
8313 if (game_status_new != -1)
8315 // set game status for font use after storing last game status
8316 last_game_status = game_status;
8317 game_status = game_status_new;
8321 // reset game status after font use from last stored game status
8322 game_status = last_game_status;
8326 void ResetFontStatus()
8331 void ChangeViewportPropertiesIfNeeded()
8333 int gfx_game_mode = game_status;
8334 int gfx_game_mode2 = (game_status == GAME_MODE_EDITOR ? GAME_MODE_DEFAULT :
8336 struct RectWithBorder *vp_window = &viewport.window[gfx_game_mode];
8337 struct RectWithBorder *vp_playfield = &viewport.playfield[gfx_game_mode];
8338 struct RectWithBorder *vp_door_1 = &viewport.door_1[gfx_game_mode];
8339 struct RectWithBorder *vp_door_2 = &viewport.door_2[gfx_game_mode2];
8340 struct RectWithBorder *vp_door_3 = &viewport.door_2[GAME_MODE_EDITOR];
8341 int new_win_xsize = vp_window->width;
8342 int new_win_ysize = vp_window->height;
8343 int border_size = vp_playfield->border_size;
8344 int new_sx = vp_playfield->x + border_size;
8345 int new_sy = vp_playfield->y + border_size;
8346 int new_sxsize = vp_playfield->width - 2 * border_size;
8347 int new_sysize = vp_playfield->height - 2 * border_size;
8348 int new_real_sx = vp_playfield->x;
8349 int new_real_sy = vp_playfield->y;
8350 int new_full_sxsize = vp_playfield->width;
8351 int new_full_sysize = vp_playfield->height;
8352 int new_dx = vp_door_1->x;
8353 int new_dy = vp_door_1->y;
8354 int new_dxsize = vp_door_1->width;
8355 int new_dysize = vp_door_1->height;
8356 int new_vx = vp_door_2->x;
8357 int new_vy = vp_door_2->y;
8358 int new_vxsize = vp_door_2->width;
8359 int new_vysize = vp_door_2->height;
8360 int new_ex = vp_door_3->x;
8361 int new_ey = vp_door_3->y;
8362 int new_exsize = vp_door_3->width;
8363 int new_eysize = vp_door_3->height;
8364 int new_tilesize_var =
8365 (setup.small_game_graphics ? MINI_TILESIZE : game.tile_size);
8367 int tilesize = (gfx_game_mode == GAME_MODE_PLAYING ? new_tilesize_var :
8368 gfx_game_mode == GAME_MODE_EDITOR ? MINI_TILESIZE : TILESIZE);
8369 int new_scr_fieldx = new_sxsize / tilesize;
8370 int new_scr_fieldy = new_sysize / tilesize;
8371 int new_scr_fieldx_buffers = new_sxsize / new_tilesize_var;
8372 int new_scr_fieldy_buffers = new_sysize / new_tilesize_var;
8373 boolean init_gfx_buffers = FALSE;
8374 boolean init_video_buffer = FALSE;
8375 boolean init_gadgets_and_anims = FALSE;
8376 boolean init_em_graphics = FALSE;
8378 if (new_win_xsize != WIN_XSIZE ||
8379 new_win_ysize != WIN_YSIZE)
8381 WIN_XSIZE = new_win_xsize;
8382 WIN_YSIZE = new_win_ysize;
8384 init_video_buffer = TRUE;
8385 init_gfx_buffers = TRUE;
8386 init_gadgets_and_anims = TRUE;
8388 // printf("::: video: init_video_buffer, init_gfx_buffers\n");
8391 if (new_scr_fieldx != SCR_FIELDX ||
8392 new_scr_fieldy != SCR_FIELDY)
8394 /* this always toggles between MAIN and GAME when using small tile size */
8396 SCR_FIELDX = new_scr_fieldx;
8397 SCR_FIELDY = new_scr_fieldy;
8399 // printf("::: new_scr_fieldx != SCR_FIELDX ...\n");
8410 new_sxsize != SXSIZE ||
8411 new_sysize != SYSIZE ||
8412 new_dxsize != DXSIZE ||
8413 new_dysize != DYSIZE ||
8414 new_vxsize != VXSIZE ||
8415 new_vysize != VYSIZE ||
8416 new_exsize != EXSIZE ||
8417 new_eysize != EYSIZE ||
8418 new_real_sx != REAL_SX ||
8419 new_real_sy != REAL_SY ||
8420 new_full_sxsize != FULL_SXSIZE ||
8421 new_full_sysize != FULL_SYSIZE ||
8422 new_tilesize_var != TILESIZE_VAR
8425 // ------------------------------------------------------------------------
8426 // determine next fading area for changed viewport definitions
8427 // ------------------------------------------------------------------------
8429 // start with current playfield area (default fading area)
8432 FADE_SXSIZE = FULL_SXSIZE;
8433 FADE_SYSIZE = FULL_SYSIZE;
8435 // add new playfield area if position or size has changed
8436 if (new_real_sx != REAL_SX || new_real_sy != REAL_SY ||
8437 new_full_sxsize != FULL_SXSIZE || new_full_sysize != FULL_SYSIZE)
8439 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
8440 new_real_sx, new_real_sy, new_full_sxsize,new_full_sysize);
8443 // add current and new door 1 area if position or size has changed
8444 if (new_dx != DX || new_dy != DY ||
8445 new_dxsize != DXSIZE || new_dysize != DYSIZE)
8447 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
8448 DX, DY, DXSIZE, DYSIZE);
8449 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
8450 new_dx, new_dy, new_dxsize, new_dysize);
8453 // add current and new door 2 area if position or size has changed
8454 if (new_dx != VX || new_dy != VY ||
8455 new_dxsize != VXSIZE || new_dysize != VYSIZE)
8457 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
8458 VX, VY, VXSIZE, VYSIZE);
8459 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
8460 new_vx, new_vy, new_vxsize, new_vysize);
8463 // ------------------------------------------------------------------------
8464 // handle changed tile size
8465 // ------------------------------------------------------------------------
8467 if (new_tilesize_var != TILESIZE_VAR)
8469 // printf("::: new_tilesize_var != TILESIZE_VAR\n");
8471 // changing tile size invalidates scroll values of engine snapshots
8472 FreeEngineSnapshotSingle();
8474 // changing tile size requires update of graphic mapping for EM engine
8475 init_em_graphics = TRUE;
8486 SXSIZE = new_sxsize;
8487 SYSIZE = new_sysize;
8488 DXSIZE = new_dxsize;
8489 DYSIZE = new_dysize;
8490 VXSIZE = new_vxsize;
8491 VYSIZE = new_vysize;
8492 EXSIZE = new_exsize;
8493 EYSIZE = new_eysize;
8494 REAL_SX = new_real_sx;
8495 REAL_SY = new_real_sy;
8496 FULL_SXSIZE = new_full_sxsize;
8497 FULL_SYSIZE = new_full_sysize;
8498 TILESIZE_VAR = new_tilesize_var;
8500 init_gfx_buffers = TRUE;
8501 init_gadgets_and_anims = TRUE;
8503 // printf("::: viewports: init_gfx_buffers\n");
8504 // printf("::: viewports: init_gadgets_and_anims\n");
8507 if (init_gfx_buffers)
8509 // printf("::: init_gfx_buffers\n");
8511 SCR_FIELDX = new_scr_fieldx_buffers;
8512 SCR_FIELDY = new_scr_fieldy_buffers;
8516 SCR_FIELDX = new_scr_fieldx;
8517 SCR_FIELDY = new_scr_fieldy;
8519 SetDrawDeactivationMask(REDRAW_NONE);
8520 SetDrawBackgroundMask(REDRAW_FIELD);
8523 if (init_video_buffer)
8525 // printf("::: init_video_buffer\n");
8527 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
8528 InitImageTextures();
8531 if (init_gadgets_and_anims)
8533 // printf("::: init_gadgets_and_anims\n");
8536 InitGlobalAnimations();
8539 if (init_em_graphics)
8541 InitGraphicInfo_EM();