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;
533 static int last_redraw_mask = REDRAW_NONE;
535 // force screen redraw in every frame to continue drawing global animations
536 // (but always use the last redraw mask to prevent unwanted side effects)
537 if (redraw_mask == REDRAW_NONE)
538 redraw_mask = last_redraw_mask;
540 last_redraw_mask = redraw_mask;
543 // masked border now drawn immediately when blitting backbuffer to window
545 // draw masked border to all viewports, if defined
546 DrawMaskedBorder(redraw_mask);
549 // draw frames per second (only if debug mode is enabled)
550 if (redraw_mask & REDRAW_FPS)
551 DrawFramesPerSecond();
553 // remove playfield redraw before potentially merging with doors redraw
554 if (DrawingDeactivated(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE))
555 redraw_mask &= ~REDRAW_FIELD;
557 // redraw complete window if both playfield and (some) doors need redraw
558 if (redraw_mask & REDRAW_FIELD && redraw_mask & REDRAW_DOORS)
559 redraw_mask = REDRAW_ALL;
561 /* although redrawing the whole window would be fine for normal gameplay,
562 being able to only redraw the playfield is required for deactivating
563 certain drawing areas (mainly playfield) to work, which is needed for
564 warp-forward to be fast enough (by skipping redraw of most frames) */
566 if (redraw_mask & REDRAW_ALL)
568 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
570 else if (redraw_mask & REDRAW_FIELD)
572 BlitBitmap(backbuffer, window,
573 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
575 else if (redraw_mask & REDRAW_DOORS)
577 // merge door areas to prevent calling screen redraw more than once
583 if (redraw_mask & REDRAW_DOOR_1)
587 x2 = MAX(x2, DX + DXSIZE);
588 y2 = MAX(y2, DY + DYSIZE);
590 else if (redraw_mask & REDRAW_DOOR_2)
594 x2 = MAX(x2, VX + VXSIZE);
595 y2 = MAX(y2, VY + VYSIZE);
597 else if (redraw_mask & REDRAW_DOOR_3)
601 x2 = MAX(x2, EX + EXSIZE);
602 y2 = MAX(y2, EY + EYSIZE);
605 BlitBitmap(backbuffer, window, x1, y1, x2 - x1, y2 - y1, x1, y1);
608 redraw_mask = REDRAW_NONE;
611 PrintFrameTimeDebugging();
615 void BackToFront_WithFrameDelay(unsigned int frame_delay_value)
617 unsigned int frame_delay_value_old = GetVideoFrameDelay();
619 SetVideoFrameDelay(frame_delay_value);
623 SetVideoFrameDelay(frame_delay_value_old);
626 static void FadeExt(int fade_mask, int fade_mode, int fade_type)
628 static int fade_type_skip = FADE_TYPE_NONE;
629 void (*draw_border_function)(void) = NULL;
630 int x, y, width, height;
631 int fade_delay, post_delay;
633 if (fade_type == FADE_TYPE_FADE_OUT)
635 if (fade_type_skip != FADE_TYPE_NONE)
637 /* skip all fade operations until specified fade operation */
638 if (fade_type & fade_type_skip)
639 fade_type_skip = FADE_TYPE_NONE;
644 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
648 redraw_mask |= fade_mask;
650 if (fade_type == FADE_TYPE_SKIP)
652 fade_type_skip = fade_mode;
657 fade_delay = fading.fade_delay;
658 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
660 if (fade_type_skip != FADE_TYPE_NONE)
662 /* skip all fade operations until specified fade operation */
663 if (fade_type & fade_type_skip)
664 fade_type_skip = FADE_TYPE_NONE;
669 if (global.autoplay_leveldir)
674 if (fade_mask == REDRAW_FIELD)
679 height = FADE_SYSIZE;
681 if (border.draw_masked_when_fading)
682 draw_border_function = DrawMaskedBorder_FIELD; /* update when fading */
684 DrawMaskedBorder_FIELD(); /* draw once */
686 else /* REDRAW_ALL */
694 if (!setup.fade_screens ||
696 fading.fade_mode == FADE_MODE_NONE)
698 if (fade_mode == FADE_MODE_FADE_OUT)
701 BlitBitmap(backbuffer, window, x, y, width, height, x, y);
703 redraw_mask &= ~fade_mask;
708 FadeRectangle(x, y, width, height, fade_mode, fade_delay, post_delay,
709 draw_border_function);
711 redraw_mask &= ~fade_mask;
714 static void SetScreenStates_BeforeFadingIn()
716 // temporarily set screen mode for animations to screen after fading in
717 global.anim_status = global.anim_status_next;
719 // store backbuffer with all animations that will be started after fading in
720 PrepareFadeBitmap(DRAW_TO_FADE_TARGET);
722 // set screen mode for animations back to fading
723 global.anim_status = GAME_MODE_PSEUDO_FADING;
726 static void SetScreenStates_AfterFadingIn()
728 // store new source screen (to use correct masked border for fading)
729 gfx.fade_border_source_status = global.border_status;
731 global.anim_status = global.anim_status_next;
733 // force update of global animation status in case of rapid screen changes
734 redraw_mask = REDRAW_ALL;
738 static void SetScreenStates_BeforeFadingOut()
740 // store new target screen (to use correct masked border for fading)
741 gfx.fade_border_target_status = game_status;
743 // set screen mode for animations to fading
744 global.anim_status = GAME_MODE_PSEUDO_FADING;
746 // store backbuffer with all animations that will be stopped for fading out
747 PrepareFadeBitmap(DRAW_TO_FADE_SOURCE);
750 static void SetScreenStates_AfterFadingOut()
752 global.border_status = game_status;
755 void FadeIn(int fade_mask)
757 SetScreenStates_BeforeFadingIn();
760 DrawMaskedBorder(REDRAW_ALL);
763 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
764 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_IN);
766 FadeExt(fade_mask, FADE_MODE_FADE_IN, FADE_TYPE_FADE_IN);
770 FADE_SXSIZE = FULL_SXSIZE;
771 FADE_SYSIZE = FULL_SYSIZE;
773 SetScreenStates_AfterFadingIn();
776 void FadeOut(int fade_mask)
778 SetScreenStates_BeforeFadingOut();
781 DrawMaskedBorder(REDRAW_ALL);
784 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
785 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_OUT);
787 FadeExt(fade_mask, FADE_MODE_FADE_OUT, FADE_TYPE_FADE_OUT);
789 SetScreenStates_AfterFadingOut();
792 static void FadeSetLeaveNext(struct TitleFadingInfo fading_leave, boolean set)
794 static struct TitleFadingInfo fading_leave_stored;
797 fading_leave_stored = fading_leave;
799 fading = fading_leave_stored;
802 void FadeSetEnterMenu()
804 fading = menu.enter_menu;
806 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
809 void FadeSetLeaveMenu()
811 fading = menu.leave_menu;
813 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
816 void FadeSetEnterScreen()
818 fading = menu.enter_screen[game_status];
820 FadeSetLeaveNext(menu.leave_screen[game_status], TRUE); /* store */
823 void FadeSetNextScreen()
825 fading = menu.next_screen[game_status];
827 // (do not overwrite fade mode set by FadeSetEnterScreen)
828 // FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
831 void FadeSetLeaveScreen()
833 FadeSetLeaveNext(menu.leave_screen[game_status], FALSE); /* recall */
836 void FadeSetFromType(int type)
838 if (type & TYPE_ENTER_SCREEN)
839 FadeSetEnterScreen();
840 else if (type & TYPE_ENTER)
842 else if (type & TYPE_LEAVE)
846 void FadeSetDisabled()
848 static struct TitleFadingInfo fading_none = { FADE_MODE_NONE, -1, -1, -1 };
850 fading = fading_none;
853 void FadeSkipNextFadeIn()
855 FadeExt(0, FADE_MODE_SKIP_FADE_IN, FADE_TYPE_SKIP);
858 void FadeSkipNextFadeOut()
860 FadeExt(0, FADE_MODE_SKIP_FADE_OUT, FADE_TYPE_SKIP);
863 Bitmap *getBitmapFromGraphicOrDefault(int graphic, int default_graphic)
865 boolean redefined = getImageListEntryFromImageID(graphic)->redefined;
867 return (graphic == IMG_UNDEFINED ? NULL :
868 graphic_info[graphic].bitmap != NULL || redefined ?
869 graphic_info[graphic].bitmap :
870 graphic_info[default_graphic].bitmap);
873 Bitmap *getBackgroundBitmap(int graphic)
875 return getBitmapFromGraphicOrDefault(graphic, IMG_BACKGROUND);
878 Bitmap *getGlobalBorderBitmap(int graphic)
880 return getBitmapFromGraphicOrDefault(graphic, IMG_GLOBAL_BORDER);
883 Bitmap *getGlobalBorderBitmapFromStatus(int status)
886 (status == GAME_MODE_MAIN ||
887 status == GAME_MODE_PSEUDO_TYPENAME ? IMG_GLOBAL_BORDER_MAIN :
888 status == GAME_MODE_SCORES ? IMG_GLOBAL_BORDER_SCORES :
889 status == GAME_MODE_EDITOR ? IMG_GLOBAL_BORDER_EDITOR :
890 status == GAME_MODE_PLAYING ? IMG_GLOBAL_BORDER_PLAYING :
893 return getGlobalBorderBitmap(graphic);
896 void SetWindowBackgroundImageIfDefined(int graphic)
898 if (graphic_info[graphic].bitmap)
899 SetWindowBackgroundBitmap(graphic_info[graphic].bitmap);
902 void SetMainBackgroundImageIfDefined(int graphic)
904 if (graphic_info[graphic].bitmap)
905 SetMainBackgroundBitmap(graphic_info[graphic].bitmap);
908 void SetDoorBackgroundImageIfDefined(int graphic)
910 if (graphic_info[graphic].bitmap)
911 SetDoorBackgroundBitmap(graphic_info[graphic].bitmap);
914 void SetWindowBackgroundImage(int graphic)
916 SetWindowBackgroundBitmap(getBackgroundBitmap(graphic));
919 void SetMainBackgroundImage(int graphic)
921 SetMainBackgroundBitmap(getBackgroundBitmap(graphic));
924 void SetDoorBackgroundImage(int graphic)
926 SetDoorBackgroundBitmap(getBackgroundBitmap(graphic));
929 void SetPanelBackground()
931 struct GraphicInfo *gfx = &graphic_info[IMG_BACKGROUND_PANEL];
933 BlitBitmapTiled(gfx->bitmap, bitmap_db_panel, gfx->src_x, gfx->src_y,
934 gfx->width, gfx->height, 0, 0, DXSIZE, DYSIZE);
936 SetDoorBackgroundBitmap(bitmap_db_panel);
939 void DrawBackground(int x, int y, int width, int height)
941 /* "drawto" might still point to playfield buffer here (hall of fame) */
942 ClearRectangleOnBackground(backbuffer, x, y, width, height);
944 if (IN_GFX_FIELD_FULL(x, y))
945 redraw_mask |= REDRAW_FIELD;
946 else if (IN_GFX_DOOR_1(x, y))
947 redraw_mask |= REDRAW_DOOR_1;
948 else if (IN_GFX_DOOR_2(x, y))
949 redraw_mask |= REDRAW_DOOR_2;
950 else if (IN_GFX_DOOR_3(x, y))
951 redraw_mask |= REDRAW_DOOR_3;
954 void DrawBackgroundForFont(int x, int y, int width, int height, int font_nr)
956 struct FontBitmapInfo *font = getFontBitmapInfo(font_nr);
958 if (font->bitmap == NULL)
961 DrawBackground(x, y, width, height);
964 void DrawBackgroundForGraphic(int x, int y, int width, int height, int graphic)
966 struct GraphicInfo *g = &graphic_info[graphic];
968 if (g->bitmap == NULL)
971 DrawBackground(x, y, width, height);
974 static int game_status_last = -1;
975 static Bitmap *global_border_bitmap_last = NULL;
976 static Bitmap *global_border_bitmap = NULL;
977 static int real_sx_last = -1, real_sy_last = -1;
978 static int full_sxsize_last = -1, full_sysize_last = -1;
979 static int dx_last = -1, dy_last = -1;
980 static int dxsize_last = -1, dysize_last = -1;
981 static int vx_last = -1, vy_last = -1;
982 static int vxsize_last = -1, vysize_last = -1;
984 boolean CheckIfGlobalBorderHasChanged()
986 // if game status has not changed, global border has not changed either
987 if (game_status == game_status_last)
990 // determine and store new global border bitmap for current game status
991 global_border_bitmap = getGlobalBorderBitmapFromStatus(game_status);
993 return (global_border_bitmap_last != global_border_bitmap);
996 boolean CheckIfGlobalBorderRedrawIsNeeded()
998 // if game status has not changed, nothing has to be redrawn
999 if (game_status == game_status_last)
1002 // redraw if last screen was title screen
1003 if (game_status_last == GAME_MODE_TITLE)
1006 // redraw if global screen border has changed
1007 if (CheckIfGlobalBorderHasChanged())
1010 // redraw if position or size of playfield area has changed
1011 if (real_sx_last != REAL_SX || real_sy_last != REAL_SY ||
1012 full_sxsize_last != FULL_SXSIZE || full_sysize_last != FULL_SYSIZE)
1015 // redraw if position or size of door area has changed
1016 if (dx_last != DX || dy_last != DY ||
1017 dxsize_last != DXSIZE || dysize_last != DYSIZE)
1020 // redraw if position or size of tape area has changed
1021 if (vx_last != VX || vy_last != VY ||
1022 vxsize_last != VXSIZE || vysize_last != VYSIZE)
1028 void RedrawGlobalBorderFromBitmap(Bitmap *bitmap)
1031 BlitBitmap(bitmap, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
1033 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
1036 void RedrawGlobalBorder()
1038 Bitmap *bitmap = getGlobalBorderBitmapFromStatus(game_status);
1040 RedrawGlobalBorderFromBitmap(bitmap);
1042 redraw_mask = REDRAW_ALL;
1045 static void RedrawGlobalBorderIfNeeded()
1047 if (game_status == game_status_last)
1050 // copy current draw buffer to later copy back areas that have not changed
1051 if (game_status_last != GAME_MODE_TITLE)
1052 BlitBitmap(backbuffer, bitmap_db_store_1, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
1054 if (CheckIfGlobalBorderRedrawIsNeeded())
1056 // redraw global screen border (or clear, if defined to be empty)
1057 RedrawGlobalBorderFromBitmap(global_border_bitmap);
1059 // copy previous playfield and door areas, if they are defined on both
1060 // previous and current screen and if they still have the same size
1062 if (real_sx_last != -1 && real_sy_last != -1 &&
1063 REAL_SX != -1 && REAL_SY != -1 &&
1064 full_sxsize_last == FULL_SXSIZE && full_sysize_last == FULL_SYSIZE)
1065 BlitBitmap(bitmap_db_store_1, backbuffer,
1066 real_sx_last, real_sy_last, FULL_SXSIZE, FULL_SYSIZE,
1069 if (dx_last != -1 && dy_last != -1 &&
1070 DX != -1 && DY != -1 &&
1071 dxsize_last == DXSIZE && dysize_last == DYSIZE)
1072 BlitBitmap(bitmap_db_store_1, backbuffer,
1073 dx_last, dy_last, DXSIZE, DYSIZE, DX, DY);
1075 if (vx_last != -1 && vy_last != -1 &&
1076 VX != -1 && VY != -1 &&
1077 vxsize_last == VXSIZE && vysize_last == VYSIZE)
1078 BlitBitmap(bitmap_db_store_1, backbuffer,
1079 vx_last, vy_last, VXSIZE, VYSIZE, VX, VY);
1081 redraw_mask = REDRAW_ALL;
1084 game_status_last = game_status;
1086 global_border_bitmap_last = global_border_bitmap;
1088 real_sx_last = REAL_SX;
1089 real_sy_last = REAL_SY;
1090 full_sxsize_last = FULL_SXSIZE;
1091 full_sysize_last = FULL_SYSIZE;
1094 dxsize_last = DXSIZE;
1095 dysize_last = DYSIZE;
1098 vxsize_last = VXSIZE;
1099 vysize_last = VYSIZE;
1104 RedrawGlobalBorderIfNeeded();
1106 /* !!! "drawto" might still point to playfield buffer here (see above) !!! */
1107 /* (when entering hall of fame after playing) */
1108 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
1110 /* !!! maybe this should be done before clearing the background !!! */
1111 if (game_status == GAME_MODE_PLAYING)
1113 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
1114 SetDrawtoField(DRAW_TO_FIELDBUFFER);
1118 SetDrawtoField(DRAW_TO_BACKBUFFER);
1122 void MarkTileDirty(int x, int y)
1124 redraw_mask |= REDRAW_FIELD;
1127 void SetBorderElement()
1131 BorderElement = EL_EMPTY;
1133 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
1135 for (x = 0; x < lev_fieldx; x++)
1137 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
1138 BorderElement = EL_STEELWALL;
1140 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
1146 void FloodFillLevel(int from_x, int from_y, int fill_element,
1147 short field[MAX_LEV_FIELDX][MAX_LEV_FIELDY],
1148 int max_fieldx, int max_fieldy)
1152 static int check[4][2] = { { -1, 0 }, { 0, -1 }, { 1, 0 }, { 0, 1 } };
1153 static int safety = 0;
1155 /* check if starting field still has the desired content */
1156 if (field[from_x][from_y] == fill_element)
1161 if (safety > max_fieldx * max_fieldy)
1162 Error(ERR_EXIT, "Something went wrong in 'FloodFill()'. Please debug.");
1164 old_element = field[from_x][from_y];
1165 field[from_x][from_y] = fill_element;
1167 for (i = 0; i < 4; i++)
1169 x = from_x + check[i][0];
1170 y = from_y + check[i][1];
1172 if (IN_FIELD(x, y, max_fieldx, max_fieldy) && field[x][y] == old_element)
1173 FloodFillLevel(x, y, fill_element, field, max_fieldx, max_fieldy);
1179 void SetRandomAnimationValue(int x, int y)
1181 gfx.anim_random_frame = GfxRandom[x][y];
1184 int getGraphicAnimationFrame(int graphic, int sync_frame)
1186 /* animation synchronized with global frame counter, not move position */
1187 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
1188 sync_frame = FrameCounter;
1190 return getAnimationFrame(graphic_info[graphic].anim_frames,
1191 graphic_info[graphic].anim_delay,
1192 graphic_info[graphic].anim_mode,
1193 graphic_info[graphic].anim_start_frame,
1197 void getSizedGraphicSourceExt(int graphic, int frame, int tilesize,
1198 Bitmap **bitmap, int *x, int *y,
1199 boolean get_backside)
1201 struct GraphicInfo *g = &graphic_info[graphic];
1202 Bitmap *src_bitmap = g->bitmap;
1203 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
1204 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
1205 int tilesize_capped = MIN(MAX(1, tilesize), TILESIZE);
1207 // if no in-game graphics defined, always use standard graphic size
1208 if (g->bitmaps[IMG_BITMAP_GAME] == NULL)
1209 tilesize = TILESIZE;
1211 if (tilesize == gfx.standard_tile_size)
1212 src_bitmap = g->bitmaps[IMG_BITMAP_STANDARD];
1213 else if (tilesize == game.tile_size)
1214 src_bitmap = g->bitmaps[IMG_BITMAP_GAME];
1216 src_bitmap = g->bitmaps[IMG_BITMAP_1x1 - log_2(tilesize_capped)];
1218 if (g->offset_y == 0) /* frames are ordered horizontally */
1220 int max_width = g->anim_frames_per_line * g->width;
1221 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
1223 src_x = pos % max_width;
1224 src_y = src_y % g->height + pos / max_width * g->height;
1226 else if (g->offset_x == 0) /* frames are ordered vertically */
1228 int max_height = g->anim_frames_per_line * g->height;
1229 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
1231 src_x = src_x % g->width + pos / max_height * g->width;
1232 src_y = pos % max_height;
1234 else /* frames are ordered diagonally */
1236 src_x = src_x + frame * g->offset_x;
1237 src_y = src_y + frame * g->offset_y;
1240 *bitmap = src_bitmap;
1241 *x = src_x * tilesize / g->tile_size;
1242 *y = src_y * tilesize / g->tile_size;
1245 void getFixedGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1246 int *x, int *y, boolean get_backside)
1248 getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y,
1252 void getSizedGraphicSource(int graphic, int frame, int tilesize,
1253 Bitmap **bitmap, int *x, int *y)
1255 getSizedGraphicSourceExt(graphic, frame, tilesize, bitmap, x, y, FALSE);
1258 void getFixedGraphicSource(int graphic, int frame,
1259 Bitmap **bitmap, int *x, int *y)
1261 getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y, FALSE);
1264 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1266 getSizedGraphicSource(graphic, 0, MINI_TILESIZE, bitmap, x, y);
1269 inline static void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1270 int *x, int *y, boolean get_backside)
1272 struct GraphicInfo *g = &graphic_info[graphic];
1273 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
1274 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
1276 if (TILESIZE_VAR != TILESIZE)
1277 return getSizedGraphicSourceExt(graphic, frame, TILESIZE_VAR, bitmap, x, y,
1280 *bitmap = g->bitmap;
1282 if (g->offset_y == 0) /* frames are ordered horizontally */
1284 int max_width = g->anim_frames_per_line * g->width;
1285 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
1287 *x = pos % max_width;
1288 *y = src_y % g->height + pos / max_width * g->height;
1290 else if (g->offset_x == 0) /* frames are ordered vertically */
1292 int max_height = g->anim_frames_per_line * g->height;
1293 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
1295 *x = src_x % g->width + pos / max_height * g->width;
1296 *y = pos % max_height;
1298 else /* frames are ordered diagonally */
1300 *x = src_x + frame * g->offset_x;
1301 *y = src_y + frame * g->offset_y;
1304 *x = *x * TILESIZE_VAR / g->tile_size;
1305 *y = *y * TILESIZE_VAR / g->tile_size;
1308 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
1310 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
1313 void DrawGraphic(int x, int y, int graphic, int frame)
1316 if (!IN_SCR_FIELD(x, y))
1318 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1319 printf("DrawGraphic(): This should never happen!\n");
1324 DrawGraphicExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR, graphic,
1327 MarkTileDirty(x, y);
1330 void DrawFixedGraphic(int x, int y, int graphic, int frame)
1333 if (!IN_SCR_FIELD(x, y))
1335 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1336 printf("DrawGraphic(): This should never happen!\n");
1341 DrawFixedGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic,
1343 MarkTileDirty(x, y);
1346 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1352 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1354 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX_VAR, TILEY_VAR, x, y);
1357 void DrawFixedGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1363 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1364 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
1367 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
1370 if (!IN_SCR_FIELD(x, y))
1372 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1373 printf("DrawGraphicThruMask(): This should never happen!\n");
1378 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
1381 MarkTileDirty(x, y);
1384 void DrawFixedGraphicThruMask(int x, int y, int graphic, int frame)
1387 if (!IN_SCR_FIELD(x, y))
1389 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1390 printf("DrawGraphicThruMask(): This should never happen!\n");
1395 DrawFixedGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
1397 MarkTileDirty(x, y);
1400 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
1406 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1408 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX_VAR, TILEY_VAR,
1412 void DrawFixedGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y,
1413 int graphic, int frame)
1418 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1420 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY,
1424 void DrawSizedGraphic(int x, int y, int graphic, int frame, int tilesize)
1426 DrawSizedGraphicExt(drawto, SX + x * tilesize, SY + y * tilesize, graphic,
1428 MarkTileDirty(x / tilesize, y / tilesize);
1431 void DrawSizedGraphicExt(DrawBuffer *d, int x, int y, int graphic, int frame,
1437 getSizedGraphicSource(graphic, frame, tilesize, &src_bitmap, &src_x, &src_y);
1438 BlitBitmap(src_bitmap, d, src_x, src_y, tilesize, tilesize, x, y);
1441 void DrawMiniGraphic(int x, int y, int graphic)
1443 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
1444 MarkTileDirty(x / 2, y / 2);
1447 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
1452 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1453 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
1456 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
1457 int graphic, int frame,
1458 int cut_mode, int mask_mode)
1463 int width = TILEX, height = TILEY;
1466 if (dx || dy) /* shifted graphic */
1468 if (x < BX1) /* object enters playfield from the left */
1475 else if (x > BX2) /* object enters playfield from the right */
1481 else if (x == BX1 && dx < 0) /* object leaves playfield to the left */
1487 else if (x == BX2 && dx > 0) /* object leaves playfield to the right */
1489 else if (dx) /* general horizontal movement */
1490 MarkTileDirty(x + SIGN(dx), y);
1492 if (y < BY1) /* object enters playfield from the top */
1494 if (cut_mode == CUT_BELOW) /* object completely above top border */
1502 else if (y > BY2) /* object enters playfield from the bottom */
1508 else if (y == BY1 && dy < 0) /* object leaves playfield to the top */
1514 else if (dy > 0 && cut_mode == CUT_ABOVE)
1516 if (y == BY2) /* object completely above bottom border */
1522 MarkTileDirty(x, y + 1);
1523 } /* object leaves playfield to the bottom */
1524 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1526 else if (dy) /* general vertical movement */
1527 MarkTileDirty(x, y + SIGN(dy));
1531 if (!IN_SCR_FIELD(x, y))
1533 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1534 printf("DrawGraphicShifted(): This should never happen!\n");
1539 width = width * TILESIZE_VAR / TILESIZE;
1540 height = height * TILESIZE_VAR / TILESIZE;
1541 cx = cx * TILESIZE_VAR / TILESIZE;
1542 cy = cy * TILESIZE_VAR / TILESIZE;
1543 dx = dx * TILESIZE_VAR / TILESIZE;
1544 dy = dy * TILESIZE_VAR / TILESIZE;
1546 if (width > 0 && height > 0)
1548 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1553 dst_x = FX + x * TILEX_VAR + dx;
1554 dst_y = FY + y * TILEY_VAR + dy;
1556 if (mask_mode == USE_MASKING)
1557 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1560 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1563 MarkTileDirty(x, y);
1567 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
1568 int graphic, int frame,
1569 int cut_mode, int mask_mode)
1574 int width = TILEX_VAR, height = TILEY_VAR;
1577 int x2 = x + SIGN(dx);
1578 int y2 = y + SIGN(dy);
1580 /* movement with two-tile animations must be sync'ed with movement position,
1581 not with current GfxFrame (which can be higher when using slow movement) */
1582 int anim_pos = (dx ? ABS(dx) : ABS(dy));
1583 int anim_frames = graphic_info[graphic].anim_frames;
1585 /* (we also need anim_delay here for movement animations with less frames) */
1586 int anim_delay = graphic_info[graphic].anim_delay;
1587 int sync_frame = anim_pos * anim_frames * anim_delay / TILESIZE;
1589 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
1590 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
1592 /* re-calculate animation frame for two-tile movement animation */
1593 frame = getGraphicAnimationFrame(graphic, sync_frame);
1595 /* check if movement start graphic inside screen area and should be drawn */
1596 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
1598 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
1600 dst_x = FX + x1 * TILEX_VAR;
1601 dst_y = FY + y1 * TILEY_VAR;
1603 if (mask_mode == USE_MASKING)
1604 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1607 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1610 MarkTileDirty(x1, y1);
1613 /* check if movement end graphic inside screen area and should be drawn */
1614 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
1616 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
1618 dst_x = FX + x2 * TILEX_VAR;
1619 dst_y = FY + y2 * TILEY_VAR;
1621 if (mask_mode == USE_MASKING)
1622 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1625 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1628 MarkTileDirty(x2, y2);
1632 static void DrawGraphicShifted(int x, int y, int dx, int dy,
1633 int graphic, int frame,
1634 int cut_mode, int mask_mode)
1638 DrawGraphic(x, y, graphic, frame);
1643 if (graphic_info[graphic].double_movement) /* EM style movement images */
1644 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1646 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1649 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1650 int frame, int cut_mode)
1652 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
1655 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1656 int cut_mode, int mask_mode)
1658 int lx = LEVELX(x), ly = LEVELY(y);
1662 if (IN_LEV_FIELD(lx, ly))
1664 SetRandomAnimationValue(lx, ly);
1666 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
1667 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1669 /* do not use double (EM style) movement graphic when not moving */
1670 if (graphic_info[graphic].double_movement && !dx && !dy)
1672 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
1673 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1676 else /* border element */
1678 graphic = el2img(element);
1679 frame = getGraphicAnimationFrame(graphic, -1);
1682 if (element == EL_EXPANDABLE_WALL)
1684 boolean left_stopped = FALSE, right_stopped = FALSE;
1686 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1687 left_stopped = TRUE;
1688 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1689 right_stopped = TRUE;
1691 if (left_stopped && right_stopped)
1693 else if (left_stopped)
1695 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1696 frame = graphic_info[graphic].anim_frames - 1;
1698 else if (right_stopped)
1700 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1701 frame = graphic_info[graphic].anim_frames - 1;
1706 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1707 else if (mask_mode == USE_MASKING)
1708 DrawGraphicThruMask(x, y, graphic, frame);
1710 DrawGraphic(x, y, graphic, frame);
1713 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1714 int cut_mode, int mask_mode)
1716 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1717 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1718 cut_mode, mask_mode);
1721 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1724 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1727 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1730 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1733 void DrawLevelElementThruMask(int x, int y, int element)
1735 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1738 void DrawLevelFieldThruMask(int x, int y)
1740 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1743 /* !!! implementation of quicksand is totally broken !!! */
1744 #define IS_CRUMBLED_TILE(x, y, e) \
1745 (GFX_CRUMBLED(e) && (!IN_LEV_FIELD(x, y) || \
1746 !IS_MOVING(x, y) || \
1747 (e) == EL_QUICKSAND_EMPTYING || \
1748 (e) == EL_QUICKSAND_FAST_EMPTYING))
1750 static void DrawLevelFieldCrumbledInnerCorners(int x, int y, int dx, int dy,
1755 int width, height, cx, cy;
1756 int sx = SCREENX(x), sy = SCREENY(y);
1757 int crumbled_border_size = graphic_info[graphic].border_size;
1760 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1762 for (i = 1; i < 4; i++)
1764 int dxx = (i & 1 ? dx : 0);
1765 int dyy = (i & 2 ? dy : 0);
1768 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1771 /* check if neighbour field is of same crumble type */
1772 boolean same = (IS_CRUMBLED_TILE(xx, yy, element) &&
1773 graphic_info[graphic].class ==
1774 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class);
1776 /* return if check prevents inner corner */
1777 if (same == (dxx == dx && dyy == dy))
1781 /* if we reach this point, we have an inner corner */
1783 getGraphicSource(graphic, 1, &src_bitmap, &src_x, &src_y);
1785 width = crumbled_border_size * TILESIZE_VAR / TILESIZE;
1786 height = crumbled_border_size * TILESIZE_VAR / TILESIZE;
1787 cx = (dx > 0 ? TILESIZE_VAR - width : 0);
1788 cy = (dy > 0 ? TILESIZE_VAR - height : 0);
1790 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1791 width, height, FX + sx * TILEX_VAR + cx, FY + sy * TILEY_VAR + cy);
1794 static void DrawLevelFieldCrumbledBorders(int x, int y, int graphic, int frame,
1799 int width, height, bx, by, cx, cy;
1800 int sx = SCREENX(x), sy = SCREENY(y);
1801 int crumbled_border_size = graphic_info[graphic].border_size;
1802 int crumbled_border_size_var = crumbled_border_size * TILESIZE_VAR / TILESIZE;
1803 int crumbled_border_pos_var = TILESIZE_VAR - crumbled_border_size_var;
1806 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1808 /* draw simple, sloppy, non-corner-accurate crumbled border */
1810 width = (dir == 1 || dir == 2 ? crumbled_border_size_var : TILESIZE_VAR);
1811 height = (dir == 0 || dir == 3 ? crumbled_border_size_var : TILESIZE_VAR);
1812 cx = (dir == 2 ? crumbled_border_pos_var : 0);
1813 cy = (dir == 3 ? crumbled_border_pos_var : 0);
1815 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy, width, height,
1816 FX + sx * TILEX_VAR + cx,
1817 FY + sy * TILEY_VAR + cy);
1819 /* (remaining middle border part must be at least as big as corner part) */
1820 if (!(graphic_info[graphic].style & STYLE_ACCURATE_BORDERS) ||
1821 crumbled_border_size >= TILESIZE / 3)
1824 /* correct corners of crumbled border, if needed */
1826 for (i = -1; i <= 1; i += 2)
1828 int xx = x + (dir == 0 || dir == 3 ? i : 0);
1829 int yy = y + (dir == 1 || dir == 2 ? i : 0);
1830 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1833 /* check if neighbour field is of same crumble type */
1834 if (IS_CRUMBLED_TILE(xx, yy, element) &&
1835 graphic_info[graphic].class ==
1836 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1838 /* no crumbled corner, but continued crumbled border */
1840 int c1 = (dir == 2 || dir == 3 ? crumbled_border_pos_var : 0);
1841 int c2 = (i == 1 ? crumbled_border_pos_var : 0);
1842 int b1 = (i == 1 ? crumbled_border_size_var :
1843 TILESIZE_VAR - 2 * crumbled_border_size_var);
1845 width = crumbled_border_size_var;
1846 height = crumbled_border_size_var;
1848 if (dir == 1 || dir == 2)
1863 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
1865 FX + sx * TILEX_VAR + cx,
1866 FY + sy * TILEY_VAR + cy);
1871 static void DrawLevelFieldCrumbledExt(int x, int y, int graphic, int frame)
1873 int sx = SCREENX(x), sy = SCREENY(y);
1876 static int xy[4][2] =
1884 if (!IN_LEV_FIELD(x, y))
1887 element = TILE_GFX_ELEMENT(x, y);
1889 /* crumble field itself */
1890 if (IS_CRUMBLED_TILE(x, y, element))
1892 if (!IN_SCR_FIELD(sx, sy))
1895 for (i = 0; i < 4; i++)
1897 int xx = x + xy[i][0];
1898 int yy = y + xy[i][1];
1900 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1903 /* check if neighbour field is of same crumble type */
1904 if (IS_CRUMBLED_TILE(xx, yy, element) &&
1905 graphic_info[graphic].class ==
1906 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1909 DrawLevelFieldCrumbledBorders(x, y, graphic, frame, i);
1912 if ((graphic_info[graphic].style & STYLE_INNER_CORNERS) &&
1913 graphic_info[graphic].anim_frames == 2)
1915 for (i = 0; i < 4; i++)
1917 int dx = (i & 1 ? +1 : -1);
1918 int dy = (i & 2 ? +1 : -1);
1920 DrawLevelFieldCrumbledInnerCorners(x, y, dx, dy, graphic);
1924 MarkTileDirty(sx, sy);
1926 else /* center field not crumbled -- crumble neighbour fields */
1928 for (i = 0; i < 4; i++)
1930 int xx = x + xy[i][0];
1931 int yy = y + xy[i][1];
1932 int sxx = sx + xy[i][0];
1933 int syy = sy + xy[i][1];
1935 if (!IN_LEV_FIELD(xx, yy) ||
1936 !IN_SCR_FIELD(sxx, syy))
1939 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
1942 element = TILE_GFX_ELEMENT(xx, yy);
1944 if (!IS_CRUMBLED_TILE(xx, yy, element))
1947 graphic = el_act2crm(element, ACTION_DEFAULT);
1949 DrawLevelFieldCrumbledBorders(xx, yy, graphic, 0, 3 - i);
1951 MarkTileDirty(sxx, syy);
1956 void DrawLevelFieldCrumbled(int x, int y)
1960 if (!IN_LEV_FIELD(x, y))
1963 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1964 GfxElement[x][y] != EL_UNDEFINED &&
1965 GFX_CRUMBLED(GfxElement[x][y]))
1967 DrawLevelFieldCrumbledDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
1972 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
1974 DrawLevelFieldCrumbledExt(x, y, graphic, 0);
1977 void DrawLevelFieldCrumbledDigging(int x, int y, int direction,
1980 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1981 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1982 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1983 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1984 int sx = SCREENX(x), sy = SCREENY(y);
1986 DrawGraphic(sx, sy, graphic1, frame1);
1987 DrawLevelFieldCrumbledExt(x, y, graphic2, frame2);
1990 void DrawLevelFieldCrumbledNeighbours(int x, int y)
1992 int sx = SCREENX(x), sy = SCREENY(y);
1993 static int xy[4][2] =
2002 for (i = 0; i < 4; i++)
2004 int xx = x + xy[i][0];
2005 int yy = y + xy[i][1];
2006 int sxx = sx + xy[i][0];
2007 int syy = sy + xy[i][1];
2009 if (!IN_LEV_FIELD(xx, yy) ||
2010 !IN_SCR_FIELD(sxx, syy) ||
2011 !GFX_CRUMBLED(Feld[xx][yy]) ||
2015 DrawLevelField(xx, yy);
2019 static int getBorderElement(int x, int y)
2023 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
2024 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
2025 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
2026 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
2027 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
2028 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
2029 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
2031 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
2032 int steel_position = (x == -1 && y == -1 ? 0 :
2033 x == lev_fieldx && y == -1 ? 1 :
2034 x == -1 && y == lev_fieldy ? 2 :
2035 x == lev_fieldx && y == lev_fieldy ? 3 :
2036 x == -1 || x == lev_fieldx ? 4 :
2037 y == -1 || y == lev_fieldy ? 5 : 6);
2039 return border[steel_position][steel_type];
2042 void DrawScreenElement(int x, int y, int element)
2044 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
2045 DrawLevelFieldCrumbled(LEVELX(x), LEVELY(y));
2048 void DrawLevelElement(int x, int y, int element)
2050 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2051 DrawScreenElement(SCREENX(x), SCREENY(y), element);
2054 void DrawScreenField(int x, int y)
2056 int lx = LEVELX(x), ly = LEVELY(y);
2057 int element, content;
2059 if (!IN_LEV_FIELD(lx, ly))
2061 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
2064 element = getBorderElement(lx, ly);
2066 DrawScreenElement(x, y, element);
2071 element = Feld[lx][ly];
2072 content = Store[lx][ly];
2074 if (IS_MOVING(lx, ly))
2076 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
2077 boolean cut_mode = NO_CUTTING;
2079 if (element == EL_QUICKSAND_EMPTYING ||
2080 element == EL_QUICKSAND_FAST_EMPTYING ||
2081 element == EL_MAGIC_WALL_EMPTYING ||
2082 element == EL_BD_MAGIC_WALL_EMPTYING ||
2083 element == EL_DC_MAGIC_WALL_EMPTYING ||
2084 element == EL_AMOEBA_DROPPING)
2085 cut_mode = CUT_ABOVE;
2086 else if (element == EL_QUICKSAND_FILLING ||
2087 element == EL_QUICKSAND_FAST_FILLING ||
2088 element == EL_MAGIC_WALL_FILLING ||
2089 element == EL_BD_MAGIC_WALL_FILLING ||
2090 element == EL_DC_MAGIC_WALL_FILLING)
2091 cut_mode = CUT_BELOW;
2093 if (cut_mode == CUT_ABOVE)
2094 DrawScreenElement(x, y, element);
2096 DrawScreenElement(x, y, EL_EMPTY);
2099 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
2100 else if (cut_mode == NO_CUTTING)
2101 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
2104 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
2106 if (cut_mode == CUT_BELOW &&
2107 IN_LEV_FIELD(lx, ly + 1) && IN_SCR_FIELD(x, y + 1))
2108 DrawLevelElement(lx, ly + 1, element);
2111 if (content == EL_ACID)
2113 int dir = MovDir[lx][ly];
2114 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
2115 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
2117 DrawLevelElementThruMask(newlx, newly, EL_ACID);
2120 else if (IS_BLOCKED(lx, ly))
2125 boolean cut_mode = NO_CUTTING;
2126 int element_old, content_old;
2128 Blocked2Moving(lx, ly, &oldx, &oldy);
2131 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
2132 MovDir[oldx][oldy] == MV_RIGHT);
2134 element_old = Feld[oldx][oldy];
2135 content_old = Store[oldx][oldy];
2137 if (element_old == EL_QUICKSAND_EMPTYING ||
2138 element_old == EL_QUICKSAND_FAST_EMPTYING ||
2139 element_old == EL_MAGIC_WALL_EMPTYING ||
2140 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
2141 element_old == EL_DC_MAGIC_WALL_EMPTYING ||
2142 element_old == EL_AMOEBA_DROPPING)
2143 cut_mode = CUT_ABOVE;
2145 DrawScreenElement(x, y, EL_EMPTY);
2148 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
2150 else if (cut_mode == NO_CUTTING)
2151 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
2154 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
2157 else if (IS_DRAWABLE(element))
2158 DrawScreenElement(x, y, element);
2160 DrawScreenElement(x, y, EL_EMPTY);
2163 void DrawLevelField(int x, int y)
2165 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2166 DrawScreenField(SCREENX(x), SCREENY(y));
2167 else if (IS_MOVING(x, y))
2171 Moving2Blocked(x, y, &newx, &newy);
2172 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
2173 DrawScreenField(SCREENX(newx), SCREENY(newy));
2175 else if (IS_BLOCKED(x, y))
2179 Blocked2Moving(x, y, &oldx, &oldy);
2180 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
2181 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
2185 void DrawSizedElement(int x, int y, int element, int tilesize)
2189 graphic = el2edimg(element);
2190 DrawSizedGraphic(x, y, graphic, 0, tilesize);
2193 void DrawMiniElement(int x, int y, int element)
2197 graphic = el2edimg(element);
2198 DrawMiniGraphic(x, y, graphic);
2201 void DrawSizedElementOrWall(int sx, int sy, int scroll_x, int scroll_y,
2204 int x = sx + scroll_x, y = sy + scroll_y;
2206 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
2207 DrawSizedElement(sx, sy, EL_EMPTY, tilesize);
2208 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
2209 DrawSizedElement(sx, sy, Feld[x][y], tilesize);
2211 DrawSizedGraphic(sx, sy, el2edimg(getBorderElement(x, y)), 0, tilesize);
2214 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
2216 int x = sx + scroll_x, y = sy + scroll_y;
2218 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
2219 DrawMiniElement(sx, sy, EL_EMPTY);
2220 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
2221 DrawMiniElement(sx, sy, Feld[x][y]);
2223 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
2226 void DrawEnvelopeBackgroundTiles(int graphic, int startx, int starty,
2227 int x, int y, int xsize, int ysize,
2228 int tile_width, int tile_height)
2232 int dst_x = startx + x * tile_width;
2233 int dst_y = starty + y * tile_height;
2234 int width = graphic_info[graphic].width;
2235 int height = graphic_info[graphic].height;
2236 int inner_width_raw = MAX(width - 2 * tile_width, tile_width);
2237 int inner_height_raw = MAX(height - 2 * tile_height, tile_height);
2238 int inner_width = inner_width_raw - (inner_width_raw % tile_width);
2239 int inner_height = inner_height_raw - (inner_height_raw % tile_height);
2240 int inner_sx = (width >= 3 * tile_width ? tile_width : 0);
2241 int inner_sy = (height >= 3 * tile_height ? tile_height : 0);
2242 boolean draw_masked = graphic_info[graphic].draw_masked;
2244 getFixedGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
2246 if (src_bitmap == NULL || width < tile_width || height < tile_height)
2248 ClearRectangle(drawto, dst_x, dst_y, tile_width, tile_height);
2252 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - tile_width :
2253 inner_sx + (x - 1) * tile_width % inner_width);
2254 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - tile_height :
2255 inner_sy + (y - 1) * tile_height % inner_height);
2258 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
2261 BlitBitmap(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
2265 void DrawEnvelopeBackground(int graphic, int startx, int starty,
2266 int x, int y, int xsize, int ysize, int font_nr)
2268 int font_width = getFontWidth(font_nr);
2269 int font_height = getFontHeight(font_nr);
2271 DrawEnvelopeBackgroundTiles(graphic, startx, starty, x, y, xsize, ysize,
2272 font_width, font_height);
2275 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
2277 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2278 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2279 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2280 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2281 boolean no_delay = (tape.warp_forward);
2282 unsigned int anim_delay = 0;
2283 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
2284 int anim_delay_value = (no_delay ? 0 : frame_delay_value) / 2;
2285 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
2286 int font_width = getFontWidth(font_nr);
2287 int font_height = getFontHeight(font_nr);
2288 int max_xsize = level.envelope[envelope_nr].xsize;
2289 int max_ysize = level.envelope[envelope_nr].ysize;
2290 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
2291 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
2292 int xend = max_xsize;
2293 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
2294 int xstep = (xstart < xend ? 1 : 0);
2295 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2297 int end = MAX(xend - xstart, yend - ystart);
2300 for (i = start; i <= end; i++)
2302 int last_frame = end; // last frame of this "for" loop
2303 int x = xstart + i * xstep;
2304 int y = ystart + i * ystep;
2305 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2306 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2307 int sx = SX + (SXSIZE - xsize * font_width) / 2;
2308 int sy = SY + (SYSIZE - ysize * font_height) / 2;
2311 SetDrawtoField(DRAW_TO_FIELDBUFFER);
2313 BlitScreenToBitmap(backbuffer);
2315 SetDrawtoField(DRAW_TO_BACKBUFFER);
2317 for (yy = 0; yy < ysize; yy++)
2318 for (xx = 0; xx < xsize; xx++)
2319 DrawEnvelopeBackground(graphic, sx, sy, xx, yy, xsize, ysize, font_nr);
2321 DrawTextBuffer(sx + font_width, sy + font_height,
2322 level.envelope[envelope_nr].text, font_nr, max_xsize,
2323 xsize - 2, ysize - 2, 0, mask_mode,
2324 level.envelope[envelope_nr].autowrap,
2325 level.envelope[envelope_nr].centered, FALSE);
2327 redraw_mask |= REDRAW_FIELD;
2330 SkipUntilDelayReached(&anim_delay, anim_delay_value, &i, last_frame);
2334 void ShowEnvelope(int envelope_nr)
2336 int element = EL_ENVELOPE_1 + envelope_nr;
2337 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2338 int sound_opening = element_info[element].sound[ACTION_OPENING];
2339 int sound_closing = element_info[element].sound[ACTION_CLOSING];
2340 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2341 boolean no_delay = (tape.warp_forward);
2342 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
2343 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
2344 int anim_mode = graphic_info[graphic].anim_mode;
2345 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2346 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2348 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
2350 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2352 if (anim_mode == ANIM_DEFAULT)
2353 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
2355 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
2358 Delay(wait_delay_value);
2360 WaitForEventToContinue();
2362 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2364 if (anim_mode != ANIM_NONE)
2365 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
2367 if (anim_mode == ANIM_DEFAULT)
2368 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
2370 game.envelope_active = FALSE;
2372 SetDrawtoField(DRAW_TO_FIELDBUFFER);
2374 redraw_mask |= REDRAW_FIELD;
2378 static void setRequestBasePosition(int *x, int *y)
2380 int sx_base, sy_base;
2382 if (request.x != -1)
2383 sx_base = request.x;
2384 else if (request.align == ALIGN_LEFT)
2386 else if (request.align == ALIGN_RIGHT)
2387 sx_base = SX + SXSIZE;
2389 sx_base = SX + SXSIZE / 2;
2391 if (request.y != -1)
2392 sy_base = request.y;
2393 else if (request.valign == VALIGN_TOP)
2395 else if (request.valign == VALIGN_BOTTOM)
2396 sy_base = SY + SYSIZE;
2398 sy_base = SY + SYSIZE / 2;
2404 static void setRequestPositionExt(int *x, int *y, int width, int height,
2405 boolean add_border_size)
2407 int border_size = request.border_size;
2408 int sx_base, sy_base;
2411 setRequestBasePosition(&sx_base, &sy_base);
2413 if (request.align == ALIGN_LEFT)
2415 else if (request.align == ALIGN_RIGHT)
2416 sx = sx_base - width;
2418 sx = sx_base - width / 2;
2420 if (request.valign == VALIGN_TOP)
2422 else if (request.valign == VALIGN_BOTTOM)
2423 sy = sy_base - height;
2425 sy = sy_base - height / 2;
2427 sx = MAX(0, MIN(sx, WIN_XSIZE - width));
2428 sy = MAX(0, MIN(sy, WIN_YSIZE - height));
2430 if (add_border_size)
2440 static void setRequestPosition(int *x, int *y, boolean add_border_size)
2442 setRequestPositionExt(x, y, request.width, request.height, add_border_size);
2445 void DrawEnvelopeRequest(char *text)
2447 char *text_final = text;
2448 char *text_door_style = NULL;
2449 int graphic = IMG_BACKGROUND_REQUEST;
2450 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2451 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2452 int font_nr = FONT_REQUEST;
2453 int font_width = getFontWidth(font_nr);
2454 int font_height = getFontHeight(font_nr);
2455 int border_size = request.border_size;
2456 int line_spacing = request.line_spacing;
2457 int line_height = font_height + line_spacing;
2458 int max_text_width = request.width - 2 * border_size;
2459 int max_text_height = request.height - 2 * border_size;
2460 int line_length = max_text_width / font_width;
2461 int max_lines = max_text_height / line_height;
2462 int text_width = line_length * font_width;
2463 int width = request.width;
2464 int height = request.height;
2465 int tile_size = MAX(request.step_offset, 1);
2466 int x_steps = width / tile_size;
2467 int y_steps = height / tile_size;
2468 int sx_offset = border_size;
2469 int sy_offset = border_size;
2473 if (request.centered)
2474 sx_offset = (request.width - text_width) / 2;
2476 if (request.wrap_single_words && !request.autowrap)
2478 char *src_text_ptr, *dst_text_ptr;
2480 text_door_style = checked_malloc(2 * strlen(text) + 1);
2482 src_text_ptr = text;
2483 dst_text_ptr = text_door_style;
2485 while (*src_text_ptr)
2487 if (*src_text_ptr == ' ' ||
2488 *src_text_ptr == '?' ||
2489 *src_text_ptr == '!')
2490 *dst_text_ptr++ = '\n';
2492 if (*src_text_ptr != ' ')
2493 *dst_text_ptr++ = *src_text_ptr;
2498 *dst_text_ptr = '\0';
2500 text_final = text_door_style;
2503 setRequestPosition(&sx, &sy, FALSE);
2505 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
2507 for (y = 0; y < y_steps; y++)
2508 for (x = 0; x < x_steps; x++)
2509 DrawEnvelopeBackgroundTiles(graphic, sx, sy,
2510 x, y, x_steps, y_steps,
2511 tile_size, tile_size);
2513 /* force DOOR font inside door area */
2514 SetFontStatus(GAME_MODE_PSEUDO_DOOR);
2516 DrawTextBuffer(sx + sx_offset, sy + sy_offset, text_final, font_nr,
2517 line_length, -1, max_lines, line_spacing, mask_mode,
2518 request.autowrap, request.centered, FALSE);
2522 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2523 RedrawGadget(tool_gadget[i]);
2525 // store readily prepared envelope request for later use when animating
2526 BlitBitmap(backbuffer, bitmap_db_store_2, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2528 if (text_door_style)
2529 free(text_door_style);
2532 void AnimateEnvelopeRequest(int anim_mode, int action)
2534 int graphic = IMG_BACKGROUND_REQUEST;
2535 boolean draw_masked = graphic_info[graphic].draw_masked;
2536 int delay_value_normal = request.step_delay;
2537 int delay_value_fast = delay_value_normal / 2;
2538 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2539 boolean no_delay = (tape.warp_forward);
2540 int delay_value = (ffwd_delay ? delay_value_fast : delay_value_normal);
2541 int anim_delay_value = (no_delay ? 0 : delay_value + 500 * 0) / 2;
2542 unsigned int anim_delay = 0;
2544 int tile_size = MAX(request.step_offset, 1);
2545 int max_xsize = request.width / tile_size;
2546 int max_ysize = request.height / tile_size;
2547 int max_xsize_inner = max_xsize - 2;
2548 int max_ysize_inner = max_ysize - 2;
2550 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize_inner : 0);
2551 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize_inner : 0);
2552 int xend = max_xsize_inner;
2553 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize_inner : 0);
2554 int xstep = (xstart < xend ? 1 : 0);
2555 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2557 int end = MAX(xend - xstart, yend - ystart);
2560 if (setup.quick_doors)
2567 for (i = start; i <= end; i++)
2569 int last_frame = end; // last frame of this "for" loop
2570 int x = xstart + i * xstep;
2571 int y = ystart + i * ystep;
2572 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2573 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2574 int xsize_size_left = (xsize - 1) * tile_size;
2575 int ysize_size_top = (ysize - 1) * tile_size;
2576 int max_xsize_pos = (max_xsize - 1) * tile_size;
2577 int max_ysize_pos = (max_ysize - 1) * tile_size;
2578 int width = xsize * tile_size;
2579 int height = ysize * tile_size;
2584 setRequestPosition(&src_x, &src_y, FALSE);
2585 setRequestPositionExt(&dst_x, &dst_y, width, height, FALSE);
2587 BlitBitmap(bitmap_db_store_1, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2589 for (yy = 0; yy < 2; yy++)
2591 for (xx = 0; xx < 2; xx++)
2593 int src_xx = src_x + xx * max_xsize_pos;
2594 int src_yy = src_y + yy * max_ysize_pos;
2595 int dst_xx = dst_x + xx * xsize_size_left;
2596 int dst_yy = dst_y + yy * ysize_size_top;
2597 int xx_size = (xx ? tile_size : xsize_size_left);
2598 int yy_size = (yy ? tile_size : ysize_size_top);
2601 BlitBitmapMasked(bitmap_db_store_2, backbuffer,
2602 src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
2604 BlitBitmap(bitmap_db_store_2, backbuffer,
2605 src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
2609 redraw_mask |= REDRAW_FIELD;
2613 SkipUntilDelayReached(&anim_delay, anim_delay_value, &i, last_frame);
2617 void ShowEnvelopeRequest(char *text, unsigned int req_state, int action)
2619 int graphic = IMG_BACKGROUND_REQUEST;
2620 int sound_opening = SND_REQUEST_OPENING;
2621 int sound_closing = SND_REQUEST_CLOSING;
2622 int anim_mode_1 = request.anim_mode; /* (higher priority) */
2623 int anim_mode_2 = graphic_info[graphic].anim_mode; /* (lower priority) */
2624 int anim_mode = (anim_mode_1 != ANIM_DEFAULT ? anim_mode_1 : anim_mode_2);
2625 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2626 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2628 if (game_status == GAME_MODE_PLAYING)
2629 BlitScreenToBitmap(backbuffer);
2631 SetDrawtoField(DRAW_TO_BACKBUFFER);
2633 // SetDrawBackgroundMask(REDRAW_NONE);
2635 if (action == ACTION_OPENING)
2637 BlitBitmap(backbuffer, bitmap_db_store_1, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2639 if (req_state & REQ_ASK)
2641 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2642 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2644 else if (req_state & REQ_CONFIRM)
2646 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2648 else if (req_state & REQ_PLAYER)
2650 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2651 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2652 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2653 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2656 DrawEnvelopeRequest(text);
2659 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
2661 if (action == ACTION_OPENING)
2663 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2665 if (anim_mode == ANIM_DEFAULT)
2666 AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_OPENING);
2668 AnimateEnvelopeRequest(main_anim_mode, ACTION_OPENING);
2672 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2674 if (anim_mode != ANIM_NONE)
2675 AnimateEnvelopeRequest(main_anim_mode, ACTION_CLOSING);
2677 if (anim_mode == ANIM_DEFAULT)
2678 AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_CLOSING);
2681 game.envelope_active = FALSE;
2683 if (action == ACTION_CLOSING)
2684 BlitBitmap(bitmap_db_store_1, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2686 // SetDrawBackgroundMask(last_draw_background_mask);
2688 redraw_mask |= REDRAW_FIELD;
2692 if (action == ACTION_CLOSING &&
2693 game_status == GAME_MODE_PLAYING &&
2694 level.game_engine_type == GAME_ENGINE_TYPE_RND)
2695 SetDrawtoField(DRAW_TO_FIELDBUFFER);
2698 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
2702 int graphic = el2preimg(element);
2704 getSizedGraphicSource(graphic, 0, tilesize, &src_bitmap, &src_x, &src_y);
2705 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
2708 void DrawLevel(int draw_background_mask)
2712 SetMainBackgroundImage(IMG_BACKGROUND_PLAYING);
2713 SetDrawBackgroundMask(draw_background_mask);
2717 for (x = BX1; x <= BX2; x++)
2718 for (y = BY1; y <= BY2; y++)
2719 DrawScreenField(x, y);
2721 redraw_mask |= REDRAW_FIELD;
2724 void DrawSizedLevel(int size_x, int size_y, int scroll_x, int scroll_y,
2729 for (x = 0; x < size_x; x++)
2730 for (y = 0; y < size_y; y++)
2731 DrawSizedElementOrWall(x, y, scroll_x, scroll_y, tilesize);
2733 redraw_mask |= REDRAW_FIELD;
2736 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
2740 for (x = 0; x < size_x; x++)
2741 for (y = 0; y < size_y; y++)
2742 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
2744 redraw_mask |= REDRAW_FIELD;
2747 static void DrawPreviewLevelPlayfieldExt(int from_x, int from_y)
2749 boolean show_level_border = (BorderElement != EL_EMPTY);
2750 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2751 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2752 int tile_size = preview.tile_size;
2753 int preview_width = preview.xsize * tile_size;
2754 int preview_height = preview.ysize * tile_size;
2755 int real_preview_xsize = MIN(level_xsize, preview.xsize);
2756 int real_preview_ysize = MIN(level_ysize, preview.ysize);
2757 int real_preview_width = real_preview_xsize * tile_size;
2758 int real_preview_height = real_preview_ysize * tile_size;
2759 int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
2760 int dst_y = SY + ALIGNED_YPOS(preview.y, preview_height, preview.valign);
2763 if (!IN_GFX_FIELD_FULL(dst_x, dst_y + preview_height - 1))
2766 DrawBackground(dst_x, dst_y, preview_width, preview_height);
2768 dst_x += (preview_width - real_preview_width) / 2;
2769 dst_y += (preview_height - real_preview_height) / 2;
2771 for (x = 0; x < real_preview_xsize; x++)
2773 for (y = 0; y < real_preview_ysize; y++)
2775 int lx = from_x + x + (show_level_border ? -1 : 0);
2776 int ly = from_y + y + (show_level_border ? -1 : 0);
2777 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
2778 getBorderElement(lx, ly));
2780 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
2781 element, tile_size);
2785 redraw_mask |= REDRAW_FIELD;
2788 #define MICROLABEL_EMPTY 0
2789 #define MICROLABEL_LEVEL_NAME 1
2790 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
2791 #define MICROLABEL_LEVEL_AUTHOR 3
2792 #define MICROLABEL_IMPORTED_FROM_HEAD 4
2793 #define MICROLABEL_IMPORTED_FROM 5
2794 #define MICROLABEL_IMPORTED_BY_HEAD 6
2795 #define MICROLABEL_IMPORTED_BY 7
2797 static int getMaxTextLength(struct TextPosInfo *pos, int font_nr)
2799 int max_text_width = SXSIZE;
2800 int font_width = getFontWidth(font_nr);
2802 if (pos->align == ALIGN_CENTER)
2803 max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
2804 else if (pos->align == ALIGN_RIGHT)
2805 max_text_width = pos->x;
2807 max_text_width = SXSIZE - pos->x;
2809 return max_text_width / font_width;
2812 static void DrawPreviewLevelLabelExt(int mode)
2814 struct TextPosInfo *pos = &menu.main.text.level_info_2;
2815 char label_text[MAX_OUTPUT_LINESIZE + 1];
2816 int max_len_label_text;
2817 int font_nr = pos->font;
2820 if (!IN_GFX_FIELD_FULL(pos->x, pos->y + getFontHeight(pos->font)))
2823 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
2824 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
2825 mode == MICROLABEL_IMPORTED_BY_HEAD)
2826 font_nr = pos->font_alt;
2828 max_len_label_text = getMaxTextLength(pos, font_nr);
2830 if (pos->size != -1)
2831 max_len_label_text = pos->size;
2833 for (i = 0; i < max_len_label_text; i++)
2834 label_text[i] = ' ';
2835 label_text[max_len_label_text] = '\0';
2837 if (strlen(label_text) > 0)
2838 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2841 (mode == MICROLABEL_LEVEL_NAME ? level.name :
2842 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
2843 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
2844 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
2845 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
2846 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
2847 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
2848 max_len_label_text);
2849 label_text[max_len_label_text] = '\0';
2851 if (strlen(label_text) > 0)
2852 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2854 redraw_mask |= REDRAW_FIELD;
2857 static void DrawPreviewLevelExt(boolean restart)
2859 static unsigned int scroll_delay = 0;
2860 static unsigned int label_delay = 0;
2861 static int from_x, from_y, scroll_direction;
2862 static int label_state, label_counter;
2863 unsigned int scroll_delay_value = preview.step_delay;
2864 boolean show_level_border = (BorderElement != EL_EMPTY);
2865 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2866 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2873 if (preview.anim_mode == ANIM_CENTERED)
2875 if (level_xsize > preview.xsize)
2876 from_x = (level_xsize - preview.xsize) / 2;
2877 if (level_ysize > preview.ysize)
2878 from_y = (level_ysize - preview.ysize) / 2;
2881 from_x += preview.xoffset;
2882 from_y += preview.yoffset;
2884 scroll_direction = MV_RIGHT;
2888 DrawPreviewLevelPlayfieldExt(from_x, from_y);
2889 DrawPreviewLevelLabelExt(label_state);
2891 /* initialize delay counters */
2892 DelayReached(&scroll_delay, 0);
2893 DelayReached(&label_delay, 0);
2895 if (leveldir_current->name)
2897 struct TextPosInfo *pos = &menu.main.text.level_info_1;
2898 char label_text[MAX_OUTPUT_LINESIZE + 1];
2899 int font_nr = pos->font;
2900 int max_len_label_text = getMaxTextLength(pos, font_nr);
2902 if (pos->size != -1)
2903 max_len_label_text = pos->size;
2905 strncpy(label_text, leveldir_current->name, max_len_label_text);
2906 label_text[max_len_label_text] = '\0';
2908 if (IN_GFX_FIELD_FULL(pos->x, pos->y + getFontHeight(pos->font)))
2909 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2915 /* scroll preview level, if needed */
2916 if (preview.anim_mode != ANIM_NONE &&
2917 (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
2918 DelayReached(&scroll_delay, scroll_delay_value))
2920 switch (scroll_direction)
2925 from_x -= preview.step_offset;
2926 from_x = (from_x < 0 ? 0 : from_x);
2929 scroll_direction = MV_UP;
2933 if (from_x < level_xsize - preview.xsize)
2935 from_x += preview.step_offset;
2936 from_x = (from_x > level_xsize - preview.xsize ?
2937 level_xsize - preview.xsize : from_x);
2940 scroll_direction = MV_DOWN;
2946 from_y -= preview.step_offset;
2947 from_y = (from_y < 0 ? 0 : from_y);
2950 scroll_direction = MV_RIGHT;
2954 if (from_y < level_ysize - preview.ysize)
2956 from_y += preview.step_offset;
2957 from_y = (from_y > level_ysize - preview.ysize ?
2958 level_ysize - preview.ysize : from_y);
2961 scroll_direction = MV_LEFT;
2968 DrawPreviewLevelPlayfieldExt(from_x, from_y);
2971 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
2972 /* redraw micro level label, if needed */
2973 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
2974 !strEqual(level.author, ANONYMOUS_NAME) &&
2975 !strEqual(level.author, leveldir_current->name) &&
2976 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
2978 int max_label_counter = 23;
2980 if (leveldir_current->imported_from != NULL &&
2981 strlen(leveldir_current->imported_from) > 0)
2982 max_label_counter += 14;
2983 if (leveldir_current->imported_by != NULL &&
2984 strlen(leveldir_current->imported_by) > 0)
2985 max_label_counter += 14;
2987 label_counter = (label_counter + 1) % max_label_counter;
2988 label_state = (label_counter >= 0 && label_counter <= 7 ?
2989 MICROLABEL_LEVEL_NAME :
2990 label_counter >= 9 && label_counter <= 12 ?
2991 MICROLABEL_LEVEL_AUTHOR_HEAD :
2992 label_counter >= 14 && label_counter <= 21 ?
2993 MICROLABEL_LEVEL_AUTHOR :
2994 label_counter >= 23 && label_counter <= 26 ?
2995 MICROLABEL_IMPORTED_FROM_HEAD :
2996 label_counter >= 28 && label_counter <= 35 ?
2997 MICROLABEL_IMPORTED_FROM :
2998 label_counter >= 37 && label_counter <= 40 ?
2999 MICROLABEL_IMPORTED_BY_HEAD :
3000 label_counter >= 42 && label_counter <= 49 ?
3001 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
3003 if (leveldir_current->imported_from == NULL &&
3004 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
3005 label_state == MICROLABEL_IMPORTED_FROM))
3006 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
3007 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
3009 DrawPreviewLevelLabelExt(label_state);
3013 void DrawPreviewLevelInitial()
3015 DrawPreviewLevelExt(TRUE);
3018 void DrawPreviewLevelAnimation()
3020 DrawPreviewLevelExt(FALSE);
3023 inline static void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
3024 int graphic, int sync_frame,
3027 int frame = getGraphicAnimationFrame(graphic, sync_frame);
3029 if (mask_mode == USE_MASKING)
3030 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
3032 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
3035 void DrawFixedGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
3036 int graphic, int sync_frame, int mask_mode)
3038 int frame = getGraphicAnimationFrame(graphic, sync_frame);
3040 if (mask_mode == USE_MASKING)
3041 DrawFixedGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
3043 DrawFixedGraphicExt(dst_bitmap, x, y, graphic, frame);
3046 inline static void DrawGraphicAnimation(int x, int y, int graphic)
3048 int lx = LEVELX(x), ly = LEVELY(y);
3050 if (!IN_SCR_FIELD(x, y))
3053 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
3054 graphic, GfxFrame[lx][ly], NO_MASKING);
3056 MarkTileDirty(x, y);
3059 void DrawFixedGraphicAnimation(int x, int y, int graphic)
3061 int lx = LEVELX(x), ly = LEVELY(y);
3063 if (!IN_SCR_FIELD(x, y))
3066 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
3067 graphic, GfxFrame[lx][ly], NO_MASKING);
3068 MarkTileDirty(x, y);
3071 void DrawLevelGraphicAnimation(int x, int y, int graphic)
3073 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
3076 void DrawLevelElementAnimation(int x, int y, int element)
3078 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
3080 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
3083 void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
3085 int sx = SCREENX(x), sy = SCREENY(y);
3087 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
3090 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
3093 DrawGraphicAnimation(sx, sy, graphic);
3096 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
3097 DrawLevelFieldCrumbled(x, y);
3099 if (GFX_CRUMBLED(Feld[x][y]))
3100 DrawLevelFieldCrumbled(x, y);
3104 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
3106 int sx = SCREENX(x), sy = SCREENY(y);
3109 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
3112 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
3114 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
3117 DrawGraphicAnimation(sx, sy, graphic);
3119 if (GFX_CRUMBLED(element))
3120 DrawLevelFieldCrumbled(x, y);
3123 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
3125 if (player->use_murphy)
3127 /* this works only because currently only one player can be "murphy" ... */
3128 static int last_horizontal_dir = MV_LEFT;
3129 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
3131 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3132 last_horizontal_dir = move_dir;
3134 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
3136 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
3138 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
3144 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
3147 static boolean equalGraphics(int graphic1, int graphic2)
3149 struct GraphicInfo *g1 = &graphic_info[graphic1];
3150 struct GraphicInfo *g2 = &graphic_info[graphic2];
3152 return (g1->bitmap == g2->bitmap &&
3153 g1->src_x == g2->src_x &&
3154 g1->src_y == g2->src_y &&
3155 g1->anim_frames == g2->anim_frames &&
3156 g1->anim_delay == g2->anim_delay &&
3157 g1->anim_mode == g2->anim_mode);
3160 void DrawAllPlayers()
3164 for (i = 0; i < MAX_PLAYERS; i++)
3165 if (stored_player[i].active)
3166 DrawPlayer(&stored_player[i]);
3169 void DrawPlayerField(int x, int y)
3171 if (!IS_PLAYER(x, y))
3174 DrawPlayer(PLAYERINFO(x, y));
3177 #define DRAW_PLAYER_OVER_PUSHED_ELEMENT 1
3179 void DrawPlayer(struct PlayerInfo *player)
3181 int jx = player->jx;
3182 int jy = player->jy;
3183 int move_dir = player->MovDir;
3184 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
3185 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
3186 int last_jx = (player->is_moving ? jx - dx : jx);
3187 int last_jy = (player->is_moving ? jy - dy : jy);
3188 int next_jx = jx + dx;
3189 int next_jy = jy + dy;
3190 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
3191 boolean player_is_opaque = FALSE;
3192 int sx = SCREENX(jx), sy = SCREENY(jy);
3193 int sxx = 0, syy = 0;
3194 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
3196 int action = ACTION_DEFAULT;
3197 int last_player_graphic = getPlayerGraphic(player, move_dir);
3198 int last_player_frame = player->Frame;
3201 /* GfxElement[][] is set to the element the player is digging or collecting;
3202 remove also for off-screen player if the player is not moving anymore */
3203 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
3204 GfxElement[jx][jy] = EL_UNDEFINED;
3206 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
3210 if (!IN_LEV_FIELD(jx, jy))
3212 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
3213 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
3214 printf("DrawPlayerField(): This should never happen!\n");
3219 if (element == EL_EXPLOSION)
3222 action = (player->is_pushing ? ACTION_PUSHING :
3223 player->is_digging ? ACTION_DIGGING :
3224 player->is_collecting ? ACTION_COLLECTING :
3225 player->is_moving ? ACTION_MOVING :
3226 player->is_snapping ? ACTION_SNAPPING :
3227 player->is_dropping ? ACTION_DROPPING :
3228 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
3230 if (player->is_waiting)
3231 move_dir = player->dir_waiting;
3233 InitPlayerGfxAnimation(player, action, move_dir);
3235 /* ----------------------------------------------------------------------- */
3236 /* draw things in the field the player is leaving, if needed */
3237 /* ----------------------------------------------------------------------- */
3239 if (player->is_moving)
3241 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
3243 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
3245 if (last_element == EL_DYNAMITE_ACTIVE ||
3246 last_element == EL_EM_DYNAMITE_ACTIVE ||
3247 last_element == EL_SP_DISK_RED_ACTIVE)
3248 DrawDynamite(last_jx, last_jy);
3250 DrawLevelFieldThruMask(last_jx, last_jy);
3252 else if (last_element == EL_DYNAMITE_ACTIVE ||
3253 last_element == EL_EM_DYNAMITE_ACTIVE ||
3254 last_element == EL_SP_DISK_RED_ACTIVE)
3255 DrawDynamite(last_jx, last_jy);
3257 /* !!! this is not enough to prevent flickering of players which are
3258 moving next to each others without a free tile between them -- this
3259 can only be solved by drawing all players layer by layer (first the
3260 background, then the foreground etc.) !!! => TODO */
3261 else if (!IS_PLAYER(last_jx, last_jy))
3262 DrawLevelField(last_jx, last_jy);
3265 DrawLevelField(last_jx, last_jy);
3268 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
3269 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
3272 if (!IN_SCR_FIELD(sx, sy))
3275 /* ----------------------------------------------------------------------- */
3276 /* draw things behind the player, if needed */
3277 /* ----------------------------------------------------------------------- */
3280 DrawLevelElement(jx, jy, Back[jx][jy]);
3281 else if (IS_ACTIVE_BOMB(element))
3282 DrawLevelElement(jx, jy, EL_EMPTY);
3285 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
3287 int old_element = GfxElement[jx][jy];
3288 int old_graphic = el_act_dir2img(old_element, action, move_dir);
3289 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
3291 if (GFX_CRUMBLED(old_element))
3292 DrawLevelFieldCrumbledDigging(jx, jy, move_dir, player->StepFrame);
3294 DrawGraphic(sx, sy, old_graphic, frame);
3296 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
3297 player_is_opaque = TRUE;
3301 GfxElement[jx][jy] = EL_UNDEFINED;
3303 /* make sure that pushed elements are drawn with correct frame rate */
3304 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
3306 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
3307 GfxFrame[jx][jy] = player->StepFrame;
3309 DrawLevelField(jx, jy);
3313 #if !DRAW_PLAYER_OVER_PUSHED_ELEMENT
3314 /* ----------------------------------------------------------------------- */
3315 /* draw player himself */
3316 /* ----------------------------------------------------------------------- */
3318 graphic = getPlayerGraphic(player, move_dir);
3320 /* in the case of changed player action or direction, prevent the current
3321 animation frame from being restarted for identical animations */
3322 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
3323 player->Frame = last_player_frame;
3325 frame = getGraphicAnimationFrame(graphic, player->Frame);
3329 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3330 sxx = player->GfxPos;
3332 syy = player->GfxPos;
3335 if (player_is_opaque)
3336 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
3338 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3340 if (SHIELD_ON(player))
3342 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
3343 IMG_SHIELD_NORMAL_ACTIVE);
3344 int frame = getGraphicAnimationFrame(graphic, -1);
3346 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3350 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
3353 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3354 sxx = player->GfxPos;
3356 syy = player->GfxPos;
3360 /* ----------------------------------------------------------------------- */
3361 /* draw things the player is pushing, if needed */
3362 /* ----------------------------------------------------------------------- */
3364 if (player->is_pushing && player->is_moving)
3366 int px = SCREENX(jx), py = SCREENY(jy);
3367 int pxx = (TILEX - ABS(sxx)) * dx;
3368 int pyy = (TILEY - ABS(syy)) * dy;
3369 int gfx_frame = GfxFrame[jx][jy];
3375 if (!IS_MOVING(jx, jy)) /* push movement already finished */
3377 element = Feld[next_jx][next_jy];
3378 gfx_frame = GfxFrame[next_jx][next_jy];
3381 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
3383 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
3384 frame = getGraphicAnimationFrame(graphic, sync_frame);
3386 /* draw background element under pushed element (like the Sokoban field) */
3387 if (game.use_masked_pushing && IS_MOVING(jx, jy))
3389 /* this allows transparent pushing animation over non-black background */
3392 DrawLevelElement(jx, jy, Back[jx][jy]);
3394 DrawLevelElement(jx, jy, EL_EMPTY);
3396 if (Back[next_jx][next_jy])
3397 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3399 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
3401 else if (Back[next_jx][next_jy])
3402 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3405 /* do not draw (EM style) pushing animation when pushing is finished */
3406 /* (two-tile animations usually do not contain start and end frame) */
3407 if (graphic_info[graphic].double_movement && !IS_MOVING(jx, jy))
3408 DrawLevelElement(next_jx, next_jy, Feld[next_jx][next_jy]);
3410 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3412 /* masked drawing is needed for EMC style (double) movement graphics */
3413 /* !!! (ONLY WHEN DRAWING PUSHED ELEMENT OVER THE PLAYER) !!! */
3414 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3418 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
3419 /* ----------------------------------------------------------------------- */
3420 /* draw player himself */
3421 /* ----------------------------------------------------------------------- */
3423 graphic = getPlayerGraphic(player, move_dir);
3425 /* in the case of changed player action or direction, prevent the current
3426 animation frame from being restarted for identical animations */
3427 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
3428 player->Frame = last_player_frame;
3430 frame = getGraphicAnimationFrame(graphic, player->Frame);
3434 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3435 sxx = player->GfxPos;
3437 syy = player->GfxPos;
3440 if (player_is_opaque)
3441 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
3443 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3445 if (SHIELD_ON(player))
3447 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
3448 IMG_SHIELD_NORMAL_ACTIVE);
3449 int frame = getGraphicAnimationFrame(graphic, -1);
3451 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3455 /* ----------------------------------------------------------------------- */
3456 /* draw things in front of player (active dynamite or dynabombs) */
3457 /* ----------------------------------------------------------------------- */
3459 if (IS_ACTIVE_BOMB(element))
3461 graphic = el2img(element);
3462 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
3464 if (game.emulation == EMU_SUPAPLEX)
3465 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
3467 DrawGraphicThruMask(sx, sy, graphic, frame);
3470 if (player_is_moving && last_element == EL_EXPLOSION)
3472 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
3473 GfxElement[last_jx][last_jy] : EL_EMPTY);
3474 int graphic = el_act2img(element, ACTION_EXPLODING);
3475 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
3476 int phase = ExplodePhase[last_jx][last_jy] - 1;
3477 int frame = getGraphicAnimationFrame(graphic, phase - delay);
3480 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
3483 /* ----------------------------------------------------------------------- */
3484 /* draw elements the player is just walking/passing through/under */
3485 /* ----------------------------------------------------------------------- */
3487 if (player_is_moving)
3489 /* handle the field the player is leaving ... */
3490 if (IS_ACCESSIBLE_INSIDE(last_element))
3491 DrawLevelField(last_jx, last_jy);
3492 else if (IS_ACCESSIBLE_UNDER(last_element))
3493 DrawLevelFieldThruMask(last_jx, last_jy);
3496 /* do not redraw accessible elements if the player is just pushing them */
3497 if (!player_is_moving || !player->is_pushing)
3499 /* ... and the field the player is entering */
3500 if (IS_ACCESSIBLE_INSIDE(element))
3501 DrawLevelField(jx, jy);
3502 else if (IS_ACCESSIBLE_UNDER(element))
3503 DrawLevelFieldThruMask(jx, jy);
3506 MarkTileDirty(sx, sy);
3509 /* ------------------------------------------------------------------------- */
3511 void WaitForEventToContinue()
3513 boolean still_wait = TRUE;
3515 /* simulate releasing mouse button over last gadget, if still pressed */
3517 HandleGadgets(-1, -1, 0);
3519 button_status = MB_RELEASED;
3533 case EVENT_BUTTONPRESS:
3534 case EVENT_KEYPRESS:
3538 case EVENT_KEYRELEASE:
3539 ClearPlayerAction();
3543 HandleOtherEvents(&event);
3547 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3556 #define MAX_REQUEST_LINES 13
3557 #define MAX_REQUEST_LINE_FONT1_LEN 7
3558 #define MAX_REQUEST_LINE_FONT2_LEN 10
3560 static int RequestHandleEvents(unsigned int req_state)
3562 boolean level_solved = (game_status == GAME_MODE_PLAYING &&
3563 local_player->LevelSolved_GameEnd);
3564 int width = request.width;
3565 int height = request.height;
3569 setRequestPosition(&sx, &sy, FALSE);
3571 button_status = MB_RELEASED;
3573 request_gadget_id = -1;
3580 SetDrawtoField(DRAW_TO_FIELDBUFFER);
3582 HandleGameActions();
3584 SetDrawtoField(DRAW_TO_BACKBUFFER);
3586 if (global.use_envelope_request)
3588 /* copy current state of request area to middle of playfield area */
3589 BlitBitmap(bitmap_db_store_2, drawto, sx, sy, width, height, sx, sy);
3597 while (NextValidEvent(&event))
3601 case EVENT_BUTTONPRESS:
3602 case EVENT_BUTTONRELEASE:
3603 case EVENT_MOTIONNOTIFY:
3607 if (event.type == EVENT_MOTIONNOTIFY)
3612 motion_status = TRUE;
3613 mx = ((MotionEvent *) &event)->x;
3614 my = ((MotionEvent *) &event)->y;
3618 motion_status = FALSE;
3619 mx = ((ButtonEvent *) &event)->x;
3620 my = ((ButtonEvent *) &event)->y;
3621 if (event.type == EVENT_BUTTONPRESS)
3622 button_status = ((ButtonEvent *) &event)->button;
3624 button_status = MB_RELEASED;
3627 /* this sets 'request_gadget_id' */
3628 HandleGadgets(mx, my, button_status);
3630 switch (request_gadget_id)
3632 case TOOL_CTRL_ID_YES:
3635 case TOOL_CTRL_ID_NO:
3638 case TOOL_CTRL_ID_CONFIRM:
3639 result = TRUE | FALSE;
3642 case TOOL_CTRL_ID_PLAYER_1:
3645 case TOOL_CTRL_ID_PLAYER_2:
3648 case TOOL_CTRL_ID_PLAYER_3:
3651 case TOOL_CTRL_ID_PLAYER_4:
3662 case EVENT_KEYPRESS:
3663 switch (GetEventKey((KeyEvent *)&event, TRUE))
3666 if (req_state & REQ_CONFIRM)
3671 #if defined(TARGET_SDL2)
3678 #if defined(TARGET_SDL2)
3688 if (req_state & REQ_PLAYER)
3692 case EVENT_KEYRELEASE:
3693 ClearPlayerAction();
3697 HandleOtherEvents(&event);
3702 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3704 int joy = AnyJoystick();
3706 if (joy & JOY_BUTTON_1)
3708 else if (joy & JOY_BUTTON_2)
3714 if (global.use_envelope_request)
3716 /* copy back current state of pressed buttons inside request area */
3717 BlitBitmap(drawto, bitmap_db_store_2, sx, sy, width, height, sx, sy);
3727 static boolean RequestDoor(char *text, unsigned int req_state)
3729 unsigned int old_door_state;
3730 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
3731 int font_nr = FONT_TEXT_2;
3736 if (maxWordLengthInString(text) > MAX_REQUEST_LINE_FONT1_LEN)
3738 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
3739 font_nr = FONT_TEXT_1;
3742 if (game_status == GAME_MODE_PLAYING)
3743 BlitScreenToBitmap(backbuffer);
3745 /* disable deactivated drawing when quick-loading level tape recording */
3746 if (tape.playing && tape.deactivate_display)
3747 TapeDeactivateDisplayOff(TRUE);
3749 SetMouseCursor(CURSOR_DEFAULT);
3751 #if defined(NETWORK_AVALIABLE)
3752 /* pause network game while waiting for request to answer */
3753 if (options.network &&
3754 game_status == GAME_MODE_PLAYING &&
3755 req_state & REQUEST_WAIT_FOR_INPUT)
3756 SendToServer_PausePlaying();
3759 old_door_state = GetDoorState();
3761 /* simulate releasing mouse button over last gadget, if still pressed */
3763 HandleGadgets(-1, -1, 0);
3767 /* draw released gadget before proceeding */
3770 if (old_door_state & DOOR_OPEN_1)
3772 CloseDoor(DOOR_CLOSE_1);
3774 /* save old door content */
3775 BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
3776 0 * DXSIZE, 0, DXSIZE, DYSIZE, 1 * DXSIZE, 0);
3779 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
3780 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3782 /* clear door drawing field */
3783 DrawBackground(DX, DY, DXSIZE, DYSIZE);
3785 /* force DOOR font inside door area */
3786 SetFontStatus(GAME_MODE_PSEUDO_DOOR);
3788 /* write text for request */
3789 for (text_ptr = text, ty = 0; ty < MAX_REQUEST_LINES; ty++)
3791 char text_line[max_request_line_len + 1];
3797 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
3799 tc = *(text_ptr + tx);
3800 // if (!tc || tc == ' ')
3801 if (!tc || tc == ' ' || tc == '?' || tc == '!')
3805 if ((tc == '?' || tc == '!') && tl == 0)
3815 strncpy(text_line, text_ptr, tl);
3818 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
3819 DY + 8 + ty * (getFontHeight(font_nr) + 2),
3820 text_line, font_nr);
3822 text_ptr += tl + (tc == ' ' ? 1 : 0);
3823 // text_ptr += tl + (tc == ' ' || tc == '?' || tc == '!' ? 1 : 0);
3828 if (req_state & REQ_ASK)
3830 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
3831 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
3833 else if (req_state & REQ_CONFIRM)
3835 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
3837 else if (req_state & REQ_PLAYER)
3839 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
3840 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
3841 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
3842 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
3845 /* copy request gadgets to door backbuffer */
3846 BlitBitmap(drawto, bitmap_db_door_1, DX, DY, DXSIZE, DYSIZE, 0, 0);
3848 OpenDoor(DOOR_OPEN_1);
3850 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
3852 if (game_status == GAME_MODE_PLAYING)
3854 SetPanelBackground();
3855 SetDrawBackgroundMask(REDRAW_DOOR_1);
3859 SetDrawBackgroundMask(REDRAW_FIELD);
3865 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3867 // ---------- handle request buttons ----------
3868 result = RequestHandleEvents(req_state);
3872 if (!(req_state & REQ_STAY_OPEN))
3874 CloseDoor(DOOR_CLOSE_1);
3876 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
3877 (req_state & REQ_REOPEN))
3878 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
3883 if (game_status == GAME_MODE_PLAYING)
3885 SetPanelBackground();
3886 SetDrawBackgroundMask(REDRAW_DOOR_1);
3890 SetDrawBackgroundMask(REDRAW_FIELD);
3893 #if defined(NETWORK_AVALIABLE)
3894 /* continue network game after request */
3895 if (options.network &&
3896 game_status == GAME_MODE_PLAYING &&
3897 req_state & REQUEST_WAIT_FOR_INPUT)
3898 SendToServer_ContinuePlaying();
3901 /* restore deactivated drawing when quick-loading level tape recording */
3902 if (tape.playing && tape.deactivate_display)
3903 TapeDeactivateDisplayOn();
3908 static boolean RequestEnvelope(char *text, unsigned int req_state)
3912 if (game_status == GAME_MODE_PLAYING)
3913 BlitScreenToBitmap(backbuffer);
3915 /* disable deactivated drawing when quick-loading level tape recording */
3916 if (tape.playing && tape.deactivate_display)
3917 TapeDeactivateDisplayOff(TRUE);
3919 SetMouseCursor(CURSOR_DEFAULT);
3921 #if defined(NETWORK_AVALIABLE)
3922 /* pause network game while waiting for request to answer */
3923 if (options.network &&
3924 game_status == GAME_MODE_PLAYING &&
3925 req_state & REQUEST_WAIT_FOR_INPUT)
3926 SendToServer_PausePlaying();
3929 /* simulate releasing mouse button over last gadget, if still pressed */
3931 HandleGadgets(-1, -1, 0);
3935 // (replace with setting corresponding request background)
3936 // SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
3937 // SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3939 /* clear door drawing field */
3940 // DrawBackground(DX, DY, DXSIZE, DYSIZE);
3942 ShowEnvelopeRequest(text, req_state, ACTION_OPENING);
3944 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
3946 if (game_status == GAME_MODE_PLAYING)
3948 SetPanelBackground();
3949 SetDrawBackgroundMask(REDRAW_DOOR_1);
3953 SetDrawBackgroundMask(REDRAW_FIELD);
3959 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3961 // ---------- handle request buttons ----------
3962 result = RequestHandleEvents(req_state);
3966 ShowEnvelopeRequest(text, req_state, ACTION_CLOSING);
3970 if (game_status == GAME_MODE_PLAYING)
3972 SetPanelBackground();
3973 SetDrawBackgroundMask(REDRAW_DOOR_1);
3977 SetDrawBackgroundMask(REDRAW_FIELD);
3980 #if defined(NETWORK_AVALIABLE)
3981 /* continue network game after request */
3982 if (options.network &&
3983 game_status == GAME_MODE_PLAYING &&
3984 req_state & REQUEST_WAIT_FOR_INPUT)
3985 SendToServer_ContinuePlaying();
3988 /* restore deactivated drawing when quick-loading level tape recording */
3989 if (tape.playing && tape.deactivate_display)
3990 TapeDeactivateDisplayOn();
3995 boolean Request(char *text, unsigned int req_state)
3997 if (global.use_envelope_request)
3998 return RequestEnvelope(text, req_state);
4000 return RequestDoor(text, req_state);
4003 static int compareDoorPartOrderInfo(const void *object1, const void *object2)
4005 const struct DoorPartOrderInfo *dpo1 = (struct DoorPartOrderInfo *)object1;
4006 const struct DoorPartOrderInfo *dpo2 = (struct DoorPartOrderInfo *)object2;
4009 if (dpo1->sort_priority != dpo2->sort_priority)
4010 compare_result = dpo1->sort_priority - dpo2->sort_priority;
4012 compare_result = dpo1->nr - dpo2->nr;
4014 return compare_result;
4017 void InitGraphicCompatibilityInfo_Doors()
4023 struct DoorInfo *door;
4027 { DOOR_1, IMG_GFX_DOOR_1_PART_1, IMG_GFX_DOOR_1_PART_8, &door_1 },
4028 { DOOR_2, IMG_GFX_DOOR_2_PART_1, IMG_GFX_DOOR_2_PART_8, &door_2 },
4030 { -1, -1, -1, NULL }
4032 struct Rect door_rect_list[] =
4034 { DX, DY, DXSIZE, DYSIZE },
4035 { VX, VY, VXSIZE, VYSIZE }
4039 for (i = 0; doors[i].door_token != -1; i++)
4041 int door_token = doors[i].door_token;
4042 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
4043 int part_1 = doors[i].part_1;
4044 int part_8 = doors[i].part_8;
4045 int part_2 = part_1 + 1;
4046 int part_3 = part_1 + 2;
4047 struct DoorInfo *door = doors[i].door;
4048 struct Rect *door_rect = &door_rect_list[door_index];
4049 boolean door_gfx_redefined = FALSE;
4051 /* check if any door part graphic definitions have been redefined */
4053 for (j = 0; door_part_controls[j].door_token != -1; j++)
4055 struct DoorPartControlInfo *dpc = &door_part_controls[j];
4056 struct FileInfo *fi = getImageListEntryFromImageID(dpc->graphic);
4058 if (dpc->door_token == door_token && fi->redefined)
4059 door_gfx_redefined = TRUE;
4062 /* check for old-style door graphic/animation modifications */
4064 if (!door_gfx_redefined)
4066 if (door->anim_mode & ANIM_STATIC_PANEL)
4068 door->panel.step_xoffset = 0;
4069 door->panel.step_yoffset = 0;
4072 if (door->anim_mode & (ANIM_HORIZONTAL | ANIM_VERTICAL))
4074 struct GraphicInfo *g_part_1 = &graphic_info[part_1];
4075 struct GraphicInfo *g_part_2 = &graphic_info[part_2];
4076 int num_door_steps, num_panel_steps;
4078 /* remove door part graphics other than the two default wings */
4080 for (j = 0; door_part_controls[j].door_token != -1; j++)
4082 struct DoorPartControlInfo *dpc = &door_part_controls[j];
4083 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4085 if (dpc->graphic >= part_3 &&
4086 dpc->graphic <= part_8)
4090 /* set graphics and screen positions of the default wings */
4092 g_part_1->width = door_rect->width;
4093 g_part_1->height = door_rect->height;
4094 g_part_2->width = door_rect->width;
4095 g_part_2->height = door_rect->height;
4096 g_part_2->src_x = door_rect->width;
4097 g_part_2->src_y = g_part_1->src_y;
4099 door->part_2.x = door->part_1.x;
4100 door->part_2.y = door->part_1.y;
4102 if (door->width != -1)
4104 g_part_1->width = door->width;
4105 g_part_2->width = door->width;
4107 // special treatment for graphics and screen position of right wing
4108 g_part_2->src_x += door_rect->width - door->width;
4109 door->part_2.x += door_rect->width - door->width;
4112 if (door->height != -1)
4114 g_part_1->height = door->height;
4115 g_part_2->height = door->height;
4117 // special treatment for graphics and screen position of bottom wing
4118 g_part_2->src_y += door_rect->height - door->height;
4119 door->part_2.y += door_rect->height - door->height;
4122 /* set animation delays for the default wings and panels */
4124 door->part_1.step_delay = door->step_delay;
4125 door->part_2.step_delay = door->step_delay;
4126 door->panel.step_delay = door->step_delay;
4128 /* set animation draw order for the default wings */
4130 door->part_1.sort_priority = 2; /* draw left wing over ... */
4131 door->part_2.sort_priority = 1; /* ... right wing */
4133 /* set animation draw offset for the default wings */
4135 if (door->anim_mode & ANIM_HORIZONTAL)
4137 door->part_1.step_xoffset = door->step_offset;
4138 door->part_1.step_yoffset = 0;
4139 door->part_2.step_xoffset = door->step_offset * -1;
4140 door->part_2.step_yoffset = 0;
4142 num_door_steps = g_part_1->width / door->step_offset;
4144 else // ANIM_VERTICAL
4146 door->part_1.step_xoffset = 0;
4147 door->part_1.step_yoffset = door->step_offset;
4148 door->part_2.step_xoffset = 0;
4149 door->part_2.step_yoffset = door->step_offset * -1;
4151 num_door_steps = g_part_1->height / door->step_offset;
4154 /* set animation draw offset for the default panels */
4156 if (door->step_offset > 1)
4158 num_panel_steps = 2 * door_rect->height / door->step_offset;
4159 door->panel.start_step = num_panel_steps - num_door_steps;
4160 door->panel.start_step_closing = door->panel.start_step;
4164 num_panel_steps = door_rect->height / door->step_offset;
4165 door->panel.start_step = num_panel_steps - num_door_steps / 2;
4166 door->panel.start_step_closing = door->panel.start_step;
4167 door->panel.step_delay *= 2;
4178 for (i = 0; door_part_controls[i].door_token != -1; i++)
4180 struct DoorPartControlInfo *dpc = &door_part_controls[i];
4181 struct DoorPartOrderInfo *dpo = &door_part_order[i];
4183 /* initialize "start_step_opening" and "start_step_closing", if needed */
4184 if (dpc->pos->start_step_opening == 0 &&
4185 dpc->pos->start_step_closing == 0)
4187 // dpc->pos->start_step_opening = dpc->pos->start_step;
4188 dpc->pos->start_step_closing = dpc->pos->start_step;
4191 /* fill structure for door part draw order (sorted below) */
4193 dpo->sort_priority = dpc->pos->sort_priority;
4196 /* sort door part controls according to sort_priority and graphic number */
4197 qsort(door_part_order, MAX_DOOR_PARTS,
4198 sizeof(struct DoorPartOrderInfo), compareDoorPartOrderInfo);
4201 unsigned int OpenDoor(unsigned int door_state)
4203 if (door_state & DOOR_COPY_BACK)
4205 if (door_state & DOOR_OPEN_1)
4206 BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
4207 1 * DXSIZE, 0, DXSIZE, DYSIZE, 0 * DXSIZE, 0);
4209 if (door_state & DOOR_OPEN_2)
4210 BlitBitmap(bitmap_db_door_2, bitmap_db_door_2,
4211 1 * VXSIZE, 0, VXSIZE, VYSIZE, 0 * VXSIZE, 0);
4213 door_state &= ~DOOR_COPY_BACK;
4216 return MoveDoor(door_state);
4219 unsigned int CloseDoor(unsigned int door_state)
4221 unsigned int old_door_state = GetDoorState();
4223 if (!(door_state & DOOR_NO_COPY_BACK))
4225 if (old_door_state & DOOR_OPEN_1)
4226 BlitBitmap(backbuffer, bitmap_db_door_1,
4227 DX, DY, DXSIZE, DYSIZE, 0, 0);
4229 if (old_door_state & DOOR_OPEN_2)
4230 BlitBitmap(backbuffer, bitmap_db_door_2,
4231 VX, VY, VXSIZE, VYSIZE, 0, 0);
4233 door_state &= ~DOOR_NO_COPY_BACK;
4236 return MoveDoor(door_state);
4239 unsigned int GetDoorState()
4241 return MoveDoor(DOOR_GET_STATE);
4244 unsigned int SetDoorState(unsigned int door_state)
4246 return MoveDoor(door_state | DOOR_SET_STATE);
4249 int euclid(int a, int b)
4251 return (b ? euclid(b, a % b) : a);
4254 unsigned int MoveDoor(unsigned int door_state)
4256 struct Rect door_rect_list[] =
4258 { DX, DY, DXSIZE, DYSIZE },
4259 { VX, VY, VXSIZE, VYSIZE }
4261 static int door1 = DOOR_CLOSE_1;
4262 static int door2 = DOOR_CLOSE_2;
4263 unsigned int door_delay = 0;
4264 unsigned int door_delay_value;
4267 if (door_state == DOOR_GET_STATE)
4268 return (door1 | door2);
4270 if (door_state & DOOR_SET_STATE)
4272 if (door_state & DOOR_ACTION_1)
4273 door1 = door_state & DOOR_ACTION_1;
4274 if (door_state & DOOR_ACTION_2)
4275 door2 = door_state & DOOR_ACTION_2;
4277 return (door1 | door2);
4280 if (!(door_state & DOOR_FORCE_REDRAW))
4282 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
4283 door_state &= ~DOOR_OPEN_1;
4284 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
4285 door_state &= ~DOOR_CLOSE_1;
4286 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
4287 door_state &= ~DOOR_OPEN_2;
4288 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
4289 door_state &= ~DOOR_CLOSE_2;
4292 if (global.autoplay_leveldir)
4294 door_state |= DOOR_NO_DELAY;
4295 door_state &= ~DOOR_CLOSE_ALL;
4298 if (game_status == GAME_MODE_EDITOR)
4299 door_state |= DOOR_NO_DELAY;
4301 if (door_state & DOOR_ACTION)
4303 boolean door_panel_drawn[NUM_DOORS];
4304 boolean panel_has_doors[NUM_DOORS];
4305 boolean door_part_skip[MAX_DOOR_PARTS];
4306 boolean door_part_done[MAX_DOOR_PARTS];
4307 boolean door_part_done_all;
4308 int num_steps[MAX_DOOR_PARTS];
4309 int max_move_delay = 0; // delay for complete animations of all doors
4310 int max_step_delay = 0; // delay (ms) between two animation frames
4311 int num_move_steps = 0; // number of animation steps for all doors
4312 int max_move_delay_doors_only = 0; // delay for doors only (no panel)
4313 int num_move_steps_doors_only = 0; // steps for doors only (no panel)
4314 int current_move_delay = 0;
4318 for (i = 0; i < NUM_DOORS; i++)
4319 panel_has_doors[i] = FALSE;
4321 for (i = 0; i < MAX_DOOR_PARTS; i++)
4323 struct DoorPartControlInfo *dpc = &door_part_controls[i];
4324 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4325 int door_token = dpc->door_token;
4327 door_part_done[i] = FALSE;
4328 door_part_skip[i] = (!(door_state & door_token) ||
4332 for (i = 0; i < MAX_DOOR_PARTS; i++)
4334 int nr = door_part_order[i].nr;
4335 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
4336 struct DoorPartPosInfo *pos = dpc->pos;
4337 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4338 int door_token = dpc->door_token;
4339 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
4340 boolean is_panel = DOOR_PART_IS_PANEL(nr);
4341 int step_xoffset = ABS(pos->step_xoffset);
4342 int step_yoffset = ABS(pos->step_yoffset);
4343 int step_delay = pos->step_delay;
4344 int current_door_state = door_state & door_token;
4345 boolean door_opening = ((current_door_state & DOOR_OPEN) != 0);
4346 boolean door_closing = ((current_door_state & DOOR_CLOSE) != 0);
4347 boolean part_opening = (is_panel ? door_closing : door_opening);
4348 int start_step = (part_opening ? pos->start_step_opening :
4349 pos->start_step_closing);
4350 float move_xsize = (step_xoffset ? g->width : 0);
4351 float move_ysize = (step_yoffset ? g->height : 0);
4352 int move_xsteps = (step_xoffset ? ceil(move_xsize / step_xoffset) : 0);
4353 int move_ysteps = (step_yoffset ? ceil(move_ysize / step_yoffset) : 0);
4354 int move_steps = (move_xsteps && move_ysteps ?
4355 MIN(move_xsteps, move_ysteps) :
4356 move_xsteps ? move_xsteps : move_ysteps) - start_step;
4357 int move_delay = move_steps * step_delay;
4359 if (door_part_skip[nr])
4362 max_move_delay = MAX(max_move_delay, move_delay);
4363 max_step_delay = (max_step_delay == 0 ? step_delay :
4364 euclid(max_step_delay, step_delay));
4365 num_steps[nr] = move_steps;
4369 max_move_delay_doors_only = MAX(max_move_delay_doors_only, move_delay);
4371 panel_has_doors[door_index] = TRUE;
4375 max_step_delay = MAX(1, max_step_delay); // prevent division by zero
4377 num_move_steps = max_move_delay / max_step_delay;
4378 num_move_steps_doors_only = max_move_delay_doors_only / max_step_delay;
4380 door_delay_value = max_step_delay;
4382 if ((door_state & DOOR_NO_DELAY) || setup.quick_doors)
4384 start = num_move_steps - 1;
4388 /* opening door sound has priority over simultaneously closing door */
4389 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
4390 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
4391 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
4392 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
4395 for (k = start; k < num_move_steps; k++)
4397 int last_frame = num_move_steps - 1; // last frame of this "for" loop
4399 door_part_done_all = TRUE;
4401 for (i = 0; i < NUM_DOORS; i++)
4402 door_panel_drawn[i] = FALSE;
4404 for (i = 0; i < MAX_DOOR_PARTS; i++)
4406 int nr = door_part_order[i].nr;
4407 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
4408 struct DoorPartPosInfo *pos = dpc->pos;
4409 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4410 int door_token = dpc->door_token;
4411 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
4412 boolean is_panel = DOOR_PART_IS_PANEL(nr);
4413 boolean is_panel_and_door_has_closed = FALSE;
4414 struct Rect *door_rect = &door_rect_list[door_index];
4415 Bitmap *bitmap_db_door = (door_token == DOOR_1 ? bitmap_db_door_1 :
4417 Bitmap *bitmap = (is_panel ? bitmap_db_door : g->bitmap);
4418 int current_door_state = door_state & door_token;
4419 boolean door_opening = ((current_door_state & DOOR_OPEN) != 0);
4420 boolean door_closing = !door_opening;
4421 boolean part_opening = (is_panel ? door_closing : door_opening);
4422 boolean part_closing = !part_opening;
4423 int start_step = (part_opening ? pos->start_step_opening :
4424 pos->start_step_closing);
4425 int step_delay = pos->step_delay;
4426 int step_factor = step_delay / max_step_delay;
4427 int k1 = (step_factor ? k / step_factor + 1 : k);
4428 int k2 = (part_opening ? k1 + start_step : num_steps[nr] - k1);
4429 int kk = MAX(0, k2);
4432 int src_x, src_y, src_xx, src_yy;
4433 int dst_x, dst_y, dst_xx, dst_yy;
4436 if (door_part_skip[nr])
4439 if (!(door_state & door_token))
4447 int k2_door = (door_opening ? k : num_move_steps_doors_only - k - 1);
4448 int kk_door = MAX(0, k2_door);
4449 int sync_frame = kk_door * door_delay_value;
4450 int frame = getGraphicAnimationFrame(dpc->graphic, sync_frame);
4452 getGraphicSource(dpc->graphic, frame, &bitmap, &g_src_x, &g_src_y);
4457 if (!door_panel_drawn[door_index])
4459 ClearRectangle(drawto, door_rect->x, door_rect->y,
4460 door_rect->width, door_rect->height);
4462 door_panel_drawn[door_index] = TRUE;
4465 // draw opening or closing door parts
4467 if (pos->step_xoffset < 0) // door part on right side
4470 dst_xx = pos->x + ABS(kk * pos->step_xoffset);
4473 if (dst_xx + width > door_rect->width)
4474 width = door_rect->width - dst_xx;
4476 else // door part on left side
4479 dst_xx = pos->x - kk * pos->step_xoffset;
4483 src_xx = ABS(dst_xx);
4487 width = g->width - src_xx;
4489 if (width > door_rect->width)
4490 width = door_rect->width;
4492 // printf("::: k == %d [%d] \n", k, start_step);
4495 if (pos->step_yoffset < 0) // door part on bottom side
4498 dst_yy = pos->y + ABS(kk * pos->step_yoffset);
4501 if (dst_yy + height > door_rect->height)
4502 height = door_rect->height - dst_yy;
4504 else // door part on top side
4507 dst_yy = pos->y - kk * pos->step_yoffset;
4511 src_yy = ABS(dst_yy);
4515 height = g->height - src_yy;
4518 src_x = g_src_x + src_xx;
4519 src_y = g_src_y + src_yy;
4521 dst_x = door_rect->x + dst_xx;
4522 dst_y = door_rect->y + dst_yy;
4524 is_panel_and_door_has_closed =
4527 panel_has_doors[door_index] &&
4528 k >= num_move_steps_doors_only - 1);
4530 if (width >= 0 && width <= g->width &&
4531 height >= 0 && height <= g->height &&
4532 !is_panel_and_door_has_closed)
4534 if (is_panel || !pos->draw_masked)
4535 BlitBitmap(bitmap, drawto, src_x, src_y, width, height,
4538 BlitBitmapMasked(bitmap, drawto, src_x, src_y, width, height,
4542 redraw_mask |= REDRAW_DOOR_FROM_TOKEN(door_token);
4544 if ((part_opening && (width < 0 || height < 0)) ||
4545 (part_closing && (width >= g->width && height >= g->height)))
4546 door_part_done[nr] = TRUE;
4548 // continue door part animations, but not panel after door has closed
4549 if (!door_part_done[nr] && !is_panel_and_door_has_closed)
4550 door_part_done_all = FALSE;
4553 if (!(door_state & DOOR_NO_DELAY))
4557 SkipUntilDelayReached(&door_delay, door_delay_value, &k, last_frame);
4559 current_move_delay += max_step_delay;
4562 if (door_part_done_all)
4567 if (door_state & DOOR_ACTION_1)
4568 door1 = door_state & DOOR_ACTION_1;
4569 if (door_state & DOOR_ACTION_2)
4570 door2 = door_state & DOOR_ACTION_2;
4572 // draw masked border over door area
4573 DrawMaskedBorder(REDRAW_DOOR_1);
4574 DrawMaskedBorder(REDRAW_DOOR_2);
4576 return (door1 | door2);
4579 static boolean useSpecialEditorDoor()
4581 int graphic = IMG_GLOBAL_BORDER_EDITOR;
4582 boolean redefined = getImageListEntryFromImageID(graphic)->redefined;
4584 // do not draw special editor door if editor border defined or redefined
4585 if (graphic_info[graphic].bitmap != NULL || redefined)
4588 // do not draw special editor door if global border defined to be empty
4589 if (graphic_info[IMG_GLOBAL_BORDER].bitmap == NULL)
4592 // do not draw special editor door if viewport definitions do not match
4596 EY + EYSIZE != VY + VYSIZE)
4602 void DrawSpecialEditorDoor()
4604 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
4605 int top_border_width = gfx1->width;
4606 int top_border_height = gfx1->height;
4607 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
4608 int ex = EX - outer_border;
4609 int ey = EY - outer_border;
4610 int vy = VY - outer_border;
4611 int exsize = EXSIZE + 2 * outer_border;
4613 if (!useSpecialEditorDoor())
4616 /* draw bigger level editor toolbox window */
4617 BlitBitmap(gfx1->bitmap, drawto, gfx1->src_x, gfx1->src_y,
4618 top_border_width, top_border_height, ex, ey - top_border_height);
4619 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto, ex, vy,
4620 exsize, EYSIZE - VYSIZE + outer_border, ex, ey);
4622 redraw_mask |= REDRAW_ALL;
4625 void UndrawSpecialEditorDoor()
4627 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
4628 int top_border_width = gfx1->width;
4629 int top_border_height = gfx1->height;
4630 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
4631 int ex = EX - outer_border;
4632 int ey = EY - outer_border;
4633 int ey_top = ey - top_border_height;
4634 int exsize = EXSIZE + 2 * outer_border;
4635 int eysize = EYSIZE + 2 * outer_border;
4637 if (!useSpecialEditorDoor())
4640 /* draw normal tape recorder window */
4641 if (graphic_info[IMG_GLOBAL_BORDER].bitmap)
4643 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
4644 ex, ey_top, top_border_width, top_border_height,
4646 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
4647 ex, ey, exsize, eysize, ex, ey);
4651 // if screen background is set to "[NONE]", clear editor toolbox window
4652 ClearRectangle(drawto, ex, ey_top, top_border_width, top_border_height);
4653 ClearRectangle(drawto, ex, ey, exsize, eysize);
4656 redraw_mask |= REDRAW_ALL;
4660 /* ---------- new tool button stuff ---------------------------------------- */
4665 struct TextPosInfo *pos;
4668 } toolbutton_info[NUM_TOOL_BUTTONS] =
4671 IMG_GFX_REQUEST_BUTTON_YES, &request.button.yes,
4672 TOOL_CTRL_ID_YES, "yes"
4675 IMG_GFX_REQUEST_BUTTON_NO, &request.button.no,
4676 TOOL_CTRL_ID_NO, "no"
4679 IMG_GFX_REQUEST_BUTTON_CONFIRM, &request.button.confirm,
4680 TOOL_CTRL_ID_CONFIRM, "confirm"
4683 IMG_GFX_REQUEST_BUTTON_PLAYER_1, &request.button.player_1,
4684 TOOL_CTRL_ID_PLAYER_1, "player 1"
4687 IMG_GFX_REQUEST_BUTTON_PLAYER_2, &request.button.player_2,
4688 TOOL_CTRL_ID_PLAYER_2, "player 2"
4691 IMG_GFX_REQUEST_BUTTON_PLAYER_3, &request.button.player_3,
4692 TOOL_CTRL_ID_PLAYER_3, "player 3"
4695 IMG_GFX_REQUEST_BUTTON_PLAYER_4, &request.button.player_4,
4696 TOOL_CTRL_ID_PLAYER_4, "player 4"
4700 void CreateToolButtons()
4704 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4706 struct GraphicInfo *gfx = &graphic_info[toolbutton_info[i].graphic];
4707 struct TextPosInfo *pos = toolbutton_info[i].pos;
4708 struct GadgetInfo *gi;
4709 Bitmap *deco_bitmap = None;
4710 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
4711 unsigned int event_mask = GD_EVENT_RELEASED;
4714 int gd_x = gfx->src_x;
4715 int gd_y = gfx->src_y;
4716 int gd_xp = gfx->src_x + gfx->pressed_xoffset;
4717 int gd_yp = gfx->src_y + gfx->pressed_yoffset;
4720 if (global.use_envelope_request)
4721 setRequestPosition(&dx, &dy, TRUE);
4723 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
4725 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
4727 getSizedGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr), 0,
4728 pos->size, &deco_bitmap, &deco_x, &deco_y);
4729 deco_xpos = (gfx->width - pos->size) / 2;
4730 deco_ypos = (gfx->height - pos->size) / 2;
4733 gi = CreateGadget(GDI_CUSTOM_ID, id,
4734 GDI_INFO_TEXT, toolbutton_info[i].infotext,
4735 GDI_X, dx + GDI_ACTIVE_POS(pos->x),
4736 GDI_Y, dy + GDI_ACTIVE_POS(pos->y),
4737 GDI_WIDTH, gfx->width,
4738 GDI_HEIGHT, gfx->height,
4739 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
4740 GDI_STATE, GD_BUTTON_UNPRESSED,
4741 GDI_DESIGN_UNPRESSED, gfx->bitmap, gd_x, gd_y,
4742 GDI_DESIGN_PRESSED, gfx->bitmap, gd_xp, gd_yp,
4743 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
4744 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
4745 GDI_DECORATION_SIZE, pos->size, pos->size,
4746 GDI_DECORATION_SHIFTING, 1, 1,
4747 GDI_DIRECT_DRAW, FALSE,
4748 GDI_EVENT_MASK, event_mask,
4749 GDI_CALLBACK_ACTION, HandleToolButtons,
4753 Error(ERR_EXIT, "cannot create gadget");
4755 tool_gadget[id] = gi;
4759 void FreeToolButtons()
4763 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4764 FreeGadget(tool_gadget[i]);
4767 static void UnmapToolButtons()
4771 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4772 UnmapGadget(tool_gadget[i]);
4775 static void HandleToolButtons(struct GadgetInfo *gi)
4777 request_gadget_id = gi->custom_id;
4780 static struct Mapping_EM_to_RND_object
4783 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
4784 boolean is_backside; /* backside of moving element */
4790 em_object_mapping_list[] =
4793 Xblank, TRUE, FALSE,
4797 Yacid_splash_eB, FALSE, FALSE,
4798 EL_ACID_SPLASH_RIGHT, -1, -1
4801 Yacid_splash_wB, FALSE, FALSE,
4802 EL_ACID_SPLASH_LEFT, -1, -1
4805 #ifdef EM_ENGINE_BAD_ROLL
4807 Xstone_force_e, FALSE, FALSE,
4808 EL_ROCK, -1, MV_BIT_RIGHT
4811 Xstone_force_w, FALSE, FALSE,
4812 EL_ROCK, -1, MV_BIT_LEFT
4815 Xnut_force_e, FALSE, FALSE,
4816 EL_NUT, -1, MV_BIT_RIGHT
4819 Xnut_force_w, FALSE, FALSE,
4820 EL_NUT, -1, MV_BIT_LEFT
4823 Xspring_force_e, FALSE, FALSE,
4824 EL_SPRING, -1, MV_BIT_RIGHT
4827 Xspring_force_w, FALSE, FALSE,
4828 EL_SPRING, -1, MV_BIT_LEFT
4831 Xemerald_force_e, FALSE, FALSE,
4832 EL_EMERALD, -1, MV_BIT_RIGHT
4835 Xemerald_force_w, FALSE, FALSE,
4836 EL_EMERALD, -1, MV_BIT_LEFT
4839 Xdiamond_force_e, FALSE, FALSE,
4840 EL_DIAMOND, -1, MV_BIT_RIGHT
4843 Xdiamond_force_w, FALSE, FALSE,
4844 EL_DIAMOND, -1, MV_BIT_LEFT
4847 Xbomb_force_e, FALSE, FALSE,
4848 EL_BOMB, -1, MV_BIT_RIGHT
4851 Xbomb_force_w, FALSE, FALSE,
4852 EL_BOMB, -1, MV_BIT_LEFT
4854 #endif /* EM_ENGINE_BAD_ROLL */
4857 Xstone, TRUE, FALSE,
4861 Xstone_pause, FALSE, FALSE,
4865 Xstone_fall, FALSE, FALSE,
4869 Ystone_s, FALSE, FALSE,
4870 EL_ROCK, ACTION_FALLING, -1
4873 Ystone_sB, FALSE, TRUE,
4874 EL_ROCK, ACTION_FALLING, -1
4877 Ystone_e, FALSE, FALSE,
4878 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
4881 Ystone_eB, FALSE, TRUE,
4882 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
4885 Ystone_w, FALSE, FALSE,
4886 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
4889 Ystone_wB, FALSE, TRUE,
4890 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
4897 Xnut_pause, FALSE, FALSE,
4901 Xnut_fall, FALSE, FALSE,
4905 Ynut_s, FALSE, FALSE,
4906 EL_NUT, ACTION_FALLING, -1
4909 Ynut_sB, FALSE, TRUE,
4910 EL_NUT, ACTION_FALLING, -1
4913 Ynut_e, FALSE, FALSE,
4914 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
4917 Ynut_eB, FALSE, TRUE,
4918 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
4921 Ynut_w, FALSE, FALSE,
4922 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
4925 Ynut_wB, FALSE, TRUE,
4926 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
4929 Xbug_n, TRUE, FALSE,
4933 Xbug_e, TRUE, FALSE,
4934 EL_BUG_RIGHT, -1, -1
4937 Xbug_s, TRUE, FALSE,
4941 Xbug_w, TRUE, FALSE,
4945 Xbug_gon, FALSE, FALSE,
4949 Xbug_goe, FALSE, FALSE,
4950 EL_BUG_RIGHT, -1, -1
4953 Xbug_gos, FALSE, FALSE,
4957 Xbug_gow, FALSE, FALSE,
4961 Ybug_n, FALSE, FALSE,
4962 EL_BUG, ACTION_MOVING, MV_BIT_UP
4965 Ybug_nB, FALSE, TRUE,
4966 EL_BUG, ACTION_MOVING, MV_BIT_UP
4969 Ybug_e, FALSE, FALSE,
4970 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
4973 Ybug_eB, FALSE, TRUE,
4974 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
4977 Ybug_s, FALSE, FALSE,
4978 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
4981 Ybug_sB, FALSE, TRUE,
4982 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
4985 Ybug_w, FALSE, FALSE,
4986 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
4989 Ybug_wB, FALSE, TRUE,
4990 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
4993 Ybug_w_n, FALSE, FALSE,
4994 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
4997 Ybug_n_e, FALSE, FALSE,
4998 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
5001 Ybug_e_s, FALSE, FALSE,
5002 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
5005 Ybug_s_w, FALSE, FALSE,
5006 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
5009 Ybug_e_n, FALSE, FALSE,
5010 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
5013 Ybug_s_e, FALSE, FALSE,
5014 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
5017 Ybug_w_s, FALSE, FALSE,
5018 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
5021 Ybug_n_w, FALSE, FALSE,
5022 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
5025 Ybug_stone, FALSE, FALSE,
5026 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
5029 Ybug_spring, FALSE, FALSE,
5030 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
5033 Xtank_n, TRUE, FALSE,
5034 EL_SPACESHIP_UP, -1, -1
5037 Xtank_e, TRUE, FALSE,
5038 EL_SPACESHIP_RIGHT, -1, -1
5041 Xtank_s, TRUE, FALSE,
5042 EL_SPACESHIP_DOWN, -1, -1
5045 Xtank_w, TRUE, FALSE,
5046 EL_SPACESHIP_LEFT, -1, -1
5049 Xtank_gon, FALSE, FALSE,
5050 EL_SPACESHIP_UP, -1, -1
5053 Xtank_goe, FALSE, FALSE,
5054 EL_SPACESHIP_RIGHT, -1, -1
5057 Xtank_gos, FALSE, FALSE,
5058 EL_SPACESHIP_DOWN, -1, -1
5061 Xtank_gow, FALSE, FALSE,
5062 EL_SPACESHIP_LEFT, -1, -1
5065 Ytank_n, FALSE, FALSE,
5066 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
5069 Ytank_nB, FALSE, TRUE,
5070 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
5073 Ytank_e, FALSE, FALSE,
5074 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
5077 Ytank_eB, FALSE, TRUE,
5078 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
5081 Ytank_s, FALSE, FALSE,
5082 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
5085 Ytank_sB, FALSE, TRUE,
5086 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
5089 Ytank_w, FALSE, FALSE,
5090 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
5093 Ytank_wB, FALSE, TRUE,
5094 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
5097 Ytank_w_n, FALSE, FALSE,
5098 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
5101 Ytank_n_e, FALSE, FALSE,
5102 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
5105 Ytank_e_s, FALSE, FALSE,
5106 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
5109 Ytank_s_w, FALSE, FALSE,
5110 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
5113 Ytank_e_n, FALSE, FALSE,
5114 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
5117 Ytank_s_e, FALSE, FALSE,
5118 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
5121 Ytank_w_s, FALSE, FALSE,
5122 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
5125 Ytank_n_w, FALSE, FALSE,
5126 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
5129 Ytank_stone, FALSE, FALSE,
5130 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
5133 Ytank_spring, FALSE, FALSE,
5134 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
5137 Xandroid, TRUE, FALSE,
5138 EL_EMC_ANDROID, ACTION_ACTIVE, -1
5141 Xandroid_1_n, FALSE, FALSE,
5142 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
5145 Xandroid_2_n, FALSE, FALSE,
5146 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
5149 Xandroid_1_e, FALSE, FALSE,
5150 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
5153 Xandroid_2_e, FALSE, FALSE,
5154 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
5157 Xandroid_1_w, FALSE, FALSE,
5158 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
5161 Xandroid_2_w, FALSE, FALSE,
5162 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
5165 Xandroid_1_s, FALSE, FALSE,
5166 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
5169 Xandroid_2_s, FALSE, FALSE,
5170 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
5173 Yandroid_n, FALSE, FALSE,
5174 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
5177 Yandroid_nB, FALSE, TRUE,
5178 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
5181 Yandroid_ne, FALSE, FALSE,
5182 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
5185 Yandroid_neB, FALSE, TRUE,
5186 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
5189 Yandroid_e, FALSE, FALSE,
5190 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
5193 Yandroid_eB, FALSE, TRUE,
5194 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
5197 Yandroid_se, FALSE, FALSE,
5198 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
5201 Yandroid_seB, FALSE, TRUE,
5202 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
5205 Yandroid_s, FALSE, FALSE,
5206 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
5209 Yandroid_sB, FALSE, TRUE,
5210 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
5213 Yandroid_sw, FALSE, FALSE,
5214 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
5217 Yandroid_swB, FALSE, TRUE,
5218 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
5221 Yandroid_w, FALSE, FALSE,
5222 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
5225 Yandroid_wB, FALSE, TRUE,
5226 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
5229 Yandroid_nw, FALSE, FALSE,
5230 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
5233 Yandroid_nwB, FALSE, TRUE,
5234 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
5237 Xspring, TRUE, FALSE,
5241 Xspring_pause, FALSE, FALSE,
5245 Xspring_e, FALSE, FALSE,
5249 Xspring_w, FALSE, FALSE,
5253 Xspring_fall, FALSE, FALSE,
5257 Yspring_s, FALSE, FALSE,
5258 EL_SPRING, ACTION_FALLING, -1
5261 Yspring_sB, FALSE, TRUE,
5262 EL_SPRING, ACTION_FALLING, -1
5265 Yspring_e, FALSE, FALSE,
5266 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
5269 Yspring_eB, FALSE, TRUE,
5270 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
5273 Yspring_w, FALSE, FALSE,
5274 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
5277 Yspring_wB, FALSE, TRUE,
5278 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
5281 Yspring_kill_e, FALSE, FALSE,
5282 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
5285 Yspring_kill_eB, FALSE, TRUE,
5286 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
5289 Yspring_kill_w, FALSE, FALSE,
5290 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
5293 Yspring_kill_wB, FALSE, TRUE,
5294 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
5297 Xeater_n, TRUE, FALSE,
5298 EL_YAMYAM_UP, -1, -1
5301 Xeater_e, TRUE, FALSE,
5302 EL_YAMYAM_RIGHT, -1, -1
5305 Xeater_w, TRUE, FALSE,
5306 EL_YAMYAM_LEFT, -1, -1
5309 Xeater_s, TRUE, FALSE,
5310 EL_YAMYAM_DOWN, -1, -1
5313 Yeater_n, FALSE, FALSE,
5314 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
5317 Yeater_nB, FALSE, TRUE,
5318 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
5321 Yeater_e, FALSE, FALSE,
5322 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
5325 Yeater_eB, FALSE, TRUE,
5326 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
5329 Yeater_s, FALSE, FALSE,
5330 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
5333 Yeater_sB, FALSE, TRUE,
5334 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
5337 Yeater_w, FALSE, FALSE,
5338 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
5341 Yeater_wB, FALSE, TRUE,
5342 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
5345 Yeater_stone, FALSE, FALSE,
5346 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
5349 Yeater_spring, FALSE, FALSE,
5350 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
5353 Xalien, TRUE, FALSE,
5357 Xalien_pause, FALSE, FALSE,
5361 Yalien_n, FALSE, FALSE,
5362 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
5365 Yalien_nB, FALSE, TRUE,
5366 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
5369 Yalien_e, FALSE, FALSE,
5370 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
5373 Yalien_eB, FALSE, TRUE,
5374 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
5377 Yalien_s, FALSE, FALSE,
5378 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
5381 Yalien_sB, FALSE, TRUE,
5382 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
5385 Yalien_w, FALSE, FALSE,
5386 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
5389 Yalien_wB, FALSE, TRUE,
5390 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
5393 Yalien_stone, FALSE, FALSE,
5394 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
5397 Yalien_spring, FALSE, FALSE,
5398 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
5401 Xemerald, TRUE, FALSE,
5405 Xemerald_pause, FALSE, FALSE,
5409 Xemerald_fall, FALSE, FALSE,
5413 Xemerald_shine, FALSE, FALSE,
5414 EL_EMERALD, ACTION_TWINKLING, -1
5417 Yemerald_s, FALSE, FALSE,
5418 EL_EMERALD, ACTION_FALLING, -1
5421 Yemerald_sB, FALSE, TRUE,
5422 EL_EMERALD, ACTION_FALLING, -1
5425 Yemerald_e, FALSE, FALSE,
5426 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
5429 Yemerald_eB, FALSE, TRUE,
5430 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
5433 Yemerald_w, FALSE, FALSE,
5434 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
5437 Yemerald_wB, FALSE, TRUE,
5438 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
5441 Yemerald_eat, FALSE, FALSE,
5442 EL_EMERALD, ACTION_COLLECTING, -1
5445 Yemerald_stone, FALSE, FALSE,
5446 EL_NUT, ACTION_BREAKING, -1
5449 Xdiamond, TRUE, FALSE,
5453 Xdiamond_pause, FALSE, FALSE,
5457 Xdiamond_fall, FALSE, FALSE,
5461 Xdiamond_shine, FALSE, FALSE,
5462 EL_DIAMOND, ACTION_TWINKLING, -1
5465 Ydiamond_s, FALSE, FALSE,
5466 EL_DIAMOND, ACTION_FALLING, -1
5469 Ydiamond_sB, FALSE, TRUE,
5470 EL_DIAMOND, ACTION_FALLING, -1
5473 Ydiamond_e, FALSE, FALSE,
5474 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
5477 Ydiamond_eB, FALSE, TRUE,
5478 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
5481 Ydiamond_w, FALSE, FALSE,
5482 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
5485 Ydiamond_wB, FALSE, TRUE,
5486 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
5489 Ydiamond_eat, FALSE, FALSE,
5490 EL_DIAMOND, ACTION_COLLECTING, -1
5493 Ydiamond_stone, FALSE, FALSE,
5494 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
5497 Xdrip_fall, TRUE, FALSE,
5498 EL_AMOEBA_DROP, -1, -1
5501 Xdrip_stretch, FALSE, FALSE,
5502 EL_AMOEBA_DROP, ACTION_FALLING, -1
5505 Xdrip_stretchB, FALSE, TRUE,
5506 EL_AMOEBA_DROP, ACTION_FALLING, -1
5509 Xdrip_eat, FALSE, FALSE,
5510 EL_AMOEBA_DROP, ACTION_GROWING, -1
5513 Ydrip_s1, FALSE, FALSE,
5514 EL_AMOEBA_DROP, ACTION_FALLING, -1
5517 Ydrip_s1B, FALSE, TRUE,
5518 EL_AMOEBA_DROP, ACTION_FALLING, -1
5521 Ydrip_s2, FALSE, FALSE,
5522 EL_AMOEBA_DROP, ACTION_FALLING, -1
5525 Ydrip_s2B, FALSE, TRUE,
5526 EL_AMOEBA_DROP, ACTION_FALLING, -1
5533 Xbomb_pause, FALSE, FALSE,
5537 Xbomb_fall, FALSE, FALSE,
5541 Ybomb_s, FALSE, FALSE,
5542 EL_BOMB, ACTION_FALLING, -1
5545 Ybomb_sB, FALSE, TRUE,
5546 EL_BOMB, ACTION_FALLING, -1
5549 Ybomb_e, FALSE, FALSE,
5550 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
5553 Ybomb_eB, FALSE, TRUE,
5554 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
5557 Ybomb_w, FALSE, FALSE,
5558 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
5561 Ybomb_wB, FALSE, TRUE,
5562 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
5565 Ybomb_eat, FALSE, FALSE,
5566 EL_BOMB, ACTION_ACTIVATING, -1
5569 Xballoon, TRUE, FALSE,
5573 Yballoon_n, FALSE, FALSE,
5574 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
5577 Yballoon_nB, FALSE, TRUE,
5578 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
5581 Yballoon_e, FALSE, FALSE,
5582 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
5585 Yballoon_eB, FALSE, TRUE,
5586 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
5589 Yballoon_s, FALSE, FALSE,
5590 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
5593 Yballoon_sB, FALSE, TRUE,
5594 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
5597 Yballoon_w, FALSE, FALSE,
5598 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
5601 Yballoon_wB, FALSE, TRUE,
5602 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
5605 Xgrass, TRUE, FALSE,
5606 EL_EMC_GRASS, -1, -1
5609 Ygrass_nB, FALSE, FALSE,
5610 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
5613 Ygrass_eB, FALSE, FALSE,
5614 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
5617 Ygrass_sB, FALSE, FALSE,
5618 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
5621 Ygrass_wB, FALSE, FALSE,
5622 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
5629 Ydirt_nB, FALSE, FALSE,
5630 EL_SAND, ACTION_DIGGING, MV_BIT_UP
5633 Ydirt_eB, FALSE, FALSE,
5634 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
5637 Ydirt_sB, FALSE, FALSE,
5638 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
5641 Ydirt_wB, FALSE, FALSE,
5642 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
5645 Xacid_ne, TRUE, FALSE,
5646 EL_ACID_POOL_TOPRIGHT, -1, -1
5649 Xacid_se, TRUE, FALSE,
5650 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
5653 Xacid_s, TRUE, FALSE,
5654 EL_ACID_POOL_BOTTOM, -1, -1
5657 Xacid_sw, TRUE, FALSE,
5658 EL_ACID_POOL_BOTTOMLEFT, -1, -1
5661 Xacid_nw, TRUE, FALSE,
5662 EL_ACID_POOL_TOPLEFT, -1, -1
5665 Xacid_1, TRUE, FALSE,
5669 Xacid_2, FALSE, FALSE,
5673 Xacid_3, FALSE, FALSE,
5677 Xacid_4, FALSE, FALSE,
5681 Xacid_5, FALSE, FALSE,
5685 Xacid_6, FALSE, FALSE,
5689 Xacid_7, FALSE, FALSE,
5693 Xacid_8, FALSE, FALSE,
5697 Xball_1, TRUE, FALSE,
5698 EL_EMC_MAGIC_BALL, -1, -1
5701 Xball_1B, FALSE, FALSE,
5702 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5705 Xball_2, FALSE, FALSE,
5706 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5709 Xball_2B, FALSE, FALSE,
5710 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5713 Yball_eat, FALSE, FALSE,
5714 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
5717 Ykey_1_eat, FALSE, FALSE,
5718 EL_EM_KEY_1, ACTION_COLLECTING, -1
5721 Ykey_2_eat, FALSE, FALSE,
5722 EL_EM_KEY_2, ACTION_COLLECTING, -1
5725 Ykey_3_eat, FALSE, FALSE,
5726 EL_EM_KEY_3, ACTION_COLLECTING, -1
5729 Ykey_4_eat, FALSE, FALSE,
5730 EL_EM_KEY_4, ACTION_COLLECTING, -1
5733 Ykey_5_eat, FALSE, FALSE,
5734 EL_EMC_KEY_5, ACTION_COLLECTING, -1
5737 Ykey_6_eat, FALSE, FALSE,
5738 EL_EMC_KEY_6, ACTION_COLLECTING, -1
5741 Ykey_7_eat, FALSE, FALSE,
5742 EL_EMC_KEY_7, ACTION_COLLECTING, -1
5745 Ykey_8_eat, FALSE, FALSE,
5746 EL_EMC_KEY_8, ACTION_COLLECTING, -1
5749 Ylenses_eat, FALSE, FALSE,
5750 EL_EMC_LENSES, ACTION_COLLECTING, -1
5753 Ymagnify_eat, FALSE, FALSE,
5754 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
5757 Ygrass_eat, FALSE, FALSE,
5758 EL_EMC_GRASS, ACTION_SNAPPING, -1
5761 Ydirt_eat, FALSE, FALSE,
5762 EL_SAND, ACTION_SNAPPING, -1
5765 Xgrow_ns, TRUE, FALSE,
5766 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
5769 Ygrow_ns_eat, FALSE, FALSE,
5770 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
5773 Xgrow_ew, TRUE, FALSE,
5774 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
5777 Ygrow_ew_eat, FALSE, FALSE,
5778 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
5781 Xwonderwall, TRUE, FALSE,
5782 EL_MAGIC_WALL, -1, -1
5785 XwonderwallB, FALSE, FALSE,
5786 EL_MAGIC_WALL, ACTION_ACTIVE, -1
5789 Xamoeba_1, TRUE, FALSE,
5790 EL_AMOEBA_DRY, ACTION_OTHER, -1
5793 Xamoeba_2, FALSE, FALSE,
5794 EL_AMOEBA_DRY, ACTION_OTHER, -1
5797 Xamoeba_3, FALSE, FALSE,
5798 EL_AMOEBA_DRY, ACTION_OTHER, -1
5801 Xamoeba_4, FALSE, FALSE,
5802 EL_AMOEBA_DRY, ACTION_OTHER, -1
5805 Xamoeba_5, TRUE, FALSE,
5806 EL_AMOEBA_WET, ACTION_OTHER, -1
5809 Xamoeba_6, FALSE, FALSE,
5810 EL_AMOEBA_WET, ACTION_OTHER, -1
5813 Xamoeba_7, FALSE, FALSE,
5814 EL_AMOEBA_WET, ACTION_OTHER, -1
5817 Xamoeba_8, FALSE, FALSE,
5818 EL_AMOEBA_WET, ACTION_OTHER, -1
5821 Xdoor_1, TRUE, FALSE,
5822 EL_EM_GATE_1, -1, -1
5825 Xdoor_2, TRUE, FALSE,
5826 EL_EM_GATE_2, -1, -1
5829 Xdoor_3, TRUE, FALSE,
5830 EL_EM_GATE_3, -1, -1
5833 Xdoor_4, TRUE, FALSE,
5834 EL_EM_GATE_4, -1, -1
5837 Xdoor_5, TRUE, FALSE,
5838 EL_EMC_GATE_5, -1, -1
5841 Xdoor_6, TRUE, FALSE,
5842 EL_EMC_GATE_6, -1, -1
5845 Xdoor_7, TRUE, FALSE,
5846 EL_EMC_GATE_7, -1, -1
5849 Xdoor_8, TRUE, FALSE,
5850 EL_EMC_GATE_8, -1, -1
5853 Xkey_1, TRUE, FALSE,
5857 Xkey_2, TRUE, FALSE,
5861 Xkey_3, TRUE, FALSE,
5865 Xkey_4, TRUE, FALSE,
5869 Xkey_5, TRUE, FALSE,
5870 EL_EMC_KEY_5, -1, -1
5873 Xkey_6, TRUE, FALSE,
5874 EL_EMC_KEY_6, -1, -1
5877 Xkey_7, TRUE, FALSE,
5878 EL_EMC_KEY_7, -1, -1
5881 Xkey_8, TRUE, FALSE,
5882 EL_EMC_KEY_8, -1, -1
5885 Xwind_n, TRUE, FALSE,
5886 EL_BALLOON_SWITCH_UP, -1, -1
5889 Xwind_e, TRUE, FALSE,
5890 EL_BALLOON_SWITCH_RIGHT, -1, -1
5893 Xwind_s, TRUE, FALSE,
5894 EL_BALLOON_SWITCH_DOWN, -1, -1
5897 Xwind_w, TRUE, FALSE,
5898 EL_BALLOON_SWITCH_LEFT, -1, -1
5901 Xwind_nesw, TRUE, FALSE,
5902 EL_BALLOON_SWITCH_ANY, -1, -1
5905 Xwind_stop, TRUE, FALSE,
5906 EL_BALLOON_SWITCH_NONE, -1, -1
5910 EL_EM_EXIT_CLOSED, -1, -1
5913 Xexit_1, TRUE, FALSE,
5914 EL_EM_EXIT_OPEN, -1, -1
5917 Xexit_2, FALSE, FALSE,
5918 EL_EM_EXIT_OPEN, -1, -1
5921 Xexit_3, FALSE, FALSE,
5922 EL_EM_EXIT_OPEN, -1, -1
5925 Xdynamite, TRUE, FALSE,
5926 EL_EM_DYNAMITE, -1, -1
5929 Ydynamite_eat, FALSE, FALSE,
5930 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
5933 Xdynamite_1, TRUE, FALSE,
5934 EL_EM_DYNAMITE_ACTIVE, -1, -1
5937 Xdynamite_2, FALSE, FALSE,
5938 EL_EM_DYNAMITE_ACTIVE, -1, -1
5941 Xdynamite_3, FALSE, FALSE,
5942 EL_EM_DYNAMITE_ACTIVE, -1, -1
5945 Xdynamite_4, FALSE, FALSE,
5946 EL_EM_DYNAMITE_ACTIVE, -1, -1
5949 Xbumper, TRUE, FALSE,
5950 EL_EMC_SPRING_BUMPER, -1, -1
5953 XbumperB, FALSE, FALSE,
5954 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
5957 Xwheel, TRUE, FALSE,
5958 EL_ROBOT_WHEEL, -1, -1
5961 XwheelB, FALSE, FALSE,
5962 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
5965 Xswitch, TRUE, FALSE,
5966 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
5969 XswitchB, FALSE, FALSE,
5970 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
5974 EL_QUICKSAND_EMPTY, -1, -1
5977 Xsand_stone, TRUE, FALSE,
5978 EL_QUICKSAND_FULL, -1, -1
5981 Xsand_stonein_1, FALSE, TRUE,
5982 EL_ROCK, ACTION_FILLING, -1
5985 Xsand_stonein_2, FALSE, TRUE,
5986 EL_ROCK, ACTION_FILLING, -1
5989 Xsand_stonein_3, FALSE, TRUE,
5990 EL_ROCK, ACTION_FILLING, -1
5993 Xsand_stonein_4, FALSE, TRUE,
5994 EL_ROCK, ACTION_FILLING, -1
5997 Xsand_stonesand_1, FALSE, FALSE,
5998 EL_QUICKSAND_EMPTYING, -1, -1
6001 Xsand_stonesand_2, FALSE, FALSE,
6002 EL_QUICKSAND_EMPTYING, -1, -1
6005 Xsand_stonesand_3, FALSE, FALSE,
6006 EL_QUICKSAND_EMPTYING, -1, -1
6009 Xsand_stonesand_4, FALSE, FALSE,
6010 EL_QUICKSAND_EMPTYING, -1, -1
6013 Xsand_stonesand_quickout_1, FALSE, FALSE,
6014 EL_QUICKSAND_EMPTYING, -1, -1
6017 Xsand_stonesand_quickout_2, FALSE, FALSE,
6018 EL_QUICKSAND_EMPTYING, -1, -1
6021 Xsand_stoneout_1, FALSE, FALSE,
6022 EL_ROCK, ACTION_EMPTYING, -1
6025 Xsand_stoneout_2, FALSE, FALSE,
6026 EL_ROCK, ACTION_EMPTYING, -1
6029 Xsand_sandstone_1, FALSE, FALSE,
6030 EL_QUICKSAND_FILLING, -1, -1
6033 Xsand_sandstone_2, FALSE, FALSE,
6034 EL_QUICKSAND_FILLING, -1, -1
6037 Xsand_sandstone_3, FALSE, FALSE,
6038 EL_QUICKSAND_FILLING, -1, -1
6041 Xsand_sandstone_4, FALSE, FALSE,
6042 EL_QUICKSAND_FILLING, -1, -1
6045 Xplant, TRUE, FALSE,
6046 EL_EMC_PLANT, -1, -1
6049 Yplant, FALSE, FALSE,
6050 EL_EMC_PLANT, -1, -1
6053 Xlenses, TRUE, FALSE,
6054 EL_EMC_LENSES, -1, -1
6057 Xmagnify, TRUE, FALSE,
6058 EL_EMC_MAGNIFIER, -1, -1
6061 Xdripper, TRUE, FALSE,
6062 EL_EMC_DRIPPER, -1, -1
6065 XdripperB, FALSE, FALSE,
6066 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
6069 Xfake_blank, TRUE, FALSE,
6070 EL_INVISIBLE_WALL, -1, -1
6073 Xfake_blankB, FALSE, FALSE,
6074 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
6077 Xfake_grass, TRUE, FALSE,
6078 EL_EMC_FAKE_GRASS, -1, -1
6081 Xfake_grassB, FALSE, FALSE,
6082 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
6085 Xfake_door_1, TRUE, FALSE,
6086 EL_EM_GATE_1_GRAY, -1, -1
6089 Xfake_door_2, TRUE, FALSE,
6090 EL_EM_GATE_2_GRAY, -1, -1
6093 Xfake_door_3, TRUE, FALSE,
6094 EL_EM_GATE_3_GRAY, -1, -1
6097 Xfake_door_4, TRUE, FALSE,
6098 EL_EM_GATE_4_GRAY, -1, -1
6101 Xfake_door_5, TRUE, FALSE,
6102 EL_EMC_GATE_5_GRAY, -1, -1
6105 Xfake_door_6, TRUE, FALSE,
6106 EL_EMC_GATE_6_GRAY, -1, -1
6109 Xfake_door_7, TRUE, FALSE,
6110 EL_EMC_GATE_7_GRAY, -1, -1
6113 Xfake_door_8, TRUE, FALSE,
6114 EL_EMC_GATE_8_GRAY, -1, -1
6117 Xfake_acid_1, TRUE, FALSE,
6118 EL_EMC_FAKE_ACID, -1, -1
6121 Xfake_acid_2, FALSE, FALSE,
6122 EL_EMC_FAKE_ACID, -1, -1
6125 Xfake_acid_3, FALSE, FALSE,
6126 EL_EMC_FAKE_ACID, -1, -1
6129 Xfake_acid_4, FALSE, FALSE,
6130 EL_EMC_FAKE_ACID, -1, -1
6133 Xfake_acid_5, FALSE, FALSE,
6134 EL_EMC_FAKE_ACID, -1, -1
6137 Xfake_acid_6, FALSE, FALSE,
6138 EL_EMC_FAKE_ACID, -1, -1
6141 Xfake_acid_7, FALSE, FALSE,
6142 EL_EMC_FAKE_ACID, -1, -1
6145 Xfake_acid_8, FALSE, FALSE,
6146 EL_EMC_FAKE_ACID, -1, -1
6149 Xsteel_1, TRUE, FALSE,
6150 EL_STEELWALL, -1, -1
6153 Xsteel_2, TRUE, FALSE,
6154 EL_EMC_STEELWALL_2, -1, -1
6157 Xsteel_3, TRUE, FALSE,
6158 EL_EMC_STEELWALL_3, -1, -1
6161 Xsteel_4, TRUE, FALSE,
6162 EL_EMC_STEELWALL_4, -1, -1
6165 Xwall_1, TRUE, FALSE,
6169 Xwall_2, TRUE, FALSE,
6170 EL_EMC_WALL_14, -1, -1
6173 Xwall_3, TRUE, FALSE,
6174 EL_EMC_WALL_15, -1, -1
6177 Xwall_4, TRUE, FALSE,
6178 EL_EMC_WALL_16, -1, -1
6181 Xround_wall_1, TRUE, FALSE,
6182 EL_WALL_SLIPPERY, -1, -1
6185 Xround_wall_2, TRUE, FALSE,
6186 EL_EMC_WALL_SLIPPERY_2, -1, -1
6189 Xround_wall_3, TRUE, FALSE,
6190 EL_EMC_WALL_SLIPPERY_3, -1, -1
6193 Xround_wall_4, TRUE, FALSE,
6194 EL_EMC_WALL_SLIPPERY_4, -1, -1
6197 Xdecor_1, TRUE, FALSE,
6198 EL_EMC_WALL_8, -1, -1
6201 Xdecor_2, TRUE, FALSE,
6202 EL_EMC_WALL_6, -1, -1
6205 Xdecor_3, TRUE, FALSE,
6206 EL_EMC_WALL_4, -1, -1
6209 Xdecor_4, TRUE, FALSE,
6210 EL_EMC_WALL_7, -1, -1
6213 Xdecor_5, TRUE, FALSE,
6214 EL_EMC_WALL_5, -1, -1
6217 Xdecor_6, TRUE, FALSE,
6218 EL_EMC_WALL_9, -1, -1
6221 Xdecor_7, TRUE, FALSE,
6222 EL_EMC_WALL_10, -1, -1
6225 Xdecor_8, TRUE, FALSE,
6226 EL_EMC_WALL_1, -1, -1
6229 Xdecor_9, TRUE, FALSE,
6230 EL_EMC_WALL_2, -1, -1
6233 Xdecor_10, TRUE, FALSE,
6234 EL_EMC_WALL_3, -1, -1
6237 Xdecor_11, TRUE, FALSE,
6238 EL_EMC_WALL_11, -1, -1
6241 Xdecor_12, TRUE, FALSE,
6242 EL_EMC_WALL_12, -1, -1
6245 Xalpha_0, TRUE, FALSE,
6246 EL_CHAR('0'), -1, -1
6249 Xalpha_1, TRUE, FALSE,
6250 EL_CHAR('1'), -1, -1
6253 Xalpha_2, TRUE, FALSE,
6254 EL_CHAR('2'), -1, -1
6257 Xalpha_3, TRUE, FALSE,
6258 EL_CHAR('3'), -1, -1
6261 Xalpha_4, TRUE, FALSE,
6262 EL_CHAR('4'), -1, -1
6265 Xalpha_5, TRUE, FALSE,
6266 EL_CHAR('5'), -1, -1
6269 Xalpha_6, TRUE, FALSE,
6270 EL_CHAR('6'), -1, -1
6273 Xalpha_7, TRUE, FALSE,
6274 EL_CHAR('7'), -1, -1
6277 Xalpha_8, TRUE, FALSE,
6278 EL_CHAR('8'), -1, -1
6281 Xalpha_9, TRUE, FALSE,
6282 EL_CHAR('9'), -1, -1
6285 Xalpha_excla, TRUE, FALSE,
6286 EL_CHAR('!'), -1, -1
6289 Xalpha_quote, TRUE, FALSE,
6290 EL_CHAR('"'), -1, -1
6293 Xalpha_comma, TRUE, FALSE,
6294 EL_CHAR(','), -1, -1
6297 Xalpha_minus, TRUE, FALSE,
6298 EL_CHAR('-'), -1, -1
6301 Xalpha_perio, TRUE, FALSE,
6302 EL_CHAR('.'), -1, -1
6305 Xalpha_colon, TRUE, FALSE,
6306 EL_CHAR(':'), -1, -1
6309 Xalpha_quest, TRUE, FALSE,
6310 EL_CHAR('?'), -1, -1
6313 Xalpha_a, TRUE, FALSE,
6314 EL_CHAR('A'), -1, -1
6317 Xalpha_b, TRUE, FALSE,
6318 EL_CHAR('B'), -1, -1
6321 Xalpha_c, TRUE, FALSE,
6322 EL_CHAR('C'), -1, -1
6325 Xalpha_d, TRUE, FALSE,
6326 EL_CHAR('D'), -1, -1
6329 Xalpha_e, TRUE, FALSE,
6330 EL_CHAR('E'), -1, -1
6333 Xalpha_f, TRUE, FALSE,
6334 EL_CHAR('F'), -1, -1
6337 Xalpha_g, TRUE, FALSE,
6338 EL_CHAR('G'), -1, -1
6341 Xalpha_h, TRUE, FALSE,
6342 EL_CHAR('H'), -1, -1
6345 Xalpha_i, TRUE, FALSE,
6346 EL_CHAR('I'), -1, -1
6349 Xalpha_j, TRUE, FALSE,
6350 EL_CHAR('J'), -1, -1
6353 Xalpha_k, TRUE, FALSE,
6354 EL_CHAR('K'), -1, -1
6357 Xalpha_l, TRUE, FALSE,
6358 EL_CHAR('L'), -1, -1
6361 Xalpha_m, TRUE, FALSE,
6362 EL_CHAR('M'), -1, -1
6365 Xalpha_n, TRUE, FALSE,
6366 EL_CHAR('N'), -1, -1
6369 Xalpha_o, TRUE, FALSE,
6370 EL_CHAR('O'), -1, -1
6373 Xalpha_p, TRUE, FALSE,
6374 EL_CHAR('P'), -1, -1
6377 Xalpha_q, TRUE, FALSE,
6378 EL_CHAR('Q'), -1, -1
6381 Xalpha_r, TRUE, FALSE,
6382 EL_CHAR('R'), -1, -1
6385 Xalpha_s, TRUE, FALSE,
6386 EL_CHAR('S'), -1, -1
6389 Xalpha_t, TRUE, FALSE,
6390 EL_CHAR('T'), -1, -1
6393 Xalpha_u, TRUE, FALSE,
6394 EL_CHAR('U'), -1, -1
6397 Xalpha_v, TRUE, FALSE,
6398 EL_CHAR('V'), -1, -1
6401 Xalpha_w, TRUE, FALSE,
6402 EL_CHAR('W'), -1, -1
6405 Xalpha_x, TRUE, FALSE,
6406 EL_CHAR('X'), -1, -1
6409 Xalpha_y, TRUE, FALSE,
6410 EL_CHAR('Y'), -1, -1
6413 Xalpha_z, TRUE, FALSE,
6414 EL_CHAR('Z'), -1, -1
6417 Xalpha_arrow_e, TRUE, FALSE,
6418 EL_CHAR('>'), -1, -1
6421 Xalpha_arrow_w, TRUE, FALSE,
6422 EL_CHAR('<'), -1, -1
6425 Xalpha_copyr, TRUE, FALSE,
6426 EL_CHAR(CHAR_BYTE_COPYRIGHT), -1, -1
6430 Xboom_bug, FALSE, FALSE,
6431 EL_BUG, ACTION_EXPLODING, -1
6434 Xboom_bomb, FALSE, FALSE,
6435 EL_BOMB, ACTION_EXPLODING, -1
6438 Xboom_android, FALSE, FALSE,
6439 EL_EMC_ANDROID, ACTION_OTHER, -1
6442 Xboom_1, FALSE, FALSE,
6443 EL_DEFAULT, ACTION_EXPLODING, -1
6446 Xboom_2, FALSE, FALSE,
6447 EL_DEFAULT, ACTION_EXPLODING, -1
6450 Znormal, FALSE, FALSE,
6454 Zdynamite, FALSE, FALSE,
6458 Zplayer, FALSE, FALSE,
6462 ZBORDER, FALSE, FALSE,
6472 static struct Mapping_EM_to_RND_player
6481 em_player_mapping_list[] =
6485 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
6489 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
6493 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
6497 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
6501 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
6505 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
6509 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
6513 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
6517 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
6521 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
6525 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
6529 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
6533 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
6537 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
6541 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
6545 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
6549 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
6553 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
6557 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
6561 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
6565 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
6569 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
6573 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
6577 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
6581 EL_PLAYER_1, ACTION_DEFAULT, -1,
6585 EL_PLAYER_2, ACTION_DEFAULT, -1,
6589 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
6593 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
6597 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
6601 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
6605 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
6609 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
6613 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
6617 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
6621 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
6625 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
6629 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
6633 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
6637 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
6641 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
6645 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
6649 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
6653 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
6657 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
6661 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
6665 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
6669 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
6673 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
6677 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
6681 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
6685 EL_PLAYER_3, ACTION_DEFAULT, -1,
6689 EL_PLAYER_4, ACTION_DEFAULT, -1,
6698 int map_element_RND_to_EM(int element_rnd)
6700 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
6701 static boolean mapping_initialized = FALSE;
6703 if (!mapping_initialized)
6707 /* return "Xalpha_quest" for all undefined elements in mapping array */
6708 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
6709 mapping_RND_to_EM[i] = Xalpha_quest;
6711 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6712 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
6713 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
6714 em_object_mapping_list[i].element_em;
6716 mapping_initialized = TRUE;
6719 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
6720 return mapping_RND_to_EM[element_rnd];
6722 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
6727 int map_element_EM_to_RND(int element_em)
6729 static unsigned short mapping_EM_to_RND[TILE_MAX];
6730 static boolean mapping_initialized = FALSE;
6732 if (!mapping_initialized)
6736 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
6737 for (i = 0; i < TILE_MAX; i++)
6738 mapping_EM_to_RND[i] = EL_UNKNOWN;
6740 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6741 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
6742 em_object_mapping_list[i].element_rnd;
6744 mapping_initialized = TRUE;
6747 if (element_em >= 0 && element_em < TILE_MAX)
6748 return mapping_EM_to_RND[element_em];
6750 Error(ERR_WARN, "invalid EM level element %d", element_em);
6755 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
6757 struct LevelInfo_EM *level_em = level->native_em_level;
6758 struct LEVEL *lev = level_em->lev;
6761 for (i = 0; i < TILE_MAX; i++)
6762 lev->android_array[i] = Xblank;
6764 for (i = 0; i < level->num_android_clone_elements; i++)
6766 int element_rnd = level->android_clone_element[i];
6767 int element_em = map_element_RND_to_EM(element_rnd);
6769 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
6770 if (em_object_mapping_list[j].element_rnd == element_rnd)
6771 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
6775 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
6777 struct LevelInfo_EM *level_em = level->native_em_level;
6778 struct LEVEL *lev = level_em->lev;
6781 level->num_android_clone_elements = 0;
6783 for (i = 0; i < TILE_MAX; i++)
6785 int element_em = lev->android_array[i];
6787 boolean element_found = FALSE;
6789 if (element_em == Xblank)
6792 element_rnd = map_element_EM_to_RND(element_em);
6794 for (j = 0; j < level->num_android_clone_elements; j++)
6795 if (level->android_clone_element[j] == element_rnd)
6796 element_found = TRUE;
6800 level->android_clone_element[level->num_android_clone_elements++] =
6803 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
6808 if (level->num_android_clone_elements == 0)
6810 level->num_android_clone_elements = 1;
6811 level->android_clone_element[0] = EL_EMPTY;
6815 int map_direction_RND_to_EM(int direction)
6817 return (direction == MV_UP ? 0 :
6818 direction == MV_RIGHT ? 1 :
6819 direction == MV_DOWN ? 2 :
6820 direction == MV_LEFT ? 3 :
6824 int map_direction_EM_to_RND(int direction)
6826 return (direction == 0 ? MV_UP :
6827 direction == 1 ? MV_RIGHT :
6828 direction == 2 ? MV_DOWN :
6829 direction == 3 ? MV_LEFT :
6833 int map_element_RND_to_SP(int element_rnd)
6835 int element_sp = 0x20; /* map unknown elements to yellow "hardware" */
6837 if (element_rnd >= EL_SP_START &&
6838 element_rnd <= EL_SP_END)
6839 element_sp = element_rnd - EL_SP_START;
6840 else if (element_rnd == EL_EMPTY_SPACE)
6842 else if (element_rnd == EL_INVISIBLE_WALL)
6848 int map_element_SP_to_RND(int element_sp)
6850 int element_rnd = EL_UNKNOWN;
6852 if (element_sp >= 0x00 &&
6854 element_rnd = EL_SP_START + element_sp;
6855 else if (element_sp == 0x28)
6856 element_rnd = EL_INVISIBLE_WALL;
6861 int map_action_SP_to_RND(int action_sp)
6865 case actActive: return ACTION_ACTIVE;
6866 case actImpact: return ACTION_IMPACT;
6867 case actExploding: return ACTION_EXPLODING;
6868 case actDigging: return ACTION_DIGGING;
6869 case actSnapping: return ACTION_SNAPPING;
6870 case actCollecting: return ACTION_COLLECTING;
6871 case actPassing: return ACTION_PASSING;
6872 case actPushing: return ACTION_PUSHING;
6873 case actDropping: return ACTION_DROPPING;
6875 default: return ACTION_DEFAULT;
6879 int get_next_element(int element)
6883 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
6884 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
6885 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
6886 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
6887 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
6888 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
6889 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
6890 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
6891 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
6892 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
6893 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
6895 default: return element;
6899 int el_act_dir2img(int element, int action, int direction)
6901 element = GFX_ELEMENT(element);
6902 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
6904 /* direction_graphic[][] == graphic[] for undefined direction graphics */
6905 return element_info[element].direction_graphic[action][direction];
6908 static int el_act_dir2crm(int element, int action, int direction)
6910 element = GFX_ELEMENT(element);
6911 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
6913 /* direction_graphic[][] == graphic[] for undefined direction graphics */
6914 return element_info[element].direction_crumbled[action][direction];
6917 int el_act2img(int element, int action)
6919 element = GFX_ELEMENT(element);
6921 return element_info[element].graphic[action];
6924 int el_act2crm(int element, int action)
6926 element = GFX_ELEMENT(element);
6928 return element_info[element].crumbled[action];
6931 int el_dir2img(int element, int direction)
6933 element = GFX_ELEMENT(element);
6935 return el_act_dir2img(element, ACTION_DEFAULT, direction);
6938 int el2baseimg(int element)
6940 return element_info[element].graphic[ACTION_DEFAULT];
6943 int el2img(int element)
6945 element = GFX_ELEMENT(element);
6947 return element_info[element].graphic[ACTION_DEFAULT];
6950 int el2edimg(int element)
6952 element = GFX_ELEMENT(element);
6954 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
6957 int el2preimg(int element)
6959 element = GFX_ELEMENT(element);
6961 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
6964 int el2panelimg(int element)
6966 element = GFX_ELEMENT(element);
6968 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL];
6971 int font2baseimg(int font_nr)
6973 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
6976 int getBeltNrFromBeltElement(int element)
6978 return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
6979 element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
6980 element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
6983 int getBeltNrFromBeltActiveElement(int element)
6985 return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
6986 element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
6987 element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
6990 int getBeltNrFromBeltSwitchElement(int element)
6992 return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
6993 element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
6994 element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
6997 int getBeltDirNrFromBeltElement(int element)
6999 static int belt_base_element[4] =
7001 EL_CONVEYOR_BELT_1_LEFT,
7002 EL_CONVEYOR_BELT_2_LEFT,
7003 EL_CONVEYOR_BELT_3_LEFT,
7004 EL_CONVEYOR_BELT_4_LEFT
7007 int belt_nr = getBeltNrFromBeltElement(element);
7008 int belt_dir_nr = element - belt_base_element[belt_nr];
7010 return (belt_dir_nr % 3);
7013 int getBeltDirNrFromBeltSwitchElement(int element)
7015 static int belt_base_element[4] =
7017 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
7018 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
7019 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
7020 EL_CONVEYOR_BELT_4_SWITCH_LEFT
7023 int belt_nr = getBeltNrFromBeltSwitchElement(element);
7024 int belt_dir_nr = element - belt_base_element[belt_nr];
7026 return (belt_dir_nr % 3);
7029 int getBeltDirFromBeltElement(int element)
7031 static int belt_move_dir[3] =
7038 int belt_dir_nr = getBeltDirNrFromBeltElement(element);
7040 return belt_move_dir[belt_dir_nr];
7043 int getBeltDirFromBeltSwitchElement(int element)
7045 static int belt_move_dir[3] =
7052 int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
7054 return belt_move_dir[belt_dir_nr];
7057 int getBeltElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
7059 static int belt_base_element[4] =
7061 EL_CONVEYOR_BELT_1_LEFT,
7062 EL_CONVEYOR_BELT_2_LEFT,
7063 EL_CONVEYOR_BELT_3_LEFT,
7064 EL_CONVEYOR_BELT_4_LEFT
7067 return belt_base_element[belt_nr] + belt_dir_nr;
7070 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
7072 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
7074 return getBeltElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
7077 int getBeltSwitchElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
7079 static int belt_base_element[4] =
7081 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
7082 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
7083 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
7084 EL_CONVEYOR_BELT_4_SWITCH_LEFT
7087 return belt_base_element[belt_nr] + belt_dir_nr;
7090 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
7092 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
7094 return getBeltSwitchElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
7097 boolean getTeamMode_EM()
7099 return game.team_mode;
7102 int getGameFrameDelay_EM(int native_em_game_frame_delay)
7104 int game_frame_delay_value;
7106 game_frame_delay_value =
7107 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
7108 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
7111 if (tape.playing && tape.warp_forward && !tape.pausing)
7112 game_frame_delay_value = 0;
7114 return game_frame_delay_value;
7117 unsigned int InitRND(int seed)
7119 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
7120 return InitEngineRandom_EM(seed);
7121 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
7122 return InitEngineRandom_SP(seed);
7124 return InitEngineRandom_RND(seed);
7127 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
7128 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
7130 inline static int get_effective_element_EM(int tile, int frame_em)
7132 int element = object_mapping[tile].element_rnd;
7133 int action = object_mapping[tile].action;
7134 boolean is_backside = object_mapping[tile].is_backside;
7135 boolean action_removing = (action == ACTION_DIGGING ||
7136 action == ACTION_SNAPPING ||
7137 action == ACTION_COLLECTING);
7143 case Yacid_splash_eB:
7144 case Yacid_splash_wB:
7145 return (frame_em > 5 ? EL_EMPTY : element);
7151 else /* frame_em == 7 */
7155 case Yacid_splash_eB:
7156 case Yacid_splash_wB:
7159 case Yemerald_stone:
7162 case Ydiamond_stone:
7166 case Xdrip_stretchB:
7185 case Xsand_stonein_1:
7186 case Xsand_stonein_2:
7187 case Xsand_stonein_3:
7188 case Xsand_stonein_4:
7192 return (is_backside || action_removing ? EL_EMPTY : element);
7197 inline static boolean check_linear_animation_EM(int tile)
7201 case Xsand_stonesand_1:
7202 case Xsand_stonesand_quickout_1:
7203 case Xsand_sandstone_1:
7204 case Xsand_stonein_1:
7205 case Xsand_stoneout_1:
7224 case Yacid_splash_eB:
7225 case Yacid_splash_wB:
7226 case Yemerald_stone:
7233 inline static void set_crumbled_graphics_EM(struct GraphicInfo_EM *g_em,
7234 boolean has_crumbled_graphics,
7235 int crumbled, int sync_frame)
7237 /* if element can be crumbled, but certain action graphics are just empty
7238 space (like instantly snapping sand to empty space in 1 frame), do not
7239 treat these empty space graphics as crumbled graphics in EMC engine */
7240 if (crumbled == IMG_EMPTY_SPACE)
7241 has_crumbled_graphics = FALSE;
7243 if (has_crumbled_graphics)
7245 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
7246 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
7247 g_crumbled->anim_delay,
7248 g_crumbled->anim_mode,
7249 g_crumbled->anim_start_frame,
7252 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
7253 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
7255 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
7257 g_em->has_crumbled_graphics = TRUE;
7261 g_em->crumbled_bitmap = NULL;
7262 g_em->crumbled_src_x = 0;
7263 g_em->crumbled_src_y = 0;
7264 g_em->crumbled_border_size = 0;
7266 g_em->has_crumbled_graphics = FALSE;
7270 void ResetGfxAnimation_EM(int x, int y, int tile)
7275 void SetGfxAnimation_EM(struct GraphicInfo_EM *g_em,
7276 int tile, int frame_em, int x, int y)
7278 int action = object_mapping[tile].action;
7279 int direction = object_mapping[tile].direction;
7280 int effective_element = get_effective_element_EM(tile, frame_em);
7281 int graphic = (direction == MV_NONE ?
7282 el_act2img(effective_element, action) :
7283 el_act_dir2img(effective_element, action, direction));
7284 struct GraphicInfo *g = &graphic_info[graphic];
7286 boolean action_removing = (action == ACTION_DIGGING ||
7287 action == ACTION_SNAPPING ||
7288 action == ACTION_COLLECTING);
7289 boolean action_moving = (action == ACTION_FALLING ||
7290 action == ACTION_MOVING ||
7291 action == ACTION_PUSHING ||
7292 action == ACTION_EATING ||
7293 action == ACTION_FILLING ||
7294 action == ACTION_EMPTYING);
7295 boolean action_falling = (action == ACTION_FALLING ||
7296 action == ACTION_FILLING ||
7297 action == ACTION_EMPTYING);
7299 /* special case: graphic uses "2nd movement tile" and has defined
7300 7 frames for movement animation (or less) => use default graphic
7301 for last (8th) frame which ends the movement animation */
7302 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
7304 action = ACTION_DEFAULT; /* (keep action_* unchanged for now) */
7305 graphic = (direction == MV_NONE ?
7306 el_act2img(effective_element, action) :
7307 el_act_dir2img(effective_element, action, direction));
7309 g = &graphic_info[graphic];
7312 if ((action_removing || check_linear_animation_EM(tile)) && frame_em == 0)
7316 else if (action_moving)
7318 boolean is_backside = object_mapping[tile].is_backside;
7322 int direction = object_mapping[tile].direction;
7323 int move_dir = (action_falling ? MV_DOWN : direction);
7328 /* !!! TEST !!! NEW !!! DOES NOT WORK RIGHT YET !!! */
7329 if (g->double_movement && frame_em == 0)
7333 if (move_dir == MV_LEFT)
7334 GfxFrame[x - 1][y] = GfxFrame[x][y];
7335 else if (move_dir == MV_RIGHT)
7336 GfxFrame[x + 1][y] = GfxFrame[x][y];
7337 else if (move_dir == MV_UP)
7338 GfxFrame[x][y - 1] = GfxFrame[x][y];
7339 else if (move_dir == MV_DOWN)
7340 GfxFrame[x][y + 1] = GfxFrame[x][y];
7347 /* special case: animation for Xsand_stonesand_quickout_1/2 twice as fast */
7348 if (tile == Xsand_stonesand_quickout_1 ||
7349 tile == Xsand_stonesand_quickout_2)
7353 if (graphic_info[graphic].anim_global_sync)
7354 sync_frame = FrameCounter;
7355 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
7356 sync_frame = GfxFrame[x][y];
7358 sync_frame = 0; /* playfield border (pseudo steel) */
7360 SetRandomAnimationValue(x, y);
7362 int frame = getAnimationFrame(g->anim_frames,
7365 g->anim_start_frame,
7368 g_em->unique_identifier =
7369 (graphic << 16) | ((frame % 8) << 12) | (g_em->width << 6) | g_em->height;
7372 void getGraphicSourceObjectExt_EM(struct GraphicInfo_EM *g_em,
7373 int tile, int frame_em, int x, int y)
7375 int action = object_mapping[tile].action;
7376 int direction = object_mapping[tile].direction;
7377 boolean is_backside = object_mapping[tile].is_backside;
7378 int effective_element = get_effective_element_EM(tile, frame_em);
7379 int effective_action = action;
7380 int graphic = (direction == MV_NONE ?
7381 el_act2img(effective_element, effective_action) :
7382 el_act_dir2img(effective_element, effective_action,
7384 int crumbled = (direction == MV_NONE ?
7385 el_act2crm(effective_element, effective_action) :
7386 el_act_dir2crm(effective_element, effective_action,
7388 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7389 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7390 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7391 struct GraphicInfo *g = &graphic_info[graphic];
7394 /* special case: graphic uses "2nd movement tile" and has defined
7395 7 frames for movement animation (or less) => use default graphic
7396 for last (8th) frame which ends the movement animation */
7397 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
7399 effective_action = ACTION_DEFAULT;
7400 graphic = (direction == MV_NONE ?
7401 el_act2img(effective_element, effective_action) :
7402 el_act_dir2img(effective_element, effective_action,
7404 crumbled = (direction == MV_NONE ?
7405 el_act2crm(effective_element, effective_action) :
7406 el_act_dir2crm(effective_element, effective_action,
7409 g = &graphic_info[graphic];
7412 if (graphic_info[graphic].anim_global_sync)
7413 sync_frame = FrameCounter;
7414 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
7415 sync_frame = GfxFrame[x][y];
7417 sync_frame = 0; /* playfield border (pseudo steel) */
7419 SetRandomAnimationValue(x, y);
7421 int frame = getAnimationFrame(g->anim_frames,
7424 g->anim_start_frame,
7427 getGraphicSourceExt(graphic, frame, &g_em->bitmap, &g_em->src_x, &g_em->src_y,
7428 g->double_movement && is_backside);
7430 /* (updating the "crumbled" graphic definitions is probably not really needed,
7431 as animations for crumbled graphics can't be longer than one EMC cycle) */
7432 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
7436 void getGraphicSourcePlayerExt_EM(struct GraphicInfo_EM *g_em,
7437 int player_nr, int anim, int frame_em)
7439 int element = player_mapping[player_nr][anim].element_rnd;
7440 int action = player_mapping[player_nr][anim].action;
7441 int direction = player_mapping[player_nr][anim].direction;
7442 int graphic = (direction == MV_NONE ?
7443 el_act2img(element, action) :
7444 el_act_dir2img(element, action, direction));
7445 struct GraphicInfo *g = &graphic_info[graphic];
7448 InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
7450 stored_player[player_nr].StepFrame = frame_em;
7452 sync_frame = stored_player[player_nr].Frame;
7454 int frame = getAnimationFrame(g->anim_frames,
7457 g->anim_start_frame,
7460 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
7461 &g_em->src_x, &g_em->src_y, FALSE);
7464 void InitGraphicInfo_EM(void)
7469 int num_em_gfx_errors = 0;
7471 if (graphic_info_em_object[0][0].bitmap == NULL)
7473 /* EM graphics not yet initialized in em_open_all() */
7478 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
7481 /* always start with reliable default values */
7482 for (i = 0; i < TILE_MAX; i++)
7484 object_mapping[i].element_rnd = EL_UNKNOWN;
7485 object_mapping[i].is_backside = FALSE;
7486 object_mapping[i].action = ACTION_DEFAULT;
7487 object_mapping[i].direction = MV_NONE;
7490 /* always start with reliable default values */
7491 for (p = 0; p < MAX_PLAYERS; p++)
7493 for (i = 0; i < SPR_MAX; i++)
7495 player_mapping[p][i].element_rnd = EL_UNKNOWN;
7496 player_mapping[p][i].action = ACTION_DEFAULT;
7497 player_mapping[p][i].direction = MV_NONE;
7501 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
7503 int e = em_object_mapping_list[i].element_em;
7505 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
7506 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
7508 if (em_object_mapping_list[i].action != -1)
7509 object_mapping[e].action = em_object_mapping_list[i].action;
7511 if (em_object_mapping_list[i].direction != -1)
7512 object_mapping[e].direction =
7513 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
7516 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
7518 int a = em_player_mapping_list[i].action_em;
7519 int p = em_player_mapping_list[i].player_nr;
7521 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
7523 if (em_player_mapping_list[i].action != -1)
7524 player_mapping[p][a].action = em_player_mapping_list[i].action;
7526 if (em_player_mapping_list[i].direction != -1)
7527 player_mapping[p][a].direction =
7528 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
7531 for (i = 0; i < TILE_MAX; i++)
7533 int element = object_mapping[i].element_rnd;
7534 int action = object_mapping[i].action;
7535 int direction = object_mapping[i].direction;
7536 boolean is_backside = object_mapping[i].is_backside;
7537 boolean action_exploding = ((action == ACTION_EXPLODING ||
7538 action == ACTION_SMASHED_BY_ROCK ||
7539 action == ACTION_SMASHED_BY_SPRING) &&
7540 element != EL_DIAMOND);
7541 boolean action_active = (action == ACTION_ACTIVE);
7542 boolean action_other = (action == ACTION_OTHER);
7544 for (j = 0; j < 8; j++)
7546 int effective_element = get_effective_element_EM(i, j);
7547 int effective_action = (j < 7 ? action :
7548 i == Xdrip_stretch ? action :
7549 i == Xdrip_stretchB ? action :
7550 i == Ydrip_s1 ? action :
7551 i == Ydrip_s1B ? action :
7552 i == Xball_1B ? action :
7553 i == Xball_2 ? action :
7554 i == Xball_2B ? action :
7555 i == Yball_eat ? action :
7556 i == Ykey_1_eat ? action :
7557 i == Ykey_2_eat ? action :
7558 i == Ykey_3_eat ? action :
7559 i == Ykey_4_eat ? action :
7560 i == Ykey_5_eat ? action :
7561 i == Ykey_6_eat ? action :
7562 i == Ykey_7_eat ? action :
7563 i == Ykey_8_eat ? action :
7564 i == Ylenses_eat ? action :
7565 i == Ymagnify_eat ? action :
7566 i == Ygrass_eat ? action :
7567 i == Ydirt_eat ? action :
7568 i == Xsand_stonein_1 ? action :
7569 i == Xsand_stonein_2 ? action :
7570 i == Xsand_stonein_3 ? action :
7571 i == Xsand_stonein_4 ? action :
7572 i == Xsand_stoneout_1 ? action :
7573 i == Xsand_stoneout_2 ? action :
7574 i == Xboom_android ? ACTION_EXPLODING :
7575 action_exploding ? ACTION_EXPLODING :
7576 action_active ? action :
7577 action_other ? action :
7579 int graphic = (el_act_dir2img(effective_element, effective_action,
7581 int crumbled = (el_act_dir2crm(effective_element, effective_action,
7583 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7584 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7585 boolean has_action_graphics = (graphic != base_graphic);
7586 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7587 struct GraphicInfo *g = &graphic_info[graphic];
7588 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7591 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
7592 boolean special_animation = (action != ACTION_DEFAULT &&
7593 g->anim_frames == 3 &&
7594 g->anim_delay == 2 &&
7595 g->anim_mode & ANIM_LINEAR);
7596 int sync_frame = (i == Xdrip_stretch ? 7 :
7597 i == Xdrip_stretchB ? 7 :
7598 i == Ydrip_s2 ? j + 8 :
7599 i == Ydrip_s2B ? j + 8 :
7608 i == Xfake_acid_1 ? 0 :
7609 i == Xfake_acid_2 ? 10 :
7610 i == Xfake_acid_3 ? 20 :
7611 i == Xfake_acid_4 ? 30 :
7612 i == Xfake_acid_5 ? 40 :
7613 i == Xfake_acid_6 ? 50 :
7614 i == Xfake_acid_7 ? 60 :
7615 i == Xfake_acid_8 ? 70 :
7617 i == Xball_2B ? j + 8 :
7618 i == Yball_eat ? j + 1 :
7619 i == Ykey_1_eat ? j + 1 :
7620 i == Ykey_2_eat ? j + 1 :
7621 i == Ykey_3_eat ? j + 1 :
7622 i == Ykey_4_eat ? j + 1 :
7623 i == Ykey_5_eat ? j + 1 :
7624 i == Ykey_6_eat ? j + 1 :
7625 i == Ykey_7_eat ? j + 1 :
7626 i == Ykey_8_eat ? j + 1 :
7627 i == Ylenses_eat ? j + 1 :
7628 i == Ymagnify_eat ? j + 1 :
7629 i == Ygrass_eat ? j + 1 :
7630 i == Ydirt_eat ? j + 1 :
7631 i == Xamoeba_1 ? 0 :
7632 i == Xamoeba_2 ? 1 :
7633 i == Xamoeba_3 ? 2 :
7634 i == Xamoeba_4 ? 3 :
7635 i == Xamoeba_5 ? 0 :
7636 i == Xamoeba_6 ? 1 :
7637 i == Xamoeba_7 ? 2 :
7638 i == Xamoeba_8 ? 3 :
7639 i == Xexit_2 ? j + 8 :
7640 i == Xexit_3 ? j + 16 :
7641 i == Xdynamite_1 ? 0 :
7642 i == Xdynamite_2 ? 8 :
7643 i == Xdynamite_3 ? 16 :
7644 i == Xdynamite_4 ? 24 :
7645 i == Xsand_stonein_1 ? j + 1 :
7646 i == Xsand_stonein_2 ? j + 9 :
7647 i == Xsand_stonein_3 ? j + 17 :
7648 i == Xsand_stonein_4 ? j + 25 :
7649 i == Xsand_stoneout_1 && j == 0 ? 0 :
7650 i == Xsand_stoneout_1 && j == 1 ? 0 :
7651 i == Xsand_stoneout_1 && j == 2 ? 1 :
7652 i == Xsand_stoneout_1 && j == 3 ? 2 :
7653 i == Xsand_stoneout_1 && j == 4 ? 2 :
7654 i == Xsand_stoneout_1 && j == 5 ? 3 :
7655 i == Xsand_stoneout_1 && j == 6 ? 4 :
7656 i == Xsand_stoneout_1 && j == 7 ? 4 :
7657 i == Xsand_stoneout_2 && j == 0 ? 5 :
7658 i == Xsand_stoneout_2 && j == 1 ? 6 :
7659 i == Xsand_stoneout_2 && j == 2 ? 7 :
7660 i == Xsand_stoneout_2 && j == 3 ? 8 :
7661 i == Xsand_stoneout_2 && j == 4 ? 9 :
7662 i == Xsand_stoneout_2 && j == 5 ? 11 :
7663 i == Xsand_stoneout_2 && j == 6 ? 13 :
7664 i == Xsand_stoneout_2 && j == 7 ? 15 :
7665 i == Xboom_bug && j == 1 ? 2 :
7666 i == Xboom_bug && j == 2 ? 2 :
7667 i == Xboom_bug && j == 3 ? 4 :
7668 i == Xboom_bug && j == 4 ? 4 :
7669 i == Xboom_bug && j == 5 ? 2 :
7670 i == Xboom_bug && j == 6 ? 2 :
7671 i == Xboom_bug && j == 7 ? 0 :
7672 i == Xboom_bomb && j == 1 ? 2 :
7673 i == Xboom_bomb && j == 2 ? 2 :
7674 i == Xboom_bomb && j == 3 ? 4 :
7675 i == Xboom_bomb && j == 4 ? 4 :
7676 i == Xboom_bomb && j == 5 ? 2 :
7677 i == Xboom_bomb && j == 6 ? 2 :
7678 i == Xboom_bomb && j == 7 ? 0 :
7679 i == Xboom_android && j == 7 ? 6 :
7680 i == Xboom_1 && j == 1 ? 2 :
7681 i == Xboom_1 && j == 2 ? 2 :
7682 i == Xboom_1 && j == 3 ? 4 :
7683 i == Xboom_1 && j == 4 ? 4 :
7684 i == Xboom_1 && j == 5 ? 6 :
7685 i == Xboom_1 && j == 6 ? 6 :
7686 i == Xboom_1 && j == 7 ? 8 :
7687 i == Xboom_2 && j == 0 ? 8 :
7688 i == Xboom_2 && j == 1 ? 8 :
7689 i == Xboom_2 && j == 2 ? 10 :
7690 i == Xboom_2 && j == 3 ? 10 :
7691 i == Xboom_2 && j == 4 ? 10 :
7692 i == Xboom_2 && j == 5 ? 12 :
7693 i == Xboom_2 && j == 6 ? 12 :
7694 i == Xboom_2 && j == 7 ? 12 :
7695 special_animation && j == 4 ? 3 :
7696 effective_action != action ? 0 :
7700 Bitmap *debug_bitmap = g_em->bitmap;
7701 int debug_src_x = g_em->src_x;
7702 int debug_src_y = g_em->src_y;
7705 int frame = getAnimationFrame(g->anim_frames,
7708 g->anim_start_frame,
7711 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
7712 g->double_movement && is_backside);
7714 g_em->bitmap = src_bitmap;
7715 g_em->src_x = src_x;
7716 g_em->src_y = src_y;
7717 g_em->src_offset_x = 0;
7718 g_em->src_offset_y = 0;
7719 g_em->dst_offset_x = 0;
7720 g_em->dst_offset_y = 0;
7721 g_em->width = TILEX;
7722 g_em->height = TILEY;
7724 g_em->preserve_background = FALSE;
7726 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
7729 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
7730 effective_action == ACTION_MOVING ||
7731 effective_action == ACTION_PUSHING ||
7732 effective_action == ACTION_EATING)) ||
7733 (!has_action_graphics && (effective_action == ACTION_FILLING ||
7734 effective_action == ACTION_EMPTYING)))
7737 (effective_action == ACTION_FALLING ||
7738 effective_action == ACTION_FILLING ||
7739 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
7740 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
7741 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
7742 int num_steps = (i == Ydrip_s1 ? 16 :
7743 i == Ydrip_s1B ? 16 :
7744 i == Ydrip_s2 ? 16 :
7745 i == Ydrip_s2B ? 16 :
7746 i == Xsand_stonein_1 ? 32 :
7747 i == Xsand_stonein_2 ? 32 :
7748 i == Xsand_stonein_3 ? 32 :
7749 i == Xsand_stonein_4 ? 32 :
7750 i == Xsand_stoneout_1 ? 16 :
7751 i == Xsand_stoneout_2 ? 16 : 8);
7752 int cx = ABS(dx) * (TILEX / num_steps);
7753 int cy = ABS(dy) * (TILEY / num_steps);
7754 int step_frame = (i == Ydrip_s2 ? j + 8 :
7755 i == Ydrip_s2B ? j + 8 :
7756 i == Xsand_stonein_2 ? j + 8 :
7757 i == Xsand_stonein_3 ? j + 16 :
7758 i == Xsand_stonein_4 ? j + 24 :
7759 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
7760 int step = (is_backside ? step_frame : num_steps - step_frame);
7762 if (is_backside) /* tile where movement starts */
7764 if (dx < 0 || dy < 0)
7766 g_em->src_offset_x = cx * step;
7767 g_em->src_offset_y = cy * step;
7771 g_em->dst_offset_x = cx * step;
7772 g_em->dst_offset_y = cy * step;
7775 else /* tile where movement ends */
7777 if (dx < 0 || dy < 0)
7779 g_em->dst_offset_x = cx * step;
7780 g_em->dst_offset_y = cy * step;
7784 g_em->src_offset_x = cx * step;
7785 g_em->src_offset_y = cy * step;
7789 g_em->width = TILEX - cx * step;
7790 g_em->height = TILEY - cy * step;
7793 /* create unique graphic identifier to decide if tile must be redrawn */
7794 /* bit 31 - 16 (16 bit): EM style graphic
7795 bit 15 - 12 ( 4 bit): EM style frame
7796 bit 11 - 6 ( 6 bit): graphic width
7797 bit 5 - 0 ( 6 bit): graphic height */
7798 g_em->unique_identifier =
7799 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
7803 /* skip check for EMC elements not contained in original EMC artwork */
7804 if (element == EL_EMC_FAKE_ACID)
7807 if (g_em->bitmap != debug_bitmap ||
7808 g_em->src_x != debug_src_x ||
7809 g_em->src_y != debug_src_y ||
7810 g_em->src_offset_x != 0 ||
7811 g_em->src_offset_y != 0 ||
7812 g_em->dst_offset_x != 0 ||
7813 g_em->dst_offset_y != 0 ||
7814 g_em->width != TILEX ||
7815 g_em->height != TILEY)
7817 static int last_i = -1;
7825 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
7826 i, element, element_info[element].token_name,
7827 element_action_info[effective_action].suffix, direction);
7829 if (element != effective_element)
7830 printf(" [%d ('%s')]",
7832 element_info[effective_element].token_name);
7836 if (g_em->bitmap != debug_bitmap)
7837 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
7838 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
7840 if (g_em->src_x != debug_src_x ||
7841 g_em->src_y != debug_src_y)
7842 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
7843 j, (is_backside ? 'B' : 'F'),
7844 g_em->src_x, g_em->src_y,
7845 g_em->src_x / 32, g_em->src_y / 32,
7846 debug_src_x, debug_src_y,
7847 debug_src_x / 32, debug_src_y / 32);
7849 if (g_em->src_offset_x != 0 ||
7850 g_em->src_offset_y != 0 ||
7851 g_em->dst_offset_x != 0 ||
7852 g_em->dst_offset_y != 0)
7853 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
7855 g_em->src_offset_x, g_em->src_offset_y,
7856 g_em->dst_offset_x, g_em->dst_offset_y);
7858 if (g_em->width != TILEX ||
7859 g_em->height != TILEY)
7860 printf(" %d (%d): size %d,%d should be %d,%d\n",
7862 g_em->width, g_em->height, TILEX, TILEY);
7864 num_em_gfx_errors++;
7871 for (i = 0; i < TILE_MAX; i++)
7873 for (j = 0; j < 8; j++)
7875 int element = object_mapping[i].element_rnd;
7876 int action = object_mapping[i].action;
7877 int direction = object_mapping[i].direction;
7878 boolean is_backside = object_mapping[i].is_backside;
7879 int graphic_action = el_act_dir2img(element, action, direction);
7880 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
7882 if ((action == ACTION_SMASHED_BY_ROCK ||
7883 action == ACTION_SMASHED_BY_SPRING ||
7884 action == ACTION_EATING) &&
7885 graphic_action == graphic_default)
7887 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
7888 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
7889 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
7890 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
7893 /* no separate animation for "smashed by rock" -- use rock instead */
7894 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7895 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
7897 g_em->bitmap = g_xx->bitmap;
7898 g_em->src_x = g_xx->src_x;
7899 g_em->src_y = g_xx->src_y;
7900 g_em->src_offset_x = g_xx->src_offset_x;
7901 g_em->src_offset_y = g_xx->src_offset_y;
7902 g_em->dst_offset_x = g_xx->dst_offset_x;
7903 g_em->dst_offset_y = g_xx->dst_offset_y;
7904 g_em->width = g_xx->width;
7905 g_em->height = g_xx->height;
7906 g_em->unique_identifier = g_xx->unique_identifier;
7909 g_em->preserve_background = TRUE;
7914 for (p = 0; p < MAX_PLAYERS; p++)
7916 for (i = 0; i < SPR_MAX; i++)
7918 int element = player_mapping[p][i].element_rnd;
7919 int action = player_mapping[p][i].action;
7920 int direction = player_mapping[p][i].direction;
7922 for (j = 0; j < 8; j++)
7924 int effective_element = element;
7925 int effective_action = action;
7926 int graphic = (direction == MV_NONE ?
7927 el_act2img(effective_element, effective_action) :
7928 el_act_dir2img(effective_element, effective_action,
7930 struct GraphicInfo *g = &graphic_info[graphic];
7931 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
7937 Bitmap *debug_bitmap = g_em->bitmap;
7938 int debug_src_x = g_em->src_x;
7939 int debug_src_y = g_em->src_y;
7942 int frame = getAnimationFrame(g->anim_frames,
7945 g->anim_start_frame,
7948 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
7950 g_em->bitmap = src_bitmap;
7951 g_em->src_x = src_x;
7952 g_em->src_y = src_y;
7953 g_em->src_offset_x = 0;
7954 g_em->src_offset_y = 0;
7955 g_em->dst_offset_x = 0;
7956 g_em->dst_offset_y = 0;
7957 g_em->width = TILEX;
7958 g_em->height = TILEY;
7962 /* skip check for EMC elements not contained in original EMC artwork */
7963 if (element == EL_PLAYER_3 ||
7964 element == EL_PLAYER_4)
7967 if (g_em->bitmap != debug_bitmap ||
7968 g_em->src_x != debug_src_x ||
7969 g_em->src_y != debug_src_y)
7971 static int last_i = -1;
7979 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
7980 p, i, element, element_info[element].token_name,
7981 element_action_info[effective_action].suffix, direction);
7983 if (element != effective_element)
7984 printf(" [%d ('%s')]",
7986 element_info[effective_element].token_name);
7990 if (g_em->bitmap != debug_bitmap)
7991 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
7992 j, (int)(g_em->bitmap), (int)(debug_bitmap));
7994 if (g_em->src_x != debug_src_x ||
7995 g_em->src_y != debug_src_y)
7996 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
7998 g_em->src_x, g_em->src_y,
7999 g_em->src_x / 32, g_em->src_y / 32,
8000 debug_src_x, debug_src_y,
8001 debug_src_x / 32, debug_src_y / 32);
8003 num_em_gfx_errors++;
8013 printf("::: [%d errors found]\n", num_em_gfx_errors);
8019 void CheckSaveEngineSnapshot_EM(byte action[MAX_PLAYERS], int frame,
8020 boolean any_player_moving,
8021 boolean any_player_snapping,
8022 boolean any_player_dropping)
8024 static boolean player_was_waiting = TRUE;
8026 if (frame == 0 && !any_player_dropping)
8028 if (!player_was_waiting)
8030 if (!SaveEngineSnapshotToList())
8033 player_was_waiting = TRUE;
8036 else if (any_player_moving || any_player_snapping || any_player_dropping)
8038 player_was_waiting = FALSE;
8042 void CheckSaveEngineSnapshot_SP(boolean murphy_is_waiting,
8043 boolean murphy_is_dropping)
8045 static boolean player_was_waiting = TRUE;
8047 if (murphy_is_waiting)
8049 if (!player_was_waiting)
8051 if (!SaveEngineSnapshotToList())
8054 player_was_waiting = TRUE;
8059 player_was_waiting = FALSE;
8063 void CheckSingleStepMode_EM(byte action[MAX_PLAYERS], int frame,
8064 boolean any_player_moving,
8065 boolean any_player_snapping,
8066 boolean any_player_dropping)
8068 if (tape.single_step && tape.recording && !tape.pausing)
8069 if (frame == 0 && !any_player_dropping)
8070 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
8072 CheckSaveEngineSnapshot_EM(action, frame, any_player_moving,
8073 any_player_snapping, any_player_dropping);
8076 void CheckSingleStepMode_SP(boolean murphy_is_waiting,
8077 boolean murphy_is_dropping)
8079 if (tape.single_step && tape.recording && !tape.pausing)
8080 if (murphy_is_waiting)
8081 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
8083 CheckSaveEngineSnapshot_SP(murphy_is_waiting, murphy_is_dropping);
8086 void getGraphicSource_SP(struct GraphicInfo_SP *g_sp,
8087 int graphic, int sync_frame, int x, int y)
8089 int frame = getGraphicAnimationFrame(graphic, sync_frame);
8091 getGraphicSource(graphic, frame, &g_sp->bitmap, &g_sp->src_x, &g_sp->src_y);
8094 boolean isNextAnimationFrame_SP(int graphic, int sync_frame)
8096 return (IS_NEXT_FRAME(sync_frame, graphic));
8099 int getGraphicInfo_Delay(int graphic)
8101 return graphic_info[graphic].anim_delay;
8104 void PlayMenuSoundExt(int sound)
8106 if (sound == SND_UNDEFINED)
8109 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8110 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8113 if (IS_LOOP_SOUND(sound))
8114 PlaySoundLoop(sound);
8119 void PlayMenuSound()
8121 PlayMenuSoundExt(menu.sound[game_status]);
8124 void PlayMenuSoundStereo(int sound, int stereo_position)
8126 if (sound == SND_UNDEFINED)
8129 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8130 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8133 if (IS_LOOP_SOUND(sound))
8134 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
8136 PlaySoundStereo(sound, stereo_position);
8139 void PlayMenuSoundIfLoopExt(int sound)
8141 if (sound == SND_UNDEFINED)
8144 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8145 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8148 if (IS_LOOP_SOUND(sound))
8149 PlaySoundLoop(sound);
8152 void PlayMenuSoundIfLoop()
8154 PlayMenuSoundIfLoopExt(menu.sound[game_status]);
8157 void PlayMenuMusicExt(int music)
8159 if (music == MUS_UNDEFINED)
8162 if (!setup.sound_music)
8168 void PlayMenuMusic()
8170 PlayMenuMusicExt(menu.music[game_status]);
8173 void PlaySoundActivating()
8176 PlaySound(SND_MENU_ITEM_ACTIVATING);
8180 void PlaySoundSelecting()
8183 PlaySound(SND_MENU_ITEM_SELECTING);
8187 void ToggleFullscreenOrChangeWindowScalingIfNeeded()
8189 boolean change_fullscreen = (setup.fullscreen !=
8190 video.fullscreen_enabled);
8191 boolean change_window_scaling_percent = (!video.fullscreen_enabled &&
8192 setup.window_scaling_percent !=
8193 video.window_scaling_percent);
8195 if (change_window_scaling_percent && video.fullscreen_enabled)
8198 if (!change_window_scaling_percent && !video.fullscreen_available)
8201 #if defined(TARGET_SDL2)
8202 if (change_window_scaling_percent)
8204 SDLSetWindowScaling(setup.window_scaling_percent);
8208 else if (change_fullscreen)
8210 SDLSetWindowFullscreen(setup.fullscreen);
8212 /* set setup value according to successfully changed fullscreen mode */
8213 setup.fullscreen = video.fullscreen_enabled;
8219 if (change_fullscreen ||
8220 change_window_scaling_percent)
8222 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
8224 /* save backbuffer content which gets lost when toggling fullscreen mode */
8225 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8227 if (change_window_scaling_percent)
8229 /* keep window mode, but change window scaling */
8230 video.fullscreen_enabled = TRUE; /* force new window scaling */
8233 /* toggle fullscreen */
8234 ChangeVideoModeIfNeeded(setup.fullscreen);
8236 /* set setup value according to successfully changed fullscreen mode */
8237 setup.fullscreen = video.fullscreen_enabled;
8239 /* restore backbuffer content from temporary backbuffer backup bitmap */
8240 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8242 FreeBitmap(tmp_backbuffer);
8244 /* update visible window/screen */
8245 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8249 void JoinRectangles(int *x, int *y, int *width, int *height,
8250 int x2, int y2, int width2, int height2)
8252 // do not join with "off-screen" rectangle
8253 if (x2 == -1 || y2 == -1)
8258 *width = MAX(*width, width2);
8259 *height = MAX(*height, height2);
8262 void SetAnimStatus(int anim_status_new)
8264 if (anim_status_new == GAME_MODE_MAIN)
8265 anim_status_new = GAME_MODE_PSEUDO_MAINONLY;
8267 global.anim_status_next = anim_status_new;
8269 // directly set screen modes that are entered without fading
8270 if ((global.anim_status == GAME_MODE_PSEUDO_MAINONLY &&
8271 global.anim_status_next == GAME_MODE_PSEUDO_TYPENAME) ||
8272 (global.anim_status == GAME_MODE_PSEUDO_TYPENAME &&
8273 global.anim_status_next == GAME_MODE_PSEUDO_MAINONLY))
8274 global.anim_status = global.anim_status_next;
8277 void SetGameStatus(int game_status_new)
8279 game_status = game_status_new;
8281 SetAnimStatus(game_status_new);
8284 void SetFontStatus(int game_status_new)
8286 static int last_game_status = -1;
8288 if (game_status_new != -1)
8290 // set game status for font use after storing last game status
8291 last_game_status = game_status;
8292 game_status = game_status_new;
8296 // reset game status after font use from last stored game status
8297 game_status = last_game_status;
8301 void ResetFontStatus()
8306 void ChangeViewportPropertiesIfNeeded()
8308 int gfx_game_mode = game_status;
8309 int gfx_game_mode2 = (game_status == GAME_MODE_EDITOR ? GAME_MODE_DEFAULT :
8311 struct RectWithBorder *vp_window = &viewport.window[gfx_game_mode];
8312 struct RectWithBorder *vp_playfield = &viewport.playfield[gfx_game_mode];
8313 struct RectWithBorder *vp_door_1 = &viewport.door_1[gfx_game_mode];
8314 struct RectWithBorder *vp_door_2 = &viewport.door_2[gfx_game_mode2];
8315 struct RectWithBorder *vp_door_3 = &viewport.door_2[GAME_MODE_EDITOR];
8316 int new_win_xsize = vp_window->width;
8317 int new_win_ysize = vp_window->height;
8318 int border_size = vp_playfield->border_size;
8319 int new_sx = vp_playfield->x + border_size;
8320 int new_sy = vp_playfield->y + border_size;
8321 int new_sxsize = vp_playfield->width - 2 * border_size;
8322 int new_sysize = vp_playfield->height - 2 * border_size;
8323 int new_real_sx = vp_playfield->x;
8324 int new_real_sy = vp_playfield->y;
8325 int new_full_sxsize = vp_playfield->width;
8326 int new_full_sysize = vp_playfield->height;
8327 int new_dx = vp_door_1->x;
8328 int new_dy = vp_door_1->y;
8329 int new_dxsize = vp_door_1->width;
8330 int new_dysize = vp_door_1->height;
8331 int new_vx = vp_door_2->x;
8332 int new_vy = vp_door_2->y;
8333 int new_vxsize = vp_door_2->width;
8334 int new_vysize = vp_door_2->height;
8335 int new_ex = vp_door_3->x;
8336 int new_ey = vp_door_3->y;
8337 int new_exsize = vp_door_3->width;
8338 int new_eysize = vp_door_3->height;
8339 int new_tilesize_var =
8340 (setup.small_game_graphics ? MINI_TILESIZE : game.tile_size);
8342 int tilesize = (gfx_game_mode == GAME_MODE_PLAYING ? new_tilesize_var :
8343 gfx_game_mode == GAME_MODE_EDITOR ? MINI_TILESIZE : TILESIZE);
8344 int new_scr_fieldx = new_sxsize / tilesize;
8345 int new_scr_fieldy = new_sysize / tilesize;
8346 int new_scr_fieldx_buffers = new_sxsize / new_tilesize_var;
8347 int new_scr_fieldy_buffers = new_sysize / new_tilesize_var;
8348 boolean init_gfx_buffers = FALSE;
8349 boolean init_video_buffer = FALSE;
8350 boolean init_gadgets_and_anims = FALSE;
8351 boolean init_em_graphics = FALSE;
8353 if (new_win_xsize != WIN_XSIZE ||
8354 new_win_ysize != WIN_YSIZE)
8356 WIN_XSIZE = new_win_xsize;
8357 WIN_YSIZE = new_win_ysize;
8359 init_video_buffer = TRUE;
8360 init_gfx_buffers = TRUE;
8361 init_gadgets_and_anims = TRUE;
8363 // printf("::: video: init_video_buffer, init_gfx_buffers\n");
8366 if (new_scr_fieldx != SCR_FIELDX ||
8367 new_scr_fieldy != SCR_FIELDY)
8369 /* this always toggles between MAIN and GAME when using small tile size */
8371 SCR_FIELDX = new_scr_fieldx;
8372 SCR_FIELDY = new_scr_fieldy;
8374 // printf("::: new_scr_fieldx != SCR_FIELDX ...\n");
8385 new_sxsize != SXSIZE ||
8386 new_sysize != SYSIZE ||
8387 new_dxsize != DXSIZE ||
8388 new_dysize != DYSIZE ||
8389 new_vxsize != VXSIZE ||
8390 new_vysize != VYSIZE ||
8391 new_exsize != EXSIZE ||
8392 new_eysize != EYSIZE ||
8393 new_real_sx != REAL_SX ||
8394 new_real_sy != REAL_SY ||
8395 new_full_sxsize != FULL_SXSIZE ||
8396 new_full_sysize != FULL_SYSIZE ||
8397 new_tilesize_var != TILESIZE_VAR
8400 // ------------------------------------------------------------------------
8401 // determine next fading area for changed viewport definitions
8402 // ------------------------------------------------------------------------
8404 // start with current playfield area (default fading area)
8407 FADE_SXSIZE = FULL_SXSIZE;
8408 FADE_SYSIZE = FULL_SYSIZE;
8410 // add new playfield area if position or size has changed
8411 if (new_real_sx != REAL_SX || new_real_sy != REAL_SY ||
8412 new_full_sxsize != FULL_SXSIZE || new_full_sysize != FULL_SYSIZE)
8414 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
8415 new_real_sx, new_real_sy, new_full_sxsize,new_full_sysize);
8418 // add current and new door 1 area if position or size has changed
8419 if (new_dx != DX || new_dy != DY ||
8420 new_dxsize != DXSIZE || new_dysize != DYSIZE)
8422 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
8423 DX, DY, DXSIZE, DYSIZE);
8424 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
8425 new_dx, new_dy, new_dxsize, new_dysize);
8428 // add current and new door 2 area if position or size has changed
8429 if (new_dx != VX || new_dy != VY ||
8430 new_dxsize != VXSIZE || new_dysize != VYSIZE)
8432 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
8433 VX, VY, VXSIZE, VYSIZE);
8434 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
8435 new_vx, new_vy, new_vxsize, new_vysize);
8438 // ------------------------------------------------------------------------
8439 // handle changed tile size
8440 // ------------------------------------------------------------------------
8442 if (new_tilesize_var != TILESIZE_VAR)
8444 // printf("::: new_tilesize_var != TILESIZE_VAR\n");
8446 // changing tile size invalidates scroll values of engine snapshots
8447 FreeEngineSnapshotSingle();
8449 // changing tile size requires update of graphic mapping for EM engine
8450 init_em_graphics = TRUE;
8461 SXSIZE = new_sxsize;
8462 SYSIZE = new_sysize;
8463 DXSIZE = new_dxsize;
8464 DYSIZE = new_dysize;
8465 VXSIZE = new_vxsize;
8466 VYSIZE = new_vysize;
8467 EXSIZE = new_exsize;
8468 EYSIZE = new_eysize;
8469 REAL_SX = new_real_sx;
8470 REAL_SY = new_real_sy;
8471 FULL_SXSIZE = new_full_sxsize;
8472 FULL_SYSIZE = new_full_sysize;
8473 TILESIZE_VAR = new_tilesize_var;
8475 init_gfx_buffers = TRUE;
8476 init_gadgets_and_anims = TRUE;
8478 // printf("::: viewports: init_gfx_buffers\n");
8479 // printf("::: viewports: init_gadgets_and_anims\n");
8482 if (init_gfx_buffers)
8484 // printf("::: init_gfx_buffers\n");
8486 SCR_FIELDX = new_scr_fieldx_buffers;
8487 SCR_FIELDY = new_scr_fieldy_buffers;
8491 SCR_FIELDX = new_scr_fieldx;
8492 SCR_FIELDY = new_scr_fieldy;
8494 SetDrawDeactivationMask(REDRAW_NONE);
8495 SetDrawBackgroundMask(REDRAW_FIELD);
8498 if (init_video_buffer)
8500 // printf("::: init_video_buffer\n");
8502 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
8503 InitImageTextures();
8506 if (init_gadgets_and_anims)
8508 // printf("::: init_gadgets_and_anims\n");
8511 InitGlobalAnimations();
8514 if (init_em_graphics)
8516 InitGraphicInfo_EM();