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);
2327 else if (IS_BLOCKED(lx, ly))
2332 boolean cut_mode = NO_CUTTING;
2333 int element_old, content_old;
2335 Blocked2Moving(lx, ly, &oldx, &oldy);
2338 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
2339 MovDir[oldx][oldy] == MV_RIGHT);
2341 element_old = Feld[oldx][oldy];
2342 content_old = Store[oldx][oldy];
2344 if (element_old == EL_QUICKSAND_EMPTYING ||
2345 element_old == EL_QUICKSAND_FAST_EMPTYING ||
2346 element_old == EL_MAGIC_WALL_EMPTYING ||
2347 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
2348 element_old == EL_DC_MAGIC_WALL_EMPTYING ||
2349 element_old == EL_AMOEBA_DROPPING)
2350 cut_mode = CUT_ABOVE;
2352 DrawScreenElement(x, y, EL_EMPTY);
2355 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
2357 else if (cut_mode == NO_CUTTING)
2358 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
2361 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
2364 else if (IS_DRAWABLE(element))
2365 DrawScreenElement(x, y, element);
2367 DrawScreenElement(x, y, EL_EMPTY);
2370 void DrawLevelField(int x, int y)
2372 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2373 DrawScreenField(SCREENX(x), SCREENY(y));
2374 else if (IS_MOVING(x, y))
2378 Moving2Blocked(x, y, &newx, &newy);
2379 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
2380 DrawScreenField(SCREENX(newx), SCREENY(newy));
2382 else if (IS_BLOCKED(x, y))
2386 Blocked2Moving(x, y, &oldx, &oldy);
2387 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
2388 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
2392 void DrawSizedElement(int x, int y, int element, int tilesize)
2396 graphic = el2edimg(element);
2397 DrawSizedGraphic(x, y, graphic, 0, tilesize);
2400 void DrawMiniElement(int x, int y, int element)
2404 graphic = el2edimg(element);
2405 DrawMiniGraphic(x, y, graphic);
2408 void DrawSizedElementOrWall(int sx, int sy, int scroll_x, int scroll_y,
2411 int x = sx + scroll_x, y = sy + scroll_y;
2413 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
2414 DrawSizedElement(sx, sy, EL_EMPTY, tilesize);
2415 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
2416 DrawSizedElement(sx, sy, Feld[x][y], tilesize);
2418 DrawSizedGraphic(sx, sy, el2edimg(getBorderElement(x, y)), 0, tilesize);
2421 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
2423 int x = sx + scroll_x, y = sy + scroll_y;
2425 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
2426 DrawMiniElement(sx, sy, EL_EMPTY);
2427 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
2428 DrawMiniElement(sx, sy, Feld[x][y]);
2430 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
2433 void DrawEnvelopeBackgroundTiles(int graphic, int startx, int starty,
2434 int x, int y, int xsize, int ysize,
2435 int tile_width, int tile_height)
2439 int dst_x = startx + x * tile_width;
2440 int dst_y = starty + y * tile_height;
2441 int width = graphic_info[graphic].width;
2442 int height = graphic_info[graphic].height;
2443 int inner_width_raw = MAX(width - 2 * tile_width, tile_width);
2444 int inner_height_raw = MAX(height - 2 * tile_height, tile_height);
2445 int inner_width = inner_width_raw - (inner_width_raw % tile_width);
2446 int inner_height = inner_height_raw - (inner_height_raw % tile_height);
2447 int inner_sx = (width >= 3 * tile_width ? tile_width : 0);
2448 int inner_sy = (height >= 3 * tile_height ? tile_height : 0);
2449 boolean draw_masked = graphic_info[graphic].draw_masked;
2451 getFixedGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
2453 if (src_bitmap == NULL || width < tile_width || height < tile_height)
2455 ClearRectangle(drawto, dst_x, dst_y, tile_width, tile_height);
2459 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - tile_width :
2460 inner_sx + (x - 1) * tile_width % inner_width);
2461 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - tile_height :
2462 inner_sy + (y - 1) * tile_height % inner_height);
2465 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
2468 BlitBitmap(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
2472 void DrawEnvelopeBackground(int graphic, int startx, int starty,
2473 int x, int y, int xsize, int ysize, int font_nr)
2475 int font_width = getFontWidth(font_nr);
2476 int font_height = getFontHeight(font_nr);
2478 DrawEnvelopeBackgroundTiles(graphic, startx, starty, x, y, xsize, ysize,
2479 font_width, font_height);
2482 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
2484 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2485 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2486 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2487 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2488 boolean no_delay = (tape.warp_forward);
2489 unsigned int anim_delay = 0;
2490 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
2491 int anim_delay_value = (no_delay ? 0 : frame_delay_value) / 2;
2492 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
2493 int font_width = getFontWidth(font_nr);
2494 int font_height = getFontHeight(font_nr);
2495 int max_xsize = level.envelope[envelope_nr].xsize;
2496 int max_ysize = level.envelope[envelope_nr].ysize;
2497 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
2498 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
2499 int xend = max_xsize;
2500 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
2501 int xstep = (xstart < xend ? 1 : 0);
2502 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2504 int end = MAX(xend - xstart, yend - ystart);
2507 for (i = start; i <= end; i++)
2509 int last_frame = end; // last frame of this "for" loop
2510 int x = xstart + i * xstep;
2511 int y = ystart + i * ystep;
2512 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2513 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2514 int sx = SX + (SXSIZE - xsize * font_width) / 2;
2515 int sy = SY + (SYSIZE - ysize * font_height) / 2;
2518 SetDrawtoField(DRAW_TO_FIELDBUFFER);
2520 BlitScreenToBitmap(backbuffer);
2522 SetDrawtoField(DRAW_TO_BACKBUFFER);
2524 for (yy = 0; yy < ysize; yy++)
2525 for (xx = 0; xx < xsize; xx++)
2526 DrawEnvelopeBackground(graphic, sx, sy, xx, yy, xsize, ysize, font_nr);
2528 DrawTextBuffer(sx + font_width, sy + font_height,
2529 level.envelope[envelope_nr].text, font_nr, max_xsize,
2530 xsize - 2, ysize - 2, 0, mask_mode,
2531 level.envelope[envelope_nr].autowrap,
2532 level.envelope[envelope_nr].centered, FALSE);
2534 redraw_mask |= REDRAW_FIELD;
2537 SkipUntilDelayReached(&anim_delay, anim_delay_value, &i, last_frame);
2541 void ShowEnvelope(int envelope_nr)
2543 int element = EL_ENVELOPE_1 + envelope_nr;
2544 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2545 int sound_opening = element_info[element].sound[ACTION_OPENING];
2546 int sound_closing = element_info[element].sound[ACTION_CLOSING];
2547 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2548 boolean no_delay = (tape.warp_forward);
2549 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
2550 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
2551 int anim_mode = graphic_info[graphic].anim_mode;
2552 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2553 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2555 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
2557 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2559 if (anim_mode == ANIM_DEFAULT)
2560 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
2562 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
2565 Delay(wait_delay_value);
2567 WaitForEventToContinue();
2569 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2571 if (anim_mode != ANIM_NONE)
2572 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
2574 if (anim_mode == ANIM_DEFAULT)
2575 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
2577 game.envelope_active = FALSE;
2579 SetDrawtoField(DRAW_TO_FIELDBUFFER);
2581 redraw_mask |= REDRAW_FIELD;
2585 static void setRequestBasePosition(int *x, int *y)
2587 int sx_base, sy_base;
2589 if (request.x != -1)
2590 sx_base = request.x;
2591 else if (request.align == ALIGN_LEFT)
2593 else if (request.align == ALIGN_RIGHT)
2594 sx_base = SX + SXSIZE;
2596 sx_base = SX + SXSIZE / 2;
2598 if (request.y != -1)
2599 sy_base = request.y;
2600 else if (request.valign == VALIGN_TOP)
2602 else if (request.valign == VALIGN_BOTTOM)
2603 sy_base = SY + SYSIZE;
2605 sy_base = SY + SYSIZE / 2;
2611 static void setRequestPositionExt(int *x, int *y, int width, int height,
2612 boolean add_border_size)
2614 int border_size = request.border_size;
2615 int sx_base, sy_base;
2618 setRequestBasePosition(&sx_base, &sy_base);
2620 if (request.align == ALIGN_LEFT)
2622 else if (request.align == ALIGN_RIGHT)
2623 sx = sx_base - width;
2625 sx = sx_base - width / 2;
2627 if (request.valign == VALIGN_TOP)
2629 else if (request.valign == VALIGN_BOTTOM)
2630 sy = sy_base - height;
2632 sy = sy_base - height / 2;
2634 sx = MAX(0, MIN(sx, WIN_XSIZE - width));
2635 sy = MAX(0, MIN(sy, WIN_YSIZE - height));
2637 if (add_border_size)
2647 static void setRequestPosition(int *x, int *y, boolean add_border_size)
2649 setRequestPositionExt(x, y, request.width, request.height, add_border_size);
2652 void DrawEnvelopeRequest(char *text)
2654 char *text_final = text;
2655 char *text_door_style = NULL;
2656 int graphic = IMG_BACKGROUND_REQUEST;
2657 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2658 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2659 int font_nr = FONT_REQUEST;
2660 int font_width = getFontWidth(font_nr);
2661 int font_height = getFontHeight(font_nr);
2662 int border_size = request.border_size;
2663 int line_spacing = request.line_spacing;
2664 int line_height = font_height + line_spacing;
2665 int max_text_width = request.width - 2 * border_size;
2666 int max_text_height = request.height - 2 * border_size;
2667 int line_length = max_text_width / font_width;
2668 int max_lines = max_text_height / line_height;
2669 int text_width = line_length * font_width;
2670 int width = request.width;
2671 int height = request.height;
2672 int tile_size = MAX(request.step_offset, 1);
2673 int x_steps = width / tile_size;
2674 int y_steps = height / tile_size;
2675 int sx_offset = border_size;
2676 int sy_offset = border_size;
2680 if (request.centered)
2681 sx_offset = (request.width - text_width) / 2;
2683 if (request.wrap_single_words && !request.autowrap)
2685 char *src_text_ptr, *dst_text_ptr;
2687 text_door_style = checked_malloc(2 * strlen(text) + 1);
2689 src_text_ptr = text;
2690 dst_text_ptr = text_door_style;
2692 while (*src_text_ptr)
2694 if (*src_text_ptr == ' ' ||
2695 *src_text_ptr == '?' ||
2696 *src_text_ptr == '!')
2697 *dst_text_ptr++ = '\n';
2699 if (*src_text_ptr != ' ')
2700 *dst_text_ptr++ = *src_text_ptr;
2705 *dst_text_ptr = '\0';
2707 text_final = text_door_style;
2710 setRequestPosition(&sx, &sy, FALSE);
2712 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
2714 for (y = 0; y < y_steps; y++)
2715 for (x = 0; x < x_steps; x++)
2716 DrawEnvelopeBackgroundTiles(graphic, sx, sy,
2717 x, y, x_steps, y_steps,
2718 tile_size, tile_size);
2720 /* force DOOR font inside door area */
2721 SetFontStatus(GAME_MODE_PSEUDO_DOOR);
2723 DrawTextBuffer(sx + sx_offset, sy + sy_offset, text_final, font_nr,
2724 line_length, -1, max_lines, line_spacing, mask_mode,
2725 request.autowrap, request.centered, FALSE);
2729 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2730 RedrawGadget(tool_gadget[i]);
2732 // store readily prepared envelope request for later use when animating
2733 BlitBitmap(backbuffer, bitmap_db_store_2, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2735 if (text_door_style)
2736 free(text_door_style);
2739 void AnimateEnvelopeRequest(int anim_mode, int action)
2741 int graphic = IMG_BACKGROUND_REQUEST;
2742 boolean draw_masked = graphic_info[graphic].draw_masked;
2743 int delay_value_normal = request.step_delay;
2744 int delay_value_fast = delay_value_normal / 2;
2745 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2746 boolean no_delay = (tape.warp_forward);
2747 int delay_value = (ffwd_delay ? delay_value_fast : delay_value_normal);
2748 int anim_delay_value = (no_delay ? 0 : delay_value + 500 * 0) / 2;
2749 unsigned int anim_delay = 0;
2751 int tile_size = MAX(request.step_offset, 1);
2752 int max_xsize = request.width / tile_size;
2753 int max_ysize = request.height / tile_size;
2754 int max_xsize_inner = max_xsize - 2;
2755 int max_ysize_inner = max_ysize - 2;
2757 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize_inner : 0);
2758 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize_inner : 0);
2759 int xend = max_xsize_inner;
2760 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize_inner : 0);
2761 int xstep = (xstart < xend ? 1 : 0);
2762 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2764 int end = MAX(xend - xstart, yend - ystart);
2767 if (setup.quick_doors)
2774 for (i = start; i <= end; i++)
2776 int last_frame = end; // last frame of this "for" loop
2777 int x = xstart + i * xstep;
2778 int y = ystart + i * ystep;
2779 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2780 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2781 int xsize_size_left = (xsize - 1) * tile_size;
2782 int ysize_size_top = (ysize - 1) * tile_size;
2783 int max_xsize_pos = (max_xsize - 1) * tile_size;
2784 int max_ysize_pos = (max_ysize - 1) * tile_size;
2785 int width = xsize * tile_size;
2786 int height = ysize * tile_size;
2791 setRequestPosition(&src_x, &src_y, FALSE);
2792 setRequestPositionExt(&dst_x, &dst_y, width, height, FALSE);
2794 BlitBitmap(bitmap_db_store_1, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2796 for (yy = 0; yy < 2; yy++)
2798 for (xx = 0; xx < 2; xx++)
2800 int src_xx = src_x + xx * max_xsize_pos;
2801 int src_yy = src_y + yy * max_ysize_pos;
2802 int dst_xx = dst_x + xx * xsize_size_left;
2803 int dst_yy = dst_y + yy * ysize_size_top;
2804 int xx_size = (xx ? tile_size : xsize_size_left);
2805 int yy_size = (yy ? tile_size : ysize_size_top);
2808 BlitBitmapMasked(bitmap_db_store_2, backbuffer,
2809 src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
2811 BlitBitmap(bitmap_db_store_2, backbuffer,
2812 src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
2816 redraw_mask |= REDRAW_FIELD;
2820 SkipUntilDelayReached(&anim_delay, anim_delay_value, &i, last_frame);
2824 void ShowEnvelopeRequest(char *text, unsigned int req_state, int action)
2826 int graphic = IMG_BACKGROUND_REQUEST;
2827 int sound_opening = SND_REQUEST_OPENING;
2828 int sound_closing = SND_REQUEST_CLOSING;
2829 int anim_mode_1 = request.anim_mode; /* (higher priority) */
2830 int anim_mode_2 = graphic_info[graphic].anim_mode; /* (lower priority) */
2831 int anim_mode = (anim_mode_1 != ANIM_DEFAULT ? anim_mode_1 : anim_mode_2);
2832 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2833 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2835 if (game_status == GAME_MODE_PLAYING)
2836 BlitScreenToBitmap(backbuffer);
2838 SetDrawtoField(DRAW_TO_BACKBUFFER);
2840 // SetDrawBackgroundMask(REDRAW_NONE);
2842 if (action == ACTION_OPENING)
2844 BlitBitmap(backbuffer, bitmap_db_store_1, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2846 if (req_state & REQ_ASK)
2848 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2849 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2851 else if (req_state & REQ_CONFIRM)
2853 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2855 else if (req_state & REQ_PLAYER)
2857 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2858 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2859 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2860 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2863 DrawEnvelopeRequest(text);
2866 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
2868 if (action == ACTION_OPENING)
2870 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2872 if (anim_mode == ANIM_DEFAULT)
2873 AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_OPENING);
2875 AnimateEnvelopeRequest(main_anim_mode, ACTION_OPENING);
2879 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2881 if (anim_mode != ANIM_NONE)
2882 AnimateEnvelopeRequest(main_anim_mode, ACTION_CLOSING);
2884 if (anim_mode == ANIM_DEFAULT)
2885 AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_CLOSING);
2888 game.envelope_active = FALSE;
2890 if (action == ACTION_CLOSING)
2891 BlitBitmap(bitmap_db_store_1, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2893 // SetDrawBackgroundMask(last_draw_background_mask);
2895 redraw_mask |= REDRAW_FIELD;
2899 if (action == ACTION_CLOSING &&
2900 game_status == GAME_MODE_PLAYING &&
2901 level.game_engine_type == GAME_ENGINE_TYPE_RND)
2902 SetDrawtoField(DRAW_TO_FIELDBUFFER);
2905 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
2909 int graphic = el2preimg(element);
2911 getSizedGraphicSource(graphic, 0, tilesize, &src_bitmap, &src_x, &src_y);
2912 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
2915 void DrawLevel(int draw_background_mask)
2919 SetMainBackgroundImage(IMG_BACKGROUND_PLAYING);
2920 SetDrawBackgroundMask(draw_background_mask);
2924 for (x = BX1; x <= BX2; x++)
2925 for (y = BY1; y <= BY2; y++)
2926 DrawScreenField(x, y);
2928 redraw_mask |= REDRAW_FIELD;
2931 void DrawSizedLevel(int size_x, int size_y, int scroll_x, int scroll_y,
2936 for (x = 0; x < size_x; x++)
2937 for (y = 0; y < size_y; y++)
2938 DrawSizedElementOrWall(x, y, scroll_x, scroll_y, tilesize);
2940 redraw_mask |= REDRAW_FIELD;
2943 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
2947 for (x = 0; x < size_x; x++)
2948 for (y = 0; y < size_y; y++)
2949 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
2951 redraw_mask |= REDRAW_FIELD;
2954 static void DrawPreviewLevelPlayfieldExt(int from_x, int from_y)
2956 boolean show_level_border = (BorderElement != EL_EMPTY);
2957 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2958 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2959 int tile_size = preview.tile_size;
2960 int preview_width = preview.xsize * tile_size;
2961 int preview_height = preview.ysize * tile_size;
2962 int real_preview_xsize = MIN(level_xsize, preview.xsize);
2963 int real_preview_ysize = MIN(level_ysize, preview.ysize);
2964 int real_preview_width = real_preview_xsize * tile_size;
2965 int real_preview_height = real_preview_ysize * tile_size;
2966 int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
2967 int dst_y = SY + ALIGNED_YPOS(preview.y, preview_height, preview.valign);
2970 if (!IN_GFX_FIELD_FULL(dst_x, dst_y + preview_height - 1))
2973 DrawBackground(dst_x, dst_y, preview_width, preview_height);
2975 dst_x += (preview_width - real_preview_width) / 2;
2976 dst_y += (preview_height - real_preview_height) / 2;
2978 for (x = 0; x < real_preview_xsize; x++)
2980 for (y = 0; y < real_preview_ysize; y++)
2982 int lx = from_x + x + (show_level_border ? -1 : 0);
2983 int ly = from_y + y + (show_level_border ? -1 : 0);
2984 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
2985 getBorderElement(lx, ly));
2987 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
2988 element, tile_size);
2992 redraw_mask |= REDRAW_FIELD;
2995 #define MICROLABEL_EMPTY 0
2996 #define MICROLABEL_LEVEL_NAME 1
2997 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
2998 #define MICROLABEL_LEVEL_AUTHOR 3
2999 #define MICROLABEL_IMPORTED_FROM_HEAD 4
3000 #define MICROLABEL_IMPORTED_FROM 5
3001 #define MICROLABEL_IMPORTED_BY_HEAD 6
3002 #define MICROLABEL_IMPORTED_BY 7
3004 static int getMaxTextLength(struct TextPosInfo *pos, int font_nr)
3006 int max_text_width = SXSIZE;
3007 int font_width = getFontWidth(font_nr);
3009 if (pos->align == ALIGN_CENTER)
3010 max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
3011 else if (pos->align == ALIGN_RIGHT)
3012 max_text_width = pos->x;
3014 max_text_width = SXSIZE - pos->x;
3016 return max_text_width / font_width;
3019 static void DrawPreviewLevelLabelExt(int mode)
3021 struct TextPosInfo *pos = &menu.main.text.level_info_2;
3022 char label_text[MAX_OUTPUT_LINESIZE + 1];
3023 int max_len_label_text;
3024 int font_nr = pos->font;
3027 if (!IN_GFX_FIELD_FULL(pos->x, pos->y + getFontHeight(pos->font)))
3030 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
3031 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
3032 mode == MICROLABEL_IMPORTED_BY_HEAD)
3033 font_nr = pos->font_alt;
3035 max_len_label_text = getMaxTextLength(pos, font_nr);
3037 if (pos->size != -1)
3038 max_len_label_text = pos->size;
3040 for (i = 0; i < max_len_label_text; i++)
3041 label_text[i] = ' ';
3042 label_text[max_len_label_text] = '\0';
3044 if (strlen(label_text) > 0)
3045 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
3048 (mode == MICROLABEL_LEVEL_NAME ? level.name :
3049 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
3050 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
3051 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
3052 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
3053 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
3054 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
3055 max_len_label_text);
3056 label_text[max_len_label_text] = '\0';
3058 if (strlen(label_text) > 0)
3059 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
3061 redraw_mask |= REDRAW_FIELD;
3064 static void DrawPreviewLevelExt(boolean restart)
3066 static unsigned int scroll_delay = 0;
3067 static unsigned int label_delay = 0;
3068 static int from_x, from_y, scroll_direction;
3069 static int label_state, label_counter;
3070 unsigned int scroll_delay_value = preview.step_delay;
3071 boolean show_level_border = (BorderElement != EL_EMPTY);
3072 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
3073 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
3080 if (preview.anim_mode == ANIM_CENTERED)
3082 if (level_xsize > preview.xsize)
3083 from_x = (level_xsize - preview.xsize) / 2;
3084 if (level_ysize > preview.ysize)
3085 from_y = (level_ysize - preview.ysize) / 2;
3088 from_x += preview.xoffset;
3089 from_y += preview.yoffset;
3091 scroll_direction = MV_RIGHT;
3095 DrawPreviewLevelPlayfieldExt(from_x, from_y);
3096 DrawPreviewLevelLabelExt(label_state);
3098 /* initialize delay counters */
3099 DelayReached(&scroll_delay, 0);
3100 DelayReached(&label_delay, 0);
3102 if (leveldir_current->name)
3104 struct TextPosInfo *pos = &menu.main.text.level_info_1;
3105 char label_text[MAX_OUTPUT_LINESIZE + 1];
3106 int font_nr = pos->font;
3107 int max_len_label_text = getMaxTextLength(pos, font_nr);
3109 if (pos->size != -1)
3110 max_len_label_text = pos->size;
3112 strncpy(label_text, leveldir_current->name, max_len_label_text);
3113 label_text[max_len_label_text] = '\0';
3115 if (IN_GFX_FIELD_FULL(pos->x, pos->y + getFontHeight(pos->font)))
3116 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
3122 /* scroll preview level, if needed */
3123 if (preview.anim_mode != ANIM_NONE &&
3124 (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
3125 DelayReached(&scroll_delay, scroll_delay_value))
3127 switch (scroll_direction)
3132 from_x -= preview.step_offset;
3133 from_x = (from_x < 0 ? 0 : from_x);
3136 scroll_direction = MV_UP;
3140 if (from_x < level_xsize - preview.xsize)
3142 from_x += preview.step_offset;
3143 from_x = (from_x > level_xsize - preview.xsize ?
3144 level_xsize - preview.xsize : from_x);
3147 scroll_direction = MV_DOWN;
3153 from_y -= preview.step_offset;
3154 from_y = (from_y < 0 ? 0 : from_y);
3157 scroll_direction = MV_RIGHT;
3161 if (from_y < level_ysize - preview.ysize)
3163 from_y += preview.step_offset;
3164 from_y = (from_y > level_ysize - preview.ysize ?
3165 level_ysize - preview.ysize : from_y);
3168 scroll_direction = MV_LEFT;
3175 DrawPreviewLevelPlayfieldExt(from_x, from_y);
3178 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
3179 /* redraw micro level label, if needed */
3180 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
3181 !strEqual(level.author, ANONYMOUS_NAME) &&
3182 !strEqual(level.author, leveldir_current->name) &&
3183 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
3185 int max_label_counter = 23;
3187 if (leveldir_current->imported_from != NULL &&
3188 strlen(leveldir_current->imported_from) > 0)
3189 max_label_counter += 14;
3190 if (leveldir_current->imported_by != NULL &&
3191 strlen(leveldir_current->imported_by) > 0)
3192 max_label_counter += 14;
3194 label_counter = (label_counter + 1) % max_label_counter;
3195 label_state = (label_counter >= 0 && label_counter <= 7 ?
3196 MICROLABEL_LEVEL_NAME :
3197 label_counter >= 9 && label_counter <= 12 ?
3198 MICROLABEL_LEVEL_AUTHOR_HEAD :
3199 label_counter >= 14 && label_counter <= 21 ?
3200 MICROLABEL_LEVEL_AUTHOR :
3201 label_counter >= 23 && label_counter <= 26 ?
3202 MICROLABEL_IMPORTED_FROM_HEAD :
3203 label_counter >= 28 && label_counter <= 35 ?
3204 MICROLABEL_IMPORTED_FROM :
3205 label_counter >= 37 && label_counter <= 40 ?
3206 MICROLABEL_IMPORTED_BY_HEAD :
3207 label_counter >= 42 && label_counter <= 49 ?
3208 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
3210 if (leveldir_current->imported_from == NULL &&
3211 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
3212 label_state == MICROLABEL_IMPORTED_FROM))
3213 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
3214 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
3216 DrawPreviewLevelLabelExt(label_state);
3220 void DrawPreviewLevelInitial()
3222 DrawPreviewLevelExt(TRUE);
3225 void DrawPreviewLevelAnimation()
3227 DrawPreviewLevelExt(FALSE);
3230 inline static void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
3231 int graphic, int sync_frame,
3234 int frame = getGraphicAnimationFrame(graphic, sync_frame);
3236 if (mask_mode == USE_MASKING)
3237 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
3239 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
3242 void DrawFixedGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
3243 int graphic, int sync_frame, int mask_mode)
3245 int frame = getGraphicAnimationFrame(graphic, sync_frame);
3247 if (mask_mode == USE_MASKING)
3248 DrawFixedGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
3250 DrawFixedGraphicExt(dst_bitmap, x, y, graphic, frame);
3253 inline static void DrawGraphicAnimation(int x, int y, int graphic)
3255 int lx = LEVELX(x), ly = LEVELY(y);
3257 if (!IN_SCR_FIELD(x, y))
3260 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
3261 graphic, GfxFrame[lx][ly], NO_MASKING);
3263 MarkTileDirty(x, y);
3266 void DrawFixedGraphicAnimation(int x, int y, int graphic)
3268 int lx = LEVELX(x), ly = LEVELY(y);
3270 if (!IN_SCR_FIELD(x, y))
3273 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
3274 graphic, GfxFrame[lx][ly], NO_MASKING);
3275 MarkTileDirty(x, y);
3278 void DrawLevelGraphicAnimation(int x, int y, int graphic)
3280 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
3283 void DrawLevelElementAnimation(int x, int y, int element)
3285 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
3287 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
3290 void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
3292 int sx = SCREENX(x), sy = SCREENY(y);
3294 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
3297 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
3300 DrawGraphicAnimation(sx, sy, graphic);
3303 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
3304 DrawLevelFieldCrumbled(x, y);
3306 if (GFX_CRUMBLED(Feld[x][y]))
3307 DrawLevelFieldCrumbled(x, y);
3311 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
3313 int sx = SCREENX(x), sy = SCREENY(y);
3316 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
3319 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
3321 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
3324 DrawGraphicAnimation(sx, sy, graphic);
3326 if (GFX_CRUMBLED(element))
3327 DrawLevelFieldCrumbled(x, y);
3330 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
3332 if (player->use_murphy)
3334 /* this works only because currently only one player can be "murphy" ... */
3335 static int last_horizontal_dir = MV_LEFT;
3336 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
3338 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3339 last_horizontal_dir = move_dir;
3341 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
3343 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
3345 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
3351 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
3354 static boolean equalGraphics(int graphic1, int graphic2)
3356 struct GraphicInfo *g1 = &graphic_info[graphic1];
3357 struct GraphicInfo *g2 = &graphic_info[graphic2];
3359 return (g1->bitmap == g2->bitmap &&
3360 g1->src_x == g2->src_x &&
3361 g1->src_y == g2->src_y &&
3362 g1->anim_frames == g2->anim_frames &&
3363 g1->anim_delay == g2->anim_delay &&
3364 g1->anim_mode == g2->anim_mode);
3367 void DrawAllPlayers()
3371 for (i = 0; i < MAX_PLAYERS; i++)
3372 if (stored_player[i].active)
3373 DrawPlayer(&stored_player[i]);
3376 void DrawPlayerField(int x, int y)
3378 if (!IS_PLAYER(x, y))
3381 DrawPlayer(PLAYERINFO(x, y));
3384 #define DRAW_PLAYER_OVER_PUSHED_ELEMENT 1
3386 void DrawPlayer(struct PlayerInfo *player)
3388 int jx = player->jx;
3389 int jy = player->jy;
3390 int move_dir = player->MovDir;
3391 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
3392 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
3393 int last_jx = (player->is_moving ? jx - dx : jx);
3394 int last_jy = (player->is_moving ? jy - dy : jy);
3395 int next_jx = jx + dx;
3396 int next_jy = jy + dy;
3397 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
3398 boolean player_is_opaque = FALSE;
3399 int sx = SCREENX(jx), sy = SCREENY(jy);
3400 int sxx = 0, syy = 0;
3401 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
3403 int action = ACTION_DEFAULT;
3404 int last_player_graphic = getPlayerGraphic(player, move_dir);
3405 int last_player_frame = player->Frame;
3408 /* GfxElement[][] is set to the element the player is digging or collecting;
3409 remove also for off-screen player if the player is not moving anymore */
3410 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
3411 GfxElement[jx][jy] = EL_UNDEFINED;
3413 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
3417 if (!IN_LEV_FIELD(jx, jy))
3419 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
3420 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
3421 printf("DrawPlayerField(): This should never happen!\n");
3426 if (element == EL_EXPLOSION)
3429 action = (player->is_pushing ? ACTION_PUSHING :
3430 player->is_digging ? ACTION_DIGGING :
3431 player->is_collecting ? ACTION_COLLECTING :
3432 player->is_moving ? ACTION_MOVING :
3433 player->is_snapping ? ACTION_SNAPPING :
3434 player->is_dropping ? ACTION_DROPPING :
3435 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
3437 if (player->is_waiting)
3438 move_dir = player->dir_waiting;
3440 InitPlayerGfxAnimation(player, action, move_dir);
3442 /* ----------------------------------------------------------------------- */
3443 /* draw things in the field the player is leaving, if needed */
3444 /* ----------------------------------------------------------------------- */
3446 if (player->is_moving)
3448 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
3450 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
3452 if (last_element == EL_DYNAMITE_ACTIVE ||
3453 last_element == EL_EM_DYNAMITE_ACTIVE ||
3454 last_element == EL_SP_DISK_RED_ACTIVE)
3455 DrawDynamite(last_jx, last_jy);
3457 DrawLevelFieldThruMask(last_jx, last_jy);
3459 else if (last_element == EL_DYNAMITE_ACTIVE ||
3460 last_element == EL_EM_DYNAMITE_ACTIVE ||
3461 last_element == EL_SP_DISK_RED_ACTIVE)
3462 DrawDynamite(last_jx, last_jy);
3464 /* !!! this is not enough to prevent flickering of players which are
3465 moving next to each others without a free tile between them -- this
3466 can only be solved by drawing all players layer by layer (first the
3467 background, then the foreground etc.) !!! => TODO */
3468 else if (!IS_PLAYER(last_jx, last_jy))
3469 DrawLevelField(last_jx, last_jy);
3472 DrawLevelField(last_jx, last_jy);
3475 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
3476 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
3479 if (!IN_SCR_FIELD(sx, sy))
3482 /* ----------------------------------------------------------------------- */
3483 /* draw things behind the player, if needed */
3484 /* ----------------------------------------------------------------------- */
3487 DrawLevelElement(jx, jy, Back[jx][jy]);
3488 else if (IS_ACTIVE_BOMB(element))
3489 DrawLevelElement(jx, jy, EL_EMPTY);
3492 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
3494 int old_element = GfxElement[jx][jy];
3495 int old_graphic = el_act_dir2img(old_element, action, move_dir);
3496 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
3498 if (GFX_CRUMBLED(old_element))
3499 DrawLevelFieldCrumbledDigging(jx, jy, move_dir, player->StepFrame);
3501 DrawGraphic(sx, sy, old_graphic, frame);
3503 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
3504 player_is_opaque = TRUE;
3508 GfxElement[jx][jy] = EL_UNDEFINED;
3510 /* make sure that pushed elements are drawn with correct frame rate */
3511 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
3513 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
3514 GfxFrame[jx][jy] = player->StepFrame;
3516 DrawLevelField(jx, jy);
3520 #if !DRAW_PLAYER_OVER_PUSHED_ELEMENT
3521 /* ----------------------------------------------------------------------- */
3522 /* draw player himself */
3523 /* ----------------------------------------------------------------------- */
3525 graphic = getPlayerGraphic(player, move_dir);
3527 /* in the case of changed player action or direction, prevent the current
3528 animation frame from being restarted for identical animations */
3529 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
3530 player->Frame = last_player_frame;
3532 frame = getGraphicAnimationFrame(graphic, player->Frame);
3536 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3537 sxx = player->GfxPos;
3539 syy = player->GfxPos;
3542 if (player_is_opaque)
3543 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
3545 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3547 if (SHIELD_ON(player))
3549 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
3550 IMG_SHIELD_NORMAL_ACTIVE);
3551 int frame = getGraphicAnimationFrame(graphic, -1);
3553 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3557 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
3560 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3561 sxx = player->GfxPos;
3563 syy = player->GfxPos;
3567 /* ----------------------------------------------------------------------- */
3568 /* draw things the player is pushing, if needed */
3569 /* ----------------------------------------------------------------------- */
3571 if (player->is_pushing && player->is_moving)
3573 int px = SCREENX(jx), py = SCREENY(jy);
3574 int pxx = (TILEX - ABS(sxx)) * dx;
3575 int pyy = (TILEY - ABS(syy)) * dy;
3576 int gfx_frame = GfxFrame[jx][jy];
3582 if (!IS_MOVING(jx, jy)) /* push movement already finished */
3584 element = Feld[next_jx][next_jy];
3585 gfx_frame = GfxFrame[next_jx][next_jy];
3588 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
3590 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
3591 frame = getGraphicAnimationFrame(graphic, sync_frame);
3593 /* draw background element under pushed element (like the Sokoban field) */
3594 if (game.use_masked_pushing && IS_MOVING(jx, jy))
3596 /* this allows transparent pushing animation over non-black background */
3599 DrawLevelElement(jx, jy, Back[jx][jy]);
3601 DrawLevelElement(jx, jy, EL_EMPTY);
3603 if (Back[next_jx][next_jy])
3604 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3606 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
3608 else if (Back[next_jx][next_jy])
3609 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3612 /* do not draw (EM style) pushing animation when pushing is finished */
3613 /* (two-tile animations usually do not contain start and end frame) */
3614 if (graphic_info[graphic].double_movement && !IS_MOVING(jx, jy))
3615 DrawLevelElement(next_jx, next_jy, Feld[next_jx][next_jy]);
3617 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3619 /* masked drawing is needed for EMC style (double) movement graphics */
3620 /* !!! (ONLY WHEN DRAWING PUSHED ELEMENT OVER THE PLAYER) !!! */
3621 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3625 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
3626 /* ----------------------------------------------------------------------- */
3627 /* draw player himself */
3628 /* ----------------------------------------------------------------------- */
3630 graphic = getPlayerGraphic(player, move_dir);
3632 /* in the case of changed player action or direction, prevent the current
3633 animation frame from being restarted for identical animations */
3634 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
3635 player->Frame = last_player_frame;
3637 frame = getGraphicAnimationFrame(graphic, player->Frame);
3641 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3642 sxx = player->GfxPos;
3644 syy = player->GfxPos;
3647 if (player_is_opaque)
3648 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
3650 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3652 if (SHIELD_ON(player))
3654 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
3655 IMG_SHIELD_NORMAL_ACTIVE);
3656 int frame = getGraphicAnimationFrame(graphic, -1);
3658 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3662 /* ----------------------------------------------------------------------- */
3663 /* draw things in front of player (active dynamite or dynabombs) */
3664 /* ----------------------------------------------------------------------- */
3666 if (IS_ACTIVE_BOMB(element))
3668 graphic = el2img(element);
3669 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
3671 if (game.emulation == EMU_SUPAPLEX)
3672 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
3674 DrawGraphicThruMask(sx, sy, graphic, frame);
3677 if (player_is_moving && last_element == EL_EXPLOSION)
3679 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
3680 GfxElement[last_jx][last_jy] : EL_EMPTY);
3681 int graphic = el_act2img(element, ACTION_EXPLODING);
3682 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
3683 int phase = ExplodePhase[last_jx][last_jy] - 1;
3684 int frame = getGraphicAnimationFrame(graphic, phase - delay);
3687 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
3690 /* ----------------------------------------------------------------------- */
3691 /* draw elements the player is just walking/passing through/under */
3692 /* ----------------------------------------------------------------------- */
3694 if (player_is_moving)
3696 /* handle the field the player is leaving ... */
3697 if (IS_ACCESSIBLE_INSIDE(last_element))
3698 DrawLevelField(last_jx, last_jy);
3699 else if (IS_ACCESSIBLE_UNDER(last_element))
3700 DrawLevelFieldThruMask(last_jx, last_jy);
3703 /* do not redraw accessible elements if the player is just pushing them */
3704 if (!player_is_moving || !player->is_pushing)
3706 /* ... and the field the player is entering */
3707 if (IS_ACCESSIBLE_INSIDE(element))
3708 DrawLevelField(jx, jy);
3709 else if (IS_ACCESSIBLE_UNDER(element))
3710 DrawLevelFieldThruMask(jx, jy);
3713 MarkTileDirty(sx, sy);
3716 /* ------------------------------------------------------------------------- */
3718 void WaitForEventToContinue()
3720 boolean still_wait = TRUE;
3722 /* simulate releasing mouse button over last gadget, if still pressed */
3724 HandleGadgets(-1, -1, 0);
3726 button_status = MB_RELEASED;
3740 case EVENT_BUTTONPRESS:
3741 case EVENT_KEYPRESS:
3745 case EVENT_KEYRELEASE:
3746 ClearPlayerAction();
3750 HandleOtherEvents(&event);
3754 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3763 #define MAX_REQUEST_LINES 13
3764 #define MAX_REQUEST_LINE_FONT1_LEN 7
3765 #define MAX_REQUEST_LINE_FONT2_LEN 10
3767 static int RequestHandleEvents(unsigned int req_state)
3769 boolean level_solved = (game_status == GAME_MODE_PLAYING &&
3770 local_player->LevelSolved_GameEnd);
3771 int width = request.width;
3772 int height = request.height;
3776 setRequestPosition(&sx, &sy, FALSE);
3778 button_status = MB_RELEASED;
3780 request_gadget_id = -1;
3787 SetDrawtoField(DRAW_TO_FIELDBUFFER);
3789 HandleGameActions();
3791 SetDrawtoField(DRAW_TO_BACKBUFFER);
3793 if (global.use_envelope_request)
3795 /* copy current state of request area to middle of playfield area */
3796 BlitBitmap(bitmap_db_store_2, drawto, sx, sy, width, height, sx, sy);
3804 while (NextValidEvent(&event))
3808 case EVENT_BUTTONPRESS:
3809 case EVENT_BUTTONRELEASE:
3810 case EVENT_MOTIONNOTIFY:
3814 if (event.type == EVENT_MOTIONNOTIFY)
3819 motion_status = TRUE;
3820 mx = ((MotionEvent *) &event)->x;
3821 my = ((MotionEvent *) &event)->y;
3825 motion_status = FALSE;
3826 mx = ((ButtonEvent *) &event)->x;
3827 my = ((ButtonEvent *) &event)->y;
3828 if (event.type == EVENT_BUTTONPRESS)
3829 button_status = ((ButtonEvent *) &event)->button;
3831 button_status = MB_RELEASED;
3834 /* this sets 'request_gadget_id' */
3835 HandleGadgets(mx, my, button_status);
3837 switch (request_gadget_id)
3839 case TOOL_CTRL_ID_YES:
3842 case TOOL_CTRL_ID_NO:
3845 case TOOL_CTRL_ID_CONFIRM:
3846 result = TRUE | FALSE;
3849 case TOOL_CTRL_ID_PLAYER_1:
3852 case TOOL_CTRL_ID_PLAYER_2:
3855 case TOOL_CTRL_ID_PLAYER_3:
3858 case TOOL_CTRL_ID_PLAYER_4:
3869 case EVENT_KEYPRESS:
3871 Key key = GetEventKey((KeyEvent *)&event, TRUE);
3876 if (req_state & REQ_CONFIRM)
3881 #if defined(TARGET_SDL2)
3888 #if defined(TARGET_SDL2)
3895 HandleKeysDebug(key);
3899 if (req_state & REQ_PLAYER)
3905 case EVENT_KEYRELEASE:
3906 ClearPlayerAction();
3910 HandleOtherEvents(&event);
3915 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3917 int joy = AnyJoystick();
3919 if (joy & JOY_BUTTON_1)
3921 else if (joy & JOY_BUTTON_2)
3927 if (global.use_envelope_request)
3929 /* copy back current state of pressed buttons inside request area */
3930 BlitBitmap(drawto, bitmap_db_store_2, sx, sy, width, height, sx, sy);
3940 static boolean RequestDoor(char *text, unsigned int req_state)
3942 unsigned int old_door_state;
3943 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
3944 int font_nr = FONT_TEXT_2;
3949 if (maxWordLengthInString(text) > MAX_REQUEST_LINE_FONT1_LEN)
3951 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
3952 font_nr = FONT_TEXT_1;
3955 if (game_status == GAME_MODE_PLAYING)
3956 BlitScreenToBitmap(backbuffer);
3958 /* disable deactivated drawing when quick-loading level tape recording */
3959 if (tape.playing && tape.deactivate_display)
3960 TapeDeactivateDisplayOff(TRUE);
3962 SetMouseCursor(CURSOR_DEFAULT);
3964 #if defined(NETWORK_AVALIABLE)
3965 /* pause network game while waiting for request to answer */
3966 if (options.network &&
3967 game_status == GAME_MODE_PLAYING &&
3968 req_state & REQUEST_WAIT_FOR_INPUT)
3969 SendToServer_PausePlaying();
3972 old_door_state = GetDoorState();
3974 /* simulate releasing mouse button over last gadget, if still pressed */
3976 HandleGadgets(-1, -1, 0);
3980 /* draw released gadget before proceeding */
3983 if (old_door_state & DOOR_OPEN_1)
3985 CloseDoor(DOOR_CLOSE_1);
3987 /* save old door content */
3988 BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
3989 0 * DXSIZE, 0, DXSIZE, DYSIZE, 1 * DXSIZE, 0);
3992 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
3993 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3995 /* clear door drawing field */
3996 DrawBackground(DX, DY, DXSIZE, DYSIZE);
3998 /* force DOOR font inside door area */
3999 SetFontStatus(GAME_MODE_PSEUDO_DOOR);
4001 /* write text for request */
4002 for (text_ptr = text, ty = 0; ty < MAX_REQUEST_LINES; ty++)
4004 char text_line[max_request_line_len + 1];
4010 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
4012 tc = *(text_ptr + tx);
4013 // if (!tc || tc == ' ')
4014 if (!tc || tc == ' ' || tc == '?' || tc == '!')
4018 if ((tc == '?' || tc == '!') && tl == 0)
4028 strncpy(text_line, text_ptr, tl);
4031 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
4032 DY + 8 + ty * (getFontHeight(font_nr) + 2),
4033 text_line, font_nr);
4035 text_ptr += tl + (tc == ' ' ? 1 : 0);
4036 // text_ptr += tl + (tc == ' ' || tc == '?' || tc == '!' ? 1 : 0);
4041 if (req_state & REQ_ASK)
4043 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
4044 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
4046 else if (req_state & REQ_CONFIRM)
4048 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
4050 else if (req_state & REQ_PLAYER)
4052 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
4053 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
4054 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
4055 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
4058 /* copy request gadgets to door backbuffer */
4059 BlitBitmap(drawto, bitmap_db_door_1, DX, DY, DXSIZE, DYSIZE, 0, 0);
4061 OpenDoor(DOOR_OPEN_1);
4063 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
4065 if (game_status == GAME_MODE_PLAYING)
4067 SetPanelBackground();
4068 SetDrawBackgroundMask(REDRAW_DOOR_1);
4072 SetDrawBackgroundMask(REDRAW_FIELD);
4078 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4080 // ---------- handle request buttons ----------
4081 result = RequestHandleEvents(req_state);
4085 if (!(req_state & REQ_STAY_OPEN))
4087 CloseDoor(DOOR_CLOSE_1);
4089 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
4090 (req_state & REQ_REOPEN))
4091 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
4096 if (game_status == GAME_MODE_PLAYING)
4098 SetPanelBackground();
4099 SetDrawBackgroundMask(REDRAW_DOOR_1);
4103 SetDrawBackgroundMask(REDRAW_FIELD);
4106 #if defined(NETWORK_AVALIABLE)
4107 /* continue network game after request */
4108 if (options.network &&
4109 game_status == GAME_MODE_PLAYING &&
4110 req_state & REQUEST_WAIT_FOR_INPUT)
4111 SendToServer_ContinuePlaying();
4114 /* restore deactivated drawing when quick-loading level tape recording */
4115 if (tape.playing && tape.deactivate_display)
4116 TapeDeactivateDisplayOn();
4121 static boolean RequestEnvelope(char *text, unsigned int req_state)
4125 if (game_status == GAME_MODE_PLAYING)
4126 BlitScreenToBitmap(backbuffer);
4128 /* disable deactivated drawing when quick-loading level tape recording */
4129 if (tape.playing && tape.deactivate_display)
4130 TapeDeactivateDisplayOff(TRUE);
4132 SetMouseCursor(CURSOR_DEFAULT);
4134 #if defined(NETWORK_AVALIABLE)
4135 /* pause network game while waiting for request to answer */
4136 if (options.network &&
4137 game_status == GAME_MODE_PLAYING &&
4138 req_state & REQUEST_WAIT_FOR_INPUT)
4139 SendToServer_PausePlaying();
4142 /* simulate releasing mouse button over last gadget, if still pressed */
4144 HandleGadgets(-1, -1, 0);
4148 // (replace with setting corresponding request background)
4149 // SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
4150 // SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4152 /* clear door drawing field */
4153 // DrawBackground(DX, DY, DXSIZE, DYSIZE);
4155 ShowEnvelopeRequest(text, req_state, ACTION_OPENING);
4157 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
4159 if (game_status == GAME_MODE_PLAYING)
4161 SetPanelBackground();
4162 SetDrawBackgroundMask(REDRAW_DOOR_1);
4166 SetDrawBackgroundMask(REDRAW_FIELD);
4172 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4174 // ---------- handle request buttons ----------
4175 result = RequestHandleEvents(req_state);
4179 ShowEnvelopeRequest(text, req_state, ACTION_CLOSING);
4183 if (game_status == GAME_MODE_PLAYING)
4185 SetPanelBackground();
4186 SetDrawBackgroundMask(REDRAW_DOOR_1);
4190 SetDrawBackgroundMask(REDRAW_FIELD);
4193 #if defined(NETWORK_AVALIABLE)
4194 /* continue network game after request */
4195 if (options.network &&
4196 game_status == GAME_MODE_PLAYING &&
4197 req_state & REQUEST_WAIT_FOR_INPUT)
4198 SendToServer_ContinuePlaying();
4201 /* restore deactivated drawing when quick-loading level tape recording */
4202 if (tape.playing && tape.deactivate_display)
4203 TapeDeactivateDisplayOn();
4208 boolean Request(char *text, unsigned int req_state)
4210 if (global.use_envelope_request)
4211 return RequestEnvelope(text, req_state);
4213 return RequestDoor(text, req_state);
4216 static int compareDoorPartOrderInfo(const void *object1, const void *object2)
4218 const struct DoorPartOrderInfo *dpo1 = (struct DoorPartOrderInfo *)object1;
4219 const struct DoorPartOrderInfo *dpo2 = (struct DoorPartOrderInfo *)object2;
4222 if (dpo1->sort_priority != dpo2->sort_priority)
4223 compare_result = dpo1->sort_priority - dpo2->sort_priority;
4225 compare_result = dpo1->nr - dpo2->nr;
4227 return compare_result;
4230 void InitGraphicCompatibilityInfo_Doors()
4236 struct DoorInfo *door;
4240 { DOOR_1, IMG_GFX_DOOR_1_PART_1, IMG_GFX_DOOR_1_PART_8, &door_1 },
4241 { DOOR_2, IMG_GFX_DOOR_2_PART_1, IMG_GFX_DOOR_2_PART_8, &door_2 },
4243 { -1, -1, -1, NULL }
4245 struct Rect door_rect_list[] =
4247 { DX, DY, DXSIZE, DYSIZE },
4248 { VX, VY, VXSIZE, VYSIZE }
4252 for (i = 0; doors[i].door_token != -1; i++)
4254 int door_token = doors[i].door_token;
4255 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
4256 int part_1 = doors[i].part_1;
4257 int part_8 = doors[i].part_8;
4258 int part_2 = part_1 + 1;
4259 int part_3 = part_1 + 2;
4260 struct DoorInfo *door = doors[i].door;
4261 struct Rect *door_rect = &door_rect_list[door_index];
4262 boolean door_gfx_redefined = FALSE;
4264 /* check if any door part graphic definitions have been redefined */
4266 for (j = 0; door_part_controls[j].door_token != -1; j++)
4268 struct DoorPartControlInfo *dpc = &door_part_controls[j];
4269 struct FileInfo *fi = getImageListEntryFromImageID(dpc->graphic);
4271 if (dpc->door_token == door_token && fi->redefined)
4272 door_gfx_redefined = TRUE;
4275 /* check for old-style door graphic/animation modifications */
4277 if (!door_gfx_redefined)
4279 if (door->anim_mode & ANIM_STATIC_PANEL)
4281 door->panel.step_xoffset = 0;
4282 door->panel.step_yoffset = 0;
4285 if (door->anim_mode & (ANIM_HORIZONTAL | ANIM_VERTICAL))
4287 struct GraphicInfo *g_part_1 = &graphic_info[part_1];
4288 struct GraphicInfo *g_part_2 = &graphic_info[part_2];
4289 int num_door_steps, num_panel_steps;
4291 /* remove door part graphics other than the two default wings */
4293 for (j = 0; door_part_controls[j].door_token != -1; j++)
4295 struct DoorPartControlInfo *dpc = &door_part_controls[j];
4296 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4298 if (dpc->graphic >= part_3 &&
4299 dpc->graphic <= part_8)
4303 /* set graphics and screen positions of the default wings */
4305 g_part_1->width = door_rect->width;
4306 g_part_1->height = door_rect->height;
4307 g_part_2->width = door_rect->width;
4308 g_part_2->height = door_rect->height;
4309 g_part_2->src_x = door_rect->width;
4310 g_part_2->src_y = g_part_1->src_y;
4312 door->part_2.x = door->part_1.x;
4313 door->part_2.y = door->part_1.y;
4315 if (door->width != -1)
4317 g_part_1->width = door->width;
4318 g_part_2->width = door->width;
4320 // special treatment for graphics and screen position of right wing
4321 g_part_2->src_x += door_rect->width - door->width;
4322 door->part_2.x += door_rect->width - door->width;
4325 if (door->height != -1)
4327 g_part_1->height = door->height;
4328 g_part_2->height = door->height;
4330 // special treatment for graphics and screen position of bottom wing
4331 g_part_2->src_y += door_rect->height - door->height;
4332 door->part_2.y += door_rect->height - door->height;
4335 /* set animation delays for the default wings and panels */
4337 door->part_1.step_delay = door->step_delay;
4338 door->part_2.step_delay = door->step_delay;
4339 door->panel.step_delay = door->step_delay;
4341 /* set animation draw order for the default wings */
4343 door->part_1.sort_priority = 2; /* draw left wing over ... */
4344 door->part_2.sort_priority = 1; /* ... right wing */
4346 /* set animation draw offset for the default wings */
4348 if (door->anim_mode & ANIM_HORIZONTAL)
4350 door->part_1.step_xoffset = door->step_offset;
4351 door->part_1.step_yoffset = 0;
4352 door->part_2.step_xoffset = door->step_offset * -1;
4353 door->part_2.step_yoffset = 0;
4355 num_door_steps = g_part_1->width / door->step_offset;
4357 else // ANIM_VERTICAL
4359 door->part_1.step_xoffset = 0;
4360 door->part_1.step_yoffset = door->step_offset;
4361 door->part_2.step_xoffset = 0;
4362 door->part_2.step_yoffset = door->step_offset * -1;
4364 num_door_steps = g_part_1->height / door->step_offset;
4367 /* set animation draw offset for the default panels */
4369 if (door->step_offset > 1)
4371 num_panel_steps = 2 * door_rect->height / door->step_offset;
4372 door->panel.start_step = num_panel_steps - num_door_steps;
4373 door->panel.start_step_closing = door->panel.start_step;
4377 num_panel_steps = door_rect->height / door->step_offset;
4378 door->panel.start_step = num_panel_steps - num_door_steps / 2;
4379 door->panel.start_step_closing = door->panel.start_step;
4380 door->panel.step_delay *= 2;
4391 for (i = 0; door_part_controls[i].door_token != -1; i++)
4393 struct DoorPartControlInfo *dpc = &door_part_controls[i];
4394 struct DoorPartOrderInfo *dpo = &door_part_order[i];
4396 /* initialize "start_step_opening" and "start_step_closing", if needed */
4397 if (dpc->pos->start_step_opening == 0 &&
4398 dpc->pos->start_step_closing == 0)
4400 // dpc->pos->start_step_opening = dpc->pos->start_step;
4401 dpc->pos->start_step_closing = dpc->pos->start_step;
4404 /* fill structure for door part draw order (sorted below) */
4406 dpo->sort_priority = dpc->pos->sort_priority;
4409 /* sort door part controls according to sort_priority and graphic number */
4410 qsort(door_part_order, MAX_DOOR_PARTS,
4411 sizeof(struct DoorPartOrderInfo), compareDoorPartOrderInfo);
4414 unsigned int OpenDoor(unsigned int door_state)
4416 if (door_state & DOOR_COPY_BACK)
4418 if (door_state & DOOR_OPEN_1)
4419 BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
4420 1 * DXSIZE, 0, DXSIZE, DYSIZE, 0 * DXSIZE, 0);
4422 if (door_state & DOOR_OPEN_2)
4423 BlitBitmap(bitmap_db_door_2, bitmap_db_door_2,
4424 1 * VXSIZE, 0, VXSIZE, VYSIZE, 0 * VXSIZE, 0);
4426 door_state &= ~DOOR_COPY_BACK;
4429 return MoveDoor(door_state);
4432 unsigned int CloseDoor(unsigned int door_state)
4434 unsigned int old_door_state = GetDoorState();
4436 if (!(door_state & DOOR_NO_COPY_BACK))
4438 if (old_door_state & DOOR_OPEN_1)
4439 BlitBitmap(backbuffer, bitmap_db_door_1,
4440 DX, DY, DXSIZE, DYSIZE, 0, 0);
4442 if (old_door_state & DOOR_OPEN_2)
4443 BlitBitmap(backbuffer, bitmap_db_door_2,
4444 VX, VY, VXSIZE, VYSIZE, 0, 0);
4446 door_state &= ~DOOR_NO_COPY_BACK;
4449 return MoveDoor(door_state);
4452 unsigned int GetDoorState()
4454 return MoveDoor(DOOR_GET_STATE);
4457 unsigned int SetDoorState(unsigned int door_state)
4459 return MoveDoor(door_state | DOOR_SET_STATE);
4462 int euclid(int a, int b)
4464 return (b ? euclid(b, a % b) : a);
4467 unsigned int MoveDoor(unsigned int door_state)
4469 struct Rect door_rect_list[] =
4471 { DX, DY, DXSIZE, DYSIZE },
4472 { VX, VY, VXSIZE, VYSIZE }
4474 static int door1 = DOOR_CLOSE_1;
4475 static int door2 = DOOR_CLOSE_2;
4476 unsigned int door_delay = 0;
4477 unsigned int door_delay_value;
4480 if (door_state == DOOR_GET_STATE)
4481 return (door1 | door2);
4483 if (door_state & DOOR_SET_STATE)
4485 if (door_state & DOOR_ACTION_1)
4486 door1 = door_state & DOOR_ACTION_1;
4487 if (door_state & DOOR_ACTION_2)
4488 door2 = door_state & DOOR_ACTION_2;
4490 return (door1 | door2);
4493 if (!(door_state & DOOR_FORCE_REDRAW))
4495 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
4496 door_state &= ~DOOR_OPEN_1;
4497 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
4498 door_state &= ~DOOR_CLOSE_1;
4499 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
4500 door_state &= ~DOOR_OPEN_2;
4501 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
4502 door_state &= ~DOOR_CLOSE_2;
4505 if (global.autoplay_leveldir)
4507 door_state |= DOOR_NO_DELAY;
4508 door_state &= ~DOOR_CLOSE_ALL;
4511 if (game_status == GAME_MODE_EDITOR)
4512 door_state |= DOOR_NO_DELAY;
4514 if (door_state & DOOR_ACTION)
4516 boolean door_panel_drawn[NUM_DOORS];
4517 boolean panel_has_doors[NUM_DOORS];
4518 boolean door_part_skip[MAX_DOOR_PARTS];
4519 boolean door_part_done[MAX_DOOR_PARTS];
4520 boolean door_part_done_all;
4521 int num_steps[MAX_DOOR_PARTS];
4522 int max_move_delay = 0; // delay for complete animations of all doors
4523 int max_step_delay = 0; // delay (ms) between two animation frames
4524 int num_move_steps = 0; // number of animation steps for all doors
4525 int max_move_delay_doors_only = 0; // delay for doors only (no panel)
4526 int num_move_steps_doors_only = 0; // steps for doors only (no panel)
4527 int current_move_delay = 0;
4531 for (i = 0; i < NUM_DOORS; i++)
4532 panel_has_doors[i] = FALSE;
4534 for (i = 0; i < MAX_DOOR_PARTS; i++)
4536 struct DoorPartControlInfo *dpc = &door_part_controls[i];
4537 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4538 int door_token = dpc->door_token;
4540 door_part_done[i] = FALSE;
4541 door_part_skip[i] = (!(door_state & door_token) ||
4545 for (i = 0; i < MAX_DOOR_PARTS; i++)
4547 int nr = door_part_order[i].nr;
4548 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
4549 struct DoorPartPosInfo *pos = dpc->pos;
4550 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4551 int door_token = dpc->door_token;
4552 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
4553 boolean is_panel = DOOR_PART_IS_PANEL(nr);
4554 int step_xoffset = ABS(pos->step_xoffset);
4555 int step_yoffset = ABS(pos->step_yoffset);
4556 int step_delay = pos->step_delay;
4557 int current_door_state = door_state & door_token;
4558 boolean door_opening = ((current_door_state & DOOR_OPEN) != 0);
4559 boolean door_closing = ((current_door_state & DOOR_CLOSE) != 0);
4560 boolean part_opening = (is_panel ? door_closing : door_opening);
4561 int start_step = (part_opening ? pos->start_step_opening :
4562 pos->start_step_closing);
4563 float move_xsize = (step_xoffset ? g->width : 0);
4564 float move_ysize = (step_yoffset ? g->height : 0);
4565 int move_xsteps = (step_xoffset ? ceil(move_xsize / step_xoffset) : 0);
4566 int move_ysteps = (step_yoffset ? ceil(move_ysize / step_yoffset) : 0);
4567 int move_steps = (move_xsteps && move_ysteps ?
4568 MIN(move_xsteps, move_ysteps) :
4569 move_xsteps ? move_xsteps : move_ysteps) - start_step;
4570 int move_delay = move_steps * step_delay;
4572 if (door_part_skip[nr])
4575 max_move_delay = MAX(max_move_delay, move_delay);
4576 max_step_delay = (max_step_delay == 0 ? step_delay :
4577 euclid(max_step_delay, step_delay));
4578 num_steps[nr] = move_steps;
4582 max_move_delay_doors_only = MAX(max_move_delay_doors_only, move_delay);
4584 panel_has_doors[door_index] = TRUE;
4588 max_step_delay = MAX(1, max_step_delay); // prevent division by zero
4590 num_move_steps = max_move_delay / max_step_delay;
4591 num_move_steps_doors_only = max_move_delay_doors_only / max_step_delay;
4593 door_delay_value = max_step_delay;
4595 if ((door_state & DOOR_NO_DELAY) || setup.quick_doors)
4597 start = num_move_steps - 1;
4601 /* opening door sound has priority over simultaneously closing door */
4602 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
4603 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
4604 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
4605 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
4608 for (k = start; k < num_move_steps; k++)
4610 int last_frame = num_move_steps - 1; // last frame of this "for" loop
4612 door_part_done_all = TRUE;
4614 for (i = 0; i < NUM_DOORS; i++)
4615 door_panel_drawn[i] = FALSE;
4617 for (i = 0; i < MAX_DOOR_PARTS; i++)
4619 int nr = door_part_order[i].nr;
4620 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
4621 struct DoorPartPosInfo *pos = dpc->pos;
4622 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4623 int door_token = dpc->door_token;
4624 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
4625 boolean is_panel = DOOR_PART_IS_PANEL(nr);
4626 boolean is_panel_and_door_has_closed = FALSE;
4627 struct Rect *door_rect = &door_rect_list[door_index];
4628 Bitmap *bitmap_db_door = (door_token == DOOR_1 ? bitmap_db_door_1 :
4630 Bitmap *bitmap = (is_panel ? bitmap_db_door : g->bitmap);
4631 int current_door_state = door_state & door_token;
4632 boolean door_opening = ((current_door_state & DOOR_OPEN) != 0);
4633 boolean door_closing = !door_opening;
4634 boolean part_opening = (is_panel ? door_closing : door_opening);
4635 boolean part_closing = !part_opening;
4636 int start_step = (part_opening ? pos->start_step_opening :
4637 pos->start_step_closing);
4638 int step_delay = pos->step_delay;
4639 int step_factor = step_delay / max_step_delay;
4640 int k1 = (step_factor ? k / step_factor + 1 : k);
4641 int k2 = (part_opening ? k1 + start_step : num_steps[nr] - k1);
4642 int kk = MAX(0, k2);
4645 int src_x, src_y, src_xx, src_yy;
4646 int dst_x, dst_y, dst_xx, dst_yy;
4649 if (door_part_skip[nr])
4652 if (!(door_state & door_token))
4660 int k2_door = (door_opening ? k : num_move_steps_doors_only - k - 1);
4661 int kk_door = MAX(0, k2_door);
4662 int sync_frame = kk_door * door_delay_value;
4663 int frame = getGraphicAnimationFrame(dpc->graphic, sync_frame);
4665 getFixedGraphicSource(dpc->graphic, frame, &bitmap,
4666 &g_src_x, &g_src_y);
4671 if (!door_panel_drawn[door_index])
4673 ClearRectangle(drawto, door_rect->x, door_rect->y,
4674 door_rect->width, door_rect->height);
4676 door_panel_drawn[door_index] = TRUE;
4679 // draw opening or closing door parts
4681 if (pos->step_xoffset < 0) // door part on right side
4684 dst_xx = pos->x + ABS(kk * pos->step_xoffset);
4687 if (dst_xx + width > door_rect->width)
4688 width = door_rect->width - dst_xx;
4690 else // door part on left side
4693 dst_xx = pos->x - kk * pos->step_xoffset;
4697 src_xx = ABS(dst_xx);
4701 width = g->width - src_xx;
4703 if (width > door_rect->width)
4704 width = door_rect->width;
4706 // printf("::: k == %d [%d] \n", k, start_step);
4709 if (pos->step_yoffset < 0) // door part on bottom side
4712 dst_yy = pos->y + ABS(kk * pos->step_yoffset);
4715 if (dst_yy + height > door_rect->height)
4716 height = door_rect->height - dst_yy;
4718 else // door part on top side
4721 dst_yy = pos->y - kk * pos->step_yoffset;
4725 src_yy = ABS(dst_yy);
4729 height = g->height - src_yy;
4732 src_x = g_src_x + src_xx;
4733 src_y = g_src_y + src_yy;
4735 dst_x = door_rect->x + dst_xx;
4736 dst_y = door_rect->y + dst_yy;
4738 is_panel_and_door_has_closed =
4741 panel_has_doors[door_index] &&
4742 k >= num_move_steps_doors_only - 1);
4744 if (width >= 0 && width <= g->width &&
4745 height >= 0 && height <= g->height &&
4746 !is_panel_and_door_has_closed)
4748 if (is_panel || !pos->draw_masked)
4749 BlitBitmap(bitmap, drawto, src_x, src_y, width, height,
4752 BlitBitmapMasked(bitmap, drawto, src_x, src_y, width, height,
4756 redraw_mask |= REDRAW_DOOR_FROM_TOKEN(door_token);
4758 if ((part_opening && (width < 0 || height < 0)) ||
4759 (part_closing && (width >= g->width && height >= g->height)))
4760 door_part_done[nr] = TRUE;
4762 // continue door part animations, but not panel after door has closed
4763 if (!door_part_done[nr] && !is_panel_and_door_has_closed)
4764 door_part_done_all = FALSE;
4767 if (!(door_state & DOOR_NO_DELAY))
4771 SkipUntilDelayReached(&door_delay, door_delay_value, &k, last_frame);
4773 current_move_delay += max_step_delay;
4776 if (door_part_done_all)
4781 if (door_state & DOOR_ACTION_1)
4782 door1 = door_state & DOOR_ACTION_1;
4783 if (door_state & DOOR_ACTION_2)
4784 door2 = door_state & DOOR_ACTION_2;
4786 // draw masked border over door area
4787 DrawMaskedBorder(REDRAW_DOOR_1);
4788 DrawMaskedBorder(REDRAW_DOOR_2);
4790 return (door1 | door2);
4793 static boolean useSpecialEditorDoor()
4795 int graphic = IMG_GLOBAL_BORDER_EDITOR;
4796 boolean redefined = getImageListEntryFromImageID(graphic)->redefined;
4798 // do not draw special editor door if editor border defined or redefined
4799 if (graphic_info[graphic].bitmap != NULL || redefined)
4802 // do not draw special editor door if global border defined to be empty
4803 if (graphic_info[IMG_GLOBAL_BORDER].bitmap == NULL)
4806 // do not draw special editor door if viewport definitions do not match
4810 EY + EYSIZE != VY + VYSIZE)
4816 void DrawSpecialEditorDoor()
4818 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
4819 int top_border_width = gfx1->width;
4820 int top_border_height = gfx1->height;
4821 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
4822 int ex = EX - outer_border;
4823 int ey = EY - outer_border;
4824 int vy = VY - outer_border;
4825 int exsize = EXSIZE + 2 * outer_border;
4827 if (!useSpecialEditorDoor())
4830 /* draw bigger level editor toolbox window */
4831 BlitBitmap(gfx1->bitmap, drawto, gfx1->src_x, gfx1->src_y,
4832 top_border_width, top_border_height, ex, ey - top_border_height);
4833 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto, ex, vy,
4834 exsize, EYSIZE - VYSIZE + outer_border, ex, ey);
4836 redraw_mask |= REDRAW_ALL;
4839 void UndrawSpecialEditorDoor()
4841 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
4842 int top_border_width = gfx1->width;
4843 int top_border_height = gfx1->height;
4844 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
4845 int ex = EX - outer_border;
4846 int ey = EY - outer_border;
4847 int ey_top = ey - top_border_height;
4848 int exsize = EXSIZE + 2 * outer_border;
4849 int eysize = EYSIZE + 2 * outer_border;
4851 if (!useSpecialEditorDoor())
4854 /* draw normal tape recorder window */
4855 if (graphic_info[IMG_GLOBAL_BORDER].bitmap)
4857 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
4858 ex, ey_top, top_border_width, top_border_height,
4860 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
4861 ex, ey, exsize, eysize, ex, ey);
4865 // if screen background is set to "[NONE]", clear editor toolbox window
4866 ClearRectangle(drawto, ex, ey_top, top_border_width, top_border_height);
4867 ClearRectangle(drawto, ex, ey, exsize, eysize);
4870 redraw_mask |= REDRAW_ALL;
4874 /* ---------- new tool button stuff ---------------------------------------- */
4879 struct TextPosInfo *pos;
4882 } toolbutton_info[NUM_TOOL_BUTTONS] =
4885 IMG_GFX_REQUEST_BUTTON_YES, &request.button.yes,
4886 TOOL_CTRL_ID_YES, "yes"
4889 IMG_GFX_REQUEST_BUTTON_NO, &request.button.no,
4890 TOOL_CTRL_ID_NO, "no"
4893 IMG_GFX_REQUEST_BUTTON_CONFIRM, &request.button.confirm,
4894 TOOL_CTRL_ID_CONFIRM, "confirm"
4897 IMG_GFX_REQUEST_BUTTON_PLAYER_1, &request.button.player_1,
4898 TOOL_CTRL_ID_PLAYER_1, "player 1"
4901 IMG_GFX_REQUEST_BUTTON_PLAYER_2, &request.button.player_2,
4902 TOOL_CTRL_ID_PLAYER_2, "player 2"
4905 IMG_GFX_REQUEST_BUTTON_PLAYER_3, &request.button.player_3,
4906 TOOL_CTRL_ID_PLAYER_3, "player 3"
4909 IMG_GFX_REQUEST_BUTTON_PLAYER_4, &request.button.player_4,
4910 TOOL_CTRL_ID_PLAYER_4, "player 4"
4914 void CreateToolButtons()
4918 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4920 struct GraphicInfo *gfx = &graphic_info[toolbutton_info[i].graphic];
4921 struct TextPosInfo *pos = toolbutton_info[i].pos;
4922 struct GadgetInfo *gi;
4923 Bitmap *deco_bitmap = None;
4924 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
4925 unsigned int event_mask = GD_EVENT_RELEASED;
4928 int gd_x = gfx->src_x;
4929 int gd_y = gfx->src_y;
4930 int gd_xp = gfx->src_x + gfx->pressed_xoffset;
4931 int gd_yp = gfx->src_y + gfx->pressed_yoffset;
4934 if (global.use_envelope_request)
4935 setRequestPosition(&dx, &dy, TRUE);
4937 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
4939 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
4941 getSizedGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr), 0,
4942 pos->size, &deco_bitmap, &deco_x, &deco_y);
4943 deco_xpos = (gfx->width - pos->size) / 2;
4944 deco_ypos = (gfx->height - pos->size) / 2;
4947 gi = CreateGadget(GDI_CUSTOM_ID, id,
4948 GDI_INFO_TEXT, toolbutton_info[i].infotext,
4949 GDI_X, dx + GDI_ACTIVE_POS(pos->x),
4950 GDI_Y, dy + GDI_ACTIVE_POS(pos->y),
4951 GDI_WIDTH, gfx->width,
4952 GDI_HEIGHT, gfx->height,
4953 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
4954 GDI_STATE, GD_BUTTON_UNPRESSED,
4955 GDI_DESIGN_UNPRESSED, gfx->bitmap, gd_x, gd_y,
4956 GDI_DESIGN_PRESSED, gfx->bitmap, gd_xp, gd_yp,
4957 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
4958 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
4959 GDI_DECORATION_SIZE, pos->size, pos->size,
4960 GDI_DECORATION_SHIFTING, 1, 1,
4961 GDI_DIRECT_DRAW, FALSE,
4962 GDI_EVENT_MASK, event_mask,
4963 GDI_CALLBACK_ACTION, HandleToolButtons,
4967 Error(ERR_EXIT, "cannot create gadget");
4969 tool_gadget[id] = gi;
4973 void FreeToolButtons()
4977 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4978 FreeGadget(tool_gadget[i]);
4981 static void UnmapToolButtons()
4985 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4986 UnmapGadget(tool_gadget[i]);
4989 static void HandleToolButtons(struct GadgetInfo *gi)
4991 request_gadget_id = gi->custom_id;
4994 static struct Mapping_EM_to_RND_object
4997 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
4998 boolean is_backside; /* backside of moving element */
5004 em_object_mapping_list[] =
5007 Xblank, TRUE, FALSE,
5011 Yacid_splash_eB, FALSE, FALSE,
5012 EL_ACID_SPLASH_RIGHT, -1, -1
5015 Yacid_splash_wB, FALSE, FALSE,
5016 EL_ACID_SPLASH_LEFT, -1, -1
5019 #ifdef EM_ENGINE_BAD_ROLL
5021 Xstone_force_e, FALSE, FALSE,
5022 EL_ROCK, -1, MV_BIT_RIGHT
5025 Xstone_force_w, FALSE, FALSE,
5026 EL_ROCK, -1, MV_BIT_LEFT
5029 Xnut_force_e, FALSE, FALSE,
5030 EL_NUT, -1, MV_BIT_RIGHT
5033 Xnut_force_w, FALSE, FALSE,
5034 EL_NUT, -1, MV_BIT_LEFT
5037 Xspring_force_e, FALSE, FALSE,
5038 EL_SPRING, -1, MV_BIT_RIGHT
5041 Xspring_force_w, FALSE, FALSE,
5042 EL_SPRING, -1, MV_BIT_LEFT
5045 Xemerald_force_e, FALSE, FALSE,
5046 EL_EMERALD, -1, MV_BIT_RIGHT
5049 Xemerald_force_w, FALSE, FALSE,
5050 EL_EMERALD, -1, MV_BIT_LEFT
5053 Xdiamond_force_e, FALSE, FALSE,
5054 EL_DIAMOND, -1, MV_BIT_RIGHT
5057 Xdiamond_force_w, FALSE, FALSE,
5058 EL_DIAMOND, -1, MV_BIT_LEFT
5061 Xbomb_force_e, FALSE, FALSE,
5062 EL_BOMB, -1, MV_BIT_RIGHT
5065 Xbomb_force_w, FALSE, FALSE,
5066 EL_BOMB, -1, MV_BIT_LEFT
5068 #endif /* EM_ENGINE_BAD_ROLL */
5071 Xstone, TRUE, FALSE,
5075 Xstone_pause, FALSE, FALSE,
5079 Xstone_fall, FALSE, FALSE,
5083 Ystone_s, FALSE, FALSE,
5084 EL_ROCK, ACTION_FALLING, -1
5087 Ystone_sB, FALSE, TRUE,
5088 EL_ROCK, ACTION_FALLING, -1
5091 Ystone_e, FALSE, FALSE,
5092 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
5095 Ystone_eB, FALSE, TRUE,
5096 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
5099 Ystone_w, FALSE, FALSE,
5100 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
5103 Ystone_wB, FALSE, TRUE,
5104 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
5111 Xnut_pause, FALSE, FALSE,
5115 Xnut_fall, FALSE, FALSE,
5119 Ynut_s, FALSE, FALSE,
5120 EL_NUT, ACTION_FALLING, -1
5123 Ynut_sB, FALSE, TRUE,
5124 EL_NUT, ACTION_FALLING, -1
5127 Ynut_e, FALSE, FALSE,
5128 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
5131 Ynut_eB, FALSE, TRUE,
5132 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
5135 Ynut_w, FALSE, FALSE,
5136 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
5139 Ynut_wB, FALSE, TRUE,
5140 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
5143 Xbug_n, TRUE, FALSE,
5147 Xbug_e, TRUE, FALSE,
5148 EL_BUG_RIGHT, -1, -1
5151 Xbug_s, TRUE, FALSE,
5155 Xbug_w, TRUE, FALSE,
5159 Xbug_gon, FALSE, FALSE,
5163 Xbug_goe, FALSE, FALSE,
5164 EL_BUG_RIGHT, -1, -1
5167 Xbug_gos, FALSE, FALSE,
5171 Xbug_gow, FALSE, FALSE,
5175 Ybug_n, FALSE, FALSE,
5176 EL_BUG, ACTION_MOVING, MV_BIT_UP
5179 Ybug_nB, FALSE, TRUE,
5180 EL_BUG, ACTION_MOVING, MV_BIT_UP
5183 Ybug_e, FALSE, FALSE,
5184 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
5187 Ybug_eB, FALSE, TRUE,
5188 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
5191 Ybug_s, FALSE, FALSE,
5192 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
5195 Ybug_sB, FALSE, TRUE,
5196 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
5199 Ybug_w, FALSE, FALSE,
5200 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
5203 Ybug_wB, FALSE, TRUE,
5204 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
5207 Ybug_w_n, FALSE, FALSE,
5208 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
5211 Ybug_n_e, FALSE, FALSE,
5212 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
5215 Ybug_e_s, FALSE, FALSE,
5216 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
5219 Ybug_s_w, FALSE, FALSE,
5220 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
5223 Ybug_e_n, FALSE, FALSE,
5224 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
5227 Ybug_s_e, FALSE, FALSE,
5228 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
5231 Ybug_w_s, FALSE, FALSE,
5232 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
5235 Ybug_n_w, FALSE, FALSE,
5236 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
5239 Ybug_stone, FALSE, FALSE,
5240 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
5243 Ybug_spring, FALSE, FALSE,
5244 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
5247 Xtank_n, TRUE, FALSE,
5248 EL_SPACESHIP_UP, -1, -1
5251 Xtank_e, TRUE, FALSE,
5252 EL_SPACESHIP_RIGHT, -1, -1
5255 Xtank_s, TRUE, FALSE,
5256 EL_SPACESHIP_DOWN, -1, -1
5259 Xtank_w, TRUE, FALSE,
5260 EL_SPACESHIP_LEFT, -1, -1
5263 Xtank_gon, FALSE, FALSE,
5264 EL_SPACESHIP_UP, -1, -1
5267 Xtank_goe, FALSE, FALSE,
5268 EL_SPACESHIP_RIGHT, -1, -1
5271 Xtank_gos, FALSE, FALSE,
5272 EL_SPACESHIP_DOWN, -1, -1
5275 Xtank_gow, FALSE, FALSE,
5276 EL_SPACESHIP_LEFT, -1, -1
5279 Ytank_n, FALSE, FALSE,
5280 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
5283 Ytank_nB, FALSE, TRUE,
5284 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
5287 Ytank_e, FALSE, FALSE,
5288 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
5291 Ytank_eB, FALSE, TRUE,
5292 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
5295 Ytank_s, FALSE, FALSE,
5296 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
5299 Ytank_sB, FALSE, TRUE,
5300 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
5303 Ytank_w, FALSE, FALSE,
5304 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
5307 Ytank_wB, FALSE, TRUE,
5308 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
5311 Ytank_w_n, FALSE, FALSE,
5312 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
5315 Ytank_n_e, FALSE, FALSE,
5316 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
5319 Ytank_e_s, FALSE, FALSE,
5320 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
5323 Ytank_s_w, FALSE, FALSE,
5324 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
5327 Ytank_e_n, FALSE, FALSE,
5328 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
5331 Ytank_s_e, FALSE, FALSE,
5332 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
5335 Ytank_w_s, FALSE, FALSE,
5336 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
5339 Ytank_n_w, FALSE, FALSE,
5340 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
5343 Ytank_stone, FALSE, FALSE,
5344 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
5347 Ytank_spring, FALSE, FALSE,
5348 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
5351 Xandroid, TRUE, FALSE,
5352 EL_EMC_ANDROID, ACTION_ACTIVE, -1
5355 Xandroid_1_n, FALSE, FALSE,
5356 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
5359 Xandroid_2_n, FALSE, FALSE,
5360 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
5363 Xandroid_1_e, FALSE, FALSE,
5364 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
5367 Xandroid_2_e, FALSE, FALSE,
5368 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
5371 Xandroid_1_w, FALSE, FALSE,
5372 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
5375 Xandroid_2_w, FALSE, FALSE,
5376 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
5379 Xandroid_1_s, FALSE, FALSE,
5380 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
5383 Xandroid_2_s, FALSE, FALSE,
5384 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
5387 Yandroid_n, FALSE, FALSE,
5388 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
5391 Yandroid_nB, FALSE, TRUE,
5392 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
5395 Yandroid_ne, FALSE, FALSE,
5396 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
5399 Yandroid_neB, FALSE, TRUE,
5400 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
5403 Yandroid_e, FALSE, FALSE,
5404 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
5407 Yandroid_eB, FALSE, TRUE,
5408 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
5411 Yandroid_se, FALSE, FALSE,
5412 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
5415 Yandroid_seB, FALSE, TRUE,
5416 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
5419 Yandroid_s, FALSE, FALSE,
5420 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
5423 Yandroid_sB, FALSE, TRUE,
5424 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
5427 Yandroid_sw, FALSE, FALSE,
5428 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
5431 Yandroid_swB, FALSE, TRUE,
5432 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
5435 Yandroid_w, FALSE, FALSE,
5436 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
5439 Yandroid_wB, FALSE, TRUE,
5440 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
5443 Yandroid_nw, FALSE, FALSE,
5444 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
5447 Yandroid_nwB, FALSE, TRUE,
5448 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
5451 Xspring, TRUE, FALSE,
5455 Xspring_pause, FALSE, FALSE,
5459 Xspring_e, FALSE, FALSE,
5463 Xspring_w, FALSE, FALSE,
5467 Xspring_fall, FALSE, FALSE,
5471 Yspring_s, FALSE, FALSE,
5472 EL_SPRING, ACTION_FALLING, -1
5475 Yspring_sB, FALSE, TRUE,
5476 EL_SPRING, ACTION_FALLING, -1
5479 Yspring_e, FALSE, FALSE,
5480 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
5483 Yspring_eB, FALSE, TRUE,
5484 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
5487 Yspring_w, FALSE, FALSE,
5488 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
5491 Yspring_wB, FALSE, TRUE,
5492 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
5495 Yspring_kill_e, FALSE, FALSE,
5496 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
5499 Yspring_kill_eB, FALSE, TRUE,
5500 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
5503 Yspring_kill_w, FALSE, FALSE,
5504 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
5507 Yspring_kill_wB, FALSE, TRUE,
5508 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
5511 Xeater_n, TRUE, FALSE,
5512 EL_YAMYAM_UP, -1, -1
5515 Xeater_e, TRUE, FALSE,
5516 EL_YAMYAM_RIGHT, -1, -1
5519 Xeater_w, TRUE, FALSE,
5520 EL_YAMYAM_LEFT, -1, -1
5523 Xeater_s, TRUE, FALSE,
5524 EL_YAMYAM_DOWN, -1, -1
5527 Yeater_n, FALSE, FALSE,
5528 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
5531 Yeater_nB, FALSE, TRUE,
5532 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
5535 Yeater_e, FALSE, FALSE,
5536 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
5539 Yeater_eB, FALSE, TRUE,
5540 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
5543 Yeater_s, FALSE, FALSE,
5544 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
5547 Yeater_sB, FALSE, TRUE,
5548 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
5551 Yeater_w, FALSE, FALSE,
5552 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
5555 Yeater_wB, FALSE, TRUE,
5556 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
5559 Yeater_stone, FALSE, FALSE,
5560 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
5563 Yeater_spring, FALSE, FALSE,
5564 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
5567 Xalien, TRUE, FALSE,
5571 Xalien_pause, FALSE, FALSE,
5575 Yalien_n, FALSE, FALSE,
5576 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
5579 Yalien_nB, FALSE, TRUE,
5580 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
5583 Yalien_e, FALSE, FALSE,
5584 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
5587 Yalien_eB, FALSE, TRUE,
5588 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
5591 Yalien_s, FALSE, FALSE,
5592 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
5595 Yalien_sB, FALSE, TRUE,
5596 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
5599 Yalien_w, FALSE, FALSE,
5600 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
5603 Yalien_wB, FALSE, TRUE,
5604 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
5607 Yalien_stone, FALSE, FALSE,
5608 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
5611 Yalien_spring, FALSE, FALSE,
5612 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
5615 Xemerald, TRUE, FALSE,
5619 Xemerald_pause, FALSE, FALSE,
5623 Xemerald_fall, FALSE, FALSE,
5627 Xemerald_shine, FALSE, FALSE,
5628 EL_EMERALD, ACTION_TWINKLING, -1
5631 Yemerald_s, FALSE, FALSE,
5632 EL_EMERALD, ACTION_FALLING, -1
5635 Yemerald_sB, FALSE, TRUE,
5636 EL_EMERALD, ACTION_FALLING, -1
5639 Yemerald_e, FALSE, FALSE,
5640 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
5643 Yemerald_eB, FALSE, TRUE,
5644 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
5647 Yemerald_w, FALSE, FALSE,
5648 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
5651 Yemerald_wB, FALSE, TRUE,
5652 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
5655 Yemerald_eat, FALSE, FALSE,
5656 EL_EMERALD, ACTION_COLLECTING, -1
5659 Yemerald_stone, FALSE, FALSE,
5660 EL_NUT, ACTION_BREAKING, -1
5663 Xdiamond, TRUE, FALSE,
5667 Xdiamond_pause, FALSE, FALSE,
5671 Xdiamond_fall, FALSE, FALSE,
5675 Xdiamond_shine, FALSE, FALSE,
5676 EL_DIAMOND, ACTION_TWINKLING, -1
5679 Ydiamond_s, FALSE, FALSE,
5680 EL_DIAMOND, ACTION_FALLING, -1
5683 Ydiamond_sB, FALSE, TRUE,
5684 EL_DIAMOND, ACTION_FALLING, -1
5687 Ydiamond_e, FALSE, FALSE,
5688 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
5691 Ydiamond_eB, FALSE, TRUE,
5692 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
5695 Ydiamond_w, FALSE, FALSE,
5696 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
5699 Ydiamond_wB, FALSE, TRUE,
5700 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
5703 Ydiamond_eat, FALSE, FALSE,
5704 EL_DIAMOND, ACTION_COLLECTING, -1
5707 Ydiamond_stone, FALSE, FALSE,
5708 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
5711 Xdrip_fall, TRUE, FALSE,
5712 EL_AMOEBA_DROP, -1, -1
5715 Xdrip_stretch, FALSE, FALSE,
5716 EL_AMOEBA_DROP, ACTION_FALLING, -1
5719 Xdrip_stretchB, FALSE, TRUE,
5720 EL_AMOEBA_DROP, ACTION_FALLING, -1
5723 Xdrip_eat, FALSE, FALSE,
5724 EL_AMOEBA_DROP, ACTION_GROWING, -1
5727 Ydrip_s1, FALSE, FALSE,
5728 EL_AMOEBA_DROP, ACTION_FALLING, -1
5731 Ydrip_s1B, FALSE, TRUE,
5732 EL_AMOEBA_DROP, ACTION_FALLING, -1
5735 Ydrip_s2, FALSE, FALSE,
5736 EL_AMOEBA_DROP, ACTION_FALLING, -1
5739 Ydrip_s2B, FALSE, TRUE,
5740 EL_AMOEBA_DROP, ACTION_FALLING, -1
5747 Xbomb_pause, FALSE, FALSE,
5751 Xbomb_fall, FALSE, FALSE,
5755 Ybomb_s, FALSE, FALSE,
5756 EL_BOMB, ACTION_FALLING, -1
5759 Ybomb_sB, FALSE, TRUE,
5760 EL_BOMB, ACTION_FALLING, -1
5763 Ybomb_e, FALSE, FALSE,
5764 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
5767 Ybomb_eB, FALSE, TRUE,
5768 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
5771 Ybomb_w, FALSE, FALSE,
5772 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
5775 Ybomb_wB, FALSE, TRUE,
5776 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
5779 Ybomb_eat, FALSE, FALSE,
5780 EL_BOMB, ACTION_ACTIVATING, -1
5783 Xballoon, TRUE, FALSE,
5787 Yballoon_n, FALSE, FALSE,
5788 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
5791 Yballoon_nB, FALSE, TRUE,
5792 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
5795 Yballoon_e, FALSE, FALSE,
5796 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
5799 Yballoon_eB, FALSE, TRUE,
5800 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
5803 Yballoon_s, FALSE, FALSE,
5804 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
5807 Yballoon_sB, FALSE, TRUE,
5808 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
5811 Yballoon_w, FALSE, FALSE,
5812 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
5815 Yballoon_wB, FALSE, TRUE,
5816 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
5819 Xgrass, TRUE, FALSE,
5820 EL_EMC_GRASS, -1, -1
5823 Ygrass_nB, FALSE, FALSE,
5824 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
5827 Ygrass_eB, FALSE, FALSE,
5828 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
5831 Ygrass_sB, FALSE, FALSE,
5832 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
5835 Ygrass_wB, FALSE, FALSE,
5836 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
5843 Ydirt_nB, FALSE, FALSE,
5844 EL_SAND, ACTION_DIGGING, MV_BIT_UP
5847 Ydirt_eB, FALSE, FALSE,
5848 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
5851 Ydirt_sB, FALSE, FALSE,
5852 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
5855 Ydirt_wB, FALSE, FALSE,
5856 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
5859 Xacid_ne, TRUE, FALSE,
5860 EL_ACID_POOL_TOPRIGHT, -1, -1
5863 Xacid_se, TRUE, FALSE,
5864 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
5867 Xacid_s, TRUE, FALSE,
5868 EL_ACID_POOL_BOTTOM, -1, -1
5871 Xacid_sw, TRUE, FALSE,
5872 EL_ACID_POOL_BOTTOMLEFT, -1, -1
5875 Xacid_nw, TRUE, FALSE,
5876 EL_ACID_POOL_TOPLEFT, -1, -1
5879 Xacid_1, TRUE, FALSE,
5883 Xacid_2, FALSE, FALSE,
5887 Xacid_3, FALSE, FALSE,
5891 Xacid_4, FALSE, FALSE,
5895 Xacid_5, FALSE, FALSE,
5899 Xacid_6, FALSE, FALSE,
5903 Xacid_7, FALSE, FALSE,
5907 Xacid_8, FALSE, FALSE,
5911 Xball_1, TRUE, FALSE,
5912 EL_EMC_MAGIC_BALL, -1, -1
5915 Xball_1B, FALSE, FALSE,
5916 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5919 Xball_2, FALSE, FALSE,
5920 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5923 Xball_2B, FALSE, FALSE,
5924 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5927 Yball_eat, FALSE, FALSE,
5928 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
5931 Ykey_1_eat, FALSE, FALSE,
5932 EL_EM_KEY_1, ACTION_COLLECTING, -1
5935 Ykey_2_eat, FALSE, FALSE,
5936 EL_EM_KEY_2, ACTION_COLLECTING, -1
5939 Ykey_3_eat, FALSE, FALSE,
5940 EL_EM_KEY_3, ACTION_COLLECTING, -1
5943 Ykey_4_eat, FALSE, FALSE,
5944 EL_EM_KEY_4, ACTION_COLLECTING, -1
5947 Ykey_5_eat, FALSE, FALSE,
5948 EL_EMC_KEY_5, ACTION_COLLECTING, -1
5951 Ykey_6_eat, FALSE, FALSE,
5952 EL_EMC_KEY_6, ACTION_COLLECTING, -1
5955 Ykey_7_eat, FALSE, FALSE,
5956 EL_EMC_KEY_7, ACTION_COLLECTING, -1
5959 Ykey_8_eat, FALSE, FALSE,
5960 EL_EMC_KEY_8, ACTION_COLLECTING, -1
5963 Ylenses_eat, FALSE, FALSE,
5964 EL_EMC_LENSES, ACTION_COLLECTING, -1
5967 Ymagnify_eat, FALSE, FALSE,
5968 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
5971 Ygrass_eat, FALSE, FALSE,
5972 EL_EMC_GRASS, ACTION_SNAPPING, -1
5975 Ydirt_eat, FALSE, FALSE,
5976 EL_SAND, ACTION_SNAPPING, -1
5979 Xgrow_ns, TRUE, FALSE,
5980 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
5983 Ygrow_ns_eat, FALSE, FALSE,
5984 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
5987 Xgrow_ew, TRUE, FALSE,
5988 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
5991 Ygrow_ew_eat, FALSE, FALSE,
5992 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
5995 Xwonderwall, TRUE, FALSE,
5996 EL_MAGIC_WALL, -1, -1
5999 XwonderwallB, FALSE, FALSE,
6000 EL_MAGIC_WALL, ACTION_ACTIVE, -1
6003 Xamoeba_1, TRUE, FALSE,
6004 EL_AMOEBA_DRY, ACTION_OTHER, -1
6007 Xamoeba_2, FALSE, FALSE,
6008 EL_AMOEBA_DRY, ACTION_OTHER, -1
6011 Xamoeba_3, FALSE, FALSE,
6012 EL_AMOEBA_DRY, ACTION_OTHER, -1
6015 Xamoeba_4, FALSE, FALSE,
6016 EL_AMOEBA_DRY, ACTION_OTHER, -1
6019 Xamoeba_5, TRUE, FALSE,
6020 EL_AMOEBA_WET, ACTION_OTHER, -1
6023 Xamoeba_6, FALSE, FALSE,
6024 EL_AMOEBA_WET, ACTION_OTHER, -1
6027 Xamoeba_7, FALSE, FALSE,
6028 EL_AMOEBA_WET, ACTION_OTHER, -1
6031 Xamoeba_8, FALSE, FALSE,
6032 EL_AMOEBA_WET, ACTION_OTHER, -1
6035 Xdoor_1, TRUE, FALSE,
6036 EL_EM_GATE_1, -1, -1
6039 Xdoor_2, TRUE, FALSE,
6040 EL_EM_GATE_2, -1, -1
6043 Xdoor_3, TRUE, FALSE,
6044 EL_EM_GATE_3, -1, -1
6047 Xdoor_4, TRUE, FALSE,
6048 EL_EM_GATE_4, -1, -1
6051 Xdoor_5, TRUE, FALSE,
6052 EL_EMC_GATE_5, -1, -1
6055 Xdoor_6, TRUE, FALSE,
6056 EL_EMC_GATE_6, -1, -1
6059 Xdoor_7, TRUE, FALSE,
6060 EL_EMC_GATE_7, -1, -1
6063 Xdoor_8, TRUE, FALSE,
6064 EL_EMC_GATE_8, -1, -1
6067 Xkey_1, TRUE, FALSE,
6071 Xkey_2, TRUE, FALSE,
6075 Xkey_3, TRUE, FALSE,
6079 Xkey_4, TRUE, FALSE,
6083 Xkey_5, TRUE, FALSE,
6084 EL_EMC_KEY_5, -1, -1
6087 Xkey_6, TRUE, FALSE,
6088 EL_EMC_KEY_6, -1, -1
6091 Xkey_7, TRUE, FALSE,
6092 EL_EMC_KEY_7, -1, -1
6095 Xkey_8, TRUE, FALSE,
6096 EL_EMC_KEY_8, -1, -1
6099 Xwind_n, TRUE, FALSE,
6100 EL_BALLOON_SWITCH_UP, -1, -1
6103 Xwind_e, TRUE, FALSE,
6104 EL_BALLOON_SWITCH_RIGHT, -1, -1
6107 Xwind_s, TRUE, FALSE,
6108 EL_BALLOON_SWITCH_DOWN, -1, -1
6111 Xwind_w, TRUE, FALSE,
6112 EL_BALLOON_SWITCH_LEFT, -1, -1
6115 Xwind_nesw, TRUE, FALSE,
6116 EL_BALLOON_SWITCH_ANY, -1, -1
6119 Xwind_stop, TRUE, FALSE,
6120 EL_BALLOON_SWITCH_NONE, -1, -1
6124 EL_EM_EXIT_CLOSED, -1, -1
6127 Xexit_1, TRUE, FALSE,
6128 EL_EM_EXIT_OPEN, -1, -1
6131 Xexit_2, FALSE, FALSE,
6132 EL_EM_EXIT_OPEN, -1, -1
6135 Xexit_3, FALSE, FALSE,
6136 EL_EM_EXIT_OPEN, -1, -1
6139 Xdynamite, TRUE, FALSE,
6140 EL_EM_DYNAMITE, -1, -1
6143 Ydynamite_eat, FALSE, FALSE,
6144 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
6147 Xdynamite_1, TRUE, FALSE,
6148 EL_EM_DYNAMITE_ACTIVE, -1, -1
6151 Xdynamite_2, FALSE, FALSE,
6152 EL_EM_DYNAMITE_ACTIVE, -1, -1
6155 Xdynamite_3, FALSE, FALSE,
6156 EL_EM_DYNAMITE_ACTIVE, -1, -1
6159 Xdynamite_4, FALSE, FALSE,
6160 EL_EM_DYNAMITE_ACTIVE, -1, -1
6163 Xbumper, TRUE, FALSE,
6164 EL_EMC_SPRING_BUMPER, -1, -1
6167 XbumperB, FALSE, FALSE,
6168 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
6171 Xwheel, TRUE, FALSE,
6172 EL_ROBOT_WHEEL, -1, -1
6175 XwheelB, FALSE, FALSE,
6176 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
6179 Xswitch, TRUE, FALSE,
6180 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
6183 XswitchB, FALSE, FALSE,
6184 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
6188 EL_QUICKSAND_EMPTY, -1, -1
6191 Xsand_stone, TRUE, FALSE,
6192 EL_QUICKSAND_FULL, -1, -1
6195 Xsand_stonein_1, FALSE, TRUE,
6196 EL_ROCK, ACTION_FILLING, -1
6199 Xsand_stonein_2, FALSE, TRUE,
6200 EL_ROCK, ACTION_FILLING, -1
6203 Xsand_stonein_3, FALSE, TRUE,
6204 EL_ROCK, ACTION_FILLING, -1
6207 Xsand_stonein_4, FALSE, TRUE,
6208 EL_ROCK, ACTION_FILLING, -1
6211 Xsand_stonesand_1, FALSE, FALSE,
6212 EL_QUICKSAND_EMPTYING, -1, -1
6215 Xsand_stonesand_2, FALSE, FALSE,
6216 EL_QUICKSAND_EMPTYING, -1, -1
6219 Xsand_stonesand_3, FALSE, FALSE,
6220 EL_QUICKSAND_EMPTYING, -1, -1
6223 Xsand_stonesand_4, FALSE, FALSE,
6224 EL_QUICKSAND_EMPTYING, -1, -1
6227 Xsand_stonesand_quickout_1, FALSE, FALSE,
6228 EL_QUICKSAND_EMPTYING, -1, -1
6231 Xsand_stonesand_quickout_2, FALSE, FALSE,
6232 EL_QUICKSAND_EMPTYING, -1, -1
6235 Xsand_stoneout_1, FALSE, FALSE,
6236 EL_ROCK, ACTION_EMPTYING, -1
6239 Xsand_stoneout_2, FALSE, FALSE,
6240 EL_ROCK, ACTION_EMPTYING, -1
6243 Xsand_sandstone_1, FALSE, FALSE,
6244 EL_QUICKSAND_FILLING, -1, -1
6247 Xsand_sandstone_2, FALSE, FALSE,
6248 EL_QUICKSAND_FILLING, -1, -1
6251 Xsand_sandstone_3, FALSE, FALSE,
6252 EL_QUICKSAND_FILLING, -1, -1
6255 Xsand_sandstone_4, FALSE, FALSE,
6256 EL_QUICKSAND_FILLING, -1, -1
6259 Xplant, TRUE, FALSE,
6260 EL_EMC_PLANT, -1, -1
6263 Yplant, FALSE, FALSE,
6264 EL_EMC_PLANT, -1, -1
6267 Xlenses, TRUE, FALSE,
6268 EL_EMC_LENSES, -1, -1
6271 Xmagnify, TRUE, FALSE,
6272 EL_EMC_MAGNIFIER, -1, -1
6275 Xdripper, TRUE, FALSE,
6276 EL_EMC_DRIPPER, -1, -1
6279 XdripperB, FALSE, FALSE,
6280 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
6283 Xfake_blank, TRUE, FALSE,
6284 EL_INVISIBLE_WALL, -1, -1
6287 Xfake_blankB, FALSE, FALSE,
6288 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
6291 Xfake_grass, TRUE, FALSE,
6292 EL_EMC_FAKE_GRASS, -1, -1
6295 Xfake_grassB, FALSE, FALSE,
6296 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
6299 Xfake_door_1, TRUE, FALSE,
6300 EL_EM_GATE_1_GRAY, -1, -1
6303 Xfake_door_2, TRUE, FALSE,
6304 EL_EM_GATE_2_GRAY, -1, -1
6307 Xfake_door_3, TRUE, FALSE,
6308 EL_EM_GATE_3_GRAY, -1, -1
6311 Xfake_door_4, TRUE, FALSE,
6312 EL_EM_GATE_4_GRAY, -1, -1
6315 Xfake_door_5, TRUE, FALSE,
6316 EL_EMC_GATE_5_GRAY, -1, -1
6319 Xfake_door_6, TRUE, FALSE,
6320 EL_EMC_GATE_6_GRAY, -1, -1
6323 Xfake_door_7, TRUE, FALSE,
6324 EL_EMC_GATE_7_GRAY, -1, -1
6327 Xfake_door_8, TRUE, FALSE,
6328 EL_EMC_GATE_8_GRAY, -1, -1
6331 Xfake_acid_1, TRUE, FALSE,
6332 EL_EMC_FAKE_ACID, -1, -1
6335 Xfake_acid_2, FALSE, FALSE,
6336 EL_EMC_FAKE_ACID, -1, -1
6339 Xfake_acid_3, FALSE, FALSE,
6340 EL_EMC_FAKE_ACID, -1, -1
6343 Xfake_acid_4, FALSE, FALSE,
6344 EL_EMC_FAKE_ACID, -1, -1
6347 Xfake_acid_5, FALSE, FALSE,
6348 EL_EMC_FAKE_ACID, -1, -1
6351 Xfake_acid_6, FALSE, FALSE,
6352 EL_EMC_FAKE_ACID, -1, -1
6355 Xfake_acid_7, FALSE, FALSE,
6356 EL_EMC_FAKE_ACID, -1, -1
6359 Xfake_acid_8, FALSE, FALSE,
6360 EL_EMC_FAKE_ACID, -1, -1
6363 Xsteel_1, TRUE, FALSE,
6364 EL_STEELWALL, -1, -1
6367 Xsteel_2, TRUE, FALSE,
6368 EL_EMC_STEELWALL_2, -1, -1
6371 Xsteel_3, TRUE, FALSE,
6372 EL_EMC_STEELWALL_3, -1, -1
6375 Xsteel_4, TRUE, FALSE,
6376 EL_EMC_STEELWALL_4, -1, -1
6379 Xwall_1, TRUE, FALSE,
6383 Xwall_2, TRUE, FALSE,
6384 EL_EMC_WALL_14, -1, -1
6387 Xwall_3, TRUE, FALSE,
6388 EL_EMC_WALL_15, -1, -1
6391 Xwall_4, TRUE, FALSE,
6392 EL_EMC_WALL_16, -1, -1
6395 Xround_wall_1, TRUE, FALSE,
6396 EL_WALL_SLIPPERY, -1, -1
6399 Xround_wall_2, TRUE, FALSE,
6400 EL_EMC_WALL_SLIPPERY_2, -1, -1
6403 Xround_wall_3, TRUE, FALSE,
6404 EL_EMC_WALL_SLIPPERY_3, -1, -1
6407 Xround_wall_4, TRUE, FALSE,
6408 EL_EMC_WALL_SLIPPERY_4, -1, -1
6411 Xdecor_1, TRUE, FALSE,
6412 EL_EMC_WALL_8, -1, -1
6415 Xdecor_2, TRUE, FALSE,
6416 EL_EMC_WALL_6, -1, -1
6419 Xdecor_3, TRUE, FALSE,
6420 EL_EMC_WALL_4, -1, -1
6423 Xdecor_4, TRUE, FALSE,
6424 EL_EMC_WALL_7, -1, -1
6427 Xdecor_5, TRUE, FALSE,
6428 EL_EMC_WALL_5, -1, -1
6431 Xdecor_6, TRUE, FALSE,
6432 EL_EMC_WALL_9, -1, -1
6435 Xdecor_7, TRUE, FALSE,
6436 EL_EMC_WALL_10, -1, -1
6439 Xdecor_8, TRUE, FALSE,
6440 EL_EMC_WALL_1, -1, -1
6443 Xdecor_9, TRUE, FALSE,
6444 EL_EMC_WALL_2, -1, -1
6447 Xdecor_10, TRUE, FALSE,
6448 EL_EMC_WALL_3, -1, -1
6451 Xdecor_11, TRUE, FALSE,
6452 EL_EMC_WALL_11, -1, -1
6455 Xdecor_12, TRUE, FALSE,
6456 EL_EMC_WALL_12, -1, -1
6459 Xalpha_0, TRUE, FALSE,
6460 EL_CHAR('0'), -1, -1
6463 Xalpha_1, TRUE, FALSE,
6464 EL_CHAR('1'), -1, -1
6467 Xalpha_2, TRUE, FALSE,
6468 EL_CHAR('2'), -1, -1
6471 Xalpha_3, TRUE, FALSE,
6472 EL_CHAR('3'), -1, -1
6475 Xalpha_4, TRUE, FALSE,
6476 EL_CHAR('4'), -1, -1
6479 Xalpha_5, TRUE, FALSE,
6480 EL_CHAR('5'), -1, -1
6483 Xalpha_6, TRUE, FALSE,
6484 EL_CHAR('6'), -1, -1
6487 Xalpha_7, TRUE, FALSE,
6488 EL_CHAR('7'), -1, -1
6491 Xalpha_8, TRUE, FALSE,
6492 EL_CHAR('8'), -1, -1
6495 Xalpha_9, TRUE, FALSE,
6496 EL_CHAR('9'), -1, -1
6499 Xalpha_excla, TRUE, FALSE,
6500 EL_CHAR('!'), -1, -1
6503 Xalpha_quote, TRUE, FALSE,
6504 EL_CHAR('"'), -1, -1
6507 Xalpha_comma, TRUE, FALSE,
6508 EL_CHAR(','), -1, -1
6511 Xalpha_minus, TRUE, FALSE,
6512 EL_CHAR('-'), -1, -1
6515 Xalpha_perio, TRUE, FALSE,
6516 EL_CHAR('.'), -1, -1
6519 Xalpha_colon, TRUE, FALSE,
6520 EL_CHAR(':'), -1, -1
6523 Xalpha_quest, TRUE, FALSE,
6524 EL_CHAR('?'), -1, -1
6527 Xalpha_a, TRUE, FALSE,
6528 EL_CHAR('A'), -1, -1
6531 Xalpha_b, TRUE, FALSE,
6532 EL_CHAR('B'), -1, -1
6535 Xalpha_c, TRUE, FALSE,
6536 EL_CHAR('C'), -1, -1
6539 Xalpha_d, TRUE, FALSE,
6540 EL_CHAR('D'), -1, -1
6543 Xalpha_e, TRUE, FALSE,
6544 EL_CHAR('E'), -1, -1
6547 Xalpha_f, TRUE, FALSE,
6548 EL_CHAR('F'), -1, -1
6551 Xalpha_g, TRUE, FALSE,
6552 EL_CHAR('G'), -1, -1
6555 Xalpha_h, TRUE, FALSE,
6556 EL_CHAR('H'), -1, -1
6559 Xalpha_i, TRUE, FALSE,
6560 EL_CHAR('I'), -1, -1
6563 Xalpha_j, TRUE, FALSE,
6564 EL_CHAR('J'), -1, -1
6567 Xalpha_k, TRUE, FALSE,
6568 EL_CHAR('K'), -1, -1
6571 Xalpha_l, TRUE, FALSE,
6572 EL_CHAR('L'), -1, -1
6575 Xalpha_m, TRUE, FALSE,
6576 EL_CHAR('M'), -1, -1
6579 Xalpha_n, TRUE, FALSE,
6580 EL_CHAR('N'), -1, -1
6583 Xalpha_o, TRUE, FALSE,
6584 EL_CHAR('O'), -1, -1
6587 Xalpha_p, TRUE, FALSE,
6588 EL_CHAR('P'), -1, -1
6591 Xalpha_q, TRUE, FALSE,
6592 EL_CHAR('Q'), -1, -1
6595 Xalpha_r, TRUE, FALSE,
6596 EL_CHAR('R'), -1, -1
6599 Xalpha_s, TRUE, FALSE,
6600 EL_CHAR('S'), -1, -1
6603 Xalpha_t, TRUE, FALSE,
6604 EL_CHAR('T'), -1, -1
6607 Xalpha_u, TRUE, FALSE,
6608 EL_CHAR('U'), -1, -1
6611 Xalpha_v, TRUE, FALSE,
6612 EL_CHAR('V'), -1, -1
6615 Xalpha_w, TRUE, FALSE,
6616 EL_CHAR('W'), -1, -1
6619 Xalpha_x, TRUE, FALSE,
6620 EL_CHAR('X'), -1, -1
6623 Xalpha_y, TRUE, FALSE,
6624 EL_CHAR('Y'), -1, -1
6627 Xalpha_z, TRUE, FALSE,
6628 EL_CHAR('Z'), -1, -1
6631 Xalpha_arrow_e, TRUE, FALSE,
6632 EL_CHAR('>'), -1, -1
6635 Xalpha_arrow_w, TRUE, FALSE,
6636 EL_CHAR('<'), -1, -1
6639 Xalpha_copyr, TRUE, FALSE,
6640 EL_CHAR(CHAR_BYTE_COPYRIGHT), -1, -1
6644 Xboom_bug, FALSE, FALSE,
6645 EL_BUG, ACTION_EXPLODING, -1
6648 Xboom_bomb, FALSE, FALSE,
6649 EL_BOMB, ACTION_EXPLODING, -1
6652 Xboom_android, FALSE, FALSE,
6653 EL_EMC_ANDROID, ACTION_OTHER, -1
6656 Xboom_1, FALSE, FALSE,
6657 EL_DEFAULT, ACTION_EXPLODING, -1
6660 Xboom_2, FALSE, FALSE,
6661 EL_DEFAULT, ACTION_EXPLODING, -1
6664 Znormal, FALSE, FALSE,
6668 Zdynamite, FALSE, FALSE,
6672 Zplayer, FALSE, FALSE,
6676 ZBORDER, FALSE, FALSE,
6686 static struct Mapping_EM_to_RND_player
6695 em_player_mapping_list[] =
6699 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
6703 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
6707 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
6711 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
6715 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
6719 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
6723 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
6727 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
6731 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
6735 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
6739 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
6743 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
6747 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
6751 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
6755 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
6759 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
6763 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
6767 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
6771 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
6775 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
6779 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
6783 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
6787 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
6791 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
6795 EL_PLAYER_1, ACTION_DEFAULT, -1,
6799 EL_PLAYER_2, ACTION_DEFAULT, -1,
6803 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
6807 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
6811 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
6815 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
6819 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
6823 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
6827 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
6831 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
6835 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
6839 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
6843 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
6847 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
6851 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
6855 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
6859 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
6863 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
6867 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
6871 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
6875 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
6879 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
6883 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
6887 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
6891 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
6895 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
6899 EL_PLAYER_3, ACTION_DEFAULT, -1,
6903 EL_PLAYER_4, ACTION_DEFAULT, -1,
6912 int map_element_RND_to_EM(int element_rnd)
6914 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
6915 static boolean mapping_initialized = FALSE;
6917 if (!mapping_initialized)
6921 /* return "Xalpha_quest" for all undefined elements in mapping array */
6922 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
6923 mapping_RND_to_EM[i] = Xalpha_quest;
6925 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6926 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
6927 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
6928 em_object_mapping_list[i].element_em;
6930 mapping_initialized = TRUE;
6933 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
6934 return mapping_RND_to_EM[element_rnd];
6936 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
6941 int map_element_EM_to_RND(int element_em)
6943 static unsigned short mapping_EM_to_RND[TILE_MAX];
6944 static boolean mapping_initialized = FALSE;
6946 if (!mapping_initialized)
6950 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
6951 for (i = 0; i < TILE_MAX; i++)
6952 mapping_EM_to_RND[i] = EL_UNKNOWN;
6954 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6955 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
6956 em_object_mapping_list[i].element_rnd;
6958 mapping_initialized = TRUE;
6961 if (element_em >= 0 && element_em < TILE_MAX)
6962 return mapping_EM_to_RND[element_em];
6964 Error(ERR_WARN, "invalid EM level element %d", element_em);
6969 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
6971 struct LevelInfo_EM *level_em = level->native_em_level;
6972 struct LEVEL *lev = level_em->lev;
6975 for (i = 0; i < TILE_MAX; i++)
6976 lev->android_array[i] = Xblank;
6978 for (i = 0; i < level->num_android_clone_elements; i++)
6980 int element_rnd = level->android_clone_element[i];
6981 int element_em = map_element_RND_to_EM(element_rnd);
6983 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
6984 if (em_object_mapping_list[j].element_rnd == element_rnd)
6985 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
6989 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
6991 struct LevelInfo_EM *level_em = level->native_em_level;
6992 struct LEVEL *lev = level_em->lev;
6995 level->num_android_clone_elements = 0;
6997 for (i = 0; i < TILE_MAX; i++)
6999 int element_em = lev->android_array[i];
7001 boolean element_found = FALSE;
7003 if (element_em == Xblank)
7006 element_rnd = map_element_EM_to_RND(element_em);
7008 for (j = 0; j < level->num_android_clone_elements; j++)
7009 if (level->android_clone_element[j] == element_rnd)
7010 element_found = TRUE;
7014 level->android_clone_element[level->num_android_clone_elements++] =
7017 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
7022 if (level->num_android_clone_elements == 0)
7024 level->num_android_clone_elements = 1;
7025 level->android_clone_element[0] = EL_EMPTY;
7029 int map_direction_RND_to_EM(int direction)
7031 return (direction == MV_UP ? 0 :
7032 direction == MV_RIGHT ? 1 :
7033 direction == MV_DOWN ? 2 :
7034 direction == MV_LEFT ? 3 :
7038 int map_direction_EM_to_RND(int direction)
7040 return (direction == 0 ? MV_UP :
7041 direction == 1 ? MV_RIGHT :
7042 direction == 2 ? MV_DOWN :
7043 direction == 3 ? MV_LEFT :
7047 int map_element_RND_to_SP(int element_rnd)
7049 int element_sp = 0x20; /* map unknown elements to yellow "hardware" */
7051 if (element_rnd >= EL_SP_START &&
7052 element_rnd <= EL_SP_END)
7053 element_sp = element_rnd - EL_SP_START;
7054 else if (element_rnd == EL_EMPTY_SPACE)
7056 else if (element_rnd == EL_INVISIBLE_WALL)
7062 int map_element_SP_to_RND(int element_sp)
7064 int element_rnd = EL_UNKNOWN;
7066 if (element_sp >= 0x00 &&
7068 element_rnd = EL_SP_START + element_sp;
7069 else if (element_sp == 0x28)
7070 element_rnd = EL_INVISIBLE_WALL;
7075 int map_action_SP_to_RND(int action_sp)
7079 case actActive: return ACTION_ACTIVE;
7080 case actImpact: return ACTION_IMPACT;
7081 case actExploding: return ACTION_EXPLODING;
7082 case actDigging: return ACTION_DIGGING;
7083 case actSnapping: return ACTION_SNAPPING;
7084 case actCollecting: return ACTION_COLLECTING;
7085 case actPassing: return ACTION_PASSING;
7086 case actPushing: return ACTION_PUSHING;
7087 case actDropping: return ACTION_DROPPING;
7089 default: return ACTION_DEFAULT;
7093 int get_next_element(int element)
7097 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
7098 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
7099 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
7100 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
7101 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
7102 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
7103 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
7104 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
7105 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
7106 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
7107 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
7109 default: return element;
7113 int el_act_dir2img(int element, int action, int direction)
7115 element = GFX_ELEMENT(element);
7116 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
7118 /* direction_graphic[][] == graphic[] for undefined direction graphics */
7119 return element_info[element].direction_graphic[action][direction];
7122 static int el_act_dir2crm(int element, int action, int direction)
7124 element = GFX_ELEMENT(element);
7125 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
7127 /* direction_graphic[][] == graphic[] for undefined direction graphics */
7128 return element_info[element].direction_crumbled[action][direction];
7131 int el_act2img(int element, int action)
7133 element = GFX_ELEMENT(element);
7135 return element_info[element].graphic[action];
7138 int el_act2crm(int element, int action)
7140 element = GFX_ELEMENT(element);
7142 return element_info[element].crumbled[action];
7145 int el_dir2img(int element, int direction)
7147 element = GFX_ELEMENT(element);
7149 return el_act_dir2img(element, ACTION_DEFAULT, direction);
7152 int el2baseimg(int element)
7154 return element_info[element].graphic[ACTION_DEFAULT];
7157 int el2img(int element)
7159 element = GFX_ELEMENT(element);
7161 return element_info[element].graphic[ACTION_DEFAULT];
7164 int el2edimg(int element)
7166 element = GFX_ELEMENT(element);
7168 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
7171 int el2preimg(int element)
7173 element = GFX_ELEMENT(element);
7175 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
7178 int el2panelimg(int element)
7180 element = GFX_ELEMENT(element);
7182 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL];
7185 int font2baseimg(int font_nr)
7187 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
7190 int getBeltNrFromBeltElement(int element)
7192 return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
7193 element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
7194 element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
7197 int getBeltNrFromBeltActiveElement(int element)
7199 return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
7200 element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
7201 element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
7204 int getBeltNrFromBeltSwitchElement(int element)
7206 return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
7207 element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
7208 element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
7211 int getBeltDirNrFromBeltElement(int element)
7213 static int belt_base_element[4] =
7215 EL_CONVEYOR_BELT_1_LEFT,
7216 EL_CONVEYOR_BELT_2_LEFT,
7217 EL_CONVEYOR_BELT_3_LEFT,
7218 EL_CONVEYOR_BELT_4_LEFT
7221 int belt_nr = getBeltNrFromBeltElement(element);
7222 int belt_dir_nr = element - belt_base_element[belt_nr];
7224 return (belt_dir_nr % 3);
7227 int getBeltDirNrFromBeltSwitchElement(int element)
7229 static int belt_base_element[4] =
7231 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
7232 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
7233 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
7234 EL_CONVEYOR_BELT_4_SWITCH_LEFT
7237 int belt_nr = getBeltNrFromBeltSwitchElement(element);
7238 int belt_dir_nr = element - belt_base_element[belt_nr];
7240 return (belt_dir_nr % 3);
7243 int getBeltDirFromBeltElement(int element)
7245 static int belt_move_dir[3] =
7252 int belt_dir_nr = getBeltDirNrFromBeltElement(element);
7254 return belt_move_dir[belt_dir_nr];
7257 int getBeltDirFromBeltSwitchElement(int element)
7259 static int belt_move_dir[3] =
7266 int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
7268 return belt_move_dir[belt_dir_nr];
7271 int getBeltElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
7273 static int belt_base_element[4] =
7275 EL_CONVEYOR_BELT_1_LEFT,
7276 EL_CONVEYOR_BELT_2_LEFT,
7277 EL_CONVEYOR_BELT_3_LEFT,
7278 EL_CONVEYOR_BELT_4_LEFT
7281 return belt_base_element[belt_nr] + belt_dir_nr;
7284 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
7286 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
7288 return getBeltElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
7291 int getBeltSwitchElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
7293 static int belt_base_element[4] =
7295 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
7296 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
7297 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
7298 EL_CONVEYOR_BELT_4_SWITCH_LEFT
7301 return belt_base_element[belt_nr] + belt_dir_nr;
7304 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
7306 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
7308 return getBeltSwitchElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
7311 boolean getTeamMode_EM()
7313 return game.team_mode;
7316 int getGameFrameDelay_EM(int native_em_game_frame_delay)
7318 int game_frame_delay_value;
7320 game_frame_delay_value =
7321 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
7322 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
7325 if (tape.playing && tape.warp_forward && !tape.pausing)
7326 game_frame_delay_value = 0;
7328 return game_frame_delay_value;
7331 unsigned int InitRND(int seed)
7333 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
7334 return InitEngineRandom_EM(seed);
7335 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
7336 return InitEngineRandom_SP(seed);
7338 return InitEngineRandom_RND(seed);
7341 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
7342 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
7344 inline static int get_effective_element_EM(int tile, int frame_em)
7346 int element = object_mapping[tile].element_rnd;
7347 int action = object_mapping[tile].action;
7348 boolean is_backside = object_mapping[tile].is_backside;
7349 boolean action_removing = (action == ACTION_DIGGING ||
7350 action == ACTION_SNAPPING ||
7351 action == ACTION_COLLECTING);
7357 case Yacid_splash_eB:
7358 case Yacid_splash_wB:
7359 return (frame_em > 5 ? EL_EMPTY : element);
7365 else /* frame_em == 7 */
7369 case Yacid_splash_eB:
7370 case Yacid_splash_wB:
7373 case Yemerald_stone:
7376 case Ydiamond_stone:
7380 case Xdrip_stretchB:
7399 case Xsand_stonein_1:
7400 case Xsand_stonein_2:
7401 case Xsand_stonein_3:
7402 case Xsand_stonein_4:
7406 return (is_backside || action_removing ? EL_EMPTY : element);
7411 inline static boolean check_linear_animation_EM(int tile)
7415 case Xsand_stonesand_1:
7416 case Xsand_stonesand_quickout_1:
7417 case Xsand_sandstone_1:
7418 case Xsand_stonein_1:
7419 case Xsand_stoneout_1:
7438 case Yacid_splash_eB:
7439 case Yacid_splash_wB:
7440 case Yemerald_stone:
7447 inline static void set_crumbled_graphics_EM(struct GraphicInfo_EM *g_em,
7448 boolean has_crumbled_graphics,
7449 int crumbled, int sync_frame)
7451 /* if element can be crumbled, but certain action graphics are just empty
7452 space (like instantly snapping sand to empty space in 1 frame), do not
7453 treat these empty space graphics as crumbled graphics in EMC engine */
7454 if (crumbled == IMG_EMPTY_SPACE)
7455 has_crumbled_graphics = FALSE;
7457 if (has_crumbled_graphics)
7459 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
7460 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
7461 g_crumbled->anim_delay,
7462 g_crumbled->anim_mode,
7463 g_crumbled->anim_start_frame,
7466 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
7467 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
7469 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
7470 g_em->crumbled_tile_size = graphic_info[crumbled].tile_size;
7472 g_em->has_crumbled_graphics = TRUE;
7476 g_em->crumbled_bitmap = NULL;
7477 g_em->crumbled_src_x = 0;
7478 g_em->crumbled_src_y = 0;
7479 g_em->crumbled_border_size = 0;
7480 g_em->crumbled_tile_size = 0;
7482 g_em->has_crumbled_graphics = FALSE;
7486 void ResetGfxAnimation_EM(int x, int y, int tile)
7491 void SetGfxAnimation_EM(struct GraphicInfo_EM *g_em,
7492 int tile, int frame_em, int x, int y)
7494 int action = object_mapping[tile].action;
7495 int direction = object_mapping[tile].direction;
7496 int effective_element = get_effective_element_EM(tile, frame_em);
7497 int graphic = (direction == MV_NONE ?
7498 el_act2img(effective_element, action) :
7499 el_act_dir2img(effective_element, action, direction));
7500 struct GraphicInfo *g = &graphic_info[graphic];
7502 boolean action_removing = (action == ACTION_DIGGING ||
7503 action == ACTION_SNAPPING ||
7504 action == ACTION_COLLECTING);
7505 boolean action_moving = (action == ACTION_FALLING ||
7506 action == ACTION_MOVING ||
7507 action == ACTION_PUSHING ||
7508 action == ACTION_EATING ||
7509 action == ACTION_FILLING ||
7510 action == ACTION_EMPTYING);
7511 boolean action_falling = (action == ACTION_FALLING ||
7512 action == ACTION_FILLING ||
7513 action == ACTION_EMPTYING);
7515 /* special case: graphic uses "2nd movement tile" and has defined
7516 7 frames for movement animation (or less) => use default graphic
7517 for last (8th) frame which ends the movement animation */
7518 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
7520 action = ACTION_DEFAULT; /* (keep action_* unchanged for now) */
7521 graphic = (direction == MV_NONE ?
7522 el_act2img(effective_element, action) :
7523 el_act_dir2img(effective_element, action, direction));
7525 g = &graphic_info[graphic];
7528 if ((action_removing || check_linear_animation_EM(tile)) && frame_em == 0)
7532 else if (action_moving)
7534 boolean is_backside = object_mapping[tile].is_backside;
7538 int direction = object_mapping[tile].direction;
7539 int move_dir = (action_falling ? MV_DOWN : direction);
7544 /* !!! TEST !!! NEW !!! DOES NOT WORK RIGHT YET !!! */
7545 if (g->double_movement && frame_em == 0)
7549 if (move_dir == MV_LEFT)
7550 GfxFrame[x - 1][y] = GfxFrame[x][y];
7551 else if (move_dir == MV_RIGHT)
7552 GfxFrame[x + 1][y] = GfxFrame[x][y];
7553 else if (move_dir == MV_UP)
7554 GfxFrame[x][y - 1] = GfxFrame[x][y];
7555 else if (move_dir == MV_DOWN)
7556 GfxFrame[x][y + 1] = GfxFrame[x][y];
7563 /* special case: animation for Xsand_stonesand_quickout_1/2 twice as fast */
7564 if (tile == Xsand_stonesand_quickout_1 ||
7565 tile == Xsand_stonesand_quickout_2)
7569 if (graphic_info[graphic].anim_global_sync)
7570 sync_frame = FrameCounter;
7571 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
7572 sync_frame = GfxFrame[x][y];
7574 sync_frame = 0; /* playfield border (pseudo steel) */
7576 SetRandomAnimationValue(x, y);
7578 int frame = getAnimationFrame(g->anim_frames,
7581 g->anim_start_frame,
7584 g_em->unique_identifier =
7585 (graphic << 16) | ((frame % 8) << 12) | (g_em->width << 6) | g_em->height;
7588 void getGraphicSourceObjectExt_EM(struct GraphicInfo_EM *g_em,
7589 int tile, int frame_em, int x, int y)
7591 int action = object_mapping[tile].action;
7592 int direction = object_mapping[tile].direction;
7593 boolean is_backside = object_mapping[tile].is_backside;
7594 int effective_element = get_effective_element_EM(tile, frame_em);
7595 int effective_action = action;
7596 int graphic = (direction == MV_NONE ?
7597 el_act2img(effective_element, effective_action) :
7598 el_act_dir2img(effective_element, effective_action,
7600 int crumbled = (direction == MV_NONE ?
7601 el_act2crm(effective_element, effective_action) :
7602 el_act_dir2crm(effective_element, effective_action,
7604 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7605 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7606 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7607 struct GraphicInfo *g = &graphic_info[graphic];
7610 /* special case: graphic uses "2nd movement tile" and has defined
7611 7 frames for movement animation (or less) => use default graphic
7612 for last (8th) frame which ends the movement animation */
7613 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
7615 effective_action = ACTION_DEFAULT;
7616 graphic = (direction == MV_NONE ?
7617 el_act2img(effective_element, effective_action) :
7618 el_act_dir2img(effective_element, effective_action,
7620 crumbled = (direction == MV_NONE ?
7621 el_act2crm(effective_element, effective_action) :
7622 el_act_dir2crm(effective_element, effective_action,
7625 g = &graphic_info[graphic];
7628 if (graphic_info[graphic].anim_global_sync)
7629 sync_frame = FrameCounter;
7630 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
7631 sync_frame = GfxFrame[x][y];
7633 sync_frame = 0; /* playfield border (pseudo steel) */
7635 SetRandomAnimationValue(x, y);
7637 int frame = getAnimationFrame(g->anim_frames,
7640 g->anim_start_frame,
7643 getGraphicSourceExt(graphic, frame, &g_em->bitmap, &g_em->src_x, &g_em->src_y,
7644 g->double_movement && is_backside);
7646 /* (updating the "crumbled" graphic definitions is probably not really needed,
7647 as animations for crumbled graphics can't be longer than one EMC cycle) */
7648 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
7652 void getGraphicSourcePlayerExt_EM(struct GraphicInfo_EM *g_em,
7653 int player_nr, int anim, int frame_em)
7655 int element = player_mapping[player_nr][anim].element_rnd;
7656 int action = player_mapping[player_nr][anim].action;
7657 int direction = player_mapping[player_nr][anim].direction;
7658 int graphic = (direction == MV_NONE ?
7659 el_act2img(element, action) :
7660 el_act_dir2img(element, action, direction));
7661 struct GraphicInfo *g = &graphic_info[graphic];
7664 InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
7666 stored_player[player_nr].StepFrame = frame_em;
7668 sync_frame = stored_player[player_nr].Frame;
7670 int frame = getAnimationFrame(g->anim_frames,
7673 g->anim_start_frame,
7676 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
7677 &g_em->src_x, &g_em->src_y, FALSE);
7680 void InitGraphicInfo_EM(void)
7685 int num_em_gfx_errors = 0;
7687 if (graphic_info_em_object[0][0].bitmap == NULL)
7689 /* EM graphics not yet initialized in em_open_all() */
7694 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
7697 /* always start with reliable default values */
7698 for (i = 0; i < TILE_MAX; i++)
7700 object_mapping[i].element_rnd = EL_UNKNOWN;
7701 object_mapping[i].is_backside = FALSE;
7702 object_mapping[i].action = ACTION_DEFAULT;
7703 object_mapping[i].direction = MV_NONE;
7706 /* always start with reliable default values */
7707 for (p = 0; p < MAX_PLAYERS; p++)
7709 for (i = 0; i < SPR_MAX; i++)
7711 player_mapping[p][i].element_rnd = EL_UNKNOWN;
7712 player_mapping[p][i].action = ACTION_DEFAULT;
7713 player_mapping[p][i].direction = MV_NONE;
7717 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
7719 int e = em_object_mapping_list[i].element_em;
7721 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
7722 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
7724 if (em_object_mapping_list[i].action != -1)
7725 object_mapping[e].action = em_object_mapping_list[i].action;
7727 if (em_object_mapping_list[i].direction != -1)
7728 object_mapping[e].direction =
7729 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
7732 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
7734 int a = em_player_mapping_list[i].action_em;
7735 int p = em_player_mapping_list[i].player_nr;
7737 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
7739 if (em_player_mapping_list[i].action != -1)
7740 player_mapping[p][a].action = em_player_mapping_list[i].action;
7742 if (em_player_mapping_list[i].direction != -1)
7743 player_mapping[p][a].direction =
7744 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
7747 for (i = 0; i < TILE_MAX; i++)
7749 int element = object_mapping[i].element_rnd;
7750 int action = object_mapping[i].action;
7751 int direction = object_mapping[i].direction;
7752 boolean is_backside = object_mapping[i].is_backside;
7753 boolean action_exploding = ((action == ACTION_EXPLODING ||
7754 action == ACTION_SMASHED_BY_ROCK ||
7755 action == ACTION_SMASHED_BY_SPRING) &&
7756 element != EL_DIAMOND);
7757 boolean action_active = (action == ACTION_ACTIVE);
7758 boolean action_other = (action == ACTION_OTHER);
7760 for (j = 0; j < 8; j++)
7762 int effective_element = get_effective_element_EM(i, j);
7763 int effective_action = (j < 7 ? action :
7764 i == Xdrip_stretch ? action :
7765 i == Xdrip_stretchB ? action :
7766 i == Ydrip_s1 ? action :
7767 i == Ydrip_s1B ? action :
7768 i == Xball_1B ? action :
7769 i == Xball_2 ? action :
7770 i == Xball_2B ? action :
7771 i == Yball_eat ? action :
7772 i == Ykey_1_eat ? action :
7773 i == Ykey_2_eat ? action :
7774 i == Ykey_3_eat ? action :
7775 i == Ykey_4_eat ? action :
7776 i == Ykey_5_eat ? action :
7777 i == Ykey_6_eat ? action :
7778 i == Ykey_7_eat ? action :
7779 i == Ykey_8_eat ? action :
7780 i == Ylenses_eat ? action :
7781 i == Ymagnify_eat ? action :
7782 i == Ygrass_eat ? action :
7783 i == Ydirt_eat ? action :
7784 i == Xsand_stonein_1 ? action :
7785 i == Xsand_stonein_2 ? action :
7786 i == Xsand_stonein_3 ? action :
7787 i == Xsand_stonein_4 ? action :
7788 i == Xsand_stoneout_1 ? action :
7789 i == Xsand_stoneout_2 ? action :
7790 i == Xboom_android ? ACTION_EXPLODING :
7791 action_exploding ? ACTION_EXPLODING :
7792 action_active ? action :
7793 action_other ? action :
7795 int graphic = (el_act_dir2img(effective_element, effective_action,
7797 int crumbled = (el_act_dir2crm(effective_element, effective_action,
7799 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7800 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7801 boolean has_action_graphics = (graphic != base_graphic);
7802 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7803 struct GraphicInfo *g = &graphic_info[graphic];
7804 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7807 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
7808 boolean special_animation = (action != ACTION_DEFAULT &&
7809 g->anim_frames == 3 &&
7810 g->anim_delay == 2 &&
7811 g->anim_mode & ANIM_LINEAR);
7812 int sync_frame = (i == Xdrip_stretch ? 7 :
7813 i == Xdrip_stretchB ? 7 :
7814 i == Ydrip_s2 ? j + 8 :
7815 i == Ydrip_s2B ? j + 8 :
7824 i == Xfake_acid_1 ? 0 :
7825 i == Xfake_acid_2 ? 10 :
7826 i == Xfake_acid_3 ? 20 :
7827 i == Xfake_acid_4 ? 30 :
7828 i == Xfake_acid_5 ? 40 :
7829 i == Xfake_acid_6 ? 50 :
7830 i == Xfake_acid_7 ? 60 :
7831 i == Xfake_acid_8 ? 70 :
7833 i == Xball_2B ? j + 8 :
7834 i == Yball_eat ? j + 1 :
7835 i == Ykey_1_eat ? j + 1 :
7836 i == Ykey_2_eat ? j + 1 :
7837 i == Ykey_3_eat ? j + 1 :
7838 i == Ykey_4_eat ? j + 1 :
7839 i == Ykey_5_eat ? j + 1 :
7840 i == Ykey_6_eat ? j + 1 :
7841 i == Ykey_7_eat ? j + 1 :
7842 i == Ykey_8_eat ? j + 1 :
7843 i == Ylenses_eat ? j + 1 :
7844 i == Ymagnify_eat ? j + 1 :
7845 i == Ygrass_eat ? j + 1 :
7846 i == Ydirt_eat ? j + 1 :
7847 i == Xamoeba_1 ? 0 :
7848 i == Xamoeba_2 ? 1 :
7849 i == Xamoeba_3 ? 2 :
7850 i == Xamoeba_4 ? 3 :
7851 i == Xamoeba_5 ? 0 :
7852 i == Xamoeba_6 ? 1 :
7853 i == Xamoeba_7 ? 2 :
7854 i == Xamoeba_8 ? 3 :
7855 i == Xexit_2 ? j + 8 :
7856 i == Xexit_3 ? j + 16 :
7857 i == Xdynamite_1 ? 0 :
7858 i == Xdynamite_2 ? 8 :
7859 i == Xdynamite_3 ? 16 :
7860 i == Xdynamite_4 ? 24 :
7861 i == Xsand_stonein_1 ? j + 1 :
7862 i == Xsand_stonein_2 ? j + 9 :
7863 i == Xsand_stonein_3 ? j + 17 :
7864 i == Xsand_stonein_4 ? j + 25 :
7865 i == Xsand_stoneout_1 && j == 0 ? 0 :
7866 i == Xsand_stoneout_1 && j == 1 ? 0 :
7867 i == Xsand_stoneout_1 && j == 2 ? 1 :
7868 i == Xsand_stoneout_1 && j == 3 ? 2 :
7869 i == Xsand_stoneout_1 && j == 4 ? 2 :
7870 i == Xsand_stoneout_1 && j == 5 ? 3 :
7871 i == Xsand_stoneout_1 && j == 6 ? 4 :
7872 i == Xsand_stoneout_1 && j == 7 ? 4 :
7873 i == Xsand_stoneout_2 && j == 0 ? 5 :
7874 i == Xsand_stoneout_2 && j == 1 ? 6 :
7875 i == Xsand_stoneout_2 && j == 2 ? 7 :
7876 i == Xsand_stoneout_2 && j == 3 ? 8 :
7877 i == Xsand_stoneout_2 && j == 4 ? 9 :
7878 i == Xsand_stoneout_2 && j == 5 ? 11 :
7879 i == Xsand_stoneout_2 && j == 6 ? 13 :
7880 i == Xsand_stoneout_2 && j == 7 ? 15 :
7881 i == Xboom_bug && j == 1 ? 2 :
7882 i == Xboom_bug && j == 2 ? 2 :
7883 i == Xboom_bug && j == 3 ? 4 :
7884 i == Xboom_bug && j == 4 ? 4 :
7885 i == Xboom_bug && j == 5 ? 2 :
7886 i == Xboom_bug && j == 6 ? 2 :
7887 i == Xboom_bug && j == 7 ? 0 :
7888 i == Xboom_bomb && j == 1 ? 2 :
7889 i == Xboom_bomb && j == 2 ? 2 :
7890 i == Xboom_bomb && j == 3 ? 4 :
7891 i == Xboom_bomb && j == 4 ? 4 :
7892 i == Xboom_bomb && j == 5 ? 2 :
7893 i == Xboom_bomb && j == 6 ? 2 :
7894 i == Xboom_bomb && j == 7 ? 0 :
7895 i == Xboom_android && j == 7 ? 6 :
7896 i == Xboom_1 && j == 1 ? 2 :
7897 i == Xboom_1 && j == 2 ? 2 :
7898 i == Xboom_1 && j == 3 ? 4 :
7899 i == Xboom_1 && j == 4 ? 4 :
7900 i == Xboom_1 && j == 5 ? 6 :
7901 i == Xboom_1 && j == 6 ? 6 :
7902 i == Xboom_1 && j == 7 ? 8 :
7903 i == Xboom_2 && j == 0 ? 8 :
7904 i == Xboom_2 && j == 1 ? 8 :
7905 i == Xboom_2 && j == 2 ? 10 :
7906 i == Xboom_2 && j == 3 ? 10 :
7907 i == Xboom_2 && j == 4 ? 10 :
7908 i == Xboom_2 && j == 5 ? 12 :
7909 i == Xboom_2 && j == 6 ? 12 :
7910 i == Xboom_2 && j == 7 ? 12 :
7911 special_animation && j == 4 ? 3 :
7912 effective_action != action ? 0 :
7916 Bitmap *debug_bitmap = g_em->bitmap;
7917 int debug_src_x = g_em->src_x;
7918 int debug_src_y = g_em->src_y;
7921 int frame = getAnimationFrame(g->anim_frames,
7924 g->anim_start_frame,
7927 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
7928 g->double_movement && is_backside);
7930 g_em->bitmap = src_bitmap;
7931 g_em->src_x = src_x;
7932 g_em->src_y = src_y;
7933 g_em->src_offset_x = 0;
7934 g_em->src_offset_y = 0;
7935 g_em->dst_offset_x = 0;
7936 g_em->dst_offset_y = 0;
7937 g_em->width = TILEX;
7938 g_em->height = TILEY;
7940 g_em->preserve_background = FALSE;
7942 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
7945 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
7946 effective_action == ACTION_MOVING ||
7947 effective_action == ACTION_PUSHING ||
7948 effective_action == ACTION_EATING)) ||
7949 (!has_action_graphics && (effective_action == ACTION_FILLING ||
7950 effective_action == ACTION_EMPTYING)))
7953 (effective_action == ACTION_FALLING ||
7954 effective_action == ACTION_FILLING ||
7955 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
7956 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
7957 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
7958 int num_steps = (i == Ydrip_s1 ? 16 :
7959 i == Ydrip_s1B ? 16 :
7960 i == Ydrip_s2 ? 16 :
7961 i == Ydrip_s2B ? 16 :
7962 i == Xsand_stonein_1 ? 32 :
7963 i == Xsand_stonein_2 ? 32 :
7964 i == Xsand_stonein_3 ? 32 :
7965 i == Xsand_stonein_4 ? 32 :
7966 i == Xsand_stoneout_1 ? 16 :
7967 i == Xsand_stoneout_2 ? 16 : 8);
7968 int cx = ABS(dx) * (TILEX / num_steps);
7969 int cy = ABS(dy) * (TILEY / num_steps);
7970 int step_frame = (i == Ydrip_s2 ? j + 8 :
7971 i == Ydrip_s2B ? j + 8 :
7972 i == Xsand_stonein_2 ? j + 8 :
7973 i == Xsand_stonein_3 ? j + 16 :
7974 i == Xsand_stonein_4 ? j + 24 :
7975 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
7976 int step = (is_backside ? step_frame : num_steps - step_frame);
7978 if (is_backside) /* tile where movement starts */
7980 if (dx < 0 || dy < 0)
7982 g_em->src_offset_x = cx * step;
7983 g_em->src_offset_y = cy * step;
7987 g_em->dst_offset_x = cx * step;
7988 g_em->dst_offset_y = cy * step;
7991 else /* tile where movement ends */
7993 if (dx < 0 || dy < 0)
7995 g_em->dst_offset_x = cx * step;
7996 g_em->dst_offset_y = cy * step;
8000 g_em->src_offset_x = cx * step;
8001 g_em->src_offset_y = cy * step;
8005 g_em->width = TILEX - cx * step;
8006 g_em->height = TILEY - cy * step;
8009 /* create unique graphic identifier to decide if tile must be redrawn */
8010 /* bit 31 - 16 (16 bit): EM style graphic
8011 bit 15 - 12 ( 4 bit): EM style frame
8012 bit 11 - 6 ( 6 bit): graphic width
8013 bit 5 - 0 ( 6 bit): graphic height */
8014 g_em->unique_identifier =
8015 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
8019 /* skip check for EMC elements not contained in original EMC artwork */
8020 if (element == EL_EMC_FAKE_ACID)
8023 if (g_em->bitmap != debug_bitmap ||
8024 g_em->src_x != debug_src_x ||
8025 g_em->src_y != debug_src_y ||
8026 g_em->src_offset_x != 0 ||
8027 g_em->src_offset_y != 0 ||
8028 g_em->dst_offset_x != 0 ||
8029 g_em->dst_offset_y != 0 ||
8030 g_em->width != TILEX ||
8031 g_em->height != TILEY)
8033 static int last_i = -1;
8041 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
8042 i, element, element_info[element].token_name,
8043 element_action_info[effective_action].suffix, direction);
8045 if (element != effective_element)
8046 printf(" [%d ('%s')]",
8048 element_info[effective_element].token_name);
8052 if (g_em->bitmap != debug_bitmap)
8053 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
8054 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
8056 if (g_em->src_x != debug_src_x ||
8057 g_em->src_y != debug_src_y)
8058 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
8059 j, (is_backside ? 'B' : 'F'),
8060 g_em->src_x, g_em->src_y,
8061 g_em->src_x / 32, g_em->src_y / 32,
8062 debug_src_x, debug_src_y,
8063 debug_src_x / 32, debug_src_y / 32);
8065 if (g_em->src_offset_x != 0 ||
8066 g_em->src_offset_y != 0 ||
8067 g_em->dst_offset_x != 0 ||
8068 g_em->dst_offset_y != 0)
8069 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
8071 g_em->src_offset_x, g_em->src_offset_y,
8072 g_em->dst_offset_x, g_em->dst_offset_y);
8074 if (g_em->width != TILEX ||
8075 g_em->height != TILEY)
8076 printf(" %d (%d): size %d,%d should be %d,%d\n",
8078 g_em->width, g_em->height, TILEX, TILEY);
8080 num_em_gfx_errors++;
8087 for (i = 0; i < TILE_MAX; i++)
8089 for (j = 0; j < 8; j++)
8091 int element = object_mapping[i].element_rnd;
8092 int action = object_mapping[i].action;
8093 int direction = object_mapping[i].direction;
8094 boolean is_backside = object_mapping[i].is_backside;
8095 int graphic_action = el_act_dir2img(element, action, direction);
8096 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
8098 if ((action == ACTION_SMASHED_BY_ROCK ||
8099 action == ACTION_SMASHED_BY_SPRING ||
8100 action == ACTION_EATING) &&
8101 graphic_action == graphic_default)
8103 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
8104 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
8105 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
8106 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
8109 /* no separate animation for "smashed by rock" -- use rock instead */
8110 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
8111 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
8113 g_em->bitmap = g_xx->bitmap;
8114 g_em->src_x = g_xx->src_x;
8115 g_em->src_y = g_xx->src_y;
8116 g_em->src_offset_x = g_xx->src_offset_x;
8117 g_em->src_offset_y = g_xx->src_offset_y;
8118 g_em->dst_offset_x = g_xx->dst_offset_x;
8119 g_em->dst_offset_y = g_xx->dst_offset_y;
8120 g_em->width = g_xx->width;
8121 g_em->height = g_xx->height;
8122 g_em->unique_identifier = g_xx->unique_identifier;
8125 g_em->preserve_background = TRUE;
8130 for (p = 0; p < MAX_PLAYERS; p++)
8132 for (i = 0; i < SPR_MAX; i++)
8134 int element = player_mapping[p][i].element_rnd;
8135 int action = player_mapping[p][i].action;
8136 int direction = player_mapping[p][i].direction;
8138 for (j = 0; j < 8; j++)
8140 int effective_element = element;
8141 int effective_action = action;
8142 int graphic = (direction == MV_NONE ?
8143 el_act2img(effective_element, effective_action) :
8144 el_act_dir2img(effective_element, effective_action,
8146 struct GraphicInfo *g = &graphic_info[graphic];
8147 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
8153 Bitmap *debug_bitmap = g_em->bitmap;
8154 int debug_src_x = g_em->src_x;
8155 int debug_src_y = g_em->src_y;
8158 int frame = getAnimationFrame(g->anim_frames,
8161 g->anim_start_frame,
8164 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
8166 g_em->bitmap = src_bitmap;
8167 g_em->src_x = src_x;
8168 g_em->src_y = src_y;
8169 g_em->src_offset_x = 0;
8170 g_em->src_offset_y = 0;
8171 g_em->dst_offset_x = 0;
8172 g_em->dst_offset_y = 0;
8173 g_em->width = TILEX;
8174 g_em->height = TILEY;
8178 /* skip check for EMC elements not contained in original EMC artwork */
8179 if (element == EL_PLAYER_3 ||
8180 element == EL_PLAYER_4)
8183 if (g_em->bitmap != debug_bitmap ||
8184 g_em->src_x != debug_src_x ||
8185 g_em->src_y != debug_src_y)
8187 static int last_i = -1;
8195 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
8196 p, i, element, element_info[element].token_name,
8197 element_action_info[effective_action].suffix, direction);
8199 if (element != effective_element)
8200 printf(" [%d ('%s')]",
8202 element_info[effective_element].token_name);
8206 if (g_em->bitmap != debug_bitmap)
8207 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
8208 j, (int)(g_em->bitmap), (int)(debug_bitmap));
8210 if (g_em->src_x != debug_src_x ||
8211 g_em->src_y != debug_src_y)
8212 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
8214 g_em->src_x, g_em->src_y,
8215 g_em->src_x / 32, g_em->src_y / 32,
8216 debug_src_x, debug_src_y,
8217 debug_src_x / 32, debug_src_y / 32);
8219 num_em_gfx_errors++;
8229 printf("::: [%d errors found]\n", num_em_gfx_errors);
8235 void CheckSaveEngineSnapshot_EM(byte action[MAX_PLAYERS], int frame,
8236 boolean any_player_moving,
8237 boolean any_player_snapping,
8238 boolean any_player_dropping)
8240 if (frame == 0 && !any_player_dropping)
8242 if (!local_player->was_waiting)
8244 if (!CheckSaveEngineSnapshotToList())
8247 local_player->was_waiting = TRUE;
8250 else if (any_player_moving || any_player_snapping || any_player_dropping)
8252 local_player->was_waiting = FALSE;
8256 void CheckSaveEngineSnapshot_SP(boolean murphy_is_waiting,
8257 boolean murphy_is_dropping)
8259 if (murphy_is_waiting)
8261 if (!local_player->was_waiting)
8263 if (!CheckSaveEngineSnapshotToList())
8266 local_player->was_waiting = TRUE;
8271 local_player->was_waiting = FALSE;
8275 void CheckSingleStepMode_EM(byte action[MAX_PLAYERS], int frame,
8276 boolean any_player_moving,
8277 boolean any_player_snapping,
8278 boolean any_player_dropping)
8280 if (tape.single_step && tape.recording && !tape.pausing)
8281 if (frame == 0 && !any_player_dropping)
8282 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
8284 CheckSaveEngineSnapshot_EM(action, frame, any_player_moving,
8285 any_player_snapping, any_player_dropping);
8288 void CheckSingleStepMode_SP(boolean murphy_is_waiting,
8289 boolean murphy_is_dropping)
8291 if (tape.single_step && tape.recording && !tape.pausing)
8292 if (murphy_is_waiting)
8293 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
8295 CheckSaveEngineSnapshot_SP(murphy_is_waiting, murphy_is_dropping);
8298 void getGraphicSource_SP(struct GraphicInfo_SP *g_sp,
8299 int graphic, int sync_frame, int x, int y)
8301 int frame = getGraphicAnimationFrame(graphic, sync_frame);
8303 getGraphicSource(graphic, frame, &g_sp->bitmap, &g_sp->src_x, &g_sp->src_y);
8306 boolean isNextAnimationFrame_SP(int graphic, int sync_frame)
8308 return (IS_NEXT_FRAME(sync_frame, graphic));
8311 int getGraphicInfo_Delay(int graphic)
8313 return graphic_info[graphic].anim_delay;
8316 void PlayMenuSoundExt(int sound)
8318 if (sound == SND_UNDEFINED)
8321 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8322 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8325 if (IS_LOOP_SOUND(sound))
8326 PlaySoundLoop(sound);
8331 void PlayMenuSound()
8333 PlayMenuSoundExt(menu.sound[game_status]);
8336 void PlayMenuSoundStereo(int sound, int stereo_position)
8338 if (sound == SND_UNDEFINED)
8341 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8342 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8345 if (IS_LOOP_SOUND(sound))
8346 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
8348 PlaySoundStereo(sound, stereo_position);
8351 void PlayMenuSoundIfLoopExt(int sound)
8353 if (sound == SND_UNDEFINED)
8356 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8357 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8360 if (IS_LOOP_SOUND(sound))
8361 PlaySoundLoop(sound);
8364 void PlayMenuSoundIfLoop()
8366 PlayMenuSoundIfLoopExt(menu.sound[game_status]);
8369 void PlayMenuMusicExt(int music)
8371 if (music == MUS_UNDEFINED)
8374 if (!setup.sound_music)
8380 void PlayMenuMusic()
8382 PlayMenuMusicExt(menu.music[game_status]);
8385 void PlaySoundActivating()
8388 PlaySound(SND_MENU_ITEM_ACTIVATING);
8392 void PlaySoundSelecting()
8395 PlaySound(SND_MENU_ITEM_SELECTING);
8399 void ToggleFullscreenOrChangeWindowScalingIfNeeded()
8401 boolean change_fullscreen = (setup.fullscreen !=
8402 video.fullscreen_enabled);
8403 boolean change_window_scaling_percent = (!video.fullscreen_enabled &&
8404 setup.window_scaling_percent !=
8405 video.window_scaling_percent);
8407 if (change_window_scaling_percent && video.fullscreen_enabled)
8410 if (!change_window_scaling_percent && !video.fullscreen_available)
8413 #if defined(TARGET_SDL2)
8414 if (change_window_scaling_percent)
8416 SDLSetWindowScaling(setup.window_scaling_percent);
8420 else if (change_fullscreen)
8422 SDLSetWindowFullscreen(setup.fullscreen);
8424 /* set setup value according to successfully changed fullscreen mode */
8425 setup.fullscreen = video.fullscreen_enabled;
8431 if (change_fullscreen ||
8432 change_window_scaling_percent)
8434 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
8436 /* save backbuffer content which gets lost when toggling fullscreen mode */
8437 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8439 if (change_window_scaling_percent)
8441 /* keep window mode, but change window scaling */
8442 video.fullscreen_enabled = TRUE; /* force new window scaling */
8445 /* toggle fullscreen */
8446 ChangeVideoModeIfNeeded(setup.fullscreen);
8448 /* set setup value according to successfully changed fullscreen mode */
8449 setup.fullscreen = video.fullscreen_enabled;
8451 /* restore backbuffer content from temporary backbuffer backup bitmap */
8452 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8454 FreeBitmap(tmp_backbuffer);
8456 /* update visible window/screen */
8457 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8461 void JoinRectangles(int *x, int *y, int *width, int *height,
8462 int x2, int y2, int width2, int height2)
8464 // do not join with "off-screen" rectangle
8465 if (x2 == -1 || y2 == -1)
8470 *width = MAX(*width, width2);
8471 *height = MAX(*height, height2);
8474 void SetAnimStatus(int anim_status_new)
8476 if (anim_status_new == GAME_MODE_MAIN)
8477 anim_status_new = GAME_MODE_PSEUDO_MAINONLY;
8479 global.anim_status_next = anim_status_new;
8481 // directly set screen modes that are entered without fading
8482 if ((global.anim_status == GAME_MODE_PSEUDO_MAINONLY &&
8483 global.anim_status_next == GAME_MODE_PSEUDO_TYPENAME) ||
8484 (global.anim_status == GAME_MODE_PSEUDO_TYPENAME &&
8485 global.anim_status_next == GAME_MODE_PSEUDO_MAINONLY))
8486 global.anim_status = global.anim_status_next;
8489 void SetGameStatus(int game_status_new)
8491 game_status = game_status_new;
8493 SetAnimStatus(game_status_new);
8496 void SetFontStatus(int game_status_new)
8498 static int last_game_status = -1;
8500 if (game_status_new != -1)
8502 // set game status for font use after storing last game status
8503 last_game_status = game_status;
8504 game_status = game_status_new;
8508 // reset game status after font use from last stored game status
8509 game_status = last_game_status;
8513 void ResetFontStatus()
8518 void ChangeViewportPropertiesIfNeeded()
8520 int gfx_game_mode = game_status;
8521 int gfx_game_mode2 = (game_status == GAME_MODE_EDITOR ? GAME_MODE_DEFAULT :
8523 struct RectWithBorder *vp_window = &viewport.window[gfx_game_mode];
8524 struct RectWithBorder *vp_playfield = &viewport.playfield[gfx_game_mode];
8525 struct RectWithBorder *vp_door_1 = &viewport.door_1[gfx_game_mode];
8526 struct RectWithBorder *vp_door_2 = &viewport.door_2[gfx_game_mode2];
8527 struct RectWithBorder *vp_door_3 = &viewport.door_2[GAME_MODE_EDITOR];
8528 int new_win_xsize = vp_window->width;
8529 int new_win_ysize = vp_window->height;
8530 int border_size = vp_playfield->border_size;
8531 int new_sx = vp_playfield->x + border_size;
8532 int new_sy = vp_playfield->y + border_size;
8533 int new_sxsize = vp_playfield->width - 2 * border_size;
8534 int new_sysize = vp_playfield->height - 2 * border_size;
8535 int new_real_sx = vp_playfield->x;
8536 int new_real_sy = vp_playfield->y;
8537 int new_full_sxsize = vp_playfield->width;
8538 int new_full_sysize = vp_playfield->height;
8539 int new_dx = vp_door_1->x;
8540 int new_dy = vp_door_1->y;
8541 int new_dxsize = vp_door_1->width;
8542 int new_dysize = vp_door_1->height;
8543 int new_vx = vp_door_2->x;
8544 int new_vy = vp_door_2->y;
8545 int new_vxsize = vp_door_2->width;
8546 int new_vysize = vp_door_2->height;
8547 int new_ex = vp_door_3->x;
8548 int new_ey = vp_door_3->y;
8549 int new_exsize = vp_door_3->width;
8550 int new_eysize = vp_door_3->height;
8551 int new_tilesize_var =
8552 (setup.small_game_graphics ? MINI_TILESIZE : game.tile_size);
8554 int tilesize = (gfx_game_mode == GAME_MODE_PLAYING ? new_tilesize_var :
8555 gfx_game_mode == GAME_MODE_EDITOR ? MINI_TILESIZE : TILESIZE);
8556 int new_scr_fieldx = new_sxsize / tilesize;
8557 int new_scr_fieldy = new_sysize / tilesize;
8558 int new_scr_fieldx_buffers = new_sxsize / new_tilesize_var;
8559 int new_scr_fieldy_buffers = new_sysize / new_tilesize_var;
8560 boolean init_gfx_buffers = FALSE;
8561 boolean init_video_buffer = FALSE;
8562 boolean init_gadgets_and_anims = FALSE;
8563 boolean init_em_graphics = FALSE;
8565 if (new_win_xsize != WIN_XSIZE ||
8566 new_win_ysize != WIN_YSIZE)
8568 WIN_XSIZE = new_win_xsize;
8569 WIN_YSIZE = new_win_ysize;
8571 init_video_buffer = TRUE;
8572 init_gfx_buffers = TRUE;
8573 init_gadgets_and_anims = TRUE;
8575 // printf("::: video: init_video_buffer, init_gfx_buffers\n");
8578 if (new_scr_fieldx != SCR_FIELDX ||
8579 new_scr_fieldy != SCR_FIELDY)
8581 /* this always toggles between MAIN and GAME when using small tile size */
8583 SCR_FIELDX = new_scr_fieldx;
8584 SCR_FIELDY = new_scr_fieldy;
8586 // printf("::: new_scr_fieldx != SCR_FIELDX ...\n");
8597 new_sxsize != SXSIZE ||
8598 new_sysize != SYSIZE ||
8599 new_dxsize != DXSIZE ||
8600 new_dysize != DYSIZE ||
8601 new_vxsize != VXSIZE ||
8602 new_vysize != VYSIZE ||
8603 new_exsize != EXSIZE ||
8604 new_eysize != EYSIZE ||
8605 new_real_sx != REAL_SX ||
8606 new_real_sy != REAL_SY ||
8607 new_full_sxsize != FULL_SXSIZE ||
8608 new_full_sysize != FULL_SYSIZE ||
8609 new_tilesize_var != TILESIZE_VAR
8612 // ------------------------------------------------------------------------
8613 // determine next fading area for changed viewport definitions
8614 // ------------------------------------------------------------------------
8616 // start with current playfield area (default fading area)
8619 FADE_SXSIZE = FULL_SXSIZE;
8620 FADE_SYSIZE = FULL_SYSIZE;
8622 // add new playfield area if position or size has changed
8623 if (new_real_sx != REAL_SX || new_real_sy != REAL_SY ||
8624 new_full_sxsize != FULL_SXSIZE || new_full_sysize != FULL_SYSIZE)
8626 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
8627 new_real_sx, new_real_sy, new_full_sxsize,new_full_sysize);
8630 // add current and new door 1 area if position or size has changed
8631 if (new_dx != DX || new_dy != DY ||
8632 new_dxsize != DXSIZE || new_dysize != DYSIZE)
8634 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
8635 DX, DY, DXSIZE, DYSIZE);
8636 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
8637 new_dx, new_dy, new_dxsize, new_dysize);
8640 // add current and new door 2 area if position or size has changed
8641 if (new_dx != VX || new_dy != VY ||
8642 new_dxsize != VXSIZE || new_dysize != VYSIZE)
8644 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
8645 VX, VY, VXSIZE, VYSIZE);
8646 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
8647 new_vx, new_vy, new_vxsize, new_vysize);
8650 // ------------------------------------------------------------------------
8651 // handle changed tile size
8652 // ------------------------------------------------------------------------
8654 if (new_tilesize_var != TILESIZE_VAR)
8656 // printf("::: new_tilesize_var != TILESIZE_VAR\n");
8658 // changing tile size invalidates scroll values of engine snapshots
8659 FreeEngineSnapshotSingle();
8661 // changing tile size requires update of graphic mapping for EM engine
8662 init_em_graphics = TRUE;
8673 SXSIZE = new_sxsize;
8674 SYSIZE = new_sysize;
8675 DXSIZE = new_dxsize;
8676 DYSIZE = new_dysize;
8677 VXSIZE = new_vxsize;
8678 VYSIZE = new_vysize;
8679 EXSIZE = new_exsize;
8680 EYSIZE = new_eysize;
8681 REAL_SX = new_real_sx;
8682 REAL_SY = new_real_sy;
8683 FULL_SXSIZE = new_full_sxsize;
8684 FULL_SYSIZE = new_full_sysize;
8685 TILESIZE_VAR = new_tilesize_var;
8687 init_gfx_buffers = TRUE;
8688 init_gadgets_and_anims = TRUE;
8690 // printf("::: viewports: init_gfx_buffers\n");
8691 // printf("::: viewports: init_gadgets_and_anims\n");
8694 if (init_gfx_buffers)
8696 // printf("::: init_gfx_buffers\n");
8698 SCR_FIELDX = new_scr_fieldx_buffers;
8699 SCR_FIELDY = new_scr_fieldy_buffers;
8703 SCR_FIELDX = new_scr_fieldx;
8704 SCR_FIELDY = new_scr_fieldy;
8706 SetDrawDeactivationMask(REDRAW_NONE);
8707 SetDrawBackgroundMask(REDRAW_FIELD);
8710 if (init_video_buffer)
8712 // printf("::: init_video_buffer\n");
8714 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
8715 InitImageTextures();
8718 if (init_gadgets_and_anims)
8720 // printf("::: init_gadgets_and_anims\n");
8723 InitGlobalAnimations();
8726 if (init_em_graphics)
8728 InitGraphicInfo_EM();