1 // ============================================================================
2 // Rocks'n'Diamonds - McDuffin Strikes Back!
3 // ----------------------------------------------------------------------------
4 // (c) 1995-2014 by Artsoft Entertainment
7 // http://www.artsoft.org/
8 // ----------------------------------------------------------------------------
10 // ============================================================================
14 #include "libgame/libgame.h"
26 /* select level set with EMC X11 graphics before activating EM GFX debugging */
27 #define DEBUG_EM_GFX FALSE
28 #define DEBUG_FRAME_TIME FALSE
30 /* tool button identifiers */
31 #define TOOL_CTRL_ID_YES 0
32 #define TOOL_CTRL_ID_NO 1
33 #define TOOL_CTRL_ID_CONFIRM 2
34 #define TOOL_CTRL_ID_PLAYER_1 3
35 #define TOOL_CTRL_ID_PLAYER_2 4
36 #define TOOL_CTRL_ID_PLAYER_3 5
37 #define TOOL_CTRL_ID_PLAYER_4 6
39 #define NUM_TOOL_BUTTONS 7
41 /* constants for number of doors and door parts */
43 #define NUM_PANELS NUM_DOORS
44 // #define NUM_PANELS 0
45 #define MAX_PARTS_PER_DOOR 8
46 #define MAX_DOOR_PARTS (NUM_DOORS * MAX_PARTS_PER_DOOR + NUM_PANELS)
47 #define DOOR_PART_IS_PANEL(i) ((i) >= NUM_DOORS * MAX_PARTS_PER_DOOR)
50 struct DoorPartOrderInfo
56 static struct DoorPartOrderInfo door_part_order[MAX_DOOR_PARTS];
58 struct DoorPartControlInfo
62 struct DoorPartPosInfo *pos;
65 static struct DoorPartControlInfo door_part_controls[] =
69 IMG_GFX_DOOR_1_PART_1,
74 IMG_GFX_DOOR_1_PART_2,
79 IMG_GFX_DOOR_1_PART_3,
84 IMG_GFX_DOOR_1_PART_4,
89 IMG_GFX_DOOR_1_PART_5,
94 IMG_GFX_DOOR_1_PART_6,
99 IMG_GFX_DOOR_1_PART_7,
104 IMG_GFX_DOOR_1_PART_8,
110 IMG_GFX_DOOR_2_PART_1,
115 IMG_GFX_DOOR_2_PART_2,
120 IMG_GFX_DOOR_2_PART_3,
125 IMG_GFX_DOOR_2_PART_4,
130 IMG_GFX_DOOR_2_PART_5,
135 IMG_GFX_DOOR_2_PART_6,
140 IMG_GFX_DOOR_2_PART_7,
145 IMG_GFX_DOOR_2_PART_8,
151 IMG_BACKGROUND_PANEL,
168 /* forward declaration for internal use */
169 static void UnmapToolButtons();
170 static void HandleToolButtons(struct GadgetInfo *);
171 static int el_act_dir2crm(int, int, int);
172 static int el_act2crm(int, int);
174 static struct GadgetInfo *tool_gadget[NUM_TOOL_BUTTONS];
175 static int request_gadget_id = -1;
177 static char *print_if_not_empty(int element)
179 static char *s = NULL;
180 char *token_name = element_info[element].token_name;
185 s = checked_malloc(strlen(token_name) + 10 + 1);
187 if (element != EL_EMPTY)
188 sprintf(s, "%d\t['%s']", element, token_name);
190 sprintf(s, "%d", element);
195 void DumpTile(int x, int y)
200 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
206 printf_line("-", 79);
207 printf("Field Info: SCREEN(%d, %d), LEVEL(%d, %d)\n", sx, sy, x, y);
208 printf_line("-", 79);
210 if (!IN_LEV_FIELD(x, y))
212 printf("(not in level field)\n");
218 printf(" Feld: %d\t['%s']\n", Feld[x][y],
219 element_info[Feld[x][y]].token_name);
220 printf(" Back: %s\n", print_if_not_empty(Back[x][y]));
221 printf(" Store: %s\n", print_if_not_empty(Store[x][y]));
222 printf(" Store2: %s\n", print_if_not_empty(Store2[x][y]));
223 printf(" StorePlayer: %s\n", print_if_not_empty(StorePlayer[x][y]));
224 printf(" MovPos: %d\n", MovPos[x][y]);
225 printf(" MovDir: %d\n", MovDir[x][y]);
226 printf(" MovDelay: %d\n", MovDelay[x][y]);
227 printf(" ChangeDelay: %d\n", ChangeDelay[x][y]);
228 printf(" CustomValue: %d\n", CustomValue[x][y]);
229 printf(" GfxElement: %d\n", GfxElement[x][y]);
230 printf(" GfxAction: %d\n", GfxAction[x][y]);
231 printf(" GfxFrame: %d [%d]\n", GfxFrame[x][y], FrameCounter);
235 void SetDrawtoField(int mode)
237 if (mode == DRAW_TO_FIELDBUFFER)
243 BX2 = SCR_FIELDX + 1;
244 BY2 = SCR_FIELDY + 1;
246 drawto_field = fieldbuffer;
248 else /* DRAW_TO_BACKBUFFER */
254 BX2 = SCR_FIELDX - 1;
255 BY2 = SCR_FIELDY - 1;
257 drawto_field = backbuffer;
261 static void RedrawPlayfield_RND()
263 if (game.envelope_active)
266 DrawLevel(REDRAW_ALL);
270 void RedrawPlayfield()
272 if (game_status != GAME_MODE_PLAYING)
275 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
276 RedrawPlayfield_EM(TRUE);
277 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
278 RedrawPlayfield_SP(TRUE);
279 else if (level.game_engine_type == GAME_ENGINE_TYPE_RND)
280 RedrawPlayfield_RND();
282 BlitScreenToBitmap(backbuffer);
284 BlitBitmap(drawto, window, gfx.sx, gfx.sy, gfx.sxsize, gfx.sysize,
288 static void DrawMaskedBorderExt_Rect(int x, int y, int width, int height,
291 Bitmap *src_bitmap = getGlobalBorderBitmapFromStatus(global.border_status);
292 Bitmap *dst_bitmap = gfx.masked_border_bitmap_ptr;
294 if (x == -1 && y == -1)
297 if (draw_target == DRAW_TO_SCREEN)
298 BlitToScreenMasked(src_bitmap, x, y, width, height, x, y);
300 BlitBitmapMasked(src_bitmap, dst_bitmap, x, y, width, height, x, y);
303 static void DrawMaskedBorderExt_FIELD(int draw_target)
305 if (global.border_status >= GAME_MODE_MAIN &&
306 global.border_status <= GAME_MODE_PLAYING &&
307 border.draw_masked[global.border_status])
308 DrawMaskedBorderExt_Rect(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
312 static void DrawMaskedBorderExt_DOOR_1(int draw_target)
314 // when drawing to backbuffer, never draw border over open doors
315 if (draw_target == DRAW_TO_BACKBUFFER &&
316 (GetDoorState() & DOOR_OPEN_1))
319 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
320 (global.border_status != GAME_MODE_EDITOR ||
321 border.draw_masked[GFX_SPECIAL_ARG_EDITOR]))
322 DrawMaskedBorderExt_Rect(DX, DY, DXSIZE, DYSIZE, draw_target);
325 static void DrawMaskedBorderExt_DOOR_2(int draw_target)
327 // when drawing to backbuffer, never draw border over open doors
328 if (draw_target == DRAW_TO_BACKBUFFER &&
329 (GetDoorState() & DOOR_OPEN_2))
332 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
333 global.border_status != GAME_MODE_EDITOR)
334 DrawMaskedBorderExt_Rect(VX, VY, VXSIZE, VYSIZE, draw_target);
337 static void DrawMaskedBorderExt_DOOR_3(int draw_target)
339 /* currently not available */
342 static void DrawMaskedBorderExt_ALL(int draw_target)
344 DrawMaskedBorderExt_FIELD(draw_target);
345 DrawMaskedBorderExt_DOOR_1(draw_target);
346 DrawMaskedBorderExt_DOOR_2(draw_target);
347 DrawMaskedBorderExt_DOOR_3(draw_target);
350 static void DrawMaskedBorderExt(int redraw_mask, int draw_target)
352 /* never draw masked screen borders on borderless screens */
353 if (global.border_status == GAME_MODE_LOADING ||
354 global.border_status == GAME_MODE_TITLE)
357 if (redraw_mask & REDRAW_ALL)
358 DrawMaskedBorderExt_ALL(draw_target);
361 if (redraw_mask & REDRAW_FIELD)
362 DrawMaskedBorderExt_FIELD(draw_target);
363 if (redraw_mask & REDRAW_DOOR_1)
364 DrawMaskedBorderExt_DOOR_1(draw_target);
365 if (redraw_mask & REDRAW_DOOR_2)
366 DrawMaskedBorderExt_DOOR_2(draw_target);
367 if (redraw_mask & REDRAW_DOOR_3)
368 DrawMaskedBorderExt_DOOR_3(draw_target);
372 void DrawMaskedBorder_FIELD()
374 DrawMaskedBorderExt_FIELD(DRAW_TO_BACKBUFFER);
377 void DrawMaskedBorder(int redraw_mask)
379 DrawMaskedBorderExt(redraw_mask, DRAW_TO_BACKBUFFER);
382 void DrawMaskedBorderToTarget(int draw_target)
384 if (draw_target == DRAW_TO_BACKBUFFER ||
385 draw_target == DRAW_TO_SCREEN)
387 DrawMaskedBorderExt(REDRAW_ALL, draw_target);
391 int last_border_status = global.border_status;
393 if (draw_target == DRAW_TO_FADE_SOURCE)
395 global.border_status = gfx.fade_border_source_status;
396 gfx.masked_border_bitmap_ptr = gfx.fade_bitmap_source;
398 else if (draw_target == DRAW_TO_FADE_TARGET)
400 global.border_status = gfx.fade_border_target_status;
401 gfx.masked_border_bitmap_ptr = gfx.fade_bitmap_target;
404 DrawMaskedBorderExt(REDRAW_ALL, draw_target);
406 global.border_status = last_border_status;
407 gfx.masked_border_bitmap_ptr = backbuffer;
411 void BlitScreenToBitmap_RND(Bitmap *target_bitmap)
413 int fx = FX, fy = FY;
414 int full_lev_fieldx = lev_fieldx + (BorderElement != EL_EMPTY ? 2 : 0);
415 int full_lev_fieldy = lev_fieldy + (BorderElement != EL_EMPTY ? 2 : 0);
417 int dx = (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
418 int dy = (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
419 int dx_var = dx * TILESIZE_VAR / TILESIZE;
420 int dy_var = dy * TILESIZE_VAR / TILESIZE;
423 ffx = (scroll_x - SBX_Left) * TILEX_VAR + dx_var;
424 ffy = (scroll_y - SBY_Upper) * TILEY_VAR + dy_var;
426 if (EVEN(SCR_FIELDX))
428 if (ffx < SBX_Right * TILEX_VAR + TILEX_VAR / 2 + TILEX_VAR)
429 fx += dx_var - MIN(ffx, TILEX_VAR / 2) + TILEX_VAR;
431 fx += (dx_var > 0 ? TILEX_VAR : 0);
438 if (EVEN(SCR_FIELDY))
440 if (ffy < SBY_Lower * TILEY_VAR + TILEY_VAR / 2 + TILEY_VAR)
441 fy += dy_var - MIN(ffy, TILEY_VAR / 2) + TILEY_VAR;
443 fy += (dy_var > 0 ? TILEY_VAR : 0);
450 if (full_lev_fieldx <= SCR_FIELDX)
452 if (EVEN(SCR_FIELDX))
453 fx = 2 * TILEX_VAR - (ODD(lev_fieldx) ? TILEX_VAR / 2 : 0);
455 fx = 2 * TILEX_VAR - (EVEN(lev_fieldx) ? TILEX_VAR / 2 : 0);
458 if (full_lev_fieldy <= SCR_FIELDY)
460 if (EVEN(SCR_FIELDY))
461 fy = 2 * TILEY_VAR - (ODD(lev_fieldy) ? TILEY_VAR / 2 : 0);
463 fy = 2 * TILEY_VAR - (EVEN(lev_fieldy) ? TILEY_VAR / 2 : 0);
466 BlitBitmap(drawto_field, target_bitmap, fx, fy, SXSIZE, SYSIZE, SX, SY);
469 void BlitScreenToBitmap(Bitmap *target_bitmap)
471 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
472 BlitScreenToBitmap_EM(target_bitmap);
473 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
474 BlitScreenToBitmap_SP(target_bitmap);
475 else if (level.game_engine_type == GAME_ENGINE_TYPE_RND)
476 BlitScreenToBitmap_RND(target_bitmap);
478 redraw_mask |= REDRAW_FIELD;
481 void DrawFramesPerSecond()
484 int font_nr = FONT_TEXT_2;
485 int font_width = getFontWidth(font_nr);
487 sprintf(text, "%04.1f fps", global.frames_per_second);
489 DrawTextExt(backbuffer, WIN_XSIZE - font_width * strlen(text), 0, text,
490 font_nr, BLIT_OPAQUE);
494 static void PrintFrameTimeDebugging()
496 static unsigned int last_counter = 0;
497 unsigned int counter = Counter();
498 int diff_1 = counter - last_counter;
499 int diff_2 = diff_1 - GAME_FRAME_DELAY;
501 int diff_2_cut = MIN(ABS(diff_2), diff_2_max);
502 char diff_bar[2 * diff_2_max + 5];
506 diff_bar[pos++] = (diff_2 < -diff_2_max ? '<' : ' ');
508 for (i = 0; i < diff_2_max; i++)
509 diff_bar[pos++] = (diff_2 >= 0 ? ' ' :
510 i >= diff_2_max - diff_2_cut ? '-' : ' ');
512 diff_bar[pos++] = '|';
514 for (i = 0; i < diff_2_max; i++)
515 diff_bar[pos++] = (diff_2 <= 0 ? ' ' : i < diff_2_cut ? '+' : ' ');
517 diff_bar[pos++] = (diff_2 > diff_2_max ? '>' : ' ');
519 diff_bar[pos++] = '\0';
521 Error(ERR_INFO, "%06d [%02d] [%c%02d] %s",
524 (diff_2 < 0 ? '-' : diff_2 > 0 ? '+' : ' '), ABS(diff_2),
527 last_counter = counter;
531 static int unifiedRedrawMask(int mask)
533 if (mask & REDRAW_ALL)
536 if (mask & REDRAW_FIELD && mask & REDRAW_DOORS)
542 static boolean equalRedrawMasks(int mask_1, int mask_2)
544 return unifiedRedrawMask(mask_1) == unifiedRedrawMask(mask_2);
549 static int last_redraw_mask = REDRAW_NONE;
551 // force screen redraw in every frame to continue drawing global animations
552 // (but always use the last redraw mask to prevent unwanted side effects)
553 if (redraw_mask == REDRAW_NONE)
554 redraw_mask = last_redraw_mask;
556 last_redraw_mask = redraw_mask;
559 // masked border now drawn immediately when blitting backbuffer to window
561 // draw masked border to all viewports, if defined
562 DrawMaskedBorder(redraw_mask);
565 // draw frames per second (only if debug mode is enabled)
566 if (redraw_mask & REDRAW_FPS)
567 DrawFramesPerSecond();
569 // remove playfield redraw before potentially merging with doors redraw
570 if (DrawingDeactivated(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE))
571 redraw_mask &= ~REDRAW_FIELD;
573 // redraw complete window if both playfield and (some) doors need redraw
574 if (redraw_mask & REDRAW_FIELD && redraw_mask & REDRAW_DOORS)
575 redraw_mask = REDRAW_ALL;
577 /* although redrawing the whole window would be fine for normal gameplay,
578 being able to only redraw the playfield is required for deactivating
579 certain drawing areas (mainly playfield) to work, which is needed for
580 warp-forward to be fast enough (by skipping redraw of most frames) */
582 if (redraw_mask & REDRAW_ALL)
584 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
586 else if (redraw_mask & REDRAW_FIELD)
588 BlitBitmap(backbuffer, window,
589 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
591 else if (redraw_mask & REDRAW_DOORS)
593 // merge door areas to prevent calling screen redraw more than once
599 if (redraw_mask & REDRAW_DOOR_1)
603 x2 = MAX(x2, DX + DXSIZE);
604 y2 = MAX(y2, DY + DYSIZE);
607 if (redraw_mask & REDRAW_DOOR_2)
611 x2 = MAX(x2, VX + VXSIZE);
612 y2 = MAX(y2, VY + VYSIZE);
615 if (redraw_mask & REDRAW_DOOR_3)
619 x2 = MAX(x2, EX + EXSIZE);
620 y2 = MAX(y2, EY + EYSIZE);
623 BlitBitmap(backbuffer, window, x1, y1, x2 - x1, y2 - y1, x1, y1);
626 redraw_mask = REDRAW_NONE;
629 PrintFrameTimeDebugging();
633 void BackToFront_WithFrameDelay(unsigned int frame_delay_value)
635 unsigned int frame_delay_value_old = GetVideoFrameDelay();
637 SetVideoFrameDelay(frame_delay_value);
641 SetVideoFrameDelay(frame_delay_value_old);
644 static int fade_type_skip = FADE_TYPE_NONE;
646 static void FadeExt(int fade_mask, int fade_mode, int fade_type)
648 void (*draw_border_function)(void) = NULL;
649 int x, y, width, height;
650 int fade_delay, post_delay;
652 if (fade_type == FADE_TYPE_FADE_OUT)
654 if (fade_type_skip != FADE_TYPE_NONE)
656 /* skip all fade operations until specified fade operation */
657 if (fade_type & fade_type_skip)
658 fade_type_skip = FADE_TYPE_NONE;
663 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
667 redraw_mask |= fade_mask;
669 if (fade_type == FADE_TYPE_SKIP)
671 fade_type_skip = fade_mode;
676 fade_delay = fading.fade_delay;
677 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
679 if (fade_type_skip != FADE_TYPE_NONE)
681 /* skip all fade operations until specified fade operation */
682 if (fade_type & fade_type_skip)
683 fade_type_skip = FADE_TYPE_NONE;
688 if (global.autoplay_leveldir)
693 if (fade_mask == REDRAW_FIELD)
698 height = FADE_SYSIZE;
700 if (border.draw_masked_when_fading)
701 draw_border_function = DrawMaskedBorder_FIELD; /* update when fading */
703 DrawMaskedBorder_FIELD(); /* draw once */
705 else /* REDRAW_ALL */
713 if (!setup.fade_screens ||
715 fading.fade_mode == FADE_MODE_NONE)
717 if (fade_mode == FADE_MODE_FADE_OUT)
720 BlitBitmap(backbuffer, window, x, y, width, height, x, y);
722 redraw_mask &= ~fade_mask;
727 FadeRectangle(x, y, width, height, fade_mode, fade_delay, post_delay,
728 draw_border_function);
730 redraw_mask &= ~fade_mask;
733 static void SetScreenStates_BeforeFadingIn()
735 // temporarily set screen mode for animations to screen after fading in
736 global.anim_status = global.anim_status_next;
738 // store backbuffer with all animations that will be started after fading in
739 if (fade_type_skip != FADE_MODE_SKIP_FADE_IN)
740 PrepareFadeBitmap(DRAW_TO_FADE_TARGET);
742 // set screen mode for animations back to fading
743 global.anim_status = GAME_MODE_PSEUDO_FADING;
746 static void SetScreenStates_AfterFadingIn()
748 // store new source screen (to use correct masked border for fading)
749 gfx.fade_border_source_status = global.border_status;
751 global.anim_status = global.anim_status_next;
754 static void SetScreenStates_BeforeFadingOut()
756 // store new target screen (to use correct masked border for fading)
757 gfx.fade_border_target_status = game_status;
759 // set screen mode for animations to fading
760 global.anim_status = GAME_MODE_PSEUDO_FADING;
762 // store backbuffer with all animations that will be stopped for fading out
763 if (fade_type_skip != FADE_MODE_SKIP_FADE_OUT)
764 PrepareFadeBitmap(DRAW_TO_FADE_SOURCE);
767 static void SetScreenStates_AfterFadingOut()
769 global.border_status = game_status;
772 void FadeIn(int fade_mask)
774 SetScreenStates_BeforeFadingIn();
777 DrawMaskedBorder(REDRAW_ALL);
780 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
781 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_IN);
783 FadeExt(fade_mask, FADE_MODE_FADE_IN, FADE_TYPE_FADE_IN);
787 FADE_SXSIZE = FULL_SXSIZE;
788 FADE_SYSIZE = FULL_SYSIZE;
790 SetScreenStates_AfterFadingIn();
792 // force update of global animation status in case of rapid screen changes
793 redraw_mask = REDRAW_ALL;
797 void FadeOut(int fade_mask)
799 // update screen if areas covered by "fade_mask" and "redraw_mask" differ
800 if (!equalRedrawMasks(fade_mask, redraw_mask))
803 SetScreenStates_BeforeFadingOut();
806 DrawMaskedBorder(REDRAW_ALL);
809 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
810 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_OUT);
812 FadeExt(fade_mask, FADE_MODE_FADE_OUT, FADE_TYPE_FADE_OUT);
814 SetScreenStates_AfterFadingOut();
817 static void FadeSetLeaveNext(struct TitleFadingInfo fading_leave, boolean set)
819 static struct TitleFadingInfo fading_leave_stored;
822 fading_leave_stored = fading_leave;
824 fading = fading_leave_stored;
827 void FadeSetEnterMenu()
829 fading = menu.enter_menu;
831 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
834 void FadeSetLeaveMenu()
836 fading = menu.leave_menu;
838 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
841 void FadeSetEnterScreen()
843 fading = menu.enter_screen[game_status];
845 FadeSetLeaveNext(menu.leave_screen[game_status], TRUE); /* store */
848 void FadeSetNextScreen()
850 fading = menu.next_screen[game_status];
852 // (do not overwrite fade mode set by FadeSetEnterScreen)
853 // FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
856 void FadeSetLeaveScreen()
858 FadeSetLeaveNext(menu.leave_screen[game_status], FALSE); /* recall */
861 void FadeSetFromType(int type)
863 if (type & TYPE_ENTER_SCREEN)
864 FadeSetEnterScreen();
865 else if (type & TYPE_ENTER)
867 else if (type & TYPE_LEAVE)
871 void FadeSetDisabled()
873 static struct TitleFadingInfo fading_none = { FADE_MODE_NONE, -1, -1, -1 };
875 fading = fading_none;
878 void FadeSkipNextFadeIn()
880 FadeExt(0, FADE_MODE_SKIP_FADE_IN, FADE_TYPE_SKIP);
883 void FadeSkipNextFadeOut()
885 FadeExt(0, FADE_MODE_SKIP_FADE_OUT, FADE_TYPE_SKIP);
888 Bitmap *getBitmapFromGraphicOrDefault(int graphic, int default_graphic)
890 boolean redefined = getImageListEntryFromImageID(graphic)->redefined;
892 return (graphic == IMG_UNDEFINED ? NULL :
893 graphic_info[graphic].bitmap != NULL || redefined ?
894 graphic_info[graphic].bitmap :
895 graphic_info[default_graphic].bitmap);
898 Bitmap *getBackgroundBitmap(int graphic)
900 return getBitmapFromGraphicOrDefault(graphic, IMG_BACKGROUND);
903 Bitmap *getGlobalBorderBitmap(int graphic)
905 return getBitmapFromGraphicOrDefault(graphic, IMG_GLOBAL_BORDER);
908 Bitmap *getGlobalBorderBitmapFromStatus(int status)
911 (status == GAME_MODE_MAIN ||
912 status == GAME_MODE_PSEUDO_TYPENAME ? IMG_GLOBAL_BORDER_MAIN :
913 status == GAME_MODE_SCORES ? IMG_GLOBAL_BORDER_SCORES :
914 status == GAME_MODE_EDITOR ? IMG_GLOBAL_BORDER_EDITOR :
915 status == GAME_MODE_PLAYING ? IMG_GLOBAL_BORDER_PLAYING :
918 return getGlobalBorderBitmap(graphic);
921 void SetWindowBackgroundImageIfDefined(int graphic)
923 if (graphic_info[graphic].bitmap)
924 SetWindowBackgroundBitmap(graphic_info[graphic].bitmap);
927 void SetMainBackgroundImageIfDefined(int graphic)
929 if (graphic_info[graphic].bitmap)
930 SetMainBackgroundBitmap(graphic_info[graphic].bitmap);
933 void SetDoorBackgroundImageIfDefined(int graphic)
935 if (graphic_info[graphic].bitmap)
936 SetDoorBackgroundBitmap(graphic_info[graphic].bitmap);
939 void SetWindowBackgroundImage(int graphic)
941 SetWindowBackgroundBitmap(getBackgroundBitmap(graphic));
944 void SetMainBackgroundImage(int graphic)
946 SetMainBackgroundBitmap(getBackgroundBitmap(graphic));
949 void SetDoorBackgroundImage(int graphic)
951 SetDoorBackgroundBitmap(getBackgroundBitmap(graphic));
954 void SetPanelBackground()
956 struct GraphicInfo *gfx = &graphic_info[IMG_BACKGROUND_PANEL];
958 BlitBitmapTiled(gfx->bitmap, bitmap_db_panel, gfx->src_x, gfx->src_y,
959 gfx->width, gfx->height, 0, 0, DXSIZE, DYSIZE);
961 SetDoorBackgroundBitmap(bitmap_db_panel);
964 void DrawBackground(int x, int y, int width, int height)
966 /* "drawto" might still point to playfield buffer here (hall of fame) */
967 ClearRectangleOnBackground(backbuffer, x, y, width, height);
969 if (IN_GFX_FIELD_FULL(x, y))
970 redraw_mask |= REDRAW_FIELD;
971 else if (IN_GFX_DOOR_1(x, y))
972 redraw_mask |= REDRAW_DOOR_1;
973 else if (IN_GFX_DOOR_2(x, y))
974 redraw_mask |= REDRAW_DOOR_2;
975 else if (IN_GFX_DOOR_3(x, y))
976 redraw_mask |= REDRAW_DOOR_3;
979 void DrawBackgroundForFont(int x, int y, int width, int height, int font_nr)
981 struct FontBitmapInfo *font = getFontBitmapInfo(font_nr);
983 if (font->bitmap == NULL)
986 DrawBackground(x, y, width, height);
989 void DrawBackgroundForGraphic(int x, int y, int width, int height, int graphic)
991 struct GraphicInfo *g = &graphic_info[graphic];
993 if (g->bitmap == NULL)
996 DrawBackground(x, y, width, height);
999 static int game_status_last = -1;
1000 static Bitmap *global_border_bitmap_last = NULL;
1001 static Bitmap *global_border_bitmap = NULL;
1002 static int real_sx_last = -1, real_sy_last = -1;
1003 static int full_sxsize_last = -1, full_sysize_last = -1;
1004 static int dx_last = -1, dy_last = -1;
1005 static int dxsize_last = -1, dysize_last = -1;
1006 static int vx_last = -1, vy_last = -1;
1007 static int vxsize_last = -1, vysize_last = -1;
1009 boolean CheckIfGlobalBorderHasChanged()
1011 // if game status has not changed, global border has not changed either
1012 if (game_status == game_status_last)
1015 // determine and store new global border bitmap for current game status
1016 global_border_bitmap = getGlobalBorderBitmapFromStatus(game_status);
1018 return (global_border_bitmap_last != global_border_bitmap);
1021 boolean CheckIfGlobalBorderRedrawIsNeeded()
1023 // if game status has not changed, nothing has to be redrawn
1024 if (game_status == game_status_last)
1027 // redraw if last screen was title screen
1028 if (game_status_last == GAME_MODE_TITLE)
1031 // redraw if global screen border has changed
1032 if (CheckIfGlobalBorderHasChanged())
1035 // redraw if position or size of playfield area has changed
1036 if (real_sx_last != REAL_SX || real_sy_last != REAL_SY ||
1037 full_sxsize_last != FULL_SXSIZE || full_sysize_last != FULL_SYSIZE)
1040 // redraw if position or size of door area has changed
1041 if (dx_last != DX || dy_last != DY ||
1042 dxsize_last != DXSIZE || dysize_last != DYSIZE)
1045 // redraw if position or size of tape area has changed
1046 if (vx_last != VX || vy_last != VY ||
1047 vxsize_last != VXSIZE || vysize_last != VYSIZE)
1053 void RedrawGlobalBorderFromBitmap(Bitmap *bitmap)
1056 BlitBitmap(bitmap, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
1058 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
1061 void RedrawGlobalBorder()
1063 Bitmap *bitmap = getGlobalBorderBitmapFromStatus(game_status);
1065 RedrawGlobalBorderFromBitmap(bitmap);
1067 redraw_mask = REDRAW_ALL;
1070 static void RedrawGlobalBorderIfNeeded()
1072 if (game_status == game_status_last)
1075 // copy current draw buffer to later copy back areas that have not changed
1076 if (game_status_last != GAME_MODE_TITLE)
1077 BlitBitmap(backbuffer, bitmap_db_store_1, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
1079 if (CheckIfGlobalBorderRedrawIsNeeded())
1081 // redraw global screen border (or clear, if defined to be empty)
1082 RedrawGlobalBorderFromBitmap(global_border_bitmap);
1084 // copy previous playfield and door areas, if they are defined on both
1085 // previous and current screen and if they still have the same size
1087 if (real_sx_last != -1 && real_sy_last != -1 &&
1088 REAL_SX != -1 && REAL_SY != -1 &&
1089 full_sxsize_last == FULL_SXSIZE && full_sysize_last == FULL_SYSIZE)
1090 BlitBitmap(bitmap_db_store_1, backbuffer,
1091 real_sx_last, real_sy_last, FULL_SXSIZE, FULL_SYSIZE,
1094 if (dx_last != -1 && dy_last != -1 &&
1095 DX != -1 && DY != -1 &&
1096 dxsize_last == DXSIZE && dysize_last == DYSIZE)
1097 BlitBitmap(bitmap_db_store_1, backbuffer,
1098 dx_last, dy_last, DXSIZE, DYSIZE, DX, DY);
1100 if (vx_last != -1 && vy_last != -1 &&
1101 VX != -1 && VY != -1 &&
1102 vxsize_last == VXSIZE && vysize_last == VYSIZE)
1103 BlitBitmap(bitmap_db_store_1, backbuffer,
1104 vx_last, vy_last, VXSIZE, VYSIZE, VX, VY);
1106 redraw_mask = REDRAW_ALL;
1109 game_status_last = game_status;
1111 global_border_bitmap_last = global_border_bitmap;
1113 real_sx_last = REAL_SX;
1114 real_sy_last = REAL_SY;
1115 full_sxsize_last = FULL_SXSIZE;
1116 full_sysize_last = FULL_SYSIZE;
1119 dxsize_last = DXSIZE;
1120 dysize_last = DYSIZE;
1123 vxsize_last = VXSIZE;
1124 vysize_last = VYSIZE;
1129 RedrawGlobalBorderIfNeeded();
1131 /* !!! "drawto" might still point to playfield buffer here (see above) !!! */
1132 /* (when entering hall of fame after playing) */
1133 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
1135 /* !!! maybe this should be done before clearing the background !!! */
1136 if (game_status == GAME_MODE_PLAYING)
1138 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
1139 SetDrawtoField(DRAW_TO_FIELDBUFFER);
1143 SetDrawtoField(DRAW_TO_BACKBUFFER);
1147 void MarkTileDirty(int x, int y)
1149 redraw_mask |= REDRAW_FIELD;
1152 void SetBorderElement()
1156 BorderElement = EL_EMPTY;
1158 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
1160 for (x = 0; x < lev_fieldx; x++)
1162 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
1163 BorderElement = EL_STEELWALL;
1165 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
1171 void FloodFillLevel(int from_x, int from_y, int fill_element,
1172 short field[MAX_LEV_FIELDX][MAX_LEV_FIELDY],
1173 int max_fieldx, int max_fieldy)
1177 static int check[4][2] = { { -1, 0 }, { 0, -1 }, { 1, 0 }, { 0, 1 } };
1178 static int safety = 0;
1180 /* check if starting field still has the desired content */
1181 if (field[from_x][from_y] == fill_element)
1186 if (safety > max_fieldx * max_fieldy)
1187 Error(ERR_EXIT, "Something went wrong in 'FloodFill()'. Please debug.");
1189 old_element = field[from_x][from_y];
1190 field[from_x][from_y] = fill_element;
1192 for (i = 0; i < 4; i++)
1194 x = from_x + check[i][0];
1195 y = from_y + check[i][1];
1197 if (IN_FIELD(x, y, max_fieldx, max_fieldy) && field[x][y] == old_element)
1198 FloodFillLevel(x, y, fill_element, field, max_fieldx, max_fieldy);
1204 void SetRandomAnimationValue(int x, int y)
1206 gfx.anim_random_frame = GfxRandom[x][y];
1209 int getGraphicAnimationFrame(int graphic, int sync_frame)
1211 /* animation synchronized with global frame counter, not move position */
1212 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
1213 sync_frame = FrameCounter;
1215 return getAnimationFrame(graphic_info[graphic].anim_frames,
1216 graphic_info[graphic].anim_delay,
1217 graphic_info[graphic].anim_mode,
1218 graphic_info[graphic].anim_start_frame,
1222 void getGraphicSourceBitmap(int graphic, int tilesize, Bitmap **bitmap)
1224 struct GraphicInfo *g = &graphic_info[graphic];
1225 int tilesize_capped = MIN(MAX(1, tilesize), TILESIZE);
1227 if (tilesize == gfx.standard_tile_size)
1228 *bitmap = g->bitmaps[IMG_BITMAP_STANDARD];
1229 else if (tilesize == game.tile_size)
1230 *bitmap = g->bitmaps[IMG_BITMAP_GAME];
1232 *bitmap = g->bitmaps[IMG_BITMAP_1x1 - log_2(tilesize_capped)];
1235 void getGraphicSourceXY(int graphic, int frame, int *x, int *y,
1236 boolean get_backside)
1238 struct GraphicInfo *g = &graphic_info[graphic];
1239 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
1240 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
1242 if (g->offset_y == 0) /* frames are ordered horizontally */
1244 int max_width = g->anim_frames_per_line * g->width;
1245 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
1247 *x = pos % max_width;
1248 *y = src_y % g->height + pos / max_width * g->height;
1250 else if (g->offset_x == 0) /* frames are ordered vertically */
1252 int max_height = g->anim_frames_per_line * g->height;
1253 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
1255 *x = src_x % g->width + pos / max_height * g->width;
1256 *y = pos % max_height;
1258 else /* frames are ordered diagonally */
1260 *x = src_x + frame * g->offset_x;
1261 *y = src_y + frame * g->offset_y;
1265 void getSizedGraphicSourceExt(int graphic, int frame, int tilesize,
1266 Bitmap **bitmap, int *x, int *y,
1267 boolean get_backside)
1269 struct GraphicInfo *g = &graphic_info[graphic];
1271 // if no in-game graphics defined, always use standard graphic size
1272 if (g->bitmaps[IMG_BITMAP_GAME] == NULL)
1273 tilesize = TILESIZE;
1275 getGraphicSourceBitmap(graphic, tilesize, bitmap);
1276 getGraphicSourceXY(graphic, frame, x, y, get_backside);
1278 *x = *x * tilesize / g->tile_size;
1279 *y = *y * tilesize / g->tile_size;
1282 void getFixedGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1283 int *x, int *y, boolean get_backside)
1285 getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y,
1289 void getSizedGraphicSource(int graphic, int frame, int tilesize,
1290 Bitmap **bitmap, int *x, int *y)
1292 getSizedGraphicSourceExt(graphic, frame, tilesize, bitmap, x, y, FALSE);
1295 void getFixedGraphicSource(int graphic, int frame,
1296 Bitmap **bitmap, int *x, int *y)
1298 getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y, FALSE);
1301 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1303 getSizedGraphicSource(graphic, 0, MINI_TILESIZE, bitmap, x, y);
1306 inline static void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1307 int *x, int *y, boolean get_backside)
1309 getSizedGraphicSourceExt(graphic, frame, TILESIZE_VAR, bitmap, x, y,
1313 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
1315 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
1318 void DrawGraphic(int x, int y, int graphic, int frame)
1321 if (!IN_SCR_FIELD(x, y))
1323 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1324 printf("DrawGraphic(): This should never happen!\n");
1329 DrawGraphicExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR, graphic,
1332 MarkTileDirty(x, y);
1335 void DrawFixedGraphic(int x, int y, int graphic, int frame)
1338 if (!IN_SCR_FIELD(x, y))
1340 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1341 printf("DrawGraphic(): This should never happen!\n");
1346 DrawFixedGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic,
1348 MarkTileDirty(x, y);
1351 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1357 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1359 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX_VAR, TILEY_VAR, x, y);
1362 void DrawFixedGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1368 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1369 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
1372 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
1375 if (!IN_SCR_FIELD(x, y))
1377 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1378 printf("DrawGraphicThruMask(): This should never happen!\n");
1383 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
1386 MarkTileDirty(x, y);
1389 void DrawFixedGraphicThruMask(int x, int y, int graphic, int frame)
1392 if (!IN_SCR_FIELD(x, y))
1394 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1395 printf("DrawGraphicThruMask(): This should never happen!\n");
1400 DrawFixedGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
1402 MarkTileDirty(x, y);
1405 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
1411 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1413 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX_VAR, TILEY_VAR,
1417 void DrawFixedGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y,
1418 int graphic, int frame)
1423 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1425 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY,
1429 void DrawSizedGraphic(int x, int y, int graphic, int frame, int tilesize)
1431 DrawSizedGraphicExt(drawto, SX + x * tilesize, SY + y * tilesize, graphic,
1433 MarkTileDirty(x / tilesize, y / tilesize);
1436 void DrawSizedGraphicExt(DrawBuffer *d, int x, int y, int graphic, int frame,
1442 getSizedGraphicSource(graphic, frame, tilesize, &src_bitmap, &src_x, &src_y);
1443 BlitBitmap(src_bitmap, d, src_x, src_y, tilesize, tilesize, x, y);
1446 void DrawMiniGraphic(int x, int y, int graphic)
1448 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
1449 MarkTileDirty(x / 2, y / 2);
1452 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
1457 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1458 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
1461 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
1462 int graphic, int frame,
1463 int cut_mode, int mask_mode)
1468 int width = TILEX, height = TILEY;
1471 if (dx || dy) /* shifted graphic */
1473 if (x < BX1) /* object enters playfield from the left */
1480 else if (x > BX2) /* object enters playfield from the right */
1486 else if (x == BX1 && dx < 0) /* object leaves playfield to the left */
1492 else if (x == BX2 && dx > 0) /* object leaves playfield to the right */
1494 else if (dx) /* general horizontal movement */
1495 MarkTileDirty(x + SIGN(dx), y);
1497 if (y < BY1) /* object enters playfield from the top */
1499 if (cut_mode == CUT_BELOW) /* object completely above top border */
1507 else if (y > BY2) /* object enters playfield from the bottom */
1513 else if (y == BY1 && dy < 0) /* object leaves playfield to the top */
1519 else if (dy > 0 && cut_mode == CUT_ABOVE)
1521 if (y == BY2) /* object completely above bottom border */
1527 MarkTileDirty(x, y + 1);
1528 } /* object leaves playfield to the bottom */
1529 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1531 else if (dy) /* general vertical movement */
1532 MarkTileDirty(x, y + SIGN(dy));
1536 if (!IN_SCR_FIELD(x, y))
1538 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1539 printf("DrawGraphicShifted(): This should never happen!\n");
1544 width = width * TILESIZE_VAR / TILESIZE;
1545 height = height * TILESIZE_VAR / TILESIZE;
1546 cx = cx * TILESIZE_VAR / TILESIZE;
1547 cy = cy * TILESIZE_VAR / TILESIZE;
1548 dx = dx * TILESIZE_VAR / TILESIZE;
1549 dy = dy * TILESIZE_VAR / TILESIZE;
1551 if (width > 0 && height > 0)
1553 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1558 dst_x = FX + x * TILEX_VAR + dx;
1559 dst_y = FY + y * TILEY_VAR + dy;
1561 if (mask_mode == USE_MASKING)
1562 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1565 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1568 MarkTileDirty(x, y);
1572 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
1573 int graphic, int frame,
1574 int cut_mode, int mask_mode)
1579 int width = TILEX_VAR, height = TILEY_VAR;
1582 int x2 = x + SIGN(dx);
1583 int y2 = y + SIGN(dy);
1585 /* movement with two-tile animations must be sync'ed with movement position,
1586 not with current GfxFrame (which can be higher when using slow movement) */
1587 int anim_pos = (dx ? ABS(dx) : ABS(dy));
1588 int anim_frames = graphic_info[graphic].anim_frames;
1590 /* (we also need anim_delay here for movement animations with less frames) */
1591 int anim_delay = graphic_info[graphic].anim_delay;
1592 int sync_frame = anim_pos * anim_frames * anim_delay / TILESIZE;
1594 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
1595 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
1597 /* re-calculate animation frame for two-tile movement animation */
1598 frame = getGraphicAnimationFrame(graphic, sync_frame);
1600 /* check if movement start graphic inside screen area and should be drawn */
1601 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
1603 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
1605 dst_x = FX + x1 * TILEX_VAR;
1606 dst_y = FY + y1 * TILEY_VAR;
1608 if (mask_mode == USE_MASKING)
1609 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1612 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1615 MarkTileDirty(x1, y1);
1618 /* check if movement end graphic inside screen area and should be drawn */
1619 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
1621 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
1623 dst_x = FX + x2 * TILEX_VAR;
1624 dst_y = FY + y2 * TILEY_VAR;
1626 if (mask_mode == USE_MASKING)
1627 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1630 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1633 MarkTileDirty(x2, y2);
1637 static void DrawGraphicShifted(int x, int y, int dx, int dy,
1638 int graphic, int frame,
1639 int cut_mode, int mask_mode)
1643 DrawGraphic(x, y, graphic, frame);
1648 if (graphic_info[graphic].double_movement) /* EM style movement images */
1649 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1651 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1654 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1655 int frame, int cut_mode)
1657 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
1660 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1661 int cut_mode, int mask_mode)
1663 int lx = LEVELX(x), ly = LEVELY(y);
1667 if (IN_LEV_FIELD(lx, ly))
1669 SetRandomAnimationValue(lx, ly);
1671 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
1672 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1674 /* do not use double (EM style) movement graphic when not moving */
1675 if (graphic_info[graphic].double_movement && !dx && !dy)
1677 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
1678 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1681 else /* border element */
1683 graphic = el2img(element);
1684 frame = getGraphicAnimationFrame(graphic, -1);
1687 if (element == EL_EXPANDABLE_WALL)
1689 boolean left_stopped = FALSE, right_stopped = FALSE;
1691 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1692 left_stopped = TRUE;
1693 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1694 right_stopped = TRUE;
1696 if (left_stopped && right_stopped)
1698 else if (left_stopped)
1700 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1701 frame = graphic_info[graphic].anim_frames - 1;
1703 else if (right_stopped)
1705 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1706 frame = graphic_info[graphic].anim_frames - 1;
1711 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1712 else if (mask_mode == USE_MASKING)
1713 DrawGraphicThruMask(x, y, graphic, frame);
1715 DrawGraphic(x, y, graphic, frame);
1718 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1719 int cut_mode, int mask_mode)
1721 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1722 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1723 cut_mode, mask_mode);
1726 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1729 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1732 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1735 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1738 void DrawLevelElementThruMask(int x, int y, int element)
1740 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1743 void DrawLevelFieldThruMask(int x, int y)
1745 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1748 /* !!! implementation of quicksand is totally broken !!! */
1749 #define IS_CRUMBLED_TILE(x, y, e) \
1750 (GFX_CRUMBLED(e) && (!IN_LEV_FIELD(x, y) || \
1751 !IS_MOVING(x, y) || \
1752 (e) == EL_QUICKSAND_EMPTYING || \
1753 (e) == EL_QUICKSAND_FAST_EMPTYING))
1755 static void DrawLevelFieldCrumbledInnerCorners(int x, int y, int dx, int dy,
1760 int width, height, cx, cy;
1761 int sx = SCREENX(x), sy = SCREENY(y);
1762 int crumbled_border_size = graphic_info[graphic].border_size;
1765 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1767 for (i = 1; i < 4; i++)
1769 int dxx = (i & 1 ? dx : 0);
1770 int dyy = (i & 2 ? dy : 0);
1773 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1776 /* check if neighbour field is of same crumble type */
1777 boolean same = (IS_CRUMBLED_TILE(xx, yy, element) &&
1778 graphic_info[graphic].class ==
1779 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class);
1781 /* return if check prevents inner corner */
1782 if (same == (dxx == dx && dyy == dy))
1786 /* if we reach this point, we have an inner corner */
1788 getGraphicSource(graphic, 1, &src_bitmap, &src_x, &src_y);
1790 width = crumbled_border_size * TILESIZE_VAR / TILESIZE;
1791 height = crumbled_border_size * TILESIZE_VAR / TILESIZE;
1792 cx = (dx > 0 ? TILESIZE_VAR - width : 0);
1793 cy = (dy > 0 ? TILESIZE_VAR - height : 0);
1795 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1796 width, height, FX + sx * TILEX_VAR + cx, FY + sy * TILEY_VAR + cy);
1799 static void DrawLevelFieldCrumbledBorders(int x, int y, int graphic, int frame,
1804 int width, height, bx, by, cx, cy;
1805 int sx = SCREENX(x), sy = SCREENY(y);
1806 int crumbled_border_size = graphic_info[graphic].border_size;
1807 int crumbled_border_size_var = crumbled_border_size * TILESIZE_VAR / TILESIZE;
1808 int crumbled_border_pos_var = TILESIZE_VAR - crumbled_border_size_var;
1811 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1813 /* draw simple, sloppy, non-corner-accurate crumbled border */
1815 width = (dir == 1 || dir == 2 ? crumbled_border_size_var : TILESIZE_VAR);
1816 height = (dir == 0 || dir == 3 ? crumbled_border_size_var : TILESIZE_VAR);
1817 cx = (dir == 2 ? crumbled_border_pos_var : 0);
1818 cy = (dir == 3 ? crumbled_border_pos_var : 0);
1820 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy, width, height,
1821 FX + sx * TILEX_VAR + cx,
1822 FY + sy * TILEY_VAR + cy);
1824 /* (remaining middle border part must be at least as big as corner part) */
1825 if (!(graphic_info[graphic].style & STYLE_ACCURATE_BORDERS) ||
1826 crumbled_border_size >= TILESIZE / 3)
1829 /* correct corners of crumbled border, if needed */
1831 for (i = -1; i <= 1; i += 2)
1833 int xx = x + (dir == 0 || dir == 3 ? i : 0);
1834 int yy = y + (dir == 1 || dir == 2 ? i : 0);
1835 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1838 /* check if neighbour field is of same crumble type */
1839 if (IS_CRUMBLED_TILE(xx, yy, element) &&
1840 graphic_info[graphic].class ==
1841 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1843 /* no crumbled corner, but continued crumbled border */
1845 int c1 = (dir == 2 || dir == 3 ? crumbled_border_pos_var : 0);
1846 int c2 = (i == 1 ? crumbled_border_pos_var : 0);
1847 int b1 = (i == 1 ? crumbled_border_size_var :
1848 TILESIZE_VAR - 2 * crumbled_border_size_var);
1850 width = crumbled_border_size_var;
1851 height = crumbled_border_size_var;
1853 if (dir == 1 || dir == 2)
1868 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
1870 FX + sx * TILEX_VAR + cx,
1871 FY + sy * TILEY_VAR + cy);
1876 static void DrawLevelFieldCrumbledExt(int x, int y, int graphic, int frame)
1878 int sx = SCREENX(x), sy = SCREENY(y);
1881 static int xy[4][2] =
1889 if (!IN_LEV_FIELD(x, y))
1892 element = TILE_GFX_ELEMENT(x, y);
1894 /* crumble field itself */
1895 if (IS_CRUMBLED_TILE(x, y, element))
1897 if (!IN_SCR_FIELD(sx, sy))
1900 for (i = 0; i < 4; i++)
1902 int xx = x + xy[i][0];
1903 int yy = y + xy[i][1];
1905 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1908 /* check if neighbour field is of same crumble type */
1909 if (IS_CRUMBLED_TILE(xx, yy, element) &&
1910 graphic_info[graphic].class ==
1911 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1914 DrawLevelFieldCrumbledBorders(x, y, graphic, frame, i);
1917 if ((graphic_info[graphic].style & STYLE_INNER_CORNERS) &&
1918 graphic_info[graphic].anim_frames == 2)
1920 for (i = 0; i < 4; i++)
1922 int dx = (i & 1 ? +1 : -1);
1923 int dy = (i & 2 ? +1 : -1);
1925 DrawLevelFieldCrumbledInnerCorners(x, y, dx, dy, graphic);
1929 MarkTileDirty(sx, sy);
1931 else /* center field not crumbled -- crumble neighbour fields */
1933 for (i = 0; i < 4; i++)
1935 int xx = x + xy[i][0];
1936 int yy = y + xy[i][1];
1937 int sxx = sx + xy[i][0];
1938 int syy = sy + xy[i][1];
1940 if (!IN_LEV_FIELD(xx, yy) ||
1941 !IN_SCR_FIELD(sxx, syy))
1944 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
1947 element = TILE_GFX_ELEMENT(xx, yy);
1949 if (!IS_CRUMBLED_TILE(xx, yy, element))
1952 graphic = el_act2crm(element, ACTION_DEFAULT);
1954 DrawLevelFieldCrumbledBorders(xx, yy, graphic, 0, 3 - i);
1956 MarkTileDirty(sxx, syy);
1961 void DrawLevelFieldCrumbled(int x, int y)
1965 if (!IN_LEV_FIELD(x, y))
1968 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1969 GfxElement[x][y] != EL_UNDEFINED &&
1970 GFX_CRUMBLED(GfxElement[x][y]))
1972 DrawLevelFieldCrumbledDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
1977 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
1979 DrawLevelFieldCrumbledExt(x, y, graphic, 0);
1982 void DrawLevelFieldCrumbledDigging(int x, int y, int direction,
1985 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1986 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1987 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1988 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1989 int sx = SCREENX(x), sy = SCREENY(y);
1991 DrawGraphic(sx, sy, graphic1, frame1);
1992 DrawLevelFieldCrumbledExt(x, y, graphic2, frame2);
1995 void DrawLevelFieldCrumbledNeighbours(int x, int y)
1997 int sx = SCREENX(x), sy = SCREENY(y);
1998 static int xy[4][2] =
2007 for (i = 0; i < 4; i++)
2009 int xx = x + xy[i][0];
2010 int yy = y + xy[i][1];
2011 int sxx = sx + xy[i][0];
2012 int syy = sy + xy[i][1];
2014 if (!IN_LEV_FIELD(xx, yy) ||
2015 !IN_SCR_FIELD(sxx, syy) ||
2016 !GFX_CRUMBLED(Feld[xx][yy]) ||
2020 DrawLevelField(xx, yy);
2024 static int getBorderElement(int x, int y)
2028 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
2029 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
2030 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
2031 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
2032 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
2033 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
2034 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
2036 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
2037 int steel_position = (x == -1 && y == -1 ? 0 :
2038 x == lev_fieldx && y == -1 ? 1 :
2039 x == -1 && y == lev_fieldy ? 2 :
2040 x == lev_fieldx && y == lev_fieldy ? 3 :
2041 x == -1 || x == lev_fieldx ? 4 :
2042 y == -1 || y == lev_fieldy ? 5 : 6);
2044 return border[steel_position][steel_type];
2047 void DrawScreenElement(int x, int y, int element)
2049 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
2050 DrawLevelFieldCrumbled(LEVELX(x), LEVELY(y));
2053 void DrawLevelElement(int x, int y, int element)
2055 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2056 DrawScreenElement(SCREENX(x), SCREENY(y), element);
2059 void DrawScreenField(int x, int y)
2061 int lx = LEVELX(x), ly = LEVELY(y);
2062 int element, content;
2064 if (!IN_LEV_FIELD(lx, ly))
2066 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
2069 element = getBorderElement(lx, ly);
2071 DrawScreenElement(x, y, element);
2076 element = Feld[lx][ly];
2077 content = Store[lx][ly];
2079 if (IS_MOVING(lx, ly))
2081 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
2082 boolean cut_mode = NO_CUTTING;
2084 if (element == EL_QUICKSAND_EMPTYING ||
2085 element == EL_QUICKSAND_FAST_EMPTYING ||
2086 element == EL_MAGIC_WALL_EMPTYING ||
2087 element == EL_BD_MAGIC_WALL_EMPTYING ||
2088 element == EL_DC_MAGIC_WALL_EMPTYING ||
2089 element == EL_AMOEBA_DROPPING)
2090 cut_mode = CUT_ABOVE;
2091 else if (element == EL_QUICKSAND_FILLING ||
2092 element == EL_QUICKSAND_FAST_FILLING ||
2093 element == EL_MAGIC_WALL_FILLING ||
2094 element == EL_BD_MAGIC_WALL_FILLING ||
2095 element == EL_DC_MAGIC_WALL_FILLING)
2096 cut_mode = CUT_BELOW;
2098 if (cut_mode == CUT_ABOVE)
2099 DrawScreenElement(x, y, element);
2101 DrawScreenElement(x, y, EL_EMPTY);
2104 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
2105 else if (cut_mode == NO_CUTTING)
2106 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
2109 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
2111 if (cut_mode == CUT_BELOW &&
2112 IN_LEV_FIELD(lx, ly + 1) && IN_SCR_FIELD(x, y + 1))
2113 DrawLevelElement(lx, ly + 1, element);
2116 if (content == EL_ACID)
2118 int dir = MovDir[lx][ly];
2119 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
2120 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
2122 DrawLevelElementThruMask(newlx, newly, EL_ACID);
2125 else if (IS_BLOCKED(lx, ly))
2130 boolean cut_mode = NO_CUTTING;
2131 int element_old, content_old;
2133 Blocked2Moving(lx, ly, &oldx, &oldy);
2136 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
2137 MovDir[oldx][oldy] == MV_RIGHT);
2139 element_old = Feld[oldx][oldy];
2140 content_old = Store[oldx][oldy];
2142 if (element_old == EL_QUICKSAND_EMPTYING ||
2143 element_old == EL_QUICKSAND_FAST_EMPTYING ||
2144 element_old == EL_MAGIC_WALL_EMPTYING ||
2145 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
2146 element_old == EL_DC_MAGIC_WALL_EMPTYING ||
2147 element_old == EL_AMOEBA_DROPPING)
2148 cut_mode = CUT_ABOVE;
2150 DrawScreenElement(x, y, EL_EMPTY);
2153 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
2155 else if (cut_mode == NO_CUTTING)
2156 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
2159 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
2162 else if (IS_DRAWABLE(element))
2163 DrawScreenElement(x, y, element);
2165 DrawScreenElement(x, y, EL_EMPTY);
2168 void DrawLevelField(int x, int y)
2170 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2171 DrawScreenField(SCREENX(x), SCREENY(y));
2172 else if (IS_MOVING(x, y))
2176 Moving2Blocked(x, y, &newx, &newy);
2177 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
2178 DrawScreenField(SCREENX(newx), SCREENY(newy));
2180 else if (IS_BLOCKED(x, y))
2184 Blocked2Moving(x, y, &oldx, &oldy);
2185 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
2186 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
2190 void DrawSizedElement(int x, int y, int element, int tilesize)
2194 graphic = el2edimg(element);
2195 DrawSizedGraphic(x, y, graphic, 0, tilesize);
2198 void DrawMiniElement(int x, int y, int element)
2202 graphic = el2edimg(element);
2203 DrawMiniGraphic(x, y, graphic);
2206 void DrawSizedElementOrWall(int sx, int sy, int scroll_x, int scroll_y,
2209 int x = sx + scroll_x, y = sy + scroll_y;
2211 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
2212 DrawSizedElement(sx, sy, EL_EMPTY, tilesize);
2213 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
2214 DrawSizedElement(sx, sy, Feld[x][y], tilesize);
2216 DrawSizedGraphic(sx, sy, el2edimg(getBorderElement(x, y)), 0, tilesize);
2219 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
2221 int x = sx + scroll_x, y = sy + scroll_y;
2223 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
2224 DrawMiniElement(sx, sy, EL_EMPTY);
2225 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
2226 DrawMiniElement(sx, sy, Feld[x][y]);
2228 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
2231 void DrawEnvelopeBackgroundTiles(int graphic, int startx, int starty,
2232 int x, int y, int xsize, int ysize,
2233 int tile_width, int tile_height)
2237 int dst_x = startx + x * tile_width;
2238 int dst_y = starty + y * tile_height;
2239 int width = graphic_info[graphic].width;
2240 int height = graphic_info[graphic].height;
2241 int inner_width_raw = MAX(width - 2 * tile_width, tile_width);
2242 int inner_height_raw = MAX(height - 2 * tile_height, tile_height);
2243 int inner_width = inner_width_raw - (inner_width_raw % tile_width);
2244 int inner_height = inner_height_raw - (inner_height_raw % tile_height);
2245 int inner_sx = (width >= 3 * tile_width ? tile_width : 0);
2246 int inner_sy = (height >= 3 * tile_height ? tile_height : 0);
2247 boolean draw_masked = graphic_info[graphic].draw_masked;
2249 getFixedGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
2251 if (src_bitmap == NULL || width < tile_width || height < tile_height)
2253 ClearRectangle(drawto, dst_x, dst_y, tile_width, tile_height);
2257 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - tile_width :
2258 inner_sx + (x - 1) * tile_width % inner_width);
2259 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - tile_height :
2260 inner_sy + (y - 1) * tile_height % inner_height);
2263 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
2266 BlitBitmap(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
2270 void DrawEnvelopeBackground(int graphic, int startx, int starty,
2271 int x, int y, int xsize, int ysize, int font_nr)
2273 int font_width = getFontWidth(font_nr);
2274 int font_height = getFontHeight(font_nr);
2276 DrawEnvelopeBackgroundTiles(graphic, startx, starty, x, y, xsize, ysize,
2277 font_width, font_height);
2280 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
2282 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2283 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2284 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2285 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2286 boolean no_delay = (tape.warp_forward);
2287 unsigned int anim_delay = 0;
2288 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
2289 int anim_delay_value = (no_delay ? 0 : frame_delay_value) / 2;
2290 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
2291 int font_width = getFontWidth(font_nr);
2292 int font_height = getFontHeight(font_nr);
2293 int max_xsize = level.envelope[envelope_nr].xsize;
2294 int max_ysize = level.envelope[envelope_nr].ysize;
2295 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
2296 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
2297 int xend = max_xsize;
2298 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
2299 int xstep = (xstart < xend ? 1 : 0);
2300 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2302 int end = MAX(xend - xstart, yend - ystart);
2305 for (i = start; i <= end; i++)
2307 int last_frame = end; // last frame of this "for" loop
2308 int x = xstart + i * xstep;
2309 int y = ystart + i * ystep;
2310 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2311 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2312 int sx = SX + (SXSIZE - xsize * font_width) / 2;
2313 int sy = SY + (SYSIZE - ysize * font_height) / 2;
2316 SetDrawtoField(DRAW_TO_FIELDBUFFER);
2318 BlitScreenToBitmap(backbuffer);
2320 SetDrawtoField(DRAW_TO_BACKBUFFER);
2322 for (yy = 0; yy < ysize; yy++)
2323 for (xx = 0; xx < xsize; xx++)
2324 DrawEnvelopeBackground(graphic, sx, sy, xx, yy, xsize, ysize, font_nr);
2326 DrawTextBuffer(sx + font_width, sy + font_height,
2327 level.envelope[envelope_nr].text, font_nr, max_xsize,
2328 xsize - 2, ysize - 2, 0, mask_mode,
2329 level.envelope[envelope_nr].autowrap,
2330 level.envelope[envelope_nr].centered, FALSE);
2332 redraw_mask |= REDRAW_FIELD;
2335 SkipUntilDelayReached(&anim_delay, anim_delay_value, &i, last_frame);
2339 void ShowEnvelope(int envelope_nr)
2341 int element = EL_ENVELOPE_1 + envelope_nr;
2342 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2343 int sound_opening = element_info[element].sound[ACTION_OPENING];
2344 int sound_closing = element_info[element].sound[ACTION_CLOSING];
2345 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2346 boolean no_delay = (tape.warp_forward);
2347 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
2348 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
2349 int anim_mode = graphic_info[graphic].anim_mode;
2350 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2351 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2353 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
2355 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2357 if (anim_mode == ANIM_DEFAULT)
2358 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
2360 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
2363 Delay(wait_delay_value);
2365 WaitForEventToContinue();
2367 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2369 if (anim_mode != ANIM_NONE)
2370 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
2372 if (anim_mode == ANIM_DEFAULT)
2373 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
2375 game.envelope_active = FALSE;
2377 SetDrawtoField(DRAW_TO_FIELDBUFFER);
2379 redraw_mask |= REDRAW_FIELD;
2383 static void setRequestBasePosition(int *x, int *y)
2385 int sx_base, sy_base;
2387 if (request.x != -1)
2388 sx_base = request.x;
2389 else if (request.align == ALIGN_LEFT)
2391 else if (request.align == ALIGN_RIGHT)
2392 sx_base = SX + SXSIZE;
2394 sx_base = SX + SXSIZE / 2;
2396 if (request.y != -1)
2397 sy_base = request.y;
2398 else if (request.valign == VALIGN_TOP)
2400 else if (request.valign == VALIGN_BOTTOM)
2401 sy_base = SY + SYSIZE;
2403 sy_base = SY + SYSIZE / 2;
2409 static void setRequestPositionExt(int *x, int *y, int width, int height,
2410 boolean add_border_size)
2412 int border_size = request.border_size;
2413 int sx_base, sy_base;
2416 setRequestBasePosition(&sx_base, &sy_base);
2418 if (request.align == ALIGN_LEFT)
2420 else if (request.align == ALIGN_RIGHT)
2421 sx = sx_base - width;
2423 sx = sx_base - width / 2;
2425 if (request.valign == VALIGN_TOP)
2427 else if (request.valign == VALIGN_BOTTOM)
2428 sy = sy_base - height;
2430 sy = sy_base - height / 2;
2432 sx = MAX(0, MIN(sx, WIN_XSIZE - width));
2433 sy = MAX(0, MIN(sy, WIN_YSIZE - height));
2435 if (add_border_size)
2445 static void setRequestPosition(int *x, int *y, boolean add_border_size)
2447 setRequestPositionExt(x, y, request.width, request.height, add_border_size);
2450 void DrawEnvelopeRequest(char *text)
2452 char *text_final = text;
2453 char *text_door_style = NULL;
2454 int graphic = IMG_BACKGROUND_REQUEST;
2455 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2456 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2457 int font_nr = FONT_REQUEST;
2458 int font_width = getFontWidth(font_nr);
2459 int font_height = getFontHeight(font_nr);
2460 int border_size = request.border_size;
2461 int line_spacing = request.line_spacing;
2462 int line_height = font_height + line_spacing;
2463 int max_text_width = request.width - 2 * border_size;
2464 int max_text_height = request.height - 2 * border_size;
2465 int line_length = max_text_width / font_width;
2466 int max_lines = max_text_height / line_height;
2467 int text_width = line_length * font_width;
2468 int width = request.width;
2469 int height = request.height;
2470 int tile_size = MAX(request.step_offset, 1);
2471 int x_steps = width / tile_size;
2472 int y_steps = height / tile_size;
2473 int sx_offset = border_size;
2474 int sy_offset = border_size;
2478 if (request.centered)
2479 sx_offset = (request.width - text_width) / 2;
2481 if (request.wrap_single_words && !request.autowrap)
2483 char *src_text_ptr, *dst_text_ptr;
2485 text_door_style = checked_malloc(2 * strlen(text) + 1);
2487 src_text_ptr = text;
2488 dst_text_ptr = text_door_style;
2490 while (*src_text_ptr)
2492 if (*src_text_ptr == ' ' ||
2493 *src_text_ptr == '?' ||
2494 *src_text_ptr == '!')
2495 *dst_text_ptr++ = '\n';
2497 if (*src_text_ptr != ' ')
2498 *dst_text_ptr++ = *src_text_ptr;
2503 *dst_text_ptr = '\0';
2505 text_final = text_door_style;
2508 setRequestPosition(&sx, &sy, FALSE);
2510 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
2512 for (y = 0; y < y_steps; y++)
2513 for (x = 0; x < x_steps; x++)
2514 DrawEnvelopeBackgroundTiles(graphic, sx, sy,
2515 x, y, x_steps, y_steps,
2516 tile_size, tile_size);
2518 /* force DOOR font inside door area */
2519 SetFontStatus(GAME_MODE_PSEUDO_DOOR);
2521 DrawTextBuffer(sx + sx_offset, sy + sy_offset, text_final, font_nr,
2522 line_length, -1, max_lines, line_spacing, mask_mode,
2523 request.autowrap, request.centered, FALSE);
2527 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2528 RedrawGadget(tool_gadget[i]);
2530 // store readily prepared envelope request for later use when animating
2531 BlitBitmap(backbuffer, bitmap_db_store_2, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2533 if (text_door_style)
2534 free(text_door_style);
2537 void AnimateEnvelopeRequest(int anim_mode, int action)
2539 int graphic = IMG_BACKGROUND_REQUEST;
2540 boolean draw_masked = graphic_info[graphic].draw_masked;
2541 int delay_value_normal = request.step_delay;
2542 int delay_value_fast = delay_value_normal / 2;
2543 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2544 boolean no_delay = (tape.warp_forward);
2545 int delay_value = (ffwd_delay ? delay_value_fast : delay_value_normal);
2546 int anim_delay_value = (no_delay ? 0 : delay_value + 500 * 0) / 2;
2547 unsigned int anim_delay = 0;
2549 int tile_size = MAX(request.step_offset, 1);
2550 int max_xsize = request.width / tile_size;
2551 int max_ysize = request.height / tile_size;
2552 int max_xsize_inner = max_xsize - 2;
2553 int max_ysize_inner = max_ysize - 2;
2555 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize_inner : 0);
2556 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize_inner : 0);
2557 int xend = max_xsize_inner;
2558 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize_inner : 0);
2559 int xstep = (xstart < xend ? 1 : 0);
2560 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2562 int end = MAX(xend - xstart, yend - ystart);
2565 if (setup.quick_doors)
2572 for (i = start; i <= end; i++)
2574 int last_frame = end; // last frame of this "for" loop
2575 int x = xstart + i * xstep;
2576 int y = ystart + i * ystep;
2577 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2578 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2579 int xsize_size_left = (xsize - 1) * tile_size;
2580 int ysize_size_top = (ysize - 1) * tile_size;
2581 int max_xsize_pos = (max_xsize - 1) * tile_size;
2582 int max_ysize_pos = (max_ysize - 1) * tile_size;
2583 int width = xsize * tile_size;
2584 int height = ysize * tile_size;
2589 setRequestPosition(&src_x, &src_y, FALSE);
2590 setRequestPositionExt(&dst_x, &dst_y, width, height, FALSE);
2592 BlitBitmap(bitmap_db_store_1, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2594 for (yy = 0; yy < 2; yy++)
2596 for (xx = 0; xx < 2; xx++)
2598 int src_xx = src_x + xx * max_xsize_pos;
2599 int src_yy = src_y + yy * max_ysize_pos;
2600 int dst_xx = dst_x + xx * xsize_size_left;
2601 int dst_yy = dst_y + yy * ysize_size_top;
2602 int xx_size = (xx ? tile_size : xsize_size_left);
2603 int yy_size = (yy ? tile_size : ysize_size_top);
2606 BlitBitmapMasked(bitmap_db_store_2, backbuffer,
2607 src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
2609 BlitBitmap(bitmap_db_store_2, backbuffer,
2610 src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
2614 redraw_mask |= REDRAW_FIELD;
2618 SkipUntilDelayReached(&anim_delay, anim_delay_value, &i, last_frame);
2622 void ShowEnvelopeRequest(char *text, unsigned int req_state, int action)
2624 int graphic = IMG_BACKGROUND_REQUEST;
2625 int sound_opening = SND_REQUEST_OPENING;
2626 int sound_closing = SND_REQUEST_CLOSING;
2627 int anim_mode_1 = request.anim_mode; /* (higher priority) */
2628 int anim_mode_2 = graphic_info[graphic].anim_mode; /* (lower priority) */
2629 int anim_mode = (anim_mode_1 != ANIM_DEFAULT ? anim_mode_1 : anim_mode_2);
2630 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2631 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2633 if (game_status == GAME_MODE_PLAYING)
2634 BlitScreenToBitmap(backbuffer);
2636 SetDrawtoField(DRAW_TO_BACKBUFFER);
2638 // SetDrawBackgroundMask(REDRAW_NONE);
2640 if (action == ACTION_OPENING)
2642 BlitBitmap(backbuffer, bitmap_db_store_1, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2644 if (req_state & REQ_ASK)
2646 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2647 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2649 else if (req_state & REQ_CONFIRM)
2651 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2653 else if (req_state & REQ_PLAYER)
2655 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2656 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2657 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2658 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2661 DrawEnvelopeRequest(text);
2664 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
2666 if (action == ACTION_OPENING)
2668 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2670 if (anim_mode == ANIM_DEFAULT)
2671 AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_OPENING);
2673 AnimateEnvelopeRequest(main_anim_mode, ACTION_OPENING);
2677 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2679 if (anim_mode != ANIM_NONE)
2680 AnimateEnvelopeRequest(main_anim_mode, ACTION_CLOSING);
2682 if (anim_mode == ANIM_DEFAULT)
2683 AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_CLOSING);
2686 game.envelope_active = FALSE;
2688 if (action == ACTION_CLOSING)
2689 BlitBitmap(bitmap_db_store_1, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2691 // SetDrawBackgroundMask(last_draw_background_mask);
2693 redraw_mask |= REDRAW_FIELD;
2697 if (action == ACTION_CLOSING &&
2698 game_status == GAME_MODE_PLAYING &&
2699 level.game_engine_type == GAME_ENGINE_TYPE_RND)
2700 SetDrawtoField(DRAW_TO_FIELDBUFFER);
2703 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
2707 int graphic = el2preimg(element);
2709 getSizedGraphicSource(graphic, 0, tilesize, &src_bitmap, &src_x, &src_y);
2710 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
2713 void DrawLevel(int draw_background_mask)
2717 SetMainBackgroundImage(IMG_BACKGROUND_PLAYING);
2718 SetDrawBackgroundMask(draw_background_mask);
2722 for (x = BX1; x <= BX2; x++)
2723 for (y = BY1; y <= BY2; y++)
2724 DrawScreenField(x, y);
2726 redraw_mask |= REDRAW_FIELD;
2729 void DrawSizedLevel(int size_x, int size_y, int scroll_x, int scroll_y,
2734 for (x = 0; x < size_x; x++)
2735 for (y = 0; y < size_y; y++)
2736 DrawSizedElementOrWall(x, y, scroll_x, scroll_y, tilesize);
2738 redraw_mask |= REDRAW_FIELD;
2741 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
2745 for (x = 0; x < size_x; x++)
2746 for (y = 0; y < size_y; y++)
2747 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
2749 redraw_mask |= REDRAW_FIELD;
2752 static void DrawPreviewLevelPlayfieldExt(int from_x, int from_y)
2754 boolean show_level_border = (BorderElement != EL_EMPTY);
2755 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2756 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2757 int tile_size = preview.tile_size;
2758 int preview_width = preview.xsize * tile_size;
2759 int preview_height = preview.ysize * tile_size;
2760 int real_preview_xsize = MIN(level_xsize, preview.xsize);
2761 int real_preview_ysize = MIN(level_ysize, preview.ysize);
2762 int real_preview_width = real_preview_xsize * tile_size;
2763 int real_preview_height = real_preview_ysize * tile_size;
2764 int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
2765 int dst_y = SY + ALIGNED_YPOS(preview.y, preview_height, preview.valign);
2768 if (!IN_GFX_FIELD_FULL(dst_x, dst_y + preview_height - 1))
2771 DrawBackground(dst_x, dst_y, preview_width, preview_height);
2773 dst_x += (preview_width - real_preview_width) / 2;
2774 dst_y += (preview_height - real_preview_height) / 2;
2776 for (x = 0; x < real_preview_xsize; x++)
2778 for (y = 0; y < real_preview_ysize; y++)
2780 int lx = from_x + x + (show_level_border ? -1 : 0);
2781 int ly = from_y + y + (show_level_border ? -1 : 0);
2782 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
2783 getBorderElement(lx, ly));
2785 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
2786 element, tile_size);
2790 redraw_mask |= REDRAW_FIELD;
2793 #define MICROLABEL_EMPTY 0
2794 #define MICROLABEL_LEVEL_NAME 1
2795 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
2796 #define MICROLABEL_LEVEL_AUTHOR 3
2797 #define MICROLABEL_IMPORTED_FROM_HEAD 4
2798 #define MICROLABEL_IMPORTED_FROM 5
2799 #define MICROLABEL_IMPORTED_BY_HEAD 6
2800 #define MICROLABEL_IMPORTED_BY 7
2802 static int getMaxTextLength(struct TextPosInfo *pos, int font_nr)
2804 int max_text_width = SXSIZE;
2805 int font_width = getFontWidth(font_nr);
2807 if (pos->align == ALIGN_CENTER)
2808 max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
2809 else if (pos->align == ALIGN_RIGHT)
2810 max_text_width = pos->x;
2812 max_text_width = SXSIZE - pos->x;
2814 return max_text_width / font_width;
2817 static void DrawPreviewLevelLabelExt(int mode)
2819 struct TextPosInfo *pos = &menu.main.text.level_info_2;
2820 char label_text[MAX_OUTPUT_LINESIZE + 1];
2821 int max_len_label_text;
2822 int font_nr = pos->font;
2825 if (!IN_GFX_FIELD_FULL(pos->x, pos->y + getFontHeight(pos->font)))
2828 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
2829 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
2830 mode == MICROLABEL_IMPORTED_BY_HEAD)
2831 font_nr = pos->font_alt;
2833 max_len_label_text = getMaxTextLength(pos, font_nr);
2835 if (pos->size != -1)
2836 max_len_label_text = pos->size;
2838 for (i = 0; i < max_len_label_text; i++)
2839 label_text[i] = ' ';
2840 label_text[max_len_label_text] = '\0';
2842 if (strlen(label_text) > 0)
2843 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2846 (mode == MICROLABEL_LEVEL_NAME ? level.name :
2847 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
2848 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
2849 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
2850 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
2851 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
2852 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
2853 max_len_label_text);
2854 label_text[max_len_label_text] = '\0';
2856 if (strlen(label_text) > 0)
2857 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2859 redraw_mask |= REDRAW_FIELD;
2862 static void DrawPreviewLevelExt(boolean restart)
2864 static unsigned int scroll_delay = 0;
2865 static unsigned int label_delay = 0;
2866 static int from_x, from_y, scroll_direction;
2867 static int label_state, label_counter;
2868 unsigned int scroll_delay_value = preview.step_delay;
2869 boolean show_level_border = (BorderElement != EL_EMPTY);
2870 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2871 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2878 if (preview.anim_mode == ANIM_CENTERED)
2880 if (level_xsize > preview.xsize)
2881 from_x = (level_xsize - preview.xsize) / 2;
2882 if (level_ysize > preview.ysize)
2883 from_y = (level_ysize - preview.ysize) / 2;
2886 from_x += preview.xoffset;
2887 from_y += preview.yoffset;
2889 scroll_direction = MV_RIGHT;
2893 DrawPreviewLevelPlayfieldExt(from_x, from_y);
2894 DrawPreviewLevelLabelExt(label_state);
2896 /* initialize delay counters */
2897 DelayReached(&scroll_delay, 0);
2898 DelayReached(&label_delay, 0);
2900 if (leveldir_current->name)
2902 struct TextPosInfo *pos = &menu.main.text.level_info_1;
2903 char label_text[MAX_OUTPUT_LINESIZE + 1];
2904 int font_nr = pos->font;
2905 int max_len_label_text = getMaxTextLength(pos, font_nr);
2907 if (pos->size != -1)
2908 max_len_label_text = pos->size;
2910 strncpy(label_text, leveldir_current->name, max_len_label_text);
2911 label_text[max_len_label_text] = '\0';
2913 if (IN_GFX_FIELD_FULL(pos->x, pos->y + getFontHeight(pos->font)))
2914 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2920 /* scroll preview level, if needed */
2921 if (preview.anim_mode != ANIM_NONE &&
2922 (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
2923 DelayReached(&scroll_delay, scroll_delay_value))
2925 switch (scroll_direction)
2930 from_x -= preview.step_offset;
2931 from_x = (from_x < 0 ? 0 : from_x);
2934 scroll_direction = MV_UP;
2938 if (from_x < level_xsize - preview.xsize)
2940 from_x += preview.step_offset;
2941 from_x = (from_x > level_xsize - preview.xsize ?
2942 level_xsize - preview.xsize : from_x);
2945 scroll_direction = MV_DOWN;
2951 from_y -= preview.step_offset;
2952 from_y = (from_y < 0 ? 0 : from_y);
2955 scroll_direction = MV_RIGHT;
2959 if (from_y < level_ysize - preview.ysize)
2961 from_y += preview.step_offset;
2962 from_y = (from_y > level_ysize - preview.ysize ?
2963 level_ysize - preview.ysize : from_y);
2966 scroll_direction = MV_LEFT;
2973 DrawPreviewLevelPlayfieldExt(from_x, from_y);
2976 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
2977 /* redraw micro level label, if needed */
2978 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
2979 !strEqual(level.author, ANONYMOUS_NAME) &&
2980 !strEqual(level.author, leveldir_current->name) &&
2981 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
2983 int max_label_counter = 23;
2985 if (leveldir_current->imported_from != NULL &&
2986 strlen(leveldir_current->imported_from) > 0)
2987 max_label_counter += 14;
2988 if (leveldir_current->imported_by != NULL &&
2989 strlen(leveldir_current->imported_by) > 0)
2990 max_label_counter += 14;
2992 label_counter = (label_counter + 1) % max_label_counter;
2993 label_state = (label_counter >= 0 && label_counter <= 7 ?
2994 MICROLABEL_LEVEL_NAME :
2995 label_counter >= 9 && label_counter <= 12 ?
2996 MICROLABEL_LEVEL_AUTHOR_HEAD :
2997 label_counter >= 14 && label_counter <= 21 ?
2998 MICROLABEL_LEVEL_AUTHOR :
2999 label_counter >= 23 && label_counter <= 26 ?
3000 MICROLABEL_IMPORTED_FROM_HEAD :
3001 label_counter >= 28 && label_counter <= 35 ?
3002 MICROLABEL_IMPORTED_FROM :
3003 label_counter >= 37 && label_counter <= 40 ?
3004 MICROLABEL_IMPORTED_BY_HEAD :
3005 label_counter >= 42 && label_counter <= 49 ?
3006 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
3008 if (leveldir_current->imported_from == NULL &&
3009 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
3010 label_state == MICROLABEL_IMPORTED_FROM))
3011 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
3012 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
3014 DrawPreviewLevelLabelExt(label_state);
3018 void DrawPreviewLevelInitial()
3020 DrawPreviewLevelExt(TRUE);
3023 void DrawPreviewLevelAnimation()
3025 DrawPreviewLevelExt(FALSE);
3028 inline static void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
3029 int graphic, int sync_frame,
3032 int frame = getGraphicAnimationFrame(graphic, sync_frame);
3034 if (mask_mode == USE_MASKING)
3035 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
3037 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
3040 void DrawFixedGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
3041 int graphic, int sync_frame, int mask_mode)
3043 int frame = getGraphicAnimationFrame(graphic, sync_frame);
3045 if (mask_mode == USE_MASKING)
3046 DrawFixedGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
3048 DrawFixedGraphicExt(dst_bitmap, x, y, graphic, frame);
3051 inline static void DrawGraphicAnimation(int x, int y, int graphic)
3053 int lx = LEVELX(x), ly = LEVELY(y);
3055 if (!IN_SCR_FIELD(x, y))
3058 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
3059 graphic, GfxFrame[lx][ly], NO_MASKING);
3061 MarkTileDirty(x, y);
3064 void DrawFixedGraphicAnimation(int x, int y, int graphic)
3066 int lx = LEVELX(x), ly = LEVELY(y);
3068 if (!IN_SCR_FIELD(x, y))
3071 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
3072 graphic, GfxFrame[lx][ly], NO_MASKING);
3073 MarkTileDirty(x, y);
3076 void DrawLevelGraphicAnimation(int x, int y, int graphic)
3078 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
3081 void DrawLevelElementAnimation(int x, int y, int element)
3083 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
3085 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
3088 void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
3090 int sx = SCREENX(x), sy = SCREENY(y);
3092 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
3095 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
3098 DrawGraphicAnimation(sx, sy, graphic);
3101 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
3102 DrawLevelFieldCrumbled(x, y);
3104 if (GFX_CRUMBLED(Feld[x][y]))
3105 DrawLevelFieldCrumbled(x, y);
3109 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
3111 int sx = SCREENX(x), sy = SCREENY(y);
3114 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
3117 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
3119 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
3122 DrawGraphicAnimation(sx, sy, graphic);
3124 if (GFX_CRUMBLED(element))
3125 DrawLevelFieldCrumbled(x, y);
3128 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
3130 if (player->use_murphy)
3132 /* this works only because currently only one player can be "murphy" ... */
3133 static int last_horizontal_dir = MV_LEFT;
3134 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
3136 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3137 last_horizontal_dir = move_dir;
3139 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
3141 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
3143 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
3149 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
3152 static boolean equalGraphics(int graphic1, int graphic2)
3154 struct GraphicInfo *g1 = &graphic_info[graphic1];
3155 struct GraphicInfo *g2 = &graphic_info[graphic2];
3157 return (g1->bitmap == g2->bitmap &&
3158 g1->src_x == g2->src_x &&
3159 g1->src_y == g2->src_y &&
3160 g1->anim_frames == g2->anim_frames &&
3161 g1->anim_delay == g2->anim_delay &&
3162 g1->anim_mode == g2->anim_mode);
3165 void DrawAllPlayers()
3169 for (i = 0; i < MAX_PLAYERS; i++)
3170 if (stored_player[i].active)
3171 DrawPlayer(&stored_player[i]);
3174 void DrawPlayerField(int x, int y)
3176 if (!IS_PLAYER(x, y))
3179 DrawPlayer(PLAYERINFO(x, y));
3182 #define DRAW_PLAYER_OVER_PUSHED_ELEMENT 1
3184 void DrawPlayer(struct PlayerInfo *player)
3186 int jx = player->jx;
3187 int jy = player->jy;
3188 int move_dir = player->MovDir;
3189 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
3190 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
3191 int last_jx = (player->is_moving ? jx - dx : jx);
3192 int last_jy = (player->is_moving ? jy - dy : jy);
3193 int next_jx = jx + dx;
3194 int next_jy = jy + dy;
3195 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
3196 boolean player_is_opaque = FALSE;
3197 int sx = SCREENX(jx), sy = SCREENY(jy);
3198 int sxx = 0, syy = 0;
3199 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
3201 int action = ACTION_DEFAULT;
3202 int last_player_graphic = getPlayerGraphic(player, move_dir);
3203 int last_player_frame = player->Frame;
3206 /* GfxElement[][] is set to the element the player is digging or collecting;
3207 remove also for off-screen player if the player is not moving anymore */
3208 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
3209 GfxElement[jx][jy] = EL_UNDEFINED;
3211 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
3215 if (!IN_LEV_FIELD(jx, jy))
3217 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
3218 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
3219 printf("DrawPlayerField(): This should never happen!\n");
3224 if (element == EL_EXPLOSION)
3227 action = (player->is_pushing ? ACTION_PUSHING :
3228 player->is_digging ? ACTION_DIGGING :
3229 player->is_collecting ? ACTION_COLLECTING :
3230 player->is_moving ? ACTION_MOVING :
3231 player->is_snapping ? ACTION_SNAPPING :
3232 player->is_dropping ? ACTION_DROPPING :
3233 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
3235 if (player->is_waiting)
3236 move_dir = player->dir_waiting;
3238 InitPlayerGfxAnimation(player, action, move_dir);
3240 /* ----------------------------------------------------------------------- */
3241 /* draw things in the field the player is leaving, if needed */
3242 /* ----------------------------------------------------------------------- */
3244 if (player->is_moving)
3246 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
3248 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
3250 if (last_element == EL_DYNAMITE_ACTIVE ||
3251 last_element == EL_EM_DYNAMITE_ACTIVE ||
3252 last_element == EL_SP_DISK_RED_ACTIVE)
3253 DrawDynamite(last_jx, last_jy);
3255 DrawLevelFieldThruMask(last_jx, last_jy);
3257 else if (last_element == EL_DYNAMITE_ACTIVE ||
3258 last_element == EL_EM_DYNAMITE_ACTIVE ||
3259 last_element == EL_SP_DISK_RED_ACTIVE)
3260 DrawDynamite(last_jx, last_jy);
3262 /* !!! this is not enough to prevent flickering of players which are
3263 moving next to each others without a free tile between them -- this
3264 can only be solved by drawing all players layer by layer (first the
3265 background, then the foreground etc.) !!! => TODO */
3266 else if (!IS_PLAYER(last_jx, last_jy))
3267 DrawLevelField(last_jx, last_jy);
3270 DrawLevelField(last_jx, last_jy);
3273 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
3274 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
3277 if (!IN_SCR_FIELD(sx, sy))
3280 /* ----------------------------------------------------------------------- */
3281 /* draw things behind the player, if needed */
3282 /* ----------------------------------------------------------------------- */
3285 DrawLevelElement(jx, jy, Back[jx][jy]);
3286 else if (IS_ACTIVE_BOMB(element))
3287 DrawLevelElement(jx, jy, EL_EMPTY);
3290 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
3292 int old_element = GfxElement[jx][jy];
3293 int old_graphic = el_act_dir2img(old_element, action, move_dir);
3294 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
3296 if (GFX_CRUMBLED(old_element))
3297 DrawLevelFieldCrumbledDigging(jx, jy, move_dir, player->StepFrame);
3299 DrawGraphic(sx, sy, old_graphic, frame);
3301 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
3302 player_is_opaque = TRUE;
3306 GfxElement[jx][jy] = EL_UNDEFINED;
3308 /* make sure that pushed elements are drawn with correct frame rate */
3309 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
3311 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
3312 GfxFrame[jx][jy] = player->StepFrame;
3314 DrawLevelField(jx, jy);
3318 #if !DRAW_PLAYER_OVER_PUSHED_ELEMENT
3319 /* ----------------------------------------------------------------------- */
3320 /* draw player himself */
3321 /* ----------------------------------------------------------------------- */
3323 graphic = getPlayerGraphic(player, move_dir);
3325 /* in the case of changed player action or direction, prevent the current
3326 animation frame from being restarted for identical animations */
3327 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
3328 player->Frame = last_player_frame;
3330 frame = getGraphicAnimationFrame(graphic, player->Frame);
3334 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3335 sxx = player->GfxPos;
3337 syy = player->GfxPos;
3340 if (player_is_opaque)
3341 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
3343 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3345 if (SHIELD_ON(player))
3347 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
3348 IMG_SHIELD_NORMAL_ACTIVE);
3349 int frame = getGraphicAnimationFrame(graphic, -1);
3351 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3355 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
3358 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3359 sxx = player->GfxPos;
3361 syy = player->GfxPos;
3365 /* ----------------------------------------------------------------------- */
3366 /* draw things the player is pushing, if needed */
3367 /* ----------------------------------------------------------------------- */
3369 if (player->is_pushing && player->is_moving)
3371 int px = SCREENX(jx), py = SCREENY(jy);
3372 int pxx = (TILEX - ABS(sxx)) * dx;
3373 int pyy = (TILEY - ABS(syy)) * dy;
3374 int gfx_frame = GfxFrame[jx][jy];
3380 if (!IS_MOVING(jx, jy)) /* push movement already finished */
3382 element = Feld[next_jx][next_jy];
3383 gfx_frame = GfxFrame[next_jx][next_jy];
3386 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
3388 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
3389 frame = getGraphicAnimationFrame(graphic, sync_frame);
3391 /* draw background element under pushed element (like the Sokoban field) */
3392 if (game.use_masked_pushing && IS_MOVING(jx, jy))
3394 /* this allows transparent pushing animation over non-black background */
3397 DrawLevelElement(jx, jy, Back[jx][jy]);
3399 DrawLevelElement(jx, jy, EL_EMPTY);
3401 if (Back[next_jx][next_jy])
3402 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3404 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
3406 else if (Back[next_jx][next_jy])
3407 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3410 /* do not draw (EM style) pushing animation when pushing is finished */
3411 /* (two-tile animations usually do not contain start and end frame) */
3412 if (graphic_info[graphic].double_movement && !IS_MOVING(jx, jy))
3413 DrawLevelElement(next_jx, next_jy, Feld[next_jx][next_jy]);
3415 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3417 /* masked drawing is needed for EMC style (double) movement graphics */
3418 /* !!! (ONLY WHEN DRAWING PUSHED ELEMENT OVER THE PLAYER) !!! */
3419 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3423 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
3424 /* ----------------------------------------------------------------------- */
3425 /* draw player himself */
3426 /* ----------------------------------------------------------------------- */
3428 graphic = getPlayerGraphic(player, move_dir);
3430 /* in the case of changed player action or direction, prevent the current
3431 animation frame from being restarted for identical animations */
3432 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
3433 player->Frame = last_player_frame;
3435 frame = getGraphicAnimationFrame(graphic, player->Frame);
3439 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3440 sxx = player->GfxPos;
3442 syy = player->GfxPos;
3445 if (player_is_opaque)
3446 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
3448 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3450 if (SHIELD_ON(player))
3452 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
3453 IMG_SHIELD_NORMAL_ACTIVE);
3454 int frame = getGraphicAnimationFrame(graphic, -1);
3456 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3460 /* ----------------------------------------------------------------------- */
3461 /* draw things in front of player (active dynamite or dynabombs) */
3462 /* ----------------------------------------------------------------------- */
3464 if (IS_ACTIVE_BOMB(element))
3466 graphic = el2img(element);
3467 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
3469 if (game.emulation == EMU_SUPAPLEX)
3470 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
3472 DrawGraphicThruMask(sx, sy, graphic, frame);
3475 if (player_is_moving && last_element == EL_EXPLOSION)
3477 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
3478 GfxElement[last_jx][last_jy] : EL_EMPTY);
3479 int graphic = el_act2img(element, ACTION_EXPLODING);
3480 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
3481 int phase = ExplodePhase[last_jx][last_jy] - 1;
3482 int frame = getGraphicAnimationFrame(graphic, phase - delay);
3485 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
3488 /* ----------------------------------------------------------------------- */
3489 /* draw elements the player is just walking/passing through/under */
3490 /* ----------------------------------------------------------------------- */
3492 if (player_is_moving)
3494 /* handle the field the player is leaving ... */
3495 if (IS_ACCESSIBLE_INSIDE(last_element))
3496 DrawLevelField(last_jx, last_jy);
3497 else if (IS_ACCESSIBLE_UNDER(last_element))
3498 DrawLevelFieldThruMask(last_jx, last_jy);
3501 /* do not redraw accessible elements if the player is just pushing them */
3502 if (!player_is_moving || !player->is_pushing)
3504 /* ... and the field the player is entering */
3505 if (IS_ACCESSIBLE_INSIDE(element))
3506 DrawLevelField(jx, jy);
3507 else if (IS_ACCESSIBLE_UNDER(element))
3508 DrawLevelFieldThruMask(jx, jy);
3511 MarkTileDirty(sx, sy);
3514 /* ------------------------------------------------------------------------- */
3516 void WaitForEventToContinue()
3518 boolean still_wait = TRUE;
3520 /* simulate releasing mouse button over last gadget, if still pressed */
3522 HandleGadgets(-1, -1, 0);
3524 button_status = MB_RELEASED;
3538 case EVENT_BUTTONPRESS:
3539 case EVENT_KEYPRESS:
3543 case EVENT_KEYRELEASE:
3544 ClearPlayerAction();
3548 HandleOtherEvents(&event);
3552 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3561 #define MAX_REQUEST_LINES 13
3562 #define MAX_REQUEST_LINE_FONT1_LEN 7
3563 #define MAX_REQUEST_LINE_FONT2_LEN 10
3565 static int RequestHandleEvents(unsigned int req_state)
3567 boolean level_solved = (game_status == GAME_MODE_PLAYING &&
3568 local_player->LevelSolved_GameEnd);
3569 int width = request.width;
3570 int height = request.height;
3574 setRequestPosition(&sx, &sy, FALSE);
3576 button_status = MB_RELEASED;
3578 request_gadget_id = -1;
3585 SetDrawtoField(DRAW_TO_FIELDBUFFER);
3587 HandleGameActions();
3589 SetDrawtoField(DRAW_TO_BACKBUFFER);
3591 if (global.use_envelope_request)
3593 /* copy current state of request area to middle of playfield area */
3594 BlitBitmap(bitmap_db_store_2, drawto, sx, sy, width, height, sx, sy);
3602 while (NextValidEvent(&event))
3606 case EVENT_BUTTONPRESS:
3607 case EVENT_BUTTONRELEASE:
3608 case EVENT_MOTIONNOTIFY:
3612 if (event.type == EVENT_MOTIONNOTIFY)
3617 motion_status = TRUE;
3618 mx = ((MotionEvent *) &event)->x;
3619 my = ((MotionEvent *) &event)->y;
3623 motion_status = FALSE;
3624 mx = ((ButtonEvent *) &event)->x;
3625 my = ((ButtonEvent *) &event)->y;
3626 if (event.type == EVENT_BUTTONPRESS)
3627 button_status = ((ButtonEvent *) &event)->button;
3629 button_status = MB_RELEASED;
3632 /* this sets 'request_gadget_id' */
3633 HandleGadgets(mx, my, button_status);
3635 switch (request_gadget_id)
3637 case TOOL_CTRL_ID_YES:
3640 case TOOL_CTRL_ID_NO:
3643 case TOOL_CTRL_ID_CONFIRM:
3644 result = TRUE | FALSE;
3647 case TOOL_CTRL_ID_PLAYER_1:
3650 case TOOL_CTRL_ID_PLAYER_2:
3653 case TOOL_CTRL_ID_PLAYER_3:
3656 case TOOL_CTRL_ID_PLAYER_4:
3667 case EVENT_KEYPRESS:
3669 Key key = GetEventKey((KeyEvent *)&event, TRUE);
3674 if (req_state & REQ_CONFIRM)
3679 #if defined(TARGET_SDL2)
3686 #if defined(TARGET_SDL2)
3693 HandleKeysDebug(key);
3697 if (req_state & REQ_PLAYER)
3703 case EVENT_KEYRELEASE:
3704 ClearPlayerAction();
3708 HandleOtherEvents(&event);
3713 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3715 int joy = AnyJoystick();
3717 if (joy & JOY_BUTTON_1)
3719 else if (joy & JOY_BUTTON_2)
3725 if (global.use_envelope_request)
3727 /* copy back current state of pressed buttons inside request area */
3728 BlitBitmap(drawto, bitmap_db_store_2, sx, sy, width, height, sx, sy);
3738 static boolean RequestDoor(char *text, unsigned int req_state)
3740 unsigned int old_door_state;
3741 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
3742 int font_nr = FONT_TEXT_2;
3747 if (maxWordLengthInString(text) > MAX_REQUEST_LINE_FONT1_LEN)
3749 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
3750 font_nr = FONT_TEXT_1;
3753 if (game_status == GAME_MODE_PLAYING)
3754 BlitScreenToBitmap(backbuffer);
3756 /* disable deactivated drawing when quick-loading level tape recording */
3757 if (tape.playing && tape.deactivate_display)
3758 TapeDeactivateDisplayOff(TRUE);
3760 SetMouseCursor(CURSOR_DEFAULT);
3762 #if defined(NETWORK_AVALIABLE)
3763 /* pause network game while waiting for request to answer */
3764 if (options.network &&
3765 game_status == GAME_MODE_PLAYING &&
3766 req_state & REQUEST_WAIT_FOR_INPUT)
3767 SendToServer_PausePlaying();
3770 old_door_state = GetDoorState();
3772 /* simulate releasing mouse button over last gadget, if still pressed */
3774 HandleGadgets(-1, -1, 0);
3778 /* draw released gadget before proceeding */
3781 if (old_door_state & DOOR_OPEN_1)
3783 CloseDoor(DOOR_CLOSE_1);
3785 /* save old door content */
3786 BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
3787 0 * DXSIZE, 0, DXSIZE, DYSIZE, 1 * DXSIZE, 0);
3790 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
3791 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3793 /* clear door drawing field */
3794 DrawBackground(DX, DY, DXSIZE, DYSIZE);
3796 /* force DOOR font inside door area */
3797 SetFontStatus(GAME_MODE_PSEUDO_DOOR);
3799 /* write text for request */
3800 for (text_ptr = text, ty = 0; ty < MAX_REQUEST_LINES; ty++)
3802 char text_line[max_request_line_len + 1];
3808 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
3810 tc = *(text_ptr + tx);
3811 // if (!tc || tc == ' ')
3812 if (!tc || tc == ' ' || tc == '?' || tc == '!')
3816 if ((tc == '?' || tc == '!') && tl == 0)
3826 strncpy(text_line, text_ptr, tl);
3829 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
3830 DY + 8 + ty * (getFontHeight(font_nr) + 2),
3831 text_line, font_nr);
3833 text_ptr += tl + (tc == ' ' ? 1 : 0);
3834 // text_ptr += tl + (tc == ' ' || tc == '?' || tc == '!' ? 1 : 0);
3839 if (req_state & REQ_ASK)
3841 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
3842 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
3844 else if (req_state & REQ_CONFIRM)
3846 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
3848 else if (req_state & REQ_PLAYER)
3850 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
3851 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
3852 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
3853 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
3856 /* copy request gadgets to door backbuffer */
3857 BlitBitmap(drawto, bitmap_db_door_1, DX, DY, DXSIZE, DYSIZE, 0, 0);
3859 OpenDoor(DOOR_OPEN_1);
3861 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
3863 if (game_status == GAME_MODE_PLAYING)
3865 SetPanelBackground();
3866 SetDrawBackgroundMask(REDRAW_DOOR_1);
3870 SetDrawBackgroundMask(REDRAW_FIELD);
3876 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3878 // ---------- handle request buttons ----------
3879 result = RequestHandleEvents(req_state);
3883 if (!(req_state & REQ_STAY_OPEN))
3885 CloseDoor(DOOR_CLOSE_1);
3887 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
3888 (req_state & REQ_REOPEN))
3889 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
3894 if (game_status == GAME_MODE_PLAYING)
3896 SetPanelBackground();
3897 SetDrawBackgroundMask(REDRAW_DOOR_1);
3901 SetDrawBackgroundMask(REDRAW_FIELD);
3904 #if defined(NETWORK_AVALIABLE)
3905 /* continue network game after request */
3906 if (options.network &&
3907 game_status == GAME_MODE_PLAYING &&
3908 req_state & REQUEST_WAIT_FOR_INPUT)
3909 SendToServer_ContinuePlaying();
3912 /* restore deactivated drawing when quick-loading level tape recording */
3913 if (tape.playing && tape.deactivate_display)
3914 TapeDeactivateDisplayOn();
3919 static boolean RequestEnvelope(char *text, unsigned int req_state)
3923 if (game_status == GAME_MODE_PLAYING)
3924 BlitScreenToBitmap(backbuffer);
3926 /* disable deactivated drawing when quick-loading level tape recording */
3927 if (tape.playing && tape.deactivate_display)
3928 TapeDeactivateDisplayOff(TRUE);
3930 SetMouseCursor(CURSOR_DEFAULT);
3932 #if defined(NETWORK_AVALIABLE)
3933 /* pause network game while waiting for request to answer */
3934 if (options.network &&
3935 game_status == GAME_MODE_PLAYING &&
3936 req_state & REQUEST_WAIT_FOR_INPUT)
3937 SendToServer_PausePlaying();
3940 /* simulate releasing mouse button over last gadget, if still pressed */
3942 HandleGadgets(-1, -1, 0);
3946 // (replace with setting corresponding request background)
3947 // SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
3948 // SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3950 /* clear door drawing field */
3951 // DrawBackground(DX, DY, DXSIZE, DYSIZE);
3953 ShowEnvelopeRequest(text, req_state, ACTION_OPENING);
3955 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
3957 if (game_status == GAME_MODE_PLAYING)
3959 SetPanelBackground();
3960 SetDrawBackgroundMask(REDRAW_DOOR_1);
3964 SetDrawBackgroundMask(REDRAW_FIELD);
3970 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3972 // ---------- handle request buttons ----------
3973 result = RequestHandleEvents(req_state);
3977 ShowEnvelopeRequest(text, req_state, ACTION_CLOSING);
3981 if (game_status == GAME_MODE_PLAYING)
3983 SetPanelBackground();
3984 SetDrawBackgroundMask(REDRAW_DOOR_1);
3988 SetDrawBackgroundMask(REDRAW_FIELD);
3991 #if defined(NETWORK_AVALIABLE)
3992 /* continue network game after request */
3993 if (options.network &&
3994 game_status == GAME_MODE_PLAYING &&
3995 req_state & REQUEST_WAIT_FOR_INPUT)
3996 SendToServer_ContinuePlaying();
3999 /* restore deactivated drawing when quick-loading level tape recording */
4000 if (tape.playing && tape.deactivate_display)
4001 TapeDeactivateDisplayOn();
4006 boolean Request(char *text, unsigned int req_state)
4008 if (global.use_envelope_request)
4009 return RequestEnvelope(text, req_state);
4011 return RequestDoor(text, req_state);
4014 static int compareDoorPartOrderInfo(const void *object1, const void *object2)
4016 const struct DoorPartOrderInfo *dpo1 = (struct DoorPartOrderInfo *)object1;
4017 const struct DoorPartOrderInfo *dpo2 = (struct DoorPartOrderInfo *)object2;
4020 if (dpo1->sort_priority != dpo2->sort_priority)
4021 compare_result = dpo1->sort_priority - dpo2->sort_priority;
4023 compare_result = dpo1->nr - dpo2->nr;
4025 return compare_result;
4028 void InitGraphicCompatibilityInfo_Doors()
4034 struct DoorInfo *door;
4038 { DOOR_1, IMG_GFX_DOOR_1_PART_1, IMG_GFX_DOOR_1_PART_8, &door_1 },
4039 { DOOR_2, IMG_GFX_DOOR_2_PART_1, IMG_GFX_DOOR_2_PART_8, &door_2 },
4041 { -1, -1, -1, NULL }
4043 struct Rect door_rect_list[] =
4045 { DX, DY, DXSIZE, DYSIZE },
4046 { VX, VY, VXSIZE, VYSIZE }
4050 for (i = 0; doors[i].door_token != -1; i++)
4052 int door_token = doors[i].door_token;
4053 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
4054 int part_1 = doors[i].part_1;
4055 int part_8 = doors[i].part_8;
4056 int part_2 = part_1 + 1;
4057 int part_3 = part_1 + 2;
4058 struct DoorInfo *door = doors[i].door;
4059 struct Rect *door_rect = &door_rect_list[door_index];
4060 boolean door_gfx_redefined = FALSE;
4062 /* check if any door part graphic definitions have been redefined */
4064 for (j = 0; door_part_controls[j].door_token != -1; j++)
4066 struct DoorPartControlInfo *dpc = &door_part_controls[j];
4067 struct FileInfo *fi = getImageListEntryFromImageID(dpc->graphic);
4069 if (dpc->door_token == door_token && fi->redefined)
4070 door_gfx_redefined = TRUE;
4073 /* check for old-style door graphic/animation modifications */
4075 if (!door_gfx_redefined)
4077 if (door->anim_mode & ANIM_STATIC_PANEL)
4079 door->panel.step_xoffset = 0;
4080 door->panel.step_yoffset = 0;
4083 if (door->anim_mode & (ANIM_HORIZONTAL | ANIM_VERTICAL))
4085 struct GraphicInfo *g_part_1 = &graphic_info[part_1];
4086 struct GraphicInfo *g_part_2 = &graphic_info[part_2];
4087 int num_door_steps, num_panel_steps;
4089 /* remove door part graphics other than the two default wings */
4091 for (j = 0; door_part_controls[j].door_token != -1; j++)
4093 struct DoorPartControlInfo *dpc = &door_part_controls[j];
4094 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4096 if (dpc->graphic >= part_3 &&
4097 dpc->graphic <= part_8)
4101 /* set graphics and screen positions of the default wings */
4103 g_part_1->width = door_rect->width;
4104 g_part_1->height = door_rect->height;
4105 g_part_2->width = door_rect->width;
4106 g_part_2->height = door_rect->height;
4107 g_part_2->src_x = door_rect->width;
4108 g_part_2->src_y = g_part_1->src_y;
4110 door->part_2.x = door->part_1.x;
4111 door->part_2.y = door->part_1.y;
4113 if (door->width != -1)
4115 g_part_1->width = door->width;
4116 g_part_2->width = door->width;
4118 // special treatment for graphics and screen position of right wing
4119 g_part_2->src_x += door_rect->width - door->width;
4120 door->part_2.x += door_rect->width - door->width;
4123 if (door->height != -1)
4125 g_part_1->height = door->height;
4126 g_part_2->height = door->height;
4128 // special treatment for graphics and screen position of bottom wing
4129 g_part_2->src_y += door_rect->height - door->height;
4130 door->part_2.y += door_rect->height - door->height;
4133 /* set animation delays for the default wings and panels */
4135 door->part_1.step_delay = door->step_delay;
4136 door->part_2.step_delay = door->step_delay;
4137 door->panel.step_delay = door->step_delay;
4139 /* set animation draw order for the default wings */
4141 door->part_1.sort_priority = 2; /* draw left wing over ... */
4142 door->part_2.sort_priority = 1; /* ... right wing */
4144 /* set animation draw offset for the default wings */
4146 if (door->anim_mode & ANIM_HORIZONTAL)
4148 door->part_1.step_xoffset = door->step_offset;
4149 door->part_1.step_yoffset = 0;
4150 door->part_2.step_xoffset = door->step_offset * -1;
4151 door->part_2.step_yoffset = 0;
4153 num_door_steps = g_part_1->width / door->step_offset;
4155 else // ANIM_VERTICAL
4157 door->part_1.step_xoffset = 0;
4158 door->part_1.step_yoffset = door->step_offset;
4159 door->part_2.step_xoffset = 0;
4160 door->part_2.step_yoffset = door->step_offset * -1;
4162 num_door_steps = g_part_1->height / door->step_offset;
4165 /* set animation draw offset for the default panels */
4167 if (door->step_offset > 1)
4169 num_panel_steps = 2 * door_rect->height / door->step_offset;
4170 door->panel.start_step = num_panel_steps - num_door_steps;
4171 door->panel.start_step_closing = door->panel.start_step;
4175 num_panel_steps = door_rect->height / door->step_offset;
4176 door->panel.start_step = num_panel_steps - num_door_steps / 2;
4177 door->panel.start_step_closing = door->panel.start_step;
4178 door->panel.step_delay *= 2;
4189 for (i = 0; door_part_controls[i].door_token != -1; i++)
4191 struct DoorPartControlInfo *dpc = &door_part_controls[i];
4192 struct DoorPartOrderInfo *dpo = &door_part_order[i];
4194 /* initialize "start_step_opening" and "start_step_closing", if needed */
4195 if (dpc->pos->start_step_opening == 0 &&
4196 dpc->pos->start_step_closing == 0)
4198 // dpc->pos->start_step_opening = dpc->pos->start_step;
4199 dpc->pos->start_step_closing = dpc->pos->start_step;
4202 /* fill structure for door part draw order (sorted below) */
4204 dpo->sort_priority = dpc->pos->sort_priority;
4207 /* sort door part controls according to sort_priority and graphic number */
4208 qsort(door_part_order, MAX_DOOR_PARTS,
4209 sizeof(struct DoorPartOrderInfo), compareDoorPartOrderInfo);
4212 unsigned int OpenDoor(unsigned int door_state)
4214 if (door_state & DOOR_COPY_BACK)
4216 if (door_state & DOOR_OPEN_1)
4217 BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
4218 1 * DXSIZE, 0, DXSIZE, DYSIZE, 0 * DXSIZE, 0);
4220 if (door_state & DOOR_OPEN_2)
4221 BlitBitmap(bitmap_db_door_2, bitmap_db_door_2,
4222 1 * VXSIZE, 0, VXSIZE, VYSIZE, 0 * VXSIZE, 0);
4224 door_state &= ~DOOR_COPY_BACK;
4227 return MoveDoor(door_state);
4230 unsigned int CloseDoor(unsigned int door_state)
4232 unsigned int old_door_state = GetDoorState();
4234 if (!(door_state & DOOR_NO_COPY_BACK))
4236 if (old_door_state & DOOR_OPEN_1)
4237 BlitBitmap(backbuffer, bitmap_db_door_1,
4238 DX, DY, DXSIZE, DYSIZE, 0, 0);
4240 if (old_door_state & DOOR_OPEN_2)
4241 BlitBitmap(backbuffer, bitmap_db_door_2,
4242 VX, VY, VXSIZE, VYSIZE, 0, 0);
4244 door_state &= ~DOOR_NO_COPY_BACK;
4247 return MoveDoor(door_state);
4250 unsigned int GetDoorState()
4252 return MoveDoor(DOOR_GET_STATE);
4255 unsigned int SetDoorState(unsigned int door_state)
4257 return MoveDoor(door_state | DOOR_SET_STATE);
4260 int euclid(int a, int b)
4262 return (b ? euclid(b, a % b) : a);
4265 unsigned int MoveDoor(unsigned int door_state)
4267 struct Rect door_rect_list[] =
4269 { DX, DY, DXSIZE, DYSIZE },
4270 { VX, VY, VXSIZE, VYSIZE }
4272 static int door1 = DOOR_CLOSE_1;
4273 static int door2 = DOOR_CLOSE_2;
4274 unsigned int door_delay = 0;
4275 unsigned int door_delay_value;
4278 if (door_state == DOOR_GET_STATE)
4279 return (door1 | door2);
4281 if (door_state & DOOR_SET_STATE)
4283 if (door_state & DOOR_ACTION_1)
4284 door1 = door_state & DOOR_ACTION_1;
4285 if (door_state & DOOR_ACTION_2)
4286 door2 = door_state & DOOR_ACTION_2;
4288 return (door1 | door2);
4291 if (!(door_state & DOOR_FORCE_REDRAW))
4293 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
4294 door_state &= ~DOOR_OPEN_1;
4295 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
4296 door_state &= ~DOOR_CLOSE_1;
4297 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
4298 door_state &= ~DOOR_OPEN_2;
4299 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
4300 door_state &= ~DOOR_CLOSE_2;
4303 if (global.autoplay_leveldir)
4305 door_state |= DOOR_NO_DELAY;
4306 door_state &= ~DOOR_CLOSE_ALL;
4309 if (game_status == GAME_MODE_EDITOR)
4310 door_state |= DOOR_NO_DELAY;
4312 if (door_state & DOOR_ACTION)
4314 boolean door_panel_drawn[NUM_DOORS];
4315 boolean panel_has_doors[NUM_DOORS];
4316 boolean door_part_skip[MAX_DOOR_PARTS];
4317 boolean door_part_done[MAX_DOOR_PARTS];
4318 boolean door_part_done_all;
4319 int num_steps[MAX_DOOR_PARTS];
4320 int max_move_delay = 0; // delay for complete animations of all doors
4321 int max_step_delay = 0; // delay (ms) between two animation frames
4322 int num_move_steps = 0; // number of animation steps for all doors
4323 int max_move_delay_doors_only = 0; // delay for doors only (no panel)
4324 int num_move_steps_doors_only = 0; // steps for doors only (no panel)
4325 int current_move_delay = 0;
4329 for (i = 0; i < NUM_DOORS; i++)
4330 panel_has_doors[i] = FALSE;
4332 for (i = 0; i < MAX_DOOR_PARTS; i++)
4334 struct DoorPartControlInfo *dpc = &door_part_controls[i];
4335 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4336 int door_token = dpc->door_token;
4338 door_part_done[i] = FALSE;
4339 door_part_skip[i] = (!(door_state & door_token) ||
4343 for (i = 0; i < MAX_DOOR_PARTS; i++)
4345 int nr = door_part_order[i].nr;
4346 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
4347 struct DoorPartPosInfo *pos = dpc->pos;
4348 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4349 int door_token = dpc->door_token;
4350 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
4351 boolean is_panel = DOOR_PART_IS_PANEL(nr);
4352 int step_xoffset = ABS(pos->step_xoffset);
4353 int step_yoffset = ABS(pos->step_yoffset);
4354 int step_delay = pos->step_delay;
4355 int current_door_state = door_state & door_token;
4356 boolean door_opening = ((current_door_state & DOOR_OPEN) != 0);
4357 boolean door_closing = ((current_door_state & DOOR_CLOSE) != 0);
4358 boolean part_opening = (is_panel ? door_closing : door_opening);
4359 int start_step = (part_opening ? pos->start_step_opening :
4360 pos->start_step_closing);
4361 float move_xsize = (step_xoffset ? g->width : 0);
4362 float move_ysize = (step_yoffset ? g->height : 0);
4363 int move_xsteps = (step_xoffset ? ceil(move_xsize / step_xoffset) : 0);
4364 int move_ysteps = (step_yoffset ? ceil(move_ysize / step_yoffset) : 0);
4365 int move_steps = (move_xsteps && move_ysteps ?
4366 MIN(move_xsteps, move_ysteps) :
4367 move_xsteps ? move_xsteps : move_ysteps) - start_step;
4368 int move_delay = move_steps * step_delay;
4370 if (door_part_skip[nr])
4373 max_move_delay = MAX(max_move_delay, move_delay);
4374 max_step_delay = (max_step_delay == 0 ? step_delay :
4375 euclid(max_step_delay, step_delay));
4376 num_steps[nr] = move_steps;
4380 max_move_delay_doors_only = MAX(max_move_delay_doors_only, move_delay);
4382 panel_has_doors[door_index] = TRUE;
4386 max_step_delay = MAX(1, max_step_delay); // prevent division by zero
4388 num_move_steps = max_move_delay / max_step_delay;
4389 num_move_steps_doors_only = max_move_delay_doors_only / max_step_delay;
4391 door_delay_value = max_step_delay;
4393 if ((door_state & DOOR_NO_DELAY) || setup.quick_doors)
4395 start = num_move_steps - 1;
4399 /* opening door sound has priority over simultaneously closing door */
4400 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
4401 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
4402 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
4403 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
4406 for (k = start; k < num_move_steps; k++)
4408 int last_frame = num_move_steps - 1; // last frame of this "for" loop
4410 door_part_done_all = TRUE;
4412 for (i = 0; i < NUM_DOORS; i++)
4413 door_panel_drawn[i] = FALSE;
4415 for (i = 0; i < MAX_DOOR_PARTS; i++)
4417 int nr = door_part_order[i].nr;
4418 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
4419 struct DoorPartPosInfo *pos = dpc->pos;
4420 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4421 int door_token = dpc->door_token;
4422 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
4423 boolean is_panel = DOOR_PART_IS_PANEL(nr);
4424 boolean is_panel_and_door_has_closed = FALSE;
4425 struct Rect *door_rect = &door_rect_list[door_index];
4426 Bitmap *bitmap_db_door = (door_token == DOOR_1 ? bitmap_db_door_1 :
4428 Bitmap *bitmap = (is_panel ? bitmap_db_door : g->bitmap);
4429 int current_door_state = door_state & door_token;
4430 boolean door_opening = ((current_door_state & DOOR_OPEN) != 0);
4431 boolean door_closing = !door_opening;
4432 boolean part_opening = (is_panel ? door_closing : door_opening);
4433 boolean part_closing = !part_opening;
4434 int start_step = (part_opening ? pos->start_step_opening :
4435 pos->start_step_closing);
4436 int step_delay = pos->step_delay;
4437 int step_factor = step_delay / max_step_delay;
4438 int k1 = (step_factor ? k / step_factor + 1 : k);
4439 int k2 = (part_opening ? k1 + start_step : num_steps[nr] - k1);
4440 int kk = MAX(0, k2);
4443 int src_x, src_y, src_xx, src_yy;
4444 int dst_x, dst_y, dst_xx, dst_yy;
4447 if (door_part_skip[nr])
4450 if (!(door_state & door_token))
4458 int k2_door = (door_opening ? k : num_move_steps_doors_only - k - 1);
4459 int kk_door = MAX(0, k2_door);
4460 int sync_frame = kk_door * door_delay_value;
4461 int frame = getGraphicAnimationFrame(dpc->graphic, sync_frame);
4463 getGraphicSource(dpc->graphic, frame, &bitmap, &g_src_x, &g_src_y);
4468 if (!door_panel_drawn[door_index])
4470 ClearRectangle(drawto, door_rect->x, door_rect->y,
4471 door_rect->width, door_rect->height);
4473 door_panel_drawn[door_index] = TRUE;
4476 // draw opening or closing door parts
4478 if (pos->step_xoffset < 0) // door part on right side
4481 dst_xx = pos->x + ABS(kk * pos->step_xoffset);
4484 if (dst_xx + width > door_rect->width)
4485 width = door_rect->width - dst_xx;
4487 else // door part on left side
4490 dst_xx = pos->x - kk * pos->step_xoffset;
4494 src_xx = ABS(dst_xx);
4498 width = g->width - src_xx;
4500 if (width > door_rect->width)
4501 width = door_rect->width;
4503 // printf("::: k == %d [%d] \n", k, start_step);
4506 if (pos->step_yoffset < 0) // door part on bottom side
4509 dst_yy = pos->y + ABS(kk * pos->step_yoffset);
4512 if (dst_yy + height > door_rect->height)
4513 height = door_rect->height - dst_yy;
4515 else // door part on top side
4518 dst_yy = pos->y - kk * pos->step_yoffset;
4522 src_yy = ABS(dst_yy);
4526 height = g->height - src_yy;
4529 src_x = g_src_x + src_xx;
4530 src_y = g_src_y + src_yy;
4532 dst_x = door_rect->x + dst_xx;
4533 dst_y = door_rect->y + dst_yy;
4535 is_panel_and_door_has_closed =
4538 panel_has_doors[door_index] &&
4539 k >= num_move_steps_doors_only - 1);
4541 if (width >= 0 && width <= g->width &&
4542 height >= 0 && height <= g->height &&
4543 !is_panel_and_door_has_closed)
4545 if (is_panel || !pos->draw_masked)
4546 BlitBitmap(bitmap, drawto, src_x, src_y, width, height,
4549 BlitBitmapMasked(bitmap, drawto, src_x, src_y, width, height,
4553 redraw_mask |= REDRAW_DOOR_FROM_TOKEN(door_token);
4555 if ((part_opening && (width < 0 || height < 0)) ||
4556 (part_closing && (width >= g->width && height >= g->height)))
4557 door_part_done[nr] = TRUE;
4559 // continue door part animations, but not panel after door has closed
4560 if (!door_part_done[nr] && !is_panel_and_door_has_closed)
4561 door_part_done_all = FALSE;
4564 if (!(door_state & DOOR_NO_DELAY))
4568 SkipUntilDelayReached(&door_delay, door_delay_value, &k, last_frame);
4570 current_move_delay += max_step_delay;
4573 if (door_part_done_all)
4578 if (door_state & DOOR_ACTION_1)
4579 door1 = door_state & DOOR_ACTION_1;
4580 if (door_state & DOOR_ACTION_2)
4581 door2 = door_state & DOOR_ACTION_2;
4583 // draw masked border over door area
4584 DrawMaskedBorder(REDRAW_DOOR_1);
4585 DrawMaskedBorder(REDRAW_DOOR_2);
4587 return (door1 | door2);
4590 static boolean useSpecialEditorDoor()
4592 int graphic = IMG_GLOBAL_BORDER_EDITOR;
4593 boolean redefined = getImageListEntryFromImageID(graphic)->redefined;
4595 // do not draw special editor door if editor border defined or redefined
4596 if (graphic_info[graphic].bitmap != NULL || redefined)
4599 // do not draw special editor door if global border defined to be empty
4600 if (graphic_info[IMG_GLOBAL_BORDER].bitmap == NULL)
4603 // do not draw special editor door if viewport definitions do not match
4607 EY + EYSIZE != VY + VYSIZE)
4613 void DrawSpecialEditorDoor()
4615 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
4616 int top_border_width = gfx1->width;
4617 int top_border_height = gfx1->height;
4618 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
4619 int ex = EX - outer_border;
4620 int ey = EY - outer_border;
4621 int vy = VY - outer_border;
4622 int exsize = EXSIZE + 2 * outer_border;
4624 if (!useSpecialEditorDoor())
4627 /* draw bigger level editor toolbox window */
4628 BlitBitmap(gfx1->bitmap, drawto, gfx1->src_x, gfx1->src_y,
4629 top_border_width, top_border_height, ex, ey - top_border_height);
4630 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto, ex, vy,
4631 exsize, EYSIZE - VYSIZE + outer_border, ex, ey);
4633 redraw_mask |= REDRAW_ALL;
4636 void UndrawSpecialEditorDoor()
4638 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
4639 int top_border_width = gfx1->width;
4640 int top_border_height = gfx1->height;
4641 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
4642 int ex = EX - outer_border;
4643 int ey = EY - outer_border;
4644 int ey_top = ey - top_border_height;
4645 int exsize = EXSIZE + 2 * outer_border;
4646 int eysize = EYSIZE + 2 * outer_border;
4648 if (!useSpecialEditorDoor())
4651 /* draw normal tape recorder window */
4652 if (graphic_info[IMG_GLOBAL_BORDER].bitmap)
4654 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
4655 ex, ey_top, top_border_width, top_border_height,
4657 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
4658 ex, ey, exsize, eysize, ex, ey);
4662 // if screen background is set to "[NONE]", clear editor toolbox window
4663 ClearRectangle(drawto, ex, ey_top, top_border_width, top_border_height);
4664 ClearRectangle(drawto, ex, ey, exsize, eysize);
4667 redraw_mask |= REDRAW_ALL;
4671 /* ---------- new tool button stuff ---------------------------------------- */
4676 struct TextPosInfo *pos;
4679 } toolbutton_info[NUM_TOOL_BUTTONS] =
4682 IMG_GFX_REQUEST_BUTTON_YES, &request.button.yes,
4683 TOOL_CTRL_ID_YES, "yes"
4686 IMG_GFX_REQUEST_BUTTON_NO, &request.button.no,
4687 TOOL_CTRL_ID_NO, "no"
4690 IMG_GFX_REQUEST_BUTTON_CONFIRM, &request.button.confirm,
4691 TOOL_CTRL_ID_CONFIRM, "confirm"
4694 IMG_GFX_REQUEST_BUTTON_PLAYER_1, &request.button.player_1,
4695 TOOL_CTRL_ID_PLAYER_1, "player 1"
4698 IMG_GFX_REQUEST_BUTTON_PLAYER_2, &request.button.player_2,
4699 TOOL_CTRL_ID_PLAYER_2, "player 2"
4702 IMG_GFX_REQUEST_BUTTON_PLAYER_3, &request.button.player_3,
4703 TOOL_CTRL_ID_PLAYER_3, "player 3"
4706 IMG_GFX_REQUEST_BUTTON_PLAYER_4, &request.button.player_4,
4707 TOOL_CTRL_ID_PLAYER_4, "player 4"
4711 void CreateToolButtons()
4715 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4717 struct GraphicInfo *gfx = &graphic_info[toolbutton_info[i].graphic];
4718 struct TextPosInfo *pos = toolbutton_info[i].pos;
4719 struct GadgetInfo *gi;
4720 Bitmap *deco_bitmap = None;
4721 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
4722 unsigned int event_mask = GD_EVENT_RELEASED;
4725 int gd_x = gfx->src_x;
4726 int gd_y = gfx->src_y;
4727 int gd_xp = gfx->src_x + gfx->pressed_xoffset;
4728 int gd_yp = gfx->src_y + gfx->pressed_yoffset;
4731 if (global.use_envelope_request)
4732 setRequestPosition(&dx, &dy, TRUE);
4734 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
4736 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
4738 getSizedGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr), 0,
4739 pos->size, &deco_bitmap, &deco_x, &deco_y);
4740 deco_xpos = (gfx->width - pos->size) / 2;
4741 deco_ypos = (gfx->height - pos->size) / 2;
4744 gi = CreateGadget(GDI_CUSTOM_ID, id,
4745 GDI_INFO_TEXT, toolbutton_info[i].infotext,
4746 GDI_X, dx + GDI_ACTIVE_POS(pos->x),
4747 GDI_Y, dy + GDI_ACTIVE_POS(pos->y),
4748 GDI_WIDTH, gfx->width,
4749 GDI_HEIGHT, gfx->height,
4750 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
4751 GDI_STATE, GD_BUTTON_UNPRESSED,
4752 GDI_DESIGN_UNPRESSED, gfx->bitmap, gd_x, gd_y,
4753 GDI_DESIGN_PRESSED, gfx->bitmap, gd_xp, gd_yp,
4754 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
4755 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
4756 GDI_DECORATION_SIZE, pos->size, pos->size,
4757 GDI_DECORATION_SHIFTING, 1, 1,
4758 GDI_DIRECT_DRAW, FALSE,
4759 GDI_EVENT_MASK, event_mask,
4760 GDI_CALLBACK_ACTION, HandleToolButtons,
4764 Error(ERR_EXIT, "cannot create gadget");
4766 tool_gadget[id] = gi;
4770 void FreeToolButtons()
4774 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4775 FreeGadget(tool_gadget[i]);
4778 static void UnmapToolButtons()
4782 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4783 UnmapGadget(tool_gadget[i]);
4786 static void HandleToolButtons(struct GadgetInfo *gi)
4788 request_gadget_id = gi->custom_id;
4791 static struct Mapping_EM_to_RND_object
4794 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
4795 boolean is_backside; /* backside of moving element */
4801 em_object_mapping_list[] =
4804 Xblank, TRUE, FALSE,
4808 Yacid_splash_eB, FALSE, FALSE,
4809 EL_ACID_SPLASH_RIGHT, -1, -1
4812 Yacid_splash_wB, FALSE, FALSE,
4813 EL_ACID_SPLASH_LEFT, -1, -1
4816 #ifdef EM_ENGINE_BAD_ROLL
4818 Xstone_force_e, FALSE, FALSE,
4819 EL_ROCK, -1, MV_BIT_RIGHT
4822 Xstone_force_w, FALSE, FALSE,
4823 EL_ROCK, -1, MV_BIT_LEFT
4826 Xnut_force_e, FALSE, FALSE,
4827 EL_NUT, -1, MV_BIT_RIGHT
4830 Xnut_force_w, FALSE, FALSE,
4831 EL_NUT, -1, MV_BIT_LEFT
4834 Xspring_force_e, FALSE, FALSE,
4835 EL_SPRING, -1, MV_BIT_RIGHT
4838 Xspring_force_w, FALSE, FALSE,
4839 EL_SPRING, -1, MV_BIT_LEFT
4842 Xemerald_force_e, FALSE, FALSE,
4843 EL_EMERALD, -1, MV_BIT_RIGHT
4846 Xemerald_force_w, FALSE, FALSE,
4847 EL_EMERALD, -1, MV_BIT_LEFT
4850 Xdiamond_force_e, FALSE, FALSE,
4851 EL_DIAMOND, -1, MV_BIT_RIGHT
4854 Xdiamond_force_w, FALSE, FALSE,
4855 EL_DIAMOND, -1, MV_BIT_LEFT
4858 Xbomb_force_e, FALSE, FALSE,
4859 EL_BOMB, -1, MV_BIT_RIGHT
4862 Xbomb_force_w, FALSE, FALSE,
4863 EL_BOMB, -1, MV_BIT_LEFT
4865 #endif /* EM_ENGINE_BAD_ROLL */
4868 Xstone, TRUE, FALSE,
4872 Xstone_pause, FALSE, FALSE,
4876 Xstone_fall, FALSE, FALSE,
4880 Ystone_s, FALSE, FALSE,
4881 EL_ROCK, ACTION_FALLING, -1
4884 Ystone_sB, FALSE, TRUE,
4885 EL_ROCK, ACTION_FALLING, -1
4888 Ystone_e, FALSE, FALSE,
4889 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
4892 Ystone_eB, FALSE, TRUE,
4893 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
4896 Ystone_w, FALSE, FALSE,
4897 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
4900 Ystone_wB, FALSE, TRUE,
4901 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
4908 Xnut_pause, FALSE, FALSE,
4912 Xnut_fall, FALSE, FALSE,
4916 Ynut_s, FALSE, FALSE,
4917 EL_NUT, ACTION_FALLING, -1
4920 Ynut_sB, FALSE, TRUE,
4921 EL_NUT, ACTION_FALLING, -1
4924 Ynut_e, FALSE, FALSE,
4925 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
4928 Ynut_eB, FALSE, TRUE,
4929 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
4932 Ynut_w, FALSE, FALSE,
4933 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
4936 Ynut_wB, FALSE, TRUE,
4937 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
4940 Xbug_n, TRUE, FALSE,
4944 Xbug_e, TRUE, FALSE,
4945 EL_BUG_RIGHT, -1, -1
4948 Xbug_s, TRUE, FALSE,
4952 Xbug_w, TRUE, FALSE,
4956 Xbug_gon, FALSE, FALSE,
4960 Xbug_goe, FALSE, FALSE,
4961 EL_BUG_RIGHT, -1, -1
4964 Xbug_gos, FALSE, FALSE,
4968 Xbug_gow, FALSE, FALSE,
4972 Ybug_n, FALSE, FALSE,
4973 EL_BUG, ACTION_MOVING, MV_BIT_UP
4976 Ybug_nB, FALSE, TRUE,
4977 EL_BUG, ACTION_MOVING, MV_BIT_UP
4980 Ybug_e, FALSE, FALSE,
4981 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
4984 Ybug_eB, FALSE, TRUE,
4985 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
4988 Ybug_s, FALSE, FALSE,
4989 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
4992 Ybug_sB, FALSE, TRUE,
4993 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
4996 Ybug_w, FALSE, FALSE,
4997 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
5000 Ybug_wB, FALSE, TRUE,
5001 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
5004 Ybug_w_n, FALSE, FALSE,
5005 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
5008 Ybug_n_e, FALSE, FALSE,
5009 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
5012 Ybug_e_s, FALSE, FALSE,
5013 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
5016 Ybug_s_w, FALSE, FALSE,
5017 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
5020 Ybug_e_n, FALSE, FALSE,
5021 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
5024 Ybug_s_e, FALSE, FALSE,
5025 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
5028 Ybug_w_s, FALSE, FALSE,
5029 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
5032 Ybug_n_w, FALSE, FALSE,
5033 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
5036 Ybug_stone, FALSE, FALSE,
5037 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
5040 Ybug_spring, FALSE, FALSE,
5041 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
5044 Xtank_n, TRUE, FALSE,
5045 EL_SPACESHIP_UP, -1, -1
5048 Xtank_e, TRUE, FALSE,
5049 EL_SPACESHIP_RIGHT, -1, -1
5052 Xtank_s, TRUE, FALSE,
5053 EL_SPACESHIP_DOWN, -1, -1
5056 Xtank_w, TRUE, FALSE,
5057 EL_SPACESHIP_LEFT, -1, -1
5060 Xtank_gon, FALSE, FALSE,
5061 EL_SPACESHIP_UP, -1, -1
5064 Xtank_goe, FALSE, FALSE,
5065 EL_SPACESHIP_RIGHT, -1, -1
5068 Xtank_gos, FALSE, FALSE,
5069 EL_SPACESHIP_DOWN, -1, -1
5072 Xtank_gow, FALSE, FALSE,
5073 EL_SPACESHIP_LEFT, -1, -1
5076 Ytank_n, FALSE, FALSE,
5077 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
5080 Ytank_nB, FALSE, TRUE,
5081 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
5084 Ytank_e, FALSE, FALSE,
5085 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
5088 Ytank_eB, FALSE, TRUE,
5089 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
5092 Ytank_s, FALSE, FALSE,
5093 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
5096 Ytank_sB, FALSE, TRUE,
5097 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
5100 Ytank_w, FALSE, FALSE,
5101 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
5104 Ytank_wB, FALSE, TRUE,
5105 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
5108 Ytank_w_n, FALSE, FALSE,
5109 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
5112 Ytank_n_e, FALSE, FALSE,
5113 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
5116 Ytank_e_s, FALSE, FALSE,
5117 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
5120 Ytank_s_w, FALSE, FALSE,
5121 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
5124 Ytank_e_n, FALSE, FALSE,
5125 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
5128 Ytank_s_e, FALSE, FALSE,
5129 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
5132 Ytank_w_s, FALSE, FALSE,
5133 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
5136 Ytank_n_w, FALSE, FALSE,
5137 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
5140 Ytank_stone, FALSE, FALSE,
5141 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
5144 Ytank_spring, FALSE, FALSE,
5145 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
5148 Xandroid, TRUE, FALSE,
5149 EL_EMC_ANDROID, ACTION_ACTIVE, -1
5152 Xandroid_1_n, FALSE, FALSE,
5153 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
5156 Xandroid_2_n, FALSE, FALSE,
5157 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
5160 Xandroid_1_e, FALSE, FALSE,
5161 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
5164 Xandroid_2_e, FALSE, FALSE,
5165 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
5168 Xandroid_1_w, FALSE, FALSE,
5169 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
5172 Xandroid_2_w, FALSE, FALSE,
5173 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
5176 Xandroid_1_s, FALSE, FALSE,
5177 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
5180 Xandroid_2_s, FALSE, FALSE,
5181 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
5184 Yandroid_n, FALSE, FALSE,
5185 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
5188 Yandroid_nB, FALSE, TRUE,
5189 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
5192 Yandroid_ne, FALSE, FALSE,
5193 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
5196 Yandroid_neB, FALSE, TRUE,
5197 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
5200 Yandroid_e, FALSE, FALSE,
5201 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
5204 Yandroid_eB, FALSE, TRUE,
5205 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
5208 Yandroid_se, FALSE, FALSE,
5209 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
5212 Yandroid_seB, FALSE, TRUE,
5213 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
5216 Yandroid_s, FALSE, FALSE,
5217 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
5220 Yandroid_sB, FALSE, TRUE,
5221 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
5224 Yandroid_sw, FALSE, FALSE,
5225 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
5228 Yandroid_swB, FALSE, TRUE,
5229 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
5232 Yandroid_w, FALSE, FALSE,
5233 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
5236 Yandroid_wB, FALSE, TRUE,
5237 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
5240 Yandroid_nw, FALSE, FALSE,
5241 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
5244 Yandroid_nwB, FALSE, TRUE,
5245 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
5248 Xspring, TRUE, FALSE,
5252 Xspring_pause, FALSE, FALSE,
5256 Xspring_e, FALSE, FALSE,
5260 Xspring_w, FALSE, FALSE,
5264 Xspring_fall, FALSE, FALSE,
5268 Yspring_s, FALSE, FALSE,
5269 EL_SPRING, ACTION_FALLING, -1
5272 Yspring_sB, FALSE, TRUE,
5273 EL_SPRING, ACTION_FALLING, -1
5276 Yspring_e, FALSE, FALSE,
5277 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
5280 Yspring_eB, FALSE, TRUE,
5281 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
5284 Yspring_w, FALSE, FALSE,
5285 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
5288 Yspring_wB, FALSE, TRUE,
5289 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
5292 Yspring_kill_e, FALSE, FALSE,
5293 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
5296 Yspring_kill_eB, FALSE, TRUE,
5297 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
5300 Yspring_kill_w, FALSE, FALSE,
5301 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
5304 Yspring_kill_wB, FALSE, TRUE,
5305 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
5308 Xeater_n, TRUE, FALSE,
5309 EL_YAMYAM_UP, -1, -1
5312 Xeater_e, TRUE, FALSE,
5313 EL_YAMYAM_RIGHT, -1, -1
5316 Xeater_w, TRUE, FALSE,
5317 EL_YAMYAM_LEFT, -1, -1
5320 Xeater_s, TRUE, FALSE,
5321 EL_YAMYAM_DOWN, -1, -1
5324 Yeater_n, FALSE, FALSE,
5325 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
5328 Yeater_nB, FALSE, TRUE,
5329 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
5332 Yeater_e, FALSE, FALSE,
5333 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
5336 Yeater_eB, FALSE, TRUE,
5337 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
5340 Yeater_s, FALSE, FALSE,
5341 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
5344 Yeater_sB, FALSE, TRUE,
5345 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
5348 Yeater_w, FALSE, FALSE,
5349 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
5352 Yeater_wB, FALSE, TRUE,
5353 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
5356 Yeater_stone, FALSE, FALSE,
5357 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
5360 Yeater_spring, FALSE, FALSE,
5361 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
5364 Xalien, TRUE, FALSE,
5368 Xalien_pause, FALSE, FALSE,
5372 Yalien_n, FALSE, FALSE,
5373 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
5376 Yalien_nB, FALSE, TRUE,
5377 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
5380 Yalien_e, FALSE, FALSE,
5381 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
5384 Yalien_eB, FALSE, TRUE,
5385 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
5388 Yalien_s, FALSE, FALSE,
5389 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
5392 Yalien_sB, FALSE, TRUE,
5393 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
5396 Yalien_w, FALSE, FALSE,
5397 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
5400 Yalien_wB, FALSE, TRUE,
5401 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
5404 Yalien_stone, FALSE, FALSE,
5405 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
5408 Yalien_spring, FALSE, FALSE,
5409 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
5412 Xemerald, TRUE, FALSE,
5416 Xemerald_pause, FALSE, FALSE,
5420 Xemerald_fall, FALSE, FALSE,
5424 Xemerald_shine, FALSE, FALSE,
5425 EL_EMERALD, ACTION_TWINKLING, -1
5428 Yemerald_s, FALSE, FALSE,
5429 EL_EMERALD, ACTION_FALLING, -1
5432 Yemerald_sB, FALSE, TRUE,
5433 EL_EMERALD, ACTION_FALLING, -1
5436 Yemerald_e, FALSE, FALSE,
5437 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
5440 Yemerald_eB, FALSE, TRUE,
5441 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
5444 Yemerald_w, FALSE, FALSE,
5445 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
5448 Yemerald_wB, FALSE, TRUE,
5449 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
5452 Yemerald_eat, FALSE, FALSE,
5453 EL_EMERALD, ACTION_COLLECTING, -1
5456 Yemerald_stone, FALSE, FALSE,
5457 EL_NUT, ACTION_BREAKING, -1
5460 Xdiamond, TRUE, FALSE,
5464 Xdiamond_pause, FALSE, FALSE,
5468 Xdiamond_fall, FALSE, FALSE,
5472 Xdiamond_shine, FALSE, FALSE,
5473 EL_DIAMOND, ACTION_TWINKLING, -1
5476 Ydiamond_s, FALSE, FALSE,
5477 EL_DIAMOND, ACTION_FALLING, -1
5480 Ydiamond_sB, FALSE, TRUE,
5481 EL_DIAMOND, ACTION_FALLING, -1
5484 Ydiamond_e, FALSE, FALSE,
5485 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
5488 Ydiamond_eB, FALSE, TRUE,
5489 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
5492 Ydiamond_w, FALSE, FALSE,
5493 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
5496 Ydiamond_wB, FALSE, TRUE,
5497 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
5500 Ydiamond_eat, FALSE, FALSE,
5501 EL_DIAMOND, ACTION_COLLECTING, -1
5504 Ydiamond_stone, FALSE, FALSE,
5505 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
5508 Xdrip_fall, TRUE, FALSE,
5509 EL_AMOEBA_DROP, -1, -1
5512 Xdrip_stretch, FALSE, FALSE,
5513 EL_AMOEBA_DROP, ACTION_FALLING, -1
5516 Xdrip_stretchB, FALSE, TRUE,
5517 EL_AMOEBA_DROP, ACTION_FALLING, -1
5520 Xdrip_eat, FALSE, FALSE,
5521 EL_AMOEBA_DROP, ACTION_GROWING, -1
5524 Ydrip_s1, FALSE, FALSE,
5525 EL_AMOEBA_DROP, ACTION_FALLING, -1
5528 Ydrip_s1B, FALSE, TRUE,
5529 EL_AMOEBA_DROP, ACTION_FALLING, -1
5532 Ydrip_s2, FALSE, FALSE,
5533 EL_AMOEBA_DROP, ACTION_FALLING, -1
5536 Ydrip_s2B, FALSE, TRUE,
5537 EL_AMOEBA_DROP, ACTION_FALLING, -1
5544 Xbomb_pause, FALSE, FALSE,
5548 Xbomb_fall, FALSE, FALSE,
5552 Ybomb_s, FALSE, FALSE,
5553 EL_BOMB, ACTION_FALLING, -1
5556 Ybomb_sB, FALSE, TRUE,
5557 EL_BOMB, ACTION_FALLING, -1
5560 Ybomb_e, FALSE, FALSE,
5561 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
5564 Ybomb_eB, FALSE, TRUE,
5565 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
5568 Ybomb_w, FALSE, FALSE,
5569 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
5572 Ybomb_wB, FALSE, TRUE,
5573 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
5576 Ybomb_eat, FALSE, FALSE,
5577 EL_BOMB, ACTION_ACTIVATING, -1
5580 Xballoon, TRUE, FALSE,
5584 Yballoon_n, FALSE, FALSE,
5585 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
5588 Yballoon_nB, FALSE, TRUE,
5589 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
5592 Yballoon_e, FALSE, FALSE,
5593 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
5596 Yballoon_eB, FALSE, TRUE,
5597 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
5600 Yballoon_s, FALSE, FALSE,
5601 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
5604 Yballoon_sB, FALSE, TRUE,
5605 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
5608 Yballoon_w, FALSE, FALSE,
5609 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
5612 Yballoon_wB, FALSE, TRUE,
5613 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
5616 Xgrass, TRUE, FALSE,
5617 EL_EMC_GRASS, -1, -1
5620 Ygrass_nB, FALSE, FALSE,
5621 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
5624 Ygrass_eB, FALSE, FALSE,
5625 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
5628 Ygrass_sB, FALSE, FALSE,
5629 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
5632 Ygrass_wB, FALSE, FALSE,
5633 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
5640 Ydirt_nB, FALSE, FALSE,
5641 EL_SAND, ACTION_DIGGING, MV_BIT_UP
5644 Ydirt_eB, FALSE, FALSE,
5645 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
5648 Ydirt_sB, FALSE, FALSE,
5649 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
5652 Ydirt_wB, FALSE, FALSE,
5653 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
5656 Xacid_ne, TRUE, FALSE,
5657 EL_ACID_POOL_TOPRIGHT, -1, -1
5660 Xacid_se, TRUE, FALSE,
5661 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
5664 Xacid_s, TRUE, FALSE,
5665 EL_ACID_POOL_BOTTOM, -1, -1
5668 Xacid_sw, TRUE, FALSE,
5669 EL_ACID_POOL_BOTTOMLEFT, -1, -1
5672 Xacid_nw, TRUE, FALSE,
5673 EL_ACID_POOL_TOPLEFT, -1, -1
5676 Xacid_1, TRUE, FALSE,
5680 Xacid_2, FALSE, FALSE,
5684 Xacid_3, FALSE, FALSE,
5688 Xacid_4, FALSE, FALSE,
5692 Xacid_5, FALSE, FALSE,
5696 Xacid_6, FALSE, FALSE,
5700 Xacid_7, FALSE, FALSE,
5704 Xacid_8, FALSE, FALSE,
5708 Xball_1, TRUE, FALSE,
5709 EL_EMC_MAGIC_BALL, -1, -1
5712 Xball_1B, FALSE, FALSE,
5713 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5716 Xball_2, FALSE, FALSE,
5717 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5720 Xball_2B, FALSE, FALSE,
5721 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5724 Yball_eat, FALSE, FALSE,
5725 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
5728 Ykey_1_eat, FALSE, FALSE,
5729 EL_EM_KEY_1, ACTION_COLLECTING, -1
5732 Ykey_2_eat, FALSE, FALSE,
5733 EL_EM_KEY_2, ACTION_COLLECTING, -1
5736 Ykey_3_eat, FALSE, FALSE,
5737 EL_EM_KEY_3, ACTION_COLLECTING, -1
5740 Ykey_4_eat, FALSE, FALSE,
5741 EL_EM_KEY_4, ACTION_COLLECTING, -1
5744 Ykey_5_eat, FALSE, FALSE,
5745 EL_EMC_KEY_5, ACTION_COLLECTING, -1
5748 Ykey_6_eat, FALSE, FALSE,
5749 EL_EMC_KEY_6, ACTION_COLLECTING, -1
5752 Ykey_7_eat, FALSE, FALSE,
5753 EL_EMC_KEY_7, ACTION_COLLECTING, -1
5756 Ykey_8_eat, FALSE, FALSE,
5757 EL_EMC_KEY_8, ACTION_COLLECTING, -1
5760 Ylenses_eat, FALSE, FALSE,
5761 EL_EMC_LENSES, ACTION_COLLECTING, -1
5764 Ymagnify_eat, FALSE, FALSE,
5765 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
5768 Ygrass_eat, FALSE, FALSE,
5769 EL_EMC_GRASS, ACTION_SNAPPING, -1
5772 Ydirt_eat, FALSE, FALSE,
5773 EL_SAND, ACTION_SNAPPING, -1
5776 Xgrow_ns, TRUE, FALSE,
5777 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
5780 Ygrow_ns_eat, FALSE, FALSE,
5781 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
5784 Xgrow_ew, TRUE, FALSE,
5785 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
5788 Ygrow_ew_eat, FALSE, FALSE,
5789 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
5792 Xwonderwall, TRUE, FALSE,
5793 EL_MAGIC_WALL, -1, -1
5796 XwonderwallB, FALSE, FALSE,
5797 EL_MAGIC_WALL, ACTION_ACTIVE, -1
5800 Xamoeba_1, TRUE, FALSE,
5801 EL_AMOEBA_DRY, ACTION_OTHER, -1
5804 Xamoeba_2, FALSE, FALSE,
5805 EL_AMOEBA_DRY, ACTION_OTHER, -1
5808 Xamoeba_3, FALSE, FALSE,
5809 EL_AMOEBA_DRY, ACTION_OTHER, -1
5812 Xamoeba_4, FALSE, FALSE,
5813 EL_AMOEBA_DRY, ACTION_OTHER, -1
5816 Xamoeba_5, TRUE, FALSE,
5817 EL_AMOEBA_WET, ACTION_OTHER, -1
5820 Xamoeba_6, FALSE, FALSE,
5821 EL_AMOEBA_WET, ACTION_OTHER, -1
5824 Xamoeba_7, FALSE, FALSE,
5825 EL_AMOEBA_WET, ACTION_OTHER, -1
5828 Xamoeba_8, FALSE, FALSE,
5829 EL_AMOEBA_WET, ACTION_OTHER, -1
5832 Xdoor_1, TRUE, FALSE,
5833 EL_EM_GATE_1, -1, -1
5836 Xdoor_2, TRUE, FALSE,
5837 EL_EM_GATE_2, -1, -1
5840 Xdoor_3, TRUE, FALSE,
5841 EL_EM_GATE_3, -1, -1
5844 Xdoor_4, TRUE, FALSE,
5845 EL_EM_GATE_4, -1, -1
5848 Xdoor_5, TRUE, FALSE,
5849 EL_EMC_GATE_5, -1, -1
5852 Xdoor_6, TRUE, FALSE,
5853 EL_EMC_GATE_6, -1, -1
5856 Xdoor_7, TRUE, FALSE,
5857 EL_EMC_GATE_7, -1, -1
5860 Xdoor_8, TRUE, FALSE,
5861 EL_EMC_GATE_8, -1, -1
5864 Xkey_1, TRUE, FALSE,
5868 Xkey_2, TRUE, FALSE,
5872 Xkey_3, TRUE, FALSE,
5876 Xkey_4, TRUE, FALSE,
5880 Xkey_5, TRUE, FALSE,
5881 EL_EMC_KEY_5, -1, -1
5884 Xkey_6, TRUE, FALSE,
5885 EL_EMC_KEY_6, -1, -1
5888 Xkey_7, TRUE, FALSE,
5889 EL_EMC_KEY_7, -1, -1
5892 Xkey_8, TRUE, FALSE,
5893 EL_EMC_KEY_8, -1, -1
5896 Xwind_n, TRUE, FALSE,
5897 EL_BALLOON_SWITCH_UP, -1, -1
5900 Xwind_e, TRUE, FALSE,
5901 EL_BALLOON_SWITCH_RIGHT, -1, -1
5904 Xwind_s, TRUE, FALSE,
5905 EL_BALLOON_SWITCH_DOWN, -1, -1
5908 Xwind_w, TRUE, FALSE,
5909 EL_BALLOON_SWITCH_LEFT, -1, -1
5912 Xwind_nesw, TRUE, FALSE,
5913 EL_BALLOON_SWITCH_ANY, -1, -1
5916 Xwind_stop, TRUE, FALSE,
5917 EL_BALLOON_SWITCH_NONE, -1, -1
5921 EL_EM_EXIT_CLOSED, -1, -1
5924 Xexit_1, TRUE, FALSE,
5925 EL_EM_EXIT_OPEN, -1, -1
5928 Xexit_2, FALSE, FALSE,
5929 EL_EM_EXIT_OPEN, -1, -1
5932 Xexit_3, FALSE, FALSE,
5933 EL_EM_EXIT_OPEN, -1, -1
5936 Xdynamite, TRUE, FALSE,
5937 EL_EM_DYNAMITE, -1, -1
5940 Ydynamite_eat, FALSE, FALSE,
5941 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
5944 Xdynamite_1, TRUE, FALSE,
5945 EL_EM_DYNAMITE_ACTIVE, -1, -1
5948 Xdynamite_2, FALSE, FALSE,
5949 EL_EM_DYNAMITE_ACTIVE, -1, -1
5952 Xdynamite_3, FALSE, FALSE,
5953 EL_EM_DYNAMITE_ACTIVE, -1, -1
5956 Xdynamite_4, FALSE, FALSE,
5957 EL_EM_DYNAMITE_ACTIVE, -1, -1
5960 Xbumper, TRUE, FALSE,
5961 EL_EMC_SPRING_BUMPER, -1, -1
5964 XbumperB, FALSE, FALSE,
5965 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
5968 Xwheel, TRUE, FALSE,
5969 EL_ROBOT_WHEEL, -1, -1
5972 XwheelB, FALSE, FALSE,
5973 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
5976 Xswitch, TRUE, FALSE,
5977 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
5980 XswitchB, FALSE, FALSE,
5981 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
5985 EL_QUICKSAND_EMPTY, -1, -1
5988 Xsand_stone, TRUE, FALSE,
5989 EL_QUICKSAND_FULL, -1, -1
5992 Xsand_stonein_1, FALSE, TRUE,
5993 EL_ROCK, ACTION_FILLING, -1
5996 Xsand_stonein_2, FALSE, TRUE,
5997 EL_ROCK, ACTION_FILLING, -1
6000 Xsand_stonein_3, FALSE, TRUE,
6001 EL_ROCK, ACTION_FILLING, -1
6004 Xsand_stonein_4, FALSE, TRUE,
6005 EL_ROCK, ACTION_FILLING, -1
6008 Xsand_stonesand_1, FALSE, FALSE,
6009 EL_QUICKSAND_EMPTYING, -1, -1
6012 Xsand_stonesand_2, FALSE, FALSE,
6013 EL_QUICKSAND_EMPTYING, -1, -1
6016 Xsand_stonesand_3, FALSE, FALSE,
6017 EL_QUICKSAND_EMPTYING, -1, -1
6020 Xsand_stonesand_4, FALSE, FALSE,
6021 EL_QUICKSAND_EMPTYING, -1, -1
6024 Xsand_stonesand_quickout_1, FALSE, FALSE,
6025 EL_QUICKSAND_EMPTYING, -1, -1
6028 Xsand_stonesand_quickout_2, FALSE, FALSE,
6029 EL_QUICKSAND_EMPTYING, -1, -1
6032 Xsand_stoneout_1, FALSE, FALSE,
6033 EL_ROCK, ACTION_EMPTYING, -1
6036 Xsand_stoneout_2, FALSE, FALSE,
6037 EL_ROCK, ACTION_EMPTYING, -1
6040 Xsand_sandstone_1, FALSE, FALSE,
6041 EL_QUICKSAND_FILLING, -1, -1
6044 Xsand_sandstone_2, FALSE, FALSE,
6045 EL_QUICKSAND_FILLING, -1, -1
6048 Xsand_sandstone_3, FALSE, FALSE,
6049 EL_QUICKSAND_FILLING, -1, -1
6052 Xsand_sandstone_4, FALSE, FALSE,
6053 EL_QUICKSAND_FILLING, -1, -1
6056 Xplant, TRUE, FALSE,
6057 EL_EMC_PLANT, -1, -1
6060 Yplant, FALSE, FALSE,
6061 EL_EMC_PLANT, -1, -1
6064 Xlenses, TRUE, FALSE,
6065 EL_EMC_LENSES, -1, -1
6068 Xmagnify, TRUE, FALSE,
6069 EL_EMC_MAGNIFIER, -1, -1
6072 Xdripper, TRUE, FALSE,
6073 EL_EMC_DRIPPER, -1, -1
6076 XdripperB, FALSE, FALSE,
6077 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
6080 Xfake_blank, TRUE, FALSE,
6081 EL_INVISIBLE_WALL, -1, -1
6084 Xfake_blankB, FALSE, FALSE,
6085 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
6088 Xfake_grass, TRUE, FALSE,
6089 EL_EMC_FAKE_GRASS, -1, -1
6092 Xfake_grassB, FALSE, FALSE,
6093 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
6096 Xfake_door_1, TRUE, FALSE,
6097 EL_EM_GATE_1_GRAY, -1, -1
6100 Xfake_door_2, TRUE, FALSE,
6101 EL_EM_GATE_2_GRAY, -1, -1
6104 Xfake_door_3, TRUE, FALSE,
6105 EL_EM_GATE_3_GRAY, -1, -1
6108 Xfake_door_4, TRUE, FALSE,
6109 EL_EM_GATE_4_GRAY, -1, -1
6112 Xfake_door_5, TRUE, FALSE,
6113 EL_EMC_GATE_5_GRAY, -1, -1
6116 Xfake_door_6, TRUE, FALSE,
6117 EL_EMC_GATE_6_GRAY, -1, -1
6120 Xfake_door_7, TRUE, FALSE,
6121 EL_EMC_GATE_7_GRAY, -1, -1
6124 Xfake_door_8, TRUE, FALSE,
6125 EL_EMC_GATE_8_GRAY, -1, -1
6128 Xfake_acid_1, TRUE, FALSE,
6129 EL_EMC_FAKE_ACID, -1, -1
6132 Xfake_acid_2, FALSE, FALSE,
6133 EL_EMC_FAKE_ACID, -1, -1
6136 Xfake_acid_3, FALSE, FALSE,
6137 EL_EMC_FAKE_ACID, -1, -1
6140 Xfake_acid_4, FALSE, FALSE,
6141 EL_EMC_FAKE_ACID, -1, -1
6144 Xfake_acid_5, FALSE, FALSE,
6145 EL_EMC_FAKE_ACID, -1, -1
6148 Xfake_acid_6, FALSE, FALSE,
6149 EL_EMC_FAKE_ACID, -1, -1
6152 Xfake_acid_7, FALSE, FALSE,
6153 EL_EMC_FAKE_ACID, -1, -1
6156 Xfake_acid_8, FALSE, FALSE,
6157 EL_EMC_FAKE_ACID, -1, -1
6160 Xsteel_1, TRUE, FALSE,
6161 EL_STEELWALL, -1, -1
6164 Xsteel_2, TRUE, FALSE,
6165 EL_EMC_STEELWALL_2, -1, -1
6168 Xsteel_3, TRUE, FALSE,
6169 EL_EMC_STEELWALL_3, -1, -1
6172 Xsteel_4, TRUE, FALSE,
6173 EL_EMC_STEELWALL_4, -1, -1
6176 Xwall_1, TRUE, FALSE,
6180 Xwall_2, TRUE, FALSE,
6181 EL_EMC_WALL_14, -1, -1
6184 Xwall_3, TRUE, FALSE,
6185 EL_EMC_WALL_15, -1, -1
6188 Xwall_4, TRUE, FALSE,
6189 EL_EMC_WALL_16, -1, -1
6192 Xround_wall_1, TRUE, FALSE,
6193 EL_WALL_SLIPPERY, -1, -1
6196 Xround_wall_2, TRUE, FALSE,
6197 EL_EMC_WALL_SLIPPERY_2, -1, -1
6200 Xround_wall_3, TRUE, FALSE,
6201 EL_EMC_WALL_SLIPPERY_3, -1, -1
6204 Xround_wall_4, TRUE, FALSE,
6205 EL_EMC_WALL_SLIPPERY_4, -1, -1
6208 Xdecor_1, TRUE, FALSE,
6209 EL_EMC_WALL_8, -1, -1
6212 Xdecor_2, TRUE, FALSE,
6213 EL_EMC_WALL_6, -1, -1
6216 Xdecor_3, TRUE, FALSE,
6217 EL_EMC_WALL_4, -1, -1
6220 Xdecor_4, TRUE, FALSE,
6221 EL_EMC_WALL_7, -1, -1
6224 Xdecor_5, TRUE, FALSE,
6225 EL_EMC_WALL_5, -1, -1
6228 Xdecor_6, TRUE, FALSE,
6229 EL_EMC_WALL_9, -1, -1
6232 Xdecor_7, TRUE, FALSE,
6233 EL_EMC_WALL_10, -1, -1
6236 Xdecor_8, TRUE, FALSE,
6237 EL_EMC_WALL_1, -1, -1
6240 Xdecor_9, TRUE, FALSE,
6241 EL_EMC_WALL_2, -1, -1
6244 Xdecor_10, TRUE, FALSE,
6245 EL_EMC_WALL_3, -1, -1
6248 Xdecor_11, TRUE, FALSE,
6249 EL_EMC_WALL_11, -1, -1
6252 Xdecor_12, TRUE, FALSE,
6253 EL_EMC_WALL_12, -1, -1
6256 Xalpha_0, TRUE, FALSE,
6257 EL_CHAR('0'), -1, -1
6260 Xalpha_1, TRUE, FALSE,
6261 EL_CHAR('1'), -1, -1
6264 Xalpha_2, TRUE, FALSE,
6265 EL_CHAR('2'), -1, -1
6268 Xalpha_3, TRUE, FALSE,
6269 EL_CHAR('3'), -1, -1
6272 Xalpha_4, TRUE, FALSE,
6273 EL_CHAR('4'), -1, -1
6276 Xalpha_5, TRUE, FALSE,
6277 EL_CHAR('5'), -1, -1
6280 Xalpha_6, TRUE, FALSE,
6281 EL_CHAR('6'), -1, -1
6284 Xalpha_7, TRUE, FALSE,
6285 EL_CHAR('7'), -1, -1
6288 Xalpha_8, TRUE, FALSE,
6289 EL_CHAR('8'), -1, -1
6292 Xalpha_9, TRUE, FALSE,
6293 EL_CHAR('9'), -1, -1
6296 Xalpha_excla, TRUE, FALSE,
6297 EL_CHAR('!'), -1, -1
6300 Xalpha_quote, TRUE, FALSE,
6301 EL_CHAR('"'), -1, -1
6304 Xalpha_comma, TRUE, FALSE,
6305 EL_CHAR(','), -1, -1
6308 Xalpha_minus, TRUE, FALSE,
6309 EL_CHAR('-'), -1, -1
6312 Xalpha_perio, TRUE, FALSE,
6313 EL_CHAR('.'), -1, -1
6316 Xalpha_colon, TRUE, FALSE,
6317 EL_CHAR(':'), -1, -1
6320 Xalpha_quest, TRUE, FALSE,
6321 EL_CHAR('?'), -1, -1
6324 Xalpha_a, TRUE, FALSE,
6325 EL_CHAR('A'), -1, -1
6328 Xalpha_b, TRUE, FALSE,
6329 EL_CHAR('B'), -1, -1
6332 Xalpha_c, TRUE, FALSE,
6333 EL_CHAR('C'), -1, -1
6336 Xalpha_d, TRUE, FALSE,
6337 EL_CHAR('D'), -1, -1
6340 Xalpha_e, TRUE, FALSE,
6341 EL_CHAR('E'), -1, -1
6344 Xalpha_f, TRUE, FALSE,
6345 EL_CHAR('F'), -1, -1
6348 Xalpha_g, TRUE, FALSE,
6349 EL_CHAR('G'), -1, -1
6352 Xalpha_h, TRUE, FALSE,
6353 EL_CHAR('H'), -1, -1
6356 Xalpha_i, TRUE, FALSE,
6357 EL_CHAR('I'), -1, -1
6360 Xalpha_j, TRUE, FALSE,
6361 EL_CHAR('J'), -1, -1
6364 Xalpha_k, TRUE, FALSE,
6365 EL_CHAR('K'), -1, -1
6368 Xalpha_l, TRUE, FALSE,
6369 EL_CHAR('L'), -1, -1
6372 Xalpha_m, TRUE, FALSE,
6373 EL_CHAR('M'), -1, -1
6376 Xalpha_n, TRUE, FALSE,
6377 EL_CHAR('N'), -1, -1
6380 Xalpha_o, TRUE, FALSE,
6381 EL_CHAR('O'), -1, -1
6384 Xalpha_p, TRUE, FALSE,
6385 EL_CHAR('P'), -1, -1
6388 Xalpha_q, TRUE, FALSE,
6389 EL_CHAR('Q'), -1, -1
6392 Xalpha_r, TRUE, FALSE,
6393 EL_CHAR('R'), -1, -1
6396 Xalpha_s, TRUE, FALSE,
6397 EL_CHAR('S'), -1, -1
6400 Xalpha_t, TRUE, FALSE,
6401 EL_CHAR('T'), -1, -1
6404 Xalpha_u, TRUE, FALSE,
6405 EL_CHAR('U'), -1, -1
6408 Xalpha_v, TRUE, FALSE,
6409 EL_CHAR('V'), -1, -1
6412 Xalpha_w, TRUE, FALSE,
6413 EL_CHAR('W'), -1, -1
6416 Xalpha_x, TRUE, FALSE,
6417 EL_CHAR('X'), -1, -1
6420 Xalpha_y, TRUE, FALSE,
6421 EL_CHAR('Y'), -1, -1
6424 Xalpha_z, TRUE, FALSE,
6425 EL_CHAR('Z'), -1, -1
6428 Xalpha_arrow_e, TRUE, FALSE,
6429 EL_CHAR('>'), -1, -1
6432 Xalpha_arrow_w, TRUE, FALSE,
6433 EL_CHAR('<'), -1, -1
6436 Xalpha_copyr, TRUE, FALSE,
6437 EL_CHAR(CHAR_BYTE_COPYRIGHT), -1, -1
6441 Xboom_bug, FALSE, FALSE,
6442 EL_BUG, ACTION_EXPLODING, -1
6445 Xboom_bomb, FALSE, FALSE,
6446 EL_BOMB, ACTION_EXPLODING, -1
6449 Xboom_android, FALSE, FALSE,
6450 EL_EMC_ANDROID, ACTION_OTHER, -1
6453 Xboom_1, FALSE, FALSE,
6454 EL_DEFAULT, ACTION_EXPLODING, -1
6457 Xboom_2, FALSE, FALSE,
6458 EL_DEFAULT, ACTION_EXPLODING, -1
6461 Znormal, FALSE, FALSE,
6465 Zdynamite, FALSE, FALSE,
6469 Zplayer, FALSE, FALSE,
6473 ZBORDER, FALSE, FALSE,
6483 static struct Mapping_EM_to_RND_player
6492 em_player_mapping_list[] =
6496 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
6500 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
6504 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
6508 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
6512 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
6516 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
6520 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
6524 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
6528 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
6532 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
6536 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
6540 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
6544 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
6548 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
6552 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
6556 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
6560 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
6564 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
6568 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
6572 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
6576 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
6580 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
6584 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
6588 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
6592 EL_PLAYER_1, ACTION_DEFAULT, -1,
6596 EL_PLAYER_2, ACTION_DEFAULT, -1,
6600 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
6604 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
6608 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
6612 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
6616 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
6620 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
6624 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
6628 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
6632 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
6636 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
6640 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
6644 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
6648 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
6652 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
6656 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
6660 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
6664 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
6668 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
6672 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
6676 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
6680 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
6684 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
6688 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
6692 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
6696 EL_PLAYER_3, ACTION_DEFAULT, -1,
6700 EL_PLAYER_4, ACTION_DEFAULT, -1,
6709 int map_element_RND_to_EM(int element_rnd)
6711 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
6712 static boolean mapping_initialized = FALSE;
6714 if (!mapping_initialized)
6718 /* return "Xalpha_quest" for all undefined elements in mapping array */
6719 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
6720 mapping_RND_to_EM[i] = Xalpha_quest;
6722 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6723 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
6724 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
6725 em_object_mapping_list[i].element_em;
6727 mapping_initialized = TRUE;
6730 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
6731 return mapping_RND_to_EM[element_rnd];
6733 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
6738 int map_element_EM_to_RND(int element_em)
6740 static unsigned short mapping_EM_to_RND[TILE_MAX];
6741 static boolean mapping_initialized = FALSE;
6743 if (!mapping_initialized)
6747 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
6748 for (i = 0; i < TILE_MAX; i++)
6749 mapping_EM_to_RND[i] = EL_UNKNOWN;
6751 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6752 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
6753 em_object_mapping_list[i].element_rnd;
6755 mapping_initialized = TRUE;
6758 if (element_em >= 0 && element_em < TILE_MAX)
6759 return mapping_EM_to_RND[element_em];
6761 Error(ERR_WARN, "invalid EM level element %d", element_em);
6766 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
6768 struct LevelInfo_EM *level_em = level->native_em_level;
6769 struct LEVEL *lev = level_em->lev;
6772 for (i = 0; i < TILE_MAX; i++)
6773 lev->android_array[i] = Xblank;
6775 for (i = 0; i < level->num_android_clone_elements; i++)
6777 int element_rnd = level->android_clone_element[i];
6778 int element_em = map_element_RND_to_EM(element_rnd);
6780 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
6781 if (em_object_mapping_list[j].element_rnd == element_rnd)
6782 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
6786 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
6788 struct LevelInfo_EM *level_em = level->native_em_level;
6789 struct LEVEL *lev = level_em->lev;
6792 level->num_android_clone_elements = 0;
6794 for (i = 0; i < TILE_MAX; i++)
6796 int element_em = lev->android_array[i];
6798 boolean element_found = FALSE;
6800 if (element_em == Xblank)
6803 element_rnd = map_element_EM_to_RND(element_em);
6805 for (j = 0; j < level->num_android_clone_elements; j++)
6806 if (level->android_clone_element[j] == element_rnd)
6807 element_found = TRUE;
6811 level->android_clone_element[level->num_android_clone_elements++] =
6814 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
6819 if (level->num_android_clone_elements == 0)
6821 level->num_android_clone_elements = 1;
6822 level->android_clone_element[0] = EL_EMPTY;
6826 int map_direction_RND_to_EM(int direction)
6828 return (direction == MV_UP ? 0 :
6829 direction == MV_RIGHT ? 1 :
6830 direction == MV_DOWN ? 2 :
6831 direction == MV_LEFT ? 3 :
6835 int map_direction_EM_to_RND(int direction)
6837 return (direction == 0 ? MV_UP :
6838 direction == 1 ? MV_RIGHT :
6839 direction == 2 ? MV_DOWN :
6840 direction == 3 ? MV_LEFT :
6844 int map_element_RND_to_SP(int element_rnd)
6846 int element_sp = 0x20; /* map unknown elements to yellow "hardware" */
6848 if (element_rnd >= EL_SP_START &&
6849 element_rnd <= EL_SP_END)
6850 element_sp = element_rnd - EL_SP_START;
6851 else if (element_rnd == EL_EMPTY_SPACE)
6853 else if (element_rnd == EL_INVISIBLE_WALL)
6859 int map_element_SP_to_RND(int element_sp)
6861 int element_rnd = EL_UNKNOWN;
6863 if (element_sp >= 0x00 &&
6865 element_rnd = EL_SP_START + element_sp;
6866 else if (element_sp == 0x28)
6867 element_rnd = EL_INVISIBLE_WALL;
6872 int map_action_SP_to_RND(int action_sp)
6876 case actActive: return ACTION_ACTIVE;
6877 case actImpact: return ACTION_IMPACT;
6878 case actExploding: return ACTION_EXPLODING;
6879 case actDigging: return ACTION_DIGGING;
6880 case actSnapping: return ACTION_SNAPPING;
6881 case actCollecting: return ACTION_COLLECTING;
6882 case actPassing: return ACTION_PASSING;
6883 case actPushing: return ACTION_PUSHING;
6884 case actDropping: return ACTION_DROPPING;
6886 default: return ACTION_DEFAULT;
6890 int get_next_element(int element)
6894 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
6895 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
6896 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
6897 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
6898 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
6899 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
6900 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
6901 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
6902 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
6903 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
6904 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
6906 default: return element;
6910 int el_act_dir2img(int element, int action, int direction)
6912 element = GFX_ELEMENT(element);
6913 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
6915 /* direction_graphic[][] == graphic[] for undefined direction graphics */
6916 return element_info[element].direction_graphic[action][direction];
6919 static int el_act_dir2crm(int element, int action, int direction)
6921 element = GFX_ELEMENT(element);
6922 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
6924 /* direction_graphic[][] == graphic[] for undefined direction graphics */
6925 return element_info[element].direction_crumbled[action][direction];
6928 int el_act2img(int element, int action)
6930 element = GFX_ELEMENT(element);
6932 return element_info[element].graphic[action];
6935 int el_act2crm(int element, int action)
6937 element = GFX_ELEMENT(element);
6939 return element_info[element].crumbled[action];
6942 int el_dir2img(int element, int direction)
6944 element = GFX_ELEMENT(element);
6946 return el_act_dir2img(element, ACTION_DEFAULT, direction);
6949 int el2baseimg(int element)
6951 return element_info[element].graphic[ACTION_DEFAULT];
6954 int el2img(int element)
6956 element = GFX_ELEMENT(element);
6958 return element_info[element].graphic[ACTION_DEFAULT];
6961 int el2edimg(int element)
6963 element = GFX_ELEMENT(element);
6965 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
6968 int el2preimg(int element)
6970 element = GFX_ELEMENT(element);
6972 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
6975 int el2panelimg(int element)
6977 element = GFX_ELEMENT(element);
6979 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL];
6982 int font2baseimg(int font_nr)
6984 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
6987 int getBeltNrFromBeltElement(int element)
6989 return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
6990 element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
6991 element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
6994 int getBeltNrFromBeltActiveElement(int element)
6996 return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
6997 element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
6998 element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
7001 int getBeltNrFromBeltSwitchElement(int element)
7003 return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
7004 element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
7005 element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
7008 int getBeltDirNrFromBeltElement(int element)
7010 static int belt_base_element[4] =
7012 EL_CONVEYOR_BELT_1_LEFT,
7013 EL_CONVEYOR_BELT_2_LEFT,
7014 EL_CONVEYOR_BELT_3_LEFT,
7015 EL_CONVEYOR_BELT_4_LEFT
7018 int belt_nr = getBeltNrFromBeltElement(element);
7019 int belt_dir_nr = element - belt_base_element[belt_nr];
7021 return (belt_dir_nr % 3);
7024 int getBeltDirNrFromBeltSwitchElement(int element)
7026 static int belt_base_element[4] =
7028 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
7029 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
7030 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
7031 EL_CONVEYOR_BELT_4_SWITCH_LEFT
7034 int belt_nr = getBeltNrFromBeltSwitchElement(element);
7035 int belt_dir_nr = element - belt_base_element[belt_nr];
7037 return (belt_dir_nr % 3);
7040 int getBeltDirFromBeltElement(int element)
7042 static int belt_move_dir[3] =
7049 int belt_dir_nr = getBeltDirNrFromBeltElement(element);
7051 return belt_move_dir[belt_dir_nr];
7054 int getBeltDirFromBeltSwitchElement(int element)
7056 static int belt_move_dir[3] =
7063 int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
7065 return belt_move_dir[belt_dir_nr];
7068 int getBeltElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
7070 static int belt_base_element[4] =
7072 EL_CONVEYOR_BELT_1_LEFT,
7073 EL_CONVEYOR_BELT_2_LEFT,
7074 EL_CONVEYOR_BELT_3_LEFT,
7075 EL_CONVEYOR_BELT_4_LEFT
7078 return belt_base_element[belt_nr] + belt_dir_nr;
7081 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
7083 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
7085 return getBeltElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
7088 int getBeltSwitchElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
7090 static int belt_base_element[4] =
7092 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
7093 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
7094 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
7095 EL_CONVEYOR_BELT_4_SWITCH_LEFT
7098 return belt_base_element[belt_nr] + belt_dir_nr;
7101 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
7103 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
7105 return getBeltSwitchElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
7108 boolean getTeamMode_EM()
7110 return game.team_mode;
7113 int getGameFrameDelay_EM(int native_em_game_frame_delay)
7115 int game_frame_delay_value;
7117 game_frame_delay_value =
7118 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
7119 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
7122 if (tape.playing && tape.warp_forward && !tape.pausing)
7123 game_frame_delay_value = 0;
7125 return game_frame_delay_value;
7128 unsigned int InitRND(int seed)
7130 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
7131 return InitEngineRandom_EM(seed);
7132 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
7133 return InitEngineRandom_SP(seed);
7135 return InitEngineRandom_RND(seed);
7138 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
7139 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
7141 inline static int get_effective_element_EM(int tile, int frame_em)
7143 int element = object_mapping[tile].element_rnd;
7144 int action = object_mapping[tile].action;
7145 boolean is_backside = object_mapping[tile].is_backside;
7146 boolean action_removing = (action == ACTION_DIGGING ||
7147 action == ACTION_SNAPPING ||
7148 action == ACTION_COLLECTING);
7154 case Yacid_splash_eB:
7155 case Yacid_splash_wB:
7156 return (frame_em > 5 ? EL_EMPTY : element);
7162 else /* frame_em == 7 */
7166 case Yacid_splash_eB:
7167 case Yacid_splash_wB:
7170 case Yemerald_stone:
7173 case Ydiamond_stone:
7177 case Xdrip_stretchB:
7196 case Xsand_stonein_1:
7197 case Xsand_stonein_2:
7198 case Xsand_stonein_3:
7199 case Xsand_stonein_4:
7203 return (is_backside || action_removing ? EL_EMPTY : element);
7208 inline static boolean check_linear_animation_EM(int tile)
7212 case Xsand_stonesand_1:
7213 case Xsand_stonesand_quickout_1:
7214 case Xsand_sandstone_1:
7215 case Xsand_stonein_1:
7216 case Xsand_stoneout_1:
7235 case Yacid_splash_eB:
7236 case Yacid_splash_wB:
7237 case Yemerald_stone:
7244 inline static void set_crumbled_graphics_EM(struct GraphicInfo_EM *g_em,
7245 boolean has_crumbled_graphics,
7246 int crumbled, int sync_frame)
7248 /* if element can be crumbled, but certain action graphics are just empty
7249 space (like instantly snapping sand to empty space in 1 frame), do not
7250 treat these empty space graphics as crumbled graphics in EMC engine */
7251 if (crumbled == IMG_EMPTY_SPACE)
7252 has_crumbled_graphics = FALSE;
7254 if (has_crumbled_graphics)
7256 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
7257 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
7258 g_crumbled->anim_delay,
7259 g_crumbled->anim_mode,
7260 g_crumbled->anim_start_frame,
7263 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
7264 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
7266 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
7268 g_em->has_crumbled_graphics = TRUE;
7272 g_em->crumbled_bitmap = NULL;
7273 g_em->crumbled_src_x = 0;
7274 g_em->crumbled_src_y = 0;
7275 g_em->crumbled_border_size = 0;
7277 g_em->has_crumbled_graphics = FALSE;
7281 void ResetGfxAnimation_EM(int x, int y, int tile)
7286 void SetGfxAnimation_EM(struct GraphicInfo_EM *g_em,
7287 int tile, int frame_em, int x, int y)
7289 int action = object_mapping[tile].action;
7290 int direction = object_mapping[tile].direction;
7291 int effective_element = get_effective_element_EM(tile, frame_em);
7292 int graphic = (direction == MV_NONE ?
7293 el_act2img(effective_element, action) :
7294 el_act_dir2img(effective_element, action, direction));
7295 struct GraphicInfo *g = &graphic_info[graphic];
7297 boolean action_removing = (action == ACTION_DIGGING ||
7298 action == ACTION_SNAPPING ||
7299 action == ACTION_COLLECTING);
7300 boolean action_moving = (action == ACTION_FALLING ||
7301 action == ACTION_MOVING ||
7302 action == ACTION_PUSHING ||
7303 action == ACTION_EATING ||
7304 action == ACTION_FILLING ||
7305 action == ACTION_EMPTYING);
7306 boolean action_falling = (action == ACTION_FALLING ||
7307 action == ACTION_FILLING ||
7308 action == ACTION_EMPTYING);
7310 /* special case: graphic uses "2nd movement tile" and has defined
7311 7 frames for movement animation (or less) => use default graphic
7312 for last (8th) frame which ends the movement animation */
7313 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
7315 action = ACTION_DEFAULT; /* (keep action_* unchanged for now) */
7316 graphic = (direction == MV_NONE ?
7317 el_act2img(effective_element, action) :
7318 el_act_dir2img(effective_element, action, direction));
7320 g = &graphic_info[graphic];
7323 if ((action_removing || check_linear_animation_EM(tile)) && frame_em == 0)
7327 else if (action_moving)
7329 boolean is_backside = object_mapping[tile].is_backside;
7333 int direction = object_mapping[tile].direction;
7334 int move_dir = (action_falling ? MV_DOWN : direction);
7339 /* !!! TEST !!! NEW !!! DOES NOT WORK RIGHT YET !!! */
7340 if (g->double_movement && frame_em == 0)
7344 if (move_dir == MV_LEFT)
7345 GfxFrame[x - 1][y] = GfxFrame[x][y];
7346 else if (move_dir == MV_RIGHT)
7347 GfxFrame[x + 1][y] = GfxFrame[x][y];
7348 else if (move_dir == MV_UP)
7349 GfxFrame[x][y - 1] = GfxFrame[x][y];
7350 else if (move_dir == MV_DOWN)
7351 GfxFrame[x][y + 1] = GfxFrame[x][y];
7358 /* special case: animation for Xsand_stonesand_quickout_1/2 twice as fast */
7359 if (tile == Xsand_stonesand_quickout_1 ||
7360 tile == Xsand_stonesand_quickout_2)
7364 if (graphic_info[graphic].anim_global_sync)
7365 sync_frame = FrameCounter;
7366 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
7367 sync_frame = GfxFrame[x][y];
7369 sync_frame = 0; /* playfield border (pseudo steel) */
7371 SetRandomAnimationValue(x, y);
7373 int frame = getAnimationFrame(g->anim_frames,
7376 g->anim_start_frame,
7379 g_em->unique_identifier =
7380 (graphic << 16) | ((frame % 8) << 12) | (g_em->width << 6) | g_em->height;
7383 void getGraphicSourceObjectExt_EM(struct GraphicInfo_EM *g_em,
7384 int tile, int frame_em, int x, int y)
7386 int action = object_mapping[tile].action;
7387 int direction = object_mapping[tile].direction;
7388 boolean is_backside = object_mapping[tile].is_backside;
7389 int effective_element = get_effective_element_EM(tile, frame_em);
7390 int effective_action = action;
7391 int graphic = (direction == MV_NONE ?
7392 el_act2img(effective_element, effective_action) :
7393 el_act_dir2img(effective_element, effective_action,
7395 int crumbled = (direction == MV_NONE ?
7396 el_act2crm(effective_element, effective_action) :
7397 el_act_dir2crm(effective_element, effective_action,
7399 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7400 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7401 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7402 struct GraphicInfo *g = &graphic_info[graphic];
7405 /* special case: graphic uses "2nd movement tile" and has defined
7406 7 frames for movement animation (or less) => use default graphic
7407 for last (8th) frame which ends the movement animation */
7408 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
7410 effective_action = ACTION_DEFAULT;
7411 graphic = (direction == MV_NONE ?
7412 el_act2img(effective_element, effective_action) :
7413 el_act_dir2img(effective_element, effective_action,
7415 crumbled = (direction == MV_NONE ?
7416 el_act2crm(effective_element, effective_action) :
7417 el_act_dir2crm(effective_element, effective_action,
7420 g = &graphic_info[graphic];
7423 if (graphic_info[graphic].anim_global_sync)
7424 sync_frame = FrameCounter;
7425 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
7426 sync_frame = GfxFrame[x][y];
7428 sync_frame = 0; /* playfield border (pseudo steel) */
7430 SetRandomAnimationValue(x, y);
7432 int frame = getAnimationFrame(g->anim_frames,
7435 g->anim_start_frame,
7438 getGraphicSourceExt(graphic, frame, &g_em->bitmap, &g_em->src_x, &g_em->src_y,
7439 g->double_movement && is_backside);
7441 /* (updating the "crumbled" graphic definitions is probably not really needed,
7442 as animations for crumbled graphics can't be longer than one EMC cycle) */
7443 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
7447 void getGraphicSourcePlayerExt_EM(struct GraphicInfo_EM *g_em,
7448 int player_nr, int anim, int frame_em)
7450 int element = player_mapping[player_nr][anim].element_rnd;
7451 int action = player_mapping[player_nr][anim].action;
7452 int direction = player_mapping[player_nr][anim].direction;
7453 int graphic = (direction == MV_NONE ?
7454 el_act2img(element, action) :
7455 el_act_dir2img(element, action, direction));
7456 struct GraphicInfo *g = &graphic_info[graphic];
7459 InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
7461 stored_player[player_nr].StepFrame = frame_em;
7463 sync_frame = stored_player[player_nr].Frame;
7465 int frame = getAnimationFrame(g->anim_frames,
7468 g->anim_start_frame,
7471 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
7472 &g_em->src_x, &g_em->src_y, FALSE);
7475 void InitGraphicInfo_EM(void)
7480 int num_em_gfx_errors = 0;
7482 if (graphic_info_em_object[0][0].bitmap == NULL)
7484 /* EM graphics not yet initialized in em_open_all() */
7489 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
7492 /* always start with reliable default values */
7493 for (i = 0; i < TILE_MAX; i++)
7495 object_mapping[i].element_rnd = EL_UNKNOWN;
7496 object_mapping[i].is_backside = FALSE;
7497 object_mapping[i].action = ACTION_DEFAULT;
7498 object_mapping[i].direction = MV_NONE;
7501 /* always start with reliable default values */
7502 for (p = 0; p < MAX_PLAYERS; p++)
7504 for (i = 0; i < SPR_MAX; i++)
7506 player_mapping[p][i].element_rnd = EL_UNKNOWN;
7507 player_mapping[p][i].action = ACTION_DEFAULT;
7508 player_mapping[p][i].direction = MV_NONE;
7512 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
7514 int e = em_object_mapping_list[i].element_em;
7516 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
7517 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
7519 if (em_object_mapping_list[i].action != -1)
7520 object_mapping[e].action = em_object_mapping_list[i].action;
7522 if (em_object_mapping_list[i].direction != -1)
7523 object_mapping[e].direction =
7524 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
7527 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
7529 int a = em_player_mapping_list[i].action_em;
7530 int p = em_player_mapping_list[i].player_nr;
7532 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
7534 if (em_player_mapping_list[i].action != -1)
7535 player_mapping[p][a].action = em_player_mapping_list[i].action;
7537 if (em_player_mapping_list[i].direction != -1)
7538 player_mapping[p][a].direction =
7539 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
7542 for (i = 0; i < TILE_MAX; i++)
7544 int element = object_mapping[i].element_rnd;
7545 int action = object_mapping[i].action;
7546 int direction = object_mapping[i].direction;
7547 boolean is_backside = object_mapping[i].is_backside;
7548 boolean action_exploding = ((action == ACTION_EXPLODING ||
7549 action == ACTION_SMASHED_BY_ROCK ||
7550 action == ACTION_SMASHED_BY_SPRING) &&
7551 element != EL_DIAMOND);
7552 boolean action_active = (action == ACTION_ACTIVE);
7553 boolean action_other = (action == ACTION_OTHER);
7555 for (j = 0; j < 8; j++)
7557 int effective_element = get_effective_element_EM(i, j);
7558 int effective_action = (j < 7 ? action :
7559 i == Xdrip_stretch ? action :
7560 i == Xdrip_stretchB ? action :
7561 i == Ydrip_s1 ? action :
7562 i == Ydrip_s1B ? action :
7563 i == Xball_1B ? action :
7564 i == Xball_2 ? action :
7565 i == Xball_2B ? action :
7566 i == Yball_eat ? action :
7567 i == Ykey_1_eat ? action :
7568 i == Ykey_2_eat ? action :
7569 i == Ykey_3_eat ? action :
7570 i == Ykey_4_eat ? action :
7571 i == Ykey_5_eat ? action :
7572 i == Ykey_6_eat ? action :
7573 i == Ykey_7_eat ? action :
7574 i == Ykey_8_eat ? action :
7575 i == Ylenses_eat ? action :
7576 i == Ymagnify_eat ? action :
7577 i == Ygrass_eat ? action :
7578 i == Ydirt_eat ? action :
7579 i == Xsand_stonein_1 ? action :
7580 i == Xsand_stonein_2 ? action :
7581 i == Xsand_stonein_3 ? action :
7582 i == Xsand_stonein_4 ? action :
7583 i == Xsand_stoneout_1 ? action :
7584 i == Xsand_stoneout_2 ? action :
7585 i == Xboom_android ? ACTION_EXPLODING :
7586 action_exploding ? ACTION_EXPLODING :
7587 action_active ? action :
7588 action_other ? action :
7590 int graphic = (el_act_dir2img(effective_element, effective_action,
7592 int crumbled = (el_act_dir2crm(effective_element, effective_action,
7594 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7595 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7596 boolean has_action_graphics = (graphic != base_graphic);
7597 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7598 struct GraphicInfo *g = &graphic_info[graphic];
7599 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7602 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
7603 boolean special_animation = (action != ACTION_DEFAULT &&
7604 g->anim_frames == 3 &&
7605 g->anim_delay == 2 &&
7606 g->anim_mode & ANIM_LINEAR);
7607 int sync_frame = (i == Xdrip_stretch ? 7 :
7608 i == Xdrip_stretchB ? 7 :
7609 i == Ydrip_s2 ? j + 8 :
7610 i == Ydrip_s2B ? j + 8 :
7619 i == Xfake_acid_1 ? 0 :
7620 i == Xfake_acid_2 ? 10 :
7621 i == Xfake_acid_3 ? 20 :
7622 i == Xfake_acid_4 ? 30 :
7623 i == Xfake_acid_5 ? 40 :
7624 i == Xfake_acid_6 ? 50 :
7625 i == Xfake_acid_7 ? 60 :
7626 i == Xfake_acid_8 ? 70 :
7628 i == Xball_2B ? j + 8 :
7629 i == Yball_eat ? j + 1 :
7630 i == Ykey_1_eat ? j + 1 :
7631 i == Ykey_2_eat ? j + 1 :
7632 i == Ykey_3_eat ? j + 1 :
7633 i == Ykey_4_eat ? j + 1 :
7634 i == Ykey_5_eat ? j + 1 :
7635 i == Ykey_6_eat ? j + 1 :
7636 i == Ykey_7_eat ? j + 1 :
7637 i == Ykey_8_eat ? j + 1 :
7638 i == Ylenses_eat ? j + 1 :
7639 i == Ymagnify_eat ? j + 1 :
7640 i == Ygrass_eat ? j + 1 :
7641 i == Ydirt_eat ? j + 1 :
7642 i == Xamoeba_1 ? 0 :
7643 i == Xamoeba_2 ? 1 :
7644 i == Xamoeba_3 ? 2 :
7645 i == Xamoeba_4 ? 3 :
7646 i == Xamoeba_5 ? 0 :
7647 i == Xamoeba_6 ? 1 :
7648 i == Xamoeba_7 ? 2 :
7649 i == Xamoeba_8 ? 3 :
7650 i == Xexit_2 ? j + 8 :
7651 i == Xexit_3 ? j + 16 :
7652 i == Xdynamite_1 ? 0 :
7653 i == Xdynamite_2 ? 8 :
7654 i == Xdynamite_3 ? 16 :
7655 i == Xdynamite_4 ? 24 :
7656 i == Xsand_stonein_1 ? j + 1 :
7657 i == Xsand_stonein_2 ? j + 9 :
7658 i == Xsand_stonein_3 ? j + 17 :
7659 i == Xsand_stonein_4 ? j + 25 :
7660 i == Xsand_stoneout_1 && j == 0 ? 0 :
7661 i == Xsand_stoneout_1 && j == 1 ? 0 :
7662 i == Xsand_stoneout_1 && j == 2 ? 1 :
7663 i == Xsand_stoneout_1 && j == 3 ? 2 :
7664 i == Xsand_stoneout_1 && j == 4 ? 2 :
7665 i == Xsand_stoneout_1 && j == 5 ? 3 :
7666 i == Xsand_stoneout_1 && j == 6 ? 4 :
7667 i == Xsand_stoneout_1 && j == 7 ? 4 :
7668 i == Xsand_stoneout_2 && j == 0 ? 5 :
7669 i == Xsand_stoneout_2 && j == 1 ? 6 :
7670 i == Xsand_stoneout_2 && j == 2 ? 7 :
7671 i == Xsand_stoneout_2 && j == 3 ? 8 :
7672 i == Xsand_stoneout_2 && j == 4 ? 9 :
7673 i == Xsand_stoneout_2 && j == 5 ? 11 :
7674 i == Xsand_stoneout_2 && j == 6 ? 13 :
7675 i == Xsand_stoneout_2 && j == 7 ? 15 :
7676 i == Xboom_bug && j == 1 ? 2 :
7677 i == Xboom_bug && j == 2 ? 2 :
7678 i == Xboom_bug && j == 3 ? 4 :
7679 i == Xboom_bug && j == 4 ? 4 :
7680 i == Xboom_bug && j == 5 ? 2 :
7681 i == Xboom_bug && j == 6 ? 2 :
7682 i == Xboom_bug && j == 7 ? 0 :
7683 i == Xboom_bomb && j == 1 ? 2 :
7684 i == Xboom_bomb && j == 2 ? 2 :
7685 i == Xboom_bomb && j == 3 ? 4 :
7686 i == Xboom_bomb && j == 4 ? 4 :
7687 i == Xboom_bomb && j == 5 ? 2 :
7688 i == Xboom_bomb && j == 6 ? 2 :
7689 i == Xboom_bomb && j == 7 ? 0 :
7690 i == Xboom_android && j == 7 ? 6 :
7691 i == Xboom_1 && j == 1 ? 2 :
7692 i == Xboom_1 && j == 2 ? 2 :
7693 i == Xboom_1 && j == 3 ? 4 :
7694 i == Xboom_1 && j == 4 ? 4 :
7695 i == Xboom_1 && j == 5 ? 6 :
7696 i == Xboom_1 && j == 6 ? 6 :
7697 i == Xboom_1 && j == 7 ? 8 :
7698 i == Xboom_2 && j == 0 ? 8 :
7699 i == Xboom_2 && j == 1 ? 8 :
7700 i == Xboom_2 && j == 2 ? 10 :
7701 i == Xboom_2 && j == 3 ? 10 :
7702 i == Xboom_2 && j == 4 ? 10 :
7703 i == Xboom_2 && j == 5 ? 12 :
7704 i == Xboom_2 && j == 6 ? 12 :
7705 i == Xboom_2 && j == 7 ? 12 :
7706 special_animation && j == 4 ? 3 :
7707 effective_action != action ? 0 :
7711 Bitmap *debug_bitmap = g_em->bitmap;
7712 int debug_src_x = g_em->src_x;
7713 int debug_src_y = g_em->src_y;
7716 int frame = getAnimationFrame(g->anim_frames,
7719 g->anim_start_frame,
7722 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
7723 g->double_movement && is_backside);
7725 g_em->bitmap = src_bitmap;
7726 g_em->src_x = src_x;
7727 g_em->src_y = src_y;
7728 g_em->src_offset_x = 0;
7729 g_em->src_offset_y = 0;
7730 g_em->dst_offset_x = 0;
7731 g_em->dst_offset_y = 0;
7732 g_em->width = TILEX;
7733 g_em->height = TILEY;
7735 g_em->preserve_background = FALSE;
7737 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
7740 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
7741 effective_action == ACTION_MOVING ||
7742 effective_action == ACTION_PUSHING ||
7743 effective_action == ACTION_EATING)) ||
7744 (!has_action_graphics && (effective_action == ACTION_FILLING ||
7745 effective_action == ACTION_EMPTYING)))
7748 (effective_action == ACTION_FALLING ||
7749 effective_action == ACTION_FILLING ||
7750 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
7751 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
7752 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
7753 int num_steps = (i == Ydrip_s1 ? 16 :
7754 i == Ydrip_s1B ? 16 :
7755 i == Ydrip_s2 ? 16 :
7756 i == Ydrip_s2B ? 16 :
7757 i == Xsand_stonein_1 ? 32 :
7758 i == Xsand_stonein_2 ? 32 :
7759 i == Xsand_stonein_3 ? 32 :
7760 i == Xsand_stonein_4 ? 32 :
7761 i == Xsand_stoneout_1 ? 16 :
7762 i == Xsand_stoneout_2 ? 16 : 8);
7763 int cx = ABS(dx) * (TILEX / num_steps);
7764 int cy = ABS(dy) * (TILEY / num_steps);
7765 int step_frame = (i == Ydrip_s2 ? j + 8 :
7766 i == Ydrip_s2B ? j + 8 :
7767 i == Xsand_stonein_2 ? j + 8 :
7768 i == Xsand_stonein_3 ? j + 16 :
7769 i == Xsand_stonein_4 ? j + 24 :
7770 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
7771 int step = (is_backside ? step_frame : num_steps - step_frame);
7773 if (is_backside) /* tile where movement starts */
7775 if (dx < 0 || dy < 0)
7777 g_em->src_offset_x = cx * step;
7778 g_em->src_offset_y = cy * step;
7782 g_em->dst_offset_x = cx * step;
7783 g_em->dst_offset_y = cy * step;
7786 else /* tile where movement ends */
7788 if (dx < 0 || dy < 0)
7790 g_em->dst_offset_x = cx * step;
7791 g_em->dst_offset_y = cy * step;
7795 g_em->src_offset_x = cx * step;
7796 g_em->src_offset_y = cy * step;
7800 g_em->width = TILEX - cx * step;
7801 g_em->height = TILEY - cy * step;
7804 /* create unique graphic identifier to decide if tile must be redrawn */
7805 /* bit 31 - 16 (16 bit): EM style graphic
7806 bit 15 - 12 ( 4 bit): EM style frame
7807 bit 11 - 6 ( 6 bit): graphic width
7808 bit 5 - 0 ( 6 bit): graphic height */
7809 g_em->unique_identifier =
7810 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
7814 /* skip check for EMC elements not contained in original EMC artwork */
7815 if (element == EL_EMC_FAKE_ACID)
7818 if (g_em->bitmap != debug_bitmap ||
7819 g_em->src_x != debug_src_x ||
7820 g_em->src_y != debug_src_y ||
7821 g_em->src_offset_x != 0 ||
7822 g_em->src_offset_y != 0 ||
7823 g_em->dst_offset_x != 0 ||
7824 g_em->dst_offset_y != 0 ||
7825 g_em->width != TILEX ||
7826 g_em->height != TILEY)
7828 static int last_i = -1;
7836 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
7837 i, element, element_info[element].token_name,
7838 element_action_info[effective_action].suffix, direction);
7840 if (element != effective_element)
7841 printf(" [%d ('%s')]",
7843 element_info[effective_element].token_name);
7847 if (g_em->bitmap != debug_bitmap)
7848 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
7849 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
7851 if (g_em->src_x != debug_src_x ||
7852 g_em->src_y != debug_src_y)
7853 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
7854 j, (is_backside ? 'B' : 'F'),
7855 g_em->src_x, g_em->src_y,
7856 g_em->src_x / 32, g_em->src_y / 32,
7857 debug_src_x, debug_src_y,
7858 debug_src_x / 32, debug_src_y / 32);
7860 if (g_em->src_offset_x != 0 ||
7861 g_em->src_offset_y != 0 ||
7862 g_em->dst_offset_x != 0 ||
7863 g_em->dst_offset_y != 0)
7864 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
7866 g_em->src_offset_x, g_em->src_offset_y,
7867 g_em->dst_offset_x, g_em->dst_offset_y);
7869 if (g_em->width != TILEX ||
7870 g_em->height != TILEY)
7871 printf(" %d (%d): size %d,%d should be %d,%d\n",
7873 g_em->width, g_em->height, TILEX, TILEY);
7875 num_em_gfx_errors++;
7882 for (i = 0; i < TILE_MAX; i++)
7884 for (j = 0; j < 8; j++)
7886 int element = object_mapping[i].element_rnd;
7887 int action = object_mapping[i].action;
7888 int direction = object_mapping[i].direction;
7889 boolean is_backside = object_mapping[i].is_backside;
7890 int graphic_action = el_act_dir2img(element, action, direction);
7891 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
7893 if ((action == ACTION_SMASHED_BY_ROCK ||
7894 action == ACTION_SMASHED_BY_SPRING ||
7895 action == ACTION_EATING) &&
7896 graphic_action == graphic_default)
7898 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
7899 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
7900 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
7901 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
7904 /* no separate animation for "smashed by rock" -- use rock instead */
7905 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7906 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
7908 g_em->bitmap = g_xx->bitmap;
7909 g_em->src_x = g_xx->src_x;
7910 g_em->src_y = g_xx->src_y;
7911 g_em->src_offset_x = g_xx->src_offset_x;
7912 g_em->src_offset_y = g_xx->src_offset_y;
7913 g_em->dst_offset_x = g_xx->dst_offset_x;
7914 g_em->dst_offset_y = g_xx->dst_offset_y;
7915 g_em->width = g_xx->width;
7916 g_em->height = g_xx->height;
7917 g_em->unique_identifier = g_xx->unique_identifier;
7920 g_em->preserve_background = TRUE;
7925 for (p = 0; p < MAX_PLAYERS; p++)
7927 for (i = 0; i < SPR_MAX; i++)
7929 int element = player_mapping[p][i].element_rnd;
7930 int action = player_mapping[p][i].action;
7931 int direction = player_mapping[p][i].direction;
7933 for (j = 0; j < 8; j++)
7935 int effective_element = element;
7936 int effective_action = action;
7937 int graphic = (direction == MV_NONE ?
7938 el_act2img(effective_element, effective_action) :
7939 el_act_dir2img(effective_element, effective_action,
7941 struct GraphicInfo *g = &graphic_info[graphic];
7942 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
7948 Bitmap *debug_bitmap = g_em->bitmap;
7949 int debug_src_x = g_em->src_x;
7950 int debug_src_y = g_em->src_y;
7953 int frame = getAnimationFrame(g->anim_frames,
7956 g->anim_start_frame,
7959 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
7961 g_em->bitmap = src_bitmap;
7962 g_em->src_x = src_x;
7963 g_em->src_y = src_y;
7964 g_em->src_offset_x = 0;
7965 g_em->src_offset_y = 0;
7966 g_em->dst_offset_x = 0;
7967 g_em->dst_offset_y = 0;
7968 g_em->width = TILEX;
7969 g_em->height = TILEY;
7973 /* skip check for EMC elements not contained in original EMC artwork */
7974 if (element == EL_PLAYER_3 ||
7975 element == EL_PLAYER_4)
7978 if (g_em->bitmap != debug_bitmap ||
7979 g_em->src_x != debug_src_x ||
7980 g_em->src_y != debug_src_y)
7982 static int last_i = -1;
7990 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
7991 p, i, element, element_info[element].token_name,
7992 element_action_info[effective_action].suffix, direction);
7994 if (element != effective_element)
7995 printf(" [%d ('%s')]",
7997 element_info[effective_element].token_name);
8001 if (g_em->bitmap != debug_bitmap)
8002 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
8003 j, (int)(g_em->bitmap), (int)(debug_bitmap));
8005 if (g_em->src_x != debug_src_x ||
8006 g_em->src_y != debug_src_y)
8007 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
8009 g_em->src_x, g_em->src_y,
8010 g_em->src_x / 32, g_em->src_y / 32,
8011 debug_src_x, debug_src_y,
8012 debug_src_x / 32, debug_src_y / 32);
8014 num_em_gfx_errors++;
8024 printf("::: [%d errors found]\n", num_em_gfx_errors);
8030 void CheckSaveEngineSnapshot_EM(byte action[MAX_PLAYERS], int frame,
8031 boolean any_player_moving,
8032 boolean any_player_snapping,
8033 boolean any_player_dropping)
8035 static boolean player_was_waiting = TRUE;
8037 if (frame == 0 && !any_player_dropping)
8039 if (!player_was_waiting)
8041 if (!SaveEngineSnapshotToList())
8044 player_was_waiting = TRUE;
8047 else if (any_player_moving || any_player_snapping || any_player_dropping)
8049 player_was_waiting = FALSE;
8053 void CheckSaveEngineSnapshot_SP(boolean murphy_is_waiting,
8054 boolean murphy_is_dropping)
8056 static boolean player_was_waiting = TRUE;
8058 if (murphy_is_waiting)
8060 if (!player_was_waiting)
8062 if (!SaveEngineSnapshotToList())
8065 player_was_waiting = TRUE;
8070 player_was_waiting = FALSE;
8074 void CheckSingleStepMode_EM(byte action[MAX_PLAYERS], int frame,
8075 boolean any_player_moving,
8076 boolean any_player_snapping,
8077 boolean any_player_dropping)
8079 if (tape.single_step && tape.recording && !tape.pausing)
8080 if (frame == 0 && !any_player_dropping)
8081 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
8083 CheckSaveEngineSnapshot_EM(action, frame, any_player_moving,
8084 any_player_snapping, any_player_dropping);
8087 void CheckSingleStepMode_SP(boolean murphy_is_waiting,
8088 boolean murphy_is_dropping)
8090 if (tape.single_step && tape.recording && !tape.pausing)
8091 if (murphy_is_waiting)
8092 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
8094 CheckSaveEngineSnapshot_SP(murphy_is_waiting, murphy_is_dropping);
8097 void getGraphicSource_SP(struct GraphicInfo_SP *g_sp,
8098 int graphic, int sync_frame, int x, int y)
8100 int frame = getGraphicAnimationFrame(graphic, sync_frame);
8102 getGraphicSource(graphic, frame, &g_sp->bitmap, &g_sp->src_x, &g_sp->src_y);
8105 boolean isNextAnimationFrame_SP(int graphic, int sync_frame)
8107 return (IS_NEXT_FRAME(sync_frame, graphic));
8110 int getGraphicInfo_Delay(int graphic)
8112 return graphic_info[graphic].anim_delay;
8115 void PlayMenuSoundExt(int sound)
8117 if (sound == SND_UNDEFINED)
8120 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8121 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8124 if (IS_LOOP_SOUND(sound))
8125 PlaySoundLoop(sound);
8130 void PlayMenuSound()
8132 PlayMenuSoundExt(menu.sound[game_status]);
8135 void PlayMenuSoundStereo(int sound, int stereo_position)
8137 if (sound == SND_UNDEFINED)
8140 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8141 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8144 if (IS_LOOP_SOUND(sound))
8145 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
8147 PlaySoundStereo(sound, stereo_position);
8150 void PlayMenuSoundIfLoopExt(int sound)
8152 if (sound == SND_UNDEFINED)
8155 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8156 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8159 if (IS_LOOP_SOUND(sound))
8160 PlaySoundLoop(sound);
8163 void PlayMenuSoundIfLoop()
8165 PlayMenuSoundIfLoopExt(menu.sound[game_status]);
8168 void PlayMenuMusicExt(int music)
8170 if (music == MUS_UNDEFINED)
8173 if (!setup.sound_music)
8179 void PlayMenuMusic()
8181 PlayMenuMusicExt(menu.music[game_status]);
8184 void PlaySoundActivating()
8187 PlaySound(SND_MENU_ITEM_ACTIVATING);
8191 void PlaySoundSelecting()
8194 PlaySound(SND_MENU_ITEM_SELECTING);
8198 void ToggleFullscreenOrChangeWindowScalingIfNeeded()
8200 boolean change_fullscreen = (setup.fullscreen !=
8201 video.fullscreen_enabled);
8202 boolean change_window_scaling_percent = (!video.fullscreen_enabled &&
8203 setup.window_scaling_percent !=
8204 video.window_scaling_percent);
8206 if (change_window_scaling_percent && video.fullscreen_enabled)
8209 if (!change_window_scaling_percent && !video.fullscreen_available)
8212 #if defined(TARGET_SDL2)
8213 if (change_window_scaling_percent)
8215 SDLSetWindowScaling(setup.window_scaling_percent);
8219 else if (change_fullscreen)
8221 SDLSetWindowFullscreen(setup.fullscreen);
8223 /* set setup value according to successfully changed fullscreen mode */
8224 setup.fullscreen = video.fullscreen_enabled;
8230 if (change_fullscreen ||
8231 change_window_scaling_percent)
8233 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
8235 /* save backbuffer content which gets lost when toggling fullscreen mode */
8236 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8238 if (change_window_scaling_percent)
8240 /* keep window mode, but change window scaling */
8241 video.fullscreen_enabled = TRUE; /* force new window scaling */
8244 /* toggle fullscreen */
8245 ChangeVideoModeIfNeeded(setup.fullscreen);
8247 /* set setup value according to successfully changed fullscreen mode */
8248 setup.fullscreen = video.fullscreen_enabled;
8250 /* restore backbuffer content from temporary backbuffer backup bitmap */
8251 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8253 FreeBitmap(tmp_backbuffer);
8255 /* update visible window/screen */
8256 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8260 void JoinRectangles(int *x, int *y, int *width, int *height,
8261 int x2, int y2, int width2, int height2)
8263 // do not join with "off-screen" rectangle
8264 if (x2 == -1 || y2 == -1)
8269 *width = MAX(*width, width2);
8270 *height = MAX(*height, height2);
8273 void SetAnimStatus(int anim_status_new)
8275 if (anim_status_new == GAME_MODE_MAIN)
8276 anim_status_new = GAME_MODE_PSEUDO_MAINONLY;
8278 global.anim_status_next = anim_status_new;
8280 // directly set screen modes that are entered without fading
8281 if ((global.anim_status == GAME_MODE_PSEUDO_MAINONLY &&
8282 global.anim_status_next == GAME_MODE_PSEUDO_TYPENAME) ||
8283 (global.anim_status == GAME_MODE_PSEUDO_TYPENAME &&
8284 global.anim_status_next == GAME_MODE_PSEUDO_MAINONLY))
8285 global.anim_status = global.anim_status_next;
8288 void SetGameStatus(int game_status_new)
8290 game_status = game_status_new;
8292 SetAnimStatus(game_status_new);
8295 void SetFontStatus(int game_status_new)
8297 static int last_game_status = -1;
8299 if (game_status_new != -1)
8301 // set game status for font use after storing last game status
8302 last_game_status = game_status;
8303 game_status = game_status_new;
8307 // reset game status after font use from last stored game status
8308 game_status = last_game_status;
8312 void ResetFontStatus()
8317 void ChangeViewportPropertiesIfNeeded()
8319 int gfx_game_mode = game_status;
8320 int gfx_game_mode2 = (game_status == GAME_MODE_EDITOR ? GAME_MODE_DEFAULT :
8322 struct RectWithBorder *vp_window = &viewport.window[gfx_game_mode];
8323 struct RectWithBorder *vp_playfield = &viewport.playfield[gfx_game_mode];
8324 struct RectWithBorder *vp_door_1 = &viewport.door_1[gfx_game_mode];
8325 struct RectWithBorder *vp_door_2 = &viewport.door_2[gfx_game_mode2];
8326 struct RectWithBorder *vp_door_3 = &viewport.door_2[GAME_MODE_EDITOR];
8327 int new_win_xsize = vp_window->width;
8328 int new_win_ysize = vp_window->height;
8329 int border_size = vp_playfield->border_size;
8330 int new_sx = vp_playfield->x + border_size;
8331 int new_sy = vp_playfield->y + border_size;
8332 int new_sxsize = vp_playfield->width - 2 * border_size;
8333 int new_sysize = vp_playfield->height - 2 * border_size;
8334 int new_real_sx = vp_playfield->x;
8335 int new_real_sy = vp_playfield->y;
8336 int new_full_sxsize = vp_playfield->width;
8337 int new_full_sysize = vp_playfield->height;
8338 int new_dx = vp_door_1->x;
8339 int new_dy = vp_door_1->y;
8340 int new_dxsize = vp_door_1->width;
8341 int new_dysize = vp_door_1->height;
8342 int new_vx = vp_door_2->x;
8343 int new_vy = vp_door_2->y;
8344 int new_vxsize = vp_door_2->width;
8345 int new_vysize = vp_door_2->height;
8346 int new_ex = vp_door_3->x;
8347 int new_ey = vp_door_3->y;
8348 int new_exsize = vp_door_3->width;
8349 int new_eysize = vp_door_3->height;
8350 int new_tilesize_var =
8351 (setup.small_game_graphics ? MINI_TILESIZE : game.tile_size);
8353 int tilesize = (gfx_game_mode == GAME_MODE_PLAYING ? new_tilesize_var :
8354 gfx_game_mode == GAME_MODE_EDITOR ? MINI_TILESIZE : TILESIZE);
8355 int new_scr_fieldx = new_sxsize / tilesize;
8356 int new_scr_fieldy = new_sysize / tilesize;
8357 int new_scr_fieldx_buffers = new_sxsize / new_tilesize_var;
8358 int new_scr_fieldy_buffers = new_sysize / new_tilesize_var;
8359 boolean init_gfx_buffers = FALSE;
8360 boolean init_video_buffer = FALSE;
8361 boolean init_gadgets_and_anims = FALSE;
8362 boolean init_em_graphics = FALSE;
8364 if (new_win_xsize != WIN_XSIZE ||
8365 new_win_ysize != WIN_YSIZE)
8367 WIN_XSIZE = new_win_xsize;
8368 WIN_YSIZE = new_win_ysize;
8370 init_video_buffer = TRUE;
8371 init_gfx_buffers = TRUE;
8372 init_gadgets_and_anims = TRUE;
8374 // printf("::: video: init_video_buffer, init_gfx_buffers\n");
8377 if (new_scr_fieldx != SCR_FIELDX ||
8378 new_scr_fieldy != SCR_FIELDY)
8380 /* this always toggles between MAIN and GAME when using small tile size */
8382 SCR_FIELDX = new_scr_fieldx;
8383 SCR_FIELDY = new_scr_fieldy;
8385 // printf("::: new_scr_fieldx != SCR_FIELDX ...\n");
8396 new_sxsize != SXSIZE ||
8397 new_sysize != SYSIZE ||
8398 new_dxsize != DXSIZE ||
8399 new_dysize != DYSIZE ||
8400 new_vxsize != VXSIZE ||
8401 new_vysize != VYSIZE ||
8402 new_exsize != EXSIZE ||
8403 new_eysize != EYSIZE ||
8404 new_real_sx != REAL_SX ||
8405 new_real_sy != REAL_SY ||
8406 new_full_sxsize != FULL_SXSIZE ||
8407 new_full_sysize != FULL_SYSIZE ||
8408 new_tilesize_var != TILESIZE_VAR
8411 // ------------------------------------------------------------------------
8412 // determine next fading area for changed viewport definitions
8413 // ------------------------------------------------------------------------
8415 // start with current playfield area (default fading area)
8418 FADE_SXSIZE = FULL_SXSIZE;
8419 FADE_SYSIZE = FULL_SYSIZE;
8421 // add new playfield area if position or size has changed
8422 if (new_real_sx != REAL_SX || new_real_sy != REAL_SY ||
8423 new_full_sxsize != FULL_SXSIZE || new_full_sysize != FULL_SYSIZE)
8425 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
8426 new_real_sx, new_real_sy, new_full_sxsize,new_full_sysize);
8429 // add current and new door 1 area if position or size has changed
8430 if (new_dx != DX || new_dy != DY ||
8431 new_dxsize != DXSIZE || new_dysize != DYSIZE)
8433 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
8434 DX, DY, DXSIZE, DYSIZE);
8435 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
8436 new_dx, new_dy, new_dxsize, new_dysize);
8439 // add current and new door 2 area if position or size has changed
8440 if (new_dx != VX || new_dy != VY ||
8441 new_dxsize != VXSIZE || new_dysize != VYSIZE)
8443 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
8444 VX, VY, VXSIZE, VYSIZE);
8445 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
8446 new_vx, new_vy, new_vxsize, new_vysize);
8449 // ------------------------------------------------------------------------
8450 // handle changed tile size
8451 // ------------------------------------------------------------------------
8453 if (new_tilesize_var != TILESIZE_VAR)
8455 // printf("::: new_tilesize_var != TILESIZE_VAR\n");
8457 // changing tile size invalidates scroll values of engine snapshots
8458 FreeEngineSnapshotSingle();
8460 // changing tile size requires update of graphic mapping for EM engine
8461 init_em_graphics = TRUE;
8472 SXSIZE = new_sxsize;
8473 SYSIZE = new_sysize;
8474 DXSIZE = new_dxsize;
8475 DYSIZE = new_dysize;
8476 VXSIZE = new_vxsize;
8477 VYSIZE = new_vysize;
8478 EXSIZE = new_exsize;
8479 EYSIZE = new_eysize;
8480 REAL_SX = new_real_sx;
8481 REAL_SY = new_real_sy;
8482 FULL_SXSIZE = new_full_sxsize;
8483 FULL_SYSIZE = new_full_sysize;
8484 TILESIZE_VAR = new_tilesize_var;
8486 init_gfx_buffers = TRUE;
8487 init_gadgets_and_anims = TRUE;
8489 // printf("::: viewports: init_gfx_buffers\n");
8490 // printf("::: viewports: init_gadgets_and_anims\n");
8493 if (init_gfx_buffers)
8495 // printf("::: init_gfx_buffers\n");
8497 SCR_FIELDX = new_scr_fieldx_buffers;
8498 SCR_FIELDY = new_scr_fieldy_buffers;
8502 SCR_FIELDX = new_scr_fieldx;
8503 SCR_FIELDY = new_scr_fieldy;
8505 SetDrawDeactivationMask(REDRAW_NONE);
8506 SetDrawBackgroundMask(REDRAW_FIELD);
8509 if (init_video_buffer)
8511 // printf("::: init_video_buffer\n");
8513 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
8514 InitImageTextures();
8517 if (init_gadgets_and_anims)
8519 // printf("::: init_gadgets_and_anims\n");
8522 InitGlobalAnimations();
8525 if (init_em_graphics)
8527 InitGraphicInfo_EM();