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 getFixedGraphicSource(dpc->graphic, frame, &bitmap,
4464 &g_src_x, &g_src_y);
4469 if (!door_panel_drawn[door_index])
4471 ClearRectangle(drawto, door_rect->x, door_rect->y,
4472 door_rect->width, door_rect->height);
4474 door_panel_drawn[door_index] = TRUE;
4477 // draw opening or closing door parts
4479 if (pos->step_xoffset < 0) // door part on right side
4482 dst_xx = pos->x + ABS(kk * pos->step_xoffset);
4485 if (dst_xx + width > door_rect->width)
4486 width = door_rect->width - dst_xx;
4488 else // door part on left side
4491 dst_xx = pos->x - kk * pos->step_xoffset;
4495 src_xx = ABS(dst_xx);
4499 width = g->width - src_xx;
4501 if (width > door_rect->width)
4502 width = door_rect->width;
4504 // printf("::: k == %d [%d] \n", k, start_step);
4507 if (pos->step_yoffset < 0) // door part on bottom side
4510 dst_yy = pos->y + ABS(kk * pos->step_yoffset);
4513 if (dst_yy + height > door_rect->height)
4514 height = door_rect->height - dst_yy;
4516 else // door part on top side
4519 dst_yy = pos->y - kk * pos->step_yoffset;
4523 src_yy = ABS(dst_yy);
4527 height = g->height - src_yy;
4530 src_x = g_src_x + src_xx;
4531 src_y = g_src_y + src_yy;
4533 dst_x = door_rect->x + dst_xx;
4534 dst_y = door_rect->y + dst_yy;
4536 is_panel_and_door_has_closed =
4539 panel_has_doors[door_index] &&
4540 k >= num_move_steps_doors_only - 1);
4542 if (width >= 0 && width <= g->width &&
4543 height >= 0 && height <= g->height &&
4544 !is_panel_and_door_has_closed)
4546 if (is_panel || !pos->draw_masked)
4547 BlitBitmap(bitmap, drawto, src_x, src_y, width, height,
4550 BlitBitmapMasked(bitmap, drawto, src_x, src_y, width, height,
4554 redraw_mask |= REDRAW_DOOR_FROM_TOKEN(door_token);
4556 if ((part_opening && (width < 0 || height < 0)) ||
4557 (part_closing && (width >= g->width && height >= g->height)))
4558 door_part_done[nr] = TRUE;
4560 // continue door part animations, but not panel after door has closed
4561 if (!door_part_done[nr] && !is_panel_and_door_has_closed)
4562 door_part_done_all = FALSE;
4565 if (!(door_state & DOOR_NO_DELAY))
4569 SkipUntilDelayReached(&door_delay, door_delay_value, &k, last_frame);
4571 current_move_delay += max_step_delay;
4574 if (door_part_done_all)
4579 if (door_state & DOOR_ACTION_1)
4580 door1 = door_state & DOOR_ACTION_1;
4581 if (door_state & DOOR_ACTION_2)
4582 door2 = door_state & DOOR_ACTION_2;
4584 // draw masked border over door area
4585 DrawMaskedBorder(REDRAW_DOOR_1);
4586 DrawMaskedBorder(REDRAW_DOOR_2);
4588 return (door1 | door2);
4591 static boolean useSpecialEditorDoor()
4593 int graphic = IMG_GLOBAL_BORDER_EDITOR;
4594 boolean redefined = getImageListEntryFromImageID(graphic)->redefined;
4596 // do not draw special editor door if editor border defined or redefined
4597 if (graphic_info[graphic].bitmap != NULL || redefined)
4600 // do not draw special editor door if global border defined to be empty
4601 if (graphic_info[IMG_GLOBAL_BORDER].bitmap == NULL)
4604 // do not draw special editor door if viewport definitions do not match
4608 EY + EYSIZE != VY + VYSIZE)
4614 void DrawSpecialEditorDoor()
4616 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
4617 int top_border_width = gfx1->width;
4618 int top_border_height = gfx1->height;
4619 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
4620 int ex = EX - outer_border;
4621 int ey = EY - outer_border;
4622 int vy = VY - outer_border;
4623 int exsize = EXSIZE + 2 * outer_border;
4625 if (!useSpecialEditorDoor())
4628 /* draw bigger level editor toolbox window */
4629 BlitBitmap(gfx1->bitmap, drawto, gfx1->src_x, gfx1->src_y,
4630 top_border_width, top_border_height, ex, ey - top_border_height);
4631 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto, ex, vy,
4632 exsize, EYSIZE - VYSIZE + outer_border, ex, ey);
4634 redraw_mask |= REDRAW_ALL;
4637 void UndrawSpecialEditorDoor()
4639 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
4640 int top_border_width = gfx1->width;
4641 int top_border_height = gfx1->height;
4642 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
4643 int ex = EX - outer_border;
4644 int ey = EY - outer_border;
4645 int ey_top = ey - top_border_height;
4646 int exsize = EXSIZE + 2 * outer_border;
4647 int eysize = EYSIZE + 2 * outer_border;
4649 if (!useSpecialEditorDoor())
4652 /* draw normal tape recorder window */
4653 if (graphic_info[IMG_GLOBAL_BORDER].bitmap)
4655 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
4656 ex, ey_top, top_border_width, top_border_height,
4658 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
4659 ex, ey, exsize, eysize, ex, ey);
4663 // if screen background is set to "[NONE]", clear editor toolbox window
4664 ClearRectangle(drawto, ex, ey_top, top_border_width, top_border_height);
4665 ClearRectangle(drawto, ex, ey, exsize, eysize);
4668 redraw_mask |= REDRAW_ALL;
4672 /* ---------- new tool button stuff ---------------------------------------- */
4677 struct TextPosInfo *pos;
4680 } toolbutton_info[NUM_TOOL_BUTTONS] =
4683 IMG_GFX_REQUEST_BUTTON_YES, &request.button.yes,
4684 TOOL_CTRL_ID_YES, "yes"
4687 IMG_GFX_REQUEST_BUTTON_NO, &request.button.no,
4688 TOOL_CTRL_ID_NO, "no"
4691 IMG_GFX_REQUEST_BUTTON_CONFIRM, &request.button.confirm,
4692 TOOL_CTRL_ID_CONFIRM, "confirm"
4695 IMG_GFX_REQUEST_BUTTON_PLAYER_1, &request.button.player_1,
4696 TOOL_CTRL_ID_PLAYER_1, "player 1"
4699 IMG_GFX_REQUEST_BUTTON_PLAYER_2, &request.button.player_2,
4700 TOOL_CTRL_ID_PLAYER_2, "player 2"
4703 IMG_GFX_REQUEST_BUTTON_PLAYER_3, &request.button.player_3,
4704 TOOL_CTRL_ID_PLAYER_3, "player 3"
4707 IMG_GFX_REQUEST_BUTTON_PLAYER_4, &request.button.player_4,
4708 TOOL_CTRL_ID_PLAYER_4, "player 4"
4712 void CreateToolButtons()
4716 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4718 struct GraphicInfo *gfx = &graphic_info[toolbutton_info[i].graphic];
4719 struct TextPosInfo *pos = toolbutton_info[i].pos;
4720 struct GadgetInfo *gi;
4721 Bitmap *deco_bitmap = None;
4722 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
4723 unsigned int event_mask = GD_EVENT_RELEASED;
4726 int gd_x = gfx->src_x;
4727 int gd_y = gfx->src_y;
4728 int gd_xp = gfx->src_x + gfx->pressed_xoffset;
4729 int gd_yp = gfx->src_y + gfx->pressed_yoffset;
4732 if (global.use_envelope_request)
4733 setRequestPosition(&dx, &dy, TRUE);
4735 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
4737 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
4739 getSizedGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr), 0,
4740 pos->size, &deco_bitmap, &deco_x, &deco_y);
4741 deco_xpos = (gfx->width - pos->size) / 2;
4742 deco_ypos = (gfx->height - pos->size) / 2;
4745 gi = CreateGadget(GDI_CUSTOM_ID, id,
4746 GDI_INFO_TEXT, toolbutton_info[i].infotext,
4747 GDI_X, dx + GDI_ACTIVE_POS(pos->x),
4748 GDI_Y, dy + GDI_ACTIVE_POS(pos->y),
4749 GDI_WIDTH, gfx->width,
4750 GDI_HEIGHT, gfx->height,
4751 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
4752 GDI_STATE, GD_BUTTON_UNPRESSED,
4753 GDI_DESIGN_UNPRESSED, gfx->bitmap, gd_x, gd_y,
4754 GDI_DESIGN_PRESSED, gfx->bitmap, gd_xp, gd_yp,
4755 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
4756 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
4757 GDI_DECORATION_SIZE, pos->size, pos->size,
4758 GDI_DECORATION_SHIFTING, 1, 1,
4759 GDI_DIRECT_DRAW, FALSE,
4760 GDI_EVENT_MASK, event_mask,
4761 GDI_CALLBACK_ACTION, HandleToolButtons,
4765 Error(ERR_EXIT, "cannot create gadget");
4767 tool_gadget[id] = gi;
4771 void FreeToolButtons()
4775 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4776 FreeGadget(tool_gadget[i]);
4779 static void UnmapToolButtons()
4783 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4784 UnmapGadget(tool_gadget[i]);
4787 static void HandleToolButtons(struct GadgetInfo *gi)
4789 request_gadget_id = gi->custom_id;
4792 static struct Mapping_EM_to_RND_object
4795 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
4796 boolean is_backside; /* backside of moving element */
4802 em_object_mapping_list[] =
4805 Xblank, TRUE, FALSE,
4809 Yacid_splash_eB, FALSE, FALSE,
4810 EL_ACID_SPLASH_RIGHT, -1, -1
4813 Yacid_splash_wB, FALSE, FALSE,
4814 EL_ACID_SPLASH_LEFT, -1, -1
4817 #ifdef EM_ENGINE_BAD_ROLL
4819 Xstone_force_e, FALSE, FALSE,
4820 EL_ROCK, -1, MV_BIT_RIGHT
4823 Xstone_force_w, FALSE, FALSE,
4824 EL_ROCK, -1, MV_BIT_LEFT
4827 Xnut_force_e, FALSE, FALSE,
4828 EL_NUT, -1, MV_BIT_RIGHT
4831 Xnut_force_w, FALSE, FALSE,
4832 EL_NUT, -1, MV_BIT_LEFT
4835 Xspring_force_e, FALSE, FALSE,
4836 EL_SPRING, -1, MV_BIT_RIGHT
4839 Xspring_force_w, FALSE, FALSE,
4840 EL_SPRING, -1, MV_BIT_LEFT
4843 Xemerald_force_e, FALSE, FALSE,
4844 EL_EMERALD, -1, MV_BIT_RIGHT
4847 Xemerald_force_w, FALSE, FALSE,
4848 EL_EMERALD, -1, MV_BIT_LEFT
4851 Xdiamond_force_e, FALSE, FALSE,
4852 EL_DIAMOND, -1, MV_BIT_RIGHT
4855 Xdiamond_force_w, FALSE, FALSE,
4856 EL_DIAMOND, -1, MV_BIT_LEFT
4859 Xbomb_force_e, FALSE, FALSE,
4860 EL_BOMB, -1, MV_BIT_RIGHT
4863 Xbomb_force_w, FALSE, FALSE,
4864 EL_BOMB, -1, MV_BIT_LEFT
4866 #endif /* EM_ENGINE_BAD_ROLL */
4869 Xstone, TRUE, FALSE,
4873 Xstone_pause, FALSE, FALSE,
4877 Xstone_fall, FALSE, FALSE,
4881 Ystone_s, FALSE, FALSE,
4882 EL_ROCK, ACTION_FALLING, -1
4885 Ystone_sB, FALSE, TRUE,
4886 EL_ROCK, ACTION_FALLING, -1
4889 Ystone_e, FALSE, FALSE,
4890 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
4893 Ystone_eB, FALSE, TRUE,
4894 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
4897 Ystone_w, FALSE, FALSE,
4898 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
4901 Ystone_wB, FALSE, TRUE,
4902 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
4909 Xnut_pause, FALSE, FALSE,
4913 Xnut_fall, FALSE, FALSE,
4917 Ynut_s, FALSE, FALSE,
4918 EL_NUT, ACTION_FALLING, -1
4921 Ynut_sB, FALSE, TRUE,
4922 EL_NUT, ACTION_FALLING, -1
4925 Ynut_e, FALSE, FALSE,
4926 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
4929 Ynut_eB, FALSE, TRUE,
4930 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
4933 Ynut_w, FALSE, FALSE,
4934 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
4937 Ynut_wB, FALSE, TRUE,
4938 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
4941 Xbug_n, TRUE, FALSE,
4945 Xbug_e, TRUE, FALSE,
4946 EL_BUG_RIGHT, -1, -1
4949 Xbug_s, TRUE, FALSE,
4953 Xbug_w, TRUE, FALSE,
4957 Xbug_gon, FALSE, FALSE,
4961 Xbug_goe, FALSE, FALSE,
4962 EL_BUG_RIGHT, -1, -1
4965 Xbug_gos, FALSE, FALSE,
4969 Xbug_gow, FALSE, FALSE,
4973 Ybug_n, FALSE, FALSE,
4974 EL_BUG, ACTION_MOVING, MV_BIT_UP
4977 Ybug_nB, FALSE, TRUE,
4978 EL_BUG, ACTION_MOVING, MV_BIT_UP
4981 Ybug_e, FALSE, FALSE,
4982 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
4985 Ybug_eB, FALSE, TRUE,
4986 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
4989 Ybug_s, FALSE, FALSE,
4990 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
4993 Ybug_sB, FALSE, TRUE,
4994 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
4997 Ybug_w, FALSE, FALSE,
4998 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
5001 Ybug_wB, FALSE, TRUE,
5002 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
5005 Ybug_w_n, FALSE, FALSE,
5006 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
5009 Ybug_n_e, FALSE, FALSE,
5010 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
5013 Ybug_e_s, FALSE, FALSE,
5014 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
5017 Ybug_s_w, FALSE, FALSE,
5018 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
5021 Ybug_e_n, FALSE, FALSE,
5022 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
5025 Ybug_s_e, FALSE, FALSE,
5026 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
5029 Ybug_w_s, FALSE, FALSE,
5030 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
5033 Ybug_n_w, FALSE, FALSE,
5034 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
5037 Ybug_stone, FALSE, FALSE,
5038 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
5041 Ybug_spring, FALSE, FALSE,
5042 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
5045 Xtank_n, TRUE, FALSE,
5046 EL_SPACESHIP_UP, -1, -1
5049 Xtank_e, TRUE, FALSE,
5050 EL_SPACESHIP_RIGHT, -1, -1
5053 Xtank_s, TRUE, FALSE,
5054 EL_SPACESHIP_DOWN, -1, -1
5057 Xtank_w, TRUE, FALSE,
5058 EL_SPACESHIP_LEFT, -1, -1
5061 Xtank_gon, FALSE, FALSE,
5062 EL_SPACESHIP_UP, -1, -1
5065 Xtank_goe, FALSE, FALSE,
5066 EL_SPACESHIP_RIGHT, -1, -1
5069 Xtank_gos, FALSE, FALSE,
5070 EL_SPACESHIP_DOWN, -1, -1
5073 Xtank_gow, FALSE, FALSE,
5074 EL_SPACESHIP_LEFT, -1, -1
5077 Ytank_n, FALSE, FALSE,
5078 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
5081 Ytank_nB, FALSE, TRUE,
5082 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
5085 Ytank_e, FALSE, FALSE,
5086 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
5089 Ytank_eB, FALSE, TRUE,
5090 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
5093 Ytank_s, FALSE, FALSE,
5094 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
5097 Ytank_sB, FALSE, TRUE,
5098 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
5101 Ytank_w, FALSE, FALSE,
5102 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
5105 Ytank_wB, FALSE, TRUE,
5106 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
5109 Ytank_w_n, FALSE, FALSE,
5110 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
5113 Ytank_n_e, FALSE, FALSE,
5114 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
5117 Ytank_e_s, FALSE, FALSE,
5118 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
5121 Ytank_s_w, FALSE, FALSE,
5122 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
5125 Ytank_e_n, FALSE, FALSE,
5126 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
5129 Ytank_s_e, FALSE, FALSE,
5130 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
5133 Ytank_w_s, FALSE, FALSE,
5134 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
5137 Ytank_n_w, FALSE, FALSE,
5138 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
5141 Ytank_stone, FALSE, FALSE,
5142 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
5145 Ytank_spring, FALSE, FALSE,
5146 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
5149 Xandroid, TRUE, FALSE,
5150 EL_EMC_ANDROID, ACTION_ACTIVE, -1
5153 Xandroid_1_n, FALSE, FALSE,
5154 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
5157 Xandroid_2_n, FALSE, FALSE,
5158 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
5161 Xandroid_1_e, FALSE, FALSE,
5162 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
5165 Xandroid_2_e, FALSE, FALSE,
5166 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
5169 Xandroid_1_w, FALSE, FALSE,
5170 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
5173 Xandroid_2_w, FALSE, FALSE,
5174 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
5177 Xandroid_1_s, FALSE, FALSE,
5178 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
5181 Xandroid_2_s, FALSE, FALSE,
5182 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
5185 Yandroid_n, FALSE, FALSE,
5186 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
5189 Yandroid_nB, FALSE, TRUE,
5190 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
5193 Yandroid_ne, FALSE, FALSE,
5194 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
5197 Yandroid_neB, FALSE, TRUE,
5198 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
5201 Yandroid_e, FALSE, FALSE,
5202 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
5205 Yandroid_eB, FALSE, TRUE,
5206 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
5209 Yandroid_se, FALSE, FALSE,
5210 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
5213 Yandroid_seB, FALSE, TRUE,
5214 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
5217 Yandroid_s, FALSE, FALSE,
5218 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
5221 Yandroid_sB, FALSE, TRUE,
5222 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
5225 Yandroid_sw, FALSE, FALSE,
5226 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
5229 Yandroid_swB, FALSE, TRUE,
5230 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
5233 Yandroid_w, FALSE, FALSE,
5234 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
5237 Yandroid_wB, FALSE, TRUE,
5238 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
5241 Yandroid_nw, FALSE, FALSE,
5242 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
5245 Yandroid_nwB, FALSE, TRUE,
5246 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
5249 Xspring, TRUE, FALSE,
5253 Xspring_pause, FALSE, FALSE,
5257 Xspring_e, FALSE, FALSE,
5261 Xspring_w, FALSE, FALSE,
5265 Xspring_fall, FALSE, FALSE,
5269 Yspring_s, FALSE, FALSE,
5270 EL_SPRING, ACTION_FALLING, -1
5273 Yspring_sB, FALSE, TRUE,
5274 EL_SPRING, ACTION_FALLING, -1
5277 Yspring_e, FALSE, FALSE,
5278 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
5281 Yspring_eB, FALSE, TRUE,
5282 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
5285 Yspring_w, FALSE, FALSE,
5286 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
5289 Yspring_wB, FALSE, TRUE,
5290 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
5293 Yspring_kill_e, FALSE, FALSE,
5294 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
5297 Yspring_kill_eB, FALSE, TRUE,
5298 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
5301 Yspring_kill_w, FALSE, FALSE,
5302 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
5305 Yspring_kill_wB, FALSE, TRUE,
5306 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
5309 Xeater_n, TRUE, FALSE,
5310 EL_YAMYAM_UP, -1, -1
5313 Xeater_e, TRUE, FALSE,
5314 EL_YAMYAM_RIGHT, -1, -1
5317 Xeater_w, TRUE, FALSE,
5318 EL_YAMYAM_LEFT, -1, -1
5321 Xeater_s, TRUE, FALSE,
5322 EL_YAMYAM_DOWN, -1, -1
5325 Yeater_n, FALSE, FALSE,
5326 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
5329 Yeater_nB, FALSE, TRUE,
5330 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
5333 Yeater_e, FALSE, FALSE,
5334 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
5337 Yeater_eB, FALSE, TRUE,
5338 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
5341 Yeater_s, FALSE, FALSE,
5342 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
5345 Yeater_sB, FALSE, TRUE,
5346 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
5349 Yeater_w, FALSE, FALSE,
5350 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
5353 Yeater_wB, FALSE, TRUE,
5354 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
5357 Yeater_stone, FALSE, FALSE,
5358 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
5361 Yeater_spring, FALSE, FALSE,
5362 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
5365 Xalien, TRUE, FALSE,
5369 Xalien_pause, FALSE, FALSE,
5373 Yalien_n, FALSE, FALSE,
5374 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
5377 Yalien_nB, FALSE, TRUE,
5378 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
5381 Yalien_e, FALSE, FALSE,
5382 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
5385 Yalien_eB, FALSE, TRUE,
5386 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
5389 Yalien_s, FALSE, FALSE,
5390 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
5393 Yalien_sB, FALSE, TRUE,
5394 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
5397 Yalien_w, FALSE, FALSE,
5398 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
5401 Yalien_wB, FALSE, TRUE,
5402 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
5405 Yalien_stone, FALSE, FALSE,
5406 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
5409 Yalien_spring, FALSE, FALSE,
5410 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
5413 Xemerald, TRUE, FALSE,
5417 Xemerald_pause, FALSE, FALSE,
5421 Xemerald_fall, FALSE, FALSE,
5425 Xemerald_shine, FALSE, FALSE,
5426 EL_EMERALD, ACTION_TWINKLING, -1
5429 Yemerald_s, FALSE, FALSE,
5430 EL_EMERALD, ACTION_FALLING, -1
5433 Yemerald_sB, FALSE, TRUE,
5434 EL_EMERALD, ACTION_FALLING, -1
5437 Yemerald_e, FALSE, FALSE,
5438 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
5441 Yemerald_eB, FALSE, TRUE,
5442 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
5445 Yemerald_w, FALSE, FALSE,
5446 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
5449 Yemerald_wB, FALSE, TRUE,
5450 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
5453 Yemerald_eat, FALSE, FALSE,
5454 EL_EMERALD, ACTION_COLLECTING, -1
5457 Yemerald_stone, FALSE, FALSE,
5458 EL_NUT, ACTION_BREAKING, -1
5461 Xdiamond, TRUE, FALSE,
5465 Xdiamond_pause, FALSE, FALSE,
5469 Xdiamond_fall, FALSE, FALSE,
5473 Xdiamond_shine, FALSE, FALSE,
5474 EL_DIAMOND, ACTION_TWINKLING, -1
5477 Ydiamond_s, FALSE, FALSE,
5478 EL_DIAMOND, ACTION_FALLING, -1
5481 Ydiamond_sB, FALSE, TRUE,
5482 EL_DIAMOND, ACTION_FALLING, -1
5485 Ydiamond_e, FALSE, FALSE,
5486 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
5489 Ydiamond_eB, FALSE, TRUE,
5490 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
5493 Ydiamond_w, FALSE, FALSE,
5494 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
5497 Ydiamond_wB, FALSE, TRUE,
5498 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
5501 Ydiamond_eat, FALSE, FALSE,
5502 EL_DIAMOND, ACTION_COLLECTING, -1
5505 Ydiamond_stone, FALSE, FALSE,
5506 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
5509 Xdrip_fall, TRUE, FALSE,
5510 EL_AMOEBA_DROP, -1, -1
5513 Xdrip_stretch, FALSE, FALSE,
5514 EL_AMOEBA_DROP, ACTION_FALLING, -1
5517 Xdrip_stretchB, FALSE, TRUE,
5518 EL_AMOEBA_DROP, ACTION_FALLING, -1
5521 Xdrip_eat, FALSE, FALSE,
5522 EL_AMOEBA_DROP, ACTION_GROWING, -1
5525 Ydrip_s1, FALSE, FALSE,
5526 EL_AMOEBA_DROP, ACTION_FALLING, -1
5529 Ydrip_s1B, FALSE, TRUE,
5530 EL_AMOEBA_DROP, ACTION_FALLING, -1
5533 Ydrip_s2, FALSE, FALSE,
5534 EL_AMOEBA_DROP, ACTION_FALLING, -1
5537 Ydrip_s2B, FALSE, TRUE,
5538 EL_AMOEBA_DROP, ACTION_FALLING, -1
5545 Xbomb_pause, FALSE, FALSE,
5549 Xbomb_fall, FALSE, FALSE,
5553 Ybomb_s, FALSE, FALSE,
5554 EL_BOMB, ACTION_FALLING, -1
5557 Ybomb_sB, FALSE, TRUE,
5558 EL_BOMB, ACTION_FALLING, -1
5561 Ybomb_e, FALSE, FALSE,
5562 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
5565 Ybomb_eB, FALSE, TRUE,
5566 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
5569 Ybomb_w, FALSE, FALSE,
5570 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
5573 Ybomb_wB, FALSE, TRUE,
5574 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
5577 Ybomb_eat, FALSE, FALSE,
5578 EL_BOMB, ACTION_ACTIVATING, -1
5581 Xballoon, TRUE, FALSE,
5585 Yballoon_n, FALSE, FALSE,
5586 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
5589 Yballoon_nB, FALSE, TRUE,
5590 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
5593 Yballoon_e, FALSE, FALSE,
5594 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
5597 Yballoon_eB, FALSE, TRUE,
5598 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
5601 Yballoon_s, FALSE, FALSE,
5602 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
5605 Yballoon_sB, FALSE, TRUE,
5606 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
5609 Yballoon_w, FALSE, FALSE,
5610 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
5613 Yballoon_wB, FALSE, TRUE,
5614 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
5617 Xgrass, TRUE, FALSE,
5618 EL_EMC_GRASS, -1, -1
5621 Ygrass_nB, FALSE, FALSE,
5622 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
5625 Ygrass_eB, FALSE, FALSE,
5626 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
5629 Ygrass_sB, FALSE, FALSE,
5630 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
5633 Ygrass_wB, FALSE, FALSE,
5634 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
5641 Ydirt_nB, FALSE, FALSE,
5642 EL_SAND, ACTION_DIGGING, MV_BIT_UP
5645 Ydirt_eB, FALSE, FALSE,
5646 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
5649 Ydirt_sB, FALSE, FALSE,
5650 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
5653 Ydirt_wB, FALSE, FALSE,
5654 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
5657 Xacid_ne, TRUE, FALSE,
5658 EL_ACID_POOL_TOPRIGHT, -1, -1
5661 Xacid_se, TRUE, FALSE,
5662 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
5665 Xacid_s, TRUE, FALSE,
5666 EL_ACID_POOL_BOTTOM, -1, -1
5669 Xacid_sw, TRUE, FALSE,
5670 EL_ACID_POOL_BOTTOMLEFT, -1, -1
5673 Xacid_nw, TRUE, FALSE,
5674 EL_ACID_POOL_TOPLEFT, -1, -1
5677 Xacid_1, TRUE, FALSE,
5681 Xacid_2, FALSE, FALSE,
5685 Xacid_3, FALSE, FALSE,
5689 Xacid_4, FALSE, FALSE,
5693 Xacid_5, FALSE, FALSE,
5697 Xacid_6, FALSE, FALSE,
5701 Xacid_7, FALSE, FALSE,
5705 Xacid_8, FALSE, FALSE,
5709 Xball_1, TRUE, FALSE,
5710 EL_EMC_MAGIC_BALL, -1, -1
5713 Xball_1B, FALSE, FALSE,
5714 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5717 Xball_2, FALSE, FALSE,
5718 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5721 Xball_2B, FALSE, FALSE,
5722 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5725 Yball_eat, FALSE, FALSE,
5726 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
5729 Ykey_1_eat, FALSE, FALSE,
5730 EL_EM_KEY_1, ACTION_COLLECTING, -1
5733 Ykey_2_eat, FALSE, FALSE,
5734 EL_EM_KEY_2, ACTION_COLLECTING, -1
5737 Ykey_3_eat, FALSE, FALSE,
5738 EL_EM_KEY_3, ACTION_COLLECTING, -1
5741 Ykey_4_eat, FALSE, FALSE,
5742 EL_EM_KEY_4, ACTION_COLLECTING, -1
5745 Ykey_5_eat, FALSE, FALSE,
5746 EL_EMC_KEY_5, ACTION_COLLECTING, -1
5749 Ykey_6_eat, FALSE, FALSE,
5750 EL_EMC_KEY_6, ACTION_COLLECTING, -1
5753 Ykey_7_eat, FALSE, FALSE,
5754 EL_EMC_KEY_7, ACTION_COLLECTING, -1
5757 Ykey_8_eat, FALSE, FALSE,
5758 EL_EMC_KEY_8, ACTION_COLLECTING, -1
5761 Ylenses_eat, FALSE, FALSE,
5762 EL_EMC_LENSES, ACTION_COLLECTING, -1
5765 Ymagnify_eat, FALSE, FALSE,
5766 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
5769 Ygrass_eat, FALSE, FALSE,
5770 EL_EMC_GRASS, ACTION_SNAPPING, -1
5773 Ydirt_eat, FALSE, FALSE,
5774 EL_SAND, ACTION_SNAPPING, -1
5777 Xgrow_ns, TRUE, FALSE,
5778 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
5781 Ygrow_ns_eat, FALSE, FALSE,
5782 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
5785 Xgrow_ew, TRUE, FALSE,
5786 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
5789 Ygrow_ew_eat, FALSE, FALSE,
5790 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
5793 Xwonderwall, TRUE, FALSE,
5794 EL_MAGIC_WALL, -1, -1
5797 XwonderwallB, FALSE, FALSE,
5798 EL_MAGIC_WALL, ACTION_ACTIVE, -1
5801 Xamoeba_1, TRUE, FALSE,
5802 EL_AMOEBA_DRY, ACTION_OTHER, -1
5805 Xamoeba_2, FALSE, FALSE,
5806 EL_AMOEBA_DRY, ACTION_OTHER, -1
5809 Xamoeba_3, FALSE, FALSE,
5810 EL_AMOEBA_DRY, ACTION_OTHER, -1
5813 Xamoeba_4, FALSE, FALSE,
5814 EL_AMOEBA_DRY, ACTION_OTHER, -1
5817 Xamoeba_5, TRUE, FALSE,
5818 EL_AMOEBA_WET, ACTION_OTHER, -1
5821 Xamoeba_6, FALSE, FALSE,
5822 EL_AMOEBA_WET, ACTION_OTHER, -1
5825 Xamoeba_7, FALSE, FALSE,
5826 EL_AMOEBA_WET, ACTION_OTHER, -1
5829 Xamoeba_8, FALSE, FALSE,
5830 EL_AMOEBA_WET, ACTION_OTHER, -1
5833 Xdoor_1, TRUE, FALSE,
5834 EL_EM_GATE_1, -1, -1
5837 Xdoor_2, TRUE, FALSE,
5838 EL_EM_GATE_2, -1, -1
5841 Xdoor_3, TRUE, FALSE,
5842 EL_EM_GATE_3, -1, -1
5845 Xdoor_4, TRUE, FALSE,
5846 EL_EM_GATE_4, -1, -1
5849 Xdoor_5, TRUE, FALSE,
5850 EL_EMC_GATE_5, -1, -1
5853 Xdoor_6, TRUE, FALSE,
5854 EL_EMC_GATE_6, -1, -1
5857 Xdoor_7, TRUE, FALSE,
5858 EL_EMC_GATE_7, -1, -1
5861 Xdoor_8, TRUE, FALSE,
5862 EL_EMC_GATE_8, -1, -1
5865 Xkey_1, TRUE, FALSE,
5869 Xkey_2, TRUE, FALSE,
5873 Xkey_3, TRUE, FALSE,
5877 Xkey_4, TRUE, FALSE,
5881 Xkey_5, TRUE, FALSE,
5882 EL_EMC_KEY_5, -1, -1
5885 Xkey_6, TRUE, FALSE,
5886 EL_EMC_KEY_6, -1, -1
5889 Xkey_7, TRUE, FALSE,
5890 EL_EMC_KEY_7, -1, -1
5893 Xkey_8, TRUE, FALSE,
5894 EL_EMC_KEY_8, -1, -1
5897 Xwind_n, TRUE, FALSE,
5898 EL_BALLOON_SWITCH_UP, -1, -1
5901 Xwind_e, TRUE, FALSE,
5902 EL_BALLOON_SWITCH_RIGHT, -1, -1
5905 Xwind_s, TRUE, FALSE,
5906 EL_BALLOON_SWITCH_DOWN, -1, -1
5909 Xwind_w, TRUE, FALSE,
5910 EL_BALLOON_SWITCH_LEFT, -1, -1
5913 Xwind_nesw, TRUE, FALSE,
5914 EL_BALLOON_SWITCH_ANY, -1, -1
5917 Xwind_stop, TRUE, FALSE,
5918 EL_BALLOON_SWITCH_NONE, -1, -1
5922 EL_EM_EXIT_CLOSED, -1, -1
5925 Xexit_1, TRUE, FALSE,
5926 EL_EM_EXIT_OPEN, -1, -1
5929 Xexit_2, FALSE, FALSE,
5930 EL_EM_EXIT_OPEN, -1, -1
5933 Xexit_3, FALSE, FALSE,
5934 EL_EM_EXIT_OPEN, -1, -1
5937 Xdynamite, TRUE, FALSE,
5938 EL_EM_DYNAMITE, -1, -1
5941 Ydynamite_eat, FALSE, FALSE,
5942 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
5945 Xdynamite_1, TRUE, FALSE,
5946 EL_EM_DYNAMITE_ACTIVE, -1, -1
5949 Xdynamite_2, FALSE, FALSE,
5950 EL_EM_DYNAMITE_ACTIVE, -1, -1
5953 Xdynamite_3, FALSE, FALSE,
5954 EL_EM_DYNAMITE_ACTIVE, -1, -1
5957 Xdynamite_4, FALSE, FALSE,
5958 EL_EM_DYNAMITE_ACTIVE, -1, -1
5961 Xbumper, TRUE, FALSE,
5962 EL_EMC_SPRING_BUMPER, -1, -1
5965 XbumperB, FALSE, FALSE,
5966 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
5969 Xwheel, TRUE, FALSE,
5970 EL_ROBOT_WHEEL, -1, -1
5973 XwheelB, FALSE, FALSE,
5974 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
5977 Xswitch, TRUE, FALSE,
5978 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
5981 XswitchB, FALSE, FALSE,
5982 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
5986 EL_QUICKSAND_EMPTY, -1, -1
5989 Xsand_stone, TRUE, FALSE,
5990 EL_QUICKSAND_FULL, -1, -1
5993 Xsand_stonein_1, FALSE, TRUE,
5994 EL_ROCK, ACTION_FILLING, -1
5997 Xsand_stonein_2, FALSE, TRUE,
5998 EL_ROCK, ACTION_FILLING, -1
6001 Xsand_stonein_3, FALSE, TRUE,
6002 EL_ROCK, ACTION_FILLING, -1
6005 Xsand_stonein_4, FALSE, TRUE,
6006 EL_ROCK, ACTION_FILLING, -1
6009 Xsand_stonesand_1, FALSE, FALSE,
6010 EL_QUICKSAND_EMPTYING, -1, -1
6013 Xsand_stonesand_2, FALSE, FALSE,
6014 EL_QUICKSAND_EMPTYING, -1, -1
6017 Xsand_stonesand_3, FALSE, FALSE,
6018 EL_QUICKSAND_EMPTYING, -1, -1
6021 Xsand_stonesand_4, FALSE, FALSE,
6022 EL_QUICKSAND_EMPTYING, -1, -1
6025 Xsand_stonesand_quickout_1, FALSE, FALSE,
6026 EL_QUICKSAND_EMPTYING, -1, -1
6029 Xsand_stonesand_quickout_2, FALSE, FALSE,
6030 EL_QUICKSAND_EMPTYING, -1, -1
6033 Xsand_stoneout_1, FALSE, FALSE,
6034 EL_ROCK, ACTION_EMPTYING, -1
6037 Xsand_stoneout_2, FALSE, FALSE,
6038 EL_ROCK, ACTION_EMPTYING, -1
6041 Xsand_sandstone_1, FALSE, FALSE,
6042 EL_QUICKSAND_FILLING, -1, -1
6045 Xsand_sandstone_2, FALSE, FALSE,
6046 EL_QUICKSAND_FILLING, -1, -1
6049 Xsand_sandstone_3, FALSE, FALSE,
6050 EL_QUICKSAND_FILLING, -1, -1
6053 Xsand_sandstone_4, FALSE, FALSE,
6054 EL_QUICKSAND_FILLING, -1, -1
6057 Xplant, TRUE, FALSE,
6058 EL_EMC_PLANT, -1, -1
6061 Yplant, FALSE, FALSE,
6062 EL_EMC_PLANT, -1, -1
6065 Xlenses, TRUE, FALSE,
6066 EL_EMC_LENSES, -1, -1
6069 Xmagnify, TRUE, FALSE,
6070 EL_EMC_MAGNIFIER, -1, -1
6073 Xdripper, TRUE, FALSE,
6074 EL_EMC_DRIPPER, -1, -1
6077 XdripperB, FALSE, FALSE,
6078 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
6081 Xfake_blank, TRUE, FALSE,
6082 EL_INVISIBLE_WALL, -1, -1
6085 Xfake_blankB, FALSE, FALSE,
6086 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
6089 Xfake_grass, TRUE, FALSE,
6090 EL_EMC_FAKE_GRASS, -1, -1
6093 Xfake_grassB, FALSE, FALSE,
6094 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
6097 Xfake_door_1, TRUE, FALSE,
6098 EL_EM_GATE_1_GRAY, -1, -1
6101 Xfake_door_2, TRUE, FALSE,
6102 EL_EM_GATE_2_GRAY, -1, -1
6105 Xfake_door_3, TRUE, FALSE,
6106 EL_EM_GATE_3_GRAY, -1, -1
6109 Xfake_door_4, TRUE, FALSE,
6110 EL_EM_GATE_4_GRAY, -1, -1
6113 Xfake_door_5, TRUE, FALSE,
6114 EL_EMC_GATE_5_GRAY, -1, -1
6117 Xfake_door_6, TRUE, FALSE,
6118 EL_EMC_GATE_6_GRAY, -1, -1
6121 Xfake_door_7, TRUE, FALSE,
6122 EL_EMC_GATE_7_GRAY, -1, -1
6125 Xfake_door_8, TRUE, FALSE,
6126 EL_EMC_GATE_8_GRAY, -1, -1
6129 Xfake_acid_1, TRUE, FALSE,
6130 EL_EMC_FAKE_ACID, -1, -1
6133 Xfake_acid_2, FALSE, FALSE,
6134 EL_EMC_FAKE_ACID, -1, -1
6137 Xfake_acid_3, FALSE, FALSE,
6138 EL_EMC_FAKE_ACID, -1, -1
6141 Xfake_acid_4, FALSE, FALSE,
6142 EL_EMC_FAKE_ACID, -1, -1
6145 Xfake_acid_5, FALSE, FALSE,
6146 EL_EMC_FAKE_ACID, -1, -1
6149 Xfake_acid_6, FALSE, FALSE,
6150 EL_EMC_FAKE_ACID, -1, -1
6153 Xfake_acid_7, FALSE, FALSE,
6154 EL_EMC_FAKE_ACID, -1, -1
6157 Xfake_acid_8, FALSE, FALSE,
6158 EL_EMC_FAKE_ACID, -1, -1
6161 Xsteel_1, TRUE, FALSE,
6162 EL_STEELWALL, -1, -1
6165 Xsteel_2, TRUE, FALSE,
6166 EL_EMC_STEELWALL_2, -1, -1
6169 Xsteel_3, TRUE, FALSE,
6170 EL_EMC_STEELWALL_3, -1, -1
6173 Xsteel_4, TRUE, FALSE,
6174 EL_EMC_STEELWALL_4, -1, -1
6177 Xwall_1, TRUE, FALSE,
6181 Xwall_2, TRUE, FALSE,
6182 EL_EMC_WALL_14, -1, -1
6185 Xwall_3, TRUE, FALSE,
6186 EL_EMC_WALL_15, -1, -1
6189 Xwall_4, TRUE, FALSE,
6190 EL_EMC_WALL_16, -1, -1
6193 Xround_wall_1, TRUE, FALSE,
6194 EL_WALL_SLIPPERY, -1, -1
6197 Xround_wall_2, TRUE, FALSE,
6198 EL_EMC_WALL_SLIPPERY_2, -1, -1
6201 Xround_wall_3, TRUE, FALSE,
6202 EL_EMC_WALL_SLIPPERY_3, -1, -1
6205 Xround_wall_4, TRUE, FALSE,
6206 EL_EMC_WALL_SLIPPERY_4, -1, -1
6209 Xdecor_1, TRUE, FALSE,
6210 EL_EMC_WALL_8, -1, -1
6213 Xdecor_2, TRUE, FALSE,
6214 EL_EMC_WALL_6, -1, -1
6217 Xdecor_3, TRUE, FALSE,
6218 EL_EMC_WALL_4, -1, -1
6221 Xdecor_4, TRUE, FALSE,
6222 EL_EMC_WALL_7, -1, -1
6225 Xdecor_5, TRUE, FALSE,
6226 EL_EMC_WALL_5, -1, -1
6229 Xdecor_6, TRUE, FALSE,
6230 EL_EMC_WALL_9, -1, -1
6233 Xdecor_7, TRUE, FALSE,
6234 EL_EMC_WALL_10, -1, -1
6237 Xdecor_8, TRUE, FALSE,
6238 EL_EMC_WALL_1, -1, -1
6241 Xdecor_9, TRUE, FALSE,
6242 EL_EMC_WALL_2, -1, -1
6245 Xdecor_10, TRUE, FALSE,
6246 EL_EMC_WALL_3, -1, -1
6249 Xdecor_11, TRUE, FALSE,
6250 EL_EMC_WALL_11, -1, -1
6253 Xdecor_12, TRUE, FALSE,
6254 EL_EMC_WALL_12, -1, -1
6257 Xalpha_0, TRUE, FALSE,
6258 EL_CHAR('0'), -1, -1
6261 Xalpha_1, TRUE, FALSE,
6262 EL_CHAR('1'), -1, -1
6265 Xalpha_2, TRUE, FALSE,
6266 EL_CHAR('2'), -1, -1
6269 Xalpha_3, TRUE, FALSE,
6270 EL_CHAR('3'), -1, -1
6273 Xalpha_4, TRUE, FALSE,
6274 EL_CHAR('4'), -1, -1
6277 Xalpha_5, TRUE, FALSE,
6278 EL_CHAR('5'), -1, -1
6281 Xalpha_6, TRUE, FALSE,
6282 EL_CHAR('6'), -1, -1
6285 Xalpha_7, TRUE, FALSE,
6286 EL_CHAR('7'), -1, -1
6289 Xalpha_8, TRUE, FALSE,
6290 EL_CHAR('8'), -1, -1
6293 Xalpha_9, TRUE, FALSE,
6294 EL_CHAR('9'), -1, -1
6297 Xalpha_excla, TRUE, FALSE,
6298 EL_CHAR('!'), -1, -1
6301 Xalpha_quote, TRUE, FALSE,
6302 EL_CHAR('"'), -1, -1
6305 Xalpha_comma, TRUE, FALSE,
6306 EL_CHAR(','), -1, -1
6309 Xalpha_minus, TRUE, FALSE,
6310 EL_CHAR('-'), -1, -1
6313 Xalpha_perio, TRUE, FALSE,
6314 EL_CHAR('.'), -1, -1
6317 Xalpha_colon, TRUE, FALSE,
6318 EL_CHAR(':'), -1, -1
6321 Xalpha_quest, TRUE, FALSE,
6322 EL_CHAR('?'), -1, -1
6325 Xalpha_a, TRUE, FALSE,
6326 EL_CHAR('A'), -1, -1
6329 Xalpha_b, TRUE, FALSE,
6330 EL_CHAR('B'), -1, -1
6333 Xalpha_c, TRUE, FALSE,
6334 EL_CHAR('C'), -1, -1
6337 Xalpha_d, TRUE, FALSE,
6338 EL_CHAR('D'), -1, -1
6341 Xalpha_e, TRUE, FALSE,
6342 EL_CHAR('E'), -1, -1
6345 Xalpha_f, TRUE, FALSE,
6346 EL_CHAR('F'), -1, -1
6349 Xalpha_g, TRUE, FALSE,
6350 EL_CHAR('G'), -1, -1
6353 Xalpha_h, TRUE, FALSE,
6354 EL_CHAR('H'), -1, -1
6357 Xalpha_i, TRUE, FALSE,
6358 EL_CHAR('I'), -1, -1
6361 Xalpha_j, TRUE, FALSE,
6362 EL_CHAR('J'), -1, -1
6365 Xalpha_k, TRUE, FALSE,
6366 EL_CHAR('K'), -1, -1
6369 Xalpha_l, TRUE, FALSE,
6370 EL_CHAR('L'), -1, -1
6373 Xalpha_m, TRUE, FALSE,
6374 EL_CHAR('M'), -1, -1
6377 Xalpha_n, TRUE, FALSE,
6378 EL_CHAR('N'), -1, -1
6381 Xalpha_o, TRUE, FALSE,
6382 EL_CHAR('O'), -1, -1
6385 Xalpha_p, TRUE, FALSE,
6386 EL_CHAR('P'), -1, -1
6389 Xalpha_q, TRUE, FALSE,
6390 EL_CHAR('Q'), -1, -1
6393 Xalpha_r, TRUE, FALSE,
6394 EL_CHAR('R'), -1, -1
6397 Xalpha_s, TRUE, FALSE,
6398 EL_CHAR('S'), -1, -1
6401 Xalpha_t, TRUE, FALSE,
6402 EL_CHAR('T'), -1, -1
6405 Xalpha_u, TRUE, FALSE,
6406 EL_CHAR('U'), -1, -1
6409 Xalpha_v, TRUE, FALSE,
6410 EL_CHAR('V'), -1, -1
6413 Xalpha_w, TRUE, FALSE,
6414 EL_CHAR('W'), -1, -1
6417 Xalpha_x, TRUE, FALSE,
6418 EL_CHAR('X'), -1, -1
6421 Xalpha_y, TRUE, FALSE,
6422 EL_CHAR('Y'), -1, -1
6425 Xalpha_z, TRUE, FALSE,
6426 EL_CHAR('Z'), -1, -1
6429 Xalpha_arrow_e, TRUE, FALSE,
6430 EL_CHAR('>'), -1, -1
6433 Xalpha_arrow_w, TRUE, FALSE,
6434 EL_CHAR('<'), -1, -1
6437 Xalpha_copyr, TRUE, FALSE,
6438 EL_CHAR(CHAR_BYTE_COPYRIGHT), -1, -1
6442 Xboom_bug, FALSE, FALSE,
6443 EL_BUG, ACTION_EXPLODING, -1
6446 Xboom_bomb, FALSE, FALSE,
6447 EL_BOMB, ACTION_EXPLODING, -1
6450 Xboom_android, FALSE, FALSE,
6451 EL_EMC_ANDROID, ACTION_OTHER, -1
6454 Xboom_1, FALSE, FALSE,
6455 EL_DEFAULT, ACTION_EXPLODING, -1
6458 Xboom_2, FALSE, FALSE,
6459 EL_DEFAULT, ACTION_EXPLODING, -1
6462 Znormal, FALSE, FALSE,
6466 Zdynamite, FALSE, FALSE,
6470 Zplayer, FALSE, FALSE,
6474 ZBORDER, FALSE, FALSE,
6484 static struct Mapping_EM_to_RND_player
6493 em_player_mapping_list[] =
6497 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
6501 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
6505 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
6509 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
6513 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
6517 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
6521 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
6525 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
6529 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
6533 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
6537 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
6541 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
6545 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
6549 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
6553 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
6557 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
6561 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
6565 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
6569 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
6573 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
6577 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
6581 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
6585 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
6589 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
6593 EL_PLAYER_1, ACTION_DEFAULT, -1,
6597 EL_PLAYER_2, ACTION_DEFAULT, -1,
6601 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
6605 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
6609 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
6613 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
6617 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
6621 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
6625 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
6629 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
6633 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
6637 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
6641 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
6645 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
6649 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
6653 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
6657 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
6661 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
6665 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
6669 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
6673 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
6677 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
6681 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
6685 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
6689 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
6693 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
6697 EL_PLAYER_3, ACTION_DEFAULT, -1,
6701 EL_PLAYER_4, ACTION_DEFAULT, -1,
6710 int map_element_RND_to_EM(int element_rnd)
6712 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
6713 static boolean mapping_initialized = FALSE;
6715 if (!mapping_initialized)
6719 /* return "Xalpha_quest" for all undefined elements in mapping array */
6720 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
6721 mapping_RND_to_EM[i] = Xalpha_quest;
6723 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6724 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
6725 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
6726 em_object_mapping_list[i].element_em;
6728 mapping_initialized = TRUE;
6731 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
6732 return mapping_RND_to_EM[element_rnd];
6734 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
6739 int map_element_EM_to_RND(int element_em)
6741 static unsigned short mapping_EM_to_RND[TILE_MAX];
6742 static boolean mapping_initialized = FALSE;
6744 if (!mapping_initialized)
6748 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
6749 for (i = 0; i < TILE_MAX; i++)
6750 mapping_EM_to_RND[i] = EL_UNKNOWN;
6752 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6753 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
6754 em_object_mapping_list[i].element_rnd;
6756 mapping_initialized = TRUE;
6759 if (element_em >= 0 && element_em < TILE_MAX)
6760 return mapping_EM_to_RND[element_em];
6762 Error(ERR_WARN, "invalid EM level element %d", element_em);
6767 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
6769 struct LevelInfo_EM *level_em = level->native_em_level;
6770 struct LEVEL *lev = level_em->lev;
6773 for (i = 0; i < TILE_MAX; i++)
6774 lev->android_array[i] = Xblank;
6776 for (i = 0; i < level->num_android_clone_elements; i++)
6778 int element_rnd = level->android_clone_element[i];
6779 int element_em = map_element_RND_to_EM(element_rnd);
6781 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
6782 if (em_object_mapping_list[j].element_rnd == element_rnd)
6783 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
6787 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
6789 struct LevelInfo_EM *level_em = level->native_em_level;
6790 struct LEVEL *lev = level_em->lev;
6793 level->num_android_clone_elements = 0;
6795 for (i = 0; i < TILE_MAX; i++)
6797 int element_em = lev->android_array[i];
6799 boolean element_found = FALSE;
6801 if (element_em == Xblank)
6804 element_rnd = map_element_EM_to_RND(element_em);
6806 for (j = 0; j < level->num_android_clone_elements; j++)
6807 if (level->android_clone_element[j] == element_rnd)
6808 element_found = TRUE;
6812 level->android_clone_element[level->num_android_clone_elements++] =
6815 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
6820 if (level->num_android_clone_elements == 0)
6822 level->num_android_clone_elements = 1;
6823 level->android_clone_element[0] = EL_EMPTY;
6827 int map_direction_RND_to_EM(int direction)
6829 return (direction == MV_UP ? 0 :
6830 direction == MV_RIGHT ? 1 :
6831 direction == MV_DOWN ? 2 :
6832 direction == MV_LEFT ? 3 :
6836 int map_direction_EM_to_RND(int direction)
6838 return (direction == 0 ? MV_UP :
6839 direction == 1 ? MV_RIGHT :
6840 direction == 2 ? MV_DOWN :
6841 direction == 3 ? MV_LEFT :
6845 int map_element_RND_to_SP(int element_rnd)
6847 int element_sp = 0x20; /* map unknown elements to yellow "hardware" */
6849 if (element_rnd >= EL_SP_START &&
6850 element_rnd <= EL_SP_END)
6851 element_sp = element_rnd - EL_SP_START;
6852 else if (element_rnd == EL_EMPTY_SPACE)
6854 else if (element_rnd == EL_INVISIBLE_WALL)
6860 int map_element_SP_to_RND(int element_sp)
6862 int element_rnd = EL_UNKNOWN;
6864 if (element_sp >= 0x00 &&
6866 element_rnd = EL_SP_START + element_sp;
6867 else if (element_sp == 0x28)
6868 element_rnd = EL_INVISIBLE_WALL;
6873 int map_action_SP_to_RND(int action_sp)
6877 case actActive: return ACTION_ACTIVE;
6878 case actImpact: return ACTION_IMPACT;
6879 case actExploding: return ACTION_EXPLODING;
6880 case actDigging: return ACTION_DIGGING;
6881 case actSnapping: return ACTION_SNAPPING;
6882 case actCollecting: return ACTION_COLLECTING;
6883 case actPassing: return ACTION_PASSING;
6884 case actPushing: return ACTION_PUSHING;
6885 case actDropping: return ACTION_DROPPING;
6887 default: return ACTION_DEFAULT;
6891 int get_next_element(int element)
6895 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
6896 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
6897 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
6898 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
6899 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
6900 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
6901 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
6902 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
6903 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
6904 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
6905 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
6907 default: return element;
6911 int el_act_dir2img(int element, int action, int direction)
6913 element = GFX_ELEMENT(element);
6914 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
6916 /* direction_graphic[][] == graphic[] for undefined direction graphics */
6917 return element_info[element].direction_graphic[action][direction];
6920 static int el_act_dir2crm(int element, int action, int direction)
6922 element = GFX_ELEMENT(element);
6923 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
6925 /* direction_graphic[][] == graphic[] for undefined direction graphics */
6926 return element_info[element].direction_crumbled[action][direction];
6929 int el_act2img(int element, int action)
6931 element = GFX_ELEMENT(element);
6933 return element_info[element].graphic[action];
6936 int el_act2crm(int element, int action)
6938 element = GFX_ELEMENT(element);
6940 return element_info[element].crumbled[action];
6943 int el_dir2img(int element, int direction)
6945 element = GFX_ELEMENT(element);
6947 return el_act_dir2img(element, ACTION_DEFAULT, direction);
6950 int el2baseimg(int element)
6952 return element_info[element].graphic[ACTION_DEFAULT];
6955 int el2img(int element)
6957 element = GFX_ELEMENT(element);
6959 return element_info[element].graphic[ACTION_DEFAULT];
6962 int el2edimg(int element)
6964 element = GFX_ELEMENT(element);
6966 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
6969 int el2preimg(int element)
6971 element = GFX_ELEMENT(element);
6973 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
6976 int el2panelimg(int element)
6978 element = GFX_ELEMENT(element);
6980 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL];
6983 int font2baseimg(int font_nr)
6985 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
6988 int getBeltNrFromBeltElement(int element)
6990 return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
6991 element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
6992 element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
6995 int getBeltNrFromBeltActiveElement(int element)
6997 return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
6998 element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
6999 element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
7002 int getBeltNrFromBeltSwitchElement(int element)
7004 return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
7005 element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
7006 element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
7009 int getBeltDirNrFromBeltElement(int element)
7011 static int belt_base_element[4] =
7013 EL_CONVEYOR_BELT_1_LEFT,
7014 EL_CONVEYOR_BELT_2_LEFT,
7015 EL_CONVEYOR_BELT_3_LEFT,
7016 EL_CONVEYOR_BELT_4_LEFT
7019 int belt_nr = getBeltNrFromBeltElement(element);
7020 int belt_dir_nr = element - belt_base_element[belt_nr];
7022 return (belt_dir_nr % 3);
7025 int getBeltDirNrFromBeltSwitchElement(int element)
7027 static int belt_base_element[4] =
7029 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
7030 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
7031 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
7032 EL_CONVEYOR_BELT_4_SWITCH_LEFT
7035 int belt_nr = getBeltNrFromBeltSwitchElement(element);
7036 int belt_dir_nr = element - belt_base_element[belt_nr];
7038 return (belt_dir_nr % 3);
7041 int getBeltDirFromBeltElement(int element)
7043 static int belt_move_dir[3] =
7050 int belt_dir_nr = getBeltDirNrFromBeltElement(element);
7052 return belt_move_dir[belt_dir_nr];
7055 int getBeltDirFromBeltSwitchElement(int element)
7057 static int belt_move_dir[3] =
7064 int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
7066 return belt_move_dir[belt_dir_nr];
7069 int getBeltElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
7071 static int belt_base_element[4] =
7073 EL_CONVEYOR_BELT_1_LEFT,
7074 EL_CONVEYOR_BELT_2_LEFT,
7075 EL_CONVEYOR_BELT_3_LEFT,
7076 EL_CONVEYOR_BELT_4_LEFT
7079 return belt_base_element[belt_nr] + belt_dir_nr;
7082 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
7084 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
7086 return getBeltElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
7089 int getBeltSwitchElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
7091 static int belt_base_element[4] =
7093 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
7094 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
7095 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
7096 EL_CONVEYOR_BELT_4_SWITCH_LEFT
7099 return belt_base_element[belt_nr] + belt_dir_nr;
7102 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
7104 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
7106 return getBeltSwitchElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
7109 boolean getTeamMode_EM()
7111 return game.team_mode;
7114 int getGameFrameDelay_EM(int native_em_game_frame_delay)
7116 int game_frame_delay_value;
7118 game_frame_delay_value =
7119 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
7120 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
7123 if (tape.playing && tape.warp_forward && !tape.pausing)
7124 game_frame_delay_value = 0;
7126 return game_frame_delay_value;
7129 unsigned int InitRND(int seed)
7131 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
7132 return InitEngineRandom_EM(seed);
7133 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
7134 return InitEngineRandom_SP(seed);
7136 return InitEngineRandom_RND(seed);
7139 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
7140 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
7142 inline static int get_effective_element_EM(int tile, int frame_em)
7144 int element = object_mapping[tile].element_rnd;
7145 int action = object_mapping[tile].action;
7146 boolean is_backside = object_mapping[tile].is_backside;
7147 boolean action_removing = (action == ACTION_DIGGING ||
7148 action == ACTION_SNAPPING ||
7149 action == ACTION_COLLECTING);
7155 case Yacid_splash_eB:
7156 case Yacid_splash_wB:
7157 return (frame_em > 5 ? EL_EMPTY : element);
7163 else /* frame_em == 7 */
7167 case Yacid_splash_eB:
7168 case Yacid_splash_wB:
7171 case Yemerald_stone:
7174 case Ydiamond_stone:
7178 case Xdrip_stretchB:
7197 case Xsand_stonein_1:
7198 case Xsand_stonein_2:
7199 case Xsand_stonein_3:
7200 case Xsand_stonein_4:
7204 return (is_backside || action_removing ? EL_EMPTY : element);
7209 inline static boolean check_linear_animation_EM(int tile)
7213 case Xsand_stonesand_1:
7214 case Xsand_stonesand_quickout_1:
7215 case Xsand_sandstone_1:
7216 case Xsand_stonein_1:
7217 case Xsand_stoneout_1:
7236 case Yacid_splash_eB:
7237 case Yacid_splash_wB:
7238 case Yemerald_stone:
7245 inline static void set_crumbled_graphics_EM(struct GraphicInfo_EM *g_em,
7246 boolean has_crumbled_graphics,
7247 int crumbled, int sync_frame)
7249 /* if element can be crumbled, but certain action graphics are just empty
7250 space (like instantly snapping sand to empty space in 1 frame), do not
7251 treat these empty space graphics as crumbled graphics in EMC engine */
7252 if (crumbled == IMG_EMPTY_SPACE)
7253 has_crumbled_graphics = FALSE;
7255 if (has_crumbled_graphics)
7257 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
7258 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
7259 g_crumbled->anim_delay,
7260 g_crumbled->anim_mode,
7261 g_crumbled->anim_start_frame,
7264 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
7265 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
7267 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
7269 g_em->has_crumbled_graphics = TRUE;
7273 g_em->crumbled_bitmap = NULL;
7274 g_em->crumbled_src_x = 0;
7275 g_em->crumbled_src_y = 0;
7276 g_em->crumbled_border_size = 0;
7278 g_em->has_crumbled_graphics = FALSE;
7282 void ResetGfxAnimation_EM(int x, int y, int tile)
7287 void SetGfxAnimation_EM(struct GraphicInfo_EM *g_em,
7288 int tile, int frame_em, int x, int y)
7290 int action = object_mapping[tile].action;
7291 int direction = object_mapping[tile].direction;
7292 int effective_element = get_effective_element_EM(tile, frame_em);
7293 int graphic = (direction == MV_NONE ?
7294 el_act2img(effective_element, action) :
7295 el_act_dir2img(effective_element, action, direction));
7296 struct GraphicInfo *g = &graphic_info[graphic];
7298 boolean action_removing = (action == ACTION_DIGGING ||
7299 action == ACTION_SNAPPING ||
7300 action == ACTION_COLLECTING);
7301 boolean action_moving = (action == ACTION_FALLING ||
7302 action == ACTION_MOVING ||
7303 action == ACTION_PUSHING ||
7304 action == ACTION_EATING ||
7305 action == ACTION_FILLING ||
7306 action == ACTION_EMPTYING);
7307 boolean action_falling = (action == ACTION_FALLING ||
7308 action == ACTION_FILLING ||
7309 action == ACTION_EMPTYING);
7311 /* special case: graphic uses "2nd movement tile" and has defined
7312 7 frames for movement animation (or less) => use default graphic
7313 for last (8th) frame which ends the movement animation */
7314 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
7316 action = ACTION_DEFAULT; /* (keep action_* unchanged for now) */
7317 graphic = (direction == MV_NONE ?
7318 el_act2img(effective_element, action) :
7319 el_act_dir2img(effective_element, action, direction));
7321 g = &graphic_info[graphic];
7324 if ((action_removing || check_linear_animation_EM(tile)) && frame_em == 0)
7328 else if (action_moving)
7330 boolean is_backside = object_mapping[tile].is_backside;
7334 int direction = object_mapping[tile].direction;
7335 int move_dir = (action_falling ? MV_DOWN : direction);
7340 /* !!! TEST !!! NEW !!! DOES NOT WORK RIGHT YET !!! */
7341 if (g->double_movement && frame_em == 0)
7345 if (move_dir == MV_LEFT)
7346 GfxFrame[x - 1][y] = GfxFrame[x][y];
7347 else if (move_dir == MV_RIGHT)
7348 GfxFrame[x + 1][y] = GfxFrame[x][y];
7349 else if (move_dir == MV_UP)
7350 GfxFrame[x][y - 1] = GfxFrame[x][y];
7351 else if (move_dir == MV_DOWN)
7352 GfxFrame[x][y + 1] = GfxFrame[x][y];
7359 /* special case: animation for Xsand_stonesand_quickout_1/2 twice as fast */
7360 if (tile == Xsand_stonesand_quickout_1 ||
7361 tile == Xsand_stonesand_quickout_2)
7365 if (graphic_info[graphic].anim_global_sync)
7366 sync_frame = FrameCounter;
7367 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
7368 sync_frame = GfxFrame[x][y];
7370 sync_frame = 0; /* playfield border (pseudo steel) */
7372 SetRandomAnimationValue(x, y);
7374 int frame = getAnimationFrame(g->anim_frames,
7377 g->anim_start_frame,
7380 g_em->unique_identifier =
7381 (graphic << 16) | ((frame % 8) << 12) | (g_em->width << 6) | g_em->height;
7384 void getGraphicSourceObjectExt_EM(struct GraphicInfo_EM *g_em,
7385 int tile, int frame_em, int x, int y)
7387 int action = object_mapping[tile].action;
7388 int direction = object_mapping[tile].direction;
7389 boolean is_backside = object_mapping[tile].is_backside;
7390 int effective_element = get_effective_element_EM(tile, frame_em);
7391 int effective_action = action;
7392 int graphic = (direction == MV_NONE ?
7393 el_act2img(effective_element, effective_action) :
7394 el_act_dir2img(effective_element, effective_action,
7396 int crumbled = (direction == MV_NONE ?
7397 el_act2crm(effective_element, effective_action) :
7398 el_act_dir2crm(effective_element, effective_action,
7400 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7401 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7402 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7403 struct GraphicInfo *g = &graphic_info[graphic];
7406 /* special case: graphic uses "2nd movement tile" and has defined
7407 7 frames for movement animation (or less) => use default graphic
7408 for last (8th) frame which ends the movement animation */
7409 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
7411 effective_action = ACTION_DEFAULT;
7412 graphic = (direction == MV_NONE ?
7413 el_act2img(effective_element, effective_action) :
7414 el_act_dir2img(effective_element, effective_action,
7416 crumbled = (direction == MV_NONE ?
7417 el_act2crm(effective_element, effective_action) :
7418 el_act_dir2crm(effective_element, effective_action,
7421 g = &graphic_info[graphic];
7424 if (graphic_info[graphic].anim_global_sync)
7425 sync_frame = FrameCounter;
7426 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
7427 sync_frame = GfxFrame[x][y];
7429 sync_frame = 0; /* playfield border (pseudo steel) */
7431 SetRandomAnimationValue(x, y);
7433 int frame = getAnimationFrame(g->anim_frames,
7436 g->anim_start_frame,
7439 getGraphicSourceExt(graphic, frame, &g_em->bitmap, &g_em->src_x, &g_em->src_y,
7440 g->double_movement && is_backside);
7442 /* (updating the "crumbled" graphic definitions is probably not really needed,
7443 as animations for crumbled graphics can't be longer than one EMC cycle) */
7444 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
7448 void getGraphicSourcePlayerExt_EM(struct GraphicInfo_EM *g_em,
7449 int player_nr, int anim, int frame_em)
7451 int element = player_mapping[player_nr][anim].element_rnd;
7452 int action = player_mapping[player_nr][anim].action;
7453 int direction = player_mapping[player_nr][anim].direction;
7454 int graphic = (direction == MV_NONE ?
7455 el_act2img(element, action) :
7456 el_act_dir2img(element, action, direction));
7457 struct GraphicInfo *g = &graphic_info[graphic];
7460 InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
7462 stored_player[player_nr].StepFrame = frame_em;
7464 sync_frame = stored_player[player_nr].Frame;
7466 int frame = getAnimationFrame(g->anim_frames,
7469 g->anim_start_frame,
7472 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
7473 &g_em->src_x, &g_em->src_y, FALSE);
7476 void InitGraphicInfo_EM(void)
7481 int num_em_gfx_errors = 0;
7483 if (graphic_info_em_object[0][0].bitmap == NULL)
7485 /* EM graphics not yet initialized in em_open_all() */
7490 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
7493 /* always start with reliable default values */
7494 for (i = 0; i < TILE_MAX; i++)
7496 object_mapping[i].element_rnd = EL_UNKNOWN;
7497 object_mapping[i].is_backside = FALSE;
7498 object_mapping[i].action = ACTION_DEFAULT;
7499 object_mapping[i].direction = MV_NONE;
7502 /* always start with reliable default values */
7503 for (p = 0; p < MAX_PLAYERS; p++)
7505 for (i = 0; i < SPR_MAX; i++)
7507 player_mapping[p][i].element_rnd = EL_UNKNOWN;
7508 player_mapping[p][i].action = ACTION_DEFAULT;
7509 player_mapping[p][i].direction = MV_NONE;
7513 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
7515 int e = em_object_mapping_list[i].element_em;
7517 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
7518 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
7520 if (em_object_mapping_list[i].action != -1)
7521 object_mapping[e].action = em_object_mapping_list[i].action;
7523 if (em_object_mapping_list[i].direction != -1)
7524 object_mapping[e].direction =
7525 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
7528 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
7530 int a = em_player_mapping_list[i].action_em;
7531 int p = em_player_mapping_list[i].player_nr;
7533 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
7535 if (em_player_mapping_list[i].action != -1)
7536 player_mapping[p][a].action = em_player_mapping_list[i].action;
7538 if (em_player_mapping_list[i].direction != -1)
7539 player_mapping[p][a].direction =
7540 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
7543 for (i = 0; i < TILE_MAX; i++)
7545 int element = object_mapping[i].element_rnd;
7546 int action = object_mapping[i].action;
7547 int direction = object_mapping[i].direction;
7548 boolean is_backside = object_mapping[i].is_backside;
7549 boolean action_exploding = ((action == ACTION_EXPLODING ||
7550 action == ACTION_SMASHED_BY_ROCK ||
7551 action == ACTION_SMASHED_BY_SPRING) &&
7552 element != EL_DIAMOND);
7553 boolean action_active = (action == ACTION_ACTIVE);
7554 boolean action_other = (action == ACTION_OTHER);
7556 for (j = 0; j < 8; j++)
7558 int effective_element = get_effective_element_EM(i, j);
7559 int effective_action = (j < 7 ? action :
7560 i == Xdrip_stretch ? action :
7561 i == Xdrip_stretchB ? action :
7562 i == Ydrip_s1 ? action :
7563 i == Ydrip_s1B ? action :
7564 i == Xball_1B ? action :
7565 i == Xball_2 ? action :
7566 i == Xball_2B ? action :
7567 i == Yball_eat ? action :
7568 i == Ykey_1_eat ? action :
7569 i == Ykey_2_eat ? action :
7570 i == Ykey_3_eat ? action :
7571 i == Ykey_4_eat ? action :
7572 i == Ykey_5_eat ? action :
7573 i == Ykey_6_eat ? action :
7574 i == Ykey_7_eat ? action :
7575 i == Ykey_8_eat ? action :
7576 i == Ylenses_eat ? action :
7577 i == Ymagnify_eat ? action :
7578 i == Ygrass_eat ? action :
7579 i == Ydirt_eat ? action :
7580 i == Xsand_stonein_1 ? action :
7581 i == Xsand_stonein_2 ? action :
7582 i == Xsand_stonein_3 ? action :
7583 i == Xsand_stonein_4 ? action :
7584 i == Xsand_stoneout_1 ? action :
7585 i == Xsand_stoneout_2 ? action :
7586 i == Xboom_android ? ACTION_EXPLODING :
7587 action_exploding ? ACTION_EXPLODING :
7588 action_active ? action :
7589 action_other ? action :
7591 int graphic = (el_act_dir2img(effective_element, effective_action,
7593 int crumbled = (el_act_dir2crm(effective_element, effective_action,
7595 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7596 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7597 boolean has_action_graphics = (graphic != base_graphic);
7598 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7599 struct GraphicInfo *g = &graphic_info[graphic];
7600 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7603 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
7604 boolean special_animation = (action != ACTION_DEFAULT &&
7605 g->anim_frames == 3 &&
7606 g->anim_delay == 2 &&
7607 g->anim_mode & ANIM_LINEAR);
7608 int sync_frame = (i == Xdrip_stretch ? 7 :
7609 i == Xdrip_stretchB ? 7 :
7610 i == Ydrip_s2 ? j + 8 :
7611 i == Ydrip_s2B ? j + 8 :
7620 i == Xfake_acid_1 ? 0 :
7621 i == Xfake_acid_2 ? 10 :
7622 i == Xfake_acid_3 ? 20 :
7623 i == Xfake_acid_4 ? 30 :
7624 i == Xfake_acid_5 ? 40 :
7625 i == Xfake_acid_6 ? 50 :
7626 i == Xfake_acid_7 ? 60 :
7627 i == Xfake_acid_8 ? 70 :
7629 i == Xball_2B ? j + 8 :
7630 i == Yball_eat ? j + 1 :
7631 i == Ykey_1_eat ? j + 1 :
7632 i == Ykey_2_eat ? j + 1 :
7633 i == Ykey_3_eat ? j + 1 :
7634 i == Ykey_4_eat ? j + 1 :
7635 i == Ykey_5_eat ? j + 1 :
7636 i == Ykey_6_eat ? j + 1 :
7637 i == Ykey_7_eat ? j + 1 :
7638 i == Ykey_8_eat ? j + 1 :
7639 i == Ylenses_eat ? j + 1 :
7640 i == Ymagnify_eat ? j + 1 :
7641 i == Ygrass_eat ? j + 1 :
7642 i == Ydirt_eat ? j + 1 :
7643 i == Xamoeba_1 ? 0 :
7644 i == Xamoeba_2 ? 1 :
7645 i == Xamoeba_3 ? 2 :
7646 i == Xamoeba_4 ? 3 :
7647 i == Xamoeba_5 ? 0 :
7648 i == Xamoeba_6 ? 1 :
7649 i == Xamoeba_7 ? 2 :
7650 i == Xamoeba_8 ? 3 :
7651 i == Xexit_2 ? j + 8 :
7652 i == Xexit_3 ? j + 16 :
7653 i == Xdynamite_1 ? 0 :
7654 i == Xdynamite_2 ? 8 :
7655 i == Xdynamite_3 ? 16 :
7656 i == Xdynamite_4 ? 24 :
7657 i == Xsand_stonein_1 ? j + 1 :
7658 i == Xsand_stonein_2 ? j + 9 :
7659 i == Xsand_stonein_3 ? j + 17 :
7660 i == Xsand_stonein_4 ? j + 25 :
7661 i == Xsand_stoneout_1 && j == 0 ? 0 :
7662 i == Xsand_stoneout_1 && j == 1 ? 0 :
7663 i == Xsand_stoneout_1 && j == 2 ? 1 :
7664 i == Xsand_stoneout_1 && j == 3 ? 2 :
7665 i == Xsand_stoneout_1 && j == 4 ? 2 :
7666 i == Xsand_stoneout_1 && j == 5 ? 3 :
7667 i == Xsand_stoneout_1 && j == 6 ? 4 :
7668 i == Xsand_stoneout_1 && j == 7 ? 4 :
7669 i == Xsand_stoneout_2 && j == 0 ? 5 :
7670 i == Xsand_stoneout_2 && j == 1 ? 6 :
7671 i == Xsand_stoneout_2 && j == 2 ? 7 :
7672 i == Xsand_stoneout_2 && j == 3 ? 8 :
7673 i == Xsand_stoneout_2 && j == 4 ? 9 :
7674 i == Xsand_stoneout_2 && j == 5 ? 11 :
7675 i == Xsand_stoneout_2 && j == 6 ? 13 :
7676 i == Xsand_stoneout_2 && j == 7 ? 15 :
7677 i == Xboom_bug && j == 1 ? 2 :
7678 i == Xboom_bug && j == 2 ? 2 :
7679 i == Xboom_bug && j == 3 ? 4 :
7680 i == Xboom_bug && j == 4 ? 4 :
7681 i == Xboom_bug && j == 5 ? 2 :
7682 i == Xboom_bug && j == 6 ? 2 :
7683 i == Xboom_bug && j == 7 ? 0 :
7684 i == Xboom_bomb && j == 1 ? 2 :
7685 i == Xboom_bomb && j == 2 ? 2 :
7686 i == Xboom_bomb && j == 3 ? 4 :
7687 i == Xboom_bomb && j == 4 ? 4 :
7688 i == Xboom_bomb && j == 5 ? 2 :
7689 i == Xboom_bomb && j == 6 ? 2 :
7690 i == Xboom_bomb && j == 7 ? 0 :
7691 i == Xboom_android && j == 7 ? 6 :
7692 i == Xboom_1 && j == 1 ? 2 :
7693 i == Xboom_1 && j == 2 ? 2 :
7694 i == Xboom_1 && j == 3 ? 4 :
7695 i == Xboom_1 && j == 4 ? 4 :
7696 i == Xboom_1 && j == 5 ? 6 :
7697 i == Xboom_1 && j == 6 ? 6 :
7698 i == Xboom_1 && j == 7 ? 8 :
7699 i == Xboom_2 && j == 0 ? 8 :
7700 i == Xboom_2 && j == 1 ? 8 :
7701 i == Xboom_2 && j == 2 ? 10 :
7702 i == Xboom_2 && j == 3 ? 10 :
7703 i == Xboom_2 && j == 4 ? 10 :
7704 i == Xboom_2 && j == 5 ? 12 :
7705 i == Xboom_2 && j == 6 ? 12 :
7706 i == Xboom_2 && j == 7 ? 12 :
7707 special_animation && j == 4 ? 3 :
7708 effective_action != action ? 0 :
7712 Bitmap *debug_bitmap = g_em->bitmap;
7713 int debug_src_x = g_em->src_x;
7714 int debug_src_y = g_em->src_y;
7717 int frame = getAnimationFrame(g->anim_frames,
7720 g->anim_start_frame,
7723 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
7724 g->double_movement && is_backside);
7726 g_em->bitmap = src_bitmap;
7727 g_em->src_x = src_x;
7728 g_em->src_y = src_y;
7729 g_em->src_offset_x = 0;
7730 g_em->src_offset_y = 0;
7731 g_em->dst_offset_x = 0;
7732 g_em->dst_offset_y = 0;
7733 g_em->width = TILEX;
7734 g_em->height = TILEY;
7736 g_em->preserve_background = FALSE;
7738 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
7741 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
7742 effective_action == ACTION_MOVING ||
7743 effective_action == ACTION_PUSHING ||
7744 effective_action == ACTION_EATING)) ||
7745 (!has_action_graphics && (effective_action == ACTION_FILLING ||
7746 effective_action == ACTION_EMPTYING)))
7749 (effective_action == ACTION_FALLING ||
7750 effective_action == ACTION_FILLING ||
7751 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
7752 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
7753 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
7754 int num_steps = (i == Ydrip_s1 ? 16 :
7755 i == Ydrip_s1B ? 16 :
7756 i == Ydrip_s2 ? 16 :
7757 i == Ydrip_s2B ? 16 :
7758 i == Xsand_stonein_1 ? 32 :
7759 i == Xsand_stonein_2 ? 32 :
7760 i == Xsand_stonein_3 ? 32 :
7761 i == Xsand_stonein_4 ? 32 :
7762 i == Xsand_stoneout_1 ? 16 :
7763 i == Xsand_stoneout_2 ? 16 : 8);
7764 int cx = ABS(dx) * (TILEX / num_steps);
7765 int cy = ABS(dy) * (TILEY / num_steps);
7766 int step_frame = (i == Ydrip_s2 ? j + 8 :
7767 i == Ydrip_s2B ? j + 8 :
7768 i == Xsand_stonein_2 ? j + 8 :
7769 i == Xsand_stonein_3 ? j + 16 :
7770 i == Xsand_stonein_4 ? j + 24 :
7771 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
7772 int step = (is_backside ? step_frame : num_steps - step_frame);
7774 if (is_backside) /* tile where movement starts */
7776 if (dx < 0 || dy < 0)
7778 g_em->src_offset_x = cx * step;
7779 g_em->src_offset_y = cy * step;
7783 g_em->dst_offset_x = cx * step;
7784 g_em->dst_offset_y = cy * step;
7787 else /* tile where movement ends */
7789 if (dx < 0 || dy < 0)
7791 g_em->dst_offset_x = cx * step;
7792 g_em->dst_offset_y = cy * step;
7796 g_em->src_offset_x = cx * step;
7797 g_em->src_offset_y = cy * step;
7801 g_em->width = TILEX - cx * step;
7802 g_em->height = TILEY - cy * step;
7805 /* create unique graphic identifier to decide if tile must be redrawn */
7806 /* bit 31 - 16 (16 bit): EM style graphic
7807 bit 15 - 12 ( 4 bit): EM style frame
7808 bit 11 - 6 ( 6 bit): graphic width
7809 bit 5 - 0 ( 6 bit): graphic height */
7810 g_em->unique_identifier =
7811 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
7815 /* skip check for EMC elements not contained in original EMC artwork */
7816 if (element == EL_EMC_FAKE_ACID)
7819 if (g_em->bitmap != debug_bitmap ||
7820 g_em->src_x != debug_src_x ||
7821 g_em->src_y != debug_src_y ||
7822 g_em->src_offset_x != 0 ||
7823 g_em->src_offset_y != 0 ||
7824 g_em->dst_offset_x != 0 ||
7825 g_em->dst_offset_y != 0 ||
7826 g_em->width != TILEX ||
7827 g_em->height != TILEY)
7829 static int last_i = -1;
7837 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
7838 i, element, element_info[element].token_name,
7839 element_action_info[effective_action].suffix, direction);
7841 if (element != effective_element)
7842 printf(" [%d ('%s')]",
7844 element_info[effective_element].token_name);
7848 if (g_em->bitmap != debug_bitmap)
7849 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
7850 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
7852 if (g_em->src_x != debug_src_x ||
7853 g_em->src_y != debug_src_y)
7854 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
7855 j, (is_backside ? 'B' : 'F'),
7856 g_em->src_x, g_em->src_y,
7857 g_em->src_x / 32, g_em->src_y / 32,
7858 debug_src_x, debug_src_y,
7859 debug_src_x / 32, debug_src_y / 32);
7861 if (g_em->src_offset_x != 0 ||
7862 g_em->src_offset_y != 0 ||
7863 g_em->dst_offset_x != 0 ||
7864 g_em->dst_offset_y != 0)
7865 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
7867 g_em->src_offset_x, g_em->src_offset_y,
7868 g_em->dst_offset_x, g_em->dst_offset_y);
7870 if (g_em->width != TILEX ||
7871 g_em->height != TILEY)
7872 printf(" %d (%d): size %d,%d should be %d,%d\n",
7874 g_em->width, g_em->height, TILEX, TILEY);
7876 num_em_gfx_errors++;
7883 for (i = 0; i < TILE_MAX; i++)
7885 for (j = 0; j < 8; j++)
7887 int element = object_mapping[i].element_rnd;
7888 int action = object_mapping[i].action;
7889 int direction = object_mapping[i].direction;
7890 boolean is_backside = object_mapping[i].is_backside;
7891 int graphic_action = el_act_dir2img(element, action, direction);
7892 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
7894 if ((action == ACTION_SMASHED_BY_ROCK ||
7895 action == ACTION_SMASHED_BY_SPRING ||
7896 action == ACTION_EATING) &&
7897 graphic_action == graphic_default)
7899 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
7900 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
7901 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
7902 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
7905 /* no separate animation for "smashed by rock" -- use rock instead */
7906 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7907 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
7909 g_em->bitmap = g_xx->bitmap;
7910 g_em->src_x = g_xx->src_x;
7911 g_em->src_y = g_xx->src_y;
7912 g_em->src_offset_x = g_xx->src_offset_x;
7913 g_em->src_offset_y = g_xx->src_offset_y;
7914 g_em->dst_offset_x = g_xx->dst_offset_x;
7915 g_em->dst_offset_y = g_xx->dst_offset_y;
7916 g_em->width = g_xx->width;
7917 g_em->height = g_xx->height;
7918 g_em->unique_identifier = g_xx->unique_identifier;
7921 g_em->preserve_background = TRUE;
7926 for (p = 0; p < MAX_PLAYERS; p++)
7928 for (i = 0; i < SPR_MAX; i++)
7930 int element = player_mapping[p][i].element_rnd;
7931 int action = player_mapping[p][i].action;
7932 int direction = player_mapping[p][i].direction;
7934 for (j = 0; j < 8; j++)
7936 int effective_element = element;
7937 int effective_action = action;
7938 int graphic = (direction == MV_NONE ?
7939 el_act2img(effective_element, effective_action) :
7940 el_act_dir2img(effective_element, effective_action,
7942 struct GraphicInfo *g = &graphic_info[graphic];
7943 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
7949 Bitmap *debug_bitmap = g_em->bitmap;
7950 int debug_src_x = g_em->src_x;
7951 int debug_src_y = g_em->src_y;
7954 int frame = getAnimationFrame(g->anim_frames,
7957 g->anim_start_frame,
7960 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
7962 g_em->bitmap = src_bitmap;
7963 g_em->src_x = src_x;
7964 g_em->src_y = src_y;
7965 g_em->src_offset_x = 0;
7966 g_em->src_offset_y = 0;
7967 g_em->dst_offset_x = 0;
7968 g_em->dst_offset_y = 0;
7969 g_em->width = TILEX;
7970 g_em->height = TILEY;
7974 /* skip check for EMC elements not contained in original EMC artwork */
7975 if (element == EL_PLAYER_3 ||
7976 element == EL_PLAYER_4)
7979 if (g_em->bitmap != debug_bitmap ||
7980 g_em->src_x != debug_src_x ||
7981 g_em->src_y != debug_src_y)
7983 static int last_i = -1;
7991 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
7992 p, i, element, element_info[element].token_name,
7993 element_action_info[effective_action].suffix, direction);
7995 if (element != effective_element)
7996 printf(" [%d ('%s')]",
7998 element_info[effective_element].token_name);
8002 if (g_em->bitmap != debug_bitmap)
8003 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
8004 j, (int)(g_em->bitmap), (int)(debug_bitmap));
8006 if (g_em->src_x != debug_src_x ||
8007 g_em->src_y != debug_src_y)
8008 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
8010 g_em->src_x, g_em->src_y,
8011 g_em->src_x / 32, g_em->src_y / 32,
8012 debug_src_x, debug_src_y,
8013 debug_src_x / 32, debug_src_y / 32);
8015 num_em_gfx_errors++;
8025 printf("::: [%d errors found]\n", num_em_gfx_errors);
8031 void CheckSaveEngineSnapshot_EM(byte action[MAX_PLAYERS], int frame,
8032 boolean any_player_moving,
8033 boolean any_player_snapping,
8034 boolean any_player_dropping)
8036 if (frame == 0 && !any_player_dropping)
8038 if (!local_player->was_waiting)
8040 if (!SaveEngineSnapshotToList())
8043 local_player->was_waiting = TRUE;
8046 else if (any_player_moving || any_player_snapping || any_player_dropping)
8048 local_player->was_waiting = FALSE;
8052 void CheckSaveEngineSnapshot_SP(boolean murphy_is_waiting,
8053 boolean murphy_is_dropping)
8055 if (murphy_is_waiting)
8057 if (!local_player->was_waiting)
8059 if (!SaveEngineSnapshotToList())
8062 local_player->was_waiting = TRUE;
8067 local_player->was_waiting = FALSE;
8071 void CheckSingleStepMode_EM(byte action[MAX_PLAYERS], int frame,
8072 boolean any_player_moving,
8073 boolean any_player_snapping,
8074 boolean any_player_dropping)
8076 if (tape.single_step && tape.recording && !tape.pausing)
8077 if (frame == 0 && !any_player_dropping)
8078 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
8080 CheckSaveEngineSnapshot_EM(action, frame, any_player_moving,
8081 any_player_snapping, any_player_dropping);
8084 void CheckSingleStepMode_SP(boolean murphy_is_waiting,
8085 boolean murphy_is_dropping)
8087 if (tape.single_step && tape.recording && !tape.pausing)
8088 if (murphy_is_waiting)
8089 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
8091 CheckSaveEngineSnapshot_SP(murphy_is_waiting, murphy_is_dropping);
8094 void getGraphicSource_SP(struct GraphicInfo_SP *g_sp,
8095 int graphic, int sync_frame, int x, int y)
8097 int frame = getGraphicAnimationFrame(graphic, sync_frame);
8099 getGraphicSource(graphic, frame, &g_sp->bitmap, &g_sp->src_x, &g_sp->src_y);
8102 boolean isNextAnimationFrame_SP(int graphic, int sync_frame)
8104 return (IS_NEXT_FRAME(sync_frame, graphic));
8107 int getGraphicInfo_Delay(int graphic)
8109 return graphic_info[graphic].anim_delay;
8112 void PlayMenuSoundExt(int sound)
8114 if (sound == SND_UNDEFINED)
8117 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8118 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8121 if (IS_LOOP_SOUND(sound))
8122 PlaySoundLoop(sound);
8127 void PlayMenuSound()
8129 PlayMenuSoundExt(menu.sound[game_status]);
8132 void PlayMenuSoundStereo(int sound, int stereo_position)
8134 if (sound == SND_UNDEFINED)
8137 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8138 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8141 if (IS_LOOP_SOUND(sound))
8142 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
8144 PlaySoundStereo(sound, stereo_position);
8147 void PlayMenuSoundIfLoopExt(int sound)
8149 if (sound == SND_UNDEFINED)
8152 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8153 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8156 if (IS_LOOP_SOUND(sound))
8157 PlaySoundLoop(sound);
8160 void PlayMenuSoundIfLoop()
8162 PlayMenuSoundIfLoopExt(menu.sound[game_status]);
8165 void PlayMenuMusicExt(int music)
8167 if (music == MUS_UNDEFINED)
8170 if (!setup.sound_music)
8176 void PlayMenuMusic()
8178 PlayMenuMusicExt(menu.music[game_status]);
8181 void PlaySoundActivating()
8184 PlaySound(SND_MENU_ITEM_ACTIVATING);
8188 void PlaySoundSelecting()
8191 PlaySound(SND_MENU_ITEM_SELECTING);
8195 void ToggleFullscreenOrChangeWindowScalingIfNeeded()
8197 boolean change_fullscreen = (setup.fullscreen !=
8198 video.fullscreen_enabled);
8199 boolean change_window_scaling_percent = (!video.fullscreen_enabled &&
8200 setup.window_scaling_percent !=
8201 video.window_scaling_percent);
8203 if (change_window_scaling_percent && video.fullscreen_enabled)
8206 if (!change_window_scaling_percent && !video.fullscreen_available)
8209 #if defined(TARGET_SDL2)
8210 if (change_window_scaling_percent)
8212 SDLSetWindowScaling(setup.window_scaling_percent);
8216 else if (change_fullscreen)
8218 SDLSetWindowFullscreen(setup.fullscreen);
8220 /* set setup value according to successfully changed fullscreen mode */
8221 setup.fullscreen = video.fullscreen_enabled;
8227 if (change_fullscreen ||
8228 change_window_scaling_percent)
8230 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
8232 /* save backbuffer content which gets lost when toggling fullscreen mode */
8233 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8235 if (change_window_scaling_percent)
8237 /* keep window mode, but change window scaling */
8238 video.fullscreen_enabled = TRUE; /* force new window scaling */
8241 /* toggle fullscreen */
8242 ChangeVideoModeIfNeeded(setup.fullscreen);
8244 /* set setup value according to successfully changed fullscreen mode */
8245 setup.fullscreen = video.fullscreen_enabled;
8247 /* restore backbuffer content from temporary backbuffer backup bitmap */
8248 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8250 FreeBitmap(tmp_backbuffer);
8252 /* update visible window/screen */
8253 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8257 void JoinRectangles(int *x, int *y, int *width, int *height,
8258 int x2, int y2, int width2, int height2)
8260 // do not join with "off-screen" rectangle
8261 if (x2 == -1 || y2 == -1)
8266 *width = MAX(*width, width2);
8267 *height = MAX(*height, height2);
8270 void SetAnimStatus(int anim_status_new)
8272 if (anim_status_new == GAME_MODE_MAIN)
8273 anim_status_new = GAME_MODE_PSEUDO_MAINONLY;
8275 global.anim_status_next = anim_status_new;
8277 // directly set screen modes that are entered without fading
8278 if ((global.anim_status == GAME_MODE_PSEUDO_MAINONLY &&
8279 global.anim_status_next == GAME_MODE_PSEUDO_TYPENAME) ||
8280 (global.anim_status == GAME_MODE_PSEUDO_TYPENAME &&
8281 global.anim_status_next == GAME_MODE_PSEUDO_MAINONLY))
8282 global.anim_status = global.anim_status_next;
8285 void SetGameStatus(int game_status_new)
8287 game_status = game_status_new;
8289 SetAnimStatus(game_status_new);
8292 void SetFontStatus(int game_status_new)
8294 static int last_game_status = -1;
8296 if (game_status_new != -1)
8298 // set game status for font use after storing last game status
8299 last_game_status = game_status;
8300 game_status = game_status_new;
8304 // reset game status after font use from last stored game status
8305 game_status = last_game_status;
8309 void ResetFontStatus()
8314 void ChangeViewportPropertiesIfNeeded()
8316 int gfx_game_mode = game_status;
8317 int gfx_game_mode2 = (game_status == GAME_MODE_EDITOR ? GAME_MODE_DEFAULT :
8319 struct RectWithBorder *vp_window = &viewport.window[gfx_game_mode];
8320 struct RectWithBorder *vp_playfield = &viewport.playfield[gfx_game_mode];
8321 struct RectWithBorder *vp_door_1 = &viewport.door_1[gfx_game_mode];
8322 struct RectWithBorder *vp_door_2 = &viewport.door_2[gfx_game_mode2];
8323 struct RectWithBorder *vp_door_3 = &viewport.door_2[GAME_MODE_EDITOR];
8324 int new_win_xsize = vp_window->width;
8325 int new_win_ysize = vp_window->height;
8326 int border_size = vp_playfield->border_size;
8327 int new_sx = vp_playfield->x + border_size;
8328 int new_sy = vp_playfield->y + border_size;
8329 int new_sxsize = vp_playfield->width - 2 * border_size;
8330 int new_sysize = vp_playfield->height - 2 * border_size;
8331 int new_real_sx = vp_playfield->x;
8332 int new_real_sy = vp_playfield->y;
8333 int new_full_sxsize = vp_playfield->width;
8334 int new_full_sysize = vp_playfield->height;
8335 int new_dx = vp_door_1->x;
8336 int new_dy = vp_door_1->y;
8337 int new_dxsize = vp_door_1->width;
8338 int new_dysize = vp_door_1->height;
8339 int new_vx = vp_door_2->x;
8340 int new_vy = vp_door_2->y;
8341 int new_vxsize = vp_door_2->width;
8342 int new_vysize = vp_door_2->height;
8343 int new_ex = vp_door_3->x;
8344 int new_ey = vp_door_3->y;
8345 int new_exsize = vp_door_3->width;
8346 int new_eysize = vp_door_3->height;
8347 int new_tilesize_var =
8348 (setup.small_game_graphics ? MINI_TILESIZE : game.tile_size);
8350 int tilesize = (gfx_game_mode == GAME_MODE_PLAYING ? new_tilesize_var :
8351 gfx_game_mode == GAME_MODE_EDITOR ? MINI_TILESIZE : TILESIZE);
8352 int new_scr_fieldx = new_sxsize / tilesize;
8353 int new_scr_fieldy = new_sysize / tilesize;
8354 int new_scr_fieldx_buffers = new_sxsize / new_tilesize_var;
8355 int new_scr_fieldy_buffers = new_sysize / new_tilesize_var;
8356 boolean init_gfx_buffers = FALSE;
8357 boolean init_video_buffer = FALSE;
8358 boolean init_gadgets_and_anims = FALSE;
8359 boolean init_em_graphics = FALSE;
8361 if (new_win_xsize != WIN_XSIZE ||
8362 new_win_ysize != WIN_YSIZE)
8364 WIN_XSIZE = new_win_xsize;
8365 WIN_YSIZE = new_win_ysize;
8367 init_video_buffer = TRUE;
8368 init_gfx_buffers = TRUE;
8369 init_gadgets_and_anims = TRUE;
8371 // printf("::: video: init_video_buffer, init_gfx_buffers\n");
8374 if (new_scr_fieldx != SCR_FIELDX ||
8375 new_scr_fieldy != SCR_FIELDY)
8377 /* this always toggles between MAIN and GAME when using small tile size */
8379 SCR_FIELDX = new_scr_fieldx;
8380 SCR_FIELDY = new_scr_fieldy;
8382 // printf("::: new_scr_fieldx != SCR_FIELDX ...\n");
8393 new_sxsize != SXSIZE ||
8394 new_sysize != SYSIZE ||
8395 new_dxsize != DXSIZE ||
8396 new_dysize != DYSIZE ||
8397 new_vxsize != VXSIZE ||
8398 new_vysize != VYSIZE ||
8399 new_exsize != EXSIZE ||
8400 new_eysize != EYSIZE ||
8401 new_real_sx != REAL_SX ||
8402 new_real_sy != REAL_SY ||
8403 new_full_sxsize != FULL_SXSIZE ||
8404 new_full_sysize != FULL_SYSIZE ||
8405 new_tilesize_var != TILESIZE_VAR
8408 // ------------------------------------------------------------------------
8409 // determine next fading area for changed viewport definitions
8410 // ------------------------------------------------------------------------
8412 // start with current playfield area (default fading area)
8415 FADE_SXSIZE = FULL_SXSIZE;
8416 FADE_SYSIZE = FULL_SYSIZE;
8418 // add new playfield area if position or size has changed
8419 if (new_real_sx != REAL_SX || new_real_sy != REAL_SY ||
8420 new_full_sxsize != FULL_SXSIZE || new_full_sysize != FULL_SYSIZE)
8422 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
8423 new_real_sx, new_real_sy, new_full_sxsize,new_full_sysize);
8426 // add current and new door 1 area if position or size has changed
8427 if (new_dx != DX || new_dy != DY ||
8428 new_dxsize != DXSIZE || new_dysize != DYSIZE)
8430 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
8431 DX, DY, DXSIZE, DYSIZE);
8432 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
8433 new_dx, new_dy, new_dxsize, new_dysize);
8436 // add current and new door 2 area if position or size has changed
8437 if (new_dx != VX || new_dy != VY ||
8438 new_dxsize != VXSIZE || new_dysize != VYSIZE)
8440 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
8441 VX, VY, VXSIZE, VYSIZE);
8442 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
8443 new_vx, new_vy, new_vxsize, new_vysize);
8446 // ------------------------------------------------------------------------
8447 // handle changed tile size
8448 // ------------------------------------------------------------------------
8450 if (new_tilesize_var != TILESIZE_VAR)
8452 // printf("::: new_tilesize_var != TILESIZE_VAR\n");
8454 // changing tile size invalidates scroll values of engine snapshots
8455 FreeEngineSnapshotSingle();
8457 // changing tile size requires update of graphic mapping for EM engine
8458 init_em_graphics = TRUE;
8469 SXSIZE = new_sxsize;
8470 SYSIZE = new_sysize;
8471 DXSIZE = new_dxsize;
8472 DYSIZE = new_dysize;
8473 VXSIZE = new_vxsize;
8474 VYSIZE = new_vysize;
8475 EXSIZE = new_exsize;
8476 EYSIZE = new_eysize;
8477 REAL_SX = new_real_sx;
8478 REAL_SY = new_real_sy;
8479 FULL_SXSIZE = new_full_sxsize;
8480 FULL_SYSIZE = new_full_sysize;
8481 TILESIZE_VAR = new_tilesize_var;
8483 init_gfx_buffers = TRUE;
8484 init_gadgets_and_anims = TRUE;
8486 // printf("::: viewports: init_gfx_buffers\n");
8487 // printf("::: viewports: init_gadgets_and_anims\n");
8490 if (init_gfx_buffers)
8492 // printf("::: init_gfx_buffers\n");
8494 SCR_FIELDX = new_scr_fieldx_buffers;
8495 SCR_FIELDY = new_scr_fieldy_buffers;
8499 SCR_FIELDX = new_scr_fieldx;
8500 SCR_FIELDY = new_scr_fieldy;
8502 SetDrawDeactivationMask(REDRAW_NONE);
8503 SetDrawBackgroundMask(REDRAW_FIELD);
8506 if (init_video_buffer)
8508 // printf("::: init_video_buffer\n");
8510 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
8511 InitImageTextures();
8514 if (init_gadgets_and_anims)
8516 // printf("::: init_gadgets_and_anims\n");
8519 InitGlobalAnimations();
8522 if (init_em_graphics)
8524 InitGraphicInfo_EM();