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 int correctLevelPosX_EM(int lx)
198 lx -= (BorderElement != EL_EMPTY ? 1 : 0);
203 int correctLevelPosY_EM(int ly)
206 ly -= (BorderElement != EL_EMPTY ? 1 : 0);
211 static int getFieldbufferOffsetX_RND()
213 int full_lev_fieldx = lev_fieldx + (BorderElement != EL_EMPTY ? 2 : 0);
214 int dx = (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
215 int dx_var = dx * TILESIZE_VAR / TILESIZE;
218 if (EVEN(SCR_FIELDX))
220 int ffx = (scroll_x - SBX_Left) * TILEX_VAR + dx_var;
222 if (ffx < SBX_Right * TILEX_VAR + TILEX_VAR / 2 + TILEX_VAR)
223 fx += dx_var - MIN(ffx, TILEX_VAR / 2) + TILEX_VAR;
225 fx += (dx_var > 0 ? TILEX_VAR : 0);
232 if (full_lev_fieldx <= SCR_FIELDX)
234 if (EVEN(SCR_FIELDX))
235 fx = 2 * TILEX_VAR - (ODD(lev_fieldx) ? TILEX_VAR / 2 : 0);
237 fx = 2 * TILEX_VAR - (EVEN(lev_fieldx) ? TILEX_VAR / 2 : 0);
243 static int getFieldbufferOffsetY_RND()
245 int full_lev_fieldy = lev_fieldy + (BorderElement != EL_EMPTY ? 2 : 0);
246 int dy = (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
247 int dy_var = dy * TILESIZE_VAR / TILESIZE;
250 if (EVEN(SCR_FIELDY))
252 int ffy = (scroll_y - SBY_Upper) * TILEY_VAR + dy_var;
254 if (ffy < SBY_Lower * TILEY_VAR + TILEY_VAR / 2 + TILEY_VAR)
255 fy += dy_var - MIN(ffy, TILEY_VAR / 2) + TILEY_VAR;
257 fy += (dy_var > 0 ? TILEY_VAR : 0);
264 if (full_lev_fieldy <= SCR_FIELDY)
266 if (EVEN(SCR_FIELDY))
267 fy = 2 * TILEY_VAR - (ODD(lev_fieldy) ? TILEY_VAR / 2 : 0);
269 fy = 2 * TILEY_VAR - (EVEN(lev_fieldy) ? TILEY_VAR / 2 : 0);
275 static int getLevelFromScreenX_RND(int sx)
277 int fx = getFieldbufferOffsetX_RND();
280 int lx = LEVELX((px + dx) / TILESIZE_VAR);
285 static int getLevelFromScreenY_RND(int sy)
287 int fy = getFieldbufferOffsetY_RND();
290 int ly = LEVELY((py + dy) / TILESIZE_VAR);
295 static int getLevelFromScreenX_EM(int sx)
297 int level_xsize = level.native_em_level->lev->width;
298 int full_xsize = level_xsize * TILESIZE_VAR;
300 sx -= (full_xsize < SXSIZE ? (SXSIZE - full_xsize) / 2 : 0);
302 int fx = getFieldbufferOffsetX_EM();
305 int lx = LEVELX((px + dx) / TILESIZE_VAR);
307 lx = correctLevelPosX_EM(lx);
312 static int getLevelFromScreenY_EM(int sy)
314 int level_ysize = level.native_em_level->lev->height;
315 int full_ysize = level_ysize * TILESIZE_VAR;
317 sy -= (full_ysize < SYSIZE ? (SYSIZE - full_ysize) / 2 : 0);
319 int fy = getFieldbufferOffsetY_EM();
322 int ly = LEVELY((py + dy) / TILESIZE_VAR);
324 ly = correctLevelPosY_EM(ly);
329 static int getLevelFromScreenX_SP(int sx)
331 int menBorder = setup.sp_show_border_elements;
332 int level_xsize = level.native_sp_level->width;
333 int full_xsize = (level_xsize - (menBorder ? 0 : 1)) * TILESIZE_VAR;
335 sx += (full_xsize < SXSIZE ? (SXSIZE - full_xsize) / 2 : 0);
337 int fx = getFieldbufferOffsetX_SP();
340 int lx = LEVELX((px + dx) / TILESIZE_VAR);
345 static int getLevelFromScreenY_SP(int sy)
347 int menBorder = setup.sp_show_border_elements;
348 int level_ysize = level.native_sp_level->height;
349 int full_ysize = (level_ysize - (menBorder ? 0 : 1)) * TILESIZE_VAR;
351 sy += (full_ysize < SYSIZE ? (SYSIZE - full_ysize) / 2 : 0);
353 int fy = getFieldbufferOffsetY_SP();
356 int ly = LEVELY((py + dy) / TILESIZE_VAR);
361 int getLevelFromScreenX(int x)
363 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
364 return getLevelFromScreenX_EM(x);
365 if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
366 return getLevelFromScreenX_SP(x);
368 return getLevelFromScreenX_RND(x);
371 int getLevelFromScreenY(int y)
373 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
374 return getLevelFromScreenY_EM(y);
375 if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
376 return getLevelFromScreenY_SP(y);
378 return getLevelFromScreenY_RND(y);
381 void DumpTile(int x, int y)
386 printf_line("-", 79);
387 printf("Field Info: SCREEN(%d, %d), LEVEL(%d, %d)\n", sx, sy, x, y);
388 printf_line("-", 79);
390 if (!IN_LEV_FIELD(x, y))
392 printf("(not in level field)\n");
398 printf(" Feld: %d\t['%s']\n", Feld[x][y],
399 element_info[Feld[x][y]].token_name);
400 printf(" Back: %s\n", print_if_not_empty(Back[x][y]));
401 printf(" Store: %s\n", print_if_not_empty(Store[x][y]));
402 printf(" Store2: %s\n", print_if_not_empty(Store2[x][y]));
403 printf(" StorePlayer: %s\n", print_if_not_empty(StorePlayer[x][y]));
404 printf(" MovPos: %d\n", MovPos[x][y]);
405 printf(" MovDir: %d\n", MovDir[x][y]);
406 printf(" MovDelay: %d\n", MovDelay[x][y]);
407 printf(" ChangeDelay: %d\n", ChangeDelay[x][y]);
408 printf(" CustomValue: %d\n", CustomValue[x][y]);
409 printf(" GfxElement: %d\n", GfxElement[x][y]);
410 printf(" GfxAction: %d\n", GfxAction[x][y]);
411 printf(" GfxFrame: %d [%d]\n", GfxFrame[x][y], FrameCounter);
412 printf(" Player x/y: %d, %d\n", local_player->jx, local_player->jy);
416 void DumpTileFromScreen(int sx, int sy)
418 int lx = getLevelFromScreenX(sx);
419 int ly = getLevelFromScreenY(sy);
424 void SetDrawtoField(int mode)
426 if (mode == DRAW_TO_FIELDBUFFER)
432 BX2 = SCR_FIELDX + 1;
433 BY2 = SCR_FIELDY + 1;
435 drawto_field = fieldbuffer;
437 else /* DRAW_TO_BACKBUFFER */
443 BX2 = SCR_FIELDX - 1;
444 BY2 = SCR_FIELDY - 1;
446 drawto_field = backbuffer;
450 static void RedrawPlayfield_RND()
452 if (game.envelope_active)
455 DrawLevel(REDRAW_ALL);
459 void RedrawPlayfield()
461 if (game_status != GAME_MODE_PLAYING)
464 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
465 RedrawPlayfield_EM(TRUE);
466 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
467 RedrawPlayfield_SP(TRUE);
468 else if (level.game_engine_type == GAME_ENGINE_TYPE_RND)
469 RedrawPlayfield_RND();
471 BlitScreenToBitmap(backbuffer);
473 BlitBitmap(drawto, window, gfx.sx, gfx.sy, gfx.sxsize, gfx.sysize,
477 static void DrawMaskedBorderExt_Rect(int x, int y, int width, int height,
480 Bitmap *src_bitmap = getGlobalBorderBitmapFromStatus(global.border_status);
481 Bitmap *dst_bitmap = gfx.masked_border_bitmap_ptr;
483 if (x == -1 && y == -1)
486 if (draw_target == DRAW_TO_SCREEN)
487 BlitToScreenMasked(src_bitmap, x, y, width, height, x, y);
489 BlitBitmapMasked(src_bitmap, dst_bitmap, x, y, width, height, x, y);
492 static void DrawMaskedBorderExt_FIELD(int draw_target)
494 if (global.border_status >= GAME_MODE_MAIN &&
495 global.border_status <= GAME_MODE_PLAYING &&
496 border.draw_masked[global.border_status])
497 DrawMaskedBorderExt_Rect(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
501 static void DrawMaskedBorderExt_DOOR_1(int draw_target)
503 // when drawing to backbuffer, never draw border over open doors
504 if (draw_target == DRAW_TO_BACKBUFFER &&
505 (GetDoorState() & DOOR_OPEN_1))
508 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
509 (global.border_status != GAME_MODE_EDITOR ||
510 border.draw_masked[GFX_SPECIAL_ARG_EDITOR]))
511 DrawMaskedBorderExt_Rect(DX, DY, DXSIZE, DYSIZE, draw_target);
514 static void DrawMaskedBorderExt_DOOR_2(int draw_target)
516 // when drawing to backbuffer, never draw border over open doors
517 if (draw_target == DRAW_TO_BACKBUFFER &&
518 (GetDoorState() & DOOR_OPEN_2))
521 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
522 global.border_status != GAME_MODE_EDITOR)
523 DrawMaskedBorderExt_Rect(VX, VY, VXSIZE, VYSIZE, draw_target);
526 static void DrawMaskedBorderExt_DOOR_3(int draw_target)
528 /* currently not available */
531 static void DrawMaskedBorderExt_ALL(int draw_target)
533 DrawMaskedBorderExt_FIELD(draw_target);
534 DrawMaskedBorderExt_DOOR_1(draw_target);
535 DrawMaskedBorderExt_DOOR_2(draw_target);
536 DrawMaskedBorderExt_DOOR_3(draw_target);
539 static void DrawMaskedBorderExt(int redraw_mask, int draw_target)
541 /* never draw masked screen borders on borderless screens */
542 if (global.border_status == GAME_MODE_LOADING ||
543 global.border_status == GAME_MODE_TITLE)
546 if (redraw_mask & REDRAW_ALL)
547 DrawMaskedBorderExt_ALL(draw_target);
550 if (redraw_mask & REDRAW_FIELD)
551 DrawMaskedBorderExt_FIELD(draw_target);
552 if (redraw_mask & REDRAW_DOOR_1)
553 DrawMaskedBorderExt_DOOR_1(draw_target);
554 if (redraw_mask & REDRAW_DOOR_2)
555 DrawMaskedBorderExt_DOOR_2(draw_target);
556 if (redraw_mask & REDRAW_DOOR_3)
557 DrawMaskedBorderExt_DOOR_3(draw_target);
561 void DrawMaskedBorder_FIELD()
563 DrawMaskedBorderExt_FIELD(DRAW_TO_BACKBUFFER);
566 void DrawMaskedBorder(int redraw_mask)
568 DrawMaskedBorderExt(redraw_mask, DRAW_TO_BACKBUFFER);
571 void DrawMaskedBorderToTarget(int draw_target)
573 if (draw_target == DRAW_TO_BACKBUFFER ||
574 draw_target == DRAW_TO_SCREEN)
576 DrawMaskedBorderExt(REDRAW_ALL, draw_target);
580 int last_border_status = global.border_status;
582 if (draw_target == DRAW_TO_FADE_SOURCE)
584 global.border_status = gfx.fade_border_source_status;
585 gfx.masked_border_bitmap_ptr = gfx.fade_bitmap_source;
587 else if (draw_target == DRAW_TO_FADE_TARGET)
589 global.border_status = gfx.fade_border_target_status;
590 gfx.masked_border_bitmap_ptr = gfx.fade_bitmap_target;
593 DrawMaskedBorderExt(REDRAW_ALL, draw_target);
595 global.border_status = last_border_status;
596 gfx.masked_border_bitmap_ptr = backbuffer;
600 void BlitScreenToBitmap_RND(Bitmap *target_bitmap)
602 int fx = getFieldbufferOffsetX_RND();
603 int fy = getFieldbufferOffsetY_RND();
605 BlitBitmap(drawto_field, target_bitmap, fx, fy, SXSIZE, SYSIZE, SX, SY);
608 void BlitScreenToBitmap(Bitmap *target_bitmap)
610 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
611 BlitScreenToBitmap_EM(target_bitmap);
612 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
613 BlitScreenToBitmap_SP(target_bitmap);
614 else if (level.game_engine_type == GAME_ENGINE_TYPE_RND)
615 BlitScreenToBitmap_RND(target_bitmap);
617 redraw_mask |= REDRAW_FIELD;
620 void DrawFramesPerSecond()
623 int font_nr = FONT_TEXT_2;
624 int font_width = getFontWidth(font_nr);
626 sprintf(text, "%04.1f fps", global.frames_per_second);
628 DrawTextExt(backbuffer, WIN_XSIZE - font_width * strlen(text), 0, text,
629 font_nr, BLIT_OPAQUE);
633 static void PrintFrameTimeDebugging()
635 static unsigned int last_counter = 0;
636 unsigned int counter = Counter();
637 int diff_1 = counter - last_counter;
638 int diff_2 = diff_1 - GAME_FRAME_DELAY;
640 int diff_2_cut = MIN(ABS(diff_2), diff_2_max);
641 char diff_bar[2 * diff_2_max + 5];
645 diff_bar[pos++] = (diff_2 < -diff_2_max ? '<' : ' ');
647 for (i = 0; i < diff_2_max; i++)
648 diff_bar[pos++] = (diff_2 >= 0 ? ' ' :
649 i >= diff_2_max - diff_2_cut ? '-' : ' ');
651 diff_bar[pos++] = '|';
653 for (i = 0; i < diff_2_max; i++)
654 diff_bar[pos++] = (diff_2 <= 0 ? ' ' : i < diff_2_cut ? '+' : ' ');
656 diff_bar[pos++] = (diff_2 > diff_2_max ? '>' : ' ');
658 diff_bar[pos++] = '\0';
660 Error(ERR_INFO, "%06d [%02d] [%c%02d] %s",
663 (diff_2 < 0 ? '-' : diff_2 > 0 ? '+' : ' '), ABS(diff_2),
666 last_counter = counter;
670 static int unifiedRedrawMask(int mask)
672 if (mask & REDRAW_ALL)
675 if (mask & REDRAW_FIELD && mask & REDRAW_DOORS)
681 static boolean equalRedrawMasks(int mask_1, int mask_2)
683 return unifiedRedrawMask(mask_1) == unifiedRedrawMask(mask_2);
688 static int last_redraw_mask = REDRAW_NONE;
690 // force screen redraw in every frame to continue drawing global animations
691 // (but always use the last redraw mask to prevent unwanted side effects)
692 if (redraw_mask == REDRAW_NONE)
693 redraw_mask = last_redraw_mask;
695 last_redraw_mask = redraw_mask;
698 // masked border now drawn immediately when blitting backbuffer to window
700 // draw masked border to all viewports, if defined
701 DrawMaskedBorder(redraw_mask);
704 // draw frames per second (only if debug mode is enabled)
705 if (redraw_mask & REDRAW_FPS)
706 DrawFramesPerSecond();
708 // remove playfield redraw before potentially merging with doors redraw
709 if (DrawingDeactivated(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE))
710 redraw_mask &= ~REDRAW_FIELD;
712 // redraw complete window if both playfield and (some) doors need redraw
713 if (redraw_mask & REDRAW_FIELD && redraw_mask & REDRAW_DOORS)
714 redraw_mask = REDRAW_ALL;
716 /* although redrawing the whole window would be fine for normal gameplay,
717 being able to only redraw the playfield is required for deactivating
718 certain drawing areas (mainly playfield) to work, which is needed for
719 warp-forward to be fast enough (by skipping redraw of most frames) */
721 if (redraw_mask & REDRAW_ALL)
723 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
725 else if (redraw_mask & REDRAW_FIELD)
727 BlitBitmap(backbuffer, window,
728 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
730 else if (redraw_mask & REDRAW_DOORS)
732 // merge door areas to prevent calling screen redraw more than once
738 if (redraw_mask & REDRAW_DOOR_1)
742 x2 = MAX(x2, DX + DXSIZE);
743 y2 = MAX(y2, DY + DYSIZE);
746 if (redraw_mask & REDRAW_DOOR_2)
750 x2 = MAX(x2, VX + VXSIZE);
751 y2 = MAX(y2, VY + VYSIZE);
754 if (redraw_mask & REDRAW_DOOR_3)
758 x2 = MAX(x2, EX + EXSIZE);
759 y2 = MAX(y2, EY + EYSIZE);
762 // make sure that at least one pixel is blitted, and inside the screen
763 // (else nothing is blitted, causing the animations not to be updated)
764 x1 = MIN(MAX(0, x1), WIN_XSIZE - 1);
765 y1 = MIN(MAX(0, y1), WIN_YSIZE - 1);
766 x2 = MIN(MAX(1, x2), WIN_XSIZE);
767 y2 = MIN(MAX(1, y2), WIN_YSIZE);
769 BlitBitmap(backbuffer, window, x1, y1, x2 - x1, y2 - y1, x1, y1);
772 redraw_mask = REDRAW_NONE;
775 PrintFrameTimeDebugging();
779 void BackToFront_WithFrameDelay(unsigned int frame_delay_value)
781 unsigned int frame_delay_value_old = GetVideoFrameDelay();
783 SetVideoFrameDelay(frame_delay_value);
787 SetVideoFrameDelay(frame_delay_value_old);
790 static int fade_type_skip = FADE_TYPE_NONE;
792 static void FadeExt(int fade_mask, int fade_mode, int fade_type)
794 void (*draw_border_function)(void) = NULL;
795 int x, y, width, height;
796 int fade_delay, post_delay;
798 if (fade_type == FADE_TYPE_FADE_OUT)
800 if (fade_type_skip != FADE_TYPE_NONE)
802 /* skip all fade operations until specified fade operation */
803 if (fade_type & fade_type_skip)
804 fade_type_skip = FADE_TYPE_NONE;
809 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
813 redraw_mask |= fade_mask;
815 if (fade_type == FADE_TYPE_SKIP)
817 fade_type_skip = fade_mode;
822 fade_delay = fading.fade_delay;
823 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
825 if (fade_type_skip != FADE_TYPE_NONE)
827 /* skip all fade operations until specified fade operation */
828 if (fade_type & fade_type_skip)
829 fade_type_skip = FADE_TYPE_NONE;
834 if (global.autoplay_leveldir)
839 if (fade_mask == REDRAW_FIELD)
844 height = FADE_SYSIZE;
846 if (border.draw_masked_when_fading)
847 draw_border_function = DrawMaskedBorder_FIELD; /* update when fading */
849 DrawMaskedBorder_FIELD(); /* draw once */
851 else /* REDRAW_ALL */
859 if (!setup.fade_screens ||
861 fading.fade_mode == FADE_MODE_NONE)
863 if (fade_mode == FADE_MODE_FADE_OUT)
866 BlitBitmap(backbuffer, window, x, y, width, height, x, y);
868 redraw_mask &= ~fade_mask;
873 FadeRectangle(x, y, width, height, fade_mode, fade_delay, post_delay,
874 draw_border_function);
876 redraw_mask &= ~fade_mask;
879 static void SetScreenStates_BeforeFadingIn()
881 // temporarily set screen mode for animations to screen after fading in
882 global.anim_status = global.anim_status_next;
884 // store backbuffer with all animations that will be started after fading in
885 if (fade_type_skip != FADE_MODE_SKIP_FADE_IN)
886 PrepareFadeBitmap(DRAW_TO_FADE_TARGET);
888 // set screen mode for animations back to fading
889 global.anim_status = GAME_MODE_PSEUDO_FADING;
892 static void SetScreenStates_AfterFadingIn()
894 // store new source screen (to use correct masked border for fading)
895 gfx.fade_border_source_status = global.border_status;
897 global.anim_status = global.anim_status_next;
900 static void SetScreenStates_BeforeFadingOut()
902 // store new target screen (to use correct masked border for fading)
903 gfx.fade_border_target_status = game_status;
905 // set screen mode for animations to fading
906 global.anim_status = GAME_MODE_PSEUDO_FADING;
908 // store backbuffer with all animations that will be stopped for fading out
909 if (fade_type_skip != FADE_MODE_SKIP_FADE_OUT)
910 PrepareFadeBitmap(DRAW_TO_FADE_SOURCE);
913 static void SetScreenStates_AfterFadingOut()
915 global.border_status = game_status;
918 void FadeIn(int fade_mask)
920 SetScreenStates_BeforeFadingIn();
923 DrawMaskedBorder(REDRAW_ALL);
926 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
927 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_IN);
929 FadeExt(fade_mask, FADE_MODE_FADE_IN, FADE_TYPE_FADE_IN);
933 FADE_SXSIZE = FULL_SXSIZE;
934 FADE_SYSIZE = FULL_SYSIZE;
936 if (game_status == GAME_MODE_PLAYING &&
937 strEqual(setup.touch.control_type, TOUCH_CONTROL_VIRTUAL_BUTTONS))
938 SetOverlayActive(TRUE);
940 SetScreenStates_AfterFadingIn();
942 // force update of global animation status in case of rapid screen changes
943 redraw_mask = REDRAW_ALL;
947 void FadeOut(int fade_mask)
949 // update screen if areas covered by "fade_mask" and "redraw_mask" differ
950 if (!equalRedrawMasks(fade_mask, redraw_mask))
953 SetScreenStates_BeforeFadingOut();
955 SetOverlayActive(FALSE);
958 DrawMaskedBorder(REDRAW_ALL);
961 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
962 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_OUT);
964 FadeExt(fade_mask, FADE_MODE_FADE_OUT, FADE_TYPE_FADE_OUT);
966 SetScreenStates_AfterFadingOut();
969 static void FadeSetLeaveNext(struct TitleFadingInfo fading_leave, boolean set)
971 static struct TitleFadingInfo fading_leave_stored;
974 fading_leave_stored = fading_leave;
976 fading = fading_leave_stored;
979 void FadeSetEnterMenu()
981 fading = menu.enter_menu;
983 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
986 void FadeSetLeaveMenu()
988 fading = menu.leave_menu;
990 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
993 void FadeSetEnterScreen()
995 fading = menu.enter_screen[game_status];
997 FadeSetLeaveNext(menu.leave_screen[game_status], TRUE); /* store */
1000 void FadeSetNextScreen()
1002 fading = menu.next_screen[game_status];
1004 // (do not overwrite fade mode set by FadeSetEnterScreen)
1005 // FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
1008 void FadeSetLeaveScreen()
1010 FadeSetLeaveNext(menu.leave_screen[game_status], FALSE); /* recall */
1013 void FadeSetFromType(int type)
1015 if (type & TYPE_ENTER_SCREEN)
1016 FadeSetEnterScreen();
1017 else if (type & TYPE_ENTER)
1019 else if (type & TYPE_LEAVE)
1023 void FadeSetDisabled()
1025 static struct TitleFadingInfo fading_none = { FADE_MODE_NONE, -1, -1, -1 };
1027 fading = fading_none;
1030 void FadeSkipNextFadeIn()
1032 FadeExt(0, FADE_MODE_SKIP_FADE_IN, FADE_TYPE_SKIP);
1035 void FadeSkipNextFadeOut()
1037 FadeExt(0, FADE_MODE_SKIP_FADE_OUT, FADE_TYPE_SKIP);
1040 Bitmap *getBitmapFromGraphicOrDefault(int graphic, int default_graphic)
1042 boolean redefined = getImageListEntryFromImageID(graphic)->redefined;
1044 return (graphic == IMG_UNDEFINED ? NULL :
1045 graphic_info[graphic].bitmap != NULL || redefined ?
1046 graphic_info[graphic].bitmap :
1047 graphic_info[default_graphic].bitmap);
1050 Bitmap *getBackgroundBitmap(int graphic)
1052 return getBitmapFromGraphicOrDefault(graphic, IMG_BACKGROUND);
1055 Bitmap *getGlobalBorderBitmap(int graphic)
1057 return getBitmapFromGraphicOrDefault(graphic, IMG_GLOBAL_BORDER);
1060 Bitmap *getGlobalBorderBitmapFromStatus(int status)
1063 (status == GAME_MODE_MAIN ||
1064 status == GAME_MODE_PSEUDO_TYPENAME ? IMG_GLOBAL_BORDER_MAIN :
1065 status == GAME_MODE_SCORES ? IMG_GLOBAL_BORDER_SCORES :
1066 status == GAME_MODE_EDITOR ? IMG_GLOBAL_BORDER_EDITOR :
1067 status == GAME_MODE_PLAYING ? IMG_GLOBAL_BORDER_PLAYING :
1070 return getGlobalBorderBitmap(graphic);
1073 void SetWindowBackgroundImageIfDefined(int graphic)
1075 if (graphic_info[graphic].bitmap)
1076 SetWindowBackgroundBitmap(graphic_info[graphic].bitmap);
1079 void SetMainBackgroundImageIfDefined(int graphic)
1081 if (graphic_info[graphic].bitmap)
1082 SetMainBackgroundBitmap(graphic_info[graphic].bitmap);
1085 void SetDoorBackgroundImageIfDefined(int graphic)
1087 if (graphic_info[graphic].bitmap)
1088 SetDoorBackgroundBitmap(graphic_info[graphic].bitmap);
1091 void SetWindowBackgroundImage(int graphic)
1093 SetWindowBackgroundBitmap(getBackgroundBitmap(graphic));
1096 void SetMainBackgroundImage(int graphic)
1098 SetMainBackgroundBitmap(getBackgroundBitmap(graphic));
1101 void SetDoorBackgroundImage(int graphic)
1103 SetDoorBackgroundBitmap(getBackgroundBitmap(graphic));
1106 void SetPanelBackground()
1108 struct GraphicInfo *gfx = &graphic_info[IMG_BACKGROUND_PANEL];
1110 BlitBitmapTiled(gfx->bitmap, bitmap_db_panel, gfx->src_x, gfx->src_y,
1111 gfx->width, gfx->height, 0, 0, DXSIZE, DYSIZE);
1113 SetDoorBackgroundBitmap(bitmap_db_panel);
1116 void DrawBackground(int x, int y, int width, int height)
1118 /* "drawto" might still point to playfield buffer here (hall of fame) */
1119 ClearRectangleOnBackground(backbuffer, x, y, width, height);
1121 if (IN_GFX_FIELD_FULL(x, y))
1122 redraw_mask |= REDRAW_FIELD;
1123 else if (IN_GFX_DOOR_1(x, y))
1124 redraw_mask |= REDRAW_DOOR_1;
1125 else if (IN_GFX_DOOR_2(x, y))
1126 redraw_mask |= REDRAW_DOOR_2;
1127 else if (IN_GFX_DOOR_3(x, y))
1128 redraw_mask |= REDRAW_DOOR_3;
1131 void DrawBackgroundForFont(int x, int y, int width, int height, int font_nr)
1133 struct FontBitmapInfo *font = getFontBitmapInfo(font_nr);
1135 if (font->bitmap == NULL)
1138 DrawBackground(x, y, width, height);
1141 void DrawBackgroundForGraphic(int x, int y, int width, int height, int graphic)
1143 struct GraphicInfo *g = &graphic_info[graphic];
1145 if (g->bitmap == NULL)
1148 DrawBackground(x, y, width, height);
1151 static int game_status_last = -1;
1152 static Bitmap *global_border_bitmap_last = NULL;
1153 static Bitmap *global_border_bitmap = NULL;
1154 static int real_sx_last = -1, real_sy_last = -1;
1155 static int full_sxsize_last = -1, full_sysize_last = -1;
1156 static int dx_last = -1, dy_last = -1;
1157 static int dxsize_last = -1, dysize_last = -1;
1158 static int vx_last = -1, vy_last = -1;
1159 static int vxsize_last = -1, vysize_last = -1;
1161 boolean CheckIfGlobalBorderHasChanged()
1163 // if game status has not changed, global border has not changed either
1164 if (game_status == game_status_last)
1167 // determine and store new global border bitmap for current game status
1168 global_border_bitmap = getGlobalBorderBitmapFromStatus(game_status);
1170 return (global_border_bitmap_last != global_border_bitmap);
1173 boolean CheckIfGlobalBorderRedrawIsNeeded()
1175 // if game status has not changed, nothing has to be redrawn
1176 if (game_status == game_status_last)
1179 // redraw if last screen was title screen
1180 if (game_status_last == GAME_MODE_TITLE)
1183 // redraw if global screen border has changed
1184 if (CheckIfGlobalBorderHasChanged())
1187 // redraw if position or size of playfield area has changed
1188 if (real_sx_last != REAL_SX || real_sy_last != REAL_SY ||
1189 full_sxsize_last != FULL_SXSIZE || full_sysize_last != FULL_SYSIZE)
1192 // redraw if position or size of door area has changed
1193 if (dx_last != DX || dy_last != DY ||
1194 dxsize_last != DXSIZE || dysize_last != DYSIZE)
1197 // redraw if position or size of tape area has changed
1198 if (vx_last != VX || vy_last != VY ||
1199 vxsize_last != VXSIZE || vysize_last != VYSIZE)
1205 void RedrawGlobalBorderFromBitmap(Bitmap *bitmap)
1208 BlitBitmap(bitmap, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
1210 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
1213 void RedrawGlobalBorder()
1215 Bitmap *bitmap = getGlobalBorderBitmapFromStatus(game_status);
1217 RedrawGlobalBorderFromBitmap(bitmap);
1219 redraw_mask = REDRAW_ALL;
1222 static void RedrawGlobalBorderIfNeeded()
1224 if (game_status == game_status_last)
1227 // copy current draw buffer to later copy back areas that have not changed
1228 if (game_status_last != GAME_MODE_TITLE)
1229 BlitBitmap(backbuffer, bitmap_db_store_1, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
1231 if (CheckIfGlobalBorderRedrawIsNeeded())
1233 // redraw global screen border (or clear, if defined to be empty)
1234 RedrawGlobalBorderFromBitmap(global_border_bitmap);
1236 // copy previous playfield and door areas, if they are defined on both
1237 // previous and current screen and if they still have the same size
1239 if (real_sx_last != -1 && real_sy_last != -1 &&
1240 REAL_SX != -1 && REAL_SY != -1 &&
1241 full_sxsize_last == FULL_SXSIZE && full_sysize_last == FULL_SYSIZE)
1242 BlitBitmap(bitmap_db_store_1, backbuffer,
1243 real_sx_last, real_sy_last, FULL_SXSIZE, FULL_SYSIZE,
1246 if (dx_last != -1 && dy_last != -1 &&
1247 DX != -1 && DY != -1 &&
1248 dxsize_last == DXSIZE && dysize_last == DYSIZE)
1249 BlitBitmap(bitmap_db_store_1, backbuffer,
1250 dx_last, dy_last, DXSIZE, DYSIZE, DX, DY);
1252 if (vx_last != -1 && vy_last != -1 &&
1253 VX != -1 && VY != -1 &&
1254 vxsize_last == VXSIZE && vysize_last == VYSIZE)
1255 BlitBitmap(bitmap_db_store_1, backbuffer,
1256 vx_last, vy_last, VXSIZE, VYSIZE, VX, VY);
1258 redraw_mask = REDRAW_ALL;
1261 game_status_last = game_status;
1263 global_border_bitmap_last = global_border_bitmap;
1265 real_sx_last = REAL_SX;
1266 real_sy_last = REAL_SY;
1267 full_sxsize_last = FULL_SXSIZE;
1268 full_sysize_last = FULL_SYSIZE;
1271 dxsize_last = DXSIZE;
1272 dysize_last = DYSIZE;
1275 vxsize_last = VXSIZE;
1276 vysize_last = VYSIZE;
1281 RedrawGlobalBorderIfNeeded();
1283 /* !!! "drawto" might still point to playfield buffer here (see above) !!! */
1284 /* (when entering hall of fame after playing) */
1285 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
1287 /* !!! maybe this should be done before clearing the background !!! */
1288 if (game_status == GAME_MODE_PLAYING)
1290 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
1291 SetDrawtoField(DRAW_TO_FIELDBUFFER);
1295 SetDrawtoField(DRAW_TO_BACKBUFFER);
1299 void MarkTileDirty(int x, int y)
1301 redraw_mask |= REDRAW_FIELD;
1304 void SetBorderElement()
1308 BorderElement = EL_EMPTY;
1310 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
1312 for (x = 0; x < lev_fieldx; x++)
1314 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
1315 BorderElement = EL_STEELWALL;
1317 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
1323 void FloodFillLevel(int from_x, int from_y, int fill_element,
1324 short field[MAX_LEV_FIELDX][MAX_LEV_FIELDY],
1325 int max_fieldx, int max_fieldy)
1329 static int check[4][2] = { { -1, 0 }, { 0, -1 }, { 1, 0 }, { 0, 1 } };
1330 static int safety = 0;
1332 /* check if starting field still has the desired content */
1333 if (field[from_x][from_y] == fill_element)
1338 if (safety > max_fieldx * max_fieldy)
1339 Error(ERR_EXIT, "Something went wrong in 'FloodFill()'. Please debug.");
1341 old_element = field[from_x][from_y];
1342 field[from_x][from_y] = fill_element;
1344 for (i = 0; i < 4; i++)
1346 x = from_x + check[i][0];
1347 y = from_y + check[i][1];
1349 if (IN_FIELD(x, y, max_fieldx, max_fieldy) && field[x][y] == old_element)
1350 FloodFillLevel(x, y, fill_element, field, max_fieldx, max_fieldy);
1356 void SetRandomAnimationValue(int x, int y)
1358 gfx.anim_random_frame = GfxRandom[x][y];
1361 int getGraphicAnimationFrame(int graphic, int sync_frame)
1363 /* animation synchronized with global frame counter, not move position */
1364 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
1365 sync_frame = FrameCounter;
1367 return getAnimationFrame(graphic_info[graphic].anim_frames,
1368 graphic_info[graphic].anim_delay,
1369 graphic_info[graphic].anim_mode,
1370 graphic_info[graphic].anim_start_frame,
1374 void getGraphicSourceBitmap(int graphic, int tilesize, Bitmap **bitmap)
1376 struct GraphicInfo *g = &graphic_info[graphic];
1377 int tilesize_capped = MIN(MAX(1, tilesize), TILESIZE);
1379 if (tilesize == gfx.standard_tile_size)
1380 *bitmap = g->bitmaps[IMG_BITMAP_STANDARD];
1381 else if (tilesize == game.tile_size)
1382 *bitmap = g->bitmaps[IMG_BITMAP_GAME];
1384 *bitmap = g->bitmaps[IMG_BITMAP_1x1 - log_2(tilesize_capped)];
1387 void getGraphicSourceXY(int graphic, int frame, int *x, int *y,
1388 boolean get_backside)
1390 struct GraphicInfo *g = &graphic_info[graphic];
1391 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
1392 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
1394 if (g->offset_y == 0) /* frames are ordered horizontally */
1396 int max_width = g->anim_frames_per_line * g->width;
1397 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
1399 *x = pos % max_width;
1400 *y = src_y % g->height + pos / max_width * g->height;
1402 else if (g->offset_x == 0) /* frames are ordered vertically */
1404 int max_height = g->anim_frames_per_line * g->height;
1405 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
1407 *x = src_x % g->width + pos / max_height * g->width;
1408 *y = pos % max_height;
1410 else /* frames are ordered diagonally */
1412 *x = src_x + frame * g->offset_x;
1413 *y = src_y + frame * g->offset_y;
1417 void getSizedGraphicSourceExt(int graphic, int frame, int tilesize,
1418 Bitmap **bitmap, int *x, int *y,
1419 boolean get_backside)
1421 struct GraphicInfo *g = &graphic_info[graphic];
1423 // if no in-game graphics defined, always use standard graphic size
1424 if (g->bitmaps[IMG_BITMAP_GAME] == NULL)
1425 tilesize = TILESIZE;
1427 getGraphicSourceBitmap(graphic, tilesize, bitmap);
1428 getGraphicSourceXY(graphic, frame, x, y, get_backside);
1430 *x = *x * tilesize / g->tile_size;
1431 *y = *y * tilesize / g->tile_size;
1434 void getFixedGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1435 int *x, int *y, boolean get_backside)
1437 getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y,
1441 void getSizedGraphicSource(int graphic, int frame, int tilesize,
1442 Bitmap **bitmap, int *x, int *y)
1444 getSizedGraphicSourceExt(graphic, frame, tilesize, bitmap, x, y, FALSE);
1447 void getFixedGraphicSource(int graphic, int frame,
1448 Bitmap **bitmap, int *x, int *y)
1450 getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y, FALSE);
1453 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1455 getSizedGraphicSource(graphic, 0, MINI_TILESIZE, bitmap, x, y);
1458 inline static void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1459 int *x, int *y, boolean get_backside)
1461 getSizedGraphicSourceExt(graphic, frame, TILESIZE_VAR, bitmap, x, y,
1465 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
1467 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
1470 void DrawGraphic(int x, int y, int graphic, int frame)
1473 if (!IN_SCR_FIELD(x, y))
1475 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1476 printf("DrawGraphic(): This should never happen!\n");
1481 DrawGraphicExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR, graphic,
1484 MarkTileDirty(x, y);
1487 void DrawFixedGraphic(int x, int y, int graphic, int frame)
1490 if (!IN_SCR_FIELD(x, y))
1492 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1493 printf("DrawGraphic(): This should never happen!\n");
1498 DrawFixedGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic,
1500 MarkTileDirty(x, y);
1503 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1509 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1511 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX_VAR, TILEY_VAR, x, y);
1514 void DrawFixedGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1520 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1521 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
1524 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
1527 if (!IN_SCR_FIELD(x, y))
1529 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1530 printf("DrawGraphicThruMask(): This should never happen!\n");
1535 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
1538 MarkTileDirty(x, y);
1541 void DrawFixedGraphicThruMask(int x, int y, int graphic, int frame)
1544 if (!IN_SCR_FIELD(x, y))
1546 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1547 printf("DrawGraphicThruMask(): This should never happen!\n");
1552 DrawFixedGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
1554 MarkTileDirty(x, y);
1557 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
1563 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1565 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX_VAR, TILEY_VAR,
1569 void DrawFixedGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y,
1570 int graphic, int frame)
1575 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1577 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY,
1581 void DrawSizedGraphic(int x, int y, int graphic, int frame, int tilesize)
1583 DrawSizedGraphicExt(drawto, SX + x * tilesize, SY + y * tilesize, graphic,
1585 MarkTileDirty(x / tilesize, y / tilesize);
1588 void DrawSizedGraphicExt(DrawBuffer *d, int x, int y, int graphic, int frame,
1594 getSizedGraphicSource(graphic, frame, tilesize, &src_bitmap, &src_x, &src_y);
1595 BlitBitmap(src_bitmap, d, src_x, src_y, tilesize, tilesize, x, y);
1598 void DrawMiniGraphic(int x, int y, int graphic)
1600 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
1601 MarkTileDirty(x / 2, y / 2);
1604 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
1609 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1610 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
1613 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
1614 int graphic, int frame,
1615 int cut_mode, int mask_mode)
1620 int width = TILEX, height = TILEY;
1623 if (dx || dy) /* shifted graphic */
1625 if (x < BX1) /* object enters playfield from the left */
1632 else if (x > BX2) /* object enters playfield from the right */
1638 else if (x == BX1 && dx < 0) /* object leaves playfield to the left */
1644 else if (x == BX2 && dx > 0) /* object leaves playfield to the right */
1646 else if (dx) /* general horizontal movement */
1647 MarkTileDirty(x + SIGN(dx), y);
1649 if (y < BY1) /* object enters playfield from the top */
1651 if (cut_mode == CUT_BELOW) /* object completely above top border */
1659 else if (y > BY2) /* object enters playfield from the bottom */
1665 else if (y == BY1 && dy < 0) /* object leaves playfield to the top */
1671 else if (dy > 0 && cut_mode == CUT_ABOVE)
1673 if (y == BY2) /* object completely above bottom border */
1679 MarkTileDirty(x, y + 1);
1680 } /* object leaves playfield to the bottom */
1681 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1683 else if (dy) /* general vertical movement */
1684 MarkTileDirty(x, y + SIGN(dy));
1688 if (!IN_SCR_FIELD(x, y))
1690 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1691 printf("DrawGraphicShifted(): This should never happen!\n");
1696 width = width * TILESIZE_VAR / TILESIZE;
1697 height = height * TILESIZE_VAR / TILESIZE;
1698 cx = cx * TILESIZE_VAR / TILESIZE;
1699 cy = cy * TILESIZE_VAR / TILESIZE;
1700 dx = dx * TILESIZE_VAR / TILESIZE;
1701 dy = dy * TILESIZE_VAR / TILESIZE;
1703 if (width > 0 && height > 0)
1705 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1710 dst_x = FX + x * TILEX_VAR + dx;
1711 dst_y = FY + y * TILEY_VAR + dy;
1713 if (mask_mode == USE_MASKING)
1714 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1717 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1720 MarkTileDirty(x, y);
1724 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
1725 int graphic, int frame,
1726 int cut_mode, int mask_mode)
1731 int width = TILEX_VAR, height = TILEY_VAR;
1734 int x2 = x + SIGN(dx);
1735 int y2 = y + SIGN(dy);
1737 /* movement with two-tile animations must be sync'ed with movement position,
1738 not with current GfxFrame (which can be higher when using slow movement) */
1739 int anim_pos = (dx ? ABS(dx) : ABS(dy));
1740 int anim_frames = graphic_info[graphic].anim_frames;
1742 /* (we also need anim_delay here for movement animations with less frames) */
1743 int anim_delay = graphic_info[graphic].anim_delay;
1744 int sync_frame = anim_pos * anim_frames * anim_delay / TILESIZE;
1746 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
1747 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
1749 /* re-calculate animation frame for two-tile movement animation */
1750 frame = getGraphicAnimationFrame(graphic, sync_frame);
1752 /* check if movement start graphic inside screen area and should be drawn */
1753 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
1755 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
1757 dst_x = FX + x1 * TILEX_VAR;
1758 dst_y = FY + y1 * TILEY_VAR;
1760 if (mask_mode == USE_MASKING)
1761 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1764 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1767 MarkTileDirty(x1, y1);
1770 /* check if movement end graphic inside screen area and should be drawn */
1771 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
1773 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
1775 dst_x = FX + x2 * TILEX_VAR;
1776 dst_y = FY + y2 * TILEY_VAR;
1778 if (mask_mode == USE_MASKING)
1779 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1782 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1785 MarkTileDirty(x2, y2);
1789 static void DrawGraphicShifted(int x, int y, int dx, int dy,
1790 int graphic, int frame,
1791 int cut_mode, int mask_mode)
1795 DrawGraphic(x, y, graphic, frame);
1800 if (graphic_info[graphic].double_movement) /* EM style movement images */
1801 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1803 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1806 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1807 int frame, int cut_mode)
1809 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
1812 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1813 int cut_mode, int mask_mode)
1815 int lx = LEVELX(x), ly = LEVELY(y);
1819 if (IN_LEV_FIELD(lx, ly))
1821 SetRandomAnimationValue(lx, ly);
1823 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
1824 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1826 /* do not use double (EM style) movement graphic when not moving */
1827 if (graphic_info[graphic].double_movement && !dx && !dy)
1829 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
1830 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1833 else /* border element */
1835 graphic = el2img(element);
1836 frame = getGraphicAnimationFrame(graphic, -1);
1839 if (element == EL_EXPANDABLE_WALL)
1841 boolean left_stopped = FALSE, right_stopped = FALSE;
1843 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1844 left_stopped = TRUE;
1845 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1846 right_stopped = TRUE;
1848 if (left_stopped && right_stopped)
1850 else if (left_stopped)
1852 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1853 frame = graphic_info[graphic].anim_frames - 1;
1855 else if (right_stopped)
1857 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1858 frame = graphic_info[graphic].anim_frames - 1;
1863 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1864 else if (mask_mode == USE_MASKING)
1865 DrawGraphicThruMask(x, y, graphic, frame);
1867 DrawGraphic(x, y, graphic, frame);
1870 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1871 int cut_mode, int mask_mode)
1873 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1874 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1875 cut_mode, mask_mode);
1878 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1881 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1884 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1887 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1890 void DrawLevelElementThruMask(int x, int y, int element)
1892 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1895 void DrawLevelFieldThruMask(int x, int y)
1897 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1900 /* !!! implementation of quicksand is totally broken !!! */
1901 #define IS_CRUMBLED_TILE(x, y, e) \
1902 (GFX_CRUMBLED(e) && (!IN_LEV_FIELD(x, y) || \
1903 !IS_MOVING(x, y) || \
1904 (e) == EL_QUICKSAND_EMPTYING || \
1905 (e) == EL_QUICKSAND_FAST_EMPTYING))
1907 static void DrawLevelFieldCrumbledInnerCorners(int x, int y, int dx, int dy,
1912 int width, height, cx, cy;
1913 int sx = SCREENX(x), sy = SCREENY(y);
1914 int crumbled_border_size = graphic_info[graphic].border_size;
1915 int crumbled_tile_size = graphic_info[graphic].tile_size;
1916 int crumbled_border_size_var =
1917 crumbled_border_size * TILESIZE_VAR / crumbled_tile_size;
1920 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1922 for (i = 1; i < 4; i++)
1924 int dxx = (i & 1 ? dx : 0);
1925 int dyy = (i & 2 ? dy : 0);
1928 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1931 /* check if neighbour field is of same crumble type */
1932 boolean same = (IS_CRUMBLED_TILE(xx, yy, element) &&
1933 graphic_info[graphic].class ==
1934 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class);
1936 /* return if check prevents inner corner */
1937 if (same == (dxx == dx && dyy == dy))
1941 /* if we reach this point, we have an inner corner */
1943 getGraphicSource(graphic, 1, &src_bitmap, &src_x, &src_y);
1945 width = crumbled_border_size_var;
1946 height = crumbled_border_size_var;
1947 cx = (dx > 0 ? TILESIZE_VAR - width : 0);
1948 cy = (dy > 0 ? TILESIZE_VAR - height : 0);
1950 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1951 width, height, FX + sx * TILEX_VAR + cx, FY + sy * TILEY_VAR + cy);
1954 static void DrawLevelFieldCrumbledBorders(int x, int y, int graphic, int frame,
1959 int width, height, bx, by, cx, cy;
1960 int sx = SCREENX(x), sy = SCREENY(y);
1961 int crumbled_border_size = graphic_info[graphic].border_size;
1962 int crumbled_tile_size = graphic_info[graphic].tile_size;
1963 int crumbled_border_size_var =
1964 crumbled_border_size * TILESIZE_VAR / crumbled_tile_size;
1965 int crumbled_border_pos_var = TILESIZE_VAR - crumbled_border_size_var;
1968 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1970 /* draw simple, sloppy, non-corner-accurate crumbled border */
1972 width = (dir == 1 || dir == 2 ? crumbled_border_size_var : TILESIZE_VAR);
1973 height = (dir == 0 || dir == 3 ? crumbled_border_size_var : TILESIZE_VAR);
1974 cx = (dir == 2 ? crumbled_border_pos_var : 0);
1975 cy = (dir == 3 ? crumbled_border_pos_var : 0);
1977 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy, width, height,
1978 FX + sx * TILEX_VAR + cx,
1979 FY + sy * TILEY_VAR + cy);
1981 /* (remaining middle border part must be at least as big as corner part) */
1982 if (!(graphic_info[graphic].style & STYLE_ACCURATE_BORDERS) ||
1983 crumbled_border_size_var >= TILESIZE_VAR / 3)
1986 /* correct corners of crumbled border, if needed */
1988 for (i = -1; i <= 1; i += 2)
1990 int xx = x + (dir == 0 || dir == 3 ? i : 0);
1991 int yy = y + (dir == 1 || dir == 2 ? i : 0);
1992 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1995 /* check if neighbour field is of same crumble type */
1996 if (IS_CRUMBLED_TILE(xx, yy, element) &&
1997 graphic_info[graphic].class ==
1998 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
2000 /* no crumbled corner, but continued crumbled border */
2002 int c1 = (dir == 2 || dir == 3 ? crumbled_border_pos_var : 0);
2003 int c2 = (i == 1 ? crumbled_border_pos_var : 0);
2004 int b1 = (i == 1 ? crumbled_border_size_var :
2005 TILESIZE_VAR - 2 * crumbled_border_size_var);
2007 width = crumbled_border_size_var;
2008 height = crumbled_border_size_var;
2010 if (dir == 1 || dir == 2)
2025 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
2027 FX + sx * TILEX_VAR + cx,
2028 FY + sy * TILEY_VAR + cy);
2033 static void DrawLevelFieldCrumbledExt(int x, int y, int graphic, int frame)
2035 int sx = SCREENX(x), sy = SCREENY(y);
2038 static int xy[4][2] =
2046 if (!IN_LEV_FIELD(x, y))
2049 element = TILE_GFX_ELEMENT(x, y);
2051 if (IS_CRUMBLED_TILE(x, y, element)) /* crumble field itself */
2053 if (!IN_SCR_FIELD(sx, sy))
2056 /* crumble field borders towards direct neighbour fields */
2057 for (i = 0; i < 4; i++)
2059 int xx = x + xy[i][0];
2060 int yy = y + xy[i][1];
2062 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
2065 /* check if neighbour field is of same crumble type */
2066 if (IS_CRUMBLED_TILE(xx, yy, element) &&
2067 graphic_info[graphic].class ==
2068 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
2071 DrawLevelFieldCrumbledBorders(x, y, graphic, frame, i);
2074 /* crumble inner field corners towards corner neighbour fields */
2075 if ((graphic_info[graphic].style & STYLE_INNER_CORNERS) &&
2076 graphic_info[graphic].anim_frames == 2)
2078 for (i = 0; i < 4; i++)
2080 int dx = (i & 1 ? +1 : -1);
2081 int dy = (i & 2 ? +1 : -1);
2083 DrawLevelFieldCrumbledInnerCorners(x, y, dx, dy, graphic);
2087 MarkTileDirty(sx, sy);
2089 else /* center field is not crumbled -- crumble neighbour fields */
2091 /* crumble field borders of direct neighbour fields */
2092 for (i = 0; i < 4; i++)
2094 int xx = x + xy[i][0];
2095 int yy = y + xy[i][1];
2096 int sxx = sx + xy[i][0];
2097 int syy = sy + xy[i][1];
2099 if (!IN_LEV_FIELD(xx, yy) ||
2100 !IN_SCR_FIELD(sxx, syy))
2103 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
2106 element = TILE_GFX_ELEMENT(xx, yy);
2108 if (!IS_CRUMBLED_TILE(xx, yy, element))
2111 graphic = el_act2crm(element, ACTION_DEFAULT);
2113 DrawLevelFieldCrumbledBorders(xx, yy, graphic, 0, 3 - i);
2115 MarkTileDirty(sxx, syy);
2118 /* crumble inner field corners of corner neighbour fields */
2119 for (i = 0; i < 4; i++)
2121 int dx = (i & 1 ? +1 : -1);
2122 int dy = (i & 2 ? +1 : -1);
2128 if (!IN_LEV_FIELD(xx, yy) ||
2129 !IN_SCR_FIELD(sxx, syy))
2132 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
2135 element = TILE_GFX_ELEMENT(xx, yy);
2137 if (!IS_CRUMBLED_TILE(xx, yy, element))
2140 graphic = el_act2crm(element, ACTION_DEFAULT);
2142 if ((graphic_info[graphic].style & STYLE_INNER_CORNERS) &&
2143 graphic_info[graphic].anim_frames == 2)
2144 DrawLevelFieldCrumbledInnerCorners(xx, yy, -dx, -dy, graphic);
2146 MarkTileDirty(sxx, syy);
2151 void DrawLevelFieldCrumbled(int x, int y)
2155 if (!IN_LEV_FIELD(x, y))
2158 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
2159 GfxElement[x][y] != EL_UNDEFINED &&
2160 GFX_CRUMBLED(GfxElement[x][y]))
2162 DrawLevelFieldCrumbledDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
2167 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
2169 DrawLevelFieldCrumbledExt(x, y, graphic, 0);
2172 void DrawLevelFieldCrumbledDigging(int x, int y, int direction,
2175 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
2176 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
2177 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
2178 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
2179 int sx = SCREENX(x), sy = SCREENY(y);
2181 DrawGraphic(sx, sy, graphic1, frame1);
2182 DrawLevelFieldCrumbledExt(x, y, graphic2, frame2);
2185 void DrawLevelFieldCrumbledNeighbours(int x, int y)
2187 int sx = SCREENX(x), sy = SCREENY(y);
2188 static int xy[4][2] =
2197 /* crumble direct neighbour fields (required for field borders) */
2198 for (i = 0; i < 4; i++)
2200 int xx = x + xy[i][0];
2201 int yy = y + xy[i][1];
2202 int sxx = sx + xy[i][0];
2203 int syy = sy + xy[i][1];
2205 if (!IN_LEV_FIELD(xx, yy) ||
2206 !IN_SCR_FIELD(sxx, syy) ||
2207 !GFX_CRUMBLED(Feld[xx][yy]) ||
2211 DrawLevelField(xx, yy);
2214 /* crumble corner neighbour fields (required for inner field corners) */
2215 for (i = 0; i < 4; i++)
2217 int dx = (i & 1 ? +1 : -1);
2218 int dy = (i & 2 ? +1 : -1);
2224 if (!IN_LEV_FIELD(xx, yy) ||
2225 !IN_SCR_FIELD(sxx, syy) ||
2226 !GFX_CRUMBLED(Feld[xx][yy]) ||
2230 int element = TILE_GFX_ELEMENT(xx, yy);
2231 int graphic = el_act2crm(element, ACTION_DEFAULT);
2233 if ((graphic_info[graphic].style & STYLE_INNER_CORNERS) &&
2234 graphic_info[graphic].anim_frames == 2)
2235 DrawLevelField(xx, yy);
2239 static int getBorderElement(int x, int y)
2243 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
2244 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
2245 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
2246 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
2247 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
2248 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
2249 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
2251 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
2252 int steel_position = (x == -1 && y == -1 ? 0 :
2253 x == lev_fieldx && y == -1 ? 1 :
2254 x == -1 && y == lev_fieldy ? 2 :
2255 x == lev_fieldx && y == lev_fieldy ? 3 :
2256 x == -1 || x == lev_fieldx ? 4 :
2257 y == -1 || y == lev_fieldy ? 5 : 6);
2259 return border[steel_position][steel_type];
2262 void DrawScreenElement(int x, int y, int element)
2264 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
2265 DrawLevelFieldCrumbled(LEVELX(x), LEVELY(y));
2268 void DrawLevelElement(int x, int y, int element)
2270 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2271 DrawScreenElement(SCREENX(x), SCREENY(y), element);
2274 void DrawScreenField(int x, int y)
2276 int lx = LEVELX(x), ly = LEVELY(y);
2277 int element, content;
2279 if (!IN_LEV_FIELD(lx, ly))
2281 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
2284 element = getBorderElement(lx, ly);
2286 DrawScreenElement(x, y, element);
2291 element = Feld[lx][ly];
2292 content = Store[lx][ly];
2294 if (IS_MOVING(lx, ly))
2296 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
2297 boolean cut_mode = NO_CUTTING;
2299 if (element == EL_QUICKSAND_EMPTYING ||
2300 element == EL_QUICKSAND_FAST_EMPTYING ||
2301 element == EL_MAGIC_WALL_EMPTYING ||
2302 element == EL_BD_MAGIC_WALL_EMPTYING ||
2303 element == EL_DC_MAGIC_WALL_EMPTYING ||
2304 element == EL_AMOEBA_DROPPING)
2305 cut_mode = CUT_ABOVE;
2306 else if (element == EL_QUICKSAND_FILLING ||
2307 element == EL_QUICKSAND_FAST_FILLING ||
2308 element == EL_MAGIC_WALL_FILLING ||
2309 element == EL_BD_MAGIC_WALL_FILLING ||
2310 element == EL_DC_MAGIC_WALL_FILLING)
2311 cut_mode = CUT_BELOW;
2313 if (cut_mode == CUT_ABOVE)
2314 DrawScreenElement(x, y, element);
2316 DrawScreenElement(x, y, EL_EMPTY);
2319 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
2320 else if (cut_mode == NO_CUTTING)
2321 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
2324 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
2326 if (cut_mode == CUT_BELOW &&
2327 IN_LEV_FIELD(lx, ly + 1) && IN_SCR_FIELD(x, y + 1))
2328 DrawLevelElement(lx, ly + 1, element);
2331 if (content == EL_ACID)
2333 int dir = MovDir[lx][ly];
2334 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
2335 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
2337 DrawLevelElementThruMask(newlx, newly, EL_ACID);
2339 // prevent target field from being drawn again (but without masking)
2340 // (this would happen if target field is scanned after moving element)
2341 Stop[newlx][newly] = TRUE;
2344 else if (IS_BLOCKED(lx, ly))
2349 boolean cut_mode = NO_CUTTING;
2350 int element_old, content_old;
2352 Blocked2Moving(lx, ly, &oldx, &oldy);
2355 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
2356 MovDir[oldx][oldy] == MV_RIGHT);
2358 element_old = Feld[oldx][oldy];
2359 content_old = Store[oldx][oldy];
2361 if (element_old == EL_QUICKSAND_EMPTYING ||
2362 element_old == EL_QUICKSAND_FAST_EMPTYING ||
2363 element_old == EL_MAGIC_WALL_EMPTYING ||
2364 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
2365 element_old == EL_DC_MAGIC_WALL_EMPTYING ||
2366 element_old == EL_AMOEBA_DROPPING)
2367 cut_mode = CUT_ABOVE;
2369 DrawScreenElement(x, y, EL_EMPTY);
2372 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
2374 else if (cut_mode == NO_CUTTING)
2375 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
2378 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
2381 else if (IS_DRAWABLE(element))
2382 DrawScreenElement(x, y, element);
2384 DrawScreenElement(x, y, EL_EMPTY);
2387 void DrawLevelField(int x, int y)
2389 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2390 DrawScreenField(SCREENX(x), SCREENY(y));
2391 else if (IS_MOVING(x, y))
2395 Moving2Blocked(x, y, &newx, &newy);
2396 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
2397 DrawScreenField(SCREENX(newx), SCREENY(newy));
2399 else if (IS_BLOCKED(x, y))
2403 Blocked2Moving(x, y, &oldx, &oldy);
2404 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
2405 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
2409 void DrawSizedElement(int x, int y, int element, int tilesize)
2413 graphic = el2edimg(element);
2414 DrawSizedGraphic(x, y, graphic, 0, tilesize);
2417 void DrawMiniElement(int x, int y, int element)
2421 graphic = el2edimg(element);
2422 DrawMiniGraphic(x, y, graphic);
2425 void DrawSizedElementOrWall(int sx, int sy, int scroll_x, int scroll_y,
2428 int x = sx + scroll_x, y = sy + scroll_y;
2430 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
2431 DrawSizedElement(sx, sy, EL_EMPTY, tilesize);
2432 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
2433 DrawSizedElement(sx, sy, Feld[x][y], tilesize);
2435 DrawSizedGraphic(sx, sy, el2edimg(getBorderElement(x, y)), 0, tilesize);
2438 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
2440 int x = sx + scroll_x, y = sy + scroll_y;
2442 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
2443 DrawMiniElement(sx, sy, EL_EMPTY);
2444 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
2445 DrawMiniElement(sx, sy, Feld[x][y]);
2447 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
2450 void DrawEnvelopeBackgroundTiles(int graphic, int startx, int starty,
2451 int x, int y, int xsize, int ysize,
2452 int tile_width, int tile_height)
2456 int dst_x = startx + x * tile_width;
2457 int dst_y = starty + y * tile_height;
2458 int width = graphic_info[graphic].width;
2459 int height = graphic_info[graphic].height;
2460 int inner_width_raw = MAX(width - 2 * tile_width, tile_width);
2461 int inner_height_raw = MAX(height - 2 * tile_height, tile_height);
2462 int inner_width = inner_width_raw - (inner_width_raw % tile_width);
2463 int inner_height = inner_height_raw - (inner_height_raw % tile_height);
2464 int inner_sx = (width >= 3 * tile_width ? tile_width : 0);
2465 int inner_sy = (height >= 3 * tile_height ? tile_height : 0);
2466 boolean draw_masked = graphic_info[graphic].draw_masked;
2468 getFixedGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
2470 if (src_bitmap == NULL || width < tile_width || height < tile_height)
2472 ClearRectangle(drawto, dst_x, dst_y, tile_width, tile_height);
2476 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - tile_width :
2477 inner_sx + (x - 1) * tile_width % inner_width);
2478 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - tile_height :
2479 inner_sy + (y - 1) * tile_height % inner_height);
2482 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
2485 BlitBitmap(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
2489 void DrawEnvelopeBackground(int graphic, int startx, int starty,
2490 int x, int y, int xsize, int ysize, int font_nr)
2492 int font_width = getFontWidth(font_nr);
2493 int font_height = getFontHeight(font_nr);
2495 DrawEnvelopeBackgroundTiles(graphic, startx, starty, x, y, xsize, ysize,
2496 font_width, font_height);
2499 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
2501 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2502 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2503 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2504 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2505 boolean no_delay = (tape.warp_forward);
2506 unsigned int anim_delay = 0;
2507 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
2508 int anim_delay_value = (no_delay ? 0 : frame_delay_value) / 2;
2509 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
2510 int font_width = getFontWidth(font_nr);
2511 int font_height = getFontHeight(font_nr);
2512 int max_xsize = level.envelope[envelope_nr].xsize;
2513 int max_ysize = level.envelope[envelope_nr].ysize;
2514 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
2515 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
2516 int xend = max_xsize;
2517 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
2518 int xstep = (xstart < xend ? 1 : 0);
2519 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2521 int end = MAX(xend - xstart, yend - ystart);
2524 for (i = start; i <= end; i++)
2526 int last_frame = end; // last frame of this "for" loop
2527 int x = xstart + i * xstep;
2528 int y = ystart + i * ystep;
2529 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2530 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2531 int sx = SX + (SXSIZE - xsize * font_width) / 2;
2532 int sy = SY + (SYSIZE - ysize * font_height) / 2;
2535 SetDrawtoField(DRAW_TO_FIELDBUFFER);
2537 BlitScreenToBitmap(backbuffer);
2539 SetDrawtoField(DRAW_TO_BACKBUFFER);
2541 for (yy = 0; yy < ysize; yy++)
2542 for (xx = 0; xx < xsize; xx++)
2543 DrawEnvelopeBackground(graphic, sx, sy, xx, yy, xsize, ysize, font_nr);
2545 DrawTextBuffer(sx + font_width, sy + font_height,
2546 level.envelope[envelope_nr].text, font_nr, max_xsize,
2547 xsize - 2, ysize - 2, 0, mask_mode,
2548 level.envelope[envelope_nr].autowrap,
2549 level.envelope[envelope_nr].centered, FALSE);
2551 redraw_mask |= REDRAW_FIELD;
2554 SkipUntilDelayReached(&anim_delay, anim_delay_value, &i, last_frame);
2558 void ShowEnvelope(int envelope_nr)
2560 int element = EL_ENVELOPE_1 + envelope_nr;
2561 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2562 int sound_opening = element_info[element].sound[ACTION_OPENING];
2563 int sound_closing = element_info[element].sound[ACTION_CLOSING];
2564 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2565 boolean no_delay = (tape.warp_forward);
2566 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
2567 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
2568 int anim_mode = graphic_info[graphic].anim_mode;
2569 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2570 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2572 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
2574 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2576 if (anim_mode == ANIM_DEFAULT)
2577 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
2579 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
2582 Delay(wait_delay_value);
2584 WaitForEventToContinue();
2586 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2588 if (anim_mode != ANIM_NONE)
2589 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
2591 if (anim_mode == ANIM_DEFAULT)
2592 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
2594 game.envelope_active = FALSE;
2596 SetDrawtoField(DRAW_TO_FIELDBUFFER);
2598 redraw_mask |= REDRAW_FIELD;
2602 static void setRequestBasePosition(int *x, int *y)
2604 int sx_base, sy_base;
2606 if (request.x != -1)
2607 sx_base = request.x;
2608 else if (request.align == ALIGN_LEFT)
2610 else if (request.align == ALIGN_RIGHT)
2611 sx_base = SX + SXSIZE;
2613 sx_base = SX + SXSIZE / 2;
2615 if (request.y != -1)
2616 sy_base = request.y;
2617 else if (request.valign == VALIGN_TOP)
2619 else if (request.valign == VALIGN_BOTTOM)
2620 sy_base = SY + SYSIZE;
2622 sy_base = SY + SYSIZE / 2;
2628 static void setRequestPositionExt(int *x, int *y, int width, int height,
2629 boolean add_border_size)
2631 int border_size = request.border_size;
2632 int sx_base, sy_base;
2635 setRequestBasePosition(&sx_base, &sy_base);
2637 if (request.align == ALIGN_LEFT)
2639 else if (request.align == ALIGN_RIGHT)
2640 sx = sx_base - width;
2642 sx = sx_base - width / 2;
2644 if (request.valign == VALIGN_TOP)
2646 else if (request.valign == VALIGN_BOTTOM)
2647 sy = sy_base - height;
2649 sy = sy_base - height / 2;
2651 sx = MAX(0, MIN(sx, WIN_XSIZE - width));
2652 sy = MAX(0, MIN(sy, WIN_YSIZE - height));
2654 if (add_border_size)
2664 static void setRequestPosition(int *x, int *y, boolean add_border_size)
2666 setRequestPositionExt(x, y, request.width, request.height, add_border_size);
2669 void DrawEnvelopeRequest(char *text)
2671 char *text_final = text;
2672 char *text_door_style = NULL;
2673 int graphic = IMG_BACKGROUND_REQUEST;
2674 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2675 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2676 int font_nr = FONT_REQUEST;
2677 int font_width = getFontWidth(font_nr);
2678 int font_height = getFontHeight(font_nr);
2679 int border_size = request.border_size;
2680 int line_spacing = request.line_spacing;
2681 int line_height = font_height + line_spacing;
2682 int max_text_width = request.width - 2 * border_size;
2683 int max_text_height = request.height - 2 * border_size;
2684 int line_length = max_text_width / font_width;
2685 int max_lines = max_text_height / line_height;
2686 int text_width = line_length * font_width;
2687 int width = request.width;
2688 int height = request.height;
2689 int tile_size = MAX(request.step_offset, 1);
2690 int x_steps = width / tile_size;
2691 int y_steps = height / tile_size;
2692 int sx_offset = border_size;
2693 int sy_offset = border_size;
2697 if (request.centered)
2698 sx_offset = (request.width - text_width) / 2;
2700 if (request.wrap_single_words && !request.autowrap)
2702 char *src_text_ptr, *dst_text_ptr;
2704 text_door_style = checked_malloc(2 * strlen(text) + 1);
2706 src_text_ptr = text;
2707 dst_text_ptr = text_door_style;
2709 while (*src_text_ptr)
2711 if (*src_text_ptr == ' ' ||
2712 *src_text_ptr == '?' ||
2713 *src_text_ptr == '!')
2714 *dst_text_ptr++ = '\n';
2716 if (*src_text_ptr != ' ')
2717 *dst_text_ptr++ = *src_text_ptr;
2722 *dst_text_ptr = '\0';
2724 text_final = text_door_style;
2727 setRequestPosition(&sx, &sy, FALSE);
2729 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
2731 for (y = 0; y < y_steps; y++)
2732 for (x = 0; x < x_steps; x++)
2733 DrawEnvelopeBackgroundTiles(graphic, sx, sy,
2734 x, y, x_steps, y_steps,
2735 tile_size, tile_size);
2737 /* force DOOR font inside door area */
2738 SetFontStatus(GAME_MODE_PSEUDO_DOOR);
2740 DrawTextBuffer(sx + sx_offset, sy + sy_offset, text_final, font_nr,
2741 line_length, -1, max_lines, line_spacing, mask_mode,
2742 request.autowrap, request.centered, FALSE);
2746 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2747 RedrawGadget(tool_gadget[i]);
2749 // store readily prepared envelope request for later use when animating
2750 BlitBitmap(backbuffer, bitmap_db_store_2, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2752 if (text_door_style)
2753 free(text_door_style);
2756 void AnimateEnvelopeRequest(int anim_mode, int action)
2758 int graphic = IMG_BACKGROUND_REQUEST;
2759 boolean draw_masked = graphic_info[graphic].draw_masked;
2760 int delay_value_normal = request.step_delay;
2761 int delay_value_fast = delay_value_normal / 2;
2762 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2763 boolean no_delay = (tape.warp_forward);
2764 int delay_value = (ffwd_delay ? delay_value_fast : delay_value_normal);
2765 int anim_delay_value = (no_delay ? 0 : delay_value + 500 * 0) / 2;
2766 unsigned int anim_delay = 0;
2768 int tile_size = MAX(request.step_offset, 1);
2769 int max_xsize = request.width / tile_size;
2770 int max_ysize = request.height / tile_size;
2771 int max_xsize_inner = max_xsize - 2;
2772 int max_ysize_inner = max_ysize - 2;
2774 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize_inner : 0);
2775 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize_inner : 0);
2776 int xend = max_xsize_inner;
2777 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize_inner : 0);
2778 int xstep = (xstart < xend ? 1 : 0);
2779 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2781 int end = MAX(xend - xstart, yend - ystart);
2784 if (setup.quick_doors)
2791 for (i = start; i <= end; i++)
2793 int last_frame = end; // last frame of this "for" loop
2794 int x = xstart + i * xstep;
2795 int y = ystart + i * ystep;
2796 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2797 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2798 int xsize_size_left = (xsize - 1) * tile_size;
2799 int ysize_size_top = (ysize - 1) * tile_size;
2800 int max_xsize_pos = (max_xsize - 1) * tile_size;
2801 int max_ysize_pos = (max_ysize - 1) * tile_size;
2802 int width = xsize * tile_size;
2803 int height = ysize * tile_size;
2808 setRequestPosition(&src_x, &src_y, FALSE);
2809 setRequestPositionExt(&dst_x, &dst_y, width, height, FALSE);
2811 BlitBitmap(bitmap_db_store_1, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2813 for (yy = 0; yy < 2; yy++)
2815 for (xx = 0; xx < 2; xx++)
2817 int src_xx = src_x + xx * max_xsize_pos;
2818 int src_yy = src_y + yy * max_ysize_pos;
2819 int dst_xx = dst_x + xx * xsize_size_left;
2820 int dst_yy = dst_y + yy * ysize_size_top;
2821 int xx_size = (xx ? tile_size : xsize_size_left);
2822 int yy_size = (yy ? tile_size : ysize_size_top);
2825 BlitBitmapMasked(bitmap_db_store_2, backbuffer,
2826 src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
2828 BlitBitmap(bitmap_db_store_2, backbuffer,
2829 src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
2833 redraw_mask |= REDRAW_FIELD;
2837 SkipUntilDelayReached(&anim_delay, anim_delay_value, &i, last_frame);
2841 void ShowEnvelopeRequest(char *text, unsigned int req_state, int action)
2843 int graphic = IMG_BACKGROUND_REQUEST;
2844 int sound_opening = SND_REQUEST_OPENING;
2845 int sound_closing = SND_REQUEST_CLOSING;
2846 int anim_mode_1 = request.anim_mode; /* (higher priority) */
2847 int anim_mode_2 = graphic_info[graphic].anim_mode; /* (lower priority) */
2848 int anim_mode = (anim_mode_1 != ANIM_DEFAULT ? anim_mode_1 : anim_mode_2);
2849 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2850 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2852 if (game_status == GAME_MODE_PLAYING)
2853 BlitScreenToBitmap(backbuffer);
2855 SetDrawtoField(DRAW_TO_BACKBUFFER);
2857 // SetDrawBackgroundMask(REDRAW_NONE);
2859 if (action == ACTION_OPENING)
2861 BlitBitmap(backbuffer, bitmap_db_store_1, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2863 if (req_state & REQ_ASK)
2865 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2866 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2868 else if (req_state & REQ_CONFIRM)
2870 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2872 else if (req_state & REQ_PLAYER)
2874 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2875 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2876 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2877 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2880 DrawEnvelopeRequest(text);
2883 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
2885 if (action == ACTION_OPENING)
2887 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2889 if (anim_mode == ANIM_DEFAULT)
2890 AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_OPENING);
2892 AnimateEnvelopeRequest(main_anim_mode, ACTION_OPENING);
2896 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2898 if (anim_mode != ANIM_NONE)
2899 AnimateEnvelopeRequest(main_anim_mode, ACTION_CLOSING);
2901 if (anim_mode == ANIM_DEFAULT)
2902 AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_CLOSING);
2905 game.envelope_active = FALSE;
2907 if (action == ACTION_CLOSING)
2908 BlitBitmap(bitmap_db_store_1, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2910 // SetDrawBackgroundMask(last_draw_background_mask);
2912 redraw_mask |= REDRAW_FIELD;
2916 if (action == ACTION_CLOSING &&
2917 game_status == GAME_MODE_PLAYING &&
2918 level.game_engine_type == GAME_ENGINE_TYPE_RND)
2919 SetDrawtoField(DRAW_TO_FIELDBUFFER);
2922 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
2926 int graphic = el2preimg(element);
2928 getSizedGraphicSource(graphic, 0, tilesize, &src_bitmap, &src_x, &src_y);
2929 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
2932 void DrawLevel(int draw_background_mask)
2936 SetMainBackgroundImage(IMG_BACKGROUND_PLAYING);
2937 SetDrawBackgroundMask(draw_background_mask);
2941 for (x = BX1; x <= BX2; x++)
2942 for (y = BY1; y <= BY2; y++)
2943 DrawScreenField(x, y);
2945 redraw_mask |= REDRAW_FIELD;
2948 void DrawSizedLevel(int size_x, int size_y, int scroll_x, int scroll_y,
2953 for (x = 0; x < size_x; x++)
2954 for (y = 0; y < size_y; y++)
2955 DrawSizedElementOrWall(x, y, scroll_x, scroll_y, tilesize);
2957 redraw_mask |= REDRAW_FIELD;
2960 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
2964 for (x = 0; x < size_x; x++)
2965 for (y = 0; y < size_y; y++)
2966 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
2968 redraw_mask |= REDRAW_FIELD;
2971 static void DrawPreviewLevelPlayfieldExt(int from_x, int from_y)
2973 boolean show_level_border = (BorderElement != EL_EMPTY);
2974 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2975 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2976 int tile_size = preview.tile_size;
2977 int preview_width = preview.xsize * tile_size;
2978 int preview_height = preview.ysize * tile_size;
2979 int real_preview_xsize = MIN(level_xsize, preview.xsize);
2980 int real_preview_ysize = MIN(level_ysize, preview.ysize);
2981 int real_preview_width = real_preview_xsize * tile_size;
2982 int real_preview_height = real_preview_ysize * tile_size;
2983 int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
2984 int dst_y = SY + ALIGNED_YPOS(preview.y, preview_height, preview.valign);
2987 if (!IN_GFX_FIELD_FULL(dst_x, dst_y + preview_height - 1))
2990 DrawBackground(dst_x, dst_y, preview_width, preview_height);
2992 dst_x += (preview_width - real_preview_width) / 2;
2993 dst_y += (preview_height - real_preview_height) / 2;
2995 for (x = 0; x < real_preview_xsize; x++)
2997 for (y = 0; y < real_preview_ysize; y++)
2999 int lx = from_x + x + (show_level_border ? -1 : 0);
3000 int ly = from_y + y + (show_level_border ? -1 : 0);
3001 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
3002 getBorderElement(lx, ly));
3004 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
3005 element, tile_size);
3009 redraw_mask |= REDRAW_FIELD;
3012 #define MICROLABEL_EMPTY 0
3013 #define MICROLABEL_LEVEL_NAME 1
3014 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
3015 #define MICROLABEL_LEVEL_AUTHOR 3
3016 #define MICROLABEL_IMPORTED_FROM_HEAD 4
3017 #define MICROLABEL_IMPORTED_FROM 5
3018 #define MICROLABEL_IMPORTED_BY_HEAD 6
3019 #define MICROLABEL_IMPORTED_BY 7
3021 static int getMaxTextLength(struct TextPosInfo *pos, int font_nr)
3023 int max_text_width = SXSIZE;
3024 int font_width = getFontWidth(font_nr);
3026 if (pos->align == ALIGN_CENTER)
3027 max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
3028 else if (pos->align == ALIGN_RIGHT)
3029 max_text_width = pos->x;
3031 max_text_width = SXSIZE - pos->x;
3033 return max_text_width / font_width;
3036 static void DrawPreviewLevelLabelExt(int mode)
3038 struct TextPosInfo *pos = &menu.main.text.level_info_2;
3039 char label_text[MAX_OUTPUT_LINESIZE + 1];
3040 int max_len_label_text;
3041 int font_nr = pos->font;
3044 if (!IN_GFX_FIELD_FULL(pos->x, pos->y + getFontHeight(pos->font)))
3047 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
3048 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
3049 mode == MICROLABEL_IMPORTED_BY_HEAD)
3050 font_nr = pos->font_alt;
3052 max_len_label_text = getMaxTextLength(pos, font_nr);
3054 if (pos->size != -1)
3055 max_len_label_text = pos->size;
3057 for (i = 0; i < max_len_label_text; i++)
3058 label_text[i] = ' ';
3059 label_text[max_len_label_text] = '\0';
3061 if (strlen(label_text) > 0)
3062 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
3065 (mode == MICROLABEL_LEVEL_NAME ? level.name :
3066 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
3067 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
3068 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
3069 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
3070 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
3071 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
3072 max_len_label_text);
3073 label_text[max_len_label_text] = '\0';
3075 if (strlen(label_text) > 0)
3076 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
3078 redraw_mask |= REDRAW_FIELD;
3081 static void DrawPreviewLevelExt(boolean restart)
3083 static unsigned int scroll_delay = 0;
3084 static unsigned int label_delay = 0;
3085 static int from_x, from_y, scroll_direction;
3086 static int label_state, label_counter;
3087 unsigned int scroll_delay_value = preview.step_delay;
3088 boolean show_level_border = (BorderElement != EL_EMPTY);
3089 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
3090 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
3097 if (preview.anim_mode == ANIM_CENTERED)
3099 if (level_xsize > preview.xsize)
3100 from_x = (level_xsize - preview.xsize) / 2;
3101 if (level_ysize > preview.ysize)
3102 from_y = (level_ysize - preview.ysize) / 2;
3105 from_x += preview.xoffset;
3106 from_y += preview.yoffset;
3108 scroll_direction = MV_RIGHT;
3112 DrawPreviewLevelPlayfieldExt(from_x, from_y);
3113 DrawPreviewLevelLabelExt(label_state);
3115 /* initialize delay counters */
3116 DelayReached(&scroll_delay, 0);
3117 DelayReached(&label_delay, 0);
3119 if (leveldir_current->name)
3121 struct TextPosInfo *pos = &menu.main.text.level_info_1;
3122 char label_text[MAX_OUTPUT_LINESIZE + 1];
3123 int font_nr = pos->font;
3124 int max_len_label_text = getMaxTextLength(pos, font_nr);
3126 if (pos->size != -1)
3127 max_len_label_text = pos->size;
3129 strncpy(label_text, leveldir_current->name, max_len_label_text);
3130 label_text[max_len_label_text] = '\0';
3132 if (IN_GFX_FIELD_FULL(pos->x, pos->y + getFontHeight(pos->font)))
3133 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
3139 /* scroll preview level, if needed */
3140 if (preview.anim_mode != ANIM_NONE &&
3141 (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
3142 DelayReached(&scroll_delay, scroll_delay_value))
3144 switch (scroll_direction)
3149 from_x -= preview.step_offset;
3150 from_x = (from_x < 0 ? 0 : from_x);
3153 scroll_direction = MV_UP;
3157 if (from_x < level_xsize - preview.xsize)
3159 from_x += preview.step_offset;
3160 from_x = (from_x > level_xsize - preview.xsize ?
3161 level_xsize - preview.xsize : from_x);
3164 scroll_direction = MV_DOWN;
3170 from_y -= preview.step_offset;
3171 from_y = (from_y < 0 ? 0 : from_y);
3174 scroll_direction = MV_RIGHT;
3178 if (from_y < level_ysize - preview.ysize)
3180 from_y += preview.step_offset;
3181 from_y = (from_y > level_ysize - preview.ysize ?
3182 level_ysize - preview.ysize : from_y);
3185 scroll_direction = MV_LEFT;
3192 DrawPreviewLevelPlayfieldExt(from_x, from_y);
3195 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
3196 /* redraw micro level label, if needed */
3197 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
3198 !strEqual(level.author, ANONYMOUS_NAME) &&
3199 !strEqual(level.author, leveldir_current->name) &&
3200 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
3202 int max_label_counter = 23;
3204 if (leveldir_current->imported_from != NULL &&
3205 strlen(leveldir_current->imported_from) > 0)
3206 max_label_counter += 14;
3207 if (leveldir_current->imported_by != NULL &&
3208 strlen(leveldir_current->imported_by) > 0)
3209 max_label_counter += 14;
3211 label_counter = (label_counter + 1) % max_label_counter;
3212 label_state = (label_counter >= 0 && label_counter <= 7 ?
3213 MICROLABEL_LEVEL_NAME :
3214 label_counter >= 9 && label_counter <= 12 ?
3215 MICROLABEL_LEVEL_AUTHOR_HEAD :
3216 label_counter >= 14 && label_counter <= 21 ?
3217 MICROLABEL_LEVEL_AUTHOR :
3218 label_counter >= 23 && label_counter <= 26 ?
3219 MICROLABEL_IMPORTED_FROM_HEAD :
3220 label_counter >= 28 && label_counter <= 35 ?
3221 MICROLABEL_IMPORTED_FROM :
3222 label_counter >= 37 && label_counter <= 40 ?
3223 MICROLABEL_IMPORTED_BY_HEAD :
3224 label_counter >= 42 && label_counter <= 49 ?
3225 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
3227 if (leveldir_current->imported_from == NULL &&
3228 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
3229 label_state == MICROLABEL_IMPORTED_FROM))
3230 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
3231 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
3233 DrawPreviewLevelLabelExt(label_state);
3237 void DrawPreviewLevelInitial()
3239 DrawPreviewLevelExt(TRUE);
3242 void DrawPreviewLevelAnimation()
3244 DrawPreviewLevelExt(FALSE);
3247 inline static void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
3248 int graphic, int sync_frame,
3251 int frame = getGraphicAnimationFrame(graphic, sync_frame);
3253 if (mask_mode == USE_MASKING)
3254 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
3256 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
3259 void DrawFixedGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
3260 int graphic, int sync_frame, int mask_mode)
3262 int frame = getGraphicAnimationFrame(graphic, sync_frame);
3264 if (mask_mode == USE_MASKING)
3265 DrawFixedGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
3267 DrawFixedGraphicExt(dst_bitmap, x, y, graphic, frame);
3270 inline static void DrawGraphicAnimation(int x, int y, int graphic)
3272 int lx = LEVELX(x), ly = LEVELY(y);
3274 if (!IN_SCR_FIELD(x, y))
3277 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
3278 graphic, GfxFrame[lx][ly], NO_MASKING);
3280 MarkTileDirty(x, y);
3283 void DrawFixedGraphicAnimation(int x, int y, int graphic)
3285 int lx = LEVELX(x), ly = LEVELY(y);
3287 if (!IN_SCR_FIELD(x, y))
3290 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
3291 graphic, GfxFrame[lx][ly], NO_MASKING);
3292 MarkTileDirty(x, y);
3295 void DrawLevelGraphicAnimation(int x, int y, int graphic)
3297 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
3300 void DrawLevelElementAnimation(int x, int y, int element)
3302 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
3304 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
3307 void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
3309 int sx = SCREENX(x), sy = SCREENY(y);
3311 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
3314 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
3317 DrawGraphicAnimation(sx, sy, graphic);
3320 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
3321 DrawLevelFieldCrumbled(x, y);
3323 if (GFX_CRUMBLED(Feld[x][y]))
3324 DrawLevelFieldCrumbled(x, y);
3328 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
3330 int sx = SCREENX(x), sy = SCREENY(y);
3333 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
3336 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
3338 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
3341 DrawGraphicAnimation(sx, sy, graphic);
3343 if (GFX_CRUMBLED(element))
3344 DrawLevelFieldCrumbled(x, y);
3347 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
3349 if (player->use_murphy)
3351 /* this works only because currently only one player can be "murphy" ... */
3352 static int last_horizontal_dir = MV_LEFT;
3353 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
3355 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3356 last_horizontal_dir = move_dir;
3358 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
3360 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
3362 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
3368 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
3371 static boolean equalGraphics(int graphic1, int graphic2)
3373 struct GraphicInfo *g1 = &graphic_info[graphic1];
3374 struct GraphicInfo *g2 = &graphic_info[graphic2];
3376 return (g1->bitmap == g2->bitmap &&
3377 g1->src_x == g2->src_x &&
3378 g1->src_y == g2->src_y &&
3379 g1->anim_frames == g2->anim_frames &&
3380 g1->anim_delay == g2->anim_delay &&
3381 g1->anim_mode == g2->anim_mode);
3384 void DrawAllPlayers()
3388 for (i = 0; i < MAX_PLAYERS; i++)
3389 if (stored_player[i].active)
3390 DrawPlayer(&stored_player[i]);
3393 void DrawPlayerField(int x, int y)
3395 if (!IS_PLAYER(x, y))
3398 DrawPlayer(PLAYERINFO(x, y));
3401 #define DRAW_PLAYER_OVER_PUSHED_ELEMENT 1
3403 void DrawPlayer(struct PlayerInfo *player)
3405 int jx = player->jx;
3406 int jy = player->jy;
3407 int move_dir = player->MovDir;
3408 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
3409 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
3410 int last_jx = (player->is_moving ? jx - dx : jx);
3411 int last_jy = (player->is_moving ? jy - dy : jy);
3412 int next_jx = jx + dx;
3413 int next_jy = jy + dy;
3414 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
3415 boolean player_is_opaque = FALSE;
3416 int sx = SCREENX(jx), sy = SCREENY(jy);
3417 int sxx = 0, syy = 0;
3418 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
3420 int action = ACTION_DEFAULT;
3421 int last_player_graphic = getPlayerGraphic(player, move_dir);
3422 int last_player_frame = player->Frame;
3425 /* GfxElement[][] is set to the element the player is digging or collecting;
3426 remove also for off-screen player if the player is not moving anymore */
3427 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
3428 GfxElement[jx][jy] = EL_UNDEFINED;
3430 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
3434 if (!IN_LEV_FIELD(jx, jy))
3436 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
3437 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
3438 printf("DrawPlayerField(): This should never happen!\n");
3443 if (element == EL_EXPLOSION)
3446 action = (player->is_pushing ? ACTION_PUSHING :
3447 player->is_digging ? ACTION_DIGGING :
3448 player->is_collecting ? ACTION_COLLECTING :
3449 player->is_moving ? ACTION_MOVING :
3450 player->is_snapping ? ACTION_SNAPPING :
3451 player->is_dropping ? ACTION_DROPPING :
3452 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
3454 if (player->is_waiting)
3455 move_dir = player->dir_waiting;
3457 InitPlayerGfxAnimation(player, action, move_dir);
3459 /* ----------------------------------------------------------------------- */
3460 /* draw things in the field the player is leaving, if needed */
3461 /* ----------------------------------------------------------------------- */
3463 if (player->is_moving)
3465 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
3467 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
3469 if (last_element == EL_DYNAMITE_ACTIVE ||
3470 last_element == EL_EM_DYNAMITE_ACTIVE ||
3471 last_element == EL_SP_DISK_RED_ACTIVE)
3472 DrawDynamite(last_jx, last_jy);
3474 DrawLevelFieldThruMask(last_jx, last_jy);
3476 else if (last_element == EL_DYNAMITE_ACTIVE ||
3477 last_element == EL_EM_DYNAMITE_ACTIVE ||
3478 last_element == EL_SP_DISK_RED_ACTIVE)
3479 DrawDynamite(last_jx, last_jy);
3481 /* !!! this is not enough to prevent flickering of players which are
3482 moving next to each others without a free tile between them -- this
3483 can only be solved by drawing all players layer by layer (first the
3484 background, then the foreground etc.) !!! => TODO */
3485 else if (!IS_PLAYER(last_jx, last_jy))
3486 DrawLevelField(last_jx, last_jy);
3489 DrawLevelField(last_jx, last_jy);
3492 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
3493 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
3496 if (!IN_SCR_FIELD(sx, sy))
3499 /* ----------------------------------------------------------------------- */
3500 /* draw things behind the player, if needed */
3501 /* ----------------------------------------------------------------------- */
3504 DrawLevelElement(jx, jy, Back[jx][jy]);
3505 else if (IS_ACTIVE_BOMB(element))
3506 DrawLevelElement(jx, jy, EL_EMPTY);
3509 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
3511 int old_element = GfxElement[jx][jy];
3512 int old_graphic = el_act_dir2img(old_element, action, move_dir);
3513 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
3515 if (GFX_CRUMBLED(old_element))
3516 DrawLevelFieldCrumbledDigging(jx, jy, move_dir, player->StepFrame);
3518 DrawGraphic(sx, sy, old_graphic, frame);
3520 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
3521 player_is_opaque = TRUE;
3525 GfxElement[jx][jy] = EL_UNDEFINED;
3527 /* make sure that pushed elements are drawn with correct frame rate */
3528 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
3530 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
3531 GfxFrame[jx][jy] = player->StepFrame;
3533 DrawLevelField(jx, jy);
3537 #if !DRAW_PLAYER_OVER_PUSHED_ELEMENT
3538 /* ----------------------------------------------------------------------- */
3539 /* draw player himself */
3540 /* ----------------------------------------------------------------------- */
3542 graphic = getPlayerGraphic(player, move_dir);
3544 /* in the case of changed player action or direction, prevent the current
3545 animation frame from being restarted for identical animations */
3546 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
3547 player->Frame = last_player_frame;
3549 frame = getGraphicAnimationFrame(graphic, player->Frame);
3553 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3554 sxx = player->GfxPos;
3556 syy = player->GfxPos;
3559 if (player_is_opaque)
3560 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
3562 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3564 if (SHIELD_ON(player))
3566 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
3567 IMG_SHIELD_NORMAL_ACTIVE);
3568 int frame = getGraphicAnimationFrame(graphic, -1);
3570 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3574 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
3577 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3578 sxx = player->GfxPos;
3580 syy = player->GfxPos;
3584 /* ----------------------------------------------------------------------- */
3585 /* draw things the player is pushing, if needed */
3586 /* ----------------------------------------------------------------------- */
3588 if (player->is_pushing && player->is_moving)
3590 int px = SCREENX(jx), py = SCREENY(jy);
3591 int pxx = (TILEX - ABS(sxx)) * dx;
3592 int pyy = (TILEY - ABS(syy)) * dy;
3593 int gfx_frame = GfxFrame[jx][jy];
3599 if (!IS_MOVING(jx, jy)) /* push movement already finished */
3601 element = Feld[next_jx][next_jy];
3602 gfx_frame = GfxFrame[next_jx][next_jy];
3605 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
3607 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
3608 frame = getGraphicAnimationFrame(graphic, sync_frame);
3610 /* draw background element under pushed element (like the Sokoban field) */
3611 if (game.use_masked_pushing && IS_MOVING(jx, jy))
3613 /* this allows transparent pushing animation over non-black background */
3616 DrawLevelElement(jx, jy, Back[jx][jy]);
3618 DrawLevelElement(jx, jy, EL_EMPTY);
3620 if (Back[next_jx][next_jy])
3621 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3623 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
3625 else if (Back[next_jx][next_jy])
3626 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3629 /* do not draw (EM style) pushing animation when pushing is finished */
3630 /* (two-tile animations usually do not contain start and end frame) */
3631 if (graphic_info[graphic].double_movement && !IS_MOVING(jx, jy))
3632 DrawLevelElement(next_jx, next_jy, Feld[next_jx][next_jy]);
3634 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3636 /* masked drawing is needed for EMC style (double) movement graphics */
3637 /* !!! (ONLY WHEN DRAWING PUSHED ELEMENT OVER THE PLAYER) !!! */
3638 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3642 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
3643 /* ----------------------------------------------------------------------- */
3644 /* draw player himself */
3645 /* ----------------------------------------------------------------------- */
3647 graphic = getPlayerGraphic(player, move_dir);
3649 /* in the case of changed player action or direction, prevent the current
3650 animation frame from being restarted for identical animations */
3651 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
3652 player->Frame = last_player_frame;
3654 frame = getGraphicAnimationFrame(graphic, player->Frame);
3658 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3659 sxx = player->GfxPos;
3661 syy = player->GfxPos;
3664 if (player_is_opaque)
3665 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
3667 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3669 if (SHIELD_ON(player))
3671 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
3672 IMG_SHIELD_NORMAL_ACTIVE);
3673 int frame = getGraphicAnimationFrame(graphic, -1);
3675 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3679 /* ----------------------------------------------------------------------- */
3680 /* draw things in front of player (active dynamite or dynabombs) */
3681 /* ----------------------------------------------------------------------- */
3683 if (IS_ACTIVE_BOMB(element))
3685 graphic = el2img(element);
3686 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
3688 if (game.emulation == EMU_SUPAPLEX)
3689 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
3691 DrawGraphicThruMask(sx, sy, graphic, frame);
3694 if (player_is_moving && last_element == EL_EXPLOSION)
3696 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
3697 GfxElement[last_jx][last_jy] : EL_EMPTY);
3698 int graphic = el_act2img(element, ACTION_EXPLODING);
3699 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
3700 int phase = ExplodePhase[last_jx][last_jy] - 1;
3701 int frame = getGraphicAnimationFrame(graphic, phase - delay);
3704 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
3707 /* ----------------------------------------------------------------------- */
3708 /* draw elements the player is just walking/passing through/under */
3709 /* ----------------------------------------------------------------------- */
3711 if (player_is_moving)
3713 /* handle the field the player is leaving ... */
3714 if (IS_ACCESSIBLE_INSIDE(last_element))
3715 DrawLevelField(last_jx, last_jy);
3716 else if (IS_ACCESSIBLE_UNDER(last_element))
3717 DrawLevelFieldThruMask(last_jx, last_jy);
3720 /* do not redraw accessible elements if the player is just pushing them */
3721 if (!player_is_moving || !player->is_pushing)
3723 /* ... and the field the player is entering */
3724 if (IS_ACCESSIBLE_INSIDE(element))
3725 DrawLevelField(jx, jy);
3726 else if (IS_ACCESSIBLE_UNDER(element))
3727 DrawLevelFieldThruMask(jx, jy);
3730 MarkTileDirty(sx, sy);
3733 /* ------------------------------------------------------------------------- */
3735 void WaitForEventToContinue()
3737 boolean still_wait = TRUE;
3739 if (program.headless)
3742 /* simulate releasing mouse button over last gadget, if still pressed */
3744 HandleGadgets(-1, -1, 0);
3746 button_status = MB_RELEASED;
3760 case EVENT_BUTTONPRESS:
3761 case EVENT_KEYPRESS:
3765 case EVENT_KEYRELEASE:
3766 ClearPlayerAction();
3770 HandleOtherEvents(&event);
3774 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3783 #define MAX_REQUEST_LINES 13
3784 #define MAX_REQUEST_LINE_FONT1_LEN 7
3785 #define MAX_REQUEST_LINE_FONT2_LEN 10
3787 static int RequestHandleEvents(unsigned int req_state)
3789 boolean level_solved = (game_status == GAME_MODE_PLAYING &&
3790 local_player->LevelSolved_GameEnd);
3791 int width = request.width;
3792 int height = request.height;
3796 setRequestPosition(&sx, &sy, FALSE);
3798 button_status = MB_RELEASED;
3800 request_gadget_id = -1;
3807 SetDrawtoField(DRAW_TO_FIELDBUFFER);
3809 HandleGameActions();
3811 SetDrawtoField(DRAW_TO_BACKBUFFER);
3813 if (global.use_envelope_request)
3815 /* copy current state of request area to middle of playfield area */
3816 BlitBitmap(bitmap_db_store_2, drawto, sx, sy, width, height, sx, sy);
3824 while (NextValidEvent(&event))
3828 case EVENT_BUTTONPRESS:
3829 case EVENT_BUTTONRELEASE:
3830 case EVENT_MOTIONNOTIFY:
3834 if (event.type == EVENT_MOTIONNOTIFY)
3839 motion_status = TRUE;
3840 mx = ((MotionEvent *) &event)->x;
3841 my = ((MotionEvent *) &event)->y;
3845 motion_status = FALSE;
3846 mx = ((ButtonEvent *) &event)->x;
3847 my = ((ButtonEvent *) &event)->y;
3848 if (event.type == EVENT_BUTTONPRESS)
3849 button_status = ((ButtonEvent *) &event)->button;
3851 button_status = MB_RELEASED;
3854 /* this sets 'request_gadget_id' */
3855 HandleGadgets(mx, my, button_status);
3857 switch (request_gadget_id)
3859 case TOOL_CTRL_ID_YES:
3862 case TOOL_CTRL_ID_NO:
3865 case TOOL_CTRL_ID_CONFIRM:
3866 result = TRUE | FALSE;
3869 case TOOL_CTRL_ID_PLAYER_1:
3872 case TOOL_CTRL_ID_PLAYER_2:
3875 case TOOL_CTRL_ID_PLAYER_3:
3878 case TOOL_CTRL_ID_PLAYER_4:
3889 case EVENT_KEYPRESS:
3891 Key key = GetEventKey((KeyEvent *)&event, TRUE);
3896 if (req_state & REQ_CONFIRM)
3901 #if defined(TARGET_SDL2)
3908 #if defined(TARGET_SDL2)
3915 HandleKeysDebug(key);
3919 if (req_state & REQ_PLAYER)
3925 case EVENT_KEYRELEASE:
3926 ClearPlayerAction();
3930 HandleOtherEvents(&event);
3935 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3937 int joy = AnyJoystick();
3939 if (joy & JOY_BUTTON_1)
3941 else if (joy & JOY_BUTTON_2)
3947 if (global.use_envelope_request)
3949 /* copy back current state of pressed buttons inside request area */
3950 BlitBitmap(drawto, bitmap_db_store_2, sx, sy, width, height, sx, sy);
3960 static boolean RequestDoor(char *text, unsigned int req_state)
3962 unsigned int old_door_state;
3963 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
3964 int font_nr = FONT_TEXT_2;
3969 if (maxWordLengthInString(text) > MAX_REQUEST_LINE_FONT1_LEN)
3971 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
3972 font_nr = FONT_TEXT_1;
3975 if (game_status == GAME_MODE_PLAYING)
3976 BlitScreenToBitmap(backbuffer);
3978 /* disable deactivated drawing when quick-loading level tape recording */
3979 if (tape.playing && tape.deactivate_display)
3980 TapeDeactivateDisplayOff(TRUE);
3982 SetMouseCursor(CURSOR_DEFAULT);
3984 #if defined(NETWORK_AVALIABLE)
3985 /* pause network game while waiting for request to answer */
3986 if (options.network &&
3987 game_status == GAME_MODE_PLAYING &&
3988 req_state & REQUEST_WAIT_FOR_INPUT)
3989 SendToServer_PausePlaying();
3992 old_door_state = GetDoorState();
3994 /* simulate releasing mouse button over last gadget, if still pressed */
3996 HandleGadgets(-1, -1, 0);
4000 /* draw released gadget before proceeding */
4003 if (old_door_state & DOOR_OPEN_1)
4005 CloseDoor(DOOR_CLOSE_1);
4007 /* save old door content */
4008 BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
4009 0 * DXSIZE, 0, DXSIZE, DYSIZE, 1 * DXSIZE, 0);
4012 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
4013 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4015 /* clear door drawing field */
4016 DrawBackground(DX, DY, DXSIZE, DYSIZE);
4018 /* force DOOR font inside door area */
4019 SetFontStatus(GAME_MODE_PSEUDO_DOOR);
4021 /* write text for request */
4022 for (text_ptr = text, ty = 0; ty < MAX_REQUEST_LINES; ty++)
4024 char text_line[max_request_line_len + 1];
4030 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
4032 tc = *(text_ptr + tx);
4033 // if (!tc || tc == ' ')
4034 if (!tc || tc == ' ' || tc == '?' || tc == '!')
4038 if ((tc == '?' || tc == '!') && tl == 0)
4048 strncpy(text_line, text_ptr, tl);
4051 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
4052 DY + 8 + ty * (getFontHeight(font_nr) + 2),
4053 text_line, font_nr);
4055 text_ptr += tl + (tc == ' ' ? 1 : 0);
4056 // text_ptr += tl + (tc == ' ' || tc == '?' || tc == '!' ? 1 : 0);
4061 if (req_state & REQ_ASK)
4063 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
4064 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
4066 else if (req_state & REQ_CONFIRM)
4068 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
4070 else if (req_state & REQ_PLAYER)
4072 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
4073 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
4074 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
4075 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
4078 /* copy request gadgets to door backbuffer */
4079 BlitBitmap(drawto, bitmap_db_door_1, DX, DY, DXSIZE, DYSIZE, 0, 0);
4081 OpenDoor(DOOR_OPEN_1);
4083 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
4085 if (game_status == GAME_MODE_PLAYING)
4087 SetPanelBackground();
4088 SetDrawBackgroundMask(REDRAW_DOOR_1);
4092 SetDrawBackgroundMask(REDRAW_FIELD);
4098 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4100 // ---------- handle request buttons ----------
4101 result = RequestHandleEvents(req_state);
4105 if (!(req_state & REQ_STAY_OPEN))
4107 CloseDoor(DOOR_CLOSE_1);
4109 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
4110 (req_state & REQ_REOPEN))
4111 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
4116 if (game_status == GAME_MODE_PLAYING)
4118 SetPanelBackground();
4119 SetDrawBackgroundMask(REDRAW_DOOR_1);
4123 SetDrawBackgroundMask(REDRAW_FIELD);
4126 #if defined(NETWORK_AVALIABLE)
4127 /* continue network game after request */
4128 if (options.network &&
4129 game_status == GAME_MODE_PLAYING &&
4130 req_state & REQUEST_WAIT_FOR_INPUT)
4131 SendToServer_ContinuePlaying();
4134 /* restore deactivated drawing when quick-loading level tape recording */
4135 if (tape.playing && tape.deactivate_display)
4136 TapeDeactivateDisplayOn();
4141 static boolean RequestEnvelope(char *text, unsigned int req_state)
4145 if (game_status == GAME_MODE_PLAYING)
4146 BlitScreenToBitmap(backbuffer);
4148 /* disable deactivated drawing when quick-loading level tape recording */
4149 if (tape.playing && tape.deactivate_display)
4150 TapeDeactivateDisplayOff(TRUE);
4152 SetMouseCursor(CURSOR_DEFAULT);
4154 #if defined(NETWORK_AVALIABLE)
4155 /* pause network game while waiting for request to answer */
4156 if (options.network &&
4157 game_status == GAME_MODE_PLAYING &&
4158 req_state & REQUEST_WAIT_FOR_INPUT)
4159 SendToServer_PausePlaying();
4162 /* simulate releasing mouse button over last gadget, if still pressed */
4164 HandleGadgets(-1, -1, 0);
4168 // (replace with setting corresponding request background)
4169 // SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
4170 // SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4172 /* clear door drawing field */
4173 // DrawBackground(DX, DY, DXSIZE, DYSIZE);
4175 ShowEnvelopeRequest(text, req_state, ACTION_OPENING);
4177 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
4179 if (game_status == GAME_MODE_PLAYING)
4181 SetPanelBackground();
4182 SetDrawBackgroundMask(REDRAW_DOOR_1);
4186 SetDrawBackgroundMask(REDRAW_FIELD);
4192 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4194 // ---------- handle request buttons ----------
4195 result = RequestHandleEvents(req_state);
4199 ShowEnvelopeRequest(text, req_state, ACTION_CLOSING);
4203 if (game_status == GAME_MODE_PLAYING)
4205 SetPanelBackground();
4206 SetDrawBackgroundMask(REDRAW_DOOR_1);
4210 SetDrawBackgroundMask(REDRAW_FIELD);
4213 #if defined(NETWORK_AVALIABLE)
4214 /* continue network game after request */
4215 if (options.network &&
4216 game_status == GAME_MODE_PLAYING &&
4217 req_state & REQUEST_WAIT_FOR_INPUT)
4218 SendToServer_ContinuePlaying();
4221 /* restore deactivated drawing when quick-loading level tape recording */
4222 if (tape.playing && tape.deactivate_display)
4223 TapeDeactivateDisplayOn();
4228 boolean Request(char *text, unsigned int req_state)
4230 boolean overlay_active = GetOverlayActive();
4233 SetOverlayActive(FALSE);
4235 if (global.use_envelope_request)
4236 result = RequestEnvelope(text, req_state);
4238 result = RequestDoor(text, req_state);
4240 SetOverlayActive(overlay_active);
4245 static int compareDoorPartOrderInfo(const void *object1, const void *object2)
4247 const struct DoorPartOrderInfo *dpo1 = (struct DoorPartOrderInfo *)object1;
4248 const struct DoorPartOrderInfo *dpo2 = (struct DoorPartOrderInfo *)object2;
4251 if (dpo1->sort_priority != dpo2->sort_priority)
4252 compare_result = dpo1->sort_priority - dpo2->sort_priority;
4254 compare_result = dpo1->nr - dpo2->nr;
4256 return compare_result;
4259 void InitGraphicCompatibilityInfo_Doors()
4265 struct DoorInfo *door;
4269 { DOOR_1, IMG_GFX_DOOR_1_PART_1, IMG_GFX_DOOR_1_PART_8, &door_1 },
4270 { DOOR_2, IMG_GFX_DOOR_2_PART_1, IMG_GFX_DOOR_2_PART_8, &door_2 },
4272 { -1, -1, -1, NULL }
4274 struct Rect door_rect_list[] =
4276 { DX, DY, DXSIZE, DYSIZE },
4277 { VX, VY, VXSIZE, VYSIZE }
4281 for (i = 0; doors[i].door_token != -1; i++)
4283 int door_token = doors[i].door_token;
4284 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
4285 int part_1 = doors[i].part_1;
4286 int part_8 = doors[i].part_8;
4287 int part_2 = part_1 + 1;
4288 int part_3 = part_1 + 2;
4289 struct DoorInfo *door = doors[i].door;
4290 struct Rect *door_rect = &door_rect_list[door_index];
4291 boolean door_gfx_redefined = FALSE;
4293 /* check if any door part graphic definitions have been redefined */
4295 for (j = 0; door_part_controls[j].door_token != -1; j++)
4297 struct DoorPartControlInfo *dpc = &door_part_controls[j];
4298 struct FileInfo *fi = getImageListEntryFromImageID(dpc->graphic);
4300 if (dpc->door_token == door_token && fi->redefined)
4301 door_gfx_redefined = TRUE;
4304 /* check for old-style door graphic/animation modifications */
4306 if (!door_gfx_redefined)
4308 if (door->anim_mode & ANIM_STATIC_PANEL)
4310 door->panel.step_xoffset = 0;
4311 door->panel.step_yoffset = 0;
4314 if (door->anim_mode & (ANIM_HORIZONTAL | ANIM_VERTICAL))
4316 struct GraphicInfo *g_part_1 = &graphic_info[part_1];
4317 struct GraphicInfo *g_part_2 = &graphic_info[part_2];
4318 int num_door_steps, num_panel_steps;
4320 /* remove door part graphics other than the two default wings */
4322 for (j = 0; door_part_controls[j].door_token != -1; j++)
4324 struct DoorPartControlInfo *dpc = &door_part_controls[j];
4325 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4327 if (dpc->graphic >= part_3 &&
4328 dpc->graphic <= part_8)
4332 /* set graphics and screen positions of the default wings */
4334 g_part_1->width = door_rect->width;
4335 g_part_1->height = door_rect->height;
4336 g_part_2->width = door_rect->width;
4337 g_part_2->height = door_rect->height;
4338 g_part_2->src_x = door_rect->width;
4339 g_part_2->src_y = g_part_1->src_y;
4341 door->part_2.x = door->part_1.x;
4342 door->part_2.y = door->part_1.y;
4344 if (door->width != -1)
4346 g_part_1->width = door->width;
4347 g_part_2->width = door->width;
4349 // special treatment for graphics and screen position of right wing
4350 g_part_2->src_x += door_rect->width - door->width;
4351 door->part_2.x += door_rect->width - door->width;
4354 if (door->height != -1)
4356 g_part_1->height = door->height;
4357 g_part_2->height = door->height;
4359 // special treatment for graphics and screen position of bottom wing
4360 g_part_2->src_y += door_rect->height - door->height;
4361 door->part_2.y += door_rect->height - door->height;
4364 /* set animation delays for the default wings and panels */
4366 door->part_1.step_delay = door->step_delay;
4367 door->part_2.step_delay = door->step_delay;
4368 door->panel.step_delay = door->step_delay;
4370 /* set animation draw order for the default wings */
4372 door->part_1.sort_priority = 2; /* draw left wing over ... */
4373 door->part_2.sort_priority = 1; /* ... right wing */
4375 /* set animation draw offset for the default wings */
4377 if (door->anim_mode & ANIM_HORIZONTAL)
4379 door->part_1.step_xoffset = door->step_offset;
4380 door->part_1.step_yoffset = 0;
4381 door->part_2.step_xoffset = door->step_offset * -1;
4382 door->part_2.step_yoffset = 0;
4384 num_door_steps = g_part_1->width / door->step_offset;
4386 else // ANIM_VERTICAL
4388 door->part_1.step_xoffset = 0;
4389 door->part_1.step_yoffset = door->step_offset;
4390 door->part_2.step_xoffset = 0;
4391 door->part_2.step_yoffset = door->step_offset * -1;
4393 num_door_steps = g_part_1->height / door->step_offset;
4396 /* set animation draw offset for the default panels */
4398 if (door->step_offset > 1)
4400 num_panel_steps = 2 * door_rect->height / door->step_offset;
4401 door->panel.start_step = num_panel_steps - num_door_steps;
4402 door->panel.start_step_closing = door->panel.start_step;
4406 num_panel_steps = door_rect->height / door->step_offset;
4407 door->panel.start_step = num_panel_steps - num_door_steps / 2;
4408 door->panel.start_step_closing = door->panel.start_step;
4409 door->panel.step_delay *= 2;
4420 for (i = 0; door_part_controls[i].door_token != -1; i++)
4422 struct DoorPartControlInfo *dpc = &door_part_controls[i];
4423 struct DoorPartOrderInfo *dpo = &door_part_order[i];
4425 /* initialize "start_step_opening" and "start_step_closing", if needed */
4426 if (dpc->pos->start_step_opening == 0 &&
4427 dpc->pos->start_step_closing == 0)
4429 // dpc->pos->start_step_opening = dpc->pos->start_step;
4430 dpc->pos->start_step_closing = dpc->pos->start_step;
4433 /* fill structure for door part draw order (sorted below) */
4435 dpo->sort_priority = dpc->pos->sort_priority;
4438 /* sort door part controls according to sort_priority and graphic number */
4439 qsort(door_part_order, MAX_DOOR_PARTS,
4440 sizeof(struct DoorPartOrderInfo), compareDoorPartOrderInfo);
4443 unsigned int OpenDoor(unsigned int door_state)
4445 if (door_state & DOOR_COPY_BACK)
4447 if (door_state & DOOR_OPEN_1)
4448 BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
4449 1 * DXSIZE, 0, DXSIZE, DYSIZE, 0 * DXSIZE, 0);
4451 if (door_state & DOOR_OPEN_2)
4452 BlitBitmap(bitmap_db_door_2, bitmap_db_door_2,
4453 1 * VXSIZE, 0, VXSIZE, VYSIZE, 0 * VXSIZE, 0);
4455 door_state &= ~DOOR_COPY_BACK;
4458 return MoveDoor(door_state);
4461 unsigned int CloseDoor(unsigned int door_state)
4463 unsigned int old_door_state = GetDoorState();
4465 if (!(door_state & DOOR_NO_COPY_BACK))
4467 if (old_door_state & DOOR_OPEN_1)
4468 BlitBitmap(backbuffer, bitmap_db_door_1,
4469 DX, DY, DXSIZE, DYSIZE, 0, 0);
4471 if (old_door_state & DOOR_OPEN_2)
4472 BlitBitmap(backbuffer, bitmap_db_door_2,
4473 VX, VY, VXSIZE, VYSIZE, 0, 0);
4475 door_state &= ~DOOR_NO_COPY_BACK;
4478 return MoveDoor(door_state);
4481 unsigned int GetDoorState()
4483 return MoveDoor(DOOR_GET_STATE);
4486 unsigned int SetDoorState(unsigned int door_state)
4488 return MoveDoor(door_state | DOOR_SET_STATE);
4491 int euclid(int a, int b)
4493 return (b ? euclid(b, a % b) : a);
4496 unsigned int MoveDoor(unsigned int door_state)
4498 struct Rect door_rect_list[] =
4500 { DX, DY, DXSIZE, DYSIZE },
4501 { VX, VY, VXSIZE, VYSIZE }
4503 static int door1 = DOOR_CLOSE_1;
4504 static int door2 = DOOR_CLOSE_2;
4505 unsigned int door_delay = 0;
4506 unsigned int door_delay_value;
4509 if (door_state == DOOR_GET_STATE)
4510 return (door1 | door2);
4512 if (door_state & DOOR_SET_STATE)
4514 if (door_state & DOOR_ACTION_1)
4515 door1 = door_state & DOOR_ACTION_1;
4516 if (door_state & DOOR_ACTION_2)
4517 door2 = door_state & DOOR_ACTION_2;
4519 return (door1 | door2);
4522 if (!(door_state & DOOR_FORCE_REDRAW))
4524 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
4525 door_state &= ~DOOR_OPEN_1;
4526 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
4527 door_state &= ~DOOR_CLOSE_1;
4528 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
4529 door_state &= ~DOOR_OPEN_2;
4530 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
4531 door_state &= ~DOOR_CLOSE_2;
4534 if (global.autoplay_leveldir)
4536 door_state |= DOOR_NO_DELAY;
4537 door_state &= ~DOOR_CLOSE_ALL;
4540 if (game_status == GAME_MODE_EDITOR)
4541 door_state |= DOOR_NO_DELAY;
4543 if (door_state & DOOR_ACTION)
4545 boolean door_panel_drawn[NUM_DOORS];
4546 boolean panel_has_doors[NUM_DOORS];
4547 boolean door_part_skip[MAX_DOOR_PARTS];
4548 boolean door_part_done[MAX_DOOR_PARTS];
4549 boolean door_part_done_all;
4550 int num_steps[MAX_DOOR_PARTS];
4551 int max_move_delay = 0; // delay for complete animations of all doors
4552 int max_step_delay = 0; // delay (ms) between two animation frames
4553 int num_move_steps = 0; // number of animation steps for all doors
4554 int max_move_delay_doors_only = 0; // delay for doors only (no panel)
4555 int num_move_steps_doors_only = 0; // steps for doors only (no panel)
4556 int current_move_delay = 0;
4560 for (i = 0; i < NUM_DOORS; i++)
4561 panel_has_doors[i] = FALSE;
4563 for (i = 0; i < MAX_DOOR_PARTS; i++)
4565 struct DoorPartControlInfo *dpc = &door_part_controls[i];
4566 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4567 int door_token = dpc->door_token;
4569 door_part_done[i] = FALSE;
4570 door_part_skip[i] = (!(door_state & door_token) ||
4574 for (i = 0; i < MAX_DOOR_PARTS; i++)
4576 int nr = door_part_order[i].nr;
4577 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
4578 struct DoorPartPosInfo *pos = dpc->pos;
4579 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4580 int door_token = dpc->door_token;
4581 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
4582 boolean is_panel = DOOR_PART_IS_PANEL(nr);
4583 int step_xoffset = ABS(pos->step_xoffset);
4584 int step_yoffset = ABS(pos->step_yoffset);
4585 int step_delay = pos->step_delay;
4586 int current_door_state = door_state & door_token;
4587 boolean door_opening = ((current_door_state & DOOR_OPEN) != 0);
4588 boolean door_closing = ((current_door_state & DOOR_CLOSE) != 0);
4589 boolean part_opening = (is_panel ? door_closing : door_opening);
4590 int start_step = (part_opening ? pos->start_step_opening :
4591 pos->start_step_closing);
4592 float move_xsize = (step_xoffset ? g->width : 0);
4593 float move_ysize = (step_yoffset ? g->height : 0);
4594 int move_xsteps = (step_xoffset ? ceil(move_xsize / step_xoffset) : 0);
4595 int move_ysteps = (step_yoffset ? ceil(move_ysize / step_yoffset) : 0);
4596 int move_steps = (move_xsteps && move_ysteps ?
4597 MIN(move_xsteps, move_ysteps) :
4598 move_xsteps ? move_xsteps : move_ysteps) - start_step;
4599 int move_delay = move_steps * step_delay;
4601 if (door_part_skip[nr])
4604 max_move_delay = MAX(max_move_delay, move_delay);
4605 max_step_delay = (max_step_delay == 0 ? step_delay :
4606 euclid(max_step_delay, step_delay));
4607 num_steps[nr] = move_steps;
4611 max_move_delay_doors_only = MAX(max_move_delay_doors_only, move_delay);
4613 panel_has_doors[door_index] = TRUE;
4617 max_step_delay = MAX(1, max_step_delay); // prevent division by zero
4619 num_move_steps = max_move_delay / max_step_delay;
4620 num_move_steps_doors_only = max_move_delay_doors_only / max_step_delay;
4622 door_delay_value = max_step_delay;
4624 if ((door_state & DOOR_NO_DELAY) || setup.quick_doors)
4626 start = num_move_steps - 1;
4630 /* opening door sound has priority over simultaneously closing door */
4631 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
4632 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
4633 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
4634 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
4637 for (k = start; k < num_move_steps; k++)
4639 int last_frame = num_move_steps - 1; // last frame of this "for" loop
4641 door_part_done_all = TRUE;
4643 for (i = 0; i < NUM_DOORS; i++)
4644 door_panel_drawn[i] = FALSE;
4646 for (i = 0; i < MAX_DOOR_PARTS; i++)
4648 int nr = door_part_order[i].nr;
4649 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
4650 struct DoorPartPosInfo *pos = dpc->pos;
4651 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4652 int door_token = dpc->door_token;
4653 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
4654 boolean is_panel = DOOR_PART_IS_PANEL(nr);
4655 boolean is_panel_and_door_has_closed = FALSE;
4656 struct Rect *door_rect = &door_rect_list[door_index];
4657 Bitmap *bitmap_db_door = (door_token == DOOR_1 ? bitmap_db_door_1 :
4659 Bitmap *bitmap = (is_panel ? bitmap_db_door : g->bitmap);
4660 int current_door_state = door_state & door_token;
4661 boolean door_opening = ((current_door_state & DOOR_OPEN) != 0);
4662 boolean door_closing = !door_opening;
4663 boolean part_opening = (is_panel ? door_closing : door_opening);
4664 boolean part_closing = !part_opening;
4665 int start_step = (part_opening ? pos->start_step_opening :
4666 pos->start_step_closing);
4667 int step_delay = pos->step_delay;
4668 int step_factor = step_delay / max_step_delay;
4669 int k1 = (step_factor ? k / step_factor + 1 : k);
4670 int k2 = (part_opening ? k1 + start_step : num_steps[nr] - k1);
4671 int kk = MAX(0, k2);
4674 int src_x, src_y, src_xx, src_yy;
4675 int dst_x, dst_y, dst_xx, dst_yy;
4678 if (door_part_skip[nr])
4681 if (!(door_state & door_token))
4689 int k2_door = (door_opening ? k : num_move_steps_doors_only - k - 1);
4690 int kk_door = MAX(0, k2_door);
4691 int sync_frame = kk_door * door_delay_value;
4692 int frame = getGraphicAnimationFrame(dpc->graphic, sync_frame);
4694 getFixedGraphicSource(dpc->graphic, frame, &bitmap,
4695 &g_src_x, &g_src_y);
4700 if (!door_panel_drawn[door_index])
4702 ClearRectangle(drawto, door_rect->x, door_rect->y,
4703 door_rect->width, door_rect->height);
4705 door_panel_drawn[door_index] = TRUE;
4708 // draw opening or closing door parts
4710 if (pos->step_xoffset < 0) // door part on right side
4713 dst_xx = pos->x + ABS(kk * pos->step_xoffset);
4716 if (dst_xx + width > door_rect->width)
4717 width = door_rect->width - dst_xx;
4719 else // door part on left side
4722 dst_xx = pos->x - kk * pos->step_xoffset;
4726 src_xx = ABS(dst_xx);
4730 width = g->width - src_xx;
4732 if (width > door_rect->width)
4733 width = door_rect->width;
4735 // printf("::: k == %d [%d] \n", k, start_step);
4738 if (pos->step_yoffset < 0) // door part on bottom side
4741 dst_yy = pos->y + ABS(kk * pos->step_yoffset);
4744 if (dst_yy + height > door_rect->height)
4745 height = door_rect->height - dst_yy;
4747 else // door part on top side
4750 dst_yy = pos->y - kk * pos->step_yoffset;
4754 src_yy = ABS(dst_yy);
4758 height = g->height - src_yy;
4761 src_x = g_src_x + src_xx;
4762 src_y = g_src_y + src_yy;
4764 dst_x = door_rect->x + dst_xx;
4765 dst_y = door_rect->y + dst_yy;
4767 is_panel_and_door_has_closed =
4770 panel_has_doors[door_index] &&
4771 k >= num_move_steps_doors_only - 1);
4773 if (width >= 0 && width <= g->width &&
4774 height >= 0 && height <= g->height &&
4775 !is_panel_and_door_has_closed)
4777 if (is_panel || !pos->draw_masked)
4778 BlitBitmap(bitmap, drawto, src_x, src_y, width, height,
4781 BlitBitmapMasked(bitmap, drawto, src_x, src_y, width, height,
4785 redraw_mask |= REDRAW_DOOR_FROM_TOKEN(door_token);
4787 if ((part_opening && (width < 0 || height < 0)) ||
4788 (part_closing && (width >= g->width && height >= g->height)))
4789 door_part_done[nr] = TRUE;
4791 // continue door part animations, but not panel after door has closed
4792 if (!door_part_done[nr] && !is_panel_and_door_has_closed)
4793 door_part_done_all = FALSE;
4796 if (!(door_state & DOOR_NO_DELAY))
4800 SkipUntilDelayReached(&door_delay, door_delay_value, &k, last_frame);
4802 current_move_delay += max_step_delay;
4805 if (door_part_done_all)
4810 if (door_state & DOOR_ACTION_1)
4811 door1 = door_state & DOOR_ACTION_1;
4812 if (door_state & DOOR_ACTION_2)
4813 door2 = door_state & DOOR_ACTION_2;
4815 // draw masked border over door area
4816 DrawMaskedBorder(REDRAW_DOOR_1);
4817 DrawMaskedBorder(REDRAW_DOOR_2);
4819 return (door1 | door2);
4822 static boolean useSpecialEditorDoor()
4824 int graphic = IMG_GLOBAL_BORDER_EDITOR;
4825 boolean redefined = getImageListEntryFromImageID(graphic)->redefined;
4827 // do not draw special editor door if editor border defined or redefined
4828 if (graphic_info[graphic].bitmap != NULL || redefined)
4831 // do not draw special editor door if global border defined to be empty
4832 if (graphic_info[IMG_GLOBAL_BORDER].bitmap == NULL)
4835 // do not draw special editor door if viewport definitions do not match
4839 EY + EYSIZE != VY + VYSIZE)
4845 void DrawSpecialEditorDoor()
4847 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
4848 int top_border_width = gfx1->width;
4849 int top_border_height = gfx1->height;
4850 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
4851 int ex = EX - outer_border;
4852 int ey = EY - outer_border;
4853 int vy = VY - outer_border;
4854 int exsize = EXSIZE + 2 * outer_border;
4856 if (!useSpecialEditorDoor())
4859 /* draw bigger level editor toolbox window */
4860 BlitBitmap(gfx1->bitmap, drawto, gfx1->src_x, gfx1->src_y,
4861 top_border_width, top_border_height, ex, ey - top_border_height);
4862 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto, ex, vy,
4863 exsize, EYSIZE - VYSIZE + outer_border, ex, ey);
4865 redraw_mask |= REDRAW_ALL;
4868 void UndrawSpecialEditorDoor()
4870 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
4871 int top_border_width = gfx1->width;
4872 int top_border_height = gfx1->height;
4873 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
4874 int ex = EX - outer_border;
4875 int ey = EY - outer_border;
4876 int ey_top = ey - top_border_height;
4877 int exsize = EXSIZE + 2 * outer_border;
4878 int eysize = EYSIZE + 2 * outer_border;
4880 if (!useSpecialEditorDoor())
4883 /* draw normal tape recorder window */
4884 if (graphic_info[IMG_GLOBAL_BORDER].bitmap)
4886 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
4887 ex, ey_top, top_border_width, top_border_height,
4889 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
4890 ex, ey, exsize, eysize, ex, ey);
4894 // if screen background is set to "[NONE]", clear editor toolbox window
4895 ClearRectangle(drawto, ex, ey_top, top_border_width, top_border_height);
4896 ClearRectangle(drawto, ex, ey, exsize, eysize);
4899 redraw_mask |= REDRAW_ALL;
4903 /* ---------- new tool button stuff ---------------------------------------- */
4908 struct TextPosInfo *pos;
4911 } toolbutton_info[NUM_TOOL_BUTTONS] =
4914 IMG_GFX_REQUEST_BUTTON_YES, &request.button.yes,
4915 TOOL_CTRL_ID_YES, "yes"
4918 IMG_GFX_REQUEST_BUTTON_NO, &request.button.no,
4919 TOOL_CTRL_ID_NO, "no"
4922 IMG_GFX_REQUEST_BUTTON_CONFIRM, &request.button.confirm,
4923 TOOL_CTRL_ID_CONFIRM, "confirm"
4926 IMG_GFX_REQUEST_BUTTON_PLAYER_1, &request.button.player_1,
4927 TOOL_CTRL_ID_PLAYER_1, "player 1"
4930 IMG_GFX_REQUEST_BUTTON_PLAYER_2, &request.button.player_2,
4931 TOOL_CTRL_ID_PLAYER_2, "player 2"
4934 IMG_GFX_REQUEST_BUTTON_PLAYER_3, &request.button.player_3,
4935 TOOL_CTRL_ID_PLAYER_3, "player 3"
4938 IMG_GFX_REQUEST_BUTTON_PLAYER_4, &request.button.player_4,
4939 TOOL_CTRL_ID_PLAYER_4, "player 4"
4943 void CreateToolButtons()
4947 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4949 struct GraphicInfo *gfx = &graphic_info[toolbutton_info[i].graphic];
4950 struct TextPosInfo *pos = toolbutton_info[i].pos;
4951 struct GadgetInfo *gi;
4952 Bitmap *deco_bitmap = None;
4953 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
4954 unsigned int event_mask = GD_EVENT_RELEASED;
4957 int gd_x = gfx->src_x;
4958 int gd_y = gfx->src_y;
4959 int gd_xp = gfx->src_x + gfx->pressed_xoffset;
4960 int gd_yp = gfx->src_y + gfx->pressed_yoffset;
4963 if (global.use_envelope_request)
4964 setRequestPosition(&dx, &dy, TRUE);
4966 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
4968 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
4970 getSizedGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr), 0,
4971 pos->size, &deco_bitmap, &deco_x, &deco_y);
4972 deco_xpos = (gfx->width - pos->size) / 2;
4973 deco_ypos = (gfx->height - pos->size) / 2;
4976 gi = CreateGadget(GDI_CUSTOM_ID, id,
4977 GDI_INFO_TEXT, toolbutton_info[i].infotext,
4978 GDI_X, dx + GDI_ACTIVE_POS(pos->x),
4979 GDI_Y, dy + GDI_ACTIVE_POS(pos->y),
4980 GDI_WIDTH, gfx->width,
4981 GDI_HEIGHT, gfx->height,
4982 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
4983 GDI_STATE, GD_BUTTON_UNPRESSED,
4984 GDI_DESIGN_UNPRESSED, gfx->bitmap, gd_x, gd_y,
4985 GDI_DESIGN_PRESSED, gfx->bitmap, gd_xp, gd_yp,
4986 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
4987 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
4988 GDI_DECORATION_SIZE, pos->size, pos->size,
4989 GDI_DECORATION_SHIFTING, 1, 1,
4990 GDI_DIRECT_DRAW, FALSE,
4991 GDI_EVENT_MASK, event_mask,
4992 GDI_CALLBACK_ACTION, HandleToolButtons,
4996 Error(ERR_EXIT, "cannot create gadget");
4998 tool_gadget[id] = gi;
5002 void FreeToolButtons()
5006 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
5007 FreeGadget(tool_gadget[i]);
5010 static void UnmapToolButtons()
5014 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
5015 UnmapGadget(tool_gadget[i]);
5018 static void HandleToolButtons(struct GadgetInfo *gi)
5020 request_gadget_id = gi->custom_id;
5023 static struct Mapping_EM_to_RND_object
5026 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
5027 boolean is_backside; /* backside of moving element */
5033 em_object_mapping_list[] =
5036 Xblank, TRUE, FALSE,
5040 Yacid_splash_eB, FALSE, FALSE,
5041 EL_ACID_SPLASH_RIGHT, -1, -1
5044 Yacid_splash_wB, FALSE, FALSE,
5045 EL_ACID_SPLASH_LEFT, -1, -1
5048 #ifdef EM_ENGINE_BAD_ROLL
5050 Xstone_force_e, FALSE, FALSE,
5051 EL_ROCK, -1, MV_BIT_RIGHT
5054 Xstone_force_w, FALSE, FALSE,
5055 EL_ROCK, -1, MV_BIT_LEFT
5058 Xnut_force_e, FALSE, FALSE,
5059 EL_NUT, -1, MV_BIT_RIGHT
5062 Xnut_force_w, FALSE, FALSE,
5063 EL_NUT, -1, MV_BIT_LEFT
5066 Xspring_force_e, FALSE, FALSE,
5067 EL_SPRING, -1, MV_BIT_RIGHT
5070 Xspring_force_w, FALSE, FALSE,
5071 EL_SPRING, -1, MV_BIT_LEFT
5074 Xemerald_force_e, FALSE, FALSE,
5075 EL_EMERALD, -1, MV_BIT_RIGHT
5078 Xemerald_force_w, FALSE, FALSE,
5079 EL_EMERALD, -1, MV_BIT_LEFT
5082 Xdiamond_force_e, FALSE, FALSE,
5083 EL_DIAMOND, -1, MV_BIT_RIGHT
5086 Xdiamond_force_w, FALSE, FALSE,
5087 EL_DIAMOND, -1, MV_BIT_LEFT
5090 Xbomb_force_e, FALSE, FALSE,
5091 EL_BOMB, -1, MV_BIT_RIGHT
5094 Xbomb_force_w, FALSE, FALSE,
5095 EL_BOMB, -1, MV_BIT_LEFT
5097 #endif /* EM_ENGINE_BAD_ROLL */
5100 Xstone, TRUE, FALSE,
5104 Xstone_pause, FALSE, FALSE,
5108 Xstone_fall, FALSE, FALSE,
5112 Ystone_s, FALSE, FALSE,
5113 EL_ROCK, ACTION_FALLING, -1
5116 Ystone_sB, FALSE, TRUE,
5117 EL_ROCK, ACTION_FALLING, -1
5120 Ystone_e, FALSE, FALSE,
5121 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
5124 Ystone_eB, FALSE, TRUE,
5125 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
5128 Ystone_w, FALSE, FALSE,
5129 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
5132 Ystone_wB, FALSE, TRUE,
5133 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
5140 Xnut_pause, FALSE, FALSE,
5144 Xnut_fall, FALSE, FALSE,
5148 Ynut_s, FALSE, FALSE,
5149 EL_NUT, ACTION_FALLING, -1
5152 Ynut_sB, FALSE, TRUE,
5153 EL_NUT, ACTION_FALLING, -1
5156 Ynut_e, FALSE, FALSE,
5157 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
5160 Ynut_eB, FALSE, TRUE,
5161 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
5164 Ynut_w, FALSE, FALSE,
5165 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
5168 Ynut_wB, FALSE, TRUE,
5169 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
5172 Xbug_n, TRUE, FALSE,
5176 Xbug_e, TRUE, FALSE,
5177 EL_BUG_RIGHT, -1, -1
5180 Xbug_s, TRUE, FALSE,
5184 Xbug_w, TRUE, FALSE,
5188 Xbug_gon, FALSE, FALSE,
5192 Xbug_goe, FALSE, FALSE,
5193 EL_BUG_RIGHT, -1, -1
5196 Xbug_gos, FALSE, FALSE,
5200 Xbug_gow, FALSE, FALSE,
5204 Ybug_n, FALSE, FALSE,
5205 EL_BUG, ACTION_MOVING, MV_BIT_UP
5208 Ybug_nB, FALSE, TRUE,
5209 EL_BUG, ACTION_MOVING, MV_BIT_UP
5212 Ybug_e, FALSE, FALSE,
5213 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
5216 Ybug_eB, FALSE, TRUE,
5217 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
5220 Ybug_s, FALSE, FALSE,
5221 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
5224 Ybug_sB, FALSE, TRUE,
5225 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
5228 Ybug_w, FALSE, FALSE,
5229 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
5232 Ybug_wB, FALSE, TRUE,
5233 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
5236 Ybug_w_n, FALSE, FALSE,
5237 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
5240 Ybug_n_e, FALSE, FALSE,
5241 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
5244 Ybug_e_s, FALSE, FALSE,
5245 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
5248 Ybug_s_w, FALSE, FALSE,
5249 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
5252 Ybug_e_n, FALSE, FALSE,
5253 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
5256 Ybug_s_e, FALSE, FALSE,
5257 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
5260 Ybug_w_s, FALSE, FALSE,
5261 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
5264 Ybug_n_w, FALSE, FALSE,
5265 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
5268 Ybug_stone, FALSE, FALSE,
5269 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
5272 Ybug_spring, FALSE, FALSE,
5273 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
5276 Xtank_n, TRUE, FALSE,
5277 EL_SPACESHIP_UP, -1, -1
5280 Xtank_e, TRUE, FALSE,
5281 EL_SPACESHIP_RIGHT, -1, -1
5284 Xtank_s, TRUE, FALSE,
5285 EL_SPACESHIP_DOWN, -1, -1
5288 Xtank_w, TRUE, FALSE,
5289 EL_SPACESHIP_LEFT, -1, -1
5292 Xtank_gon, FALSE, FALSE,
5293 EL_SPACESHIP_UP, -1, -1
5296 Xtank_goe, FALSE, FALSE,
5297 EL_SPACESHIP_RIGHT, -1, -1
5300 Xtank_gos, FALSE, FALSE,
5301 EL_SPACESHIP_DOWN, -1, -1
5304 Xtank_gow, FALSE, FALSE,
5305 EL_SPACESHIP_LEFT, -1, -1
5308 Ytank_n, FALSE, FALSE,
5309 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
5312 Ytank_nB, FALSE, TRUE,
5313 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
5316 Ytank_e, FALSE, FALSE,
5317 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
5320 Ytank_eB, FALSE, TRUE,
5321 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
5324 Ytank_s, FALSE, FALSE,
5325 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
5328 Ytank_sB, FALSE, TRUE,
5329 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
5332 Ytank_w, FALSE, FALSE,
5333 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
5336 Ytank_wB, FALSE, TRUE,
5337 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
5340 Ytank_w_n, FALSE, FALSE,
5341 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
5344 Ytank_n_e, FALSE, FALSE,
5345 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
5348 Ytank_e_s, FALSE, FALSE,
5349 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
5352 Ytank_s_w, FALSE, FALSE,
5353 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
5356 Ytank_e_n, FALSE, FALSE,
5357 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
5360 Ytank_s_e, FALSE, FALSE,
5361 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
5364 Ytank_w_s, FALSE, FALSE,
5365 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
5368 Ytank_n_w, FALSE, FALSE,
5369 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
5372 Ytank_stone, FALSE, FALSE,
5373 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
5376 Ytank_spring, FALSE, FALSE,
5377 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
5380 Xandroid, TRUE, FALSE,
5381 EL_EMC_ANDROID, ACTION_ACTIVE, -1
5384 Xandroid_1_n, FALSE, FALSE,
5385 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
5388 Xandroid_2_n, FALSE, FALSE,
5389 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
5392 Xandroid_1_e, FALSE, FALSE,
5393 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
5396 Xandroid_2_e, FALSE, FALSE,
5397 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
5400 Xandroid_1_w, FALSE, FALSE,
5401 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
5404 Xandroid_2_w, FALSE, FALSE,
5405 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
5408 Xandroid_1_s, FALSE, FALSE,
5409 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
5412 Xandroid_2_s, FALSE, FALSE,
5413 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
5416 Yandroid_n, FALSE, FALSE,
5417 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
5420 Yandroid_nB, FALSE, TRUE,
5421 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
5424 Yandroid_ne, FALSE, FALSE,
5425 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
5428 Yandroid_neB, FALSE, TRUE,
5429 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
5432 Yandroid_e, FALSE, FALSE,
5433 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
5436 Yandroid_eB, FALSE, TRUE,
5437 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
5440 Yandroid_se, FALSE, FALSE,
5441 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
5444 Yandroid_seB, FALSE, TRUE,
5445 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
5448 Yandroid_s, FALSE, FALSE,
5449 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
5452 Yandroid_sB, FALSE, TRUE,
5453 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
5456 Yandroid_sw, FALSE, FALSE,
5457 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
5460 Yandroid_swB, FALSE, TRUE,
5461 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
5464 Yandroid_w, FALSE, FALSE,
5465 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
5468 Yandroid_wB, FALSE, TRUE,
5469 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
5472 Yandroid_nw, FALSE, FALSE,
5473 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
5476 Yandroid_nwB, FALSE, TRUE,
5477 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
5480 Xspring, TRUE, FALSE,
5484 Xspring_pause, FALSE, FALSE,
5488 Xspring_e, FALSE, FALSE,
5492 Xspring_w, FALSE, FALSE,
5496 Xspring_fall, FALSE, FALSE,
5500 Yspring_s, FALSE, FALSE,
5501 EL_SPRING, ACTION_FALLING, -1
5504 Yspring_sB, FALSE, TRUE,
5505 EL_SPRING, ACTION_FALLING, -1
5508 Yspring_e, FALSE, FALSE,
5509 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
5512 Yspring_eB, FALSE, TRUE,
5513 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
5516 Yspring_w, FALSE, FALSE,
5517 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
5520 Yspring_wB, FALSE, TRUE,
5521 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
5524 Yspring_kill_e, FALSE, FALSE,
5525 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
5528 Yspring_kill_eB, FALSE, TRUE,
5529 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
5532 Yspring_kill_w, FALSE, FALSE,
5533 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
5536 Yspring_kill_wB, FALSE, TRUE,
5537 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
5540 Xeater_n, TRUE, FALSE,
5541 EL_YAMYAM_UP, -1, -1
5544 Xeater_e, TRUE, FALSE,
5545 EL_YAMYAM_RIGHT, -1, -1
5548 Xeater_w, TRUE, FALSE,
5549 EL_YAMYAM_LEFT, -1, -1
5552 Xeater_s, TRUE, FALSE,
5553 EL_YAMYAM_DOWN, -1, -1
5556 Yeater_n, FALSE, FALSE,
5557 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
5560 Yeater_nB, FALSE, TRUE,
5561 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
5564 Yeater_e, FALSE, FALSE,
5565 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
5568 Yeater_eB, FALSE, TRUE,
5569 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
5572 Yeater_s, FALSE, FALSE,
5573 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
5576 Yeater_sB, FALSE, TRUE,
5577 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
5580 Yeater_w, FALSE, FALSE,
5581 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
5584 Yeater_wB, FALSE, TRUE,
5585 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
5588 Yeater_stone, FALSE, FALSE,
5589 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
5592 Yeater_spring, FALSE, FALSE,
5593 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
5596 Xalien, TRUE, FALSE,
5600 Xalien_pause, FALSE, FALSE,
5604 Yalien_n, FALSE, FALSE,
5605 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
5608 Yalien_nB, FALSE, TRUE,
5609 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
5612 Yalien_e, FALSE, FALSE,
5613 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
5616 Yalien_eB, FALSE, TRUE,
5617 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
5620 Yalien_s, FALSE, FALSE,
5621 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
5624 Yalien_sB, FALSE, TRUE,
5625 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
5628 Yalien_w, FALSE, FALSE,
5629 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
5632 Yalien_wB, FALSE, TRUE,
5633 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
5636 Yalien_stone, FALSE, FALSE,
5637 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
5640 Yalien_spring, FALSE, FALSE,
5641 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
5644 Xemerald, TRUE, FALSE,
5648 Xemerald_pause, FALSE, FALSE,
5652 Xemerald_fall, FALSE, FALSE,
5656 Xemerald_shine, FALSE, FALSE,
5657 EL_EMERALD, ACTION_TWINKLING, -1
5660 Yemerald_s, FALSE, FALSE,
5661 EL_EMERALD, ACTION_FALLING, -1
5664 Yemerald_sB, FALSE, TRUE,
5665 EL_EMERALD, ACTION_FALLING, -1
5668 Yemerald_e, FALSE, FALSE,
5669 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
5672 Yemerald_eB, FALSE, TRUE,
5673 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
5676 Yemerald_w, FALSE, FALSE,
5677 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
5680 Yemerald_wB, FALSE, TRUE,
5681 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
5684 Yemerald_eat, FALSE, FALSE,
5685 EL_EMERALD, ACTION_COLLECTING, -1
5688 Yemerald_stone, FALSE, FALSE,
5689 EL_NUT, ACTION_BREAKING, -1
5692 Xdiamond, TRUE, FALSE,
5696 Xdiamond_pause, FALSE, FALSE,
5700 Xdiamond_fall, FALSE, FALSE,
5704 Xdiamond_shine, FALSE, FALSE,
5705 EL_DIAMOND, ACTION_TWINKLING, -1
5708 Ydiamond_s, FALSE, FALSE,
5709 EL_DIAMOND, ACTION_FALLING, -1
5712 Ydiamond_sB, FALSE, TRUE,
5713 EL_DIAMOND, ACTION_FALLING, -1
5716 Ydiamond_e, FALSE, FALSE,
5717 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
5720 Ydiamond_eB, FALSE, TRUE,
5721 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
5724 Ydiamond_w, FALSE, FALSE,
5725 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
5728 Ydiamond_wB, FALSE, TRUE,
5729 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
5732 Ydiamond_eat, FALSE, FALSE,
5733 EL_DIAMOND, ACTION_COLLECTING, -1
5736 Ydiamond_stone, FALSE, FALSE,
5737 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
5740 Xdrip_fall, TRUE, FALSE,
5741 EL_AMOEBA_DROP, -1, -1
5744 Xdrip_stretch, FALSE, FALSE,
5745 EL_AMOEBA_DROP, ACTION_FALLING, -1
5748 Xdrip_stretchB, FALSE, TRUE,
5749 EL_AMOEBA_DROP, ACTION_FALLING, -1
5752 Xdrip_eat, FALSE, FALSE,
5753 EL_AMOEBA_DROP, ACTION_GROWING, -1
5756 Ydrip_s1, FALSE, FALSE,
5757 EL_AMOEBA_DROP, ACTION_FALLING, -1
5760 Ydrip_s1B, FALSE, TRUE,
5761 EL_AMOEBA_DROP, ACTION_FALLING, -1
5764 Ydrip_s2, FALSE, FALSE,
5765 EL_AMOEBA_DROP, ACTION_FALLING, -1
5768 Ydrip_s2B, FALSE, TRUE,
5769 EL_AMOEBA_DROP, ACTION_FALLING, -1
5776 Xbomb_pause, FALSE, FALSE,
5780 Xbomb_fall, FALSE, FALSE,
5784 Ybomb_s, FALSE, FALSE,
5785 EL_BOMB, ACTION_FALLING, -1
5788 Ybomb_sB, FALSE, TRUE,
5789 EL_BOMB, ACTION_FALLING, -1
5792 Ybomb_e, FALSE, FALSE,
5793 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
5796 Ybomb_eB, FALSE, TRUE,
5797 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
5800 Ybomb_w, FALSE, FALSE,
5801 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
5804 Ybomb_wB, FALSE, TRUE,
5805 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
5808 Ybomb_eat, FALSE, FALSE,
5809 EL_BOMB, ACTION_ACTIVATING, -1
5812 Xballoon, TRUE, FALSE,
5816 Yballoon_n, FALSE, FALSE,
5817 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
5820 Yballoon_nB, FALSE, TRUE,
5821 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
5824 Yballoon_e, FALSE, FALSE,
5825 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
5828 Yballoon_eB, FALSE, TRUE,
5829 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
5832 Yballoon_s, FALSE, FALSE,
5833 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
5836 Yballoon_sB, FALSE, TRUE,
5837 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
5840 Yballoon_w, FALSE, FALSE,
5841 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
5844 Yballoon_wB, FALSE, TRUE,
5845 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
5848 Xgrass, TRUE, FALSE,
5849 EL_EMC_GRASS, -1, -1
5852 Ygrass_nB, FALSE, FALSE,
5853 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
5856 Ygrass_eB, FALSE, FALSE,
5857 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
5860 Ygrass_sB, FALSE, FALSE,
5861 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
5864 Ygrass_wB, FALSE, FALSE,
5865 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
5872 Ydirt_nB, FALSE, FALSE,
5873 EL_SAND, ACTION_DIGGING, MV_BIT_UP
5876 Ydirt_eB, FALSE, FALSE,
5877 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
5880 Ydirt_sB, FALSE, FALSE,
5881 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
5884 Ydirt_wB, FALSE, FALSE,
5885 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
5888 Xacid_ne, TRUE, FALSE,
5889 EL_ACID_POOL_TOPRIGHT, -1, -1
5892 Xacid_se, TRUE, FALSE,
5893 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
5896 Xacid_s, TRUE, FALSE,
5897 EL_ACID_POOL_BOTTOM, -1, -1
5900 Xacid_sw, TRUE, FALSE,
5901 EL_ACID_POOL_BOTTOMLEFT, -1, -1
5904 Xacid_nw, TRUE, FALSE,
5905 EL_ACID_POOL_TOPLEFT, -1, -1
5908 Xacid_1, TRUE, FALSE,
5912 Xacid_2, FALSE, FALSE,
5916 Xacid_3, FALSE, FALSE,
5920 Xacid_4, FALSE, FALSE,
5924 Xacid_5, FALSE, FALSE,
5928 Xacid_6, FALSE, FALSE,
5932 Xacid_7, FALSE, FALSE,
5936 Xacid_8, FALSE, FALSE,
5940 Xball_1, TRUE, FALSE,
5941 EL_EMC_MAGIC_BALL, -1, -1
5944 Xball_1B, FALSE, FALSE,
5945 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5948 Xball_2, FALSE, FALSE,
5949 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5952 Xball_2B, FALSE, FALSE,
5953 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5956 Yball_eat, FALSE, FALSE,
5957 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
5960 Ykey_1_eat, FALSE, FALSE,
5961 EL_EM_KEY_1, ACTION_COLLECTING, -1
5964 Ykey_2_eat, FALSE, FALSE,
5965 EL_EM_KEY_2, ACTION_COLLECTING, -1
5968 Ykey_3_eat, FALSE, FALSE,
5969 EL_EM_KEY_3, ACTION_COLLECTING, -1
5972 Ykey_4_eat, FALSE, FALSE,
5973 EL_EM_KEY_4, ACTION_COLLECTING, -1
5976 Ykey_5_eat, FALSE, FALSE,
5977 EL_EMC_KEY_5, ACTION_COLLECTING, -1
5980 Ykey_6_eat, FALSE, FALSE,
5981 EL_EMC_KEY_6, ACTION_COLLECTING, -1
5984 Ykey_7_eat, FALSE, FALSE,
5985 EL_EMC_KEY_7, ACTION_COLLECTING, -1
5988 Ykey_8_eat, FALSE, FALSE,
5989 EL_EMC_KEY_8, ACTION_COLLECTING, -1
5992 Ylenses_eat, FALSE, FALSE,
5993 EL_EMC_LENSES, ACTION_COLLECTING, -1
5996 Ymagnify_eat, FALSE, FALSE,
5997 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
6000 Ygrass_eat, FALSE, FALSE,
6001 EL_EMC_GRASS, ACTION_SNAPPING, -1
6004 Ydirt_eat, FALSE, FALSE,
6005 EL_SAND, ACTION_SNAPPING, -1
6008 Xgrow_ns, TRUE, FALSE,
6009 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
6012 Ygrow_ns_eat, FALSE, FALSE,
6013 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
6016 Xgrow_ew, TRUE, FALSE,
6017 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
6020 Ygrow_ew_eat, FALSE, FALSE,
6021 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
6024 Xwonderwall, TRUE, FALSE,
6025 EL_MAGIC_WALL, -1, -1
6028 XwonderwallB, FALSE, FALSE,
6029 EL_MAGIC_WALL, ACTION_ACTIVE, -1
6032 Xamoeba_1, TRUE, FALSE,
6033 EL_AMOEBA_DRY, ACTION_OTHER, -1
6036 Xamoeba_2, FALSE, FALSE,
6037 EL_AMOEBA_DRY, ACTION_OTHER, -1
6040 Xamoeba_3, FALSE, FALSE,
6041 EL_AMOEBA_DRY, ACTION_OTHER, -1
6044 Xamoeba_4, FALSE, FALSE,
6045 EL_AMOEBA_DRY, ACTION_OTHER, -1
6048 Xamoeba_5, TRUE, FALSE,
6049 EL_AMOEBA_WET, ACTION_OTHER, -1
6052 Xamoeba_6, FALSE, FALSE,
6053 EL_AMOEBA_WET, ACTION_OTHER, -1
6056 Xamoeba_7, FALSE, FALSE,
6057 EL_AMOEBA_WET, ACTION_OTHER, -1
6060 Xamoeba_8, FALSE, FALSE,
6061 EL_AMOEBA_WET, ACTION_OTHER, -1
6064 Xdoor_1, TRUE, FALSE,
6065 EL_EM_GATE_1, -1, -1
6068 Xdoor_2, TRUE, FALSE,
6069 EL_EM_GATE_2, -1, -1
6072 Xdoor_3, TRUE, FALSE,
6073 EL_EM_GATE_3, -1, -1
6076 Xdoor_4, TRUE, FALSE,
6077 EL_EM_GATE_4, -1, -1
6080 Xdoor_5, TRUE, FALSE,
6081 EL_EMC_GATE_5, -1, -1
6084 Xdoor_6, TRUE, FALSE,
6085 EL_EMC_GATE_6, -1, -1
6088 Xdoor_7, TRUE, FALSE,
6089 EL_EMC_GATE_7, -1, -1
6092 Xdoor_8, TRUE, FALSE,
6093 EL_EMC_GATE_8, -1, -1
6096 Xkey_1, TRUE, FALSE,
6100 Xkey_2, TRUE, FALSE,
6104 Xkey_3, TRUE, FALSE,
6108 Xkey_4, TRUE, FALSE,
6112 Xkey_5, TRUE, FALSE,
6113 EL_EMC_KEY_5, -1, -1
6116 Xkey_6, TRUE, FALSE,
6117 EL_EMC_KEY_6, -1, -1
6120 Xkey_7, TRUE, FALSE,
6121 EL_EMC_KEY_7, -1, -1
6124 Xkey_8, TRUE, FALSE,
6125 EL_EMC_KEY_8, -1, -1
6128 Xwind_n, TRUE, FALSE,
6129 EL_BALLOON_SWITCH_UP, -1, -1
6132 Xwind_e, TRUE, FALSE,
6133 EL_BALLOON_SWITCH_RIGHT, -1, -1
6136 Xwind_s, TRUE, FALSE,
6137 EL_BALLOON_SWITCH_DOWN, -1, -1
6140 Xwind_w, TRUE, FALSE,
6141 EL_BALLOON_SWITCH_LEFT, -1, -1
6144 Xwind_nesw, TRUE, FALSE,
6145 EL_BALLOON_SWITCH_ANY, -1, -1
6148 Xwind_stop, TRUE, FALSE,
6149 EL_BALLOON_SWITCH_NONE, -1, -1
6153 EL_EM_EXIT_CLOSED, -1, -1
6156 Xexit_1, TRUE, FALSE,
6157 EL_EM_EXIT_OPEN, -1, -1
6160 Xexit_2, FALSE, FALSE,
6161 EL_EM_EXIT_OPEN, -1, -1
6164 Xexit_3, FALSE, FALSE,
6165 EL_EM_EXIT_OPEN, -1, -1
6168 Xdynamite, TRUE, FALSE,
6169 EL_EM_DYNAMITE, -1, -1
6172 Ydynamite_eat, FALSE, FALSE,
6173 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
6176 Xdynamite_1, TRUE, FALSE,
6177 EL_EM_DYNAMITE_ACTIVE, -1, -1
6180 Xdynamite_2, FALSE, FALSE,
6181 EL_EM_DYNAMITE_ACTIVE, -1, -1
6184 Xdynamite_3, FALSE, FALSE,
6185 EL_EM_DYNAMITE_ACTIVE, -1, -1
6188 Xdynamite_4, FALSE, FALSE,
6189 EL_EM_DYNAMITE_ACTIVE, -1, -1
6192 Xbumper, TRUE, FALSE,
6193 EL_EMC_SPRING_BUMPER, -1, -1
6196 XbumperB, FALSE, FALSE,
6197 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
6200 Xwheel, TRUE, FALSE,
6201 EL_ROBOT_WHEEL, -1, -1
6204 XwheelB, FALSE, FALSE,
6205 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
6208 Xswitch, TRUE, FALSE,
6209 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
6212 XswitchB, FALSE, FALSE,
6213 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
6217 EL_QUICKSAND_EMPTY, -1, -1
6220 Xsand_stone, TRUE, FALSE,
6221 EL_QUICKSAND_FULL, -1, -1
6224 Xsand_stonein_1, FALSE, TRUE,
6225 EL_ROCK, ACTION_FILLING, -1
6228 Xsand_stonein_2, FALSE, TRUE,
6229 EL_ROCK, ACTION_FILLING, -1
6232 Xsand_stonein_3, FALSE, TRUE,
6233 EL_ROCK, ACTION_FILLING, -1
6236 Xsand_stonein_4, FALSE, TRUE,
6237 EL_ROCK, ACTION_FILLING, -1
6240 Xsand_stonesand_1, FALSE, FALSE,
6241 EL_QUICKSAND_EMPTYING, -1, -1
6244 Xsand_stonesand_2, FALSE, FALSE,
6245 EL_QUICKSAND_EMPTYING, -1, -1
6248 Xsand_stonesand_3, FALSE, FALSE,
6249 EL_QUICKSAND_EMPTYING, -1, -1
6252 Xsand_stonesand_4, FALSE, FALSE,
6253 EL_QUICKSAND_EMPTYING, -1, -1
6256 Xsand_stonesand_quickout_1, FALSE, FALSE,
6257 EL_QUICKSAND_EMPTYING, -1, -1
6260 Xsand_stonesand_quickout_2, FALSE, FALSE,
6261 EL_QUICKSAND_EMPTYING, -1, -1
6264 Xsand_stoneout_1, FALSE, FALSE,
6265 EL_ROCK, ACTION_EMPTYING, -1
6268 Xsand_stoneout_2, FALSE, FALSE,
6269 EL_ROCK, ACTION_EMPTYING, -1
6272 Xsand_sandstone_1, FALSE, FALSE,
6273 EL_QUICKSAND_FILLING, -1, -1
6276 Xsand_sandstone_2, FALSE, FALSE,
6277 EL_QUICKSAND_FILLING, -1, -1
6280 Xsand_sandstone_3, FALSE, FALSE,
6281 EL_QUICKSAND_FILLING, -1, -1
6284 Xsand_sandstone_4, FALSE, FALSE,
6285 EL_QUICKSAND_FILLING, -1, -1
6288 Xplant, TRUE, FALSE,
6289 EL_EMC_PLANT, -1, -1
6292 Yplant, FALSE, FALSE,
6293 EL_EMC_PLANT, -1, -1
6296 Xlenses, TRUE, FALSE,
6297 EL_EMC_LENSES, -1, -1
6300 Xmagnify, TRUE, FALSE,
6301 EL_EMC_MAGNIFIER, -1, -1
6304 Xdripper, TRUE, FALSE,
6305 EL_EMC_DRIPPER, -1, -1
6308 XdripperB, FALSE, FALSE,
6309 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
6312 Xfake_blank, TRUE, FALSE,
6313 EL_INVISIBLE_WALL, -1, -1
6316 Xfake_blankB, FALSE, FALSE,
6317 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
6320 Xfake_grass, TRUE, FALSE,
6321 EL_EMC_FAKE_GRASS, -1, -1
6324 Xfake_grassB, FALSE, FALSE,
6325 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
6328 Xfake_door_1, TRUE, FALSE,
6329 EL_EM_GATE_1_GRAY, -1, -1
6332 Xfake_door_2, TRUE, FALSE,
6333 EL_EM_GATE_2_GRAY, -1, -1
6336 Xfake_door_3, TRUE, FALSE,
6337 EL_EM_GATE_3_GRAY, -1, -1
6340 Xfake_door_4, TRUE, FALSE,
6341 EL_EM_GATE_4_GRAY, -1, -1
6344 Xfake_door_5, TRUE, FALSE,
6345 EL_EMC_GATE_5_GRAY, -1, -1
6348 Xfake_door_6, TRUE, FALSE,
6349 EL_EMC_GATE_6_GRAY, -1, -1
6352 Xfake_door_7, TRUE, FALSE,
6353 EL_EMC_GATE_7_GRAY, -1, -1
6356 Xfake_door_8, TRUE, FALSE,
6357 EL_EMC_GATE_8_GRAY, -1, -1
6360 Xfake_acid_1, TRUE, FALSE,
6361 EL_EMC_FAKE_ACID, -1, -1
6364 Xfake_acid_2, FALSE, FALSE,
6365 EL_EMC_FAKE_ACID, -1, -1
6368 Xfake_acid_3, FALSE, FALSE,
6369 EL_EMC_FAKE_ACID, -1, -1
6372 Xfake_acid_4, FALSE, FALSE,
6373 EL_EMC_FAKE_ACID, -1, -1
6376 Xfake_acid_5, FALSE, FALSE,
6377 EL_EMC_FAKE_ACID, -1, -1
6380 Xfake_acid_6, FALSE, FALSE,
6381 EL_EMC_FAKE_ACID, -1, -1
6384 Xfake_acid_7, FALSE, FALSE,
6385 EL_EMC_FAKE_ACID, -1, -1
6388 Xfake_acid_8, FALSE, FALSE,
6389 EL_EMC_FAKE_ACID, -1, -1
6392 Xsteel_1, TRUE, FALSE,
6393 EL_STEELWALL, -1, -1
6396 Xsteel_2, TRUE, FALSE,
6397 EL_EMC_STEELWALL_2, -1, -1
6400 Xsteel_3, TRUE, FALSE,
6401 EL_EMC_STEELWALL_3, -1, -1
6404 Xsteel_4, TRUE, FALSE,
6405 EL_EMC_STEELWALL_4, -1, -1
6408 Xwall_1, TRUE, FALSE,
6412 Xwall_2, TRUE, FALSE,
6413 EL_EMC_WALL_14, -1, -1
6416 Xwall_3, TRUE, FALSE,
6417 EL_EMC_WALL_15, -1, -1
6420 Xwall_4, TRUE, FALSE,
6421 EL_EMC_WALL_16, -1, -1
6424 Xround_wall_1, TRUE, FALSE,
6425 EL_WALL_SLIPPERY, -1, -1
6428 Xround_wall_2, TRUE, FALSE,
6429 EL_EMC_WALL_SLIPPERY_2, -1, -1
6432 Xround_wall_3, TRUE, FALSE,
6433 EL_EMC_WALL_SLIPPERY_3, -1, -1
6436 Xround_wall_4, TRUE, FALSE,
6437 EL_EMC_WALL_SLIPPERY_4, -1, -1
6440 Xdecor_1, TRUE, FALSE,
6441 EL_EMC_WALL_8, -1, -1
6444 Xdecor_2, TRUE, FALSE,
6445 EL_EMC_WALL_6, -1, -1
6448 Xdecor_3, TRUE, FALSE,
6449 EL_EMC_WALL_4, -1, -1
6452 Xdecor_4, TRUE, FALSE,
6453 EL_EMC_WALL_7, -1, -1
6456 Xdecor_5, TRUE, FALSE,
6457 EL_EMC_WALL_5, -1, -1
6460 Xdecor_6, TRUE, FALSE,
6461 EL_EMC_WALL_9, -1, -1
6464 Xdecor_7, TRUE, FALSE,
6465 EL_EMC_WALL_10, -1, -1
6468 Xdecor_8, TRUE, FALSE,
6469 EL_EMC_WALL_1, -1, -1
6472 Xdecor_9, TRUE, FALSE,
6473 EL_EMC_WALL_2, -1, -1
6476 Xdecor_10, TRUE, FALSE,
6477 EL_EMC_WALL_3, -1, -1
6480 Xdecor_11, TRUE, FALSE,
6481 EL_EMC_WALL_11, -1, -1
6484 Xdecor_12, TRUE, FALSE,
6485 EL_EMC_WALL_12, -1, -1
6488 Xalpha_0, TRUE, FALSE,
6489 EL_CHAR('0'), -1, -1
6492 Xalpha_1, TRUE, FALSE,
6493 EL_CHAR('1'), -1, -1
6496 Xalpha_2, TRUE, FALSE,
6497 EL_CHAR('2'), -1, -1
6500 Xalpha_3, TRUE, FALSE,
6501 EL_CHAR('3'), -1, -1
6504 Xalpha_4, TRUE, FALSE,
6505 EL_CHAR('4'), -1, -1
6508 Xalpha_5, TRUE, FALSE,
6509 EL_CHAR('5'), -1, -1
6512 Xalpha_6, TRUE, FALSE,
6513 EL_CHAR('6'), -1, -1
6516 Xalpha_7, TRUE, FALSE,
6517 EL_CHAR('7'), -1, -1
6520 Xalpha_8, TRUE, FALSE,
6521 EL_CHAR('8'), -1, -1
6524 Xalpha_9, TRUE, FALSE,
6525 EL_CHAR('9'), -1, -1
6528 Xalpha_excla, TRUE, FALSE,
6529 EL_CHAR('!'), -1, -1
6532 Xalpha_quote, TRUE, FALSE,
6533 EL_CHAR('"'), -1, -1
6536 Xalpha_comma, TRUE, FALSE,
6537 EL_CHAR(','), -1, -1
6540 Xalpha_minus, TRUE, FALSE,
6541 EL_CHAR('-'), -1, -1
6544 Xalpha_perio, TRUE, FALSE,
6545 EL_CHAR('.'), -1, -1
6548 Xalpha_colon, TRUE, FALSE,
6549 EL_CHAR(':'), -1, -1
6552 Xalpha_quest, TRUE, FALSE,
6553 EL_CHAR('?'), -1, -1
6556 Xalpha_a, TRUE, FALSE,
6557 EL_CHAR('A'), -1, -1
6560 Xalpha_b, TRUE, FALSE,
6561 EL_CHAR('B'), -1, -1
6564 Xalpha_c, TRUE, FALSE,
6565 EL_CHAR('C'), -1, -1
6568 Xalpha_d, TRUE, FALSE,
6569 EL_CHAR('D'), -1, -1
6572 Xalpha_e, TRUE, FALSE,
6573 EL_CHAR('E'), -1, -1
6576 Xalpha_f, TRUE, FALSE,
6577 EL_CHAR('F'), -1, -1
6580 Xalpha_g, TRUE, FALSE,
6581 EL_CHAR('G'), -1, -1
6584 Xalpha_h, TRUE, FALSE,
6585 EL_CHAR('H'), -1, -1
6588 Xalpha_i, TRUE, FALSE,
6589 EL_CHAR('I'), -1, -1
6592 Xalpha_j, TRUE, FALSE,
6593 EL_CHAR('J'), -1, -1
6596 Xalpha_k, TRUE, FALSE,
6597 EL_CHAR('K'), -1, -1
6600 Xalpha_l, TRUE, FALSE,
6601 EL_CHAR('L'), -1, -1
6604 Xalpha_m, TRUE, FALSE,
6605 EL_CHAR('M'), -1, -1
6608 Xalpha_n, TRUE, FALSE,
6609 EL_CHAR('N'), -1, -1
6612 Xalpha_o, TRUE, FALSE,
6613 EL_CHAR('O'), -1, -1
6616 Xalpha_p, TRUE, FALSE,
6617 EL_CHAR('P'), -1, -1
6620 Xalpha_q, TRUE, FALSE,
6621 EL_CHAR('Q'), -1, -1
6624 Xalpha_r, TRUE, FALSE,
6625 EL_CHAR('R'), -1, -1
6628 Xalpha_s, TRUE, FALSE,
6629 EL_CHAR('S'), -1, -1
6632 Xalpha_t, TRUE, FALSE,
6633 EL_CHAR('T'), -1, -1
6636 Xalpha_u, TRUE, FALSE,
6637 EL_CHAR('U'), -1, -1
6640 Xalpha_v, TRUE, FALSE,
6641 EL_CHAR('V'), -1, -1
6644 Xalpha_w, TRUE, FALSE,
6645 EL_CHAR('W'), -1, -1
6648 Xalpha_x, TRUE, FALSE,
6649 EL_CHAR('X'), -1, -1
6652 Xalpha_y, TRUE, FALSE,
6653 EL_CHAR('Y'), -1, -1
6656 Xalpha_z, TRUE, FALSE,
6657 EL_CHAR('Z'), -1, -1
6660 Xalpha_arrow_e, TRUE, FALSE,
6661 EL_CHAR('>'), -1, -1
6664 Xalpha_arrow_w, TRUE, FALSE,
6665 EL_CHAR('<'), -1, -1
6668 Xalpha_copyr, TRUE, FALSE,
6669 EL_CHAR(CHAR_BYTE_COPYRIGHT), -1, -1
6673 Xboom_bug, FALSE, FALSE,
6674 EL_BUG, ACTION_EXPLODING, -1
6677 Xboom_bomb, FALSE, FALSE,
6678 EL_BOMB, ACTION_EXPLODING, -1
6681 Xboom_android, FALSE, FALSE,
6682 EL_EMC_ANDROID, ACTION_OTHER, -1
6685 Xboom_1, FALSE, FALSE,
6686 EL_DEFAULT, ACTION_EXPLODING, -1
6689 Xboom_2, FALSE, FALSE,
6690 EL_DEFAULT, ACTION_EXPLODING, -1
6693 Znormal, FALSE, FALSE,
6697 Zdynamite, FALSE, FALSE,
6701 Zplayer, FALSE, FALSE,
6705 ZBORDER, FALSE, FALSE,
6715 static struct Mapping_EM_to_RND_player
6724 em_player_mapping_list[] =
6728 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
6732 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
6736 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
6740 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
6744 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
6748 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
6752 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
6756 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
6760 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
6764 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
6768 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
6772 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
6776 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
6780 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
6784 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
6788 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
6792 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
6796 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
6800 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
6804 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
6808 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
6812 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
6816 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
6820 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
6824 EL_PLAYER_1, ACTION_DEFAULT, -1,
6828 EL_PLAYER_2, ACTION_DEFAULT, -1,
6832 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
6836 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
6840 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
6844 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
6848 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
6852 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
6856 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
6860 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
6864 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
6868 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
6872 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
6876 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
6880 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
6884 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
6888 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
6892 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
6896 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
6900 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
6904 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
6908 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
6912 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
6916 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
6920 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
6924 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
6928 EL_PLAYER_3, ACTION_DEFAULT, -1,
6932 EL_PLAYER_4, ACTION_DEFAULT, -1,
6941 int map_element_RND_to_EM(int element_rnd)
6943 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
6944 static boolean mapping_initialized = FALSE;
6946 if (!mapping_initialized)
6950 /* return "Xalpha_quest" for all undefined elements in mapping array */
6951 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
6952 mapping_RND_to_EM[i] = Xalpha_quest;
6954 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6955 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
6956 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
6957 em_object_mapping_list[i].element_em;
6959 mapping_initialized = TRUE;
6962 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
6963 return mapping_RND_to_EM[element_rnd];
6965 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
6970 int map_element_EM_to_RND(int element_em)
6972 static unsigned short mapping_EM_to_RND[TILE_MAX];
6973 static boolean mapping_initialized = FALSE;
6975 if (!mapping_initialized)
6979 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
6980 for (i = 0; i < TILE_MAX; i++)
6981 mapping_EM_to_RND[i] = EL_UNKNOWN;
6983 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6984 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
6985 em_object_mapping_list[i].element_rnd;
6987 mapping_initialized = TRUE;
6990 if (element_em >= 0 && element_em < TILE_MAX)
6991 return mapping_EM_to_RND[element_em];
6993 Error(ERR_WARN, "invalid EM level element %d", element_em);
6998 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
7000 struct LevelInfo_EM *level_em = level->native_em_level;
7001 struct LEVEL *lev = level_em->lev;
7004 for (i = 0; i < TILE_MAX; i++)
7005 lev->android_array[i] = Xblank;
7007 for (i = 0; i < level->num_android_clone_elements; i++)
7009 int element_rnd = level->android_clone_element[i];
7010 int element_em = map_element_RND_to_EM(element_rnd);
7012 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
7013 if (em_object_mapping_list[j].element_rnd == element_rnd)
7014 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
7018 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
7020 struct LevelInfo_EM *level_em = level->native_em_level;
7021 struct LEVEL *lev = level_em->lev;
7024 level->num_android_clone_elements = 0;
7026 for (i = 0; i < TILE_MAX; i++)
7028 int element_em = lev->android_array[i];
7030 boolean element_found = FALSE;
7032 if (element_em == Xblank)
7035 element_rnd = map_element_EM_to_RND(element_em);
7037 for (j = 0; j < level->num_android_clone_elements; j++)
7038 if (level->android_clone_element[j] == element_rnd)
7039 element_found = TRUE;
7043 level->android_clone_element[level->num_android_clone_elements++] =
7046 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
7051 if (level->num_android_clone_elements == 0)
7053 level->num_android_clone_elements = 1;
7054 level->android_clone_element[0] = EL_EMPTY;
7058 int map_direction_RND_to_EM(int direction)
7060 return (direction == MV_UP ? 0 :
7061 direction == MV_RIGHT ? 1 :
7062 direction == MV_DOWN ? 2 :
7063 direction == MV_LEFT ? 3 :
7067 int map_direction_EM_to_RND(int direction)
7069 return (direction == 0 ? MV_UP :
7070 direction == 1 ? MV_RIGHT :
7071 direction == 2 ? MV_DOWN :
7072 direction == 3 ? MV_LEFT :
7076 int map_element_RND_to_SP(int element_rnd)
7078 int element_sp = 0x20; /* map unknown elements to yellow "hardware" */
7080 if (element_rnd >= EL_SP_START &&
7081 element_rnd <= EL_SP_END)
7082 element_sp = element_rnd - EL_SP_START;
7083 else if (element_rnd == EL_EMPTY_SPACE)
7085 else if (element_rnd == EL_INVISIBLE_WALL)
7091 int map_element_SP_to_RND(int element_sp)
7093 int element_rnd = EL_UNKNOWN;
7095 if (element_sp >= 0x00 &&
7097 element_rnd = EL_SP_START + element_sp;
7098 else if (element_sp == 0x28)
7099 element_rnd = EL_INVISIBLE_WALL;
7104 int map_action_SP_to_RND(int action_sp)
7108 case actActive: return ACTION_ACTIVE;
7109 case actImpact: return ACTION_IMPACT;
7110 case actExploding: return ACTION_EXPLODING;
7111 case actDigging: return ACTION_DIGGING;
7112 case actSnapping: return ACTION_SNAPPING;
7113 case actCollecting: return ACTION_COLLECTING;
7114 case actPassing: return ACTION_PASSING;
7115 case actPushing: return ACTION_PUSHING;
7116 case actDropping: return ACTION_DROPPING;
7118 default: return ACTION_DEFAULT;
7122 int get_next_element(int element)
7126 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
7127 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
7128 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
7129 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
7130 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
7131 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
7132 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
7133 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
7134 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
7135 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
7136 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
7138 default: return element;
7142 int el_act_dir2img(int element, int action, int direction)
7144 element = GFX_ELEMENT(element);
7145 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
7147 /* direction_graphic[][] == graphic[] for undefined direction graphics */
7148 return element_info[element].direction_graphic[action][direction];
7151 static int el_act_dir2crm(int element, int action, int direction)
7153 element = GFX_ELEMENT(element);
7154 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
7156 /* direction_graphic[][] == graphic[] for undefined direction graphics */
7157 return element_info[element].direction_crumbled[action][direction];
7160 int el_act2img(int element, int action)
7162 element = GFX_ELEMENT(element);
7164 return element_info[element].graphic[action];
7167 int el_act2crm(int element, int action)
7169 element = GFX_ELEMENT(element);
7171 return element_info[element].crumbled[action];
7174 int el_dir2img(int element, int direction)
7176 element = GFX_ELEMENT(element);
7178 return el_act_dir2img(element, ACTION_DEFAULT, direction);
7181 int el2baseimg(int element)
7183 return element_info[element].graphic[ACTION_DEFAULT];
7186 int el2img(int element)
7188 element = GFX_ELEMENT(element);
7190 return element_info[element].graphic[ACTION_DEFAULT];
7193 int el2edimg(int element)
7195 element = GFX_ELEMENT(element);
7197 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
7200 int el2preimg(int element)
7202 element = GFX_ELEMENT(element);
7204 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
7207 int el2panelimg(int element)
7209 element = GFX_ELEMENT(element);
7211 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL];
7214 int font2baseimg(int font_nr)
7216 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
7219 int getBeltNrFromBeltElement(int element)
7221 return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
7222 element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
7223 element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
7226 int getBeltNrFromBeltActiveElement(int element)
7228 return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
7229 element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
7230 element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
7233 int getBeltNrFromBeltSwitchElement(int element)
7235 return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
7236 element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
7237 element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
7240 int getBeltDirNrFromBeltElement(int element)
7242 static int belt_base_element[4] =
7244 EL_CONVEYOR_BELT_1_LEFT,
7245 EL_CONVEYOR_BELT_2_LEFT,
7246 EL_CONVEYOR_BELT_3_LEFT,
7247 EL_CONVEYOR_BELT_4_LEFT
7250 int belt_nr = getBeltNrFromBeltElement(element);
7251 int belt_dir_nr = element - belt_base_element[belt_nr];
7253 return (belt_dir_nr % 3);
7256 int getBeltDirNrFromBeltSwitchElement(int element)
7258 static int belt_base_element[4] =
7260 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
7261 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
7262 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
7263 EL_CONVEYOR_BELT_4_SWITCH_LEFT
7266 int belt_nr = getBeltNrFromBeltSwitchElement(element);
7267 int belt_dir_nr = element - belt_base_element[belt_nr];
7269 return (belt_dir_nr % 3);
7272 int getBeltDirFromBeltElement(int element)
7274 static int belt_move_dir[3] =
7281 int belt_dir_nr = getBeltDirNrFromBeltElement(element);
7283 return belt_move_dir[belt_dir_nr];
7286 int getBeltDirFromBeltSwitchElement(int element)
7288 static int belt_move_dir[3] =
7295 int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
7297 return belt_move_dir[belt_dir_nr];
7300 int getBeltElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
7302 static int belt_base_element[4] =
7304 EL_CONVEYOR_BELT_1_LEFT,
7305 EL_CONVEYOR_BELT_2_LEFT,
7306 EL_CONVEYOR_BELT_3_LEFT,
7307 EL_CONVEYOR_BELT_4_LEFT
7310 return belt_base_element[belt_nr] + belt_dir_nr;
7313 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
7315 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
7317 return getBeltElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
7320 int getBeltSwitchElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
7322 static int belt_base_element[4] =
7324 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
7325 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
7326 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
7327 EL_CONVEYOR_BELT_4_SWITCH_LEFT
7330 return belt_base_element[belt_nr] + belt_dir_nr;
7333 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
7335 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
7337 return getBeltSwitchElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
7340 boolean getTeamMode_EM()
7342 return game.team_mode;
7345 int getGameFrameDelay_EM(int native_em_game_frame_delay)
7347 int game_frame_delay_value;
7349 game_frame_delay_value =
7350 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
7351 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
7354 if (tape.playing && tape.warp_forward && !tape.pausing)
7355 game_frame_delay_value = 0;
7357 return game_frame_delay_value;
7360 unsigned int InitRND(int seed)
7362 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
7363 return InitEngineRandom_EM(seed);
7364 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
7365 return InitEngineRandom_SP(seed);
7367 return InitEngineRandom_RND(seed);
7370 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
7371 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
7373 inline static int get_effective_element_EM(int tile, int frame_em)
7375 int element = object_mapping[tile].element_rnd;
7376 int action = object_mapping[tile].action;
7377 boolean is_backside = object_mapping[tile].is_backside;
7378 boolean action_removing = (action == ACTION_DIGGING ||
7379 action == ACTION_SNAPPING ||
7380 action == ACTION_COLLECTING);
7386 case Yacid_splash_eB:
7387 case Yacid_splash_wB:
7388 return (frame_em > 5 ? EL_EMPTY : element);
7394 else /* frame_em == 7 */
7398 case Yacid_splash_eB:
7399 case Yacid_splash_wB:
7402 case Yemerald_stone:
7405 case Ydiamond_stone:
7409 case Xdrip_stretchB:
7428 case Xsand_stonein_1:
7429 case Xsand_stonein_2:
7430 case Xsand_stonein_3:
7431 case Xsand_stonein_4:
7435 return (is_backside || action_removing ? EL_EMPTY : element);
7440 inline static boolean check_linear_animation_EM(int tile)
7444 case Xsand_stonesand_1:
7445 case Xsand_stonesand_quickout_1:
7446 case Xsand_sandstone_1:
7447 case Xsand_stonein_1:
7448 case Xsand_stoneout_1:
7467 case Yacid_splash_eB:
7468 case Yacid_splash_wB:
7469 case Yemerald_stone:
7476 inline static void set_crumbled_graphics_EM(struct GraphicInfo_EM *g_em,
7477 boolean has_crumbled_graphics,
7478 int crumbled, int sync_frame)
7480 /* if element can be crumbled, but certain action graphics are just empty
7481 space (like instantly snapping sand to empty space in 1 frame), do not
7482 treat these empty space graphics as crumbled graphics in EMC engine */
7483 if (crumbled == IMG_EMPTY_SPACE)
7484 has_crumbled_graphics = FALSE;
7486 if (has_crumbled_graphics)
7488 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
7489 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
7490 g_crumbled->anim_delay,
7491 g_crumbled->anim_mode,
7492 g_crumbled->anim_start_frame,
7495 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
7496 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
7498 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
7499 g_em->crumbled_tile_size = graphic_info[crumbled].tile_size;
7501 g_em->has_crumbled_graphics = TRUE;
7505 g_em->crumbled_bitmap = NULL;
7506 g_em->crumbled_src_x = 0;
7507 g_em->crumbled_src_y = 0;
7508 g_em->crumbled_border_size = 0;
7509 g_em->crumbled_tile_size = 0;
7511 g_em->has_crumbled_graphics = FALSE;
7515 void ResetGfxAnimation_EM(int x, int y, int tile)
7520 void SetGfxAnimation_EM(struct GraphicInfo_EM *g_em,
7521 int tile, int frame_em, int x, int y)
7523 int action = object_mapping[tile].action;
7524 int direction = object_mapping[tile].direction;
7525 int effective_element = get_effective_element_EM(tile, frame_em);
7526 int graphic = (direction == MV_NONE ?
7527 el_act2img(effective_element, action) :
7528 el_act_dir2img(effective_element, action, direction));
7529 struct GraphicInfo *g = &graphic_info[graphic];
7531 boolean action_removing = (action == ACTION_DIGGING ||
7532 action == ACTION_SNAPPING ||
7533 action == ACTION_COLLECTING);
7534 boolean action_moving = (action == ACTION_FALLING ||
7535 action == ACTION_MOVING ||
7536 action == ACTION_PUSHING ||
7537 action == ACTION_EATING ||
7538 action == ACTION_FILLING ||
7539 action == ACTION_EMPTYING);
7540 boolean action_falling = (action == ACTION_FALLING ||
7541 action == ACTION_FILLING ||
7542 action == ACTION_EMPTYING);
7544 /* special case: graphic uses "2nd movement tile" and has defined
7545 7 frames for movement animation (or less) => use default graphic
7546 for last (8th) frame which ends the movement animation */
7547 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
7549 action = ACTION_DEFAULT; /* (keep action_* unchanged for now) */
7550 graphic = (direction == MV_NONE ?
7551 el_act2img(effective_element, action) :
7552 el_act_dir2img(effective_element, action, direction));
7554 g = &graphic_info[graphic];
7557 if ((action_removing || check_linear_animation_EM(tile)) && frame_em == 0)
7561 else if (action_moving)
7563 boolean is_backside = object_mapping[tile].is_backside;
7567 int direction = object_mapping[tile].direction;
7568 int move_dir = (action_falling ? MV_DOWN : direction);
7573 /* !!! TEST !!! NEW !!! DOES NOT WORK RIGHT YET !!! */
7574 if (g->double_movement && frame_em == 0)
7578 if (move_dir == MV_LEFT)
7579 GfxFrame[x - 1][y] = GfxFrame[x][y];
7580 else if (move_dir == MV_RIGHT)
7581 GfxFrame[x + 1][y] = GfxFrame[x][y];
7582 else if (move_dir == MV_UP)
7583 GfxFrame[x][y - 1] = GfxFrame[x][y];
7584 else if (move_dir == MV_DOWN)
7585 GfxFrame[x][y + 1] = GfxFrame[x][y];
7592 /* special case: animation for Xsand_stonesand_quickout_1/2 twice as fast */
7593 if (tile == Xsand_stonesand_quickout_1 ||
7594 tile == Xsand_stonesand_quickout_2)
7598 if (graphic_info[graphic].anim_global_sync)
7599 sync_frame = FrameCounter;
7600 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
7601 sync_frame = GfxFrame[x][y];
7603 sync_frame = 0; /* playfield border (pseudo steel) */
7605 SetRandomAnimationValue(x, y);
7607 int frame = getAnimationFrame(g->anim_frames,
7610 g->anim_start_frame,
7613 g_em->unique_identifier =
7614 (graphic << 16) | ((frame % 8) << 12) | (g_em->width << 6) | g_em->height;
7617 void getGraphicSourceObjectExt_EM(struct GraphicInfo_EM *g_em,
7618 int tile, int frame_em, int x, int y)
7620 int action = object_mapping[tile].action;
7621 int direction = object_mapping[tile].direction;
7622 boolean is_backside = object_mapping[tile].is_backside;
7623 int effective_element = get_effective_element_EM(tile, frame_em);
7624 int effective_action = action;
7625 int graphic = (direction == MV_NONE ?
7626 el_act2img(effective_element, effective_action) :
7627 el_act_dir2img(effective_element, effective_action,
7629 int crumbled = (direction == MV_NONE ?
7630 el_act2crm(effective_element, effective_action) :
7631 el_act_dir2crm(effective_element, effective_action,
7633 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7634 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7635 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7636 struct GraphicInfo *g = &graphic_info[graphic];
7639 /* special case: graphic uses "2nd movement tile" and has defined
7640 7 frames for movement animation (or less) => use default graphic
7641 for last (8th) frame which ends the movement animation */
7642 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
7644 effective_action = ACTION_DEFAULT;
7645 graphic = (direction == MV_NONE ?
7646 el_act2img(effective_element, effective_action) :
7647 el_act_dir2img(effective_element, effective_action,
7649 crumbled = (direction == MV_NONE ?
7650 el_act2crm(effective_element, effective_action) :
7651 el_act_dir2crm(effective_element, effective_action,
7654 g = &graphic_info[graphic];
7657 if (graphic_info[graphic].anim_global_sync)
7658 sync_frame = FrameCounter;
7659 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
7660 sync_frame = GfxFrame[x][y];
7662 sync_frame = 0; /* playfield border (pseudo steel) */
7664 SetRandomAnimationValue(x, y);
7666 int frame = getAnimationFrame(g->anim_frames,
7669 g->anim_start_frame,
7672 getGraphicSourceExt(graphic, frame, &g_em->bitmap, &g_em->src_x, &g_em->src_y,
7673 g->double_movement && is_backside);
7675 /* (updating the "crumbled" graphic definitions is probably not really needed,
7676 as animations for crumbled graphics can't be longer than one EMC cycle) */
7677 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
7681 void getGraphicSourcePlayerExt_EM(struct GraphicInfo_EM *g_em,
7682 int player_nr, int anim, int frame_em)
7684 int element = player_mapping[player_nr][anim].element_rnd;
7685 int action = player_mapping[player_nr][anim].action;
7686 int direction = player_mapping[player_nr][anim].direction;
7687 int graphic = (direction == MV_NONE ?
7688 el_act2img(element, action) :
7689 el_act_dir2img(element, action, direction));
7690 struct GraphicInfo *g = &graphic_info[graphic];
7693 InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
7695 stored_player[player_nr].StepFrame = frame_em;
7697 sync_frame = stored_player[player_nr].Frame;
7699 int frame = getAnimationFrame(g->anim_frames,
7702 g->anim_start_frame,
7705 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
7706 &g_em->src_x, &g_em->src_y, FALSE);
7709 void InitGraphicInfo_EM(void)
7714 int num_em_gfx_errors = 0;
7716 if (graphic_info_em_object[0][0].bitmap == NULL)
7718 /* EM graphics not yet initialized in em_open_all() */
7723 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
7726 /* always start with reliable default values */
7727 for (i = 0; i < TILE_MAX; i++)
7729 object_mapping[i].element_rnd = EL_UNKNOWN;
7730 object_mapping[i].is_backside = FALSE;
7731 object_mapping[i].action = ACTION_DEFAULT;
7732 object_mapping[i].direction = MV_NONE;
7735 /* always start with reliable default values */
7736 for (p = 0; p < MAX_PLAYERS; p++)
7738 for (i = 0; i < SPR_MAX; i++)
7740 player_mapping[p][i].element_rnd = EL_UNKNOWN;
7741 player_mapping[p][i].action = ACTION_DEFAULT;
7742 player_mapping[p][i].direction = MV_NONE;
7746 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
7748 int e = em_object_mapping_list[i].element_em;
7750 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
7751 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
7753 if (em_object_mapping_list[i].action != -1)
7754 object_mapping[e].action = em_object_mapping_list[i].action;
7756 if (em_object_mapping_list[i].direction != -1)
7757 object_mapping[e].direction =
7758 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
7761 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
7763 int a = em_player_mapping_list[i].action_em;
7764 int p = em_player_mapping_list[i].player_nr;
7766 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
7768 if (em_player_mapping_list[i].action != -1)
7769 player_mapping[p][a].action = em_player_mapping_list[i].action;
7771 if (em_player_mapping_list[i].direction != -1)
7772 player_mapping[p][a].direction =
7773 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
7776 for (i = 0; i < TILE_MAX; i++)
7778 int element = object_mapping[i].element_rnd;
7779 int action = object_mapping[i].action;
7780 int direction = object_mapping[i].direction;
7781 boolean is_backside = object_mapping[i].is_backside;
7782 boolean action_exploding = ((action == ACTION_EXPLODING ||
7783 action == ACTION_SMASHED_BY_ROCK ||
7784 action == ACTION_SMASHED_BY_SPRING) &&
7785 element != EL_DIAMOND);
7786 boolean action_active = (action == ACTION_ACTIVE);
7787 boolean action_other = (action == ACTION_OTHER);
7789 for (j = 0; j < 8; j++)
7791 int effective_element = get_effective_element_EM(i, j);
7792 int effective_action = (j < 7 ? action :
7793 i == Xdrip_stretch ? action :
7794 i == Xdrip_stretchB ? action :
7795 i == Ydrip_s1 ? action :
7796 i == Ydrip_s1B ? action :
7797 i == Xball_1B ? action :
7798 i == Xball_2 ? action :
7799 i == Xball_2B ? action :
7800 i == Yball_eat ? action :
7801 i == Ykey_1_eat ? action :
7802 i == Ykey_2_eat ? action :
7803 i == Ykey_3_eat ? action :
7804 i == Ykey_4_eat ? action :
7805 i == Ykey_5_eat ? action :
7806 i == Ykey_6_eat ? action :
7807 i == Ykey_7_eat ? action :
7808 i == Ykey_8_eat ? action :
7809 i == Ylenses_eat ? action :
7810 i == Ymagnify_eat ? action :
7811 i == Ygrass_eat ? action :
7812 i == Ydirt_eat ? action :
7813 i == Xsand_stonein_1 ? action :
7814 i == Xsand_stonein_2 ? action :
7815 i == Xsand_stonein_3 ? action :
7816 i == Xsand_stonein_4 ? action :
7817 i == Xsand_stoneout_1 ? action :
7818 i == Xsand_stoneout_2 ? action :
7819 i == Xboom_android ? ACTION_EXPLODING :
7820 action_exploding ? ACTION_EXPLODING :
7821 action_active ? action :
7822 action_other ? action :
7824 int graphic = (el_act_dir2img(effective_element, effective_action,
7826 int crumbled = (el_act_dir2crm(effective_element, effective_action,
7828 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7829 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7830 boolean has_action_graphics = (graphic != base_graphic);
7831 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7832 struct GraphicInfo *g = &graphic_info[graphic];
7833 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7836 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
7837 boolean special_animation = (action != ACTION_DEFAULT &&
7838 g->anim_frames == 3 &&
7839 g->anim_delay == 2 &&
7840 g->anim_mode & ANIM_LINEAR);
7841 int sync_frame = (i == Xdrip_stretch ? 7 :
7842 i == Xdrip_stretchB ? 7 :
7843 i == Ydrip_s2 ? j + 8 :
7844 i == Ydrip_s2B ? j + 8 :
7853 i == Xfake_acid_1 ? 0 :
7854 i == Xfake_acid_2 ? 10 :
7855 i == Xfake_acid_3 ? 20 :
7856 i == Xfake_acid_4 ? 30 :
7857 i == Xfake_acid_5 ? 40 :
7858 i == Xfake_acid_6 ? 50 :
7859 i == Xfake_acid_7 ? 60 :
7860 i == Xfake_acid_8 ? 70 :
7862 i == Xball_2B ? j + 8 :
7863 i == Yball_eat ? j + 1 :
7864 i == Ykey_1_eat ? j + 1 :
7865 i == Ykey_2_eat ? j + 1 :
7866 i == Ykey_3_eat ? j + 1 :
7867 i == Ykey_4_eat ? j + 1 :
7868 i == Ykey_5_eat ? j + 1 :
7869 i == Ykey_6_eat ? j + 1 :
7870 i == Ykey_7_eat ? j + 1 :
7871 i == Ykey_8_eat ? j + 1 :
7872 i == Ylenses_eat ? j + 1 :
7873 i == Ymagnify_eat ? j + 1 :
7874 i == Ygrass_eat ? j + 1 :
7875 i == Ydirt_eat ? j + 1 :
7876 i == Xamoeba_1 ? 0 :
7877 i == Xamoeba_2 ? 1 :
7878 i == Xamoeba_3 ? 2 :
7879 i == Xamoeba_4 ? 3 :
7880 i == Xamoeba_5 ? 0 :
7881 i == Xamoeba_6 ? 1 :
7882 i == Xamoeba_7 ? 2 :
7883 i == Xamoeba_8 ? 3 :
7884 i == Xexit_2 ? j + 8 :
7885 i == Xexit_3 ? j + 16 :
7886 i == Xdynamite_1 ? 0 :
7887 i == Xdynamite_2 ? 8 :
7888 i == Xdynamite_3 ? 16 :
7889 i == Xdynamite_4 ? 24 :
7890 i == Xsand_stonein_1 ? j + 1 :
7891 i == Xsand_stonein_2 ? j + 9 :
7892 i == Xsand_stonein_3 ? j + 17 :
7893 i == Xsand_stonein_4 ? j + 25 :
7894 i == Xsand_stoneout_1 && j == 0 ? 0 :
7895 i == Xsand_stoneout_1 && j == 1 ? 0 :
7896 i == Xsand_stoneout_1 && j == 2 ? 1 :
7897 i == Xsand_stoneout_1 && j == 3 ? 2 :
7898 i == Xsand_stoneout_1 && j == 4 ? 2 :
7899 i == Xsand_stoneout_1 && j == 5 ? 3 :
7900 i == Xsand_stoneout_1 && j == 6 ? 4 :
7901 i == Xsand_stoneout_1 && j == 7 ? 4 :
7902 i == Xsand_stoneout_2 && j == 0 ? 5 :
7903 i == Xsand_stoneout_2 && j == 1 ? 6 :
7904 i == Xsand_stoneout_2 && j == 2 ? 7 :
7905 i == Xsand_stoneout_2 && j == 3 ? 8 :
7906 i == Xsand_stoneout_2 && j == 4 ? 9 :
7907 i == Xsand_stoneout_2 && j == 5 ? 11 :
7908 i == Xsand_stoneout_2 && j == 6 ? 13 :
7909 i == Xsand_stoneout_2 && j == 7 ? 15 :
7910 i == Xboom_bug && j == 1 ? 2 :
7911 i == Xboom_bug && j == 2 ? 2 :
7912 i == Xboom_bug && j == 3 ? 4 :
7913 i == Xboom_bug && j == 4 ? 4 :
7914 i == Xboom_bug && j == 5 ? 2 :
7915 i == Xboom_bug && j == 6 ? 2 :
7916 i == Xboom_bug && j == 7 ? 0 :
7917 i == Xboom_bomb && j == 1 ? 2 :
7918 i == Xboom_bomb && j == 2 ? 2 :
7919 i == Xboom_bomb && j == 3 ? 4 :
7920 i == Xboom_bomb && j == 4 ? 4 :
7921 i == Xboom_bomb && j == 5 ? 2 :
7922 i == Xboom_bomb && j == 6 ? 2 :
7923 i == Xboom_bomb && j == 7 ? 0 :
7924 i == Xboom_android && j == 7 ? 6 :
7925 i == Xboom_1 && j == 1 ? 2 :
7926 i == Xboom_1 && j == 2 ? 2 :
7927 i == Xboom_1 && j == 3 ? 4 :
7928 i == Xboom_1 && j == 4 ? 4 :
7929 i == Xboom_1 && j == 5 ? 6 :
7930 i == Xboom_1 && j == 6 ? 6 :
7931 i == Xboom_1 && j == 7 ? 8 :
7932 i == Xboom_2 && j == 0 ? 8 :
7933 i == Xboom_2 && j == 1 ? 8 :
7934 i == Xboom_2 && j == 2 ? 10 :
7935 i == Xboom_2 && j == 3 ? 10 :
7936 i == Xboom_2 && j == 4 ? 10 :
7937 i == Xboom_2 && j == 5 ? 12 :
7938 i == Xboom_2 && j == 6 ? 12 :
7939 i == Xboom_2 && j == 7 ? 12 :
7940 special_animation && j == 4 ? 3 :
7941 effective_action != action ? 0 :
7945 Bitmap *debug_bitmap = g_em->bitmap;
7946 int debug_src_x = g_em->src_x;
7947 int debug_src_y = g_em->src_y;
7950 int frame = getAnimationFrame(g->anim_frames,
7953 g->anim_start_frame,
7956 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
7957 g->double_movement && is_backside);
7959 g_em->bitmap = src_bitmap;
7960 g_em->src_x = src_x;
7961 g_em->src_y = src_y;
7962 g_em->src_offset_x = 0;
7963 g_em->src_offset_y = 0;
7964 g_em->dst_offset_x = 0;
7965 g_em->dst_offset_y = 0;
7966 g_em->width = TILEX;
7967 g_em->height = TILEY;
7969 g_em->preserve_background = FALSE;
7971 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
7974 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
7975 effective_action == ACTION_MOVING ||
7976 effective_action == ACTION_PUSHING ||
7977 effective_action == ACTION_EATING)) ||
7978 (!has_action_graphics && (effective_action == ACTION_FILLING ||
7979 effective_action == ACTION_EMPTYING)))
7982 (effective_action == ACTION_FALLING ||
7983 effective_action == ACTION_FILLING ||
7984 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
7985 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
7986 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
7987 int num_steps = (i == Ydrip_s1 ? 16 :
7988 i == Ydrip_s1B ? 16 :
7989 i == Ydrip_s2 ? 16 :
7990 i == Ydrip_s2B ? 16 :
7991 i == Xsand_stonein_1 ? 32 :
7992 i == Xsand_stonein_2 ? 32 :
7993 i == Xsand_stonein_3 ? 32 :
7994 i == Xsand_stonein_4 ? 32 :
7995 i == Xsand_stoneout_1 ? 16 :
7996 i == Xsand_stoneout_2 ? 16 : 8);
7997 int cx = ABS(dx) * (TILEX / num_steps);
7998 int cy = ABS(dy) * (TILEY / num_steps);
7999 int step_frame = (i == Ydrip_s2 ? j + 8 :
8000 i == Ydrip_s2B ? j + 8 :
8001 i == Xsand_stonein_2 ? j + 8 :
8002 i == Xsand_stonein_3 ? j + 16 :
8003 i == Xsand_stonein_4 ? j + 24 :
8004 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
8005 int step = (is_backside ? step_frame : num_steps - step_frame);
8007 if (is_backside) /* tile where movement starts */
8009 if (dx < 0 || dy < 0)
8011 g_em->src_offset_x = cx * step;
8012 g_em->src_offset_y = cy * step;
8016 g_em->dst_offset_x = cx * step;
8017 g_em->dst_offset_y = cy * step;
8020 else /* tile where movement ends */
8022 if (dx < 0 || dy < 0)
8024 g_em->dst_offset_x = cx * step;
8025 g_em->dst_offset_y = cy * step;
8029 g_em->src_offset_x = cx * step;
8030 g_em->src_offset_y = cy * step;
8034 g_em->width = TILEX - cx * step;
8035 g_em->height = TILEY - cy * step;
8038 /* create unique graphic identifier to decide if tile must be redrawn */
8039 /* bit 31 - 16 (16 bit): EM style graphic
8040 bit 15 - 12 ( 4 bit): EM style frame
8041 bit 11 - 6 ( 6 bit): graphic width
8042 bit 5 - 0 ( 6 bit): graphic height */
8043 g_em->unique_identifier =
8044 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
8048 /* skip check for EMC elements not contained in original EMC artwork */
8049 if (element == EL_EMC_FAKE_ACID)
8052 if (g_em->bitmap != debug_bitmap ||
8053 g_em->src_x != debug_src_x ||
8054 g_em->src_y != debug_src_y ||
8055 g_em->src_offset_x != 0 ||
8056 g_em->src_offset_y != 0 ||
8057 g_em->dst_offset_x != 0 ||
8058 g_em->dst_offset_y != 0 ||
8059 g_em->width != TILEX ||
8060 g_em->height != TILEY)
8062 static int last_i = -1;
8070 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
8071 i, element, element_info[element].token_name,
8072 element_action_info[effective_action].suffix, direction);
8074 if (element != effective_element)
8075 printf(" [%d ('%s')]",
8077 element_info[effective_element].token_name);
8081 if (g_em->bitmap != debug_bitmap)
8082 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
8083 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
8085 if (g_em->src_x != debug_src_x ||
8086 g_em->src_y != debug_src_y)
8087 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
8088 j, (is_backside ? 'B' : 'F'),
8089 g_em->src_x, g_em->src_y,
8090 g_em->src_x / 32, g_em->src_y / 32,
8091 debug_src_x, debug_src_y,
8092 debug_src_x / 32, debug_src_y / 32);
8094 if (g_em->src_offset_x != 0 ||
8095 g_em->src_offset_y != 0 ||
8096 g_em->dst_offset_x != 0 ||
8097 g_em->dst_offset_y != 0)
8098 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
8100 g_em->src_offset_x, g_em->src_offset_y,
8101 g_em->dst_offset_x, g_em->dst_offset_y);
8103 if (g_em->width != TILEX ||
8104 g_em->height != TILEY)
8105 printf(" %d (%d): size %d,%d should be %d,%d\n",
8107 g_em->width, g_em->height, TILEX, TILEY);
8109 num_em_gfx_errors++;
8116 for (i = 0; i < TILE_MAX; i++)
8118 for (j = 0; j < 8; j++)
8120 int element = object_mapping[i].element_rnd;
8121 int action = object_mapping[i].action;
8122 int direction = object_mapping[i].direction;
8123 boolean is_backside = object_mapping[i].is_backside;
8124 int graphic_action = el_act_dir2img(element, action, direction);
8125 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
8127 if ((action == ACTION_SMASHED_BY_ROCK ||
8128 action == ACTION_SMASHED_BY_SPRING ||
8129 action == ACTION_EATING) &&
8130 graphic_action == graphic_default)
8132 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
8133 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
8134 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
8135 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
8138 /* no separate animation for "smashed by rock" -- use rock instead */
8139 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
8140 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
8142 g_em->bitmap = g_xx->bitmap;
8143 g_em->src_x = g_xx->src_x;
8144 g_em->src_y = g_xx->src_y;
8145 g_em->src_offset_x = g_xx->src_offset_x;
8146 g_em->src_offset_y = g_xx->src_offset_y;
8147 g_em->dst_offset_x = g_xx->dst_offset_x;
8148 g_em->dst_offset_y = g_xx->dst_offset_y;
8149 g_em->width = g_xx->width;
8150 g_em->height = g_xx->height;
8151 g_em->unique_identifier = g_xx->unique_identifier;
8154 g_em->preserve_background = TRUE;
8159 for (p = 0; p < MAX_PLAYERS; p++)
8161 for (i = 0; i < SPR_MAX; i++)
8163 int element = player_mapping[p][i].element_rnd;
8164 int action = player_mapping[p][i].action;
8165 int direction = player_mapping[p][i].direction;
8167 for (j = 0; j < 8; j++)
8169 int effective_element = element;
8170 int effective_action = action;
8171 int graphic = (direction == MV_NONE ?
8172 el_act2img(effective_element, effective_action) :
8173 el_act_dir2img(effective_element, effective_action,
8175 struct GraphicInfo *g = &graphic_info[graphic];
8176 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
8182 Bitmap *debug_bitmap = g_em->bitmap;
8183 int debug_src_x = g_em->src_x;
8184 int debug_src_y = g_em->src_y;
8187 int frame = getAnimationFrame(g->anim_frames,
8190 g->anim_start_frame,
8193 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
8195 g_em->bitmap = src_bitmap;
8196 g_em->src_x = src_x;
8197 g_em->src_y = src_y;
8198 g_em->src_offset_x = 0;
8199 g_em->src_offset_y = 0;
8200 g_em->dst_offset_x = 0;
8201 g_em->dst_offset_y = 0;
8202 g_em->width = TILEX;
8203 g_em->height = TILEY;
8207 /* skip check for EMC elements not contained in original EMC artwork */
8208 if (element == EL_PLAYER_3 ||
8209 element == EL_PLAYER_4)
8212 if (g_em->bitmap != debug_bitmap ||
8213 g_em->src_x != debug_src_x ||
8214 g_em->src_y != debug_src_y)
8216 static int last_i = -1;
8224 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
8225 p, i, element, element_info[element].token_name,
8226 element_action_info[effective_action].suffix, direction);
8228 if (element != effective_element)
8229 printf(" [%d ('%s')]",
8231 element_info[effective_element].token_name);
8235 if (g_em->bitmap != debug_bitmap)
8236 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
8237 j, (int)(g_em->bitmap), (int)(debug_bitmap));
8239 if (g_em->src_x != debug_src_x ||
8240 g_em->src_y != debug_src_y)
8241 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
8243 g_em->src_x, g_em->src_y,
8244 g_em->src_x / 32, g_em->src_y / 32,
8245 debug_src_x, debug_src_y,
8246 debug_src_x / 32, debug_src_y / 32);
8248 num_em_gfx_errors++;
8258 printf("::: [%d errors found]\n", num_em_gfx_errors);
8264 void CheckSaveEngineSnapshot_EM(byte action[MAX_PLAYERS], int frame,
8265 boolean any_player_moving,
8266 boolean any_player_snapping,
8267 boolean any_player_dropping)
8269 if (frame == 0 && !any_player_dropping)
8271 if (!local_player->was_waiting)
8273 if (!CheckSaveEngineSnapshotToList())
8276 local_player->was_waiting = TRUE;
8279 else if (any_player_moving || any_player_snapping || any_player_dropping)
8281 local_player->was_waiting = FALSE;
8285 void CheckSaveEngineSnapshot_SP(boolean murphy_is_waiting,
8286 boolean murphy_is_dropping)
8288 if (murphy_is_waiting)
8290 if (!local_player->was_waiting)
8292 if (!CheckSaveEngineSnapshotToList())
8295 local_player->was_waiting = TRUE;
8300 local_player->was_waiting = FALSE;
8304 void CheckSingleStepMode_EM(byte action[MAX_PLAYERS], int frame,
8305 boolean any_player_moving,
8306 boolean any_player_snapping,
8307 boolean any_player_dropping)
8309 if (tape.single_step && tape.recording && !tape.pausing)
8310 if (frame == 0 && !any_player_dropping)
8311 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
8313 CheckSaveEngineSnapshot_EM(action, frame, any_player_moving,
8314 any_player_snapping, any_player_dropping);
8317 void CheckSingleStepMode_SP(boolean murphy_is_waiting,
8318 boolean murphy_is_dropping)
8320 if (tape.single_step && tape.recording && !tape.pausing)
8321 if (murphy_is_waiting)
8322 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
8324 CheckSaveEngineSnapshot_SP(murphy_is_waiting, murphy_is_dropping);
8327 void getGraphicSource_SP(struct GraphicInfo_SP *g_sp,
8328 int graphic, int sync_frame, int x, int y)
8330 int frame = getGraphicAnimationFrame(graphic, sync_frame);
8332 getGraphicSource(graphic, frame, &g_sp->bitmap, &g_sp->src_x, &g_sp->src_y);
8335 boolean isNextAnimationFrame_SP(int graphic, int sync_frame)
8337 return (IS_NEXT_FRAME(sync_frame, graphic));
8340 int getGraphicInfo_Delay(int graphic)
8342 return graphic_info[graphic].anim_delay;
8345 void PlayMenuSoundExt(int sound)
8347 if (sound == SND_UNDEFINED)
8350 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8351 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8354 if (IS_LOOP_SOUND(sound))
8355 PlaySoundLoop(sound);
8360 void PlayMenuSound()
8362 PlayMenuSoundExt(menu.sound[game_status]);
8365 void PlayMenuSoundStereo(int sound, int stereo_position)
8367 if (sound == SND_UNDEFINED)
8370 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8371 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8374 if (IS_LOOP_SOUND(sound))
8375 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
8377 PlaySoundStereo(sound, stereo_position);
8380 void PlayMenuSoundIfLoopExt(int sound)
8382 if (sound == SND_UNDEFINED)
8385 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8386 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8389 if (IS_LOOP_SOUND(sound))
8390 PlaySoundLoop(sound);
8393 void PlayMenuSoundIfLoop()
8395 PlayMenuSoundIfLoopExt(menu.sound[game_status]);
8398 void PlayMenuMusicExt(int music)
8400 if (music == MUS_UNDEFINED)
8403 if (!setup.sound_music)
8409 void PlayMenuMusic()
8411 char *curr_music = getCurrentlyPlayingMusicFilename();
8412 char *next_music = getMusicListEntry(menu.music[game_status])->filename;
8414 if (!strEqual(curr_music, next_music))
8415 PlayMenuMusicExt(menu.music[game_status]);
8418 void PlayMenuSoundsAndMusic()
8424 static void FadeMenuSounds()
8429 static void FadeMenuMusic()
8431 char *curr_music = getCurrentlyPlayingMusicFilename();
8432 char *next_music = getMusicListEntry(menu.music[game_status])->filename;
8434 if (!strEqual(curr_music, next_music))
8438 void FadeMenuSoundsAndMusic()
8444 void PlaySoundActivating()
8447 PlaySound(SND_MENU_ITEM_ACTIVATING);
8451 void PlaySoundSelecting()
8454 PlaySound(SND_MENU_ITEM_SELECTING);
8458 void ToggleFullscreenOrChangeWindowScalingIfNeeded()
8460 boolean change_fullscreen = (setup.fullscreen !=
8461 video.fullscreen_enabled);
8462 boolean change_window_scaling_percent = (!video.fullscreen_enabled &&
8463 setup.window_scaling_percent !=
8464 video.window_scaling_percent);
8466 if (change_window_scaling_percent && video.fullscreen_enabled)
8469 if (!change_window_scaling_percent && !video.fullscreen_available)
8472 #if defined(TARGET_SDL2)
8473 if (change_window_scaling_percent)
8475 SDLSetWindowScaling(setup.window_scaling_percent);
8479 else if (change_fullscreen)
8481 SDLSetWindowFullscreen(setup.fullscreen);
8483 /* set setup value according to successfully changed fullscreen mode */
8484 setup.fullscreen = video.fullscreen_enabled;
8490 if (change_fullscreen ||
8491 change_window_scaling_percent)
8493 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
8495 /* save backbuffer content which gets lost when toggling fullscreen mode */
8496 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8498 if (change_window_scaling_percent)
8500 /* keep window mode, but change window scaling */
8501 video.fullscreen_enabled = TRUE; /* force new window scaling */
8504 /* toggle fullscreen */
8505 ChangeVideoModeIfNeeded(setup.fullscreen);
8507 /* set setup value according to successfully changed fullscreen mode */
8508 setup.fullscreen = video.fullscreen_enabled;
8510 /* restore backbuffer content from temporary backbuffer backup bitmap */
8511 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8513 FreeBitmap(tmp_backbuffer);
8515 /* update visible window/screen */
8516 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8520 void JoinRectangles(int *x, int *y, int *width, int *height,
8521 int x2, int y2, int width2, int height2)
8523 // do not join with "off-screen" rectangle
8524 if (x2 == -1 || y2 == -1)
8529 *width = MAX(*width, width2);
8530 *height = MAX(*height, height2);
8533 void SetAnimStatus(int anim_status_new)
8535 if (anim_status_new == GAME_MODE_MAIN)
8536 anim_status_new = GAME_MODE_PSEUDO_MAINONLY;
8538 global.anim_status_next = anim_status_new;
8540 // directly set screen modes that are entered without fading
8541 if ((global.anim_status == GAME_MODE_PSEUDO_MAINONLY &&
8542 global.anim_status_next == GAME_MODE_PSEUDO_TYPENAME) ||
8543 (global.anim_status == GAME_MODE_PSEUDO_TYPENAME &&
8544 global.anim_status_next == GAME_MODE_PSEUDO_MAINONLY))
8545 global.anim_status = global.anim_status_next;
8548 void SetGameStatus(int game_status_new)
8550 if (game_status_new != game_status)
8551 game_status_last_screen = game_status;
8553 game_status = game_status_new;
8555 SetAnimStatus(game_status_new);
8558 void SetFontStatus(int game_status_new)
8560 static int last_game_status = -1;
8562 if (game_status_new != -1)
8564 // set game status for font use after storing last game status
8565 last_game_status = game_status;
8566 game_status = game_status_new;
8570 // reset game status after font use from last stored game status
8571 game_status = last_game_status;
8575 void ResetFontStatus()
8580 void ChangeViewportPropertiesIfNeeded()
8582 int gfx_game_mode = game_status;
8583 int gfx_game_mode2 = (game_status == GAME_MODE_EDITOR ? GAME_MODE_DEFAULT :
8585 struct RectWithBorder *vp_window = &viewport.window[gfx_game_mode];
8586 struct RectWithBorder *vp_playfield = &viewport.playfield[gfx_game_mode];
8587 struct RectWithBorder *vp_door_1 = &viewport.door_1[gfx_game_mode];
8588 struct RectWithBorder *vp_door_2 = &viewport.door_2[gfx_game_mode2];
8589 struct RectWithBorder *vp_door_3 = &viewport.door_2[GAME_MODE_EDITOR];
8590 int new_win_xsize = vp_window->width;
8591 int new_win_ysize = vp_window->height;
8592 int border_size = vp_playfield->border_size;
8593 int new_sx = vp_playfield->x + border_size;
8594 int new_sy = vp_playfield->y + border_size;
8595 int new_sxsize = vp_playfield->width - 2 * border_size;
8596 int new_sysize = vp_playfield->height - 2 * border_size;
8597 int new_real_sx = vp_playfield->x;
8598 int new_real_sy = vp_playfield->y;
8599 int new_full_sxsize = vp_playfield->width;
8600 int new_full_sysize = vp_playfield->height;
8601 int new_dx = vp_door_1->x;
8602 int new_dy = vp_door_1->y;
8603 int new_dxsize = vp_door_1->width;
8604 int new_dysize = vp_door_1->height;
8605 int new_vx = vp_door_2->x;
8606 int new_vy = vp_door_2->y;
8607 int new_vxsize = vp_door_2->width;
8608 int new_vysize = vp_door_2->height;
8609 int new_ex = vp_door_3->x;
8610 int new_ey = vp_door_3->y;
8611 int new_exsize = vp_door_3->width;
8612 int new_eysize = vp_door_3->height;
8613 int new_tilesize_var =
8614 (setup.small_game_graphics ? MINI_TILESIZE : game.tile_size);
8616 int tilesize = (gfx_game_mode == GAME_MODE_PLAYING ? new_tilesize_var :
8617 gfx_game_mode == GAME_MODE_EDITOR ? MINI_TILESIZE : TILESIZE);
8618 int new_scr_fieldx = new_sxsize / tilesize;
8619 int new_scr_fieldy = new_sysize / tilesize;
8620 int new_scr_fieldx_buffers = new_sxsize / new_tilesize_var;
8621 int new_scr_fieldy_buffers = new_sysize / new_tilesize_var;
8622 boolean init_gfx_buffers = FALSE;
8623 boolean init_video_buffer = FALSE;
8624 boolean init_gadgets_and_anims = FALSE;
8625 boolean init_em_graphics = FALSE;
8627 if (new_win_xsize != WIN_XSIZE ||
8628 new_win_ysize != WIN_YSIZE)
8630 WIN_XSIZE = new_win_xsize;
8631 WIN_YSIZE = new_win_ysize;
8633 init_video_buffer = TRUE;
8634 init_gfx_buffers = TRUE;
8635 init_gadgets_and_anims = TRUE;
8637 // printf("::: video: init_video_buffer, init_gfx_buffers\n");
8640 if (new_scr_fieldx != SCR_FIELDX ||
8641 new_scr_fieldy != SCR_FIELDY)
8643 /* this always toggles between MAIN and GAME when using small tile size */
8645 SCR_FIELDX = new_scr_fieldx;
8646 SCR_FIELDY = new_scr_fieldy;
8648 // printf("::: new_scr_fieldx != SCR_FIELDX ...\n");
8659 new_sxsize != SXSIZE ||
8660 new_sysize != SYSIZE ||
8661 new_dxsize != DXSIZE ||
8662 new_dysize != DYSIZE ||
8663 new_vxsize != VXSIZE ||
8664 new_vysize != VYSIZE ||
8665 new_exsize != EXSIZE ||
8666 new_eysize != EYSIZE ||
8667 new_real_sx != REAL_SX ||
8668 new_real_sy != REAL_SY ||
8669 new_full_sxsize != FULL_SXSIZE ||
8670 new_full_sysize != FULL_SYSIZE ||
8671 new_tilesize_var != TILESIZE_VAR
8674 // ------------------------------------------------------------------------
8675 // determine next fading area for changed viewport definitions
8676 // ------------------------------------------------------------------------
8678 // start with current playfield area (default fading area)
8681 FADE_SXSIZE = FULL_SXSIZE;
8682 FADE_SYSIZE = FULL_SYSIZE;
8684 // add new playfield area if position or size has changed
8685 if (new_real_sx != REAL_SX || new_real_sy != REAL_SY ||
8686 new_full_sxsize != FULL_SXSIZE || new_full_sysize != FULL_SYSIZE)
8688 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
8689 new_real_sx, new_real_sy, new_full_sxsize,new_full_sysize);
8692 // add current and new door 1 area if position or size has changed
8693 if (new_dx != DX || new_dy != DY ||
8694 new_dxsize != DXSIZE || new_dysize != DYSIZE)
8696 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
8697 DX, DY, DXSIZE, DYSIZE);
8698 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
8699 new_dx, new_dy, new_dxsize, new_dysize);
8702 // add current and new door 2 area if position or size has changed
8703 if (new_dx != VX || new_dy != VY ||
8704 new_dxsize != VXSIZE || new_dysize != VYSIZE)
8706 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
8707 VX, VY, VXSIZE, VYSIZE);
8708 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
8709 new_vx, new_vy, new_vxsize, new_vysize);
8712 // ------------------------------------------------------------------------
8713 // handle changed tile size
8714 // ------------------------------------------------------------------------
8716 if (new_tilesize_var != TILESIZE_VAR)
8718 // printf("::: new_tilesize_var != TILESIZE_VAR\n");
8720 // changing tile size invalidates scroll values of engine snapshots
8721 FreeEngineSnapshotSingle();
8723 // changing tile size requires update of graphic mapping for EM engine
8724 init_em_graphics = TRUE;
8735 SXSIZE = new_sxsize;
8736 SYSIZE = new_sysize;
8737 DXSIZE = new_dxsize;
8738 DYSIZE = new_dysize;
8739 VXSIZE = new_vxsize;
8740 VYSIZE = new_vysize;
8741 EXSIZE = new_exsize;
8742 EYSIZE = new_eysize;
8743 REAL_SX = new_real_sx;
8744 REAL_SY = new_real_sy;
8745 FULL_SXSIZE = new_full_sxsize;
8746 FULL_SYSIZE = new_full_sysize;
8747 TILESIZE_VAR = new_tilesize_var;
8749 init_gfx_buffers = TRUE;
8750 init_gadgets_and_anims = TRUE;
8752 // printf("::: viewports: init_gfx_buffers\n");
8753 // printf("::: viewports: init_gadgets_and_anims\n");
8756 if (init_gfx_buffers)
8758 // printf("::: init_gfx_buffers\n");
8760 SCR_FIELDX = new_scr_fieldx_buffers;
8761 SCR_FIELDY = new_scr_fieldy_buffers;
8765 SCR_FIELDX = new_scr_fieldx;
8766 SCR_FIELDY = new_scr_fieldy;
8768 SetDrawDeactivationMask(REDRAW_NONE);
8769 SetDrawBackgroundMask(REDRAW_FIELD);
8772 if (init_video_buffer)
8774 // printf("::: init_video_buffer\n");
8776 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
8777 InitImageTextures();
8780 if (init_gadgets_and_anims)
8782 // printf("::: init_gadgets_and_anims\n");
8785 InitGlobalAnimations();
8788 if (init_em_graphics)
8790 InitGraphicInfo_EM();