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 static int getLevelFromScreenX_MM(int sx)
363 int level_xsize = level.native_mm_level->fieldx;
364 int full_xsize = level_xsize * TILESIZE_VAR;
366 sx -= (full_xsize < SXSIZE ? (SXSIZE - full_xsize) / 2 : 0);
369 int lx = (px + TILESIZE_VAR) / TILESIZE_VAR - 1;
374 static int getLevelFromScreenY_MM(int sy)
376 int level_ysize = level.native_mm_level->fieldy;
377 int full_ysize = level_ysize * TILESIZE_VAR;
379 sy -= (full_ysize < SYSIZE ? (SYSIZE - full_ysize) / 2 : 0);
382 int ly = (py + TILESIZE_VAR) / TILESIZE_VAR - 1;
387 int getLevelFromScreenX(int x)
389 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
390 return getLevelFromScreenX_EM(x);
391 if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
392 return getLevelFromScreenX_SP(x);
393 if (level.game_engine_type == GAME_ENGINE_TYPE_MM)
394 return getLevelFromScreenX_MM(x);
396 return getLevelFromScreenX_RND(x);
399 int getLevelFromScreenY(int y)
401 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
402 return getLevelFromScreenY_EM(y);
403 if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
404 return getLevelFromScreenY_SP(y);
405 if (level.game_engine_type == GAME_ENGINE_TYPE_MM)
406 return getLevelFromScreenY_MM(y);
408 return getLevelFromScreenY_RND(y);
411 void DumpTile(int x, int y)
417 printf_line("-", 79);
418 printf("Field Info: SCREEN(%d, %d), LEVEL(%d, %d)\n", sx, sy, x, y);
419 printf_line("-", 79);
421 if (!IN_LEV_FIELD(x, y))
423 printf("(not in level field)\n");
429 token_name = element_info[Feld[x][y]].token_name;
431 printf(" Feld: %d\t['%s']\n", Feld[x][y], token_name);
432 printf(" Back: %s\n", print_if_not_empty(Back[x][y]));
433 printf(" Store: %s\n", print_if_not_empty(Store[x][y]));
434 printf(" Store2: %s\n", print_if_not_empty(Store2[x][y]));
435 printf(" StorePlayer: %s\n", print_if_not_empty(StorePlayer[x][y]));
436 printf(" MovPos: %d\n", MovPos[x][y]);
437 printf(" MovDir: %d\n", MovDir[x][y]);
438 printf(" MovDelay: %d\n", MovDelay[x][y]);
439 printf(" ChangeDelay: %d\n", ChangeDelay[x][y]);
440 printf(" CustomValue: %d\n", CustomValue[x][y]);
441 printf(" GfxElement: %d\n", GfxElement[x][y]);
442 printf(" GfxAction: %d\n", GfxAction[x][y]);
443 printf(" GfxFrame: %d [%d]\n", GfxFrame[x][y], FrameCounter);
444 printf(" Player x/y: %d, %d\n", local_player->jx, local_player->jy);
448 void DumpTileFromScreen(int sx, int sy)
450 int lx = getLevelFromScreenX(sx);
451 int ly = getLevelFromScreenY(sy);
456 void SetDrawtoField(int mode)
458 if (mode == DRAW_TO_FIELDBUFFER)
464 BX2 = SCR_FIELDX + 1;
465 BY2 = SCR_FIELDY + 1;
467 drawto_field = fieldbuffer;
469 else /* DRAW_TO_BACKBUFFER */
475 BX2 = SCR_FIELDX - 1;
476 BY2 = SCR_FIELDY - 1;
478 drawto_field = backbuffer;
482 static void RedrawPlayfield_RND()
484 if (game.envelope_active)
487 DrawLevel(REDRAW_ALL);
491 void RedrawPlayfield()
493 if (game_status != GAME_MODE_PLAYING)
496 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
497 RedrawPlayfield_EM(TRUE);
498 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
499 RedrawPlayfield_SP(TRUE);
500 else if (level.game_engine_type == GAME_ENGINE_TYPE_MM)
501 RedrawPlayfield_MM();
502 else if (level.game_engine_type == GAME_ENGINE_TYPE_RND)
503 RedrawPlayfield_RND();
505 BlitScreenToBitmap(backbuffer);
507 BlitBitmap(drawto, window, gfx.sx, gfx.sy, gfx.sxsize, gfx.sysize,
511 static void DrawMaskedBorderExt_Rect(int x, int y, int width, int height,
514 Bitmap *src_bitmap = getGlobalBorderBitmapFromStatus(global.border_status);
515 Bitmap *dst_bitmap = gfx.masked_border_bitmap_ptr;
517 if (x == -1 && y == -1)
520 if (draw_target == DRAW_TO_SCREEN)
521 BlitToScreenMasked(src_bitmap, x, y, width, height, x, y);
523 BlitBitmapMasked(src_bitmap, dst_bitmap, x, y, width, height, x, y);
526 static void DrawMaskedBorderExt_FIELD(int draw_target)
528 if (global.border_status >= GAME_MODE_MAIN &&
529 global.border_status <= GAME_MODE_PLAYING &&
530 border.draw_masked[global.border_status])
531 DrawMaskedBorderExt_Rect(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
535 static void DrawMaskedBorderExt_DOOR_1(int draw_target)
537 // when drawing to backbuffer, never draw border over open doors
538 if (draw_target == DRAW_TO_BACKBUFFER &&
539 (GetDoorState() & DOOR_OPEN_1))
542 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
543 (global.border_status != GAME_MODE_EDITOR ||
544 border.draw_masked[GFX_SPECIAL_ARG_EDITOR]))
545 DrawMaskedBorderExt_Rect(DX, DY, DXSIZE, DYSIZE, draw_target);
548 static void DrawMaskedBorderExt_DOOR_2(int draw_target)
550 // when drawing to backbuffer, never draw border over open doors
551 if (draw_target == DRAW_TO_BACKBUFFER &&
552 (GetDoorState() & DOOR_OPEN_2))
555 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
556 global.border_status != GAME_MODE_EDITOR)
557 DrawMaskedBorderExt_Rect(VX, VY, VXSIZE, VYSIZE, draw_target);
560 static void DrawMaskedBorderExt_DOOR_3(int draw_target)
562 /* currently not available */
565 static void DrawMaskedBorderExt_ALL(int draw_target)
567 DrawMaskedBorderExt_FIELD(draw_target);
568 DrawMaskedBorderExt_DOOR_1(draw_target);
569 DrawMaskedBorderExt_DOOR_2(draw_target);
570 DrawMaskedBorderExt_DOOR_3(draw_target);
573 static void DrawMaskedBorderExt(int redraw_mask, int draw_target)
575 /* never draw masked screen borders on borderless screens */
576 if (global.border_status == GAME_MODE_LOADING ||
577 global.border_status == GAME_MODE_TITLE)
580 if (redraw_mask & REDRAW_ALL)
581 DrawMaskedBorderExt_ALL(draw_target);
584 if (redraw_mask & REDRAW_FIELD)
585 DrawMaskedBorderExt_FIELD(draw_target);
586 if (redraw_mask & REDRAW_DOOR_1)
587 DrawMaskedBorderExt_DOOR_1(draw_target);
588 if (redraw_mask & REDRAW_DOOR_2)
589 DrawMaskedBorderExt_DOOR_2(draw_target);
590 if (redraw_mask & REDRAW_DOOR_3)
591 DrawMaskedBorderExt_DOOR_3(draw_target);
595 void DrawMaskedBorder_FIELD()
597 DrawMaskedBorderExt_FIELD(DRAW_TO_BACKBUFFER);
600 void DrawMaskedBorder(int redraw_mask)
602 DrawMaskedBorderExt(redraw_mask, DRAW_TO_BACKBUFFER);
605 void DrawMaskedBorderToTarget(int draw_target)
607 if (draw_target == DRAW_TO_BACKBUFFER ||
608 draw_target == DRAW_TO_SCREEN)
610 DrawMaskedBorderExt(REDRAW_ALL, draw_target);
614 int last_border_status = global.border_status;
616 if (draw_target == DRAW_TO_FADE_SOURCE)
618 global.border_status = gfx.fade_border_source_status;
619 gfx.masked_border_bitmap_ptr = gfx.fade_bitmap_source;
621 else if (draw_target == DRAW_TO_FADE_TARGET)
623 global.border_status = gfx.fade_border_target_status;
624 gfx.masked_border_bitmap_ptr = gfx.fade_bitmap_target;
627 DrawMaskedBorderExt(REDRAW_ALL, draw_target);
629 global.border_status = last_border_status;
630 gfx.masked_border_bitmap_ptr = backbuffer;
634 void DrawTileCursor(int draw_target)
640 int graphic = IMG_GLOBAL_TILE_CURSOR;
642 int tilesize = TILESIZE_VAR;
643 int width = tilesize;
644 int height = tilesize;
646 if (game_status != GAME_MODE_PLAYING)
649 if (!tile_cursor.enabled ||
653 if (tile_cursor.moving)
655 int step = TILESIZE_VAR / 4;
656 int dx = tile_cursor.target_x - tile_cursor.x;
657 int dy = tile_cursor.target_y - tile_cursor.y;
660 tile_cursor.x = tile_cursor.target_x;
662 tile_cursor.x += SIGN(dx) * step;
665 tile_cursor.y = tile_cursor.target_y;
667 tile_cursor.y += SIGN(dy) * step;
669 if (tile_cursor.x == tile_cursor.target_x &&
670 tile_cursor.y == tile_cursor.target_y)
671 tile_cursor.moving = FALSE;
674 dst_x = tile_cursor.x;
675 dst_y = tile_cursor.y;
677 frame = getGraphicAnimationFrame(graphic, -1);
679 getSizedGraphicSource(graphic, frame, tilesize, &src_bitmap, &src_x, &src_y);
682 (draw_target == DRAW_TO_FADE_SOURCE ? gfx.fade_bitmap_source :
683 draw_target == DRAW_TO_FADE_TARGET ? gfx.fade_bitmap_target : NULL);
685 if (draw_target == DRAW_TO_SCREEN)
686 BlitToScreenMasked(src_bitmap, src_x, src_y, width, height, dst_x, dst_y);
688 BlitBitmapMasked(src_bitmap, fade_bitmap, src_x, src_y, width, height,
692 void BlitScreenToBitmap_RND(Bitmap *target_bitmap)
694 int fx = getFieldbufferOffsetX_RND();
695 int fy = getFieldbufferOffsetY_RND();
697 BlitBitmap(drawto_field, target_bitmap, fx, fy, SXSIZE, SYSIZE, SX, SY);
700 void BlitScreenToBitmap(Bitmap *target_bitmap)
702 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
703 BlitScreenToBitmap_EM(target_bitmap);
704 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
705 BlitScreenToBitmap_SP(target_bitmap);
706 else if (level.game_engine_type == GAME_ENGINE_TYPE_MM)
707 BlitScreenToBitmap_MM(target_bitmap);
708 else if (level.game_engine_type == GAME_ENGINE_TYPE_RND)
709 BlitScreenToBitmap_RND(target_bitmap);
711 redraw_mask |= REDRAW_FIELD;
714 void DrawFramesPerSecond()
717 int font_nr = FONT_TEXT_2;
718 int font_width = getFontWidth(font_nr);
719 int draw_deactivation_mask = GetDrawDeactivationMask();
720 boolean draw_masked = (draw_deactivation_mask == REDRAW_NONE);
722 /* draw FPS with leading space (needed if field buffer deactivated) */
723 sprintf(text, " %04.1f fps", global.frames_per_second);
725 /* override draw deactivation mask (required for invisible warp mode) */
726 SetDrawDeactivationMask(REDRAW_NONE);
728 /* draw opaque FPS if field buffer deactivated, else draw masked FPS */
729 DrawTextExt(backbuffer, SX + SXSIZE - font_width * strlen(text), SY, text,
730 font_nr, (draw_masked ? BLIT_MASKED : BLIT_OPAQUE));
732 /* set draw deactivation mask to previous value */
733 SetDrawDeactivationMask(draw_deactivation_mask);
735 /* force full-screen redraw in this frame */
736 redraw_mask = REDRAW_ALL;
740 static void PrintFrameTimeDebugging()
742 static unsigned int last_counter = 0;
743 unsigned int counter = Counter();
744 int diff_1 = counter - last_counter;
745 int diff_2 = diff_1 - GAME_FRAME_DELAY;
747 int diff_2_cut = MIN(ABS(diff_2), diff_2_max);
748 char diff_bar[2 * diff_2_max + 5];
752 diff_bar[pos++] = (diff_2 < -diff_2_max ? '<' : ' ');
754 for (i = 0; i < diff_2_max; i++)
755 diff_bar[pos++] = (diff_2 >= 0 ? ' ' :
756 i >= diff_2_max - diff_2_cut ? '-' : ' ');
758 diff_bar[pos++] = '|';
760 for (i = 0; i < diff_2_max; i++)
761 diff_bar[pos++] = (diff_2 <= 0 ? ' ' : i < diff_2_cut ? '+' : ' ');
763 diff_bar[pos++] = (diff_2 > diff_2_max ? '>' : ' ');
765 diff_bar[pos++] = '\0';
767 Error(ERR_INFO, "%06d [%02d] [%c%02d] %s",
770 (diff_2 < 0 ? '-' : diff_2 > 0 ? '+' : ' '), ABS(diff_2),
773 last_counter = counter;
777 static int unifiedRedrawMask(int mask)
779 if (mask & REDRAW_ALL)
782 if (mask & REDRAW_FIELD && mask & REDRAW_DOORS)
788 static boolean equalRedrawMasks(int mask_1, int mask_2)
790 return unifiedRedrawMask(mask_1) == unifiedRedrawMask(mask_2);
795 static int last_redraw_mask = REDRAW_NONE;
797 // force screen redraw in every frame to continue drawing global animations
798 // (but always use the last redraw mask to prevent unwanted side effects)
799 if (redraw_mask == REDRAW_NONE)
800 redraw_mask = last_redraw_mask;
802 last_redraw_mask = redraw_mask;
805 // masked border now drawn immediately when blitting backbuffer to window
807 // draw masked border to all viewports, if defined
808 DrawMaskedBorder(redraw_mask);
811 // draw frames per second (only if debug mode is enabled)
812 if (redraw_mask & REDRAW_FPS)
813 DrawFramesPerSecond();
815 // remove playfield redraw before potentially merging with doors redraw
816 if (DrawingDeactivated(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE))
817 redraw_mask &= ~REDRAW_FIELD;
819 // redraw complete window if both playfield and (some) doors need redraw
820 if (redraw_mask & REDRAW_FIELD && redraw_mask & REDRAW_DOORS)
821 redraw_mask = REDRAW_ALL;
823 /* although redrawing the whole window would be fine for normal gameplay,
824 being able to only redraw the playfield is required for deactivating
825 certain drawing areas (mainly playfield) to work, which is needed for
826 warp-forward to be fast enough (by skipping redraw of most frames) */
828 if (redraw_mask & REDRAW_ALL)
830 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
832 else if (redraw_mask & REDRAW_FIELD)
834 BlitBitmap(backbuffer, window,
835 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
837 else if (redraw_mask & REDRAW_DOORS)
839 // merge door areas to prevent calling screen redraw more than once
845 if (redraw_mask & REDRAW_DOOR_1)
849 x2 = MAX(x2, DX + DXSIZE);
850 y2 = MAX(y2, DY + DYSIZE);
853 if (redraw_mask & REDRAW_DOOR_2)
857 x2 = MAX(x2, VX + VXSIZE);
858 y2 = MAX(y2, VY + VYSIZE);
861 if (redraw_mask & REDRAW_DOOR_3)
865 x2 = MAX(x2, EX + EXSIZE);
866 y2 = MAX(y2, EY + EYSIZE);
869 // make sure that at least one pixel is blitted, and inside the screen
870 // (else nothing is blitted, causing the animations not to be updated)
871 x1 = MIN(MAX(0, x1), WIN_XSIZE - 1);
872 y1 = MIN(MAX(0, y1), WIN_YSIZE - 1);
873 x2 = MIN(MAX(1, x2), WIN_XSIZE);
874 y2 = MIN(MAX(1, y2), WIN_YSIZE);
876 BlitBitmap(backbuffer, window, x1, y1, x2 - x1, y2 - y1, x1, y1);
879 redraw_mask = REDRAW_NONE;
882 PrintFrameTimeDebugging();
886 void BackToFront_WithFrameDelay(unsigned int frame_delay_value)
888 unsigned int frame_delay_value_old = GetVideoFrameDelay();
890 SetVideoFrameDelay(frame_delay_value);
894 SetVideoFrameDelay(frame_delay_value_old);
897 static int fade_type_skip = FADE_TYPE_NONE;
899 static void FadeExt(int fade_mask, int fade_mode, int fade_type)
901 void (*draw_border_function)(void) = NULL;
902 int x, y, width, height;
903 int fade_delay, post_delay;
905 if (fade_type == FADE_TYPE_FADE_OUT)
907 if (fade_type_skip != FADE_TYPE_NONE)
909 /* skip all fade operations until specified fade operation */
910 if (fade_type & fade_type_skip)
911 fade_type_skip = FADE_TYPE_NONE;
916 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
920 redraw_mask |= fade_mask;
922 if (fade_type == FADE_TYPE_SKIP)
924 fade_type_skip = fade_mode;
929 fade_delay = fading.fade_delay;
930 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
932 if (fade_type_skip != FADE_TYPE_NONE)
934 /* skip all fade operations until specified fade operation */
935 if (fade_type & fade_type_skip)
936 fade_type_skip = FADE_TYPE_NONE;
941 if (global.autoplay_leveldir)
946 if (fade_mask == REDRAW_FIELD)
951 height = FADE_SYSIZE;
953 if (border.draw_masked_when_fading)
954 draw_border_function = DrawMaskedBorder_FIELD; /* update when fading */
956 DrawMaskedBorder_FIELD(); /* draw once */
958 else /* REDRAW_ALL */
966 if (!setup.fade_screens ||
968 fading.fade_mode == FADE_MODE_NONE)
970 if (fade_mode == FADE_MODE_FADE_OUT)
973 BlitBitmap(backbuffer, window, x, y, width, height, x, y);
975 redraw_mask &= ~fade_mask;
980 FadeRectangle(x, y, width, height, fade_mode, fade_delay, post_delay,
981 draw_border_function);
983 redraw_mask &= ~fade_mask;
986 static void SetScreenStates_BeforeFadingIn()
988 // temporarily set screen mode for animations to screen after fading in
989 global.anim_status = global.anim_status_next;
991 // store backbuffer with all animations that will be started after fading in
992 if (fade_type_skip != FADE_MODE_SKIP_FADE_IN)
993 PrepareFadeBitmap(DRAW_TO_FADE_TARGET);
995 // set screen mode for animations back to fading
996 global.anim_status = GAME_MODE_PSEUDO_FADING;
999 static void SetScreenStates_AfterFadingIn()
1001 // store new source screen (to use correct masked border for fading)
1002 gfx.fade_border_source_status = global.border_status;
1004 global.anim_status = global.anim_status_next;
1007 static void SetScreenStates_BeforeFadingOut()
1009 // store new target screen (to use correct masked border for fading)
1010 gfx.fade_border_target_status = game_status;
1012 // set screen mode for animations to fading
1013 global.anim_status = GAME_MODE_PSEUDO_FADING;
1015 // store backbuffer with all animations that will be stopped for fading out
1016 if (fade_type_skip != FADE_MODE_SKIP_FADE_OUT)
1017 PrepareFadeBitmap(DRAW_TO_FADE_SOURCE);
1020 static void SetScreenStates_AfterFadingOut()
1022 global.border_status = game_status;
1025 void FadeIn(int fade_mask)
1027 SetScreenStates_BeforeFadingIn();
1030 DrawMaskedBorder(REDRAW_ALL);
1033 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
1034 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_IN);
1036 FadeExt(fade_mask, FADE_MODE_FADE_IN, FADE_TYPE_FADE_IN);
1040 FADE_SXSIZE = FULL_SXSIZE;
1041 FADE_SYSIZE = FULL_SYSIZE;
1043 if (game_status == GAME_MODE_PLAYING &&
1044 strEqual(setup.touch.control_type, TOUCH_CONTROL_VIRTUAL_BUTTONS))
1045 SetOverlayActive(TRUE);
1047 SetScreenStates_AfterFadingIn();
1049 // force update of global animation status in case of rapid screen changes
1050 redraw_mask = REDRAW_ALL;
1054 void FadeOut(int fade_mask)
1056 // update screen if areas covered by "fade_mask" and "redraw_mask" differ
1057 if (!equalRedrawMasks(fade_mask, redraw_mask))
1060 SetScreenStates_BeforeFadingOut();
1062 SetTileCursorActive(FALSE);
1063 SetOverlayActive(FALSE);
1066 DrawMaskedBorder(REDRAW_ALL);
1069 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
1070 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_OUT);
1072 FadeExt(fade_mask, FADE_MODE_FADE_OUT, FADE_TYPE_FADE_OUT);
1074 SetScreenStates_AfterFadingOut();
1077 static void FadeSetLeaveNext(struct TitleFadingInfo fading_leave, boolean set)
1079 static struct TitleFadingInfo fading_leave_stored;
1082 fading_leave_stored = fading_leave;
1084 fading = fading_leave_stored;
1087 void FadeSetEnterMenu()
1089 fading = menu.enter_menu;
1091 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
1094 void FadeSetLeaveMenu()
1096 fading = menu.leave_menu;
1098 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
1101 void FadeSetEnterScreen()
1103 fading = menu.enter_screen[game_status];
1105 FadeSetLeaveNext(menu.leave_screen[game_status], TRUE); /* store */
1108 void FadeSetNextScreen()
1110 fading = menu.next_screen[game_status];
1112 // (do not overwrite fade mode set by FadeSetEnterScreen)
1113 // FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
1116 void FadeSetLeaveScreen()
1118 FadeSetLeaveNext(menu.leave_screen[game_status], FALSE); /* recall */
1121 void FadeSetFromType(int type)
1123 if (type & TYPE_ENTER_SCREEN)
1124 FadeSetEnterScreen();
1125 else if (type & TYPE_ENTER)
1127 else if (type & TYPE_LEAVE)
1131 void FadeSetDisabled()
1133 static struct TitleFadingInfo fading_none = { FADE_MODE_NONE, -1, -1, -1 };
1135 fading = fading_none;
1138 void FadeSkipNextFadeIn()
1140 FadeExt(0, FADE_MODE_SKIP_FADE_IN, FADE_TYPE_SKIP);
1143 void FadeSkipNextFadeOut()
1145 FadeExt(0, FADE_MODE_SKIP_FADE_OUT, FADE_TYPE_SKIP);
1148 Bitmap *getBitmapFromGraphicOrDefault(int graphic, int default_graphic)
1150 boolean redefined = getImageListEntryFromImageID(graphic)->redefined;
1152 return (graphic == IMG_UNDEFINED ? NULL :
1153 graphic_info[graphic].bitmap != NULL || redefined ?
1154 graphic_info[graphic].bitmap :
1155 graphic_info[default_graphic].bitmap);
1158 Bitmap *getBackgroundBitmap(int graphic)
1160 return getBitmapFromGraphicOrDefault(graphic, IMG_BACKGROUND);
1163 Bitmap *getGlobalBorderBitmap(int graphic)
1165 return getBitmapFromGraphicOrDefault(graphic, IMG_GLOBAL_BORDER);
1168 Bitmap *getGlobalBorderBitmapFromStatus(int status)
1171 (status == GAME_MODE_MAIN ||
1172 status == GAME_MODE_PSEUDO_TYPENAME ? IMG_GLOBAL_BORDER_MAIN :
1173 status == GAME_MODE_SCORES ? IMG_GLOBAL_BORDER_SCORES :
1174 status == GAME_MODE_EDITOR ? IMG_GLOBAL_BORDER_EDITOR :
1175 status == GAME_MODE_PLAYING ? IMG_GLOBAL_BORDER_PLAYING :
1178 return getGlobalBorderBitmap(graphic);
1181 void SetWindowBackgroundImageIfDefined(int graphic)
1183 if (graphic_info[graphic].bitmap)
1184 SetWindowBackgroundBitmap(graphic_info[graphic].bitmap);
1187 void SetMainBackgroundImageIfDefined(int graphic)
1189 if (graphic_info[graphic].bitmap)
1190 SetMainBackgroundBitmap(graphic_info[graphic].bitmap);
1193 void SetDoorBackgroundImageIfDefined(int graphic)
1195 if (graphic_info[graphic].bitmap)
1196 SetDoorBackgroundBitmap(graphic_info[graphic].bitmap);
1199 void SetWindowBackgroundImage(int graphic)
1201 SetWindowBackgroundBitmap(getBackgroundBitmap(graphic));
1204 void SetMainBackgroundImage(int graphic)
1206 SetMainBackgroundBitmap(getBackgroundBitmap(graphic));
1209 void SetDoorBackgroundImage(int graphic)
1211 SetDoorBackgroundBitmap(getBackgroundBitmap(graphic));
1214 void SetPanelBackground()
1216 struct GraphicInfo *gfx = &graphic_info[IMG_BACKGROUND_PANEL];
1218 BlitBitmapTiled(gfx->bitmap, bitmap_db_panel, gfx->src_x, gfx->src_y,
1219 gfx->width, gfx->height, 0, 0, DXSIZE, DYSIZE);
1221 SetDoorBackgroundBitmap(bitmap_db_panel);
1224 void DrawBackground(int x, int y, int width, int height)
1226 /* "drawto" might still point to playfield buffer here (hall of fame) */
1227 ClearRectangleOnBackground(backbuffer, x, y, width, height);
1229 if (IN_GFX_FIELD_FULL(x, y))
1230 redraw_mask |= REDRAW_FIELD;
1231 else if (IN_GFX_DOOR_1(x, y))
1232 redraw_mask |= REDRAW_DOOR_1;
1233 else if (IN_GFX_DOOR_2(x, y))
1234 redraw_mask |= REDRAW_DOOR_2;
1235 else if (IN_GFX_DOOR_3(x, y))
1236 redraw_mask |= REDRAW_DOOR_3;
1239 void DrawBackgroundForFont(int x, int y, int width, int height, int font_nr)
1241 struct FontBitmapInfo *font = getFontBitmapInfo(font_nr);
1243 if (font->bitmap == NULL)
1246 DrawBackground(x, y, width, height);
1249 void DrawBackgroundForGraphic(int x, int y, int width, int height, int graphic)
1251 struct GraphicInfo *g = &graphic_info[graphic];
1253 if (g->bitmap == NULL)
1256 DrawBackground(x, y, width, height);
1259 static int game_status_last = -1;
1260 static Bitmap *global_border_bitmap_last = NULL;
1261 static Bitmap *global_border_bitmap = NULL;
1262 static int real_sx_last = -1, real_sy_last = -1;
1263 static int full_sxsize_last = -1, full_sysize_last = -1;
1264 static int dx_last = -1, dy_last = -1;
1265 static int dxsize_last = -1, dysize_last = -1;
1266 static int vx_last = -1, vy_last = -1;
1267 static int vxsize_last = -1, vysize_last = -1;
1268 static int ex_last = -1, ey_last = -1;
1269 static int exsize_last = -1, eysize_last = -1;
1271 boolean CheckIfGlobalBorderHasChanged()
1273 // if game status has not changed, global border has not changed either
1274 if (game_status == game_status_last)
1277 // determine and store new global border bitmap for current game status
1278 global_border_bitmap = getGlobalBorderBitmapFromStatus(game_status);
1280 return (global_border_bitmap_last != global_border_bitmap);
1283 boolean CheckIfGlobalBorderRedrawIsNeeded()
1285 // if game status has not changed, nothing has to be redrawn
1286 if (game_status == game_status_last)
1289 // redraw if last screen was title screen
1290 if (game_status_last == GAME_MODE_TITLE)
1293 // redraw if global screen border has changed
1294 if (CheckIfGlobalBorderHasChanged())
1297 // redraw if position or size of playfield area has changed
1298 if (real_sx_last != REAL_SX || real_sy_last != REAL_SY ||
1299 full_sxsize_last != FULL_SXSIZE || full_sysize_last != FULL_SYSIZE)
1302 // redraw if position or size of door area has changed
1303 if (dx_last != DX || dy_last != DY ||
1304 dxsize_last != DXSIZE || dysize_last != DYSIZE)
1307 // redraw if position or size of tape area has changed
1308 if (vx_last != VX || vy_last != VY ||
1309 vxsize_last != VXSIZE || vysize_last != VYSIZE)
1312 // redraw if position or size of editor area has changed
1313 if (ex_last != EX || ey_last != EY ||
1314 exsize_last != EXSIZE || eysize_last != EYSIZE)
1320 void RedrawGlobalBorderFromBitmap(Bitmap *bitmap)
1323 BlitBitmap(bitmap, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
1325 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
1328 void RedrawGlobalBorder()
1330 Bitmap *bitmap = getGlobalBorderBitmapFromStatus(game_status);
1332 RedrawGlobalBorderFromBitmap(bitmap);
1334 redraw_mask = REDRAW_ALL;
1337 #define ONLY_REDRAW_GLOBAL_BORDER_IF_NEEDED 0
1339 static void RedrawGlobalBorderIfNeeded()
1341 #if ONLY_REDRAW_GLOBAL_BORDER_IF_NEEDED
1342 if (game_status == game_status_last)
1346 // copy current draw buffer to later copy back areas that have not changed
1347 if (game_status_last != GAME_MODE_TITLE)
1348 BlitBitmap(backbuffer, bitmap_db_store_1, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
1350 #if ONLY_REDRAW_GLOBAL_BORDER_IF_NEEDED
1351 if (CheckIfGlobalBorderRedrawIsNeeded())
1354 // redraw global screen border (or clear, if defined to be empty)
1355 RedrawGlobalBorderFromBitmap(global_border_bitmap);
1357 if (game_status == GAME_MODE_EDITOR)
1358 DrawSpecialEditorDoor();
1360 // copy previous playfield and door areas, if they are defined on both
1361 // previous and current screen and if they still have the same size
1363 if (real_sx_last != -1 && real_sy_last != -1 &&
1364 REAL_SX != -1 && REAL_SY != -1 &&
1365 full_sxsize_last == FULL_SXSIZE && full_sysize_last == FULL_SYSIZE)
1366 BlitBitmap(bitmap_db_store_1, backbuffer,
1367 real_sx_last, real_sy_last, FULL_SXSIZE, FULL_SYSIZE,
1370 if (dx_last != -1 && dy_last != -1 &&
1371 DX != -1 && DY != -1 &&
1372 dxsize_last == DXSIZE && dysize_last == DYSIZE)
1373 BlitBitmap(bitmap_db_store_1, backbuffer,
1374 dx_last, dy_last, DXSIZE, DYSIZE, DX, DY);
1376 if (game_status != GAME_MODE_EDITOR)
1378 if (vx_last != -1 && vy_last != -1 &&
1379 VX != -1 && VY != -1 &&
1380 vxsize_last == VXSIZE && vysize_last == VYSIZE)
1381 BlitBitmap(bitmap_db_store_1, backbuffer,
1382 vx_last, vy_last, VXSIZE, VYSIZE, VX, VY);
1386 if (ex_last != -1 && ey_last != -1 &&
1387 EX != -1 && EY != -1 &&
1388 exsize_last == EXSIZE && eysize_last == EYSIZE)
1389 BlitBitmap(bitmap_db_store_1, backbuffer,
1390 ex_last, ey_last, EXSIZE, EYSIZE, EX, EY);
1393 redraw_mask = REDRAW_ALL;
1396 game_status_last = game_status;
1398 global_border_bitmap_last = global_border_bitmap;
1400 real_sx_last = REAL_SX;
1401 real_sy_last = REAL_SY;
1402 full_sxsize_last = FULL_SXSIZE;
1403 full_sysize_last = FULL_SYSIZE;
1406 dxsize_last = DXSIZE;
1407 dysize_last = DYSIZE;
1410 vxsize_last = VXSIZE;
1411 vysize_last = VYSIZE;
1414 exsize_last = EXSIZE;
1415 eysize_last = EYSIZE;
1420 RedrawGlobalBorderIfNeeded();
1422 /* !!! "drawto" might still point to playfield buffer here (see above) !!! */
1423 /* (when entering hall of fame after playing) */
1424 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
1426 /* !!! maybe this should be done before clearing the background !!! */
1427 if (game_status == GAME_MODE_PLAYING)
1429 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
1430 SetDrawtoField(DRAW_TO_FIELDBUFFER);
1434 SetDrawtoField(DRAW_TO_BACKBUFFER);
1438 void MarkTileDirty(int x, int y)
1440 redraw_mask |= REDRAW_FIELD;
1443 void SetBorderElement()
1447 BorderElement = EL_EMPTY;
1449 /* the MM game engine does not use a visible border element */
1450 if (level.game_engine_type == GAME_ENGINE_TYPE_MM)
1453 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
1455 for (x = 0; x < lev_fieldx; x++)
1457 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
1458 BorderElement = EL_STEELWALL;
1460 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
1466 void FloodFillLevelExt(int from_x, int from_y, int fill_element,
1467 int max_array_fieldx, int max_array_fieldy,
1468 short field[max_array_fieldx][max_array_fieldy],
1469 int max_fieldx, int max_fieldy)
1473 static int check[4][2] = { { -1, 0 }, { 0, -1 }, { 1, 0 }, { 0, 1 } };
1474 static int safety = 0;
1476 /* check if starting field still has the desired content */
1477 if (field[from_x][from_y] == fill_element)
1482 if (safety > max_fieldx * max_fieldy)
1483 Error(ERR_EXIT, "Something went wrong in 'FloodFill()'. Please debug.");
1485 old_element = field[from_x][from_y];
1486 field[from_x][from_y] = fill_element;
1488 for (i = 0; i < 4; i++)
1490 x = from_x + check[i][0];
1491 y = from_y + check[i][1];
1493 if (IN_FIELD(x, y, max_fieldx, max_fieldy) && field[x][y] == old_element)
1494 FloodFillLevelExt(x, y, fill_element, max_array_fieldx, max_array_fieldy,
1495 field, max_fieldx, max_fieldy);
1501 void FloodFillLevel(int from_x, int from_y, int fill_element,
1502 short field[MAX_LEV_FIELDX][MAX_LEV_FIELDY],
1503 int max_fieldx, int max_fieldy)
1505 FloodFillLevelExt(from_x, from_y, fill_element,
1506 MAX_LEV_FIELDX, MAX_LEV_FIELDY, field,
1507 max_fieldx, max_fieldy);
1510 void SetRandomAnimationValue(int x, int y)
1512 gfx.anim_random_frame = GfxRandom[x][y];
1515 int getGraphicAnimationFrame(int graphic, int sync_frame)
1517 /* animation synchronized with global frame counter, not move position */
1518 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
1519 sync_frame = FrameCounter;
1521 return getAnimationFrame(graphic_info[graphic].anim_frames,
1522 graphic_info[graphic].anim_delay,
1523 graphic_info[graphic].anim_mode,
1524 graphic_info[graphic].anim_start_frame,
1528 void getGraphicSourceBitmap(int graphic, int tilesize, Bitmap **bitmap)
1530 struct GraphicInfo *g = &graphic_info[graphic];
1531 int tilesize_capped = MIN(MAX(1, tilesize), TILESIZE);
1533 if (tilesize == gfx.standard_tile_size)
1534 *bitmap = g->bitmaps[IMG_BITMAP_STANDARD];
1535 else if (tilesize == game.tile_size)
1536 *bitmap = g->bitmaps[IMG_BITMAP_GAME];
1538 *bitmap = g->bitmaps[IMG_BITMAP_1x1 - log_2(tilesize_capped)];
1541 void getGraphicSourceXY(int graphic, int frame, int *x, int *y,
1542 boolean get_backside)
1544 struct GraphicInfo *g = &graphic_info[graphic];
1545 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
1546 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
1548 if (g->offset_y == 0) /* frames are ordered horizontally */
1550 int max_width = g->anim_frames_per_line * g->width;
1551 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
1553 *x = pos % max_width;
1554 *y = src_y % g->height + pos / max_width * g->height;
1556 else if (g->offset_x == 0) /* frames are ordered vertically */
1558 int max_height = g->anim_frames_per_line * g->height;
1559 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
1561 *x = src_x % g->width + pos / max_height * g->width;
1562 *y = pos % max_height;
1564 else /* frames are ordered diagonally */
1566 *x = src_x + frame * g->offset_x;
1567 *y = src_y + frame * g->offset_y;
1571 void getSizedGraphicSourceExt(int graphic, int frame, int tilesize,
1572 Bitmap **bitmap, int *x, int *y,
1573 boolean get_backside)
1575 struct GraphicInfo *g = &graphic_info[graphic];
1577 // if no graphics defined at all, use fallback graphics
1578 if (g->bitmaps == NULL)
1579 *g = graphic_info[IMG_CHAR_EXCLAM];
1581 // if no in-game graphics defined, always use standard graphic size
1582 if (g->bitmaps[IMG_BITMAP_GAME] == NULL)
1583 tilesize = TILESIZE;
1585 getGraphicSourceBitmap(graphic, tilesize, bitmap);
1586 getGraphicSourceXY(graphic, frame, x, y, get_backside);
1588 *x = *x * tilesize / g->tile_size;
1589 *y = *y * tilesize / g->tile_size;
1592 void getSizedGraphicSource(int graphic, int frame, int tilesize,
1593 Bitmap **bitmap, int *x, int *y)
1595 getSizedGraphicSourceExt(graphic, frame, tilesize, bitmap, x, y, FALSE);
1598 void getFixedGraphicSource(int graphic, int frame,
1599 Bitmap **bitmap, int *x, int *y)
1601 getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y, FALSE);
1604 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1606 getSizedGraphicSource(graphic, 0, MINI_TILESIZE, bitmap, x, y);
1609 inline static void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1610 int *x, int *y, boolean get_backside)
1612 getSizedGraphicSourceExt(graphic, frame, TILESIZE_VAR, bitmap, x, y,
1616 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
1618 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
1621 void DrawGraphic(int x, int y, int graphic, int frame)
1624 if (!IN_SCR_FIELD(x, y))
1626 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1627 printf("DrawGraphic(): This should never happen!\n");
1632 DrawGraphicExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR, graphic,
1635 MarkTileDirty(x, y);
1638 void DrawFixedGraphic(int x, int y, int graphic, int frame)
1641 if (!IN_SCR_FIELD(x, y))
1643 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1644 printf("DrawGraphic(): This should never happen!\n");
1649 DrawFixedGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic,
1651 MarkTileDirty(x, y);
1654 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1660 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1662 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX_VAR, TILEY_VAR, x, y);
1665 void DrawFixedGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1671 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1672 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
1675 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
1678 if (!IN_SCR_FIELD(x, y))
1680 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1681 printf("DrawGraphicThruMask(): This should never happen!\n");
1686 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
1689 MarkTileDirty(x, y);
1692 void DrawFixedGraphicThruMask(int x, int y, int graphic, int frame)
1695 if (!IN_SCR_FIELD(x, y))
1697 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1698 printf("DrawGraphicThruMask(): This should never happen!\n");
1703 DrawFixedGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
1705 MarkTileDirty(x, y);
1708 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
1714 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1716 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX_VAR, TILEY_VAR,
1720 void DrawFixedGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y,
1721 int graphic, int frame)
1726 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1728 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY,
1732 void DrawSizedGraphic(int x, int y, int graphic, int frame, int tilesize)
1734 DrawSizedGraphicExt(drawto, SX + x * tilesize, SY + y * tilesize, graphic,
1736 MarkTileDirty(x / tilesize, y / tilesize);
1739 void DrawSizedGraphicThruMask(int x, int y, int graphic, int frame,
1742 DrawSizedGraphicThruMaskExt(drawto, SX + x * tilesize, SY + y * tilesize,
1743 graphic, frame, tilesize);
1744 MarkTileDirty(x / tilesize, y / tilesize);
1747 void DrawSizedGraphicExt(DrawBuffer *d, int x, int y, int graphic, int frame,
1753 getSizedGraphicSource(graphic, frame, tilesize, &src_bitmap, &src_x, &src_y);
1754 BlitBitmap(src_bitmap, d, src_x, src_y, tilesize, tilesize, x, y);
1757 void DrawSizedGraphicThruMaskExt(DrawBuffer *d, int x, int y, int graphic,
1758 int frame, int tilesize)
1763 getSizedGraphicSource(graphic, frame, tilesize, &src_bitmap, &src_x, &src_y);
1764 BlitBitmapMasked(src_bitmap, d, src_x, src_y, tilesize, tilesize, x, y);
1767 void DrawMiniGraphic(int x, int y, int graphic)
1769 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
1770 MarkTileDirty(x / 2, y / 2);
1773 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
1778 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1779 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
1782 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
1783 int graphic, int frame,
1784 int cut_mode, int mask_mode)
1789 int width = TILEX, height = TILEY;
1792 if (dx || dy) /* shifted graphic */
1794 if (x < BX1) /* object enters playfield from the left */
1801 else if (x > BX2) /* object enters playfield from the right */
1807 else if (x == BX1 && dx < 0) /* object leaves playfield to the left */
1813 else if (x == BX2 && dx > 0) /* object leaves playfield to the right */
1815 else if (dx) /* general horizontal movement */
1816 MarkTileDirty(x + SIGN(dx), y);
1818 if (y < BY1) /* object enters playfield from the top */
1820 if (cut_mode == CUT_BELOW) /* object completely above top border */
1828 else if (y > BY2) /* object enters playfield from the bottom */
1834 else if (y == BY1 && dy < 0) /* object leaves playfield to the top */
1840 else if (dy > 0 && cut_mode == CUT_ABOVE)
1842 if (y == BY2) /* object completely above bottom border */
1848 MarkTileDirty(x, y + 1);
1849 } /* object leaves playfield to the bottom */
1850 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1852 else if (dy) /* general vertical movement */
1853 MarkTileDirty(x, y + SIGN(dy));
1857 if (!IN_SCR_FIELD(x, y))
1859 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1860 printf("DrawGraphicShifted(): This should never happen!\n");
1865 width = width * TILESIZE_VAR / TILESIZE;
1866 height = height * TILESIZE_VAR / TILESIZE;
1867 cx = cx * TILESIZE_VAR / TILESIZE;
1868 cy = cy * TILESIZE_VAR / TILESIZE;
1869 dx = dx * TILESIZE_VAR / TILESIZE;
1870 dy = dy * TILESIZE_VAR / TILESIZE;
1872 if (width > 0 && height > 0)
1874 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1879 dst_x = FX + x * TILEX_VAR + dx;
1880 dst_y = FY + y * TILEY_VAR + dy;
1882 if (mask_mode == USE_MASKING)
1883 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1886 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1889 MarkTileDirty(x, y);
1893 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
1894 int graphic, int frame,
1895 int cut_mode, int mask_mode)
1900 int width = TILEX_VAR, height = TILEY_VAR;
1903 int x2 = x + SIGN(dx);
1904 int y2 = y + SIGN(dy);
1906 /* movement with two-tile animations must be sync'ed with movement position,
1907 not with current GfxFrame (which can be higher when using slow movement) */
1908 int anim_pos = (dx ? ABS(dx) : ABS(dy));
1909 int anim_frames = graphic_info[graphic].anim_frames;
1911 /* (we also need anim_delay here for movement animations with less frames) */
1912 int anim_delay = graphic_info[graphic].anim_delay;
1913 int sync_frame = anim_pos * anim_frames * anim_delay / TILESIZE;
1915 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
1916 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
1918 /* re-calculate animation frame for two-tile movement animation */
1919 frame = getGraphicAnimationFrame(graphic, sync_frame);
1921 /* check if movement start graphic inside screen area and should be drawn */
1922 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
1924 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
1926 dst_x = FX + x1 * TILEX_VAR;
1927 dst_y = FY + y1 * TILEY_VAR;
1929 if (mask_mode == USE_MASKING)
1930 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1933 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1936 MarkTileDirty(x1, y1);
1939 /* check if movement end graphic inside screen area and should be drawn */
1940 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
1942 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
1944 dst_x = FX + x2 * TILEX_VAR;
1945 dst_y = FY + y2 * TILEY_VAR;
1947 if (mask_mode == USE_MASKING)
1948 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1951 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1954 MarkTileDirty(x2, y2);
1958 static void DrawGraphicShifted(int x, int y, int dx, int dy,
1959 int graphic, int frame,
1960 int cut_mode, int mask_mode)
1964 DrawGraphic(x, y, graphic, frame);
1969 if (graphic_info[graphic].double_movement) /* EM style movement images */
1970 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1972 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1975 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1976 int frame, int cut_mode)
1978 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
1981 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1982 int cut_mode, int mask_mode)
1984 int lx = LEVELX(x), ly = LEVELY(y);
1988 if (IN_LEV_FIELD(lx, ly))
1990 SetRandomAnimationValue(lx, ly);
1992 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
1993 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1995 /* do not use double (EM style) movement graphic when not moving */
1996 if (graphic_info[graphic].double_movement && !dx && !dy)
1998 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
1999 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
2002 else /* border element */
2004 graphic = el2img(element);
2005 frame = getGraphicAnimationFrame(graphic, -1);
2008 if (element == EL_EXPANDABLE_WALL)
2010 boolean left_stopped = FALSE, right_stopped = FALSE;
2012 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
2013 left_stopped = TRUE;
2014 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
2015 right_stopped = TRUE;
2017 if (left_stopped && right_stopped)
2019 else if (left_stopped)
2021 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
2022 frame = graphic_info[graphic].anim_frames - 1;
2024 else if (right_stopped)
2026 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
2027 frame = graphic_info[graphic].anim_frames - 1;
2032 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
2033 else if (mask_mode == USE_MASKING)
2034 DrawGraphicThruMask(x, y, graphic, frame);
2036 DrawGraphic(x, y, graphic, frame);
2039 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
2040 int cut_mode, int mask_mode)
2042 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2043 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
2044 cut_mode, mask_mode);
2047 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
2050 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
2053 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
2056 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
2059 void DrawLevelElementThruMask(int x, int y, int element)
2061 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
2064 void DrawLevelFieldThruMask(int x, int y)
2066 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
2069 /* !!! implementation of quicksand is totally broken !!! */
2070 #define IS_CRUMBLED_TILE(x, y, e) \
2071 (GFX_CRUMBLED(e) && (!IN_LEV_FIELD(x, y) || \
2072 !IS_MOVING(x, y) || \
2073 (e) == EL_QUICKSAND_EMPTYING || \
2074 (e) == EL_QUICKSAND_FAST_EMPTYING))
2076 static void DrawLevelFieldCrumbledInnerCorners(int x, int y, int dx, int dy,
2081 int width, height, cx, cy;
2082 int sx = SCREENX(x), sy = SCREENY(y);
2083 int crumbled_border_size = graphic_info[graphic].border_size;
2084 int crumbled_tile_size = graphic_info[graphic].tile_size;
2085 int crumbled_border_size_var =
2086 crumbled_border_size * TILESIZE_VAR / crumbled_tile_size;
2089 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
2091 for (i = 1; i < 4; i++)
2093 int dxx = (i & 1 ? dx : 0);
2094 int dyy = (i & 2 ? dy : 0);
2097 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
2100 /* check if neighbour field is of same crumble type */
2101 boolean same = (IS_CRUMBLED_TILE(xx, yy, element) &&
2102 graphic_info[graphic].class ==
2103 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class);
2105 /* return if check prevents inner corner */
2106 if (same == (dxx == dx && dyy == dy))
2110 /* if we reach this point, we have an inner corner */
2112 getGraphicSource(graphic, 1, &src_bitmap, &src_x, &src_y);
2114 width = crumbled_border_size_var;
2115 height = crumbled_border_size_var;
2116 cx = (dx > 0 ? TILESIZE_VAR - width : 0);
2117 cy = (dy > 0 ? TILESIZE_VAR - height : 0);
2119 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
2120 width, height, FX + sx * TILEX_VAR + cx, FY + sy * TILEY_VAR + cy);
2123 static void DrawLevelFieldCrumbledBorders(int x, int y, int graphic, int frame,
2128 int width, height, bx, by, cx, cy;
2129 int sx = SCREENX(x), sy = SCREENY(y);
2130 int crumbled_border_size = graphic_info[graphic].border_size;
2131 int crumbled_tile_size = graphic_info[graphic].tile_size;
2132 int crumbled_border_size_var =
2133 crumbled_border_size * TILESIZE_VAR / crumbled_tile_size;
2134 int crumbled_border_pos_var = TILESIZE_VAR - crumbled_border_size_var;
2137 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
2139 /* draw simple, sloppy, non-corner-accurate crumbled border */
2141 width = (dir == 1 || dir == 2 ? crumbled_border_size_var : TILESIZE_VAR);
2142 height = (dir == 0 || dir == 3 ? crumbled_border_size_var : TILESIZE_VAR);
2143 cx = (dir == 2 ? crumbled_border_pos_var : 0);
2144 cy = (dir == 3 ? crumbled_border_pos_var : 0);
2146 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy, width, height,
2147 FX + sx * TILEX_VAR + cx,
2148 FY + sy * TILEY_VAR + cy);
2150 /* (remaining middle border part must be at least as big as corner part) */
2151 if (!(graphic_info[graphic].style & STYLE_ACCURATE_BORDERS) ||
2152 crumbled_border_size_var >= TILESIZE_VAR / 3)
2155 /* correct corners of crumbled border, if needed */
2157 for (i = -1; i <= 1; i += 2)
2159 int xx = x + (dir == 0 || dir == 3 ? i : 0);
2160 int yy = y + (dir == 1 || dir == 2 ? i : 0);
2161 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
2164 /* check if neighbour field is of same crumble type */
2165 if (IS_CRUMBLED_TILE(xx, yy, element) &&
2166 graphic_info[graphic].class ==
2167 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
2169 /* no crumbled corner, but continued crumbled border */
2171 int c1 = (dir == 2 || dir == 3 ? crumbled_border_pos_var : 0);
2172 int c2 = (i == 1 ? crumbled_border_pos_var : 0);
2173 int b1 = (i == 1 ? crumbled_border_size_var :
2174 TILESIZE_VAR - 2 * crumbled_border_size_var);
2176 width = crumbled_border_size_var;
2177 height = crumbled_border_size_var;
2179 if (dir == 1 || dir == 2)
2194 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
2196 FX + sx * TILEX_VAR + cx,
2197 FY + sy * TILEY_VAR + cy);
2202 static void DrawLevelFieldCrumbledExt(int x, int y, int graphic, int frame)
2204 int sx = SCREENX(x), sy = SCREENY(y);
2207 static int xy[4][2] =
2215 if (!IN_LEV_FIELD(x, y))
2218 element = TILE_GFX_ELEMENT(x, y);
2220 if (IS_CRUMBLED_TILE(x, y, element)) /* crumble field itself */
2222 if (!IN_SCR_FIELD(sx, sy))
2225 /* crumble field borders towards direct neighbour fields */
2226 for (i = 0; i < 4; i++)
2228 int xx = x + xy[i][0];
2229 int yy = y + xy[i][1];
2231 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
2234 /* check if neighbour field is of same crumble type */
2235 if (IS_CRUMBLED_TILE(xx, yy, element) &&
2236 graphic_info[graphic].class ==
2237 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
2240 DrawLevelFieldCrumbledBorders(x, y, graphic, frame, i);
2243 /* crumble inner field corners towards corner neighbour fields */
2244 if ((graphic_info[graphic].style & STYLE_INNER_CORNERS) &&
2245 graphic_info[graphic].anim_frames == 2)
2247 for (i = 0; i < 4; i++)
2249 int dx = (i & 1 ? +1 : -1);
2250 int dy = (i & 2 ? +1 : -1);
2252 DrawLevelFieldCrumbledInnerCorners(x, y, dx, dy, graphic);
2256 MarkTileDirty(sx, sy);
2258 else /* center field is not crumbled -- crumble neighbour fields */
2260 /* crumble field borders of direct neighbour fields */
2261 for (i = 0; i < 4; i++)
2263 int xx = x + xy[i][0];
2264 int yy = y + xy[i][1];
2265 int sxx = sx + xy[i][0];
2266 int syy = sy + xy[i][1];
2268 if (!IN_LEV_FIELD(xx, yy) ||
2269 !IN_SCR_FIELD(sxx, syy))
2272 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
2275 element = TILE_GFX_ELEMENT(xx, yy);
2277 if (!IS_CRUMBLED_TILE(xx, yy, element))
2280 graphic = el_act2crm(element, ACTION_DEFAULT);
2282 DrawLevelFieldCrumbledBorders(xx, yy, graphic, 0, 3 - i);
2284 MarkTileDirty(sxx, syy);
2287 /* crumble inner field corners of corner neighbour fields */
2288 for (i = 0; i < 4; i++)
2290 int dx = (i & 1 ? +1 : -1);
2291 int dy = (i & 2 ? +1 : -1);
2297 if (!IN_LEV_FIELD(xx, yy) ||
2298 !IN_SCR_FIELD(sxx, syy))
2301 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
2304 element = TILE_GFX_ELEMENT(xx, yy);
2306 if (!IS_CRUMBLED_TILE(xx, yy, element))
2309 graphic = el_act2crm(element, ACTION_DEFAULT);
2311 if ((graphic_info[graphic].style & STYLE_INNER_CORNERS) &&
2312 graphic_info[graphic].anim_frames == 2)
2313 DrawLevelFieldCrumbledInnerCorners(xx, yy, -dx, -dy, graphic);
2315 MarkTileDirty(sxx, syy);
2320 void DrawLevelFieldCrumbled(int x, int y)
2324 if (!IN_LEV_FIELD(x, y))
2327 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
2328 GfxElement[x][y] != EL_UNDEFINED &&
2329 GFX_CRUMBLED(GfxElement[x][y]))
2331 DrawLevelFieldCrumbledDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
2336 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
2338 DrawLevelFieldCrumbledExt(x, y, graphic, 0);
2341 void DrawLevelFieldCrumbledDigging(int x, int y, int direction,
2344 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
2345 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
2346 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
2347 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
2348 int sx = SCREENX(x), sy = SCREENY(y);
2350 DrawGraphic(sx, sy, graphic1, frame1);
2351 DrawLevelFieldCrumbledExt(x, y, graphic2, frame2);
2354 void DrawLevelFieldCrumbledNeighbours(int x, int y)
2356 int sx = SCREENX(x), sy = SCREENY(y);
2357 static int xy[4][2] =
2366 /* crumble direct neighbour fields (required for field borders) */
2367 for (i = 0; i < 4; i++)
2369 int xx = x + xy[i][0];
2370 int yy = y + xy[i][1];
2371 int sxx = sx + xy[i][0];
2372 int syy = sy + xy[i][1];
2374 if (!IN_LEV_FIELD(xx, yy) ||
2375 !IN_SCR_FIELD(sxx, syy) ||
2376 !GFX_CRUMBLED(Feld[xx][yy]) ||
2380 DrawLevelField(xx, yy);
2383 /* crumble corner neighbour fields (required for inner field corners) */
2384 for (i = 0; i < 4; i++)
2386 int dx = (i & 1 ? +1 : -1);
2387 int dy = (i & 2 ? +1 : -1);
2393 if (!IN_LEV_FIELD(xx, yy) ||
2394 !IN_SCR_FIELD(sxx, syy) ||
2395 !GFX_CRUMBLED(Feld[xx][yy]) ||
2399 int element = TILE_GFX_ELEMENT(xx, yy);
2400 int graphic = el_act2crm(element, ACTION_DEFAULT);
2402 if ((graphic_info[graphic].style & STYLE_INNER_CORNERS) &&
2403 graphic_info[graphic].anim_frames == 2)
2404 DrawLevelField(xx, yy);
2408 static int getBorderElement(int x, int y)
2412 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
2413 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
2414 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
2415 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
2416 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
2417 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
2418 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
2420 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
2421 int steel_position = (x == -1 && y == -1 ? 0 :
2422 x == lev_fieldx && y == -1 ? 1 :
2423 x == -1 && y == lev_fieldy ? 2 :
2424 x == lev_fieldx && y == lev_fieldy ? 3 :
2425 x == -1 || x == lev_fieldx ? 4 :
2426 y == -1 || y == lev_fieldy ? 5 : 6);
2428 return border[steel_position][steel_type];
2431 void DrawScreenElement(int x, int y, int element)
2433 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
2434 DrawLevelFieldCrumbled(LEVELX(x), LEVELY(y));
2437 void DrawLevelElement(int x, int y, int element)
2439 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2440 DrawScreenElement(SCREENX(x), SCREENY(y), element);
2443 void DrawScreenField(int x, int y)
2445 int lx = LEVELX(x), ly = LEVELY(y);
2446 int element, content;
2448 if (!IN_LEV_FIELD(lx, ly))
2450 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
2453 element = getBorderElement(lx, ly);
2455 DrawScreenElement(x, y, element);
2460 element = Feld[lx][ly];
2461 content = Store[lx][ly];
2463 if (IS_MOVING(lx, ly))
2465 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
2466 boolean cut_mode = NO_CUTTING;
2468 if (element == EL_QUICKSAND_EMPTYING ||
2469 element == EL_QUICKSAND_FAST_EMPTYING ||
2470 element == EL_MAGIC_WALL_EMPTYING ||
2471 element == EL_BD_MAGIC_WALL_EMPTYING ||
2472 element == EL_DC_MAGIC_WALL_EMPTYING ||
2473 element == EL_AMOEBA_DROPPING)
2474 cut_mode = CUT_ABOVE;
2475 else if (element == EL_QUICKSAND_FILLING ||
2476 element == EL_QUICKSAND_FAST_FILLING ||
2477 element == EL_MAGIC_WALL_FILLING ||
2478 element == EL_BD_MAGIC_WALL_FILLING ||
2479 element == EL_DC_MAGIC_WALL_FILLING)
2480 cut_mode = CUT_BELOW;
2482 if (cut_mode == CUT_ABOVE)
2483 DrawScreenElement(x, y, element);
2485 DrawScreenElement(x, y, EL_EMPTY);
2488 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
2489 else if (cut_mode == NO_CUTTING)
2490 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
2493 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
2495 if (cut_mode == CUT_BELOW &&
2496 IN_LEV_FIELD(lx, ly + 1) && IN_SCR_FIELD(x, y + 1))
2497 DrawLevelElement(lx, ly + 1, element);
2500 if (content == EL_ACID)
2502 int dir = MovDir[lx][ly];
2503 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
2504 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
2506 DrawLevelElementThruMask(newlx, newly, EL_ACID);
2508 // prevent target field from being drawn again (but without masking)
2509 // (this would happen if target field is scanned after moving element)
2510 Stop[newlx][newly] = TRUE;
2513 else if (IS_BLOCKED(lx, ly))
2518 boolean cut_mode = NO_CUTTING;
2519 int element_old, content_old;
2521 Blocked2Moving(lx, ly, &oldx, &oldy);
2524 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
2525 MovDir[oldx][oldy] == MV_RIGHT);
2527 element_old = Feld[oldx][oldy];
2528 content_old = Store[oldx][oldy];
2530 if (element_old == EL_QUICKSAND_EMPTYING ||
2531 element_old == EL_QUICKSAND_FAST_EMPTYING ||
2532 element_old == EL_MAGIC_WALL_EMPTYING ||
2533 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
2534 element_old == EL_DC_MAGIC_WALL_EMPTYING ||
2535 element_old == EL_AMOEBA_DROPPING)
2536 cut_mode = CUT_ABOVE;
2538 DrawScreenElement(x, y, EL_EMPTY);
2541 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
2543 else if (cut_mode == NO_CUTTING)
2544 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
2547 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
2550 else if (IS_DRAWABLE(element))
2551 DrawScreenElement(x, y, element);
2553 DrawScreenElement(x, y, EL_EMPTY);
2556 void DrawLevelField(int x, int y)
2558 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2559 DrawScreenField(SCREENX(x), SCREENY(y));
2560 else if (IS_MOVING(x, y))
2564 Moving2Blocked(x, y, &newx, &newy);
2565 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
2566 DrawScreenField(SCREENX(newx), SCREENY(newy));
2568 else if (IS_BLOCKED(x, y))
2572 Blocked2Moving(x, y, &oldx, &oldy);
2573 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
2574 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
2578 static void DrawSizedWallExt_MM(int dst_x, int dst_y, int element, int tilesize,
2579 int (*el2img_function)(int), boolean masked,
2580 int element_bits_draw)
2582 int element_base = map_mm_wall_element(element);
2583 int element_bits = (IS_DF_WALL(element) ?
2584 element - EL_DF_WALL_START :
2585 IS_MM_WALL(element) ?
2586 element - EL_MM_WALL_START : EL_EMPTY) & 0x000f;
2587 int graphic = el2img_function(element_base);
2588 int tilesize_draw = tilesize / 2;
2593 getSizedGraphicSource(graphic, 0, tilesize_draw, &src_bitmap, &src_x, &src_y);
2595 for (i = 0; i < 4; i++)
2597 int dst_draw_x = dst_x + (i % 2) * tilesize_draw;
2598 int dst_draw_y = dst_y + (i / 2) * tilesize_draw;
2600 if (!(element_bits_draw & (1 << i)))
2603 if (element_bits & (1 << i))
2606 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y,
2607 tilesize_draw, tilesize_draw, dst_draw_x, dst_draw_y);
2609 BlitBitmap(src_bitmap, drawto, src_x, src_y,
2610 tilesize_draw, tilesize_draw, dst_draw_x, dst_draw_y);
2615 ClearRectangle(drawto, dst_draw_x, dst_draw_y,
2616 tilesize_draw, tilesize_draw);
2621 void DrawSizedWallParts_MM(int x, int y, int element, int tilesize,
2622 boolean masked, int element_bits_draw)
2624 DrawSizedWallExt_MM(SX + x * tilesize, SY + y * tilesize,
2625 element, tilesize, el2edimg, masked, element_bits_draw);
2628 void DrawSizedWall_MM(int dst_x, int dst_y, int element, int tilesize,
2629 int (*el2img_function)(int))
2631 DrawSizedWallExt_MM(dst_x, dst_y, element, tilesize, el2img_function, FALSE,
2635 void DrawSizedElementExt(int x, int y, int element, int tilesize,
2638 if (IS_MM_WALL(element))
2640 DrawSizedWallExt_MM(SX + x * tilesize, SY + y * tilesize,
2641 element, tilesize, el2edimg, masked, 0x000f);
2645 int graphic = el2edimg(element);
2648 DrawSizedGraphicThruMask(x, y, graphic, 0, tilesize);
2650 DrawSizedGraphic(x, y, graphic, 0, tilesize);
2654 void DrawSizedElement(int x, int y, int element, int tilesize)
2656 DrawSizedElementExt(x, y, element, tilesize, FALSE);
2659 void DrawSizedElementThruMask(int x, int y, int element, int tilesize)
2661 DrawSizedElementExt(x, y, element, tilesize, TRUE);
2664 void DrawMiniElement(int x, int y, int element)
2668 graphic = el2edimg(element);
2669 DrawMiniGraphic(x, y, graphic);
2672 void DrawSizedElementOrWall(int sx, int sy, int scroll_x, int scroll_y,
2675 int x = sx + scroll_x, y = sy + scroll_y;
2677 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
2678 DrawSizedElement(sx, sy, EL_EMPTY, tilesize);
2679 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
2680 DrawSizedElement(sx, sy, Feld[x][y], tilesize);
2682 DrawSizedGraphic(sx, sy, el2edimg(getBorderElement(x, y)), 0, tilesize);
2685 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
2687 int x = sx + scroll_x, y = sy + scroll_y;
2689 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
2690 DrawMiniElement(sx, sy, EL_EMPTY);
2691 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
2692 DrawMiniElement(sx, sy, Feld[x][y]);
2694 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
2697 void DrawEnvelopeBackgroundTiles(int graphic, int startx, int starty,
2698 int x, int y, int xsize, int ysize,
2699 int tile_width, int tile_height)
2703 int dst_x = startx + x * tile_width;
2704 int dst_y = starty + y * tile_height;
2705 int width = graphic_info[graphic].width;
2706 int height = graphic_info[graphic].height;
2707 int inner_width_raw = MAX(width - 2 * tile_width, tile_width);
2708 int inner_height_raw = MAX(height - 2 * tile_height, tile_height);
2709 int inner_width = inner_width_raw - (inner_width_raw % tile_width);
2710 int inner_height = inner_height_raw - (inner_height_raw % tile_height);
2711 int inner_sx = (width >= 3 * tile_width ? tile_width : 0);
2712 int inner_sy = (height >= 3 * tile_height ? tile_height : 0);
2713 boolean draw_masked = graphic_info[graphic].draw_masked;
2715 getFixedGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
2717 if (src_bitmap == NULL || width < tile_width || height < tile_height)
2719 ClearRectangle(drawto, dst_x, dst_y, tile_width, tile_height);
2723 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - tile_width :
2724 inner_sx + (x - 1) * tile_width % inner_width);
2725 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - tile_height :
2726 inner_sy + (y - 1) * tile_height % inner_height);
2729 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
2732 BlitBitmap(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
2736 void DrawEnvelopeBackground(int graphic, int startx, int starty,
2737 int x, int y, int xsize, int ysize, int font_nr)
2739 int font_width = getFontWidth(font_nr);
2740 int font_height = getFontHeight(font_nr);
2742 DrawEnvelopeBackgroundTiles(graphic, startx, starty, x, y, xsize, ysize,
2743 font_width, font_height);
2746 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
2748 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2749 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2750 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2751 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2752 boolean no_delay = (tape.warp_forward);
2753 unsigned int anim_delay = 0;
2754 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
2755 int anim_delay_value = MAX(1, (no_delay ? 0 : frame_delay_value) / 2);
2756 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
2757 int font_width = getFontWidth(font_nr);
2758 int font_height = getFontHeight(font_nr);
2759 int max_xsize = level.envelope[envelope_nr].xsize;
2760 int max_ysize = level.envelope[envelope_nr].ysize;
2761 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
2762 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
2763 int xend = max_xsize;
2764 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
2765 int xstep = (xstart < xend ? 1 : 0);
2766 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2768 int end = MAX(xend - xstart, yend - ystart);
2771 for (i = start; i <= end; i++)
2773 int last_frame = end; // last frame of this "for" loop
2774 int x = xstart + i * xstep;
2775 int y = ystart + i * ystep;
2776 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2777 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2778 int sx = SX + (SXSIZE - xsize * font_width) / 2;
2779 int sy = SY + (SYSIZE - ysize * font_height) / 2;
2782 SetDrawtoField(DRAW_TO_FIELDBUFFER);
2784 BlitScreenToBitmap(backbuffer);
2786 SetDrawtoField(DRAW_TO_BACKBUFFER);
2788 for (yy = 0; yy < ysize; yy++)
2789 for (xx = 0; xx < xsize; xx++)
2790 DrawEnvelopeBackground(graphic, sx, sy, xx, yy, xsize, ysize, font_nr);
2792 DrawTextBuffer(sx + font_width, sy + font_height,
2793 level.envelope[envelope_nr].text, font_nr, max_xsize,
2794 xsize - 2, ysize - 2, 0, mask_mode,
2795 level.envelope[envelope_nr].autowrap,
2796 level.envelope[envelope_nr].centered, FALSE);
2798 redraw_mask |= REDRAW_FIELD;
2801 SkipUntilDelayReached(&anim_delay, anim_delay_value, &i, last_frame);
2805 void ShowEnvelope(int envelope_nr)
2807 int element = EL_ENVELOPE_1 + envelope_nr;
2808 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2809 int sound_opening = element_info[element].sound[ACTION_OPENING];
2810 int sound_closing = element_info[element].sound[ACTION_CLOSING];
2811 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2812 boolean no_delay = (tape.warp_forward);
2813 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
2814 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
2815 int anim_mode = graphic_info[graphic].anim_mode;
2816 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2817 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2819 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
2821 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2823 if (anim_mode == ANIM_DEFAULT)
2824 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
2826 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
2829 Delay(wait_delay_value);
2831 WaitForEventToContinue();
2833 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2835 if (anim_mode != ANIM_NONE)
2836 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
2838 if (anim_mode == ANIM_DEFAULT)
2839 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
2841 game.envelope_active = FALSE;
2843 SetDrawtoField(DRAW_TO_FIELDBUFFER);
2845 redraw_mask |= REDRAW_FIELD;
2849 static void setRequestBasePosition(int *x, int *y)
2851 int sx_base, sy_base;
2853 if (request.x != -1)
2854 sx_base = request.x;
2855 else if (request.align == ALIGN_LEFT)
2857 else if (request.align == ALIGN_RIGHT)
2858 sx_base = SX + SXSIZE;
2860 sx_base = SX + SXSIZE / 2;
2862 if (request.y != -1)
2863 sy_base = request.y;
2864 else if (request.valign == VALIGN_TOP)
2866 else if (request.valign == VALIGN_BOTTOM)
2867 sy_base = SY + SYSIZE;
2869 sy_base = SY + SYSIZE / 2;
2875 static void setRequestPositionExt(int *x, int *y, int width, int height,
2876 boolean add_border_size)
2878 int border_size = request.border_size;
2879 int sx_base, sy_base;
2882 setRequestBasePosition(&sx_base, &sy_base);
2884 if (request.align == ALIGN_LEFT)
2886 else if (request.align == ALIGN_RIGHT)
2887 sx = sx_base - width;
2889 sx = sx_base - width / 2;
2891 if (request.valign == VALIGN_TOP)
2893 else if (request.valign == VALIGN_BOTTOM)
2894 sy = sy_base - height;
2896 sy = sy_base - height / 2;
2898 sx = MAX(0, MIN(sx, WIN_XSIZE - width));
2899 sy = MAX(0, MIN(sy, WIN_YSIZE - height));
2901 if (add_border_size)
2911 static void setRequestPosition(int *x, int *y, boolean add_border_size)
2913 setRequestPositionExt(x, y, request.width, request.height, add_border_size);
2916 void DrawEnvelopeRequest(char *text)
2918 char *text_final = text;
2919 char *text_door_style = NULL;
2920 int graphic = IMG_BACKGROUND_REQUEST;
2921 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2922 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2923 int font_nr = FONT_REQUEST;
2924 int font_width = getFontWidth(font_nr);
2925 int font_height = getFontHeight(font_nr);
2926 int border_size = request.border_size;
2927 int line_spacing = request.line_spacing;
2928 int line_height = font_height + line_spacing;
2929 int max_text_width = request.width - 2 * border_size;
2930 int max_text_height = request.height - 2 * border_size;
2931 int line_length = max_text_width / font_width;
2932 int max_lines = max_text_height / line_height;
2933 int text_width = line_length * font_width;
2934 int width = request.width;
2935 int height = request.height;
2936 int tile_size = MAX(request.step_offset, 1);
2937 int x_steps = width / tile_size;
2938 int y_steps = height / tile_size;
2939 int sx_offset = border_size;
2940 int sy_offset = border_size;
2944 if (request.centered)
2945 sx_offset = (request.width - text_width) / 2;
2947 if (request.wrap_single_words && !request.autowrap)
2949 char *src_text_ptr, *dst_text_ptr;
2951 text_door_style = checked_malloc(2 * strlen(text) + 1);
2953 src_text_ptr = text;
2954 dst_text_ptr = text_door_style;
2956 while (*src_text_ptr)
2958 if (*src_text_ptr == ' ' ||
2959 *src_text_ptr == '?' ||
2960 *src_text_ptr == '!')
2961 *dst_text_ptr++ = '\n';
2963 if (*src_text_ptr != ' ')
2964 *dst_text_ptr++ = *src_text_ptr;
2969 *dst_text_ptr = '\0';
2971 text_final = text_door_style;
2974 setRequestPosition(&sx, &sy, FALSE);
2976 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
2978 for (y = 0; y < y_steps; y++)
2979 for (x = 0; x < x_steps; x++)
2980 DrawEnvelopeBackgroundTiles(graphic, sx, sy,
2981 x, y, x_steps, y_steps,
2982 tile_size, tile_size);
2984 /* force DOOR font inside door area */
2985 SetFontStatus(GAME_MODE_PSEUDO_DOOR);
2987 DrawTextBuffer(sx + sx_offset, sy + sy_offset, text_final, font_nr,
2988 line_length, -1, max_lines, line_spacing, mask_mode,
2989 request.autowrap, request.centered, FALSE);
2993 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2994 RedrawGadget(tool_gadget[i]);
2996 // store readily prepared envelope request for later use when animating
2997 BlitBitmap(backbuffer, bitmap_db_store_2, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2999 if (text_door_style)
3000 free(text_door_style);
3003 void AnimateEnvelopeRequest(int anim_mode, int action)
3005 int graphic = IMG_BACKGROUND_REQUEST;
3006 boolean draw_masked = graphic_info[graphic].draw_masked;
3007 int delay_value_normal = request.step_delay;
3008 int delay_value_fast = delay_value_normal / 2;
3009 boolean ffwd_delay = (tape.playing && tape.fast_forward);
3010 boolean no_delay = (tape.warp_forward);
3011 int delay_value = (ffwd_delay ? delay_value_fast : delay_value_normal);
3012 int anim_delay_value = MAX(1, (no_delay ? 0 : delay_value + 500 * 0) / 2);
3013 unsigned int anim_delay = 0;
3015 int tile_size = MAX(request.step_offset, 1);
3016 int max_xsize = request.width / tile_size;
3017 int max_ysize = request.height / tile_size;
3018 int max_xsize_inner = max_xsize - 2;
3019 int max_ysize_inner = max_ysize - 2;
3021 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize_inner : 0);
3022 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize_inner : 0);
3023 int xend = max_xsize_inner;
3024 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize_inner : 0);
3025 int xstep = (xstart < xend ? 1 : 0);
3026 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
3028 int end = MAX(xend - xstart, yend - ystart);
3031 if (setup.quick_doors)
3038 for (i = start; i <= end; i++)
3040 int last_frame = end; // last frame of this "for" loop
3041 int x = xstart + i * xstep;
3042 int y = ystart + i * ystep;
3043 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
3044 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
3045 int xsize_size_left = (xsize - 1) * tile_size;
3046 int ysize_size_top = (ysize - 1) * tile_size;
3047 int max_xsize_pos = (max_xsize - 1) * tile_size;
3048 int max_ysize_pos = (max_ysize - 1) * tile_size;
3049 int width = xsize * tile_size;
3050 int height = ysize * tile_size;
3055 setRequestPosition(&src_x, &src_y, FALSE);
3056 setRequestPositionExt(&dst_x, &dst_y, width, height, FALSE);
3058 BlitBitmap(bitmap_db_store_1, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
3060 for (yy = 0; yy < 2; yy++)
3062 for (xx = 0; xx < 2; xx++)
3064 int src_xx = src_x + xx * max_xsize_pos;
3065 int src_yy = src_y + yy * max_ysize_pos;
3066 int dst_xx = dst_x + xx * xsize_size_left;
3067 int dst_yy = dst_y + yy * ysize_size_top;
3068 int xx_size = (xx ? tile_size : xsize_size_left);
3069 int yy_size = (yy ? tile_size : ysize_size_top);
3072 BlitBitmapMasked(bitmap_db_store_2, backbuffer,
3073 src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
3075 BlitBitmap(bitmap_db_store_2, backbuffer,
3076 src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
3080 redraw_mask |= REDRAW_FIELD;
3084 SkipUntilDelayReached(&anim_delay, anim_delay_value, &i, last_frame);
3088 void ShowEnvelopeRequest(char *text, unsigned int req_state, int action)
3090 int graphic = IMG_BACKGROUND_REQUEST;
3091 int sound_opening = SND_REQUEST_OPENING;
3092 int sound_closing = SND_REQUEST_CLOSING;
3093 int anim_mode_1 = request.anim_mode; /* (higher priority) */
3094 int anim_mode_2 = graphic_info[graphic].anim_mode; /* (lower priority) */
3095 int anim_mode = (anim_mode_1 != ANIM_DEFAULT ? anim_mode_1 : anim_mode_2);
3096 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
3097 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
3099 if (game_status == GAME_MODE_PLAYING)
3100 BlitScreenToBitmap(backbuffer);
3102 SetDrawtoField(DRAW_TO_BACKBUFFER);
3104 // SetDrawBackgroundMask(REDRAW_NONE);
3106 if (action == ACTION_OPENING)
3108 BlitBitmap(backbuffer, bitmap_db_store_1, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
3110 if (req_state & REQ_ASK)
3112 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
3113 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
3115 else if (req_state & REQ_CONFIRM)
3117 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
3119 else if (req_state & REQ_PLAYER)
3121 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
3122 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
3123 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
3124 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
3127 DrawEnvelopeRequest(text);
3130 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
3132 if (action == ACTION_OPENING)
3134 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
3136 if (anim_mode == ANIM_DEFAULT)
3137 AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_OPENING);
3139 AnimateEnvelopeRequest(main_anim_mode, ACTION_OPENING);
3143 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
3145 if (anim_mode != ANIM_NONE)
3146 AnimateEnvelopeRequest(main_anim_mode, ACTION_CLOSING);
3148 if (anim_mode == ANIM_DEFAULT)
3149 AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_CLOSING);
3152 game.envelope_active = FALSE;
3154 if (action == ACTION_CLOSING)
3155 BlitBitmap(bitmap_db_store_1, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
3157 // SetDrawBackgroundMask(last_draw_background_mask);
3159 redraw_mask |= REDRAW_FIELD;
3163 if (action == ACTION_CLOSING &&
3164 game_status == GAME_MODE_PLAYING &&
3165 level.game_engine_type == GAME_ENGINE_TYPE_RND)
3166 SetDrawtoField(DRAW_TO_FIELDBUFFER);
3169 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
3171 if (IS_MM_WALL(element))
3173 DrawSizedWall_MM(dst_x, dst_y, element, tilesize, el2preimg);
3179 int graphic = el2preimg(element);
3181 getSizedGraphicSource(graphic, 0, tilesize, &src_bitmap, &src_x, &src_y);
3182 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize,
3187 void DrawLevel(int draw_background_mask)
3191 SetMainBackgroundImage(IMG_BACKGROUND_PLAYING);
3192 SetDrawBackgroundMask(draw_background_mask);
3196 for (x = BX1; x <= BX2; x++)
3197 for (y = BY1; y <= BY2; y++)
3198 DrawScreenField(x, y);
3200 redraw_mask |= REDRAW_FIELD;
3203 void DrawSizedLevel(int size_x, int size_y, int scroll_x, int scroll_y,
3208 for (x = 0; x < size_x; x++)
3209 for (y = 0; y < size_y; y++)
3210 DrawSizedElementOrWall(x, y, scroll_x, scroll_y, tilesize);
3212 redraw_mask |= REDRAW_FIELD;
3215 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
3219 for (x = 0; x < size_x; x++)
3220 for (y = 0; y < size_y; y++)
3221 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
3223 redraw_mask |= REDRAW_FIELD;
3226 static void DrawPreviewLevelPlayfield(int from_x, int from_y)
3228 boolean show_level_border = (BorderElement != EL_EMPTY);
3229 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
3230 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
3231 int tile_size = preview.tile_size;
3232 int preview_width = preview.xsize * tile_size;
3233 int preview_height = preview.ysize * tile_size;
3234 int real_preview_xsize = MIN(level_xsize, preview.xsize);
3235 int real_preview_ysize = MIN(level_ysize, preview.ysize);
3236 int real_preview_width = real_preview_xsize * tile_size;
3237 int real_preview_height = real_preview_ysize * tile_size;
3238 int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
3239 int dst_y = SY + ALIGNED_YPOS(preview.y, preview_height, preview.valign);
3242 if (!IN_GFX_FIELD_FULL(dst_x, dst_y + preview_height - 1))
3245 DrawBackground(dst_x, dst_y, preview_width, preview_height);
3247 dst_x += (preview_width - real_preview_width) / 2;
3248 dst_y += (preview_height - real_preview_height) / 2;
3250 for (x = 0; x < real_preview_xsize; x++)
3252 for (y = 0; y < real_preview_ysize; y++)
3254 int lx = from_x + x + (show_level_border ? -1 : 0);
3255 int ly = from_y + y + (show_level_border ? -1 : 0);
3256 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
3257 getBorderElement(lx, ly));
3259 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
3260 element, tile_size);
3264 redraw_mask |= REDRAW_FIELD;
3267 #define MICROLABEL_EMPTY 0
3268 #define MICROLABEL_LEVEL_NAME 1
3269 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
3270 #define MICROLABEL_LEVEL_AUTHOR 3
3271 #define MICROLABEL_IMPORTED_FROM_HEAD 4
3272 #define MICROLABEL_IMPORTED_FROM 5
3273 #define MICROLABEL_IMPORTED_BY_HEAD 6
3274 #define MICROLABEL_IMPORTED_BY 7
3276 static int getMaxTextLength(struct TextPosInfo *pos, int font_nr)
3278 int max_text_width = SXSIZE;
3279 int font_width = getFontWidth(font_nr);
3281 if (pos->align == ALIGN_CENTER)
3282 max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
3283 else if (pos->align == ALIGN_RIGHT)
3284 max_text_width = pos->x;
3286 max_text_width = SXSIZE - pos->x;
3288 return max_text_width / font_width;
3291 static void DrawPreviewLevelLabelExt(int mode, struct TextPosInfo *pos)
3293 char label_text[MAX_OUTPUT_LINESIZE + 1];
3294 int max_len_label_text;
3295 int font_nr = pos->font;
3298 if (!IN_GFX_FIELD_FULL(pos->x, pos->y + getFontHeight(pos->font)))
3301 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
3302 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
3303 mode == MICROLABEL_IMPORTED_BY_HEAD)
3304 font_nr = pos->font_alt;
3306 max_len_label_text = getMaxTextLength(pos, font_nr);
3308 if (pos->size != -1)
3309 max_len_label_text = pos->size;
3311 for (i = 0; i < max_len_label_text; i++)
3312 label_text[i] = ' ';
3313 label_text[max_len_label_text] = '\0';
3315 if (strlen(label_text) > 0)
3316 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
3319 (mode == MICROLABEL_LEVEL_NAME ? level.name :
3320 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
3321 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
3322 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
3323 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
3324 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
3325 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
3326 max_len_label_text);
3327 label_text[max_len_label_text] = '\0';
3329 if (strlen(label_text) > 0)
3330 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
3332 redraw_mask |= REDRAW_FIELD;
3335 static void DrawPreviewLevelLabel(int mode)
3337 DrawPreviewLevelLabelExt(mode, &menu.main.text.level_info_2);
3340 static void DrawPreviewLevelInfo(int mode)
3342 if (mode == MICROLABEL_LEVEL_NAME)
3343 DrawPreviewLevelLabelExt(mode, &menu.main.text.level_name);
3344 else if (mode == MICROLABEL_LEVEL_AUTHOR)
3345 DrawPreviewLevelLabelExt(mode, &menu.main.text.level_author);
3348 static void DrawPreviewLevelExt(boolean restart)
3350 static unsigned int scroll_delay = 0;
3351 static unsigned int label_delay = 0;
3352 static int from_x, from_y, scroll_direction;
3353 static int label_state, label_counter;
3354 unsigned int scroll_delay_value = preview.step_delay;
3355 boolean show_level_border = (BorderElement != EL_EMPTY);
3356 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
3357 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
3364 if (preview.anim_mode == ANIM_CENTERED)
3366 if (level_xsize > preview.xsize)
3367 from_x = (level_xsize - preview.xsize) / 2;
3368 if (level_ysize > preview.ysize)
3369 from_y = (level_ysize - preview.ysize) / 2;
3372 from_x += preview.xoffset;
3373 from_y += preview.yoffset;
3375 scroll_direction = MV_RIGHT;
3379 DrawPreviewLevelPlayfield(from_x, from_y);
3380 DrawPreviewLevelLabel(label_state);
3382 DrawPreviewLevelInfo(MICROLABEL_LEVEL_NAME);
3383 DrawPreviewLevelInfo(MICROLABEL_LEVEL_AUTHOR);
3385 /* initialize delay counters */
3386 DelayReached(&scroll_delay, 0);
3387 DelayReached(&label_delay, 0);
3389 if (leveldir_current->name)
3391 struct TextPosInfo *pos = &menu.main.text.level_info_1;
3392 char label_text[MAX_OUTPUT_LINESIZE + 1];
3393 int font_nr = pos->font;
3394 int max_len_label_text = getMaxTextLength(pos, font_nr);
3396 if (pos->size != -1)
3397 max_len_label_text = pos->size;
3399 strncpy(label_text, leveldir_current->name, max_len_label_text);
3400 label_text[max_len_label_text] = '\0';
3402 if (IN_GFX_FIELD_FULL(pos->x, pos->y + getFontHeight(pos->font)))
3403 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
3409 /* scroll preview level, if needed */
3410 if (preview.anim_mode != ANIM_NONE &&
3411 (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
3412 DelayReached(&scroll_delay, scroll_delay_value))
3414 switch (scroll_direction)
3419 from_x -= preview.step_offset;
3420 from_x = (from_x < 0 ? 0 : from_x);
3423 scroll_direction = MV_UP;
3427 if (from_x < level_xsize - preview.xsize)
3429 from_x += preview.step_offset;
3430 from_x = (from_x > level_xsize - preview.xsize ?
3431 level_xsize - preview.xsize : from_x);
3434 scroll_direction = MV_DOWN;
3440 from_y -= preview.step_offset;
3441 from_y = (from_y < 0 ? 0 : from_y);
3444 scroll_direction = MV_RIGHT;
3448 if (from_y < level_ysize - preview.ysize)
3450 from_y += preview.step_offset;
3451 from_y = (from_y > level_ysize - preview.ysize ?
3452 level_ysize - preview.ysize : from_y);
3455 scroll_direction = MV_LEFT;
3462 DrawPreviewLevelPlayfield(from_x, from_y);
3465 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
3466 /* redraw micro level label, if needed */
3467 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
3468 !strEqual(level.author, ANONYMOUS_NAME) &&
3469 !strEqual(level.author, leveldir_current->name) &&
3470 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
3472 int max_label_counter = 23;
3474 if (leveldir_current->imported_from != NULL &&
3475 strlen(leveldir_current->imported_from) > 0)
3476 max_label_counter += 14;
3477 if (leveldir_current->imported_by != NULL &&
3478 strlen(leveldir_current->imported_by) > 0)
3479 max_label_counter += 14;
3481 label_counter = (label_counter + 1) % max_label_counter;
3482 label_state = (label_counter >= 0 && label_counter <= 7 ?
3483 MICROLABEL_LEVEL_NAME :
3484 label_counter >= 9 && label_counter <= 12 ?
3485 MICROLABEL_LEVEL_AUTHOR_HEAD :
3486 label_counter >= 14 && label_counter <= 21 ?
3487 MICROLABEL_LEVEL_AUTHOR :
3488 label_counter >= 23 && label_counter <= 26 ?
3489 MICROLABEL_IMPORTED_FROM_HEAD :
3490 label_counter >= 28 && label_counter <= 35 ?
3491 MICROLABEL_IMPORTED_FROM :
3492 label_counter >= 37 && label_counter <= 40 ?
3493 MICROLABEL_IMPORTED_BY_HEAD :
3494 label_counter >= 42 && label_counter <= 49 ?
3495 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
3497 if (leveldir_current->imported_from == NULL &&
3498 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
3499 label_state == MICROLABEL_IMPORTED_FROM))
3500 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
3501 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
3503 DrawPreviewLevelLabel(label_state);
3507 void DrawPreviewLevelInitial()
3509 DrawPreviewLevelExt(TRUE);
3512 void DrawPreviewLevelAnimation()
3514 DrawPreviewLevelExt(FALSE);
3517 static void DrawNetworkPlayer(int x, int y, int player_nr, int tile_size,
3518 int border_size, int font_nr)
3520 int graphic = el2img(EL_PLAYER_1 + player_nr);
3521 int font_height = getFontHeight(font_nr);
3522 int player_height = MAX(tile_size, font_height);
3523 int xoffset_text = tile_size + border_size;
3524 int yoffset_text = (player_height - font_height) / 2;
3525 int yoffset_graphic = (player_height - tile_size) / 2;
3526 char *player_name = getNetworkPlayerName(player_nr + 1);
3528 DrawSizedGraphicThruMaskExt(drawto, x, y + yoffset_graphic, graphic, 0,
3530 DrawText(x + xoffset_text, y + yoffset_text, player_name, font_nr);
3533 void DrawNetworkPlayers()
3535 if (!network.enabled || !network.connected)
3538 int num_players = 0;
3541 for (i = 0; i < MAX_PLAYERS; i++)
3542 if (stored_player[i].connected_network)
3545 struct TextPosInfo *pos = &menu.main.network_players;
3546 int tile_size = pos->tile_size;
3547 int border_size = 2;
3548 int xoffset_text = tile_size + border_size;
3549 int font_nr = pos->font;
3550 int font_width = getFontWidth(font_nr);
3551 int font_height = getFontHeight(font_nr);
3552 int player_height = MAX(tile_size, font_height);
3553 int player_yoffset = player_height + border_size;
3554 int max_players_width = xoffset_text + MAX_PLAYER_NAME_LEN * font_width;
3555 int max_players_height = MAX_PLAYERS * player_yoffset - border_size;
3556 int all_players_height = num_players * player_yoffset - border_size;
3557 int max_xpos = SX + ALIGNED_XPOS(pos->x, max_players_width, pos->align);
3558 int max_ypos = SY + ALIGNED_YPOS(pos->y, max_players_height, pos->valign);
3559 int ypos = SY + ALIGNED_YPOS(pos->y, all_players_height, pos->valign);
3561 ClearRectangleOnBackground(drawto, max_xpos, max_ypos,
3562 max_players_width, max_players_height);
3564 /* first draw local network player ... */
3565 for (i = 0; i < MAX_PLAYERS; i++)
3567 if (stored_player[i].connected_locally)
3569 char *player_name = getNetworkPlayerName(i + 1);
3570 int player_width = xoffset_text + getTextWidth(player_name, font_nr);
3571 int xpos = SX + ALIGNED_XPOS(pos->x, player_width, pos->align);
3573 DrawNetworkPlayer(xpos, ypos, i, tile_size, border_size, font_nr);
3575 ypos += player_yoffset;
3579 /* ... then draw all other network players */
3580 for (i = 0; i < MAX_PLAYERS; i++)
3582 if (stored_player[i].connected_network &&
3583 !stored_player[i].connected_locally)
3585 char *player_name = getNetworkPlayerName(i + 1);
3586 int player_width = xoffset_text + getTextWidth(player_name, font_nr);
3587 int xpos = SX + ALIGNED_XPOS(pos->x, player_width, pos->align);
3589 DrawNetworkPlayer(xpos, ypos, i, tile_size, border_size, font_nr);
3591 ypos += player_yoffset;
3596 inline static void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
3597 int graphic, int sync_frame,
3600 int frame = getGraphicAnimationFrame(graphic, sync_frame);
3602 if (mask_mode == USE_MASKING)
3603 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
3605 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
3608 void DrawFixedGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
3609 int graphic, int sync_frame, int mask_mode)
3611 int frame = getGraphicAnimationFrame(graphic, sync_frame);
3613 if (mask_mode == USE_MASKING)
3614 DrawFixedGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
3616 DrawFixedGraphicExt(dst_bitmap, x, y, graphic, frame);
3619 inline static void DrawGraphicAnimation(int x, int y, int graphic)
3621 int lx = LEVELX(x), ly = LEVELY(y);
3623 if (!IN_SCR_FIELD(x, y))
3626 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
3627 graphic, GfxFrame[lx][ly], NO_MASKING);
3629 MarkTileDirty(x, y);
3632 void DrawFixedGraphicAnimation(int x, int y, int graphic)
3634 int lx = LEVELX(x), ly = LEVELY(y);
3636 if (!IN_SCR_FIELD(x, y))
3639 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
3640 graphic, GfxFrame[lx][ly], NO_MASKING);
3641 MarkTileDirty(x, y);
3644 void DrawLevelGraphicAnimation(int x, int y, int graphic)
3646 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
3649 void DrawLevelElementAnimation(int x, int y, int element)
3651 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
3653 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
3656 void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
3658 int sx = SCREENX(x), sy = SCREENY(y);
3660 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
3663 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
3666 DrawGraphicAnimation(sx, sy, graphic);
3669 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
3670 DrawLevelFieldCrumbled(x, y);
3672 if (GFX_CRUMBLED(Feld[x][y]))
3673 DrawLevelFieldCrumbled(x, y);
3677 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
3679 int sx = SCREENX(x), sy = SCREENY(y);
3682 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
3685 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
3687 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
3690 DrawGraphicAnimation(sx, sy, graphic);
3692 if (GFX_CRUMBLED(element))
3693 DrawLevelFieldCrumbled(x, y);
3696 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
3698 if (player->use_murphy)
3700 /* this works only because currently only one player can be "murphy" ... */
3701 static int last_horizontal_dir = MV_LEFT;
3702 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
3704 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3705 last_horizontal_dir = move_dir;
3707 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
3709 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
3711 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
3717 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
3720 static boolean equalGraphics(int graphic1, int graphic2)
3722 struct GraphicInfo *g1 = &graphic_info[graphic1];
3723 struct GraphicInfo *g2 = &graphic_info[graphic2];
3725 return (g1->bitmap == g2->bitmap &&
3726 g1->src_x == g2->src_x &&
3727 g1->src_y == g2->src_y &&
3728 g1->anim_frames == g2->anim_frames &&
3729 g1->anim_delay == g2->anim_delay &&
3730 g1->anim_mode == g2->anim_mode);
3733 void DrawAllPlayers()
3737 for (i = 0; i < MAX_PLAYERS; i++)
3738 if (stored_player[i].active)
3739 DrawPlayer(&stored_player[i]);
3742 void DrawPlayerField(int x, int y)
3744 if (!IS_PLAYER(x, y))
3747 DrawPlayer(PLAYERINFO(x, y));
3750 #define DRAW_PLAYER_OVER_PUSHED_ELEMENT 1
3752 void DrawPlayer(struct PlayerInfo *player)
3754 int jx = player->jx;
3755 int jy = player->jy;
3756 int move_dir = player->MovDir;
3757 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
3758 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
3759 int last_jx = (player->is_moving ? jx - dx : jx);
3760 int last_jy = (player->is_moving ? jy - dy : jy);
3761 int next_jx = jx + dx;
3762 int next_jy = jy + dy;
3763 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
3764 boolean player_is_opaque = FALSE;
3765 int sx = SCREENX(jx), sy = SCREENY(jy);
3766 int sxx = 0, syy = 0;
3767 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
3769 int action = ACTION_DEFAULT;
3770 int last_player_graphic = getPlayerGraphic(player, move_dir);
3771 int last_player_frame = player->Frame;
3774 /* GfxElement[][] is set to the element the player is digging or collecting;
3775 remove also for off-screen player if the player is not moving anymore */
3776 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
3777 GfxElement[jx][jy] = EL_UNDEFINED;
3779 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
3783 if (!IN_LEV_FIELD(jx, jy))
3785 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
3786 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
3787 printf("DrawPlayerField(): This should never happen!\n");
3792 if (element == EL_EXPLOSION)
3795 action = (player->is_pushing ? ACTION_PUSHING :
3796 player->is_digging ? ACTION_DIGGING :
3797 player->is_collecting ? ACTION_COLLECTING :
3798 player->is_moving ? ACTION_MOVING :
3799 player->is_snapping ? ACTION_SNAPPING :
3800 player->is_dropping ? ACTION_DROPPING :
3801 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
3803 if (player->is_waiting)
3804 move_dir = player->dir_waiting;
3806 InitPlayerGfxAnimation(player, action, move_dir);
3808 /* ----------------------------------------------------------------------- */
3809 /* draw things in the field the player is leaving, if needed */
3810 /* ----------------------------------------------------------------------- */
3812 if (player->is_moving)
3814 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
3816 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
3818 if (last_element == EL_DYNAMITE_ACTIVE ||
3819 last_element == EL_EM_DYNAMITE_ACTIVE ||
3820 last_element == EL_SP_DISK_RED_ACTIVE)
3821 DrawDynamite(last_jx, last_jy);
3823 DrawLevelFieldThruMask(last_jx, last_jy);
3825 else if (last_element == EL_DYNAMITE_ACTIVE ||
3826 last_element == EL_EM_DYNAMITE_ACTIVE ||
3827 last_element == EL_SP_DISK_RED_ACTIVE)
3828 DrawDynamite(last_jx, last_jy);
3830 /* !!! this is not enough to prevent flickering of players which are
3831 moving next to each others without a free tile between them -- this
3832 can only be solved by drawing all players layer by layer (first the
3833 background, then the foreground etc.) !!! => TODO */
3834 else if (!IS_PLAYER(last_jx, last_jy))
3835 DrawLevelField(last_jx, last_jy);
3838 DrawLevelField(last_jx, last_jy);
3841 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
3842 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
3845 if (!IN_SCR_FIELD(sx, sy))
3848 /* ----------------------------------------------------------------------- */
3849 /* draw things behind the player, if needed */
3850 /* ----------------------------------------------------------------------- */
3853 DrawLevelElement(jx, jy, Back[jx][jy]);
3854 else if (IS_ACTIVE_BOMB(element))
3855 DrawLevelElement(jx, jy, EL_EMPTY);
3858 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
3860 int old_element = GfxElement[jx][jy];
3861 int old_graphic = el_act_dir2img(old_element, action, move_dir);
3862 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
3864 if (GFX_CRUMBLED(old_element))
3865 DrawLevelFieldCrumbledDigging(jx, jy, move_dir, player->StepFrame);
3867 DrawGraphic(sx, sy, old_graphic, frame);
3869 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
3870 player_is_opaque = TRUE;
3874 GfxElement[jx][jy] = EL_UNDEFINED;
3876 /* make sure that pushed elements are drawn with correct frame rate */
3877 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
3879 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
3880 GfxFrame[jx][jy] = player->StepFrame;
3882 DrawLevelField(jx, jy);
3886 #if !DRAW_PLAYER_OVER_PUSHED_ELEMENT
3887 /* ----------------------------------------------------------------------- */
3888 /* draw player himself */
3889 /* ----------------------------------------------------------------------- */
3891 graphic = getPlayerGraphic(player, move_dir);
3893 /* in the case of changed player action or direction, prevent the current
3894 animation frame from being restarted for identical animations */
3895 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
3896 player->Frame = last_player_frame;
3898 frame = getGraphicAnimationFrame(graphic, player->Frame);
3902 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3903 sxx = player->GfxPos;
3905 syy = player->GfxPos;
3908 if (player_is_opaque)
3909 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
3911 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3913 if (SHIELD_ON(player))
3915 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
3916 IMG_SHIELD_NORMAL_ACTIVE);
3917 int frame = getGraphicAnimationFrame(graphic, -1);
3919 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3923 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
3926 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3927 sxx = player->GfxPos;
3929 syy = player->GfxPos;
3933 /* ----------------------------------------------------------------------- */
3934 /* draw things the player is pushing, if needed */
3935 /* ----------------------------------------------------------------------- */
3937 if (player->is_pushing && player->is_moving)
3939 int px = SCREENX(jx), py = SCREENY(jy);
3940 int pxx = (TILEX - ABS(sxx)) * dx;
3941 int pyy = (TILEY - ABS(syy)) * dy;
3942 int gfx_frame = GfxFrame[jx][jy];
3948 if (!IS_MOVING(jx, jy)) /* push movement already finished */
3950 element = Feld[next_jx][next_jy];
3951 gfx_frame = GfxFrame[next_jx][next_jy];
3954 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
3956 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
3957 frame = getGraphicAnimationFrame(graphic, sync_frame);
3959 /* draw background element under pushed element (like the Sokoban field) */
3960 if (game.use_masked_pushing && IS_MOVING(jx, jy))
3962 /* this allows transparent pushing animation over non-black background */
3965 DrawLevelElement(jx, jy, Back[jx][jy]);
3967 DrawLevelElement(jx, jy, EL_EMPTY);
3969 if (Back[next_jx][next_jy])
3970 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3972 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
3974 else if (Back[next_jx][next_jy])
3975 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3978 /* do not draw (EM style) pushing animation when pushing is finished */
3979 /* (two-tile animations usually do not contain start and end frame) */
3980 if (graphic_info[graphic].double_movement && !IS_MOVING(jx, jy))
3981 DrawLevelElement(next_jx, next_jy, Feld[next_jx][next_jy]);
3983 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3985 /* masked drawing is needed for EMC style (double) movement graphics */
3986 /* !!! (ONLY WHEN DRAWING PUSHED ELEMENT OVER THE PLAYER) !!! */
3987 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3991 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
3992 /* ----------------------------------------------------------------------- */
3993 /* draw player himself */
3994 /* ----------------------------------------------------------------------- */
3996 graphic = getPlayerGraphic(player, move_dir);
3998 /* in the case of changed player action or direction, prevent the current
3999 animation frame from being restarted for identical animations */
4000 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
4001 player->Frame = last_player_frame;
4003 frame = getGraphicAnimationFrame(graphic, player->Frame);
4007 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
4008 sxx = player->GfxPos;
4010 syy = player->GfxPos;
4013 if (player_is_opaque)
4014 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
4016 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
4018 if (SHIELD_ON(player))
4020 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
4021 IMG_SHIELD_NORMAL_ACTIVE);
4022 int frame = getGraphicAnimationFrame(graphic, -1);
4024 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
4028 /* ----------------------------------------------------------------------- */
4029 /* draw things in front of player (active dynamite or dynabombs) */
4030 /* ----------------------------------------------------------------------- */
4032 if (IS_ACTIVE_BOMB(element))
4034 graphic = el2img(element);
4035 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
4037 if (game.emulation == EMU_SUPAPLEX)
4038 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
4040 DrawGraphicThruMask(sx, sy, graphic, frame);
4043 if (player_is_moving && last_element == EL_EXPLOSION)
4045 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
4046 GfxElement[last_jx][last_jy] : EL_EMPTY);
4047 int graphic = el_act2img(element, ACTION_EXPLODING);
4048 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
4049 int phase = ExplodePhase[last_jx][last_jy] - 1;
4050 int frame = getGraphicAnimationFrame(graphic, phase - delay);
4053 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
4056 /* ----------------------------------------------------------------------- */
4057 /* draw elements the player is just walking/passing through/under */
4058 /* ----------------------------------------------------------------------- */
4060 if (player_is_moving)
4062 /* handle the field the player is leaving ... */
4063 if (IS_ACCESSIBLE_INSIDE(last_element))
4064 DrawLevelField(last_jx, last_jy);
4065 else if (IS_ACCESSIBLE_UNDER(last_element))
4066 DrawLevelFieldThruMask(last_jx, last_jy);
4069 /* do not redraw accessible elements if the player is just pushing them */
4070 if (!player_is_moving || !player->is_pushing)
4072 /* ... and the field the player is entering */
4073 if (IS_ACCESSIBLE_INSIDE(element))
4074 DrawLevelField(jx, jy);
4075 else if (IS_ACCESSIBLE_UNDER(element))
4076 DrawLevelFieldThruMask(jx, jy);
4079 MarkTileDirty(sx, sy);
4082 /* ------------------------------------------------------------------------- */
4084 void WaitForEventToContinue()
4086 boolean still_wait = TRUE;
4088 if (program.headless)
4091 /* simulate releasing mouse button over last gadget, if still pressed */
4093 HandleGadgets(-1, -1, 0);
4095 button_status = MB_RELEASED;
4103 if (NextValidEvent(&event))
4107 case EVENT_BUTTONPRESS:
4108 case EVENT_KEYPRESS:
4109 #if defined(TARGET_SDL2)
4110 case SDL_CONTROLLERBUTTONDOWN:
4112 case SDL_JOYBUTTONDOWN:
4116 case EVENT_KEYRELEASE:
4117 ClearPlayerAction();
4121 HandleOtherEvents(&event);
4125 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
4134 #define MAX_REQUEST_LINES 13
4135 #define MAX_REQUEST_LINE_FONT1_LEN 7
4136 #define MAX_REQUEST_LINE_FONT2_LEN 10
4138 static int RequestHandleEvents(unsigned int req_state)
4140 boolean level_solved = (game_status == GAME_MODE_PLAYING &&
4141 local_player->LevelSolved_GameEnd);
4142 int width = request.width;
4143 int height = request.height;
4147 setRequestPosition(&sx, &sy, FALSE);
4149 button_status = MB_RELEASED;
4151 request_gadget_id = -1;
4158 /* the MM game engine does not use a special (scrollable) field buffer */
4159 if (level.game_engine_type != GAME_ENGINE_TYPE_MM)
4160 SetDrawtoField(DRAW_TO_FIELDBUFFER);
4162 HandleGameActions();
4164 SetDrawtoField(DRAW_TO_BACKBUFFER);
4166 if (global.use_envelope_request)
4168 /* copy current state of request area to middle of playfield area */
4169 BlitBitmap(bitmap_db_store_2, drawto, sx, sy, width, height, sx, sy);
4177 while (NextValidEvent(&event))
4181 case EVENT_BUTTONPRESS:
4182 case EVENT_BUTTONRELEASE:
4183 case EVENT_MOTIONNOTIFY:
4187 if (event.type == EVENT_MOTIONNOTIFY)
4192 motion_status = TRUE;
4193 mx = ((MotionEvent *) &event)->x;
4194 my = ((MotionEvent *) &event)->y;
4198 motion_status = FALSE;
4199 mx = ((ButtonEvent *) &event)->x;
4200 my = ((ButtonEvent *) &event)->y;
4201 if (event.type == EVENT_BUTTONPRESS)
4202 button_status = ((ButtonEvent *) &event)->button;
4204 button_status = MB_RELEASED;
4207 /* this sets 'request_gadget_id' */
4208 HandleGadgets(mx, my, button_status);
4210 switch (request_gadget_id)
4212 case TOOL_CTRL_ID_YES:
4215 case TOOL_CTRL_ID_NO:
4218 case TOOL_CTRL_ID_CONFIRM:
4219 result = TRUE | FALSE;
4222 case TOOL_CTRL_ID_PLAYER_1:
4225 case TOOL_CTRL_ID_PLAYER_2:
4228 case TOOL_CTRL_ID_PLAYER_3:
4231 case TOOL_CTRL_ID_PLAYER_4:
4242 #if defined(TARGET_SDL2)
4243 case SDL_WINDOWEVENT:
4244 HandleWindowEvent((WindowEvent *) &event);
4247 case SDL_APP_WILLENTERBACKGROUND:
4248 case SDL_APP_DIDENTERBACKGROUND:
4249 case SDL_APP_WILLENTERFOREGROUND:
4250 case SDL_APP_DIDENTERFOREGROUND:
4251 HandlePauseResumeEvent((PauseResumeEvent *) &event);
4255 case EVENT_KEYPRESS:
4257 Key key = GetEventKey((KeyEvent *)&event, TRUE);
4262 if (req_state & REQ_CONFIRM)
4268 #if defined(TARGET_SDL2)
4272 #if defined(KSYM_Rewind)
4273 case KSYM_Rewind: /* for Amazon Fire TV remote */
4281 #if defined(TARGET_SDL2)
4284 #if defined(KSYM_FastForward)
4285 case KSYM_FastForward: /* for Amazon Fire TV remote */
4292 HandleKeysDebug(key);
4296 if (req_state & REQ_PLAYER)
4298 int old_player_nr = setup.network_player_nr;
4301 result = old_player_nr + 1;
4306 result = old_player_nr + 1;
4337 case EVENT_KEYRELEASE:
4338 ClearPlayerAction();
4341 #if defined(TARGET_SDL2)
4342 case SDL_CONTROLLERBUTTONDOWN:
4343 switch (event.cbutton.button)
4345 case SDL_CONTROLLER_BUTTON_A:
4346 case SDL_CONTROLLER_BUTTON_X:
4347 case SDL_CONTROLLER_BUTTON_LEFTSHOULDER:
4348 case SDL_CONTROLLER_BUTTON_LEFTSTICK:
4352 case SDL_CONTROLLER_BUTTON_B:
4353 case SDL_CONTROLLER_BUTTON_Y:
4354 case SDL_CONTROLLER_BUTTON_RIGHTSHOULDER:
4355 case SDL_CONTROLLER_BUTTON_RIGHTSTICK:
4356 case SDL_CONTROLLER_BUTTON_BACK:
4361 if (req_state & REQ_PLAYER)
4363 int old_player_nr = setup.network_player_nr;
4366 result = old_player_nr + 1;
4368 switch (event.cbutton.button)
4370 case SDL_CONTROLLER_BUTTON_DPAD_UP:
4371 case SDL_CONTROLLER_BUTTON_Y:
4375 case SDL_CONTROLLER_BUTTON_DPAD_RIGHT:
4376 case SDL_CONTROLLER_BUTTON_B:
4380 case SDL_CONTROLLER_BUTTON_DPAD_DOWN:
4381 case SDL_CONTROLLER_BUTTON_A:
4385 case SDL_CONTROLLER_BUTTON_DPAD_LEFT:
4386 case SDL_CONTROLLER_BUTTON_X:
4397 case SDL_CONTROLLERBUTTONUP:
4398 HandleJoystickEvent(&event);
4399 ClearPlayerAction();
4404 HandleOtherEvents(&event);
4409 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
4411 int joy = AnyJoystick();
4413 if (joy & JOY_BUTTON_1)
4415 else if (joy & JOY_BUTTON_2)
4418 else if (AnyJoystick())
4420 int joy = AnyJoystick();
4422 if (req_state & REQ_PLAYER)
4426 else if (joy & JOY_RIGHT)
4428 else if (joy & JOY_DOWN)
4430 else if (joy & JOY_LEFT)
4437 if (global.use_envelope_request)
4439 /* copy back current state of pressed buttons inside request area */
4440 BlitBitmap(drawto, bitmap_db_store_2, sx, sy, width, height, sx, sy);
4450 static boolean RequestDoor(char *text, unsigned int req_state)
4452 unsigned int old_door_state;
4453 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
4454 int font_nr = FONT_TEXT_2;
4459 if (maxWordLengthInString(text) > MAX_REQUEST_LINE_FONT1_LEN)
4461 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
4462 font_nr = FONT_TEXT_1;
4465 if (game_status == GAME_MODE_PLAYING)
4466 BlitScreenToBitmap(backbuffer);
4468 /* disable deactivated drawing when quick-loading level tape recording */
4469 if (tape.playing && tape.deactivate_display)
4470 TapeDeactivateDisplayOff(TRUE);
4472 SetMouseCursor(CURSOR_DEFAULT);
4474 /* pause network game while waiting for request to answer */
4475 if (network.enabled &&
4476 game_status == GAME_MODE_PLAYING &&
4477 req_state & REQUEST_WAIT_FOR_INPUT)
4478 SendToServer_PausePlaying();
4480 old_door_state = GetDoorState();
4482 /* simulate releasing mouse button over last gadget, if still pressed */
4484 HandleGadgets(-1, -1, 0);
4488 /* draw released gadget before proceeding */
4491 if (old_door_state & DOOR_OPEN_1)
4493 CloseDoor(DOOR_CLOSE_1);
4495 /* save old door content */
4496 BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
4497 0 * DXSIZE, 0, DXSIZE, DYSIZE, 1 * DXSIZE, 0);
4500 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
4501 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4503 /* clear door drawing field */
4504 DrawBackground(DX, DY, DXSIZE, DYSIZE);
4506 /* force DOOR font inside door area */
4507 SetFontStatus(GAME_MODE_PSEUDO_DOOR);
4509 /* write text for request */
4510 for (text_ptr = text, ty = 0; ty < MAX_REQUEST_LINES; ty++)
4512 char text_line[max_request_line_len + 1];
4518 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
4520 tc = *(text_ptr + tx);
4521 // if (!tc || tc == ' ')
4522 if (!tc || tc == ' ' || tc == '?' || tc == '!')
4526 if ((tc == '?' || tc == '!') && tl == 0)
4536 strncpy(text_line, text_ptr, tl);
4539 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
4540 DY + 8 + ty * (getFontHeight(font_nr) + 2),
4541 text_line, font_nr);
4543 text_ptr += tl + (tc == ' ' ? 1 : 0);
4544 // text_ptr += tl + (tc == ' ' || tc == '?' || tc == '!' ? 1 : 0);
4549 if (req_state & REQ_ASK)
4551 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
4552 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
4554 else if (req_state & REQ_CONFIRM)
4556 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
4558 else if (req_state & REQ_PLAYER)
4560 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
4561 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
4562 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
4563 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
4566 /* copy request gadgets to door backbuffer */
4567 BlitBitmap(drawto, bitmap_db_door_1, DX, DY, DXSIZE, DYSIZE, 0, 0);
4569 OpenDoor(DOOR_OPEN_1);
4571 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
4573 if (game_status == GAME_MODE_PLAYING)
4575 SetPanelBackground();
4576 SetDrawBackgroundMask(REDRAW_DOOR_1);
4580 SetDrawBackgroundMask(REDRAW_FIELD);
4586 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4588 // ---------- handle request buttons ----------
4589 result = RequestHandleEvents(req_state);
4593 if (!(req_state & REQ_STAY_OPEN))
4595 CloseDoor(DOOR_CLOSE_1);
4597 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
4598 (req_state & REQ_REOPEN))
4599 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
4604 if (game_status == GAME_MODE_PLAYING)
4606 SetPanelBackground();
4607 SetDrawBackgroundMask(REDRAW_DOOR_1);
4611 SetDrawBackgroundMask(REDRAW_FIELD);
4614 /* continue network game after request */
4615 if (network.enabled &&
4616 game_status == GAME_MODE_PLAYING &&
4617 req_state & REQUEST_WAIT_FOR_INPUT)
4618 SendToServer_ContinuePlaying();
4620 /* restore deactivated drawing when quick-loading level tape recording */
4621 if (tape.playing && tape.deactivate_display)
4622 TapeDeactivateDisplayOn();
4627 static boolean RequestEnvelope(char *text, unsigned int req_state)
4631 if (game_status == GAME_MODE_PLAYING)
4632 BlitScreenToBitmap(backbuffer);
4634 /* disable deactivated drawing when quick-loading level tape recording */
4635 if (tape.playing && tape.deactivate_display)
4636 TapeDeactivateDisplayOff(TRUE);
4638 SetMouseCursor(CURSOR_DEFAULT);
4640 /* pause network game while waiting for request to answer */
4641 if (network.enabled &&
4642 game_status == GAME_MODE_PLAYING &&
4643 req_state & REQUEST_WAIT_FOR_INPUT)
4644 SendToServer_PausePlaying();
4646 /* simulate releasing mouse button over last gadget, if still pressed */
4648 HandleGadgets(-1, -1, 0);
4652 // (replace with setting corresponding request background)
4653 // SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
4654 // SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4656 /* clear door drawing field */
4657 // DrawBackground(DX, DY, DXSIZE, DYSIZE);
4659 ShowEnvelopeRequest(text, req_state, ACTION_OPENING);
4661 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
4663 if (game_status == GAME_MODE_PLAYING)
4665 SetPanelBackground();
4666 SetDrawBackgroundMask(REDRAW_DOOR_1);
4670 SetDrawBackgroundMask(REDRAW_FIELD);
4676 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4678 // ---------- handle request buttons ----------
4679 result = RequestHandleEvents(req_state);
4683 ShowEnvelopeRequest(text, req_state, ACTION_CLOSING);
4687 if (game_status == GAME_MODE_PLAYING)
4689 SetPanelBackground();
4690 SetDrawBackgroundMask(REDRAW_DOOR_1);
4694 SetDrawBackgroundMask(REDRAW_FIELD);
4697 /* continue network game after request */
4698 if (network.enabled &&
4699 game_status == GAME_MODE_PLAYING &&
4700 req_state & REQUEST_WAIT_FOR_INPUT)
4701 SendToServer_ContinuePlaying();
4703 /* restore deactivated drawing when quick-loading level tape recording */
4704 if (tape.playing && tape.deactivate_display)
4705 TapeDeactivateDisplayOn();
4710 boolean Request(char *text, unsigned int req_state)
4712 boolean overlay_active = GetOverlayActive();
4715 SetOverlayActive(FALSE);
4717 if (global.use_envelope_request)
4718 result = RequestEnvelope(text, req_state);
4720 result = RequestDoor(text, req_state);
4722 SetOverlayActive(overlay_active);
4727 static int compareDoorPartOrderInfo(const void *object1, const void *object2)
4729 const struct DoorPartOrderInfo *dpo1 = (struct DoorPartOrderInfo *)object1;
4730 const struct DoorPartOrderInfo *dpo2 = (struct DoorPartOrderInfo *)object2;
4733 if (dpo1->sort_priority != dpo2->sort_priority)
4734 compare_result = dpo1->sort_priority - dpo2->sort_priority;
4736 compare_result = dpo1->nr - dpo2->nr;
4738 return compare_result;
4741 void InitGraphicCompatibilityInfo_Doors()
4747 struct DoorInfo *door;
4751 { DOOR_1, IMG_GFX_DOOR_1_PART_1, IMG_GFX_DOOR_1_PART_8, &door_1 },
4752 { DOOR_2, IMG_GFX_DOOR_2_PART_1, IMG_GFX_DOOR_2_PART_8, &door_2 },
4754 { -1, -1, -1, NULL }
4756 struct Rect door_rect_list[] =
4758 { DX, DY, DXSIZE, DYSIZE },
4759 { VX, VY, VXSIZE, VYSIZE }
4763 for (i = 0; doors[i].door_token != -1; i++)
4765 int door_token = doors[i].door_token;
4766 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
4767 int part_1 = doors[i].part_1;
4768 int part_8 = doors[i].part_8;
4769 int part_2 = part_1 + 1;
4770 int part_3 = part_1 + 2;
4771 struct DoorInfo *door = doors[i].door;
4772 struct Rect *door_rect = &door_rect_list[door_index];
4773 boolean door_gfx_redefined = FALSE;
4775 /* check if any door part graphic definitions have been redefined */
4777 for (j = 0; door_part_controls[j].door_token != -1; j++)
4779 struct DoorPartControlInfo *dpc = &door_part_controls[j];
4780 struct FileInfo *fi = getImageListEntryFromImageID(dpc->graphic);
4782 if (dpc->door_token == door_token && fi->redefined)
4783 door_gfx_redefined = TRUE;
4786 /* check for old-style door graphic/animation modifications */
4788 if (!door_gfx_redefined)
4790 if (door->anim_mode & ANIM_STATIC_PANEL)
4792 door->panel.step_xoffset = 0;
4793 door->panel.step_yoffset = 0;
4796 if (door->anim_mode & (ANIM_HORIZONTAL | ANIM_VERTICAL))
4798 struct GraphicInfo *g_part_1 = &graphic_info[part_1];
4799 struct GraphicInfo *g_part_2 = &graphic_info[part_2];
4800 int num_door_steps, num_panel_steps;
4802 /* remove door part graphics other than the two default wings */
4804 for (j = 0; door_part_controls[j].door_token != -1; j++)
4806 struct DoorPartControlInfo *dpc = &door_part_controls[j];
4807 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4809 if (dpc->graphic >= part_3 &&
4810 dpc->graphic <= part_8)
4814 /* set graphics and screen positions of the default wings */
4816 g_part_1->width = door_rect->width;
4817 g_part_1->height = door_rect->height;
4818 g_part_2->width = door_rect->width;
4819 g_part_2->height = door_rect->height;
4820 g_part_2->src_x = door_rect->width;
4821 g_part_2->src_y = g_part_1->src_y;
4823 door->part_2.x = door->part_1.x;
4824 door->part_2.y = door->part_1.y;
4826 if (door->width != -1)
4828 g_part_1->width = door->width;
4829 g_part_2->width = door->width;
4831 // special treatment for graphics and screen position of right wing
4832 g_part_2->src_x += door_rect->width - door->width;
4833 door->part_2.x += door_rect->width - door->width;
4836 if (door->height != -1)
4838 g_part_1->height = door->height;
4839 g_part_2->height = door->height;
4841 // special treatment for graphics and screen position of bottom wing
4842 g_part_2->src_y += door_rect->height - door->height;
4843 door->part_2.y += door_rect->height - door->height;
4846 /* set animation delays for the default wings and panels */
4848 door->part_1.step_delay = door->step_delay;
4849 door->part_2.step_delay = door->step_delay;
4850 door->panel.step_delay = door->step_delay;
4852 /* set animation draw order for the default wings */
4854 door->part_1.sort_priority = 2; /* draw left wing over ... */
4855 door->part_2.sort_priority = 1; /* ... right wing */
4857 /* set animation draw offset for the default wings */
4859 if (door->anim_mode & ANIM_HORIZONTAL)
4861 door->part_1.step_xoffset = door->step_offset;
4862 door->part_1.step_yoffset = 0;
4863 door->part_2.step_xoffset = door->step_offset * -1;
4864 door->part_2.step_yoffset = 0;
4866 num_door_steps = g_part_1->width / door->step_offset;
4868 else // ANIM_VERTICAL
4870 door->part_1.step_xoffset = 0;
4871 door->part_1.step_yoffset = door->step_offset;
4872 door->part_2.step_xoffset = 0;
4873 door->part_2.step_yoffset = door->step_offset * -1;
4875 num_door_steps = g_part_1->height / door->step_offset;
4878 /* set animation draw offset for the default panels */
4880 if (door->step_offset > 1)
4882 num_panel_steps = 2 * door_rect->height / door->step_offset;
4883 door->panel.start_step = num_panel_steps - num_door_steps;
4884 door->panel.start_step_closing = door->panel.start_step;
4888 num_panel_steps = door_rect->height / door->step_offset;
4889 door->panel.start_step = num_panel_steps - num_door_steps / 2;
4890 door->panel.start_step_closing = door->panel.start_step;
4891 door->panel.step_delay *= 2;
4902 for (i = 0; door_part_controls[i].door_token != -1; i++)
4904 struct DoorPartControlInfo *dpc = &door_part_controls[i];
4905 struct DoorPartOrderInfo *dpo = &door_part_order[i];
4907 /* initialize "start_step_opening" and "start_step_closing", if needed */
4908 if (dpc->pos->start_step_opening == 0 &&
4909 dpc->pos->start_step_closing == 0)
4911 // dpc->pos->start_step_opening = dpc->pos->start_step;
4912 dpc->pos->start_step_closing = dpc->pos->start_step;
4915 /* fill structure for door part draw order (sorted below) */
4917 dpo->sort_priority = dpc->pos->sort_priority;
4920 /* sort door part controls according to sort_priority and graphic number */
4921 qsort(door_part_order, MAX_DOOR_PARTS,
4922 sizeof(struct DoorPartOrderInfo), compareDoorPartOrderInfo);
4925 unsigned int OpenDoor(unsigned int door_state)
4927 if (door_state & DOOR_COPY_BACK)
4929 if (door_state & DOOR_OPEN_1)
4930 BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
4931 1 * DXSIZE, 0, DXSIZE, DYSIZE, 0 * DXSIZE, 0);
4933 if (door_state & DOOR_OPEN_2)
4934 BlitBitmap(bitmap_db_door_2, bitmap_db_door_2,
4935 1 * VXSIZE, 0, VXSIZE, VYSIZE, 0 * VXSIZE, 0);
4937 door_state &= ~DOOR_COPY_BACK;
4940 return MoveDoor(door_state);
4943 unsigned int CloseDoor(unsigned int door_state)
4945 unsigned int old_door_state = GetDoorState();
4947 if (!(door_state & DOOR_NO_COPY_BACK))
4949 if (old_door_state & DOOR_OPEN_1)
4950 BlitBitmap(backbuffer, bitmap_db_door_1,
4951 DX, DY, DXSIZE, DYSIZE, 0, 0);
4953 if (old_door_state & DOOR_OPEN_2)
4954 BlitBitmap(backbuffer, bitmap_db_door_2,
4955 VX, VY, VXSIZE, VYSIZE, 0, 0);
4957 door_state &= ~DOOR_NO_COPY_BACK;
4960 return MoveDoor(door_state);
4963 unsigned int GetDoorState()
4965 return MoveDoor(DOOR_GET_STATE);
4968 unsigned int SetDoorState(unsigned int door_state)
4970 return MoveDoor(door_state | DOOR_SET_STATE);
4973 int euclid(int a, int b)
4975 return (b ? euclid(b, a % b) : a);
4978 unsigned int MoveDoor(unsigned int door_state)
4980 struct Rect door_rect_list[] =
4982 { DX, DY, DXSIZE, DYSIZE },
4983 { VX, VY, VXSIZE, VYSIZE }
4985 static int door1 = DOOR_CLOSE_1;
4986 static int door2 = DOOR_CLOSE_2;
4987 unsigned int door_delay = 0;
4988 unsigned int door_delay_value;
4991 if (door_state == DOOR_GET_STATE)
4992 return (door1 | door2);
4994 if (door_state & DOOR_SET_STATE)
4996 if (door_state & DOOR_ACTION_1)
4997 door1 = door_state & DOOR_ACTION_1;
4998 if (door_state & DOOR_ACTION_2)
4999 door2 = door_state & DOOR_ACTION_2;
5001 return (door1 | door2);
5004 if (!(door_state & DOOR_FORCE_REDRAW))
5006 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
5007 door_state &= ~DOOR_OPEN_1;
5008 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
5009 door_state &= ~DOOR_CLOSE_1;
5010 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
5011 door_state &= ~DOOR_OPEN_2;
5012 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
5013 door_state &= ~DOOR_CLOSE_2;
5016 if (global.autoplay_leveldir)
5018 door_state |= DOOR_NO_DELAY;
5019 door_state &= ~DOOR_CLOSE_ALL;
5022 if (game_status == GAME_MODE_EDITOR && !(door_state & DOOR_FORCE_ANIM))
5023 door_state |= DOOR_NO_DELAY;
5025 if (door_state & DOOR_ACTION)
5027 boolean door_panel_drawn[NUM_DOORS];
5028 boolean panel_has_doors[NUM_DOORS];
5029 boolean door_part_skip[MAX_DOOR_PARTS];
5030 boolean door_part_done[MAX_DOOR_PARTS];
5031 boolean door_part_done_all;
5032 int num_steps[MAX_DOOR_PARTS];
5033 int max_move_delay = 0; // delay for complete animations of all doors
5034 int max_step_delay = 0; // delay (ms) between two animation frames
5035 int num_move_steps = 0; // number of animation steps for all doors
5036 int max_move_delay_doors_only = 0; // delay for doors only (no panel)
5037 int num_move_steps_doors_only = 0; // steps for doors only (no panel)
5038 int current_move_delay = 0;
5042 for (i = 0; i < NUM_DOORS; i++)
5043 panel_has_doors[i] = FALSE;
5045 for (i = 0; i < MAX_DOOR_PARTS; i++)
5047 struct DoorPartControlInfo *dpc = &door_part_controls[i];
5048 struct GraphicInfo *g = &graphic_info[dpc->graphic];
5049 int door_token = dpc->door_token;
5051 door_part_done[i] = FALSE;
5052 door_part_skip[i] = (!(door_state & door_token) ||
5056 for (i = 0; i < MAX_DOOR_PARTS; i++)
5058 int nr = door_part_order[i].nr;
5059 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
5060 struct DoorPartPosInfo *pos = dpc->pos;
5061 struct GraphicInfo *g = &graphic_info[dpc->graphic];
5062 int door_token = dpc->door_token;
5063 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
5064 boolean is_panel = DOOR_PART_IS_PANEL(nr);
5065 int step_xoffset = ABS(pos->step_xoffset);
5066 int step_yoffset = ABS(pos->step_yoffset);
5067 int step_delay = pos->step_delay;
5068 int current_door_state = door_state & door_token;
5069 boolean door_opening = ((current_door_state & DOOR_OPEN) != 0);
5070 boolean door_closing = ((current_door_state & DOOR_CLOSE) != 0);
5071 boolean part_opening = (is_panel ? door_closing : door_opening);
5072 int start_step = (part_opening ? pos->start_step_opening :
5073 pos->start_step_closing);
5074 float move_xsize = (step_xoffset ? g->width : 0);
5075 float move_ysize = (step_yoffset ? g->height : 0);
5076 int move_xsteps = (step_xoffset ? ceil(move_xsize / step_xoffset) : 0);
5077 int move_ysteps = (step_yoffset ? ceil(move_ysize / step_yoffset) : 0);
5078 int move_steps = (move_xsteps && move_ysteps ?
5079 MIN(move_xsteps, move_ysteps) :
5080 move_xsteps ? move_xsteps : move_ysteps) - start_step;
5081 int move_delay = move_steps * step_delay;
5083 if (door_part_skip[nr])
5086 max_move_delay = MAX(max_move_delay, move_delay);
5087 max_step_delay = (max_step_delay == 0 ? step_delay :
5088 euclid(max_step_delay, step_delay));
5089 num_steps[nr] = move_steps;
5093 max_move_delay_doors_only = MAX(max_move_delay_doors_only, move_delay);
5095 panel_has_doors[door_index] = TRUE;
5099 max_step_delay = MAX(1, max_step_delay); // prevent division by zero
5101 num_move_steps = max_move_delay / max_step_delay;
5102 num_move_steps_doors_only = max_move_delay_doors_only / max_step_delay;
5104 door_delay_value = max_step_delay;
5106 if ((door_state & DOOR_NO_DELAY) || setup.quick_doors)
5108 start = num_move_steps - 1;
5112 /* opening door sound has priority over simultaneously closing door */
5113 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
5115 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
5117 if (door_state & DOOR_OPEN_1)
5118 PlayMenuSoundStereo(SND_DOOR_1_OPENING, SOUND_MIDDLE);
5119 if (door_state & DOOR_OPEN_2)
5120 PlayMenuSoundStereo(SND_DOOR_2_OPENING, SOUND_MIDDLE);
5122 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
5124 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
5126 if (door_state & DOOR_CLOSE_1)
5127 PlayMenuSoundStereo(SND_DOOR_1_CLOSING, SOUND_MIDDLE);
5128 if (door_state & DOOR_CLOSE_2)
5129 PlayMenuSoundStereo(SND_DOOR_2_CLOSING, SOUND_MIDDLE);
5133 for (k = start; k < num_move_steps; k++)
5135 int last_frame = num_move_steps - 1; // last frame of this "for" loop
5137 door_part_done_all = TRUE;
5139 for (i = 0; i < NUM_DOORS; i++)
5140 door_panel_drawn[i] = FALSE;
5142 for (i = 0; i < MAX_DOOR_PARTS; i++)
5144 int nr = door_part_order[i].nr;
5145 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
5146 struct DoorPartPosInfo *pos = dpc->pos;
5147 struct GraphicInfo *g = &graphic_info[dpc->graphic];
5148 int door_token = dpc->door_token;
5149 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
5150 boolean is_panel = DOOR_PART_IS_PANEL(nr);
5151 boolean is_panel_and_door_has_closed = FALSE;
5152 struct Rect *door_rect = &door_rect_list[door_index];
5153 Bitmap *bitmap_db_door = (door_token == DOOR_1 ? bitmap_db_door_1 :
5155 Bitmap *bitmap = (is_panel ? bitmap_db_door : g->bitmap);
5156 int current_door_state = door_state & door_token;
5157 boolean door_opening = ((current_door_state & DOOR_OPEN) != 0);
5158 boolean door_closing = !door_opening;
5159 boolean part_opening = (is_panel ? door_closing : door_opening);
5160 boolean part_closing = !part_opening;
5161 int start_step = (part_opening ? pos->start_step_opening :
5162 pos->start_step_closing);
5163 int step_delay = pos->step_delay;
5164 int step_factor = step_delay / max_step_delay;
5165 int k1 = (step_factor ? k / step_factor + 1 : k);
5166 int k2 = (part_opening ? k1 + start_step : num_steps[nr] - k1);
5167 int kk = MAX(0, k2);
5170 int src_x, src_y, src_xx, src_yy;
5171 int dst_x, dst_y, dst_xx, dst_yy;
5174 if (door_part_skip[nr])
5177 if (!(door_state & door_token))
5185 int k2_door = (door_opening ? k : num_move_steps_doors_only - k - 1);
5186 int kk_door = MAX(0, k2_door);
5187 int sync_frame = kk_door * door_delay_value;
5188 int frame = getGraphicAnimationFrame(dpc->graphic, sync_frame);
5190 getFixedGraphicSource(dpc->graphic, frame, &bitmap,
5191 &g_src_x, &g_src_y);
5196 if (!door_panel_drawn[door_index])
5198 ClearRectangle(drawto, door_rect->x, door_rect->y,
5199 door_rect->width, door_rect->height);
5201 door_panel_drawn[door_index] = TRUE;
5204 // draw opening or closing door parts
5206 if (pos->step_xoffset < 0) // door part on right side
5209 dst_xx = pos->x + ABS(kk * pos->step_xoffset);
5212 if (dst_xx + width > door_rect->width)
5213 width = door_rect->width - dst_xx;
5215 else // door part on left side
5218 dst_xx = pos->x - kk * pos->step_xoffset;
5222 src_xx = ABS(dst_xx);
5226 width = g->width - src_xx;
5228 if (width > door_rect->width)
5229 width = door_rect->width;
5231 // printf("::: k == %d [%d] \n", k, start_step);
5234 if (pos->step_yoffset < 0) // door part on bottom side
5237 dst_yy = pos->y + ABS(kk * pos->step_yoffset);
5240 if (dst_yy + height > door_rect->height)
5241 height = door_rect->height - dst_yy;
5243 else // door part on top side
5246 dst_yy = pos->y - kk * pos->step_yoffset;
5250 src_yy = ABS(dst_yy);
5254 height = g->height - src_yy;
5257 src_x = g_src_x + src_xx;
5258 src_y = g_src_y + src_yy;
5260 dst_x = door_rect->x + dst_xx;
5261 dst_y = door_rect->y + dst_yy;
5263 is_panel_and_door_has_closed =
5266 panel_has_doors[door_index] &&
5267 k >= num_move_steps_doors_only - 1);
5269 if (width >= 0 && width <= g->width &&
5270 height >= 0 && height <= g->height &&
5271 !is_panel_and_door_has_closed)
5273 if (is_panel || !pos->draw_masked)
5274 BlitBitmap(bitmap, drawto, src_x, src_y, width, height,
5277 BlitBitmapMasked(bitmap, drawto, src_x, src_y, width, height,
5281 redraw_mask |= REDRAW_DOOR_FROM_TOKEN(door_token);
5283 if ((part_opening && (width < 0 || height < 0)) ||
5284 (part_closing && (width >= g->width && height >= g->height)))
5285 door_part_done[nr] = TRUE;
5287 // continue door part animations, but not panel after door has closed
5288 if (!door_part_done[nr] && !is_panel_and_door_has_closed)
5289 door_part_done_all = FALSE;
5292 if (!(door_state & DOOR_NO_DELAY))
5296 SkipUntilDelayReached(&door_delay, door_delay_value, &k, last_frame);
5298 current_move_delay += max_step_delay;
5300 /* prevent OS (Windows) from complaining about program not responding */
5304 if (door_part_done_all)
5308 if (!(door_state & DOOR_NO_DELAY))
5310 /* wait for specified door action post delay */
5311 if (door_state & DOOR_ACTION_1 && door_state & DOOR_ACTION_2)
5312 door_delay_value = MAX(door_1.post_delay, door_2.post_delay);
5313 else if (door_state & DOOR_ACTION_1)
5314 door_delay_value = door_1.post_delay;
5315 else if (door_state & DOOR_ACTION_2)
5316 door_delay_value = door_2.post_delay;
5318 while (!DelayReached(&door_delay, door_delay_value))
5323 if (door_state & DOOR_ACTION_1)
5324 door1 = door_state & DOOR_ACTION_1;
5325 if (door_state & DOOR_ACTION_2)
5326 door2 = door_state & DOOR_ACTION_2;
5328 // draw masked border over door area
5329 DrawMaskedBorder(REDRAW_DOOR_1);
5330 DrawMaskedBorder(REDRAW_DOOR_2);
5332 return (door1 | door2);
5335 static boolean useSpecialEditorDoor()
5337 int graphic = IMG_GLOBAL_BORDER_EDITOR;
5338 boolean redefined = getImageListEntryFromImageID(graphic)->redefined;
5340 // do not draw special editor door if editor border defined or redefined
5341 if (graphic_info[graphic].bitmap != NULL || redefined)
5344 // do not draw special editor door if global border defined to be empty
5345 if (graphic_info[IMG_GLOBAL_BORDER].bitmap == NULL)
5348 // do not draw special editor door if viewport definitions do not match
5352 EY + EYSIZE != VY + VYSIZE)
5358 void DrawSpecialEditorDoor()
5360 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
5361 int top_border_width = gfx1->width;
5362 int top_border_height = gfx1->height;
5363 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
5364 int ex = EX - outer_border;
5365 int ey = EY - outer_border;
5366 int vy = VY - outer_border;
5367 int exsize = EXSIZE + 2 * outer_border;
5369 if (!useSpecialEditorDoor())
5372 /* draw bigger level editor toolbox window */
5373 BlitBitmap(gfx1->bitmap, drawto, gfx1->src_x, gfx1->src_y,
5374 top_border_width, top_border_height, ex, ey - top_border_height);
5375 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto, ex, vy,
5376 exsize, EYSIZE - VYSIZE + outer_border, ex, ey);
5378 redraw_mask |= REDRAW_ALL;
5381 void UndrawSpecialEditorDoor()
5383 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
5384 int top_border_width = gfx1->width;
5385 int top_border_height = gfx1->height;
5386 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
5387 int ex = EX - outer_border;
5388 int ey = EY - outer_border;
5389 int ey_top = ey - top_border_height;
5390 int exsize = EXSIZE + 2 * outer_border;
5391 int eysize = EYSIZE + 2 * outer_border;
5393 if (!useSpecialEditorDoor())
5396 /* draw normal tape recorder window */
5397 if (graphic_info[IMG_GLOBAL_BORDER].bitmap)
5399 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
5400 ex, ey_top, top_border_width, top_border_height,
5402 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
5403 ex, ey, exsize, eysize, ex, ey);
5407 // if screen background is set to "[NONE]", clear editor toolbox window
5408 ClearRectangle(drawto, ex, ey_top, top_border_width, top_border_height);
5409 ClearRectangle(drawto, ex, ey, exsize, eysize);
5412 redraw_mask |= REDRAW_ALL;
5416 /* ---------- new tool button stuff ---------------------------------------- */
5421 struct TextPosInfo *pos;
5424 } toolbutton_info[NUM_TOOL_BUTTONS] =
5427 IMG_GFX_REQUEST_BUTTON_YES, &request.button.yes,
5428 TOOL_CTRL_ID_YES, "yes"
5431 IMG_GFX_REQUEST_BUTTON_NO, &request.button.no,
5432 TOOL_CTRL_ID_NO, "no"
5435 IMG_GFX_REQUEST_BUTTON_CONFIRM, &request.button.confirm,
5436 TOOL_CTRL_ID_CONFIRM, "confirm"
5439 IMG_GFX_REQUEST_BUTTON_PLAYER_1, &request.button.player_1,
5440 TOOL_CTRL_ID_PLAYER_1, "player 1"
5443 IMG_GFX_REQUEST_BUTTON_PLAYER_2, &request.button.player_2,
5444 TOOL_CTRL_ID_PLAYER_2, "player 2"
5447 IMG_GFX_REQUEST_BUTTON_PLAYER_3, &request.button.player_3,
5448 TOOL_CTRL_ID_PLAYER_3, "player 3"
5451 IMG_GFX_REQUEST_BUTTON_PLAYER_4, &request.button.player_4,
5452 TOOL_CTRL_ID_PLAYER_4, "player 4"
5456 void CreateToolButtons()
5460 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
5462 int graphic = toolbutton_info[i].graphic;
5463 struct GraphicInfo *gfx = &graphic_info[graphic];
5464 struct TextPosInfo *pos = toolbutton_info[i].pos;
5465 struct GadgetInfo *gi;
5466 Bitmap *deco_bitmap = None;
5467 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
5468 unsigned int event_mask = GD_EVENT_RELEASED;
5471 int gd_x = gfx->src_x;
5472 int gd_y = gfx->src_y;
5473 int gd_xp = gfx->src_x + gfx->pressed_xoffset;
5474 int gd_yp = gfx->src_y + gfx->pressed_yoffset;
5479 if (global.use_envelope_request)
5481 setRequestPosition(&dx, &dy, TRUE);
5483 // check if request buttons are outside of envelope and fix, if needed
5484 if (x < 0 || x + gfx->width > request.width ||
5485 y < 0 || y + gfx->height > request.height)
5487 if (id == TOOL_CTRL_ID_YES)
5490 y = request.height - 2 * request.border_size - gfx->height;
5492 else if (id == TOOL_CTRL_ID_NO)
5494 x = request.width - 2 * request.border_size - gfx->width;
5495 y = request.height - 2 * request.border_size - gfx->height;
5497 else if (id == TOOL_CTRL_ID_CONFIRM)
5499 x = (request.width - 2 * request.border_size - gfx->width) / 2;
5500 y = request.height - 2 * request.border_size - gfx->height;
5502 else if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
5504 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
5506 x = (request.width - 2 * request.border_size - gfx->width) / 2;
5507 y = request.height - 2 * request.border_size - gfx->height * 2;
5509 x += (player_nr == 3 ? -1 : player_nr == 1 ? +1 : 0) * gfx->width;
5510 y += (player_nr == 0 ? -1 : player_nr == 2 ? +1 : 0) * gfx->height;
5515 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
5517 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
5519 getSizedGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr), 0,
5520 pos->size, &deco_bitmap, &deco_x, &deco_y);
5521 deco_xpos = (gfx->width - pos->size) / 2;
5522 deco_ypos = (gfx->height - pos->size) / 2;
5525 gi = CreateGadget(GDI_CUSTOM_ID, id,
5526 GDI_IMAGE_ID, graphic,
5527 GDI_INFO_TEXT, toolbutton_info[i].infotext,
5530 GDI_WIDTH, gfx->width,
5531 GDI_HEIGHT, gfx->height,
5532 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
5533 GDI_STATE, GD_BUTTON_UNPRESSED,
5534 GDI_DESIGN_UNPRESSED, gfx->bitmap, gd_x, gd_y,
5535 GDI_DESIGN_PRESSED, gfx->bitmap, gd_xp, gd_yp,
5536 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
5537 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
5538 GDI_DECORATION_SIZE, pos->size, pos->size,
5539 GDI_DECORATION_SHIFTING, 1, 1,
5540 GDI_DIRECT_DRAW, FALSE,
5541 GDI_EVENT_MASK, event_mask,
5542 GDI_CALLBACK_ACTION, HandleToolButtons,
5546 Error(ERR_EXIT, "cannot create gadget");
5548 tool_gadget[id] = gi;
5552 void FreeToolButtons()
5556 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
5557 FreeGadget(tool_gadget[i]);
5560 static void UnmapToolButtons()
5564 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
5565 UnmapGadget(tool_gadget[i]);
5568 static void HandleToolButtons(struct GadgetInfo *gi)
5570 request_gadget_id = gi->custom_id;
5573 static struct Mapping_EM_to_RND_object
5576 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
5577 boolean is_backside; /* backside of moving element */
5583 em_object_mapping_list[] =
5586 Xblank, TRUE, FALSE,
5590 Yacid_splash_eB, FALSE, FALSE,
5591 EL_ACID_SPLASH_RIGHT, -1, -1
5594 Yacid_splash_wB, FALSE, FALSE,
5595 EL_ACID_SPLASH_LEFT, -1, -1
5598 #ifdef EM_ENGINE_BAD_ROLL
5600 Xstone_force_e, FALSE, FALSE,
5601 EL_ROCK, -1, MV_BIT_RIGHT
5604 Xstone_force_w, FALSE, FALSE,
5605 EL_ROCK, -1, MV_BIT_LEFT
5608 Xnut_force_e, FALSE, FALSE,
5609 EL_NUT, -1, MV_BIT_RIGHT
5612 Xnut_force_w, FALSE, FALSE,
5613 EL_NUT, -1, MV_BIT_LEFT
5616 Xspring_force_e, FALSE, FALSE,
5617 EL_SPRING, -1, MV_BIT_RIGHT
5620 Xspring_force_w, FALSE, FALSE,
5621 EL_SPRING, -1, MV_BIT_LEFT
5624 Xemerald_force_e, FALSE, FALSE,
5625 EL_EMERALD, -1, MV_BIT_RIGHT
5628 Xemerald_force_w, FALSE, FALSE,
5629 EL_EMERALD, -1, MV_BIT_LEFT
5632 Xdiamond_force_e, FALSE, FALSE,
5633 EL_DIAMOND, -1, MV_BIT_RIGHT
5636 Xdiamond_force_w, FALSE, FALSE,
5637 EL_DIAMOND, -1, MV_BIT_LEFT
5640 Xbomb_force_e, FALSE, FALSE,
5641 EL_BOMB, -1, MV_BIT_RIGHT
5644 Xbomb_force_w, FALSE, FALSE,
5645 EL_BOMB, -1, MV_BIT_LEFT
5647 #endif /* EM_ENGINE_BAD_ROLL */
5650 Xstone, TRUE, FALSE,
5654 Xstone_pause, FALSE, FALSE,
5658 Xstone_fall, FALSE, FALSE,
5662 Ystone_s, FALSE, FALSE,
5663 EL_ROCK, ACTION_FALLING, -1
5666 Ystone_sB, FALSE, TRUE,
5667 EL_ROCK, ACTION_FALLING, -1
5670 Ystone_e, FALSE, FALSE,
5671 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
5674 Ystone_eB, FALSE, TRUE,
5675 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
5678 Ystone_w, FALSE, FALSE,
5679 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
5682 Ystone_wB, FALSE, TRUE,
5683 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
5690 Xnut_pause, FALSE, FALSE,
5694 Xnut_fall, FALSE, FALSE,
5698 Ynut_s, FALSE, FALSE,
5699 EL_NUT, ACTION_FALLING, -1
5702 Ynut_sB, FALSE, TRUE,
5703 EL_NUT, ACTION_FALLING, -1
5706 Ynut_e, FALSE, FALSE,
5707 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
5710 Ynut_eB, FALSE, TRUE,
5711 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
5714 Ynut_w, FALSE, FALSE,
5715 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
5718 Ynut_wB, FALSE, TRUE,
5719 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
5722 Xbug_n, TRUE, FALSE,
5726 Xbug_e, TRUE, FALSE,
5727 EL_BUG_RIGHT, -1, -1
5730 Xbug_s, TRUE, FALSE,
5734 Xbug_w, TRUE, FALSE,
5738 Xbug_gon, FALSE, FALSE,
5742 Xbug_goe, FALSE, FALSE,
5743 EL_BUG_RIGHT, -1, -1
5746 Xbug_gos, FALSE, FALSE,
5750 Xbug_gow, FALSE, FALSE,
5754 Ybug_n, FALSE, FALSE,
5755 EL_BUG, ACTION_MOVING, MV_BIT_UP
5758 Ybug_nB, FALSE, TRUE,
5759 EL_BUG, ACTION_MOVING, MV_BIT_UP
5762 Ybug_e, FALSE, FALSE,
5763 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
5766 Ybug_eB, FALSE, TRUE,
5767 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
5770 Ybug_s, FALSE, FALSE,
5771 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
5774 Ybug_sB, FALSE, TRUE,
5775 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
5778 Ybug_w, FALSE, FALSE,
5779 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
5782 Ybug_wB, FALSE, TRUE,
5783 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
5786 Ybug_w_n, FALSE, FALSE,
5787 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
5790 Ybug_n_e, FALSE, FALSE,
5791 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
5794 Ybug_e_s, FALSE, FALSE,
5795 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
5798 Ybug_s_w, FALSE, FALSE,
5799 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
5802 Ybug_e_n, FALSE, FALSE,
5803 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
5806 Ybug_s_e, FALSE, FALSE,
5807 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
5810 Ybug_w_s, FALSE, FALSE,
5811 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
5814 Ybug_n_w, FALSE, FALSE,
5815 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
5818 Ybug_stone, FALSE, FALSE,
5819 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
5822 Ybug_spring, FALSE, FALSE,
5823 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
5826 Xtank_n, TRUE, FALSE,
5827 EL_SPACESHIP_UP, -1, -1
5830 Xtank_e, TRUE, FALSE,
5831 EL_SPACESHIP_RIGHT, -1, -1
5834 Xtank_s, TRUE, FALSE,
5835 EL_SPACESHIP_DOWN, -1, -1
5838 Xtank_w, TRUE, FALSE,
5839 EL_SPACESHIP_LEFT, -1, -1
5842 Xtank_gon, FALSE, FALSE,
5843 EL_SPACESHIP_UP, -1, -1
5846 Xtank_goe, FALSE, FALSE,
5847 EL_SPACESHIP_RIGHT, -1, -1
5850 Xtank_gos, FALSE, FALSE,
5851 EL_SPACESHIP_DOWN, -1, -1
5854 Xtank_gow, FALSE, FALSE,
5855 EL_SPACESHIP_LEFT, -1, -1
5858 Ytank_n, FALSE, FALSE,
5859 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
5862 Ytank_nB, FALSE, TRUE,
5863 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
5866 Ytank_e, FALSE, FALSE,
5867 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
5870 Ytank_eB, FALSE, TRUE,
5871 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
5874 Ytank_s, FALSE, FALSE,
5875 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
5878 Ytank_sB, FALSE, TRUE,
5879 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
5882 Ytank_w, FALSE, FALSE,
5883 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
5886 Ytank_wB, FALSE, TRUE,
5887 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
5890 Ytank_w_n, FALSE, FALSE,
5891 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
5894 Ytank_n_e, FALSE, FALSE,
5895 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
5898 Ytank_e_s, FALSE, FALSE,
5899 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
5902 Ytank_s_w, FALSE, FALSE,
5903 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
5906 Ytank_e_n, FALSE, FALSE,
5907 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
5910 Ytank_s_e, FALSE, FALSE,
5911 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
5914 Ytank_w_s, FALSE, FALSE,
5915 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
5918 Ytank_n_w, FALSE, FALSE,
5919 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
5922 Ytank_stone, FALSE, FALSE,
5923 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
5926 Ytank_spring, FALSE, FALSE,
5927 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
5930 Xandroid, TRUE, FALSE,
5931 EL_EMC_ANDROID, ACTION_ACTIVE, -1
5934 Xandroid_1_n, FALSE, FALSE,
5935 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
5938 Xandroid_2_n, FALSE, FALSE,
5939 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
5942 Xandroid_1_e, FALSE, FALSE,
5943 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
5946 Xandroid_2_e, FALSE, FALSE,
5947 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
5950 Xandroid_1_w, FALSE, FALSE,
5951 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
5954 Xandroid_2_w, FALSE, FALSE,
5955 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
5958 Xandroid_1_s, FALSE, FALSE,
5959 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
5962 Xandroid_2_s, FALSE, FALSE,
5963 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
5966 Yandroid_n, FALSE, FALSE,
5967 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
5970 Yandroid_nB, FALSE, TRUE,
5971 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
5974 Yandroid_ne, FALSE, FALSE,
5975 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
5978 Yandroid_neB, FALSE, TRUE,
5979 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
5982 Yandroid_e, FALSE, FALSE,
5983 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
5986 Yandroid_eB, FALSE, TRUE,
5987 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
5990 Yandroid_se, FALSE, FALSE,
5991 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
5994 Yandroid_seB, FALSE, TRUE,
5995 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
5998 Yandroid_s, FALSE, FALSE,
5999 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
6002 Yandroid_sB, FALSE, TRUE,
6003 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
6006 Yandroid_sw, FALSE, FALSE,
6007 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
6010 Yandroid_swB, FALSE, TRUE,
6011 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
6014 Yandroid_w, FALSE, FALSE,
6015 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
6018 Yandroid_wB, FALSE, TRUE,
6019 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
6022 Yandroid_nw, FALSE, FALSE,
6023 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
6026 Yandroid_nwB, FALSE, TRUE,
6027 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
6030 Xspring, TRUE, FALSE,
6034 Xspring_pause, FALSE, FALSE,
6038 Xspring_e, FALSE, FALSE,
6042 Xspring_w, FALSE, FALSE,
6046 Xspring_fall, FALSE, FALSE,
6050 Yspring_s, FALSE, FALSE,
6051 EL_SPRING, ACTION_FALLING, -1
6054 Yspring_sB, FALSE, TRUE,
6055 EL_SPRING, ACTION_FALLING, -1
6058 Yspring_e, FALSE, FALSE,
6059 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
6062 Yspring_eB, FALSE, TRUE,
6063 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
6066 Yspring_w, FALSE, FALSE,
6067 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
6070 Yspring_wB, FALSE, TRUE,
6071 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
6074 Yspring_kill_e, FALSE, FALSE,
6075 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
6078 Yspring_kill_eB, FALSE, TRUE,
6079 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
6082 Yspring_kill_w, FALSE, FALSE,
6083 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
6086 Yspring_kill_wB, FALSE, TRUE,
6087 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
6090 Xeater_n, TRUE, FALSE,
6091 EL_YAMYAM_UP, -1, -1
6094 Xeater_e, TRUE, FALSE,
6095 EL_YAMYAM_RIGHT, -1, -1
6098 Xeater_w, TRUE, FALSE,
6099 EL_YAMYAM_LEFT, -1, -1
6102 Xeater_s, TRUE, FALSE,
6103 EL_YAMYAM_DOWN, -1, -1
6106 Yeater_n, FALSE, FALSE,
6107 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
6110 Yeater_nB, FALSE, TRUE,
6111 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
6114 Yeater_e, FALSE, FALSE,
6115 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
6118 Yeater_eB, FALSE, TRUE,
6119 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
6122 Yeater_s, FALSE, FALSE,
6123 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
6126 Yeater_sB, FALSE, TRUE,
6127 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
6130 Yeater_w, FALSE, FALSE,
6131 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
6134 Yeater_wB, FALSE, TRUE,
6135 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
6138 Yeater_stone, FALSE, FALSE,
6139 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
6142 Yeater_spring, FALSE, FALSE,
6143 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
6146 Xalien, TRUE, FALSE,
6150 Xalien_pause, FALSE, FALSE,
6154 Yalien_n, FALSE, FALSE,
6155 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
6158 Yalien_nB, FALSE, TRUE,
6159 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
6162 Yalien_e, FALSE, FALSE,
6163 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
6166 Yalien_eB, FALSE, TRUE,
6167 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
6170 Yalien_s, FALSE, FALSE,
6171 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
6174 Yalien_sB, FALSE, TRUE,
6175 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
6178 Yalien_w, FALSE, FALSE,
6179 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
6182 Yalien_wB, FALSE, TRUE,
6183 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
6186 Yalien_stone, FALSE, FALSE,
6187 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
6190 Yalien_spring, FALSE, FALSE,
6191 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
6194 Xemerald, TRUE, FALSE,
6198 Xemerald_pause, FALSE, FALSE,
6202 Xemerald_fall, FALSE, FALSE,
6206 Xemerald_shine, FALSE, FALSE,
6207 EL_EMERALD, ACTION_TWINKLING, -1
6210 Yemerald_s, FALSE, FALSE,
6211 EL_EMERALD, ACTION_FALLING, -1
6214 Yemerald_sB, FALSE, TRUE,
6215 EL_EMERALD, ACTION_FALLING, -1
6218 Yemerald_e, FALSE, FALSE,
6219 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
6222 Yemerald_eB, FALSE, TRUE,
6223 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
6226 Yemerald_w, FALSE, FALSE,
6227 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
6230 Yemerald_wB, FALSE, TRUE,
6231 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
6234 Yemerald_eat, FALSE, FALSE,
6235 EL_EMERALD, ACTION_COLLECTING, -1
6238 Yemerald_stone, FALSE, FALSE,
6239 EL_NUT, ACTION_BREAKING, -1
6242 Xdiamond, TRUE, FALSE,
6246 Xdiamond_pause, FALSE, FALSE,
6250 Xdiamond_fall, FALSE, FALSE,
6254 Xdiamond_shine, FALSE, FALSE,
6255 EL_DIAMOND, ACTION_TWINKLING, -1
6258 Ydiamond_s, FALSE, FALSE,
6259 EL_DIAMOND, ACTION_FALLING, -1
6262 Ydiamond_sB, FALSE, TRUE,
6263 EL_DIAMOND, ACTION_FALLING, -1
6266 Ydiamond_e, FALSE, FALSE,
6267 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
6270 Ydiamond_eB, FALSE, TRUE,
6271 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
6274 Ydiamond_w, FALSE, FALSE,
6275 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
6278 Ydiamond_wB, FALSE, TRUE,
6279 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
6282 Ydiamond_eat, FALSE, FALSE,
6283 EL_DIAMOND, ACTION_COLLECTING, -1
6286 Ydiamond_stone, FALSE, FALSE,
6287 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
6290 Xdrip_fall, TRUE, FALSE,
6291 EL_AMOEBA_DROP, -1, -1
6294 Xdrip_stretch, FALSE, FALSE,
6295 EL_AMOEBA_DROP, ACTION_FALLING, -1
6298 Xdrip_stretchB, FALSE, TRUE,
6299 EL_AMOEBA_DROP, ACTION_FALLING, -1
6302 Xdrip_eat, FALSE, FALSE,
6303 EL_AMOEBA_DROP, ACTION_GROWING, -1
6306 Ydrip_s1, FALSE, FALSE,
6307 EL_AMOEBA_DROP, ACTION_FALLING, -1
6310 Ydrip_s1B, FALSE, TRUE,
6311 EL_AMOEBA_DROP, ACTION_FALLING, -1
6314 Ydrip_s2, FALSE, FALSE,
6315 EL_AMOEBA_DROP, ACTION_FALLING, -1
6318 Ydrip_s2B, FALSE, TRUE,
6319 EL_AMOEBA_DROP, ACTION_FALLING, -1
6326 Xbomb_pause, FALSE, FALSE,
6330 Xbomb_fall, FALSE, FALSE,
6334 Ybomb_s, FALSE, FALSE,
6335 EL_BOMB, ACTION_FALLING, -1
6338 Ybomb_sB, FALSE, TRUE,
6339 EL_BOMB, ACTION_FALLING, -1
6342 Ybomb_e, FALSE, FALSE,
6343 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
6346 Ybomb_eB, FALSE, TRUE,
6347 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
6350 Ybomb_w, FALSE, FALSE,
6351 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
6354 Ybomb_wB, FALSE, TRUE,
6355 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
6358 Ybomb_eat, FALSE, FALSE,
6359 EL_BOMB, ACTION_ACTIVATING, -1
6362 Xballoon, TRUE, FALSE,
6366 Yballoon_n, FALSE, FALSE,
6367 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
6370 Yballoon_nB, FALSE, TRUE,
6371 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
6374 Yballoon_e, FALSE, FALSE,
6375 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
6378 Yballoon_eB, FALSE, TRUE,
6379 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
6382 Yballoon_s, FALSE, FALSE,
6383 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
6386 Yballoon_sB, FALSE, TRUE,
6387 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
6390 Yballoon_w, FALSE, FALSE,
6391 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
6394 Yballoon_wB, FALSE, TRUE,
6395 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
6398 Xgrass, TRUE, FALSE,
6399 EL_EMC_GRASS, -1, -1
6402 Ygrass_nB, FALSE, FALSE,
6403 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
6406 Ygrass_eB, FALSE, FALSE,
6407 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
6410 Ygrass_sB, FALSE, FALSE,
6411 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
6414 Ygrass_wB, FALSE, FALSE,
6415 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
6422 Ydirt_nB, FALSE, FALSE,
6423 EL_SAND, ACTION_DIGGING, MV_BIT_UP
6426 Ydirt_eB, FALSE, FALSE,
6427 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
6430 Ydirt_sB, FALSE, FALSE,
6431 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
6434 Ydirt_wB, FALSE, FALSE,
6435 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
6438 Xacid_ne, TRUE, FALSE,
6439 EL_ACID_POOL_TOPRIGHT, -1, -1
6442 Xacid_se, TRUE, FALSE,
6443 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
6446 Xacid_s, TRUE, FALSE,
6447 EL_ACID_POOL_BOTTOM, -1, -1
6450 Xacid_sw, TRUE, FALSE,
6451 EL_ACID_POOL_BOTTOMLEFT, -1, -1
6454 Xacid_nw, TRUE, FALSE,
6455 EL_ACID_POOL_TOPLEFT, -1, -1
6458 Xacid_1, TRUE, FALSE,
6462 Xacid_2, FALSE, FALSE,
6466 Xacid_3, FALSE, FALSE,
6470 Xacid_4, FALSE, FALSE,
6474 Xacid_5, FALSE, FALSE,
6478 Xacid_6, FALSE, FALSE,
6482 Xacid_7, FALSE, FALSE,
6486 Xacid_8, FALSE, FALSE,
6490 Xball_1, TRUE, FALSE,
6491 EL_EMC_MAGIC_BALL, -1, -1
6494 Xball_1B, FALSE, FALSE,
6495 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
6498 Xball_2, FALSE, FALSE,
6499 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
6502 Xball_2B, FALSE, FALSE,
6503 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
6506 Yball_eat, FALSE, FALSE,
6507 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
6510 Ykey_1_eat, FALSE, FALSE,
6511 EL_EM_KEY_1, ACTION_COLLECTING, -1
6514 Ykey_2_eat, FALSE, FALSE,
6515 EL_EM_KEY_2, ACTION_COLLECTING, -1
6518 Ykey_3_eat, FALSE, FALSE,
6519 EL_EM_KEY_3, ACTION_COLLECTING, -1
6522 Ykey_4_eat, FALSE, FALSE,
6523 EL_EM_KEY_4, ACTION_COLLECTING, -1
6526 Ykey_5_eat, FALSE, FALSE,
6527 EL_EMC_KEY_5, ACTION_COLLECTING, -1
6530 Ykey_6_eat, FALSE, FALSE,
6531 EL_EMC_KEY_6, ACTION_COLLECTING, -1
6534 Ykey_7_eat, FALSE, FALSE,
6535 EL_EMC_KEY_7, ACTION_COLLECTING, -1
6538 Ykey_8_eat, FALSE, FALSE,
6539 EL_EMC_KEY_8, ACTION_COLLECTING, -1
6542 Ylenses_eat, FALSE, FALSE,
6543 EL_EMC_LENSES, ACTION_COLLECTING, -1
6546 Ymagnify_eat, FALSE, FALSE,
6547 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
6550 Ygrass_eat, FALSE, FALSE,
6551 EL_EMC_GRASS, ACTION_SNAPPING, -1
6554 Ydirt_eat, FALSE, FALSE,
6555 EL_SAND, ACTION_SNAPPING, -1
6558 Xgrow_ns, TRUE, FALSE,
6559 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
6562 Ygrow_ns_eat, FALSE, FALSE,
6563 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
6566 Xgrow_ew, TRUE, FALSE,
6567 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
6570 Ygrow_ew_eat, FALSE, FALSE,
6571 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
6574 Xwonderwall, TRUE, FALSE,
6575 EL_MAGIC_WALL, -1, -1
6578 XwonderwallB, FALSE, FALSE,
6579 EL_MAGIC_WALL, ACTION_ACTIVE, -1
6582 Xamoeba_1, TRUE, FALSE,
6583 EL_AMOEBA_DRY, ACTION_OTHER, -1
6586 Xamoeba_2, FALSE, FALSE,
6587 EL_AMOEBA_DRY, ACTION_OTHER, -1
6590 Xamoeba_3, FALSE, FALSE,
6591 EL_AMOEBA_DRY, ACTION_OTHER, -1
6594 Xamoeba_4, FALSE, FALSE,
6595 EL_AMOEBA_DRY, ACTION_OTHER, -1
6598 Xamoeba_5, TRUE, FALSE,
6599 EL_AMOEBA_WET, ACTION_OTHER, -1
6602 Xamoeba_6, FALSE, FALSE,
6603 EL_AMOEBA_WET, ACTION_OTHER, -1
6606 Xamoeba_7, FALSE, FALSE,
6607 EL_AMOEBA_WET, ACTION_OTHER, -1
6610 Xamoeba_8, FALSE, FALSE,
6611 EL_AMOEBA_WET, ACTION_OTHER, -1
6614 Xdoor_1, TRUE, FALSE,
6615 EL_EM_GATE_1, -1, -1
6618 Xdoor_2, TRUE, FALSE,
6619 EL_EM_GATE_2, -1, -1
6622 Xdoor_3, TRUE, FALSE,
6623 EL_EM_GATE_3, -1, -1
6626 Xdoor_4, TRUE, FALSE,
6627 EL_EM_GATE_4, -1, -1
6630 Xdoor_5, TRUE, FALSE,
6631 EL_EMC_GATE_5, -1, -1
6634 Xdoor_6, TRUE, FALSE,
6635 EL_EMC_GATE_6, -1, -1
6638 Xdoor_7, TRUE, FALSE,
6639 EL_EMC_GATE_7, -1, -1
6642 Xdoor_8, TRUE, FALSE,
6643 EL_EMC_GATE_8, -1, -1
6646 Xkey_1, TRUE, FALSE,
6650 Xkey_2, TRUE, FALSE,
6654 Xkey_3, TRUE, FALSE,
6658 Xkey_4, TRUE, FALSE,
6662 Xkey_5, TRUE, FALSE,
6663 EL_EMC_KEY_5, -1, -1
6666 Xkey_6, TRUE, FALSE,
6667 EL_EMC_KEY_6, -1, -1
6670 Xkey_7, TRUE, FALSE,
6671 EL_EMC_KEY_7, -1, -1
6674 Xkey_8, TRUE, FALSE,
6675 EL_EMC_KEY_8, -1, -1
6678 Xwind_n, TRUE, FALSE,
6679 EL_BALLOON_SWITCH_UP, -1, -1
6682 Xwind_e, TRUE, FALSE,
6683 EL_BALLOON_SWITCH_RIGHT, -1, -1
6686 Xwind_s, TRUE, FALSE,
6687 EL_BALLOON_SWITCH_DOWN, -1, -1
6690 Xwind_w, TRUE, FALSE,
6691 EL_BALLOON_SWITCH_LEFT, -1, -1
6694 Xwind_nesw, TRUE, FALSE,
6695 EL_BALLOON_SWITCH_ANY, -1, -1
6698 Xwind_stop, TRUE, FALSE,
6699 EL_BALLOON_SWITCH_NONE, -1, -1
6703 EL_EM_EXIT_CLOSED, -1, -1
6706 Xexit_1, TRUE, FALSE,
6707 EL_EM_EXIT_OPEN, -1, -1
6710 Xexit_2, FALSE, FALSE,
6711 EL_EM_EXIT_OPEN, -1, -1
6714 Xexit_3, FALSE, FALSE,
6715 EL_EM_EXIT_OPEN, -1, -1
6718 Xdynamite, TRUE, FALSE,
6719 EL_EM_DYNAMITE, -1, -1
6722 Ydynamite_eat, FALSE, FALSE,
6723 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
6726 Xdynamite_1, TRUE, FALSE,
6727 EL_EM_DYNAMITE_ACTIVE, -1, -1
6730 Xdynamite_2, FALSE, FALSE,
6731 EL_EM_DYNAMITE_ACTIVE, -1, -1
6734 Xdynamite_3, FALSE, FALSE,
6735 EL_EM_DYNAMITE_ACTIVE, -1, -1
6738 Xdynamite_4, FALSE, FALSE,
6739 EL_EM_DYNAMITE_ACTIVE, -1, -1
6742 Xbumper, TRUE, FALSE,
6743 EL_EMC_SPRING_BUMPER, -1, -1
6746 XbumperB, FALSE, FALSE,
6747 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
6750 Xwheel, TRUE, FALSE,
6751 EL_ROBOT_WHEEL, -1, -1
6754 XwheelB, FALSE, FALSE,
6755 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
6758 Xswitch, TRUE, FALSE,
6759 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
6762 XswitchB, FALSE, FALSE,
6763 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
6767 EL_QUICKSAND_EMPTY, -1, -1
6770 Xsand_stone, TRUE, FALSE,
6771 EL_QUICKSAND_FULL, -1, -1
6774 Xsand_stonein_1, FALSE, TRUE,
6775 EL_ROCK, ACTION_FILLING, -1
6778 Xsand_stonein_2, FALSE, TRUE,
6779 EL_ROCK, ACTION_FILLING, -1
6782 Xsand_stonein_3, FALSE, TRUE,
6783 EL_ROCK, ACTION_FILLING, -1
6786 Xsand_stonein_4, FALSE, TRUE,
6787 EL_ROCK, ACTION_FILLING, -1
6790 Xsand_stonesand_1, FALSE, FALSE,
6791 EL_QUICKSAND_EMPTYING, -1, -1
6794 Xsand_stonesand_2, FALSE, FALSE,
6795 EL_QUICKSAND_EMPTYING, -1, -1
6798 Xsand_stonesand_3, FALSE, FALSE,
6799 EL_QUICKSAND_EMPTYING, -1, -1
6802 Xsand_stonesand_4, FALSE, FALSE,
6803 EL_QUICKSAND_EMPTYING, -1, -1
6806 Xsand_stonesand_quickout_1, FALSE, FALSE,
6807 EL_QUICKSAND_EMPTYING, -1, -1
6810 Xsand_stonesand_quickout_2, FALSE, FALSE,
6811 EL_QUICKSAND_EMPTYING, -1, -1
6814 Xsand_stoneout_1, FALSE, FALSE,
6815 EL_ROCK, ACTION_EMPTYING, -1
6818 Xsand_stoneout_2, FALSE, FALSE,
6819 EL_ROCK, ACTION_EMPTYING, -1
6822 Xsand_sandstone_1, FALSE, FALSE,
6823 EL_QUICKSAND_FILLING, -1, -1
6826 Xsand_sandstone_2, FALSE, FALSE,
6827 EL_QUICKSAND_FILLING, -1, -1
6830 Xsand_sandstone_3, FALSE, FALSE,
6831 EL_QUICKSAND_FILLING, -1, -1
6834 Xsand_sandstone_4, FALSE, FALSE,
6835 EL_QUICKSAND_FILLING, -1, -1
6838 Xplant, TRUE, FALSE,
6839 EL_EMC_PLANT, -1, -1
6842 Yplant, FALSE, FALSE,
6843 EL_EMC_PLANT, -1, -1
6846 Xlenses, TRUE, FALSE,
6847 EL_EMC_LENSES, -1, -1
6850 Xmagnify, TRUE, FALSE,
6851 EL_EMC_MAGNIFIER, -1, -1
6854 Xdripper, TRUE, FALSE,
6855 EL_EMC_DRIPPER, -1, -1
6858 XdripperB, FALSE, FALSE,
6859 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
6862 Xfake_blank, TRUE, FALSE,
6863 EL_INVISIBLE_WALL, -1, -1
6866 Xfake_blankB, FALSE, FALSE,
6867 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
6870 Xfake_grass, TRUE, FALSE,
6871 EL_EMC_FAKE_GRASS, -1, -1
6874 Xfake_grassB, FALSE, FALSE,
6875 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
6878 Xfake_door_1, TRUE, FALSE,
6879 EL_EM_GATE_1_GRAY, -1, -1
6882 Xfake_door_2, TRUE, FALSE,
6883 EL_EM_GATE_2_GRAY, -1, -1
6886 Xfake_door_3, TRUE, FALSE,
6887 EL_EM_GATE_3_GRAY, -1, -1
6890 Xfake_door_4, TRUE, FALSE,
6891 EL_EM_GATE_4_GRAY, -1, -1
6894 Xfake_door_5, TRUE, FALSE,
6895 EL_EMC_GATE_5_GRAY, -1, -1
6898 Xfake_door_6, TRUE, FALSE,
6899 EL_EMC_GATE_6_GRAY, -1, -1
6902 Xfake_door_7, TRUE, FALSE,
6903 EL_EMC_GATE_7_GRAY, -1, -1
6906 Xfake_door_8, TRUE, FALSE,
6907 EL_EMC_GATE_8_GRAY, -1, -1
6910 Xfake_acid_1, TRUE, FALSE,
6911 EL_EMC_FAKE_ACID, -1, -1
6914 Xfake_acid_2, FALSE, FALSE,
6915 EL_EMC_FAKE_ACID, -1, -1
6918 Xfake_acid_3, FALSE, FALSE,
6919 EL_EMC_FAKE_ACID, -1, -1
6922 Xfake_acid_4, FALSE, FALSE,
6923 EL_EMC_FAKE_ACID, -1, -1
6926 Xfake_acid_5, FALSE, FALSE,
6927 EL_EMC_FAKE_ACID, -1, -1
6930 Xfake_acid_6, FALSE, FALSE,
6931 EL_EMC_FAKE_ACID, -1, -1
6934 Xfake_acid_7, FALSE, FALSE,
6935 EL_EMC_FAKE_ACID, -1, -1
6938 Xfake_acid_8, FALSE, FALSE,
6939 EL_EMC_FAKE_ACID, -1, -1
6942 Xsteel_1, TRUE, FALSE,
6943 EL_STEELWALL, -1, -1
6946 Xsteel_2, TRUE, FALSE,
6947 EL_EMC_STEELWALL_2, -1, -1
6950 Xsteel_3, TRUE, FALSE,
6951 EL_EMC_STEELWALL_3, -1, -1
6954 Xsteel_4, TRUE, FALSE,
6955 EL_EMC_STEELWALL_4, -1, -1
6958 Xwall_1, TRUE, FALSE,
6962 Xwall_2, TRUE, FALSE,
6963 EL_EMC_WALL_14, -1, -1
6966 Xwall_3, TRUE, FALSE,
6967 EL_EMC_WALL_15, -1, -1
6970 Xwall_4, TRUE, FALSE,
6971 EL_EMC_WALL_16, -1, -1
6974 Xround_wall_1, TRUE, FALSE,
6975 EL_WALL_SLIPPERY, -1, -1
6978 Xround_wall_2, TRUE, FALSE,
6979 EL_EMC_WALL_SLIPPERY_2, -1, -1
6982 Xround_wall_3, TRUE, FALSE,
6983 EL_EMC_WALL_SLIPPERY_3, -1, -1
6986 Xround_wall_4, TRUE, FALSE,
6987 EL_EMC_WALL_SLIPPERY_4, -1, -1
6990 Xdecor_1, TRUE, FALSE,
6991 EL_EMC_WALL_8, -1, -1
6994 Xdecor_2, TRUE, FALSE,
6995 EL_EMC_WALL_6, -1, -1
6998 Xdecor_3, TRUE, FALSE,
6999 EL_EMC_WALL_4, -1, -1
7002 Xdecor_4, TRUE, FALSE,
7003 EL_EMC_WALL_7, -1, -1
7006 Xdecor_5, TRUE, FALSE,
7007 EL_EMC_WALL_5, -1, -1
7010 Xdecor_6, TRUE, FALSE,
7011 EL_EMC_WALL_9, -1, -1
7014 Xdecor_7, TRUE, FALSE,
7015 EL_EMC_WALL_10, -1, -1
7018 Xdecor_8, TRUE, FALSE,
7019 EL_EMC_WALL_1, -1, -1
7022 Xdecor_9, TRUE, FALSE,
7023 EL_EMC_WALL_2, -1, -1
7026 Xdecor_10, TRUE, FALSE,
7027 EL_EMC_WALL_3, -1, -1
7030 Xdecor_11, TRUE, FALSE,
7031 EL_EMC_WALL_11, -1, -1
7034 Xdecor_12, TRUE, FALSE,
7035 EL_EMC_WALL_12, -1, -1
7038 Xalpha_0, TRUE, FALSE,
7039 EL_CHAR('0'), -1, -1
7042 Xalpha_1, TRUE, FALSE,
7043 EL_CHAR('1'), -1, -1
7046 Xalpha_2, TRUE, FALSE,
7047 EL_CHAR('2'), -1, -1
7050 Xalpha_3, TRUE, FALSE,
7051 EL_CHAR('3'), -1, -1
7054 Xalpha_4, TRUE, FALSE,
7055 EL_CHAR('4'), -1, -1
7058 Xalpha_5, TRUE, FALSE,
7059 EL_CHAR('5'), -1, -1
7062 Xalpha_6, TRUE, FALSE,
7063 EL_CHAR('6'), -1, -1
7066 Xalpha_7, TRUE, FALSE,
7067 EL_CHAR('7'), -1, -1
7070 Xalpha_8, TRUE, FALSE,
7071 EL_CHAR('8'), -1, -1
7074 Xalpha_9, TRUE, FALSE,
7075 EL_CHAR('9'), -1, -1
7078 Xalpha_excla, TRUE, FALSE,
7079 EL_CHAR('!'), -1, -1
7082 Xalpha_quote, TRUE, FALSE,
7083 EL_CHAR('"'), -1, -1
7086 Xalpha_comma, TRUE, FALSE,
7087 EL_CHAR(','), -1, -1
7090 Xalpha_minus, TRUE, FALSE,
7091 EL_CHAR('-'), -1, -1
7094 Xalpha_perio, TRUE, FALSE,
7095 EL_CHAR('.'), -1, -1
7098 Xalpha_colon, TRUE, FALSE,
7099 EL_CHAR(':'), -1, -1
7102 Xalpha_quest, TRUE, FALSE,
7103 EL_CHAR('?'), -1, -1
7106 Xalpha_a, TRUE, FALSE,
7107 EL_CHAR('A'), -1, -1
7110 Xalpha_b, TRUE, FALSE,
7111 EL_CHAR('B'), -1, -1
7114 Xalpha_c, TRUE, FALSE,
7115 EL_CHAR('C'), -1, -1
7118 Xalpha_d, TRUE, FALSE,
7119 EL_CHAR('D'), -1, -1
7122 Xalpha_e, TRUE, FALSE,
7123 EL_CHAR('E'), -1, -1
7126 Xalpha_f, TRUE, FALSE,
7127 EL_CHAR('F'), -1, -1
7130 Xalpha_g, TRUE, FALSE,
7131 EL_CHAR('G'), -1, -1
7134 Xalpha_h, TRUE, FALSE,
7135 EL_CHAR('H'), -1, -1
7138 Xalpha_i, TRUE, FALSE,
7139 EL_CHAR('I'), -1, -1
7142 Xalpha_j, TRUE, FALSE,
7143 EL_CHAR('J'), -1, -1
7146 Xalpha_k, TRUE, FALSE,
7147 EL_CHAR('K'), -1, -1
7150 Xalpha_l, TRUE, FALSE,
7151 EL_CHAR('L'), -1, -1
7154 Xalpha_m, TRUE, FALSE,
7155 EL_CHAR('M'), -1, -1
7158 Xalpha_n, TRUE, FALSE,
7159 EL_CHAR('N'), -1, -1
7162 Xalpha_o, TRUE, FALSE,
7163 EL_CHAR('O'), -1, -1
7166 Xalpha_p, TRUE, FALSE,
7167 EL_CHAR('P'), -1, -1
7170 Xalpha_q, TRUE, FALSE,
7171 EL_CHAR('Q'), -1, -1
7174 Xalpha_r, TRUE, FALSE,
7175 EL_CHAR('R'), -1, -1
7178 Xalpha_s, TRUE, FALSE,
7179 EL_CHAR('S'), -1, -1
7182 Xalpha_t, TRUE, FALSE,
7183 EL_CHAR('T'), -1, -1
7186 Xalpha_u, TRUE, FALSE,
7187 EL_CHAR('U'), -1, -1
7190 Xalpha_v, TRUE, FALSE,
7191 EL_CHAR('V'), -1, -1
7194 Xalpha_w, TRUE, FALSE,
7195 EL_CHAR('W'), -1, -1
7198 Xalpha_x, TRUE, FALSE,
7199 EL_CHAR('X'), -1, -1
7202 Xalpha_y, TRUE, FALSE,
7203 EL_CHAR('Y'), -1, -1
7206 Xalpha_z, TRUE, FALSE,
7207 EL_CHAR('Z'), -1, -1
7210 Xalpha_arrow_e, TRUE, FALSE,
7211 EL_CHAR('>'), -1, -1
7214 Xalpha_arrow_w, TRUE, FALSE,
7215 EL_CHAR('<'), -1, -1
7218 Xalpha_copyr, TRUE, FALSE,
7219 EL_CHAR(CHAR_BYTE_COPYRIGHT), -1, -1
7223 Xboom_bug, FALSE, FALSE,
7224 EL_BUG, ACTION_EXPLODING, -1
7227 Xboom_bomb, FALSE, FALSE,
7228 EL_BOMB, ACTION_EXPLODING, -1
7231 Xboom_android, FALSE, FALSE,
7232 EL_EMC_ANDROID, ACTION_OTHER, -1
7235 Xboom_1, FALSE, FALSE,
7236 EL_DEFAULT, ACTION_EXPLODING, -1
7239 Xboom_2, FALSE, FALSE,
7240 EL_DEFAULT, ACTION_EXPLODING, -1
7243 Znormal, FALSE, FALSE,
7247 Zdynamite, FALSE, FALSE,
7251 Zplayer, FALSE, FALSE,
7255 ZBORDER, FALSE, FALSE,
7265 static struct Mapping_EM_to_RND_player
7274 em_player_mapping_list[] =
7278 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
7282 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
7286 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
7290 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
7294 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
7298 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
7302 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
7306 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
7310 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
7314 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
7318 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
7322 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
7326 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
7330 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
7334 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
7338 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
7342 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
7346 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
7350 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
7354 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
7358 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
7362 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
7366 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
7370 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
7374 EL_PLAYER_1, ACTION_DEFAULT, -1,
7378 EL_PLAYER_2, ACTION_DEFAULT, -1,
7382 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
7386 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
7390 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
7394 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
7398 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
7402 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
7406 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
7410 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
7414 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
7418 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
7422 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
7426 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
7430 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
7434 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
7438 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
7442 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
7446 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
7450 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
7454 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
7458 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
7462 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
7466 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
7470 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
7474 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
7478 EL_PLAYER_3, ACTION_DEFAULT, -1,
7482 EL_PLAYER_4, ACTION_DEFAULT, -1,
7491 int map_element_RND_to_EM(int element_rnd)
7493 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
7494 static boolean mapping_initialized = FALSE;
7496 if (!mapping_initialized)
7500 /* return "Xalpha_quest" for all undefined elements in mapping array */
7501 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
7502 mapping_RND_to_EM[i] = Xalpha_quest;
7504 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
7505 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
7506 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
7507 em_object_mapping_list[i].element_em;
7509 mapping_initialized = TRUE;
7512 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
7513 return mapping_RND_to_EM[element_rnd];
7515 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
7520 int map_element_EM_to_RND(int element_em)
7522 static unsigned short mapping_EM_to_RND[TILE_MAX];
7523 static boolean mapping_initialized = FALSE;
7525 if (!mapping_initialized)
7529 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
7530 for (i = 0; i < TILE_MAX; i++)
7531 mapping_EM_to_RND[i] = EL_UNKNOWN;
7533 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
7534 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
7535 em_object_mapping_list[i].element_rnd;
7537 mapping_initialized = TRUE;
7540 if (element_em >= 0 && element_em < TILE_MAX)
7541 return mapping_EM_to_RND[element_em];
7543 Error(ERR_WARN, "invalid EM level element %d", element_em);
7548 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
7550 struct LevelInfo_EM *level_em = level->native_em_level;
7551 struct LEVEL *lev = level_em->lev;
7554 for (i = 0; i < TILE_MAX; i++)
7555 lev->android_array[i] = Xblank;
7557 for (i = 0; i < level->num_android_clone_elements; i++)
7559 int element_rnd = level->android_clone_element[i];
7560 int element_em = map_element_RND_to_EM(element_rnd);
7562 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
7563 if (em_object_mapping_list[j].element_rnd == element_rnd)
7564 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
7568 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
7570 struct LevelInfo_EM *level_em = level->native_em_level;
7571 struct LEVEL *lev = level_em->lev;
7574 level->num_android_clone_elements = 0;
7576 for (i = 0; i < TILE_MAX; i++)
7578 int element_em = lev->android_array[i];
7580 boolean element_found = FALSE;
7582 if (element_em == Xblank)
7585 element_rnd = map_element_EM_to_RND(element_em);
7587 for (j = 0; j < level->num_android_clone_elements; j++)
7588 if (level->android_clone_element[j] == element_rnd)
7589 element_found = TRUE;
7593 level->android_clone_element[level->num_android_clone_elements++] =
7596 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
7601 if (level->num_android_clone_elements == 0)
7603 level->num_android_clone_elements = 1;
7604 level->android_clone_element[0] = EL_EMPTY;
7608 int map_direction_RND_to_EM(int direction)
7610 return (direction == MV_UP ? 0 :
7611 direction == MV_RIGHT ? 1 :
7612 direction == MV_DOWN ? 2 :
7613 direction == MV_LEFT ? 3 :
7617 int map_direction_EM_to_RND(int direction)
7619 return (direction == 0 ? MV_UP :
7620 direction == 1 ? MV_RIGHT :
7621 direction == 2 ? MV_DOWN :
7622 direction == 3 ? MV_LEFT :
7626 int map_element_RND_to_SP(int element_rnd)
7628 int element_sp = 0x20; /* map unknown elements to yellow "hardware" */
7630 if (element_rnd >= EL_SP_START &&
7631 element_rnd <= EL_SP_END)
7632 element_sp = element_rnd - EL_SP_START;
7633 else if (element_rnd == EL_EMPTY_SPACE)
7635 else if (element_rnd == EL_INVISIBLE_WALL)
7641 int map_element_SP_to_RND(int element_sp)
7643 int element_rnd = EL_UNKNOWN;
7645 if (element_sp >= 0x00 &&
7647 element_rnd = EL_SP_START + element_sp;
7648 else if (element_sp == 0x28)
7649 element_rnd = EL_INVISIBLE_WALL;
7654 int map_action_SP_to_RND(int action_sp)
7658 case actActive: return ACTION_ACTIVE;
7659 case actImpact: return ACTION_IMPACT;
7660 case actExploding: return ACTION_EXPLODING;
7661 case actDigging: return ACTION_DIGGING;
7662 case actSnapping: return ACTION_SNAPPING;
7663 case actCollecting: return ACTION_COLLECTING;
7664 case actPassing: return ACTION_PASSING;
7665 case actPushing: return ACTION_PUSHING;
7666 case actDropping: return ACTION_DROPPING;
7668 default: return ACTION_DEFAULT;
7672 int map_element_RND_to_MM(int element_rnd)
7674 return (element_rnd >= EL_MM_START_1 &&
7675 element_rnd <= EL_MM_END_1 ?
7676 EL_MM_START_1_NATIVE + element_rnd - EL_MM_START_1 :
7678 element_rnd >= EL_MM_START_2 &&
7679 element_rnd <= EL_MM_END_2 ?
7680 EL_MM_START_2_NATIVE + element_rnd - EL_MM_START_2 :
7682 element_rnd >= EL_CHAR_START &&
7683 element_rnd <= EL_CHAR_END ?
7684 EL_MM_CHAR_START_NATIVE + element_rnd - EL_CHAR_START :
7686 element_rnd >= EL_MM_RUNTIME_START &&
7687 element_rnd <= EL_MM_RUNTIME_END ?
7688 EL_MM_RUNTIME_START_NATIVE + element_rnd - EL_MM_RUNTIME_START :
7690 element_rnd >= EL_MM_DUMMY_START &&
7691 element_rnd <= EL_MM_DUMMY_END ?
7692 EL_MM_DUMMY_START_NATIVE + element_rnd - EL_MM_DUMMY_START :
7694 EL_MM_EMPTY_NATIVE);
7697 int map_element_MM_to_RND(int element_mm)
7699 return (element_mm == EL_MM_EMPTY_NATIVE ||
7700 element_mm == EL_DF_EMPTY_NATIVE ?
7703 element_mm >= EL_MM_START_1_NATIVE &&
7704 element_mm <= EL_MM_END_1_NATIVE ?
7705 EL_MM_START_1 + element_mm - EL_MM_START_1_NATIVE :
7707 element_mm >= EL_MM_START_2_NATIVE &&
7708 element_mm <= EL_MM_END_2_NATIVE ?
7709 EL_MM_START_2 + element_mm - EL_MM_START_2_NATIVE :
7711 element_mm >= EL_MM_CHAR_START_NATIVE &&
7712 element_mm <= EL_MM_CHAR_END_NATIVE ?
7713 EL_CHAR_START + element_mm - EL_MM_CHAR_START_NATIVE :
7715 element_mm >= EL_MM_RUNTIME_START_NATIVE &&
7716 element_mm <= EL_MM_RUNTIME_END_NATIVE ?
7717 EL_MM_RUNTIME_START + element_mm - EL_MM_RUNTIME_START_NATIVE :
7719 element_mm >= EL_MM_DUMMY_START_NATIVE &&
7720 element_mm <= EL_MM_DUMMY_END_NATIVE ?
7721 EL_MM_DUMMY_START + element_mm - EL_MM_DUMMY_START_NATIVE :
7726 int map_action_MM_to_RND(int action_mm)
7728 /* all MM actions are defined to exactly match their RND counterparts */
7732 int map_sound_MM_to_RND(int sound_mm)
7736 case SND_MM_GAME_LEVELTIME_CHARGING:
7737 return SND_GAME_LEVELTIME_CHARGING;
7739 case SND_MM_GAME_HEALTH_CHARGING:
7740 return SND_GAME_HEALTH_CHARGING;
7743 return SND_UNDEFINED;
7747 int map_mm_wall_element(int element)
7749 return (element >= EL_MM_STEEL_WALL_START &&
7750 element <= EL_MM_STEEL_WALL_END ?
7753 element >= EL_MM_WOODEN_WALL_START &&
7754 element <= EL_MM_WOODEN_WALL_END ?
7757 element >= EL_MM_ICE_WALL_START &&
7758 element <= EL_MM_ICE_WALL_END ?
7761 element >= EL_MM_AMOEBA_WALL_START &&
7762 element <= EL_MM_AMOEBA_WALL_END ?
7765 element >= EL_DF_STEEL_WALL_START &&
7766 element <= EL_DF_STEEL_WALL_END ?
7769 element >= EL_DF_WOODEN_WALL_START &&
7770 element <= EL_DF_WOODEN_WALL_END ?
7776 int map_mm_wall_element_editor(int element)
7780 case EL_MM_STEEL_WALL: return EL_MM_STEEL_WALL_START;
7781 case EL_MM_WOODEN_WALL: return EL_MM_WOODEN_WALL_START;
7782 case EL_MM_ICE_WALL: return EL_MM_ICE_WALL_START;
7783 case EL_MM_AMOEBA_WALL: return EL_MM_AMOEBA_WALL_START;
7784 case EL_DF_STEEL_WALL: return EL_DF_STEEL_WALL_START;
7785 case EL_DF_WOODEN_WALL: return EL_DF_WOODEN_WALL_START;
7787 default: return element;
7791 int get_next_element(int element)
7795 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
7796 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
7797 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
7798 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
7799 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
7800 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
7801 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
7802 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
7803 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
7804 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
7805 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
7807 default: return element;
7811 int el2img_mm(int element_mm)
7813 return el2img(map_element_MM_to_RND(element_mm));
7816 int el_act_dir2img(int element, int action, int direction)
7818 element = GFX_ELEMENT(element);
7819 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
7821 /* direction_graphic[][] == graphic[] for undefined direction graphics */
7822 return element_info[element].direction_graphic[action][direction];
7825 static int el_act_dir2crm(int element, int action, int direction)
7827 element = GFX_ELEMENT(element);
7828 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
7830 /* direction_graphic[][] == graphic[] for undefined direction graphics */
7831 return element_info[element].direction_crumbled[action][direction];
7834 int el_act2img(int element, int action)
7836 element = GFX_ELEMENT(element);
7838 return element_info[element].graphic[action];
7841 int el_act2crm(int element, int action)
7843 element = GFX_ELEMENT(element);
7845 return element_info[element].crumbled[action];
7848 int el_dir2img(int element, int direction)
7850 element = GFX_ELEMENT(element);
7852 return el_act_dir2img(element, ACTION_DEFAULT, direction);
7855 int el2baseimg(int element)
7857 return element_info[element].graphic[ACTION_DEFAULT];
7860 int el2img(int element)
7862 element = GFX_ELEMENT(element);
7864 return element_info[element].graphic[ACTION_DEFAULT];
7867 int el2edimg(int element)
7869 element = GFX_ELEMENT(element);
7871 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
7874 int el2preimg(int element)
7876 element = GFX_ELEMENT(element);
7878 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
7881 int el2panelimg(int element)
7883 element = GFX_ELEMENT(element);
7885 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL];
7888 int font2baseimg(int font_nr)
7890 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
7893 int getBeltNrFromBeltElement(int element)
7895 return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
7896 element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
7897 element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
7900 int getBeltNrFromBeltActiveElement(int element)
7902 return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
7903 element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
7904 element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
7907 int getBeltNrFromBeltSwitchElement(int element)
7909 return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
7910 element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
7911 element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
7914 int getBeltDirNrFromBeltElement(int element)
7916 static int belt_base_element[4] =
7918 EL_CONVEYOR_BELT_1_LEFT,
7919 EL_CONVEYOR_BELT_2_LEFT,
7920 EL_CONVEYOR_BELT_3_LEFT,
7921 EL_CONVEYOR_BELT_4_LEFT
7924 int belt_nr = getBeltNrFromBeltElement(element);
7925 int belt_dir_nr = element - belt_base_element[belt_nr];
7927 return (belt_dir_nr % 3);
7930 int getBeltDirNrFromBeltSwitchElement(int element)
7932 static int belt_base_element[4] =
7934 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
7935 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
7936 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
7937 EL_CONVEYOR_BELT_4_SWITCH_LEFT
7940 int belt_nr = getBeltNrFromBeltSwitchElement(element);
7941 int belt_dir_nr = element - belt_base_element[belt_nr];
7943 return (belt_dir_nr % 3);
7946 int getBeltDirFromBeltElement(int element)
7948 static int belt_move_dir[3] =
7955 int belt_dir_nr = getBeltDirNrFromBeltElement(element);
7957 return belt_move_dir[belt_dir_nr];
7960 int getBeltDirFromBeltSwitchElement(int element)
7962 static int belt_move_dir[3] =
7969 int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
7971 return belt_move_dir[belt_dir_nr];
7974 int getBeltElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
7976 static int belt_base_element[4] =
7978 EL_CONVEYOR_BELT_1_LEFT,
7979 EL_CONVEYOR_BELT_2_LEFT,
7980 EL_CONVEYOR_BELT_3_LEFT,
7981 EL_CONVEYOR_BELT_4_LEFT
7984 return belt_base_element[belt_nr] + belt_dir_nr;
7987 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
7989 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
7991 return getBeltElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
7994 int getBeltSwitchElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
7996 static int belt_base_element[4] =
7998 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
7999 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
8000 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
8001 EL_CONVEYOR_BELT_4_SWITCH_LEFT
8004 return belt_base_element[belt_nr] + belt_dir_nr;
8007 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
8009 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
8011 return getBeltSwitchElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
8014 boolean getTeamMode_EM()
8016 return game.team_mode;
8019 int getGameFrameDelay_EM(int native_em_game_frame_delay)
8021 int game_frame_delay_value;
8023 game_frame_delay_value =
8024 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
8025 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
8028 if (tape.playing && tape.warp_forward && !tape.pausing)
8029 game_frame_delay_value = 0;
8031 return game_frame_delay_value;
8034 unsigned int InitRND(int seed)
8036 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
8037 return InitEngineRandom_EM(seed);
8038 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
8039 return InitEngineRandom_SP(seed);
8040 else if (level.game_engine_type == GAME_ENGINE_TYPE_MM)
8041 return InitEngineRandom_MM(seed);
8043 return InitEngineRandom_RND(seed);
8046 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
8047 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
8049 inline static int get_effective_element_EM(int tile, int frame_em)
8051 int element = object_mapping[tile].element_rnd;
8052 int action = object_mapping[tile].action;
8053 boolean is_backside = object_mapping[tile].is_backside;
8054 boolean action_removing = (action == ACTION_DIGGING ||
8055 action == ACTION_SNAPPING ||
8056 action == ACTION_COLLECTING);
8062 case Yacid_splash_eB:
8063 case Yacid_splash_wB:
8064 return (frame_em > 5 ? EL_EMPTY : element);
8070 else /* frame_em == 7 */
8074 case Yacid_splash_eB:
8075 case Yacid_splash_wB:
8078 case Yemerald_stone:
8081 case Ydiamond_stone:
8085 case Xdrip_stretchB:
8104 case Xsand_stonein_1:
8105 case Xsand_stonein_2:
8106 case Xsand_stonein_3:
8107 case Xsand_stonein_4:
8111 return (is_backside || action_removing ? EL_EMPTY : element);
8116 inline static boolean check_linear_animation_EM(int tile)
8120 case Xsand_stonesand_1:
8121 case Xsand_stonesand_quickout_1:
8122 case Xsand_sandstone_1:
8123 case Xsand_stonein_1:
8124 case Xsand_stoneout_1:
8143 case Yacid_splash_eB:
8144 case Yacid_splash_wB:
8145 case Yemerald_stone:
8152 inline static void set_crumbled_graphics_EM(struct GraphicInfo_EM *g_em,
8153 boolean has_crumbled_graphics,
8154 int crumbled, int sync_frame)
8156 /* if element can be crumbled, but certain action graphics are just empty
8157 space (like instantly snapping sand to empty space in 1 frame), do not
8158 treat these empty space graphics as crumbled graphics in EMC engine */
8159 if (crumbled == IMG_EMPTY_SPACE)
8160 has_crumbled_graphics = FALSE;
8162 if (has_crumbled_graphics)
8164 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
8165 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
8166 g_crumbled->anim_delay,
8167 g_crumbled->anim_mode,
8168 g_crumbled->anim_start_frame,
8171 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
8172 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
8174 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
8175 g_em->crumbled_tile_size = graphic_info[crumbled].tile_size;
8177 g_em->has_crumbled_graphics = TRUE;
8181 g_em->crumbled_bitmap = NULL;
8182 g_em->crumbled_src_x = 0;
8183 g_em->crumbled_src_y = 0;
8184 g_em->crumbled_border_size = 0;
8185 g_em->crumbled_tile_size = 0;
8187 g_em->has_crumbled_graphics = FALSE;
8191 void ResetGfxAnimation_EM(int x, int y, int tile)
8196 void SetGfxAnimation_EM(struct GraphicInfo_EM *g_em,
8197 int tile, int frame_em, int x, int y)
8199 int action = object_mapping[tile].action;
8200 int direction = object_mapping[tile].direction;
8201 int effective_element = get_effective_element_EM(tile, frame_em);
8202 int graphic = (direction == MV_NONE ?
8203 el_act2img(effective_element, action) :
8204 el_act_dir2img(effective_element, action, direction));
8205 struct GraphicInfo *g = &graphic_info[graphic];
8207 boolean action_removing = (action == ACTION_DIGGING ||
8208 action == ACTION_SNAPPING ||
8209 action == ACTION_COLLECTING);
8210 boolean action_moving = (action == ACTION_FALLING ||
8211 action == ACTION_MOVING ||
8212 action == ACTION_PUSHING ||
8213 action == ACTION_EATING ||
8214 action == ACTION_FILLING ||
8215 action == ACTION_EMPTYING);
8216 boolean action_falling = (action == ACTION_FALLING ||
8217 action == ACTION_FILLING ||
8218 action == ACTION_EMPTYING);
8220 /* special case: graphic uses "2nd movement tile" and has defined
8221 7 frames for movement animation (or less) => use default graphic
8222 for last (8th) frame which ends the movement animation */
8223 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
8225 action = ACTION_DEFAULT; /* (keep action_* unchanged for now) */
8226 graphic = (direction == MV_NONE ?
8227 el_act2img(effective_element, action) :
8228 el_act_dir2img(effective_element, action, direction));
8230 g = &graphic_info[graphic];
8233 if ((action_removing || check_linear_animation_EM(tile)) && frame_em == 0)
8237 else if (action_moving)
8239 boolean is_backside = object_mapping[tile].is_backside;
8243 int direction = object_mapping[tile].direction;
8244 int move_dir = (action_falling ? MV_DOWN : direction);
8249 /* !!! TEST !!! NEW !!! DOES NOT WORK RIGHT YET !!! */
8250 if (g->double_movement && frame_em == 0)
8254 if (move_dir == MV_LEFT)
8255 GfxFrame[x - 1][y] = GfxFrame[x][y];
8256 else if (move_dir == MV_RIGHT)
8257 GfxFrame[x + 1][y] = GfxFrame[x][y];
8258 else if (move_dir == MV_UP)
8259 GfxFrame[x][y - 1] = GfxFrame[x][y];
8260 else if (move_dir == MV_DOWN)
8261 GfxFrame[x][y + 1] = GfxFrame[x][y];
8268 /* special case: animation for Xsand_stonesand_quickout_1/2 twice as fast */
8269 if (tile == Xsand_stonesand_quickout_1 ||
8270 tile == Xsand_stonesand_quickout_2)
8274 if (graphic_info[graphic].anim_global_sync)
8275 sync_frame = FrameCounter;
8276 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
8277 sync_frame = GfxFrame[x][y];
8279 sync_frame = 0; /* playfield border (pseudo steel) */
8281 SetRandomAnimationValue(x, y);
8283 int frame = getAnimationFrame(g->anim_frames,
8286 g->anim_start_frame,
8289 g_em->unique_identifier =
8290 (graphic << 16) | ((frame % 8) << 12) | (g_em->width << 6) | g_em->height;
8293 void getGraphicSourceObjectExt_EM(struct GraphicInfo_EM *g_em,
8294 int tile, int frame_em, int x, int y)
8296 int action = object_mapping[tile].action;
8297 int direction = object_mapping[tile].direction;
8298 boolean is_backside = object_mapping[tile].is_backside;
8299 int effective_element = get_effective_element_EM(tile, frame_em);
8300 int effective_action = action;
8301 int graphic = (direction == MV_NONE ?
8302 el_act2img(effective_element, effective_action) :
8303 el_act_dir2img(effective_element, effective_action,
8305 int crumbled = (direction == MV_NONE ?
8306 el_act2crm(effective_element, effective_action) :
8307 el_act_dir2crm(effective_element, effective_action,
8309 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
8310 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
8311 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
8312 struct GraphicInfo *g = &graphic_info[graphic];
8315 /* special case: graphic uses "2nd movement tile" and has defined
8316 7 frames for movement animation (or less) => use default graphic
8317 for last (8th) frame which ends the movement animation */
8318 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
8320 effective_action = ACTION_DEFAULT;
8321 graphic = (direction == MV_NONE ?
8322 el_act2img(effective_element, effective_action) :
8323 el_act_dir2img(effective_element, effective_action,
8325 crumbled = (direction == MV_NONE ?
8326 el_act2crm(effective_element, effective_action) :
8327 el_act_dir2crm(effective_element, effective_action,
8330 g = &graphic_info[graphic];
8333 if (graphic_info[graphic].anim_global_sync)
8334 sync_frame = FrameCounter;
8335 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
8336 sync_frame = GfxFrame[x][y];
8338 sync_frame = 0; /* playfield border (pseudo steel) */
8340 SetRandomAnimationValue(x, y);
8342 int frame = getAnimationFrame(g->anim_frames,
8345 g->anim_start_frame,
8348 getGraphicSourceExt(graphic, frame, &g_em->bitmap, &g_em->src_x, &g_em->src_y,
8349 g->double_movement && is_backside);
8351 /* (updating the "crumbled" graphic definitions is probably not really needed,
8352 as animations for crumbled graphics can't be longer than one EMC cycle) */
8353 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
8357 void getGraphicSourcePlayerExt_EM(struct GraphicInfo_EM *g_em,
8358 int player_nr, int anim, int frame_em)
8360 int element = player_mapping[player_nr][anim].element_rnd;
8361 int action = player_mapping[player_nr][anim].action;
8362 int direction = player_mapping[player_nr][anim].direction;
8363 int graphic = (direction == MV_NONE ?
8364 el_act2img(element, action) :
8365 el_act_dir2img(element, action, direction));
8366 struct GraphicInfo *g = &graphic_info[graphic];
8369 InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
8371 stored_player[player_nr].StepFrame = frame_em;
8373 sync_frame = stored_player[player_nr].Frame;
8375 int frame = getAnimationFrame(g->anim_frames,
8378 g->anim_start_frame,
8381 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
8382 &g_em->src_x, &g_em->src_y, FALSE);
8385 void InitGraphicInfo_EM(void)
8390 int num_em_gfx_errors = 0;
8392 if (graphic_info_em_object[0][0].bitmap == NULL)
8394 /* EM graphics not yet initialized in em_open_all() */
8399 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
8402 /* always start with reliable default values */
8403 for (i = 0; i < TILE_MAX; i++)
8405 object_mapping[i].element_rnd = EL_UNKNOWN;
8406 object_mapping[i].is_backside = FALSE;
8407 object_mapping[i].action = ACTION_DEFAULT;
8408 object_mapping[i].direction = MV_NONE;
8411 /* always start with reliable default values */
8412 for (p = 0; p < MAX_PLAYERS; p++)
8414 for (i = 0; i < SPR_MAX; i++)
8416 player_mapping[p][i].element_rnd = EL_UNKNOWN;
8417 player_mapping[p][i].action = ACTION_DEFAULT;
8418 player_mapping[p][i].direction = MV_NONE;
8422 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
8424 int e = em_object_mapping_list[i].element_em;
8426 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
8427 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
8429 if (em_object_mapping_list[i].action != -1)
8430 object_mapping[e].action = em_object_mapping_list[i].action;
8432 if (em_object_mapping_list[i].direction != -1)
8433 object_mapping[e].direction =
8434 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
8437 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
8439 int a = em_player_mapping_list[i].action_em;
8440 int p = em_player_mapping_list[i].player_nr;
8442 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
8444 if (em_player_mapping_list[i].action != -1)
8445 player_mapping[p][a].action = em_player_mapping_list[i].action;
8447 if (em_player_mapping_list[i].direction != -1)
8448 player_mapping[p][a].direction =
8449 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
8452 for (i = 0; i < TILE_MAX; i++)
8454 int element = object_mapping[i].element_rnd;
8455 int action = object_mapping[i].action;
8456 int direction = object_mapping[i].direction;
8457 boolean is_backside = object_mapping[i].is_backside;
8458 boolean action_exploding = ((action == ACTION_EXPLODING ||
8459 action == ACTION_SMASHED_BY_ROCK ||
8460 action == ACTION_SMASHED_BY_SPRING) &&
8461 element != EL_DIAMOND);
8462 boolean action_active = (action == ACTION_ACTIVE);
8463 boolean action_other = (action == ACTION_OTHER);
8465 for (j = 0; j < 8; j++)
8467 int effective_element = get_effective_element_EM(i, j);
8468 int effective_action = (j < 7 ? action :
8469 i == Xdrip_stretch ? action :
8470 i == Xdrip_stretchB ? action :
8471 i == Ydrip_s1 ? action :
8472 i == Ydrip_s1B ? action :
8473 i == Xball_1B ? action :
8474 i == Xball_2 ? action :
8475 i == Xball_2B ? action :
8476 i == Yball_eat ? action :
8477 i == Ykey_1_eat ? action :
8478 i == Ykey_2_eat ? action :
8479 i == Ykey_3_eat ? action :
8480 i == Ykey_4_eat ? action :
8481 i == Ykey_5_eat ? action :
8482 i == Ykey_6_eat ? action :
8483 i == Ykey_7_eat ? action :
8484 i == Ykey_8_eat ? action :
8485 i == Ylenses_eat ? action :
8486 i == Ymagnify_eat ? action :
8487 i == Ygrass_eat ? action :
8488 i == Ydirt_eat ? action :
8489 i == Xsand_stonein_1 ? action :
8490 i == Xsand_stonein_2 ? action :
8491 i == Xsand_stonein_3 ? action :
8492 i == Xsand_stonein_4 ? action :
8493 i == Xsand_stoneout_1 ? action :
8494 i == Xsand_stoneout_2 ? action :
8495 i == Xboom_android ? ACTION_EXPLODING :
8496 action_exploding ? ACTION_EXPLODING :
8497 action_active ? action :
8498 action_other ? action :
8500 int graphic = (el_act_dir2img(effective_element, effective_action,
8502 int crumbled = (el_act_dir2crm(effective_element, effective_action,
8504 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
8505 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
8506 boolean has_action_graphics = (graphic != base_graphic);
8507 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
8508 struct GraphicInfo *g = &graphic_info[graphic];
8509 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
8512 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
8513 boolean special_animation = (action != ACTION_DEFAULT &&
8514 g->anim_frames == 3 &&
8515 g->anim_delay == 2 &&
8516 g->anim_mode & ANIM_LINEAR);
8517 int sync_frame = (i == Xdrip_stretch ? 7 :
8518 i == Xdrip_stretchB ? 7 :
8519 i == Ydrip_s2 ? j + 8 :
8520 i == Ydrip_s2B ? j + 8 :
8529 i == Xfake_acid_1 ? 0 :
8530 i == Xfake_acid_2 ? 10 :
8531 i == Xfake_acid_3 ? 20 :
8532 i == Xfake_acid_4 ? 30 :
8533 i == Xfake_acid_5 ? 40 :
8534 i == Xfake_acid_6 ? 50 :
8535 i == Xfake_acid_7 ? 60 :
8536 i == Xfake_acid_8 ? 70 :
8538 i == Xball_2B ? j + 8 :
8539 i == Yball_eat ? j + 1 :
8540 i == Ykey_1_eat ? j + 1 :
8541 i == Ykey_2_eat ? j + 1 :
8542 i == Ykey_3_eat ? j + 1 :
8543 i == Ykey_4_eat ? j + 1 :
8544 i == Ykey_5_eat ? j + 1 :
8545 i == Ykey_6_eat ? j + 1 :
8546 i == Ykey_7_eat ? j + 1 :
8547 i == Ykey_8_eat ? j + 1 :
8548 i == Ylenses_eat ? j + 1 :
8549 i == Ymagnify_eat ? j + 1 :
8550 i == Ygrass_eat ? j + 1 :
8551 i == Ydirt_eat ? j + 1 :
8552 i == Xamoeba_1 ? 0 :
8553 i == Xamoeba_2 ? 1 :
8554 i == Xamoeba_3 ? 2 :
8555 i == Xamoeba_4 ? 3 :
8556 i == Xamoeba_5 ? 0 :
8557 i == Xamoeba_6 ? 1 :
8558 i == Xamoeba_7 ? 2 :
8559 i == Xamoeba_8 ? 3 :
8560 i == Xexit_2 ? j + 8 :
8561 i == Xexit_3 ? j + 16 :
8562 i == Xdynamite_1 ? 0 :
8563 i == Xdynamite_2 ? 8 :
8564 i == Xdynamite_3 ? 16 :
8565 i == Xdynamite_4 ? 24 :
8566 i == Xsand_stonein_1 ? j + 1 :
8567 i == Xsand_stonein_2 ? j + 9 :
8568 i == Xsand_stonein_3 ? j + 17 :
8569 i == Xsand_stonein_4 ? j + 25 :
8570 i == Xsand_stoneout_1 && j == 0 ? 0 :
8571 i == Xsand_stoneout_1 && j == 1 ? 0 :
8572 i == Xsand_stoneout_1 && j == 2 ? 1 :
8573 i == Xsand_stoneout_1 && j == 3 ? 2 :
8574 i == Xsand_stoneout_1 && j == 4 ? 2 :
8575 i == Xsand_stoneout_1 && j == 5 ? 3 :
8576 i == Xsand_stoneout_1 && j == 6 ? 4 :
8577 i == Xsand_stoneout_1 && j == 7 ? 4 :
8578 i == Xsand_stoneout_2 && j == 0 ? 5 :
8579 i == Xsand_stoneout_2 && j == 1 ? 6 :
8580 i == Xsand_stoneout_2 && j == 2 ? 7 :
8581 i == Xsand_stoneout_2 && j == 3 ? 8 :
8582 i == Xsand_stoneout_2 && j == 4 ? 9 :
8583 i == Xsand_stoneout_2 && j == 5 ? 11 :
8584 i == Xsand_stoneout_2 && j == 6 ? 13 :
8585 i == Xsand_stoneout_2 && j == 7 ? 15 :
8586 i == Xboom_bug && j == 1 ? 2 :
8587 i == Xboom_bug && j == 2 ? 2 :
8588 i == Xboom_bug && j == 3 ? 4 :
8589 i == Xboom_bug && j == 4 ? 4 :
8590 i == Xboom_bug && j == 5 ? 2 :
8591 i == Xboom_bug && j == 6 ? 2 :
8592 i == Xboom_bug && j == 7 ? 0 :
8593 i == Xboom_bomb && j == 1 ? 2 :
8594 i == Xboom_bomb && j == 2 ? 2 :
8595 i == Xboom_bomb && j == 3 ? 4 :
8596 i == Xboom_bomb && j == 4 ? 4 :
8597 i == Xboom_bomb && j == 5 ? 2 :
8598 i == Xboom_bomb && j == 6 ? 2 :
8599 i == Xboom_bomb && j == 7 ? 0 :
8600 i == Xboom_android && j == 7 ? 6 :
8601 i == Xboom_1 && j == 1 ? 2 :
8602 i == Xboom_1 && j == 2 ? 2 :
8603 i == Xboom_1 && j == 3 ? 4 :
8604 i == Xboom_1 && j == 4 ? 4 :
8605 i == Xboom_1 && j == 5 ? 6 :
8606 i == Xboom_1 && j == 6 ? 6 :
8607 i == Xboom_1 && j == 7 ? 8 :
8608 i == Xboom_2 && j == 0 ? 8 :
8609 i == Xboom_2 && j == 1 ? 8 :
8610 i == Xboom_2 && j == 2 ? 10 :
8611 i == Xboom_2 && j == 3 ? 10 :
8612 i == Xboom_2 && j == 4 ? 10 :
8613 i == Xboom_2 && j == 5 ? 12 :
8614 i == Xboom_2 && j == 6 ? 12 :
8615 i == Xboom_2 && j == 7 ? 12 :
8616 special_animation && j == 4 ? 3 :
8617 effective_action != action ? 0 :
8621 Bitmap *debug_bitmap = g_em->bitmap;
8622 int debug_src_x = g_em->src_x;
8623 int debug_src_y = g_em->src_y;
8626 int frame = getAnimationFrame(g->anim_frames,
8629 g->anim_start_frame,
8632 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
8633 g->double_movement && is_backside);
8635 g_em->bitmap = src_bitmap;
8636 g_em->src_x = src_x;
8637 g_em->src_y = src_y;
8638 g_em->src_offset_x = 0;
8639 g_em->src_offset_y = 0;
8640 g_em->dst_offset_x = 0;
8641 g_em->dst_offset_y = 0;
8642 g_em->width = TILEX;
8643 g_em->height = TILEY;
8645 g_em->preserve_background = FALSE;
8647 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
8650 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
8651 effective_action == ACTION_MOVING ||
8652 effective_action == ACTION_PUSHING ||
8653 effective_action == ACTION_EATING)) ||
8654 (!has_action_graphics && (effective_action == ACTION_FILLING ||
8655 effective_action == ACTION_EMPTYING)))
8658 (effective_action == ACTION_FALLING ||
8659 effective_action == ACTION_FILLING ||
8660 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
8661 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
8662 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
8663 int num_steps = (i == Ydrip_s1 ? 16 :
8664 i == Ydrip_s1B ? 16 :
8665 i == Ydrip_s2 ? 16 :
8666 i == Ydrip_s2B ? 16 :
8667 i == Xsand_stonein_1 ? 32 :
8668 i == Xsand_stonein_2 ? 32 :
8669 i == Xsand_stonein_3 ? 32 :
8670 i == Xsand_stonein_4 ? 32 :
8671 i == Xsand_stoneout_1 ? 16 :
8672 i == Xsand_stoneout_2 ? 16 : 8);
8673 int cx = ABS(dx) * (TILEX / num_steps);
8674 int cy = ABS(dy) * (TILEY / num_steps);
8675 int step_frame = (i == Ydrip_s2 ? j + 8 :
8676 i == Ydrip_s2B ? j + 8 :
8677 i == Xsand_stonein_2 ? j + 8 :
8678 i == Xsand_stonein_3 ? j + 16 :
8679 i == Xsand_stonein_4 ? j + 24 :
8680 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
8681 int step = (is_backside ? step_frame : num_steps - step_frame);
8683 if (is_backside) /* tile where movement starts */
8685 if (dx < 0 || dy < 0)
8687 g_em->src_offset_x = cx * step;
8688 g_em->src_offset_y = cy * step;
8692 g_em->dst_offset_x = cx * step;
8693 g_em->dst_offset_y = cy * step;
8696 else /* tile where movement ends */
8698 if (dx < 0 || dy < 0)
8700 g_em->dst_offset_x = cx * step;
8701 g_em->dst_offset_y = cy * step;
8705 g_em->src_offset_x = cx * step;
8706 g_em->src_offset_y = cy * step;
8710 g_em->width = TILEX - cx * step;
8711 g_em->height = TILEY - cy * step;
8714 /* create unique graphic identifier to decide if tile must be redrawn */
8715 /* bit 31 - 16 (16 bit): EM style graphic
8716 bit 15 - 12 ( 4 bit): EM style frame
8717 bit 11 - 6 ( 6 bit): graphic width
8718 bit 5 - 0 ( 6 bit): graphic height */
8719 g_em->unique_identifier =
8720 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
8724 /* skip check for EMC elements not contained in original EMC artwork */
8725 if (element == EL_EMC_FAKE_ACID)
8728 if (g_em->bitmap != debug_bitmap ||
8729 g_em->src_x != debug_src_x ||
8730 g_em->src_y != debug_src_y ||
8731 g_em->src_offset_x != 0 ||
8732 g_em->src_offset_y != 0 ||
8733 g_em->dst_offset_x != 0 ||
8734 g_em->dst_offset_y != 0 ||
8735 g_em->width != TILEX ||
8736 g_em->height != TILEY)
8738 static int last_i = -1;
8746 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
8747 i, element, element_info[element].token_name,
8748 element_action_info[effective_action].suffix, direction);
8750 if (element != effective_element)
8751 printf(" [%d ('%s')]",
8753 element_info[effective_element].token_name);
8757 if (g_em->bitmap != debug_bitmap)
8758 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
8759 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
8761 if (g_em->src_x != debug_src_x ||
8762 g_em->src_y != debug_src_y)
8763 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
8764 j, (is_backside ? 'B' : 'F'),
8765 g_em->src_x, g_em->src_y,
8766 g_em->src_x / 32, g_em->src_y / 32,
8767 debug_src_x, debug_src_y,
8768 debug_src_x / 32, debug_src_y / 32);
8770 if (g_em->src_offset_x != 0 ||
8771 g_em->src_offset_y != 0 ||
8772 g_em->dst_offset_x != 0 ||
8773 g_em->dst_offset_y != 0)
8774 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
8776 g_em->src_offset_x, g_em->src_offset_y,
8777 g_em->dst_offset_x, g_em->dst_offset_y);
8779 if (g_em->width != TILEX ||
8780 g_em->height != TILEY)
8781 printf(" %d (%d): size %d,%d should be %d,%d\n",
8783 g_em->width, g_em->height, TILEX, TILEY);
8785 num_em_gfx_errors++;
8792 for (i = 0; i < TILE_MAX; i++)
8794 for (j = 0; j < 8; j++)
8796 int element = object_mapping[i].element_rnd;
8797 int action = object_mapping[i].action;
8798 int direction = object_mapping[i].direction;
8799 boolean is_backside = object_mapping[i].is_backside;
8800 int graphic_action = el_act_dir2img(element, action, direction);
8801 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
8803 if ((action == ACTION_SMASHED_BY_ROCK ||
8804 action == ACTION_SMASHED_BY_SPRING ||
8805 action == ACTION_EATING) &&
8806 graphic_action == graphic_default)
8808 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
8809 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
8810 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
8811 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
8814 /* no separate animation for "smashed by rock" -- use rock instead */
8815 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
8816 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
8818 g_em->bitmap = g_xx->bitmap;
8819 g_em->src_x = g_xx->src_x;
8820 g_em->src_y = g_xx->src_y;
8821 g_em->src_offset_x = g_xx->src_offset_x;
8822 g_em->src_offset_y = g_xx->src_offset_y;
8823 g_em->dst_offset_x = g_xx->dst_offset_x;
8824 g_em->dst_offset_y = g_xx->dst_offset_y;
8825 g_em->width = g_xx->width;
8826 g_em->height = g_xx->height;
8827 g_em->unique_identifier = g_xx->unique_identifier;
8830 g_em->preserve_background = TRUE;
8835 for (p = 0; p < MAX_PLAYERS; p++)
8837 for (i = 0; i < SPR_MAX; i++)
8839 int element = player_mapping[p][i].element_rnd;
8840 int action = player_mapping[p][i].action;
8841 int direction = player_mapping[p][i].direction;
8843 for (j = 0; j < 8; j++)
8845 int effective_element = element;
8846 int effective_action = action;
8847 int graphic = (direction == MV_NONE ?
8848 el_act2img(effective_element, effective_action) :
8849 el_act_dir2img(effective_element, effective_action,
8851 struct GraphicInfo *g = &graphic_info[graphic];
8852 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
8858 Bitmap *debug_bitmap = g_em->bitmap;
8859 int debug_src_x = g_em->src_x;
8860 int debug_src_y = g_em->src_y;
8863 int frame = getAnimationFrame(g->anim_frames,
8866 g->anim_start_frame,
8869 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
8871 g_em->bitmap = src_bitmap;
8872 g_em->src_x = src_x;
8873 g_em->src_y = src_y;
8874 g_em->src_offset_x = 0;
8875 g_em->src_offset_y = 0;
8876 g_em->dst_offset_x = 0;
8877 g_em->dst_offset_y = 0;
8878 g_em->width = TILEX;
8879 g_em->height = TILEY;
8883 /* skip check for EMC elements not contained in original EMC artwork */
8884 if (element == EL_PLAYER_3 ||
8885 element == EL_PLAYER_4)
8888 if (g_em->bitmap != debug_bitmap ||
8889 g_em->src_x != debug_src_x ||
8890 g_em->src_y != debug_src_y)
8892 static int last_i = -1;
8900 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
8901 p, i, element, element_info[element].token_name,
8902 element_action_info[effective_action].suffix, direction);
8904 if (element != effective_element)
8905 printf(" [%d ('%s')]",
8907 element_info[effective_element].token_name);
8911 if (g_em->bitmap != debug_bitmap)
8912 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
8913 j, (int)(g_em->bitmap), (int)(debug_bitmap));
8915 if (g_em->src_x != debug_src_x ||
8916 g_em->src_y != debug_src_y)
8917 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
8919 g_em->src_x, g_em->src_y,
8920 g_em->src_x / 32, g_em->src_y / 32,
8921 debug_src_x, debug_src_y,
8922 debug_src_x / 32, debug_src_y / 32);
8924 num_em_gfx_errors++;
8934 printf("::: [%d errors found]\n", num_em_gfx_errors);
8940 void CheckSaveEngineSnapshot_EM(byte action[MAX_PLAYERS], int frame,
8941 boolean any_player_moving,
8942 boolean any_player_snapping,
8943 boolean any_player_dropping)
8945 if (frame == 0 && !any_player_dropping)
8947 if (!local_player->was_waiting)
8949 if (!CheckSaveEngineSnapshotToList())
8952 local_player->was_waiting = TRUE;
8955 else if (any_player_moving || any_player_snapping || any_player_dropping)
8957 local_player->was_waiting = FALSE;
8961 void CheckSaveEngineSnapshot_SP(boolean murphy_is_waiting,
8962 boolean murphy_is_dropping)
8964 if (murphy_is_waiting)
8966 if (!local_player->was_waiting)
8968 if (!CheckSaveEngineSnapshotToList())
8971 local_player->was_waiting = TRUE;
8976 local_player->was_waiting = FALSE;
8980 void CheckSaveEngineSnapshot_MM(boolean element_clicked,
8981 boolean button_released)
8983 if (button_released)
8985 if (game.snapshot.mode == SNAPSHOT_MODE_EVERY_MOVE)
8986 CheckSaveEngineSnapshotToList();
8988 else if (element_clicked)
8990 if (game.snapshot.mode != SNAPSHOT_MODE_EVERY_MOVE)
8991 CheckSaveEngineSnapshotToList();
8993 game.snapshot.changed_action = TRUE;
8997 void CheckSingleStepMode_EM(byte action[MAX_PLAYERS], int frame,
8998 boolean any_player_moving,
8999 boolean any_player_snapping,
9000 boolean any_player_dropping)
9002 if (tape.single_step && tape.recording && !tape.pausing)
9003 if (frame == 0 && !any_player_dropping)
9004 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
9006 CheckSaveEngineSnapshot_EM(action, frame, any_player_moving,
9007 any_player_snapping, any_player_dropping);
9010 void CheckSingleStepMode_SP(boolean murphy_is_waiting,
9011 boolean murphy_is_dropping)
9013 boolean murphy_starts_dropping = FALSE;
9016 for (i = 0; i < MAX_PLAYERS; i++)
9017 if (stored_player[i].force_dropping)
9018 murphy_starts_dropping = TRUE;
9020 if (tape.single_step && tape.recording && !tape.pausing)
9021 if (murphy_is_waiting && !murphy_starts_dropping)
9022 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
9024 CheckSaveEngineSnapshot_SP(murphy_is_waiting, murphy_is_dropping);
9027 void CheckSingleStepMode_MM(boolean element_clicked,
9028 boolean button_released)
9030 if (tape.single_step && tape.recording && !tape.pausing)
9031 if (button_released)
9032 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
9034 CheckSaveEngineSnapshot_MM(element_clicked, button_released);
9037 void getGraphicSource_SP(struct GraphicInfo_SP *g_sp,
9038 int graphic, int sync_frame, int x, int y)
9040 int frame = getGraphicAnimationFrame(graphic, sync_frame);
9042 getGraphicSource(graphic, frame, &g_sp->bitmap, &g_sp->src_x, &g_sp->src_y);
9045 boolean isNextAnimationFrame_SP(int graphic, int sync_frame)
9047 return (IS_NEXT_FRAME(sync_frame, graphic));
9050 int getGraphicInfo_Delay(int graphic)
9052 return graphic_info[graphic].anim_delay;
9055 void PlayMenuSoundExt(int sound)
9057 if (sound == SND_UNDEFINED)
9060 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
9061 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
9064 if (IS_LOOP_SOUND(sound))
9065 PlaySoundLoop(sound);
9070 void PlayMenuSound()
9072 PlayMenuSoundExt(menu.sound[game_status]);
9075 void PlayMenuSoundStereo(int sound, int stereo_position)
9077 if (sound == SND_UNDEFINED)
9080 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
9081 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
9084 if (IS_LOOP_SOUND(sound))
9085 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
9087 PlaySoundStereo(sound, stereo_position);
9090 void PlayMenuSoundIfLoopExt(int sound)
9092 if (sound == SND_UNDEFINED)
9095 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
9096 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
9099 if (IS_LOOP_SOUND(sound))
9100 PlaySoundLoop(sound);
9103 void PlayMenuSoundIfLoop()
9105 PlayMenuSoundIfLoopExt(menu.sound[game_status]);
9108 void PlayMenuMusicExt(int music)
9110 if (music == MUS_UNDEFINED)
9113 if (!setup.sound_music)
9119 void PlayMenuMusic()
9121 char *curr_music = getCurrentlyPlayingMusicFilename();
9122 char *next_music = getMusicInfoEntryFilename(menu.music[game_status]);
9124 if (!strEqual(curr_music, next_music))
9125 PlayMenuMusicExt(menu.music[game_status]);
9128 void PlayMenuSoundsAndMusic()
9134 static void FadeMenuSounds()
9139 static void FadeMenuMusic()
9141 char *curr_music = getCurrentlyPlayingMusicFilename();
9142 char *next_music = getMusicInfoEntryFilename(menu.music[game_status]);
9144 if (!strEqual(curr_music, next_music))
9148 void FadeMenuSoundsAndMusic()
9154 void PlaySoundActivating()
9157 PlaySound(SND_MENU_ITEM_ACTIVATING);
9161 void PlaySoundSelecting()
9164 PlaySound(SND_MENU_ITEM_SELECTING);
9168 void ToggleFullscreenOrChangeWindowScalingIfNeeded()
9170 boolean change_fullscreen = (setup.fullscreen !=
9171 video.fullscreen_enabled);
9172 boolean change_window_scaling_percent = (!video.fullscreen_enabled &&
9173 setup.window_scaling_percent !=
9174 video.window_scaling_percent);
9176 if (change_window_scaling_percent && video.fullscreen_enabled)
9179 if (!change_window_scaling_percent && !video.fullscreen_available)
9182 #if defined(TARGET_SDL2)
9183 if (change_window_scaling_percent)
9185 SDLSetWindowScaling(setup.window_scaling_percent);
9189 else if (change_fullscreen)
9191 SDLSetWindowFullscreen(setup.fullscreen);
9193 /* set setup value according to successfully changed fullscreen mode */
9194 setup.fullscreen = video.fullscreen_enabled;
9200 if (change_fullscreen ||
9201 change_window_scaling_percent)
9203 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
9205 /* save backbuffer content which gets lost when toggling fullscreen mode */
9206 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
9208 if (change_window_scaling_percent)
9210 /* keep window mode, but change window scaling */
9211 video.fullscreen_enabled = TRUE; /* force new window scaling */
9214 /* toggle fullscreen */
9215 ChangeVideoModeIfNeeded(setup.fullscreen);
9217 /* set setup value according to successfully changed fullscreen mode */
9218 setup.fullscreen = video.fullscreen_enabled;
9220 /* restore backbuffer content from temporary backbuffer backup bitmap */
9221 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
9223 FreeBitmap(tmp_backbuffer);
9225 /* update visible window/screen */
9226 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
9230 void JoinRectangles(int *x, int *y, int *width, int *height,
9231 int x2, int y2, int width2, int height2)
9233 // do not join with "off-screen" rectangle
9234 if (x2 == -1 || y2 == -1)
9239 *width = MAX(*width, width2);
9240 *height = MAX(*height, height2);
9243 void SetAnimStatus(int anim_status_new)
9245 if (anim_status_new == GAME_MODE_MAIN)
9246 anim_status_new = GAME_MODE_PSEUDO_MAINONLY;
9247 else if (anim_status_new == GAME_MODE_SCORES)
9248 anim_status_new = GAME_MODE_PSEUDO_SCORESOLD;
9250 global.anim_status_next = anim_status_new;
9252 // directly set screen modes that are entered without fading
9253 if ((global.anim_status == GAME_MODE_PSEUDO_MAINONLY &&
9254 global.anim_status_next == GAME_MODE_PSEUDO_TYPENAME) ||
9255 (global.anim_status == GAME_MODE_PSEUDO_TYPENAME &&
9256 global.anim_status_next == GAME_MODE_PSEUDO_MAINONLY))
9257 global.anim_status = global.anim_status_next;
9260 void SetGameStatus(int game_status_new)
9262 if (game_status_new != game_status)
9263 game_status_last_screen = game_status;
9265 game_status = game_status_new;
9267 SetAnimStatus(game_status_new);
9270 void SetFontStatus(int game_status_new)
9272 static int last_game_status = -1;
9274 if (game_status_new != -1)
9276 // set game status for font use after storing last game status
9277 last_game_status = game_status;
9278 game_status = game_status_new;
9282 // reset game status after font use from last stored game status
9283 game_status = last_game_status;
9287 void ResetFontStatus()
9292 boolean CheckIfPlayfieldViewportHasChanged()
9294 // if game status has not changed, playfield viewport has not changed either
9295 if (game_status == game_status_last)
9298 // check if playfield viewport has changed with current game status
9299 struct RectWithBorder *vp_playfield = &viewport.playfield[game_status];
9300 int new_real_sx = vp_playfield->x;
9301 int new_real_sy = vp_playfield->y;
9302 int new_full_sxsize = vp_playfield->width;
9303 int new_full_sysize = vp_playfield->height;
9305 return (new_real_sx != REAL_SX ||
9306 new_real_sy != REAL_SY ||
9307 new_full_sxsize != FULL_SXSIZE ||
9308 new_full_sysize != FULL_SYSIZE);
9311 boolean CheckIfGlobalBorderOrPlayfieldViewportHasChanged()
9313 return (CheckIfGlobalBorderHasChanged() ||
9314 CheckIfPlayfieldViewportHasChanged());
9317 void ChangeViewportPropertiesIfNeeded()
9319 boolean use_mini_tilesize = (level.game_engine_type == GAME_ENGINE_TYPE_MM ?
9320 FALSE : setup.small_game_graphics);
9321 int gfx_game_mode = game_status;
9322 int gfx_game_mode2 = (game_status == GAME_MODE_EDITOR ? GAME_MODE_DEFAULT :
9324 struct RectWithBorder *vp_window = &viewport.window[gfx_game_mode];
9325 struct RectWithBorder *vp_playfield = &viewport.playfield[gfx_game_mode];
9326 struct RectWithBorder *vp_door_1 = &viewport.door_1[gfx_game_mode];
9327 struct RectWithBorder *vp_door_2 = &viewport.door_2[gfx_game_mode2];
9328 struct RectWithBorder *vp_door_3 = &viewport.door_2[GAME_MODE_EDITOR];
9329 int new_win_xsize = vp_window->width;
9330 int new_win_ysize = vp_window->height;
9331 int border_size = vp_playfield->border_size;
9332 int new_sx = vp_playfield->x + border_size;
9333 int new_sy = vp_playfield->y + border_size;
9334 int new_sxsize = vp_playfield->width - 2 * border_size;
9335 int new_sysize = vp_playfield->height - 2 * border_size;
9336 int new_real_sx = vp_playfield->x;
9337 int new_real_sy = vp_playfield->y;
9338 int new_full_sxsize = vp_playfield->width;
9339 int new_full_sysize = vp_playfield->height;
9340 int new_dx = vp_door_1->x;
9341 int new_dy = vp_door_1->y;
9342 int new_dxsize = vp_door_1->width;
9343 int new_dysize = vp_door_1->height;
9344 int new_vx = vp_door_2->x;
9345 int new_vy = vp_door_2->y;
9346 int new_vxsize = vp_door_2->width;
9347 int new_vysize = vp_door_2->height;
9348 int new_ex = vp_door_3->x;
9349 int new_ey = vp_door_3->y;
9350 int new_exsize = vp_door_3->width;
9351 int new_eysize = vp_door_3->height;
9352 int new_tilesize_var = (use_mini_tilesize ? MINI_TILESIZE : game.tile_size);
9353 int tilesize = (gfx_game_mode == GAME_MODE_PLAYING ? new_tilesize_var :
9354 gfx_game_mode == GAME_MODE_EDITOR ? MINI_TILESIZE : TILESIZE);
9355 int new_scr_fieldx = new_sxsize / tilesize;
9356 int new_scr_fieldy = new_sysize / tilesize;
9357 int new_scr_fieldx_buffers = new_sxsize / new_tilesize_var;
9358 int new_scr_fieldy_buffers = new_sysize / new_tilesize_var;
9359 boolean init_gfx_buffers = FALSE;
9360 boolean init_video_buffer = FALSE;
9361 boolean init_gadgets_and_anims = FALSE;
9362 boolean init_em_graphics = FALSE;
9364 if (new_win_xsize != WIN_XSIZE ||
9365 new_win_ysize != WIN_YSIZE)
9367 WIN_XSIZE = new_win_xsize;
9368 WIN_YSIZE = new_win_ysize;
9370 init_video_buffer = TRUE;
9371 init_gfx_buffers = TRUE;
9372 init_gadgets_and_anims = TRUE;
9374 // printf("::: video: init_video_buffer, init_gfx_buffers\n");
9377 if (new_scr_fieldx != SCR_FIELDX ||
9378 new_scr_fieldy != SCR_FIELDY)
9380 /* this always toggles between MAIN and GAME when using small tile size */
9382 SCR_FIELDX = new_scr_fieldx;
9383 SCR_FIELDY = new_scr_fieldy;
9385 // printf("::: new_scr_fieldx != SCR_FIELDX ...\n");
9396 new_sxsize != SXSIZE ||
9397 new_sysize != SYSIZE ||
9398 new_dxsize != DXSIZE ||
9399 new_dysize != DYSIZE ||
9400 new_vxsize != VXSIZE ||
9401 new_vysize != VYSIZE ||
9402 new_exsize != EXSIZE ||
9403 new_eysize != EYSIZE ||
9404 new_real_sx != REAL_SX ||
9405 new_real_sy != REAL_SY ||
9406 new_full_sxsize != FULL_SXSIZE ||
9407 new_full_sysize != FULL_SYSIZE ||
9408 new_tilesize_var != TILESIZE_VAR
9411 // ------------------------------------------------------------------------
9412 // determine next fading area for changed viewport definitions
9413 // ------------------------------------------------------------------------
9415 // start with current playfield area (default fading area)
9418 FADE_SXSIZE = FULL_SXSIZE;
9419 FADE_SYSIZE = FULL_SYSIZE;
9421 // add new playfield area if position or size has changed
9422 if (new_real_sx != REAL_SX || new_real_sy != REAL_SY ||
9423 new_full_sxsize != FULL_SXSIZE || new_full_sysize != FULL_SYSIZE)
9425 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
9426 new_real_sx, new_real_sy, new_full_sxsize,new_full_sysize);
9429 // add current and new door 1 area if position or size has changed
9430 if (new_dx != DX || new_dy != DY ||
9431 new_dxsize != DXSIZE || new_dysize != DYSIZE)
9433 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
9434 DX, DY, DXSIZE, DYSIZE);
9435 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
9436 new_dx, new_dy, new_dxsize, new_dysize);
9439 // add current and new door 2 area if position or size has changed
9440 if (new_dx != VX || new_dy != VY ||
9441 new_dxsize != VXSIZE || new_dysize != VYSIZE)
9443 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
9444 VX, VY, VXSIZE, VYSIZE);
9445 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
9446 new_vx, new_vy, new_vxsize, new_vysize);
9449 // ------------------------------------------------------------------------
9450 // handle changed tile size
9451 // ------------------------------------------------------------------------
9453 if (new_tilesize_var != TILESIZE_VAR)
9455 // printf("::: new_tilesize_var != TILESIZE_VAR\n");
9457 // changing tile size invalidates scroll values of engine snapshots
9458 FreeEngineSnapshotSingle();
9460 // changing tile size requires update of graphic mapping for EM engine
9461 init_em_graphics = TRUE;
9472 SXSIZE = new_sxsize;
9473 SYSIZE = new_sysize;
9474 DXSIZE = new_dxsize;
9475 DYSIZE = new_dysize;
9476 VXSIZE = new_vxsize;
9477 VYSIZE = new_vysize;
9478 EXSIZE = new_exsize;
9479 EYSIZE = new_eysize;
9480 REAL_SX = new_real_sx;
9481 REAL_SY = new_real_sy;
9482 FULL_SXSIZE = new_full_sxsize;
9483 FULL_SYSIZE = new_full_sysize;
9484 TILESIZE_VAR = new_tilesize_var;
9486 init_gfx_buffers = TRUE;
9487 init_gadgets_and_anims = TRUE;
9489 // printf("::: viewports: init_gfx_buffers\n");
9490 // printf("::: viewports: init_gadgets_and_anims\n");
9493 if (init_gfx_buffers)
9495 // printf("::: init_gfx_buffers\n");
9497 SCR_FIELDX = new_scr_fieldx_buffers;
9498 SCR_FIELDY = new_scr_fieldy_buffers;
9502 SCR_FIELDX = new_scr_fieldx;
9503 SCR_FIELDY = new_scr_fieldy;
9505 SetDrawDeactivationMask(REDRAW_NONE);
9506 SetDrawBackgroundMask(REDRAW_FIELD);
9509 if (init_video_buffer)
9511 // printf("::: init_video_buffer\n");
9513 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
9514 InitImageTextures();
9517 if (init_gadgets_and_anims)
9519 // printf("::: init_gadgets_and_anims\n");
9522 InitGlobalAnimations();
9525 if (init_em_graphics)
9527 InitGraphicInfo_EM();