1 // ============================================================================
2 // Rocks'n'Diamonds - McDuffin Strikes Back!
3 // ----------------------------------------------------------------------------
4 // (c) 1995-2014 by Artsoft Entertainment
7 // http://www.artsoft.org/
8 // ----------------------------------------------------------------------------
10 // ============================================================================
14 #include "libgame/libgame.h"
26 /* select level set with EMC X11 graphics before activating EM GFX debugging */
27 #define DEBUG_EM_GFX FALSE
28 #define DEBUG_FRAME_TIME FALSE
30 /* tool button identifiers */
31 #define TOOL_CTRL_ID_YES 0
32 #define TOOL_CTRL_ID_NO 1
33 #define TOOL_CTRL_ID_CONFIRM 2
34 #define TOOL_CTRL_ID_PLAYER_1 3
35 #define TOOL_CTRL_ID_PLAYER_2 4
36 #define TOOL_CTRL_ID_PLAYER_3 5
37 #define TOOL_CTRL_ID_PLAYER_4 6
39 #define NUM_TOOL_BUTTONS 7
41 /* constants for number of doors and door parts */
43 #define NUM_PANELS NUM_DOORS
44 // #define NUM_PANELS 0
45 #define MAX_PARTS_PER_DOOR 8
46 #define MAX_DOOR_PARTS (NUM_DOORS * MAX_PARTS_PER_DOOR + NUM_PANELS)
47 #define DOOR_PART_IS_PANEL(i) ((i) >= NUM_DOORS * MAX_PARTS_PER_DOOR)
50 struct DoorPartOrderInfo
56 static struct DoorPartOrderInfo door_part_order[MAX_DOOR_PARTS];
58 struct DoorPartControlInfo
62 struct DoorPartPosInfo *pos;
65 static struct DoorPartControlInfo door_part_controls[] =
69 IMG_GFX_DOOR_1_PART_1,
74 IMG_GFX_DOOR_1_PART_2,
79 IMG_GFX_DOOR_1_PART_3,
84 IMG_GFX_DOOR_1_PART_4,
89 IMG_GFX_DOOR_1_PART_5,
94 IMG_GFX_DOOR_1_PART_6,
99 IMG_GFX_DOOR_1_PART_7,
104 IMG_GFX_DOOR_1_PART_8,
110 IMG_GFX_DOOR_2_PART_1,
115 IMG_GFX_DOOR_2_PART_2,
120 IMG_GFX_DOOR_2_PART_3,
125 IMG_GFX_DOOR_2_PART_4,
130 IMG_GFX_DOOR_2_PART_5,
135 IMG_GFX_DOOR_2_PART_6,
140 IMG_GFX_DOOR_2_PART_7,
145 IMG_GFX_DOOR_2_PART_8,
151 IMG_BACKGROUND_PANEL,
168 /* forward declaration for internal use */
169 static void UnmapToolButtons();
170 static void HandleToolButtons(struct GadgetInfo *);
171 static int el_act_dir2crm(int, int, int);
172 static int el_act2crm(int, int);
174 static struct GadgetInfo *tool_gadget[NUM_TOOL_BUTTONS];
175 static int request_gadget_id = -1;
177 static char *print_if_not_empty(int element)
179 static char *s = NULL;
180 char *token_name = element_info[element].token_name;
185 s = checked_malloc(strlen(token_name) + 10 + 1);
187 if (element != EL_EMPTY)
188 sprintf(s, "%d\t['%s']", element, token_name);
190 sprintf(s, "%d", element);
195 void DumpTile(int x, int y)
200 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
206 printf_line("-", 79);
207 printf("Field Info: SCREEN(%d, %d), LEVEL(%d, %d)\n", sx, sy, x, y);
208 printf_line("-", 79);
210 if (!IN_LEV_FIELD(x, y))
212 printf("(not in level field)\n");
218 printf(" Feld: %d\t['%s']\n", Feld[x][y],
219 element_info[Feld[x][y]].token_name);
220 printf(" Back: %s\n", print_if_not_empty(Back[x][y]));
221 printf(" Store: %s\n", print_if_not_empty(Store[x][y]));
222 printf(" Store2: %s\n", print_if_not_empty(Store2[x][y]));
223 printf(" StorePlayer: %s\n", print_if_not_empty(StorePlayer[x][y]));
224 printf(" MovPos: %d\n", MovPos[x][y]);
225 printf(" MovDir: %d\n", MovDir[x][y]);
226 printf(" MovDelay: %d\n", MovDelay[x][y]);
227 printf(" ChangeDelay: %d\n", ChangeDelay[x][y]);
228 printf(" CustomValue: %d\n", CustomValue[x][y]);
229 printf(" GfxElement: %d\n", GfxElement[x][y]);
230 printf(" GfxAction: %d\n", GfxAction[x][y]);
231 printf(" GfxFrame: %d [%d]\n", GfxFrame[x][y], FrameCounter);
235 void SetDrawtoField(int mode)
237 if (mode == DRAW_TO_FIELDBUFFER)
243 BX2 = SCR_FIELDX + 1;
244 BY2 = SCR_FIELDY + 1;
246 drawto_field = fieldbuffer;
248 else /* DRAW_TO_BACKBUFFER */
254 BX2 = SCR_FIELDX - 1;
255 BY2 = SCR_FIELDY - 1;
257 drawto_field = backbuffer;
261 static void RedrawPlayfield_RND()
263 if (game.envelope_active)
266 DrawLevel(REDRAW_ALL);
270 void RedrawPlayfield()
272 if (game_status != GAME_MODE_PLAYING)
275 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
276 RedrawPlayfield_EM(TRUE);
277 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
278 RedrawPlayfield_SP(TRUE);
279 else if (level.game_engine_type == GAME_ENGINE_TYPE_RND)
280 RedrawPlayfield_RND();
282 BlitScreenToBitmap(backbuffer);
284 BlitBitmap(drawto, window, gfx.sx, gfx.sy, gfx.sxsize, gfx.sysize,
288 static void DrawMaskedBorderExt_Rect(int x, int y, int width, int height,
291 Bitmap *src_bitmap = getGlobalBorderBitmapFromStatus(global.border_status);
292 Bitmap *dst_bitmap = gfx.masked_border_bitmap_ptr;
294 if (x == -1 && y == -1)
297 if (draw_target == DRAW_TO_SCREEN)
298 BlitToScreenMasked(src_bitmap, x, y, width, height, x, y);
300 BlitBitmapMasked(src_bitmap, dst_bitmap, x, y, width, height, x, y);
303 static void DrawMaskedBorderExt_FIELD(int draw_target)
305 if (global.border_status >= GAME_MODE_MAIN &&
306 global.border_status <= GAME_MODE_PLAYING &&
307 border.draw_masked[global.border_status])
308 DrawMaskedBorderExt_Rect(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
312 static void DrawMaskedBorderExt_DOOR_1(int draw_target)
314 // when drawing to backbuffer, never draw border over open doors
315 if (draw_target == DRAW_TO_BACKBUFFER &&
316 (GetDoorState() & DOOR_OPEN_1))
319 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
320 (global.border_status != GAME_MODE_EDITOR ||
321 border.draw_masked[GFX_SPECIAL_ARG_EDITOR]))
322 DrawMaskedBorderExt_Rect(DX, DY, DXSIZE, DYSIZE, draw_target);
325 static void DrawMaskedBorderExt_DOOR_2(int draw_target)
327 // when drawing to backbuffer, never draw border over open doors
328 if (draw_target == DRAW_TO_BACKBUFFER &&
329 (GetDoorState() & DOOR_OPEN_2))
332 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
333 global.border_status != GAME_MODE_EDITOR)
334 DrawMaskedBorderExt_Rect(VX, VY, VXSIZE, VYSIZE, draw_target);
337 static void DrawMaskedBorderExt_DOOR_3(int draw_target)
339 /* currently not available */
342 static void DrawMaskedBorderExt_ALL(int draw_target)
344 DrawMaskedBorderExt_FIELD(draw_target);
345 DrawMaskedBorderExt_DOOR_1(draw_target);
346 DrawMaskedBorderExt_DOOR_2(draw_target);
347 DrawMaskedBorderExt_DOOR_3(draw_target);
350 static void DrawMaskedBorderExt(int redraw_mask, int draw_target)
352 /* never draw masked screen borders on borderless screens */
353 if (global.border_status == GAME_MODE_LOADING ||
354 global.border_status == GAME_MODE_TITLE)
357 if (redraw_mask & REDRAW_ALL)
358 DrawMaskedBorderExt_ALL(draw_target);
361 if (redraw_mask & REDRAW_FIELD)
362 DrawMaskedBorderExt_FIELD(draw_target);
363 if (redraw_mask & REDRAW_DOOR_1)
364 DrawMaskedBorderExt_DOOR_1(draw_target);
365 if (redraw_mask & REDRAW_DOOR_2)
366 DrawMaskedBorderExt_DOOR_2(draw_target);
367 if (redraw_mask & REDRAW_DOOR_3)
368 DrawMaskedBorderExt_DOOR_3(draw_target);
372 void DrawMaskedBorder_FIELD()
374 DrawMaskedBorderExt_FIELD(DRAW_TO_BACKBUFFER);
377 void DrawMaskedBorder(int redraw_mask)
379 DrawMaskedBorderExt(redraw_mask, DRAW_TO_BACKBUFFER);
382 void DrawMaskedBorderToTarget(int draw_target)
384 if (draw_target == DRAW_TO_BACKBUFFER ||
385 draw_target == DRAW_TO_SCREEN)
387 DrawMaskedBorderExt(REDRAW_ALL, draw_target);
391 int last_border_status = global.border_status;
393 if (draw_target == DRAW_TO_FADE_SOURCE)
395 global.border_status = gfx.fade_border_source_status;
396 gfx.masked_border_bitmap_ptr = gfx.fade_bitmap_source;
398 else if (draw_target == DRAW_TO_FADE_TARGET)
400 global.border_status = gfx.fade_border_target_status;
401 gfx.masked_border_bitmap_ptr = gfx.fade_bitmap_target;
404 DrawMaskedBorderExt(REDRAW_ALL, draw_target);
406 global.border_status = last_border_status;
407 gfx.masked_border_bitmap_ptr = backbuffer;
411 void BlitScreenToBitmap_RND(Bitmap *target_bitmap)
413 int fx = FX, fy = FY;
414 int full_lev_fieldx = lev_fieldx + (BorderElement != EL_EMPTY ? 2 : 0);
415 int full_lev_fieldy = lev_fieldy + (BorderElement != EL_EMPTY ? 2 : 0);
417 int dx = (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
418 int dy = (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
419 int dx_var = dx * TILESIZE_VAR / TILESIZE;
420 int dy_var = dy * TILESIZE_VAR / TILESIZE;
423 ffx = (scroll_x - SBX_Left) * TILEX_VAR + dx_var;
424 ffy = (scroll_y - SBY_Upper) * TILEY_VAR + dy_var;
426 if (EVEN(SCR_FIELDX))
428 if (ffx < SBX_Right * TILEX_VAR + TILEX_VAR / 2 + TILEX_VAR)
429 fx += dx_var - MIN(ffx, TILEX_VAR / 2) + TILEX_VAR;
431 fx += (dx_var > 0 ? TILEX_VAR : 0);
438 if (EVEN(SCR_FIELDY))
440 if (ffy < SBY_Lower * TILEY_VAR + TILEY_VAR / 2 + TILEY_VAR)
441 fy += dy_var - MIN(ffy, TILEY_VAR / 2) + TILEY_VAR;
443 fy += (dy_var > 0 ? TILEY_VAR : 0);
450 if (full_lev_fieldx <= SCR_FIELDX)
452 if (EVEN(SCR_FIELDX))
453 fx = 2 * TILEX_VAR - (ODD(lev_fieldx) ? TILEX_VAR / 2 : 0);
455 fx = 2 * TILEX_VAR - (EVEN(lev_fieldx) ? TILEX_VAR / 2 : 0);
458 if (full_lev_fieldy <= SCR_FIELDY)
460 if (EVEN(SCR_FIELDY))
461 fy = 2 * TILEY_VAR - (ODD(lev_fieldy) ? TILEY_VAR / 2 : 0);
463 fy = 2 * TILEY_VAR - (EVEN(lev_fieldy) ? TILEY_VAR / 2 : 0);
466 BlitBitmap(drawto_field, target_bitmap, fx, fy, SXSIZE, SYSIZE, SX, SY);
469 void BlitScreenToBitmap(Bitmap *target_bitmap)
471 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
472 BlitScreenToBitmap_EM(target_bitmap);
473 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
474 BlitScreenToBitmap_SP(target_bitmap);
475 else if (level.game_engine_type == GAME_ENGINE_TYPE_RND)
476 BlitScreenToBitmap_RND(target_bitmap);
478 redraw_mask |= REDRAW_FIELD;
481 void DrawFramesPerSecond()
484 int font_nr = FONT_TEXT_2;
485 int font_width = getFontWidth(font_nr);
487 sprintf(text, "%04.1f fps", global.frames_per_second);
489 DrawTextExt(backbuffer, WIN_XSIZE - font_width * strlen(text), 0, text,
490 font_nr, BLIT_OPAQUE);
494 static void PrintFrameTimeDebugging()
496 static unsigned int last_counter = 0;
497 unsigned int counter = Counter();
498 int diff_1 = counter - last_counter;
499 int diff_2 = diff_1 - GAME_FRAME_DELAY;
501 int diff_2_cut = MIN(ABS(diff_2), diff_2_max);
502 char diff_bar[2 * diff_2_max + 5];
506 diff_bar[pos++] = (diff_2 < -diff_2_max ? '<' : ' ');
508 for (i = 0; i < diff_2_max; i++)
509 diff_bar[pos++] = (diff_2 >= 0 ? ' ' :
510 i >= diff_2_max - diff_2_cut ? '-' : ' ');
512 diff_bar[pos++] = '|';
514 for (i = 0; i < diff_2_max; i++)
515 diff_bar[pos++] = (diff_2 <= 0 ? ' ' : i < diff_2_cut ? '+' : ' ');
517 diff_bar[pos++] = (diff_2 > diff_2_max ? '>' : ' ');
519 diff_bar[pos++] = '\0';
521 Error(ERR_INFO, "%06d [%02d] [%c%02d] %s",
524 (diff_2 < 0 ? '-' : diff_2 > 0 ? '+' : ' '), ABS(diff_2),
527 last_counter = counter;
531 static int unifiedRedrawMask(int mask)
533 if (mask & REDRAW_ALL)
536 if (mask & REDRAW_FIELD && mask & REDRAW_DOORS)
542 static boolean equalRedrawMasks(int mask_1, int mask_2)
544 return unifiedRedrawMask(mask_1) == unifiedRedrawMask(mask_2);
549 static int last_redraw_mask = REDRAW_NONE;
551 // force screen redraw in every frame to continue drawing global animations
552 // (but always use the last redraw mask to prevent unwanted side effects)
553 if (redraw_mask == REDRAW_NONE)
554 redraw_mask = last_redraw_mask;
556 last_redraw_mask = redraw_mask;
559 // masked border now drawn immediately when blitting backbuffer to window
561 // draw masked border to all viewports, if defined
562 DrawMaskedBorder(redraw_mask);
565 // draw frames per second (only if debug mode is enabled)
566 if (redraw_mask & REDRAW_FPS)
567 DrawFramesPerSecond();
569 // remove playfield redraw before potentially merging with doors redraw
570 if (DrawingDeactivated(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE))
571 redraw_mask &= ~REDRAW_FIELD;
573 // redraw complete window if both playfield and (some) doors need redraw
574 if (redraw_mask & REDRAW_FIELD && redraw_mask & REDRAW_DOORS)
575 redraw_mask = REDRAW_ALL;
577 /* although redrawing the whole window would be fine for normal gameplay,
578 being able to only redraw the playfield is required for deactivating
579 certain drawing areas (mainly playfield) to work, which is needed for
580 warp-forward to be fast enough (by skipping redraw of most frames) */
582 if (redraw_mask & REDRAW_ALL)
584 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
586 else if (redraw_mask & REDRAW_FIELD)
588 BlitBitmap(backbuffer, window,
589 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
591 else if (redraw_mask & REDRAW_DOORS)
593 // merge door areas to prevent calling screen redraw more than once
599 if (redraw_mask & REDRAW_DOOR_1)
603 x2 = MAX(x2, DX + DXSIZE);
604 y2 = MAX(y2, DY + DYSIZE);
607 if (redraw_mask & REDRAW_DOOR_2)
611 x2 = MAX(x2, VX + VXSIZE);
612 y2 = MAX(y2, VY + VYSIZE);
615 if (redraw_mask & REDRAW_DOOR_3)
619 x2 = MAX(x2, EX + EXSIZE);
620 y2 = MAX(y2, EY + EYSIZE);
623 BlitBitmap(backbuffer, window, x1, y1, x2 - x1, y2 - y1, x1, y1);
626 redraw_mask = REDRAW_NONE;
629 PrintFrameTimeDebugging();
633 void BackToFront_WithFrameDelay(unsigned int frame_delay_value)
635 unsigned int frame_delay_value_old = GetVideoFrameDelay();
637 SetVideoFrameDelay(frame_delay_value);
641 SetVideoFrameDelay(frame_delay_value_old);
644 static int fade_type_skip = FADE_TYPE_NONE;
646 static void FadeExt(int fade_mask, int fade_mode, int fade_type)
648 void (*draw_border_function)(void) = NULL;
649 int x, y, width, height;
650 int fade_delay, post_delay;
652 if (fade_type == FADE_TYPE_FADE_OUT)
654 if (fade_type_skip != FADE_TYPE_NONE)
656 /* skip all fade operations until specified fade operation */
657 if (fade_type & fade_type_skip)
658 fade_type_skip = FADE_TYPE_NONE;
663 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
667 redraw_mask |= fade_mask;
669 if (fade_type == FADE_TYPE_SKIP)
671 fade_type_skip = fade_mode;
676 fade_delay = fading.fade_delay;
677 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
679 if (fade_type_skip != FADE_TYPE_NONE)
681 /* skip all fade operations until specified fade operation */
682 if (fade_type & fade_type_skip)
683 fade_type_skip = FADE_TYPE_NONE;
688 if (global.autoplay_leveldir)
693 if (fade_mask == REDRAW_FIELD)
698 height = FADE_SYSIZE;
700 if (border.draw_masked_when_fading)
701 draw_border_function = DrawMaskedBorder_FIELD; /* update when fading */
703 DrawMaskedBorder_FIELD(); /* draw once */
705 else /* REDRAW_ALL */
713 if (!setup.fade_screens ||
715 fading.fade_mode == FADE_MODE_NONE)
717 if (fade_mode == FADE_MODE_FADE_OUT)
720 BlitBitmap(backbuffer, window, x, y, width, height, x, y);
722 redraw_mask &= ~fade_mask;
727 FadeRectangle(x, y, width, height, fade_mode, fade_delay, post_delay,
728 draw_border_function);
730 redraw_mask &= ~fade_mask;
733 static void SetScreenStates_BeforeFadingIn()
735 // temporarily set screen mode for animations to screen after fading in
736 global.anim_status = global.anim_status_next;
738 // store backbuffer with all animations that will be started after fading in
739 if (fade_type_skip != FADE_MODE_SKIP_FADE_IN)
740 PrepareFadeBitmap(DRAW_TO_FADE_TARGET);
742 // set screen mode for animations back to fading
743 global.anim_status = GAME_MODE_PSEUDO_FADING;
746 static void SetScreenStates_AfterFadingIn()
748 // store new source screen (to use correct masked border for fading)
749 gfx.fade_border_source_status = global.border_status;
751 global.anim_status = global.anim_status_next;
754 static void SetScreenStates_BeforeFadingOut()
756 // store new target screen (to use correct masked border for fading)
757 gfx.fade_border_target_status = game_status;
759 // set screen mode for animations to fading
760 global.anim_status = GAME_MODE_PSEUDO_FADING;
762 // store backbuffer with all animations that will be stopped for fading out
763 if (fade_type_skip != FADE_MODE_SKIP_FADE_OUT)
764 PrepareFadeBitmap(DRAW_TO_FADE_SOURCE);
767 static void SetScreenStates_AfterFadingOut()
769 global.border_status = game_status;
772 void FadeIn(int fade_mask)
774 SetScreenStates_BeforeFadingIn();
777 DrawMaskedBorder(REDRAW_ALL);
780 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
781 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_IN);
783 FadeExt(fade_mask, FADE_MODE_FADE_IN, FADE_TYPE_FADE_IN);
787 FADE_SXSIZE = FULL_SXSIZE;
788 FADE_SYSIZE = FULL_SYSIZE;
790 SetScreenStates_AfterFadingIn();
792 // force update of global animation status in case of rapid screen changes
793 redraw_mask = REDRAW_ALL;
797 void FadeOut(int fade_mask)
799 // update screen if areas covered by "fade_mask" and "redraw_mask" differ
800 if (!equalRedrawMasks(fade_mask, redraw_mask))
803 SetScreenStates_BeforeFadingOut();
806 DrawMaskedBorder(REDRAW_ALL);
809 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
810 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_OUT);
812 FadeExt(fade_mask, FADE_MODE_FADE_OUT, FADE_TYPE_FADE_OUT);
814 SetScreenStates_AfterFadingOut();
817 static void FadeSetLeaveNext(struct TitleFadingInfo fading_leave, boolean set)
819 static struct TitleFadingInfo fading_leave_stored;
822 fading_leave_stored = fading_leave;
824 fading = fading_leave_stored;
827 void FadeSetEnterMenu()
829 fading = menu.enter_menu;
831 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
834 void FadeSetLeaveMenu()
836 fading = menu.leave_menu;
838 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
841 void FadeSetEnterScreen()
843 fading = menu.enter_screen[game_status];
845 FadeSetLeaveNext(menu.leave_screen[game_status], TRUE); /* store */
848 void FadeSetNextScreen()
850 fading = menu.next_screen[game_status];
852 // (do not overwrite fade mode set by FadeSetEnterScreen)
853 // FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
856 void FadeSetLeaveScreen()
858 FadeSetLeaveNext(menu.leave_screen[game_status], FALSE); /* recall */
861 void FadeSetFromType(int type)
863 if (type & TYPE_ENTER_SCREEN)
864 FadeSetEnterScreen();
865 else if (type & TYPE_ENTER)
867 else if (type & TYPE_LEAVE)
871 void FadeSetDisabled()
873 static struct TitleFadingInfo fading_none = { FADE_MODE_NONE, -1, -1, -1 };
875 fading = fading_none;
878 void FadeSkipNextFadeIn()
880 FadeExt(0, FADE_MODE_SKIP_FADE_IN, FADE_TYPE_SKIP);
883 void FadeSkipNextFadeOut()
885 FadeExt(0, FADE_MODE_SKIP_FADE_OUT, FADE_TYPE_SKIP);
888 Bitmap *getBitmapFromGraphicOrDefault(int graphic, int default_graphic)
890 boolean redefined = getImageListEntryFromImageID(graphic)->redefined;
892 return (graphic == IMG_UNDEFINED ? NULL :
893 graphic_info[graphic].bitmap != NULL || redefined ?
894 graphic_info[graphic].bitmap :
895 graphic_info[default_graphic].bitmap);
898 Bitmap *getBackgroundBitmap(int graphic)
900 return getBitmapFromGraphicOrDefault(graphic, IMG_BACKGROUND);
903 Bitmap *getGlobalBorderBitmap(int graphic)
905 return getBitmapFromGraphicOrDefault(graphic, IMG_GLOBAL_BORDER);
908 Bitmap *getGlobalBorderBitmapFromStatus(int status)
911 (status == GAME_MODE_MAIN ||
912 status == GAME_MODE_PSEUDO_TYPENAME ? IMG_GLOBAL_BORDER_MAIN :
913 status == GAME_MODE_SCORES ? IMG_GLOBAL_BORDER_SCORES :
914 status == GAME_MODE_EDITOR ? IMG_GLOBAL_BORDER_EDITOR :
915 status == GAME_MODE_PLAYING ? IMG_GLOBAL_BORDER_PLAYING :
918 return getGlobalBorderBitmap(graphic);
921 void SetWindowBackgroundImageIfDefined(int graphic)
923 if (graphic_info[graphic].bitmap)
924 SetWindowBackgroundBitmap(graphic_info[graphic].bitmap);
927 void SetMainBackgroundImageIfDefined(int graphic)
929 if (graphic_info[graphic].bitmap)
930 SetMainBackgroundBitmap(graphic_info[graphic].bitmap);
933 void SetDoorBackgroundImageIfDefined(int graphic)
935 if (graphic_info[graphic].bitmap)
936 SetDoorBackgroundBitmap(graphic_info[graphic].bitmap);
939 void SetWindowBackgroundImage(int graphic)
941 SetWindowBackgroundBitmap(getBackgroundBitmap(graphic));
944 void SetMainBackgroundImage(int graphic)
946 SetMainBackgroundBitmap(getBackgroundBitmap(graphic));
949 void SetDoorBackgroundImage(int graphic)
951 SetDoorBackgroundBitmap(getBackgroundBitmap(graphic));
954 void SetPanelBackground()
956 struct GraphicInfo *gfx = &graphic_info[IMG_BACKGROUND_PANEL];
958 BlitBitmapTiled(gfx->bitmap, bitmap_db_panel, gfx->src_x, gfx->src_y,
959 gfx->width, gfx->height, 0, 0, DXSIZE, DYSIZE);
961 SetDoorBackgroundBitmap(bitmap_db_panel);
964 void DrawBackground(int x, int y, int width, int height)
966 /* "drawto" might still point to playfield buffer here (hall of fame) */
967 ClearRectangleOnBackground(backbuffer, x, y, width, height);
969 if (IN_GFX_FIELD_FULL(x, y))
970 redraw_mask |= REDRAW_FIELD;
971 else if (IN_GFX_DOOR_1(x, y))
972 redraw_mask |= REDRAW_DOOR_1;
973 else if (IN_GFX_DOOR_2(x, y))
974 redraw_mask |= REDRAW_DOOR_2;
975 else if (IN_GFX_DOOR_3(x, y))
976 redraw_mask |= REDRAW_DOOR_3;
979 void DrawBackgroundForFont(int x, int y, int width, int height, int font_nr)
981 struct FontBitmapInfo *font = getFontBitmapInfo(font_nr);
983 if (font->bitmap == NULL)
986 DrawBackground(x, y, width, height);
989 void DrawBackgroundForGraphic(int x, int y, int width, int height, int graphic)
991 struct GraphicInfo *g = &graphic_info[graphic];
993 if (g->bitmap == NULL)
996 DrawBackground(x, y, width, height);
999 static int game_status_last = -1;
1000 static Bitmap *global_border_bitmap_last = NULL;
1001 static Bitmap *global_border_bitmap = NULL;
1002 static int real_sx_last = -1, real_sy_last = -1;
1003 static int full_sxsize_last = -1, full_sysize_last = -1;
1004 static int dx_last = -1, dy_last = -1;
1005 static int dxsize_last = -1, dysize_last = -1;
1006 static int vx_last = -1, vy_last = -1;
1007 static int vxsize_last = -1, vysize_last = -1;
1009 boolean CheckIfGlobalBorderHasChanged()
1011 // if game status has not changed, global border has not changed either
1012 if (game_status == game_status_last)
1015 // determine and store new global border bitmap for current game status
1016 global_border_bitmap = getGlobalBorderBitmapFromStatus(game_status);
1018 return (global_border_bitmap_last != global_border_bitmap);
1021 boolean CheckIfGlobalBorderRedrawIsNeeded()
1023 // if game status has not changed, nothing has to be redrawn
1024 if (game_status == game_status_last)
1027 // redraw if last screen was title screen
1028 if (game_status_last == GAME_MODE_TITLE)
1031 // redraw if global screen border has changed
1032 if (CheckIfGlobalBorderHasChanged())
1035 // redraw if position or size of playfield area has changed
1036 if (real_sx_last != REAL_SX || real_sy_last != REAL_SY ||
1037 full_sxsize_last != FULL_SXSIZE || full_sysize_last != FULL_SYSIZE)
1040 // redraw if position or size of door area has changed
1041 if (dx_last != DX || dy_last != DY ||
1042 dxsize_last != DXSIZE || dysize_last != DYSIZE)
1045 // redraw if position or size of tape area has changed
1046 if (vx_last != VX || vy_last != VY ||
1047 vxsize_last != VXSIZE || vysize_last != VYSIZE)
1053 void RedrawGlobalBorderFromBitmap(Bitmap *bitmap)
1056 BlitBitmap(bitmap, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
1058 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
1061 void RedrawGlobalBorder()
1063 Bitmap *bitmap = getGlobalBorderBitmapFromStatus(game_status);
1065 RedrawGlobalBorderFromBitmap(bitmap);
1067 redraw_mask = REDRAW_ALL;
1070 static void RedrawGlobalBorderIfNeeded()
1072 if (game_status == game_status_last)
1075 // copy current draw buffer to later copy back areas that have not changed
1076 if (game_status_last != GAME_MODE_TITLE)
1077 BlitBitmap(backbuffer, bitmap_db_store_1, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
1079 if (CheckIfGlobalBorderRedrawIsNeeded())
1081 // redraw global screen border (or clear, if defined to be empty)
1082 RedrawGlobalBorderFromBitmap(global_border_bitmap);
1084 // copy previous playfield and door areas, if they are defined on both
1085 // previous and current screen and if they still have the same size
1087 if (real_sx_last != -1 && real_sy_last != -1 &&
1088 REAL_SX != -1 && REAL_SY != -1 &&
1089 full_sxsize_last == FULL_SXSIZE && full_sysize_last == FULL_SYSIZE)
1090 BlitBitmap(bitmap_db_store_1, backbuffer,
1091 real_sx_last, real_sy_last, FULL_SXSIZE, FULL_SYSIZE,
1094 if (dx_last != -1 && dy_last != -1 &&
1095 DX != -1 && DY != -1 &&
1096 dxsize_last == DXSIZE && dysize_last == DYSIZE)
1097 BlitBitmap(bitmap_db_store_1, backbuffer,
1098 dx_last, dy_last, DXSIZE, DYSIZE, DX, DY);
1100 if (vx_last != -1 && vy_last != -1 &&
1101 VX != -1 && VY != -1 &&
1102 vxsize_last == VXSIZE && vysize_last == VYSIZE)
1103 BlitBitmap(bitmap_db_store_1, backbuffer,
1104 vx_last, vy_last, VXSIZE, VYSIZE, VX, VY);
1106 redraw_mask = REDRAW_ALL;
1109 game_status_last = game_status;
1111 global_border_bitmap_last = global_border_bitmap;
1113 real_sx_last = REAL_SX;
1114 real_sy_last = REAL_SY;
1115 full_sxsize_last = FULL_SXSIZE;
1116 full_sysize_last = FULL_SYSIZE;
1119 dxsize_last = DXSIZE;
1120 dysize_last = DYSIZE;
1123 vxsize_last = VXSIZE;
1124 vysize_last = VYSIZE;
1129 RedrawGlobalBorderIfNeeded();
1131 /* !!! "drawto" might still point to playfield buffer here (see above) !!! */
1132 /* (when entering hall of fame after playing) */
1133 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
1135 /* !!! maybe this should be done before clearing the background !!! */
1136 if (game_status == GAME_MODE_PLAYING)
1138 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
1139 SetDrawtoField(DRAW_TO_FIELDBUFFER);
1143 SetDrawtoField(DRAW_TO_BACKBUFFER);
1147 void MarkTileDirty(int x, int y)
1149 redraw_mask |= REDRAW_FIELD;
1152 void SetBorderElement()
1156 BorderElement = EL_EMPTY;
1158 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
1160 for (x = 0; x < lev_fieldx; x++)
1162 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
1163 BorderElement = EL_STEELWALL;
1165 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
1171 void FloodFillLevel(int from_x, int from_y, int fill_element,
1172 short field[MAX_LEV_FIELDX][MAX_LEV_FIELDY],
1173 int max_fieldx, int max_fieldy)
1177 static int check[4][2] = { { -1, 0 }, { 0, -1 }, { 1, 0 }, { 0, 1 } };
1178 static int safety = 0;
1180 /* check if starting field still has the desired content */
1181 if (field[from_x][from_y] == fill_element)
1186 if (safety > max_fieldx * max_fieldy)
1187 Error(ERR_EXIT, "Something went wrong in 'FloodFill()'. Please debug.");
1189 old_element = field[from_x][from_y];
1190 field[from_x][from_y] = fill_element;
1192 for (i = 0; i < 4; i++)
1194 x = from_x + check[i][0];
1195 y = from_y + check[i][1];
1197 if (IN_FIELD(x, y, max_fieldx, max_fieldy) && field[x][y] == old_element)
1198 FloodFillLevel(x, y, fill_element, field, max_fieldx, max_fieldy);
1204 void SetRandomAnimationValue(int x, int y)
1206 gfx.anim_random_frame = GfxRandom[x][y];
1209 int getGraphicAnimationFrame(int graphic, int sync_frame)
1211 /* animation synchronized with global frame counter, not move position */
1212 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
1213 sync_frame = FrameCounter;
1215 return getAnimationFrame(graphic_info[graphic].anim_frames,
1216 graphic_info[graphic].anim_delay,
1217 graphic_info[graphic].anim_mode,
1218 graphic_info[graphic].anim_start_frame,
1222 void getSizedGraphicSourceExt(int graphic, int frame, int tilesize,
1223 Bitmap **bitmap, int *x, int *y,
1224 boolean get_backside)
1226 struct GraphicInfo *g = &graphic_info[graphic];
1227 Bitmap *src_bitmap = g->bitmap;
1228 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
1229 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
1230 int tilesize_capped = MIN(MAX(1, tilesize), TILESIZE);
1232 // if no in-game graphics defined, always use standard graphic size
1233 if (g->bitmaps[IMG_BITMAP_GAME] == NULL)
1234 tilesize = TILESIZE;
1236 if (tilesize == gfx.standard_tile_size)
1237 src_bitmap = g->bitmaps[IMG_BITMAP_STANDARD];
1238 else if (tilesize == game.tile_size)
1239 src_bitmap = g->bitmaps[IMG_BITMAP_GAME];
1241 src_bitmap = g->bitmaps[IMG_BITMAP_1x1 - log_2(tilesize_capped)];
1243 if (g->offset_y == 0) /* frames are ordered horizontally */
1245 int max_width = g->anim_frames_per_line * g->width;
1246 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
1248 src_x = pos % max_width;
1249 src_y = src_y % g->height + pos / max_width * g->height;
1251 else if (g->offset_x == 0) /* frames are ordered vertically */
1253 int max_height = g->anim_frames_per_line * g->height;
1254 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
1256 src_x = src_x % g->width + pos / max_height * g->width;
1257 src_y = pos % max_height;
1259 else /* frames are ordered diagonally */
1261 src_x = src_x + frame * g->offset_x;
1262 src_y = src_y + frame * g->offset_y;
1265 *bitmap = src_bitmap;
1266 *x = src_x * tilesize / g->tile_size;
1267 *y = src_y * tilesize / g->tile_size;
1270 void getFixedGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1271 int *x, int *y, boolean get_backside)
1273 getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y,
1277 void getSizedGraphicSource(int graphic, int frame, int tilesize,
1278 Bitmap **bitmap, int *x, int *y)
1280 getSizedGraphicSourceExt(graphic, frame, tilesize, bitmap, x, y, FALSE);
1283 void getFixedGraphicSource(int graphic, int frame,
1284 Bitmap **bitmap, int *x, int *y)
1286 getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y, FALSE);
1289 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1291 getSizedGraphicSource(graphic, 0, MINI_TILESIZE, bitmap, x, y);
1294 inline static void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1295 int *x, int *y, boolean get_backside)
1297 struct GraphicInfo *g = &graphic_info[graphic];
1298 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
1299 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
1301 if (TILESIZE_VAR != TILESIZE)
1302 return getSizedGraphicSourceExt(graphic, frame, TILESIZE_VAR, bitmap, x, y,
1305 *bitmap = g->bitmap;
1307 if (g->offset_y == 0) /* frames are ordered horizontally */
1309 int max_width = g->anim_frames_per_line * g->width;
1310 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
1312 *x = pos % max_width;
1313 *y = src_y % g->height + pos / max_width * g->height;
1315 else if (g->offset_x == 0) /* frames are ordered vertically */
1317 int max_height = g->anim_frames_per_line * g->height;
1318 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
1320 *x = src_x % g->width + pos / max_height * g->width;
1321 *y = pos % max_height;
1323 else /* frames are ordered diagonally */
1325 *x = src_x + frame * g->offset_x;
1326 *y = src_y + frame * g->offset_y;
1329 *x = *x * TILESIZE_VAR / g->tile_size;
1330 *y = *y * TILESIZE_VAR / g->tile_size;
1333 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
1335 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
1338 void DrawGraphic(int x, int y, int graphic, int frame)
1341 if (!IN_SCR_FIELD(x, y))
1343 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1344 printf("DrawGraphic(): This should never happen!\n");
1349 DrawGraphicExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR, graphic,
1352 MarkTileDirty(x, y);
1355 void DrawFixedGraphic(int x, int y, int graphic, int frame)
1358 if (!IN_SCR_FIELD(x, y))
1360 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1361 printf("DrawGraphic(): This should never happen!\n");
1366 DrawFixedGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic,
1368 MarkTileDirty(x, y);
1371 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1377 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1379 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX_VAR, TILEY_VAR, x, y);
1382 void DrawFixedGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1388 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1389 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
1392 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
1395 if (!IN_SCR_FIELD(x, y))
1397 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1398 printf("DrawGraphicThruMask(): This should never happen!\n");
1403 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
1406 MarkTileDirty(x, y);
1409 void DrawFixedGraphicThruMask(int x, int y, int graphic, int frame)
1412 if (!IN_SCR_FIELD(x, y))
1414 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1415 printf("DrawGraphicThruMask(): This should never happen!\n");
1420 DrawFixedGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
1422 MarkTileDirty(x, y);
1425 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
1431 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1433 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX_VAR, TILEY_VAR,
1437 void DrawFixedGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y,
1438 int graphic, int frame)
1443 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1445 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY,
1449 void DrawSizedGraphic(int x, int y, int graphic, int frame, int tilesize)
1451 DrawSizedGraphicExt(drawto, SX + x * tilesize, SY + y * tilesize, graphic,
1453 MarkTileDirty(x / tilesize, y / tilesize);
1456 void DrawSizedGraphicExt(DrawBuffer *d, int x, int y, int graphic, int frame,
1462 getSizedGraphicSource(graphic, frame, tilesize, &src_bitmap, &src_x, &src_y);
1463 BlitBitmap(src_bitmap, d, src_x, src_y, tilesize, tilesize, x, y);
1466 void DrawMiniGraphic(int x, int y, int graphic)
1468 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
1469 MarkTileDirty(x / 2, y / 2);
1472 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
1477 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1478 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
1481 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
1482 int graphic, int frame,
1483 int cut_mode, int mask_mode)
1488 int width = TILEX, height = TILEY;
1491 if (dx || dy) /* shifted graphic */
1493 if (x < BX1) /* object enters playfield from the left */
1500 else if (x > BX2) /* object enters playfield from the right */
1506 else if (x == BX1 && dx < 0) /* object leaves playfield to the left */
1512 else if (x == BX2 && dx > 0) /* object leaves playfield to the right */
1514 else if (dx) /* general horizontal movement */
1515 MarkTileDirty(x + SIGN(dx), y);
1517 if (y < BY1) /* object enters playfield from the top */
1519 if (cut_mode == CUT_BELOW) /* object completely above top border */
1527 else if (y > BY2) /* object enters playfield from the bottom */
1533 else if (y == BY1 && dy < 0) /* object leaves playfield to the top */
1539 else if (dy > 0 && cut_mode == CUT_ABOVE)
1541 if (y == BY2) /* object completely above bottom border */
1547 MarkTileDirty(x, y + 1);
1548 } /* object leaves playfield to the bottom */
1549 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1551 else if (dy) /* general vertical movement */
1552 MarkTileDirty(x, y + SIGN(dy));
1556 if (!IN_SCR_FIELD(x, y))
1558 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1559 printf("DrawGraphicShifted(): This should never happen!\n");
1564 width = width * TILESIZE_VAR / TILESIZE;
1565 height = height * TILESIZE_VAR / TILESIZE;
1566 cx = cx * TILESIZE_VAR / TILESIZE;
1567 cy = cy * TILESIZE_VAR / TILESIZE;
1568 dx = dx * TILESIZE_VAR / TILESIZE;
1569 dy = dy * TILESIZE_VAR / TILESIZE;
1571 if (width > 0 && height > 0)
1573 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1578 dst_x = FX + x * TILEX_VAR + dx;
1579 dst_y = FY + y * TILEY_VAR + dy;
1581 if (mask_mode == USE_MASKING)
1582 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1585 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1588 MarkTileDirty(x, y);
1592 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
1593 int graphic, int frame,
1594 int cut_mode, int mask_mode)
1599 int width = TILEX_VAR, height = TILEY_VAR;
1602 int x2 = x + SIGN(dx);
1603 int y2 = y + SIGN(dy);
1605 /* movement with two-tile animations must be sync'ed with movement position,
1606 not with current GfxFrame (which can be higher when using slow movement) */
1607 int anim_pos = (dx ? ABS(dx) : ABS(dy));
1608 int anim_frames = graphic_info[graphic].anim_frames;
1610 /* (we also need anim_delay here for movement animations with less frames) */
1611 int anim_delay = graphic_info[graphic].anim_delay;
1612 int sync_frame = anim_pos * anim_frames * anim_delay / TILESIZE;
1614 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
1615 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
1617 /* re-calculate animation frame for two-tile movement animation */
1618 frame = getGraphicAnimationFrame(graphic, sync_frame);
1620 /* check if movement start graphic inside screen area and should be drawn */
1621 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
1623 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
1625 dst_x = FX + x1 * TILEX_VAR;
1626 dst_y = FY + y1 * TILEY_VAR;
1628 if (mask_mode == USE_MASKING)
1629 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1632 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1635 MarkTileDirty(x1, y1);
1638 /* check if movement end graphic inside screen area and should be drawn */
1639 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
1641 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
1643 dst_x = FX + x2 * TILEX_VAR;
1644 dst_y = FY + y2 * TILEY_VAR;
1646 if (mask_mode == USE_MASKING)
1647 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1650 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1653 MarkTileDirty(x2, y2);
1657 static void DrawGraphicShifted(int x, int y, int dx, int dy,
1658 int graphic, int frame,
1659 int cut_mode, int mask_mode)
1663 DrawGraphic(x, y, graphic, frame);
1668 if (graphic_info[graphic].double_movement) /* EM style movement images */
1669 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1671 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1674 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1675 int frame, int cut_mode)
1677 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
1680 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1681 int cut_mode, int mask_mode)
1683 int lx = LEVELX(x), ly = LEVELY(y);
1687 if (IN_LEV_FIELD(lx, ly))
1689 SetRandomAnimationValue(lx, ly);
1691 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
1692 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1694 /* do not use double (EM style) movement graphic when not moving */
1695 if (graphic_info[graphic].double_movement && !dx && !dy)
1697 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
1698 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1701 else /* border element */
1703 graphic = el2img(element);
1704 frame = getGraphicAnimationFrame(graphic, -1);
1707 if (element == EL_EXPANDABLE_WALL)
1709 boolean left_stopped = FALSE, right_stopped = FALSE;
1711 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1712 left_stopped = TRUE;
1713 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1714 right_stopped = TRUE;
1716 if (left_stopped && right_stopped)
1718 else if (left_stopped)
1720 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1721 frame = graphic_info[graphic].anim_frames - 1;
1723 else if (right_stopped)
1725 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1726 frame = graphic_info[graphic].anim_frames - 1;
1731 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1732 else if (mask_mode == USE_MASKING)
1733 DrawGraphicThruMask(x, y, graphic, frame);
1735 DrawGraphic(x, y, graphic, frame);
1738 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1739 int cut_mode, int mask_mode)
1741 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1742 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1743 cut_mode, mask_mode);
1746 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1749 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1752 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1755 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1758 void DrawLevelElementThruMask(int x, int y, int element)
1760 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1763 void DrawLevelFieldThruMask(int x, int y)
1765 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1768 /* !!! implementation of quicksand is totally broken !!! */
1769 #define IS_CRUMBLED_TILE(x, y, e) \
1770 (GFX_CRUMBLED(e) && (!IN_LEV_FIELD(x, y) || \
1771 !IS_MOVING(x, y) || \
1772 (e) == EL_QUICKSAND_EMPTYING || \
1773 (e) == EL_QUICKSAND_FAST_EMPTYING))
1775 static void DrawLevelFieldCrumbledInnerCorners(int x, int y, int dx, int dy,
1780 int width, height, cx, cy;
1781 int sx = SCREENX(x), sy = SCREENY(y);
1782 int crumbled_border_size = graphic_info[graphic].border_size;
1785 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1787 for (i = 1; i < 4; i++)
1789 int dxx = (i & 1 ? dx : 0);
1790 int dyy = (i & 2 ? dy : 0);
1793 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1796 /* check if neighbour field is of same crumble type */
1797 boolean same = (IS_CRUMBLED_TILE(xx, yy, element) &&
1798 graphic_info[graphic].class ==
1799 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class);
1801 /* return if check prevents inner corner */
1802 if (same == (dxx == dx && dyy == dy))
1806 /* if we reach this point, we have an inner corner */
1808 getGraphicSource(graphic, 1, &src_bitmap, &src_x, &src_y);
1810 width = crumbled_border_size * TILESIZE_VAR / TILESIZE;
1811 height = crumbled_border_size * TILESIZE_VAR / TILESIZE;
1812 cx = (dx > 0 ? TILESIZE_VAR - width : 0);
1813 cy = (dy > 0 ? TILESIZE_VAR - height : 0);
1815 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1816 width, height, FX + sx * TILEX_VAR + cx, FY + sy * TILEY_VAR + cy);
1819 static void DrawLevelFieldCrumbledBorders(int x, int y, int graphic, int frame,
1824 int width, height, bx, by, cx, cy;
1825 int sx = SCREENX(x), sy = SCREENY(y);
1826 int crumbled_border_size = graphic_info[graphic].border_size;
1827 int crumbled_border_size_var = crumbled_border_size * TILESIZE_VAR / TILESIZE;
1828 int crumbled_border_pos_var = TILESIZE_VAR - crumbled_border_size_var;
1831 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1833 /* draw simple, sloppy, non-corner-accurate crumbled border */
1835 width = (dir == 1 || dir == 2 ? crumbled_border_size_var : TILESIZE_VAR);
1836 height = (dir == 0 || dir == 3 ? crumbled_border_size_var : TILESIZE_VAR);
1837 cx = (dir == 2 ? crumbled_border_pos_var : 0);
1838 cy = (dir == 3 ? crumbled_border_pos_var : 0);
1840 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy, width, height,
1841 FX + sx * TILEX_VAR + cx,
1842 FY + sy * TILEY_VAR + cy);
1844 /* (remaining middle border part must be at least as big as corner part) */
1845 if (!(graphic_info[graphic].style & STYLE_ACCURATE_BORDERS) ||
1846 crumbled_border_size >= TILESIZE / 3)
1849 /* correct corners of crumbled border, if needed */
1851 for (i = -1; i <= 1; i += 2)
1853 int xx = x + (dir == 0 || dir == 3 ? i : 0);
1854 int yy = y + (dir == 1 || dir == 2 ? i : 0);
1855 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1858 /* check if neighbour field is of same crumble type */
1859 if (IS_CRUMBLED_TILE(xx, yy, element) &&
1860 graphic_info[graphic].class ==
1861 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1863 /* no crumbled corner, but continued crumbled border */
1865 int c1 = (dir == 2 || dir == 3 ? crumbled_border_pos_var : 0);
1866 int c2 = (i == 1 ? crumbled_border_pos_var : 0);
1867 int b1 = (i == 1 ? crumbled_border_size_var :
1868 TILESIZE_VAR - 2 * crumbled_border_size_var);
1870 width = crumbled_border_size_var;
1871 height = crumbled_border_size_var;
1873 if (dir == 1 || dir == 2)
1888 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
1890 FX + sx * TILEX_VAR + cx,
1891 FY + sy * TILEY_VAR + cy);
1896 static void DrawLevelFieldCrumbledExt(int x, int y, int graphic, int frame)
1898 int sx = SCREENX(x), sy = SCREENY(y);
1901 static int xy[4][2] =
1909 if (!IN_LEV_FIELD(x, y))
1912 element = TILE_GFX_ELEMENT(x, y);
1914 /* crumble field itself */
1915 if (IS_CRUMBLED_TILE(x, y, element))
1917 if (!IN_SCR_FIELD(sx, sy))
1920 for (i = 0; i < 4; i++)
1922 int xx = x + xy[i][0];
1923 int yy = y + xy[i][1];
1925 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1928 /* check if neighbour field is of same crumble type */
1929 if (IS_CRUMBLED_TILE(xx, yy, element) &&
1930 graphic_info[graphic].class ==
1931 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1934 DrawLevelFieldCrumbledBorders(x, y, graphic, frame, i);
1937 if ((graphic_info[graphic].style & STYLE_INNER_CORNERS) &&
1938 graphic_info[graphic].anim_frames == 2)
1940 for (i = 0; i < 4; i++)
1942 int dx = (i & 1 ? +1 : -1);
1943 int dy = (i & 2 ? +1 : -1);
1945 DrawLevelFieldCrumbledInnerCorners(x, y, dx, dy, graphic);
1949 MarkTileDirty(sx, sy);
1951 else /* center field not crumbled -- crumble neighbour fields */
1953 for (i = 0; i < 4; i++)
1955 int xx = x + xy[i][0];
1956 int yy = y + xy[i][1];
1957 int sxx = sx + xy[i][0];
1958 int syy = sy + xy[i][1];
1960 if (!IN_LEV_FIELD(xx, yy) ||
1961 !IN_SCR_FIELD(sxx, syy))
1964 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
1967 element = TILE_GFX_ELEMENT(xx, yy);
1969 if (!IS_CRUMBLED_TILE(xx, yy, element))
1972 graphic = el_act2crm(element, ACTION_DEFAULT);
1974 DrawLevelFieldCrumbledBorders(xx, yy, graphic, 0, 3 - i);
1976 MarkTileDirty(sxx, syy);
1981 void DrawLevelFieldCrumbled(int x, int y)
1985 if (!IN_LEV_FIELD(x, y))
1988 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1989 GfxElement[x][y] != EL_UNDEFINED &&
1990 GFX_CRUMBLED(GfxElement[x][y]))
1992 DrawLevelFieldCrumbledDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
1997 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
1999 DrawLevelFieldCrumbledExt(x, y, graphic, 0);
2002 void DrawLevelFieldCrumbledDigging(int x, int y, int direction,
2005 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
2006 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
2007 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
2008 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
2009 int sx = SCREENX(x), sy = SCREENY(y);
2011 DrawGraphic(sx, sy, graphic1, frame1);
2012 DrawLevelFieldCrumbledExt(x, y, graphic2, frame2);
2015 void DrawLevelFieldCrumbledNeighbours(int x, int y)
2017 int sx = SCREENX(x), sy = SCREENY(y);
2018 static int xy[4][2] =
2027 for (i = 0; i < 4; i++)
2029 int xx = x + xy[i][0];
2030 int yy = y + xy[i][1];
2031 int sxx = sx + xy[i][0];
2032 int syy = sy + xy[i][1];
2034 if (!IN_LEV_FIELD(xx, yy) ||
2035 !IN_SCR_FIELD(sxx, syy) ||
2036 !GFX_CRUMBLED(Feld[xx][yy]) ||
2040 DrawLevelField(xx, yy);
2044 static int getBorderElement(int x, int y)
2048 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
2049 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
2050 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
2051 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
2052 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
2053 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
2054 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
2056 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
2057 int steel_position = (x == -1 && y == -1 ? 0 :
2058 x == lev_fieldx && y == -1 ? 1 :
2059 x == -1 && y == lev_fieldy ? 2 :
2060 x == lev_fieldx && y == lev_fieldy ? 3 :
2061 x == -1 || x == lev_fieldx ? 4 :
2062 y == -1 || y == lev_fieldy ? 5 : 6);
2064 return border[steel_position][steel_type];
2067 void DrawScreenElement(int x, int y, int element)
2069 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
2070 DrawLevelFieldCrumbled(LEVELX(x), LEVELY(y));
2073 void DrawLevelElement(int x, int y, int element)
2075 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2076 DrawScreenElement(SCREENX(x), SCREENY(y), element);
2079 void DrawScreenField(int x, int y)
2081 int lx = LEVELX(x), ly = LEVELY(y);
2082 int element, content;
2084 if (!IN_LEV_FIELD(lx, ly))
2086 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
2089 element = getBorderElement(lx, ly);
2091 DrawScreenElement(x, y, element);
2096 element = Feld[lx][ly];
2097 content = Store[lx][ly];
2099 if (IS_MOVING(lx, ly))
2101 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
2102 boolean cut_mode = NO_CUTTING;
2104 if (element == EL_QUICKSAND_EMPTYING ||
2105 element == EL_QUICKSAND_FAST_EMPTYING ||
2106 element == EL_MAGIC_WALL_EMPTYING ||
2107 element == EL_BD_MAGIC_WALL_EMPTYING ||
2108 element == EL_DC_MAGIC_WALL_EMPTYING ||
2109 element == EL_AMOEBA_DROPPING)
2110 cut_mode = CUT_ABOVE;
2111 else if (element == EL_QUICKSAND_FILLING ||
2112 element == EL_QUICKSAND_FAST_FILLING ||
2113 element == EL_MAGIC_WALL_FILLING ||
2114 element == EL_BD_MAGIC_WALL_FILLING ||
2115 element == EL_DC_MAGIC_WALL_FILLING)
2116 cut_mode = CUT_BELOW;
2118 if (cut_mode == CUT_ABOVE)
2119 DrawScreenElement(x, y, element);
2121 DrawScreenElement(x, y, EL_EMPTY);
2124 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
2125 else if (cut_mode == NO_CUTTING)
2126 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
2129 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
2131 if (cut_mode == CUT_BELOW &&
2132 IN_LEV_FIELD(lx, ly + 1) && IN_SCR_FIELD(x, y + 1))
2133 DrawLevelElement(lx, ly + 1, element);
2136 if (content == EL_ACID)
2138 int dir = MovDir[lx][ly];
2139 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
2140 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
2142 DrawLevelElementThruMask(newlx, newly, EL_ACID);
2145 else if (IS_BLOCKED(lx, ly))
2150 boolean cut_mode = NO_CUTTING;
2151 int element_old, content_old;
2153 Blocked2Moving(lx, ly, &oldx, &oldy);
2156 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
2157 MovDir[oldx][oldy] == MV_RIGHT);
2159 element_old = Feld[oldx][oldy];
2160 content_old = Store[oldx][oldy];
2162 if (element_old == EL_QUICKSAND_EMPTYING ||
2163 element_old == EL_QUICKSAND_FAST_EMPTYING ||
2164 element_old == EL_MAGIC_WALL_EMPTYING ||
2165 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
2166 element_old == EL_DC_MAGIC_WALL_EMPTYING ||
2167 element_old == EL_AMOEBA_DROPPING)
2168 cut_mode = CUT_ABOVE;
2170 DrawScreenElement(x, y, EL_EMPTY);
2173 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
2175 else if (cut_mode == NO_CUTTING)
2176 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
2179 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
2182 else if (IS_DRAWABLE(element))
2183 DrawScreenElement(x, y, element);
2185 DrawScreenElement(x, y, EL_EMPTY);
2188 void DrawLevelField(int x, int y)
2190 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2191 DrawScreenField(SCREENX(x), SCREENY(y));
2192 else if (IS_MOVING(x, y))
2196 Moving2Blocked(x, y, &newx, &newy);
2197 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
2198 DrawScreenField(SCREENX(newx), SCREENY(newy));
2200 else if (IS_BLOCKED(x, y))
2204 Blocked2Moving(x, y, &oldx, &oldy);
2205 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
2206 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
2210 void DrawSizedElement(int x, int y, int element, int tilesize)
2214 graphic = el2edimg(element);
2215 DrawSizedGraphic(x, y, graphic, 0, tilesize);
2218 void DrawMiniElement(int x, int y, int element)
2222 graphic = el2edimg(element);
2223 DrawMiniGraphic(x, y, graphic);
2226 void DrawSizedElementOrWall(int sx, int sy, int scroll_x, int scroll_y,
2229 int x = sx + scroll_x, y = sy + scroll_y;
2231 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
2232 DrawSizedElement(sx, sy, EL_EMPTY, tilesize);
2233 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
2234 DrawSizedElement(sx, sy, Feld[x][y], tilesize);
2236 DrawSizedGraphic(sx, sy, el2edimg(getBorderElement(x, y)), 0, tilesize);
2239 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
2241 int x = sx + scroll_x, y = sy + scroll_y;
2243 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
2244 DrawMiniElement(sx, sy, EL_EMPTY);
2245 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
2246 DrawMiniElement(sx, sy, Feld[x][y]);
2248 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
2251 void DrawEnvelopeBackgroundTiles(int graphic, int startx, int starty,
2252 int x, int y, int xsize, int ysize,
2253 int tile_width, int tile_height)
2257 int dst_x = startx + x * tile_width;
2258 int dst_y = starty + y * tile_height;
2259 int width = graphic_info[graphic].width;
2260 int height = graphic_info[graphic].height;
2261 int inner_width_raw = MAX(width - 2 * tile_width, tile_width);
2262 int inner_height_raw = MAX(height - 2 * tile_height, tile_height);
2263 int inner_width = inner_width_raw - (inner_width_raw % tile_width);
2264 int inner_height = inner_height_raw - (inner_height_raw % tile_height);
2265 int inner_sx = (width >= 3 * tile_width ? tile_width : 0);
2266 int inner_sy = (height >= 3 * tile_height ? tile_height : 0);
2267 boolean draw_masked = graphic_info[graphic].draw_masked;
2269 getFixedGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
2271 if (src_bitmap == NULL || width < tile_width || height < tile_height)
2273 ClearRectangle(drawto, dst_x, dst_y, tile_width, tile_height);
2277 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - tile_width :
2278 inner_sx + (x - 1) * tile_width % inner_width);
2279 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - tile_height :
2280 inner_sy + (y - 1) * tile_height % inner_height);
2283 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
2286 BlitBitmap(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
2290 void DrawEnvelopeBackground(int graphic, int startx, int starty,
2291 int x, int y, int xsize, int ysize, int font_nr)
2293 int font_width = getFontWidth(font_nr);
2294 int font_height = getFontHeight(font_nr);
2296 DrawEnvelopeBackgroundTiles(graphic, startx, starty, x, y, xsize, ysize,
2297 font_width, font_height);
2300 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
2302 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2303 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2304 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2305 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2306 boolean no_delay = (tape.warp_forward);
2307 unsigned int anim_delay = 0;
2308 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
2309 int anim_delay_value = (no_delay ? 0 : frame_delay_value) / 2;
2310 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
2311 int font_width = getFontWidth(font_nr);
2312 int font_height = getFontHeight(font_nr);
2313 int max_xsize = level.envelope[envelope_nr].xsize;
2314 int max_ysize = level.envelope[envelope_nr].ysize;
2315 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
2316 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
2317 int xend = max_xsize;
2318 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
2319 int xstep = (xstart < xend ? 1 : 0);
2320 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2322 int end = MAX(xend - xstart, yend - ystart);
2325 for (i = start; i <= end; i++)
2327 int last_frame = end; // last frame of this "for" loop
2328 int x = xstart + i * xstep;
2329 int y = ystart + i * ystep;
2330 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2331 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2332 int sx = SX + (SXSIZE - xsize * font_width) / 2;
2333 int sy = SY + (SYSIZE - ysize * font_height) / 2;
2336 SetDrawtoField(DRAW_TO_FIELDBUFFER);
2338 BlitScreenToBitmap(backbuffer);
2340 SetDrawtoField(DRAW_TO_BACKBUFFER);
2342 for (yy = 0; yy < ysize; yy++)
2343 for (xx = 0; xx < xsize; xx++)
2344 DrawEnvelopeBackground(graphic, sx, sy, xx, yy, xsize, ysize, font_nr);
2346 DrawTextBuffer(sx + font_width, sy + font_height,
2347 level.envelope[envelope_nr].text, font_nr, max_xsize,
2348 xsize - 2, ysize - 2, 0, mask_mode,
2349 level.envelope[envelope_nr].autowrap,
2350 level.envelope[envelope_nr].centered, FALSE);
2352 redraw_mask |= REDRAW_FIELD;
2355 SkipUntilDelayReached(&anim_delay, anim_delay_value, &i, last_frame);
2359 void ShowEnvelope(int envelope_nr)
2361 int element = EL_ENVELOPE_1 + envelope_nr;
2362 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2363 int sound_opening = element_info[element].sound[ACTION_OPENING];
2364 int sound_closing = element_info[element].sound[ACTION_CLOSING];
2365 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2366 boolean no_delay = (tape.warp_forward);
2367 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
2368 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
2369 int anim_mode = graphic_info[graphic].anim_mode;
2370 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2371 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2373 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
2375 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2377 if (anim_mode == ANIM_DEFAULT)
2378 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
2380 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
2383 Delay(wait_delay_value);
2385 WaitForEventToContinue();
2387 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2389 if (anim_mode != ANIM_NONE)
2390 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
2392 if (anim_mode == ANIM_DEFAULT)
2393 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
2395 game.envelope_active = FALSE;
2397 SetDrawtoField(DRAW_TO_FIELDBUFFER);
2399 redraw_mask |= REDRAW_FIELD;
2403 static void setRequestBasePosition(int *x, int *y)
2405 int sx_base, sy_base;
2407 if (request.x != -1)
2408 sx_base = request.x;
2409 else if (request.align == ALIGN_LEFT)
2411 else if (request.align == ALIGN_RIGHT)
2412 sx_base = SX + SXSIZE;
2414 sx_base = SX + SXSIZE / 2;
2416 if (request.y != -1)
2417 sy_base = request.y;
2418 else if (request.valign == VALIGN_TOP)
2420 else if (request.valign == VALIGN_BOTTOM)
2421 sy_base = SY + SYSIZE;
2423 sy_base = SY + SYSIZE / 2;
2429 static void setRequestPositionExt(int *x, int *y, int width, int height,
2430 boolean add_border_size)
2432 int border_size = request.border_size;
2433 int sx_base, sy_base;
2436 setRequestBasePosition(&sx_base, &sy_base);
2438 if (request.align == ALIGN_LEFT)
2440 else if (request.align == ALIGN_RIGHT)
2441 sx = sx_base - width;
2443 sx = sx_base - width / 2;
2445 if (request.valign == VALIGN_TOP)
2447 else if (request.valign == VALIGN_BOTTOM)
2448 sy = sy_base - height;
2450 sy = sy_base - height / 2;
2452 sx = MAX(0, MIN(sx, WIN_XSIZE - width));
2453 sy = MAX(0, MIN(sy, WIN_YSIZE - height));
2455 if (add_border_size)
2465 static void setRequestPosition(int *x, int *y, boolean add_border_size)
2467 setRequestPositionExt(x, y, request.width, request.height, add_border_size);
2470 void DrawEnvelopeRequest(char *text)
2472 char *text_final = text;
2473 char *text_door_style = NULL;
2474 int graphic = IMG_BACKGROUND_REQUEST;
2475 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2476 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2477 int font_nr = FONT_REQUEST;
2478 int font_width = getFontWidth(font_nr);
2479 int font_height = getFontHeight(font_nr);
2480 int border_size = request.border_size;
2481 int line_spacing = request.line_spacing;
2482 int line_height = font_height + line_spacing;
2483 int max_text_width = request.width - 2 * border_size;
2484 int max_text_height = request.height - 2 * border_size;
2485 int line_length = max_text_width / font_width;
2486 int max_lines = max_text_height / line_height;
2487 int text_width = line_length * font_width;
2488 int width = request.width;
2489 int height = request.height;
2490 int tile_size = MAX(request.step_offset, 1);
2491 int x_steps = width / tile_size;
2492 int y_steps = height / tile_size;
2493 int sx_offset = border_size;
2494 int sy_offset = border_size;
2498 if (request.centered)
2499 sx_offset = (request.width - text_width) / 2;
2501 if (request.wrap_single_words && !request.autowrap)
2503 char *src_text_ptr, *dst_text_ptr;
2505 text_door_style = checked_malloc(2 * strlen(text) + 1);
2507 src_text_ptr = text;
2508 dst_text_ptr = text_door_style;
2510 while (*src_text_ptr)
2512 if (*src_text_ptr == ' ' ||
2513 *src_text_ptr == '?' ||
2514 *src_text_ptr == '!')
2515 *dst_text_ptr++ = '\n';
2517 if (*src_text_ptr != ' ')
2518 *dst_text_ptr++ = *src_text_ptr;
2523 *dst_text_ptr = '\0';
2525 text_final = text_door_style;
2528 setRequestPosition(&sx, &sy, FALSE);
2530 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
2532 for (y = 0; y < y_steps; y++)
2533 for (x = 0; x < x_steps; x++)
2534 DrawEnvelopeBackgroundTiles(graphic, sx, sy,
2535 x, y, x_steps, y_steps,
2536 tile_size, tile_size);
2538 /* force DOOR font inside door area */
2539 SetFontStatus(GAME_MODE_PSEUDO_DOOR);
2541 DrawTextBuffer(sx + sx_offset, sy + sy_offset, text_final, font_nr,
2542 line_length, -1, max_lines, line_spacing, mask_mode,
2543 request.autowrap, request.centered, FALSE);
2547 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2548 RedrawGadget(tool_gadget[i]);
2550 // store readily prepared envelope request for later use when animating
2551 BlitBitmap(backbuffer, bitmap_db_store_2, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2553 if (text_door_style)
2554 free(text_door_style);
2557 void AnimateEnvelopeRequest(int anim_mode, int action)
2559 int graphic = IMG_BACKGROUND_REQUEST;
2560 boolean draw_masked = graphic_info[graphic].draw_masked;
2561 int delay_value_normal = request.step_delay;
2562 int delay_value_fast = delay_value_normal / 2;
2563 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2564 boolean no_delay = (tape.warp_forward);
2565 int delay_value = (ffwd_delay ? delay_value_fast : delay_value_normal);
2566 int anim_delay_value = (no_delay ? 0 : delay_value + 500 * 0) / 2;
2567 unsigned int anim_delay = 0;
2569 int tile_size = MAX(request.step_offset, 1);
2570 int max_xsize = request.width / tile_size;
2571 int max_ysize = request.height / tile_size;
2572 int max_xsize_inner = max_xsize - 2;
2573 int max_ysize_inner = max_ysize - 2;
2575 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize_inner : 0);
2576 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize_inner : 0);
2577 int xend = max_xsize_inner;
2578 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize_inner : 0);
2579 int xstep = (xstart < xend ? 1 : 0);
2580 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2582 int end = MAX(xend - xstart, yend - ystart);
2585 if (setup.quick_doors)
2592 for (i = start; i <= end; i++)
2594 int last_frame = end; // last frame of this "for" loop
2595 int x = xstart + i * xstep;
2596 int y = ystart + i * ystep;
2597 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2598 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2599 int xsize_size_left = (xsize - 1) * tile_size;
2600 int ysize_size_top = (ysize - 1) * tile_size;
2601 int max_xsize_pos = (max_xsize - 1) * tile_size;
2602 int max_ysize_pos = (max_ysize - 1) * tile_size;
2603 int width = xsize * tile_size;
2604 int height = ysize * tile_size;
2609 setRequestPosition(&src_x, &src_y, FALSE);
2610 setRequestPositionExt(&dst_x, &dst_y, width, height, FALSE);
2612 BlitBitmap(bitmap_db_store_1, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2614 for (yy = 0; yy < 2; yy++)
2616 for (xx = 0; xx < 2; xx++)
2618 int src_xx = src_x + xx * max_xsize_pos;
2619 int src_yy = src_y + yy * max_ysize_pos;
2620 int dst_xx = dst_x + xx * xsize_size_left;
2621 int dst_yy = dst_y + yy * ysize_size_top;
2622 int xx_size = (xx ? tile_size : xsize_size_left);
2623 int yy_size = (yy ? tile_size : ysize_size_top);
2626 BlitBitmapMasked(bitmap_db_store_2, backbuffer,
2627 src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
2629 BlitBitmap(bitmap_db_store_2, backbuffer,
2630 src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
2634 redraw_mask |= REDRAW_FIELD;
2638 SkipUntilDelayReached(&anim_delay, anim_delay_value, &i, last_frame);
2642 void ShowEnvelopeRequest(char *text, unsigned int req_state, int action)
2644 int graphic = IMG_BACKGROUND_REQUEST;
2645 int sound_opening = SND_REQUEST_OPENING;
2646 int sound_closing = SND_REQUEST_CLOSING;
2647 int anim_mode_1 = request.anim_mode; /* (higher priority) */
2648 int anim_mode_2 = graphic_info[graphic].anim_mode; /* (lower priority) */
2649 int anim_mode = (anim_mode_1 != ANIM_DEFAULT ? anim_mode_1 : anim_mode_2);
2650 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2651 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2653 if (game_status == GAME_MODE_PLAYING)
2654 BlitScreenToBitmap(backbuffer);
2656 SetDrawtoField(DRAW_TO_BACKBUFFER);
2658 // SetDrawBackgroundMask(REDRAW_NONE);
2660 if (action == ACTION_OPENING)
2662 BlitBitmap(backbuffer, bitmap_db_store_1, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2664 if (req_state & REQ_ASK)
2666 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2667 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2669 else if (req_state & REQ_CONFIRM)
2671 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2673 else if (req_state & REQ_PLAYER)
2675 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2676 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2677 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2678 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2681 DrawEnvelopeRequest(text);
2684 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
2686 if (action == ACTION_OPENING)
2688 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2690 if (anim_mode == ANIM_DEFAULT)
2691 AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_OPENING);
2693 AnimateEnvelopeRequest(main_anim_mode, ACTION_OPENING);
2697 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2699 if (anim_mode != ANIM_NONE)
2700 AnimateEnvelopeRequest(main_anim_mode, ACTION_CLOSING);
2702 if (anim_mode == ANIM_DEFAULT)
2703 AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_CLOSING);
2706 game.envelope_active = FALSE;
2708 if (action == ACTION_CLOSING)
2709 BlitBitmap(bitmap_db_store_1, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2711 // SetDrawBackgroundMask(last_draw_background_mask);
2713 redraw_mask |= REDRAW_FIELD;
2717 if (action == ACTION_CLOSING &&
2718 game_status == GAME_MODE_PLAYING &&
2719 level.game_engine_type == GAME_ENGINE_TYPE_RND)
2720 SetDrawtoField(DRAW_TO_FIELDBUFFER);
2723 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
2727 int graphic = el2preimg(element);
2729 getSizedGraphicSource(graphic, 0, tilesize, &src_bitmap, &src_x, &src_y);
2730 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
2733 void DrawLevel(int draw_background_mask)
2737 SetMainBackgroundImage(IMG_BACKGROUND_PLAYING);
2738 SetDrawBackgroundMask(draw_background_mask);
2742 for (x = BX1; x <= BX2; x++)
2743 for (y = BY1; y <= BY2; y++)
2744 DrawScreenField(x, y);
2746 redraw_mask |= REDRAW_FIELD;
2749 void DrawSizedLevel(int size_x, int size_y, int scroll_x, int scroll_y,
2754 for (x = 0; x < size_x; x++)
2755 for (y = 0; y < size_y; y++)
2756 DrawSizedElementOrWall(x, y, scroll_x, scroll_y, tilesize);
2758 redraw_mask |= REDRAW_FIELD;
2761 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
2765 for (x = 0; x < size_x; x++)
2766 for (y = 0; y < size_y; y++)
2767 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
2769 redraw_mask |= REDRAW_FIELD;
2772 static void DrawPreviewLevelPlayfieldExt(int from_x, int from_y)
2774 boolean show_level_border = (BorderElement != EL_EMPTY);
2775 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2776 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2777 int tile_size = preview.tile_size;
2778 int preview_width = preview.xsize * tile_size;
2779 int preview_height = preview.ysize * tile_size;
2780 int real_preview_xsize = MIN(level_xsize, preview.xsize);
2781 int real_preview_ysize = MIN(level_ysize, preview.ysize);
2782 int real_preview_width = real_preview_xsize * tile_size;
2783 int real_preview_height = real_preview_ysize * tile_size;
2784 int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
2785 int dst_y = SY + ALIGNED_YPOS(preview.y, preview_height, preview.valign);
2788 if (!IN_GFX_FIELD_FULL(dst_x, dst_y + preview_height - 1))
2791 DrawBackground(dst_x, dst_y, preview_width, preview_height);
2793 dst_x += (preview_width - real_preview_width) / 2;
2794 dst_y += (preview_height - real_preview_height) / 2;
2796 for (x = 0; x < real_preview_xsize; x++)
2798 for (y = 0; y < real_preview_ysize; y++)
2800 int lx = from_x + x + (show_level_border ? -1 : 0);
2801 int ly = from_y + y + (show_level_border ? -1 : 0);
2802 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
2803 getBorderElement(lx, ly));
2805 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
2806 element, tile_size);
2810 redraw_mask |= REDRAW_FIELD;
2813 #define MICROLABEL_EMPTY 0
2814 #define MICROLABEL_LEVEL_NAME 1
2815 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
2816 #define MICROLABEL_LEVEL_AUTHOR 3
2817 #define MICROLABEL_IMPORTED_FROM_HEAD 4
2818 #define MICROLABEL_IMPORTED_FROM 5
2819 #define MICROLABEL_IMPORTED_BY_HEAD 6
2820 #define MICROLABEL_IMPORTED_BY 7
2822 static int getMaxTextLength(struct TextPosInfo *pos, int font_nr)
2824 int max_text_width = SXSIZE;
2825 int font_width = getFontWidth(font_nr);
2827 if (pos->align == ALIGN_CENTER)
2828 max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
2829 else if (pos->align == ALIGN_RIGHT)
2830 max_text_width = pos->x;
2832 max_text_width = SXSIZE - pos->x;
2834 return max_text_width / font_width;
2837 static void DrawPreviewLevelLabelExt(int mode)
2839 struct TextPosInfo *pos = &menu.main.text.level_info_2;
2840 char label_text[MAX_OUTPUT_LINESIZE + 1];
2841 int max_len_label_text;
2842 int font_nr = pos->font;
2845 if (!IN_GFX_FIELD_FULL(pos->x, pos->y + getFontHeight(pos->font)))
2848 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
2849 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
2850 mode == MICROLABEL_IMPORTED_BY_HEAD)
2851 font_nr = pos->font_alt;
2853 max_len_label_text = getMaxTextLength(pos, font_nr);
2855 if (pos->size != -1)
2856 max_len_label_text = pos->size;
2858 for (i = 0; i < max_len_label_text; i++)
2859 label_text[i] = ' ';
2860 label_text[max_len_label_text] = '\0';
2862 if (strlen(label_text) > 0)
2863 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2866 (mode == MICROLABEL_LEVEL_NAME ? level.name :
2867 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
2868 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
2869 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
2870 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
2871 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
2872 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
2873 max_len_label_text);
2874 label_text[max_len_label_text] = '\0';
2876 if (strlen(label_text) > 0)
2877 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2879 redraw_mask |= REDRAW_FIELD;
2882 static void DrawPreviewLevelExt(boolean restart)
2884 static unsigned int scroll_delay = 0;
2885 static unsigned int label_delay = 0;
2886 static int from_x, from_y, scroll_direction;
2887 static int label_state, label_counter;
2888 unsigned int scroll_delay_value = preview.step_delay;
2889 boolean show_level_border = (BorderElement != EL_EMPTY);
2890 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2891 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2898 if (preview.anim_mode == ANIM_CENTERED)
2900 if (level_xsize > preview.xsize)
2901 from_x = (level_xsize - preview.xsize) / 2;
2902 if (level_ysize > preview.ysize)
2903 from_y = (level_ysize - preview.ysize) / 2;
2906 from_x += preview.xoffset;
2907 from_y += preview.yoffset;
2909 scroll_direction = MV_RIGHT;
2913 DrawPreviewLevelPlayfieldExt(from_x, from_y);
2914 DrawPreviewLevelLabelExt(label_state);
2916 /* initialize delay counters */
2917 DelayReached(&scroll_delay, 0);
2918 DelayReached(&label_delay, 0);
2920 if (leveldir_current->name)
2922 struct TextPosInfo *pos = &menu.main.text.level_info_1;
2923 char label_text[MAX_OUTPUT_LINESIZE + 1];
2924 int font_nr = pos->font;
2925 int max_len_label_text = getMaxTextLength(pos, font_nr);
2927 if (pos->size != -1)
2928 max_len_label_text = pos->size;
2930 strncpy(label_text, leveldir_current->name, max_len_label_text);
2931 label_text[max_len_label_text] = '\0';
2933 if (IN_GFX_FIELD_FULL(pos->x, pos->y + getFontHeight(pos->font)))
2934 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2940 /* scroll preview level, if needed */
2941 if (preview.anim_mode != ANIM_NONE &&
2942 (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
2943 DelayReached(&scroll_delay, scroll_delay_value))
2945 switch (scroll_direction)
2950 from_x -= preview.step_offset;
2951 from_x = (from_x < 0 ? 0 : from_x);
2954 scroll_direction = MV_UP;
2958 if (from_x < level_xsize - preview.xsize)
2960 from_x += preview.step_offset;
2961 from_x = (from_x > level_xsize - preview.xsize ?
2962 level_xsize - preview.xsize : from_x);
2965 scroll_direction = MV_DOWN;
2971 from_y -= preview.step_offset;
2972 from_y = (from_y < 0 ? 0 : from_y);
2975 scroll_direction = MV_RIGHT;
2979 if (from_y < level_ysize - preview.ysize)
2981 from_y += preview.step_offset;
2982 from_y = (from_y > level_ysize - preview.ysize ?
2983 level_ysize - preview.ysize : from_y);
2986 scroll_direction = MV_LEFT;
2993 DrawPreviewLevelPlayfieldExt(from_x, from_y);
2996 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
2997 /* redraw micro level label, if needed */
2998 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
2999 !strEqual(level.author, ANONYMOUS_NAME) &&
3000 !strEqual(level.author, leveldir_current->name) &&
3001 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
3003 int max_label_counter = 23;
3005 if (leveldir_current->imported_from != NULL &&
3006 strlen(leveldir_current->imported_from) > 0)
3007 max_label_counter += 14;
3008 if (leveldir_current->imported_by != NULL &&
3009 strlen(leveldir_current->imported_by) > 0)
3010 max_label_counter += 14;
3012 label_counter = (label_counter + 1) % max_label_counter;
3013 label_state = (label_counter >= 0 && label_counter <= 7 ?
3014 MICROLABEL_LEVEL_NAME :
3015 label_counter >= 9 && label_counter <= 12 ?
3016 MICROLABEL_LEVEL_AUTHOR_HEAD :
3017 label_counter >= 14 && label_counter <= 21 ?
3018 MICROLABEL_LEVEL_AUTHOR :
3019 label_counter >= 23 && label_counter <= 26 ?
3020 MICROLABEL_IMPORTED_FROM_HEAD :
3021 label_counter >= 28 && label_counter <= 35 ?
3022 MICROLABEL_IMPORTED_FROM :
3023 label_counter >= 37 && label_counter <= 40 ?
3024 MICROLABEL_IMPORTED_BY_HEAD :
3025 label_counter >= 42 && label_counter <= 49 ?
3026 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
3028 if (leveldir_current->imported_from == NULL &&
3029 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
3030 label_state == MICROLABEL_IMPORTED_FROM))
3031 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
3032 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
3034 DrawPreviewLevelLabelExt(label_state);
3038 void DrawPreviewLevelInitial()
3040 DrawPreviewLevelExt(TRUE);
3043 void DrawPreviewLevelAnimation()
3045 DrawPreviewLevelExt(FALSE);
3048 inline static void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
3049 int graphic, int sync_frame,
3052 int frame = getGraphicAnimationFrame(graphic, sync_frame);
3054 if (mask_mode == USE_MASKING)
3055 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
3057 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
3060 void DrawFixedGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
3061 int graphic, int sync_frame, int mask_mode)
3063 int frame = getGraphicAnimationFrame(graphic, sync_frame);
3065 if (mask_mode == USE_MASKING)
3066 DrawFixedGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
3068 DrawFixedGraphicExt(dst_bitmap, x, y, graphic, frame);
3071 inline static void DrawGraphicAnimation(int x, int y, int graphic)
3073 int lx = LEVELX(x), ly = LEVELY(y);
3075 if (!IN_SCR_FIELD(x, y))
3078 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
3079 graphic, GfxFrame[lx][ly], NO_MASKING);
3081 MarkTileDirty(x, y);
3084 void DrawFixedGraphicAnimation(int x, int y, int graphic)
3086 int lx = LEVELX(x), ly = LEVELY(y);
3088 if (!IN_SCR_FIELD(x, y))
3091 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
3092 graphic, GfxFrame[lx][ly], NO_MASKING);
3093 MarkTileDirty(x, y);
3096 void DrawLevelGraphicAnimation(int x, int y, int graphic)
3098 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
3101 void DrawLevelElementAnimation(int x, int y, int element)
3103 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
3105 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
3108 void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
3110 int sx = SCREENX(x), sy = SCREENY(y);
3112 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
3115 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
3118 DrawGraphicAnimation(sx, sy, graphic);
3121 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
3122 DrawLevelFieldCrumbled(x, y);
3124 if (GFX_CRUMBLED(Feld[x][y]))
3125 DrawLevelFieldCrumbled(x, y);
3129 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
3131 int sx = SCREENX(x), sy = SCREENY(y);
3134 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
3137 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
3139 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
3142 DrawGraphicAnimation(sx, sy, graphic);
3144 if (GFX_CRUMBLED(element))
3145 DrawLevelFieldCrumbled(x, y);
3148 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
3150 if (player->use_murphy)
3152 /* this works only because currently only one player can be "murphy" ... */
3153 static int last_horizontal_dir = MV_LEFT;
3154 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
3156 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3157 last_horizontal_dir = move_dir;
3159 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
3161 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
3163 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
3169 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
3172 static boolean equalGraphics(int graphic1, int graphic2)
3174 struct GraphicInfo *g1 = &graphic_info[graphic1];
3175 struct GraphicInfo *g2 = &graphic_info[graphic2];
3177 return (g1->bitmap == g2->bitmap &&
3178 g1->src_x == g2->src_x &&
3179 g1->src_y == g2->src_y &&
3180 g1->anim_frames == g2->anim_frames &&
3181 g1->anim_delay == g2->anim_delay &&
3182 g1->anim_mode == g2->anim_mode);
3185 void DrawAllPlayers()
3189 for (i = 0; i < MAX_PLAYERS; i++)
3190 if (stored_player[i].active)
3191 DrawPlayer(&stored_player[i]);
3194 void DrawPlayerField(int x, int y)
3196 if (!IS_PLAYER(x, y))
3199 DrawPlayer(PLAYERINFO(x, y));
3202 #define DRAW_PLAYER_OVER_PUSHED_ELEMENT 1
3204 void DrawPlayer(struct PlayerInfo *player)
3206 int jx = player->jx;
3207 int jy = player->jy;
3208 int move_dir = player->MovDir;
3209 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
3210 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
3211 int last_jx = (player->is_moving ? jx - dx : jx);
3212 int last_jy = (player->is_moving ? jy - dy : jy);
3213 int next_jx = jx + dx;
3214 int next_jy = jy + dy;
3215 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
3216 boolean player_is_opaque = FALSE;
3217 int sx = SCREENX(jx), sy = SCREENY(jy);
3218 int sxx = 0, syy = 0;
3219 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
3221 int action = ACTION_DEFAULT;
3222 int last_player_graphic = getPlayerGraphic(player, move_dir);
3223 int last_player_frame = player->Frame;
3226 /* GfxElement[][] is set to the element the player is digging or collecting;
3227 remove also for off-screen player if the player is not moving anymore */
3228 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
3229 GfxElement[jx][jy] = EL_UNDEFINED;
3231 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
3235 if (!IN_LEV_FIELD(jx, jy))
3237 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
3238 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
3239 printf("DrawPlayerField(): This should never happen!\n");
3244 if (element == EL_EXPLOSION)
3247 action = (player->is_pushing ? ACTION_PUSHING :
3248 player->is_digging ? ACTION_DIGGING :
3249 player->is_collecting ? ACTION_COLLECTING :
3250 player->is_moving ? ACTION_MOVING :
3251 player->is_snapping ? ACTION_SNAPPING :
3252 player->is_dropping ? ACTION_DROPPING :
3253 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
3255 if (player->is_waiting)
3256 move_dir = player->dir_waiting;
3258 InitPlayerGfxAnimation(player, action, move_dir);
3260 /* ----------------------------------------------------------------------- */
3261 /* draw things in the field the player is leaving, if needed */
3262 /* ----------------------------------------------------------------------- */
3264 if (player->is_moving)
3266 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
3268 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
3270 if (last_element == EL_DYNAMITE_ACTIVE ||
3271 last_element == EL_EM_DYNAMITE_ACTIVE ||
3272 last_element == EL_SP_DISK_RED_ACTIVE)
3273 DrawDynamite(last_jx, last_jy);
3275 DrawLevelFieldThruMask(last_jx, last_jy);
3277 else if (last_element == EL_DYNAMITE_ACTIVE ||
3278 last_element == EL_EM_DYNAMITE_ACTIVE ||
3279 last_element == EL_SP_DISK_RED_ACTIVE)
3280 DrawDynamite(last_jx, last_jy);
3282 /* !!! this is not enough to prevent flickering of players which are
3283 moving next to each others without a free tile between them -- this
3284 can only be solved by drawing all players layer by layer (first the
3285 background, then the foreground etc.) !!! => TODO */
3286 else if (!IS_PLAYER(last_jx, last_jy))
3287 DrawLevelField(last_jx, last_jy);
3290 DrawLevelField(last_jx, last_jy);
3293 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
3294 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
3297 if (!IN_SCR_FIELD(sx, sy))
3300 /* ----------------------------------------------------------------------- */
3301 /* draw things behind the player, if needed */
3302 /* ----------------------------------------------------------------------- */
3305 DrawLevelElement(jx, jy, Back[jx][jy]);
3306 else if (IS_ACTIVE_BOMB(element))
3307 DrawLevelElement(jx, jy, EL_EMPTY);
3310 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
3312 int old_element = GfxElement[jx][jy];
3313 int old_graphic = el_act_dir2img(old_element, action, move_dir);
3314 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
3316 if (GFX_CRUMBLED(old_element))
3317 DrawLevelFieldCrumbledDigging(jx, jy, move_dir, player->StepFrame);
3319 DrawGraphic(sx, sy, old_graphic, frame);
3321 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
3322 player_is_opaque = TRUE;
3326 GfxElement[jx][jy] = EL_UNDEFINED;
3328 /* make sure that pushed elements are drawn with correct frame rate */
3329 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
3331 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
3332 GfxFrame[jx][jy] = player->StepFrame;
3334 DrawLevelField(jx, jy);
3338 #if !DRAW_PLAYER_OVER_PUSHED_ELEMENT
3339 /* ----------------------------------------------------------------------- */
3340 /* draw player himself */
3341 /* ----------------------------------------------------------------------- */
3343 graphic = getPlayerGraphic(player, move_dir);
3345 /* in the case of changed player action or direction, prevent the current
3346 animation frame from being restarted for identical animations */
3347 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
3348 player->Frame = last_player_frame;
3350 frame = getGraphicAnimationFrame(graphic, player->Frame);
3354 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3355 sxx = player->GfxPos;
3357 syy = player->GfxPos;
3360 if (player_is_opaque)
3361 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
3363 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3365 if (SHIELD_ON(player))
3367 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
3368 IMG_SHIELD_NORMAL_ACTIVE);
3369 int frame = getGraphicAnimationFrame(graphic, -1);
3371 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3375 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
3378 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3379 sxx = player->GfxPos;
3381 syy = player->GfxPos;
3385 /* ----------------------------------------------------------------------- */
3386 /* draw things the player is pushing, if needed */
3387 /* ----------------------------------------------------------------------- */
3389 if (player->is_pushing && player->is_moving)
3391 int px = SCREENX(jx), py = SCREENY(jy);
3392 int pxx = (TILEX - ABS(sxx)) * dx;
3393 int pyy = (TILEY - ABS(syy)) * dy;
3394 int gfx_frame = GfxFrame[jx][jy];
3400 if (!IS_MOVING(jx, jy)) /* push movement already finished */
3402 element = Feld[next_jx][next_jy];
3403 gfx_frame = GfxFrame[next_jx][next_jy];
3406 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
3408 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
3409 frame = getGraphicAnimationFrame(graphic, sync_frame);
3411 /* draw background element under pushed element (like the Sokoban field) */
3412 if (game.use_masked_pushing && IS_MOVING(jx, jy))
3414 /* this allows transparent pushing animation over non-black background */
3417 DrawLevelElement(jx, jy, Back[jx][jy]);
3419 DrawLevelElement(jx, jy, EL_EMPTY);
3421 if (Back[next_jx][next_jy])
3422 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3424 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
3426 else if (Back[next_jx][next_jy])
3427 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3430 /* do not draw (EM style) pushing animation when pushing is finished */
3431 /* (two-tile animations usually do not contain start and end frame) */
3432 if (graphic_info[graphic].double_movement && !IS_MOVING(jx, jy))
3433 DrawLevelElement(next_jx, next_jy, Feld[next_jx][next_jy]);
3435 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3437 /* masked drawing is needed for EMC style (double) movement graphics */
3438 /* !!! (ONLY WHEN DRAWING PUSHED ELEMENT OVER THE PLAYER) !!! */
3439 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3443 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
3444 /* ----------------------------------------------------------------------- */
3445 /* draw player himself */
3446 /* ----------------------------------------------------------------------- */
3448 graphic = getPlayerGraphic(player, move_dir);
3450 /* in the case of changed player action or direction, prevent the current
3451 animation frame from being restarted for identical animations */
3452 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
3453 player->Frame = last_player_frame;
3455 frame = getGraphicAnimationFrame(graphic, player->Frame);
3459 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3460 sxx = player->GfxPos;
3462 syy = player->GfxPos;
3465 if (player_is_opaque)
3466 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
3468 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3470 if (SHIELD_ON(player))
3472 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
3473 IMG_SHIELD_NORMAL_ACTIVE);
3474 int frame = getGraphicAnimationFrame(graphic, -1);
3476 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3480 /* ----------------------------------------------------------------------- */
3481 /* draw things in front of player (active dynamite or dynabombs) */
3482 /* ----------------------------------------------------------------------- */
3484 if (IS_ACTIVE_BOMB(element))
3486 graphic = el2img(element);
3487 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
3489 if (game.emulation == EMU_SUPAPLEX)
3490 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
3492 DrawGraphicThruMask(sx, sy, graphic, frame);
3495 if (player_is_moving && last_element == EL_EXPLOSION)
3497 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
3498 GfxElement[last_jx][last_jy] : EL_EMPTY);
3499 int graphic = el_act2img(element, ACTION_EXPLODING);
3500 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
3501 int phase = ExplodePhase[last_jx][last_jy] - 1;
3502 int frame = getGraphicAnimationFrame(graphic, phase - delay);
3505 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
3508 /* ----------------------------------------------------------------------- */
3509 /* draw elements the player is just walking/passing through/under */
3510 /* ----------------------------------------------------------------------- */
3512 if (player_is_moving)
3514 /* handle the field the player is leaving ... */
3515 if (IS_ACCESSIBLE_INSIDE(last_element))
3516 DrawLevelField(last_jx, last_jy);
3517 else if (IS_ACCESSIBLE_UNDER(last_element))
3518 DrawLevelFieldThruMask(last_jx, last_jy);
3521 /* do not redraw accessible elements if the player is just pushing them */
3522 if (!player_is_moving || !player->is_pushing)
3524 /* ... and the field the player is entering */
3525 if (IS_ACCESSIBLE_INSIDE(element))
3526 DrawLevelField(jx, jy);
3527 else if (IS_ACCESSIBLE_UNDER(element))
3528 DrawLevelFieldThruMask(jx, jy);
3531 MarkTileDirty(sx, sy);
3534 /* ------------------------------------------------------------------------- */
3536 void WaitForEventToContinue()
3538 boolean still_wait = TRUE;
3540 /* simulate releasing mouse button over last gadget, if still pressed */
3542 HandleGadgets(-1, -1, 0);
3544 button_status = MB_RELEASED;
3558 case EVENT_BUTTONPRESS:
3559 case EVENT_KEYPRESS:
3563 case EVENT_KEYRELEASE:
3564 ClearPlayerAction();
3568 HandleOtherEvents(&event);
3572 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3581 #define MAX_REQUEST_LINES 13
3582 #define MAX_REQUEST_LINE_FONT1_LEN 7
3583 #define MAX_REQUEST_LINE_FONT2_LEN 10
3585 static int RequestHandleEvents(unsigned int req_state)
3587 boolean level_solved = (game_status == GAME_MODE_PLAYING &&
3588 local_player->LevelSolved_GameEnd);
3589 int width = request.width;
3590 int height = request.height;
3594 setRequestPosition(&sx, &sy, FALSE);
3596 button_status = MB_RELEASED;
3598 request_gadget_id = -1;
3605 SetDrawtoField(DRAW_TO_FIELDBUFFER);
3607 HandleGameActions();
3609 SetDrawtoField(DRAW_TO_BACKBUFFER);
3611 if (global.use_envelope_request)
3613 /* copy current state of request area to middle of playfield area */
3614 BlitBitmap(bitmap_db_store_2, drawto, sx, sy, width, height, sx, sy);
3622 while (NextValidEvent(&event))
3626 case EVENT_BUTTONPRESS:
3627 case EVENT_BUTTONRELEASE:
3628 case EVENT_MOTIONNOTIFY:
3632 if (event.type == EVENT_MOTIONNOTIFY)
3637 motion_status = TRUE;
3638 mx = ((MotionEvent *) &event)->x;
3639 my = ((MotionEvent *) &event)->y;
3643 motion_status = FALSE;
3644 mx = ((ButtonEvent *) &event)->x;
3645 my = ((ButtonEvent *) &event)->y;
3646 if (event.type == EVENT_BUTTONPRESS)
3647 button_status = ((ButtonEvent *) &event)->button;
3649 button_status = MB_RELEASED;
3652 /* this sets 'request_gadget_id' */
3653 HandleGadgets(mx, my, button_status);
3655 switch (request_gadget_id)
3657 case TOOL_CTRL_ID_YES:
3660 case TOOL_CTRL_ID_NO:
3663 case TOOL_CTRL_ID_CONFIRM:
3664 result = TRUE | FALSE;
3667 case TOOL_CTRL_ID_PLAYER_1:
3670 case TOOL_CTRL_ID_PLAYER_2:
3673 case TOOL_CTRL_ID_PLAYER_3:
3676 case TOOL_CTRL_ID_PLAYER_4:
3687 case EVENT_KEYPRESS:
3689 Key key = GetEventKey((KeyEvent *)&event, TRUE);
3694 if (req_state & REQ_CONFIRM)
3699 #if defined(TARGET_SDL2)
3706 #if defined(TARGET_SDL2)
3713 HandleKeysDebug(key);
3717 if (req_state & REQ_PLAYER)
3723 case EVENT_KEYRELEASE:
3724 ClearPlayerAction();
3728 HandleOtherEvents(&event);
3733 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3735 int joy = AnyJoystick();
3737 if (joy & JOY_BUTTON_1)
3739 else if (joy & JOY_BUTTON_2)
3745 if (global.use_envelope_request)
3747 /* copy back current state of pressed buttons inside request area */
3748 BlitBitmap(drawto, bitmap_db_store_2, sx, sy, width, height, sx, sy);
3758 static boolean RequestDoor(char *text, unsigned int req_state)
3760 unsigned int old_door_state;
3761 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
3762 int font_nr = FONT_TEXT_2;
3767 if (maxWordLengthInString(text) > MAX_REQUEST_LINE_FONT1_LEN)
3769 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
3770 font_nr = FONT_TEXT_1;
3773 if (game_status == GAME_MODE_PLAYING)
3774 BlitScreenToBitmap(backbuffer);
3776 /* disable deactivated drawing when quick-loading level tape recording */
3777 if (tape.playing && tape.deactivate_display)
3778 TapeDeactivateDisplayOff(TRUE);
3780 SetMouseCursor(CURSOR_DEFAULT);
3782 #if defined(NETWORK_AVALIABLE)
3783 /* pause network game while waiting for request to answer */
3784 if (options.network &&
3785 game_status == GAME_MODE_PLAYING &&
3786 req_state & REQUEST_WAIT_FOR_INPUT)
3787 SendToServer_PausePlaying();
3790 old_door_state = GetDoorState();
3792 /* simulate releasing mouse button over last gadget, if still pressed */
3794 HandleGadgets(-1, -1, 0);
3798 /* draw released gadget before proceeding */
3801 if (old_door_state & DOOR_OPEN_1)
3803 CloseDoor(DOOR_CLOSE_1);
3805 /* save old door content */
3806 BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
3807 0 * DXSIZE, 0, DXSIZE, DYSIZE, 1 * DXSIZE, 0);
3810 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
3811 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3813 /* clear door drawing field */
3814 DrawBackground(DX, DY, DXSIZE, DYSIZE);
3816 /* force DOOR font inside door area */
3817 SetFontStatus(GAME_MODE_PSEUDO_DOOR);
3819 /* write text for request */
3820 for (text_ptr = text, ty = 0; ty < MAX_REQUEST_LINES; ty++)
3822 char text_line[max_request_line_len + 1];
3828 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
3830 tc = *(text_ptr + tx);
3831 // if (!tc || tc == ' ')
3832 if (!tc || tc == ' ' || tc == '?' || tc == '!')
3836 if ((tc == '?' || tc == '!') && tl == 0)
3846 strncpy(text_line, text_ptr, tl);
3849 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
3850 DY + 8 + ty * (getFontHeight(font_nr) + 2),
3851 text_line, font_nr);
3853 text_ptr += tl + (tc == ' ' ? 1 : 0);
3854 // text_ptr += tl + (tc == ' ' || tc == '?' || tc == '!' ? 1 : 0);
3859 if (req_state & REQ_ASK)
3861 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
3862 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
3864 else if (req_state & REQ_CONFIRM)
3866 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
3868 else if (req_state & REQ_PLAYER)
3870 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
3871 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
3872 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
3873 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
3876 /* copy request gadgets to door backbuffer */
3877 BlitBitmap(drawto, bitmap_db_door_1, DX, DY, DXSIZE, DYSIZE, 0, 0);
3879 OpenDoor(DOOR_OPEN_1);
3881 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
3883 if (game_status == GAME_MODE_PLAYING)
3885 SetPanelBackground();
3886 SetDrawBackgroundMask(REDRAW_DOOR_1);
3890 SetDrawBackgroundMask(REDRAW_FIELD);
3896 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3898 // ---------- handle request buttons ----------
3899 result = RequestHandleEvents(req_state);
3903 if (!(req_state & REQ_STAY_OPEN))
3905 CloseDoor(DOOR_CLOSE_1);
3907 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
3908 (req_state & REQ_REOPEN))
3909 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
3914 if (game_status == GAME_MODE_PLAYING)
3916 SetPanelBackground();
3917 SetDrawBackgroundMask(REDRAW_DOOR_1);
3921 SetDrawBackgroundMask(REDRAW_FIELD);
3924 #if defined(NETWORK_AVALIABLE)
3925 /* continue network game after request */
3926 if (options.network &&
3927 game_status == GAME_MODE_PLAYING &&
3928 req_state & REQUEST_WAIT_FOR_INPUT)
3929 SendToServer_ContinuePlaying();
3932 /* restore deactivated drawing when quick-loading level tape recording */
3933 if (tape.playing && tape.deactivate_display)
3934 TapeDeactivateDisplayOn();
3939 static boolean RequestEnvelope(char *text, unsigned int req_state)
3943 if (game_status == GAME_MODE_PLAYING)
3944 BlitScreenToBitmap(backbuffer);
3946 /* disable deactivated drawing when quick-loading level tape recording */
3947 if (tape.playing && tape.deactivate_display)
3948 TapeDeactivateDisplayOff(TRUE);
3950 SetMouseCursor(CURSOR_DEFAULT);
3952 #if defined(NETWORK_AVALIABLE)
3953 /* pause network game while waiting for request to answer */
3954 if (options.network &&
3955 game_status == GAME_MODE_PLAYING &&
3956 req_state & REQUEST_WAIT_FOR_INPUT)
3957 SendToServer_PausePlaying();
3960 /* simulate releasing mouse button over last gadget, if still pressed */
3962 HandleGadgets(-1, -1, 0);
3966 // (replace with setting corresponding request background)
3967 // SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
3968 // SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3970 /* clear door drawing field */
3971 // DrawBackground(DX, DY, DXSIZE, DYSIZE);
3973 ShowEnvelopeRequest(text, req_state, ACTION_OPENING);
3975 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
3977 if (game_status == GAME_MODE_PLAYING)
3979 SetPanelBackground();
3980 SetDrawBackgroundMask(REDRAW_DOOR_1);
3984 SetDrawBackgroundMask(REDRAW_FIELD);
3990 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3992 // ---------- handle request buttons ----------
3993 result = RequestHandleEvents(req_state);
3997 ShowEnvelopeRequest(text, req_state, ACTION_CLOSING);
4001 if (game_status == GAME_MODE_PLAYING)
4003 SetPanelBackground();
4004 SetDrawBackgroundMask(REDRAW_DOOR_1);
4008 SetDrawBackgroundMask(REDRAW_FIELD);
4011 #if defined(NETWORK_AVALIABLE)
4012 /* continue network game after request */
4013 if (options.network &&
4014 game_status == GAME_MODE_PLAYING &&
4015 req_state & REQUEST_WAIT_FOR_INPUT)
4016 SendToServer_ContinuePlaying();
4019 /* restore deactivated drawing when quick-loading level tape recording */
4020 if (tape.playing && tape.deactivate_display)
4021 TapeDeactivateDisplayOn();
4026 boolean Request(char *text, unsigned int req_state)
4028 if (global.use_envelope_request)
4029 return RequestEnvelope(text, req_state);
4031 return RequestDoor(text, req_state);
4034 static int compareDoorPartOrderInfo(const void *object1, const void *object2)
4036 const struct DoorPartOrderInfo *dpo1 = (struct DoorPartOrderInfo *)object1;
4037 const struct DoorPartOrderInfo *dpo2 = (struct DoorPartOrderInfo *)object2;
4040 if (dpo1->sort_priority != dpo2->sort_priority)
4041 compare_result = dpo1->sort_priority - dpo2->sort_priority;
4043 compare_result = dpo1->nr - dpo2->nr;
4045 return compare_result;
4048 void InitGraphicCompatibilityInfo_Doors()
4054 struct DoorInfo *door;
4058 { DOOR_1, IMG_GFX_DOOR_1_PART_1, IMG_GFX_DOOR_1_PART_8, &door_1 },
4059 { DOOR_2, IMG_GFX_DOOR_2_PART_1, IMG_GFX_DOOR_2_PART_8, &door_2 },
4061 { -1, -1, -1, NULL }
4063 struct Rect door_rect_list[] =
4065 { DX, DY, DXSIZE, DYSIZE },
4066 { VX, VY, VXSIZE, VYSIZE }
4070 for (i = 0; doors[i].door_token != -1; i++)
4072 int door_token = doors[i].door_token;
4073 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
4074 int part_1 = doors[i].part_1;
4075 int part_8 = doors[i].part_8;
4076 int part_2 = part_1 + 1;
4077 int part_3 = part_1 + 2;
4078 struct DoorInfo *door = doors[i].door;
4079 struct Rect *door_rect = &door_rect_list[door_index];
4080 boolean door_gfx_redefined = FALSE;
4082 /* check if any door part graphic definitions have been redefined */
4084 for (j = 0; door_part_controls[j].door_token != -1; j++)
4086 struct DoorPartControlInfo *dpc = &door_part_controls[j];
4087 struct FileInfo *fi = getImageListEntryFromImageID(dpc->graphic);
4089 if (dpc->door_token == door_token && fi->redefined)
4090 door_gfx_redefined = TRUE;
4093 /* check for old-style door graphic/animation modifications */
4095 if (!door_gfx_redefined)
4097 if (door->anim_mode & ANIM_STATIC_PANEL)
4099 door->panel.step_xoffset = 0;
4100 door->panel.step_yoffset = 0;
4103 if (door->anim_mode & (ANIM_HORIZONTAL | ANIM_VERTICAL))
4105 struct GraphicInfo *g_part_1 = &graphic_info[part_1];
4106 struct GraphicInfo *g_part_2 = &graphic_info[part_2];
4107 int num_door_steps, num_panel_steps;
4109 /* remove door part graphics other than the two default wings */
4111 for (j = 0; door_part_controls[j].door_token != -1; j++)
4113 struct DoorPartControlInfo *dpc = &door_part_controls[j];
4114 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4116 if (dpc->graphic >= part_3 &&
4117 dpc->graphic <= part_8)
4121 /* set graphics and screen positions of the default wings */
4123 g_part_1->width = door_rect->width;
4124 g_part_1->height = door_rect->height;
4125 g_part_2->width = door_rect->width;
4126 g_part_2->height = door_rect->height;
4127 g_part_2->src_x = door_rect->width;
4128 g_part_2->src_y = g_part_1->src_y;
4130 door->part_2.x = door->part_1.x;
4131 door->part_2.y = door->part_1.y;
4133 if (door->width != -1)
4135 g_part_1->width = door->width;
4136 g_part_2->width = door->width;
4138 // special treatment for graphics and screen position of right wing
4139 g_part_2->src_x += door_rect->width - door->width;
4140 door->part_2.x += door_rect->width - door->width;
4143 if (door->height != -1)
4145 g_part_1->height = door->height;
4146 g_part_2->height = door->height;
4148 // special treatment for graphics and screen position of bottom wing
4149 g_part_2->src_y += door_rect->height - door->height;
4150 door->part_2.y += door_rect->height - door->height;
4153 /* set animation delays for the default wings and panels */
4155 door->part_1.step_delay = door->step_delay;
4156 door->part_2.step_delay = door->step_delay;
4157 door->panel.step_delay = door->step_delay;
4159 /* set animation draw order for the default wings */
4161 door->part_1.sort_priority = 2; /* draw left wing over ... */
4162 door->part_2.sort_priority = 1; /* ... right wing */
4164 /* set animation draw offset for the default wings */
4166 if (door->anim_mode & ANIM_HORIZONTAL)
4168 door->part_1.step_xoffset = door->step_offset;
4169 door->part_1.step_yoffset = 0;
4170 door->part_2.step_xoffset = door->step_offset * -1;
4171 door->part_2.step_yoffset = 0;
4173 num_door_steps = g_part_1->width / door->step_offset;
4175 else // ANIM_VERTICAL
4177 door->part_1.step_xoffset = 0;
4178 door->part_1.step_yoffset = door->step_offset;
4179 door->part_2.step_xoffset = 0;
4180 door->part_2.step_yoffset = door->step_offset * -1;
4182 num_door_steps = g_part_1->height / door->step_offset;
4185 /* set animation draw offset for the default panels */
4187 if (door->step_offset > 1)
4189 num_panel_steps = 2 * door_rect->height / door->step_offset;
4190 door->panel.start_step = num_panel_steps - num_door_steps;
4191 door->panel.start_step_closing = door->panel.start_step;
4195 num_panel_steps = door_rect->height / door->step_offset;
4196 door->panel.start_step = num_panel_steps - num_door_steps / 2;
4197 door->panel.start_step_closing = door->panel.start_step;
4198 door->panel.step_delay *= 2;
4209 for (i = 0; door_part_controls[i].door_token != -1; i++)
4211 struct DoorPartControlInfo *dpc = &door_part_controls[i];
4212 struct DoorPartOrderInfo *dpo = &door_part_order[i];
4214 /* initialize "start_step_opening" and "start_step_closing", if needed */
4215 if (dpc->pos->start_step_opening == 0 &&
4216 dpc->pos->start_step_closing == 0)
4218 // dpc->pos->start_step_opening = dpc->pos->start_step;
4219 dpc->pos->start_step_closing = dpc->pos->start_step;
4222 /* fill structure for door part draw order (sorted below) */
4224 dpo->sort_priority = dpc->pos->sort_priority;
4227 /* sort door part controls according to sort_priority and graphic number */
4228 qsort(door_part_order, MAX_DOOR_PARTS,
4229 sizeof(struct DoorPartOrderInfo), compareDoorPartOrderInfo);
4232 unsigned int OpenDoor(unsigned int door_state)
4234 if (door_state & DOOR_COPY_BACK)
4236 if (door_state & DOOR_OPEN_1)
4237 BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
4238 1 * DXSIZE, 0, DXSIZE, DYSIZE, 0 * DXSIZE, 0);
4240 if (door_state & DOOR_OPEN_2)
4241 BlitBitmap(bitmap_db_door_2, bitmap_db_door_2,
4242 1 * VXSIZE, 0, VXSIZE, VYSIZE, 0 * VXSIZE, 0);
4244 door_state &= ~DOOR_COPY_BACK;
4247 return MoveDoor(door_state);
4250 unsigned int CloseDoor(unsigned int door_state)
4252 unsigned int old_door_state = GetDoorState();
4254 if (!(door_state & DOOR_NO_COPY_BACK))
4256 if (old_door_state & DOOR_OPEN_1)
4257 BlitBitmap(backbuffer, bitmap_db_door_1,
4258 DX, DY, DXSIZE, DYSIZE, 0, 0);
4260 if (old_door_state & DOOR_OPEN_2)
4261 BlitBitmap(backbuffer, bitmap_db_door_2,
4262 VX, VY, VXSIZE, VYSIZE, 0, 0);
4264 door_state &= ~DOOR_NO_COPY_BACK;
4267 return MoveDoor(door_state);
4270 unsigned int GetDoorState()
4272 return MoveDoor(DOOR_GET_STATE);
4275 unsigned int SetDoorState(unsigned int door_state)
4277 return MoveDoor(door_state | DOOR_SET_STATE);
4280 int euclid(int a, int b)
4282 return (b ? euclid(b, a % b) : a);
4285 unsigned int MoveDoor(unsigned int door_state)
4287 struct Rect door_rect_list[] =
4289 { DX, DY, DXSIZE, DYSIZE },
4290 { VX, VY, VXSIZE, VYSIZE }
4292 static int door1 = DOOR_CLOSE_1;
4293 static int door2 = DOOR_CLOSE_2;
4294 unsigned int door_delay = 0;
4295 unsigned int door_delay_value;
4298 if (door_state == DOOR_GET_STATE)
4299 return (door1 | door2);
4301 if (door_state & DOOR_SET_STATE)
4303 if (door_state & DOOR_ACTION_1)
4304 door1 = door_state & DOOR_ACTION_1;
4305 if (door_state & DOOR_ACTION_2)
4306 door2 = door_state & DOOR_ACTION_2;
4308 return (door1 | door2);
4311 if (!(door_state & DOOR_FORCE_REDRAW))
4313 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
4314 door_state &= ~DOOR_OPEN_1;
4315 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
4316 door_state &= ~DOOR_CLOSE_1;
4317 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
4318 door_state &= ~DOOR_OPEN_2;
4319 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
4320 door_state &= ~DOOR_CLOSE_2;
4323 if (global.autoplay_leveldir)
4325 door_state |= DOOR_NO_DELAY;
4326 door_state &= ~DOOR_CLOSE_ALL;
4329 if (game_status == GAME_MODE_EDITOR)
4330 door_state |= DOOR_NO_DELAY;
4332 if (door_state & DOOR_ACTION)
4334 boolean door_panel_drawn[NUM_DOORS];
4335 boolean panel_has_doors[NUM_DOORS];
4336 boolean door_part_skip[MAX_DOOR_PARTS];
4337 boolean door_part_done[MAX_DOOR_PARTS];
4338 boolean door_part_done_all;
4339 int num_steps[MAX_DOOR_PARTS];
4340 int max_move_delay = 0; // delay for complete animations of all doors
4341 int max_step_delay = 0; // delay (ms) between two animation frames
4342 int num_move_steps = 0; // number of animation steps for all doors
4343 int max_move_delay_doors_only = 0; // delay for doors only (no panel)
4344 int num_move_steps_doors_only = 0; // steps for doors only (no panel)
4345 int current_move_delay = 0;
4349 for (i = 0; i < NUM_DOORS; i++)
4350 panel_has_doors[i] = FALSE;
4352 for (i = 0; i < MAX_DOOR_PARTS; i++)
4354 struct DoorPartControlInfo *dpc = &door_part_controls[i];
4355 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4356 int door_token = dpc->door_token;
4358 door_part_done[i] = FALSE;
4359 door_part_skip[i] = (!(door_state & door_token) ||
4363 for (i = 0; i < MAX_DOOR_PARTS; i++)
4365 int nr = door_part_order[i].nr;
4366 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
4367 struct DoorPartPosInfo *pos = dpc->pos;
4368 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4369 int door_token = dpc->door_token;
4370 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
4371 boolean is_panel = DOOR_PART_IS_PANEL(nr);
4372 int step_xoffset = ABS(pos->step_xoffset);
4373 int step_yoffset = ABS(pos->step_yoffset);
4374 int step_delay = pos->step_delay;
4375 int current_door_state = door_state & door_token;
4376 boolean door_opening = ((current_door_state & DOOR_OPEN) != 0);
4377 boolean door_closing = ((current_door_state & DOOR_CLOSE) != 0);
4378 boolean part_opening = (is_panel ? door_closing : door_opening);
4379 int start_step = (part_opening ? pos->start_step_opening :
4380 pos->start_step_closing);
4381 float move_xsize = (step_xoffset ? g->width : 0);
4382 float move_ysize = (step_yoffset ? g->height : 0);
4383 int move_xsteps = (step_xoffset ? ceil(move_xsize / step_xoffset) : 0);
4384 int move_ysteps = (step_yoffset ? ceil(move_ysize / step_yoffset) : 0);
4385 int move_steps = (move_xsteps && move_ysteps ?
4386 MIN(move_xsteps, move_ysteps) :
4387 move_xsteps ? move_xsteps : move_ysteps) - start_step;
4388 int move_delay = move_steps * step_delay;
4390 if (door_part_skip[nr])
4393 max_move_delay = MAX(max_move_delay, move_delay);
4394 max_step_delay = (max_step_delay == 0 ? step_delay :
4395 euclid(max_step_delay, step_delay));
4396 num_steps[nr] = move_steps;
4400 max_move_delay_doors_only = MAX(max_move_delay_doors_only, move_delay);
4402 panel_has_doors[door_index] = TRUE;
4406 max_step_delay = MAX(1, max_step_delay); // prevent division by zero
4408 num_move_steps = max_move_delay / max_step_delay;
4409 num_move_steps_doors_only = max_move_delay_doors_only / max_step_delay;
4411 door_delay_value = max_step_delay;
4413 if ((door_state & DOOR_NO_DELAY) || setup.quick_doors)
4415 start = num_move_steps - 1;
4419 /* opening door sound has priority over simultaneously closing door */
4420 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
4421 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
4422 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
4423 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
4426 for (k = start; k < num_move_steps; k++)
4428 int last_frame = num_move_steps - 1; // last frame of this "for" loop
4430 door_part_done_all = TRUE;
4432 for (i = 0; i < NUM_DOORS; i++)
4433 door_panel_drawn[i] = FALSE;
4435 for (i = 0; i < MAX_DOOR_PARTS; i++)
4437 int nr = door_part_order[i].nr;
4438 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
4439 struct DoorPartPosInfo *pos = dpc->pos;
4440 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4441 int door_token = dpc->door_token;
4442 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
4443 boolean is_panel = DOOR_PART_IS_PANEL(nr);
4444 boolean is_panel_and_door_has_closed = FALSE;
4445 struct Rect *door_rect = &door_rect_list[door_index];
4446 Bitmap *bitmap_db_door = (door_token == DOOR_1 ? bitmap_db_door_1 :
4448 Bitmap *bitmap = (is_panel ? bitmap_db_door : g->bitmap);
4449 int current_door_state = door_state & door_token;
4450 boolean door_opening = ((current_door_state & DOOR_OPEN) != 0);
4451 boolean door_closing = !door_opening;
4452 boolean part_opening = (is_panel ? door_closing : door_opening);
4453 boolean part_closing = !part_opening;
4454 int start_step = (part_opening ? pos->start_step_opening :
4455 pos->start_step_closing);
4456 int step_delay = pos->step_delay;
4457 int step_factor = step_delay / max_step_delay;
4458 int k1 = (step_factor ? k / step_factor + 1 : k);
4459 int k2 = (part_opening ? k1 + start_step : num_steps[nr] - k1);
4460 int kk = MAX(0, k2);
4463 int src_x, src_y, src_xx, src_yy;
4464 int dst_x, dst_y, dst_xx, dst_yy;
4467 if (door_part_skip[nr])
4470 if (!(door_state & door_token))
4478 int k2_door = (door_opening ? k : num_move_steps_doors_only - k - 1);
4479 int kk_door = MAX(0, k2_door);
4480 int sync_frame = kk_door * door_delay_value;
4481 int frame = getGraphicAnimationFrame(dpc->graphic, sync_frame);
4483 getGraphicSource(dpc->graphic, frame, &bitmap, &g_src_x, &g_src_y);
4488 if (!door_panel_drawn[door_index])
4490 ClearRectangle(drawto, door_rect->x, door_rect->y,
4491 door_rect->width, door_rect->height);
4493 door_panel_drawn[door_index] = TRUE;
4496 // draw opening or closing door parts
4498 if (pos->step_xoffset < 0) // door part on right side
4501 dst_xx = pos->x + ABS(kk * pos->step_xoffset);
4504 if (dst_xx + width > door_rect->width)
4505 width = door_rect->width - dst_xx;
4507 else // door part on left side
4510 dst_xx = pos->x - kk * pos->step_xoffset;
4514 src_xx = ABS(dst_xx);
4518 width = g->width - src_xx;
4520 if (width > door_rect->width)
4521 width = door_rect->width;
4523 // printf("::: k == %d [%d] \n", k, start_step);
4526 if (pos->step_yoffset < 0) // door part on bottom side
4529 dst_yy = pos->y + ABS(kk * pos->step_yoffset);
4532 if (dst_yy + height > door_rect->height)
4533 height = door_rect->height - dst_yy;
4535 else // door part on top side
4538 dst_yy = pos->y - kk * pos->step_yoffset;
4542 src_yy = ABS(dst_yy);
4546 height = g->height - src_yy;
4549 src_x = g_src_x + src_xx;
4550 src_y = g_src_y + src_yy;
4552 dst_x = door_rect->x + dst_xx;
4553 dst_y = door_rect->y + dst_yy;
4555 is_panel_and_door_has_closed =
4558 panel_has_doors[door_index] &&
4559 k >= num_move_steps_doors_only - 1);
4561 if (width >= 0 && width <= g->width &&
4562 height >= 0 && height <= g->height &&
4563 !is_panel_and_door_has_closed)
4565 if (is_panel || !pos->draw_masked)
4566 BlitBitmap(bitmap, drawto, src_x, src_y, width, height,
4569 BlitBitmapMasked(bitmap, drawto, src_x, src_y, width, height,
4573 redraw_mask |= REDRAW_DOOR_FROM_TOKEN(door_token);
4575 if ((part_opening && (width < 0 || height < 0)) ||
4576 (part_closing && (width >= g->width && height >= g->height)))
4577 door_part_done[nr] = TRUE;
4579 // continue door part animations, but not panel after door has closed
4580 if (!door_part_done[nr] && !is_panel_and_door_has_closed)
4581 door_part_done_all = FALSE;
4584 if (!(door_state & DOOR_NO_DELAY))
4588 SkipUntilDelayReached(&door_delay, door_delay_value, &k, last_frame);
4590 current_move_delay += max_step_delay;
4593 if (door_part_done_all)
4598 if (door_state & DOOR_ACTION_1)
4599 door1 = door_state & DOOR_ACTION_1;
4600 if (door_state & DOOR_ACTION_2)
4601 door2 = door_state & DOOR_ACTION_2;
4603 // draw masked border over door area
4604 DrawMaskedBorder(REDRAW_DOOR_1);
4605 DrawMaskedBorder(REDRAW_DOOR_2);
4607 return (door1 | door2);
4610 static boolean useSpecialEditorDoor()
4612 int graphic = IMG_GLOBAL_BORDER_EDITOR;
4613 boolean redefined = getImageListEntryFromImageID(graphic)->redefined;
4615 // do not draw special editor door if editor border defined or redefined
4616 if (graphic_info[graphic].bitmap != NULL || redefined)
4619 // do not draw special editor door if global border defined to be empty
4620 if (graphic_info[IMG_GLOBAL_BORDER].bitmap == NULL)
4623 // do not draw special editor door if viewport definitions do not match
4627 EY + EYSIZE != VY + VYSIZE)
4633 void DrawSpecialEditorDoor()
4635 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
4636 int top_border_width = gfx1->width;
4637 int top_border_height = gfx1->height;
4638 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
4639 int ex = EX - outer_border;
4640 int ey = EY - outer_border;
4641 int vy = VY - outer_border;
4642 int exsize = EXSIZE + 2 * outer_border;
4644 if (!useSpecialEditorDoor())
4647 /* draw bigger level editor toolbox window */
4648 BlitBitmap(gfx1->bitmap, drawto, gfx1->src_x, gfx1->src_y,
4649 top_border_width, top_border_height, ex, ey - top_border_height);
4650 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto, ex, vy,
4651 exsize, EYSIZE - VYSIZE + outer_border, ex, ey);
4653 redraw_mask |= REDRAW_ALL;
4656 void UndrawSpecialEditorDoor()
4658 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
4659 int top_border_width = gfx1->width;
4660 int top_border_height = gfx1->height;
4661 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
4662 int ex = EX - outer_border;
4663 int ey = EY - outer_border;
4664 int ey_top = ey - top_border_height;
4665 int exsize = EXSIZE + 2 * outer_border;
4666 int eysize = EYSIZE + 2 * outer_border;
4668 if (!useSpecialEditorDoor())
4671 /* draw normal tape recorder window */
4672 if (graphic_info[IMG_GLOBAL_BORDER].bitmap)
4674 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
4675 ex, ey_top, top_border_width, top_border_height,
4677 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
4678 ex, ey, exsize, eysize, ex, ey);
4682 // if screen background is set to "[NONE]", clear editor toolbox window
4683 ClearRectangle(drawto, ex, ey_top, top_border_width, top_border_height);
4684 ClearRectangle(drawto, ex, ey, exsize, eysize);
4687 redraw_mask |= REDRAW_ALL;
4691 /* ---------- new tool button stuff ---------------------------------------- */
4696 struct TextPosInfo *pos;
4699 } toolbutton_info[NUM_TOOL_BUTTONS] =
4702 IMG_GFX_REQUEST_BUTTON_YES, &request.button.yes,
4703 TOOL_CTRL_ID_YES, "yes"
4706 IMG_GFX_REQUEST_BUTTON_NO, &request.button.no,
4707 TOOL_CTRL_ID_NO, "no"
4710 IMG_GFX_REQUEST_BUTTON_CONFIRM, &request.button.confirm,
4711 TOOL_CTRL_ID_CONFIRM, "confirm"
4714 IMG_GFX_REQUEST_BUTTON_PLAYER_1, &request.button.player_1,
4715 TOOL_CTRL_ID_PLAYER_1, "player 1"
4718 IMG_GFX_REQUEST_BUTTON_PLAYER_2, &request.button.player_2,
4719 TOOL_CTRL_ID_PLAYER_2, "player 2"
4722 IMG_GFX_REQUEST_BUTTON_PLAYER_3, &request.button.player_3,
4723 TOOL_CTRL_ID_PLAYER_3, "player 3"
4726 IMG_GFX_REQUEST_BUTTON_PLAYER_4, &request.button.player_4,
4727 TOOL_CTRL_ID_PLAYER_4, "player 4"
4731 void CreateToolButtons()
4735 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4737 struct GraphicInfo *gfx = &graphic_info[toolbutton_info[i].graphic];
4738 struct TextPosInfo *pos = toolbutton_info[i].pos;
4739 struct GadgetInfo *gi;
4740 Bitmap *deco_bitmap = None;
4741 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
4742 unsigned int event_mask = GD_EVENT_RELEASED;
4745 int gd_x = gfx->src_x;
4746 int gd_y = gfx->src_y;
4747 int gd_xp = gfx->src_x + gfx->pressed_xoffset;
4748 int gd_yp = gfx->src_y + gfx->pressed_yoffset;
4751 if (global.use_envelope_request)
4752 setRequestPosition(&dx, &dy, TRUE);
4754 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
4756 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
4758 getSizedGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr), 0,
4759 pos->size, &deco_bitmap, &deco_x, &deco_y);
4760 deco_xpos = (gfx->width - pos->size) / 2;
4761 deco_ypos = (gfx->height - pos->size) / 2;
4764 gi = CreateGadget(GDI_CUSTOM_ID, id,
4765 GDI_INFO_TEXT, toolbutton_info[i].infotext,
4766 GDI_X, dx + GDI_ACTIVE_POS(pos->x),
4767 GDI_Y, dy + GDI_ACTIVE_POS(pos->y),
4768 GDI_WIDTH, gfx->width,
4769 GDI_HEIGHT, gfx->height,
4770 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
4771 GDI_STATE, GD_BUTTON_UNPRESSED,
4772 GDI_DESIGN_UNPRESSED, gfx->bitmap, gd_x, gd_y,
4773 GDI_DESIGN_PRESSED, gfx->bitmap, gd_xp, gd_yp,
4774 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
4775 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
4776 GDI_DECORATION_SIZE, pos->size, pos->size,
4777 GDI_DECORATION_SHIFTING, 1, 1,
4778 GDI_DIRECT_DRAW, FALSE,
4779 GDI_EVENT_MASK, event_mask,
4780 GDI_CALLBACK_ACTION, HandleToolButtons,
4784 Error(ERR_EXIT, "cannot create gadget");
4786 tool_gadget[id] = gi;
4790 void FreeToolButtons()
4794 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4795 FreeGadget(tool_gadget[i]);
4798 static void UnmapToolButtons()
4802 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4803 UnmapGadget(tool_gadget[i]);
4806 static void HandleToolButtons(struct GadgetInfo *gi)
4808 request_gadget_id = gi->custom_id;
4811 static struct Mapping_EM_to_RND_object
4814 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
4815 boolean is_backside; /* backside of moving element */
4821 em_object_mapping_list[] =
4824 Xblank, TRUE, FALSE,
4828 Yacid_splash_eB, FALSE, FALSE,
4829 EL_ACID_SPLASH_RIGHT, -1, -1
4832 Yacid_splash_wB, FALSE, FALSE,
4833 EL_ACID_SPLASH_LEFT, -1, -1
4836 #ifdef EM_ENGINE_BAD_ROLL
4838 Xstone_force_e, FALSE, FALSE,
4839 EL_ROCK, -1, MV_BIT_RIGHT
4842 Xstone_force_w, FALSE, FALSE,
4843 EL_ROCK, -1, MV_BIT_LEFT
4846 Xnut_force_e, FALSE, FALSE,
4847 EL_NUT, -1, MV_BIT_RIGHT
4850 Xnut_force_w, FALSE, FALSE,
4851 EL_NUT, -1, MV_BIT_LEFT
4854 Xspring_force_e, FALSE, FALSE,
4855 EL_SPRING, -1, MV_BIT_RIGHT
4858 Xspring_force_w, FALSE, FALSE,
4859 EL_SPRING, -1, MV_BIT_LEFT
4862 Xemerald_force_e, FALSE, FALSE,
4863 EL_EMERALD, -1, MV_BIT_RIGHT
4866 Xemerald_force_w, FALSE, FALSE,
4867 EL_EMERALD, -1, MV_BIT_LEFT
4870 Xdiamond_force_e, FALSE, FALSE,
4871 EL_DIAMOND, -1, MV_BIT_RIGHT
4874 Xdiamond_force_w, FALSE, FALSE,
4875 EL_DIAMOND, -1, MV_BIT_LEFT
4878 Xbomb_force_e, FALSE, FALSE,
4879 EL_BOMB, -1, MV_BIT_RIGHT
4882 Xbomb_force_w, FALSE, FALSE,
4883 EL_BOMB, -1, MV_BIT_LEFT
4885 #endif /* EM_ENGINE_BAD_ROLL */
4888 Xstone, TRUE, FALSE,
4892 Xstone_pause, FALSE, FALSE,
4896 Xstone_fall, FALSE, FALSE,
4900 Ystone_s, FALSE, FALSE,
4901 EL_ROCK, ACTION_FALLING, -1
4904 Ystone_sB, FALSE, TRUE,
4905 EL_ROCK, ACTION_FALLING, -1
4908 Ystone_e, FALSE, FALSE,
4909 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
4912 Ystone_eB, FALSE, TRUE,
4913 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
4916 Ystone_w, FALSE, FALSE,
4917 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
4920 Ystone_wB, FALSE, TRUE,
4921 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
4928 Xnut_pause, FALSE, FALSE,
4932 Xnut_fall, FALSE, FALSE,
4936 Ynut_s, FALSE, FALSE,
4937 EL_NUT, ACTION_FALLING, -1
4940 Ynut_sB, FALSE, TRUE,
4941 EL_NUT, ACTION_FALLING, -1
4944 Ynut_e, FALSE, FALSE,
4945 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
4948 Ynut_eB, FALSE, TRUE,
4949 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
4952 Ynut_w, FALSE, FALSE,
4953 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
4956 Ynut_wB, FALSE, TRUE,
4957 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
4960 Xbug_n, TRUE, FALSE,
4964 Xbug_e, TRUE, FALSE,
4965 EL_BUG_RIGHT, -1, -1
4968 Xbug_s, TRUE, FALSE,
4972 Xbug_w, TRUE, FALSE,
4976 Xbug_gon, FALSE, FALSE,
4980 Xbug_goe, FALSE, FALSE,
4981 EL_BUG_RIGHT, -1, -1
4984 Xbug_gos, FALSE, FALSE,
4988 Xbug_gow, FALSE, FALSE,
4992 Ybug_n, FALSE, FALSE,
4993 EL_BUG, ACTION_MOVING, MV_BIT_UP
4996 Ybug_nB, FALSE, TRUE,
4997 EL_BUG, ACTION_MOVING, MV_BIT_UP
5000 Ybug_e, FALSE, FALSE,
5001 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
5004 Ybug_eB, FALSE, TRUE,
5005 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
5008 Ybug_s, FALSE, FALSE,
5009 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
5012 Ybug_sB, FALSE, TRUE,
5013 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
5016 Ybug_w, FALSE, FALSE,
5017 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
5020 Ybug_wB, FALSE, TRUE,
5021 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
5024 Ybug_w_n, FALSE, FALSE,
5025 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
5028 Ybug_n_e, FALSE, FALSE,
5029 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
5032 Ybug_e_s, FALSE, FALSE,
5033 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
5036 Ybug_s_w, FALSE, FALSE,
5037 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
5040 Ybug_e_n, FALSE, FALSE,
5041 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
5044 Ybug_s_e, FALSE, FALSE,
5045 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
5048 Ybug_w_s, FALSE, FALSE,
5049 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
5052 Ybug_n_w, FALSE, FALSE,
5053 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
5056 Ybug_stone, FALSE, FALSE,
5057 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
5060 Ybug_spring, FALSE, FALSE,
5061 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
5064 Xtank_n, TRUE, FALSE,
5065 EL_SPACESHIP_UP, -1, -1
5068 Xtank_e, TRUE, FALSE,
5069 EL_SPACESHIP_RIGHT, -1, -1
5072 Xtank_s, TRUE, FALSE,
5073 EL_SPACESHIP_DOWN, -1, -1
5076 Xtank_w, TRUE, FALSE,
5077 EL_SPACESHIP_LEFT, -1, -1
5080 Xtank_gon, FALSE, FALSE,
5081 EL_SPACESHIP_UP, -1, -1
5084 Xtank_goe, FALSE, FALSE,
5085 EL_SPACESHIP_RIGHT, -1, -1
5088 Xtank_gos, FALSE, FALSE,
5089 EL_SPACESHIP_DOWN, -1, -1
5092 Xtank_gow, FALSE, FALSE,
5093 EL_SPACESHIP_LEFT, -1, -1
5096 Ytank_n, FALSE, FALSE,
5097 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
5100 Ytank_nB, FALSE, TRUE,
5101 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
5104 Ytank_e, FALSE, FALSE,
5105 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
5108 Ytank_eB, FALSE, TRUE,
5109 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
5112 Ytank_s, FALSE, FALSE,
5113 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
5116 Ytank_sB, FALSE, TRUE,
5117 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
5120 Ytank_w, FALSE, FALSE,
5121 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
5124 Ytank_wB, FALSE, TRUE,
5125 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
5128 Ytank_w_n, FALSE, FALSE,
5129 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
5132 Ytank_n_e, FALSE, FALSE,
5133 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
5136 Ytank_e_s, FALSE, FALSE,
5137 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
5140 Ytank_s_w, FALSE, FALSE,
5141 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
5144 Ytank_e_n, FALSE, FALSE,
5145 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
5148 Ytank_s_e, FALSE, FALSE,
5149 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
5152 Ytank_w_s, FALSE, FALSE,
5153 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
5156 Ytank_n_w, FALSE, FALSE,
5157 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
5160 Ytank_stone, FALSE, FALSE,
5161 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
5164 Ytank_spring, FALSE, FALSE,
5165 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
5168 Xandroid, TRUE, FALSE,
5169 EL_EMC_ANDROID, ACTION_ACTIVE, -1
5172 Xandroid_1_n, FALSE, FALSE,
5173 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
5176 Xandroid_2_n, FALSE, FALSE,
5177 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
5180 Xandroid_1_e, FALSE, FALSE,
5181 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
5184 Xandroid_2_e, FALSE, FALSE,
5185 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
5188 Xandroid_1_w, FALSE, FALSE,
5189 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
5192 Xandroid_2_w, FALSE, FALSE,
5193 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
5196 Xandroid_1_s, FALSE, FALSE,
5197 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
5200 Xandroid_2_s, FALSE, FALSE,
5201 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
5204 Yandroid_n, FALSE, FALSE,
5205 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
5208 Yandroid_nB, FALSE, TRUE,
5209 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
5212 Yandroid_ne, FALSE, FALSE,
5213 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
5216 Yandroid_neB, FALSE, TRUE,
5217 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
5220 Yandroid_e, FALSE, FALSE,
5221 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
5224 Yandroid_eB, FALSE, TRUE,
5225 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
5228 Yandroid_se, FALSE, FALSE,
5229 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
5232 Yandroid_seB, FALSE, TRUE,
5233 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
5236 Yandroid_s, FALSE, FALSE,
5237 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
5240 Yandroid_sB, FALSE, TRUE,
5241 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
5244 Yandroid_sw, FALSE, FALSE,
5245 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
5248 Yandroid_swB, FALSE, TRUE,
5249 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
5252 Yandroid_w, FALSE, FALSE,
5253 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
5256 Yandroid_wB, FALSE, TRUE,
5257 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
5260 Yandroid_nw, FALSE, FALSE,
5261 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
5264 Yandroid_nwB, FALSE, TRUE,
5265 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
5268 Xspring, TRUE, FALSE,
5272 Xspring_pause, FALSE, FALSE,
5276 Xspring_e, FALSE, FALSE,
5280 Xspring_w, FALSE, FALSE,
5284 Xspring_fall, FALSE, FALSE,
5288 Yspring_s, FALSE, FALSE,
5289 EL_SPRING, ACTION_FALLING, -1
5292 Yspring_sB, FALSE, TRUE,
5293 EL_SPRING, ACTION_FALLING, -1
5296 Yspring_e, FALSE, FALSE,
5297 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
5300 Yspring_eB, FALSE, TRUE,
5301 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
5304 Yspring_w, FALSE, FALSE,
5305 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
5308 Yspring_wB, FALSE, TRUE,
5309 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
5312 Yspring_kill_e, FALSE, FALSE,
5313 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
5316 Yspring_kill_eB, FALSE, TRUE,
5317 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
5320 Yspring_kill_w, FALSE, FALSE,
5321 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
5324 Yspring_kill_wB, FALSE, TRUE,
5325 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
5328 Xeater_n, TRUE, FALSE,
5329 EL_YAMYAM_UP, -1, -1
5332 Xeater_e, TRUE, FALSE,
5333 EL_YAMYAM_RIGHT, -1, -1
5336 Xeater_w, TRUE, FALSE,
5337 EL_YAMYAM_LEFT, -1, -1
5340 Xeater_s, TRUE, FALSE,
5341 EL_YAMYAM_DOWN, -1, -1
5344 Yeater_n, FALSE, FALSE,
5345 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
5348 Yeater_nB, FALSE, TRUE,
5349 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
5352 Yeater_e, FALSE, FALSE,
5353 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
5356 Yeater_eB, FALSE, TRUE,
5357 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
5360 Yeater_s, FALSE, FALSE,
5361 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
5364 Yeater_sB, FALSE, TRUE,
5365 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
5368 Yeater_w, FALSE, FALSE,
5369 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
5372 Yeater_wB, FALSE, TRUE,
5373 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
5376 Yeater_stone, FALSE, FALSE,
5377 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
5380 Yeater_spring, FALSE, FALSE,
5381 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
5384 Xalien, TRUE, FALSE,
5388 Xalien_pause, FALSE, FALSE,
5392 Yalien_n, FALSE, FALSE,
5393 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
5396 Yalien_nB, FALSE, TRUE,
5397 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
5400 Yalien_e, FALSE, FALSE,
5401 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
5404 Yalien_eB, FALSE, TRUE,
5405 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
5408 Yalien_s, FALSE, FALSE,
5409 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
5412 Yalien_sB, FALSE, TRUE,
5413 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
5416 Yalien_w, FALSE, FALSE,
5417 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
5420 Yalien_wB, FALSE, TRUE,
5421 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
5424 Yalien_stone, FALSE, FALSE,
5425 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
5428 Yalien_spring, FALSE, FALSE,
5429 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
5432 Xemerald, TRUE, FALSE,
5436 Xemerald_pause, FALSE, FALSE,
5440 Xemerald_fall, FALSE, FALSE,
5444 Xemerald_shine, FALSE, FALSE,
5445 EL_EMERALD, ACTION_TWINKLING, -1
5448 Yemerald_s, FALSE, FALSE,
5449 EL_EMERALD, ACTION_FALLING, -1
5452 Yemerald_sB, FALSE, TRUE,
5453 EL_EMERALD, ACTION_FALLING, -1
5456 Yemerald_e, FALSE, FALSE,
5457 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
5460 Yemerald_eB, FALSE, TRUE,
5461 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
5464 Yemerald_w, FALSE, FALSE,
5465 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
5468 Yemerald_wB, FALSE, TRUE,
5469 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
5472 Yemerald_eat, FALSE, FALSE,
5473 EL_EMERALD, ACTION_COLLECTING, -1
5476 Yemerald_stone, FALSE, FALSE,
5477 EL_NUT, ACTION_BREAKING, -1
5480 Xdiamond, TRUE, FALSE,
5484 Xdiamond_pause, FALSE, FALSE,
5488 Xdiamond_fall, FALSE, FALSE,
5492 Xdiamond_shine, FALSE, FALSE,
5493 EL_DIAMOND, ACTION_TWINKLING, -1
5496 Ydiamond_s, FALSE, FALSE,
5497 EL_DIAMOND, ACTION_FALLING, -1
5500 Ydiamond_sB, FALSE, TRUE,
5501 EL_DIAMOND, ACTION_FALLING, -1
5504 Ydiamond_e, FALSE, FALSE,
5505 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
5508 Ydiamond_eB, FALSE, TRUE,
5509 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
5512 Ydiamond_w, FALSE, FALSE,
5513 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
5516 Ydiamond_wB, FALSE, TRUE,
5517 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
5520 Ydiamond_eat, FALSE, FALSE,
5521 EL_DIAMOND, ACTION_COLLECTING, -1
5524 Ydiamond_stone, FALSE, FALSE,
5525 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
5528 Xdrip_fall, TRUE, FALSE,
5529 EL_AMOEBA_DROP, -1, -1
5532 Xdrip_stretch, FALSE, FALSE,
5533 EL_AMOEBA_DROP, ACTION_FALLING, -1
5536 Xdrip_stretchB, FALSE, TRUE,
5537 EL_AMOEBA_DROP, ACTION_FALLING, -1
5540 Xdrip_eat, FALSE, FALSE,
5541 EL_AMOEBA_DROP, ACTION_GROWING, -1
5544 Ydrip_s1, FALSE, FALSE,
5545 EL_AMOEBA_DROP, ACTION_FALLING, -1
5548 Ydrip_s1B, FALSE, TRUE,
5549 EL_AMOEBA_DROP, ACTION_FALLING, -1
5552 Ydrip_s2, FALSE, FALSE,
5553 EL_AMOEBA_DROP, ACTION_FALLING, -1
5556 Ydrip_s2B, FALSE, TRUE,
5557 EL_AMOEBA_DROP, ACTION_FALLING, -1
5564 Xbomb_pause, FALSE, FALSE,
5568 Xbomb_fall, FALSE, FALSE,
5572 Ybomb_s, FALSE, FALSE,
5573 EL_BOMB, ACTION_FALLING, -1
5576 Ybomb_sB, FALSE, TRUE,
5577 EL_BOMB, ACTION_FALLING, -1
5580 Ybomb_e, FALSE, FALSE,
5581 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
5584 Ybomb_eB, FALSE, TRUE,
5585 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
5588 Ybomb_w, FALSE, FALSE,
5589 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
5592 Ybomb_wB, FALSE, TRUE,
5593 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
5596 Ybomb_eat, FALSE, FALSE,
5597 EL_BOMB, ACTION_ACTIVATING, -1
5600 Xballoon, TRUE, FALSE,
5604 Yballoon_n, FALSE, FALSE,
5605 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
5608 Yballoon_nB, FALSE, TRUE,
5609 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
5612 Yballoon_e, FALSE, FALSE,
5613 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
5616 Yballoon_eB, FALSE, TRUE,
5617 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
5620 Yballoon_s, FALSE, FALSE,
5621 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
5624 Yballoon_sB, FALSE, TRUE,
5625 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
5628 Yballoon_w, FALSE, FALSE,
5629 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
5632 Yballoon_wB, FALSE, TRUE,
5633 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
5636 Xgrass, TRUE, FALSE,
5637 EL_EMC_GRASS, -1, -1
5640 Ygrass_nB, FALSE, FALSE,
5641 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
5644 Ygrass_eB, FALSE, FALSE,
5645 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
5648 Ygrass_sB, FALSE, FALSE,
5649 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
5652 Ygrass_wB, FALSE, FALSE,
5653 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
5660 Ydirt_nB, FALSE, FALSE,
5661 EL_SAND, ACTION_DIGGING, MV_BIT_UP
5664 Ydirt_eB, FALSE, FALSE,
5665 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
5668 Ydirt_sB, FALSE, FALSE,
5669 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
5672 Ydirt_wB, FALSE, FALSE,
5673 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
5676 Xacid_ne, TRUE, FALSE,
5677 EL_ACID_POOL_TOPRIGHT, -1, -1
5680 Xacid_se, TRUE, FALSE,
5681 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
5684 Xacid_s, TRUE, FALSE,
5685 EL_ACID_POOL_BOTTOM, -1, -1
5688 Xacid_sw, TRUE, FALSE,
5689 EL_ACID_POOL_BOTTOMLEFT, -1, -1
5692 Xacid_nw, TRUE, FALSE,
5693 EL_ACID_POOL_TOPLEFT, -1, -1
5696 Xacid_1, TRUE, FALSE,
5700 Xacid_2, FALSE, FALSE,
5704 Xacid_3, FALSE, FALSE,
5708 Xacid_4, FALSE, FALSE,
5712 Xacid_5, FALSE, FALSE,
5716 Xacid_6, FALSE, FALSE,
5720 Xacid_7, FALSE, FALSE,
5724 Xacid_8, FALSE, FALSE,
5728 Xball_1, TRUE, FALSE,
5729 EL_EMC_MAGIC_BALL, -1, -1
5732 Xball_1B, FALSE, FALSE,
5733 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5736 Xball_2, FALSE, FALSE,
5737 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5740 Xball_2B, FALSE, FALSE,
5741 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5744 Yball_eat, FALSE, FALSE,
5745 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
5748 Ykey_1_eat, FALSE, FALSE,
5749 EL_EM_KEY_1, ACTION_COLLECTING, -1
5752 Ykey_2_eat, FALSE, FALSE,
5753 EL_EM_KEY_2, ACTION_COLLECTING, -1
5756 Ykey_3_eat, FALSE, FALSE,
5757 EL_EM_KEY_3, ACTION_COLLECTING, -1
5760 Ykey_4_eat, FALSE, FALSE,
5761 EL_EM_KEY_4, ACTION_COLLECTING, -1
5764 Ykey_5_eat, FALSE, FALSE,
5765 EL_EMC_KEY_5, ACTION_COLLECTING, -1
5768 Ykey_6_eat, FALSE, FALSE,
5769 EL_EMC_KEY_6, ACTION_COLLECTING, -1
5772 Ykey_7_eat, FALSE, FALSE,
5773 EL_EMC_KEY_7, ACTION_COLLECTING, -1
5776 Ykey_8_eat, FALSE, FALSE,
5777 EL_EMC_KEY_8, ACTION_COLLECTING, -1
5780 Ylenses_eat, FALSE, FALSE,
5781 EL_EMC_LENSES, ACTION_COLLECTING, -1
5784 Ymagnify_eat, FALSE, FALSE,
5785 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
5788 Ygrass_eat, FALSE, FALSE,
5789 EL_EMC_GRASS, ACTION_SNAPPING, -1
5792 Ydirt_eat, FALSE, FALSE,
5793 EL_SAND, ACTION_SNAPPING, -1
5796 Xgrow_ns, TRUE, FALSE,
5797 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
5800 Ygrow_ns_eat, FALSE, FALSE,
5801 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
5804 Xgrow_ew, TRUE, FALSE,
5805 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
5808 Ygrow_ew_eat, FALSE, FALSE,
5809 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
5812 Xwonderwall, TRUE, FALSE,
5813 EL_MAGIC_WALL, -1, -1
5816 XwonderwallB, FALSE, FALSE,
5817 EL_MAGIC_WALL, ACTION_ACTIVE, -1
5820 Xamoeba_1, TRUE, FALSE,
5821 EL_AMOEBA_DRY, ACTION_OTHER, -1
5824 Xamoeba_2, FALSE, FALSE,
5825 EL_AMOEBA_DRY, ACTION_OTHER, -1
5828 Xamoeba_3, FALSE, FALSE,
5829 EL_AMOEBA_DRY, ACTION_OTHER, -1
5832 Xamoeba_4, FALSE, FALSE,
5833 EL_AMOEBA_DRY, ACTION_OTHER, -1
5836 Xamoeba_5, TRUE, FALSE,
5837 EL_AMOEBA_WET, ACTION_OTHER, -1
5840 Xamoeba_6, FALSE, FALSE,
5841 EL_AMOEBA_WET, ACTION_OTHER, -1
5844 Xamoeba_7, FALSE, FALSE,
5845 EL_AMOEBA_WET, ACTION_OTHER, -1
5848 Xamoeba_8, FALSE, FALSE,
5849 EL_AMOEBA_WET, ACTION_OTHER, -1
5852 Xdoor_1, TRUE, FALSE,
5853 EL_EM_GATE_1, -1, -1
5856 Xdoor_2, TRUE, FALSE,
5857 EL_EM_GATE_2, -1, -1
5860 Xdoor_3, TRUE, FALSE,
5861 EL_EM_GATE_3, -1, -1
5864 Xdoor_4, TRUE, FALSE,
5865 EL_EM_GATE_4, -1, -1
5868 Xdoor_5, TRUE, FALSE,
5869 EL_EMC_GATE_5, -1, -1
5872 Xdoor_6, TRUE, FALSE,
5873 EL_EMC_GATE_6, -1, -1
5876 Xdoor_7, TRUE, FALSE,
5877 EL_EMC_GATE_7, -1, -1
5880 Xdoor_8, TRUE, FALSE,
5881 EL_EMC_GATE_8, -1, -1
5884 Xkey_1, TRUE, FALSE,
5888 Xkey_2, TRUE, FALSE,
5892 Xkey_3, TRUE, FALSE,
5896 Xkey_4, TRUE, FALSE,
5900 Xkey_5, TRUE, FALSE,
5901 EL_EMC_KEY_5, -1, -1
5904 Xkey_6, TRUE, FALSE,
5905 EL_EMC_KEY_6, -1, -1
5908 Xkey_7, TRUE, FALSE,
5909 EL_EMC_KEY_7, -1, -1
5912 Xkey_8, TRUE, FALSE,
5913 EL_EMC_KEY_8, -1, -1
5916 Xwind_n, TRUE, FALSE,
5917 EL_BALLOON_SWITCH_UP, -1, -1
5920 Xwind_e, TRUE, FALSE,
5921 EL_BALLOON_SWITCH_RIGHT, -1, -1
5924 Xwind_s, TRUE, FALSE,
5925 EL_BALLOON_SWITCH_DOWN, -1, -1
5928 Xwind_w, TRUE, FALSE,
5929 EL_BALLOON_SWITCH_LEFT, -1, -1
5932 Xwind_nesw, TRUE, FALSE,
5933 EL_BALLOON_SWITCH_ANY, -1, -1
5936 Xwind_stop, TRUE, FALSE,
5937 EL_BALLOON_SWITCH_NONE, -1, -1
5941 EL_EM_EXIT_CLOSED, -1, -1
5944 Xexit_1, TRUE, FALSE,
5945 EL_EM_EXIT_OPEN, -1, -1
5948 Xexit_2, FALSE, FALSE,
5949 EL_EM_EXIT_OPEN, -1, -1
5952 Xexit_3, FALSE, FALSE,
5953 EL_EM_EXIT_OPEN, -1, -1
5956 Xdynamite, TRUE, FALSE,
5957 EL_EM_DYNAMITE, -1, -1
5960 Ydynamite_eat, FALSE, FALSE,
5961 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
5964 Xdynamite_1, TRUE, FALSE,
5965 EL_EM_DYNAMITE_ACTIVE, -1, -1
5968 Xdynamite_2, FALSE, FALSE,
5969 EL_EM_DYNAMITE_ACTIVE, -1, -1
5972 Xdynamite_3, FALSE, FALSE,
5973 EL_EM_DYNAMITE_ACTIVE, -1, -1
5976 Xdynamite_4, FALSE, FALSE,
5977 EL_EM_DYNAMITE_ACTIVE, -1, -1
5980 Xbumper, TRUE, FALSE,
5981 EL_EMC_SPRING_BUMPER, -1, -1
5984 XbumperB, FALSE, FALSE,
5985 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
5988 Xwheel, TRUE, FALSE,
5989 EL_ROBOT_WHEEL, -1, -1
5992 XwheelB, FALSE, FALSE,
5993 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
5996 Xswitch, TRUE, FALSE,
5997 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
6000 XswitchB, FALSE, FALSE,
6001 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
6005 EL_QUICKSAND_EMPTY, -1, -1
6008 Xsand_stone, TRUE, FALSE,
6009 EL_QUICKSAND_FULL, -1, -1
6012 Xsand_stonein_1, FALSE, TRUE,
6013 EL_ROCK, ACTION_FILLING, -1
6016 Xsand_stonein_2, FALSE, TRUE,
6017 EL_ROCK, ACTION_FILLING, -1
6020 Xsand_stonein_3, FALSE, TRUE,
6021 EL_ROCK, ACTION_FILLING, -1
6024 Xsand_stonein_4, FALSE, TRUE,
6025 EL_ROCK, ACTION_FILLING, -1
6028 Xsand_stonesand_1, FALSE, FALSE,
6029 EL_QUICKSAND_EMPTYING, -1, -1
6032 Xsand_stonesand_2, FALSE, FALSE,
6033 EL_QUICKSAND_EMPTYING, -1, -1
6036 Xsand_stonesand_3, FALSE, FALSE,
6037 EL_QUICKSAND_EMPTYING, -1, -1
6040 Xsand_stonesand_4, FALSE, FALSE,
6041 EL_QUICKSAND_EMPTYING, -1, -1
6044 Xsand_stonesand_quickout_1, FALSE, FALSE,
6045 EL_QUICKSAND_EMPTYING, -1, -1
6048 Xsand_stonesand_quickout_2, FALSE, FALSE,
6049 EL_QUICKSAND_EMPTYING, -1, -1
6052 Xsand_stoneout_1, FALSE, FALSE,
6053 EL_ROCK, ACTION_EMPTYING, -1
6056 Xsand_stoneout_2, FALSE, FALSE,
6057 EL_ROCK, ACTION_EMPTYING, -1
6060 Xsand_sandstone_1, FALSE, FALSE,
6061 EL_QUICKSAND_FILLING, -1, -1
6064 Xsand_sandstone_2, FALSE, FALSE,
6065 EL_QUICKSAND_FILLING, -1, -1
6068 Xsand_sandstone_3, FALSE, FALSE,
6069 EL_QUICKSAND_FILLING, -1, -1
6072 Xsand_sandstone_4, FALSE, FALSE,
6073 EL_QUICKSAND_FILLING, -1, -1
6076 Xplant, TRUE, FALSE,
6077 EL_EMC_PLANT, -1, -1
6080 Yplant, FALSE, FALSE,
6081 EL_EMC_PLANT, -1, -1
6084 Xlenses, TRUE, FALSE,
6085 EL_EMC_LENSES, -1, -1
6088 Xmagnify, TRUE, FALSE,
6089 EL_EMC_MAGNIFIER, -1, -1
6092 Xdripper, TRUE, FALSE,
6093 EL_EMC_DRIPPER, -1, -1
6096 XdripperB, FALSE, FALSE,
6097 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
6100 Xfake_blank, TRUE, FALSE,
6101 EL_INVISIBLE_WALL, -1, -1
6104 Xfake_blankB, FALSE, FALSE,
6105 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
6108 Xfake_grass, TRUE, FALSE,
6109 EL_EMC_FAKE_GRASS, -1, -1
6112 Xfake_grassB, FALSE, FALSE,
6113 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
6116 Xfake_door_1, TRUE, FALSE,
6117 EL_EM_GATE_1_GRAY, -1, -1
6120 Xfake_door_2, TRUE, FALSE,
6121 EL_EM_GATE_2_GRAY, -1, -1
6124 Xfake_door_3, TRUE, FALSE,
6125 EL_EM_GATE_3_GRAY, -1, -1
6128 Xfake_door_4, TRUE, FALSE,
6129 EL_EM_GATE_4_GRAY, -1, -1
6132 Xfake_door_5, TRUE, FALSE,
6133 EL_EMC_GATE_5_GRAY, -1, -1
6136 Xfake_door_6, TRUE, FALSE,
6137 EL_EMC_GATE_6_GRAY, -1, -1
6140 Xfake_door_7, TRUE, FALSE,
6141 EL_EMC_GATE_7_GRAY, -1, -1
6144 Xfake_door_8, TRUE, FALSE,
6145 EL_EMC_GATE_8_GRAY, -1, -1
6148 Xfake_acid_1, TRUE, FALSE,
6149 EL_EMC_FAKE_ACID, -1, -1
6152 Xfake_acid_2, FALSE, FALSE,
6153 EL_EMC_FAKE_ACID, -1, -1
6156 Xfake_acid_3, FALSE, FALSE,
6157 EL_EMC_FAKE_ACID, -1, -1
6160 Xfake_acid_4, FALSE, FALSE,
6161 EL_EMC_FAKE_ACID, -1, -1
6164 Xfake_acid_5, FALSE, FALSE,
6165 EL_EMC_FAKE_ACID, -1, -1
6168 Xfake_acid_6, FALSE, FALSE,
6169 EL_EMC_FAKE_ACID, -1, -1
6172 Xfake_acid_7, FALSE, FALSE,
6173 EL_EMC_FAKE_ACID, -1, -1
6176 Xfake_acid_8, FALSE, FALSE,
6177 EL_EMC_FAKE_ACID, -1, -1
6180 Xsteel_1, TRUE, FALSE,
6181 EL_STEELWALL, -1, -1
6184 Xsteel_2, TRUE, FALSE,
6185 EL_EMC_STEELWALL_2, -1, -1
6188 Xsteel_3, TRUE, FALSE,
6189 EL_EMC_STEELWALL_3, -1, -1
6192 Xsteel_4, TRUE, FALSE,
6193 EL_EMC_STEELWALL_4, -1, -1
6196 Xwall_1, TRUE, FALSE,
6200 Xwall_2, TRUE, FALSE,
6201 EL_EMC_WALL_14, -1, -1
6204 Xwall_3, TRUE, FALSE,
6205 EL_EMC_WALL_15, -1, -1
6208 Xwall_4, TRUE, FALSE,
6209 EL_EMC_WALL_16, -1, -1
6212 Xround_wall_1, TRUE, FALSE,
6213 EL_WALL_SLIPPERY, -1, -1
6216 Xround_wall_2, TRUE, FALSE,
6217 EL_EMC_WALL_SLIPPERY_2, -1, -1
6220 Xround_wall_3, TRUE, FALSE,
6221 EL_EMC_WALL_SLIPPERY_3, -1, -1
6224 Xround_wall_4, TRUE, FALSE,
6225 EL_EMC_WALL_SLIPPERY_4, -1, -1
6228 Xdecor_1, TRUE, FALSE,
6229 EL_EMC_WALL_8, -1, -1
6232 Xdecor_2, TRUE, FALSE,
6233 EL_EMC_WALL_6, -1, -1
6236 Xdecor_3, TRUE, FALSE,
6237 EL_EMC_WALL_4, -1, -1
6240 Xdecor_4, TRUE, FALSE,
6241 EL_EMC_WALL_7, -1, -1
6244 Xdecor_5, TRUE, FALSE,
6245 EL_EMC_WALL_5, -1, -1
6248 Xdecor_6, TRUE, FALSE,
6249 EL_EMC_WALL_9, -1, -1
6252 Xdecor_7, TRUE, FALSE,
6253 EL_EMC_WALL_10, -1, -1
6256 Xdecor_8, TRUE, FALSE,
6257 EL_EMC_WALL_1, -1, -1
6260 Xdecor_9, TRUE, FALSE,
6261 EL_EMC_WALL_2, -1, -1
6264 Xdecor_10, TRUE, FALSE,
6265 EL_EMC_WALL_3, -1, -1
6268 Xdecor_11, TRUE, FALSE,
6269 EL_EMC_WALL_11, -1, -1
6272 Xdecor_12, TRUE, FALSE,
6273 EL_EMC_WALL_12, -1, -1
6276 Xalpha_0, TRUE, FALSE,
6277 EL_CHAR('0'), -1, -1
6280 Xalpha_1, TRUE, FALSE,
6281 EL_CHAR('1'), -1, -1
6284 Xalpha_2, TRUE, FALSE,
6285 EL_CHAR('2'), -1, -1
6288 Xalpha_3, TRUE, FALSE,
6289 EL_CHAR('3'), -1, -1
6292 Xalpha_4, TRUE, FALSE,
6293 EL_CHAR('4'), -1, -1
6296 Xalpha_5, TRUE, FALSE,
6297 EL_CHAR('5'), -1, -1
6300 Xalpha_6, TRUE, FALSE,
6301 EL_CHAR('6'), -1, -1
6304 Xalpha_7, TRUE, FALSE,
6305 EL_CHAR('7'), -1, -1
6308 Xalpha_8, TRUE, FALSE,
6309 EL_CHAR('8'), -1, -1
6312 Xalpha_9, TRUE, FALSE,
6313 EL_CHAR('9'), -1, -1
6316 Xalpha_excla, TRUE, FALSE,
6317 EL_CHAR('!'), -1, -1
6320 Xalpha_quote, TRUE, FALSE,
6321 EL_CHAR('"'), -1, -1
6324 Xalpha_comma, TRUE, FALSE,
6325 EL_CHAR(','), -1, -1
6328 Xalpha_minus, TRUE, FALSE,
6329 EL_CHAR('-'), -1, -1
6332 Xalpha_perio, TRUE, FALSE,
6333 EL_CHAR('.'), -1, -1
6336 Xalpha_colon, TRUE, FALSE,
6337 EL_CHAR(':'), -1, -1
6340 Xalpha_quest, TRUE, FALSE,
6341 EL_CHAR('?'), -1, -1
6344 Xalpha_a, TRUE, FALSE,
6345 EL_CHAR('A'), -1, -1
6348 Xalpha_b, TRUE, FALSE,
6349 EL_CHAR('B'), -1, -1
6352 Xalpha_c, TRUE, FALSE,
6353 EL_CHAR('C'), -1, -1
6356 Xalpha_d, TRUE, FALSE,
6357 EL_CHAR('D'), -1, -1
6360 Xalpha_e, TRUE, FALSE,
6361 EL_CHAR('E'), -1, -1
6364 Xalpha_f, TRUE, FALSE,
6365 EL_CHAR('F'), -1, -1
6368 Xalpha_g, TRUE, FALSE,
6369 EL_CHAR('G'), -1, -1
6372 Xalpha_h, TRUE, FALSE,
6373 EL_CHAR('H'), -1, -1
6376 Xalpha_i, TRUE, FALSE,
6377 EL_CHAR('I'), -1, -1
6380 Xalpha_j, TRUE, FALSE,
6381 EL_CHAR('J'), -1, -1
6384 Xalpha_k, TRUE, FALSE,
6385 EL_CHAR('K'), -1, -1
6388 Xalpha_l, TRUE, FALSE,
6389 EL_CHAR('L'), -1, -1
6392 Xalpha_m, TRUE, FALSE,
6393 EL_CHAR('M'), -1, -1
6396 Xalpha_n, TRUE, FALSE,
6397 EL_CHAR('N'), -1, -1
6400 Xalpha_o, TRUE, FALSE,
6401 EL_CHAR('O'), -1, -1
6404 Xalpha_p, TRUE, FALSE,
6405 EL_CHAR('P'), -1, -1
6408 Xalpha_q, TRUE, FALSE,
6409 EL_CHAR('Q'), -1, -1
6412 Xalpha_r, TRUE, FALSE,
6413 EL_CHAR('R'), -1, -1
6416 Xalpha_s, TRUE, FALSE,
6417 EL_CHAR('S'), -1, -1
6420 Xalpha_t, TRUE, FALSE,
6421 EL_CHAR('T'), -1, -1
6424 Xalpha_u, TRUE, FALSE,
6425 EL_CHAR('U'), -1, -1
6428 Xalpha_v, TRUE, FALSE,
6429 EL_CHAR('V'), -1, -1
6432 Xalpha_w, TRUE, FALSE,
6433 EL_CHAR('W'), -1, -1
6436 Xalpha_x, TRUE, FALSE,
6437 EL_CHAR('X'), -1, -1
6440 Xalpha_y, TRUE, FALSE,
6441 EL_CHAR('Y'), -1, -1
6444 Xalpha_z, TRUE, FALSE,
6445 EL_CHAR('Z'), -1, -1
6448 Xalpha_arrow_e, TRUE, FALSE,
6449 EL_CHAR('>'), -1, -1
6452 Xalpha_arrow_w, TRUE, FALSE,
6453 EL_CHAR('<'), -1, -1
6456 Xalpha_copyr, TRUE, FALSE,
6457 EL_CHAR(CHAR_BYTE_COPYRIGHT), -1, -1
6461 Xboom_bug, FALSE, FALSE,
6462 EL_BUG, ACTION_EXPLODING, -1
6465 Xboom_bomb, FALSE, FALSE,
6466 EL_BOMB, ACTION_EXPLODING, -1
6469 Xboom_android, FALSE, FALSE,
6470 EL_EMC_ANDROID, ACTION_OTHER, -1
6473 Xboom_1, FALSE, FALSE,
6474 EL_DEFAULT, ACTION_EXPLODING, -1
6477 Xboom_2, FALSE, FALSE,
6478 EL_DEFAULT, ACTION_EXPLODING, -1
6481 Znormal, FALSE, FALSE,
6485 Zdynamite, FALSE, FALSE,
6489 Zplayer, FALSE, FALSE,
6493 ZBORDER, FALSE, FALSE,
6503 static struct Mapping_EM_to_RND_player
6512 em_player_mapping_list[] =
6516 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
6520 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
6524 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
6528 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
6532 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
6536 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
6540 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
6544 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
6548 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
6552 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
6556 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
6560 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
6564 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
6568 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
6572 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
6576 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
6580 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
6584 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
6588 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
6592 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
6596 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
6600 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
6604 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
6608 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
6612 EL_PLAYER_1, ACTION_DEFAULT, -1,
6616 EL_PLAYER_2, ACTION_DEFAULT, -1,
6620 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
6624 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
6628 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
6632 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
6636 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
6640 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
6644 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
6648 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
6652 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
6656 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
6660 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
6664 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
6668 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
6672 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
6676 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
6680 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
6684 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
6688 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
6692 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
6696 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
6700 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
6704 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
6708 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
6712 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
6716 EL_PLAYER_3, ACTION_DEFAULT, -1,
6720 EL_PLAYER_4, ACTION_DEFAULT, -1,
6729 int map_element_RND_to_EM(int element_rnd)
6731 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
6732 static boolean mapping_initialized = FALSE;
6734 if (!mapping_initialized)
6738 /* return "Xalpha_quest" for all undefined elements in mapping array */
6739 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
6740 mapping_RND_to_EM[i] = Xalpha_quest;
6742 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6743 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
6744 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
6745 em_object_mapping_list[i].element_em;
6747 mapping_initialized = TRUE;
6750 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
6751 return mapping_RND_to_EM[element_rnd];
6753 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
6758 int map_element_EM_to_RND(int element_em)
6760 static unsigned short mapping_EM_to_RND[TILE_MAX];
6761 static boolean mapping_initialized = FALSE;
6763 if (!mapping_initialized)
6767 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
6768 for (i = 0; i < TILE_MAX; i++)
6769 mapping_EM_to_RND[i] = EL_UNKNOWN;
6771 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6772 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
6773 em_object_mapping_list[i].element_rnd;
6775 mapping_initialized = TRUE;
6778 if (element_em >= 0 && element_em < TILE_MAX)
6779 return mapping_EM_to_RND[element_em];
6781 Error(ERR_WARN, "invalid EM level element %d", element_em);
6786 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
6788 struct LevelInfo_EM *level_em = level->native_em_level;
6789 struct LEVEL *lev = level_em->lev;
6792 for (i = 0; i < TILE_MAX; i++)
6793 lev->android_array[i] = Xblank;
6795 for (i = 0; i < level->num_android_clone_elements; i++)
6797 int element_rnd = level->android_clone_element[i];
6798 int element_em = map_element_RND_to_EM(element_rnd);
6800 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
6801 if (em_object_mapping_list[j].element_rnd == element_rnd)
6802 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
6806 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
6808 struct LevelInfo_EM *level_em = level->native_em_level;
6809 struct LEVEL *lev = level_em->lev;
6812 level->num_android_clone_elements = 0;
6814 for (i = 0; i < TILE_MAX; i++)
6816 int element_em = lev->android_array[i];
6818 boolean element_found = FALSE;
6820 if (element_em == Xblank)
6823 element_rnd = map_element_EM_to_RND(element_em);
6825 for (j = 0; j < level->num_android_clone_elements; j++)
6826 if (level->android_clone_element[j] == element_rnd)
6827 element_found = TRUE;
6831 level->android_clone_element[level->num_android_clone_elements++] =
6834 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
6839 if (level->num_android_clone_elements == 0)
6841 level->num_android_clone_elements = 1;
6842 level->android_clone_element[0] = EL_EMPTY;
6846 int map_direction_RND_to_EM(int direction)
6848 return (direction == MV_UP ? 0 :
6849 direction == MV_RIGHT ? 1 :
6850 direction == MV_DOWN ? 2 :
6851 direction == MV_LEFT ? 3 :
6855 int map_direction_EM_to_RND(int direction)
6857 return (direction == 0 ? MV_UP :
6858 direction == 1 ? MV_RIGHT :
6859 direction == 2 ? MV_DOWN :
6860 direction == 3 ? MV_LEFT :
6864 int map_element_RND_to_SP(int element_rnd)
6866 int element_sp = 0x20; /* map unknown elements to yellow "hardware" */
6868 if (element_rnd >= EL_SP_START &&
6869 element_rnd <= EL_SP_END)
6870 element_sp = element_rnd - EL_SP_START;
6871 else if (element_rnd == EL_EMPTY_SPACE)
6873 else if (element_rnd == EL_INVISIBLE_WALL)
6879 int map_element_SP_to_RND(int element_sp)
6881 int element_rnd = EL_UNKNOWN;
6883 if (element_sp >= 0x00 &&
6885 element_rnd = EL_SP_START + element_sp;
6886 else if (element_sp == 0x28)
6887 element_rnd = EL_INVISIBLE_WALL;
6892 int map_action_SP_to_RND(int action_sp)
6896 case actActive: return ACTION_ACTIVE;
6897 case actImpact: return ACTION_IMPACT;
6898 case actExploding: return ACTION_EXPLODING;
6899 case actDigging: return ACTION_DIGGING;
6900 case actSnapping: return ACTION_SNAPPING;
6901 case actCollecting: return ACTION_COLLECTING;
6902 case actPassing: return ACTION_PASSING;
6903 case actPushing: return ACTION_PUSHING;
6904 case actDropping: return ACTION_DROPPING;
6906 default: return ACTION_DEFAULT;
6910 int get_next_element(int element)
6914 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
6915 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
6916 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
6917 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
6918 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
6919 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
6920 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
6921 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
6922 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
6923 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
6924 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
6926 default: return element;
6930 int el_act_dir2img(int element, int action, int direction)
6932 element = GFX_ELEMENT(element);
6933 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
6935 /* direction_graphic[][] == graphic[] for undefined direction graphics */
6936 return element_info[element].direction_graphic[action][direction];
6939 static int el_act_dir2crm(int element, int action, int direction)
6941 element = GFX_ELEMENT(element);
6942 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
6944 /* direction_graphic[][] == graphic[] for undefined direction graphics */
6945 return element_info[element].direction_crumbled[action][direction];
6948 int el_act2img(int element, int action)
6950 element = GFX_ELEMENT(element);
6952 return element_info[element].graphic[action];
6955 int el_act2crm(int element, int action)
6957 element = GFX_ELEMENT(element);
6959 return element_info[element].crumbled[action];
6962 int el_dir2img(int element, int direction)
6964 element = GFX_ELEMENT(element);
6966 return el_act_dir2img(element, ACTION_DEFAULT, direction);
6969 int el2baseimg(int element)
6971 return element_info[element].graphic[ACTION_DEFAULT];
6974 int el2img(int element)
6976 element = GFX_ELEMENT(element);
6978 return element_info[element].graphic[ACTION_DEFAULT];
6981 int el2edimg(int element)
6983 element = GFX_ELEMENT(element);
6985 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
6988 int el2preimg(int element)
6990 element = GFX_ELEMENT(element);
6992 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
6995 int el2panelimg(int element)
6997 element = GFX_ELEMENT(element);
6999 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL];
7002 int font2baseimg(int font_nr)
7004 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
7007 int getBeltNrFromBeltElement(int element)
7009 return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
7010 element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
7011 element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
7014 int getBeltNrFromBeltActiveElement(int element)
7016 return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
7017 element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
7018 element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
7021 int getBeltNrFromBeltSwitchElement(int element)
7023 return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
7024 element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
7025 element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
7028 int getBeltDirNrFromBeltElement(int element)
7030 static int belt_base_element[4] =
7032 EL_CONVEYOR_BELT_1_LEFT,
7033 EL_CONVEYOR_BELT_2_LEFT,
7034 EL_CONVEYOR_BELT_3_LEFT,
7035 EL_CONVEYOR_BELT_4_LEFT
7038 int belt_nr = getBeltNrFromBeltElement(element);
7039 int belt_dir_nr = element - belt_base_element[belt_nr];
7041 return (belt_dir_nr % 3);
7044 int getBeltDirNrFromBeltSwitchElement(int element)
7046 static int belt_base_element[4] =
7048 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
7049 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
7050 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
7051 EL_CONVEYOR_BELT_4_SWITCH_LEFT
7054 int belt_nr = getBeltNrFromBeltSwitchElement(element);
7055 int belt_dir_nr = element - belt_base_element[belt_nr];
7057 return (belt_dir_nr % 3);
7060 int getBeltDirFromBeltElement(int element)
7062 static int belt_move_dir[3] =
7069 int belt_dir_nr = getBeltDirNrFromBeltElement(element);
7071 return belt_move_dir[belt_dir_nr];
7074 int getBeltDirFromBeltSwitchElement(int element)
7076 static int belt_move_dir[3] =
7083 int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
7085 return belt_move_dir[belt_dir_nr];
7088 int getBeltElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
7090 static int belt_base_element[4] =
7092 EL_CONVEYOR_BELT_1_LEFT,
7093 EL_CONVEYOR_BELT_2_LEFT,
7094 EL_CONVEYOR_BELT_3_LEFT,
7095 EL_CONVEYOR_BELT_4_LEFT
7098 return belt_base_element[belt_nr] + belt_dir_nr;
7101 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
7103 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
7105 return getBeltElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
7108 int getBeltSwitchElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
7110 static int belt_base_element[4] =
7112 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
7113 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
7114 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
7115 EL_CONVEYOR_BELT_4_SWITCH_LEFT
7118 return belt_base_element[belt_nr] + belt_dir_nr;
7121 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
7123 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
7125 return getBeltSwitchElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
7128 boolean getTeamMode_EM()
7130 return game.team_mode;
7133 int getGameFrameDelay_EM(int native_em_game_frame_delay)
7135 int game_frame_delay_value;
7137 game_frame_delay_value =
7138 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
7139 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
7142 if (tape.playing && tape.warp_forward && !tape.pausing)
7143 game_frame_delay_value = 0;
7145 return game_frame_delay_value;
7148 unsigned int InitRND(int seed)
7150 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
7151 return InitEngineRandom_EM(seed);
7152 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
7153 return InitEngineRandom_SP(seed);
7155 return InitEngineRandom_RND(seed);
7158 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
7159 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
7161 inline static int get_effective_element_EM(int tile, int frame_em)
7163 int element = object_mapping[tile].element_rnd;
7164 int action = object_mapping[tile].action;
7165 boolean is_backside = object_mapping[tile].is_backside;
7166 boolean action_removing = (action == ACTION_DIGGING ||
7167 action == ACTION_SNAPPING ||
7168 action == ACTION_COLLECTING);
7174 case Yacid_splash_eB:
7175 case Yacid_splash_wB:
7176 return (frame_em > 5 ? EL_EMPTY : element);
7182 else /* frame_em == 7 */
7186 case Yacid_splash_eB:
7187 case Yacid_splash_wB:
7190 case Yemerald_stone:
7193 case Ydiamond_stone:
7197 case Xdrip_stretchB:
7216 case Xsand_stonein_1:
7217 case Xsand_stonein_2:
7218 case Xsand_stonein_3:
7219 case Xsand_stonein_4:
7223 return (is_backside || action_removing ? EL_EMPTY : element);
7228 inline static boolean check_linear_animation_EM(int tile)
7232 case Xsand_stonesand_1:
7233 case Xsand_stonesand_quickout_1:
7234 case Xsand_sandstone_1:
7235 case Xsand_stonein_1:
7236 case Xsand_stoneout_1:
7255 case Yacid_splash_eB:
7256 case Yacid_splash_wB:
7257 case Yemerald_stone:
7264 inline static void set_crumbled_graphics_EM(struct GraphicInfo_EM *g_em,
7265 boolean has_crumbled_graphics,
7266 int crumbled, int sync_frame)
7268 /* if element can be crumbled, but certain action graphics are just empty
7269 space (like instantly snapping sand to empty space in 1 frame), do not
7270 treat these empty space graphics as crumbled graphics in EMC engine */
7271 if (crumbled == IMG_EMPTY_SPACE)
7272 has_crumbled_graphics = FALSE;
7274 if (has_crumbled_graphics)
7276 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
7277 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
7278 g_crumbled->anim_delay,
7279 g_crumbled->anim_mode,
7280 g_crumbled->anim_start_frame,
7283 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
7284 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
7286 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
7288 g_em->has_crumbled_graphics = TRUE;
7292 g_em->crumbled_bitmap = NULL;
7293 g_em->crumbled_src_x = 0;
7294 g_em->crumbled_src_y = 0;
7295 g_em->crumbled_border_size = 0;
7297 g_em->has_crumbled_graphics = FALSE;
7301 void ResetGfxAnimation_EM(int x, int y, int tile)
7306 void SetGfxAnimation_EM(struct GraphicInfo_EM *g_em,
7307 int tile, int frame_em, int x, int y)
7309 int action = object_mapping[tile].action;
7310 int direction = object_mapping[tile].direction;
7311 int effective_element = get_effective_element_EM(tile, frame_em);
7312 int graphic = (direction == MV_NONE ?
7313 el_act2img(effective_element, action) :
7314 el_act_dir2img(effective_element, action, direction));
7315 struct GraphicInfo *g = &graphic_info[graphic];
7317 boolean action_removing = (action == ACTION_DIGGING ||
7318 action == ACTION_SNAPPING ||
7319 action == ACTION_COLLECTING);
7320 boolean action_moving = (action == ACTION_FALLING ||
7321 action == ACTION_MOVING ||
7322 action == ACTION_PUSHING ||
7323 action == ACTION_EATING ||
7324 action == ACTION_FILLING ||
7325 action == ACTION_EMPTYING);
7326 boolean action_falling = (action == ACTION_FALLING ||
7327 action == ACTION_FILLING ||
7328 action == ACTION_EMPTYING);
7330 /* special case: graphic uses "2nd movement tile" and has defined
7331 7 frames for movement animation (or less) => use default graphic
7332 for last (8th) frame which ends the movement animation */
7333 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
7335 action = ACTION_DEFAULT; /* (keep action_* unchanged for now) */
7336 graphic = (direction == MV_NONE ?
7337 el_act2img(effective_element, action) :
7338 el_act_dir2img(effective_element, action, direction));
7340 g = &graphic_info[graphic];
7343 if ((action_removing || check_linear_animation_EM(tile)) && frame_em == 0)
7347 else if (action_moving)
7349 boolean is_backside = object_mapping[tile].is_backside;
7353 int direction = object_mapping[tile].direction;
7354 int move_dir = (action_falling ? MV_DOWN : direction);
7359 /* !!! TEST !!! NEW !!! DOES NOT WORK RIGHT YET !!! */
7360 if (g->double_movement && frame_em == 0)
7364 if (move_dir == MV_LEFT)
7365 GfxFrame[x - 1][y] = GfxFrame[x][y];
7366 else if (move_dir == MV_RIGHT)
7367 GfxFrame[x + 1][y] = GfxFrame[x][y];
7368 else if (move_dir == MV_UP)
7369 GfxFrame[x][y - 1] = GfxFrame[x][y];
7370 else if (move_dir == MV_DOWN)
7371 GfxFrame[x][y + 1] = GfxFrame[x][y];
7378 /* special case: animation for Xsand_stonesand_quickout_1/2 twice as fast */
7379 if (tile == Xsand_stonesand_quickout_1 ||
7380 tile == Xsand_stonesand_quickout_2)
7384 if (graphic_info[graphic].anim_global_sync)
7385 sync_frame = FrameCounter;
7386 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
7387 sync_frame = GfxFrame[x][y];
7389 sync_frame = 0; /* playfield border (pseudo steel) */
7391 SetRandomAnimationValue(x, y);
7393 int frame = getAnimationFrame(g->anim_frames,
7396 g->anim_start_frame,
7399 g_em->unique_identifier =
7400 (graphic << 16) | ((frame % 8) << 12) | (g_em->width << 6) | g_em->height;
7403 void getGraphicSourceObjectExt_EM(struct GraphicInfo_EM *g_em,
7404 int tile, int frame_em, int x, int y)
7406 int action = object_mapping[tile].action;
7407 int direction = object_mapping[tile].direction;
7408 boolean is_backside = object_mapping[tile].is_backside;
7409 int effective_element = get_effective_element_EM(tile, frame_em);
7410 int effective_action = action;
7411 int graphic = (direction == MV_NONE ?
7412 el_act2img(effective_element, effective_action) :
7413 el_act_dir2img(effective_element, effective_action,
7415 int crumbled = (direction == MV_NONE ?
7416 el_act2crm(effective_element, effective_action) :
7417 el_act_dir2crm(effective_element, effective_action,
7419 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7420 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7421 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7422 struct GraphicInfo *g = &graphic_info[graphic];
7425 /* special case: graphic uses "2nd movement tile" and has defined
7426 7 frames for movement animation (or less) => use default graphic
7427 for last (8th) frame which ends the movement animation */
7428 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
7430 effective_action = ACTION_DEFAULT;
7431 graphic = (direction == MV_NONE ?
7432 el_act2img(effective_element, effective_action) :
7433 el_act_dir2img(effective_element, effective_action,
7435 crumbled = (direction == MV_NONE ?
7436 el_act2crm(effective_element, effective_action) :
7437 el_act_dir2crm(effective_element, effective_action,
7440 g = &graphic_info[graphic];
7443 if (graphic_info[graphic].anim_global_sync)
7444 sync_frame = FrameCounter;
7445 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
7446 sync_frame = GfxFrame[x][y];
7448 sync_frame = 0; /* playfield border (pseudo steel) */
7450 SetRandomAnimationValue(x, y);
7452 int frame = getAnimationFrame(g->anim_frames,
7455 g->anim_start_frame,
7458 getGraphicSourceExt(graphic, frame, &g_em->bitmap, &g_em->src_x, &g_em->src_y,
7459 g->double_movement && is_backside);
7461 /* (updating the "crumbled" graphic definitions is probably not really needed,
7462 as animations for crumbled graphics can't be longer than one EMC cycle) */
7463 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
7467 void getGraphicSourcePlayerExt_EM(struct GraphicInfo_EM *g_em,
7468 int player_nr, int anim, int frame_em)
7470 int element = player_mapping[player_nr][anim].element_rnd;
7471 int action = player_mapping[player_nr][anim].action;
7472 int direction = player_mapping[player_nr][anim].direction;
7473 int graphic = (direction == MV_NONE ?
7474 el_act2img(element, action) :
7475 el_act_dir2img(element, action, direction));
7476 struct GraphicInfo *g = &graphic_info[graphic];
7479 InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
7481 stored_player[player_nr].StepFrame = frame_em;
7483 sync_frame = stored_player[player_nr].Frame;
7485 int frame = getAnimationFrame(g->anim_frames,
7488 g->anim_start_frame,
7491 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
7492 &g_em->src_x, &g_em->src_y, FALSE);
7495 void InitGraphicInfo_EM(void)
7500 int num_em_gfx_errors = 0;
7502 if (graphic_info_em_object[0][0].bitmap == NULL)
7504 /* EM graphics not yet initialized in em_open_all() */
7509 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
7512 /* always start with reliable default values */
7513 for (i = 0; i < TILE_MAX; i++)
7515 object_mapping[i].element_rnd = EL_UNKNOWN;
7516 object_mapping[i].is_backside = FALSE;
7517 object_mapping[i].action = ACTION_DEFAULT;
7518 object_mapping[i].direction = MV_NONE;
7521 /* always start with reliable default values */
7522 for (p = 0; p < MAX_PLAYERS; p++)
7524 for (i = 0; i < SPR_MAX; i++)
7526 player_mapping[p][i].element_rnd = EL_UNKNOWN;
7527 player_mapping[p][i].action = ACTION_DEFAULT;
7528 player_mapping[p][i].direction = MV_NONE;
7532 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
7534 int e = em_object_mapping_list[i].element_em;
7536 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
7537 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
7539 if (em_object_mapping_list[i].action != -1)
7540 object_mapping[e].action = em_object_mapping_list[i].action;
7542 if (em_object_mapping_list[i].direction != -1)
7543 object_mapping[e].direction =
7544 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
7547 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
7549 int a = em_player_mapping_list[i].action_em;
7550 int p = em_player_mapping_list[i].player_nr;
7552 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
7554 if (em_player_mapping_list[i].action != -1)
7555 player_mapping[p][a].action = em_player_mapping_list[i].action;
7557 if (em_player_mapping_list[i].direction != -1)
7558 player_mapping[p][a].direction =
7559 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
7562 for (i = 0; i < TILE_MAX; i++)
7564 int element = object_mapping[i].element_rnd;
7565 int action = object_mapping[i].action;
7566 int direction = object_mapping[i].direction;
7567 boolean is_backside = object_mapping[i].is_backside;
7568 boolean action_exploding = ((action == ACTION_EXPLODING ||
7569 action == ACTION_SMASHED_BY_ROCK ||
7570 action == ACTION_SMASHED_BY_SPRING) &&
7571 element != EL_DIAMOND);
7572 boolean action_active = (action == ACTION_ACTIVE);
7573 boolean action_other = (action == ACTION_OTHER);
7575 for (j = 0; j < 8; j++)
7577 int effective_element = get_effective_element_EM(i, j);
7578 int effective_action = (j < 7 ? action :
7579 i == Xdrip_stretch ? action :
7580 i == Xdrip_stretchB ? action :
7581 i == Ydrip_s1 ? action :
7582 i == Ydrip_s1B ? action :
7583 i == Xball_1B ? action :
7584 i == Xball_2 ? action :
7585 i == Xball_2B ? action :
7586 i == Yball_eat ? action :
7587 i == Ykey_1_eat ? action :
7588 i == Ykey_2_eat ? action :
7589 i == Ykey_3_eat ? action :
7590 i == Ykey_4_eat ? action :
7591 i == Ykey_5_eat ? action :
7592 i == Ykey_6_eat ? action :
7593 i == Ykey_7_eat ? action :
7594 i == Ykey_8_eat ? action :
7595 i == Ylenses_eat ? action :
7596 i == Ymagnify_eat ? action :
7597 i == Ygrass_eat ? action :
7598 i == Ydirt_eat ? action :
7599 i == Xsand_stonein_1 ? action :
7600 i == Xsand_stonein_2 ? action :
7601 i == Xsand_stonein_3 ? action :
7602 i == Xsand_stonein_4 ? action :
7603 i == Xsand_stoneout_1 ? action :
7604 i == Xsand_stoneout_2 ? action :
7605 i == Xboom_android ? ACTION_EXPLODING :
7606 action_exploding ? ACTION_EXPLODING :
7607 action_active ? action :
7608 action_other ? action :
7610 int graphic = (el_act_dir2img(effective_element, effective_action,
7612 int crumbled = (el_act_dir2crm(effective_element, effective_action,
7614 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7615 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7616 boolean has_action_graphics = (graphic != base_graphic);
7617 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7618 struct GraphicInfo *g = &graphic_info[graphic];
7619 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7622 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
7623 boolean special_animation = (action != ACTION_DEFAULT &&
7624 g->anim_frames == 3 &&
7625 g->anim_delay == 2 &&
7626 g->anim_mode & ANIM_LINEAR);
7627 int sync_frame = (i == Xdrip_stretch ? 7 :
7628 i == Xdrip_stretchB ? 7 :
7629 i == Ydrip_s2 ? j + 8 :
7630 i == Ydrip_s2B ? j + 8 :
7639 i == Xfake_acid_1 ? 0 :
7640 i == Xfake_acid_2 ? 10 :
7641 i == Xfake_acid_3 ? 20 :
7642 i == Xfake_acid_4 ? 30 :
7643 i == Xfake_acid_5 ? 40 :
7644 i == Xfake_acid_6 ? 50 :
7645 i == Xfake_acid_7 ? 60 :
7646 i == Xfake_acid_8 ? 70 :
7648 i == Xball_2B ? j + 8 :
7649 i == Yball_eat ? j + 1 :
7650 i == Ykey_1_eat ? j + 1 :
7651 i == Ykey_2_eat ? j + 1 :
7652 i == Ykey_3_eat ? j + 1 :
7653 i == Ykey_4_eat ? j + 1 :
7654 i == Ykey_5_eat ? j + 1 :
7655 i == Ykey_6_eat ? j + 1 :
7656 i == Ykey_7_eat ? j + 1 :
7657 i == Ykey_8_eat ? j + 1 :
7658 i == Ylenses_eat ? j + 1 :
7659 i == Ymagnify_eat ? j + 1 :
7660 i == Ygrass_eat ? j + 1 :
7661 i == Ydirt_eat ? j + 1 :
7662 i == Xamoeba_1 ? 0 :
7663 i == Xamoeba_2 ? 1 :
7664 i == Xamoeba_3 ? 2 :
7665 i == Xamoeba_4 ? 3 :
7666 i == Xamoeba_5 ? 0 :
7667 i == Xamoeba_6 ? 1 :
7668 i == Xamoeba_7 ? 2 :
7669 i == Xamoeba_8 ? 3 :
7670 i == Xexit_2 ? j + 8 :
7671 i == Xexit_3 ? j + 16 :
7672 i == Xdynamite_1 ? 0 :
7673 i == Xdynamite_2 ? 8 :
7674 i == Xdynamite_3 ? 16 :
7675 i == Xdynamite_4 ? 24 :
7676 i == Xsand_stonein_1 ? j + 1 :
7677 i == Xsand_stonein_2 ? j + 9 :
7678 i == Xsand_stonein_3 ? j + 17 :
7679 i == Xsand_stonein_4 ? j + 25 :
7680 i == Xsand_stoneout_1 && j == 0 ? 0 :
7681 i == Xsand_stoneout_1 && j == 1 ? 0 :
7682 i == Xsand_stoneout_1 && j == 2 ? 1 :
7683 i == Xsand_stoneout_1 && j == 3 ? 2 :
7684 i == Xsand_stoneout_1 && j == 4 ? 2 :
7685 i == Xsand_stoneout_1 && j == 5 ? 3 :
7686 i == Xsand_stoneout_1 && j == 6 ? 4 :
7687 i == Xsand_stoneout_1 && j == 7 ? 4 :
7688 i == Xsand_stoneout_2 && j == 0 ? 5 :
7689 i == Xsand_stoneout_2 && j == 1 ? 6 :
7690 i == Xsand_stoneout_2 && j == 2 ? 7 :
7691 i == Xsand_stoneout_2 && j == 3 ? 8 :
7692 i == Xsand_stoneout_2 && j == 4 ? 9 :
7693 i == Xsand_stoneout_2 && j == 5 ? 11 :
7694 i == Xsand_stoneout_2 && j == 6 ? 13 :
7695 i == Xsand_stoneout_2 && j == 7 ? 15 :
7696 i == Xboom_bug && j == 1 ? 2 :
7697 i == Xboom_bug && j == 2 ? 2 :
7698 i == Xboom_bug && j == 3 ? 4 :
7699 i == Xboom_bug && j == 4 ? 4 :
7700 i == Xboom_bug && j == 5 ? 2 :
7701 i == Xboom_bug && j == 6 ? 2 :
7702 i == Xboom_bug && j == 7 ? 0 :
7703 i == Xboom_bomb && j == 1 ? 2 :
7704 i == Xboom_bomb && j == 2 ? 2 :
7705 i == Xboom_bomb && j == 3 ? 4 :
7706 i == Xboom_bomb && j == 4 ? 4 :
7707 i == Xboom_bomb && j == 5 ? 2 :
7708 i == Xboom_bomb && j == 6 ? 2 :
7709 i == Xboom_bomb && j == 7 ? 0 :
7710 i == Xboom_android && j == 7 ? 6 :
7711 i == Xboom_1 && j == 1 ? 2 :
7712 i == Xboom_1 && j == 2 ? 2 :
7713 i == Xboom_1 && j == 3 ? 4 :
7714 i == Xboom_1 && j == 4 ? 4 :
7715 i == Xboom_1 && j == 5 ? 6 :
7716 i == Xboom_1 && j == 6 ? 6 :
7717 i == Xboom_1 && j == 7 ? 8 :
7718 i == Xboom_2 && j == 0 ? 8 :
7719 i == Xboom_2 && j == 1 ? 8 :
7720 i == Xboom_2 && j == 2 ? 10 :
7721 i == Xboom_2 && j == 3 ? 10 :
7722 i == Xboom_2 && j == 4 ? 10 :
7723 i == Xboom_2 && j == 5 ? 12 :
7724 i == Xboom_2 && j == 6 ? 12 :
7725 i == Xboom_2 && j == 7 ? 12 :
7726 special_animation && j == 4 ? 3 :
7727 effective_action != action ? 0 :
7731 Bitmap *debug_bitmap = g_em->bitmap;
7732 int debug_src_x = g_em->src_x;
7733 int debug_src_y = g_em->src_y;
7736 int frame = getAnimationFrame(g->anim_frames,
7739 g->anim_start_frame,
7742 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
7743 g->double_movement && is_backside);
7745 g_em->bitmap = src_bitmap;
7746 g_em->src_x = src_x;
7747 g_em->src_y = src_y;
7748 g_em->src_offset_x = 0;
7749 g_em->src_offset_y = 0;
7750 g_em->dst_offset_x = 0;
7751 g_em->dst_offset_y = 0;
7752 g_em->width = TILEX;
7753 g_em->height = TILEY;
7755 g_em->preserve_background = FALSE;
7757 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
7760 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
7761 effective_action == ACTION_MOVING ||
7762 effective_action == ACTION_PUSHING ||
7763 effective_action == ACTION_EATING)) ||
7764 (!has_action_graphics && (effective_action == ACTION_FILLING ||
7765 effective_action == ACTION_EMPTYING)))
7768 (effective_action == ACTION_FALLING ||
7769 effective_action == ACTION_FILLING ||
7770 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
7771 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
7772 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
7773 int num_steps = (i == Ydrip_s1 ? 16 :
7774 i == Ydrip_s1B ? 16 :
7775 i == Ydrip_s2 ? 16 :
7776 i == Ydrip_s2B ? 16 :
7777 i == Xsand_stonein_1 ? 32 :
7778 i == Xsand_stonein_2 ? 32 :
7779 i == Xsand_stonein_3 ? 32 :
7780 i == Xsand_stonein_4 ? 32 :
7781 i == Xsand_stoneout_1 ? 16 :
7782 i == Xsand_stoneout_2 ? 16 : 8);
7783 int cx = ABS(dx) * (TILEX / num_steps);
7784 int cy = ABS(dy) * (TILEY / num_steps);
7785 int step_frame = (i == Ydrip_s2 ? j + 8 :
7786 i == Ydrip_s2B ? j + 8 :
7787 i == Xsand_stonein_2 ? j + 8 :
7788 i == Xsand_stonein_3 ? j + 16 :
7789 i == Xsand_stonein_4 ? j + 24 :
7790 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
7791 int step = (is_backside ? step_frame : num_steps - step_frame);
7793 if (is_backside) /* tile where movement starts */
7795 if (dx < 0 || dy < 0)
7797 g_em->src_offset_x = cx * step;
7798 g_em->src_offset_y = cy * step;
7802 g_em->dst_offset_x = cx * step;
7803 g_em->dst_offset_y = cy * step;
7806 else /* tile where movement ends */
7808 if (dx < 0 || dy < 0)
7810 g_em->dst_offset_x = cx * step;
7811 g_em->dst_offset_y = cy * step;
7815 g_em->src_offset_x = cx * step;
7816 g_em->src_offset_y = cy * step;
7820 g_em->width = TILEX - cx * step;
7821 g_em->height = TILEY - cy * step;
7824 /* create unique graphic identifier to decide if tile must be redrawn */
7825 /* bit 31 - 16 (16 bit): EM style graphic
7826 bit 15 - 12 ( 4 bit): EM style frame
7827 bit 11 - 6 ( 6 bit): graphic width
7828 bit 5 - 0 ( 6 bit): graphic height */
7829 g_em->unique_identifier =
7830 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
7834 /* skip check for EMC elements not contained in original EMC artwork */
7835 if (element == EL_EMC_FAKE_ACID)
7838 if (g_em->bitmap != debug_bitmap ||
7839 g_em->src_x != debug_src_x ||
7840 g_em->src_y != debug_src_y ||
7841 g_em->src_offset_x != 0 ||
7842 g_em->src_offset_y != 0 ||
7843 g_em->dst_offset_x != 0 ||
7844 g_em->dst_offset_y != 0 ||
7845 g_em->width != TILEX ||
7846 g_em->height != TILEY)
7848 static int last_i = -1;
7856 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
7857 i, element, element_info[element].token_name,
7858 element_action_info[effective_action].suffix, direction);
7860 if (element != effective_element)
7861 printf(" [%d ('%s')]",
7863 element_info[effective_element].token_name);
7867 if (g_em->bitmap != debug_bitmap)
7868 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
7869 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
7871 if (g_em->src_x != debug_src_x ||
7872 g_em->src_y != debug_src_y)
7873 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
7874 j, (is_backside ? 'B' : 'F'),
7875 g_em->src_x, g_em->src_y,
7876 g_em->src_x / 32, g_em->src_y / 32,
7877 debug_src_x, debug_src_y,
7878 debug_src_x / 32, debug_src_y / 32);
7880 if (g_em->src_offset_x != 0 ||
7881 g_em->src_offset_y != 0 ||
7882 g_em->dst_offset_x != 0 ||
7883 g_em->dst_offset_y != 0)
7884 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
7886 g_em->src_offset_x, g_em->src_offset_y,
7887 g_em->dst_offset_x, g_em->dst_offset_y);
7889 if (g_em->width != TILEX ||
7890 g_em->height != TILEY)
7891 printf(" %d (%d): size %d,%d should be %d,%d\n",
7893 g_em->width, g_em->height, TILEX, TILEY);
7895 num_em_gfx_errors++;
7902 for (i = 0; i < TILE_MAX; i++)
7904 for (j = 0; j < 8; j++)
7906 int element = object_mapping[i].element_rnd;
7907 int action = object_mapping[i].action;
7908 int direction = object_mapping[i].direction;
7909 boolean is_backside = object_mapping[i].is_backside;
7910 int graphic_action = el_act_dir2img(element, action, direction);
7911 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
7913 if ((action == ACTION_SMASHED_BY_ROCK ||
7914 action == ACTION_SMASHED_BY_SPRING ||
7915 action == ACTION_EATING) &&
7916 graphic_action == graphic_default)
7918 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
7919 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
7920 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
7921 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
7924 /* no separate animation for "smashed by rock" -- use rock instead */
7925 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7926 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
7928 g_em->bitmap = g_xx->bitmap;
7929 g_em->src_x = g_xx->src_x;
7930 g_em->src_y = g_xx->src_y;
7931 g_em->src_offset_x = g_xx->src_offset_x;
7932 g_em->src_offset_y = g_xx->src_offset_y;
7933 g_em->dst_offset_x = g_xx->dst_offset_x;
7934 g_em->dst_offset_y = g_xx->dst_offset_y;
7935 g_em->width = g_xx->width;
7936 g_em->height = g_xx->height;
7937 g_em->unique_identifier = g_xx->unique_identifier;
7940 g_em->preserve_background = TRUE;
7945 for (p = 0; p < MAX_PLAYERS; p++)
7947 for (i = 0; i < SPR_MAX; i++)
7949 int element = player_mapping[p][i].element_rnd;
7950 int action = player_mapping[p][i].action;
7951 int direction = player_mapping[p][i].direction;
7953 for (j = 0; j < 8; j++)
7955 int effective_element = element;
7956 int effective_action = action;
7957 int graphic = (direction == MV_NONE ?
7958 el_act2img(effective_element, effective_action) :
7959 el_act_dir2img(effective_element, effective_action,
7961 struct GraphicInfo *g = &graphic_info[graphic];
7962 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
7968 Bitmap *debug_bitmap = g_em->bitmap;
7969 int debug_src_x = g_em->src_x;
7970 int debug_src_y = g_em->src_y;
7973 int frame = getAnimationFrame(g->anim_frames,
7976 g->anim_start_frame,
7979 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
7981 g_em->bitmap = src_bitmap;
7982 g_em->src_x = src_x;
7983 g_em->src_y = src_y;
7984 g_em->src_offset_x = 0;
7985 g_em->src_offset_y = 0;
7986 g_em->dst_offset_x = 0;
7987 g_em->dst_offset_y = 0;
7988 g_em->width = TILEX;
7989 g_em->height = TILEY;
7993 /* skip check for EMC elements not contained in original EMC artwork */
7994 if (element == EL_PLAYER_3 ||
7995 element == EL_PLAYER_4)
7998 if (g_em->bitmap != debug_bitmap ||
7999 g_em->src_x != debug_src_x ||
8000 g_em->src_y != debug_src_y)
8002 static int last_i = -1;
8010 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
8011 p, i, element, element_info[element].token_name,
8012 element_action_info[effective_action].suffix, direction);
8014 if (element != effective_element)
8015 printf(" [%d ('%s')]",
8017 element_info[effective_element].token_name);
8021 if (g_em->bitmap != debug_bitmap)
8022 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
8023 j, (int)(g_em->bitmap), (int)(debug_bitmap));
8025 if (g_em->src_x != debug_src_x ||
8026 g_em->src_y != debug_src_y)
8027 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
8029 g_em->src_x, g_em->src_y,
8030 g_em->src_x / 32, g_em->src_y / 32,
8031 debug_src_x, debug_src_y,
8032 debug_src_x / 32, debug_src_y / 32);
8034 num_em_gfx_errors++;
8044 printf("::: [%d errors found]\n", num_em_gfx_errors);
8050 void CheckSaveEngineSnapshot_EM(byte action[MAX_PLAYERS], int frame,
8051 boolean any_player_moving,
8052 boolean any_player_snapping,
8053 boolean any_player_dropping)
8055 static boolean player_was_waiting = TRUE;
8057 if (frame == 0 && !any_player_dropping)
8059 if (!player_was_waiting)
8061 if (!SaveEngineSnapshotToList())
8064 player_was_waiting = TRUE;
8067 else if (any_player_moving || any_player_snapping || any_player_dropping)
8069 player_was_waiting = FALSE;
8073 void CheckSaveEngineSnapshot_SP(boolean murphy_is_waiting,
8074 boolean murphy_is_dropping)
8076 static boolean player_was_waiting = TRUE;
8078 if (murphy_is_waiting)
8080 if (!player_was_waiting)
8082 if (!SaveEngineSnapshotToList())
8085 player_was_waiting = TRUE;
8090 player_was_waiting = FALSE;
8094 void CheckSingleStepMode_EM(byte action[MAX_PLAYERS], int frame,
8095 boolean any_player_moving,
8096 boolean any_player_snapping,
8097 boolean any_player_dropping)
8099 if (tape.single_step && tape.recording && !tape.pausing)
8100 if (frame == 0 && !any_player_dropping)
8101 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
8103 CheckSaveEngineSnapshot_EM(action, frame, any_player_moving,
8104 any_player_snapping, any_player_dropping);
8107 void CheckSingleStepMode_SP(boolean murphy_is_waiting,
8108 boolean murphy_is_dropping)
8110 if (tape.single_step && tape.recording && !tape.pausing)
8111 if (murphy_is_waiting)
8112 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
8114 CheckSaveEngineSnapshot_SP(murphy_is_waiting, murphy_is_dropping);
8117 void getGraphicSource_SP(struct GraphicInfo_SP *g_sp,
8118 int graphic, int sync_frame, int x, int y)
8120 int frame = getGraphicAnimationFrame(graphic, sync_frame);
8122 getGraphicSource(graphic, frame, &g_sp->bitmap, &g_sp->src_x, &g_sp->src_y);
8125 boolean isNextAnimationFrame_SP(int graphic, int sync_frame)
8127 return (IS_NEXT_FRAME(sync_frame, graphic));
8130 int getGraphicInfo_Delay(int graphic)
8132 return graphic_info[graphic].anim_delay;
8135 void PlayMenuSoundExt(int sound)
8137 if (sound == SND_UNDEFINED)
8140 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8141 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8144 if (IS_LOOP_SOUND(sound))
8145 PlaySoundLoop(sound);
8150 void PlayMenuSound()
8152 PlayMenuSoundExt(menu.sound[game_status]);
8155 void PlayMenuSoundStereo(int sound, int stereo_position)
8157 if (sound == SND_UNDEFINED)
8160 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8161 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8164 if (IS_LOOP_SOUND(sound))
8165 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
8167 PlaySoundStereo(sound, stereo_position);
8170 void PlayMenuSoundIfLoopExt(int sound)
8172 if (sound == SND_UNDEFINED)
8175 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8176 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8179 if (IS_LOOP_SOUND(sound))
8180 PlaySoundLoop(sound);
8183 void PlayMenuSoundIfLoop()
8185 PlayMenuSoundIfLoopExt(menu.sound[game_status]);
8188 void PlayMenuMusicExt(int music)
8190 if (music == MUS_UNDEFINED)
8193 if (!setup.sound_music)
8199 void PlayMenuMusic()
8201 PlayMenuMusicExt(menu.music[game_status]);
8204 void PlaySoundActivating()
8207 PlaySound(SND_MENU_ITEM_ACTIVATING);
8211 void PlaySoundSelecting()
8214 PlaySound(SND_MENU_ITEM_SELECTING);
8218 void ToggleFullscreenOrChangeWindowScalingIfNeeded()
8220 boolean change_fullscreen = (setup.fullscreen !=
8221 video.fullscreen_enabled);
8222 boolean change_window_scaling_percent = (!video.fullscreen_enabled &&
8223 setup.window_scaling_percent !=
8224 video.window_scaling_percent);
8226 if (change_window_scaling_percent && video.fullscreen_enabled)
8229 if (!change_window_scaling_percent && !video.fullscreen_available)
8232 #if defined(TARGET_SDL2)
8233 if (change_window_scaling_percent)
8235 SDLSetWindowScaling(setup.window_scaling_percent);
8239 else if (change_fullscreen)
8241 SDLSetWindowFullscreen(setup.fullscreen);
8243 /* set setup value according to successfully changed fullscreen mode */
8244 setup.fullscreen = video.fullscreen_enabled;
8250 if (change_fullscreen ||
8251 change_window_scaling_percent)
8253 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
8255 /* save backbuffer content which gets lost when toggling fullscreen mode */
8256 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8258 if (change_window_scaling_percent)
8260 /* keep window mode, but change window scaling */
8261 video.fullscreen_enabled = TRUE; /* force new window scaling */
8264 /* toggle fullscreen */
8265 ChangeVideoModeIfNeeded(setup.fullscreen);
8267 /* set setup value according to successfully changed fullscreen mode */
8268 setup.fullscreen = video.fullscreen_enabled;
8270 /* restore backbuffer content from temporary backbuffer backup bitmap */
8271 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8273 FreeBitmap(tmp_backbuffer);
8275 /* update visible window/screen */
8276 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8280 void JoinRectangles(int *x, int *y, int *width, int *height,
8281 int x2, int y2, int width2, int height2)
8283 // do not join with "off-screen" rectangle
8284 if (x2 == -1 || y2 == -1)
8289 *width = MAX(*width, width2);
8290 *height = MAX(*height, height2);
8293 void SetAnimStatus(int anim_status_new)
8295 if (anim_status_new == GAME_MODE_MAIN)
8296 anim_status_new = GAME_MODE_PSEUDO_MAINONLY;
8298 global.anim_status_next = anim_status_new;
8300 // directly set screen modes that are entered without fading
8301 if ((global.anim_status == GAME_MODE_PSEUDO_MAINONLY &&
8302 global.anim_status_next == GAME_MODE_PSEUDO_TYPENAME) ||
8303 (global.anim_status == GAME_MODE_PSEUDO_TYPENAME &&
8304 global.anim_status_next == GAME_MODE_PSEUDO_MAINONLY))
8305 global.anim_status = global.anim_status_next;
8308 void SetGameStatus(int game_status_new)
8310 game_status = game_status_new;
8312 SetAnimStatus(game_status_new);
8315 void SetFontStatus(int game_status_new)
8317 static int last_game_status = -1;
8319 if (game_status_new != -1)
8321 // set game status for font use after storing last game status
8322 last_game_status = game_status;
8323 game_status = game_status_new;
8327 // reset game status after font use from last stored game status
8328 game_status = last_game_status;
8332 void ResetFontStatus()
8337 void ChangeViewportPropertiesIfNeeded()
8339 int gfx_game_mode = game_status;
8340 int gfx_game_mode2 = (game_status == GAME_MODE_EDITOR ? GAME_MODE_DEFAULT :
8342 struct RectWithBorder *vp_window = &viewport.window[gfx_game_mode];
8343 struct RectWithBorder *vp_playfield = &viewport.playfield[gfx_game_mode];
8344 struct RectWithBorder *vp_door_1 = &viewport.door_1[gfx_game_mode];
8345 struct RectWithBorder *vp_door_2 = &viewport.door_2[gfx_game_mode2];
8346 struct RectWithBorder *vp_door_3 = &viewport.door_2[GAME_MODE_EDITOR];
8347 int new_win_xsize = vp_window->width;
8348 int new_win_ysize = vp_window->height;
8349 int border_size = vp_playfield->border_size;
8350 int new_sx = vp_playfield->x + border_size;
8351 int new_sy = vp_playfield->y + border_size;
8352 int new_sxsize = vp_playfield->width - 2 * border_size;
8353 int new_sysize = vp_playfield->height - 2 * border_size;
8354 int new_real_sx = vp_playfield->x;
8355 int new_real_sy = vp_playfield->y;
8356 int new_full_sxsize = vp_playfield->width;
8357 int new_full_sysize = vp_playfield->height;
8358 int new_dx = vp_door_1->x;
8359 int new_dy = vp_door_1->y;
8360 int new_dxsize = vp_door_1->width;
8361 int new_dysize = vp_door_1->height;
8362 int new_vx = vp_door_2->x;
8363 int new_vy = vp_door_2->y;
8364 int new_vxsize = vp_door_2->width;
8365 int new_vysize = vp_door_2->height;
8366 int new_ex = vp_door_3->x;
8367 int new_ey = vp_door_3->y;
8368 int new_exsize = vp_door_3->width;
8369 int new_eysize = vp_door_3->height;
8370 int new_tilesize_var =
8371 (setup.small_game_graphics ? MINI_TILESIZE : game.tile_size);
8373 int tilesize = (gfx_game_mode == GAME_MODE_PLAYING ? new_tilesize_var :
8374 gfx_game_mode == GAME_MODE_EDITOR ? MINI_TILESIZE : TILESIZE);
8375 int new_scr_fieldx = new_sxsize / tilesize;
8376 int new_scr_fieldy = new_sysize / tilesize;
8377 int new_scr_fieldx_buffers = new_sxsize / new_tilesize_var;
8378 int new_scr_fieldy_buffers = new_sysize / new_tilesize_var;
8379 boolean init_gfx_buffers = FALSE;
8380 boolean init_video_buffer = FALSE;
8381 boolean init_gadgets_and_anims = FALSE;
8382 boolean init_em_graphics = FALSE;
8384 if (new_win_xsize != WIN_XSIZE ||
8385 new_win_ysize != WIN_YSIZE)
8387 WIN_XSIZE = new_win_xsize;
8388 WIN_YSIZE = new_win_ysize;
8390 init_video_buffer = TRUE;
8391 init_gfx_buffers = TRUE;
8392 init_gadgets_and_anims = TRUE;
8394 // printf("::: video: init_video_buffer, init_gfx_buffers\n");
8397 if (new_scr_fieldx != SCR_FIELDX ||
8398 new_scr_fieldy != SCR_FIELDY)
8400 /* this always toggles between MAIN and GAME when using small tile size */
8402 SCR_FIELDX = new_scr_fieldx;
8403 SCR_FIELDY = new_scr_fieldy;
8405 // printf("::: new_scr_fieldx != SCR_FIELDX ...\n");
8416 new_sxsize != SXSIZE ||
8417 new_sysize != SYSIZE ||
8418 new_dxsize != DXSIZE ||
8419 new_dysize != DYSIZE ||
8420 new_vxsize != VXSIZE ||
8421 new_vysize != VYSIZE ||
8422 new_exsize != EXSIZE ||
8423 new_eysize != EYSIZE ||
8424 new_real_sx != REAL_SX ||
8425 new_real_sy != REAL_SY ||
8426 new_full_sxsize != FULL_SXSIZE ||
8427 new_full_sysize != FULL_SYSIZE ||
8428 new_tilesize_var != TILESIZE_VAR
8431 // ------------------------------------------------------------------------
8432 // determine next fading area for changed viewport definitions
8433 // ------------------------------------------------------------------------
8435 // start with current playfield area (default fading area)
8438 FADE_SXSIZE = FULL_SXSIZE;
8439 FADE_SYSIZE = FULL_SYSIZE;
8441 // add new playfield area if position or size has changed
8442 if (new_real_sx != REAL_SX || new_real_sy != REAL_SY ||
8443 new_full_sxsize != FULL_SXSIZE || new_full_sysize != FULL_SYSIZE)
8445 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
8446 new_real_sx, new_real_sy, new_full_sxsize,new_full_sysize);
8449 // add current and new door 1 area if position or size has changed
8450 if (new_dx != DX || new_dy != DY ||
8451 new_dxsize != DXSIZE || new_dysize != DYSIZE)
8453 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
8454 DX, DY, DXSIZE, DYSIZE);
8455 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
8456 new_dx, new_dy, new_dxsize, new_dysize);
8459 // add current and new door 2 area if position or size has changed
8460 if (new_dx != VX || new_dy != VY ||
8461 new_dxsize != VXSIZE || new_dysize != VYSIZE)
8463 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
8464 VX, VY, VXSIZE, VYSIZE);
8465 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
8466 new_vx, new_vy, new_vxsize, new_vysize);
8469 // ------------------------------------------------------------------------
8470 // handle changed tile size
8471 // ------------------------------------------------------------------------
8473 if (new_tilesize_var != TILESIZE_VAR)
8475 // printf("::: new_tilesize_var != TILESIZE_VAR\n");
8477 // changing tile size invalidates scroll values of engine snapshots
8478 FreeEngineSnapshotSingle();
8480 // changing tile size requires update of graphic mapping for EM engine
8481 init_em_graphics = TRUE;
8492 SXSIZE = new_sxsize;
8493 SYSIZE = new_sysize;
8494 DXSIZE = new_dxsize;
8495 DYSIZE = new_dysize;
8496 VXSIZE = new_vxsize;
8497 VYSIZE = new_vysize;
8498 EXSIZE = new_exsize;
8499 EYSIZE = new_eysize;
8500 REAL_SX = new_real_sx;
8501 REAL_SY = new_real_sy;
8502 FULL_SXSIZE = new_full_sxsize;
8503 FULL_SYSIZE = new_full_sysize;
8504 TILESIZE_VAR = new_tilesize_var;
8506 init_gfx_buffers = TRUE;
8507 init_gadgets_and_anims = TRUE;
8509 // printf("::: viewports: init_gfx_buffers\n");
8510 // printf("::: viewports: init_gadgets_and_anims\n");
8513 if (init_gfx_buffers)
8515 // printf("::: init_gfx_buffers\n");
8517 SCR_FIELDX = new_scr_fieldx_buffers;
8518 SCR_FIELDY = new_scr_fieldy_buffers;
8522 SCR_FIELDX = new_scr_fieldx;
8523 SCR_FIELDY = new_scr_fieldy;
8525 SetDrawDeactivationMask(REDRAW_NONE);
8526 SetDrawBackgroundMask(REDRAW_FIELD);
8529 if (init_video_buffer)
8531 // printf("::: init_video_buffer\n");
8533 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
8534 InitImageTextures();
8537 if (init_gadgets_and_anims)
8539 // printf("::: init_gadgets_and_anims\n");
8542 InitGlobalAnimations();
8545 if (init_em_graphics)
8547 InitGraphicInfo_EM();