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 BlitBitmap(backbuffer, window, x1, y1, x2 - x1, y2 - y1, x1, y1);
765 redraw_mask = REDRAW_NONE;
768 PrintFrameTimeDebugging();
772 void BackToFront_WithFrameDelay(unsigned int frame_delay_value)
774 unsigned int frame_delay_value_old = GetVideoFrameDelay();
776 SetVideoFrameDelay(frame_delay_value);
780 SetVideoFrameDelay(frame_delay_value_old);
783 static int fade_type_skip = FADE_TYPE_NONE;
785 static void FadeExt(int fade_mask, int fade_mode, int fade_type)
787 void (*draw_border_function)(void) = NULL;
788 int x, y, width, height;
789 int fade_delay, post_delay;
791 if (fade_type == FADE_TYPE_FADE_OUT)
793 if (fade_type_skip != FADE_TYPE_NONE)
795 /* skip all fade operations until specified fade operation */
796 if (fade_type & fade_type_skip)
797 fade_type_skip = FADE_TYPE_NONE;
802 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
806 redraw_mask |= fade_mask;
808 if (fade_type == FADE_TYPE_SKIP)
810 fade_type_skip = fade_mode;
815 fade_delay = fading.fade_delay;
816 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
818 if (fade_type_skip != FADE_TYPE_NONE)
820 /* skip all fade operations until specified fade operation */
821 if (fade_type & fade_type_skip)
822 fade_type_skip = FADE_TYPE_NONE;
827 if (global.autoplay_leveldir)
832 if (fade_mask == REDRAW_FIELD)
837 height = FADE_SYSIZE;
839 if (border.draw_masked_when_fading)
840 draw_border_function = DrawMaskedBorder_FIELD; /* update when fading */
842 DrawMaskedBorder_FIELD(); /* draw once */
844 else /* REDRAW_ALL */
852 if (!setup.fade_screens ||
854 fading.fade_mode == FADE_MODE_NONE)
856 if (fade_mode == FADE_MODE_FADE_OUT)
859 BlitBitmap(backbuffer, window, x, y, width, height, x, y);
861 redraw_mask &= ~fade_mask;
866 FadeRectangle(x, y, width, height, fade_mode, fade_delay, post_delay,
867 draw_border_function);
869 redraw_mask &= ~fade_mask;
872 static void SetScreenStates_BeforeFadingIn()
874 // temporarily set screen mode for animations to screen after fading in
875 global.anim_status = global.anim_status_next;
877 // store backbuffer with all animations that will be started after fading in
878 if (fade_type_skip != FADE_MODE_SKIP_FADE_IN)
879 PrepareFadeBitmap(DRAW_TO_FADE_TARGET);
881 // set screen mode for animations back to fading
882 global.anim_status = GAME_MODE_PSEUDO_FADING;
885 static void SetScreenStates_AfterFadingIn()
887 // store new source screen (to use correct masked border for fading)
888 gfx.fade_border_source_status = global.border_status;
890 global.anim_status = global.anim_status_next;
893 static void SetScreenStates_BeforeFadingOut()
895 // store new target screen (to use correct masked border for fading)
896 gfx.fade_border_target_status = game_status;
898 // set screen mode for animations to fading
899 global.anim_status = GAME_MODE_PSEUDO_FADING;
901 // store backbuffer with all animations that will be stopped for fading out
902 if (fade_type_skip != FADE_MODE_SKIP_FADE_OUT)
903 PrepareFadeBitmap(DRAW_TO_FADE_SOURCE);
906 static void SetScreenStates_AfterFadingOut()
908 global.border_status = game_status;
911 void FadeIn(int fade_mask)
913 SetScreenStates_BeforeFadingIn();
916 DrawMaskedBorder(REDRAW_ALL);
919 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
920 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_IN);
922 FadeExt(fade_mask, FADE_MODE_FADE_IN, FADE_TYPE_FADE_IN);
926 FADE_SXSIZE = FULL_SXSIZE;
927 FADE_SYSIZE = FULL_SYSIZE;
929 SetScreenStates_AfterFadingIn();
931 // force update of global animation status in case of rapid screen changes
932 redraw_mask = REDRAW_ALL;
936 void FadeOut(int fade_mask)
938 // update screen if areas covered by "fade_mask" and "redraw_mask" differ
939 if (!equalRedrawMasks(fade_mask, redraw_mask))
942 SetScreenStates_BeforeFadingOut();
945 DrawMaskedBorder(REDRAW_ALL);
948 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
949 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_OUT);
951 FadeExt(fade_mask, FADE_MODE_FADE_OUT, FADE_TYPE_FADE_OUT);
953 SetScreenStates_AfterFadingOut();
956 static void FadeSetLeaveNext(struct TitleFadingInfo fading_leave, boolean set)
958 static struct TitleFadingInfo fading_leave_stored;
961 fading_leave_stored = fading_leave;
963 fading = fading_leave_stored;
966 void FadeSetEnterMenu()
968 fading = menu.enter_menu;
970 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
973 void FadeSetLeaveMenu()
975 fading = menu.leave_menu;
977 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
980 void FadeSetEnterScreen()
982 fading = menu.enter_screen[game_status];
984 FadeSetLeaveNext(menu.leave_screen[game_status], TRUE); /* store */
987 void FadeSetNextScreen()
989 fading = menu.next_screen[game_status];
991 // (do not overwrite fade mode set by FadeSetEnterScreen)
992 // FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
995 void FadeSetLeaveScreen()
997 FadeSetLeaveNext(menu.leave_screen[game_status], FALSE); /* recall */
1000 void FadeSetFromType(int type)
1002 if (type & TYPE_ENTER_SCREEN)
1003 FadeSetEnterScreen();
1004 else if (type & TYPE_ENTER)
1006 else if (type & TYPE_LEAVE)
1010 void FadeSetDisabled()
1012 static struct TitleFadingInfo fading_none = { FADE_MODE_NONE, -1, -1, -1 };
1014 fading = fading_none;
1017 void FadeSkipNextFadeIn()
1019 FadeExt(0, FADE_MODE_SKIP_FADE_IN, FADE_TYPE_SKIP);
1022 void FadeSkipNextFadeOut()
1024 FadeExt(0, FADE_MODE_SKIP_FADE_OUT, FADE_TYPE_SKIP);
1027 Bitmap *getBitmapFromGraphicOrDefault(int graphic, int default_graphic)
1029 boolean redefined = getImageListEntryFromImageID(graphic)->redefined;
1031 return (graphic == IMG_UNDEFINED ? NULL :
1032 graphic_info[graphic].bitmap != NULL || redefined ?
1033 graphic_info[graphic].bitmap :
1034 graphic_info[default_graphic].bitmap);
1037 Bitmap *getBackgroundBitmap(int graphic)
1039 return getBitmapFromGraphicOrDefault(graphic, IMG_BACKGROUND);
1042 Bitmap *getGlobalBorderBitmap(int graphic)
1044 return getBitmapFromGraphicOrDefault(graphic, IMG_GLOBAL_BORDER);
1047 Bitmap *getGlobalBorderBitmapFromStatus(int status)
1050 (status == GAME_MODE_MAIN ||
1051 status == GAME_MODE_PSEUDO_TYPENAME ? IMG_GLOBAL_BORDER_MAIN :
1052 status == GAME_MODE_SCORES ? IMG_GLOBAL_BORDER_SCORES :
1053 status == GAME_MODE_EDITOR ? IMG_GLOBAL_BORDER_EDITOR :
1054 status == GAME_MODE_PLAYING ? IMG_GLOBAL_BORDER_PLAYING :
1057 return getGlobalBorderBitmap(graphic);
1060 void SetWindowBackgroundImageIfDefined(int graphic)
1062 if (graphic_info[graphic].bitmap)
1063 SetWindowBackgroundBitmap(graphic_info[graphic].bitmap);
1066 void SetMainBackgroundImageIfDefined(int graphic)
1068 if (graphic_info[graphic].bitmap)
1069 SetMainBackgroundBitmap(graphic_info[graphic].bitmap);
1072 void SetDoorBackgroundImageIfDefined(int graphic)
1074 if (graphic_info[graphic].bitmap)
1075 SetDoorBackgroundBitmap(graphic_info[graphic].bitmap);
1078 void SetWindowBackgroundImage(int graphic)
1080 SetWindowBackgroundBitmap(getBackgroundBitmap(graphic));
1083 void SetMainBackgroundImage(int graphic)
1085 SetMainBackgroundBitmap(getBackgroundBitmap(graphic));
1088 void SetDoorBackgroundImage(int graphic)
1090 SetDoorBackgroundBitmap(getBackgroundBitmap(graphic));
1093 void SetPanelBackground()
1095 struct GraphicInfo *gfx = &graphic_info[IMG_BACKGROUND_PANEL];
1097 BlitBitmapTiled(gfx->bitmap, bitmap_db_panel, gfx->src_x, gfx->src_y,
1098 gfx->width, gfx->height, 0, 0, DXSIZE, DYSIZE);
1100 SetDoorBackgroundBitmap(bitmap_db_panel);
1103 void DrawBackground(int x, int y, int width, int height)
1105 /* "drawto" might still point to playfield buffer here (hall of fame) */
1106 ClearRectangleOnBackground(backbuffer, x, y, width, height);
1108 if (IN_GFX_FIELD_FULL(x, y))
1109 redraw_mask |= REDRAW_FIELD;
1110 else if (IN_GFX_DOOR_1(x, y))
1111 redraw_mask |= REDRAW_DOOR_1;
1112 else if (IN_GFX_DOOR_2(x, y))
1113 redraw_mask |= REDRAW_DOOR_2;
1114 else if (IN_GFX_DOOR_3(x, y))
1115 redraw_mask |= REDRAW_DOOR_3;
1118 void DrawBackgroundForFont(int x, int y, int width, int height, int font_nr)
1120 struct FontBitmapInfo *font = getFontBitmapInfo(font_nr);
1122 if (font->bitmap == NULL)
1125 DrawBackground(x, y, width, height);
1128 void DrawBackgroundForGraphic(int x, int y, int width, int height, int graphic)
1130 struct GraphicInfo *g = &graphic_info[graphic];
1132 if (g->bitmap == NULL)
1135 DrawBackground(x, y, width, height);
1138 static int game_status_last = -1;
1139 static Bitmap *global_border_bitmap_last = NULL;
1140 static Bitmap *global_border_bitmap = NULL;
1141 static int real_sx_last = -1, real_sy_last = -1;
1142 static int full_sxsize_last = -1, full_sysize_last = -1;
1143 static int dx_last = -1, dy_last = -1;
1144 static int dxsize_last = -1, dysize_last = -1;
1145 static int vx_last = -1, vy_last = -1;
1146 static int vxsize_last = -1, vysize_last = -1;
1148 boolean CheckIfGlobalBorderHasChanged()
1150 // if game status has not changed, global border has not changed either
1151 if (game_status == game_status_last)
1154 // determine and store new global border bitmap for current game status
1155 global_border_bitmap = getGlobalBorderBitmapFromStatus(game_status);
1157 return (global_border_bitmap_last != global_border_bitmap);
1160 boolean CheckIfGlobalBorderRedrawIsNeeded()
1162 // if game status has not changed, nothing has to be redrawn
1163 if (game_status == game_status_last)
1166 // redraw if last screen was title screen
1167 if (game_status_last == GAME_MODE_TITLE)
1170 // redraw if global screen border has changed
1171 if (CheckIfGlobalBorderHasChanged())
1174 // redraw if position or size of playfield area has changed
1175 if (real_sx_last != REAL_SX || real_sy_last != REAL_SY ||
1176 full_sxsize_last != FULL_SXSIZE || full_sysize_last != FULL_SYSIZE)
1179 // redraw if position or size of door area has changed
1180 if (dx_last != DX || dy_last != DY ||
1181 dxsize_last != DXSIZE || dysize_last != DYSIZE)
1184 // redraw if position or size of tape area has changed
1185 if (vx_last != VX || vy_last != VY ||
1186 vxsize_last != VXSIZE || vysize_last != VYSIZE)
1192 void RedrawGlobalBorderFromBitmap(Bitmap *bitmap)
1195 BlitBitmap(bitmap, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
1197 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
1200 void RedrawGlobalBorder()
1202 Bitmap *bitmap = getGlobalBorderBitmapFromStatus(game_status);
1204 RedrawGlobalBorderFromBitmap(bitmap);
1206 redraw_mask = REDRAW_ALL;
1209 static void RedrawGlobalBorderIfNeeded()
1211 if (game_status == game_status_last)
1214 // copy current draw buffer to later copy back areas that have not changed
1215 if (game_status_last != GAME_MODE_TITLE)
1216 BlitBitmap(backbuffer, bitmap_db_store_1, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
1218 if (CheckIfGlobalBorderRedrawIsNeeded())
1220 // redraw global screen border (or clear, if defined to be empty)
1221 RedrawGlobalBorderFromBitmap(global_border_bitmap);
1223 // copy previous playfield and door areas, if they are defined on both
1224 // previous and current screen and if they still have the same size
1226 if (real_sx_last != -1 && real_sy_last != -1 &&
1227 REAL_SX != -1 && REAL_SY != -1 &&
1228 full_sxsize_last == FULL_SXSIZE && full_sysize_last == FULL_SYSIZE)
1229 BlitBitmap(bitmap_db_store_1, backbuffer,
1230 real_sx_last, real_sy_last, FULL_SXSIZE, FULL_SYSIZE,
1233 if (dx_last != -1 && dy_last != -1 &&
1234 DX != -1 && DY != -1 &&
1235 dxsize_last == DXSIZE && dysize_last == DYSIZE)
1236 BlitBitmap(bitmap_db_store_1, backbuffer,
1237 dx_last, dy_last, DXSIZE, DYSIZE, DX, DY);
1239 if (vx_last != -1 && vy_last != -1 &&
1240 VX != -1 && VY != -1 &&
1241 vxsize_last == VXSIZE && vysize_last == VYSIZE)
1242 BlitBitmap(bitmap_db_store_1, backbuffer,
1243 vx_last, vy_last, VXSIZE, VYSIZE, VX, VY);
1245 redraw_mask = REDRAW_ALL;
1248 game_status_last = game_status;
1250 global_border_bitmap_last = global_border_bitmap;
1252 real_sx_last = REAL_SX;
1253 real_sy_last = REAL_SY;
1254 full_sxsize_last = FULL_SXSIZE;
1255 full_sysize_last = FULL_SYSIZE;
1258 dxsize_last = DXSIZE;
1259 dysize_last = DYSIZE;
1262 vxsize_last = VXSIZE;
1263 vysize_last = VYSIZE;
1268 RedrawGlobalBorderIfNeeded();
1270 /* !!! "drawto" might still point to playfield buffer here (see above) !!! */
1271 /* (when entering hall of fame after playing) */
1272 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
1274 /* !!! maybe this should be done before clearing the background !!! */
1275 if (game_status == GAME_MODE_PLAYING)
1277 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
1278 SetDrawtoField(DRAW_TO_FIELDBUFFER);
1282 SetDrawtoField(DRAW_TO_BACKBUFFER);
1286 void MarkTileDirty(int x, int y)
1288 redraw_mask |= REDRAW_FIELD;
1291 void SetBorderElement()
1295 BorderElement = EL_EMPTY;
1297 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
1299 for (x = 0; x < lev_fieldx; x++)
1301 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
1302 BorderElement = EL_STEELWALL;
1304 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
1310 void FloodFillLevel(int from_x, int from_y, int fill_element,
1311 short field[MAX_LEV_FIELDX][MAX_LEV_FIELDY],
1312 int max_fieldx, int max_fieldy)
1316 static int check[4][2] = { { -1, 0 }, { 0, -1 }, { 1, 0 }, { 0, 1 } };
1317 static int safety = 0;
1319 /* check if starting field still has the desired content */
1320 if (field[from_x][from_y] == fill_element)
1325 if (safety > max_fieldx * max_fieldy)
1326 Error(ERR_EXIT, "Something went wrong in 'FloodFill()'. Please debug.");
1328 old_element = field[from_x][from_y];
1329 field[from_x][from_y] = fill_element;
1331 for (i = 0; i < 4; i++)
1333 x = from_x + check[i][0];
1334 y = from_y + check[i][1];
1336 if (IN_FIELD(x, y, max_fieldx, max_fieldy) && field[x][y] == old_element)
1337 FloodFillLevel(x, y, fill_element, field, max_fieldx, max_fieldy);
1343 void SetRandomAnimationValue(int x, int y)
1345 gfx.anim_random_frame = GfxRandom[x][y];
1348 int getGraphicAnimationFrame(int graphic, int sync_frame)
1350 /* animation synchronized with global frame counter, not move position */
1351 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
1352 sync_frame = FrameCounter;
1354 return getAnimationFrame(graphic_info[graphic].anim_frames,
1355 graphic_info[graphic].anim_delay,
1356 graphic_info[graphic].anim_mode,
1357 graphic_info[graphic].anim_start_frame,
1361 void getGraphicSourceBitmap(int graphic, int tilesize, Bitmap **bitmap)
1363 struct GraphicInfo *g = &graphic_info[graphic];
1364 int tilesize_capped = MIN(MAX(1, tilesize), TILESIZE);
1366 if (tilesize == gfx.standard_tile_size)
1367 *bitmap = g->bitmaps[IMG_BITMAP_STANDARD];
1368 else if (tilesize == game.tile_size)
1369 *bitmap = g->bitmaps[IMG_BITMAP_GAME];
1371 *bitmap = g->bitmaps[IMG_BITMAP_1x1 - log_2(tilesize_capped)];
1374 void getGraphicSourceXY(int graphic, int frame, int *x, int *y,
1375 boolean get_backside)
1377 struct GraphicInfo *g = &graphic_info[graphic];
1378 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
1379 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
1381 if (g->offset_y == 0) /* frames are ordered horizontally */
1383 int max_width = g->anim_frames_per_line * g->width;
1384 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
1386 *x = pos % max_width;
1387 *y = src_y % g->height + pos / max_width * g->height;
1389 else if (g->offset_x == 0) /* frames are ordered vertically */
1391 int max_height = g->anim_frames_per_line * g->height;
1392 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
1394 *x = src_x % g->width + pos / max_height * g->width;
1395 *y = pos % max_height;
1397 else /* frames are ordered diagonally */
1399 *x = src_x + frame * g->offset_x;
1400 *y = src_y + frame * g->offset_y;
1404 void getSizedGraphicSourceExt(int graphic, int frame, int tilesize,
1405 Bitmap **bitmap, int *x, int *y,
1406 boolean get_backside)
1408 struct GraphicInfo *g = &graphic_info[graphic];
1410 // if no in-game graphics defined, always use standard graphic size
1411 if (g->bitmaps[IMG_BITMAP_GAME] == NULL)
1412 tilesize = TILESIZE;
1414 getGraphicSourceBitmap(graphic, tilesize, bitmap);
1415 getGraphicSourceXY(graphic, frame, x, y, get_backside);
1417 *x = *x * tilesize / g->tile_size;
1418 *y = *y * tilesize / g->tile_size;
1421 void getFixedGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1422 int *x, int *y, boolean get_backside)
1424 getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y,
1428 void getSizedGraphicSource(int graphic, int frame, int tilesize,
1429 Bitmap **bitmap, int *x, int *y)
1431 getSizedGraphicSourceExt(graphic, frame, tilesize, bitmap, x, y, FALSE);
1434 void getFixedGraphicSource(int graphic, int frame,
1435 Bitmap **bitmap, int *x, int *y)
1437 getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y, FALSE);
1440 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1442 getSizedGraphicSource(graphic, 0, MINI_TILESIZE, bitmap, x, y);
1445 inline static void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1446 int *x, int *y, boolean get_backside)
1448 getSizedGraphicSourceExt(graphic, frame, TILESIZE_VAR, bitmap, x, y,
1452 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
1454 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
1457 void DrawGraphic(int x, int y, int graphic, int frame)
1460 if (!IN_SCR_FIELD(x, y))
1462 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1463 printf("DrawGraphic(): This should never happen!\n");
1468 DrawGraphicExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR, graphic,
1471 MarkTileDirty(x, y);
1474 void DrawFixedGraphic(int x, int y, int graphic, int frame)
1477 if (!IN_SCR_FIELD(x, y))
1479 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1480 printf("DrawGraphic(): This should never happen!\n");
1485 DrawFixedGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic,
1487 MarkTileDirty(x, y);
1490 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1496 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1498 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX_VAR, TILEY_VAR, x, y);
1501 void DrawFixedGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1507 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1508 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
1511 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
1514 if (!IN_SCR_FIELD(x, y))
1516 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1517 printf("DrawGraphicThruMask(): This should never happen!\n");
1522 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
1525 MarkTileDirty(x, y);
1528 void DrawFixedGraphicThruMask(int x, int y, int graphic, int frame)
1531 if (!IN_SCR_FIELD(x, y))
1533 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1534 printf("DrawGraphicThruMask(): This should never happen!\n");
1539 DrawFixedGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
1541 MarkTileDirty(x, y);
1544 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
1550 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1552 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX_VAR, TILEY_VAR,
1556 void DrawFixedGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y,
1557 int graphic, int frame)
1562 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1564 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY,
1568 void DrawSizedGraphic(int x, int y, int graphic, int frame, int tilesize)
1570 DrawSizedGraphicExt(drawto, SX + x * tilesize, SY + y * tilesize, graphic,
1572 MarkTileDirty(x / tilesize, y / tilesize);
1575 void DrawSizedGraphicExt(DrawBuffer *d, int x, int y, int graphic, int frame,
1581 getSizedGraphicSource(graphic, frame, tilesize, &src_bitmap, &src_x, &src_y);
1582 BlitBitmap(src_bitmap, d, src_x, src_y, tilesize, tilesize, x, y);
1585 void DrawMiniGraphic(int x, int y, int graphic)
1587 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
1588 MarkTileDirty(x / 2, y / 2);
1591 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
1596 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1597 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
1600 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
1601 int graphic, int frame,
1602 int cut_mode, int mask_mode)
1607 int width = TILEX, height = TILEY;
1610 if (dx || dy) /* shifted graphic */
1612 if (x < BX1) /* object enters playfield from the left */
1619 else if (x > BX2) /* object enters playfield from the right */
1625 else if (x == BX1 && dx < 0) /* object leaves playfield to the left */
1631 else if (x == BX2 && dx > 0) /* object leaves playfield to the right */
1633 else if (dx) /* general horizontal movement */
1634 MarkTileDirty(x + SIGN(dx), y);
1636 if (y < BY1) /* object enters playfield from the top */
1638 if (cut_mode == CUT_BELOW) /* object completely above top border */
1646 else if (y > BY2) /* object enters playfield from the bottom */
1652 else if (y == BY1 && dy < 0) /* object leaves playfield to the top */
1658 else if (dy > 0 && cut_mode == CUT_ABOVE)
1660 if (y == BY2) /* object completely above bottom border */
1666 MarkTileDirty(x, y + 1);
1667 } /* object leaves playfield to the bottom */
1668 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1670 else if (dy) /* general vertical movement */
1671 MarkTileDirty(x, y + SIGN(dy));
1675 if (!IN_SCR_FIELD(x, y))
1677 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1678 printf("DrawGraphicShifted(): This should never happen!\n");
1683 width = width * TILESIZE_VAR / TILESIZE;
1684 height = height * TILESIZE_VAR / TILESIZE;
1685 cx = cx * TILESIZE_VAR / TILESIZE;
1686 cy = cy * TILESIZE_VAR / TILESIZE;
1687 dx = dx * TILESIZE_VAR / TILESIZE;
1688 dy = dy * TILESIZE_VAR / TILESIZE;
1690 if (width > 0 && height > 0)
1692 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1697 dst_x = FX + x * TILEX_VAR + dx;
1698 dst_y = FY + y * TILEY_VAR + dy;
1700 if (mask_mode == USE_MASKING)
1701 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1704 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1707 MarkTileDirty(x, y);
1711 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
1712 int graphic, int frame,
1713 int cut_mode, int mask_mode)
1718 int width = TILEX_VAR, height = TILEY_VAR;
1721 int x2 = x + SIGN(dx);
1722 int y2 = y + SIGN(dy);
1724 /* movement with two-tile animations must be sync'ed with movement position,
1725 not with current GfxFrame (which can be higher when using slow movement) */
1726 int anim_pos = (dx ? ABS(dx) : ABS(dy));
1727 int anim_frames = graphic_info[graphic].anim_frames;
1729 /* (we also need anim_delay here for movement animations with less frames) */
1730 int anim_delay = graphic_info[graphic].anim_delay;
1731 int sync_frame = anim_pos * anim_frames * anim_delay / TILESIZE;
1733 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
1734 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
1736 /* re-calculate animation frame for two-tile movement animation */
1737 frame = getGraphicAnimationFrame(graphic, sync_frame);
1739 /* check if movement start graphic inside screen area and should be drawn */
1740 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
1742 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
1744 dst_x = FX + x1 * TILEX_VAR;
1745 dst_y = FY + y1 * TILEY_VAR;
1747 if (mask_mode == USE_MASKING)
1748 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1751 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1754 MarkTileDirty(x1, y1);
1757 /* check if movement end graphic inside screen area and should be drawn */
1758 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
1760 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
1762 dst_x = FX + x2 * TILEX_VAR;
1763 dst_y = FY + y2 * TILEY_VAR;
1765 if (mask_mode == USE_MASKING)
1766 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1769 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1772 MarkTileDirty(x2, y2);
1776 static void DrawGraphicShifted(int x, int y, int dx, int dy,
1777 int graphic, int frame,
1778 int cut_mode, int mask_mode)
1782 DrawGraphic(x, y, graphic, frame);
1787 if (graphic_info[graphic].double_movement) /* EM style movement images */
1788 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1790 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1793 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1794 int frame, int cut_mode)
1796 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
1799 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1800 int cut_mode, int mask_mode)
1802 int lx = LEVELX(x), ly = LEVELY(y);
1806 if (IN_LEV_FIELD(lx, ly))
1808 SetRandomAnimationValue(lx, ly);
1810 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
1811 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1813 /* do not use double (EM style) movement graphic when not moving */
1814 if (graphic_info[graphic].double_movement && !dx && !dy)
1816 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
1817 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1820 else /* border element */
1822 graphic = el2img(element);
1823 frame = getGraphicAnimationFrame(graphic, -1);
1826 if (element == EL_EXPANDABLE_WALL)
1828 boolean left_stopped = FALSE, right_stopped = FALSE;
1830 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1831 left_stopped = TRUE;
1832 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1833 right_stopped = TRUE;
1835 if (left_stopped && right_stopped)
1837 else if (left_stopped)
1839 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1840 frame = graphic_info[graphic].anim_frames - 1;
1842 else if (right_stopped)
1844 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1845 frame = graphic_info[graphic].anim_frames - 1;
1850 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1851 else if (mask_mode == USE_MASKING)
1852 DrawGraphicThruMask(x, y, graphic, frame);
1854 DrawGraphic(x, y, graphic, frame);
1857 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1858 int cut_mode, int mask_mode)
1860 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1861 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1862 cut_mode, mask_mode);
1865 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1868 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1871 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1874 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1877 void DrawLevelElementThruMask(int x, int y, int element)
1879 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1882 void DrawLevelFieldThruMask(int x, int y)
1884 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1887 /* !!! implementation of quicksand is totally broken !!! */
1888 #define IS_CRUMBLED_TILE(x, y, e) \
1889 (GFX_CRUMBLED(e) && (!IN_LEV_FIELD(x, y) || \
1890 !IS_MOVING(x, y) || \
1891 (e) == EL_QUICKSAND_EMPTYING || \
1892 (e) == EL_QUICKSAND_FAST_EMPTYING))
1894 static void DrawLevelFieldCrumbledInnerCorners(int x, int y, int dx, int dy,
1899 int width, height, cx, cy;
1900 int sx = SCREENX(x), sy = SCREENY(y);
1901 int crumbled_border_size = graphic_info[graphic].border_size;
1902 int crumbled_tile_size = graphic_info[graphic].tile_size;
1903 int crumbled_border_size_var =
1904 crumbled_border_size * TILESIZE_VAR / crumbled_tile_size;
1907 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1909 for (i = 1; i < 4; i++)
1911 int dxx = (i & 1 ? dx : 0);
1912 int dyy = (i & 2 ? dy : 0);
1915 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1918 /* check if neighbour field is of same crumble type */
1919 boolean same = (IS_CRUMBLED_TILE(xx, yy, element) &&
1920 graphic_info[graphic].class ==
1921 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class);
1923 /* return if check prevents inner corner */
1924 if (same == (dxx == dx && dyy == dy))
1928 /* if we reach this point, we have an inner corner */
1930 getGraphicSource(graphic, 1, &src_bitmap, &src_x, &src_y);
1932 width = crumbled_border_size_var;
1933 height = crumbled_border_size_var;
1934 cx = (dx > 0 ? TILESIZE_VAR - width : 0);
1935 cy = (dy > 0 ? TILESIZE_VAR - height : 0);
1937 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1938 width, height, FX + sx * TILEX_VAR + cx, FY + sy * TILEY_VAR + cy);
1941 static void DrawLevelFieldCrumbledBorders(int x, int y, int graphic, int frame,
1946 int width, height, bx, by, cx, cy;
1947 int sx = SCREENX(x), sy = SCREENY(y);
1948 int crumbled_border_size = graphic_info[graphic].border_size;
1949 int crumbled_tile_size = graphic_info[graphic].tile_size;
1950 int crumbled_border_size_var =
1951 crumbled_border_size * TILESIZE_VAR / crumbled_tile_size;
1952 int crumbled_border_pos_var = TILESIZE_VAR - crumbled_border_size_var;
1955 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1957 /* draw simple, sloppy, non-corner-accurate crumbled border */
1959 width = (dir == 1 || dir == 2 ? crumbled_border_size_var : TILESIZE_VAR);
1960 height = (dir == 0 || dir == 3 ? crumbled_border_size_var : TILESIZE_VAR);
1961 cx = (dir == 2 ? crumbled_border_pos_var : 0);
1962 cy = (dir == 3 ? crumbled_border_pos_var : 0);
1964 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy, width, height,
1965 FX + sx * TILEX_VAR + cx,
1966 FY + sy * TILEY_VAR + cy);
1968 /* (remaining middle border part must be at least as big as corner part) */
1969 if (!(graphic_info[graphic].style & STYLE_ACCURATE_BORDERS) ||
1970 crumbled_border_size_var >= TILESIZE_VAR / 3)
1973 /* correct corners of crumbled border, if needed */
1975 for (i = -1; i <= 1; i += 2)
1977 int xx = x + (dir == 0 || dir == 3 ? i : 0);
1978 int yy = y + (dir == 1 || dir == 2 ? i : 0);
1979 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1982 /* check if neighbour field is of same crumble type */
1983 if (IS_CRUMBLED_TILE(xx, yy, element) &&
1984 graphic_info[graphic].class ==
1985 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1987 /* no crumbled corner, but continued crumbled border */
1989 int c1 = (dir == 2 || dir == 3 ? crumbled_border_pos_var : 0);
1990 int c2 = (i == 1 ? crumbled_border_pos_var : 0);
1991 int b1 = (i == 1 ? crumbled_border_size_var :
1992 TILESIZE_VAR - 2 * crumbled_border_size_var);
1994 width = crumbled_border_size_var;
1995 height = crumbled_border_size_var;
1997 if (dir == 1 || dir == 2)
2012 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
2014 FX + sx * TILEX_VAR + cx,
2015 FY + sy * TILEY_VAR + cy);
2020 static void DrawLevelFieldCrumbledExt(int x, int y, int graphic, int frame)
2022 int sx = SCREENX(x), sy = SCREENY(y);
2025 static int xy[4][2] =
2033 if (!IN_LEV_FIELD(x, y))
2036 element = TILE_GFX_ELEMENT(x, y);
2038 if (IS_CRUMBLED_TILE(x, y, element)) /* crumble field itself */
2040 if (!IN_SCR_FIELD(sx, sy))
2043 /* crumble field borders towards direct neighbour fields */
2044 for (i = 0; i < 4; i++)
2046 int xx = x + xy[i][0];
2047 int yy = y + xy[i][1];
2049 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
2052 /* check if neighbour field is of same crumble type */
2053 if (IS_CRUMBLED_TILE(xx, yy, element) &&
2054 graphic_info[graphic].class ==
2055 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
2058 DrawLevelFieldCrumbledBorders(x, y, graphic, frame, i);
2061 /* crumble inner field corners towards corner neighbour fields */
2062 if ((graphic_info[graphic].style & STYLE_INNER_CORNERS) &&
2063 graphic_info[graphic].anim_frames == 2)
2065 for (i = 0; i < 4; i++)
2067 int dx = (i & 1 ? +1 : -1);
2068 int dy = (i & 2 ? +1 : -1);
2070 DrawLevelFieldCrumbledInnerCorners(x, y, dx, dy, graphic);
2074 MarkTileDirty(sx, sy);
2076 else /* center field is not crumbled -- crumble neighbour fields */
2078 /* crumble field borders of direct neighbour fields */
2079 for (i = 0; i < 4; i++)
2081 int xx = x + xy[i][0];
2082 int yy = y + xy[i][1];
2083 int sxx = sx + xy[i][0];
2084 int syy = sy + xy[i][1];
2086 if (!IN_LEV_FIELD(xx, yy) ||
2087 !IN_SCR_FIELD(sxx, syy))
2090 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
2093 element = TILE_GFX_ELEMENT(xx, yy);
2095 if (!IS_CRUMBLED_TILE(xx, yy, element))
2098 graphic = el_act2crm(element, ACTION_DEFAULT);
2100 DrawLevelFieldCrumbledBorders(xx, yy, graphic, 0, 3 - i);
2102 MarkTileDirty(sxx, syy);
2105 /* crumble inner field corners of corner neighbour fields */
2106 for (i = 0; i < 4; i++)
2108 int dx = (i & 1 ? +1 : -1);
2109 int dy = (i & 2 ? +1 : -1);
2115 if (!IN_LEV_FIELD(xx, yy) ||
2116 !IN_SCR_FIELD(sxx, syy))
2119 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
2122 element = TILE_GFX_ELEMENT(xx, yy);
2124 if (!IS_CRUMBLED_TILE(xx, yy, element))
2127 graphic = el_act2crm(element, ACTION_DEFAULT);
2129 if ((graphic_info[graphic].style & STYLE_INNER_CORNERS) &&
2130 graphic_info[graphic].anim_frames == 2)
2131 DrawLevelFieldCrumbledInnerCorners(xx, yy, -dx, -dy, graphic);
2133 MarkTileDirty(sxx, syy);
2138 void DrawLevelFieldCrumbled(int x, int y)
2142 if (!IN_LEV_FIELD(x, y))
2145 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
2146 GfxElement[x][y] != EL_UNDEFINED &&
2147 GFX_CRUMBLED(GfxElement[x][y]))
2149 DrawLevelFieldCrumbledDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
2154 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
2156 DrawLevelFieldCrumbledExt(x, y, graphic, 0);
2159 void DrawLevelFieldCrumbledDigging(int x, int y, int direction,
2162 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
2163 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
2164 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
2165 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
2166 int sx = SCREENX(x), sy = SCREENY(y);
2168 DrawGraphic(sx, sy, graphic1, frame1);
2169 DrawLevelFieldCrumbledExt(x, y, graphic2, frame2);
2172 void DrawLevelFieldCrumbledNeighbours(int x, int y)
2174 int sx = SCREENX(x), sy = SCREENY(y);
2175 static int xy[4][2] =
2184 /* crumble direct neighbour fields (required for field borders) */
2185 for (i = 0; i < 4; i++)
2187 int xx = x + xy[i][0];
2188 int yy = y + xy[i][1];
2189 int sxx = sx + xy[i][0];
2190 int syy = sy + xy[i][1];
2192 if (!IN_LEV_FIELD(xx, yy) ||
2193 !IN_SCR_FIELD(sxx, syy) ||
2194 !GFX_CRUMBLED(Feld[xx][yy]) ||
2198 DrawLevelField(xx, yy);
2201 /* crumble corner neighbour fields (required for inner field corners) */
2202 for (i = 0; i < 4; i++)
2204 int dx = (i & 1 ? +1 : -1);
2205 int dy = (i & 2 ? +1 : -1);
2211 if (!IN_LEV_FIELD(xx, yy) ||
2212 !IN_SCR_FIELD(sxx, syy) ||
2213 !GFX_CRUMBLED(Feld[xx][yy]) ||
2217 int element = TILE_GFX_ELEMENT(xx, yy);
2218 int graphic = el_act2crm(element, ACTION_DEFAULT);
2220 if ((graphic_info[graphic].style & STYLE_INNER_CORNERS) &&
2221 graphic_info[graphic].anim_frames == 2)
2222 DrawLevelField(xx, yy);
2226 static int getBorderElement(int x, int y)
2230 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
2231 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
2232 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
2233 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
2234 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
2235 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
2236 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
2238 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
2239 int steel_position = (x == -1 && y == -1 ? 0 :
2240 x == lev_fieldx && y == -1 ? 1 :
2241 x == -1 && y == lev_fieldy ? 2 :
2242 x == lev_fieldx && y == lev_fieldy ? 3 :
2243 x == -1 || x == lev_fieldx ? 4 :
2244 y == -1 || y == lev_fieldy ? 5 : 6);
2246 return border[steel_position][steel_type];
2249 void DrawScreenElement(int x, int y, int element)
2251 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
2252 DrawLevelFieldCrumbled(LEVELX(x), LEVELY(y));
2255 void DrawLevelElement(int x, int y, int element)
2257 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2258 DrawScreenElement(SCREENX(x), SCREENY(y), element);
2261 void DrawScreenField(int x, int y)
2263 int lx = LEVELX(x), ly = LEVELY(y);
2264 int element, content;
2266 if (!IN_LEV_FIELD(lx, ly))
2268 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
2271 element = getBorderElement(lx, ly);
2273 DrawScreenElement(x, y, element);
2278 element = Feld[lx][ly];
2279 content = Store[lx][ly];
2281 if (IS_MOVING(lx, ly))
2283 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
2284 boolean cut_mode = NO_CUTTING;
2286 if (element == EL_QUICKSAND_EMPTYING ||
2287 element == EL_QUICKSAND_FAST_EMPTYING ||
2288 element == EL_MAGIC_WALL_EMPTYING ||
2289 element == EL_BD_MAGIC_WALL_EMPTYING ||
2290 element == EL_DC_MAGIC_WALL_EMPTYING ||
2291 element == EL_AMOEBA_DROPPING)
2292 cut_mode = CUT_ABOVE;
2293 else if (element == EL_QUICKSAND_FILLING ||
2294 element == EL_QUICKSAND_FAST_FILLING ||
2295 element == EL_MAGIC_WALL_FILLING ||
2296 element == EL_BD_MAGIC_WALL_FILLING ||
2297 element == EL_DC_MAGIC_WALL_FILLING)
2298 cut_mode = CUT_BELOW;
2300 if (cut_mode == CUT_ABOVE)
2301 DrawScreenElement(x, y, element);
2303 DrawScreenElement(x, y, EL_EMPTY);
2306 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
2307 else if (cut_mode == NO_CUTTING)
2308 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
2311 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
2313 if (cut_mode == CUT_BELOW &&
2314 IN_LEV_FIELD(lx, ly + 1) && IN_SCR_FIELD(x, y + 1))
2315 DrawLevelElement(lx, ly + 1, element);
2318 if (content == EL_ACID)
2320 int dir = MovDir[lx][ly];
2321 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
2322 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
2324 DrawLevelElementThruMask(newlx, newly, EL_ACID);
2326 // prevent target field from being drawn again (but without masking)
2327 // (this would happen if target field is scanned after moving element)
2328 Stop[newlx][newly] = TRUE;
2331 else if (IS_BLOCKED(lx, ly))
2336 boolean cut_mode = NO_CUTTING;
2337 int element_old, content_old;
2339 Blocked2Moving(lx, ly, &oldx, &oldy);
2342 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
2343 MovDir[oldx][oldy] == MV_RIGHT);
2345 element_old = Feld[oldx][oldy];
2346 content_old = Store[oldx][oldy];
2348 if (element_old == EL_QUICKSAND_EMPTYING ||
2349 element_old == EL_QUICKSAND_FAST_EMPTYING ||
2350 element_old == EL_MAGIC_WALL_EMPTYING ||
2351 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
2352 element_old == EL_DC_MAGIC_WALL_EMPTYING ||
2353 element_old == EL_AMOEBA_DROPPING)
2354 cut_mode = CUT_ABOVE;
2356 DrawScreenElement(x, y, EL_EMPTY);
2359 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
2361 else if (cut_mode == NO_CUTTING)
2362 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
2365 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
2368 else if (IS_DRAWABLE(element))
2369 DrawScreenElement(x, y, element);
2371 DrawScreenElement(x, y, EL_EMPTY);
2374 void DrawLevelField(int x, int y)
2376 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2377 DrawScreenField(SCREENX(x), SCREENY(y));
2378 else if (IS_MOVING(x, y))
2382 Moving2Blocked(x, y, &newx, &newy);
2383 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
2384 DrawScreenField(SCREENX(newx), SCREENY(newy));
2386 else if (IS_BLOCKED(x, y))
2390 Blocked2Moving(x, y, &oldx, &oldy);
2391 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
2392 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
2396 void DrawSizedElement(int x, int y, int element, int tilesize)
2400 graphic = el2edimg(element);
2401 DrawSizedGraphic(x, y, graphic, 0, tilesize);
2404 void DrawMiniElement(int x, int y, int element)
2408 graphic = el2edimg(element);
2409 DrawMiniGraphic(x, y, graphic);
2412 void DrawSizedElementOrWall(int sx, int sy, int scroll_x, int scroll_y,
2415 int x = sx + scroll_x, y = sy + scroll_y;
2417 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
2418 DrawSizedElement(sx, sy, EL_EMPTY, tilesize);
2419 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
2420 DrawSizedElement(sx, sy, Feld[x][y], tilesize);
2422 DrawSizedGraphic(sx, sy, el2edimg(getBorderElement(x, y)), 0, tilesize);
2425 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
2427 int x = sx + scroll_x, y = sy + scroll_y;
2429 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
2430 DrawMiniElement(sx, sy, EL_EMPTY);
2431 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
2432 DrawMiniElement(sx, sy, Feld[x][y]);
2434 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
2437 void DrawEnvelopeBackgroundTiles(int graphic, int startx, int starty,
2438 int x, int y, int xsize, int ysize,
2439 int tile_width, int tile_height)
2443 int dst_x = startx + x * tile_width;
2444 int dst_y = starty + y * tile_height;
2445 int width = graphic_info[graphic].width;
2446 int height = graphic_info[graphic].height;
2447 int inner_width_raw = MAX(width - 2 * tile_width, tile_width);
2448 int inner_height_raw = MAX(height - 2 * tile_height, tile_height);
2449 int inner_width = inner_width_raw - (inner_width_raw % tile_width);
2450 int inner_height = inner_height_raw - (inner_height_raw % tile_height);
2451 int inner_sx = (width >= 3 * tile_width ? tile_width : 0);
2452 int inner_sy = (height >= 3 * tile_height ? tile_height : 0);
2453 boolean draw_masked = graphic_info[graphic].draw_masked;
2455 getFixedGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
2457 if (src_bitmap == NULL || width < tile_width || height < tile_height)
2459 ClearRectangle(drawto, dst_x, dst_y, tile_width, tile_height);
2463 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - tile_width :
2464 inner_sx + (x - 1) * tile_width % inner_width);
2465 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - tile_height :
2466 inner_sy + (y - 1) * tile_height % inner_height);
2469 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
2472 BlitBitmap(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
2476 void DrawEnvelopeBackground(int graphic, int startx, int starty,
2477 int x, int y, int xsize, int ysize, int font_nr)
2479 int font_width = getFontWidth(font_nr);
2480 int font_height = getFontHeight(font_nr);
2482 DrawEnvelopeBackgroundTiles(graphic, startx, starty, x, y, xsize, ysize,
2483 font_width, font_height);
2486 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
2488 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2489 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2490 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2491 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2492 boolean no_delay = (tape.warp_forward);
2493 unsigned int anim_delay = 0;
2494 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
2495 int anim_delay_value = (no_delay ? 0 : frame_delay_value) / 2;
2496 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
2497 int font_width = getFontWidth(font_nr);
2498 int font_height = getFontHeight(font_nr);
2499 int max_xsize = level.envelope[envelope_nr].xsize;
2500 int max_ysize = level.envelope[envelope_nr].ysize;
2501 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
2502 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
2503 int xend = max_xsize;
2504 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
2505 int xstep = (xstart < xend ? 1 : 0);
2506 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2508 int end = MAX(xend - xstart, yend - ystart);
2511 for (i = start; i <= end; i++)
2513 int last_frame = end; // last frame of this "for" loop
2514 int x = xstart + i * xstep;
2515 int y = ystart + i * ystep;
2516 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2517 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2518 int sx = SX + (SXSIZE - xsize * font_width) / 2;
2519 int sy = SY + (SYSIZE - ysize * font_height) / 2;
2522 SetDrawtoField(DRAW_TO_FIELDBUFFER);
2524 BlitScreenToBitmap(backbuffer);
2526 SetDrawtoField(DRAW_TO_BACKBUFFER);
2528 for (yy = 0; yy < ysize; yy++)
2529 for (xx = 0; xx < xsize; xx++)
2530 DrawEnvelopeBackground(graphic, sx, sy, xx, yy, xsize, ysize, font_nr);
2532 DrawTextBuffer(sx + font_width, sy + font_height,
2533 level.envelope[envelope_nr].text, font_nr, max_xsize,
2534 xsize - 2, ysize - 2, 0, mask_mode,
2535 level.envelope[envelope_nr].autowrap,
2536 level.envelope[envelope_nr].centered, FALSE);
2538 redraw_mask |= REDRAW_FIELD;
2541 SkipUntilDelayReached(&anim_delay, anim_delay_value, &i, last_frame);
2545 void ShowEnvelope(int envelope_nr)
2547 int element = EL_ENVELOPE_1 + envelope_nr;
2548 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2549 int sound_opening = element_info[element].sound[ACTION_OPENING];
2550 int sound_closing = element_info[element].sound[ACTION_CLOSING];
2551 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2552 boolean no_delay = (tape.warp_forward);
2553 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
2554 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
2555 int anim_mode = graphic_info[graphic].anim_mode;
2556 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2557 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2559 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
2561 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2563 if (anim_mode == ANIM_DEFAULT)
2564 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
2566 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
2569 Delay(wait_delay_value);
2571 WaitForEventToContinue();
2573 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2575 if (anim_mode != ANIM_NONE)
2576 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
2578 if (anim_mode == ANIM_DEFAULT)
2579 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
2581 game.envelope_active = FALSE;
2583 SetDrawtoField(DRAW_TO_FIELDBUFFER);
2585 redraw_mask |= REDRAW_FIELD;
2589 static void setRequestBasePosition(int *x, int *y)
2591 int sx_base, sy_base;
2593 if (request.x != -1)
2594 sx_base = request.x;
2595 else if (request.align == ALIGN_LEFT)
2597 else if (request.align == ALIGN_RIGHT)
2598 sx_base = SX + SXSIZE;
2600 sx_base = SX + SXSIZE / 2;
2602 if (request.y != -1)
2603 sy_base = request.y;
2604 else if (request.valign == VALIGN_TOP)
2606 else if (request.valign == VALIGN_BOTTOM)
2607 sy_base = SY + SYSIZE;
2609 sy_base = SY + SYSIZE / 2;
2615 static void setRequestPositionExt(int *x, int *y, int width, int height,
2616 boolean add_border_size)
2618 int border_size = request.border_size;
2619 int sx_base, sy_base;
2622 setRequestBasePosition(&sx_base, &sy_base);
2624 if (request.align == ALIGN_LEFT)
2626 else if (request.align == ALIGN_RIGHT)
2627 sx = sx_base - width;
2629 sx = sx_base - width / 2;
2631 if (request.valign == VALIGN_TOP)
2633 else if (request.valign == VALIGN_BOTTOM)
2634 sy = sy_base - height;
2636 sy = sy_base - height / 2;
2638 sx = MAX(0, MIN(sx, WIN_XSIZE - width));
2639 sy = MAX(0, MIN(sy, WIN_YSIZE - height));
2641 if (add_border_size)
2651 static void setRequestPosition(int *x, int *y, boolean add_border_size)
2653 setRequestPositionExt(x, y, request.width, request.height, add_border_size);
2656 void DrawEnvelopeRequest(char *text)
2658 char *text_final = text;
2659 char *text_door_style = NULL;
2660 int graphic = IMG_BACKGROUND_REQUEST;
2661 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2662 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2663 int font_nr = FONT_REQUEST;
2664 int font_width = getFontWidth(font_nr);
2665 int font_height = getFontHeight(font_nr);
2666 int border_size = request.border_size;
2667 int line_spacing = request.line_spacing;
2668 int line_height = font_height + line_spacing;
2669 int max_text_width = request.width - 2 * border_size;
2670 int max_text_height = request.height - 2 * border_size;
2671 int line_length = max_text_width / font_width;
2672 int max_lines = max_text_height / line_height;
2673 int text_width = line_length * font_width;
2674 int width = request.width;
2675 int height = request.height;
2676 int tile_size = MAX(request.step_offset, 1);
2677 int x_steps = width / tile_size;
2678 int y_steps = height / tile_size;
2679 int sx_offset = border_size;
2680 int sy_offset = border_size;
2684 if (request.centered)
2685 sx_offset = (request.width - text_width) / 2;
2687 if (request.wrap_single_words && !request.autowrap)
2689 char *src_text_ptr, *dst_text_ptr;
2691 text_door_style = checked_malloc(2 * strlen(text) + 1);
2693 src_text_ptr = text;
2694 dst_text_ptr = text_door_style;
2696 while (*src_text_ptr)
2698 if (*src_text_ptr == ' ' ||
2699 *src_text_ptr == '?' ||
2700 *src_text_ptr == '!')
2701 *dst_text_ptr++ = '\n';
2703 if (*src_text_ptr != ' ')
2704 *dst_text_ptr++ = *src_text_ptr;
2709 *dst_text_ptr = '\0';
2711 text_final = text_door_style;
2714 setRequestPosition(&sx, &sy, FALSE);
2716 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
2718 for (y = 0; y < y_steps; y++)
2719 for (x = 0; x < x_steps; x++)
2720 DrawEnvelopeBackgroundTiles(graphic, sx, sy,
2721 x, y, x_steps, y_steps,
2722 tile_size, tile_size);
2724 /* force DOOR font inside door area */
2725 SetFontStatus(GAME_MODE_PSEUDO_DOOR);
2727 DrawTextBuffer(sx + sx_offset, sy + sy_offset, text_final, font_nr,
2728 line_length, -1, max_lines, line_spacing, mask_mode,
2729 request.autowrap, request.centered, FALSE);
2733 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2734 RedrawGadget(tool_gadget[i]);
2736 // store readily prepared envelope request for later use when animating
2737 BlitBitmap(backbuffer, bitmap_db_store_2, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2739 if (text_door_style)
2740 free(text_door_style);
2743 void AnimateEnvelopeRequest(int anim_mode, int action)
2745 int graphic = IMG_BACKGROUND_REQUEST;
2746 boolean draw_masked = graphic_info[graphic].draw_masked;
2747 int delay_value_normal = request.step_delay;
2748 int delay_value_fast = delay_value_normal / 2;
2749 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2750 boolean no_delay = (tape.warp_forward);
2751 int delay_value = (ffwd_delay ? delay_value_fast : delay_value_normal);
2752 int anim_delay_value = (no_delay ? 0 : delay_value + 500 * 0) / 2;
2753 unsigned int anim_delay = 0;
2755 int tile_size = MAX(request.step_offset, 1);
2756 int max_xsize = request.width / tile_size;
2757 int max_ysize = request.height / tile_size;
2758 int max_xsize_inner = max_xsize - 2;
2759 int max_ysize_inner = max_ysize - 2;
2761 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize_inner : 0);
2762 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize_inner : 0);
2763 int xend = max_xsize_inner;
2764 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize_inner : 0);
2765 int xstep = (xstart < xend ? 1 : 0);
2766 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2768 int end = MAX(xend - xstart, yend - ystart);
2771 if (setup.quick_doors)
2778 for (i = start; i <= end; i++)
2780 int last_frame = end; // last frame of this "for" loop
2781 int x = xstart + i * xstep;
2782 int y = ystart + i * ystep;
2783 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2784 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2785 int xsize_size_left = (xsize - 1) * tile_size;
2786 int ysize_size_top = (ysize - 1) * tile_size;
2787 int max_xsize_pos = (max_xsize - 1) * tile_size;
2788 int max_ysize_pos = (max_ysize - 1) * tile_size;
2789 int width = xsize * tile_size;
2790 int height = ysize * tile_size;
2795 setRequestPosition(&src_x, &src_y, FALSE);
2796 setRequestPositionExt(&dst_x, &dst_y, width, height, FALSE);
2798 BlitBitmap(bitmap_db_store_1, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2800 for (yy = 0; yy < 2; yy++)
2802 for (xx = 0; xx < 2; xx++)
2804 int src_xx = src_x + xx * max_xsize_pos;
2805 int src_yy = src_y + yy * max_ysize_pos;
2806 int dst_xx = dst_x + xx * xsize_size_left;
2807 int dst_yy = dst_y + yy * ysize_size_top;
2808 int xx_size = (xx ? tile_size : xsize_size_left);
2809 int yy_size = (yy ? tile_size : ysize_size_top);
2812 BlitBitmapMasked(bitmap_db_store_2, backbuffer,
2813 src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
2815 BlitBitmap(bitmap_db_store_2, backbuffer,
2816 src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
2820 redraw_mask |= REDRAW_FIELD;
2824 SkipUntilDelayReached(&anim_delay, anim_delay_value, &i, last_frame);
2828 void ShowEnvelopeRequest(char *text, unsigned int req_state, int action)
2830 int graphic = IMG_BACKGROUND_REQUEST;
2831 int sound_opening = SND_REQUEST_OPENING;
2832 int sound_closing = SND_REQUEST_CLOSING;
2833 int anim_mode_1 = request.anim_mode; /* (higher priority) */
2834 int anim_mode_2 = graphic_info[graphic].anim_mode; /* (lower priority) */
2835 int anim_mode = (anim_mode_1 != ANIM_DEFAULT ? anim_mode_1 : anim_mode_2);
2836 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2837 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2839 if (game_status == GAME_MODE_PLAYING)
2840 BlitScreenToBitmap(backbuffer);
2842 SetDrawtoField(DRAW_TO_BACKBUFFER);
2844 // SetDrawBackgroundMask(REDRAW_NONE);
2846 if (action == ACTION_OPENING)
2848 BlitBitmap(backbuffer, bitmap_db_store_1, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2850 if (req_state & REQ_ASK)
2852 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2853 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2855 else if (req_state & REQ_CONFIRM)
2857 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2859 else if (req_state & REQ_PLAYER)
2861 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2862 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2863 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2864 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2867 DrawEnvelopeRequest(text);
2870 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
2872 if (action == ACTION_OPENING)
2874 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2876 if (anim_mode == ANIM_DEFAULT)
2877 AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_OPENING);
2879 AnimateEnvelopeRequest(main_anim_mode, ACTION_OPENING);
2883 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2885 if (anim_mode != ANIM_NONE)
2886 AnimateEnvelopeRequest(main_anim_mode, ACTION_CLOSING);
2888 if (anim_mode == ANIM_DEFAULT)
2889 AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_CLOSING);
2892 game.envelope_active = FALSE;
2894 if (action == ACTION_CLOSING)
2895 BlitBitmap(bitmap_db_store_1, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2897 // SetDrawBackgroundMask(last_draw_background_mask);
2899 redraw_mask |= REDRAW_FIELD;
2903 if (action == ACTION_CLOSING &&
2904 game_status == GAME_MODE_PLAYING &&
2905 level.game_engine_type == GAME_ENGINE_TYPE_RND)
2906 SetDrawtoField(DRAW_TO_FIELDBUFFER);
2909 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
2913 int graphic = el2preimg(element);
2915 getSizedGraphicSource(graphic, 0, tilesize, &src_bitmap, &src_x, &src_y);
2916 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
2919 void DrawLevel(int draw_background_mask)
2923 SetMainBackgroundImage(IMG_BACKGROUND_PLAYING);
2924 SetDrawBackgroundMask(draw_background_mask);
2928 for (x = BX1; x <= BX2; x++)
2929 for (y = BY1; y <= BY2; y++)
2930 DrawScreenField(x, y);
2932 redraw_mask |= REDRAW_FIELD;
2935 void DrawSizedLevel(int size_x, int size_y, int scroll_x, int scroll_y,
2940 for (x = 0; x < size_x; x++)
2941 for (y = 0; y < size_y; y++)
2942 DrawSizedElementOrWall(x, y, scroll_x, scroll_y, tilesize);
2944 redraw_mask |= REDRAW_FIELD;
2947 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
2951 for (x = 0; x < size_x; x++)
2952 for (y = 0; y < size_y; y++)
2953 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
2955 redraw_mask |= REDRAW_FIELD;
2958 static void DrawPreviewLevelPlayfieldExt(int from_x, int from_y)
2960 boolean show_level_border = (BorderElement != EL_EMPTY);
2961 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2962 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2963 int tile_size = preview.tile_size;
2964 int preview_width = preview.xsize * tile_size;
2965 int preview_height = preview.ysize * tile_size;
2966 int real_preview_xsize = MIN(level_xsize, preview.xsize);
2967 int real_preview_ysize = MIN(level_ysize, preview.ysize);
2968 int real_preview_width = real_preview_xsize * tile_size;
2969 int real_preview_height = real_preview_ysize * tile_size;
2970 int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
2971 int dst_y = SY + ALIGNED_YPOS(preview.y, preview_height, preview.valign);
2974 if (!IN_GFX_FIELD_FULL(dst_x, dst_y + preview_height - 1))
2977 DrawBackground(dst_x, dst_y, preview_width, preview_height);
2979 dst_x += (preview_width - real_preview_width) / 2;
2980 dst_y += (preview_height - real_preview_height) / 2;
2982 for (x = 0; x < real_preview_xsize; x++)
2984 for (y = 0; y < real_preview_ysize; y++)
2986 int lx = from_x + x + (show_level_border ? -1 : 0);
2987 int ly = from_y + y + (show_level_border ? -1 : 0);
2988 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
2989 getBorderElement(lx, ly));
2991 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
2992 element, tile_size);
2996 redraw_mask |= REDRAW_FIELD;
2999 #define MICROLABEL_EMPTY 0
3000 #define MICROLABEL_LEVEL_NAME 1
3001 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
3002 #define MICROLABEL_LEVEL_AUTHOR 3
3003 #define MICROLABEL_IMPORTED_FROM_HEAD 4
3004 #define MICROLABEL_IMPORTED_FROM 5
3005 #define MICROLABEL_IMPORTED_BY_HEAD 6
3006 #define MICROLABEL_IMPORTED_BY 7
3008 static int getMaxTextLength(struct TextPosInfo *pos, int font_nr)
3010 int max_text_width = SXSIZE;
3011 int font_width = getFontWidth(font_nr);
3013 if (pos->align == ALIGN_CENTER)
3014 max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
3015 else if (pos->align == ALIGN_RIGHT)
3016 max_text_width = pos->x;
3018 max_text_width = SXSIZE - pos->x;
3020 return max_text_width / font_width;
3023 static void DrawPreviewLevelLabelExt(int mode)
3025 struct TextPosInfo *pos = &menu.main.text.level_info_2;
3026 char label_text[MAX_OUTPUT_LINESIZE + 1];
3027 int max_len_label_text;
3028 int font_nr = pos->font;
3031 if (!IN_GFX_FIELD_FULL(pos->x, pos->y + getFontHeight(pos->font)))
3034 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
3035 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
3036 mode == MICROLABEL_IMPORTED_BY_HEAD)
3037 font_nr = pos->font_alt;
3039 max_len_label_text = getMaxTextLength(pos, font_nr);
3041 if (pos->size != -1)
3042 max_len_label_text = pos->size;
3044 for (i = 0; i < max_len_label_text; i++)
3045 label_text[i] = ' ';
3046 label_text[max_len_label_text] = '\0';
3048 if (strlen(label_text) > 0)
3049 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
3052 (mode == MICROLABEL_LEVEL_NAME ? level.name :
3053 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
3054 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
3055 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
3056 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
3057 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
3058 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
3059 max_len_label_text);
3060 label_text[max_len_label_text] = '\0';
3062 if (strlen(label_text) > 0)
3063 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
3065 redraw_mask |= REDRAW_FIELD;
3068 static void DrawPreviewLevelExt(boolean restart)
3070 static unsigned int scroll_delay = 0;
3071 static unsigned int label_delay = 0;
3072 static int from_x, from_y, scroll_direction;
3073 static int label_state, label_counter;
3074 unsigned int scroll_delay_value = preview.step_delay;
3075 boolean show_level_border = (BorderElement != EL_EMPTY);
3076 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
3077 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
3084 if (preview.anim_mode == ANIM_CENTERED)
3086 if (level_xsize > preview.xsize)
3087 from_x = (level_xsize - preview.xsize) / 2;
3088 if (level_ysize > preview.ysize)
3089 from_y = (level_ysize - preview.ysize) / 2;
3092 from_x += preview.xoffset;
3093 from_y += preview.yoffset;
3095 scroll_direction = MV_RIGHT;
3099 DrawPreviewLevelPlayfieldExt(from_x, from_y);
3100 DrawPreviewLevelLabelExt(label_state);
3102 /* initialize delay counters */
3103 DelayReached(&scroll_delay, 0);
3104 DelayReached(&label_delay, 0);
3106 if (leveldir_current->name)
3108 struct TextPosInfo *pos = &menu.main.text.level_info_1;
3109 char label_text[MAX_OUTPUT_LINESIZE + 1];
3110 int font_nr = pos->font;
3111 int max_len_label_text = getMaxTextLength(pos, font_nr);
3113 if (pos->size != -1)
3114 max_len_label_text = pos->size;
3116 strncpy(label_text, leveldir_current->name, max_len_label_text);
3117 label_text[max_len_label_text] = '\0';
3119 if (IN_GFX_FIELD_FULL(pos->x, pos->y + getFontHeight(pos->font)))
3120 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
3126 /* scroll preview level, if needed */
3127 if (preview.anim_mode != ANIM_NONE &&
3128 (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
3129 DelayReached(&scroll_delay, scroll_delay_value))
3131 switch (scroll_direction)
3136 from_x -= preview.step_offset;
3137 from_x = (from_x < 0 ? 0 : from_x);
3140 scroll_direction = MV_UP;
3144 if (from_x < level_xsize - preview.xsize)
3146 from_x += preview.step_offset;
3147 from_x = (from_x > level_xsize - preview.xsize ?
3148 level_xsize - preview.xsize : from_x);
3151 scroll_direction = MV_DOWN;
3157 from_y -= preview.step_offset;
3158 from_y = (from_y < 0 ? 0 : from_y);
3161 scroll_direction = MV_RIGHT;
3165 if (from_y < level_ysize - preview.ysize)
3167 from_y += preview.step_offset;
3168 from_y = (from_y > level_ysize - preview.ysize ?
3169 level_ysize - preview.ysize : from_y);
3172 scroll_direction = MV_LEFT;
3179 DrawPreviewLevelPlayfieldExt(from_x, from_y);
3182 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
3183 /* redraw micro level label, if needed */
3184 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
3185 !strEqual(level.author, ANONYMOUS_NAME) &&
3186 !strEqual(level.author, leveldir_current->name) &&
3187 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
3189 int max_label_counter = 23;
3191 if (leveldir_current->imported_from != NULL &&
3192 strlen(leveldir_current->imported_from) > 0)
3193 max_label_counter += 14;
3194 if (leveldir_current->imported_by != NULL &&
3195 strlen(leveldir_current->imported_by) > 0)
3196 max_label_counter += 14;
3198 label_counter = (label_counter + 1) % max_label_counter;
3199 label_state = (label_counter >= 0 && label_counter <= 7 ?
3200 MICROLABEL_LEVEL_NAME :
3201 label_counter >= 9 && label_counter <= 12 ?
3202 MICROLABEL_LEVEL_AUTHOR_HEAD :
3203 label_counter >= 14 && label_counter <= 21 ?
3204 MICROLABEL_LEVEL_AUTHOR :
3205 label_counter >= 23 && label_counter <= 26 ?
3206 MICROLABEL_IMPORTED_FROM_HEAD :
3207 label_counter >= 28 && label_counter <= 35 ?
3208 MICROLABEL_IMPORTED_FROM :
3209 label_counter >= 37 && label_counter <= 40 ?
3210 MICROLABEL_IMPORTED_BY_HEAD :
3211 label_counter >= 42 && label_counter <= 49 ?
3212 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
3214 if (leveldir_current->imported_from == NULL &&
3215 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
3216 label_state == MICROLABEL_IMPORTED_FROM))
3217 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
3218 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
3220 DrawPreviewLevelLabelExt(label_state);
3224 void DrawPreviewLevelInitial()
3226 DrawPreviewLevelExt(TRUE);
3229 void DrawPreviewLevelAnimation()
3231 DrawPreviewLevelExt(FALSE);
3234 inline static void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
3235 int graphic, int sync_frame,
3238 int frame = getGraphicAnimationFrame(graphic, sync_frame);
3240 if (mask_mode == USE_MASKING)
3241 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
3243 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
3246 void DrawFixedGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
3247 int graphic, int sync_frame, int mask_mode)
3249 int frame = getGraphicAnimationFrame(graphic, sync_frame);
3251 if (mask_mode == USE_MASKING)
3252 DrawFixedGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
3254 DrawFixedGraphicExt(dst_bitmap, x, y, graphic, frame);
3257 inline static void DrawGraphicAnimation(int x, int y, int graphic)
3259 int lx = LEVELX(x), ly = LEVELY(y);
3261 if (!IN_SCR_FIELD(x, y))
3264 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
3265 graphic, GfxFrame[lx][ly], NO_MASKING);
3267 MarkTileDirty(x, y);
3270 void DrawFixedGraphicAnimation(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, FY + y * TILEY,
3278 graphic, GfxFrame[lx][ly], NO_MASKING);
3279 MarkTileDirty(x, y);
3282 void DrawLevelGraphicAnimation(int x, int y, int graphic)
3284 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
3287 void DrawLevelElementAnimation(int x, int y, int element)
3289 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
3291 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
3294 void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
3296 int sx = SCREENX(x), sy = SCREENY(y);
3298 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
3301 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
3304 DrawGraphicAnimation(sx, sy, graphic);
3307 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
3308 DrawLevelFieldCrumbled(x, y);
3310 if (GFX_CRUMBLED(Feld[x][y]))
3311 DrawLevelFieldCrumbled(x, y);
3315 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
3317 int sx = SCREENX(x), sy = SCREENY(y);
3320 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
3323 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
3325 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
3328 DrawGraphicAnimation(sx, sy, graphic);
3330 if (GFX_CRUMBLED(element))
3331 DrawLevelFieldCrumbled(x, y);
3334 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
3336 if (player->use_murphy)
3338 /* this works only because currently only one player can be "murphy" ... */
3339 static int last_horizontal_dir = MV_LEFT;
3340 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
3342 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3343 last_horizontal_dir = move_dir;
3345 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
3347 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
3349 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
3355 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
3358 static boolean equalGraphics(int graphic1, int graphic2)
3360 struct GraphicInfo *g1 = &graphic_info[graphic1];
3361 struct GraphicInfo *g2 = &graphic_info[graphic2];
3363 return (g1->bitmap == g2->bitmap &&
3364 g1->src_x == g2->src_x &&
3365 g1->src_y == g2->src_y &&
3366 g1->anim_frames == g2->anim_frames &&
3367 g1->anim_delay == g2->anim_delay &&
3368 g1->anim_mode == g2->anim_mode);
3371 void DrawAllPlayers()
3375 for (i = 0; i < MAX_PLAYERS; i++)
3376 if (stored_player[i].active)
3377 DrawPlayer(&stored_player[i]);
3380 void DrawPlayerField(int x, int y)
3382 if (!IS_PLAYER(x, y))
3385 DrawPlayer(PLAYERINFO(x, y));
3388 #define DRAW_PLAYER_OVER_PUSHED_ELEMENT 1
3390 void DrawPlayer(struct PlayerInfo *player)
3392 int jx = player->jx;
3393 int jy = player->jy;
3394 int move_dir = player->MovDir;
3395 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
3396 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
3397 int last_jx = (player->is_moving ? jx - dx : jx);
3398 int last_jy = (player->is_moving ? jy - dy : jy);
3399 int next_jx = jx + dx;
3400 int next_jy = jy + dy;
3401 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
3402 boolean player_is_opaque = FALSE;
3403 int sx = SCREENX(jx), sy = SCREENY(jy);
3404 int sxx = 0, syy = 0;
3405 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
3407 int action = ACTION_DEFAULT;
3408 int last_player_graphic = getPlayerGraphic(player, move_dir);
3409 int last_player_frame = player->Frame;
3412 /* GfxElement[][] is set to the element the player is digging or collecting;
3413 remove also for off-screen player if the player is not moving anymore */
3414 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
3415 GfxElement[jx][jy] = EL_UNDEFINED;
3417 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
3421 if (!IN_LEV_FIELD(jx, jy))
3423 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
3424 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
3425 printf("DrawPlayerField(): This should never happen!\n");
3430 if (element == EL_EXPLOSION)
3433 action = (player->is_pushing ? ACTION_PUSHING :
3434 player->is_digging ? ACTION_DIGGING :
3435 player->is_collecting ? ACTION_COLLECTING :
3436 player->is_moving ? ACTION_MOVING :
3437 player->is_snapping ? ACTION_SNAPPING :
3438 player->is_dropping ? ACTION_DROPPING :
3439 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
3441 if (player->is_waiting)
3442 move_dir = player->dir_waiting;
3444 InitPlayerGfxAnimation(player, action, move_dir);
3446 /* ----------------------------------------------------------------------- */
3447 /* draw things in the field the player is leaving, if needed */
3448 /* ----------------------------------------------------------------------- */
3450 if (player->is_moving)
3452 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
3454 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
3456 if (last_element == EL_DYNAMITE_ACTIVE ||
3457 last_element == EL_EM_DYNAMITE_ACTIVE ||
3458 last_element == EL_SP_DISK_RED_ACTIVE)
3459 DrawDynamite(last_jx, last_jy);
3461 DrawLevelFieldThruMask(last_jx, last_jy);
3463 else if (last_element == EL_DYNAMITE_ACTIVE ||
3464 last_element == EL_EM_DYNAMITE_ACTIVE ||
3465 last_element == EL_SP_DISK_RED_ACTIVE)
3466 DrawDynamite(last_jx, last_jy);
3468 /* !!! this is not enough to prevent flickering of players which are
3469 moving next to each others without a free tile between them -- this
3470 can only be solved by drawing all players layer by layer (first the
3471 background, then the foreground etc.) !!! => TODO */
3472 else if (!IS_PLAYER(last_jx, last_jy))
3473 DrawLevelField(last_jx, last_jy);
3476 DrawLevelField(last_jx, last_jy);
3479 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
3480 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
3483 if (!IN_SCR_FIELD(sx, sy))
3486 /* ----------------------------------------------------------------------- */
3487 /* draw things behind the player, if needed */
3488 /* ----------------------------------------------------------------------- */
3491 DrawLevelElement(jx, jy, Back[jx][jy]);
3492 else if (IS_ACTIVE_BOMB(element))
3493 DrawLevelElement(jx, jy, EL_EMPTY);
3496 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
3498 int old_element = GfxElement[jx][jy];
3499 int old_graphic = el_act_dir2img(old_element, action, move_dir);
3500 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
3502 if (GFX_CRUMBLED(old_element))
3503 DrawLevelFieldCrumbledDigging(jx, jy, move_dir, player->StepFrame);
3505 DrawGraphic(sx, sy, old_graphic, frame);
3507 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
3508 player_is_opaque = TRUE;
3512 GfxElement[jx][jy] = EL_UNDEFINED;
3514 /* make sure that pushed elements are drawn with correct frame rate */
3515 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
3517 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
3518 GfxFrame[jx][jy] = player->StepFrame;
3520 DrawLevelField(jx, jy);
3524 #if !DRAW_PLAYER_OVER_PUSHED_ELEMENT
3525 /* ----------------------------------------------------------------------- */
3526 /* draw player himself */
3527 /* ----------------------------------------------------------------------- */
3529 graphic = getPlayerGraphic(player, move_dir);
3531 /* in the case of changed player action or direction, prevent the current
3532 animation frame from being restarted for identical animations */
3533 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
3534 player->Frame = last_player_frame;
3536 frame = getGraphicAnimationFrame(graphic, player->Frame);
3540 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3541 sxx = player->GfxPos;
3543 syy = player->GfxPos;
3546 if (player_is_opaque)
3547 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
3549 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3551 if (SHIELD_ON(player))
3553 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
3554 IMG_SHIELD_NORMAL_ACTIVE);
3555 int frame = getGraphicAnimationFrame(graphic, -1);
3557 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3561 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
3564 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3565 sxx = player->GfxPos;
3567 syy = player->GfxPos;
3571 /* ----------------------------------------------------------------------- */
3572 /* draw things the player is pushing, if needed */
3573 /* ----------------------------------------------------------------------- */
3575 if (player->is_pushing && player->is_moving)
3577 int px = SCREENX(jx), py = SCREENY(jy);
3578 int pxx = (TILEX - ABS(sxx)) * dx;
3579 int pyy = (TILEY - ABS(syy)) * dy;
3580 int gfx_frame = GfxFrame[jx][jy];
3586 if (!IS_MOVING(jx, jy)) /* push movement already finished */
3588 element = Feld[next_jx][next_jy];
3589 gfx_frame = GfxFrame[next_jx][next_jy];
3592 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
3594 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
3595 frame = getGraphicAnimationFrame(graphic, sync_frame);
3597 /* draw background element under pushed element (like the Sokoban field) */
3598 if (game.use_masked_pushing && IS_MOVING(jx, jy))
3600 /* this allows transparent pushing animation over non-black background */
3603 DrawLevelElement(jx, jy, Back[jx][jy]);
3605 DrawLevelElement(jx, jy, EL_EMPTY);
3607 if (Back[next_jx][next_jy])
3608 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3610 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
3612 else if (Back[next_jx][next_jy])
3613 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3616 /* do not draw (EM style) pushing animation when pushing is finished */
3617 /* (two-tile animations usually do not contain start and end frame) */
3618 if (graphic_info[graphic].double_movement && !IS_MOVING(jx, jy))
3619 DrawLevelElement(next_jx, next_jy, Feld[next_jx][next_jy]);
3621 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3623 /* masked drawing is needed for EMC style (double) movement graphics */
3624 /* !!! (ONLY WHEN DRAWING PUSHED ELEMENT OVER THE PLAYER) !!! */
3625 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3629 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
3630 /* ----------------------------------------------------------------------- */
3631 /* draw player himself */
3632 /* ----------------------------------------------------------------------- */
3634 graphic = getPlayerGraphic(player, move_dir);
3636 /* in the case of changed player action or direction, prevent the current
3637 animation frame from being restarted for identical animations */
3638 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
3639 player->Frame = last_player_frame;
3641 frame = getGraphicAnimationFrame(graphic, player->Frame);
3645 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3646 sxx = player->GfxPos;
3648 syy = player->GfxPos;
3651 if (player_is_opaque)
3652 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
3654 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3656 if (SHIELD_ON(player))
3658 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
3659 IMG_SHIELD_NORMAL_ACTIVE);
3660 int frame = getGraphicAnimationFrame(graphic, -1);
3662 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3666 /* ----------------------------------------------------------------------- */
3667 /* draw things in front of player (active dynamite or dynabombs) */
3668 /* ----------------------------------------------------------------------- */
3670 if (IS_ACTIVE_BOMB(element))
3672 graphic = el2img(element);
3673 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
3675 if (game.emulation == EMU_SUPAPLEX)
3676 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
3678 DrawGraphicThruMask(sx, sy, graphic, frame);
3681 if (player_is_moving && last_element == EL_EXPLOSION)
3683 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
3684 GfxElement[last_jx][last_jy] : EL_EMPTY);
3685 int graphic = el_act2img(element, ACTION_EXPLODING);
3686 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
3687 int phase = ExplodePhase[last_jx][last_jy] - 1;
3688 int frame = getGraphicAnimationFrame(graphic, phase - delay);
3691 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
3694 /* ----------------------------------------------------------------------- */
3695 /* draw elements the player is just walking/passing through/under */
3696 /* ----------------------------------------------------------------------- */
3698 if (player_is_moving)
3700 /* handle the field the player is leaving ... */
3701 if (IS_ACCESSIBLE_INSIDE(last_element))
3702 DrawLevelField(last_jx, last_jy);
3703 else if (IS_ACCESSIBLE_UNDER(last_element))
3704 DrawLevelFieldThruMask(last_jx, last_jy);
3707 /* do not redraw accessible elements if the player is just pushing them */
3708 if (!player_is_moving || !player->is_pushing)
3710 /* ... and the field the player is entering */
3711 if (IS_ACCESSIBLE_INSIDE(element))
3712 DrawLevelField(jx, jy);
3713 else if (IS_ACCESSIBLE_UNDER(element))
3714 DrawLevelFieldThruMask(jx, jy);
3717 MarkTileDirty(sx, sy);
3720 /* ------------------------------------------------------------------------- */
3722 void WaitForEventToContinue()
3724 boolean still_wait = TRUE;
3726 /* simulate releasing mouse button over last gadget, if still pressed */
3728 HandleGadgets(-1, -1, 0);
3730 button_status = MB_RELEASED;
3744 case EVENT_BUTTONPRESS:
3745 case EVENT_KEYPRESS:
3749 case EVENT_KEYRELEASE:
3750 ClearPlayerAction();
3754 HandleOtherEvents(&event);
3758 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3767 #define MAX_REQUEST_LINES 13
3768 #define MAX_REQUEST_LINE_FONT1_LEN 7
3769 #define MAX_REQUEST_LINE_FONT2_LEN 10
3771 static int RequestHandleEvents(unsigned int req_state)
3773 boolean level_solved = (game_status == GAME_MODE_PLAYING &&
3774 local_player->LevelSolved_GameEnd);
3775 int width = request.width;
3776 int height = request.height;
3780 setRequestPosition(&sx, &sy, FALSE);
3782 button_status = MB_RELEASED;
3784 request_gadget_id = -1;
3791 SetDrawtoField(DRAW_TO_FIELDBUFFER);
3793 HandleGameActions();
3795 SetDrawtoField(DRAW_TO_BACKBUFFER);
3797 if (global.use_envelope_request)
3799 /* copy current state of request area to middle of playfield area */
3800 BlitBitmap(bitmap_db_store_2, drawto, sx, sy, width, height, sx, sy);
3808 while (NextValidEvent(&event))
3812 case EVENT_BUTTONPRESS:
3813 case EVENT_BUTTONRELEASE:
3814 case EVENT_MOTIONNOTIFY:
3818 if (event.type == EVENT_MOTIONNOTIFY)
3823 motion_status = TRUE;
3824 mx = ((MotionEvent *) &event)->x;
3825 my = ((MotionEvent *) &event)->y;
3829 motion_status = FALSE;
3830 mx = ((ButtonEvent *) &event)->x;
3831 my = ((ButtonEvent *) &event)->y;
3832 if (event.type == EVENT_BUTTONPRESS)
3833 button_status = ((ButtonEvent *) &event)->button;
3835 button_status = MB_RELEASED;
3838 /* this sets 'request_gadget_id' */
3839 HandleGadgets(mx, my, button_status);
3841 switch (request_gadget_id)
3843 case TOOL_CTRL_ID_YES:
3846 case TOOL_CTRL_ID_NO:
3849 case TOOL_CTRL_ID_CONFIRM:
3850 result = TRUE | FALSE;
3853 case TOOL_CTRL_ID_PLAYER_1:
3856 case TOOL_CTRL_ID_PLAYER_2:
3859 case TOOL_CTRL_ID_PLAYER_3:
3862 case TOOL_CTRL_ID_PLAYER_4:
3873 case EVENT_KEYPRESS:
3875 Key key = GetEventKey((KeyEvent *)&event, TRUE);
3880 if (req_state & REQ_CONFIRM)
3885 #if defined(TARGET_SDL2)
3892 #if defined(TARGET_SDL2)
3899 HandleKeysDebug(key);
3903 if (req_state & REQ_PLAYER)
3909 case EVENT_KEYRELEASE:
3910 ClearPlayerAction();
3914 HandleOtherEvents(&event);
3919 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3921 int joy = AnyJoystick();
3923 if (joy & JOY_BUTTON_1)
3925 else if (joy & JOY_BUTTON_2)
3931 if (global.use_envelope_request)
3933 /* copy back current state of pressed buttons inside request area */
3934 BlitBitmap(drawto, bitmap_db_store_2, sx, sy, width, height, sx, sy);
3944 static boolean RequestDoor(char *text, unsigned int req_state)
3946 unsigned int old_door_state;
3947 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
3948 int font_nr = FONT_TEXT_2;
3953 if (maxWordLengthInString(text) > MAX_REQUEST_LINE_FONT1_LEN)
3955 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
3956 font_nr = FONT_TEXT_1;
3959 if (game_status == GAME_MODE_PLAYING)
3960 BlitScreenToBitmap(backbuffer);
3962 /* disable deactivated drawing when quick-loading level tape recording */
3963 if (tape.playing && tape.deactivate_display)
3964 TapeDeactivateDisplayOff(TRUE);
3966 SetMouseCursor(CURSOR_DEFAULT);
3968 #if defined(NETWORK_AVALIABLE)
3969 /* pause network game while waiting for request to answer */
3970 if (options.network &&
3971 game_status == GAME_MODE_PLAYING &&
3972 req_state & REQUEST_WAIT_FOR_INPUT)
3973 SendToServer_PausePlaying();
3976 old_door_state = GetDoorState();
3978 /* simulate releasing mouse button over last gadget, if still pressed */
3980 HandleGadgets(-1, -1, 0);
3984 /* draw released gadget before proceeding */
3987 if (old_door_state & DOOR_OPEN_1)
3989 CloseDoor(DOOR_CLOSE_1);
3991 /* save old door content */
3992 BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
3993 0 * DXSIZE, 0, DXSIZE, DYSIZE, 1 * DXSIZE, 0);
3996 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
3997 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3999 /* clear door drawing field */
4000 DrawBackground(DX, DY, DXSIZE, DYSIZE);
4002 /* force DOOR font inside door area */
4003 SetFontStatus(GAME_MODE_PSEUDO_DOOR);
4005 /* write text for request */
4006 for (text_ptr = text, ty = 0; ty < MAX_REQUEST_LINES; ty++)
4008 char text_line[max_request_line_len + 1];
4014 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
4016 tc = *(text_ptr + tx);
4017 // if (!tc || tc == ' ')
4018 if (!tc || tc == ' ' || tc == '?' || tc == '!')
4022 if ((tc == '?' || tc == '!') && tl == 0)
4032 strncpy(text_line, text_ptr, tl);
4035 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
4036 DY + 8 + ty * (getFontHeight(font_nr) + 2),
4037 text_line, font_nr);
4039 text_ptr += tl + (tc == ' ' ? 1 : 0);
4040 // text_ptr += tl + (tc == ' ' || tc == '?' || tc == '!' ? 1 : 0);
4045 if (req_state & REQ_ASK)
4047 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
4048 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
4050 else if (req_state & REQ_CONFIRM)
4052 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
4054 else if (req_state & REQ_PLAYER)
4056 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
4057 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
4058 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
4059 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
4062 /* copy request gadgets to door backbuffer */
4063 BlitBitmap(drawto, bitmap_db_door_1, DX, DY, DXSIZE, DYSIZE, 0, 0);
4065 OpenDoor(DOOR_OPEN_1);
4067 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
4069 if (game_status == GAME_MODE_PLAYING)
4071 SetPanelBackground();
4072 SetDrawBackgroundMask(REDRAW_DOOR_1);
4076 SetDrawBackgroundMask(REDRAW_FIELD);
4082 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4084 // ---------- handle request buttons ----------
4085 result = RequestHandleEvents(req_state);
4089 if (!(req_state & REQ_STAY_OPEN))
4091 CloseDoor(DOOR_CLOSE_1);
4093 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
4094 (req_state & REQ_REOPEN))
4095 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
4100 if (game_status == GAME_MODE_PLAYING)
4102 SetPanelBackground();
4103 SetDrawBackgroundMask(REDRAW_DOOR_1);
4107 SetDrawBackgroundMask(REDRAW_FIELD);
4110 #if defined(NETWORK_AVALIABLE)
4111 /* continue network game after request */
4112 if (options.network &&
4113 game_status == GAME_MODE_PLAYING &&
4114 req_state & REQUEST_WAIT_FOR_INPUT)
4115 SendToServer_ContinuePlaying();
4118 /* restore deactivated drawing when quick-loading level tape recording */
4119 if (tape.playing && tape.deactivate_display)
4120 TapeDeactivateDisplayOn();
4125 static boolean RequestEnvelope(char *text, unsigned int req_state)
4129 if (game_status == GAME_MODE_PLAYING)
4130 BlitScreenToBitmap(backbuffer);
4132 /* disable deactivated drawing when quick-loading level tape recording */
4133 if (tape.playing && tape.deactivate_display)
4134 TapeDeactivateDisplayOff(TRUE);
4136 SetMouseCursor(CURSOR_DEFAULT);
4138 #if defined(NETWORK_AVALIABLE)
4139 /* pause network game while waiting for request to answer */
4140 if (options.network &&
4141 game_status == GAME_MODE_PLAYING &&
4142 req_state & REQUEST_WAIT_FOR_INPUT)
4143 SendToServer_PausePlaying();
4146 /* simulate releasing mouse button over last gadget, if still pressed */
4148 HandleGadgets(-1, -1, 0);
4152 // (replace with setting corresponding request background)
4153 // SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
4154 // SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4156 /* clear door drawing field */
4157 // DrawBackground(DX, DY, DXSIZE, DYSIZE);
4159 ShowEnvelopeRequest(text, req_state, ACTION_OPENING);
4161 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
4163 if (game_status == GAME_MODE_PLAYING)
4165 SetPanelBackground();
4166 SetDrawBackgroundMask(REDRAW_DOOR_1);
4170 SetDrawBackgroundMask(REDRAW_FIELD);
4176 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4178 // ---------- handle request buttons ----------
4179 result = RequestHandleEvents(req_state);
4183 ShowEnvelopeRequest(text, req_state, ACTION_CLOSING);
4187 if (game_status == GAME_MODE_PLAYING)
4189 SetPanelBackground();
4190 SetDrawBackgroundMask(REDRAW_DOOR_1);
4194 SetDrawBackgroundMask(REDRAW_FIELD);
4197 #if defined(NETWORK_AVALIABLE)
4198 /* continue network game after request */
4199 if (options.network &&
4200 game_status == GAME_MODE_PLAYING &&
4201 req_state & REQUEST_WAIT_FOR_INPUT)
4202 SendToServer_ContinuePlaying();
4205 /* restore deactivated drawing when quick-loading level tape recording */
4206 if (tape.playing && tape.deactivate_display)
4207 TapeDeactivateDisplayOn();
4212 boolean Request(char *text, unsigned int req_state)
4214 if (global.use_envelope_request)
4215 return RequestEnvelope(text, req_state);
4217 return RequestDoor(text, req_state);
4220 static int compareDoorPartOrderInfo(const void *object1, const void *object2)
4222 const struct DoorPartOrderInfo *dpo1 = (struct DoorPartOrderInfo *)object1;
4223 const struct DoorPartOrderInfo *dpo2 = (struct DoorPartOrderInfo *)object2;
4226 if (dpo1->sort_priority != dpo2->sort_priority)
4227 compare_result = dpo1->sort_priority - dpo2->sort_priority;
4229 compare_result = dpo1->nr - dpo2->nr;
4231 return compare_result;
4234 void InitGraphicCompatibilityInfo_Doors()
4240 struct DoorInfo *door;
4244 { DOOR_1, IMG_GFX_DOOR_1_PART_1, IMG_GFX_DOOR_1_PART_8, &door_1 },
4245 { DOOR_2, IMG_GFX_DOOR_2_PART_1, IMG_GFX_DOOR_2_PART_8, &door_2 },
4247 { -1, -1, -1, NULL }
4249 struct Rect door_rect_list[] =
4251 { DX, DY, DXSIZE, DYSIZE },
4252 { VX, VY, VXSIZE, VYSIZE }
4256 for (i = 0; doors[i].door_token != -1; i++)
4258 int door_token = doors[i].door_token;
4259 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
4260 int part_1 = doors[i].part_1;
4261 int part_8 = doors[i].part_8;
4262 int part_2 = part_1 + 1;
4263 int part_3 = part_1 + 2;
4264 struct DoorInfo *door = doors[i].door;
4265 struct Rect *door_rect = &door_rect_list[door_index];
4266 boolean door_gfx_redefined = FALSE;
4268 /* check if any door part graphic definitions have been redefined */
4270 for (j = 0; door_part_controls[j].door_token != -1; j++)
4272 struct DoorPartControlInfo *dpc = &door_part_controls[j];
4273 struct FileInfo *fi = getImageListEntryFromImageID(dpc->graphic);
4275 if (dpc->door_token == door_token && fi->redefined)
4276 door_gfx_redefined = TRUE;
4279 /* check for old-style door graphic/animation modifications */
4281 if (!door_gfx_redefined)
4283 if (door->anim_mode & ANIM_STATIC_PANEL)
4285 door->panel.step_xoffset = 0;
4286 door->panel.step_yoffset = 0;
4289 if (door->anim_mode & (ANIM_HORIZONTAL | ANIM_VERTICAL))
4291 struct GraphicInfo *g_part_1 = &graphic_info[part_1];
4292 struct GraphicInfo *g_part_2 = &graphic_info[part_2];
4293 int num_door_steps, num_panel_steps;
4295 /* remove door part graphics other than the two default wings */
4297 for (j = 0; door_part_controls[j].door_token != -1; j++)
4299 struct DoorPartControlInfo *dpc = &door_part_controls[j];
4300 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4302 if (dpc->graphic >= part_3 &&
4303 dpc->graphic <= part_8)
4307 /* set graphics and screen positions of the default wings */
4309 g_part_1->width = door_rect->width;
4310 g_part_1->height = door_rect->height;
4311 g_part_2->width = door_rect->width;
4312 g_part_2->height = door_rect->height;
4313 g_part_2->src_x = door_rect->width;
4314 g_part_2->src_y = g_part_1->src_y;
4316 door->part_2.x = door->part_1.x;
4317 door->part_2.y = door->part_1.y;
4319 if (door->width != -1)
4321 g_part_1->width = door->width;
4322 g_part_2->width = door->width;
4324 // special treatment for graphics and screen position of right wing
4325 g_part_2->src_x += door_rect->width - door->width;
4326 door->part_2.x += door_rect->width - door->width;
4329 if (door->height != -1)
4331 g_part_1->height = door->height;
4332 g_part_2->height = door->height;
4334 // special treatment for graphics and screen position of bottom wing
4335 g_part_2->src_y += door_rect->height - door->height;
4336 door->part_2.y += door_rect->height - door->height;
4339 /* set animation delays for the default wings and panels */
4341 door->part_1.step_delay = door->step_delay;
4342 door->part_2.step_delay = door->step_delay;
4343 door->panel.step_delay = door->step_delay;
4345 /* set animation draw order for the default wings */
4347 door->part_1.sort_priority = 2; /* draw left wing over ... */
4348 door->part_2.sort_priority = 1; /* ... right wing */
4350 /* set animation draw offset for the default wings */
4352 if (door->anim_mode & ANIM_HORIZONTAL)
4354 door->part_1.step_xoffset = door->step_offset;
4355 door->part_1.step_yoffset = 0;
4356 door->part_2.step_xoffset = door->step_offset * -1;
4357 door->part_2.step_yoffset = 0;
4359 num_door_steps = g_part_1->width / door->step_offset;
4361 else // ANIM_VERTICAL
4363 door->part_1.step_xoffset = 0;
4364 door->part_1.step_yoffset = door->step_offset;
4365 door->part_2.step_xoffset = 0;
4366 door->part_2.step_yoffset = door->step_offset * -1;
4368 num_door_steps = g_part_1->height / door->step_offset;
4371 /* set animation draw offset for the default panels */
4373 if (door->step_offset > 1)
4375 num_panel_steps = 2 * door_rect->height / door->step_offset;
4376 door->panel.start_step = num_panel_steps - num_door_steps;
4377 door->panel.start_step_closing = door->panel.start_step;
4381 num_panel_steps = door_rect->height / door->step_offset;
4382 door->panel.start_step = num_panel_steps - num_door_steps / 2;
4383 door->panel.start_step_closing = door->panel.start_step;
4384 door->panel.step_delay *= 2;
4395 for (i = 0; door_part_controls[i].door_token != -1; i++)
4397 struct DoorPartControlInfo *dpc = &door_part_controls[i];
4398 struct DoorPartOrderInfo *dpo = &door_part_order[i];
4400 /* initialize "start_step_opening" and "start_step_closing", if needed */
4401 if (dpc->pos->start_step_opening == 0 &&
4402 dpc->pos->start_step_closing == 0)
4404 // dpc->pos->start_step_opening = dpc->pos->start_step;
4405 dpc->pos->start_step_closing = dpc->pos->start_step;
4408 /* fill structure for door part draw order (sorted below) */
4410 dpo->sort_priority = dpc->pos->sort_priority;
4413 /* sort door part controls according to sort_priority and graphic number */
4414 qsort(door_part_order, MAX_DOOR_PARTS,
4415 sizeof(struct DoorPartOrderInfo), compareDoorPartOrderInfo);
4418 unsigned int OpenDoor(unsigned int door_state)
4420 if (door_state & DOOR_COPY_BACK)
4422 if (door_state & DOOR_OPEN_1)
4423 BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
4424 1 * DXSIZE, 0, DXSIZE, DYSIZE, 0 * DXSIZE, 0);
4426 if (door_state & DOOR_OPEN_2)
4427 BlitBitmap(bitmap_db_door_2, bitmap_db_door_2,
4428 1 * VXSIZE, 0, VXSIZE, VYSIZE, 0 * VXSIZE, 0);
4430 door_state &= ~DOOR_COPY_BACK;
4433 return MoveDoor(door_state);
4436 unsigned int CloseDoor(unsigned int door_state)
4438 unsigned int old_door_state = GetDoorState();
4440 if (!(door_state & DOOR_NO_COPY_BACK))
4442 if (old_door_state & DOOR_OPEN_1)
4443 BlitBitmap(backbuffer, bitmap_db_door_1,
4444 DX, DY, DXSIZE, DYSIZE, 0, 0);
4446 if (old_door_state & DOOR_OPEN_2)
4447 BlitBitmap(backbuffer, bitmap_db_door_2,
4448 VX, VY, VXSIZE, VYSIZE, 0, 0);
4450 door_state &= ~DOOR_NO_COPY_BACK;
4453 return MoveDoor(door_state);
4456 unsigned int GetDoorState()
4458 return MoveDoor(DOOR_GET_STATE);
4461 unsigned int SetDoorState(unsigned int door_state)
4463 return MoveDoor(door_state | DOOR_SET_STATE);
4466 int euclid(int a, int b)
4468 return (b ? euclid(b, a % b) : a);
4471 unsigned int MoveDoor(unsigned int door_state)
4473 struct Rect door_rect_list[] =
4475 { DX, DY, DXSIZE, DYSIZE },
4476 { VX, VY, VXSIZE, VYSIZE }
4478 static int door1 = DOOR_CLOSE_1;
4479 static int door2 = DOOR_CLOSE_2;
4480 unsigned int door_delay = 0;
4481 unsigned int door_delay_value;
4484 if (door_state == DOOR_GET_STATE)
4485 return (door1 | door2);
4487 if (door_state & DOOR_SET_STATE)
4489 if (door_state & DOOR_ACTION_1)
4490 door1 = door_state & DOOR_ACTION_1;
4491 if (door_state & DOOR_ACTION_2)
4492 door2 = door_state & DOOR_ACTION_2;
4494 return (door1 | door2);
4497 if (!(door_state & DOOR_FORCE_REDRAW))
4499 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
4500 door_state &= ~DOOR_OPEN_1;
4501 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
4502 door_state &= ~DOOR_CLOSE_1;
4503 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
4504 door_state &= ~DOOR_OPEN_2;
4505 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
4506 door_state &= ~DOOR_CLOSE_2;
4509 if (global.autoplay_leveldir)
4511 door_state |= DOOR_NO_DELAY;
4512 door_state &= ~DOOR_CLOSE_ALL;
4515 if (game_status == GAME_MODE_EDITOR)
4516 door_state |= DOOR_NO_DELAY;
4518 if (door_state & DOOR_ACTION)
4520 boolean door_panel_drawn[NUM_DOORS];
4521 boolean panel_has_doors[NUM_DOORS];
4522 boolean door_part_skip[MAX_DOOR_PARTS];
4523 boolean door_part_done[MAX_DOOR_PARTS];
4524 boolean door_part_done_all;
4525 int num_steps[MAX_DOOR_PARTS];
4526 int max_move_delay = 0; // delay for complete animations of all doors
4527 int max_step_delay = 0; // delay (ms) between two animation frames
4528 int num_move_steps = 0; // number of animation steps for all doors
4529 int max_move_delay_doors_only = 0; // delay for doors only (no panel)
4530 int num_move_steps_doors_only = 0; // steps for doors only (no panel)
4531 int current_move_delay = 0;
4535 for (i = 0; i < NUM_DOORS; i++)
4536 panel_has_doors[i] = FALSE;
4538 for (i = 0; i < MAX_DOOR_PARTS; i++)
4540 struct DoorPartControlInfo *dpc = &door_part_controls[i];
4541 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4542 int door_token = dpc->door_token;
4544 door_part_done[i] = FALSE;
4545 door_part_skip[i] = (!(door_state & door_token) ||
4549 for (i = 0; i < MAX_DOOR_PARTS; i++)
4551 int nr = door_part_order[i].nr;
4552 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
4553 struct DoorPartPosInfo *pos = dpc->pos;
4554 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4555 int door_token = dpc->door_token;
4556 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
4557 boolean is_panel = DOOR_PART_IS_PANEL(nr);
4558 int step_xoffset = ABS(pos->step_xoffset);
4559 int step_yoffset = ABS(pos->step_yoffset);
4560 int step_delay = pos->step_delay;
4561 int current_door_state = door_state & door_token;
4562 boolean door_opening = ((current_door_state & DOOR_OPEN) != 0);
4563 boolean door_closing = ((current_door_state & DOOR_CLOSE) != 0);
4564 boolean part_opening = (is_panel ? door_closing : door_opening);
4565 int start_step = (part_opening ? pos->start_step_opening :
4566 pos->start_step_closing);
4567 float move_xsize = (step_xoffset ? g->width : 0);
4568 float move_ysize = (step_yoffset ? g->height : 0);
4569 int move_xsteps = (step_xoffset ? ceil(move_xsize / step_xoffset) : 0);
4570 int move_ysteps = (step_yoffset ? ceil(move_ysize / step_yoffset) : 0);
4571 int move_steps = (move_xsteps && move_ysteps ?
4572 MIN(move_xsteps, move_ysteps) :
4573 move_xsteps ? move_xsteps : move_ysteps) - start_step;
4574 int move_delay = move_steps * step_delay;
4576 if (door_part_skip[nr])
4579 max_move_delay = MAX(max_move_delay, move_delay);
4580 max_step_delay = (max_step_delay == 0 ? step_delay :
4581 euclid(max_step_delay, step_delay));
4582 num_steps[nr] = move_steps;
4586 max_move_delay_doors_only = MAX(max_move_delay_doors_only, move_delay);
4588 panel_has_doors[door_index] = TRUE;
4592 max_step_delay = MAX(1, max_step_delay); // prevent division by zero
4594 num_move_steps = max_move_delay / max_step_delay;
4595 num_move_steps_doors_only = max_move_delay_doors_only / max_step_delay;
4597 door_delay_value = max_step_delay;
4599 if ((door_state & DOOR_NO_DELAY) || setup.quick_doors)
4601 start = num_move_steps - 1;
4605 /* opening door sound has priority over simultaneously closing door */
4606 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
4607 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
4608 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
4609 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
4612 for (k = start; k < num_move_steps; k++)
4614 int last_frame = num_move_steps - 1; // last frame of this "for" loop
4616 door_part_done_all = TRUE;
4618 for (i = 0; i < NUM_DOORS; i++)
4619 door_panel_drawn[i] = FALSE;
4621 for (i = 0; i < MAX_DOOR_PARTS; i++)
4623 int nr = door_part_order[i].nr;
4624 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
4625 struct DoorPartPosInfo *pos = dpc->pos;
4626 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4627 int door_token = dpc->door_token;
4628 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
4629 boolean is_panel = DOOR_PART_IS_PANEL(nr);
4630 boolean is_panel_and_door_has_closed = FALSE;
4631 struct Rect *door_rect = &door_rect_list[door_index];
4632 Bitmap *bitmap_db_door = (door_token == DOOR_1 ? bitmap_db_door_1 :
4634 Bitmap *bitmap = (is_panel ? bitmap_db_door : g->bitmap);
4635 int current_door_state = door_state & door_token;
4636 boolean door_opening = ((current_door_state & DOOR_OPEN) != 0);
4637 boolean door_closing = !door_opening;
4638 boolean part_opening = (is_panel ? door_closing : door_opening);
4639 boolean part_closing = !part_opening;
4640 int start_step = (part_opening ? pos->start_step_opening :
4641 pos->start_step_closing);
4642 int step_delay = pos->step_delay;
4643 int step_factor = step_delay / max_step_delay;
4644 int k1 = (step_factor ? k / step_factor + 1 : k);
4645 int k2 = (part_opening ? k1 + start_step : num_steps[nr] - k1);
4646 int kk = MAX(0, k2);
4649 int src_x, src_y, src_xx, src_yy;
4650 int dst_x, dst_y, dst_xx, dst_yy;
4653 if (door_part_skip[nr])
4656 if (!(door_state & door_token))
4664 int k2_door = (door_opening ? k : num_move_steps_doors_only - k - 1);
4665 int kk_door = MAX(0, k2_door);
4666 int sync_frame = kk_door * door_delay_value;
4667 int frame = getGraphicAnimationFrame(dpc->graphic, sync_frame);
4669 getFixedGraphicSource(dpc->graphic, frame, &bitmap,
4670 &g_src_x, &g_src_y);
4675 if (!door_panel_drawn[door_index])
4677 ClearRectangle(drawto, door_rect->x, door_rect->y,
4678 door_rect->width, door_rect->height);
4680 door_panel_drawn[door_index] = TRUE;
4683 // draw opening or closing door parts
4685 if (pos->step_xoffset < 0) // door part on right side
4688 dst_xx = pos->x + ABS(kk * pos->step_xoffset);
4691 if (dst_xx + width > door_rect->width)
4692 width = door_rect->width - dst_xx;
4694 else // door part on left side
4697 dst_xx = pos->x - kk * pos->step_xoffset;
4701 src_xx = ABS(dst_xx);
4705 width = g->width - src_xx;
4707 if (width > door_rect->width)
4708 width = door_rect->width;
4710 // printf("::: k == %d [%d] \n", k, start_step);
4713 if (pos->step_yoffset < 0) // door part on bottom side
4716 dst_yy = pos->y + ABS(kk * pos->step_yoffset);
4719 if (dst_yy + height > door_rect->height)
4720 height = door_rect->height - dst_yy;
4722 else // door part on top side
4725 dst_yy = pos->y - kk * pos->step_yoffset;
4729 src_yy = ABS(dst_yy);
4733 height = g->height - src_yy;
4736 src_x = g_src_x + src_xx;
4737 src_y = g_src_y + src_yy;
4739 dst_x = door_rect->x + dst_xx;
4740 dst_y = door_rect->y + dst_yy;
4742 is_panel_and_door_has_closed =
4745 panel_has_doors[door_index] &&
4746 k >= num_move_steps_doors_only - 1);
4748 if (width >= 0 && width <= g->width &&
4749 height >= 0 && height <= g->height &&
4750 !is_panel_and_door_has_closed)
4752 if (is_panel || !pos->draw_masked)
4753 BlitBitmap(bitmap, drawto, src_x, src_y, width, height,
4756 BlitBitmapMasked(bitmap, drawto, src_x, src_y, width, height,
4760 redraw_mask |= REDRAW_DOOR_FROM_TOKEN(door_token);
4762 if ((part_opening && (width < 0 || height < 0)) ||
4763 (part_closing && (width >= g->width && height >= g->height)))
4764 door_part_done[nr] = TRUE;
4766 // continue door part animations, but not panel after door has closed
4767 if (!door_part_done[nr] && !is_panel_and_door_has_closed)
4768 door_part_done_all = FALSE;
4771 if (!(door_state & DOOR_NO_DELAY))
4775 SkipUntilDelayReached(&door_delay, door_delay_value, &k, last_frame);
4777 current_move_delay += max_step_delay;
4780 if (door_part_done_all)
4785 if (door_state & DOOR_ACTION_1)
4786 door1 = door_state & DOOR_ACTION_1;
4787 if (door_state & DOOR_ACTION_2)
4788 door2 = door_state & DOOR_ACTION_2;
4790 // draw masked border over door area
4791 DrawMaskedBorder(REDRAW_DOOR_1);
4792 DrawMaskedBorder(REDRAW_DOOR_2);
4794 return (door1 | door2);
4797 static boolean useSpecialEditorDoor()
4799 int graphic = IMG_GLOBAL_BORDER_EDITOR;
4800 boolean redefined = getImageListEntryFromImageID(graphic)->redefined;
4802 // do not draw special editor door if editor border defined or redefined
4803 if (graphic_info[graphic].bitmap != NULL || redefined)
4806 // do not draw special editor door if global border defined to be empty
4807 if (graphic_info[IMG_GLOBAL_BORDER].bitmap == NULL)
4810 // do not draw special editor door if viewport definitions do not match
4814 EY + EYSIZE != VY + VYSIZE)
4820 void DrawSpecialEditorDoor()
4822 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
4823 int top_border_width = gfx1->width;
4824 int top_border_height = gfx1->height;
4825 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
4826 int ex = EX - outer_border;
4827 int ey = EY - outer_border;
4828 int vy = VY - outer_border;
4829 int exsize = EXSIZE + 2 * outer_border;
4831 if (!useSpecialEditorDoor())
4834 /* draw bigger level editor toolbox window */
4835 BlitBitmap(gfx1->bitmap, drawto, gfx1->src_x, gfx1->src_y,
4836 top_border_width, top_border_height, ex, ey - top_border_height);
4837 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto, ex, vy,
4838 exsize, EYSIZE - VYSIZE + outer_border, ex, ey);
4840 redraw_mask |= REDRAW_ALL;
4843 void UndrawSpecialEditorDoor()
4845 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
4846 int top_border_width = gfx1->width;
4847 int top_border_height = gfx1->height;
4848 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
4849 int ex = EX - outer_border;
4850 int ey = EY - outer_border;
4851 int ey_top = ey - top_border_height;
4852 int exsize = EXSIZE + 2 * outer_border;
4853 int eysize = EYSIZE + 2 * outer_border;
4855 if (!useSpecialEditorDoor())
4858 /* draw normal tape recorder window */
4859 if (graphic_info[IMG_GLOBAL_BORDER].bitmap)
4861 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
4862 ex, ey_top, top_border_width, top_border_height,
4864 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
4865 ex, ey, exsize, eysize, ex, ey);
4869 // if screen background is set to "[NONE]", clear editor toolbox window
4870 ClearRectangle(drawto, ex, ey_top, top_border_width, top_border_height);
4871 ClearRectangle(drawto, ex, ey, exsize, eysize);
4874 redraw_mask |= REDRAW_ALL;
4878 /* ---------- new tool button stuff ---------------------------------------- */
4883 struct TextPosInfo *pos;
4886 } toolbutton_info[NUM_TOOL_BUTTONS] =
4889 IMG_GFX_REQUEST_BUTTON_YES, &request.button.yes,
4890 TOOL_CTRL_ID_YES, "yes"
4893 IMG_GFX_REQUEST_BUTTON_NO, &request.button.no,
4894 TOOL_CTRL_ID_NO, "no"
4897 IMG_GFX_REQUEST_BUTTON_CONFIRM, &request.button.confirm,
4898 TOOL_CTRL_ID_CONFIRM, "confirm"
4901 IMG_GFX_REQUEST_BUTTON_PLAYER_1, &request.button.player_1,
4902 TOOL_CTRL_ID_PLAYER_1, "player 1"
4905 IMG_GFX_REQUEST_BUTTON_PLAYER_2, &request.button.player_2,
4906 TOOL_CTRL_ID_PLAYER_2, "player 2"
4909 IMG_GFX_REQUEST_BUTTON_PLAYER_3, &request.button.player_3,
4910 TOOL_CTRL_ID_PLAYER_3, "player 3"
4913 IMG_GFX_REQUEST_BUTTON_PLAYER_4, &request.button.player_4,
4914 TOOL_CTRL_ID_PLAYER_4, "player 4"
4918 void CreateToolButtons()
4922 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4924 struct GraphicInfo *gfx = &graphic_info[toolbutton_info[i].graphic];
4925 struct TextPosInfo *pos = toolbutton_info[i].pos;
4926 struct GadgetInfo *gi;
4927 Bitmap *deco_bitmap = None;
4928 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
4929 unsigned int event_mask = GD_EVENT_RELEASED;
4932 int gd_x = gfx->src_x;
4933 int gd_y = gfx->src_y;
4934 int gd_xp = gfx->src_x + gfx->pressed_xoffset;
4935 int gd_yp = gfx->src_y + gfx->pressed_yoffset;
4938 if (global.use_envelope_request)
4939 setRequestPosition(&dx, &dy, TRUE);
4941 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
4943 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
4945 getSizedGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr), 0,
4946 pos->size, &deco_bitmap, &deco_x, &deco_y);
4947 deco_xpos = (gfx->width - pos->size) / 2;
4948 deco_ypos = (gfx->height - pos->size) / 2;
4951 gi = CreateGadget(GDI_CUSTOM_ID, id,
4952 GDI_INFO_TEXT, toolbutton_info[i].infotext,
4953 GDI_X, dx + GDI_ACTIVE_POS(pos->x),
4954 GDI_Y, dy + GDI_ACTIVE_POS(pos->y),
4955 GDI_WIDTH, gfx->width,
4956 GDI_HEIGHT, gfx->height,
4957 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
4958 GDI_STATE, GD_BUTTON_UNPRESSED,
4959 GDI_DESIGN_UNPRESSED, gfx->bitmap, gd_x, gd_y,
4960 GDI_DESIGN_PRESSED, gfx->bitmap, gd_xp, gd_yp,
4961 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
4962 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
4963 GDI_DECORATION_SIZE, pos->size, pos->size,
4964 GDI_DECORATION_SHIFTING, 1, 1,
4965 GDI_DIRECT_DRAW, FALSE,
4966 GDI_EVENT_MASK, event_mask,
4967 GDI_CALLBACK_ACTION, HandleToolButtons,
4971 Error(ERR_EXIT, "cannot create gadget");
4973 tool_gadget[id] = gi;
4977 void FreeToolButtons()
4981 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4982 FreeGadget(tool_gadget[i]);
4985 static void UnmapToolButtons()
4989 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4990 UnmapGadget(tool_gadget[i]);
4993 static void HandleToolButtons(struct GadgetInfo *gi)
4995 request_gadget_id = gi->custom_id;
4998 static struct Mapping_EM_to_RND_object
5001 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
5002 boolean is_backside; /* backside of moving element */
5008 em_object_mapping_list[] =
5011 Xblank, TRUE, FALSE,
5015 Yacid_splash_eB, FALSE, FALSE,
5016 EL_ACID_SPLASH_RIGHT, -1, -1
5019 Yacid_splash_wB, FALSE, FALSE,
5020 EL_ACID_SPLASH_LEFT, -1, -1
5023 #ifdef EM_ENGINE_BAD_ROLL
5025 Xstone_force_e, FALSE, FALSE,
5026 EL_ROCK, -1, MV_BIT_RIGHT
5029 Xstone_force_w, FALSE, FALSE,
5030 EL_ROCK, -1, MV_BIT_LEFT
5033 Xnut_force_e, FALSE, FALSE,
5034 EL_NUT, -1, MV_BIT_RIGHT
5037 Xnut_force_w, FALSE, FALSE,
5038 EL_NUT, -1, MV_BIT_LEFT
5041 Xspring_force_e, FALSE, FALSE,
5042 EL_SPRING, -1, MV_BIT_RIGHT
5045 Xspring_force_w, FALSE, FALSE,
5046 EL_SPRING, -1, MV_BIT_LEFT
5049 Xemerald_force_e, FALSE, FALSE,
5050 EL_EMERALD, -1, MV_BIT_RIGHT
5053 Xemerald_force_w, FALSE, FALSE,
5054 EL_EMERALD, -1, MV_BIT_LEFT
5057 Xdiamond_force_e, FALSE, FALSE,
5058 EL_DIAMOND, -1, MV_BIT_RIGHT
5061 Xdiamond_force_w, FALSE, FALSE,
5062 EL_DIAMOND, -1, MV_BIT_LEFT
5065 Xbomb_force_e, FALSE, FALSE,
5066 EL_BOMB, -1, MV_BIT_RIGHT
5069 Xbomb_force_w, FALSE, FALSE,
5070 EL_BOMB, -1, MV_BIT_LEFT
5072 #endif /* EM_ENGINE_BAD_ROLL */
5075 Xstone, TRUE, FALSE,
5079 Xstone_pause, FALSE, FALSE,
5083 Xstone_fall, FALSE, FALSE,
5087 Ystone_s, FALSE, FALSE,
5088 EL_ROCK, ACTION_FALLING, -1
5091 Ystone_sB, FALSE, TRUE,
5092 EL_ROCK, ACTION_FALLING, -1
5095 Ystone_e, FALSE, FALSE,
5096 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
5099 Ystone_eB, FALSE, TRUE,
5100 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
5103 Ystone_w, FALSE, FALSE,
5104 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
5107 Ystone_wB, FALSE, TRUE,
5108 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
5115 Xnut_pause, FALSE, FALSE,
5119 Xnut_fall, FALSE, FALSE,
5123 Ynut_s, FALSE, FALSE,
5124 EL_NUT, ACTION_FALLING, -1
5127 Ynut_sB, FALSE, TRUE,
5128 EL_NUT, ACTION_FALLING, -1
5131 Ynut_e, FALSE, FALSE,
5132 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
5135 Ynut_eB, FALSE, TRUE,
5136 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
5139 Ynut_w, FALSE, FALSE,
5140 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
5143 Ynut_wB, FALSE, TRUE,
5144 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
5147 Xbug_n, TRUE, FALSE,
5151 Xbug_e, TRUE, FALSE,
5152 EL_BUG_RIGHT, -1, -1
5155 Xbug_s, TRUE, FALSE,
5159 Xbug_w, TRUE, FALSE,
5163 Xbug_gon, FALSE, FALSE,
5167 Xbug_goe, FALSE, FALSE,
5168 EL_BUG_RIGHT, -1, -1
5171 Xbug_gos, FALSE, FALSE,
5175 Xbug_gow, FALSE, FALSE,
5179 Ybug_n, FALSE, FALSE,
5180 EL_BUG, ACTION_MOVING, MV_BIT_UP
5183 Ybug_nB, FALSE, TRUE,
5184 EL_BUG, ACTION_MOVING, MV_BIT_UP
5187 Ybug_e, FALSE, FALSE,
5188 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
5191 Ybug_eB, FALSE, TRUE,
5192 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
5195 Ybug_s, FALSE, FALSE,
5196 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
5199 Ybug_sB, FALSE, TRUE,
5200 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
5203 Ybug_w, FALSE, FALSE,
5204 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
5207 Ybug_wB, FALSE, TRUE,
5208 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
5211 Ybug_w_n, FALSE, FALSE,
5212 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
5215 Ybug_n_e, FALSE, FALSE,
5216 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
5219 Ybug_e_s, FALSE, FALSE,
5220 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
5223 Ybug_s_w, FALSE, FALSE,
5224 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
5227 Ybug_e_n, FALSE, FALSE,
5228 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
5231 Ybug_s_e, FALSE, FALSE,
5232 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
5235 Ybug_w_s, FALSE, FALSE,
5236 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
5239 Ybug_n_w, FALSE, FALSE,
5240 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
5243 Ybug_stone, FALSE, FALSE,
5244 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
5247 Ybug_spring, FALSE, FALSE,
5248 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
5251 Xtank_n, TRUE, FALSE,
5252 EL_SPACESHIP_UP, -1, -1
5255 Xtank_e, TRUE, FALSE,
5256 EL_SPACESHIP_RIGHT, -1, -1
5259 Xtank_s, TRUE, FALSE,
5260 EL_SPACESHIP_DOWN, -1, -1
5263 Xtank_w, TRUE, FALSE,
5264 EL_SPACESHIP_LEFT, -1, -1
5267 Xtank_gon, FALSE, FALSE,
5268 EL_SPACESHIP_UP, -1, -1
5271 Xtank_goe, FALSE, FALSE,
5272 EL_SPACESHIP_RIGHT, -1, -1
5275 Xtank_gos, FALSE, FALSE,
5276 EL_SPACESHIP_DOWN, -1, -1
5279 Xtank_gow, FALSE, FALSE,
5280 EL_SPACESHIP_LEFT, -1, -1
5283 Ytank_n, FALSE, FALSE,
5284 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
5287 Ytank_nB, FALSE, TRUE,
5288 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
5291 Ytank_e, FALSE, FALSE,
5292 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
5295 Ytank_eB, FALSE, TRUE,
5296 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
5299 Ytank_s, FALSE, FALSE,
5300 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
5303 Ytank_sB, FALSE, TRUE,
5304 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
5307 Ytank_w, FALSE, FALSE,
5308 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
5311 Ytank_wB, FALSE, TRUE,
5312 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
5315 Ytank_w_n, FALSE, FALSE,
5316 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
5319 Ytank_n_e, FALSE, FALSE,
5320 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
5323 Ytank_e_s, FALSE, FALSE,
5324 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
5327 Ytank_s_w, FALSE, FALSE,
5328 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
5331 Ytank_e_n, FALSE, FALSE,
5332 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
5335 Ytank_s_e, FALSE, FALSE,
5336 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
5339 Ytank_w_s, FALSE, FALSE,
5340 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
5343 Ytank_n_w, FALSE, FALSE,
5344 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
5347 Ytank_stone, FALSE, FALSE,
5348 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
5351 Ytank_spring, FALSE, FALSE,
5352 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
5355 Xandroid, TRUE, FALSE,
5356 EL_EMC_ANDROID, ACTION_ACTIVE, -1
5359 Xandroid_1_n, FALSE, FALSE,
5360 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
5363 Xandroid_2_n, FALSE, FALSE,
5364 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
5367 Xandroid_1_e, FALSE, FALSE,
5368 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
5371 Xandroid_2_e, FALSE, FALSE,
5372 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
5375 Xandroid_1_w, FALSE, FALSE,
5376 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
5379 Xandroid_2_w, FALSE, FALSE,
5380 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
5383 Xandroid_1_s, FALSE, FALSE,
5384 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
5387 Xandroid_2_s, FALSE, FALSE,
5388 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
5391 Yandroid_n, FALSE, FALSE,
5392 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
5395 Yandroid_nB, FALSE, TRUE,
5396 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
5399 Yandroid_ne, FALSE, FALSE,
5400 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
5403 Yandroid_neB, FALSE, TRUE,
5404 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
5407 Yandroid_e, FALSE, FALSE,
5408 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
5411 Yandroid_eB, FALSE, TRUE,
5412 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
5415 Yandroid_se, FALSE, FALSE,
5416 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
5419 Yandroid_seB, FALSE, TRUE,
5420 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
5423 Yandroid_s, FALSE, FALSE,
5424 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
5427 Yandroid_sB, FALSE, TRUE,
5428 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
5431 Yandroid_sw, FALSE, FALSE,
5432 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
5435 Yandroid_swB, FALSE, TRUE,
5436 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
5439 Yandroid_w, FALSE, FALSE,
5440 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
5443 Yandroid_wB, FALSE, TRUE,
5444 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
5447 Yandroid_nw, FALSE, FALSE,
5448 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
5451 Yandroid_nwB, FALSE, TRUE,
5452 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
5455 Xspring, TRUE, FALSE,
5459 Xspring_pause, FALSE, FALSE,
5463 Xspring_e, FALSE, FALSE,
5467 Xspring_w, FALSE, FALSE,
5471 Xspring_fall, FALSE, FALSE,
5475 Yspring_s, FALSE, FALSE,
5476 EL_SPRING, ACTION_FALLING, -1
5479 Yspring_sB, FALSE, TRUE,
5480 EL_SPRING, ACTION_FALLING, -1
5483 Yspring_e, FALSE, FALSE,
5484 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
5487 Yspring_eB, FALSE, TRUE,
5488 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
5491 Yspring_w, FALSE, FALSE,
5492 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
5495 Yspring_wB, FALSE, TRUE,
5496 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
5499 Yspring_kill_e, FALSE, FALSE,
5500 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
5503 Yspring_kill_eB, FALSE, TRUE,
5504 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
5507 Yspring_kill_w, FALSE, FALSE,
5508 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
5511 Yspring_kill_wB, FALSE, TRUE,
5512 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
5515 Xeater_n, TRUE, FALSE,
5516 EL_YAMYAM_UP, -1, -1
5519 Xeater_e, TRUE, FALSE,
5520 EL_YAMYAM_RIGHT, -1, -1
5523 Xeater_w, TRUE, FALSE,
5524 EL_YAMYAM_LEFT, -1, -1
5527 Xeater_s, TRUE, FALSE,
5528 EL_YAMYAM_DOWN, -1, -1
5531 Yeater_n, FALSE, FALSE,
5532 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
5535 Yeater_nB, FALSE, TRUE,
5536 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
5539 Yeater_e, FALSE, FALSE,
5540 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
5543 Yeater_eB, FALSE, TRUE,
5544 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
5547 Yeater_s, FALSE, FALSE,
5548 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
5551 Yeater_sB, FALSE, TRUE,
5552 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
5555 Yeater_w, FALSE, FALSE,
5556 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
5559 Yeater_wB, FALSE, TRUE,
5560 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
5563 Yeater_stone, FALSE, FALSE,
5564 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
5567 Yeater_spring, FALSE, FALSE,
5568 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
5571 Xalien, TRUE, FALSE,
5575 Xalien_pause, FALSE, FALSE,
5579 Yalien_n, FALSE, FALSE,
5580 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
5583 Yalien_nB, FALSE, TRUE,
5584 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
5587 Yalien_e, FALSE, FALSE,
5588 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
5591 Yalien_eB, FALSE, TRUE,
5592 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
5595 Yalien_s, FALSE, FALSE,
5596 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
5599 Yalien_sB, FALSE, TRUE,
5600 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
5603 Yalien_w, FALSE, FALSE,
5604 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
5607 Yalien_wB, FALSE, TRUE,
5608 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
5611 Yalien_stone, FALSE, FALSE,
5612 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
5615 Yalien_spring, FALSE, FALSE,
5616 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
5619 Xemerald, TRUE, FALSE,
5623 Xemerald_pause, FALSE, FALSE,
5627 Xemerald_fall, FALSE, FALSE,
5631 Xemerald_shine, FALSE, FALSE,
5632 EL_EMERALD, ACTION_TWINKLING, -1
5635 Yemerald_s, FALSE, FALSE,
5636 EL_EMERALD, ACTION_FALLING, -1
5639 Yemerald_sB, FALSE, TRUE,
5640 EL_EMERALD, ACTION_FALLING, -1
5643 Yemerald_e, FALSE, FALSE,
5644 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
5647 Yemerald_eB, FALSE, TRUE,
5648 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
5651 Yemerald_w, FALSE, FALSE,
5652 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
5655 Yemerald_wB, FALSE, TRUE,
5656 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
5659 Yemerald_eat, FALSE, FALSE,
5660 EL_EMERALD, ACTION_COLLECTING, -1
5663 Yemerald_stone, FALSE, FALSE,
5664 EL_NUT, ACTION_BREAKING, -1
5667 Xdiamond, TRUE, FALSE,
5671 Xdiamond_pause, FALSE, FALSE,
5675 Xdiamond_fall, FALSE, FALSE,
5679 Xdiamond_shine, FALSE, FALSE,
5680 EL_DIAMOND, ACTION_TWINKLING, -1
5683 Ydiamond_s, FALSE, FALSE,
5684 EL_DIAMOND, ACTION_FALLING, -1
5687 Ydiamond_sB, FALSE, TRUE,
5688 EL_DIAMOND, ACTION_FALLING, -1
5691 Ydiamond_e, FALSE, FALSE,
5692 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
5695 Ydiamond_eB, FALSE, TRUE,
5696 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
5699 Ydiamond_w, FALSE, FALSE,
5700 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
5703 Ydiamond_wB, FALSE, TRUE,
5704 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
5707 Ydiamond_eat, FALSE, FALSE,
5708 EL_DIAMOND, ACTION_COLLECTING, -1
5711 Ydiamond_stone, FALSE, FALSE,
5712 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
5715 Xdrip_fall, TRUE, FALSE,
5716 EL_AMOEBA_DROP, -1, -1
5719 Xdrip_stretch, FALSE, FALSE,
5720 EL_AMOEBA_DROP, ACTION_FALLING, -1
5723 Xdrip_stretchB, FALSE, TRUE,
5724 EL_AMOEBA_DROP, ACTION_FALLING, -1
5727 Xdrip_eat, FALSE, FALSE,
5728 EL_AMOEBA_DROP, ACTION_GROWING, -1
5731 Ydrip_s1, FALSE, FALSE,
5732 EL_AMOEBA_DROP, ACTION_FALLING, -1
5735 Ydrip_s1B, FALSE, TRUE,
5736 EL_AMOEBA_DROP, ACTION_FALLING, -1
5739 Ydrip_s2, FALSE, FALSE,
5740 EL_AMOEBA_DROP, ACTION_FALLING, -1
5743 Ydrip_s2B, FALSE, TRUE,
5744 EL_AMOEBA_DROP, ACTION_FALLING, -1
5751 Xbomb_pause, FALSE, FALSE,
5755 Xbomb_fall, FALSE, FALSE,
5759 Ybomb_s, FALSE, FALSE,
5760 EL_BOMB, ACTION_FALLING, -1
5763 Ybomb_sB, FALSE, TRUE,
5764 EL_BOMB, ACTION_FALLING, -1
5767 Ybomb_e, FALSE, FALSE,
5768 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
5771 Ybomb_eB, FALSE, TRUE,
5772 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
5775 Ybomb_w, FALSE, FALSE,
5776 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
5779 Ybomb_wB, FALSE, TRUE,
5780 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
5783 Ybomb_eat, FALSE, FALSE,
5784 EL_BOMB, ACTION_ACTIVATING, -1
5787 Xballoon, TRUE, FALSE,
5791 Yballoon_n, FALSE, FALSE,
5792 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
5795 Yballoon_nB, FALSE, TRUE,
5796 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
5799 Yballoon_e, FALSE, FALSE,
5800 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
5803 Yballoon_eB, FALSE, TRUE,
5804 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
5807 Yballoon_s, FALSE, FALSE,
5808 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
5811 Yballoon_sB, FALSE, TRUE,
5812 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
5815 Yballoon_w, FALSE, FALSE,
5816 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
5819 Yballoon_wB, FALSE, TRUE,
5820 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
5823 Xgrass, TRUE, FALSE,
5824 EL_EMC_GRASS, -1, -1
5827 Ygrass_nB, FALSE, FALSE,
5828 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
5831 Ygrass_eB, FALSE, FALSE,
5832 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
5835 Ygrass_sB, FALSE, FALSE,
5836 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
5839 Ygrass_wB, FALSE, FALSE,
5840 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
5847 Ydirt_nB, FALSE, FALSE,
5848 EL_SAND, ACTION_DIGGING, MV_BIT_UP
5851 Ydirt_eB, FALSE, FALSE,
5852 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
5855 Ydirt_sB, FALSE, FALSE,
5856 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
5859 Ydirt_wB, FALSE, FALSE,
5860 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
5863 Xacid_ne, TRUE, FALSE,
5864 EL_ACID_POOL_TOPRIGHT, -1, -1
5867 Xacid_se, TRUE, FALSE,
5868 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
5871 Xacid_s, TRUE, FALSE,
5872 EL_ACID_POOL_BOTTOM, -1, -1
5875 Xacid_sw, TRUE, FALSE,
5876 EL_ACID_POOL_BOTTOMLEFT, -1, -1
5879 Xacid_nw, TRUE, FALSE,
5880 EL_ACID_POOL_TOPLEFT, -1, -1
5883 Xacid_1, TRUE, FALSE,
5887 Xacid_2, FALSE, FALSE,
5891 Xacid_3, FALSE, FALSE,
5895 Xacid_4, FALSE, FALSE,
5899 Xacid_5, FALSE, FALSE,
5903 Xacid_6, FALSE, FALSE,
5907 Xacid_7, FALSE, FALSE,
5911 Xacid_8, FALSE, FALSE,
5915 Xball_1, TRUE, FALSE,
5916 EL_EMC_MAGIC_BALL, -1, -1
5919 Xball_1B, FALSE, FALSE,
5920 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5923 Xball_2, FALSE, FALSE,
5924 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5927 Xball_2B, FALSE, FALSE,
5928 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5931 Yball_eat, FALSE, FALSE,
5932 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
5935 Ykey_1_eat, FALSE, FALSE,
5936 EL_EM_KEY_1, ACTION_COLLECTING, -1
5939 Ykey_2_eat, FALSE, FALSE,
5940 EL_EM_KEY_2, ACTION_COLLECTING, -1
5943 Ykey_3_eat, FALSE, FALSE,
5944 EL_EM_KEY_3, ACTION_COLLECTING, -1
5947 Ykey_4_eat, FALSE, FALSE,
5948 EL_EM_KEY_4, ACTION_COLLECTING, -1
5951 Ykey_5_eat, FALSE, FALSE,
5952 EL_EMC_KEY_5, ACTION_COLLECTING, -1
5955 Ykey_6_eat, FALSE, FALSE,
5956 EL_EMC_KEY_6, ACTION_COLLECTING, -1
5959 Ykey_7_eat, FALSE, FALSE,
5960 EL_EMC_KEY_7, ACTION_COLLECTING, -1
5963 Ykey_8_eat, FALSE, FALSE,
5964 EL_EMC_KEY_8, ACTION_COLLECTING, -1
5967 Ylenses_eat, FALSE, FALSE,
5968 EL_EMC_LENSES, ACTION_COLLECTING, -1
5971 Ymagnify_eat, FALSE, FALSE,
5972 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
5975 Ygrass_eat, FALSE, FALSE,
5976 EL_EMC_GRASS, ACTION_SNAPPING, -1
5979 Ydirt_eat, FALSE, FALSE,
5980 EL_SAND, ACTION_SNAPPING, -1
5983 Xgrow_ns, TRUE, FALSE,
5984 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
5987 Ygrow_ns_eat, FALSE, FALSE,
5988 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
5991 Xgrow_ew, TRUE, FALSE,
5992 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
5995 Ygrow_ew_eat, FALSE, FALSE,
5996 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
5999 Xwonderwall, TRUE, FALSE,
6000 EL_MAGIC_WALL, -1, -1
6003 XwonderwallB, FALSE, FALSE,
6004 EL_MAGIC_WALL, ACTION_ACTIVE, -1
6007 Xamoeba_1, TRUE, FALSE,
6008 EL_AMOEBA_DRY, ACTION_OTHER, -1
6011 Xamoeba_2, FALSE, FALSE,
6012 EL_AMOEBA_DRY, ACTION_OTHER, -1
6015 Xamoeba_3, FALSE, FALSE,
6016 EL_AMOEBA_DRY, ACTION_OTHER, -1
6019 Xamoeba_4, FALSE, FALSE,
6020 EL_AMOEBA_DRY, ACTION_OTHER, -1
6023 Xamoeba_5, TRUE, FALSE,
6024 EL_AMOEBA_WET, ACTION_OTHER, -1
6027 Xamoeba_6, FALSE, FALSE,
6028 EL_AMOEBA_WET, ACTION_OTHER, -1
6031 Xamoeba_7, FALSE, FALSE,
6032 EL_AMOEBA_WET, ACTION_OTHER, -1
6035 Xamoeba_8, FALSE, FALSE,
6036 EL_AMOEBA_WET, ACTION_OTHER, -1
6039 Xdoor_1, TRUE, FALSE,
6040 EL_EM_GATE_1, -1, -1
6043 Xdoor_2, TRUE, FALSE,
6044 EL_EM_GATE_2, -1, -1
6047 Xdoor_3, TRUE, FALSE,
6048 EL_EM_GATE_3, -1, -1
6051 Xdoor_4, TRUE, FALSE,
6052 EL_EM_GATE_4, -1, -1
6055 Xdoor_5, TRUE, FALSE,
6056 EL_EMC_GATE_5, -1, -1
6059 Xdoor_6, TRUE, FALSE,
6060 EL_EMC_GATE_6, -1, -1
6063 Xdoor_7, TRUE, FALSE,
6064 EL_EMC_GATE_7, -1, -1
6067 Xdoor_8, TRUE, FALSE,
6068 EL_EMC_GATE_8, -1, -1
6071 Xkey_1, TRUE, FALSE,
6075 Xkey_2, TRUE, FALSE,
6079 Xkey_3, TRUE, FALSE,
6083 Xkey_4, TRUE, FALSE,
6087 Xkey_5, TRUE, FALSE,
6088 EL_EMC_KEY_5, -1, -1
6091 Xkey_6, TRUE, FALSE,
6092 EL_EMC_KEY_6, -1, -1
6095 Xkey_7, TRUE, FALSE,
6096 EL_EMC_KEY_7, -1, -1
6099 Xkey_8, TRUE, FALSE,
6100 EL_EMC_KEY_8, -1, -1
6103 Xwind_n, TRUE, FALSE,
6104 EL_BALLOON_SWITCH_UP, -1, -1
6107 Xwind_e, TRUE, FALSE,
6108 EL_BALLOON_SWITCH_RIGHT, -1, -1
6111 Xwind_s, TRUE, FALSE,
6112 EL_BALLOON_SWITCH_DOWN, -1, -1
6115 Xwind_w, TRUE, FALSE,
6116 EL_BALLOON_SWITCH_LEFT, -1, -1
6119 Xwind_nesw, TRUE, FALSE,
6120 EL_BALLOON_SWITCH_ANY, -1, -1
6123 Xwind_stop, TRUE, FALSE,
6124 EL_BALLOON_SWITCH_NONE, -1, -1
6128 EL_EM_EXIT_CLOSED, -1, -1
6131 Xexit_1, TRUE, FALSE,
6132 EL_EM_EXIT_OPEN, -1, -1
6135 Xexit_2, FALSE, FALSE,
6136 EL_EM_EXIT_OPEN, -1, -1
6139 Xexit_3, FALSE, FALSE,
6140 EL_EM_EXIT_OPEN, -1, -1
6143 Xdynamite, TRUE, FALSE,
6144 EL_EM_DYNAMITE, -1, -1
6147 Ydynamite_eat, FALSE, FALSE,
6148 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
6151 Xdynamite_1, TRUE, FALSE,
6152 EL_EM_DYNAMITE_ACTIVE, -1, -1
6155 Xdynamite_2, FALSE, FALSE,
6156 EL_EM_DYNAMITE_ACTIVE, -1, -1
6159 Xdynamite_3, FALSE, FALSE,
6160 EL_EM_DYNAMITE_ACTIVE, -1, -1
6163 Xdynamite_4, FALSE, FALSE,
6164 EL_EM_DYNAMITE_ACTIVE, -1, -1
6167 Xbumper, TRUE, FALSE,
6168 EL_EMC_SPRING_BUMPER, -1, -1
6171 XbumperB, FALSE, FALSE,
6172 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
6175 Xwheel, TRUE, FALSE,
6176 EL_ROBOT_WHEEL, -1, -1
6179 XwheelB, FALSE, FALSE,
6180 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
6183 Xswitch, TRUE, FALSE,
6184 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
6187 XswitchB, FALSE, FALSE,
6188 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
6192 EL_QUICKSAND_EMPTY, -1, -1
6195 Xsand_stone, TRUE, FALSE,
6196 EL_QUICKSAND_FULL, -1, -1
6199 Xsand_stonein_1, FALSE, TRUE,
6200 EL_ROCK, ACTION_FILLING, -1
6203 Xsand_stonein_2, FALSE, TRUE,
6204 EL_ROCK, ACTION_FILLING, -1
6207 Xsand_stonein_3, FALSE, TRUE,
6208 EL_ROCK, ACTION_FILLING, -1
6211 Xsand_stonein_4, FALSE, TRUE,
6212 EL_ROCK, ACTION_FILLING, -1
6215 Xsand_stonesand_1, FALSE, FALSE,
6216 EL_QUICKSAND_EMPTYING, -1, -1
6219 Xsand_stonesand_2, FALSE, FALSE,
6220 EL_QUICKSAND_EMPTYING, -1, -1
6223 Xsand_stonesand_3, FALSE, FALSE,
6224 EL_QUICKSAND_EMPTYING, -1, -1
6227 Xsand_stonesand_4, FALSE, FALSE,
6228 EL_QUICKSAND_EMPTYING, -1, -1
6231 Xsand_stonesand_quickout_1, FALSE, FALSE,
6232 EL_QUICKSAND_EMPTYING, -1, -1
6235 Xsand_stonesand_quickout_2, FALSE, FALSE,
6236 EL_QUICKSAND_EMPTYING, -1, -1
6239 Xsand_stoneout_1, FALSE, FALSE,
6240 EL_ROCK, ACTION_EMPTYING, -1
6243 Xsand_stoneout_2, FALSE, FALSE,
6244 EL_ROCK, ACTION_EMPTYING, -1
6247 Xsand_sandstone_1, FALSE, FALSE,
6248 EL_QUICKSAND_FILLING, -1, -1
6251 Xsand_sandstone_2, FALSE, FALSE,
6252 EL_QUICKSAND_FILLING, -1, -1
6255 Xsand_sandstone_3, FALSE, FALSE,
6256 EL_QUICKSAND_FILLING, -1, -1
6259 Xsand_sandstone_4, FALSE, FALSE,
6260 EL_QUICKSAND_FILLING, -1, -1
6263 Xplant, TRUE, FALSE,
6264 EL_EMC_PLANT, -1, -1
6267 Yplant, FALSE, FALSE,
6268 EL_EMC_PLANT, -1, -1
6271 Xlenses, TRUE, FALSE,
6272 EL_EMC_LENSES, -1, -1
6275 Xmagnify, TRUE, FALSE,
6276 EL_EMC_MAGNIFIER, -1, -1
6279 Xdripper, TRUE, FALSE,
6280 EL_EMC_DRIPPER, -1, -1
6283 XdripperB, FALSE, FALSE,
6284 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
6287 Xfake_blank, TRUE, FALSE,
6288 EL_INVISIBLE_WALL, -1, -1
6291 Xfake_blankB, FALSE, FALSE,
6292 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
6295 Xfake_grass, TRUE, FALSE,
6296 EL_EMC_FAKE_GRASS, -1, -1
6299 Xfake_grassB, FALSE, FALSE,
6300 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
6303 Xfake_door_1, TRUE, FALSE,
6304 EL_EM_GATE_1_GRAY, -1, -1
6307 Xfake_door_2, TRUE, FALSE,
6308 EL_EM_GATE_2_GRAY, -1, -1
6311 Xfake_door_3, TRUE, FALSE,
6312 EL_EM_GATE_3_GRAY, -1, -1
6315 Xfake_door_4, TRUE, FALSE,
6316 EL_EM_GATE_4_GRAY, -1, -1
6319 Xfake_door_5, TRUE, FALSE,
6320 EL_EMC_GATE_5_GRAY, -1, -1
6323 Xfake_door_6, TRUE, FALSE,
6324 EL_EMC_GATE_6_GRAY, -1, -1
6327 Xfake_door_7, TRUE, FALSE,
6328 EL_EMC_GATE_7_GRAY, -1, -1
6331 Xfake_door_8, TRUE, FALSE,
6332 EL_EMC_GATE_8_GRAY, -1, -1
6335 Xfake_acid_1, TRUE, FALSE,
6336 EL_EMC_FAKE_ACID, -1, -1
6339 Xfake_acid_2, FALSE, FALSE,
6340 EL_EMC_FAKE_ACID, -1, -1
6343 Xfake_acid_3, FALSE, FALSE,
6344 EL_EMC_FAKE_ACID, -1, -1
6347 Xfake_acid_4, FALSE, FALSE,
6348 EL_EMC_FAKE_ACID, -1, -1
6351 Xfake_acid_5, FALSE, FALSE,
6352 EL_EMC_FAKE_ACID, -1, -1
6355 Xfake_acid_6, FALSE, FALSE,
6356 EL_EMC_FAKE_ACID, -1, -1
6359 Xfake_acid_7, FALSE, FALSE,
6360 EL_EMC_FAKE_ACID, -1, -1
6363 Xfake_acid_8, FALSE, FALSE,
6364 EL_EMC_FAKE_ACID, -1, -1
6367 Xsteel_1, TRUE, FALSE,
6368 EL_STEELWALL, -1, -1
6371 Xsteel_2, TRUE, FALSE,
6372 EL_EMC_STEELWALL_2, -1, -1
6375 Xsteel_3, TRUE, FALSE,
6376 EL_EMC_STEELWALL_3, -1, -1
6379 Xsteel_4, TRUE, FALSE,
6380 EL_EMC_STEELWALL_4, -1, -1
6383 Xwall_1, TRUE, FALSE,
6387 Xwall_2, TRUE, FALSE,
6388 EL_EMC_WALL_14, -1, -1
6391 Xwall_3, TRUE, FALSE,
6392 EL_EMC_WALL_15, -1, -1
6395 Xwall_4, TRUE, FALSE,
6396 EL_EMC_WALL_16, -1, -1
6399 Xround_wall_1, TRUE, FALSE,
6400 EL_WALL_SLIPPERY, -1, -1
6403 Xround_wall_2, TRUE, FALSE,
6404 EL_EMC_WALL_SLIPPERY_2, -1, -1
6407 Xround_wall_3, TRUE, FALSE,
6408 EL_EMC_WALL_SLIPPERY_3, -1, -1
6411 Xround_wall_4, TRUE, FALSE,
6412 EL_EMC_WALL_SLIPPERY_4, -1, -1
6415 Xdecor_1, TRUE, FALSE,
6416 EL_EMC_WALL_8, -1, -1
6419 Xdecor_2, TRUE, FALSE,
6420 EL_EMC_WALL_6, -1, -1
6423 Xdecor_3, TRUE, FALSE,
6424 EL_EMC_WALL_4, -1, -1
6427 Xdecor_4, TRUE, FALSE,
6428 EL_EMC_WALL_7, -1, -1
6431 Xdecor_5, TRUE, FALSE,
6432 EL_EMC_WALL_5, -1, -1
6435 Xdecor_6, TRUE, FALSE,
6436 EL_EMC_WALL_9, -1, -1
6439 Xdecor_7, TRUE, FALSE,
6440 EL_EMC_WALL_10, -1, -1
6443 Xdecor_8, TRUE, FALSE,
6444 EL_EMC_WALL_1, -1, -1
6447 Xdecor_9, TRUE, FALSE,
6448 EL_EMC_WALL_2, -1, -1
6451 Xdecor_10, TRUE, FALSE,
6452 EL_EMC_WALL_3, -1, -1
6455 Xdecor_11, TRUE, FALSE,
6456 EL_EMC_WALL_11, -1, -1
6459 Xdecor_12, TRUE, FALSE,
6460 EL_EMC_WALL_12, -1, -1
6463 Xalpha_0, TRUE, FALSE,
6464 EL_CHAR('0'), -1, -1
6467 Xalpha_1, TRUE, FALSE,
6468 EL_CHAR('1'), -1, -1
6471 Xalpha_2, TRUE, FALSE,
6472 EL_CHAR('2'), -1, -1
6475 Xalpha_3, TRUE, FALSE,
6476 EL_CHAR('3'), -1, -1
6479 Xalpha_4, TRUE, FALSE,
6480 EL_CHAR('4'), -1, -1
6483 Xalpha_5, TRUE, FALSE,
6484 EL_CHAR('5'), -1, -1
6487 Xalpha_6, TRUE, FALSE,
6488 EL_CHAR('6'), -1, -1
6491 Xalpha_7, TRUE, FALSE,
6492 EL_CHAR('7'), -1, -1
6495 Xalpha_8, TRUE, FALSE,
6496 EL_CHAR('8'), -1, -1
6499 Xalpha_9, TRUE, FALSE,
6500 EL_CHAR('9'), -1, -1
6503 Xalpha_excla, TRUE, FALSE,
6504 EL_CHAR('!'), -1, -1
6507 Xalpha_quote, TRUE, FALSE,
6508 EL_CHAR('"'), -1, -1
6511 Xalpha_comma, TRUE, FALSE,
6512 EL_CHAR(','), -1, -1
6515 Xalpha_minus, TRUE, FALSE,
6516 EL_CHAR('-'), -1, -1
6519 Xalpha_perio, TRUE, FALSE,
6520 EL_CHAR('.'), -1, -1
6523 Xalpha_colon, TRUE, FALSE,
6524 EL_CHAR(':'), -1, -1
6527 Xalpha_quest, TRUE, FALSE,
6528 EL_CHAR('?'), -1, -1
6531 Xalpha_a, TRUE, FALSE,
6532 EL_CHAR('A'), -1, -1
6535 Xalpha_b, TRUE, FALSE,
6536 EL_CHAR('B'), -1, -1
6539 Xalpha_c, TRUE, FALSE,
6540 EL_CHAR('C'), -1, -1
6543 Xalpha_d, TRUE, FALSE,
6544 EL_CHAR('D'), -1, -1
6547 Xalpha_e, TRUE, FALSE,
6548 EL_CHAR('E'), -1, -1
6551 Xalpha_f, TRUE, FALSE,
6552 EL_CHAR('F'), -1, -1
6555 Xalpha_g, TRUE, FALSE,
6556 EL_CHAR('G'), -1, -1
6559 Xalpha_h, TRUE, FALSE,
6560 EL_CHAR('H'), -1, -1
6563 Xalpha_i, TRUE, FALSE,
6564 EL_CHAR('I'), -1, -1
6567 Xalpha_j, TRUE, FALSE,
6568 EL_CHAR('J'), -1, -1
6571 Xalpha_k, TRUE, FALSE,
6572 EL_CHAR('K'), -1, -1
6575 Xalpha_l, TRUE, FALSE,
6576 EL_CHAR('L'), -1, -1
6579 Xalpha_m, TRUE, FALSE,
6580 EL_CHAR('M'), -1, -1
6583 Xalpha_n, TRUE, FALSE,
6584 EL_CHAR('N'), -1, -1
6587 Xalpha_o, TRUE, FALSE,
6588 EL_CHAR('O'), -1, -1
6591 Xalpha_p, TRUE, FALSE,
6592 EL_CHAR('P'), -1, -1
6595 Xalpha_q, TRUE, FALSE,
6596 EL_CHAR('Q'), -1, -1
6599 Xalpha_r, TRUE, FALSE,
6600 EL_CHAR('R'), -1, -1
6603 Xalpha_s, TRUE, FALSE,
6604 EL_CHAR('S'), -1, -1
6607 Xalpha_t, TRUE, FALSE,
6608 EL_CHAR('T'), -1, -1
6611 Xalpha_u, TRUE, FALSE,
6612 EL_CHAR('U'), -1, -1
6615 Xalpha_v, TRUE, FALSE,
6616 EL_CHAR('V'), -1, -1
6619 Xalpha_w, TRUE, FALSE,
6620 EL_CHAR('W'), -1, -1
6623 Xalpha_x, TRUE, FALSE,
6624 EL_CHAR('X'), -1, -1
6627 Xalpha_y, TRUE, FALSE,
6628 EL_CHAR('Y'), -1, -1
6631 Xalpha_z, TRUE, FALSE,
6632 EL_CHAR('Z'), -1, -1
6635 Xalpha_arrow_e, TRUE, FALSE,
6636 EL_CHAR('>'), -1, -1
6639 Xalpha_arrow_w, TRUE, FALSE,
6640 EL_CHAR('<'), -1, -1
6643 Xalpha_copyr, TRUE, FALSE,
6644 EL_CHAR(CHAR_BYTE_COPYRIGHT), -1, -1
6648 Xboom_bug, FALSE, FALSE,
6649 EL_BUG, ACTION_EXPLODING, -1
6652 Xboom_bomb, FALSE, FALSE,
6653 EL_BOMB, ACTION_EXPLODING, -1
6656 Xboom_android, FALSE, FALSE,
6657 EL_EMC_ANDROID, ACTION_OTHER, -1
6660 Xboom_1, FALSE, FALSE,
6661 EL_DEFAULT, ACTION_EXPLODING, -1
6664 Xboom_2, FALSE, FALSE,
6665 EL_DEFAULT, ACTION_EXPLODING, -1
6668 Znormal, FALSE, FALSE,
6672 Zdynamite, FALSE, FALSE,
6676 Zplayer, FALSE, FALSE,
6680 ZBORDER, FALSE, FALSE,
6690 static struct Mapping_EM_to_RND_player
6699 em_player_mapping_list[] =
6703 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
6707 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
6711 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
6715 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
6719 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
6723 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
6727 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
6731 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
6735 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
6739 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
6743 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
6747 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
6751 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
6755 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
6759 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
6763 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
6767 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
6771 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
6775 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
6779 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
6783 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
6787 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
6791 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
6795 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
6799 EL_PLAYER_1, ACTION_DEFAULT, -1,
6803 EL_PLAYER_2, ACTION_DEFAULT, -1,
6807 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
6811 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
6815 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
6819 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
6823 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
6827 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
6831 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
6835 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
6839 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
6843 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
6847 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
6851 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
6855 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
6859 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
6863 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
6867 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
6871 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
6875 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
6879 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
6883 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
6887 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
6891 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
6895 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
6899 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
6903 EL_PLAYER_3, ACTION_DEFAULT, -1,
6907 EL_PLAYER_4, ACTION_DEFAULT, -1,
6916 int map_element_RND_to_EM(int element_rnd)
6918 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
6919 static boolean mapping_initialized = FALSE;
6921 if (!mapping_initialized)
6925 /* return "Xalpha_quest" for all undefined elements in mapping array */
6926 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
6927 mapping_RND_to_EM[i] = Xalpha_quest;
6929 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6930 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
6931 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
6932 em_object_mapping_list[i].element_em;
6934 mapping_initialized = TRUE;
6937 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
6938 return mapping_RND_to_EM[element_rnd];
6940 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
6945 int map_element_EM_to_RND(int element_em)
6947 static unsigned short mapping_EM_to_RND[TILE_MAX];
6948 static boolean mapping_initialized = FALSE;
6950 if (!mapping_initialized)
6954 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
6955 for (i = 0; i < TILE_MAX; i++)
6956 mapping_EM_to_RND[i] = EL_UNKNOWN;
6958 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6959 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
6960 em_object_mapping_list[i].element_rnd;
6962 mapping_initialized = TRUE;
6965 if (element_em >= 0 && element_em < TILE_MAX)
6966 return mapping_EM_to_RND[element_em];
6968 Error(ERR_WARN, "invalid EM level element %d", element_em);
6973 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
6975 struct LevelInfo_EM *level_em = level->native_em_level;
6976 struct LEVEL *lev = level_em->lev;
6979 for (i = 0; i < TILE_MAX; i++)
6980 lev->android_array[i] = Xblank;
6982 for (i = 0; i < level->num_android_clone_elements; i++)
6984 int element_rnd = level->android_clone_element[i];
6985 int element_em = map_element_RND_to_EM(element_rnd);
6987 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
6988 if (em_object_mapping_list[j].element_rnd == element_rnd)
6989 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
6993 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
6995 struct LevelInfo_EM *level_em = level->native_em_level;
6996 struct LEVEL *lev = level_em->lev;
6999 level->num_android_clone_elements = 0;
7001 for (i = 0; i < TILE_MAX; i++)
7003 int element_em = lev->android_array[i];
7005 boolean element_found = FALSE;
7007 if (element_em == Xblank)
7010 element_rnd = map_element_EM_to_RND(element_em);
7012 for (j = 0; j < level->num_android_clone_elements; j++)
7013 if (level->android_clone_element[j] == element_rnd)
7014 element_found = TRUE;
7018 level->android_clone_element[level->num_android_clone_elements++] =
7021 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
7026 if (level->num_android_clone_elements == 0)
7028 level->num_android_clone_elements = 1;
7029 level->android_clone_element[0] = EL_EMPTY;
7033 int map_direction_RND_to_EM(int direction)
7035 return (direction == MV_UP ? 0 :
7036 direction == MV_RIGHT ? 1 :
7037 direction == MV_DOWN ? 2 :
7038 direction == MV_LEFT ? 3 :
7042 int map_direction_EM_to_RND(int direction)
7044 return (direction == 0 ? MV_UP :
7045 direction == 1 ? MV_RIGHT :
7046 direction == 2 ? MV_DOWN :
7047 direction == 3 ? MV_LEFT :
7051 int map_element_RND_to_SP(int element_rnd)
7053 int element_sp = 0x20; /* map unknown elements to yellow "hardware" */
7055 if (element_rnd >= EL_SP_START &&
7056 element_rnd <= EL_SP_END)
7057 element_sp = element_rnd - EL_SP_START;
7058 else if (element_rnd == EL_EMPTY_SPACE)
7060 else if (element_rnd == EL_INVISIBLE_WALL)
7066 int map_element_SP_to_RND(int element_sp)
7068 int element_rnd = EL_UNKNOWN;
7070 if (element_sp >= 0x00 &&
7072 element_rnd = EL_SP_START + element_sp;
7073 else if (element_sp == 0x28)
7074 element_rnd = EL_INVISIBLE_WALL;
7079 int map_action_SP_to_RND(int action_sp)
7083 case actActive: return ACTION_ACTIVE;
7084 case actImpact: return ACTION_IMPACT;
7085 case actExploding: return ACTION_EXPLODING;
7086 case actDigging: return ACTION_DIGGING;
7087 case actSnapping: return ACTION_SNAPPING;
7088 case actCollecting: return ACTION_COLLECTING;
7089 case actPassing: return ACTION_PASSING;
7090 case actPushing: return ACTION_PUSHING;
7091 case actDropping: return ACTION_DROPPING;
7093 default: return ACTION_DEFAULT;
7097 int get_next_element(int element)
7101 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
7102 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
7103 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
7104 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
7105 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
7106 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
7107 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
7108 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
7109 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
7110 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
7111 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
7113 default: return element;
7117 int el_act_dir2img(int element, int action, int direction)
7119 element = GFX_ELEMENT(element);
7120 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
7122 /* direction_graphic[][] == graphic[] for undefined direction graphics */
7123 return element_info[element].direction_graphic[action][direction];
7126 static int el_act_dir2crm(int element, int action, int direction)
7128 element = GFX_ELEMENT(element);
7129 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
7131 /* direction_graphic[][] == graphic[] for undefined direction graphics */
7132 return element_info[element].direction_crumbled[action][direction];
7135 int el_act2img(int element, int action)
7137 element = GFX_ELEMENT(element);
7139 return element_info[element].graphic[action];
7142 int el_act2crm(int element, int action)
7144 element = GFX_ELEMENT(element);
7146 return element_info[element].crumbled[action];
7149 int el_dir2img(int element, int direction)
7151 element = GFX_ELEMENT(element);
7153 return el_act_dir2img(element, ACTION_DEFAULT, direction);
7156 int el2baseimg(int element)
7158 return element_info[element].graphic[ACTION_DEFAULT];
7161 int el2img(int element)
7163 element = GFX_ELEMENT(element);
7165 return element_info[element].graphic[ACTION_DEFAULT];
7168 int el2edimg(int element)
7170 element = GFX_ELEMENT(element);
7172 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
7175 int el2preimg(int element)
7177 element = GFX_ELEMENT(element);
7179 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
7182 int el2panelimg(int element)
7184 element = GFX_ELEMENT(element);
7186 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL];
7189 int font2baseimg(int font_nr)
7191 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
7194 int getBeltNrFromBeltElement(int element)
7196 return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
7197 element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
7198 element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
7201 int getBeltNrFromBeltActiveElement(int element)
7203 return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
7204 element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
7205 element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
7208 int getBeltNrFromBeltSwitchElement(int element)
7210 return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
7211 element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
7212 element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
7215 int getBeltDirNrFromBeltElement(int element)
7217 static int belt_base_element[4] =
7219 EL_CONVEYOR_BELT_1_LEFT,
7220 EL_CONVEYOR_BELT_2_LEFT,
7221 EL_CONVEYOR_BELT_3_LEFT,
7222 EL_CONVEYOR_BELT_4_LEFT
7225 int belt_nr = getBeltNrFromBeltElement(element);
7226 int belt_dir_nr = element - belt_base_element[belt_nr];
7228 return (belt_dir_nr % 3);
7231 int getBeltDirNrFromBeltSwitchElement(int element)
7233 static int belt_base_element[4] =
7235 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
7236 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
7237 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
7238 EL_CONVEYOR_BELT_4_SWITCH_LEFT
7241 int belt_nr = getBeltNrFromBeltSwitchElement(element);
7242 int belt_dir_nr = element - belt_base_element[belt_nr];
7244 return (belt_dir_nr % 3);
7247 int getBeltDirFromBeltElement(int element)
7249 static int belt_move_dir[3] =
7256 int belt_dir_nr = getBeltDirNrFromBeltElement(element);
7258 return belt_move_dir[belt_dir_nr];
7261 int getBeltDirFromBeltSwitchElement(int element)
7263 static int belt_move_dir[3] =
7270 int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
7272 return belt_move_dir[belt_dir_nr];
7275 int getBeltElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
7277 static int belt_base_element[4] =
7279 EL_CONVEYOR_BELT_1_LEFT,
7280 EL_CONVEYOR_BELT_2_LEFT,
7281 EL_CONVEYOR_BELT_3_LEFT,
7282 EL_CONVEYOR_BELT_4_LEFT
7285 return belt_base_element[belt_nr] + belt_dir_nr;
7288 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
7290 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
7292 return getBeltElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
7295 int getBeltSwitchElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
7297 static int belt_base_element[4] =
7299 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
7300 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
7301 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
7302 EL_CONVEYOR_BELT_4_SWITCH_LEFT
7305 return belt_base_element[belt_nr] + belt_dir_nr;
7308 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
7310 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
7312 return getBeltSwitchElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
7315 boolean getTeamMode_EM()
7317 return game.team_mode;
7320 int getGameFrameDelay_EM(int native_em_game_frame_delay)
7322 int game_frame_delay_value;
7324 game_frame_delay_value =
7325 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
7326 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
7329 if (tape.playing && tape.warp_forward && !tape.pausing)
7330 game_frame_delay_value = 0;
7332 return game_frame_delay_value;
7335 unsigned int InitRND(int seed)
7337 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
7338 return InitEngineRandom_EM(seed);
7339 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
7340 return InitEngineRandom_SP(seed);
7342 return InitEngineRandom_RND(seed);
7345 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
7346 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
7348 inline static int get_effective_element_EM(int tile, int frame_em)
7350 int element = object_mapping[tile].element_rnd;
7351 int action = object_mapping[tile].action;
7352 boolean is_backside = object_mapping[tile].is_backside;
7353 boolean action_removing = (action == ACTION_DIGGING ||
7354 action == ACTION_SNAPPING ||
7355 action == ACTION_COLLECTING);
7361 case Yacid_splash_eB:
7362 case Yacid_splash_wB:
7363 return (frame_em > 5 ? EL_EMPTY : element);
7369 else /* frame_em == 7 */
7373 case Yacid_splash_eB:
7374 case Yacid_splash_wB:
7377 case Yemerald_stone:
7380 case Ydiamond_stone:
7384 case Xdrip_stretchB:
7403 case Xsand_stonein_1:
7404 case Xsand_stonein_2:
7405 case Xsand_stonein_3:
7406 case Xsand_stonein_4:
7410 return (is_backside || action_removing ? EL_EMPTY : element);
7415 inline static boolean check_linear_animation_EM(int tile)
7419 case Xsand_stonesand_1:
7420 case Xsand_stonesand_quickout_1:
7421 case Xsand_sandstone_1:
7422 case Xsand_stonein_1:
7423 case Xsand_stoneout_1:
7442 case Yacid_splash_eB:
7443 case Yacid_splash_wB:
7444 case Yemerald_stone:
7451 inline static void set_crumbled_graphics_EM(struct GraphicInfo_EM *g_em,
7452 boolean has_crumbled_graphics,
7453 int crumbled, int sync_frame)
7455 /* if element can be crumbled, but certain action graphics are just empty
7456 space (like instantly snapping sand to empty space in 1 frame), do not
7457 treat these empty space graphics as crumbled graphics in EMC engine */
7458 if (crumbled == IMG_EMPTY_SPACE)
7459 has_crumbled_graphics = FALSE;
7461 if (has_crumbled_graphics)
7463 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
7464 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
7465 g_crumbled->anim_delay,
7466 g_crumbled->anim_mode,
7467 g_crumbled->anim_start_frame,
7470 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
7471 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
7473 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
7474 g_em->crumbled_tile_size = graphic_info[crumbled].tile_size;
7476 g_em->has_crumbled_graphics = TRUE;
7480 g_em->crumbled_bitmap = NULL;
7481 g_em->crumbled_src_x = 0;
7482 g_em->crumbled_src_y = 0;
7483 g_em->crumbled_border_size = 0;
7484 g_em->crumbled_tile_size = 0;
7486 g_em->has_crumbled_graphics = FALSE;
7490 void ResetGfxAnimation_EM(int x, int y, int tile)
7495 void SetGfxAnimation_EM(struct GraphicInfo_EM *g_em,
7496 int tile, int frame_em, int x, int y)
7498 int action = object_mapping[tile].action;
7499 int direction = object_mapping[tile].direction;
7500 int effective_element = get_effective_element_EM(tile, frame_em);
7501 int graphic = (direction == MV_NONE ?
7502 el_act2img(effective_element, action) :
7503 el_act_dir2img(effective_element, action, direction));
7504 struct GraphicInfo *g = &graphic_info[graphic];
7506 boolean action_removing = (action == ACTION_DIGGING ||
7507 action == ACTION_SNAPPING ||
7508 action == ACTION_COLLECTING);
7509 boolean action_moving = (action == ACTION_FALLING ||
7510 action == ACTION_MOVING ||
7511 action == ACTION_PUSHING ||
7512 action == ACTION_EATING ||
7513 action == ACTION_FILLING ||
7514 action == ACTION_EMPTYING);
7515 boolean action_falling = (action == ACTION_FALLING ||
7516 action == ACTION_FILLING ||
7517 action == ACTION_EMPTYING);
7519 /* special case: graphic uses "2nd movement tile" and has defined
7520 7 frames for movement animation (or less) => use default graphic
7521 for last (8th) frame which ends the movement animation */
7522 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
7524 action = ACTION_DEFAULT; /* (keep action_* unchanged for now) */
7525 graphic = (direction == MV_NONE ?
7526 el_act2img(effective_element, action) :
7527 el_act_dir2img(effective_element, action, direction));
7529 g = &graphic_info[graphic];
7532 if ((action_removing || check_linear_animation_EM(tile)) && frame_em == 0)
7536 else if (action_moving)
7538 boolean is_backside = object_mapping[tile].is_backside;
7542 int direction = object_mapping[tile].direction;
7543 int move_dir = (action_falling ? MV_DOWN : direction);
7548 /* !!! TEST !!! NEW !!! DOES NOT WORK RIGHT YET !!! */
7549 if (g->double_movement && frame_em == 0)
7553 if (move_dir == MV_LEFT)
7554 GfxFrame[x - 1][y] = GfxFrame[x][y];
7555 else if (move_dir == MV_RIGHT)
7556 GfxFrame[x + 1][y] = GfxFrame[x][y];
7557 else if (move_dir == MV_UP)
7558 GfxFrame[x][y - 1] = GfxFrame[x][y];
7559 else if (move_dir == MV_DOWN)
7560 GfxFrame[x][y + 1] = GfxFrame[x][y];
7567 /* special case: animation for Xsand_stonesand_quickout_1/2 twice as fast */
7568 if (tile == Xsand_stonesand_quickout_1 ||
7569 tile == Xsand_stonesand_quickout_2)
7573 if (graphic_info[graphic].anim_global_sync)
7574 sync_frame = FrameCounter;
7575 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
7576 sync_frame = GfxFrame[x][y];
7578 sync_frame = 0; /* playfield border (pseudo steel) */
7580 SetRandomAnimationValue(x, y);
7582 int frame = getAnimationFrame(g->anim_frames,
7585 g->anim_start_frame,
7588 g_em->unique_identifier =
7589 (graphic << 16) | ((frame % 8) << 12) | (g_em->width << 6) | g_em->height;
7592 void getGraphicSourceObjectExt_EM(struct GraphicInfo_EM *g_em,
7593 int tile, int frame_em, int x, int y)
7595 int action = object_mapping[tile].action;
7596 int direction = object_mapping[tile].direction;
7597 boolean is_backside = object_mapping[tile].is_backside;
7598 int effective_element = get_effective_element_EM(tile, frame_em);
7599 int effective_action = action;
7600 int graphic = (direction == MV_NONE ?
7601 el_act2img(effective_element, effective_action) :
7602 el_act_dir2img(effective_element, effective_action,
7604 int crumbled = (direction == MV_NONE ?
7605 el_act2crm(effective_element, effective_action) :
7606 el_act_dir2crm(effective_element, effective_action,
7608 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7609 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7610 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7611 struct GraphicInfo *g = &graphic_info[graphic];
7614 /* special case: graphic uses "2nd movement tile" and has defined
7615 7 frames for movement animation (or less) => use default graphic
7616 for last (8th) frame which ends the movement animation */
7617 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
7619 effective_action = ACTION_DEFAULT;
7620 graphic = (direction == MV_NONE ?
7621 el_act2img(effective_element, effective_action) :
7622 el_act_dir2img(effective_element, effective_action,
7624 crumbled = (direction == MV_NONE ?
7625 el_act2crm(effective_element, effective_action) :
7626 el_act_dir2crm(effective_element, effective_action,
7629 g = &graphic_info[graphic];
7632 if (graphic_info[graphic].anim_global_sync)
7633 sync_frame = FrameCounter;
7634 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
7635 sync_frame = GfxFrame[x][y];
7637 sync_frame = 0; /* playfield border (pseudo steel) */
7639 SetRandomAnimationValue(x, y);
7641 int frame = getAnimationFrame(g->anim_frames,
7644 g->anim_start_frame,
7647 getGraphicSourceExt(graphic, frame, &g_em->bitmap, &g_em->src_x, &g_em->src_y,
7648 g->double_movement && is_backside);
7650 /* (updating the "crumbled" graphic definitions is probably not really needed,
7651 as animations for crumbled graphics can't be longer than one EMC cycle) */
7652 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
7656 void getGraphicSourcePlayerExt_EM(struct GraphicInfo_EM *g_em,
7657 int player_nr, int anim, int frame_em)
7659 int element = player_mapping[player_nr][anim].element_rnd;
7660 int action = player_mapping[player_nr][anim].action;
7661 int direction = player_mapping[player_nr][anim].direction;
7662 int graphic = (direction == MV_NONE ?
7663 el_act2img(element, action) :
7664 el_act_dir2img(element, action, direction));
7665 struct GraphicInfo *g = &graphic_info[graphic];
7668 InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
7670 stored_player[player_nr].StepFrame = frame_em;
7672 sync_frame = stored_player[player_nr].Frame;
7674 int frame = getAnimationFrame(g->anim_frames,
7677 g->anim_start_frame,
7680 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
7681 &g_em->src_x, &g_em->src_y, FALSE);
7684 void InitGraphicInfo_EM(void)
7689 int num_em_gfx_errors = 0;
7691 if (graphic_info_em_object[0][0].bitmap == NULL)
7693 /* EM graphics not yet initialized in em_open_all() */
7698 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
7701 /* always start with reliable default values */
7702 for (i = 0; i < TILE_MAX; i++)
7704 object_mapping[i].element_rnd = EL_UNKNOWN;
7705 object_mapping[i].is_backside = FALSE;
7706 object_mapping[i].action = ACTION_DEFAULT;
7707 object_mapping[i].direction = MV_NONE;
7710 /* always start with reliable default values */
7711 for (p = 0; p < MAX_PLAYERS; p++)
7713 for (i = 0; i < SPR_MAX; i++)
7715 player_mapping[p][i].element_rnd = EL_UNKNOWN;
7716 player_mapping[p][i].action = ACTION_DEFAULT;
7717 player_mapping[p][i].direction = MV_NONE;
7721 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
7723 int e = em_object_mapping_list[i].element_em;
7725 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
7726 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
7728 if (em_object_mapping_list[i].action != -1)
7729 object_mapping[e].action = em_object_mapping_list[i].action;
7731 if (em_object_mapping_list[i].direction != -1)
7732 object_mapping[e].direction =
7733 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
7736 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
7738 int a = em_player_mapping_list[i].action_em;
7739 int p = em_player_mapping_list[i].player_nr;
7741 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
7743 if (em_player_mapping_list[i].action != -1)
7744 player_mapping[p][a].action = em_player_mapping_list[i].action;
7746 if (em_player_mapping_list[i].direction != -1)
7747 player_mapping[p][a].direction =
7748 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
7751 for (i = 0; i < TILE_MAX; i++)
7753 int element = object_mapping[i].element_rnd;
7754 int action = object_mapping[i].action;
7755 int direction = object_mapping[i].direction;
7756 boolean is_backside = object_mapping[i].is_backside;
7757 boolean action_exploding = ((action == ACTION_EXPLODING ||
7758 action == ACTION_SMASHED_BY_ROCK ||
7759 action == ACTION_SMASHED_BY_SPRING) &&
7760 element != EL_DIAMOND);
7761 boolean action_active = (action == ACTION_ACTIVE);
7762 boolean action_other = (action == ACTION_OTHER);
7764 for (j = 0; j < 8; j++)
7766 int effective_element = get_effective_element_EM(i, j);
7767 int effective_action = (j < 7 ? action :
7768 i == Xdrip_stretch ? action :
7769 i == Xdrip_stretchB ? action :
7770 i == Ydrip_s1 ? action :
7771 i == Ydrip_s1B ? action :
7772 i == Xball_1B ? action :
7773 i == Xball_2 ? action :
7774 i == Xball_2B ? action :
7775 i == Yball_eat ? action :
7776 i == Ykey_1_eat ? action :
7777 i == Ykey_2_eat ? action :
7778 i == Ykey_3_eat ? action :
7779 i == Ykey_4_eat ? action :
7780 i == Ykey_5_eat ? action :
7781 i == Ykey_6_eat ? action :
7782 i == Ykey_7_eat ? action :
7783 i == Ykey_8_eat ? action :
7784 i == Ylenses_eat ? action :
7785 i == Ymagnify_eat ? action :
7786 i == Ygrass_eat ? action :
7787 i == Ydirt_eat ? action :
7788 i == Xsand_stonein_1 ? action :
7789 i == Xsand_stonein_2 ? action :
7790 i == Xsand_stonein_3 ? action :
7791 i == Xsand_stonein_4 ? action :
7792 i == Xsand_stoneout_1 ? action :
7793 i == Xsand_stoneout_2 ? action :
7794 i == Xboom_android ? ACTION_EXPLODING :
7795 action_exploding ? ACTION_EXPLODING :
7796 action_active ? action :
7797 action_other ? action :
7799 int graphic = (el_act_dir2img(effective_element, effective_action,
7801 int crumbled = (el_act_dir2crm(effective_element, effective_action,
7803 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7804 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7805 boolean has_action_graphics = (graphic != base_graphic);
7806 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7807 struct GraphicInfo *g = &graphic_info[graphic];
7808 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7811 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
7812 boolean special_animation = (action != ACTION_DEFAULT &&
7813 g->anim_frames == 3 &&
7814 g->anim_delay == 2 &&
7815 g->anim_mode & ANIM_LINEAR);
7816 int sync_frame = (i == Xdrip_stretch ? 7 :
7817 i == Xdrip_stretchB ? 7 :
7818 i == Ydrip_s2 ? j + 8 :
7819 i == Ydrip_s2B ? j + 8 :
7828 i == Xfake_acid_1 ? 0 :
7829 i == Xfake_acid_2 ? 10 :
7830 i == Xfake_acid_3 ? 20 :
7831 i == Xfake_acid_4 ? 30 :
7832 i == Xfake_acid_5 ? 40 :
7833 i == Xfake_acid_6 ? 50 :
7834 i == Xfake_acid_7 ? 60 :
7835 i == Xfake_acid_8 ? 70 :
7837 i == Xball_2B ? j + 8 :
7838 i == Yball_eat ? j + 1 :
7839 i == Ykey_1_eat ? j + 1 :
7840 i == Ykey_2_eat ? j + 1 :
7841 i == Ykey_3_eat ? j + 1 :
7842 i == Ykey_4_eat ? j + 1 :
7843 i == Ykey_5_eat ? j + 1 :
7844 i == Ykey_6_eat ? j + 1 :
7845 i == Ykey_7_eat ? j + 1 :
7846 i == Ykey_8_eat ? j + 1 :
7847 i == Ylenses_eat ? j + 1 :
7848 i == Ymagnify_eat ? j + 1 :
7849 i == Ygrass_eat ? j + 1 :
7850 i == Ydirt_eat ? j + 1 :
7851 i == Xamoeba_1 ? 0 :
7852 i == Xamoeba_2 ? 1 :
7853 i == Xamoeba_3 ? 2 :
7854 i == Xamoeba_4 ? 3 :
7855 i == Xamoeba_5 ? 0 :
7856 i == Xamoeba_6 ? 1 :
7857 i == Xamoeba_7 ? 2 :
7858 i == Xamoeba_8 ? 3 :
7859 i == Xexit_2 ? j + 8 :
7860 i == Xexit_3 ? j + 16 :
7861 i == Xdynamite_1 ? 0 :
7862 i == Xdynamite_2 ? 8 :
7863 i == Xdynamite_3 ? 16 :
7864 i == Xdynamite_4 ? 24 :
7865 i == Xsand_stonein_1 ? j + 1 :
7866 i == Xsand_stonein_2 ? j + 9 :
7867 i == Xsand_stonein_3 ? j + 17 :
7868 i == Xsand_stonein_4 ? j + 25 :
7869 i == Xsand_stoneout_1 && j == 0 ? 0 :
7870 i == Xsand_stoneout_1 && j == 1 ? 0 :
7871 i == Xsand_stoneout_1 && j == 2 ? 1 :
7872 i == Xsand_stoneout_1 && j == 3 ? 2 :
7873 i == Xsand_stoneout_1 && j == 4 ? 2 :
7874 i == Xsand_stoneout_1 && j == 5 ? 3 :
7875 i == Xsand_stoneout_1 && j == 6 ? 4 :
7876 i == Xsand_stoneout_1 && j == 7 ? 4 :
7877 i == Xsand_stoneout_2 && j == 0 ? 5 :
7878 i == Xsand_stoneout_2 && j == 1 ? 6 :
7879 i == Xsand_stoneout_2 && j == 2 ? 7 :
7880 i == Xsand_stoneout_2 && j == 3 ? 8 :
7881 i == Xsand_stoneout_2 && j == 4 ? 9 :
7882 i == Xsand_stoneout_2 && j == 5 ? 11 :
7883 i == Xsand_stoneout_2 && j == 6 ? 13 :
7884 i == Xsand_stoneout_2 && j == 7 ? 15 :
7885 i == Xboom_bug && j == 1 ? 2 :
7886 i == Xboom_bug && j == 2 ? 2 :
7887 i == Xboom_bug && j == 3 ? 4 :
7888 i == Xboom_bug && j == 4 ? 4 :
7889 i == Xboom_bug && j == 5 ? 2 :
7890 i == Xboom_bug && j == 6 ? 2 :
7891 i == Xboom_bug && j == 7 ? 0 :
7892 i == Xboom_bomb && j == 1 ? 2 :
7893 i == Xboom_bomb && j == 2 ? 2 :
7894 i == Xboom_bomb && j == 3 ? 4 :
7895 i == Xboom_bomb && j == 4 ? 4 :
7896 i == Xboom_bomb && j == 5 ? 2 :
7897 i == Xboom_bomb && j == 6 ? 2 :
7898 i == Xboom_bomb && j == 7 ? 0 :
7899 i == Xboom_android && j == 7 ? 6 :
7900 i == Xboom_1 && j == 1 ? 2 :
7901 i == Xboom_1 && j == 2 ? 2 :
7902 i == Xboom_1 && j == 3 ? 4 :
7903 i == Xboom_1 && j == 4 ? 4 :
7904 i == Xboom_1 && j == 5 ? 6 :
7905 i == Xboom_1 && j == 6 ? 6 :
7906 i == Xboom_1 && j == 7 ? 8 :
7907 i == Xboom_2 && j == 0 ? 8 :
7908 i == Xboom_2 && j == 1 ? 8 :
7909 i == Xboom_2 && j == 2 ? 10 :
7910 i == Xboom_2 && j == 3 ? 10 :
7911 i == Xboom_2 && j == 4 ? 10 :
7912 i == Xboom_2 && j == 5 ? 12 :
7913 i == Xboom_2 && j == 6 ? 12 :
7914 i == Xboom_2 && j == 7 ? 12 :
7915 special_animation && j == 4 ? 3 :
7916 effective_action != action ? 0 :
7920 Bitmap *debug_bitmap = g_em->bitmap;
7921 int debug_src_x = g_em->src_x;
7922 int debug_src_y = g_em->src_y;
7925 int frame = getAnimationFrame(g->anim_frames,
7928 g->anim_start_frame,
7931 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
7932 g->double_movement && is_backside);
7934 g_em->bitmap = src_bitmap;
7935 g_em->src_x = src_x;
7936 g_em->src_y = src_y;
7937 g_em->src_offset_x = 0;
7938 g_em->src_offset_y = 0;
7939 g_em->dst_offset_x = 0;
7940 g_em->dst_offset_y = 0;
7941 g_em->width = TILEX;
7942 g_em->height = TILEY;
7944 g_em->preserve_background = FALSE;
7946 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
7949 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
7950 effective_action == ACTION_MOVING ||
7951 effective_action == ACTION_PUSHING ||
7952 effective_action == ACTION_EATING)) ||
7953 (!has_action_graphics && (effective_action == ACTION_FILLING ||
7954 effective_action == ACTION_EMPTYING)))
7957 (effective_action == ACTION_FALLING ||
7958 effective_action == ACTION_FILLING ||
7959 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
7960 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
7961 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
7962 int num_steps = (i == Ydrip_s1 ? 16 :
7963 i == Ydrip_s1B ? 16 :
7964 i == Ydrip_s2 ? 16 :
7965 i == Ydrip_s2B ? 16 :
7966 i == Xsand_stonein_1 ? 32 :
7967 i == Xsand_stonein_2 ? 32 :
7968 i == Xsand_stonein_3 ? 32 :
7969 i == Xsand_stonein_4 ? 32 :
7970 i == Xsand_stoneout_1 ? 16 :
7971 i == Xsand_stoneout_2 ? 16 : 8);
7972 int cx = ABS(dx) * (TILEX / num_steps);
7973 int cy = ABS(dy) * (TILEY / num_steps);
7974 int step_frame = (i == Ydrip_s2 ? j + 8 :
7975 i == Ydrip_s2B ? j + 8 :
7976 i == Xsand_stonein_2 ? j + 8 :
7977 i == Xsand_stonein_3 ? j + 16 :
7978 i == Xsand_stonein_4 ? j + 24 :
7979 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
7980 int step = (is_backside ? step_frame : num_steps - step_frame);
7982 if (is_backside) /* tile where movement starts */
7984 if (dx < 0 || dy < 0)
7986 g_em->src_offset_x = cx * step;
7987 g_em->src_offset_y = cy * step;
7991 g_em->dst_offset_x = cx * step;
7992 g_em->dst_offset_y = cy * step;
7995 else /* tile where movement ends */
7997 if (dx < 0 || dy < 0)
7999 g_em->dst_offset_x = cx * step;
8000 g_em->dst_offset_y = cy * step;
8004 g_em->src_offset_x = cx * step;
8005 g_em->src_offset_y = cy * step;
8009 g_em->width = TILEX - cx * step;
8010 g_em->height = TILEY - cy * step;
8013 /* create unique graphic identifier to decide if tile must be redrawn */
8014 /* bit 31 - 16 (16 bit): EM style graphic
8015 bit 15 - 12 ( 4 bit): EM style frame
8016 bit 11 - 6 ( 6 bit): graphic width
8017 bit 5 - 0 ( 6 bit): graphic height */
8018 g_em->unique_identifier =
8019 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
8023 /* skip check for EMC elements not contained in original EMC artwork */
8024 if (element == EL_EMC_FAKE_ACID)
8027 if (g_em->bitmap != debug_bitmap ||
8028 g_em->src_x != debug_src_x ||
8029 g_em->src_y != debug_src_y ||
8030 g_em->src_offset_x != 0 ||
8031 g_em->src_offset_y != 0 ||
8032 g_em->dst_offset_x != 0 ||
8033 g_em->dst_offset_y != 0 ||
8034 g_em->width != TILEX ||
8035 g_em->height != TILEY)
8037 static int last_i = -1;
8045 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
8046 i, element, element_info[element].token_name,
8047 element_action_info[effective_action].suffix, direction);
8049 if (element != effective_element)
8050 printf(" [%d ('%s')]",
8052 element_info[effective_element].token_name);
8056 if (g_em->bitmap != debug_bitmap)
8057 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
8058 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
8060 if (g_em->src_x != debug_src_x ||
8061 g_em->src_y != debug_src_y)
8062 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
8063 j, (is_backside ? 'B' : 'F'),
8064 g_em->src_x, g_em->src_y,
8065 g_em->src_x / 32, g_em->src_y / 32,
8066 debug_src_x, debug_src_y,
8067 debug_src_x / 32, debug_src_y / 32);
8069 if (g_em->src_offset_x != 0 ||
8070 g_em->src_offset_y != 0 ||
8071 g_em->dst_offset_x != 0 ||
8072 g_em->dst_offset_y != 0)
8073 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
8075 g_em->src_offset_x, g_em->src_offset_y,
8076 g_em->dst_offset_x, g_em->dst_offset_y);
8078 if (g_em->width != TILEX ||
8079 g_em->height != TILEY)
8080 printf(" %d (%d): size %d,%d should be %d,%d\n",
8082 g_em->width, g_em->height, TILEX, TILEY);
8084 num_em_gfx_errors++;
8091 for (i = 0; i < TILE_MAX; i++)
8093 for (j = 0; j < 8; j++)
8095 int element = object_mapping[i].element_rnd;
8096 int action = object_mapping[i].action;
8097 int direction = object_mapping[i].direction;
8098 boolean is_backside = object_mapping[i].is_backside;
8099 int graphic_action = el_act_dir2img(element, action, direction);
8100 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
8102 if ((action == ACTION_SMASHED_BY_ROCK ||
8103 action == ACTION_SMASHED_BY_SPRING ||
8104 action == ACTION_EATING) &&
8105 graphic_action == graphic_default)
8107 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
8108 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
8109 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
8110 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
8113 /* no separate animation for "smashed by rock" -- use rock instead */
8114 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
8115 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
8117 g_em->bitmap = g_xx->bitmap;
8118 g_em->src_x = g_xx->src_x;
8119 g_em->src_y = g_xx->src_y;
8120 g_em->src_offset_x = g_xx->src_offset_x;
8121 g_em->src_offset_y = g_xx->src_offset_y;
8122 g_em->dst_offset_x = g_xx->dst_offset_x;
8123 g_em->dst_offset_y = g_xx->dst_offset_y;
8124 g_em->width = g_xx->width;
8125 g_em->height = g_xx->height;
8126 g_em->unique_identifier = g_xx->unique_identifier;
8129 g_em->preserve_background = TRUE;
8134 for (p = 0; p < MAX_PLAYERS; p++)
8136 for (i = 0; i < SPR_MAX; i++)
8138 int element = player_mapping[p][i].element_rnd;
8139 int action = player_mapping[p][i].action;
8140 int direction = player_mapping[p][i].direction;
8142 for (j = 0; j < 8; j++)
8144 int effective_element = element;
8145 int effective_action = action;
8146 int graphic = (direction == MV_NONE ?
8147 el_act2img(effective_element, effective_action) :
8148 el_act_dir2img(effective_element, effective_action,
8150 struct GraphicInfo *g = &graphic_info[graphic];
8151 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
8157 Bitmap *debug_bitmap = g_em->bitmap;
8158 int debug_src_x = g_em->src_x;
8159 int debug_src_y = g_em->src_y;
8162 int frame = getAnimationFrame(g->anim_frames,
8165 g->anim_start_frame,
8168 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
8170 g_em->bitmap = src_bitmap;
8171 g_em->src_x = src_x;
8172 g_em->src_y = src_y;
8173 g_em->src_offset_x = 0;
8174 g_em->src_offset_y = 0;
8175 g_em->dst_offset_x = 0;
8176 g_em->dst_offset_y = 0;
8177 g_em->width = TILEX;
8178 g_em->height = TILEY;
8182 /* skip check for EMC elements not contained in original EMC artwork */
8183 if (element == EL_PLAYER_3 ||
8184 element == EL_PLAYER_4)
8187 if (g_em->bitmap != debug_bitmap ||
8188 g_em->src_x != debug_src_x ||
8189 g_em->src_y != debug_src_y)
8191 static int last_i = -1;
8199 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
8200 p, i, element, element_info[element].token_name,
8201 element_action_info[effective_action].suffix, direction);
8203 if (element != effective_element)
8204 printf(" [%d ('%s')]",
8206 element_info[effective_element].token_name);
8210 if (g_em->bitmap != debug_bitmap)
8211 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
8212 j, (int)(g_em->bitmap), (int)(debug_bitmap));
8214 if (g_em->src_x != debug_src_x ||
8215 g_em->src_y != debug_src_y)
8216 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
8218 g_em->src_x, g_em->src_y,
8219 g_em->src_x / 32, g_em->src_y / 32,
8220 debug_src_x, debug_src_y,
8221 debug_src_x / 32, debug_src_y / 32);
8223 num_em_gfx_errors++;
8233 printf("::: [%d errors found]\n", num_em_gfx_errors);
8239 void CheckSaveEngineSnapshot_EM(byte action[MAX_PLAYERS], int frame,
8240 boolean any_player_moving,
8241 boolean any_player_snapping,
8242 boolean any_player_dropping)
8244 if (frame == 0 && !any_player_dropping)
8246 if (!local_player->was_waiting)
8248 if (!CheckSaveEngineSnapshotToList())
8251 local_player->was_waiting = TRUE;
8254 else if (any_player_moving || any_player_snapping || any_player_dropping)
8256 local_player->was_waiting = FALSE;
8260 void CheckSaveEngineSnapshot_SP(boolean murphy_is_waiting,
8261 boolean murphy_is_dropping)
8263 if (murphy_is_waiting)
8265 if (!local_player->was_waiting)
8267 if (!CheckSaveEngineSnapshotToList())
8270 local_player->was_waiting = TRUE;
8275 local_player->was_waiting = FALSE;
8279 void CheckSingleStepMode_EM(byte action[MAX_PLAYERS], int frame,
8280 boolean any_player_moving,
8281 boolean any_player_snapping,
8282 boolean any_player_dropping)
8284 if (tape.single_step && tape.recording && !tape.pausing)
8285 if (frame == 0 && !any_player_dropping)
8286 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
8288 CheckSaveEngineSnapshot_EM(action, frame, any_player_moving,
8289 any_player_snapping, any_player_dropping);
8292 void CheckSingleStepMode_SP(boolean murphy_is_waiting,
8293 boolean murphy_is_dropping)
8295 if (tape.single_step && tape.recording && !tape.pausing)
8296 if (murphy_is_waiting)
8297 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
8299 CheckSaveEngineSnapshot_SP(murphy_is_waiting, murphy_is_dropping);
8302 void getGraphicSource_SP(struct GraphicInfo_SP *g_sp,
8303 int graphic, int sync_frame, int x, int y)
8305 int frame = getGraphicAnimationFrame(graphic, sync_frame);
8307 getGraphicSource(graphic, frame, &g_sp->bitmap, &g_sp->src_x, &g_sp->src_y);
8310 boolean isNextAnimationFrame_SP(int graphic, int sync_frame)
8312 return (IS_NEXT_FRAME(sync_frame, graphic));
8315 int getGraphicInfo_Delay(int graphic)
8317 return graphic_info[graphic].anim_delay;
8320 void PlayMenuSoundExt(int sound)
8322 if (sound == SND_UNDEFINED)
8325 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8326 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8329 if (IS_LOOP_SOUND(sound))
8330 PlaySoundLoop(sound);
8335 void PlayMenuSound()
8337 PlayMenuSoundExt(menu.sound[game_status]);
8340 void PlayMenuSoundStereo(int sound, int stereo_position)
8342 if (sound == SND_UNDEFINED)
8345 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8346 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8349 if (IS_LOOP_SOUND(sound))
8350 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
8352 PlaySoundStereo(sound, stereo_position);
8355 void PlayMenuSoundIfLoopExt(int sound)
8357 if (sound == SND_UNDEFINED)
8360 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8361 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8364 if (IS_LOOP_SOUND(sound))
8365 PlaySoundLoop(sound);
8368 void PlayMenuSoundIfLoop()
8370 PlayMenuSoundIfLoopExt(menu.sound[game_status]);
8373 void PlayMenuMusicExt(int music)
8375 if (music == MUS_UNDEFINED)
8378 if (!setup.sound_music)
8384 void PlayMenuMusic()
8386 PlayMenuMusicExt(menu.music[game_status]);
8389 void PlaySoundActivating()
8392 PlaySound(SND_MENU_ITEM_ACTIVATING);
8396 void PlaySoundSelecting()
8399 PlaySound(SND_MENU_ITEM_SELECTING);
8403 void ToggleFullscreenOrChangeWindowScalingIfNeeded()
8405 boolean change_fullscreen = (setup.fullscreen !=
8406 video.fullscreen_enabled);
8407 boolean change_window_scaling_percent = (!video.fullscreen_enabled &&
8408 setup.window_scaling_percent !=
8409 video.window_scaling_percent);
8411 if (change_window_scaling_percent && video.fullscreen_enabled)
8414 if (!change_window_scaling_percent && !video.fullscreen_available)
8417 #if defined(TARGET_SDL2)
8418 if (change_window_scaling_percent)
8420 SDLSetWindowScaling(setup.window_scaling_percent);
8424 else if (change_fullscreen)
8426 SDLSetWindowFullscreen(setup.fullscreen);
8428 /* set setup value according to successfully changed fullscreen mode */
8429 setup.fullscreen = video.fullscreen_enabled;
8435 if (change_fullscreen ||
8436 change_window_scaling_percent)
8438 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
8440 /* save backbuffer content which gets lost when toggling fullscreen mode */
8441 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8443 if (change_window_scaling_percent)
8445 /* keep window mode, but change window scaling */
8446 video.fullscreen_enabled = TRUE; /* force new window scaling */
8449 /* toggle fullscreen */
8450 ChangeVideoModeIfNeeded(setup.fullscreen);
8452 /* set setup value according to successfully changed fullscreen mode */
8453 setup.fullscreen = video.fullscreen_enabled;
8455 /* restore backbuffer content from temporary backbuffer backup bitmap */
8456 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8458 FreeBitmap(tmp_backbuffer);
8460 /* update visible window/screen */
8461 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8465 void JoinRectangles(int *x, int *y, int *width, int *height,
8466 int x2, int y2, int width2, int height2)
8468 // do not join with "off-screen" rectangle
8469 if (x2 == -1 || y2 == -1)
8474 *width = MAX(*width, width2);
8475 *height = MAX(*height, height2);
8478 void SetAnimStatus(int anim_status_new)
8480 if (anim_status_new == GAME_MODE_MAIN)
8481 anim_status_new = GAME_MODE_PSEUDO_MAINONLY;
8483 global.anim_status_next = anim_status_new;
8485 // directly set screen modes that are entered without fading
8486 if ((global.anim_status == GAME_MODE_PSEUDO_MAINONLY &&
8487 global.anim_status_next == GAME_MODE_PSEUDO_TYPENAME) ||
8488 (global.anim_status == GAME_MODE_PSEUDO_TYPENAME &&
8489 global.anim_status_next == GAME_MODE_PSEUDO_MAINONLY))
8490 global.anim_status = global.anim_status_next;
8493 void SetGameStatus(int game_status_new)
8495 game_status = game_status_new;
8497 SetAnimStatus(game_status_new);
8500 void SetFontStatus(int game_status_new)
8502 static int last_game_status = -1;
8504 if (game_status_new != -1)
8506 // set game status for font use after storing last game status
8507 last_game_status = game_status;
8508 game_status = game_status_new;
8512 // reset game status after font use from last stored game status
8513 game_status = last_game_status;
8517 void ResetFontStatus()
8522 void ChangeViewportPropertiesIfNeeded()
8524 int gfx_game_mode = game_status;
8525 int gfx_game_mode2 = (game_status == GAME_MODE_EDITOR ? GAME_MODE_DEFAULT :
8527 struct RectWithBorder *vp_window = &viewport.window[gfx_game_mode];
8528 struct RectWithBorder *vp_playfield = &viewport.playfield[gfx_game_mode];
8529 struct RectWithBorder *vp_door_1 = &viewport.door_1[gfx_game_mode];
8530 struct RectWithBorder *vp_door_2 = &viewport.door_2[gfx_game_mode2];
8531 struct RectWithBorder *vp_door_3 = &viewport.door_2[GAME_MODE_EDITOR];
8532 int new_win_xsize = vp_window->width;
8533 int new_win_ysize = vp_window->height;
8534 int border_size = vp_playfield->border_size;
8535 int new_sx = vp_playfield->x + border_size;
8536 int new_sy = vp_playfield->y + border_size;
8537 int new_sxsize = vp_playfield->width - 2 * border_size;
8538 int new_sysize = vp_playfield->height - 2 * border_size;
8539 int new_real_sx = vp_playfield->x;
8540 int new_real_sy = vp_playfield->y;
8541 int new_full_sxsize = vp_playfield->width;
8542 int new_full_sysize = vp_playfield->height;
8543 int new_dx = vp_door_1->x;
8544 int new_dy = vp_door_1->y;
8545 int new_dxsize = vp_door_1->width;
8546 int new_dysize = vp_door_1->height;
8547 int new_vx = vp_door_2->x;
8548 int new_vy = vp_door_2->y;
8549 int new_vxsize = vp_door_2->width;
8550 int new_vysize = vp_door_2->height;
8551 int new_ex = vp_door_3->x;
8552 int new_ey = vp_door_3->y;
8553 int new_exsize = vp_door_3->width;
8554 int new_eysize = vp_door_3->height;
8555 int new_tilesize_var =
8556 (setup.small_game_graphics ? MINI_TILESIZE : game.tile_size);
8558 int tilesize = (gfx_game_mode == GAME_MODE_PLAYING ? new_tilesize_var :
8559 gfx_game_mode == GAME_MODE_EDITOR ? MINI_TILESIZE : TILESIZE);
8560 int new_scr_fieldx = new_sxsize / tilesize;
8561 int new_scr_fieldy = new_sysize / tilesize;
8562 int new_scr_fieldx_buffers = new_sxsize / new_tilesize_var;
8563 int new_scr_fieldy_buffers = new_sysize / new_tilesize_var;
8564 boolean init_gfx_buffers = FALSE;
8565 boolean init_video_buffer = FALSE;
8566 boolean init_gadgets_and_anims = FALSE;
8567 boolean init_em_graphics = FALSE;
8569 if (new_win_xsize != WIN_XSIZE ||
8570 new_win_ysize != WIN_YSIZE)
8572 WIN_XSIZE = new_win_xsize;
8573 WIN_YSIZE = new_win_ysize;
8575 init_video_buffer = TRUE;
8576 init_gfx_buffers = TRUE;
8577 init_gadgets_and_anims = TRUE;
8579 // printf("::: video: init_video_buffer, init_gfx_buffers\n");
8582 if (new_scr_fieldx != SCR_FIELDX ||
8583 new_scr_fieldy != SCR_FIELDY)
8585 /* this always toggles between MAIN and GAME when using small tile size */
8587 SCR_FIELDX = new_scr_fieldx;
8588 SCR_FIELDY = new_scr_fieldy;
8590 // printf("::: new_scr_fieldx != SCR_FIELDX ...\n");
8601 new_sxsize != SXSIZE ||
8602 new_sysize != SYSIZE ||
8603 new_dxsize != DXSIZE ||
8604 new_dysize != DYSIZE ||
8605 new_vxsize != VXSIZE ||
8606 new_vysize != VYSIZE ||
8607 new_exsize != EXSIZE ||
8608 new_eysize != EYSIZE ||
8609 new_real_sx != REAL_SX ||
8610 new_real_sy != REAL_SY ||
8611 new_full_sxsize != FULL_SXSIZE ||
8612 new_full_sysize != FULL_SYSIZE ||
8613 new_tilesize_var != TILESIZE_VAR
8616 // ------------------------------------------------------------------------
8617 // determine next fading area for changed viewport definitions
8618 // ------------------------------------------------------------------------
8620 // start with current playfield area (default fading area)
8623 FADE_SXSIZE = FULL_SXSIZE;
8624 FADE_SYSIZE = FULL_SYSIZE;
8626 // add new playfield area if position or size has changed
8627 if (new_real_sx != REAL_SX || new_real_sy != REAL_SY ||
8628 new_full_sxsize != FULL_SXSIZE || new_full_sysize != FULL_SYSIZE)
8630 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
8631 new_real_sx, new_real_sy, new_full_sxsize,new_full_sysize);
8634 // add current and new door 1 area if position or size has changed
8635 if (new_dx != DX || new_dy != DY ||
8636 new_dxsize != DXSIZE || new_dysize != DYSIZE)
8638 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
8639 DX, DY, DXSIZE, DYSIZE);
8640 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
8641 new_dx, new_dy, new_dxsize, new_dysize);
8644 // add current and new door 2 area if position or size has changed
8645 if (new_dx != VX || new_dy != VY ||
8646 new_dxsize != VXSIZE || new_dysize != VYSIZE)
8648 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
8649 VX, VY, VXSIZE, VYSIZE);
8650 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
8651 new_vx, new_vy, new_vxsize, new_vysize);
8654 // ------------------------------------------------------------------------
8655 // handle changed tile size
8656 // ------------------------------------------------------------------------
8658 if (new_tilesize_var != TILESIZE_VAR)
8660 // printf("::: new_tilesize_var != TILESIZE_VAR\n");
8662 // changing tile size invalidates scroll values of engine snapshots
8663 FreeEngineSnapshotSingle();
8665 // changing tile size requires update of graphic mapping for EM engine
8666 init_em_graphics = TRUE;
8677 SXSIZE = new_sxsize;
8678 SYSIZE = new_sysize;
8679 DXSIZE = new_dxsize;
8680 DYSIZE = new_dysize;
8681 VXSIZE = new_vxsize;
8682 VYSIZE = new_vysize;
8683 EXSIZE = new_exsize;
8684 EYSIZE = new_eysize;
8685 REAL_SX = new_real_sx;
8686 REAL_SY = new_real_sy;
8687 FULL_SXSIZE = new_full_sxsize;
8688 FULL_SYSIZE = new_full_sysize;
8689 TILESIZE_VAR = new_tilesize_var;
8691 init_gfx_buffers = TRUE;
8692 init_gadgets_and_anims = TRUE;
8694 // printf("::: viewports: init_gfx_buffers\n");
8695 // printf("::: viewports: init_gadgets_and_anims\n");
8698 if (init_gfx_buffers)
8700 // printf("::: init_gfx_buffers\n");
8702 SCR_FIELDX = new_scr_fieldx_buffers;
8703 SCR_FIELDY = new_scr_fieldy_buffers;
8707 SCR_FIELDX = new_scr_fieldx;
8708 SCR_FIELDY = new_scr_fieldy;
8710 SetDrawDeactivationMask(REDRAW_NONE);
8711 SetDrawBackgroundMask(REDRAW_FIELD);
8714 if (init_video_buffer)
8716 // printf("::: init_video_buffer\n");
8718 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
8719 InitImageTextures();
8722 if (init_gadgets_and_anims)
8724 // printf("::: init_gadgets_and_anims\n");
8727 InitGlobalAnimations();
8730 if (init_em_graphics)
8732 InitGraphicInfo_EM();