1 // ============================================================================
2 // Rocks'n'Diamonds - McDuffin Strikes Back!
3 // ----------------------------------------------------------------------------
4 // (c) 1995-2014 by Artsoft Entertainment
7 // http://www.artsoft.org/
8 // ----------------------------------------------------------------------------
10 // ============================================================================
14 #include "libgame/libgame.h"
26 /* select level set with EMC X11 graphics before activating EM GFX debugging */
27 #define DEBUG_EM_GFX FALSE
28 #define DEBUG_FRAME_TIME FALSE
30 /* tool button identifiers */
31 #define TOOL_CTRL_ID_YES 0
32 #define TOOL_CTRL_ID_NO 1
33 #define TOOL_CTRL_ID_CONFIRM 2
34 #define TOOL_CTRL_ID_PLAYER_1 3
35 #define TOOL_CTRL_ID_PLAYER_2 4
36 #define TOOL_CTRL_ID_PLAYER_3 5
37 #define TOOL_CTRL_ID_PLAYER_4 6
39 #define NUM_TOOL_BUTTONS 7
41 /* constants for number of doors and door parts */
43 #define NUM_PANELS NUM_DOORS
44 // #define NUM_PANELS 0
45 #define MAX_PARTS_PER_DOOR 8
46 #define MAX_DOOR_PARTS (NUM_DOORS * MAX_PARTS_PER_DOOR + NUM_PANELS)
47 #define DOOR_PART_IS_PANEL(i) ((i) >= NUM_DOORS * MAX_PARTS_PER_DOOR)
50 struct DoorPartOrderInfo
56 static struct DoorPartOrderInfo door_part_order[MAX_DOOR_PARTS];
58 struct DoorPartControlInfo
62 struct DoorPartPosInfo *pos;
65 static struct DoorPartControlInfo door_part_controls[] =
69 IMG_GFX_DOOR_1_PART_1,
74 IMG_GFX_DOOR_1_PART_2,
79 IMG_GFX_DOOR_1_PART_3,
84 IMG_GFX_DOOR_1_PART_4,
89 IMG_GFX_DOOR_1_PART_5,
94 IMG_GFX_DOOR_1_PART_6,
99 IMG_GFX_DOOR_1_PART_7,
104 IMG_GFX_DOOR_1_PART_8,
110 IMG_GFX_DOOR_2_PART_1,
115 IMG_GFX_DOOR_2_PART_2,
120 IMG_GFX_DOOR_2_PART_3,
125 IMG_GFX_DOOR_2_PART_4,
130 IMG_GFX_DOOR_2_PART_5,
135 IMG_GFX_DOOR_2_PART_6,
140 IMG_GFX_DOOR_2_PART_7,
145 IMG_GFX_DOOR_2_PART_8,
151 IMG_BACKGROUND_PANEL,
168 /* forward declaration for internal use */
169 static void UnmapToolButtons();
170 static void HandleToolButtons(struct GadgetInfo *);
171 static int el_act_dir2crm(int, int, int);
172 static int el_act2crm(int, int);
174 static struct GadgetInfo *tool_gadget[NUM_TOOL_BUTTONS];
175 static int request_gadget_id = -1;
177 static char *print_if_not_empty(int element)
179 static char *s = NULL;
180 char *token_name = element_info[element].token_name;
185 s = checked_malloc(strlen(token_name) + 10 + 1);
187 if (element != EL_EMPTY)
188 sprintf(s, "%d\t['%s']", element, token_name);
190 sprintf(s, "%d", element);
195 int correctLevelPosX_EM(int lx)
198 lx -= (BorderElement != EL_EMPTY ? 1 : 0);
203 int correctLevelPosY_EM(int ly)
206 ly -= (BorderElement != EL_EMPTY ? 1 : 0);
211 static int getFieldbufferOffsetX_RND()
213 int full_lev_fieldx = lev_fieldx + (BorderElement != EL_EMPTY ? 2 : 0);
214 int dx = (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
215 int dx_var = dx * TILESIZE_VAR / TILESIZE;
218 if (EVEN(SCR_FIELDX))
220 int ffx = (scroll_x - SBX_Left) * TILEX_VAR + dx_var;
222 if (ffx < SBX_Right * TILEX_VAR + TILEX_VAR / 2 + TILEX_VAR)
223 fx += dx_var - MIN(ffx, TILEX_VAR / 2) + TILEX_VAR;
225 fx += (dx_var > 0 ? TILEX_VAR : 0);
232 if (full_lev_fieldx <= SCR_FIELDX)
234 if (EVEN(SCR_FIELDX))
235 fx = 2 * TILEX_VAR - (ODD(lev_fieldx) ? TILEX_VAR / 2 : 0);
237 fx = 2 * TILEX_VAR - (EVEN(lev_fieldx) ? TILEX_VAR / 2 : 0);
243 static int getFieldbufferOffsetY_RND()
245 int full_lev_fieldy = lev_fieldy + (BorderElement != EL_EMPTY ? 2 : 0);
246 int dy = (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
247 int dy_var = dy * TILESIZE_VAR / TILESIZE;
250 if (EVEN(SCR_FIELDY))
252 int ffy = (scroll_y - SBY_Upper) * TILEY_VAR + dy_var;
254 if (ffy < SBY_Lower * TILEY_VAR + TILEY_VAR / 2 + TILEY_VAR)
255 fy += dy_var - MIN(ffy, TILEY_VAR / 2) + TILEY_VAR;
257 fy += (dy_var > 0 ? TILEY_VAR : 0);
264 if (full_lev_fieldy <= SCR_FIELDY)
266 if (EVEN(SCR_FIELDY))
267 fy = 2 * TILEY_VAR - (ODD(lev_fieldy) ? TILEY_VAR / 2 : 0);
269 fy = 2 * TILEY_VAR - (EVEN(lev_fieldy) ? TILEY_VAR / 2 : 0);
275 static int getLevelFromScreenX_RND(int sx)
277 int fx = getFieldbufferOffsetX_RND();
280 int lx = LEVELX((px + dx) / TILESIZE_VAR);
285 static int getLevelFromScreenY_RND(int sy)
287 int fy = getFieldbufferOffsetY_RND();
290 int ly = LEVELY((py + dy) / TILESIZE_VAR);
295 static int getLevelFromScreenX_EM(int sx)
297 int level_xsize = level.native_em_level->lev->width;
298 int full_xsize = level_xsize * TILESIZE_VAR;
300 sx -= (full_xsize < SXSIZE ? (SXSIZE - full_xsize) / 2 : 0);
302 int fx = getFieldbufferOffsetX_EM();
305 int lx = LEVELX((px + dx) / TILESIZE_VAR);
307 lx = correctLevelPosX_EM(lx);
312 static int getLevelFromScreenY_EM(int sy)
314 int level_ysize = level.native_em_level->lev->height;
315 int full_ysize = level_ysize * TILESIZE_VAR;
317 sy -= (full_ysize < SYSIZE ? (SYSIZE - full_ysize) / 2 : 0);
319 int fy = getFieldbufferOffsetY_EM();
322 int ly = LEVELY((py + dy) / TILESIZE_VAR);
324 ly = correctLevelPosY_EM(ly);
329 static int getLevelFromScreenX_SP(int sx)
331 int menBorder = setup.sp_show_border_elements;
332 int level_xsize = level.native_sp_level->width;
333 int full_xsize = (level_xsize - (menBorder ? 0 : 1)) * TILESIZE_VAR;
335 sx += (full_xsize < SXSIZE ? (SXSIZE - full_xsize) / 2 : 0);
337 int fx = getFieldbufferOffsetX_SP();
340 int lx = LEVELX((px + dx) / TILESIZE_VAR);
345 static int getLevelFromScreenY_SP(int sy)
347 int menBorder = setup.sp_show_border_elements;
348 int level_ysize = level.native_sp_level->height;
349 int full_ysize = (level_ysize - (menBorder ? 0 : 1)) * TILESIZE_VAR;
351 sy += (full_ysize < SYSIZE ? (SYSIZE - full_ysize) / 2 : 0);
353 int fy = getFieldbufferOffsetY_SP();
356 int ly = LEVELY((py + dy) / TILESIZE_VAR);
361 int getLevelFromScreenX(int x)
363 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
364 return getLevelFromScreenX_EM(x);
365 if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
366 return getLevelFromScreenX_SP(x);
368 return getLevelFromScreenX_RND(x);
371 int getLevelFromScreenY(int y)
373 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
374 return getLevelFromScreenY_EM(y);
375 if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
376 return getLevelFromScreenY_SP(y);
378 return getLevelFromScreenY_RND(y);
381 void DumpTile(int x, int y)
386 printf_line("-", 79);
387 printf("Field Info: SCREEN(%d, %d), LEVEL(%d, %d)\n", sx, sy, x, y);
388 printf_line("-", 79);
390 if (!IN_LEV_FIELD(x, y))
392 printf("(not in level field)\n");
398 printf(" Feld: %d\t['%s']\n", Feld[x][y],
399 element_info[Feld[x][y]].token_name);
400 printf(" Back: %s\n", print_if_not_empty(Back[x][y]));
401 printf(" Store: %s\n", print_if_not_empty(Store[x][y]));
402 printf(" Store2: %s\n", print_if_not_empty(Store2[x][y]));
403 printf(" StorePlayer: %s\n", print_if_not_empty(StorePlayer[x][y]));
404 printf(" MovPos: %d\n", MovPos[x][y]);
405 printf(" MovDir: %d\n", MovDir[x][y]);
406 printf(" MovDelay: %d\n", MovDelay[x][y]);
407 printf(" ChangeDelay: %d\n", ChangeDelay[x][y]);
408 printf(" CustomValue: %d\n", CustomValue[x][y]);
409 printf(" GfxElement: %d\n", GfxElement[x][y]);
410 printf(" GfxAction: %d\n", GfxAction[x][y]);
411 printf(" GfxFrame: %d [%d]\n", GfxFrame[x][y], FrameCounter);
412 printf(" Player x/y: %d, %d\n", local_player->jx, local_player->jy);
416 void DumpTileFromScreen(int sx, int sy)
418 int lx = getLevelFromScreenX(sx);
419 int ly = getLevelFromScreenY(sy);
424 void SetDrawtoField(int mode)
426 if (mode == DRAW_TO_FIELDBUFFER)
432 BX2 = SCR_FIELDX + 1;
433 BY2 = SCR_FIELDY + 1;
435 drawto_field = fieldbuffer;
437 else /* DRAW_TO_BACKBUFFER */
443 BX2 = SCR_FIELDX - 1;
444 BY2 = SCR_FIELDY - 1;
446 drawto_field = backbuffer;
450 static void RedrawPlayfield_RND()
452 if (game.envelope_active)
455 DrawLevel(REDRAW_ALL);
459 void RedrawPlayfield()
461 if (game_status != GAME_MODE_PLAYING)
464 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
465 RedrawPlayfield_EM(TRUE);
466 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
467 RedrawPlayfield_SP(TRUE);
468 else if (level.game_engine_type == GAME_ENGINE_TYPE_RND)
469 RedrawPlayfield_RND();
471 BlitScreenToBitmap(backbuffer);
473 BlitBitmap(drawto, window, gfx.sx, gfx.sy, gfx.sxsize, gfx.sysize,
477 static void DrawMaskedBorderExt_Rect(int x, int y, int width, int height,
480 Bitmap *src_bitmap = getGlobalBorderBitmapFromStatus(global.border_status);
481 Bitmap *dst_bitmap = gfx.masked_border_bitmap_ptr;
483 if (x == -1 && y == -1)
486 if (draw_target == DRAW_TO_SCREEN)
487 BlitToScreenMasked(src_bitmap, x, y, width, height, x, y);
489 BlitBitmapMasked(src_bitmap, dst_bitmap, x, y, width, height, x, y);
492 static void DrawMaskedBorderExt_FIELD(int draw_target)
494 if (global.border_status >= GAME_MODE_MAIN &&
495 global.border_status <= GAME_MODE_PLAYING &&
496 border.draw_masked[global.border_status])
497 DrawMaskedBorderExt_Rect(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
501 static void DrawMaskedBorderExt_DOOR_1(int draw_target)
503 // when drawing to backbuffer, never draw border over open doors
504 if (draw_target == DRAW_TO_BACKBUFFER &&
505 (GetDoorState() & DOOR_OPEN_1))
508 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
509 (global.border_status != GAME_MODE_EDITOR ||
510 border.draw_masked[GFX_SPECIAL_ARG_EDITOR]))
511 DrawMaskedBorderExt_Rect(DX, DY, DXSIZE, DYSIZE, draw_target);
514 static void DrawMaskedBorderExt_DOOR_2(int draw_target)
516 // when drawing to backbuffer, never draw border over open doors
517 if (draw_target == DRAW_TO_BACKBUFFER &&
518 (GetDoorState() & DOOR_OPEN_2))
521 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
522 global.border_status != GAME_MODE_EDITOR)
523 DrawMaskedBorderExt_Rect(VX, VY, VXSIZE, VYSIZE, draw_target);
526 static void DrawMaskedBorderExt_DOOR_3(int draw_target)
528 /* currently not available */
531 static void DrawMaskedBorderExt_ALL(int draw_target)
533 DrawMaskedBorderExt_FIELD(draw_target);
534 DrawMaskedBorderExt_DOOR_1(draw_target);
535 DrawMaskedBorderExt_DOOR_2(draw_target);
536 DrawMaskedBorderExt_DOOR_3(draw_target);
539 static void DrawMaskedBorderExt(int redraw_mask, int draw_target)
541 /* never draw masked screen borders on borderless screens */
542 if (global.border_status == GAME_MODE_LOADING ||
543 global.border_status == GAME_MODE_TITLE)
546 if (redraw_mask & REDRAW_ALL)
547 DrawMaskedBorderExt_ALL(draw_target);
550 if (redraw_mask & REDRAW_FIELD)
551 DrawMaskedBorderExt_FIELD(draw_target);
552 if (redraw_mask & REDRAW_DOOR_1)
553 DrawMaskedBorderExt_DOOR_1(draw_target);
554 if (redraw_mask & REDRAW_DOOR_2)
555 DrawMaskedBorderExt_DOOR_2(draw_target);
556 if (redraw_mask & REDRAW_DOOR_3)
557 DrawMaskedBorderExt_DOOR_3(draw_target);
561 void DrawMaskedBorder_FIELD()
563 DrawMaskedBorderExt_FIELD(DRAW_TO_BACKBUFFER);
566 void DrawMaskedBorder(int redraw_mask)
568 DrawMaskedBorderExt(redraw_mask, DRAW_TO_BACKBUFFER);
571 void DrawMaskedBorderToTarget(int draw_target)
573 if (draw_target == DRAW_TO_BACKBUFFER ||
574 draw_target == DRAW_TO_SCREEN)
576 DrawMaskedBorderExt(REDRAW_ALL, draw_target);
580 int last_border_status = global.border_status;
582 if (draw_target == DRAW_TO_FADE_SOURCE)
584 global.border_status = gfx.fade_border_source_status;
585 gfx.masked_border_bitmap_ptr = gfx.fade_bitmap_source;
587 else if (draw_target == DRAW_TO_FADE_TARGET)
589 global.border_status = gfx.fade_border_target_status;
590 gfx.masked_border_bitmap_ptr = gfx.fade_bitmap_target;
593 DrawMaskedBorderExt(REDRAW_ALL, draw_target);
595 global.border_status = last_border_status;
596 gfx.masked_border_bitmap_ptr = backbuffer;
600 void BlitScreenToBitmap_RND(Bitmap *target_bitmap)
602 int fx = getFieldbufferOffsetX_RND();
603 int fy = getFieldbufferOffsetY_RND();
605 BlitBitmap(drawto_field, target_bitmap, fx, fy, SXSIZE, SYSIZE, SX, SY);
608 void BlitScreenToBitmap(Bitmap *target_bitmap)
610 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
611 BlitScreenToBitmap_EM(target_bitmap);
612 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
613 BlitScreenToBitmap_SP(target_bitmap);
614 else if (level.game_engine_type == GAME_ENGINE_TYPE_RND)
615 BlitScreenToBitmap_RND(target_bitmap);
617 redraw_mask |= REDRAW_FIELD;
620 void DrawFramesPerSecond()
623 int font_nr = FONT_TEXT_2;
624 int font_width = getFontWidth(font_nr);
626 sprintf(text, "%04.1f fps", global.frames_per_second);
628 DrawTextExt(backbuffer, WIN_XSIZE - font_width * strlen(text), 0, text,
629 font_nr, BLIT_OPAQUE);
633 static void PrintFrameTimeDebugging()
635 static unsigned int last_counter = 0;
636 unsigned int counter = Counter();
637 int diff_1 = counter - last_counter;
638 int diff_2 = diff_1 - GAME_FRAME_DELAY;
640 int diff_2_cut = MIN(ABS(diff_2), diff_2_max);
641 char diff_bar[2 * diff_2_max + 5];
645 diff_bar[pos++] = (diff_2 < -diff_2_max ? '<' : ' ');
647 for (i = 0; i < diff_2_max; i++)
648 diff_bar[pos++] = (diff_2 >= 0 ? ' ' :
649 i >= diff_2_max - diff_2_cut ? '-' : ' ');
651 diff_bar[pos++] = '|';
653 for (i = 0; i < diff_2_max; i++)
654 diff_bar[pos++] = (diff_2 <= 0 ? ' ' : i < diff_2_cut ? '+' : ' ');
656 diff_bar[pos++] = (diff_2 > diff_2_max ? '>' : ' ');
658 diff_bar[pos++] = '\0';
660 Error(ERR_INFO, "%06d [%02d] [%c%02d] %s",
663 (diff_2 < 0 ? '-' : diff_2 > 0 ? '+' : ' '), ABS(diff_2),
666 last_counter = counter;
670 static int unifiedRedrawMask(int mask)
672 if (mask & REDRAW_ALL)
675 if (mask & REDRAW_FIELD && mask & REDRAW_DOORS)
681 static boolean equalRedrawMasks(int mask_1, int mask_2)
683 return unifiedRedrawMask(mask_1) == unifiedRedrawMask(mask_2);
688 static int last_redraw_mask = REDRAW_NONE;
690 // force screen redraw in every frame to continue drawing global animations
691 // (but always use the last redraw mask to prevent unwanted side effects)
692 if (redraw_mask == REDRAW_NONE)
693 redraw_mask = last_redraw_mask;
695 last_redraw_mask = redraw_mask;
698 // masked border now drawn immediately when blitting backbuffer to window
700 // draw masked border to all viewports, if defined
701 DrawMaskedBorder(redraw_mask);
704 // draw frames per second (only if debug mode is enabled)
705 if (redraw_mask & REDRAW_FPS)
706 DrawFramesPerSecond();
708 // remove playfield redraw before potentially merging with doors redraw
709 if (DrawingDeactivated(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE))
710 redraw_mask &= ~REDRAW_FIELD;
712 // redraw complete window if both playfield and (some) doors need redraw
713 if (redraw_mask & REDRAW_FIELD && redraw_mask & REDRAW_DOORS)
714 redraw_mask = REDRAW_ALL;
716 /* although redrawing the whole window would be fine for normal gameplay,
717 being able to only redraw the playfield is required for deactivating
718 certain drawing areas (mainly playfield) to work, which is needed for
719 warp-forward to be fast enough (by skipping redraw of most frames) */
721 if (redraw_mask & REDRAW_ALL)
723 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
725 else if (redraw_mask & REDRAW_FIELD)
727 BlitBitmap(backbuffer, window,
728 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
730 else if (redraw_mask & REDRAW_DOORS)
732 // merge door areas to prevent calling screen redraw more than once
738 if (redraw_mask & REDRAW_DOOR_1)
742 x2 = MAX(x2, DX + DXSIZE);
743 y2 = MAX(y2, DY + DYSIZE);
746 if (redraw_mask & REDRAW_DOOR_2)
750 x2 = MAX(x2, VX + VXSIZE);
751 y2 = MAX(y2, VY + VYSIZE);
754 if (redraw_mask & REDRAW_DOOR_3)
758 x2 = MAX(x2, EX + EXSIZE);
759 y2 = MAX(y2, EY + EYSIZE);
762 // make sure that at least one pixel is blitted, and inside the screen
763 // (else nothing is blitted, causing the animations not to be updated)
764 x1 = MIN(MAX(0, x1), WIN_XSIZE - 1);
765 y1 = MIN(MAX(0, y1), WIN_YSIZE - 1);
766 x2 = MIN(MAX(1, x2), WIN_XSIZE);
767 y2 = MIN(MAX(1, y2), WIN_YSIZE);
769 BlitBitmap(backbuffer, window, x1, y1, x2 - x1, y2 - y1, x1, y1);
772 redraw_mask = REDRAW_NONE;
775 PrintFrameTimeDebugging();
779 void BackToFront_WithFrameDelay(unsigned int frame_delay_value)
781 unsigned int frame_delay_value_old = GetVideoFrameDelay();
783 SetVideoFrameDelay(frame_delay_value);
787 SetVideoFrameDelay(frame_delay_value_old);
790 static int fade_type_skip = FADE_TYPE_NONE;
792 static void FadeExt(int fade_mask, int fade_mode, int fade_type)
794 void (*draw_border_function)(void) = NULL;
795 int x, y, width, height;
796 int fade_delay, post_delay;
798 if (fade_type == FADE_TYPE_FADE_OUT)
800 if (fade_type_skip != FADE_TYPE_NONE)
802 /* skip all fade operations until specified fade operation */
803 if (fade_type & fade_type_skip)
804 fade_type_skip = FADE_TYPE_NONE;
809 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
813 redraw_mask |= fade_mask;
815 if (fade_type == FADE_TYPE_SKIP)
817 fade_type_skip = fade_mode;
822 fade_delay = fading.fade_delay;
823 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
825 if (fade_type_skip != FADE_TYPE_NONE)
827 /* skip all fade operations until specified fade operation */
828 if (fade_type & fade_type_skip)
829 fade_type_skip = FADE_TYPE_NONE;
834 if (global.autoplay_leveldir)
839 if (fade_mask == REDRAW_FIELD)
844 height = FADE_SYSIZE;
846 if (border.draw_masked_when_fading)
847 draw_border_function = DrawMaskedBorder_FIELD; /* update when fading */
849 DrawMaskedBorder_FIELD(); /* draw once */
851 else /* REDRAW_ALL */
859 if (!setup.fade_screens ||
861 fading.fade_mode == FADE_MODE_NONE)
863 if (fade_mode == FADE_MODE_FADE_OUT)
866 BlitBitmap(backbuffer, window, x, y, width, height, x, y);
868 redraw_mask &= ~fade_mask;
873 FadeRectangle(x, y, width, height, fade_mode, fade_delay, post_delay,
874 draw_border_function);
876 redraw_mask &= ~fade_mask;
879 static void SetScreenStates_BeforeFadingIn()
881 // temporarily set screen mode for animations to screen after fading in
882 global.anim_status = global.anim_status_next;
884 // store backbuffer with all animations that will be started after fading in
885 if (fade_type_skip != FADE_MODE_SKIP_FADE_IN)
886 PrepareFadeBitmap(DRAW_TO_FADE_TARGET);
888 // set screen mode for animations back to fading
889 global.anim_status = GAME_MODE_PSEUDO_FADING;
892 static void SetScreenStates_AfterFadingIn()
894 // store new source screen (to use correct masked border for fading)
895 gfx.fade_border_source_status = global.border_status;
897 global.anim_status = global.anim_status_next;
900 static void SetScreenStates_BeforeFadingOut()
902 // store new target screen (to use correct masked border for fading)
903 gfx.fade_border_target_status = game_status;
905 // set screen mode for animations to fading
906 global.anim_status = GAME_MODE_PSEUDO_FADING;
908 // store backbuffer with all animations that will be stopped for fading out
909 if (fade_type_skip != FADE_MODE_SKIP_FADE_OUT)
910 PrepareFadeBitmap(DRAW_TO_FADE_SOURCE);
913 static void SetScreenStates_AfterFadingOut()
915 global.border_status = game_status;
918 void FadeIn(int fade_mask)
920 SetScreenStates_BeforeFadingIn();
923 DrawMaskedBorder(REDRAW_ALL);
926 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
927 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_IN);
929 FadeExt(fade_mask, FADE_MODE_FADE_IN, FADE_TYPE_FADE_IN);
933 FADE_SXSIZE = FULL_SXSIZE;
934 FADE_SYSIZE = FULL_SYSIZE;
936 if (game_status == GAME_MODE_PLAYING &&
937 strEqual(setup.touch.control_type, TOUCH_CONTROL_VIRTUAL_BUTTONS))
938 SetOverlayActive(TRUE);
940 SetScreenStates_AfterFadingIn();
942 // force update of global animation status in case of rapid screen changes
943 redraw_mask = REDRAW_ALL;
947 void FadeOut(int fade_mask)
949 // update screen if areas covered by "fade_mask" and "redraw_mask" differ
950 if (!equalRedrawMasks(fade_mask, redraw_mask))
953 SetScreenStates_BeforeFadingOut();
955 SetOverlayActive(FALSE);
958 DrawMaskedBorder(REDRAW_ALL);
961 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
962 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_OUT);
964 FadeExt(fade_mask, FADE_MODE_FADE_OUT, FADE_TYPE_FADE_OUT);
966 SetScreenStates_AfterFadingOut();
969 static void FadeSetLeaveNext(struct TitleFadingInfo fading_leave, boolean set)
971 static struct TitleFadingInfo fading_leave_stored;
974 fading_leave_stored = fading_leave;
976 fading = fading_leave_stored;
979 void FadeSetEnterMenu()
981 fading = menu.enter_menu;
983 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
986 void FadeSetLeaveMenu()
988 fading = menu.leave_menu;
990 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
993 void FadeSetEnterScreen()
995 fading = menu.enter_screen[game_status];
997 FadeSetLeaveNext(menu.leave_screen[game_status], TRUE); /* store */
1000 void FadeSetNextScreen()
1002 fading = menu.next_screen[game_status];
1004 // (do not overwrite fade mode set by FadeSetEnterScreen)
1005 // FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
1008 void FadeSetLeaveScreen()
1010 FadeSetLeaveNext(menu.leave_screen[game_status], FALSE); /* recall */
1013 void FadeSetFromType(int type)
1015 if (type & TYPE_ENTER_SCREEN)
1016 FadeSetEnterScreen();
1017 else if (type & TYPE_ENTER)
1019 else if (type & TYPE_LEAVE)
1023 void FadeSetDisabled()
1025 static struct TitleFadingInfo fading_none = { FADE_MODE_NONE, -1, -1, -1 };
1027 fading = fading_none;
1030 void FadeSkipNextFadeIn()
1032 FadeExt(0, FADE_MODE_SKIP_FADE_IN, FADE_TYPE_SKIP);
1035 void FadeSkipNextFadeOut()
1037 FadeExt(0, FADE_MODE_SKIP_FADE_OUT, FADE_TYPE_SKIP);
1040 Bitmap *getBitmapFromGraphicOrDefault(int graphic, int default_graphic)
1042 boolean redefined = getImageListEntryFromImageID(graphic)->redefined;
1044 return (graphic == IMG_UNDEFINED ? NULL :
1045 graphic_info[graphic].bitmap != NULL || redefined ?
1046 graphic_info[graphic].bitmap :
1047 graphic_info[default_graphic].bitmap);
1050 Bitmap *getBackgroundBitmap(int graphic)
1052 return getBitmapFromGraphicOrDefault(graphic, IMG_BACKGROUND);
1055 Bitmap *getGlobalBorderBitmap(int graphic)
1057 return getBitmapFromGraphicOrDefault(graphic, IMG_GLOBAL_BORDER);
1060 Bitmap *getGlobalBorderBitmapFromStatus(int status)
1063 (status == GAME_MODE_MAIN ||
1064 status == GAME_MODE_PSEUDO_TYPENAME ? IMG_GLOBAL_BORDER_MAIN :
1065 status == GAME_MODE_SCORES ? IMG_GLOBAL_BORDER_SCORES :
1066 status == GAME_MODE_EDITOR ? IMG_GLOBAL_BORDER_EDITOR :
1067 status == GAME_MODE_PLAYING ? IMG_GLOBAL_BORDER_PLAYING :
1070 return getGlobalBorderBitmap(graphic);
1073 void SetWindowBackgroundImageIfDefined(int graphic)
1075 if (graphic_info[graphic].bitmap)
1076 SetWindowBackgroundBitmap(graphic_info[graphic].bitmap);
1079 void SetMainBackgroundImageIfDefined(int graphic)
1081 if (graphic_info[graphic].bitmap)
1082 SetMainBackgroundBitmap(graphic_info[graphic].bitmap);
1085 void SetDoorBackgroundImageIfDefined(int graphic)
1087 if (graphic_info[graphic].bitmap)
1088 SetDoorBackgroundBitmap(graphic_info[graphic].bitmap);
1091 void SetWindowBackgroundImage(int graphic)
1093 SetWindowBackgroundBitmap(getBackgroundBitmap(graphic));
1096 void SetMainBackgroundImage(int graphic)
1098 SetMainBackgroundBitmap(getBackgroundBitmap(graphic));
1101 void SetDoorBackgroundImage(int graphic)
1103 SetDoorBackgroundBitmap(getBackgroundBitmap(graphic));
1106 void SetPanelBackground()
1108 struct GraphicInfo *gfx = &graphic_info[IMG_BACKGROUND_PANEL];
1110 BlitBitmapTiled(gfx->bitmap, bitmap_db_panel, gfx->src_x, gfx->src_y,
1111 gfx->width, gfx->height, 0, 0, DXSIZE, DYSIZE);
1113 SetDoorBackgroundBitmap(bitmap_db_panel);
1116 void DrawBackground(int x, int y, int width, int height)
1118 /* "drawto" might still point to playfield buffer here (hall of fame) */
1119 ClearRectangleOnBackground(backbuffer, x, y, width, height);
1121 if (IN_GFX_FIELD_FULL(x, y))
1122 redraw_mask |= REDRAW_FIELD;
1123 else if (IN_GFX_DOOR_1(x, y))
1124 redraw_mask |= REDRAW_DOOR_1;
1125 else if (IN_GFX_DOOR_2(x, y))
1126 redraw_mask |= REDRAW_DOOR_2;
1127 else if (IN_GFX_DOOR_3(x, y))
1128 redraw_mask |= REDRAW_DOOR_3;
1131 void DrawBackgroundForFont(int x, int y, int width, int height, int font_nr)
1133 struct FontBitmapInfo *font = getFontBitmapInfo(font_nr);
1135 if (font->bitmap == NULL)
1138 DrawBackground(x, y, width, height);
1141 void DrawBackgroundForGraphic(int x, int y, int width, int height, int graphic)
1143 struct GraphicInfo *g = &graphic_info[graphic];
1145 if (g->bitmap == NULL)
1148 DrawBackground(x, y, width, height);
1151 static int game_status_last = -1;
1152 static Bitmap *global_border_bitmap_last = NULL;
1153 static Bitmap *global_border_bitmap = NULL;
1154 static int real_sx_last = -1, real_sy_last = -1;
1155 static int full_sxsize_last = -1, full_sysize_last = -1;
1156 static int dx_last = -1, dy_last = -1;
1157 static int dxsize_last = -1, dysize_last = -1;
1158 static int vx_last = -1, vy_last = -1;
1159 static int vxsize_last = -1, vysize_last = -1;
1161 boolean CheckIfGlobalBorderHasChanged()
1163 // if game status has not changed, global border has not changed either
1164 if (game_status == game_status_last)
1167 // determine and store new global border bitmap for current game status
1168 global_border_bitmap = getGlobalBorderBitmapFromStatus(game_status);
1170 return (global_border_bitmap_last != global_border_bitmap);
1173 boolean CheckIfGlobalBorderRedrawIsNeeded()
1175 // if game status has not changed, nothing has to be redrawn
1176 if (game_status == game_status_last)
1179 // redraw if last screen was title screen
1180 if (game_status_last == GAME_MODE_TITLE)
1183 // redraw if global screen border has changed
1184 if (CheckIfGlobalBorderHasChanged())
1187 // redraw if position or size of playfield area has changed
1188 if (real_sx_last != REAL_SX || real_sy_last != REAL_SY ||
1189 full_sxsize_last != FULL_SXSIZE || full_sysize_last != FULL_SYSIZE)
1192 // redraw if position or size of door area has changed
1193 if (dx_last != DX || dy_last != DY ||
1194 dxsize_last != DXSIZE || dysize_last != DYSIZE)
1197 // redraw if position or size of tape area has changed
1198 if (vx_last != VX || vy_last != VY ||
1199 vxsize_last != VXSIZE || vysize_last != VYSIZE)
1205 void RedrawGlobalBorderFromBitmap(Bitmap *bitmap)
1208 BlitBitmap(bitmap, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
1210 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
1213 void RedrawGlobalBorder()
1215 Bitmap *bitmap = getGlobalBorderBitmapFromStatus(game_status);
1217 RedrawGlobalBorderFromBitmap(bitmap);
1219 redraw_mask = REDRAW_ALL;
1222 static void RedrawGlobalBorderIfNeeded()
1224 if (game_status == game_status_last)
1227 // copy current draw buffer to later copy back areas that have not changed
1228 if (game_status_last != GAME_MODE_TITLE)
1229 BlitBitmap(backbuffer, bitmap_db_store_1, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
1231 if (CheckIfGlobalBorderRedrawIsNeeded())
1233 // redraw global screen border (or clear, if defined to be empty)
1234 RedrawGlobalBorderFromBitmap(global_border_bitmap);
1236 // copy previous playfield and door areas, if they are defined on both
1237 // previous and current screen and if they still have the same size
1239 if (real_sx_last != -1 && real_sy_last != -1 &&
1240 REAL_SX != -1 && REAL_SY != -1 &&
1241 full_sxsize_last == FULL_SXSIZE && full_sysize_last == FULL_SYSIZE)
1242 BlitBitmap(bitmap_db_store_1, backbuffer,
1243 real_sx_last, real_sy_last, FULL_SXSIZE, FULL_SYSIZE,
1246 if (dx_last != -1 && dy_last != -1 &&
1247 DX != -1 && DY != -1 &&
1248 dxsize_last == DXSIZE && dysize_last == DYSIZE)
1249 BlitBitmap(bitmap_db_store_1, backbuffer,
1250 dx_last, dy_last, DXSIZE, DYSIZE, DX, DY);
1252 if (vx_last != -1 && vy_last != -1 &&
1253 VX != -1 && VY != -1 &&
1254 vxsize_last == VXSIZE && vysize_last == VYSIZE)
1255 BlitBitmap(bitmap_db_store_1, backbuffer,
1256 vx_last, vy_last, VXSIZE, VYSIZE, VX, VY);
1258 redraw_mask = REDRAW_ALL;
1261 game_status_last = game_status;
1263 global_border_bitmap_last = global_border_bitmap;
1265 real_sx_last = REAL_SX;
1266 real_sy_last = REAL_SY;
1267 full_sxsize_last = FULL_SXSIZE;
1268 full_sysize_last = FULL_SYSIZE;
1271 dxsize_last = DXSIZE;
1272 dysize_last = DYSIZE;
1275 vxsize_last = VXSIZE;
1276 vysize_last = VYSIZE;
1281 RedrawGlobalBorderIfNeeded();
1283 /* !!! "drawto" might still point to playfield buffer here (see above) !!! */
1284 /* (when entering hall of fame after playing) */
1285 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
1287 /* !!! maybe this should be done before clearing the background !!! */
1288 if (game_status == GAME_MODE_PLAYING)
1290 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
1291 SetDrawtoField(DRAW_TO_FIELDBUFFER);
1295 SetDrawtoField(DRAW_TO_BACKBUFFER);
1299 void MarkTileDirty(int x, int y)
1301 redraw_mask |= REDRAW_FIELD;
1304 void SetBorderElement()
1308 BorderElement = EL_EMPTY;
1310 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
1312 for (x = 0; x < lev_fieldx; x++)
1314 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
1315 BorderElement = EL_STEELWALL;
1317 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
1323 void FloodFillLevel(int from_x, int from_y, int fill_element,
1324 short field[MAX_LEV_FIELDX][MAX_LEV_FIELDY],
1325 int max_fieldx, int max_fieldy)
1329 static int check[4][2] = { { -1, 0 }, { 0, -1 }, { 1, 0 }, { 0, 1 } };
1330 static int safety = 0;
1332 /* check if starting field still has the desired content */
1333 if (field[from_x][from_y] == fill_element)
1338 if (safety > max_fieldx * max_fieldy)
1339 Error(ERR_EXIT, "Something went wrong in 'FloodFill()'. Please debug.");
1341 old_element = field[from_x][from_y];
1342 field[from_x][from_y] = fill_element;
1344 for (i = 0; i < 4; i++)
1346 x = from_x + check[i][0];
1347 y = from_y + check[i][1];
1349 if (IN_FIELD(x, y, max_fieldx, max_fieldy) && field[x][y] == old_element)
1350 FloodFillLevel(x, y, fill_element, field, max_fieldx, max_fieldy);
1356 void SetRandomAnimationValue(int x, int y)
1358 gfx.anim_random_frame = GfxRandom[x][y];
1361 int getGraphicAnimationFrame(int graphic, int sync_frame)
1363 /* animation synchronized with global frame counter, not move position */
1364 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
1365 sync_frame = FrameCounter;
1367 return getAnimationFrame(graphic_info[graphic].anim_frames,
1368 graphic_info[graphic].anim_delay,
1369 graphic_info[graphic].anim_mode,
1370 graphic_info[graphic].anim_start_frame,
1374 void getGraphicSourceBitmap(int graphic, int tilesize, Bitmap **bitmap)
1376 struct GraphicInfo *g = &graphic_info[graphic];
1377 int tilesize_capped = MIN(MAX(1, tilesize), TILESIZE);
1379 if (tilesize == gfx.standard_tile_size)
1380 *bitmap = g->bitmaps[IMG_BITMAP_STANDARD];
1381 else if (tilesize == game.tile_size)
1382 *bitmap = g->bitmaps[IMG_BITMAP_GAME];
1384 *bitmap = g->bitmaps[IMG_BITMAP_1x1 - log_2(tilesize_capped)];
1387 void getGraphicSourceXY(int graphic, int frame, int *x, int *y,
1388 boolean get_backside)
1390 struct GraphicInfo *g = &graphic_info[graphic];
1391 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
1392 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
1394 if (g->offset_y == 0) /* frames are ordered horizontally */
1396 int max_width = g->anim_frames_per_line * g->width;
1397 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
1399 *x = pos % max_width;
1400 *y = src_y % g->height + pos / max_width * g->height;
1402 else if (g->offset_x == 0) /* frames are ordered vertically */
1404 int max_height = g->anim_frames_per_line * g->height;
1405 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
1407 *x = src_x % g->width + pos / max_height * g->width;
1408 *y = pos % max_height;
1410 else /* frames are ordered diagonally */
1412 *x = src_x + frame * g->offset_x;
1413 *y = src_y + frame * g->offset_y;
1417 void getSizedGraphicSourceExt(int graphic, int frame, int tilesize,
1418 Bitmap **bitmap, int *x, int *y,
1419 boolean get_backside)
1421 struct GraphicInfo *g = &graphic_info[graphic];
1423 // if no in-game graphics defined, always use standard graphic size
1424 if (g->bitmaps[IMG_BITMAP_GAME] == NULL)
1425 tilesize = TILESIZE;
1427 getGraphicSourceBitmap(graphic, tilesize, bitmap);
1428 getGraphicSourceXY(graphic, frame, x, y, get_backside);
1430 *x = *x * tilesize / g->tile_size;
1431 *y = *y * tilesize / g->tile_size;
1434 void getFixedGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1435 int *x, int *y, boolean get_backside)
1437 getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y,
1441 void getSizedGraphicSource(int graphic, int frame, int tilesize,
1442 Bitmap **bitmap, int *x, int *y)
1444 getSizedGraphicSourceExt(graphic, frame, tilesize, bitmap, x, y, FALSE);
1447 void getFixedGraphicSource(int graphic, int frame,
1448 Bitmap **bitmap, int *x, int *y)
1450 getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y, FALSE);
1453 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1455 getSizedGraphicSource(graphic, 0, MINI_TILESIZE, bitmap, x, y);
1458 inline static void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1459 int *x, int *y, boolean get_backside)
1461 getSizedGraphicSourceExt(graphic, frame, TILESIZE_VAR, bitmap, x, y,
1465 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
1467 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
1470 void DrawGraphic(int x, int y, int graphic, int frame)
1473 if (!IN_SCR_FIELD(x, y))
1475 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1476 printf("DrawGraphic(): This should never happen!\n");
1481 DrawGraphicExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR, graphic,
1484 MarkTileDirty(x, y);
1487 void DrawFixedGraphic(int x, int y, int graphic, int frame)
1490 if (!IN_SCR_FIELD(x, y))
1492 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1493 printf("DrawGraphic(): This should never happen!\n");
1498 DrawFixedGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic,
1500 MarkTileDirty(x, y);
1503 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1509 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1511 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX_VAR, TILEY_VAR, x, y);
1514 void DrawFixedGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1520 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1521 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
1524 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
1527 if (!IN_SCR_FIELD(x, y))
1529 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1530 printf("DrawGraphicThruMask(): This should never happen!\n");
1535 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
1538 MarkTileDirty(x, y);
1541 void DrawFixedGraphicThruMask(int x, int y, int graphic, int frame)
1544 if (!IN_SCR_FIELD(x, y))
1546 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1547 printf("DrawGraphicThruMask(): This should never happen!\n");
1552 DrawFixedGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
1554 MarkTileDirty(x, y);
1557 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
1563 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1565 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX_VAR, TILEY_VAR,
1569 void DrawFixedGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y,
1570 int graphic, int frame)
1575 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1577 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY,
1581 void DrawSizedGraphic(int x, int y, int graphic, int frame, int tilesize)
1583 DrawSizedGraphicExt(drawto, SX + x * tilesize, SY + y * tilesize, graphic,
1585 MarkTileDirty(x / tilesize, y / tilesize);
1588 void DrawSizedGraphicExt(DrawBuffer *d, int x, int y, int graphic, int frame,
1594 getSizedGraphicSource(graphic, frame, tilesize, &src_bitmap, &src_x, &src_y);
1595 BlitBitmap(src_bitmap, d, src_x, src_y, tilesize, tilesize, x, y);
1598 void DrawMiniGraphic(int x, int y, int graphic)
1600 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
1601 MarkTileDirty(x / 2, y / 2);
1604 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
1609 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1610 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
1613 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
1614 int graphic, int frame,
1615 int cut_mode, int mask_mode)
1620 int width = TILEX, height = TILEY;
1623 if (dx || dy) /* shifted graphic */
1625 if (x < BX1) /* object enters playfield from the left */
1632 else if (x > BX2) /* object enters playfield from the right */
1638 else if (x == BX1 && dx < 0) /* object leaves playfield to the left */
1644 else if (x == BX2 && dx > 0) /* object leaves playfield to the right */
1646 else if (dx) /* general horizontal movement */
1647 MarkTileDirty(x + SIGN(dx), y);
1649 if (y < BY1) /* object enters playfield from the top */
1651 if (cut_mode == CUT_BELOW) /* object completely above top border */
1659 else if (y > BY2) /* object enters playfield from the bottom */
1665 else if (y == BY1 && dy < 0) /* object leaves playfield to the top */
1671 else if (dy > 0 && cut_mode == CUT_ABOVE)
1673 if (y == BY2) /* object completely above bottom border */
1679 MarkTileDirty(x, y + 1);
1680 } /* object leaves playfield to the bottom */
1681 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1683 else if (dy) /* general vertical movement */
1684 MarkTileDirty(x, y + SIGN(dy));
1688 if (!IN_SCR_FIELD(x, y))
1690 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1691 printf("DrawGraphicShifted(): This should never happen!\n");
1696 width = width * TILESIZE_VAR / TILESIZE;
1697 height = height * TILESIZE_VAR / TILESIZE;
1698 cx = cx * TILESIZE_VAR / TILESIZE;
1699 cy = cy * TILESIZE_VAR / TILESIZE;
1700 dx = dx * TILESIZE_VAR / TILESIZE;
1701 dy = dy * TILESIZE_VAR / TILESIZE;
1703 if (width > 0 && height > 0)
1705 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1710 dst_x = FX + x * TILEX_VAR + dx;
1711 dst_y = FY + y * TILEY_VAR + dy;
1713 if (mask_mode == USE_MASKING)
1714 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1717 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1720 MarkTileDirty(x, y);
1724 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
1725 int graphic, int frame,
1726 int cut_mode, int mask_mode)
1731 int width = TILEX_VAR, height = TILEY_VAR;
1734 int x2 = x + SIGN(dx);
1735 int y2 = y + SIGN(dy);
1737 /* movement with two-tile animations must be sync'ed with movement position,
1738 not with current GfxFrame (which can be higher when using slow movement) */
1739 int anim_pos = (dx ? ABS(dx) : ABS(dy));
1740 int anim_frames = graphic_info[graphic].anim_frames;
1742 /* (we also need anim_delay here for movement animations with less frames) */
1743 int anim_delay = graphic_info[graphic].anim_delay;
1744 int sync_frame = anim_pos * anim_frames * anim_delay / TILESIZE;
1746 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
1747 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
1749 /* re-calculate animation frame for two-tile movement animation */
1750 frame = getGraphicAnimationFrame(graphic, sync_frame);
1752 /* check if movement start graphic inside screen area and should be drawn */
1753 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
1755 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
1757 dst_x = FX + x1 * TILEX_VAR;
1758 dst_y = FY + y1 * TILEY_VAR;
1760 if (mask_mode == USE_MASKING)
1761 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1764 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1767 MarkTileDirty(x1, y1);
1770 /* check if movement end graphic inside screen area and should be drawn */
1771 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
1773 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
1775 dst_x = FX + x2 * TILEX_VAR;
1776 dst_y = FY + y2 * TILEY_VAR;
1778 if (mask_mode == USE_MASKING)
1779 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1782 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1785 MarkTileDirty(x2, y2);
1789 static void DrawGraphicShifted(int x, int y, int dx, int dy,
1790 int graphic, int frame,
1791 int cut_mode, int mask_mode)
1795 DrawGraphic(x, y, graphic, frame);
1800 if (graphic_info[graphic].double_movement) /* EM style movement images */
1801 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1803 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1806 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1807 int frame, int cut_mode)
1809 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
1812 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1813 int cut_mode, int mask_mode)
1815 int lx = LEVELX(x), ly = LEVELY(y);
1819 if (IN_LEV_FIELD(lx, ly))
1821 SetRandomAnimationValue(lx, ly);
1823 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
1824 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1826 /* do not use double (EM style) movement graphic when not moving */
1827 if (graphic_info[graphic].double_movement && !dx && !dy)
1829 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
1830 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1833 else /* border element */
1835 graphic = el2img(element);
1836 frame = getGraphicAnimationFrame(graphic, -1);
1839 if (element == EL_EXPANDABLE_WALL)
1841 boolean left_stopped = FALSE, right_stopped = FALSE;
1843 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1844 left_stopped = TRUE;
1845 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1846 right_stopped = TRUE;
1848 if (left_stopped && right_stopped)
1850 else if (left_stopped)
1852 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1853 frame = graphic_info[graphic].anim_frames - 1;
1855 else if (right_stopped)
1857 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1858 frame = graphic_info[graphic].anim_frames - 1;
1863 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1864 else if (mask_mode == USE_MASKING)
1865 DrawGraphicThruMask(x, y, graphic, frame);
1867 DrawGraphic(x, y, graphic, frame);
1870 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1871 int cut_mode, int mask_mode)
1873 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1874 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1875 cut_mode, mask_mode);
1878 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1881 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1884 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1887 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1890 void DrawLevelElementThruMask(int x, int y, int element)
1892 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1895 void DrawLevelFieldThruMask(int x, int y)
1897 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1900 /* !!! implementation of quicksand is totally broken !!! */
1901 #define IS_CRUMBLED_TILE(x, y, e) \
1902 (GFX_CRUMBLED(e) && (!IN_LEV_FIELD(x, y) || \
1903 !IS_MOVING(x, y) || \
1904 (e) == EL_QUICKSAND_EMPTYING || \
1905 (e) == EL_QUICKSAND_FAST_EMPTYING))
1907 static void DrawLevelFieldCrumbledInnerCorners(int x, int y, int dx, int dy,
1912 int width, height, cx, cy;
1913 int sx = SCREENX(x), sy = SCREENY(y);
1914 int crumbled_border_size = graphic_info[graphic].border_size;
1915 int crumbled_tile_size = graphic_info[graphic].tile_size;
1916 int crumbled_border_size_var =
1917 crumbled_border_size * TILESIZE_VAR / crumbled_tile_size;
1920 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1922 for (i = 1; i < 4; i++)
1924 int dxx = (i & 1 ? dx : 0);
1925 int dyy = (i & 2 ? dy : 0);
1928 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1931 /* check if neighbour field is of same crumble type */
1932 boolean same = (IS_CRUMBLED_TILE(xx, yy, element) &&
1933 graphic_info[graphic].class ==
1934 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class);
1936 /* return if check prevents inner corner */
1937 if (same == (dxx == dx && dyy == dy))
1941 /* if we reach this point, we have an inner corner */
1943 getGraphicSource(graphic, 1, &src_bitmap, &src_x, &src_y);
1945 width = crumbled_border_size_var;
1946 height = crumbled_border_size_var;
1947 cx = (dx > 0 ? TILESIZE_VAR - width : 0);
1948 cy = (dy > 0 ? TILESIZE_VAR - height : 0);
1950 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1951 width, height, FX + sx * TILEX_VAR + cx, FY + sy * TILEY_VAR + cy);
1954 static void DrawLevelFieldCrumbledBorders(int x, int y, int graphic, int frame,
1959 int width, height, bx, by, cx, cy;
1960 int sx = SCREENX(x), sy = SCREENY(y);
1961 int crumbled_border_size = graphic_info[graphic].border_size;
1962 int crumbled_tile_size = graphic_info[graphic].tile_size;
1963 int crumbled_border_size_var =
1964 crumbled_border_size * TILESIZE_VAR / crumbled_tile_size;
1965 int crumbled_border_pos_var = TILESIZE_VAR - crumbled_border_size_var;
1968 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1970 /* draw simple, sloppy, non-corner-accurate crumbled border */
1972 width = (dir == 1 || dir == 2 ? crumbled_border_size_var : TILESIZE_VAR);
1973 height = (dir == 0 || dir == 3 ? crumbled_border_size_var : TILESIZE_VAR);
1974 cx = (dir == 2 ? crumbled_border_pos_var : 0);
1975 cy = (dir == 3 ? crumbled_border_pos_var : 0);
1977 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy, width, height,
1978 FX + sx * TILEX_VAR + cx,
1979 FY + sy * TILEY_VAR + cy);
1981 /* (remaining middle border part must be at least as big as corner part) */
1982 if (!(graphic_info[graphic].style & STYLE_ACCURATE_BORDERS) ||
1983 crumbled_border_size_var >= TILESIZE_VAR / 3)
1986 /* correct corners of crumbled border, if needed */
1988 for (i = -1; i <= 1; i += 2)
1990 int xx = x + (dir == 0 || dir == 3 ? i : 0);
1991 int yy = y + (dir == 1 || dir == 2 ? i : 0);
1992 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1995 /* check if neighbour field is of same crumble type */
1996 if (IS_CRUMBLED_TILE(xx, yy, element) &&
1997 graphic_info[graphic].class ==
1998 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
2000 /* no crumbled corner, but continued crumbled border */
2002 int c1 = (dir == 2 || dir == 3 ? crumbled_border_pos_var : 0);
2003 int c2 = (i == 1 ? crumbled_border_pos_var : 0);
2004 int b1 = (i == 1 ? crumbled_border_size_var :
2005 TILESIZE_VAR - 2 * crumbled_border_size_var);
2007 width = crumbled_border_size_var;
2008 height = crumbled_border_size_var;
2010 if (dir == 1 || dir == 2)
2025 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
2027 FX + sx * TILEX_VAR + cx,
2028 FY + sy * TILEY_VAR + cy);
2033 static void DrawLevelFieldCrumbledExt(int x, int y, int graphic, int frame)
2035 int sx = SCREENX(x), sy = SCREENY(y);
2038 static int xy[4][2] =
2046 if (!IN_LEV_FIELD(x, y))
2049 element = TILE_GFX_ELEMENT(x, y);
2051 if (IS_CRUMBLED_TILE(x, y, element)) /* crumble field itself */
2053 if (!IN_SCR_FIELD(sx, sy))
2056 /* crumble field borders towards direct neighbour fields */
2057 for (i = 0; i < 4; i++)
2059 int xx = x + xy[i][0];
2060 int yy = y + xy[i][1];
2062 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
2065 /* check if neighbour field is of same crumble type */
2066 if (IS_CRUMBLED_TILE(xx, yy, element) &&
2067 graphic_info[graphic].class ==
2068 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
2071 DrawLevelFieldCrumbledBorders(x, y, graphic, frame, i);
2074 /* crumble inner field corners towards corner neighbour fields */
2075 if ((graphic_info[graphic].style & STYLE_INNER_CORNERS) &&
2076 graphic_info[graphic].anim_frames == 2)
2078 for (i = 0; i < 4; i++)
2080 int dx = (i & 1 ? +1 : -1);
2081 int dy = (i & 2 ? +1 : -1);
2083 DrawLevelFieldCrumbledInnerCorners(x, y, dx, dy, graphic);
2087 MarkTileDirty(sx, sy);
2089 else /* center field is not crumbled -- crumble neighbour fields */
2091 /* crumble field borders of direct neighbour fields */
2092 for (i = 0; i < 4; i++)
2094 int xx = x + xy[i][0];
2095 int yy = y + xy[i][1];
2096 int sxx = sx + xy[i][0];
2097 int syy = sy + xy[i][1];
2099 if (!IN_LEV_FIELD(xx, yy) ||
2100 !IN_SCR_FIELD(sxx, syy))
2103 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
2106 element = TILE_GFX_ELEMENT(xx, yy);
2108 if (!IS_CRUMBLED_TILE(xx, yy, element))
2111 graphic = el_act2crm(element, ACTION_DEFAULT);
2113 DrawLevelFieldCrumbledBorders(xx, yy, graphic, 0, 3 - i);
2115 MarkTileDirty(sxx, syy);
2118 /* crumble inner field corners of corner neighbour fields */
2119 for (i = 0; i < 4; i++)
2121 int dx = (i & 1 ? +1 : -1);
2122 int dy = (i & 2 ? +1 : -1);
2128 if (!IN_LEV_FIELD(xx, yy) ||
2129 !IN_SCR_FIELD(sxx, syy))
2132 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
2135 element = TILE_GFX_ELEMENT(xx, yy);
2137 if (!IS_CRUMBLED_TILE(xx, yy, element))
2140 graphic = el_act2crm(element, ACTION_DEFAULT);
2142 if ((graphic_info[graphic].style & STYLE_INNER_CORNERS) &&
2143 graphic_info[graphic].anim_frames == 2)
2144 DrawLevelFieldCrumbledInnerCorners(xx, yy, -dx, -dy, graphic);
2146 MarkTileDirty(sxx, syy);
2151 void DrawLevelFieldCrumbled(int x, int y)
2155 if (!IN_LEV_FIELD(x, y))
2158 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
2159 GfxElement[x][y] != EL_UNDEFINED &&
2160 GFX_CRUMBLED(GfxElement[x][y]))
2162 DrawLevelFieldCrumbledDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
2167 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
2169 DrawLevelFieldCrumbledExt(x, y, graphic, 0);
2172 void DrawLevelFieldCrumbledDigging(int x, int y, int direction,
2175 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
2176 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
2177 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
2178 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
2179 int sx = SCREENX(x), sy = SCREENY(y);
2181 DrawGraphic(sx, sy, graphic1, frame1);
2182 DrawLevelFieldCrumbledExt(x, y, graphic2, frame2);
2185 void DrawLevelFieldCrumbledNeighbours(int x, int y)
2187 int sx = SCREENX(x), sy = SCREENY(y);
2188 static int xy[4][2] =
2197 /* crumble direct neighbour fields (required for field borders) */
2198 for (i = 0; i < 4; i++)
2200 int xx = x + xy[i][0];
2201 int yy = y + xy[i][1];
2202 int sxx = sx + xy[i][0];
2203 int syy = sy + xy[i][1];
2205 if (!IN_LEV_FIELD(xx, yy) ||
2206 !IN_SCR_FIELD(sxx, syy) ||
2207 !GFX_CRUMBLED(Feld[xx][yy]) ||
2211 DrawLevelField(xx, yy);
2214 /* crumble corner neighbour fields (required for inner field corners) */
2215 for (i = 0; i < 4; i++)
2217 int dx = (i & 1 ? +1 : -1);
2218 int dy = (i & 2 ? +1 : -1);
2224 if (!IN_LEV_FIELD(xx, yy) ||
2225 !IN_SCR_FIELD(sxx, syy) ||
2226 !GFX_CRUMBLED(Feld[xx][yy]) ||
2230 int element = TILE_GFX_ELEMENT(xx, yy);
2231 int graphic = el_act2crm(element, ACTION_DEFAULT);
2233 if ((graphic_info[graphic].style & STYLE_INNER_CORNERS) &&
2234 graphic_info[graphic].anim_frames == 2)
2235 DrawLevelField(xx, yy);
2239 static int getBorderElement(int x, int y)
2243 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
2244 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
2245 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
2246 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
2247 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
2248 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
2249 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
2251 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
2252 int steel_position = (x == -1 && y == -1 ? 0 :
2253 x == lev_fieldx && y == -1 ? 1 :
2254 x == -1 && y == lev_fieldy ? 2 :
2255 x == lev_fieldx && y == lev_fieldy ? 3 :
2256 x == -1 || x == lev_fieldx ? 4 :
2257 y == -1 || y == lev_fieldy ? 5 : 6);
2259 return border[steel_position][steel_type];
2262 void DrawScreenElement(int x, int y, int element)
2264 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
2265 DrawLevelFieldCrumbled(LEVELX(x), LEVELY(y));
2268 void DrawLevelElement(int x, int y, int element)
2270 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2271 DrawScreenElement(SCREENX(x), SCREENY(y), element);
2274 void DrawScreenField(int x, int y)
2276 int lx = LEVELX(x), ly = LEVELY(y);
2277 int element, content;
2279 if (!IN_LEV_FIELD(lx, ly))
2281 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
2284 element = getBorderElement(lx, ly);
2286 DrawScreenElement(x, y, element);
2291 element = Feld[lx][ly];
2292 content = Store[lx][ly];
2294 if (IS_MOVING(lx, ly))
2296 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
2297 boolean cut_mode = NO_CUTTING;
2299 if (element == EL_QUICKSAND_EMPTYING ||
2300 element == EL_QUICKSAND_FAST_EMPTYING ||
2301 element == EL_MAGIC_WALL_EMPTYING ||
2302 element == EL_BD_MAGIC_WALL_EMPTYING ||
2303 element == EL_DC_MAGIC_WALL_EMPTYING ||
2304 element == EL_AMOEBA_DROPPING)
2305 cut_mode = CUT_ABOVE;
2306 else if (element == EL_QUICKSAND_FILLING ||
2307 element == EL_QUICKSAND_FAST_FILLING ||
2308 element == EL_MAGIC_WALL_FILLING ||
2309 element == EL_BD_MAGIC_WALL_FILLING ||
2310 element == EL_DC_MAGIC_WALL_FILLING)
2311 cut_mode = CUT_BELOW;
2313 if (cut_mode == CUT_ABOVE)
2314 DrawScreenElement(x, y, element);
2316 DrawScreenElement(x, y, EL_EMPTY);
2319 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
2320 else if (cut_mode == NO_CUTTING)
2321 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
2324 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
2326 if (cut_mode == CUT_BELOW &&
2327 IN_LEV_FIELD(lx, ly + 1) && IN_SCR_FIELD(x, y + 1))
2328 DrawLevelElement(lx, ly + 1, element);
2331 if (content == EL_ACID)
2333 int dir = MovDir[lx][ly];
2334 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
2335 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
2337 DrawLevelElementThruMask(newlx, newly, EL_ACID);
2339 // prevent target field from being drawn again (but without masking)
2340 // (this would happen if target field is scanned after moving element)
2341 Stop[newlx][newly] = TRUE;
2344 else if (IS_BLOCKED(lx, ly))
2349 boolean cut_mode = NO_CUTTING;
2350 int element_old, content_old;
2352 Blocked2Moving(lx, ly, &oldx, &oldy);
2355 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
2356 MovDir[oldx][oldy] == MV_RIGHT);
2358 element_old = Feld[oldx][oldy];
2359 content_old = Store[oldx][oldy];
2361 if (element_old == EL_QUICKSAND_EMPTYING ||
2362 element_old == EL_QUICKSAND_FAST_EMPTYING ||
2363 element_old == EL_MAGIC_WALL_EMPTYING ||
2364 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
2365 element_old == EL_DC_MAGIC_WALL_EMPTYING ||
2366 element_old == EL_AMOEBA_DROPPING)
2367 cut_mode = CUT_ABOVE;
2369 DrawScreenElement(x, y, EL_EMPTY);
2372 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
2374 else if (cut_mode == NO_CUTTING)
2375 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
2378 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
2381 else if (IS_DRAWABLE(element))
2382 DrawScreenElement(x, y, element);
2384 DrawScreenElement(x, y, EL_EMPTY);
2387 void DrawLevelField(int x, int y)
2389 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2390 DrawScreenField(SCREENX(x), SCREENY(y));
2391 else if (IS_MOVING(x, y))
2395 Moving2Blocked(x, y, &newx, &newy);
2396 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
2397 DrawScreenField(SCREENX(newx), SCREENY(newy));
2399 else if (IS_BLOCKED(x, y))
2403 Blocked2Moving(x, y, &oldx, &oldy);
2404 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
2405 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
2409 void DrawSizedElement(int x, int y, int element, int tilesize)
2413 graphic = el2edimg(element);
2414 DrawSizedGraphic(x, y, graphic, 0, tilesize);
2417 void DrawMiniElement(int x, int y, int element)
2421 graphic = el2edimg(element);
2422 DrawMiniGraphic(x, y, graphic);
2425 void DrawSizedElementOrWall(int sx, int sy, int scroll_x, int scroll_y,
2428 int x = sx + scroll_x, y = sy + scroll_y;
2430 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
2431 DrawSizedElement(sx, sy, EL_EMPTY, tilesize);
2432 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
2433 DrawSizedElement(sx, sy, Feld[x][y], tilesize);
2435 DrawSizedGraphic(sx, sy, el2edimg(getBorderElement(x, y)), 0, tilesize);
2438 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
2440 int x = sx + scroll_x, y = sy + scroll_y;
2442 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
2443 DrawMiniElement(sx, sy, EL_EMPTY);
2444 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
2445 DrawMiniElement(sx, sy, Feld[x][y]);
2447 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
2450 void DrawEnvelopeBackgroundTiles(int graphic, int startx, int starty,
2451 int x, int y, int xsize, int ysize,
2452 int tile_width, int tile_height)
2456 int dst_x = startx + x * tile_width;
2457 int dst_y = starty + y * tile_height;
2458 int width = graphic_info[graphic].width;
2459 int height = graphic_info[graphic].height;
2460 int inner_width_raw = MAX(width - 2 * tile_width, tile_width);
2461 int inner_height_raw = MAX(height - 2 * tile_height, tile_height);
2462 int inner_width = inner_width_raw - (inner_width_raw % tile_width);
2463 int inner_height = inner_height_raw - (inner_height_raw % tile_height);
2464 int inner_sx = (width >= 3 * tile_width ? tile_width : 0);
2465 int inner_sy = (height >= 3 * tile_height ? tile_height : 0);
2466 boolean draw_masked = graphic_info[graphic].draw_masked;
2468 getFixedGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
2470 if (src_bitmap == NULL || width < tile_width || height < tile_height)
2472 ClearRectangle(drawto, dst_x, dst_y, tile_width, tile_height);
2476 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - tile_width :
2477 inner_sx + (x - 1) * tile_width % inner_width);
2478 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - tile_height :
2479 inner_sy + (y - 1) * tile_height % inner_height);
2482 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
2485 BlitBitmap(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
2489 void DrawEnvelopeBackground(int graphic, int startx, int starty,
2490 int x, int y, int xsize, int ysize, int font_nr)
2492 int font_width = getFontWidth(font_nr);
2493 int font_height = getFontHeight(font_nr);
2495 DrawEnvelopeBackgroundTiles(graphic, startx, starty, x, y, xsize, ysize,
2496 font_width, font_height);
2499 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
2501 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2502 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2503 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2504 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2505 boolean no_delay = (tape.warp_forward);
2506 unsigned int anim_delay = 0;
2507 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
2508 int anim_delay_value = (no_delay ? 0 : frame_delay_value) / 2;
2509 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
2510 int font_width = getFontWidth(font_nr);
2511 int font_height = getFontHeight(font_nr);
2512 int max_xsize = level.envelope[envelope_nr].xsize;
2513 int max_ysize = level.envelope[envelope_nr].ysize;
2514 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
2515 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
2516 int xend = max_xsize;
2517 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
2518 int xstep = (xstart < xend ? 1 : 0);
2519 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2521 int end = MAX(xend - xstart, yend - ystart);
2524 for (i = start; i <= end; i++)
2526 int last_frame = end; // last frame of this "for" loop
2527 int x = xstart + i * xstep;
2528 int y = ystart + i * ystep;
2529 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2530 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2531 int sx = SX + (SXSIZE - xsize * font_width) / 2;
2532 int sy = SY + (SYSIZE - ysize * font_height) / 2;
2535 SetDrawtoField(DRAW_TO_FIELDBUFFER);
2537 BlitScreenToBitmap(backbuffer);
2539 SetDrawtoField(DRAW_TO_BACKBUFFER);
2541 for (yy = 0; yy < ysize; yy++)
2542 for (xx = 0; xx < xsize; xx++)
2543 DrawEnvelopeBackground(graphic, sx, sy, xx, yy, xsize, ysize, font_nr);
2545 DrawTextBuffer(sx + font_width, sy + font_height,
2546 level.envelope[envelope_nr].text, font_nr, max_xsize,
2547 xsize - 2, ysize - 2, 0, mask_mode,
2548 level.envelope[envelope_nr].autowrap,
2549 level.envelope[envelope_nr].centered, FALSE);
2551 redraw_mask |= REDRAW_FIELD;
2554 SkipUntilDelayReached(&anim_delay, anim_delay_value, &i, last_frame);
2558 void ShowEnvelope(int envelope_nr)
2560 int element = EL_ENVELOPE_1 + envelope_nr;
2561 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2562 int sound_opening = element_info[element].sound[ACTION_OPENING];
2563 int sound_closing = element_info[element].sound[ACTION_CLOSING];
2564 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2565 boolean no_delay = (tape.warp_forward);
2566 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
2567 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
2568 int anim_mode = graphic_info[graphic].anim_mode;
2569 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2570 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2572 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
2574 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2576 if (anim_mode == ANIM_DEFAULT)
2577 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
2579 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
2582 Delay(wait_delay_value);
2584 WaitForEventToContinue();
2586 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2588 if (anim_mode != ANIM_NONE)
2589 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
2591 if (anim_mode == ANIM_DEFAULT)
2592 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
2594 game.envelope_active = FALSE;
2596 SetDrawtoField(DRAW_TO_FIELDBUFFER);
2598 redraw_mask |= REDRAW_FIELD;
2602 static void setRequestBasePosition(int *x, int *y)
2604 int sx_base, sy_base;
2606 if (request.x != -1)
2607 sx_base = request.x;
2608 else if (request.align == ALIGN_LEFT)
2610 else if (request.align == ALIGN_RIGHT)
2611 sx_base = SX + SXSIZE;
2613 sx_base = SX + SXSIZE / 2;
2615 if (request.y != -1)
2616 sy_base = request.y;
2617 else if (request.valign == VALIGN_TOP)
2619 else if (request.valign == VALIGN_BOTTOM)
2620 sy_base = SY + SYSIZE;
2622 sy_base = SY + SYSIZE / 2;
2628 static void setRequestPositionExt(int *x, int *y, int width, int height,
2629 boolean add_border_size)
2631 int border_size = request.border_size;
2632 int sx_base, sy_base;
2635 setRequestBasePosition(&sx_base, &sy_base);
2637 if (request.align == ALIGN_LEFT)
2639 else if (request.align == ALIGN_RIGHT)
2640 sx = sx_base - width;
2642 sx = sx_base - width / 2;
2644 if (request.valign == VALIGN_TOP)
2646 else if (request.valign == VALIGN_BOTTOM)
2647 sy = sy_base - height;
2649 sy = sy_base - height / 2;
2651 sx = MAX(0, MIN(sx, WIN_XSIZE - width));
2652 sy = MAX(0, MIN(sy, WIN_YSIZE - height));
2654 if (add_border_size)
2664 static void setRequestPosition(int *x, int *y, boolean add_border_size)
2666 setRequestPositionExt(x, y, request.width, request.height, add_border_size);
2669 void DrawEnvelopeRequest(char *text)
2671 char *text_final = text;
2672 char *text_door_style = NULL;
2673 int graphic = IMG_BACKGROUND_REQUEST;
2674 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2675 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2676 int font_nr = FONT_REQUEST;
2677 int font_width = getFontWidth(font_nr);
2678 int font_height = getFontHeight(font_nr);
2679 int border_size = request.border_size;
2680 int line_spacing = request.line_spacing;
2681 int line_height = font_height + line_spacing;
2682 int max_text_width = request.width - 2 * border_size;
2683 int max_text_height = request.height - 2 * border_size;
2684 int line_length = max_text_width / font_width;
2685 int max_lines = max_text_height / line_height;
2686 int text_width = line_length * font_width;
2687 int width = request.width;
2688 int height = request.height;
2689 int tile_size = MAX(request.step_offset, 1);
2690 int x_steps = width / tile_size;
2691 int y_steps = height / tile_size;
2692 int sx_offset = border_size;
2693 int sy_offset = border_size;
2697 if (request.centered)
2698 sx_offset = (request.width - text_width) / 2;
2700 if (request.wrap_single_words && !request.autowrap)
2702 char *src_text_ptr, *dst_text_ptr;
2704 text_door_style = checked_malloc(2 * strlen(text) + 1);
2706 src_text_ptr = text;
2707 dst_text_ptr = text_door_style;
2709 while (*src_text_ptr)
2711 if (*src_text_ptr == ' ' ||
2712 *src_text_ptr == '?' ||
2713 *src_text_ptr == '!')
2714 *dst_text_ptr++ = '\n';
2716 if (*src_text_ptr != ' ')
2717 *dst_text_ptr++ = *src_text_ptr;
2722 *dst_text_ptr = '\0';
2724 text_final = text_door_style;
2727 setRequestPosition(&sx, &sy, FALSE);
2729 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
2731 for (y = 0; y < y_steps; y++)
2732 for (x = 0; x < x_steps; x++)
2733 DrawEnvelopeBackgroundTiles(graphic, sx, sy,
2734 x, y, x_steps, y_steps,
2735 tile_size, tile_size);
2737 /* force DOOR font inside door area */
2738 SetFontStatus(GAME_MODE_PSEUDO_DOOR);
2740 DrawTextBuffer(sx + sx_offset, sy + sy_offset, text_final, font_nr,
2741 line_length, -1, max_lines, line_spacing, mask_mode,
2742 request.autowrap, request.centered, FALSE);
2746 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2747 RedrawGadget(tool_gadget[i]);
2749 // store readily prepared envelope request for later use when animating
2750 BlitBitmap(backbuffer, bitmap_db_store_2, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2752 if (text_door_style)
2753 free(text_door_style);
2756 void AnimateEnvelopeRequest(int anim_mode, int action)
2758 int graphic = IMG_BACKGROUND_REQUEST;
2759 boolean draw_masked = graphic_info[graphic].draw_masked;
2760 int delay_value_normal = request.step_delay;
2761 int delay_value_fast = delay_value_normal / 2;
2762 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2763 boolean no_delay = (tape.warp_forward);
2764 int delay_value = (ffwd_delay ? delay_value_fast : delay_value_normal);
2765 int anim_delay_value = (no_delay ? 0 : delay_value + 500 * 0) / 2;
2766 unsigned int anim_delay = 0;
2768 int tile_size = MAX(request.step_offset, 1);
2769 int max_xsize = request.width / tile_size;
2770 int max_ysize = request.height / tile_size;
2771 int max_xsize_inner = max_xsize - 2;
2772 int max_ysize_inner = max_ysize - 2;
2774 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize_inner : 0);
2775 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize_inner : 0);
2776 int xend = max_xsize_inner;
2777 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize_inner : 0);
2778 int xstep = (xstart < xend ? 1 : 0);
2779 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2781 int end = MAX(xend - xstart, yend - ystart);
2784 if (setup.quick_doors)
2791 for (i = start; i <= end; i++)
2793 int last_frame = end; // last frame of this "for" loop
2794 int x = xstart + i * xstep;
2795 int y = ystart + i * ystep;
2796 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2797 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2798 int xsize_size_left = (xsize - 1) * tile_size;
2799 int ysize_size_top = (ysize - 1) * tile_size;
2800 int max_xsize_pos = (max_xsize - 1) * tile_size;
2801 int max_ysize_pos = (max_ysize - 1) * tile_size;
2802 int width = xsize * tile_size;
2803 int height = ysize * tile_size;
2808 setRequestPosition(&src_x, &src_y, FALSE);
2809 setRequestPositionExt(&dst_x, &dst_y, width, height, FALSE);
2811 BlitBitmap(bitmap_db_store_1, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2813 for (yy = 0; yy < 2; yy++)
2815 for (xx = 0; xx < 2; xx++)
2817 int src_xx = src_x + xx * max_xsize_pos;
2818 int src_yy = src_y + yy * max_ysize_pos;
2819 int dst_xx = dst_x + xx * xsize_size_left;
2820 int dst_yy = dst_y + yy * ysize_size_top;
2821 int xx_size = (xx ? tile_size : xsize_size_left);
2822 int yy_size = (yy ? tile_size : ysize_size_top);
2825 BlitBitmapMasked(bitmap_db_store_2, backbuffer,
2826 src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
2828 BlitBitmap(bitmap_db_store_2, backbuffer,
2829 src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
2833 redraw_mask |= REDRAW_FIELD;
2837 SkipUntilDelayReached(&anim_delay, anim_delay_value, &i, last_frame);
2841 void ShowEnvelopeRequest(char *text, unsigned int req_state, int action)
2843 int graphic = IMG_BACKGROUND_REQUEST;
2844 int sound_opening = SND_REQUEST_OPENING;
2845 int sound_closing = SND_REQUEST_CLOSING;
2846 int anim_mode_1 = request.anim_mode; /* (higher priority) */
2847 int anim_mode_2 = graphic_info[graphic].anim_mode; /* (lower priority) */
2848 int anim_mode = (anim_mode_1 != ANIM_DEFAULT ? anim_mode_1 : anim_mode_2);
2849 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2850 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2852 if (game_status == GAME_MODE_PLAYING)
2853 BlitScreenToBitmap(backbuffer);
2855 SetDrawtoField(DRAW_TO_BACKBUFFER);
2857 // SetDrawBackgroundMask(REDRAW_NONE);
2859 if (action == ACTION_OPENING)
2861 BlitBitmap(backbuffer, bitmap_db_store_1, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2863 if (req_state & REQ_ASK)
2865 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2866 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2868 else if (req_state & REQ_CONFIRM)
2870 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2872 else if (req_state & REQ_PLAYER)
2874 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2875 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2876 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2877 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2880 DrawEnvelopeRequest(text);
2883 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
2885 if (action == ACTION_OPENING)
2887 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2889 if (anim_mode == ANIM_DEFAULT)
2890 AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_OPENING);
2892 AnimateEnvelopeRequest(main_anim_mode, ACTION_OPENING);
2896 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2898 if (anim_mode != ANIM_NONE)
2899 AnimateEnvelopeRequest(main_anim_mode, ACTION_CLOSING);
2901 if (anim_mode == ANIM_DEFAULT)
2902 AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_CLOSING);
2905 game.envelope_active = FALSE;
2907 if (action == ACTION_CLOSING)
2908 BlitBitmap(bitmap_db_store_1, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2910 // SetDrawBackgroundMask(last_draw_background_mask);
2912 redraw_mask |= REDRAW_FIELD;
2916 if (action == ACTION_CLOSING &&
2917 game_status == GAME_MODE_PLAYING &&
2918 level.game_engine_type == GAME_ENGINE_TYPE_RND)
2919 SetDrawtoField(DRAW_TO_FIELDBUFFER);
2922 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
2926 int graphic = el2preimg(element);
2928 getSizedGraphicSource(graphic, 0, tilesize, &src_bitmap, &src_x, &src_y);
2929 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
2932 void DrawLevel(int draw_background_mask)
2936 SetMainBackgroundImage(IMG_BACKGROUND_PLAYING);
2937 SetDrawBackgroundMask(draw_background_mask);
2941 for (x = BX1; x <= BX2; x++)
2942 for (y = BY1; y <= BY2; y++)
2943 DrawScreenField(x, y);
2945 redraw_mask |= REDRAW_FIELD;
2948 void DrawSizedLevel(int size_x, int size_y, int scroll_x, int scroll_y,
2953 for (x = 0; x < size_x; x++)
2954 for (y = 0; y < size_y; y++)
2955 DrawSizedElementOrWall(x, y, scroll_x, scroll_y, tilesize);
2957 redraw_mask |= REDRAW_FIELD;
2960 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
2964 for (x = 0; x < size_x; x++)
2965 for (y = 0; y < size_y; y++)
2966 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
2968 redraw_mask |= REDRAW_FIELD;
2971 static void DrawPreviewLevelPlayfieldExt(int from_x, int from_y)
2973 boolean show_level_border = (BorderElement != EL_EMPTY);
2974 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2975 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2976 int tile_size = preview.tile_size;
2977 int preview_width = preview.xsize * tile_size;
2978 int preview_height = preview.ysize * tile_size;
2979 int real_preview_xsize = MIN(level_xsize, preview.xsize);
2980 int real_preview_ysize = MIN(level_ysize, preview.ysize);
2981 int real_preview_width = real_preview_xsize * tile_size;
2982 int real_preview_height = real_preview_ysize * tile_size;
2983 int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
2984 int dst_y = SY + ALIGNED_YPOS(preview.y, preview_height, preview.valign);
2987 if (!IN_GFX_FIELD_FULL(dst_x, dst_y + preview_height - 1))
2990 DrawBackground(dst_x, dst_y, preview_width, preview_height);
2992 dst_x += (preview_width - real_preview_width) / 2;
2993 dst_y += (preview_height - real_preview_height) / 2;
2995 for (x = 0; x < real_preview_xsize; x++)
2997 for (y = 0; y < real_preview_ysize; y++)
2999 int lx = from_x + x + (show_level_border ? -1 : 0);
3000 int ly = from_y + y + (show_level_border ? -1 : 0);
3001 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
3002 getBorderElement(lx, ly));
3004 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
3005 element, tile_size);
3009 redraw_mask |= REDRAW_FIELD;
3012 #define MICROLABEL_EMPTY 0
3013 #define MICROLABEL_LEVEL_NAME 1
3014 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
3015 #define MICROLABEL_LEVEL_AUTHOR 3
3016 #define MICROLABEL_IMPORTED_FROM_HEAD 4
3017 #define MICROLABEL_IMPORTED_FROM 5
3018 #define MICROLABEL_IMPORTED_BY_HEAD 6
3019 #define MICROLABEL_IMPORTED_BY 7
3021 static int getMaxTextLength(struct TextPosInfo *pos, int font_nr)
3023 int max_text_width = SXSIZE;
3024 int font_width = getFontWidth(font_nr);
3026 if (pos->align == ALIGN_CENTER)
3027 max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
3028 else if (pos->align == ALIGN_RIGHT)
3029 max_text_width = pos->x;
3031 max_text_width = SXSIZE - pos->x;
3033 return max_text_width / font_width;
3036 static void DrawPreviewLevelLabelExt(int mode)
3038 struct TextPosInfo *pos = &menu.main.text.level_info_2;
3039 char label_text[MAX_OUTPUT_LINESIZE + 1];
3040 int max_len_label_text;
3041 int font_nr = pos->font;
3044 if (!IN_GFX_FIELD_FULL(pos->x, pos->y + getFontHeight(pos->font)))
3047 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
3048 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
3049 mode == MICROLABEL_IMPORTED_BY_HEAD)
3050 font_nr = pos->font_alt;
3052 max_len_label_text = getMaxTextLength(pos, font_nr);
3054 if (pos->size != -1)
3055 max_len_label_text = pos->size;
3057 for (i = 0; i < max_len_label_text; i++)
3058 label_text[i] = ' ';
3059 label_text[max_len_label_text] = '\0';
3061 if (strlen(label_text) > 0)
3062 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
3065 (mode == MICROLABEL_LEVEL_NAME ? level.name :
3066 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
3067 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
3068 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
3069 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
3070 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
3071 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
3072 max_len_label_text);
3073 label_text[max_len_label_text] = '\0';
3075 if (strlen(label_text) > 0)
3076 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
3078 redraw_mask |= REDRAW_FIELD;
3081 static void DrawPreviewLevelExt(boolean restart)
3083 static unsigned int scroll_delay = 0;
3084 static unsigned int label_delay = 0;
3085 static int from_x, from_y, scroll_direction;
3086 static int label_state, label_counter;
3087 unsigned int scroll_delay_value = preview.step_delay;
3088 boolean show_level_border = (BorderElement != EL_EMPTY);
3089 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
3090 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
3097 if (preview.anim_mode == ANIM_CENTERED)
3099 if (level_xsize > preview.xsize)
3100 from_x = (level_xsize - preview.xsize) / 2;
3101 if (level_ysize > preview.ysize)
3102 from_y = (level_ysize - preview.ysize) / 2;
3105 from_x += preview.xoffset;
3106 from_y += preview.yoffset;
3108 scroll_direction = MV_RIGHT;
3112 DrawPreviewLevelPlayfieldExt(from_x, from_y);
3113 DrawPreviewLevelLabelExt(label_state);
3115 /* initialize delay counters */
3116 DelayReached(&scroll_delay, 0);
3117 DelayReached(&label_delay, 0);
3119 if (leveldir_current->name)
3121 struct TextPosInfo *pos = &menu.main.text.level_info_1;
3122 char label_text[MAX_OUTPUT_LINESIZE + 1];
3123 int font_nr = pos->font;
3124 int max_len_label_text = getMaxTextLength(pos, font_nr);
3126 if (pos->size != -1)
3127 max_len_label_text = pos->size;
3129 strncpy(label_text, leveldir_current->name, max_len_label_text);
3130 label_text[max_len_label_text] = '\0';
3132 if (IN_GFX_FIELD_FULL(pos->x, pos->y + getFontHeight(pos->font)))
3133 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
3139 /* scroll preview level, if needed */
3140 if (preview.anim_mode != ANIM_NONE &&
3141 (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
3142 DelayReached(&scroll_delay, scroll_delay_value))
3144 switch (scroll_direction)
3149 from_x -= preview.step_offset;
3150 from_x = (from_x < 0 ? 0 : from_x);
3153 scroll_direction = MV_UP;
3157 if (from_x < level_xsize - preview.xsize)
3159 from_x += preview.step_offset;
3160 from_x = (from_x > level_xsize - preview.xsize ?
3161 level_xsize - preview.xsize : from_x);
3164 scroll_direction = MV_DOWN;
3170 from_y -= preview.step_offset;
3171 from_y = (from_y < 0 ? 0 : from_y);
3174 scroll_direction = MV_RIGHT;
3178 if (from_y < level_ysize - preview.ysize)
3180 from_y += preview.step_offset;
3181 from_y = (from_y > level_ysize - preview.ysize ?
3182 level_ysize - preview.ysize : from_y);
3185 scroll_direction = MV_LEFT;
3192 DrawPreviewLevelPlayfieldExt(from_x, from_y);
3195 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
3196 /* redraw micro level label, if needed */
3197 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
3198 !strEqual(level.author, ANONYMOUS_NAME) &&
3199 !strEqual(level.author, leveldir_current->name) &&
3200 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
3202 int max_label_counter = 23;
3204 if (leveldir_current->imported_from != NULL &&
3205 strlen(leveldir_current->imported_from) > 0)
3206 max_label_counter += 14;
3207 if (leveldir_current->imported_by != NULL &&
3208 strlen(leveldir_current->imported_by) > 0)
3209 max_label_counter += 14;
3211 label_counter = (label_counter + 1) % max_label_counter;
3212 label_state = (label_counter >= 0 && label_counter <= 7 ?
3213 MICROLABEL_LEVEL_NAME :
3214 label_counter >= 9 && label_counter <= 12 ?
3215 MICROLABEL_LEVEL_AUTHOR_HEAD :
3216 label_counter >= 14 && label_counter <= 21 ?
3217 MICROLABEL_LEVEL_AUTHOR :
3218 label_counter >= 23 && label_counter <= 26 ?
3219 MICROLABEL_IMPORTED_FROM_HEAD :
3220 label_counter >= 28 && label_counter <= 35 ?
3221 MICROLABEL_IMPORTED_FROM :
3222 label_counter >= 37 && label_counter <= 40 ?
3223 MICROLABEL_IMPORTED_BY_HEAD :
3224 label_counter >= 42 && label_counter <= 49 ?
3225 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
3227 if (leveldir_current->imported_from == NULL &&
3228 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
3229 label_state == MICROLABEL_IMPORTED_FROM))
3230 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
3231 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
3233 DrawPreviewLevelLabelExt(label_state);
3237 void DrawPreviewLevelInitial()
3239 DrawPreviewLevelExt(TRUE);
3242 void DrawPreviewLevelAnimation()
3244 DrawPreviewLevelExt(FALSE);
3247 inline static void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
3248 int graphic, int sync_frame,
3251 int frame = getGraphicAnimationFrame(graphic, sync_frame);
3253 if (mask_mode == USE_MASKING)
3254 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
3256 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
3259 void DrawFixedGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
3260 int graphic, int sync_frame, int mask_mode)
3262 int frame = getGraphicAnimationFrame(graphic, sync_frame);
3264 if (mask_mode == USE_MASKING)
3265 DrawFixedGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
3267 DrawFixedGraphicExt(dst_bitmap, x, y, graphic, frame);
3270 inline static void DrawGraphicAnimation(int x, int y, int graphic)
3272 int lx = LEVELX(x), ly = LEVELY(y);
3274 if (!IN_SCR_FIELD(x, y))
3277 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
3278 graphic, GfxFrame[lx][ly], NO_MASKING);
3280 MarkTileDirty(x, y);
3283 void DrawFixedGraphicAnimation(int x, int y, int graphic)
3285 int lx = LEVELX(x), ly = LEVELY(y);
3287 if (!IN_SCR_FIELD(x, y))
3290 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
3291 graphic, GfxFrame[lx][ly], NO_MASKING);
3292 MarkTileDirty(x, y);
3295 void DrawLevelGraphicAnimation(int x, int y, int graphic)
3297 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
3300 void DrawLevelElementAnimation(int x, int y, int element)
3302 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
3304 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
3307 void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
3309 int sx = SCREENX(x), sy = SCREENY(y);
3311 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
3314 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
3317 DrawGraphicAnimation(sx, sy, graphic);
3320 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
3321 DrawLevelFieldCrumbled(x, y);
3323 if (GFX_CRUMBLED(Feld[x][y]))
3324 DrawLevelFieldCrumbled(x, y);
3328 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
3330 int sx = SCREENX(x), sy = SCREENY(y);
3333 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
3336 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
3338 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
3341 DrawGraphicAnimation(sx, sy, graphic);
3343 if (GFX_CRUMBLED(element))
3344 DrawLevelFieldCrumbled(x, y);
3347 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
3349 if (player->use_murphy)
3351 /* this works only because currently only one player can be "murphy" ... */
3352 static int last_horizontal_dir = MV_LEFT;
3353 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
3355 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3356 last_horizontal_dir = move_dir;
3358 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
3360 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
3362 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
3368 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
3371 static boolean equalGraphics(int graphic1, int graphic2)
3373 struct GraphicInfo *g1 = &graphic_info[graphic1];
3374 struct GraphicInfo *g2 = &graphic_info[graphic2];
3376 return (g1->bitmap == g2->bitmap &&
3377 g1->src_x == g2->src_x &&
3378 g1->src_y == g2->src_y &&
3379 g1->anim_frames == g2->anim_frames &&
3380 g1->anim_delay == g2->anim_delay &&
3381 g1->anim_mode == g2->anim_mode);
3384 void DrawAllPlayers()
3388 for (i = 0; i < MAX_PLAYERS; i++)
3389 if (stored_player[i].active)
3390 DrawPlayer(&stored_player[i]);
3393 void DrawPlayerField(int x, int y)
3395 if (!IS_PLAYER(x, y))
3398 DrawPlayer(PLAYERINFO(x, y));
3401 #define DRAW_PLAYER_OVER_PUSHED_ELEMENT 1
3403 void DrawPlayer(struct PlayerInfo *player)
3405 int jx = player->jx;
3406 int jy = player->jy;
3407 int move_dir = player->MovDir;
3408 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
3409 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
3410 int last_jx = (player->is_moving ? jx - dx : jx);
3411 int last_jy = (player->is_moving ? jy - dy : jy);
3412 int next_jx = jx + dx;
3413 int next_jy = jy + dy;
3414 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
3415 boolean player_is_opaque = FALSE;
3416 int sx = SCREENX(jx), sy = SCREENY(jy);
3417 int sxx = 0, syy = 0;
3418 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
3420 int action = ACTION_DEFAULT;
3421 int last_player_graphic = getPlayerGraphic(player, move_dir);
3422 int last_player_frame = player->Frame;
3425 /* GfxElement[][] is set to the element the player is digging or collecting;
3426 remove also for off-screen player if the player is not moving anymore */
3427 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
3428 GfxElement[jx][jy] = EL_UNDEFINED;
3430 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
3434 if (!IN_LEV_FIELD(jx, jy))
3436 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
3437 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
3438 printf("DrawPlayerField(): This should never happen!\n");
3443 if (element == EL_EXPLOSION)
3446 action = (player->is_pushing ? ACTION_PUSHING :
3447 player->is_digging ? ACTION_DIGGING :
3448 player->is_collecting ? ACTION_COLLECTING :
3449 player->is_moving ? ACTION_MOVING :
3450 player->is_snapping ? ACTION_SNAPPING :
3451 player->is_dropping ? ACTION_DROPPING :
3452 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
3454 if (player->is_waiting)
3455 move_dir = player->dir_waiting;
3457 InitPlayerGfxAnimation(player, action, move_dir);
3459 /* ----------------------------------------------------------------------- */
3460 /* draw things in the field the player is leaving, if needed */
3461 /* ----------------------------------------------------------------------- */
3463 if (player->is_moving)
3465 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
3467 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
3469 if (last_element == EL_DYNAMITE_ACTIVE ||
3470 last_element == EL_EM_DYNAMITE_ACTIVE ||
3471 last_element == EL_SP_DISK_RED_ACTIVE)
3472 DrawDynamite(last_jx, last_jy);
3474 DrawLevelFieldThruMask(last_jx, last_jy);
3476 else if (last_element == EL_DYNAMITE_ACTIVE ||
3477 last_element == EL_EM_DYNAMITE_ACTIVE ||
3478 last_element == EL_SP_DISK_RED_ACTIVE)
3479 DrawDynamite(last_jx, last_jy);
3481 /* !!! this is not enough to prevent flickering of players which are
3482 moving next to each others without a free tile between them -- this
3483 can only be solved by drawing all players layer by layer (first the
3484 background, then the foreground etc.) !!! => TODO */
3485 else if (!IS_PLAYER(last_jx, last_jy))
3486 DrawLevelField(last_jx, last_jy);
3489 DrawLevelField(last_jx, last_jy);
3492 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
3493 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
3496 if (!IN_SCR_FIELD(sx, sy))
3499 /* ----------------------------------------------------------------------- */
3500 /* draw things behind the player, if needed */
3501 /* ----------------------------------------------------------------------- */
3504 DrawLevelElement(jx, jy, Back[jx][jy]);
3505 else if (IS_ACTIVE_BOMB(element))
3506 DrawLevelElement(jx, jy, EL_EMPTY);
3509 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
3511 int old_element = GfxElement[jx][jy];
3512 int old_graphic = el_act_dir2img(old_element, action, move_dir);
3513 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
3515 if (GFX_CRUMBLED(old_element))
3516 DrawLevelFieldCrumbledDigging(jx, jy, move_dir, player->StepFrame);
3518 DrawGraphic(sx, sy, old_graphic, frame);
3520 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
3521 player_is_opaque = TRUE;
3525 GfxElement[jx][jy] = EL_UNDEFINED;
3527 /* make sure that pushed elements are drawn with correct frame rate */
3528 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
3530 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
3531 GfxFrame[jx][jy] = player->StepFrame;
3533 DrawLevelField(jx, jy);
3537 #if !DRAW_PLAYER_OVER_PUSHED_ELEMENT
3538 /* ----------------------------------------------------------------------- */
3539 /* draw player himself */
3540 /* ----------------------------------------------------------------------- */
3542 graphic = getPlayerGraphic(player, move_dir);
3544 /* in the case of changed player action or direction, prevent the current
3545 animation frame from being restarted for identical animations */
3546 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
3547 player->Frame = last_player_frame;
3549 frame = getGraphicAnimationFrame(graphic, player->Frame);
3553 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3554 sxx = player->GfxPos;
3556 syy = player->GfxPos;
3559 if (player_is_opaque)
3560 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
3562 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3564 if (SHIELD_ON(player))
3566 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
3567 IMG_SHIELD_NORMAL_ACTIVE);
3568 int frame = getGraphicAnimationFrame(graphic, -1);
3570 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3574 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
3577 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3578 sxx = player->GfxPos;
3580 syy = player->GfxPos;
3584 /* ----------------------------------------------------------------------- */
3585 /* draw things the player is pushing, if needed */
3586 /* ----------------------------------------------------------------------- */
3588 if (player->is_pushing && player->is_moving)
3590 int px = SCREENX(jx), py = SCREENY(jy);
3591 int pxx = (TILEX - ABS(sxx)) * dx;
3592 int pyy = (TILEY - ABS(syy)) * dy;
3593 int gfx_frame = GfxFrame[jx][jy];
3599 if (!IS_MOVING(jx, jy)) /* push movement already finished */
3601 element = Feld[next_jx][next_jy];
3602 gfx_frame = GfxFrame[next_jx][next_jy];
3605 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
3607 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
3608 frame = getGraphicAnimationFrame(graphic, sync_frame);
3610 /* draw background element under pushed element (like the Sokoban field) */
3611 if (game.use_masked_pushing && IS_MOVING(jx, jy))
3613 /* this allows transparent pushing animation over non-black background */
3616 DrawLevelElement(jx, jy, Back[jx][jy]);
3618 DrawLevelElement(jx, jy, EL_EMPTY);
3620 if (Back[next_jx][next_jy])
3621 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3623 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
3625 else if (Back[next_jx][next_jy])
3626 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3629 /* do not draw (EM style) pushing animation when pushing is finished */
3630 /* (two-tile animations usually do not contain start and end frame) */
3631 if (graphic_info[graphic].double_movement && !IS_MOVING(jx, jy))
3632 DrawLevelElement(next_jx, next_jy, Feld[next_jx][next_jy]);
3634 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3636 /* masked drawing is needed for EMC style (double) movement graphics */
3637 /* !!! (ONLY WHEN DRAWING PUSHED ELEMENT OVER THE PLAYER) !!! */
3638 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3642 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
3643 /* ----------------------------------------------------------------------- */
3644 /* draw player himself */
3645 /* ----------------------------------------------------------------------- */
3647 graphic = getPlayerGraphic(player, move_dir);
3649 /* in the case of changed player action or direction, prevent the current
3650 animation frame from being restarted for identical animations */
3651 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
3652 player->Frame = last_player_frame;
3654 frame = getGraphicAnimationFrame(graphic, player->Frame);
3658 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3659 sxx = player->GfxPos;
3661 syy = player->GfxPos;
3664 if (player_is_opaque)
3665 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
3667 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3669 if (SHIELD_ON(player))
3671 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
3672 IMG_SHIELD_NORMAL_ACTIVE);
3673 int frame = getGraphicAnimationFrame(graphic, -1);
3675 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3679 /* ----------------------------------------------------------------------- */
3680 /* draw things in front of player (active dynamite or dynabombs) */
3681 /* ----------------------------------------------------------------------- */
3683 if (IS_ACTIVE_BOMB(element))
3685 graphic = el2img(element);
3686 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
3688 if (game.emulation == EMU_SUPAPLEX)
3689 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
3691 DrawGraphicThruMask(sx, sy, graphic, frame);
3694 if (player_is_moving && last_element == EL_EXPLOSION)
3696 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
3697 GfxElement[last_jx][last_jy] : EL_EMPTY);
3698 int graphic = el_act2img(element, ACTION_EXPLODING);
3699 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
3700 int phase = ExplodePhase[last_jx][last_jy] - 1;
3701 int frame = getGraphicAnimationFrame(graphic, phase - delay);
3704 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
3707 /* ----------------------------------------------------------------------- */
3708 /* draw elements the player is just walking/passing through/under */
3709 /* ----------------------------------------------------------------------- */
3711 if (player_is_moving)
3713 /* handle the field the player is leaving ... */
3714 if (IS_ACCESSIBLE_INSIDE(last_element))
3715 DrawLevelField(last_jx, last_jy);
3716 else if (IS_ACCESSIBLE_UNDER(last_element))
3717 DrawLevelFieldThruMask(last_jx, last_jy);
3720 /* do not redraw accessible elements if the player is just pushing them */
3721 if (!player_is_moving || !player->is_pushing)
3723 /* ... and the field the player is entering */
3724 if (IS_ACCESSIBLE_INSIDE(element))
3725 DrawLevelField(jx, jy);
3726 else if (IS_ACCESSIBLE_UNDER(element))
3727 DrawLevelFieldThruMask(jx, jy);
3730 MarkTileDirty(sx, sy);
3733 /* ------------------------------------------------------------------------- */
3735 void WaitForEventToContinue()
3737 boolean still_wait = TRUE;
3739 if (program.headless)
3742 /* simulate releasing mouse button over last gadget, if still pressed */
3744 HandleGadgets(-1, -1, 0);
3746 button_status = MB_RELEASED;
3760 case EVENT_BUTTONPRESS:
3761 case EVENT_KEYPRESS:
3762 #if defined(TARGET_SDL2)
3763 case SDL_CONTROLLERBUTTONDOWN:
3765 case SDL_JOYBUTTONDOWN:
3769 case EVENT_KEYRELEASE:
3770 ClearPlayerAction();
3774 HandleOtherEvents(&event);
3778 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3787 #define MAX_REQUEST_LINES 13
3788 #define MAX_REQUEST_LINE_FONT1_LEN 7
3789 #define MAX_REQUEST_LINE_FONT2_LEN 10
3791 static int RequestHandleEvents(unsigned int req_state)
3793 boolean level_solved = (game_status == GAME_MODE_PLAYING &&
3794 local_player->LevelSolved_GameEnd);
3795 int width = request.width;
3796 int height = request.height;
3800 setRequestPosition(&sx, &sy, FALSE);
3802 button_status = MB_RELEASED;
3804 request_gadget_id = -1;
3811 SetDrawtoField(DRAW_TO_FIELDBUFFER);
3813 HandleGameActions();
3815 SetDrawtoField(DRAW_TO_BACKBUFFER);
3817 if (global.use_envelope_request)
3819 /* copy current state of request area to middle of playfield area */
3820 BlitBitmap(bitmap_db_store_2, drawto, sx, sy, width, height, sx, sy);
3828 while (NextValidEvent(&event))
3832 case EVENT_BUTTONPRESS:
3833 case EVENT_BUTTONRELEASE:
3834 case EVENT_MOTIONNOTIFY:
3838 if (event.type == EVENT_MOTIONNOTIFY)
3843 motion_status = TRUE;
3844 mx = ((MotionEvent *) &event)->x;
3845 my = ((MotionEvent *) &event)->y;
3849 motion_status = FALSE;
3850 mx = ((ButtonEvent *) &event)->x;
3851 my = ((ButtonEvent *) &event)->y;
3852 if (event.type == EVENT_BUTTONPRESS)
3853 button_status = ((ButtonEvent *) &event)->button;
3855 button_status = MB_RELEASED;
3858 /* this sets 'request_gadget_id' */
3859 HandleGadgets(mx, my, button_status);
3861 switch (request_gadget_id)
3863 case TOOL_CTRL_ID_YES:
3866 case TOOL_CTRL_ID_NO:
3869 case TOOL_CTRL_ID_CONFIRM:
3870 result = TRUE | FALSE;
3873 case TOOL_CTRL_ID_PLAYER_1:
3876 case TOOL_CTRL_ID_PLAYER_2:
3879 case TOOL_CTRL_ID_PLAYER_3:
3882 case TOOL_CTRL_ID_PLAYER_4:
3893 #if defined(TARGET_SDL2)
3894 case SDL_WINDOWEVENT:
3895 HandleWindowEvent((WindowEvent *) &event);
3898 case SDL_APP_WILLENTERBACKGROUND:
3899 case SDL_APP_DIDENTERBACKGROUND:
3900 case SDL_APP_WILLENTERFOREGROUND:
3901 case SDL_APP_DIDENTERFOREGROUND:
3902 HandlePauseResumeEvent((PauseResumeEvent *) &event);
3906 case EVENT_KEYPRESS:
3908 Key key = GetEventKey((KeyEvent *)&event, TRUE);
3913 if (req_state & REQ_CONFIRM)
3918 #if defined(TARGET_SDL2)
3921 #if defined(KSYM_Rewind)
3922 case KSYM_Rewind: /* for Amazon Fire TV remote */
3929 #if defined(TARGET_SDL2)
3931 #if defined(KSYM_FastForward)
3932 case KSYM_FastForward: /* for Amazon Fire TV remote */
3939 HandleKeysDebug(key);
3943 if (req_state & REQ_PLAYER)
3949 case EVENT_KEYRELEASE:
3950 ClearPlayerAction();
3953 #if defined(TARGET_SDL2)
3954 case SDL_CONTROLLERBUTTONDOWN:
3955 switch (event.cbutton.button)
3957 case SDL_CONTROLLER_BUTTON_A:
3958 case SDL_CONTROLLER_BUTTON_X:
3959 case SDL_CONTROLLER_BUTTON_LEFTSHOULDER:
3963 case SDL_CONTROLLER_BUTTON_B:
3964 case SDL_CONTROLLER_BUTTON_Y:
3965 case SDL_CONTROLLER_BUTTON_RIGHTSHOULDER:
3966 case SDL_CONTROLLER_BUTTON_BACK:
3971 if (req_state & REQ_PLAYER)
3976 case SDL_CONTROLLERBUTTONUP:
3977 HandleJoystickEvent(&event);
3978 ClearPlayerAction();
3983 HandleOtherEvents(&event);
3988 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3990 int joy = AnyJoystick();
3992 if (joy & JOY_BUTTON_1)
3994 else if (joy & JOY_BUTTON_2)
4000 if (global.use_envelope_request)
4002 /* copy back current state of pressed buttons inside request area */
4003 BlitBitmap(drawto, bitmap_db_store_2, sx, sy, width, height, sx, sy);
4013 static boolean RequestDoor(char *text, unsigned int req_state)
4015 unsigned int old_door_state;
4016 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
4017 int font_nr = FONT_TEXT_2;
4022 if (maxWordLengthInString(text) > MAX_REQUEST_LINE_FONT1_LEN)
4024 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
4025 font_nr = FONT_TEXT_1;
4028 if (game_status == GAME_MODE_PLAYING)
4029 BlitScreenToBitmap(backbuffer);
4031 /* disable deactivated drawing when quick-loading level tape recording */
4032 if (tape.playing && tape.deactivate_display)
4033 TapeDeactivateDisplayOff(TRUE);
4035 SetMouseCursor(CURSOR_DEFAULT);
4037 #if defined(NETWORK_AVALIABLE)
4038 /* pause network game while waiting for request to answer */
4039 if (options.network &&
4040 game_status == GAME_MODE_PLAYING &&
4041 req_state & REQUEST_WAIT_FOR_INPUT)
4042 SendToServer_PausePlaying();
4045 old_door_state = GetDoorState();
4047 /* simulate releasing mouse button over last gadget, if still pressed */
4049 HandleGadgets(-1, -1, 0);
4053 /* draw released gadget before proceeding */
4056 if (old_door_state & DOOR_OPEN_1)
4058 CloseDoor(DOOR_CLOSE_1);
4060 /* save old door content */
4061 BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
4062 0 * DXSIZE, 0, DXSIZE, DYSIZE, 1 * DXSIZE, 0);
4065 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
4066 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4068 /* clear door drawing field */
4069 DrawBackground(DX, DY, DXSIZE, DYSIZE);
4071 /* force DOOR font inside door area */
4072 SetFontStatus(GAME_MODE_PSEUDO_DOOR);
4074 /* write text for request */
4075 for (text_ptr = text, ty = 0; ty < MAX_REQUEST_LINES; ty++)
4077 char text_line[max_request_line_len + 1];
4083 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
4085 tc = *(text_ptr + tx);
4086 // if (!tc || tc == ' ')
4087 if (!tc || tc == ' ' || tc == '?' || tc == '!')
4091 if ((tc == '?' || tc == '!') && tl == 0)
4101 strncpy(text_line, text_ptr, tl);
4104 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
4105 DY + 8 + ty * (getFontHeight(font_nr) + 2),
4106 text_line, font_nr);
4108 text_ptr += tl + (tc == ' ' ? 1 : 0);
4109 // text_ptr += tl + (tc == ' ' || tc == '?' || tc == '!' ? 1 : 0);
4114 if (req_state & REQ_ASK)
4116 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
4117 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
4119 else if (req_state & REQ_CONFIRM)
4121 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
4123 else if (req_state & REQ_PLAYER)
4125 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
4126 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
4127 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
4128 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
4131 /* copy request gadgets to door backbuffer */
4132 BlitBitmap(drawto, bitmap_db_door_1, DX, DY, DXSIZE, DYSIZE, 0, 0);
4134 OpenDoor(DOOR_OPEN_1);
4136 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
4138 if (game_status == GAME_MODE_PLAYING)
4140 SetPanelBackground();
4141 SetDrawBackgroundMask(REDRAW_DOOR_1);
4145 SetDrawBackgroundMask(REDRAW_FIELD);
4151 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4153 // ---------- handle request buttons ----------
4154 result = RequestHandleEvents(req_state);
4158 if (!(req_state & REQ_STAY_OPEN))
4160 CloseDoor(DOOR_CLOSE_1);
4162 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
4163 (req_state & REQ_REOPEN))
4164 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
4169 if (game_status == GAME_MODE_PLAYING)
4171 SetPanelBackground();
4172 SetDrawBackgroundMask(REDRAW_DOOR_1);
4176 SetDrawBackgroundMask(REDRAW_FIELD);
4179 #if defined(NETWORK_AVALIABLE)
4180 /* continue network game after request */
4181 if (options.network &&
4182 game_status == GAME_MODE_PLAYING &&
4183 req_state & REQUEST_WAIT_FOR_INPUT)
4184 SendToServer_ContinuePlaying();
4187 /* restore deactivated drawing when quick-loading level tape recording */
4188 if (tape.playing && tape.deactivate_display)
4189 TapeDeactivateDisplayOn();
4194 static boolean RequestEnvelope(char *text, unsigned int req_state)
4198 if (game_status == GAME_MODE_PLAYING)
4199 BlitScreenToBitmap(backbuffer);
4201 /* disable deactivated drawing when quick-loading level tape recording */
4202 if (tape.playing && tape.deactivate_display)
4203 TapeDeactivateDisplayOff(TRUE);
4205 SetMouseCursor(CURSOR_DEFAULT);
4207 #if defined(NETWORK_AVALIABLE)
4208 /* pause network game while waiting for request to answer */
4209 if (options.network &&
4210 game_status == GAME_MODE_PLAYING &&
4211 req_state & REQUEST_WAIT_FOR_INPUT)
4212 SendToServer_PausePlaying();
4215 /* simulate releasing mouse button over last gadget, if still pressed */
4217 HandleGadgets(-1, -1, 0);
4221 // (replace with setting corresponding request background)
4222 // SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
4223 // SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4225 /* clear door drawing field */
4226 // DrawBackground(DX, DY, DXSIZE, DYSIZE);
4228 ShowEnvelopeRequest(text, req_state, ACTION_OPENING);
4230 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
4232 if (game_status == GAME_MODE_PLAYING)
4234 SetPanelBackground();
4235 SetDrawBackgroundMask(REDRAW_DOOR_1);
4239 SetDrawBackgroundMask(REDRAW_FIELD);
4245 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4247 // ---------- handle request buttons ----------
4248 result = RequestHandleEvents(req_state);
4252 ShowEnvelopeRequest(text, req_state, ACTION_CLOSING);
4256 if (game_status == GAME_MODE_PLAYING)
4258 SetPanelBackground();
4259 SetDrawBackgroundMask(REDRAW_DOOR_1);
4263 SetDrawBackgroundMask(REDRAW_FIELD);
4266 #if defined(NETWORK_AVALIABLE)
4267 /* continue network game after request */
4268 if (options.network &&
4269 game_status == GAME_MODE_PLAYING &&
4270 req_state & REQUEST_WAIT_FOR_INPUT)
4271 SendToServer_ContinuePlaying();
4274 /* restore deactivated drawing when quick-loading level tape recording */
4275 if (tape.playing && tape.deactivate_display)
4276 TapeDeactivateDisplayOn();
4281 boolean Request(char *text, unsigned int req_state)
4283 boolean overlay_active = GetOverlayActive();
4286 SetOverlayActive(FALSE);
4288 if (global.use_envelope_request)
4289 result = RequestEnvelope(text, req_state);
4291 result = RequestDoor(text, req_state);
4293 SetOverlayActive(overlay_active);
4298 static int compareDoorPartOrderInfo(const void *object1, const void *object2)
4300 const struct DoorPartOrderInfo *dpo1 = (struct DoorPartOrderInfo *)object1;
4301 const struct DoorPartOrderInfo *dpo2 = (struct DoorPartOrderInfo *)object2;
4304 if (dpo1->sort_priority != dpo2->sort_priority)
4305 compare_result = dpo1->sort_priority - dpo2->sort_priority;
4307 compare_result = dpo1->nr - dpo2->nr;
4309 return compare_result;
4312 void InitGraphicCompatibilityInfo_Doors()
4318 struct DoorInfo *door;
4322 { DOOR_1, IMG_GFX_DOOR_1_PART_1, IMG_GFX_DOOR_1_PART_8, &door_1 },
4323 { DOOR_2, IMG_GFX_DOOR_2_PART_1, IMG_GFX_DOOR_2_PART_8, &door_2 },
4325 { -1, -1, -1, NULL }
4327 struct Rect door_rect_list[] =
4329 { DX, DY, DXSIZE, DYSIZE },
4330 { VX, VY, VXSIZE, VYSIZE }
4334 for (i = 0; doors[i].door_token != -1; i++)
4336 int door_token = doors[i].door_token;
4337 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
4338 int part_1 = doors[i].part_1;
4339 int part_8 = doors[i].part_8;
4340 int part_2 = part_1 + 1;
4341 int part_3 = part_1 + 2;
4342 struct DoorInfo *door = doors[i].door;
4343 struct Rect *door_rect = &door_rect_list[door_index];
4344 boolean door_gfx_redefined = FALSE;
4346 /* check if any door part graphic definitions have been redefined */
4348 for (j = 0; door_part_controls[j].door_token != -1; j++)
4350 struct DoorPartControlInfo *dpc = &door_part_controls[j];
4351 struct FileInfo *fi = getImageListEntryFromImageID(dpc->graphic);
4353 if (dpc->door_token == door_token && fi->redefined)
4354 door_gfx_redefined = TRUE;
4357 /* check for old-style door graphic/animation modifications */
4359 if (!door_gfx_redefined)
4361 if (door->anim_mode & ANIM_STATIC_PANEL)
4363 door->panel.step_xoffset = 0;
4364 door->panel.step_yoffset = 0;
4367 if (door->anim_mode & (ANIM_HORIZONTAL | ANIM_VERTICAL))
4369 struct GraphicInfo *g_part_1 = &graphic_info[part_1];
4370 struct GraphicInfo *g_part_2 = &graphic_info[part_2];
4371 int num_door_steps, num_panel_steps;
4373 /* remove door part graphics other than the two default wings */
4375 for (j = 0; door_part_controls[j].door_token != -1; j++)
4377 struct DoorPartControlInfo *dpc = &door_part_controls[j];
4378 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4380 if (dpc->graphic >= part_3 &&
4381 dpc->graphic <= part_8)
4385 /* set graphics and screen positions of the default wings */
4387 g_part_1->width = door_rect->width;
4388 g_part_1->height = door_rect->height;
4389 g_part_2->width = door_rect->width;
4390 g_part_2->height = door_rect->height;
4391 g_part_2->src_x = door_rect->width;
4392 g_part_2->src_y = g_part_1->src_y;
4394 door->part_2.x = door->part_1.x;
4395 door->part_2.y = door->part_1.y;
4397 if (door->width != -1)
4399 g_part_1->width = door->width;
4400 g_part_2->width = door->width;
4402 // special treatment for graphics and screen position of right wing
4403 g_part_2->src_x += door_rect->width - door->width;
4404 door->part_2.x += door_rect->width - door->width;
4407 if (door->height != -1)
4409 g_part_1->height = door->height;
4410 g_part_2->height = door->height;
4412 // special treatment for graphics and screen position of bottom wing
4413 g_part_2->src_y += door_rect->height - door->height;
4414 door->part_2.y += door_rect->height - door->height;
4417 /* set animation delays for the default wings and panels */
4419 door->part_1.step_delay = door->step_delay;
4420 door->part_2.step_delay = door->step_delay;
4421 door->panel.step_delay = door->step_delay;
4423 /* set animation draw order for the default wings */
4425 door->part_1.sort_priority = 2; /* draw left wing over ... */
4426 door->part_2.sort_priority = 1; /* ... right wing */
4428 /* set animation draw offset for the default wings */
4430 if (door->anim_mode & ANIM_HORIZONTAL)
4432 door->part_1.step_xoffset = door->step_offset;
4433 door->part_1.step_yoffset = 0;
4434 door->part_2.step_xoffset = door->step_offset * -1;
4435 door->part_2.step_yoffset = 0;
4437 num_door_steps = g_part_1->width / door->step_offset;
4439 else // ANIM_VERTICAL
4441 door->part_1.step_xoffset = 0;
4442 door->part_1.step_yoffset = door->step_offset;
4443 door->part_2.step_xoffset = 0;
4444 door->part_2.step_yoffset = door->step_offset * -1;
4446 num_door_steps = g_part_1->height / door->step_offset;
4449 /* set animation draw offset for the default panels */
4451 if (door->step_offset > 1)
4453 num_panel_steps = 2 * door_rect->height / door->step_offset;
4454 door->panel.start_step = num_panel_steps - num_door_steps;
4455 door->panel.start_step_closing = door->panel.start_step;
4459 num_panel_steps = door_rect->height / door->step_offset;
4460 door->panel.start_step = num_panel_steps - num_door_steps / 2;
4461 door->panel.start_step_closing = door->panel.start_step;
4462 door->panel.step_delay *= 2;
4473 for (i = 0; door_part_controls[i].door_token != -1; i++)
4475 struct DoorPartControlInfo *dpc = &door_part_controls[i];
4476 struct DoorPartOrderInfo *dpo = &door_part_order[i];
4478 /* initialize "start_step_opening" and "start_step_closing", if needed */
4479 if (dpc->pos->start_step_opening == 0 &&
4480 dpc->pos->start_step_closing == 0)
4482 // dpc->pos->start_step_opening = dpc->pos->start_step;
4483 dpc->pos->start_step_closing = dpc->pos->start_step;
4486 /* fill structure for door part draw order (sorted below) */
4488 dpo->sort_priority = dpc->pos->sort_priority;
4491 /* sort door part controls according to sort_priority and graphic number */
4492 qsort(door_part_order, MAX_DOOR_PARTS,
4493 sizeof(struct DoorPartOrderInfo), compareDoorPartOrderInfo);
4496 unsigned int OpenDoor(unsigned int door_state)
4498 if (door_state & DOOR_COPY_BACK)
4500 if (door_state & DOOR_OPEN_1)
4501 BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
4502 1 * DXSIZE, 0, DXSIZE, DYSIZE, 0 * DXSIZE, 0);
4504 if (door_state & DOOR_OPEN_2)
4505 BlitBitmap(bitmap_db_door_2, bitmap_db_door_2,
4506 1 * VXSIZE, 0, VXSIZE, VYSIZE, 0 * VXSIZE, 0);
4508 door_state &= ~DOOR_COPY_BACK;
4511 return MoveDoor(door_state);
4514 unsigned int CloseDoor(unsigned int door_state)
4516 unsigned int old_door_state = GetDoorState();
4518 if (!(door_state & DOOR_NO_COPY_BACK))
4520 if (old_door_state & DOOR_OPEN_1)
4521 BlitBitmap(backbuffer, bitmap_db_door_1,
4522 DX, DY, DXSIZE, DYSIZE, 0, 0);
4524 if (old_door_state & DOOR_OPEN_2)
4525 BlitBitmap(backbuffer, bitmap_db_door_2,
4526 VX, VY, VXSIZE, VYSIZE, 0, 0);
4528 door_state &= ~DOOR_NO_COPY_BACK;
4531 return MoveDoor(door_state);
4534 unsigned int GetDoorState()
4536 return MoveDoor(DOOR_GET_STATE);
4539 unsigned int SetDoorState(unsigned int door_state)
4541 return MoveDoor(door_state | DOOR_SET_STATE);
4544 int euclid(int a, int b)
4546 return (b ? euclid(b, a % b) : a);
4549 unsigned int MoveDoor(unsigned int door_state)
4551 struct Rect door_rect_list[] =
4553 { DX, DY, DXSIZE, DYSIZE },
4554 { VX, VY, VXSIZE, VYSIZE }
4556 static int door1 = DOOR_CLOSE_1;
4557 static int door2 = DOOR_CLOSE_2;
4558 unsigned int door_delay = 0;
4559 unsigned int door_delay_value;
4562 if (door_state == DOOR_GET_STATE)
4563 return (door1 | door2);
4565 if (door_state & DOOR_SET_STATE)
4567 if (door_state & DOOR_ACTION_1)
4568 door1 = door_state & DOOR_ACTION_1;
4569 if (door_state & DOOR_ACTION_2)
4570 door2 = door_state & DOOR_ACTION_2;
4572 return (door1 | door2);
4575 if (!(door_state & DOOR_FORCE_REDRAW))
4577 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
4578 door_state &= ~DOOR_OPEN_1;
4579 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
4580 door_state &= ~DOOR_CLOSE_1;
4581 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
4582 door_state &= ~DOOR_OPEN_2;
4583 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
4584 door_state &= ~DOOR_CLOSE_2;
4587 if (global.autoplay_leveldir)
4589 door_state |= DOOR_NO_DELAY;
4590 door_state &= ~DOOR_CLOSE_ALL;
4593 if (game_status == GAME_MODE_EDITOR)
4594 door_state |= DOOR_NO_DELAY;
4596 if (door_state & DOOR_ACTION)
4598 boolean door_panel_drawn[NUM_DOORS];
4599 boolean panel_has_doors[NUM_DOORS];
4600 boolean door_part_skip[MAX_DOOR_PARTS];
4601 boolean door_part_done[MAX_DOOR_PARTS];
4602 boolean door_part_done_all;
4603 int num_steps[MAX_DOOR_PARTS];
4604 int max_move_delay = 0; // delay for complete animations of all doors
4605 int max_step_delay = 0; // delay (ms) between two animation frames
4606 int num_move_steps = 0; // number of animation steps for all doors
4607 int max_move_delay_doors_only = 0; // delay for doors only (no panel)
4608 int num_move_steps_doors_only = 0; // steps for doors only (no panel)
4609 int current_move_delay = 0;
4613 for (i = 0; i < NUM_DOORS; i++)
4614 panel_has_doors[i] = FALSE;
4616 for (i = 0; i < MAX_DOOR_PARTS; i++)
4618 struct DoorPartControlInfo *dpc = &door_part_controls[i];
4619 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4620 int door_token = dpc->door_token;
4622 door_part_done[i] = FALSE;
4623 door_part_skip[i] = (!(door_state & door_token) ||
4627 for (i = 0; i < MAX_DOOR_PARTS; i++)
4629 int nr = door_part_order[i].nr;
4630 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
4631 struct DoorPartPosInfo *pos = dpc->pos;
4632 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4633 int door_token = dpc->door_token;
4634 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
4635 boolean is_panel = DOOR_PART_IS_PANEL(nr);
4636 int step_xoffset = ABS(pos->step_xoffset);
4637 int step_yoffset = ABS(pos->step_yoffset);
4638 int step_delay = pos->step_delay;
4639 int current_door_state = door_state & door_token;
4640 boolean door_opening = ((current_door_state & DOOR_OPEN) != 0);
4641 boolean door_closing = ((current_door_state & DOOR_CLOSE) != 0);
4642 boolean part_opening = (is_panel ? door_closing : door_opening);
4643 int start_step = (part_opening ? pos->start_step_opening :
4644 pos->start_step_closing);
4645 float move_xsize = (step_xoffset ? g->width : 0);
4646 float move_ysize = (step_yoffset ? g->height : 0);
4647 int move_xsteps = (step_xoffset ? ceil(move_xsize / step_xoffset) : 0);
4648 int move_ysteps = (step_yoffset ? ceil(move_ysize / step_yoffset) : 0);
4649 int move_steps = (move_xsteps && move_ysteps ?
4650 MIN(move_xsteps, move_ysteps) :
4651 move_xsteps ? move_xsteps : move_ysteps) - start_step;
4652 int move_delay = move_steps * step_delay;
4654 if (door_part_skip[nr])
4657 max_move_delay = MAX(max_move_delay, move_delay);
4658 max_step_delay = (max_step_delay == 0 ? step_delay :
4659 euclid(max_step_delay, step_delay));
4660 num_steps[nr] = move_steps;
4664 max_move_delay_doors_only = MAX(max_move_delay_doors_only, move_delay);
4666 panel_has_doors[door_index] = TRUE;
4670 max_step_delay = MAX(1, max_step_delay); // prevent division by zero
4672 num_move_steps = max_move_delay / max_step_delay;
4673 num_move_steps_doors_only = max_move_delay_doors_only / max_step_delay;
4675 door_delay_value = max_step_delay;
4677 if ((door_state & DOOR_NO_DELAY) || setup.quick_doors)
4679 start = num_move_steps - 1;
4683 /* opening door sound has priority over simultaneously closing door */
4684 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
4685 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
4686 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
4687 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
4690 for (k = start; k < num_move_steps; k++)
4692 int last_frame = num_move_steps - 1; // last frame of this "for" loop
4694 door_part_done_all = TRUE;
4696 for (i = 0; i < NUM_DOORS; i++)
4697 door_panel_drawn[i] = FALSE;
4699 for (i = 0; i < MAX_DOOR_PARTS; i++)
4701 int nr = door_part_order[i].nr;
4702 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
4703 struct DoorPartPosInfo *pos = dpc->pos;
4704 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4705 int door_token = dpc->door_token;
4706 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
4707 boolean is_panel = DOOR_PART_IS_PANEL(nr);
4708 boolean is_panel_and_door_has_closed = FALSE;
4709 struct Rect *door_rect = &door_rect_list[door_index];
4710 Bitmap *bitmap_db_door = (door_token == DOOR_1 ? bitmap_db_door_1 :
4712 Bitmap *bitmap = (is_panel ? bitmap_db_door : g->bitmap);
4713 int current_door_state = door_state & door_token;
4714 boolean door_opening = ((current_door_state & DOOR_OPEN) != 0);
4715 boolean door_closing = !door_opening;
4716 boolean part_opening = (is_panel ? door_closing : door_opening);
4717 boolean part_closing = !part_opening;
4718 int start_step = (part_opening ? pos->start_step_opening :
4719 pos->start_step_closing);
4720 int step_delay = pos->step_delay;
4721 int step_factor = step_delay / max_step_delay;
4722 int k1 = (step_factor ? k / step_factor + 1 : k);
4723 int k2 = (part_opening ? k1 + start_step : num_steps[nr] - k1);
4724 int kk = MAX(0, k2);
4727 int src_x, src_y, src_xx, src_yy;
4728 int dst_x, dst_y, dst_xx, dst_yy;
4731 if (door_part_skip[nr])
4734 if (!(door_state & door_token))
4742 int k2_door = (door_opening ? k : num_move_steps_doors_only - k - 1);
4743 int kk_door = MAX(0, k2_door);
4744 int sync_frame = kk_door * door_delay_value;
4745 int frame = getGraphicAnimationFrame(dpc->graphic, sync_frame);
4747 getFixedGraphicSource(dpc->graphic, frame, &bitmap,
4748 &g_src_x, &g_src_y);
4753 if (!door_panel_drawn[door_index])
4755 ClearRectangle(drawto, door_rect->x, door_rect->y,
4756 door_rect->width, door_rect->height);
4758 door_panel_drawn[door_index] = TRUE;
4761 // draw opening or closing door parts
4763 if (pos->step_xoffset < 0) // door part on right side
4766 dst_xx = pos->x + ABS(kk * pos->step_xoffset);
4769 if (dst_xx + width > door_rect->width)
4770 width = door_rect->width - dst_xx;
4772 else // door part on left side
4775 dst_xx = pos->x - kk * pos->step_xoffset;
4779 src_xx = ABS(dst_xx);
4783 width = g->width - src_xx;
4785 if (width > door_rect->width)
4786 width = door_rect->width;
4788 // printf("::: k == %d [%d] \n", k, start_step);
4791 if (pos->step_yoffset < 0) // door part on bottom side
4794 dst_yy = pos->y + ABS(kk * pos->step_yoffset);
4797 if (dst_yy + height > door_rect->height)
4798 height = door_rect->height - dst_yy;
4800 else // door part on top side
4803 dst_yy = pos->y - kk * pos->step_yoffset;
4807 src_yy = ABS(dst_yy);
4811 height = g->height - src_yy;
4814 src_x = g_src_x + src_xx;
4815 src_y = g_src_y + src_yy;
4817 dst_x = door_rect->x + dst_xx;
4818 dst_y = door_rect->y + dst_yy;
4820 is_panel_and_door_has_closed =
4823 panel_has_doors[door_index] &&
4824 k >= num_move_steps_doors_only - 1);
4826 if (width >= 0 && width <= g->width &&
4827 height >= 0 && height <= g->height &&
4828 !is_panel_and_door_has_closed)
4830 if (is_panel || !pos->draw_masked)
4831 BlitBitmap(bitmap, drawto, src_x, src_y, width, height,
4834 BlitBitmapMasked(bitmap, drawto, src_x, src_y, width, height,
4838 redraw_mask |= REDRAW_DOOR_FROM_TOKEN(door_token);
4840 if ((part_opening && (width < 0 || height < 0)) ||
4841 (part_closing && (width >= g->width && height >= g->height)))
4842 door_part_done[nr] = TRUE;
4844 // continue door part animations, but not panel after door has closed
4845 if (!door_part_done[nr] && !is_panel_and_door_has_closed)
4846 door_part_done_all = FALSE;
4849 if (!(door_state & DOOR_NO_DELAY))
4853 SkipUntilDelayReached(&door_delay, door_delay_value, &k, last_frame);
4855 current_move_delay += max_step_delay;
4858 if (door_part_done_all)
4863 if (door_state & DOOR_ACTION_1)
4864 door1 = door_state & DOOR_ACTION_1;
4865 if (door_state & DOOR_ACTION_2)
4866 door2 = door_state & DOOR_ACTION_2;
4868 // draw masked border over door area
4869 DrawMaskedBorder(REDRAW_DOOR_1);
4870 DrawMaskedBorder(REDRAW_DOOR_2);
4872 return (door1 | door2);
4875 static boolean useSpecialEditorDoor()
4877 int graphic = IMG_GLOBAL_BORDER_EDITOR;
4878 boolean redefined = getImageListEntryFromImageID(graphic)->redefined;
4880 // do not draw special editor door if editor border defined or redefined
4881 if (graphic_info[graphic].bitmap != NULL || redefined)
4884 // do not draw special editor door if global border defined to be empty
4885 if (graphic_info[IMG_GLOBAL_BORDER].bitmap == NULL)
4888 // do not draw special editor door if viewport definitions do not match
4892 EY + EYSIZE != VY + VYSIZE)
4898 void DrawSpecialEditorDoor()
4900 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
4901 int top_border_width = gfx1->width;
4902 int top_border_height = gfx1->height;
4903 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
4904 int ex = EX - outer_border;
4905 int ey = EY - outer_border;
4906 int vy = VY - outer_border;
4907 int exsize = EXSIZE + 2 * outer_border;
4909 if (!useSpecialEditorDoor())
4912 /* draw bigger level editor toolbox window */
4913 BlitBitmap(gfx1->bitmap, drawto, gfx1->src_x, gfx1->src_y,
4914 top_border_width, top_border_height, ex, ey - top_border_height);
4915 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto, ex, vy,
4916 exsize, EYSIZE - VYSIZE + outer_border, ex, ey);
4918 redraw_mask |= REDRAW_ALL;
4921 void UndrawSpecialEditorDoor()
4923 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
4924 int top_border_width = gfx1->width;
4925 int top_border_height = gfx1->height;
4926 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
4927 int ex = EX - outer_border;
4928 int ey = EY - outer_border;
4929 int ey_top = ey - top_border_height;
4930 int exsize = EXSIZE + 2 * outer_border;
4931 int eysize = EYSIZE + 2 * outer_border;
4933 if (!useSpecialEditorDoor())
4936 /* draw normal tape recorder window */
4937 if (graphic_info[IMG_GLOBAL_BORDER].bitmap)
4939 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
4940 ex, ey_top, top_border_width, top_border_height,
4942 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
4943 ex, ey, exsize, eysize, ex, ey);
4947 // if screen background is set to "[NONE]", clear editor toolbox window
4948 ClearRectangle(drawto, ex, ey_top, top_border_width, top_border_height);
4949 ClearRectangle(drawto, ex, ey, exsize, eysize);
4952 redraw_mask |= REDRAW_ALL;
4956 /* ---------- new tool button stuff ---------------------------------------- */
4961 struct TextPosInfo *pos;
4964 } toolbutton_info[NUM_TOOL_BUTTONS] =
4967 IMG_GFX_REQUEST_BUTTON_YES, &request.button.yes,
4968 TOOL_CTRL_ID_YES, "yes"
4971 IMG_GFX_REQUEST_BUTTON_NO, &request.button.no,
4972 TOOL_CTRL_ID_NO, "no"
4975 IMG_GFX_REQUEST_BUTTON_CONFIRM, &request.button.confirm,
4976 TOOL_CTRL_ID_CONFIRM, "confirm"
4979 IMG_GFX_REQUEST_BUTTON_PLAYER_1, &request.button.player_1,
4980 TOOL_CTRL_ID_PLAYER_1, "player 1"
4983 IMG_GFX_REQUEST_BUTTON_PLAYER_2, &request.button.player_2,
4984 TOOL_CTRL_ID_PLAYER_2, "player 2"
4987 IMG_GFX_REQUEST_BUTTON_PLAYER_3, &request.button.player_3,
4988 TOOL_CTRL_ID_PLAYER_3, "player 3"
4991 IMG_GFX_REQUEST_BUTTON_PLAYER_4, &request.button.player_4,
4992 TOOL_CTRL_ID_PLAYER_4, "player 4"
4996 void CreateToolButtons()
5000 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
5002 struct GraphicInfo *gfx = &graphic_info[toolbutton_info[i].graphic];
5003 struct TextPosInfo *pos = toolbutton_info[i].pos;
5004 struct GadgetInfo *gi;
5005 Bitmap *deco_bitmap = None;
5006 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
5007 unsigned int event_mask = GD_EVENT_RELEASED;
5010 int gd_x = gfx->src_x;
5011 int gd_y = gfx->src_y;
5012 int gd_xp = gfx->src_x + gfx->pressed_xoffset;
5013 int gd_yp = gfx->src_y + gfx->pressed_yoffset;
5016 if (global.use_envelope_request)
5017 setRequestPosition(&dx, &dy, TRUE);
5019 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
5021 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
5023 getSizedGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr), 0,
5024 pos->size, &deco_bitmap, &deco_x, &deco_y);
5025 deco_xpos = (gfx->width - pos->size) / 2;
5026 deco_ypos = (gfx->height - pos->size) / 2;
5029 gi = CreateGadget(GDI_CUSTOM_ID, id,
5030 GDI_INFO_TEXT, toolbutton_info[i].infotext,
5031 GDI_X, dx + GDI_ACTIVE_POS(pos->x),
5032 GDI_Y, dy + GDI_ACTIVE_POS(pos->y),
5033 GDI_WIDTH, gfx->width,
5034 GDI_HEIGHT, gfx->height,
5035 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
5036 GDI_STATE, GD_BUTTON_UNPRESSED,
5037 GDI_DESIGN_UNPRESSED, gfx->bitmap, gd_x, gd_y,
5038 GDI_DESIGN_PRESSED, gfx->bitmap, gd_xp, gd_yp,
5039 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
5040 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
5041 GDI_DECORATION_SIZE, pos->size, pos->size,
5042 GDI_DECORATION_SHIFTING, 1, 1,
5043 GDI_DIRECT_DRAW, FALSE,
5044 GDI_EVENT_MASK, event_mask,
5045 GDI_CALLBACK_ACTION, HandleToolButtons,
5049 Error(ERR_EXIT, "cannot create gadget");
5051 tool_gadget[id] = gi;
5055 void FreeToolButtons()
5059 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
5060 FreeGadget(tool_gadget[i]);
5063 static void UnmapToolButtons()
5067 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
5068 UnmapGadget(tool_gadget[i]);
5071 static void HandleToolButtons(struct GadgetInfo *gi)
5073 request_gadget_id = gi->custom_id;
5076 static struct Mapping_EM_to_RND_object
5079 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
5080 boolean is_backside; /* backside of moving element */
5086 em_object_mapping_list[] =
5089 Xblank, TRUE, FALSE,
5093 Yacid_splash_eB, FALSE, FALSE,
5094 EL_ACID_SPLASH_RIGHT, -1, -1
5097 Yacid_splash_wB, FALSE, FALSE,
5098 EL_ACID_SPLASH_LEFT, -1, -1
5101 #ifdef EM_ENGINE_BAD_ROLL
5103 Xstone_force_e, FALSE, FALSE,
5104 EL_ROCK, -1, MV_BIT_RIGHT
5107 Xstone_force_w, FALSE, FALSE,
5108 EL_ROCK, -1, MV_BIT_LEFT
5111 Xnut_force_e, FALSE, FALSE,
5112 EL_NUT, -1, MV_BIT_RIGHT
5115 Xnut_force_w, FALSE, FALSE,
5116 EL_NUT, -1, MV_BIT_LEFT
5119 Xspring_force_e, FALSE, FALSE,
5120 EL_SPRING, -1, MV_BIT_RIGHT
5123 Xspring_force_w, FALSE, FALSE,
5124 EL_SPRING, -1, MV_BIT_LEFT
5127 Xemerald_force_e, FALSE, FALSE,
5128 EL_EMERALD, -1, MV_BIT_RIGHT
5131 Xemerald_force_w, FALSE, FALSE,
5132 EL_EMERALD, -1, MV_BIT_LEFT
5135 Xdiamond_force_e, FALSE, FALSE,
5136 EL_DIAMOND, -1, MV_BIT_RIGHT
5139 Xdiamond_force_w, FALSE, FALSE,
5140 EL_DIAMOND, -1, MV_BIT_LEFT
5143 Xbomb_force_e, FALSE, FALSE,
5144 EL_BOMB, -1, MV_BIT_RIGHT
5147 Xbomb_force_w, FALSE, FALSE,
5148 EL_BOMB, -1, MV_BIT_LEFT
5150 #endif /* EM_ENGINE_BAD_ROLL */
5153 Xstone, TRUE, FALSE,
5157 Xstone_pause, FALSE, FALSE,
5161 Xstone_fall, FALSE, FALSE,
5165 Ystone_s, FALSE, FALSE,
5166 EL_ROCK, ACTION_FALLING, -1
5169 Ystone_sB, FALSE, TRUE,
5170 EL_ROCK, ACTION_FALLING, -1
5173 Ystone_e, FALSE, FALSE,
5174 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
5177 Ystone_eB, FALSE, TRUE,
5178 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
5181 Ystone_w, FALSE, FALSE,
5182 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
5185 Ystone_wB, FALSE, TRUE,
5186 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
5193 Xnut_pause, FALSE, FALSE,
5197 Xnut_fall, FALSE, FALSE,
5201 Ynut_s, FALSE, FALSE,
5202 EL_NUT, ACTION_FALLING, -1
5205 Ynut_sB, FALSE, TRUE,
5206 EL_NUT, ACTION_FALLING, -1
5209 Ynut_e, FALSE, FALSE,
5210 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
5213 Ynut_eB, FALSE, TRUE,
5214 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
5217 Ynut_w, FALSE, FALSE,
5218 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
5221 Ynut_wB, FALSE, TRUE,
5222 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
5225 Xbug_n, TRUE, FALSE,
5229 Xbug_e, TRUE, FALSE,
5230 EL_BUG_RIGHT, -1, -1
5233 Xbug_s, TRUE, FALSE,
5237 Xbug_w, TRUE, FALSE,
5241 Xbug_gon, FALSE, FALSE,
5245 Xbug_goe, FALSE, FALSE,
5246 EL_BUG_RIGHT, -1, -1
5249 Xbug_gos, FALSE, FALSE,
5253 Xbug_gow, FALSE, FALSE,
5257 Ybug_n, FALSE, FALSE,
5258 EL_BUG, ACTION_MOVING, MV_BIT_UP
5261 Ybug_nB, FALSE, TRUE,
5262 EL_BUG, ACTION_MOVING, MV_BIT_UP
5265 Ybug_e, FALSE, FALSE,
5266 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
5269 Ybug_eB, FALSE, TRUE,
5270 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
5273 Ybug_s, FALSE, FALSE,
5274 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
5277 Ybug_sB, FALSE, TRUE,
5278 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
5281 Ybug_w, FALSE, FALSE,
5282 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
5285 Ybug_wB, FALSE, TRUE,
5286 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
5289 Ybug_w_n, FALSE, FALSE,
5290 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
5293 Ybug_n_e, FALSE, FALSE,
5294 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
5297 Ybug_e_s, FALSE, FALSE,
5298 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
5301 Ybug_s_w, FALSE, FALSE,
5302 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
5305 Ybug_e_n, FALSE, FALSE,
5306 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
5309 Ybug_s_e, FALSE, FALSE,
5310 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
5313 Ybug_w_s, FALSE, FALSE,
5314 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
5317 Ybug_n_w, FALSE, FALSE,
5318 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
5321 Ybug_stone, FALSE, FALSE,
5322 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
5325 Ybug_spring, FALSE, FALSE,
5326 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
5329 Xtank_n, TRUE, FALSE,
5330 EL_SPACESHIP_UP, -1, -1
5333 Xtank_e, TRUE, FALSE,
5334 EL_SPACESHIP_RIGHT, -1, -1
5337 Xtank_s, TRUE, FALSE,
5338 EL_SPACESHIP_DOWN, -1, -1
5341 Xtank_w, TRUE, FALSE,
5342 EL_SPACESHIP_LEFT, -1, -1
5345 Xtank_gon, FALSE, FALSE,
5346 EL_SPACESHIP_UP, -1, -1
5349 Xtank_goe, FALSE, FALSE,
5350 EL_SPACESHIP_RIGHT, -1, -1
5353 Xtank_gos, FALSE, FALSE,
5354 EL_SPACESHIP_DOWN, -1, -1
5357 Xtank_gow, FALSE, FALSE,
5358 EL_SPACESHIP_LEFT, -1, -1
5361 Ytank_n, FALSE, FALSE,
5362 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
5365 Ytank_nB, FALSE, TRUE,
5366 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
5369 Ytank_e, FALSE, FALSE,
5370 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
5373 Ytank_eB, FALSE, TRUE,
5374 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
5377 Ytank_s, FALSE, FALSE,
5378 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
5381 Ytank_sB, FALSE, TRUE,
5382 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
5385 Ytank_w, FALSE, FALSE,
5386 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
5389 Ytank_wB, FALSE, TRUE,
5390 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
5393 Ytank_w_n, FALSE, FALSE,
5394 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
5397 Ytank_n_e, FALSE, FALSE,
5398 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
5401 Ytank_e_s, FALSE, FALSE,
5402 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
5405 Ytank_s_w, FALSE, FALSE,
5406 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
5409 Ytank_e_n, FALSE, FALSE,
5410 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
5413 Ytank_s_e, FALSE, FALSE,
5414 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
5417 Ytank_w_s, FALSE, FALSE,
5418 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
5421 Ytank_n_w, FALSE, FALSE,
5422 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
5425 Ytank_stone, FALSE, FALSE,
5426 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
5429 Ytank_spring, FALSE, FALSE,
5430 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
5433 Xandroid, TRUE, FALSE,
5434 EL_EMC_ANDROID, ACTION_ACTIVE, -1
5437 Xandroid_1_n, FALSE, FALSE,
5438 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
5441 Xandroid_2_n, FALSE, FALSE,
5442 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
5445 Xandroid_1_e, FALSE, FALSE,
5446 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
5449 Xandroid_2_e, FALSE, FALSE,
5450 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
5453 Xandroid_1_w, FALSE, FALSE,
5454 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
5457 Xandroid_2_w, FALSE, FALSE,
5458 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
5461 Xandroid_1_s, FALSE, FALSE,
5462 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
5465 Xandroid_2_s, FALSE, FALSE,
5466 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
5469 Yandroid_n, FALSE, FALSE,
5470 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
5473 Yandroid_nB, FALSE, TRUE,
5474 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
5477 Yandroid_ne, FALSE, FALSE,
5478 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
5481 Yandroid_neB, FALSE, TRUE,
5482 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
5485 Yandroid_e, FALSE, FALSE,
5486 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
5489 Yandroid_eB, FALSE, TRUE,
5490 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
5493 Yandroid_se, FALSE, FALSE,
5494 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
5497 Yandroid_seB, FALSE, TRUE,
5498 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
5501 Yandroid_s, FALSE, FALSE,
5502 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
5505 Yandroid_sB, FALSE, TRUE,
5506 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
5509 Yandroid_sw, FALSE, FALSE,
5510 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
5513 Yandroid_swB, FALSE, TRUE,
5514 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
5517 Yandroid_w, FALSE, FALSE,
5518 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
5521 Yandroid_wB, FALSE, TRUE,
5522 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
5525 Yandroid_nw, FALSE, FALSE,
5526 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
5529 Yandroid_nwB, FALSE, TRUE,
5530 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
5533 Xspring, TRUE, FALSE,
5537 Xspring_pause, FALSE, FALSE,
5541 Xspring_e, FALSE, FALSE,
5545 Xspring_w, FALSE, FALSE,
5549 Xspring_fall, FALSE, FALSE,
5553 Yspring_s, FALSE, FALSE,
5554 EL_SPRING, ACTION_FALLING, -1
5557 Yspring_sB, FALSE, TRUE,
5558 EL_SPRING, ACTION_FALLING, -1
5561 Yspring_e, FALSE, FALSE,
5562 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
5565 Yspring_eB, FALSE, TRUE,
5566 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
5569 Yspring_w, FALSE, FALSE,
5570 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
5573 Yspring_wB, FALSE, TRUE,
5574 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
5577 Yspring_kill_e, FALSE, FALSE,
5578 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
5581 Yspring_kill_eB, FALSE, TRUE,
5582 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
5585 Yspring_kill_w, FALSE, FALSE,
5586 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
5589 Yspring_kill_wB, FALSE, TRUE,
5590 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
5593 Xeater_n, TRUE, FALSE,
5594 EL_YAMYAM_UP, -1, -1
5597 Xeater_e, TRUE, FALSE,
5598 EL_YAMYAM_RIGHT, -1, -1
5601 Xeater_w, TRUE, FALSE,
5602 EL_YAMYAM_LEFT, -1, -1
5605 Xeater_s, TRUE, FALSE,
5606 EL_YAMYAM_DOWN, -1, -1
5609 Yeater_n, FALSE, FALSE,
5610 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
5613 Yeater_nB, FALSE, TRUE,
5614 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
5617 Yeater_e, FALSE, FALSE,
5618 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
5621 Yeater_eB, FALSE, TRUE,
5622 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
5625 Yeater_s, FALSE, FALSE,
5626 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
5629 Yeater_sB, FALSE, TRUE,
5630 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
5633 Yeater_w, FALSE, FALSE,
5634 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
5637 Yeater_wB, FALSE, TRUE,
5638 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
5641 Yeater_stone, FALSE, FALSE,
5642 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
5645 Yeater_spring, FALSE, FALSE,
5646 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
5649 Xalien, TRUE, FALSE,
5653 Xalien_pause, FALSE, FALSE,
5657 Yalien_n, FALSE, FALSE,
5658 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
5661 Yalien_nB, FALSE, TRUE,
5662 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
5665 Yalien_e, FALSE, FALSE,
5666 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
5669 Yalien_eB, FALSE, TRUE,
5670 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
5673 Yalien_s, FALSE, FALSE,
5674 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
5677 Yalien_sB, FALSE, TRUE,
5678 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
5681 Yalien_w, FALSE, FALSE,
5682 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
5685 Yalien_wB, FALSE, TRUE,
5686 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
5689 Yalien_stone, FALSE, FALSE,
5690 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
5693 Yalien_spring, FALSE, FALSE,
5694 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
5697 Xemerald, TRUE, FALSE,
5701 Xemerald_pause, FALSE, FALSE,
5705 Xemerald_fall, FALSE, FALSE,
5709 Xemerald_shine, FALSE, FALSE,
5710 EL_EMERALD, ACTION_TWINKLING, -1
5713 Yemerald_s, FALSE, FALSE,
5714 EL_EMERALD, ACTION_FALLING, -1
5717 Yemerald_sB, FALSE, TRUE,
5718 EL_EMERALD, ACTION_FALLING, -1
5721 Yemerald_e, FALSE, FALSE,
5722 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
5725 Yemerald_eB, FALSE, TRUE,
5726 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
5729 Yemerald_w, FALSE, FALSE,
5730 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
5733 Yemerald_wB, FALSE, TRUE,
5734 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
5737 Yemerald_eat, FALSE, FALSE,
5738 EL_EMERALD, ACTION_COLLECTING, -1
5741 Yemerald_stone, FALSE, FALSE,
5742 EL_NUT, ACTION_BREAKING, -1
5745 Xdiamond, TRUE, FALSE,
5749 Xdiamond_pause, FALSE, FALSE,
5753 Xdiamond_fall, FALSE, FALSE,
5757 Xdiamond_shine, FALSE, FALSE,
5758 EL_DIAMOND, ACTION_TWINKLING, -1
5761 Ydiamond_s, FALSE, FALSE,
5762 EL_DIAMOND, ACTION_FALLING, -1
5765 Ydiamond_sB, FALSE, TRUE,
5766 EL_DIAMOND, ACTION_FALLING, -1
5769 Ydiamond_e, FALSE, FALSE,
5770 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
5773 Ydiamond_eB, FALSE, TRUE,
5774 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
5777 Ydiamond_w, FALSE, FALSE,
5778 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
5781 Ydiamond_wB, FALSE, TRUE,
5782 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
5785 Ydiamond_eat, FALSE, FALSE,
5786 EL_DIAMOND, ACTION_COLLECTING, -1
5789 Ydiamond_stone, FALSE, FALSE,
5790 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
5793 Xdrip_fall, TRUE, FALSE,
5794 EL_AMOEBA_DROP, -1, -1
5797 Xdrip_stretch, FALSE, FALSE,
5798 EL_AMOEBA_DROP, ACTION_FALLING, -1
5801 Xdrip_stretchB, FALSE, TRUE,
5802 EL_AMOEBA_DROP, ACTION_FALLING, -1
5805 Xdrip_eat, FALSE, FALSE,
5806 EL_AMOEBA_DROP, ACTION_GROWING, -1
5809 Ydrip_s1, FALSE, FALSE,
5810 EL_AMOEBA_DROP, ACTION_FALLING, -1
5813 Ydrip_s1B, FALSE, TRUE,
5814 EL_AMOEBA_DROP, ACTION_FALLING, -1
5817 Ydrip_s2, FALSE, FALSE,
5818 EL_AMOEBA_DROP, ACTION_FALLING, -1
5821 Ydrip_s2B, FALSE, TRUE,
5822 EL_AMOEBA_DROP, ACTION_FALLING, -1
5829 Xbomb_pause, FALSE, FALSE,
5833 Xbomb_fall, FALSE, FALSE,
5837 Ybomb_s, FALSE, FALSE,
5838 EL_BOMB, ACTION_FALLING, -1
5841 Ybomb_sB, FALSE, TRUE,
5842 EL_BOMB, ACTION_FALLING, -1
5845 Ybomb_e, FALSE, FALSE,
5846 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
5849 Ybomb_eB, FALSE, TRUE,
5850 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
5853 Ybomb_w, FALSE, FALSE,
5854 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
5857 Ybomb_wB, FALSE, TRUE,
5858 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
5861 Ybomb_eat, FALSE, FALSE,
5862 EL_BOMB, ACTION_ACTIVATING, -1
5865 Xballoon, TRUE, FALSE,
5869 Yballoon_n, FALSE, FALSE,
5870 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
5873 Yballoon_nB, FALSE, TRUE,
5874 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
5877 Yballoon_e, FALSE, FALSE,
5878 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
5881 Yballoon_eB, FALSE, TRUE,
5882 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
5885 Yballoon_s, FALSE, FALSE,
5886 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
5889 Yballoon_sB, FALSE, TRUE,
5890 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
5893 Yballoon_w, FALSE, FALSE,
5894 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
5897 Yballoon_wB, FALSE, TRUE,
5898 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
5901 Xgrass, TRUE, FALSE,
5902 EL_EMC_GRASS, -1, -1
5905 Ygrass_nB, FALSE, FALSE,
5906 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
5909 Ygrass_eB, FALSE, FALSE,
5910 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
5913 Ygrass_sB, FALSE, FALSE,
5914 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
5917 Ygrass_wB, FALSE, FALSE,
5918 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
5925 Ydirt_nB, FALSE, FALSE,
5926 EL_SAND, ACTION_DIGGING, MV_BIT_UP
5929 Ydirt_eB, FALSE, FALSE,
5930 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
5933 Ydirt_sB, FALSE, FALSE,
5934 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
5937 Ydirt_wB, FALSE, FALSE,
5938 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
5941 Xacid_ne, TRUE, FALSE,
5942 EL_ACID_POOL_TOPRIGHT, -1, -1
5945 Xacid_se, TRUE, FALSE,
5946 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
5949 Xacid_s, TRUE, FALSE,
5950 EL_ACID_POOL_BOTTOM, -1, -1
5953 Xacid_sw, TRUE, FALSE,
5954 EL_ACID_POOL_BOTTOMLEFT, -1, -1
5957 Xacid_nw, TRUE, FALSE,
5958 EL_ACID_POOL_TOPLEFT, -1, -1
5961 Xacid_1, TRUE, FALSE,
5965 Xacid_2, FALSE, FALSE,
5969 Xacid_3, FALSE, FALSE,
5973 Xacid_4, FALSE, FALSE,
5977 Xacid_5, FALSE, FALSE,
5981 Xacid_6, FALSE, FALSE,
5985 Xacid_7, FALSE, FALSE,
5989 Xacid_8, FALSE, FALSE,
5993 Xball_1, TRUE, FALSE,
5994 EL_EMC_MAGIC_BALL, -1, -1
5997 Xball_1B, FALSE, FALSE,
5998 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
6001 Xball_2, FALSE, FALSE,
6002 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
6005 Xball_2B, FALSE, FALSE,
6006 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
6009 Yball_eat, FALSE, FALSE,
6010 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
6013 Ykey_1_eat, FALSE, FALSE,
6014 EL_EM_KEY_1, ACTION_COLLECTING, -1
6017 Ykey_2_eat, FALSE, FALSE,
6018 EL_EM_KEY_2, ACTION_COLLECTING, -1
6021 Ykey_3_eat, FALSE, FALSE,
6022 EL_EM_KEY_3, ACTION_COLLECTING, -1
6025 Ykey_4_eat, FALSE, FALSE,
6026 EL_EM_KEY_4, ACTION_COLLECTING, -1
6029 Ykey_5_eat, FALSE, FALSE,
6030 EL_EMC_KEY_5, ACTION_COLLECTING, -1
6033 Ykey_6_eat, FALSE, FALSE,
6034 EL_EMC_KEY_6, ACTION_COLLECTING, -1
6037 Ykey_7_eat, FALSE, FALSE,
6038 EL_EMC_KEY_7, ACTION_COLLECTING, -1
6041 Ykey_8_eat, FALSE, FALSE,
6042 EL_EMC_KEY_8, ACTION_COLLECTING, -1
6045 Ylenses_eat, FALSE, FALSE,
6046 EL_EMC_LENSES, ACTION_COLLECTING, -1
6049 Ymagnify_eat, FALSE, FALSE,
6050 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
6053 Ygrass_eat, FALSE, FALSE,
6054 EL_EMC_GRASS, ACTION_SNAPPING, -1
6057 Ydirt_eat, FALSE, FALSE,
6058 EL_SAND, ACTION_SNAPPING, -1
6061 Xgrow_ns, TRUE, FALSE,
6062 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
6065 Ygrow_ns_eat, FALSE, FALSE,
6066 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
6069 Xgrow_ew, TRUE, FALSE,
6070 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
6073 Ygrow_ew_eat, FALSE, FALSE,
6074 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
6077 Xwonderwall, TRUE, FALSE,
6078 EL_MAGIC_WALL, -1, -1
6081 XwonderwallB, FALSE, FALSE,
6082 EL_MAGIC_WALL, ACTION_ACTIVE, -1
6085 Xamoeba_1, TRUE, FALSE,
6086 EL_AMOEBA_DRY, ACTION_OTHER, -1
6089 Xamoeba_2, FALSE, FALSE,
6090 EL_AMOEBA_DRY, ACTION_OTHER, -1
6093 Xamoeba_3, FALSE, FALSE,
6094 EL_AMOEBA_DRY, ACTION_OTHER, -1
6097 Xamoeba_4, FALSE, FALSE,
6098 EL_AMOEBA_DRY, ACTION_OTHER, -1
6101 Xamoeba_5, TRUE, FALSE,
6102 EL_AMOEBA_WET, ACTION_OTHER, -1
6105 Xamoeba_6, FALSE, FALSE,
6106 EL_AMOEBA_WET, ACTION_OTHER, -1
6109 Xamoeba_7, FALSE, FALSE,
6110 EL_AMOEBA_WET, ACTION_OTHER, -1
6113 Xamoeba_8, FALSE, FALSE,
6114 EL_AMOEBA_WET, ACTION_OTHER, -1
6117 Xdoor_1, TRUE, FALSE,
6118 EL_EM_GATE_1, -1, -1
6121 Xdoor_2, TRUE, FALSE,
6122 EL_EM_GATE_2, -1, -1
6125 Xdoor_3, TRUE, FALSE,
6126 EL_EM_GATE_3, -1, -1
6129 Xdoor_4, TRUE, FALSE,
6130 EL_EM_GATE_4, -1, -1
6133 Xdoor_5, TRUE, FALSE,
6134 EL_EMC_GATE_5, -1, -1
6137 Xdoor_6, TRUE, FALSE,
6138 EL_EMC_GATE_6, -1, -1
6141 Xdoor_7, TRUE, FALSE,
6142 EL_EMC_GATE_7, -1, -1
6145 Xdoor_8, TRUE, FALSE,
6146 EL_EMC_GATE_8, -1, -1
6149 Xkey_1, TRUE, FALSE,
6153 Xkey_2, TRUE, FALSE,
6157 Xkey_3, TRUE, FALSE,
6161 Xkey_4, TRUE, FALSE,
6165 Xkey_5, TRUE, FALSE,
6166 EL_EMC_KEY_5, -1, -1
6169 Xkey_6, TRUE, FALSE,
6170 EL_EMC_KEY_6, -1, -1
6173 Xkey_7, TRUE, FALSE,
6174 EL_EMC_KEY_7, -1, -1
6177 Xkey_8, TRUE, FALSE,
6178 EL_EMC_KEY_8, -1, -1
6181 Xwind_n, TRUE, FALSE,
6182 EL_BALLOON_SWITCH_UP, -1, -1
6185 Xwind_e, TRUE, FALSE,
6186 EL_BALLOON_SWITCH_RIGHT, -1, -1
6189 Xwind_s, TRUE, FALSE,
6190 EL_BALLOON_SWITCH_DOWN, -1, -1
6193 Xwind_w, TRUE, FALSE,
6194 EL_BALLOON_SWITCH_LEFT, -1, -1
6197 Xwind_nesw, TRUE, FALSE,
6198 EL_BALLOON_SWITCH_ANY, -1, -1
6201 Xwind_stop, TRUE, FALSE,
6202 EL_BALLOON_SWITCH_NONE, -1, -1
6206 EL_EM_EXIT_CLOSED, -1, -1
6209 Xexit_1, TRUE, FALSE,
6210 EL_EM_EXIT_OPEN, -1, -1
6213 Xexit_2, FALSE, FALSE,
6214 EL_EM_EXIT_OPEN, -1, -1
6217 Xexit_3, FALSE, FALSE,
6218 EL_EM_EXIT_OPEN, -1, -1
6221 Xdynamite, TRUE, FALSE,
6222 EL_EM_DYNAMITE, -1, -1
6225 Ydynamite_eat, FALSE, FALSE,
6226 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
6229 Xdynamite_1, TRUE, FALSE,
6230 EL_EM_DYNAMITE_ACTIVE, -1, -1
6233 Xdynamite_2, FALSE, FALSE,
6234 EL_EM_DYNAMITE_ACTIVE, -1, -1
6237 Xdynamite_3, FALSE, FALSE,
6238 EL_EM_DYNAMITE_ACTIVE, -1, -1
6241 Xdynamite_4, FALSE, FALSE,
6242 EL_EM_DYNAMITE_ACTIVE, -1, -1
6245 Xbumper, TRUE, FALSE,
6246 EL_EMC_SPRING_BUMPER, -1, -1
6249 XbumperB, FALSE, FALSE,
6250 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
6253 Xwheel, TRUE, FALSE,
6254 EL_ROBOT_WHEEL, -1, -1
6257 XwheelB, FALSE, FALSE,
6258 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
6261 Xswitch, TRUE, FALSE,
6262 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
6265 XswitchB, FALSE, FALSE,
6266 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
6270 EL_QUICKSAND_EMPTY, -1, -1
6273 Xsand_stone, TRUE, FALSE,
6274 EL_QUICKSAND_FULL, -1, -1
6277 Xsand_stonein_1, FALSE, TRUE,
6278 EL_ROCK, ACTION_FILLING, -1
6281 Xsand_stonein_2, FALSE, TRUE,
6282 EL_ROCK, ACTION_FILLING, -1
6285 Xsand_stonein_3, FALSE, TRUE,
6286 EL_ROCK, ACTION_FILLING, -1
6289 Xsand_stonein_4, FALSE, TRUE,
6290 EL_ROCK, ACTION_FILLING, -1
6293 Xsand_stonesand_1, FALSE, FALSE,
6294 EL_QUICKSAND_EMPTYING, -1, -1
6297 Xsand_stonesand_2, FALSE, FALSE,
6298 EL_QUICKSAND_EMPTYING, -1, -1
6301 Xsand_stonesand_3, FALSE, FALSE,
6302 EL_QUICKSAND_EMPTYING, -1, -1
6305 Xsand_stonesand_4, FALSE, FALSE,
6306 EL_QUICKSAND_EMPTYING, -1, -1
6309 Xsand_stonesand_quickout_1, FALSE, FALSE,
6310 EL_QUICKSAND_EMPTYING, -1, -1
6313 Xsand_stonesand_quickout_2, FALSE, FALSE,
6314 EL_QUICKSAND_EMPTYING, -1, -1
6317 Xsand_stoneout_1, FALSE, FALSE,
6318 EL_ROCK, ACTION_EMPTYING, -1
6321 Xsand_stoneout_2, FALSE, FALSE,
6322 EL_ROCK, ACTION_EMPTYING, -1
6325 Xsand_sandstone_1, FALSE, FALSE,
6326 EL_QUICKSAND_FILLING, -1, -1
6329 Xsand_sandstone_2, FALSE, FALSE,
6330 EL_QUICKSAND_FILLING, -1, -1
6333 Xsand_sandstone_3, FALSE, FALSE,
6334 EL_QUICKSAND_FILLING, -1, -1
6337 Xsand_sandstone_4, FALSE, FALSE,
6338 EL_QUICKSAND_FILLING, -1, -1
6341 Xplant, TRUE, FALSE,
6342 EL_EMC_PLANT, -1, -1
6345 Yplant, FALSE, FALSE,
6346 EL_EMC_PLANT, -1, -1
6349 Xlenses, TRUE, FALSE,
6350 EL_EMC_LENSES, -1, -1
6353 Xmagnify, TRUE, FALSE,
6354 EL_EMC_MAGNIFIER, -1, -1
6357 Xdripper, TRUE, FALSE,
6358 EL_EMC_DRIPPER, -1, -1
6361 XdripperB, FALSE, FALSE,
6362 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
6365 Xfake_blank, TRUE, FALSE,
6366 EL_INVISIBLE_WALL, -1, -1
6369 Xfake_blankB, FALSE, FALSE,
6370 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
6373 Xfake_grass, TRUE, FALSE,
6374 EL_EMC_FAKE_GRASS, -1, -1
6377 Xfake_grassB, FALSE, FALSE,
6378 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
6381 Xfake_door_1, TRUE, FALSE,
6382 EL_EM_GATE_1_GRAY, -1, -1
6385 Xfake_door_2, TRUE, FALSE,
6386 EL_EM_GATE_2_GRAY, -1, -1
6389 Xfake_door_3, TRUE, FALSE,
6390 EL_EM_GATE_3_GRAY, -1, -1
6393 Xfake_door_4, TRUE, FALSE,
6394 EL_EM_GATE_4_GRAY, -1, -1
6397 Xfake_door_5, TRUE, FALSE,
6398 EL_EMC_GATE_5_GRAY, -1, -1
6401 Xfake_door_6, TRUE, FALSE,
6402 EL_EMC_GATE_6_GRAY, -1, -1
6405 Xfake_door_7, TRUE, FALSE,
6406 EL_EMC_GATE_7_GRAY, -1, -1
6409 Xfake_door_8, TRUE, FALSE,
6410 EL_EMC_GATE_8_GRAY, -1, -1
6413 Xfake_acid_1, TRUE, FALSE,
6414 EL_EMC_FAKE_ACID, -1, -1
6417 Xfake_acid_2, FALSE, FALSE,
6418 EL_EMC_FAKE_ACID, -1, -1
6421 Xfake_acid_3, FALSE, FALSE,
6422 EL_EMC_FAKE_ACID, -1, -1
6425 Xfake_acid_4, FALSE, FALSE,
6426 EL_EMC_FAKE_ACID, -1, -1
6429 Xfake_acid_5, FALSE, FALSE,
6430 EL_EMC_FAKE_ACID, -1, -1
6433 Xfake_acid_6, FALSE, FALSE,
6434 EL_EMC_FAKE_ACID, -1, -1
6437 Xfake_acid_7, FALSE, FALSE,
6438 EL_EMC_FAKE_ACID, -1, -1
6441 Xfake_acid_8, FALSE, FALSE,
6442 EL_EMC_FAKE_ACID, -1, -1
6445 Xsteel_1, TRUE, FALSE,
6446 EL_STEELWALL, -1, -1
6449 Xsteel_2, TRUE, FALSE,
6450 EL_EMC_STEELWALL_2, -1, -1
6453 Xsteel_3, TRUE, FALSE,
6454 EL_EMC_STEELWALL_3, -1, -1
6457 Xsteel_4, TRUE, FALSE,
6458 EL_EMC_STEELWALL_4, -1, -1
6461 Xwall_1, TRUE, FALSE,
6465 Xwall_2, TRUE, FALSE,
6466 EL_EMC_WALL_14, -1, -1
6469 Xwall_3, TRUE, FALSE,
6470 EL_EMC_WALL_15, -1, -1
6473 Xwall_4, TRUE, FALSE,
6474 EL_EMC_WALL_16, -1, -1
6477 Xround_wall_1, TRUE, FALSE,
6478 EL_WALL_SLIPPERY, -1, -1
6481 Xround_wall_2, TRUE, FALSE,
6482 EL_EMC_WALL_SLIPPERY_2, -1, -1
6485 Xround_wall_3, TRUE, FALSE,
6486 EL_EMC_WALL_SLIPPERY_3, -1, -1
6489 Xround_wall_4, TRUE, FALSE,
6490 EL_EMC_WALL_SLIPPERY_4, -1, -1
6493 Xdecor_1, TRUE, FALSE,
6494 EL_EMC_WALL_8, -1, -1
6497 Xdecor_2, TRUE, FALSE,
6498 EL_EMC_WALL_6, -1, -1
6501 Xdecor_3, TRUE, FALSE,
6502 EL_EMC_WALL_4, -1, -1
6505 Xdecor_4, TRUE, FALSE,
6506 EL_EMC_WALL_7, -1, -1
6509 Xdecor_5, TRUE, FALSE,
6510 EL_EMC_WALL_5, -1, -1
6513 Xdecor_6, TRUE, FALSE,
6514 EL_EMC_WALL_9, -1, -1
6517 Xdecor_7, TRUE, FALSE,
6518 EL_EMC_WALL_10, -1, -1
6521 Xdecor_8, TRUE, FALSE,
6522 EL_EMC_WALL_1, -1, -1
6525 Xdecor_9, TRUE, FALSE,
6526 EL_EMC_WALL_2, -1, -1
6529 Xdecor_10, TRUE, FALSE,
6530 EL_EMC_WALL_3, -1, -1
6533 Xdecor_11, TRUE, FALSE,
6534 EL_EMC_WALL_11, -1, -1
6537 Xdecor_12, TRUE, FALSE,
6538 EL_EMC_WALL_12, -1, -1
6541 Xalpha_0, TRUE, FALSE,
6542 EL_CHAR('0'), -1, -1
6545 Xalpha_1, TRUE, FALSE,
6546 EL_CHAR('1'), -1, -1
6549 Xalpha_2, TRUE, FALSE,
6550 EL_CHAR('2'), -1, -1
6553 Xalpha_3, TRUE, FALSE,
6554 EL_CHAR('3'), -1, -1
6557 Xalpha_4, TRUE, FALSE,
6558 EL_CHAR('4'), -1, -1
6561 Xalpha_5, TRUE, FALSE,
6562 EL_CHAR('5'), -1, -1
6565 Xalpha_6, TRUE, FALSE,
6566 EL_CHAR('6'), -1, -1
6569 Xalpha_7, TRUE, FALSE,
6570 EL_CHAR('7'), -1, -1
6573 Xalpha_8, TRUE, FALSE,
6574 EL_CHAR('8'), -1, -1
6577 Xalpha_9, TRUE, FALSE,
6578 EL_CHAR('9'), -1, -1
6581 Xalpha_excla, TRUE, FALSE,
6582 EL_CHAR('!'), -1, -1
6585 Xalpha_quote, TRUE, FALSE,
6586 EL_CHAR('"'), -1, -1
6589 Xalpha_comma, TRUE, FALSE,
6590 EL_CHAR(','), -1, -1
6593 Xalpha_minus, TRUE, FALSE,
6594 EL_CHAR('-'), -1, -1
6597 Xalpha_perio, TRUE, FALSE,
6598 EL_CHAR('.'), -1, -1
6601 Xalpha_colon, TRUE, FALSE,
6602 EL_CHAR(':'), -1, -1
6605 Xalpha_quest, TRUE, FALSE,
6606 EL_CHAR('?'), -1, -1
6609 Xalpha_a, TRUE, FALSE,
6610 EL_CHAR('A'), -1, -1
6613 Xalpha_b, TRUE, FALSE,
6614 EL_CHAR('B'), -1, -1
6617 Xalpha_c, TRUE, FALSE,
6618 EL_CHAR('C'), -1, -1
6621 Xalpha_d, TRUE, FALSE,
6622 EL_CHAR('D'), -1, -1
6625 Xalpha_e, TRUE, FALSE,
6626 EL_CHAR('E'), -1, -1
6629 Xalpha_f, TRUE, FALSE,
6630 EL_CHAR('F'), -1, -1
6633 Xalpha_g, TRUE, FALSE,
6634 EL_CHAR('G'), -1, -1
6637 Xalpha_h, TRUE, FALSE,
6638 EL_CHAR('H'), -1, -1
6641 Xalpha_i, TRUE, FALSE,
6642 EL_CHAR('I'), -1, -1
6645 Xalpha_j, TRUE, FALSE,
6646 EL_CHAR('J'), -1, -1
6649 Xalpha_k, TRUE, FALSE,
6650 EL_CHAR('K'), -1, -1
6653 Xalpha_l, TRUE, FALSE,
6654 EL_CHAR('L'), -1, -1
6657 Xalpha_m, TRUE, FALSE,
6658 EL_CHAR('M'), -1, -1
6661 Xalpha_n, TRUE, FALSE,
6662 EL_CHAR('N'), -1, -1
6665 Xalpha_o, TRUE, FALSE,
6666 EL_CHAR('O'), -1, -1
6669 Xalpha_p, TRUE, FALSE,
6670 EL_CHAR('P'), -1, -1
6673 Xalpha_q, TRUE, FALSE,
6674 EL_CHAR('Q'), -1, -1
6677 Xalpha_r, TRUE, FALSE,
6678 EL_CHAR('R'), -1, -1
6681 Xalpha_s, TRUE, FALSE,
6682 EL_CHAR('S'), -1, -1
6685 Xalpha_t, TRUE, FALSE,
6686 EL_CHAR('T'), -1, -1
6689 Xalpha_u, TRUE, FALSE,
6690 EL_CHAR('U'), -1, -1
6693 Xalpha_v, TRUE, FALSE,
6694 EL_CHAR('V'), -1, -1
6697 Xalpha_w, TRUE, FALSE,
6698 EL_CHAR('W'), -1, -1
6701 Xalpha_x, TRUE, FALSE,
6702 EL_CHAR('X'), -1, -1
6705 Xalpha_y, TRUE, FALSE,
6706 EL_CHAR('Y'), -1, -1
6709 Xalpha_z, TRUE, FALSE,
6710 EL_CHAR('Z'), -1, -1
6713 Xalpha_arrow_e, TRUE, FALSE,
6714 EL_CHAR('>'), -1, -1
6717 Xalpha_arrow_w, TRUE, FALSE,
6718 EL_CHAR('<'), -1, -1
6721 Xalpha_copyr, TRUE, FALSE,
6722 EL_CHAR(CHAR_BYTE_COPYRIGHT), -1, -1
6726 Xboom_bug, FALSE, FALSE,
6727 EL_BUG, ACTION_EXPLODING, -1
6730 Xboom_bomb, FALSE, FALSE,
6731 EL_BOMB, ACTION_EXPLODING, -1
6734 Xboom_android, FALSE, FALSE,
6735 EL_EMC_ANDROID, ACTION_OTHER, -1
6738 Xboom_1, FALSE, FALSE,
6739 EL_DEFAULT, ACTION_EXPLODING, -1
6742 Xboom_2, FALSE, FALSE,
6743 EL_DEFAULT, ACTION_EXPLODING, -1
6746 Znormal, FALSE, FALSE,
6750 Zdynamite, FALSE, FALSE,
6754 Zplayer, FALSE, FALSE,
6758 ZBORDER, FALSE, FALSE,
6768 static struct Mapping_EM_to_RND_player
6777 em_player_mapping_list[] =
6781 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
6785 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
6789 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
6793 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
6797 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
6801 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
6805 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
6809 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
6813 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
6817 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
6821 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
6825 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
6829 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
6833 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
6837 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
6841 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
6845 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
6849 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
6853 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
6857 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
6861 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
6865 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
6869 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
6873 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
6877 EL_PLAYER_1, ACTION_DEFAULT, -1,
6881 EL_PLAYER_2, ACTION_DEFAULT, -1,
6885 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
6889 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
6893 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
6897 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
6901 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
6905 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
6909 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
6913 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
6917 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
6921 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
6925 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
6929 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
6933 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
6937 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
6941 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
6945 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
6949 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
6953 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
6957 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
6961 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
6965 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
6969 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
6973 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
6977 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
6981 EL_PLAYER_3, ACTION_DEFAULT, -1,
6985 EL_PLAYER_4, ACTION_DEFAULT, -1,
6994 int map_element_RND_to_EM(int element_rnd)
6996 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
6997 static boolean mapping_initialized = FALSE;
6999 if (!mapping_initialized)
7003 /* return "Xalpha_quest" for all undefined elements in mapping array */
7004 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
7005 mapping_RND_to_EM[i] = Xalpha_quest;
7007 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
7008 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
7009 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
7010 em_object_mapping_list[i].element_em;
7012 mapping_initialized = TRUE;
7015 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
7016 return mapping_RND_to_EM[element_rnd];
7018 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
7023 int map_element_EM_to_RND(int element_em)
7025 static unsigned short mapping_EM_to_RND[TILE_MAX];
7026 static boolean mapping_initialized = FALSE;
7028 if (!mapping_initialized)
7032 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
7033 for (i = 0; i < TILE_MAX; i++)
7034 mapping_EM_to_RND[i] = EL_UNKNOWN;
7036 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
7037 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
7038 em_object_mapping_list[i].element_rnd;
7040 mapping_initialized = TRUE;
7043 if (element_em >= 0 && element_em < TILE_MAX)
7044 return mapping_EM_to_RND[element_em];
7046 Error(ERR_WARN, "invalid EM level element %d", element_em);
7051 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
7053 struct LevelInfo_EM *level_em = level->native_em_level;
7054 struct LEVEL *lev = level_em->lev;
7057 for (i = 0; i < TILE_MAX; i++)
7058 lev->android_array[i] = Xblank;
7060 for (i = 0; i < level->num_android_clone_elements; i++)
7062 int element_rnd = level->android_clone_element[i];
7063 int element_em = map_element_RND_to_EM(element_rnd);
7065 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
7066 if (em_object_mapping_list[j].element_rnd == element_rnd)
7067 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
7071 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
7073 struct LevelInfo_EM *level_em = level->native_em_level;
7074 struct LEVEL *lev = level_em->lev;
7077 level->num_android_clone_elements = 0;
7079 for (i = 0; i < TILE_MAX; i++)
7081 int element_em = lev->android_array[i];
7083 boolean element_found = FALSE;
7085 if (element_em == Xblank)
7088 element_rnd = map_element_EM_to_RND(element_em);
7090 for (j = 0; j < level->num_android_clone_elements; j++)
7091 if (level->android_clone_element[j] == element_rnd)
7092 element_found = TRUE;
7096 level->android_clone_element[level->num_android_clone_elements++] =
7099 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
7104 if (level->num_android_clone_elements == 0)
7106 level->num_android_clone_elements = 1;
7107 level->android_clone_element[0] = EL_EMPTY;
7111 int map_direction_RND_to_EM(int direction)
7113 return (direction == MV_UP ? 0 :
7114 direction == MV_RIGHT ? 1 :
7115 direction == MV_DOWN ? 2 :
7116 direction == MV_LEFT ? 3 :
7120 int map_direction_EM_to_RND(int direction)
7122 return (direction == 0 ? MV_UP :
7123 direction == 1 ? MV_RIGHT :
7124 direction == 2 ? MV_DOWN :
7125 direction == 3 ? MV_LEFT :
7129 int map_element_RND_to_SP(int element_rnd)
7131 int element_sp = 0x20; /* map unknown elements to yellow "hardware" */
7133 if (element_rnd >= EL_SP_START &&
7134 element_rnd <= EL_SP_END)
7135 element_sp = element_rnd - EL_SP_START;
7136 else if (element_rnd == EL_EMPTY_SPACE)
7138 else if (element_rnd == EL_INVISIBLE_WALL)
7144 int map_element_SP_to_RND(int element_sp)
7146 int element_rnd = EL_UNKNOWN;
7148 if (element_sp >= 0x00 &&
7150 element_rnd = EL_SP_START + element_sp;
7151 else if (element_sp == 0x28)
7152 element_rnd = EL_INVISIBLE_WALL;
7157 int map_action_SP_to_RND(int action_sp)
7161 case actActive: return ACTION_ACTIVE;
7162 case actImpact: return ACTION_IMPACT;
7163 case actExploding: return ACTION_EXPLODING;
7164 case actDigging: return ACTION_DIGGING;
7165 case actSnapping: return ACTION_SNAPPING;
7166 case actCollecting: return ACTION_COLLECTING;
7167 case actPassing: return ACTION_PASSING;
7168 case actPushing: return ACTION_PUSHING;
7169 case actDropping: return ACTION_DROPPING;
7171 default: return ACTION_DEFAULT;
7175 int get_next_element(int element)
7179 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
7180 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
7181 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
7182 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
7183 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
7184 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
7185 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
7186 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
7187 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
7188 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
7189 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
7191 default: return element;
7195 int el_act_dir2img(int element, int action, int direction)
7197 element = GFX_ELEMENT(element);
7198 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
7200 /* direction_graphic[][] == graphic[] for undefined direction graphics */
7201 return element_info[element].direction_graphic[action][direction];
7204 static int el_act_dir2crm(int element, int action, int direction)
7206 element = GFX_ELEMENT(element);
7207 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
7209 /* direction_graphic[][] == graphic[] for undefined direction graphics */
7210 return element_info[element].direction_crumbled[action][direction];
7213 int el_act2img(int element, int action)
7215 element = GFX_ELEMENT(element);
7217 return element_info[element].graphic[action];
7220 int el_act2crm(int element, int action)
7222 element = GFX_ELEMENT(element);
7224 return element_info[element].crumbled[action];
7227 int el_dir2img(int element, int direction)
7229 element = GFX_ELEMENT(element);
7231 return el_act_dir2img(element, ACTION_DEFAULT, direction);
7234 int el2baseimg(int element)
7236 return element_info[element].graphic[ACTION_DEFAULT];
7239 int el2img(int element)
7241 element = GFX_ELEMENT(element);
7243 return element_info[element].graphic[ACTION_DEFAULT];
7246 int el2edimg(int element)
7248 element = GFX_ELEMENT(element);
7250 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
7253 int el2preimg(int element)
7255 element = GFX_ELEMENT(element);
7257 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
7260 int el2panelimg(int element)
7262 element = GFX_ELEMENT(element);
7264 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL];
7267 int font2baseimg(int font_nr)
7269 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
7272 int getBeltNrFromBeltElement(int element)
7274 return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
7275 element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
7276 element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
7279 int getBeltNrFromBeltActiveElement(int element)
7281 return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
7282 element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
7283 element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
7286 int getBeltNrFromBeltSwitchElement(int element)
7288 return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
7289 element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
7290 element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
7293 int getBeltDirNrFromBeltElement(int element)
7295 static int belt_base_element[4] =
7297 EL_CONVEYOR_BELT_1_LEFT,
7298 EL_CONVEYOR_BELT_2_LEFT,
7299 EL_CONVEYOR_BELT_3_LEFT,
7300 EL_CONVEYOR_BELT_4_LEFT
7303 int belt_nr = getBeltNrFromBeltElement(element);
7304 int belt_dir_nr = element - belt_base_element[belt_nr];
7306 return (belt_dir_nr % 3);
7309 int getBeltDirNrFromBeltSwitchElement(int element)
7311 static int belt_base_element[4] =
7313 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
7314 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
7315 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
7316 EL_CONVEYOR_BELT_4_SWITCH_LEFT
7319 int belt_nr = getBeltNrFromBeltSwitchElement(element);
7320 int belt_dir_nr = element - belt_base_element[belt_nr];
7322 return (belt_dir_nr % 3);
7325 int getBeltDirFromBeltElement(int element)
7327 static int belt_move_dir[3] =
7334 int belt_dir_nr = getBeltDirNrFromBeltElement(element);
7336 return belt_move_dir[belt_dir_nr];
7339 int getBeltDirFromBeltSwitchElement(int element)
7341 static int belt_move_dir[3] =
7348 int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
7350 return belt_move_dir[belt_dir_nr];
7353 int getBeltElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
7355 static int belt_base_element[4] =
7357 EL_CONVEYOR_BELT_1_LEFT,
7358 EL_CONVEYOR_BELT_2_LEFT,
7359 EL_CONVEYOR_BELT_3_LEFT,
7360 EL_CONVEYOR_BELT_4_LEFT
7363 return belt_base_element[belt_nr] + belt_dir_nr;
7366 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
7368 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
7370 return getBeltElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
7373 int getBeltSwitchElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
7375 static int belt_base_element[4] =
7377 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
7378 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
7379 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
7380 EL_CONVEYOR_BELT_4_SWITCH_LEFT
7383 return belt_base_element[belt_nr] + belt_dir_nr;
7386 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
7388 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
7390 return getBeltSwitchElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
7393 boolean getTeamMode_EM()
7395 return game.team_mode;
7398 int getGameFrameDelay_EM(int native_em_game_frame_delay)
7400 int game_frame_delay_value;
7402 game_frame_delay_value =
7403 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
7404 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
7407 if (tape.playing && tape.warp_forward && !tape.pausing)
7408 game_frame_delay_value = 0;
7410 return game_frame_delay_value;
7413 unsigned int InitRND(int seed)
7415 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
7416 return InitEngineRandom_EM(seed);
7417 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
7418 return InitEngineRandom_SP(seed);
7420 return InitEngineRandom_RND(seed);
7423 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
7424 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
7426 inline static int get_effective_element_EM(int tile, int frame_em)
7428 int element = object_mapping[tile].element_rnd;
7429 int action = object_mapping[tile].action;
7430 boolean is_backside = object_mapping[tile].is_backside;
7431 boolean action_removing = (action == ACTION_DIGGING ||
7432 action == ACTION_SNAPPING ||
7433 action == ACTION_COLLECTING);
7439 case Yacid_splash_eB:
7440 case Yacid_splash_wB:
7441 return (frame_em > 5 ? EL_EMPTY : element);
7447 else /* frame_em == 7 */
7451 case Yacid_splash_eB:
7452 case Yacid_splash_wB:
7455 case Yemerald_stone:
7458 case Ydiamond_stone:
7462 case Xdrip_stretchB:
7481 case Xsand_stonein_1:
7482 case Xsand_stonein_2:
7483 case Xsand_stonein_3:
7484 case Xsand_stonein_4:
7488 return (is_backside || action_removing ? EL_EMPTY : element);
7493 inline static boolean check_linear_animation_EM(int tile)
7497 case Xsand_stonesand_1:
7498 case Xsand_stonesand_quickout_1:
7499 case Xsand_sandstone_1:
7500 case Xsand_stonein_1:
7501 case Xsand_stoneout_1:
7520 case Yacid_splash_eB:
7521 case Yacid_splash_wB:
7522 case Yemerald_stone:
7529 inline static void set_crumbled_graphics_EM(struct GraphicInfo_EM *g_em,
7530 boolean has_crumbled_graphics,
7531 int crumbled, int sync_frame)
7533 /* if element can be crumbled, but certain action graphics are just empty
7534 space (like instantly snapping sand to empty space in 1 frame), do not
7535 treat these empty space graphics as crumbled graphics in EMC engine */
7536 if (crumbled == IMG_EMPTY_SPACE)
7537 has_crumbled_graphics = FALSE;
7539 if (has_crumbled_graphics)
7541 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
7542 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
7543 g_crumbled->anim_delay,
7544 g_crumbled->anim_mode,
7545 g_crumbled->anim_start_frame,
7548 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
7549 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
7551 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
7552 g_em->crumbled_tile_size = graphic_info[crumbled].tile_size;
7554 g_em->has_crumbled_graphics = TRUE;
7558 g_em->crumbled_bitmap = NULL;
7559 g_em->crumbled_src_x = 0;
7560 g_em->crumbled_src_y = 0;
7561 g_em->crumbled_border_size = 0;
7562 g_em->crumbled_tile_size = 0;
7564 g_em->has_crumbled_graphics = FALSE;
7568 void ResetGfxAnimation_EM(int x, int y, int tile)
7573 void SetGfxAnimation_EM(struct GraphicInfo_EM *g_em,
7574 int tile, int frame_em, int x, int y)
7576 int action = object_mapping[tile].action;
7577 int direction = object_mapping[tile].direction;
7578 int effective_element = get_effective_element_EM(tile, frame_em);
7579 int graphic = (direction == MV_NONE ?
7580 el_act2img(effective_element, action) :
7581 el_act_dir2img(effective_element, action, direction));
7582 struct GraphicInfo *g = &graphic_info[graphic];
7584 boolean action_removing = (action == ACTION_DIGGING ||
7585 action == ACTION_SNAPPING ||
7586 action == ACTION_COLLECTING);
7587 boolean action_moving = (action == ACTION_FALLING ||
7588 action == ACTION_MOVING ||
7589 action == ACTION_PUSHING ||
7590 action == ACTION_EATING ||
7591 action == ACTION_FILLING ||
7592 action == ACTION_EMPTYING);
7593 boolean action_falling = (action == ACTION_FALLING ||
7594 action == ACTION_FILLING ||
7595 action == ACTION_EMPTYING);
7597 /* special case: graphic uses "2nd movement tile" and has defined
7598 7 frames for movement animation (or less) => use default graphic
7599 for last (8th) frame which ends the movement animation */
7600 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
7602 action = ACTION_DEFAULT; /* (keep action_* unchanged for now) */
7603 graphic = (direction == MV_NONE ?
7604 el_act2img(effective_element, action) :
7605 el_act_dir2img(effective_element, action, direction));
7607 g = &graphic_info[graphic];
7610 if ((action_removing || check_linear_animation_EM(tile)) && frame_em == 0)
7614 else if (action_moving)
7616 boolean is_backside = object_mapping[tile].is_backside;
7620 int direction = object_mapping[tile].direction;
7621 int move_dir = (action_falling ? MV_DOWN : direction);
7626 /* !!! TEST !!! NEW !!! DOES NOT WORK RIGHT YET !!! */
7627 if (g->double_movement && frame_em == 0)
7631 if (move_dir == MV_LEFT)
7632 GfxFrame[x - 1][y] = GfxFrame[x][y];
7633 else if (move_dir == MV_RIGHT)
7634 GfxFrame[x + 1][y] = GfxFrame[x][y];
7635 else if (move_dir == MV_UP)
7636 GfxFrame[x][y - 1] = GfxFrame[x][y];
7637 else if (move_dir == MV_DOWN)
7638 GfxFrame[x][y + 1] = GfxFrame[x][y];
7645 /* special case: animation for Xsand_stonesand_quickout_1/2 twice as fast */
7646 if (tile == Xsand_stonesand_quickout_1 ||
7647 tile == Xsand_stonesand_quickout_2)
7651 if (graphic_info[graphic].anim_global_sync)
7652 sync_frame = FrameCounter;
7653 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
7654 sync_frame = GfxFrame[x][y];
7656 sync_frame = 0; /* playfield border (pseudo steel) */
7658 SetRandomAnimationValue(x, y);
7660 int frame = getAnimationFrame(g->anim_frames,
7663 g->anim_start_frame,
7666 g_em->unique_identifier =
7667 (graphic << 16) | ((frame % 8) << 12) | (g_em->width << 6) | g_em->height;
7670 void getGraphicSourceObjectExt_EM(struct GraphicInfo_EM *g_em,
7671 int tile, int frame_em, int x, int y)
7673 int action = object_mapping[tile].action;
7674 int direction = object_mapping[tile].direction;
7675 boolean is_backside = object_mapping[tile].is_backside;
7676 int effective_element = get_effective_element_EM(tile, frame_em);
7677 int effective_action = action;
7678 int graphic = (direction == MV_NONE ?
7679 el_act2img(effective_element, effective_action) :
7680 el_act_dir2img(effective_element, effective_action,
7682 int crumbled = (direction == MV_NONE ?
7683 el_act2crm(effective_element, effective_action) :
7684 el_act_dir2crm(effective_element, effective_action,
7686 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7687 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7688 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7689 struct GraphicInfo *g = &graphic_info[graphic];
7692 /* special case: graphic uses "2nd movement tile" and has defined
7693 7 frames for movement animation (or less) => use default graphic
7694 for last (8th) frame which ends the movement animation */
7695 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
7697 effective_action = ACTION_DEFAULT;
7698 graphic = (direction == MV_NONE ?
7699 el_act2img(effective_element, effective_action) :
7700 el_act_dir2img(effective_element, effective_action,
7702 crumbled = (direction == MV_NONE ?
7703 el_act2crm(effective_element, effective_action) :
7704 el_act_dir2crm(effective_element, effective_action,
7707 g = &graphic_info[graphic];
7710 if (graphic_info[graphic].anim_global_sync)
7711 sync_frame = FrameCounter;
7712 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
7713 sync_frame = GfxFrame[x][y];
7715 sync_frame = 0; /* playfield border (pseudo steel) */
7717 SetRandomAnimationValue(x, y);
7719 int frame = getAnimationFrame(g->anim_frames,
7722 g->anim_start_frame,
7725 getGraphicSourceExt(graphic, frame, &g_em->bitmap, &g_em->src_x, &g_em->src_y,
7726 g->double_movement && is_backside);
7728 /* (updating the "crumbled" graphic definitions is probably not really needed,
7729 as animations for crumbled graphics can't be longer than one EMC cycle) */
7730 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
7734 void getGraphicSourcePlayerExt_EM(struct GraphicInfo_EM *g_em,
7735 int player_nr, int anim, int frame_em)
7737 int element = player_mapping[player_nr][anim].element_rnd;
7738 int action = player_mapping[player_nr][anim].action;
7739 int direction = player_mapping[player_nr][anim].direction;
7740 int graphic = (direction == MV_NONE ?
7741 el_act2img(element, action) :
7742 el_act_dir2img(element, action, direction));
7743 struct GraphicInfo *g = &graphic_info[graphic];
7746 InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
7748 stored_player[player_nr].StepFrame = frame_em;
7750 sync_frame = stored_player[player_nr].Frame;
7752 int frame = getAnimationFrame(g->anim_frames,
7755 g->anim_start_frame,
7758 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
7759 &g_em->src_x, &g_em->src_y, FALSE);
7762 void InitGraphicInfo_EM(void)
7767 int num_em_gfx_errors = 0;
7769 if (graphic_info_em_object[0][0].bitmap == NULL)
7771 /* EM graphics not yet initialized in em_open_all() */
7776 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
7779 /* always start with reliable default values */
7780 for (i = 0; i < TILE_MAX; i++)
7782 object_mapping[i].element_rnd = EL_UNKNOWN;
7783 object_mapping[i].is_backside = FALSE;
7784 object_mapping[i].action = ACTION_DEFAULT;
7785 object_mapping[i].direction = MV_NONE;
7788 /* always start with reliable default values */
7789 for (p = 0; p < MAX_PLAYERS; p++)
7791 for (i = 0; i < SPR_MAX; i++)
7793 player_mapping[p][i].element_rnd = EL_UNKNOWN;
7794 player_mapping[p][i].action = ACTION_DEFAULT;
7795 player_mapping[p][i].direction = MV_NONE;
7799 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
7801 int e = em_object_mapping_list[i].element_em;
7803 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
7804 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
7806 if (em_object_mapping_list[i].action != -1)
7807 object_mapping[e].action = em_object_mapping_list[i].action;
7809 if (em_object_mapping_list[i].direction != -1)
7810 object_mapping[e].direction =
7811 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
7814 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
7816 int a = em_player_mapping_list[i].action_em;
7817 int p = em_player_mapping_list[i].player_nr;
7819 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
7821 if (em_player_mapping_list[i].action != -1)
7822 player_mapping[p][a].action = em_player_mapping_list[i].action;
7824 if (em_player_mapping_list[i].direction != -1)
7825 player_mapping[p][a].direction =
7826 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
7829 for (i = 0; i < TILE_MAX; i++)
7831 int element = object_mapping[i].element_rnd;
7832 int action = object_mapping[i].action;
7833 int direction = object_mapping[i].direction;
7834 boolean is_backside = object_mapping[i].is_backside;
7835 boolean action_exploding = ((action == ACTION_EXPLODING ||
7836 action == ACTION_SMASHED_BY_ROCK ||
7837 action == ACTION_SMASHED_BY_SPRING) &&
7838 element != EL_DIAMOND);
7839 boolean action_active = (action == ACTION_ACTIVE);
7840 boolean action_other = (action == ACTION_OTHER);
7842 for (j = 0; j < 8; j++)
7844 int effective_element = get_effective_element_EM(i, j);
7845 int effective_action = (j < 7 ? action :
7846 i == Xdrip_stretch ? action :
7847 i == Xdrip_stretchB ? action :
7848 i == Ydrip_s1 ? action :
7849 i == Ydrip_s1B ? action :
7850 i == Xball_1B ? action :
7851 i == Xball_2 ? action :
7852 i == Xball_2B ? action :
7853 i == Yball_eat ? action :
7854 i == Ykey_1_eat ? action :
7855 i == Ykey_2_eat ? action :
7856 i == Ykey_3_eat ? action :
7857 i == Ykey_4_eat ? action :
7858 i == Ykey_5_eat ? action :
7859 i == Ykey_6_eat ? action :
7860 i == Ykey_7_eat ? action :
7861 i == Ykey_8_eat ? action :
7862 i == Ylenses_eat ? action :
7863 i == Ymagnify_eat ? action :
7864 i == Ygrass_eat ? action :
7865 i == Ydirt_eat ? action :
7866 i == Xsand_stonein_1 ? action :
7867 i == Xsand_stonein_2 ? action :
7868 i == Xsand_stonein_3 ? action :
7869 i == Xsand_stonein_4 ? action :
7870 i == Xsand_stoneout_1 ? action :
7871 i == Xsand_stoneout_2 ? action :
7872 i == Xboom_android ? ACTION_EXPLODING :
7873 action_exploding ? ACTION_EXPLODING :
7874 action_active ? action :
7875 action_other ? action :
7877 int graphic = (el_act_dir2img(effective_element, effective_action,
7879 int crumbled = (el_act_dir2crm(effective_element, effective_action,
7881 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7882 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7883 boolean has_action_graphics = (graphic != base_graphic);
7884 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7885 struct GraphicInfo *g = &graphic_info[graphic];
7886 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7889 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
7890 boolean special_animation = (action != ACTION_DEFAULT &&
7891 g->anim_frames == 3 &&
7892 g->anim_delay == 2 &&
7893 g->anim_mode & ANIM_LINEAR);
7894 int sync_frame = (i == Xdrip_stretch ? 7 :
7895 i == Xdrip_stretchB ? 7 :
7896 i == Ydrip_s2 ? j + 8 :
7897 i == Ydrip_s2B ? j + 8 :
7906 i == Xfake_acid_1 ? 0 :
7907 i == Xfake_acid_2 ? 10 :
7908 i == Xfake_acid_3 ? 20 :
7909 i == Xfake_acid_4 ? 30 :
7910 i == Xfake_acid_5 ? 40 :
7911 i == Xfake_acid_6 ? 50 :
7912 i == Xfake_acid_7 ? 60 :
7913 i == Xfake_acid_8 ? 70 :
7915 i == Xball_2B ? j + 8 :
7916 i == Yball_eat ? j + 1 :
7917 i == Ykey_1_eat ? j + 1 :
7918 i == Ykey_2_eat ? j + 1 :
7919 i == Ykey_3_eat ? j + 1 :
7920 i == Ykey_4_eat ? j + 1 :
7921 i == Ykey_5_eat ? j + 1 :
7922 i == Ykey_6_eat ? j + 1 :
7923 i == Ykey_7_eat ? j + 1 :
7924 i == Ykey_8_eat ? j + 1 :
7925 i == Ylenses_eat ? j + 1 :
7926 i == Ymagnify_eat ? j + 1 :
7927 i == Ygrass_eat ? j + 1 :
7928 i == Ydirt_eat ? j + 1 :
7929 i == Xamoeba_1 ? 0 :
7930 i == Xamoeba_2 ? 1 :
7931 i == Xamoeba_3 ? 2 :
7932 i == Xamoeba_4 ? 3 :
7933 i == Xamoeba_5 ? 0 :
7934 i == Xamoeba_6 ? 1 :
7935 i == Xamoeba_7 ? 2 :
7936 i == Xamoeba_8 ? 3 :
7937 i == Xexit_2 ? j + 8 :
7938 i == Xexit_3 ? j + 16 :
7939 i == Xdynamite_1 ? 0 :
7940 i == Xdynamite_2 ? 8 :
7941 i == Xdynamite_3 ? 16 :
7942 i == Xdynamite_4 ? 24 :
7943 i == Xsand_stonein_1 ? j + 1 :
7944 i == Xsand_stonein_2 ? j + 9 :
7945 i == Xsand_stonein_3 ? j + 17 :
7946 i == Xsand_stonein_4 ? j + 25 :
7947 i == Xsand_stoneout_1 && j == 0 ? 0 :
7948 i == Xsand_stoneout_1 && j == 1 ? 0 :
7949 i == Xsand_stoneout_1 && j == 2 ? 1 :
7950 i == Xsand_stoneout_1 && j == 3 ? 2 :
7951 i == Xsand_stoneout_1 && j == 4 ? 2 :
7952 i == Xsand_stoneout_1 && j == 5 ? 3 :
7953 i == Xsand_stoneout_1 && j == 6 ? 4 :
7954 i == Xsand_stoneout_1 && j == 7 ? 4 :
7955 i == Xsand_stoneout_2 && j == 0 ? 5 :
7956 i == Xsand_stoneout_2 && j == 1 ? 6 :
7957 i == Xsand_stoneout_2 && j == 2 ? 7 :
7958 i == Xsand_stoneout_2 && j == 3 ? 8 :
7959 i == Xsand_stoneout_2 && j == 4 ? 9 :
7960 i == Xsand_stoneout_2 && j == 5 ? 11 :
7961 i == Xsand_stoneout_2 && j == 6 ? 13 :
7962 i == Xsand_stoneout_2 && j == 7 ? 15 :
7963 i == Xboom_bug && j == 1 ? 2 :
7964 i == Xboom_bug && j == 2 ? 2 :
7965 i == Xboom_bug && j == 3 ? 4 :
7966 i == Xboom_bug && j == 4 ? 4 :
7967 i == Xboom_bug && j == 5 ? 2 :
7968 i == Xboom_bug && j == 6 ? 2 :
7969 i == Xboom_bug && j == 7 ? 0 :
7970 i == Xboom_bomb && j == 1 ? 2 :
7971 i == Xboom_bomb && j == 2 ? 2 :
7972 i == Xboom_bomb && j == 3 ? 4 :
7973 i == Xboom_bomb && j == 4 ? 4 :
7974 i == Xboom_bomb && j == 5 ? 2 :
7975 i == Xboom_bomb && j == 6 ? 2 :
7976 i == Xboom_bomb && j == 7 ? 0 :
7977 i == Xboom_android && j == 7 ? 6 :
7978 i == Xboom_1 && j == 1 ? 2 :
7979 i == Xboom_1 && j == 2 ? 2 :
7980 i == Xboom_1 && j == 3 ? 4 :
7981 i == Xboom_1 && j == 4 ? 4 :
7982 i == Xboom_1 && j == 5 ? 6 :
7983 i == Xboom_1 && j == 6 ? 6 :
7984 i == Xboom_1 && j == 7 ? 8 :
7985 i == Xboom_2 && j == 0 ? 8 :
7986 i == Xboom_2 && j == 1 ? 8 :
7987 i == Xboom_2 && j == 2 ? 10 :
7988 i == Xboom_2 && j == 3 ? 10 :
7989 i == Xboom_2 && j == 4 ? 10 :
7990 i == Xboom_2 && j == 5 ? 12 :
7991 i == Xboom_2 && j == 6 ? 12 :
7992 i == Xboom_2 && j == 7 ? 12 :
7993 special_animation && j == 4 ? 3 :
7994 effective_action != action ? 0 :
7998 Bitmap *debug_bitmap = g_em->bitmap;
7999 int debug_src_x = g_em->src_x;
8000 int debug_src_y = g_em->src_y;
8003 int frame = getAnimationFrame(g->anim_frames,
8006 g->anim_start_frame,
8009 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
8010 g->double_movement && is_backside);
8012 g_em->bitmap = src_bitmap;
8013 g_em->src_x = src_x;
8014 g_em->src_y = src_y;
8015 g_em->src_offset_x = 0;
8016 g_em->src_offset_y = 0;
8017 g_em->dst_offset_x = 0;
8018 g_em->dst_offset_y = 0;
8019 g_em->width = TILEX;
8020 g_em->height = TILEY;
8022 g_em->preserve_background = FALSE;
8024 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
8027 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
8028 effective_action == ACTION_MOVING ||
8029 effective_action == ACTION_PUSHING ||
8030 effective_action == ACTION_EATING)) ||
8031 (!has_action_graphics && (effective_action == ACTION_FILLING ||
8032 effective_action == ACTION_EMPTYING)))
8035 (effective_action == ACTION_FALLING ||
8036 effective_action == ACTION_FILLING ||
8037 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
8038 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
8039 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
8040 int num_steps = (i == Ydrip_s1 ? 16 :
8041 i == Ydrip_s1B ? 16 :
8042 i == Ydrip_s2 ? 16 :
8043 i == Ydrip_s2B ? 16 :
8044 i == Xsand_stonein_1 ? 32 :
8045 i == Xsand_stonein_2 ? 32 :
8046 i == Xsand_stonein_3 ? 32 :
8047 i == Xsand_stonein_4 ? 32 :
8048 i == Xsand_stoneout_1 ? 16 :
8049 i == Xsand_stoneout_2 ? 16 : 8);
8050 int cx = ABS(dx) * (TILEX / num_steps);
8051 int cy = ABS(dy) * (TILEY / num_steps);
8052 int step_frame = (i == Ydrip_s2 ? j + 8 :
8053 i == Ydrip_s2B ? j + 8 :
8054 i == Xsand_stonein_2 ? j + 8 :
8055 i == Xsand_stonein_3 ? j + 16 :
8056 i == Xsand_stonein_4 ? j + 24 :
8057 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
8058 int step = (is_backside ? step_frame : num_steps - step_frame);
8060 if (is_backside) /* tile where movement starts */
8062 if (dx < 0 || dy < 0)
8064 g_em->src_offset_x = cx * step;
8065 g_em->src_offset_y = cy * step;
8069 g_em->dst_offset_x = cx * step;
8070 g_em->dst_offset_y = cy * step;
8073 else /* tile where movement ends */
8075 if (dx < 0 || dy < 0)
8077 g_em->dst_offset_x = cx * step;
8078 g_em->dst_offset_y = cy * step;
8082 g_em->src_offset_x = cx * step;
8083 g_em->src_offset_y = cy * step;
8087 g_em->width = TILEX - cx * step;
8088 g_em->height = TILEY - cy * step;
8091 /* create unique graphic identifier to decide if tile must be redrawn */
8092 /* bit 31 - 16 (16 bit): EM style graphic
8093 bit 15 - 12 ( 4 bit): EM style frame
8094 bit 11 - 6 ( 6 bit): graphic width
8095 bit 5 - 0 ( 6 bit): graphic height */
8096 g_em->unique_identifier =
8097 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
8101 /* skip check for EMC elements not contained in original EMC artwork */
8102 if (element == EL_EMC_FAKE_ACID)
8105 if (g_em->bitmap != debug_bitmap ||
8106 g_em->src_x != debug_src_x ||
8107 g_em->src_y != debug_src_y ||
8108 g_em->src_offset_x != 0 ||
8109 g_em->src_offset_y != 0 ||
8110 g_em->dst_offset_x != 0 ||
8111 g_em->dst_offset_y != 0 ||
8112 g_em->width != TILEX ||
8113 g_em->height != TILEY)
8115 static int last_i = -1;
8123 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
8124 i, element, element_info[element].token_name,
8125 element_action_info[effective_action].suffix, direction);
8127 if (element != effective_element)
8128 printf(" [%d ('%s')]",
8130 element_info[effective_element].token_name);
8134 if (g_em->bitmap != debug_bitmap)
8135 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
8136 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
8138 if (g_em->src_x != debug_src_x ||
8139 g_em->src_y != debug_src_y)
8140 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
8141 j, (is_backside ? 'B' : 'F'),
8142 g_em->src_x, g_em->src_y,
8143 g_em->src_x / 32, g_em->src_y / 32,
8144 debug_src_x, debug_src_y,
8145 debug_src_x / 32, debug_src_y / 32);
8147 if (g_em->src_offset_x != 0 ||
8148 g_em->src_offset_y != 0 ||
8149 g_em->dst_offset_x != 0 ||
8150 g_em->dst_offset_y != 0)
8151 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
8153 g_em->src_offset_x, g_em->src_offset_y,
8154 g_em->dst_offset_x, g_em->dst_offset_y);
8156 if (g_em->width != TILEX ||
8157 g_em->height != TILEY)
8158 printf(" %d (%d): size %d,%d should be %d,%d\n",
8160 g_em->width, g_em->height, TILEX, TILEY);
8162 num_em_gfx_errors++;
8169 for (i = 0; i < TILE_MAX; i++)
8171 for (j = 0; j < 8; j++)
8173 int element = object_mapping[i].element_rnd;
8174 int action = object_mapping[i].action;
8175 int direction = object_mapping[i].direction;
8176 boolean is_backside = object_mapping[i].is_backside;
8177 int graphic_action = el_act_dir2img(element, action, direction);
8178 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
8180 if ((action == ACTION_SMASHED_BY_ROCK ||
8181 action == ACTION_SMASHED_BY_SPRING ||
8182 action == ACTION_EATING) &&
8183 graphic_action == graphic_default)
8185 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
8186 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
8187 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
8188 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
8191 /* no separate animation for "smashed by rock" -- use rock instead */
8192 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
8193 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
8195 g_em->bitmap = g_xx->bitmap;
8196 g_em->src_x = g_xx->src_x;
8197 g_em->src_y = g_xx->src_y;
8198 g_em->src_offset_x = g_xx->src_offset_x;
8199 g_em->src_offset_y = g_xx->src_offset_y;
8200 g_em->dst_offset_x = g_xx->dst_offset_x;
8201 g_em->dst_offset_y = g_xx->dst_offset_y;
8202 g_em->width = g_xx->width;
8203 g_em->height = g_xx->height;
8204 g_em->unique_identifier = g_xx->unique_identifier;
8207 g_em->preserve_background = TRUE;
8212 for (p = 0; p < MAX_PLAYERS; p++)
8214 for (i = 0; i < SPR_MAX; i++)
8216 int element = player_mapping[p][i].element_rnd;
8217 int action = player_mapping[p][i].action;
8218 int direction = player_mapping[p][i].direction;
8220 for (j = 0; j < 8; j++)
8222 int effective_element = element;
8223 int effective_action = action;
8224 int graphic = (direction == MV_NONE ?
8225 el_act2img(effective_element, effective_action) :
8226 el_act_dir2img(effective_element, effective_action,
8228 struct GraphicInfo *g = &graphic_info[graphic];
8229 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
8235 Bitmap *debug_bitmap = g_em->bitmap;
8236 int debug_src_x = g_em->src_x;
8237 int debug_src_y = g_em->src_y;
8240 int frame = getAnimationFrame(g->anim_frames,
8243 g->anim_start_frame,
8246 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
8248 g_em->bitmap = src_bitmap;
8249 g_em->src_x = src_x;
8250 g_em->src_y = src_y;
8251 g_em->src_offset_x = 0;
8252 g_em->src_offset_y = 0;
8253 g_em->dst_offset_x = 0;
8254 g_em->dst_offset_y = 0;
8255 g_em->width = TILEX;
8256 g_em->height = TILEY;
8260 /* skip check for EMC elements not contained in original EMC artwork */
8261 if (element == EL_PLAYER_3 ||
8262 element == EL_PLAYER_4)
8265 if (g_em->bitmap != debug_bitmap ||
8266 g_em->src_x != debug_src_x ||
8267 g_em->src_y != debug_src_y)
8269 static int last_i = -1;
8277 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
8278 p, i, element, element_info[element].token_name,
8279 element_action_info[effective_action].suffix, direction);
8281 if (element != effective_element)
8282 printf(" [%d ('%s')]",
8284 element_info[effective_element].token_name);
8288 if (g_em->bitmap != debug_bitmap)
8289 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
8290 j, (int)(g_em->bitmap), (int)(debug_bitmap));
8292 if (g_em->src_x != debug_src_x ||
8293 g_em->src_y != debug_src_y)
8294 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
8296 g_em->src_x, g_em->src_y,
8297 g_em->src_x / 32, g_em->src_y / 32,
8298 debug_src_x, debug_src_y,
8299 debug_src_x / 32, debug_src_y / 32);
8301 num_em_gfx_errors++;
8311 printf("::: [%d errors found]\n", num_em_gfx_errors);
8317 void CheckSaveEngineSnapshot_EM(byte action[MAX_PLAYERS], int frame,
8318 boolean any_player_moving,
8319 boolean any_player_snapping,
8320 boolean any_player_dropping)
8322 if (frame == 0 && !any_player_dropping)
8324 if (!local_player->was_waiting)
8326 if (!CheckSaveEngineSnapshotToList())
8329 local_player->was_waiting = TRUE;
8332 else if (any_player_moving || any_player_snapping || any_player_dropping)
8334 local_player->was_waiting = FALSE;
8338 void CheckSaveEngineSnapshot_SP(boolean murphy_is_waiting,
8339 boolean murphy_is_dropping)
8341 if (murphy_is_waiting)
8343 if (!local_player->was_waiting)
8345 if (!CheckSaveEngineSnapshotToList())
8348 local_player->was_waiting = TRUE;
8353 local_player->was_waiting = FALSE;
8357 void CheckSingleStepMode_EM(byte action[MAX_PLAYERS], int frame,
8358 boolean any_player_moving,
8359 boolean any_player_snapping,
8360 boolean any_player_dropping)
8362 if (tape.single_step && tape.recording && !tape.pausing)
8363 if (frame == 0 && !any_player_dropping)
8364 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
8366 CheckSaveEngineSnapshot_EM(action, frame, any_player_moving,
8367 any_player_snapping, any_player_dropping);
8370 void CheckSingleStepMode_SP(boolean murphy_is_waiting,
8371 boolean murphy_is_dropping)
8373 if (tape.single_step && tape.recording && !tape.pausing)
8374 if (murphy_is_waiting)
8375 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
8377 CheckSaveEngineSnapshot_SP(murphy_is_waiting, murphy_is_dropping);
8380 void getGraphicSource_SP(struct GraphicInfo_SP *g_sp,
8381 int graphic, int sync_frame, int x, int y)
8383 int frame = getGraphicAnimationFrame(graphic, sync_frame);
8385 getGraphicSource(graphic, frame, &g_sp->bitmap, &g_sp->src_x, &g_sp->src_y);
8388 boolean isNextAnimationFrame_SP(int graphic, int sync_frame)
8390 return (IS_NEXT_FRAME(sync_frame, graphic));
8393 int getGraphicInfo_Delay(int graphic)
8395 return graphic_info[graphic].anim_delay;
8398 void PlayMenuSoundExt(int sound)
8400 if (sound == SND_UNDEFINED)
8403 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8404 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8407 if (IS_LOOP_SOUND(sound))
8408 PlaySoundLoop(sound);
8413 void PlayMenuSound()
8415 PlayMenuSoundExt(menu.sound[game_status]);
8418 void PlayMenuSoundStereo(int sound, int stereo_position)
8420 if (sound == SND_UNDEFINED)
8423 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8424 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8427 if (IS_LOOP_SOUND(sound))
8428 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
8430 PlaySoundStereo(sound, stereo_position);
8433 void PlayMenuSoundIfLoopExt(int sound)
8435 if (sound == SND_UNDEFINED)
8438 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8439 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8442 if (IS_LOOP_SOUND(sound))
8443 PlaySoundLoop(sound);
8446 void PlayMenuSoundIfLoop()
8448 PlayMenuSoundIfLoopExt(menu.sound[game_status]);
8451 void PlayMenuMusicExt(int music)
8453 if (music == MUS_UNDEFINED)
8456 if (!setup.sound_music)
8462 void PlayMenuMusic()
8464 char *curr_music = getCurrentlyPlayingMusicFilename();
8465 char *next_music = getMusicListEntry(menu.music[game_status])->filename;
8467 if (!strEqual(curr_music, next_music))
8468 PlayMenuMusicExt(menu.music[game_status]);
8471 void PlayMenuSoundsAndMusic()
8477 static void FadeMenuSounds()
8482 static void FadeMenuMusic()
8484 char *curr_music = getCurrentlyPlayingMusicFilename();
8485 char *next_music = getMusicListEntry(menu.music[game_status])->filename;
8487 if (!strEqual(curr_music, next_music))
8491 void FadeMenuSoundsAndMusic()
8497 void PlaySoundActivating()
8500 PlaySound(SND_MENU_ITEM_ACTIVATING);
8504 void PlaySoundSelecting()
8507 PlaySound(SND_MENU_ITEM_SELECTING);
8511 void ToggleFullscreenOrChangeWindowScalingIfNeeded()
8513 boolean change_fullscreen = (setup.fullscreen !=
8514 video.fullscreen_enabled);
8515 boolean change_window_scaling_percent = (!video.fullscreen_enabled &&
8516 setup.window_scaling_percent !=
8517 video.window_scaling_percent);
8519 if (change_window_scaling_percent && video.fullscreen_enabled)
8522 if (!change_window_scaling_percent && !video.fullscreen_available)
8525 #if defined(TARGET_SDL2)
8526 if (change_window_scaling_percent)
8528 SDLSetWindowScaling(setup.window_scaling_percent);
8532 else if (change_fullscreen)
8534 SDLSetWindowFullscreen(setup.fullscreen);
8536 /* set setup value according to successfully changed fullscreen mode */
8537 setup.fullscreen = video.fullscreen_enabled;
8543 if (change_fullscreen ||
8544 change_window_scaling_percent)
8546 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
8548 /* save backbuffer content which gets lost when toggling fullscreen mode */
8549 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8551 if (change_window_scaling_percent)
8553 /* keep window mode, but change window scaling */
8554 video.fullscreen_enabled = TRUE; /* force new window scaling */
8557 /* toggle fullscreen */
8558 ChangeVideoModeIfNeeded(setup.fullscreen);
8560 /* set setup value according to successfully changed fullscreen mode */
8561 setup.fullscreen = video.fullscreen_enabled;
8563 /* restore backbuffer content from temporary backbuffer backup bitmap */
8564 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8566 FreeBitmap(tmp_backbuffer);
8568 /* update visible window/screen */
8569 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8573 void JoinRectangles(int *x, int *y, int *width, int *height,
8574 int x2, int y2, int width2, int height2)
8576 // do not join with "off-screen" rectangle
8577 if (x2 == -1 || y2 == -1)
8582 *width = MAX(*width, width2);
8583 *height = MAX(*height, height2);
8586 void SetAnimStatus(int anim_status_new)
8588 if (anim_status_new == GAME_MODE_MAIN)
8589 anim_status_new = GAME_MODE_PSEUDO_MAINONLY;
8590 else if (anim_status_new == GAME_MODE_SCORES)
8591 anim_status_new = GAME_MODE_PSEUDO_SCORESOLD;
8593 global.anim_status_next = anim_status_new;
8595 // directly set screen modes that are entered without fading
8596 if ((global.anim_status == GAME_MODE_PSEUDO_MAINONLY &&
8597 global.anim_status_next == GAME_MODE_PSEUDO_TYPENAME) ||
8598 (global.anim_status == GAME_MODE_PSEUDO_TYPENAME &&
8599 global.anim_status_next == GAME_MODE_PSEUDO_MAINONLY))
8600 global.anim_status = global.anim_status_next;
8603 void SetGameStatus(int game_status_new)
8605 if (game_status_new != game_status)
8606 game_status_last_screen = game_status;
8608 game_status = game_status_new;
8610 SetAnimStatus(game_status_new);
8613 void SetFontStatus(int game_status_new)
8615 static int last_game_status = -1;
8617 if (game_status_new != -1)
8619 // set game status for font use after storing last game status
8620 last_game_status = game_status;
8621 game_status = game_status_new;
8625 // reset game status after font use from last stored game status
8626 game_status = last_game_status;
8630 void ResetFontStatus()
8635 void ChangeViewportPropertiesIfNeeded()
8637 int gfx_game_mode = game_status;
8638 int gfx_game_mode2 = (game_status == GAME_MODE_EDITOR ? GAME_MODE_DEFAULT :
8640 struct RectWithBorder *vp_window = &viewport.window[gfx_game_mode];
8641 struct RectWithBorder *vp_playfield = &viewport.playfield[gfx_game_mode];
8642 struct RectWithBorder *vp_door_1 = &viewport.door_1[gfx_game_mode];
8643 struct RectWithBorder *vp_door_2 = &viewport.door_2[gfx_game_mode2];
8644 struct RectWithBorder *vp_door_3 = &viewport.door_2[GAME_MODE_EDITOR];
8645 int new_win_xsize = vp_window->width;
8646 int new_win_ysize = vp_window->height;
8647 int border_size = vp_playfield->border_size;
8648 int new_sx = vp_playfield->x + border_size;
8649 int new_sy = vp_playfield->y + border_size;
8650 int new_sxsize = vp_playfield->width - 2 * border_size;
8651 int new_sysize = vp_playfield->height - 2 * border_size;
8652 int new_real_sx = vp_playfield->x;
8653 int new_real_sy = vp_playfield->y;
8654 int new_full_sxsize = vp_playfield->width;
8655 int new_full_sysize = vp_playfield->height;
8656 int new_dx = vp_door_1->x;
8657 int new_dy = vp_door_1->y;
8658 int new_dxsize = vp_door_1->width;
8659 int new_dysize = vp_door_1->height;
8660 int new_vx = vp_door_2->x;
8661 int new_vy = vp_door_2->y;
8662 int new_vxsize = vp_door_2->width;
8663 int new_vysize = vp_door_2->height;
8664 int new_ex = vp_door_3->x;
8665 int new_ey = vp_door_3->y;
8666 int new_exsize = vp_door_3->width;
8667 int new_eysize = vp_door_3->height;
8668 int new_tilesize_var =
8669 (setup.small_game_graphics ? MINI_TILESIZE : game.tile_size);
8671 int tilesize = (gfx_game_mode == GAME_MODE_PLAYING ? new_tilesize_var :
8672 gfx_game_mode == GAME_MODE_EDITOR ? MINI_TILESIZE : TILESIZE);
8673 int new_scr_fieldx = new_sxsize / tilesize;
8674 int new_scr_fieldy = new_sysize / tilesize;
8675 int new_scr_fieldx_buffers = new_sxsize / new_tilesize_var;
8676 int new_scr_fieldy_buffers = new_sysize / new_tilesize_var;
8677 boolean init_gfx_buffers = FALSE;
8678 boolean init_video_buffer = FALSE;
8679 boolean init_gadgets_and_anims = FALSE;
8680 boolean init_em_graphics = FALSE;
8682 if (new_win_xsize != WIN_XSIZE ||
8683 new_win_ysize != WIN_YSIZE)
8685 WIN_XSIZE = new_win_xsize;
8686 WIN_YSIZE = new_win_ysize;
8688 init_video_buffer = TRUE;
8689 init_gfx_buffers = TRUE;
8690 init_gadgets_and_anims = TRUE;
8692 // printf("::: video: init_video_buffer, init_gfx_buffers\n");
8695 if (new_scr_fieldx != SCR_FIELDX ||
8696 new_scr_fieldy != SCR_FIELDY)
8698 /* this always toggles between MAIN and GAME when using small tile size */
8700 SCR_FIELDX = new_scr_fieldx;
8701 SCR_FIELDY = new_scr_fieldy;
8703 // printf("::: new_scr_fieldx != SCR_FIELDX ...\n");
8714 new_sxsize != SXSIZE ||
8715 new_sysize != SYSIZE ||
8716 new_dxsize != DXSIZE ||
8717 new_dysize != DYSIZE ||
8718 new_vxsize != VXSIZE ||
8719 new_vysize != VYSIZE ||
8720 new_exsize != EXSIZE ||
8721 new_eysize != EYSIZE ||
8722 new_real_sx != REAL_SX ||
8723 new_real_sy != REAL_SY ||
8724 new_full_sxsize != FULL_SXSIZE ||
8725 new_full_sysize != FULL_SYSIZE ||
8726 new_tilesize_var != TILESIZE_VAR
8729 // ------------------------------------------------------------------------
8730 // determine next fading area for changed viewport definitions
8731 // ------------------------------------------------------------------------
8733 // start with current playfield area (default fading area)
8736 FADE_SXSIZE = FULL_SXSIZE;
8737 FADE_SYSIZE = FULL_SYSIZE;
8739 // add new playfield area if position or size has changed
8740 if (new_real_sx != REAL_SX || new_real_sy != REAL_SY ||
8741 new_full_sxsize != FULL_SXSIZE || new_full_sysize != FULL_SYSIZE)
8743 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
8744 new_real_sx, new_real_sy, new_full_sxsize,new_full_sysize);
8747 // add current and new door 1 area if position or size has changed
8748 if (new_dx != DX || new_dy != DY ||
8749 new_dxsize != DXSIZE || new_dysize != DYSIZE)
8751 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
8752 DX, DY, DXSIZE, DYSIZE);
8753 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
8754 new_dx, new_dy, new_dxsize, new_dysize);
8757 // add current and new door 2 area if position or size has changed
8758 if (new_dx != VX || new_dy != VY ||
8759 new_dxsize != VXSIZE || new_dysize != VYSIZE)
8761 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
8762 VX, VY, VXSIZE, VYSIZE);
8763 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
8764 new_vx, new_vy, new_vxsize, new_vysize);
8767 // ------------------------------------------------------------------------
8768 // handle changed tile size
8769 // ------------------------------------------------------------------------
8771 if (new_tilesize_var != TILESIZE_VAR)
8773 // printf("::: new_tilesize_var != TILESIZE_VAR\n");
8775 // changing tile size invalidates scroll values of engine snapshots
8776 FreeEngineSnapshotSingle();
8778 // changing tile size requires update of graphic mapping for EM engine
8779 init_em_graphics = TRUE;
8790 SXSIZE = new_sxsize;
8791 SYSIZE = new_sysize;
8792 DXSIZE = new_dxsize;
8793 DYSIZE = new_dysize;
8794 VXSIZE = new_vxsize;
8795 VYSIZE = new_vysize;
8796 EXSIZE = new_exsize;
8797 EYSIZE = new_eysize;
8798 REAL_SX = new_real_sx;
8799 REAL_SY = new_real_sy;
8800 FULL_SXSIZE = new_full_sxsize;
8801 FULL_SYSIZE = new_full_sysize;
8802 TILESIZE_VAR = new_tilesize_var;
8804 init_gfx_buffers = TRUE;
8805 init_gadgets_and_anims = TRUE;
8807 // printf("::: viewports: init_gfx_buffers\n");
8808 // printf("::: viewports: init_gadgets_and_anims\n");
8811 if (init_gfx_buffers)
8813 // printf("::: init_gfx_buffers\n");
8815 SCR_FIELDX = new_scr_fieldx_buffers;
8816 SCR_FIELDY = new_scr_fieldy_buffers;
8820 SCR_FIELDX = new_scr_fieldx;
8821 SCR_FIELDY = new_scr_fieldy;
8823 SetDrawDeactivationMask(REDRAW_NONE);
8824 SetDrawBackgroundMask(REDRAW_FIELD);
8827 if (init_video_buffer)
8829 // printf("::: init_video_buffer\n");
8831 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
8832 InitImageTextures();
8835 if (init_gadgets_and_anims)
8837 // printf("::: init_gadgets_and_anims\n");
8840 InitGlobalAnimations();
8843 if (init_em_graphics)
8845 InitGraphicInfo_EM();