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 inline static void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
3518 int graphic, int sync_frame,
3521 int frame = getGraphicAnimationFrame(graphic, sync_frame);
3523 if (mask_mode == USE_MASKING)
3524 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
3526 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
3529 void DrawFixedGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
3530 int graphic, int sync_frame, int mask_mode)
3532 int frame = getGraphicAnimationFrame(graphic, sync_frame);
3534 if (mask_mode == USE_MASKING)
3535 DrawFixedGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
3537 DrawFixedGraphicExt(dst_bitmap, x, y, graphic, frame);
3540 inline static void DrawGraphicAnimation(int x, int y, int graphic)
3542 int lx = LEVELX(x), ly = LEVELY(y);
3544 if (!IN_SCR_FIELD(x, y))
3547 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
3548 graphic, GfxFrame[lx][ly], NO_MASKING);
3550 MarkTileDirty(x, y);
3553 void DrawFixedGraphicAnimation(int x, int y, int graphic)
3555 int lx = LEVELX(x), ly = LEVELY(y);
3557 if (!IN_SCR_FIELD(x, y))
3560 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
3561 graphic, GfxFrame[lx][ly], NO_MASKING);
3562 MarkTileDirty(x, y);
3565 void DrawLevelGraphicAnimation(int x, int y, int graphic)
3567 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
3570 void DrawLevelElementAnimation(int x, int y, int element)
3572 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
3574 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
3577 void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
3579 int sx = SCREENX(x), sy = SCREENY(y);
3581 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
3584 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
3587 DrawGraphicAnimation(sx, sy, graphic);
3590 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
3591 DrawLevelFieldCrumbled(x, y);
3593 if (GFX_CRUMBLED(Feld[x][y]))
3594 DrawLevelFieldCrumbled(x, y);
3598 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
3600 int sx = SCREENX(x), sy = SCREENY(y);
3603 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
3606 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
3608 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
3611 DrawGraphicAnimation(sx, sy, graphic);
3613 if (GFX_CRUMBLED(element))
3614 DrawLevelFieldCrumbled(x, y);
3617 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
3619 if (player->use_murphy)
3621 /* this works only because currently only one player can be "murphy" ... */
3622 static int last_horizontal_dir = MV_LEFT;
3623 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
3625 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3626 last_horizontal_dir = move_dir;
3628 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
3630 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
3632 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
3638 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
3641 static boolean equalGraphics(int graphic1, int graphic2)
3643 struct GraphicInfo *g1 = &graphic_info[graphic1];
3644 struct GraphicInfo *g2 = &graphic_info[graphic2];
3646 return (g1->bitmap == g2->bitmap &&
3647 g1->src_x == g2->src_x &&
3648 g1->src_y == g2->src_y &&
3649 g1->anim_frames == g2->anim_frames &&
3650 g1->anim_delay == g2->anim_delay &&
3651 g1->anim_mode == g2->anim_mode);
3654 void DrawAllPlayers()
3658 for (i = 0; i < MAX_PLAYERS; i++)
3659 if (stored_player[i].active)
3660 DrawPlayer(&stored_player[i]);
3663 void DrawPlayerField(int x, int y)
3665 if (!IS_PLAYER(x, y))
3668 DrawPlayer(PLAYERINFO(x, y));
3671 #define DRAW_PLAYER_OVER_PUSHED_ELEMENT 1
3673 void DrawPlayer(struct PlayerInfo *player)
3675 int jx = player->jx;
3676 int jy = player->jy;
3677 int move_dir = player->MovDir;
3678 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
3679 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
3680 int last_jx = (player->is_moving ? jx - dx : jx);
3681 int last_jy = (player->is_moving ? jy - dy : jy);
3682 int next_jx = jx + dx;
3683 int next_jy = jy + dy;
3684 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
3685 boolean player_is_opaque = FALSE;
3686 int sx = SCREENX(jx), sy = SCREENY(jy);
3687 int sxx = 0, syy = 0;
3688 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
3690 int action = ACTION_DEFAULT;
3691 int last_player_graphic = getPlayerGraphic(player, move_dir);
3692 int last_player_frame = player->Frame;
3695 /* GfxElement[][] is set to the element the player is digging or collecting;
3696 remove also for off-screen player if the player is not moving anymore */
3697 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
3698 GfxElement[jx][jy] = EL_UNDEFINED;
3700 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
3704 if (!IN_LEV_FIELD(jx, jy))
3706 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
3707 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
3708 printf("DrawPlayerField(): This should never happen!\n");
3713 if (element == EL_EXPLOSION)
3716 action = (player->is_pushing ? ACTION_PUSHING :
3717 player->is_digging ? ACTION_DIGGING :
3718 player->is_collecting ? ACTION_COLLECTING :
3719 player->is_moving ? ACTION_MOVING :
3720 player->is_snapping ? ACTION_SNAPPING :
3721 player->is_dropping ? ACTION_DROPPING :
3722 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
3724 if (player->is_waiting)
3725 move_dir = player->dir_waiting;
3727 InitPlayerGfxAnimation(player, action, move_dir);
3729 /* ----------------------------------------------------------------------- */
3730 /* draw things in the field the player is leaving, if needed */
3731 /* ----------------------------------------------------------------------- */
3733 if (player->is_moving)
3735 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
3737 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
3739 if (last_element == EL_DYNAMITE_ACTIVE ||
3740 last_element == EL_EM_DYNAMITE_ACTIVE ||
3741 last_element == EL_SP_DISK_RED_ACTIVE)
3742 DrawDynamite(last_jx, last_jy);
3744 DrawLevelFieldThruMask(last_jx, last_jy);
3746 else if (last_element == EL_DYNAMITE_ACTIVE ||
3747 last_element == EL_EM_DYNAMITE_ACTIVE ||
3748 last_element == EL_SP_DISK_RED_ACTIVE)
3749 DrawDynamite(last_jx, last_jy);
3751 /* !!! this is not enough to prevent flickering of players which are
3752 moving next to each others without a free tile between them -- this
3753 can only be solved by drawing all players layer by layer (first the
3754 background, then the foreground etc.) !!! => TODO */
3755 else if (!IS_PLAYER(last_jx, last_jy))
3756 DrawLevelField(last_jx, last_jy);
3759 DrawLevelField(last_jx, last_jy);
3762 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
3763 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
3766 if (!IN_SCR_FIELD(sx, sy))
3769 /* ----------------------------------------------------------------------- */
3770 /* draw things behind the player, if needed */
3771 /* ----------------------------------------------------------------------- */
3774 DrawLevelElement(jx, jy, Back[jx][jy]);
3775 else if (IS_ACTIVE_BOMB(element))
3776 DrawLevelElement(jx, jy, EL_EMPTY);
3779 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
3781 int old_element = GfxElement[jx][jy];
3782 int old_graphic = el_act_dir2img(old_element, action, move_dir);
3783 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
3785 if (GFX_CRUMBLED(old_element))
3786 DrawLevelFieldCrumbledDigging(jx, jy, move_dir, player->StepFrame);
3788 DrawGraphic(sx, sy, old_graphic, frame);
3790 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
3791 player_is_opaque = TRUE;
3795 GfxElement[jx][jy] = EL_UNDEFINED;
3797 /* make sure that pushed elements are drawn with correct frame rate */
3798 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
3800 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
3801 GfxFrame[jx][jy] = player->StepFrame;
3803 DrawLevelField(jx, jy);
3807 #if !DRAW_PLAYER_OVER_PUSHED_ELEMENT
3808 /* ----------------------------------------------------------------------- */
3809 /* draw player himself */
3810 /* ----------------------------------------------------------------------- */
3812 graphic = getPlayerGraphic(player, move_dir);
3814 /* in the case of changed player action or direction, prevent the current
3815 animation frame from being restarted for identical animations */
3816 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
3817 player->Frame = last_player_frame;
3819 frame = getGraphicAnimationFrame(graphic, player->Frame);
3823 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3824 sxx = player->GfxPos;
3826 syy = player->GfxPos;
3829 if (player_is_opaque)
3830 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
3832 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3834 if (SHIELD_ON(player))
3836 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
3837 IMG_SHIELD_NORMAL_ACTIVE);
3838 int frame = getGraphicAnimationFrame(graphic, -1);
3840 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3844 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
3847 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3848 sxx = player->GfxPos;
3850 syy = player->GfxPos;
3854 /* ----------------------------------------------------------------------- */
3855 /* draw things the player is pushing, if needed */
3856 /* ----------------------------------------------------------------------- */
3858 if (player->is_pushing && player->is_moving)
3860 int px = SCREENX(jx), py = SCREENY(jy);
3861 int pxx = (TILEX - ABS(sxx)) * dx;
3862 int pyy = (TILEY - ABS(syy)) * dy;
3863 int gfx_frame = GfxFrame[jx][jy];
3869 if (!IS_MOVING(jx, jy)) /* push movement already finished */
3871 element = Feld[next_jx][next_jy];
3872 gfx_frame = GfxFrame[next_jx][next_jy];
3875 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
3877 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
3878 frame = getGraphicAnimationFrame(graphic, sync_frame);
3880 /* draw background element under pushed element (like the Sokoban field) */
3881 if (game.use_masked_pushing && IS_MOVING(jx, jy))
3883 /* this allows transparent pushing animation over non-black background */
3886 DrawLevelElement(jx, jy, Back[jx][jy]);
3888 DrawLevelElement(jx, jy, EL_EMPTY);
3890 if (Back[next_jx][next_jy])
3891 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3893 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
3895 else if (Back[next_jx][next_jy])
3896 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3899 /* do not draw (EM style) pushing animation when pushing is finished */
3900 /* (two-tile animations usually do not contain start and end frame) */
3901 if (graphic_info[graphic].double_movement && !IS_MOVING(jx, jy))
3902 DrawLevelElement(next_jx, next_jy, Feld[next_jx][next_jy]);
3904 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3906 /* masked drawing is needed for EMC style (double) movement graphics */
3907 /* !!! (ONLY WHEN DRAWING PUSHED ELEMENT OVER THE PLAYER) !!! */
3908 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3912 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
3913 /* ----------------------------------------------------------------------- */
3914 /* draw player himself */
3915 /* ----------------------------------------------------------------------- */
3917 graphic = getPlayerGraphic(player, move_dir);
3919 /* in the case of changed player action or direction, prevent the current
3920 animation frame from being restarted for identical animations */
3921 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
3922 player->Frame = last_player_frame;
3924 frame = getGraphicAnimationFrame(graphic, player->Frame);
3928 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3929 sxx = player->GfxPos;
3931 syy = player->GfxPos;
3934 if (player_is_opaque)
3935 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
3937 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3939 if (SHIELD_ON(player))
3941 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
3942 IMG_SHIELD_NORMAL_ACTIVE);
3943 int frame = getGraphicAnimationFrame(graphic, -1);
3945 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3949 /* ----------------------------------------------------------------------- */
3950 /* draw things in front of player (active dynamite or dynabombs) */
3951 /* ----------------------------------------------------------------------- */
3953 if (IS_ACTIVE_BOMB(element))
3955 graphic = el2img(element);
3956 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
3958 if (game.emulation == EMU_SUPAPLEX)
3959 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
3961 DrawGraphicThruMask(sx, sy, graphic, frame);
3964 if (player_is_moving && last_element == EL_EXPLOSION)
3966 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
3967 GfxElement[last_jx][last_jy] : EL_EMPTY);
3968 int graphic = el_act2img(element, ACTION_EXPLODING);
3969 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
3970 int phase = ExplodePhase[last_jx][last_jy] - 1;
3971 int frame = getGraphicAnimationFrame(graphic, phase - delay);
3974 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
3977 /* ----------------------------------------------------------------------- */
3978 /* draw elements the player is just walking/passing through/under */
3979 /* ----------------------------------------------------------------------- */
3981 if (player_is_moving)
3983 /* handle the field the player is leaving ... */
3984 if (IS_ACCESSIBLE_INSIDE(last_element))
3985 DrawLevelField(last_jx, last_jy);
3986 else if (IS_ACCESSIBLE_UNDER(last_element))
3987 DrawLevelFieldThruMask(last_jx, last_jy);
3990 /* do not redraw accessible elements if the player is just pushing them */
3991 if (!player_is_moving || !player->is_pushing)
3993 /* ... and the field the player is entering */
3994 if (IS_ACCESSIBLE_INSIDE(element))
3995 DrawLevelField(jx, jy);
3996 else if (IS_ACCESSIBLE_UNDER(element))
3997 DrawLevelFieldThruMask(jx, jy);
4000 MarkTileDirty(sx, sy);
4003 /* ------------------------------------------------------------------------- */
4005 void WaitForEventToContinue()
4007 boolean still_wait = TRUE;
4009 if (program.headless)
4012 /* simulate releasing mouse button over last gadget, if still pressed */
4014 HandleGadgets(-1, -1, 0);
4016 button_status = MB_RELEASED;
4024 if (NextValidEvent(&event))
4028 case EVENT_BUTTONPRESS:
4029 case EVENT_KEYPRESS:
4030 #if defined(TARGET_SDL2)
4031 case SDL_CONTROLLERBUTTONDOWN:
4033 case SDL_JOYBUTTONDOWN:
4037 case EVENT_KEYRELEASE:
4038 ClearPlayerAction();
4042 HandleOtherEvents(&event);
4046 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
4055 #define MAX_REQUEST_LINES 13
4056 #define MAX_REQUEST_LINE_FONT1_LEN 7
4057 #define MAX_REQUEST_LINE_FONT2_LEN 10
4059 static int RequestHandleEvents(unsigned int req_state)
4061 boolean level_solved = (game_status == GAME_MODE_PLAYING &&
4062 local_player->LevelSolved_GameEnd);
4063 int width = request.width;
4064 int height = request.height;
4068 setRequestPosition(&sx, &sy, FALSE);
4070 button_status = MB_RELEASED;
4072 request_gadget_id = -1;
4079 /* the MM game engine does not use a special (scrollable) field buffer */
4080 if (level.game_engine_type != GAME_ENGINE_TYPE_MM)
4081 SetDrawtoField(DRAW_TO_FIELDBUFFER);
4083 HandleGameActions();
4085 SetDrawtoField(DRAW_TO_BACKBUFFER);
4087 if (global.use_envelope_request)
4089 /* copy current state of request area to middle of playfield area */
4090 BlitBitmap(bitmap_db_store_2, drawto, sx, sy, width, height, sx, sy);
4098 while (NextValidEvent(&event))
4102 case EVENT_BUTTONPRESS:
4103 case EVENT_BUTTONRELEASE:
4104 case EVENT_MOTIONNOTIFY:
4108 if (event.type == EVENT_MOTIONNOTIFY)
4113 motion_status = TRUE;
4114 mx = ((MotionEvent *) &event)->x;
4115 my = ((MotionEvent *) &event)->y;
4119 motion_status = FALSE;
4120 mx = ((ButtonEvent *) &event)->x;
4121 my = ((ButtonEvent *) &event)->y;
4122 if (event.type == EVENT_BUTTONPRESS)
4123 button_status = ((ButtonEvent *) &event)->button;
4125 button_status = MB_RELEASED;
4128 /* this sets 'request_gadget_id' */
4129 HandleGadgets(mx, my, button_status);
4131 switch (request_gadget_id)
4133 case TOOL_CTRL_ID_YES:
4136 case TOOL_CTRL_ID_NO:
4139 case TOOL_CTRL_ID_CONFIRM:
4140 result = TRUE | FALSE;
4143 case TOOL_CTRL_ID_PLAYER_1:
4146 case TOOL_CTRL_ID_PLAYER_2:
4149 case TOOL_CTRL_ID_PLAYER_3:
4152 case TOOL_CTRL_ID_PLAYER_4:
4163 #if defined(TARGET_SDL2)
4164 case SDL_WINDOWEVENT:
4165 HandleWindowEvent((WindowEvent *) &event);
4168 case SDL_APP_WILLENTERBACKGROUND:
4169 case SDL_APP_DIDENTERBACKGROUND:
4170 case SDL_APP_WILLENTERFOREGROUND:
4171 case SDL_APP_DIDENTERFOREGROUND:
4172 HandlePauseResumeEvent((PauseResumeEvent *) &event);
4176 case EVENT_KEYPRESS:
4178 Key key = GetEventKey((KeyEvent *)&event, TRUE);
4183 if (req_state & REQ_CONFIRM)
4189 #if defined(TARGET_SDL2)
4193 #if defined(KSYM_Rewind)
4194 case KSYM_Rewind: /* for Amazon Fire TV remote */
4202 #if defined(TARGET_SDL2)
4205 #if defined(KSYM_FastForward)
4206 case KSYM_FastForward: /* for Amazon Fire TV remote */
4213 HandleKeysDebug(key);
4217 if (req_state & REQ_PLAYER)
4219 int old_player_nr = setup.network_player_nr;
4222 result = old_player_nr + 1;
4227 result = old_player_nr + 1;
4258 case EVENT_KEYRELEASE:
4259 ClearPlayerAction();
4262 #if defined(TARGET_SDL2)
4263 case SDL_CONTROLLERBUTTONDOWN:
4264 switch (event.cbutton.button)
4266 case SDL_CONTROLLER_BUTTON_A:
4267 case SDL_CONTROLLER_BUTTON_X:
4268 case SDL_CONTROLLER_BUTTON_LEFTSHOULDER:
4269 case SDL_CONTROLLER_BUTTON_LEFTSTICK:
4273 case SDL_CONTROLLER_BUTTON_B:
4274 case SDL_CONTROLLER_BUTTON_Y:
4275 case SDL_CONTROLLER_BUTTON_RIGHTSHOULDER:
4276 case SDL_CONTROLLER_BUTTON_RIGHTSTICK:
4277 case SDL_CONTROLLER_BUTTON_BACK:
4282 if (req_state & REQ_PLAYER)
4284 int old_player_nr = setup.network_player_nr;
4287 result = old_player_nr + 1;
4289 switch (event.cbutton.button)
4291 case SDL_CONTROLLER_BUTTON_DPAD_UP:
4292 case SDL_CONTROLLER_BUTTON_Y:
4296 case SDL_CONTROLLER_BUTTON_DPAD_RIGHT:
4297 case SDL_CONTROLLER_BUTTON_B:
4301 case SDL_CONTROLLER_BUTTON_DPAD_DOWN:
4302 case SDL_CONTROLLER_BUTTON_A:
4306 case SDL_CONTROLLER_BUTTON_DPAD_LEFT:
4307 case SDL_CONTROLLER_BUTTON_X:
4318 case SDL_CONTROLLERBUTTONUP:
4319 HandleJoystickEvent(&event);
4320 ClearPlayerAction();
4325 HandleOtherEvents(&event);
4330 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
4332 int joy = AnyJoystick();
4334 if (joy & JOY_BUTTON_1)
4336 else if (joy & JOY_BUTTON_2)
4339 else if (AnyJoystick())
4341 int joy = AnyJoystick();
4343 if (req_state & REQ_PLAYER)
4347 else if (joy & JOY_RIGHT)
4349 else if (joy & JOY_DOWN)
4351 else if (joy & JOY_LEFT)
4358 if (global.use_envelope_request)
4360 /* copy back current state of pressed buttons inside request area */
4361 BlitBitmap(drawto, bitmap_db_store_2, sx, sy, width, height, sx, sy);
4371 static boolean RequestDoor(char *text, unsigned int req_state)
4373 unsigned int old_door_state;
4374 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
4375 int font_nr = FONT_TEXT_2;
4380 if (maxWordLengthInString(text) > MAX_REQUEST_LINE_FONT1_LEN)
4382 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
4383 font_nr = FONT_TEXT_1;
4386 if (game_status == GAME_MODE_PLAYING)
4387 BlitScreenToBitmap(backbuffer);
4389 /* disable deactivated drawing when quick-loading level tape recording */
4390 if (tape.playing && tape.deactivate_display)
4391 TapeDeactivateDisplayOff(TRUE);
4393 SetMouseCursor(CURSOR_DEFAULT);
4395 /* pause network game while waiting for request to answer */
4396 if (network.enabled &&
4397 game_status == GAME_MODE_PLAYING &&
4398 req_state & REQUEST_WAIT_FOR_INPUT)
4399 SendToServer_PausePlaying();
4401 old_door_state = GetDoorState();
4403 /* simulate releasing mouse button over last gadget, if still pressed */
4405 HandleGadgets(-1, -1, 0);
4409 /* draw released gadget before proceeding */
4412 if (old_door_state & DOOR_OPEN_1)
4414 CloseDoor(DOOR_CLOSE_1);
4416 /* save old door content */
4417 BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
4418 0 * DXSIZE, 0, DXSIZE, DYSIZE, 1 * DXSIZE, 0);
4421 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
4422 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4424 /* clear door drawing field */
4425 DrawBackground(DX, DY, DXSIZE, DYSIZE);
4427 /* force DOOR font inside door area */
4428 SetFontStatus(GAME_MODE_PSEUDO_DOOR);
4430 /* write text for request */
4431 for (text_ptr = text, ty = 0; ty < MAX_REQUEST_LINES; ty++)
4433 char text_line[max_request_line_len + 1];
4439 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
4441 tc = *(text_ptr + tx);
4442 // if (!tc || tc == ' ')
4443 if (!tc || tc == ' ' || tc == '?' || tc == '!')
4447 if ((tc == '?' || tc == '!') && tl == 0)
4457 strncpy(text_line, text_ptr, tl);
4460 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
4461 DY + 8 + ty * (getFontHeight(font_nr) + 2),
4462 text_line, font_nr);
4464 text_ptr += tl + (tc == ' ' ? 1 : 0);
4465 // text_ptr += tl + (tc == ' ' || tc == '?' || tc == '!' ? 1 : 0);
4470 if (req_state & REQ_ASK)
4472 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
4473 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
4475 else if (req_state & REQ_CONFIRM)
4477 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
4479 else if (req_state & REQ_PLAYER)
4481 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
4482 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
4483 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
4484 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
4487 /* copy request gadgets to door backbuffer */
4488 BlitBitmap(drawto, bitmap_db_door_1, DX, DY, DXSIZE, DYSIZE, 0, 0);
4490 OpenDoor(DOOR_OPEN_1);
4492 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
4494 if (game_status == GAME_MODE_PLAYING)
4496 SetPanelBackground();
4497 SetDrawBackgroundMask(REDRAW_DOOR_1);
4501 SetDrawBackgroundMask(REDRAW_FIELD);
4507 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4509 // ---------- handle request buttons ----------
4510 result = RequestHandleEvents(req_state);
4514 if (!(req_state & REQ_STAY_OPEN))
4516 CloseDoor(DOOR_CLOSE_1);
4518 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
4519 (req_state & REQ_REOPEN))
4520 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
4525 if (game_status == GAME_MODE_PLAYING)
4527 SetPanelBackground();
4528 SetDrawBackgroundMask(REDRAW_DOOR_1);
4532 SetDrawBackgroundMask(REDRAW_FIELD);
4535 /* continue network game after request */
4536 if (network.enabled &&
4537 game_status == GAME_MODE_PLAYING &&
4538 req_state & REQUEST_WAIT_FOR_INPUT)
4539 SendToServer_ContinuePlaying();
4541 /* restore deactivated drawing when quick-loading level tape recording */
4542 if (tape.playing && tape.deactivate_display)
4543 TapeDeactivateDisplayOn();
4548 static boolean RequestEnvelope(char *text, unsigned int req_state)
4552 if (game_status == GAME_MODE_PLAYING)
4553 BlitScreenToBitmap(backbuffer);
4555 /* disable deactivated drawing when quick-loading level tape recording */
4556 if (tape.playing && tape.deactivate_display)
4557 TapeDeactivateDisplayOff(TRUE);
4559 SetMouseCursor(CURSOR_DEFAULT);
4561 /* pause network game while waiting for request to answer */
4562 if (network.enabled &&
4563 game_status == GAME_MODE_PLAYING &&
4564 req_state & REQUEST_WAIT_FOR_INPUT)
4565 SendToServer_PausePlaying();
4567 /* simulate releasing mouse button over last gadget, if still pressed */
4569 HandleGadgets(-1, -1, 0);
4573 // (replace with setting corresponding request background)
4574 // SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
4575 // SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4577 /* clear door drawing field */
4578 // DrawBackground(DX, DY, DXSIZE, DYSIZE);
4580 ShowEnvelopeRequest(text, req_state, ACTION_OPENING);
4582 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
4584 if (game_status == GAME_MODE_PLAYING)
4586 SetPanelBackground();
4587 SetDrawBackgroundMask(REDRAW_DOOR_1);
4591 SetDrawBackgroundMask(REDRAW_FIELD);
4597 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4599 // ---------- handle request buttons ----------
4600 result = RequestHandleEvents(req_state);
4604 ShowEnvelopeRequest(text, req_state, ACTION_CLOSING);
4608 if (game_status == GAME_MODE_PLAYING)
4610 SetPanelBackground();
4611 SetDrawBackgroundMask(REDRAW_DOOR_1);
4615 SetDrawBackgroundMask(REDRAW_FIELD);
4618 /* continue network game after request */
4619 if (network.enabled &&
4620 game_status == GAME_MODE_PLAYING &&
4621 req_state & REQUEST_WAIT_FOR_INPUT)
4622 SendToServer_ContinuePlaying();
4624 /* restore deactivated drawing when quick-loading level tape recording */
4625 if (tape.playing && tape.deactivate_display)
4626 TapeDeactivateDisplayOn();
4631 boolean Request(char *text, unsigned int req_state)
4633 boolean overlay_active = GetOverlayActive();
4636 SetOverlayActive(FALSE);
4638 if (global.use_envelope_request)
4639 result = RequestEnvelope(text, req_state);
4641 result = RequestDoor(text, req_state);
4643 SetOverlayActive(overlay_active);
4648 static int compareDoorPartOrderInfo(const void *object1, const void *object2)
4650 const struct DoorPartOrderInfo *dpo1 = (struct DoorPartOrderInfo *)object1;
4651 const struct DoorPartOrderInfo *dpo2 = (struct DoorPartOrderInfo *)object2;
4654 if (dpo1->sort_priority != dpo2->sort_priority)
4655 compare_result = dpo1->sort_priority - dpo2->sort_priority;
4657 compare_result = dpo1->nr - dpo2->nr;
4659 return compare_result;
4662 void InitGraphicCompatibilityInfo_Doors()
4668 struct DoorInfo *door;
4672 { DOOR_1, IMG_GFX_DOOR_1_PART_1, IMG_GFX_DOOR_1_PART_8, &door_1 },
4673 { DOOR_2, IMG_GFX_DOOR_2_PART_1, IMG_GFX_DOOR_2_PART_8, &door_2 },
4675 { -1, -1, -1, NULL }
4677 struct Rect door_rect_list[] =
4679 { DX, DY, DXSIZE, DYSIZE },
4680 { VX, VY, VXSIZE, VYSIZE }
4684 for (i = 0; doors[i].door_token != -1; i++)
4686 int door_token = doors[i].door_token;
4687 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
4688 int part_1 = doors[i].part_1;
4689 int part_8 = doors[i].part_8;
4690 int part_2 = part_1 + 1;
4691 int part_3 = part_1 + 2;
4692 struct DoorInfo *door = doors[i].door;
4693 struct Rect *door_rect = &door_rect_list[door_index];
4694 boolean door_gfx_redefined = FALSE;
4696 /* check if any door part graphic definitions have been redefined */
4698 for (j = 0; door_part_controls[j].door_token != -1; j++)
4700 struct DoorPartControlInfo *dpc = &door_part_controls[j];
4701 struct FileInfo *fi = getImageListEntryFromImageID(dpc->graphic);
4703 if (dpc->door_token == door_token && fi->redefined)
4704 door_gfx_redefined = TRUE;
4707 /* check for old-style door graphic/animation modifications */
4709 if (!door_gfx_redefined)
4711 if (door->anim_mode & ANIM_STATIC_PANEL)
4713 door->panel.step_xoffset = 0;
4714 door->panel.step_yoffset = 0;
4717 if (door->anim_mode & (ANIM_HORIZONTAL | ANIM_VERTICAL))
4719 struct GraphicInfo *g_part_1 = &graphic_info[part_1];
4720 struct GraphicInfo *g_part_2 = &graphic_info[part_2];
4721 int num_door_steps, num_panel_steps;
4723 /* remove door part graphics other than the two default wings */
4725 for (j = 0; door_part_controls[j].door_token != -1; j++)
4727 struct DoorPartControlInfo *dpc = &door_part_controls[j];
4728 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4730 if (dpc->graphic >= part_3 &&
4731 dpc->graphic <= part_8)
4735 /* set graphics and screen positions of the default wings */
4737 g_part_1->width = door_rect->width;
4738 g_part_1->height = door_rect->height;
4739 g_part_2->width = door_rect->width;
4740 g_part_2->height = door_rect->height;
4741 g_part_2->src_x = door_rect->width;
4742 g_part_2->src_y = g_part_1->src_y;
4744 door->part_2.x = door->part_1.x;
4745 door->part_2.y = door->part_1.y;
4747 if (door->width != -1)
4749 g_part_1->width = door->width;
4750 g_part_2->width = door->width;
4752 // special treatment for graphics and screen position of right wing
4753 g_part_2->src_x += door_rect->width - door->width;
4754 door->part_2.x += door_rect->width - door->width;
4757 if (door->height != -1)
4759 g_part_1->height = door->height;
4760 g_part_2->height = door->height;
4762 // special treatment for graphics and screen position of bottom wing
4763 g_part_2->src_y += door_rect->height - door->height;
4764 door->part_2.y += door_rect->height - door->height;
4767 /* set animation delays for the default wings and panels */
4769 door->part_1.step_delay = door->step_delay;
4770 door->part_2.step_delay = door->step_delay;
4771 door->panel.step_delay = door->step_delay;
4773 /* set animation draw order for the default wings */
4775 door->part_1.sort_priority = 2; /* draw left wing over ... */
4776 door->part_2.sort_priority = 1; /* ... right wing */
4778 /* set animation draw offset for the default wings */
4780 if (door->anim_mode & ANIM_HORIZONTAL)
4782 door->part_1.step_xoffset = door->step_offset;
4783 door->part_1.step_yoffset = 0;
4784 door->part_2.step_xoffset = door->step_offset * -1;
4785 door->part_2.step_yoffset = 0;
4787 num_door_steps = g_part_1->width / door->step_offset;
4789 else // ANIM_VERTICAL
4791 door->part_1.step_xoffset = 0;
4792 door->part_1.step_yoffset = door->step_offset;
4793 door->part_2.step_xoffset = 0;
4794 door->part_2.step_yoffset = door->step_offset * -1;
4796 num_door_steps = g_part_1->height / door->step_offset;
4799 /* set animation draw offset for the default panels */
4801 if (door->step_offset > 1)
4803 num_panel_steps = 2 * door_rect->height / door->step_offset;
4804 door->panel.start_step = num_panel_steps - num_door_steps;
4805 door->panel.start_step_closing = door->panel.start_step;
4809 num_panel_steps = door_rect->height / door->step_offset;
4810 door->panel.start_step = num_panel_steps - num_door_steps / 2;
4811 door->panel.start_step_closing = door->panel.start_step;
4812 door->panel.step_delay *= 2;
4823 for (i = 0; door_part_controls[i].door_token != -1; i++)
4825 struct DoorPartControlInfo *dpc = &door_part_controls[i];
4826 struct DoorPartOrderInfo *dpo = &door_part_order[i];
4828 /* initialize "start_step_opening" and "start_step_closing", if needed */
4829 if (dpc->pos->start_step_opening == 0 &&
4830 dpc->pos->start_step_closing == 0)
4832 // dpc->pos->start_step_opening = dpc->pos->start_step;
4833 dpc->pos->start_step_closing = dpc->pos->start_step;
4836 /* fill structure for door part draw order (sorted below) */
4838 dpo->sort_priority = dpc->pos->sort_priority;
4841 /* sort door part controls according to sort_priority and graphic number */
4842 qsort(door_part_order, MAX_DOOR_PARTS,
4843 sizeof(struct DoorPartOrderInfo), compareDoorPartOrderInfo);
4846 unsigned int OpenDoor(unsigned int door_state)
4848 if (door_state & DOOR_COPY_BACK)
4850 if (door_state & DOOR_OPEN_1)
4851 BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
4852 1 * DXSIZE, 0, DXSIZE, DYSIZE, 0 * DXSIZE, 0);
4854 if (door_state & DOOR_OPEN_2)
4855 BlitBitmap(bitmap_db_door_2, bitmap_db_door_2,
4856 1 * VXSIZE, 0, VXSIZE, VYSIZE, 0 * VXSIZE, 0);
4858 door_state &= ~DOOR_COPY_BACK;
4861 return MoveDoor(door_state);
4864 unsigned int CloseDoor(unsigned int door_state)
4866 unsigned int old_door_state = GetDoorState();
4868 if (!(door_state & DOOR_NO_COPY_BACK))
4870 if (old_door_state & DOOR_OPEN_1)
4871 BlitBitmap(backbuffer, bitmap_db_door_1,
4872 DX, DY, DXSIZE, DYSIZE, 0, 0);
4874 if (old_door_state & DOOR_OPEN_2)
4875 BlitBitmap(backbuffer, bitmap_db_door_2,
4876 VX, VY, VXSIZE, VYSIZE, 0, 0);
4878 door_state &= ~DOOR_NO_COPY_BACK;
4881 return MoveDoor(door_state);
4884 unsigned int GetDoorState()
4886 return MoveDoor(DOOR_GET_STATE);
4889 unsigned int SetDoorState(unsigned int door_state)
4891 return MoveDoor(door_state | DOOR_SET_STATE);
4894 int euclid(int a, int b)
4896 return (b ? euclid(b, a % b) : a);
4899 unsigned int MoveDoor(unsigned int door_state)
4901 struct Rect door_rect_list[] =
4903 { DX, DY, DXSIZE, DYSIZE },
4904 { VX, VY, VXSIZE, VYSIZE }
4906 static int door1 = DOOR_CLOSE_1;
4907 static int door2 = DOOR_CLOSE_2;
4908 unsigned int door_delay = 0;
4909 unsigned int door_delay_value;
4912 if (door_state == DOOR_GET_STATE)
4913 return (door1 | door2);
4915 if (door_state & DOOR_SET_STATE)
4917 if (door_state & DOOR_ACTION_1)
4918 door1 = door_state & DOOR_ACTION_1;
4919 if (door_state & DOOR_ACTION_2)
4920 door2 = door_state & DOOR_ACTION_2;
4922 return (door1 | door2);
4925 if (!(door_state & DOOR_FORCE_REDRAW))
4927 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
4928 door_state &= ~DOOR_OPEN_1;
4929 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
4930 door_state &= ~DOOR_CLOSE_1;
4931 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
4932 door_state &= ~DOOR_OPEN_2;
4933 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
4934 door_state &= ~DOOR_CLOSE_2;
4937 if (global.autoplay_leveldir)
4939 door_state |= DOOR_NO_DELAY;
4940 door_state &= ~DOOR_CLOSE_ALL;
4943 if (game_status == GAME_MODE_EDITOR && !(door_state & DOOR_FORCE_ANIM))
4944 door_state |= DOOR_NO_DELAY;
4946 if (door_state & DOOR_ACTION)
4948 boolean door_panel_drawn[NUM_DOORS];
4949 boolean panel_has_doors[NUM_DOORS];
4950 boolean door_part_skip[MAX_DOOR_PARTS];
4951 boolean door_part_done[MAX_DOOR_PARTS];
4952 boolean door_part_done_all;
4953 int num_steps[MAX_DOOR_PARTS];
4954 int max_move_delay = 0; // delay for complete animations of all doors
4955 int max_step_delay = 0; // delay (ms) between two animation frames
4956 int num_move_steps = 0; // number of animation steps for all doors
4957 int max_move_delay_doors_only = 0; // delay for doors only (no panel)
4958 int num_move_steps_doors_only = 0; // steps for doors only (no panel)
4959 int current_move_delay = 0;
4963 for (i = 0; i < NUM_DOORS; i++)
4964 panel_has_doors[i] = FALSE;
4966 for (i = 0; i < MAX_DOOR_PARTS; i++)
4968 struct DoorPartControlInfo *dpc = &door_part_controls[i];
4969 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4970 int door_token = dpc->door_token;
4972 door_part_done[i] = FALSE;
4973 door_part_skip[i] = (!(door_state & door_token) ||
4977 for (i = 0; i < MAX_DOOR_PARTS; i++)
4979 int nr = door_part_order[i].nr;
4980 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
4981 struct DoorPartPosInfo *pos = dpc->pos;
4982 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4983 int door_token = dpc->door_token;
4984 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
4985 boolean is_panel = DOOR_PART_IS_PANEL(nr);
4986 int step_xoffset = ABS(pos->step_xoffset);
4987 int step_yoffset = ABS(pos->step_yoffset);
4988 int step_delay = pos->step_delay;
4989 int current_door_state = door_state & door_token;
4990 boolean door_opening = ((current_door_state & DOOR_OPEN) != 0);
4991 boolean door_closing = ((current_door_state & DOOR_CLOSE) != 0);
4992 boolean part_opening = (is_panel ? door_closing : door_opening);
4993 int start_step = (part_opening ? pos->start_step_opening :
4994 pos->start_step_closing);
4995 float move_xsize = (step_xoffset ? g->width : 0);
4996 float move_ysize = (step_yoffset ? g->height : 0);
4997 int move_xsteps = (step_xoffset ? ceil(move_xsize / step_xoffset) : 0);
4998 int move_ysteps = (step_yoffset ? ceil(move_ysize / step_yoffset) : 0);
4999 int move_steps = (move_xsteps && move_ysteps ?
5000 MIN(move_xsteps, move_ysteps) :
5001 move_xsteps ? move_xsteps : move_ysteps) - start_step;
5002 int move_delay = move_steps * step_delay;
5004 if (door_part_skip[nr])
5007 max_move_delay = MAX(max_move_delay, move_delay);
5008 max_step_delay = (max_step_delay == 0 ? step_delay :
5009 euclid(max_step_delay, step_delay));
5010 num_steps[nr] = move_steps;
5014 max_move_delay_doors_only = MAX(max_move_delay_doors_only, move_delay);
5016 panel_has_doors[door_index] = TRUE;
5020 max_step_delay = MAX(1, max_step_delay); // prevent division by zero
5022 num_move_steps = max_move_delay / max_step_delay;
5023 num_move_steps_doors_only = max_move_delay_doors_only / max_step_delay;
5025 door_delay_value = max_step_delay;
5027 if ((door_state & DOOR_NO_DELAY) || setup.quick_doors)
5029 start = num_move_steps - 1;
5033 /* opening door sound has priority over simultaneously closing door */
5034 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
5036 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
5038 if (door_state & DOOR_OPEN_1)
5039 PlayMenuSoundStereo(SND_DOOR_1_OPENING, SOUND_MIDDLE);
5040 if (door_state & DOOR_OPEN_2)
5041 PlayMenuSoundStereo(SND_DOOR_2_OPENING, SOUND_MIDDLE);
5043 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
5045 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
5047 if (door_state & DOOR_CLOSE_1)
5048 PlayMenuSoundStereo(SND_DOOR_1_CLOSING, SOUND_MIDDLE);
5049 if (door_state & DOOR_CLOSE_2)
5050 PlayMenuSoundStereo(SND_DOOR_2_CLOSING, SOUND_MIDDLE);
5054 for (k = start; k < num_move_steps; k++)
5056 int last_frame = num_move_steps - 1; // last frame of this "for" loop
5058 door_part_done_all = TRUE;
5060 for (i = 0; i < NUM_DOORS; i++)
5061 door_panel_drawn[i] = FALSE;
5063 for (i = 0; i < MAX_DOOR_PARTS; i++)
5065 int nr = door_part_order[i].nr;
5066 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
5067 struct DoorPartPosInfo *pos = dpc->pos;
5068 struct GraphicInfo *g = &graphic_info[dpc->graphic];
5069 int door_token = dpc->door_token;
5070 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
5071 boolean is_panel = DOOR_PART_IS_PANEL(nr);
5072 boolean is_panel_and_door_has_closed = FALSE;
5073 struct Rect *door_rect = &door_rect_list[door_index];
5074 Bitmap *bitmap_db_door = (door_token == DOOR_1 ? bitmap_db_door_1 :
5076 Bitmap *bitmap = (is_panel ? bitmap_db_door : g->bitmap);
5077 int current_door_state = door_state & door_token;
5078 boolean door_opening = ((current_door_state & DOOR_OPEN) != 0);
5079 boolean door_closing = !door_opening;
5080 boolean part_opening = (is_panel ? door_closing : door_opening);
5081 boolean part_closing = !part_opening;
5082 int start_step = (part_opening ? pos->start_step_opening :
5083 pos->start_step_closing);
5084 int step_delay = pos->step_delay;
5085 int step_factor = step_delay / max_step_delay;
5086 int k1 = (step_factor ? k / step_factor + 1 : k);
5087 int k2 = (part_opening ? k1 + start_step : num_steps[nr] - k1);
5088 int kk = MAX(0, k2);
5091 int src_x, src_y, src_xx, src_yy;
5092 int dst_x, dst_y, dst_xx, dst_yy;
5095 if (door_part_skip[nr])
5098 if (!(door_state & door_token))
5106 int k2_door = (door_opening ? k : num_move_steps_doors_only - k - 1);
5107 int kk_door = MAX(0, k2_door);
5108 int sync_frame = kk_door * door_delay_value;
5109 int frame = getGraphicAnimationFrame(dpc->graphic, sync_frame);
5111 getFixedGraphicSource(dpc->graphic, frame, &bitmap,
5112 &g_src_x, &g_src_y);
5117 if (!door_panel_drawn[door_index])
5119 ClearRectangle(drawto, door_rect->x, door_rect->y,
5120 door_rect->width, door_rect->height);
5122 door_panel_drawn[door_index] = TRUE;
5125 // draw opening or closing door parts
5127 if (pos->step_xoffset < 0) // door part on right side
5130 dst_xx = pos->x + ABS(kk * pos->step_xoffset);
5133 if (dst_xx + width > door_rect->width)
5134 width = door_rect->width - dst_xx;
5136 else // door part on left side
5139 dst_xx = pos->x - kk * pos->step_xoffset;
5143 src_xx = ABS(dst_xx);
5147 width = g->width - src_xx;
5149 if (width > door_rect->width)
5150 width = door_rect->width;
5152 // printf("::: k == %d [%d] \n", k, start_step);
5155 if (pos->step_yoffset < 0) // door part on bottom side
5158 dst_yy = pos->y + ABS(kk * pos->step_yoffset);
5161 if (dst_yy + height > door_rect->height)
5162 height = door_rect->height - dst_yy;
5164 else // door part on top side
5167 dst_yy = pos->y - kk * pos->step_yoffset;
5171 src_yy = ABS(dst_yy);
5175 height = g->height - src_yy;
5178 src_x = g_src_x + src_xx;
5179 src_y = g_src_y + src_yy;
5181 dst_x = door_rect->x + dst_xx;
5182 dst_y = door_rect->y + dst_yy;
5184 is_panel_and_door_has_closed =
5187 panel_has_doors[door_index] &&
5188 k >= num_move_steps_doors_only - 1);
5190 if (width >= 0 && width <= g->width &&
5191 height >= 0 && height <= g->height &&
5192 !is_panel_and_door_has_closed)
5194 if (is_panel || !pos->draw_masked)
5195 BlitBitmap(bitmap, drawto, src_x, src_y, width, height,
5198 BlitBitmapMasked(bitmap, drawto, src_x, src_y, width, height,
5202 redraw_mask |= REDRAW_DOOR_FROM_TOKEN(door_token);
5204 if ((part_opening && (width < 0 || height < 0)) ||
5205 (part_closing && (width >= g->width && height >= g->height)))
5206 door_part_done[nr] = TRUE;
5208 // continue door part animations, but not panel after door has closed
5209 if (!door_part_done[nr] && !is_panel_and_door_has_closed)
5210 door_part_done_all = FALSE;
5213 if (!(door_state & DOOR_NO_DELAY))
5217 SkipUntilDelayReached(&door_delay, door_delay_value, &k, last_frame);
5219 current_move_delay += max_step_delay;
5221 /* prevent OS (Windows) from complaining about program not responding */
5225 if (door_part_done_all)
5229 if (!(door_state & DOOR_NO_DELAY))
5231 /* wait for specified door action post delay */
5232 if (door_state & DOOR_ACTION_1 && door_state & DOOR_ACTION_2)
5233 door_delay_value = MAX(door_1.post_delay, door_2.post_delay);
5234 else if (door_state & DOOR_ACTION_1)
5235 door_delay_value = door_1.post_delay;
5236 else if (door_state & DOOR_ACTION_2)
5237 door_delay_value = door_2.post_delay;
5239 while (!DelayReached(&door_delay, door_delay_value))
5244 if (door_state & DOOR_ACTION_1)
5245 door1 = door_state & DOOR_ACTION_1;
5246 if (door_state & DOOR_ACTION_2)
5247 door2 = door_state & DOOR_ACTION_2;
5249 // draw masked border over door area
5250 DrawMaskedBorder(REDRAW_DOOR_1);
5251 DrawMaskedBorder(REDRAW_DOOR_2);
5253 return (door1 | door2);
5256 static boolean useSpecialEditorDoor()
5258 int graphic = IMG_GLOBAL_BORDER_EDITOR;
5259 boolean redefined = getImageListEntryFromImageID(graphic)->redefined;
5261 // do not draw special editor door if editor border defined or redefined
5262 if (graphic_info[graphic].bitmap != NULL || redefined)
5265 // do not draw special editor door if global border defined to be empty
5266 if (graphic_info[IMG_GLOBAL_BORDER].bitmap == NULL)
5269 // do not draw special editor door if viewport definitions do not match
5273 EY + EYSIZE != VY + VYSIZE)
5279 void DrawSpecialEditorDoor()
5281 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
5282 int top_border_width = gfx1->width;
5283 int top_border_height = gfx1->height;
5284 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
5285 int ex = EX - outer_border;
5286 int ey = EY - outer_border;
5287 int vy = VY - outer_border;
5288 int exsize = EXSIZE + 2 * outer_border;
5290 if (!useSpecialEditorDoor())
5293 /* draw bigger level editor toolbox window */
5294 BlitBitmap(gfx1->bitmap, drawto, gfx1->src_x, gfx1->src_y,
5295 top_border_width, top_border_height, ex, ey - top_border_height);
5296 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto, ex, vy,
5297 exsize, EYSIZE - VYSIZE + outer_border, ex, ey);
5299 redraw_mask |= REDRAW_ALL;
5302 void UndrawSpecialEditorDoor()
5304 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
5305 int top_border_width = gfx1->width;
5306 int top_border_height = gfx1->height;
5307 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
5308 int ex = EX - outer_border;
5309 int ey = EY - outer_border;
5310 int ey_top = ey - top_border_height;
5311 int exsize = EXSIZE + 2 * outer_border;
5312 int eysize = EYSIZE + 2 * outer_border;
5314 if (!useSpecialEditorDoor())
5317 /* draw normal tape recorder window */
5318 if (graphic_info[IMG_GLOBAL_BORDER].bitmap)
5320 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
5321 ex, ey_top, top_border_width, top_border_height,
5323 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
5324 ex, ey, exsize, eysize, ex, ey);
5328 // if screen background is set to "[NONE]", clear editor toolbox window
5329 ClearRectangle(drawto, ex, ey_top, top_border_width, top_border_height);
5330 ClearRectangle(drawto, ex, ey, exsize, eysize);
5333 redraw_mask |= REDRAW_ALL;
5337 /* ---------- new tool button stuff ---------------------------------------- */
5342 struct TextPosInfo *pos;
5345 } toolbutton_info[NUM_TOOL_BUTTONS] =
5348 IMG_GFX_REQUEST_BUTTON_YES, &request.button.yes,
5349 TOOL_CTRL_ID_YES, "yes"
5352 IMG_GFX_REQUEST_BUTTON_NO, &request.button.no,
5353 TOOL_CTRL_ID_NO, "no"
5356 IMG_GFX_REQUEST_BUTTON_CONFIRM, &request.button.confirm,
5357 TOOL_CTRL_ID_CONFIRM, "confirm"
5360 IMG_GFX_REQUEST_BUTTON_PLAYER_1, &request.button.player_1,
5361 TOOL_CTRL_ID_PLAYER_1, "player 1"
5364 IMG_GFX_REQUEST_BUTTON_PLAYER_2, &request.button.player_2,
5365 TOOL_CTRL_ID_PLAYER_2, "player 2"
5368 IMG_GFX_REQUEST_BUTTON_PLAYER_3, &request.button.player_3,
5369 TOOL_CTRL_ID_PLAYER_3, "player 3"
5372 IMG_GFX_REQUEST_BUTTON_PLAYER_4, &request.button.player_4,
5373 TOOL_CTRL_ID_PLAYER_4, "player 4"
5377 void CreateToolButtons()
5381 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
5383 int graphic = toolbutton_info[i].graphic;
5384 struct GraphicInfo *gfx = &graphic_info[graphic];
5385 struct TextPosInfo *pos = toolbutton_info[i].pos;
5386 struct GadgetInfo *gi;
5387 Bitmap *deco_bitmap = None;
5388 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
5389 unsigned int event_mask = GD_EVENT_RELEASED;
5392 int gd_x = gfx->src_x;
5393 int gd_y = gfx->src_y;
5394 int gd_xp = gfx->src_x + gfx->pressed_xoffset;
5395 int gd_yp = gfx->src_y + gfx->pressed_yoffset;
5400 if (global.use_envelope_request)
5402 setRequestPosition(&dx, &dy, TRUE);
5404 // check if request buttons are outside of envelope and fix, if needed
5405 if (x < 0 || x + gfx->width > request.width ||
5406 y < 0 || y + gfx->height > request.height)
5408 if (id == TOOL_CTRL_ID_YES)
5411 y = request.height - 2 * request.border_size - gfx->height;
5413 else if (id == TOOL_CTRL_ID_NO)
5415 x = request.width - 2 * request.border_size - gfx->width;
5416 y = request.height - 2 * request.border_size - gfx->height;
5418 else if (id == TOOL_CTRL_ID_CONFIRM)
5420 x = (request.width - 2 * request.border_size - gfx->width) / 2;
5421 y = request.height - 2 * request.border_size - gfx->height;
5423 else if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
5425 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
5427 x = (request.width - 2 * request.border_size - gfx->width) / 2;
5428 y = request.height - 2 * request.border_size - gfx->height * 2;
5430 x += (player_nr == 3 ? -1 : player_nr == 1 ? +1 : 0) * gfx->width;
5431 y += (player_nr == 0 ? -1 : player_nr == 2 ? +1 : 0) * gfx->height;
5436 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
5438 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
5440 getSizedGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr), 0,
5441 pos->size, &deco_bitmap, &deco_x, &deco_y);
5442 deco_xpos = (gfx->width - pos->size) / 2;
5443 deco_ypos = (gfx->height - pos->size) / 2;
5446 gi = CreateGadget(GDI_CUSTOM_ID, id,
5447 GDI_IMAGE_ID, graphic,
5448 GDI_INFO_TEXT, toolbutton_info[i].infotext,
5451 GDI_WIDTH, gfx->width,
5452 GDI_HEIGHT, gfx->height,
5453 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
5454 GDI_STATE, GD_BUTTON_UNPRESSED,
5455 GDI_DESIGN_UNPRESSED, gfx->bitmap, gd_x, gd_y,
5456 GDI_DESIGN_PRESSED, gfx->bitmap, gd_xp, gd_yp,
5457 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
5458 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
5459 GDI_DECORATION_SIZE, pos->size, pos->size,
5460 GDI_DECORATION_SHIFTING, 1, 1,
5461 GDI_DIRECT_DRAW, FALSE,
5462 GDI_EVENT_MASK, event_mask,
5463 GDI_CALLBACK_ACTION, HandleToolButtons,
5467 Error(ERR_EXIT, "cannot create gadget");
5469 tool_gadget[id] = gi;
5473 void FreeToolButtons()
5477 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
5478 FreeGadget(tool_gadget[i]);
5481 static void UnmapToolButtons()
5485 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
5486 UnmapGadget(tool_gadget[i]);
5489 static void HandleToolButtons(struct GadgetInfo *gi)
5491 request_gadget_id = gi->custom_id;
5494 static struct Mapping_EM_to_RND_object
5497 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
5498 boolean is_backside; /* backside of moving element */
5504 em_object_mapping_list[] =
5507 Xblank, TRUE, FALSE,
5511 Yacid_splash_eB, FALSE, FALSE,
5512 EL_ACID_SPLASH_RIGHT, -1, -1
5515 Yacid_splash_wB, FALSE, FALSE,
5516 EL_ACID_SPLASH_LEFT, -1, -1
5519 #ifdef EM_ENGINE_BAD_ROLL
5521 Xstone_force_e, FALSE, FALSE,
5522 EL_ROCK, -1, MV_BIT_RIGHT
5525 Xstone_force_w, FALSE, FALSE,
5526 EL_ROCK, -1, MV_BIT_LEFT
5529 Xnut_force_e, FALSE, FALSE,
5530 EL_NUT, -1, MV_BIT_RIGHT
5533 Xnut_force_w, FALSE, FALSE,
5534 EL_NUT, -1, MV_BIT_LEFT
5537 Xspring_force_e, FALSE, FALSE,
5538 EL_SPRING, -1, MV_BIT_RIGHT
5541 Xspring_force_w, FALSE, FALSE,
5542 EL_SPRING, -1, MV_BIT_LEFT
5545 Xemerald_force_e, FALSE, FALSE,
5546 EL_EMERALD, -1, MV_BIT_RIGHT
5549 Xemerald_force_w, FALSE, FALSE,
5550 EL_EMERALD, -1, MV_BIT_LEFT
5553 Xdiamond_force_e, FALSE, FALSE,
5554 EL_DIAMOND, -1, MV_BIT_RIGHT
5557 Xdiamond_force_w, FALSE, FALSE,
5558 EL_DIAMOND, -1, MV_BIT_LEFT
5561 Xbomb_force_e, FALSE, FALSE,
5562 EL_BOMB, -1, MV_BIT_RIGHT
5565 Xbomb_force_w, FALSE, FALSE,
5566 EL_BOMB, -1, MV_BIT_LEFT
5568 #endif /* EM_ENGINE_BAD_ROLL */
5571 Xstone, TRUE, FALSE,
5575 Xstone_pause, FALSE, FALSE,
5579 Xstone_fall, FALSE, FALSE,
5583 Ystone_s, FALSE, FALSE,
5584 EL_ROCK, ACTION_FALLING, -1
5587 Ystone_sB, FALSE, TRUE,
5588 EL_ROCK, ACTION_FALLING, -1
5591 Ystone_e, FALSE, FALSE,
5592 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
5595 Ystone_eB, FALSE, TRUE,
5596 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
5599 Ystone_w, FALSE, FALSE,
5600 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
5603 Ystone_wB, FALSE, TRUE,
5604 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
5611 Xnut_pause, FALSE, FALSE,
5615 Xnut_fall, FALSE, FALSE,
5619 Ynut_s, FALSE, FALSE,
5620 EL_NUT, ACTION_FALLING, -1
5623 Ynut_sB, FALSE, TRUE,
5624 EL_NUT, ACTION_FALLING, -1
5627 Ynut_e, FALSE, FALSE,
5628 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
5631 Ynut_eB, FALSE, TRUE,
5632 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
5635 Ynut_w, FALSE, FALSE,
5636 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
5639 Ynut_wB, FALSE, TRUE,
5640 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
5643 Xbug_n, TRUE, FALSE,
5647 Xbug_e, TRUE, FALSE,
5648 EL_BUG_RIGHT, -1, -1
5651 Xbug_s, TRUE, FALSE,
5655 Xbug_w, TRUE, FALSE,
5659 Xbug_gon, FALSE, FALSE,
5663 Xbug_goe, FALSE, FALSE,
5664 EL_BUG_RIGHT, -1, -1
5667 Xbug_gos, FALSE, FALSE,
5671 Xbug_gow, FALSE, FALSE,
5675 Ybug_n, FALSE, FALSE,
5676 EL_BUG, ACTION_MOVING, MV_BIT_UP
5679 Ybug_nB, FALSE, TRUE,
5680 EL_BUG, ACTION_MOVING, MV_BIT_UP
5683 Ybug_e, FALSE, FALSE,
5684 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
5687 Ybug_eB, FALSE, TRUE,
5688 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
5691 Ybug_s, FALSE, FALSE,
5692 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
5695 Ybug_sB, FALSE, TRUE,
5696 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
5699 Ybug_w, FALSE, FALSE,
5700 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
5703 Ybug_wB, FALSE, TRUE,
5704 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
5707 Ybug_w_n, FALSE, FALSE,
5708 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
5711 Ybug_n_e, FALSE, FALSE,
5712 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
5715 Ybug_e_s, FALSE, FALSE,
5716 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
5719 Ybug_s_w, FALSE, FALSE,
5720 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
5723 Ybug_e_n, FALSE, FALSE,
5724 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
5727 Ybug_s_e, FALSE, FALSE,
5728 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
5731 Ybug_w_s, FALSE, FALSE,
5732 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
5735 Ybug_n_w, FALSE, FALSE,
5736 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
5739 Ybug_stone, FALSE, FALSE,
5740 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
5743 Ybug_spring, FALSE, FALSE,
5744 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
5747 Xtank_n, TRUE, FALSE,
5748 EL_SPACESHIP_UP, -1, -1
5751 Xtank_e, TRUE, FALSE,
5752 EL_SPACESHIP_RIGHT, -1, -1
5755 Xtank_s, TRUE, FALSE,
5756 EL_SPACESHIP_DOWN, -1, -1
5759 Xtank_w, TRUE, FALSE,
5760 EL_SPACESHIP_LEFT, -1, -1
5763 Xtank_gon, FALSE, FALSE,
5764 EL_SPACESHIP_UP, -1, -1
5767 Xtank_goe, FALSE, FALSE,
5768 EL_SPACESHIP_RIGHT, -1, -1
5771 Xtank_gos, FALSE, FALSE,
5772 EL_SPACESHIP_DOWN, -1, -1
5775 Xtank_gow, FALSE, FALSE,
5776 EL_SPACESHIP_LEFT, -1, -1
5779 Ytank_n, FALSE, FALSE,
5780 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
5783 Ytank_nB, FALSE, TRUE,
5784 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
5787 Ytank_e, FALSE, FALSE,
5788 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
5791 Ytank_eB, FALSE, TRUE,
5792 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
5795 Ytank_s, FALSE, FALSE,
5796 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
5799 Ytank_sB, FALSE, TRUE,
5800 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
5803 Ytank_w, FALSE, FALSE,
5804 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
5807 Ytank_wB, FALSE, TRUE,
5808 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
5811 Ytank_w_n, FALSE, FALSE,
5812 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
5815 Ytank_n_e, FALSE, FALSE,
5816 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
5819 Ytank_e_s, FALSE, FALSE,
5820 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
5823 Ytank_s_w, FALSE, FALSE,
5824 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
5827 Ytank_e_n, FALSE, FALSE,
5828 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
5831 Ytank_s_e, FALSE, FALSE,
5832 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
5835 Ytank_w_s, FALSE, FALSE,
5836 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
5839 Ytank_n_w, FALSE, FALSE,
5840 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
5843 Ytank_stone, FALSE, FALSE,
5844 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
5847 Ytank_spring, FALSE, FALSE,
5848 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
5851 Xandroid, TRUE, FALSE,
5852 EL_EMC_ANDROID, ACTION_ACTIVE, -1
5855 Xandroid_1_n, FALSE, FALSE,
5856 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
5859 Xandroid_2_n, FALSE, FALSE,
5860 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
5863 Xandroid_1_e, FALSE, FALSE,
5864 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
5867 Xandroid_2_e, FALSE, FALSE,
5868 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
5871 Xandroid_1_w, FALSE, FALSE,
5872 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
5875 Xandroid_2_w, FALSE, FALSE,
5876 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
5879 Xandroid_1_s, FALSE, FALSE,
5880 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
5883 Xandroid_2_s, FALSE, FALSE,
5884 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
5887 Yandroid_n, FALSE, FALSE,
5888 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
5891 Yandroid_nB, FALSE, TRUE,
5892 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
5895 Yandroid_ne, FALSE, FALSE,
5896 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
5899 Yandroid_neB, FALSE, TRUE,
5900 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
5903 Yandroid_e, FALSE, FALSE,
5904 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
5907 Yandroid_eB, FALSE, TRUE,
5908 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
5911 Yandroid_se, FALSE, FALSE,
5912 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
5915 Yandroid_seB, FALSE, TRUE,
5916 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
5919 Yandroid_s, FALSE, FALSE,
5920 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
5923 Yandroid_sB, FALSE, TRUE,
5924 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
5927 Yandroid_sw, FALSE, FALSE,
5928 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
5931 Yandroid_swB, FALSE, TRUE,
5932 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
5935 Yandroid_w, FALSE, FALSE,
5936 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
5939 Yandroid_wB, FALSE, TRUE,
5940 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
5943 Yandroid_nw, FALSE, FALSE,
5944 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
5947 Yandroid_nwB, FALSE, TRUE,
5948 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
5951 Xspring, TRUE, FALSE,
5955 Xspring_pause, FALSE, FALSE,
5959 Xspring_e, FALSE, FALSE,
5963 Xspring_w, FALSE, FALSE,
5967 Xspring_fall, FALSE, FALSE,
5971 Yspring_s, FALSE, FALSE,
5972 EL_SPRING, ACTION_FALLING, -1
5975 Yspring_sB, FALSE, TRUE,
5976 EL_SPRING, ACTION_FALLING, -1
5979 Yspring_e, FALSE, FALSE,
5980 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
5983 Yspring_eB, FALSE, TRUE,
5984 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
5987 Yspring_w, FALSE, FALSE,
5988 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
5991 Yspring_wB, FALSE, TRUE,
5992 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
5995 Yspring_kill_e, FALSE, FALSE,
5996 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
5999 Yspring_kill_eB, FALSE, TRUE,
6000 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
6003 Yspring_kill_w, FALSE, FALSE,
6004 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
6007 Yspring_kill_wB, FALSE, TRUE,
6008 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
6011 Xeater_n, TRUE, FALSE,
6012 EL_YAMYAM_UP, -1, -1
6015 Xeater_e, TRUE, FALSE,
6016 EL_YAMYAM_RIGHT, -1, -1
6019 Xeater_w, TRUE, FALSE,
6020 EL_YAMYAM_LEFT, -1, -1
6023 Xeater_s, TRUE, FALSE,
6024 EL_YAMYAM_DOWN, -1, -1
6027 Yeater_n, FALSE, FALSE,
6028 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
6031 Yeater_nB, FALSE, TRUE,
6032 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
6035 Yeater_e, FALSE, FALSE,
6036 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
6039 Yeater_eB, FALSE, TRUE,
6040 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
6043 Yeater_s, FALSE, FALSE,
6044 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
6047 Yeater_sB, FALSE, TRUE,
6048 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
6051 Yeater_w, FALSE, FALSE,
6052 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
6055 Yeater_wB, FALSE, TRUE,
6056 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
6059 Yeater_stone, FALSE, FALSE,
6060 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
6063 Yeater_spring, FALSE, FALSE,
6064 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
6067 Xalien, TRUE, FALSE,
6071 Xalien_pause, FALSE, FALSE,
6075 Yalien_n, FALSE, FALSE,
6076 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
6079 Yalien_nB, FALSE, TRUE,
6080 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
6083 Yalien_e, FALSE, FALSE,
6084 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
6087 Yalien_eB, FALSE, TRUE,
6088 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
6091 Yalien_s, FALSE, FALSE,
6092 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
6095 Yalien_sB, FALSE, TRUE,
6096 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
6099 Yalien_w, FALSE, FALSE,
6100 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
6103 Yalien_wB, FALSE, TRUE,
6104 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
6107 Yalien_stone, FALSE, FALSE,
6108 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
6111 Yalien_spring, FALSE, FALSE,
6112 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
6115 Xemerald, TRUE, FALSE,
6119 Xemerald_pause, FALSE, FALSE,
6123 Xemerald_fall, FALSE, FALSE,
6127 Xemerald_shine, FALSE, FALSE,
6128 EL_EMERALD, ACTION_TWINKLING, -1
6131 Yemerald_s, FALSE, FALSE,
6132 EL_EMERALD, ACTION_FALLING, -1
6135 Yemerald_sB, FALSE, TRUE,
6136 EL_EMERALD, ACTION_FALLING, -1
6139 Yemerald_e, FALSE, FALSE,
6140 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
6143 Yemerald_eB, FALSE, TRUE,
6144 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
6147 Yemerald_w, FALSE, FALSE,
6148 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
6151 Yemerald_wB, FALSE, TRUE,
6152 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
6155 Yemerald_eat, FALSE, FALSE,
6156 EL_EMERALD, ACTION_COLLECTING, -1
6159 Yemerald_stone, FALSE, FALSE,
6160 EL_NUT, ACTION_BREAKING, -1
6163 Xdiamond, TRUE, FALSE,
6167 Xdiamond_pause, FALSE, FALSE,
6171 Xdiamond_fall, FALSE, FALSE,
6175 Xdiamond_shine, FALSE, FALSE,
6176 EL_DIAMOND, ACTION_TWINKLING, -1
6179 Ydiamond_s, FALSE, FALSE,
6180 EL_DIAMOND, ACTION_FALLING, -1
6183 Ydiamond_sB, FALSE, TRUE,
6184 EL_DIAMOND, ACTION_FALLING, -1
6187 Ydiamond_e, FALSE, FALSE,
6188 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
6191 Ydiamond_eB, FALSE, TRUE,
6192 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
6195 Ydiamond_w, FALSE, FALSE,
6196 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
6199 Ydiamond_wB, FALSE, TRUE,
6200 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
6203 Ydiamond_eat, FALSE, FALSE,
6204 EL_DIAMOND, ACTION_COLLECTING, -1
6207 Ydiamond_stone, FALSE, FALSE,
6208 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
6211 Xdrip_fall, TRUE, FALSE,
6212 EL_AMOEBA_DROP, -1, -1
6215 Xdrip_stretch, FALSE, FALSE,
6216 EL_AMOEBA_DROP, ACTION_FALLING, -1
6219 Xdrip_stretchB, FALSE, TRUE,
6220 EL_AMOEBA_DROP, ACTION_FALLING, -1
6223 Xdrip_eat, FALSE, FALSE,
6224 EL_AMOEBA_DROP, ACTION_GROWING, -1
6227 Ydrip_s1, FALSE, FALSE,
6228 EL_AMOEBA_DROP, ACTION_FALLING, -1
6231 Ydrip_s1B, FALSE, TRUE,
6232 EL_AMOEBA_DROP, ACTION_FALLING, -1
6235 Ydrip_s2, FALSE, FALSE,
6236 EL_AMOEBA_DROP, ACTION_FALLING, -1
6239 Ydrip_s2B, FALSE, TRUE,
6240 EL_AMOEBA_DROP, ACTION_FALLING, -1
6247 Xbomb_pause, FALSE, FALSE,
6251 Xbomb_fall, FALSE, FALSE,
6255 Ybomb_s, FALSE, FALSE,
6256 EL_BOMB, ACTION_FALLING, -1
6259 Ybomb_sB, FALSE, TRUE,
6260 EL_BOMB, ACTION_FALLING, -1
6263 Ybomb_e, FALSE, FALSE,
6264 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
6267 Ybomb_eB, FALSE, TRUE,
6268 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
6271 Ybomb_w, FALSE, FALSE,
6272 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
6275 Ybomb_wB, FALSE, TRUE,
6276 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
6279 Ybomb_eat, FALSE, FALSE,
6280 EL_BOMB, ACTION_ACTIVATING, -1
6283 Xballoon, TRUE, FALSE,
6287 Yballoon_n, FALSE, FALSE,
6288 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
6291 Yballoon_nB, FALSE, TRUE,
6292 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
6295 Yballoon_e, FALSE, FALSE,
6296 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
6299 Yballoon_eB, FALSE, TRUE,
6300 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
6303 Yballoon_s, FALSE, FALSE,
6304 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
6307 Yballoon_sB, FALSE, TRUE,
6308 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
6311 Yballoon_w, FALSE, FALSE,
6312 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
6315 Yballoon_wB, FALSE, TRUE,
6316 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
6319 Xgrass, TRUE, FALSE,
6320 EL_EMC_GRASS, -1, -1
6323 Ygrass_nB, FALSE, FALSE,
6324 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
6327 Ygrass_eB, FALSE, FALSE,
6328 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
6331 Ygrass_sB, FALSE, FALSE,
6332 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
6335 Ygrass_wB, FALSE, FALSE,
6336 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
6343 Ydirt_nB, FALSE, FALSE,
6344 EL_SAND, ACTION_DIGGING, MV_BIT_UP
6347 Ydirt_eB, FALSE, FALSE,
6348 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
6351 Ydirt_sB, FALSE, FALSE,
6352 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
6355 Ydirt_wB, FALSE, FALSE,
6356 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
6359 Xacid_ne, TRUE, FALSE,
6360 EL_ACID_POOL_TOPRIGHT, -1, -1
6363 Xacid_se, TRUE, FALSE,
6364 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
6367 Xacid_s, TRUE, FALSE,
6368 EL_ACID_POOL_BOTTOM, -1, -1
6371 Xacid_sw, TRUE, FALSE,
6372 EL_ACID_POOL_BOTTOMLEFT, -1, -1
6375 Xacid_nw, TRUE, FALSE,
6376 EL_ACID_POOL_TOPLEFT, -1, -1
6379 Xacid_1, TRUE, FALSE,
6383 Xacid_2, FALSE, FALSE,
6387 Xacid_3, FALSE, FALSE,
6391 Xacid_4, FALSE, FALSE,
6395 Xacid_5, FALSE, FALSE,
6399 Xacid_6, FALSE, FALSE,
6403 Xacid_7, FALSE, FALSE,
6407 Xacid_8, FALSE, FALSE,
6411 Xball_1, TRUE, FALSE,
6412 EL_EMC_MAGIC_BALL, -1, -1
6415 Xball_1B, FALSE, FALSE,
6416 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
6419 Xball_2, FALSE, FALSE,
6420 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
6423 Xball_2B, FALSE, FALSE,
6424 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
6427 Yball_eat, FALSE, FALSE,
6428 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
6431 Ykey_1_eat, FALSE, FALSE,
6432 EL_EM_KEY_1, ACTION_COLLECTING, -1
6435 Ykey_2_eat, FALSE, FALSE,
6436 EL_EM_KEY_2, ACTION_COLLECTING, -1
6439 Ykey_3_eat, FALSE, FALSE,
6440 EL_EM_KEY_3, ACTION_COLLECTING, -1
6443 Ykey_4_eat, FALSE, FALSE,
6444 EL_EM_KEY_4, ACTION_COLLECTING, -1
6447 Ykey_5_eat, FALSE, FALSE,
6448 EL_EMC_KEY_5, ACTION_COLLECTING, -1
6451 Ykey_6_eat, FALSE, FALSE,
6452 EL_EMC_KEY_6, ACTION_COLLECTING, -1
6455 Ykey_7_eat, FALSE, FALSE,
6456 EL_EMC_KEY_7, ACTION_COLLECTING, -1
6459 Ykey_8_eat, FALSE, FALSE,
6460 EL_EMC_KEY_8, ACTION_COLLECTING, -1
6463 Ylenses_eat, FALSE, FALSE,
6464 EL_EMC_LENSES, ACTION_COLLECTING, -1
6467 Ymagnify_eat, FALSE, FALSE,
6468 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
6471 Ygrass_eat, FALSE, FALSE,
6472 EL_EMC_GRASS, ACTION_SNAPPING, -1
6475 Ydirt_eat, FALSE, FALSE,
6476 EL_SAND, ACTION_SNAPPING, -1
6479 Xgrow_ns, TRUE, FALSE,
6480 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
6483 Ygrow_ns_eat, FALSE, FALSE,
6484 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
6487 Xgrow_ew, TRUE, FALSE,
6488 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
6491 Ygrow_ew_eat, FALSE, FALSE,
6492 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
6495 Xwonderwall, TRUE, FALSE,
6496 EL_MAGIC_WALL, -1, -1
6499 XwonderwallB, FALSE, FALSE,
6500 EL_MAGIC_WALL, ACTION_ACTIVE, -1
6503 Xamoeba_1, TRUE, FALSE,
6504 EL_AMOEBA_DRY, ACTION_OTHER, -1
6507 Xamoeba_2, FALSE, FALSE,
6508 EL_AMOEBA_DRY, ACTION_OTHER, -1
6511 Xamoeba_3, FALSE, FALSE,
6512 EL_AMOEBA_DRY, ACTION_OTHER, -1
6515 Xamoeba_4, FALSE, FALSE,
6516 EL_AMOEBA_DRY, ACTION_OTHER, -1
6519 Xamoeba_5, TRUE, FALSE,
6520 EL_AMOEBA_WET, ACTION_OTHER, -1
6523 Xamoeba_6, FALSE, FALSE,
6524 EL_AMOEBA_WET, ACTION_OTHER, -1
6527 Xamoeba_7, FALSE, FALSE,
6528 EL_AMOEBA_WET, ACTION_OTHER, -1
6531 Xamoeba_8, FALSE, FALSE,
6532 EL_AMOEBA_WET, ACTION_OTHER, -1
6535 Xdoor_1, TRUE, FALSE,
6536 EL_EM_GATE_1, -1, -1
6539 Xdoor_2, TRUE, FALSE,
6540 EL_EM_GATE_2, -1, -1
6543 Xdoor_3, TRUE, FALSE,
6544 EL_EM_GATE_3, -1, -1
6547 Xdoor_4, TRUE, FALSE,
6548 EL_EM_GATE_4, -1, -1
6551 Xdoor_5, TRUE, FALSE,
6552 EL_EMC_GATE_5, -1, -1
6555 Xdoor_6, TRUE, FALSE,
6556 EL_EMC_GATE_6, -1, -1
6559 Xdoor_7, TRUE, FALSE,
6560 EL_EMC_GATE_7, -1, -1
6563 Xdoor_8, TRUE, FALSE,
6564 EL_EMC_GATE_8, -1, -1
6567 Xkey_1, TRUE, FALSE,
6571 Xkey_2, TRUE, FALSE,
6575 Xkey_3, TRUE, FALSE,
6579 Xkey_4, TRUE, FALSE,
6583 Xkey_5, TRUE, FALSE,
6584 EL_EMC_KEY_5, -1, -1
6587 Xkey_6, TRUE, FALSE,
6588 EL_EMC_KEY_6, -1, -1
6591 Xkey_7, TRUE, FALSE,
6592 EL_EMC_KEY_7, -1, -1
6595 Xkey_8, TRUE, FALSE,
6596 EL_EMC_KEY_8, -1, -1
6599 Xwind_n, TRUE, FALSE,
6600 EL_BALLOON_SWITCH_UP, -1, -1
6603 Xwind_e, TRUE, FALSE,
6604 EL_BALLOON_SWITCH_RIGHT, -1, -1
6607 Xwind_s, TRUE, FALSE,
6608 EL_BALLOON_SWITCH_DOWN, -1, -1
6611 Xwind_w, TRUE, FALSE,
6612 EL_BALLOON_SWITCH_LEFT, -1, -1
6615 Xwind_nesw, TRUE, FALSE,
6616 EL_BALLOON_SWITCH_ANY, -1, -1
6619 Xwind_stop, TRUE, FALSE,
6620 EL_BALLOON_SWITCH_NONE, -1, -1
6624 EL_EM_EXIT_CLOSED, -1, -1
6627 Xexit_1, TRUE, FALSE,
6628 EL_EM_EXIT_OPEN, -1, -1
6631 Xexit_2, FALSE, FALSE,
6632 EL_EM_EXIT_OPEN, -1, -1
6635 Xexit_3, FALSE, FALSE,
6636 EL_EM_EXIT_OPEN, -1, -1
6639 Xdynamite, TRUE, FALSE,
6640 EL_EM_DYNAMITE, -1, -1
6643 Ydynamite_eat, FALSE, FALSE,
6644 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
6647 Xdynamite_1, TRUE, FALSE,
6648 EL_EM_DYNAMITE_ACTIVE, -1, -1
6651 Xdynamite_2, FALSE, FALSE,
6652 EL_EM_DYNAMITE_ACTIVE, -1, -1
6655 Xdynamite_3, FALSE, FALSE,
6656 EL_EM_DYNAMITE_ACTIVE, -1, -1
6659 Xdynamite_4, FALSE, FALSE,
6660 EL_EM_DYNAMITE_ACTIVE, -1, -1
6663 Xbumper, TRUE, FALSE,
6664 EL_EMC_SPRING_BUMPER, -1, -1
6667 XbumperB, FALSE, FALSE,
6668 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
6671 Xwheel, TRUE, FALSE,
6672 EL_ROBOT_WHEEL, -1, -1
6675 XwheelB, FALSE, FALSE,
6676 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
6679 Xswitch, TRUE, FALSE,
6680 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
6683 XswitchB, FALSE, FALSE,
6684 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
6688 EL_QUICKSAND_EMPTY, -1, -1
6691 Xsand_stone, TRUE, FALSE,
6692 EL_QUICKSAND_FULL, -1, -1
6695 Xsand_stonein_1, FALSE, TRUE,
6696 EL_ROCK, ACTION_FILLING, -1
6699 Xsand_stonein_2, FALSE, TRUE,
6700 EL_ROCK, ACTION_FILLING, -1
6703 Xsand_stonein_3, FALSE, TRUE,
6704 EL_ROCK, ACTION_FILLING, -1
6707 Xsand_stonein_4, FALSE, TRUE,
6708 EL_ROCK, ACTION_FILLING, -1
6711 Xsand_stonesand_1, FALSE, FALSE,
6712 EL_QUICKSAND_EMPTYING, -1, -1
6715 Xsand_stonesand_2, FALSE, FALSE,
6716 EL_QUICKSAND_EMPTYING, -1, -1
6719 Xsand_stonesand_3, FALSE, FALSE,
6720 EL_QUICKSAND_EMPTYING, -1, -1
6723 Xsand_stonesand_4, FALSE, FALSE,
6724 EL_QUICKSAND_EMPTYING, -1, -1
6727 Xsand_stonesand_quickout_1, FALSE, FALSE,
6728 EL_QUICKSAND_EMPTYING, -1, -1
6731 Xsand_stonesand_quickout_2, FALSE, FALSE,
6732 EL_QUICKSAND_EMPTYING, -1, -1
6735 Xsand_stoneout_1, FALSE, FALSE,
6736 EL_ROCK, ACTION_EMPTYING, -1
6739 Xsand_stoneout_2, FALSE, FALSE,
6740 EL_ROCK, ACTION_EMPTYING, -1
6743 Xsand_sandstone_1, FALSE, FALSE,
6744 EL_QUICKSAND_FILLING, -1, -1
6747 Xsand_sandstone_2, FALSE, FALSE,
6748 EL_QUICKSAND_FILLING, -1, -1
6751 Xsand_sandstone_3, FALSE, FALSE,
6752 EL_QUICKSAND_FILLING, -1, -1
6755 Xsand_sandstone_4, FALSE, FALSE,
6756 EL_QUICKSAND_FILLING, -1, -1
6759 Xplant, TRUE, FALSE,
6760 EL_EMC_PLANT, -1, -1
6763 Yplant, FALSE, FALSE,
6764 EL_EMC_PLANT, -1, -1
6767 Xlenses, TRUE, FALSE,
6768 EL_EMC_LENSES, -1, -1
6771 Xmagnify, TRUE, FALSE,
6772 EL_EMC_MAGNIFIER, -1, -1
6775 Xdripper, TRUE, FALSE,
6776 EL_EMC_DRIPPER, -1, -1
6779 XdripperB, FALSE, FALSE,
6780 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
6783 Xfake_blank, TRUE, FALSE,
6784 EL_INVISIBLE_WALL, -1, -1
6787 Xfake_blankB, FALSE, FALSE,
6788 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
6791 Xfake_grass, TRUE, FALSE,
6792 EL_EMC_FAKE_GRASS, -1, -1
6795 Xfake_grassB, FALSE, FALSE,
6796 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
6799 Xfake_door_1, TRUE, FALSE,
6800 EL_EM_GATE_1_GRAY, -1, -1
6803 Xfake_door_2, TRUE, FALSE,
6804 EL_EM_GATE_2_GRAY, -1, -1
6807 Xfake_door_3, TRUE, FALSE,
6808 EL_EM_GATE_3_GRAY, -1, -1
6811 Xfake_door_4, TRUE, FALSE,
6812 EL_EM_GATE_4_GRAY, -1, -1
6815 Xfake_door_5, TRUE, FALSE,
6816 EL_EMC_GATE_5_GRAY, -1, -1
6819 Xfake_door_6, TRUE, FALSE,
6820 EL_EMC_GATE_6_GRAY, -1, -1
6823 Xfake_door_7, TRUE, FALSE,
6824 EL_EMC_GATE_7_GRAY, -1, -1
6827 Xfake_door_8, TRUE, FALSE,
6828 EL_EMC_GATE_8_GRAY, -1, -1
6831 Xfake_acid_1, TRUE, FALSE,
6832 EL_EMC_FAKE_ACID, -1, -1
6835 Xfake_acid_2, FALSE, FALSE,
6836 EL_EMC_FAKE_ACID, -1, -1
6839 Xfake_acid_3, FALSE, FALSE,
6840 EL_EMC_FAKE_ACID, -1, -1
6843 Xfake_acid_4, FALSE, FALSE,
6844 EL_EMC_FAKE_ACID, -1, -1
6847 Xfake_acid_5, FALSE, FALSE,
6848 EL_EMC_FAKE_ACID, -1, -1
6851 Xfake_acid_6, FALSE, FALSE,
6852 EL_EMC_FAKE_ACID, -1, -1
6855 Xfake_acid_7, FALSE, FALSE,
6856 EL_EMC_FAKE_ACID, -1, -1
6859 Xfake_acid_8, FALSE, FALSE,
6860 EL_EMC_FAKE_ACID, -1, -1
6863 Xsteel_1, TRUE, FALSE,
6864 EL_STEELWALL, -1, -1
6867 Xsteel_2, TRUE, FALSE,
6868 EL_EMC_STEELWALL_2, -1, -1
6871 Xsteel_3, TRUE, FALSE,
6872 EL_EMC_STEELWALL_3, -1, -1
6875 Xsteel_4, TRUE, FALSE,
6876 EL_EMC_STEELWALL_4, -1, -1
6879 Xwall_1, TRUE, FALSE,
6883 Xwall_2, TRUE, FALSE,
6884 EL_EMC_WALL_14, -1, -1
6887 Xwall_3, TRUE, FALSE,
6888 EL_EMC_WALL_15, -1, -1
6891 Xwall_4, TRUE, FALSE,
6892 EL_EMC_WALL_16, -1, -1
6895 Xround_wall_1, TRUE, FALSE,
6896 EL_WALL_SLIPPERY, -1, -1
6899 Xround_wall_2, TRUE, FALSE,
6900 EL_EMC_WALL_SLIPPERY_2, -1, -1
6903 Xround_wall_3, TRUE, FALSE,
6904 EL_EMC_WALL_SLIPPERY_3, -1, -1
6907 Xround_wall_4, TRUE, FALSE,
6908 EL_EMC_WALL_SLIPPERY_4, -1, -1
6911 Xdecor_1, TRUE, FALSE,
6912 EL_EMC_WALL_8, -1, -1
6915 Xdecor_2, TRUE, FALSE,
6916 EL_EMC_WALL_6, -1, -1
6919 Xdecor_3, TRUE, FALSE,
6920 EL_EMC_WALL_4, -1, -1
6923 Xdecor_4, TRUE, FALSE,
6924 EL_EMC_WALL_7, -1, -1
6927 Xdecor_5, TRUE, FALSE,
6928 EL_EMC_WALL_5, -1, -1
6931 Xdecor_6, TRUE, FALSE,
6932 EL_EMC_WALL_9, -1, -1
6935 Xdecor_7, TRUE, FALSE,
6936 EL_EMC_WALL_10, -1, -1
6939 Xdecor_8, TRUE, FALSE,
6940 EL_EMC_WALL_1, -1, -1
6943 Xdecor_9, TRUE, FALSE,
6944 EL_EMC_WALL_2, -1, -1
6947 Xdecor_10, TRUE, FALSE,
6948 EL_EMC_WALL_3, -1, -1
6951 Xdecor_11, TRUE, FALSE,
6952 EL_EMC_WALL_11, -1, -1
6955 Xdecor_12, TRUE, FALSE,
6956 EL_EMC_WALL_12, -1, -1
6959 Xalpha_0, TRUE, FALSE,
6960 EL_CHAR('0'), -1, -1
6963 Xalpha_1, TRUE, FALSE,
6964 EL_CHAR('1'), -1, -1
6967 Xalpha_2, TRUE, FALSE,
6968 EL_CHAR('2'), -1, -1
6971 Xalpha_3, TRUE, FALSE,
6972 EL_CHAR('3'), -1, -1
6975 Xalpha_4, TRUE, FALSE,
6976 EL_CHAR('4'), -1, -1
6979 Xalpha_5, TRUE, FALSE,
6980 EL_CHAR('5'), -1, -1
6983 Xalpha_6, TRUE, FALSE,
6984 EL_CHAR('6'), -1, -1
6987 Xalpha_7, TRUE, FALSE,
6988 EL_CHAR('7'), -1, -1
6991 Xalpha_8, TRUE, FALSE,
6992 EL_CHAR('8'), -1, -1
6995 Xalpha_9, TRUE, FALSE,
6996 EL_CHAR('9'), -1, -1
6999 Xalpha_excla, TRUE, FALSE,
7000 EL_CHAR('!'), -1, -1
7003 Xalpha_quote, TRUE, FALSE,
7004 EL_CHAR('"'), -1, -1
7007 Xalpha_comma, TRUE, FALSE,
7008 EL_CHAR(','), -1, -1
7011 Xalpha_minus, TRUE, FALSE,
7012 EL_CHAR('-'), -1, -1
7015 Xalpha_perio, TRUE, FALSE,
7016 EL_CHAR('.'), -1, -1
7019 Xalpha_colon, TRUE, FALSE,
7020 EL_CHAR(':'), -1, -1
7023 Xalpha_quest, TRUE, FALSE,
7024 EL_CHAR('?'), -1, -1
7027 Xalpha_a, TRUE, FALSE,
7028 EL_CHAR('A'), -1, -1
7031 Xalpha_b, TRUE, FALSE,
7032 EL_CHAR('B'), -1, -1
7035 Xalpha_c, TRUE, FALSE,
7036 EL_CHAR('C'), -1, -1
7039 Xalpha_d, TRUE, FALSE,
7040 EL_CHAR('D'), -1, -1
7043 Xalpha_e, TRUE, FALSE,
7044 EL_CHAR('E'), -1, -1
7047 Xalpha_f, TRUE, FALSE,
7048 EL_CHAR('F'), -1, -1
7051 Xalpha_g, TRUE, FALSE,
7052 EL_CHAR('G'), -1, -1
7055 Xalpha_h, TRUE, FALSE,
7056 EL_CHAR('H'), -1, -1
7059 Xalpha_i, TRUE, FALSE,
7060 EL_CHAR('I'), -1, -1
7063 Xalpha_j, TRUE, FALSE,
7064 EL_CHAR('J'), -1, -1
7067 Xalpha_k, TRUE, FALSE,
7068 EL_CHAR('K'), -1, -1
7071 Xalpha_l, TRUE, FALSE,
7072 EL_CHAR('L'), -1, -1
7075 Xalpha_m, TRUE, FALSE,
7076 EL_CHAR('M'), -1, -1
7079 Xalpha_n, TRUE, FALSE,
7080 EL_CHAR('N'), -1, -1
7083 Xalpha_o, TRUE, FALSE,
7084 EL_CHAR('O'), -1, -1
7087 Xalpha_p, TRUE, FALSE,
7088 EL_CHAR('P'), -1, -1
7091 Xalpha_q, TRUE, FALSE,
7092 EL_CHAR('Q'), -1, -1
7095 Xalpha_r, TRUE, FALSE,
7096 EL_CHAR('R'), -1, -1
7099 Xalpha_s, TRUE, FALSE,
7100 EL_CHAR('S'), -1, -1
7103 Xalpha_t, TRUE, FALSE,
7104 EL_CHAR('T'), -1, -1
7107 Xalpha_u, TRUE, FALSE,
7108 EL_CHAR('U'), -1, -1
7111 Xalpha_v, TRUE, FALSE,
7112 EL_CHAR('V'), -1, -1
7115 Xalpha_w, TRUE, FALSE,
7116 EL_CHAR('W'), -1, -1
7119 Xalpha_x, TRUE, FALSE,
7120 EL_CHAR('X'), -1, -1
7123 Xalpha_y, TRUE, FALSE,
7124 EL_CHAR('Y'), -1, -1
7127 Xalpha_z, TRUE, FALSE,
7128 EL_CHAR('Z'), -1, -1
7131 Xalpha_arrow_e, TRUE, FALSE,
7132 EL_CHAR('>'), -1, -1
7135 Xalpha_arrow_w, TRUE, FALSE,
7136 EL_CHAR('<'), -1, -1
7139 Xalpha_copyr, TRUE, FALSE,
7140 EL_CHAR(CHAR_BYTE_COPYRIGHT), -1, -1
7144 Xboom_bug, FALSE, FALSE,
7145 EL_BUG, ACTION_EXPLODING, -1
7148 Xboom_bomb, FALSE, FALSE,
7149 EL_BOMB, ACTION_EXPLODING, -1
7152 Xboom_android, FALSE, FALSE,
7153 EL_EMC_ANDROID, ACTION_OTHER, -1
7156 Xboom_1, FALSE, FALSE,
7157 EL_DEFAULT, ACTION_EXPLODING, -1
7160 Xboom_2, FALSE, FALSE,
7161 EL_DEFAULT, ACTION_EXPLODING, -1
7164 Znormal, FALSE, FALSE,
7168 Zdynamite, FALSE, FALSE,
7172 Zplayer, FALSE, FALSE,
7176 ZBORDER, FALSE, FALSE,
7186 static struct Mapping_EM_to_RND_player
7195 em_player_mapping_list[] =
7199 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
7203 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
7207 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
7211 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
7215 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
7219 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
7223 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
7227 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
7231 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
7235 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
7239 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
7243 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
7247 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
7251 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
7255 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
7259 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
7263 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
7267 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
7271 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
7275 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
7279 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
7283 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
7287 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
7291 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
7295 EL_PLAYER_1, ACTION_DEFAULT, -1,
7299 EL_PLAYER_2, ACTION_DEFAULT, -1,
7303 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
7307 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
7311 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
7315 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
7319 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
7323 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
7327 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
7331 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
7335 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
7339 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
7343 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
7347 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
7351 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
7355 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
7359 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
7363 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
7367 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
7371 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
7375 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
7379 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
7383 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
7387 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
7391 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
7395 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
7399 EL_PLAYER_3, ACTION_DEFAULT, -1,
7403 EL_PLAYER_4, ACTION_DEFAULT, -1,
7412 int map_element_RND_to_EM(int element_rnd)
7414 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
7415 static boolean mapping_initialized = FALSE;
7417 if (!mapping_initialized)
7421 /* return "Xalpha_quest" for all undefined elements in mapping array */
7422 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
7423 mapping_RND_to_EM[i] = Xalpha_quest;
7425 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
7426 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
7427 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
7428 em_object_mapping_list[i].element_em;
7430 mapping_initialized = TRUE;
7433 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
7434 return mapping_RND_to_EM[element_rnd];
7436 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
7441 int map_element_EM_to_RND(int element_em)
7443 static unsigned short mapping_EM_to_RND[TILE_MAX];
7444 static boolean mapping_initialized = FALSE;
7446 if (!mapping_initialized)
7450 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
7451 for (i = 0; i < TILE_MAX; i++)
7452 mapping_EM_to_RND[i] = EL_UNKNOWN;
7454 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
7455 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
7456 em_object_mapping_list[i].element_rnd;
7458 mapping_initialized = TRUE;
7461 if (element_em >= 0 && element_em < TILE_MAX)
7462 return mapping_EM_to_RND[element_em];
7464 Error(ERR_WARN, "invalid EM level element %d", element_em);
7469 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
7471 struct LevelInfo_EM *level_em = level->native_em_level;
7472 struct LEVEL *lev = level_em->lev;
7475 for (i = 0; i < TILE_MAX; i++)
7476 lev->android_array[i] = Xblank;
7478 for (i = 0; i < level->num_android_clone_elements; i++)
7480 int element_rnd = level->android_clone_element[i];
7481 int element_em = map_element_RND_to_EM(element_rnd);
7483 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
7484 if (em_object_mapping_list[j].element_rnd == element_rnd)
7485 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
7489 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
7491 struct LevelInfo_EM *level_em = level->native_em_level;
7492 struct LEVEL *lev = level_em->lev;
7495 level->num_android_clone_elements = 0;
7497 for (i = 0; i < TILE_MAX; i++)
7499 int element_em = lev->android_array[i];
7501 boolean element_found = FALSE;
7503 if (element_em == Xblank)
7506 element_rnd = map_element_EM_to_RND(element_em);
7508 for (j = 0; j < level->num_android_clone_elements; j++)
7509 if (level->android_clone_element[j] == element_rnd)
7510 element_found = TRUE;
7514 level->android_clone_element[level->num_android_clone_elements++] =
7517 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
7522 if (level->num_android_clone_elements == 0)
7524 level->num_android_clone_elements = 1;
7525 level->android_clone_element[0] = EL_EMPTY;
7529 int map_direction_RND_to_EM(int direction)
7531 return (direction == MV_UP ? 0 :
7532 direction == MV_RIGHT ? 1 :
7533 direction == MV_DOWN ? 2 :
7534 direction == MV_LEFT ? 3 :
7538 int map_direction_EM_to_RND(int direction)
7540 return (direction == 0 ? MV_UP :
7541 direction == 1 ? MV_RIGHT :
7542 direction == 2 ? MV_DOWN :
7543 direction == 3 ? MV_LEFT :
7547 int map_element_RND_to_SP(int element_rnd)
7549 int element_sp = 0x20; /* map unknown elements to yellow "hardware" */
7551 if (element_rnd >= EL_SP_START &&
7552 element_rnd <= EL_SP_END)
7553 element_sp = element_rnd - EL_SP_START;
7554 else if (element_rnd == EL_EMPTY_SPACE)
7556 else if (element_rnd == EL_INVISIBLE_WALL)
7562 int map_element_SP_to_RND(int element_sp)
7564 int element_rnd = EL_UNKNOWN;
7566 if (element_sp >= 0x00 &&
7568 element_rnd = EL_SP_START + element_sp;
7569 else if (element_sp == 0x28)
7570 element_rnd = EL_INVISIBLE_WALL;
7575 int map_action_SP_to_RND(int action_sp)
7579 case actActive: return ACTION_ACTIVE;
7580 case actImpact: return ACTION_IMPACT;
7581 case actExploding: return ACTION_EXPLODING;
7582 case actDigging: return ACTION_DIGGING;
7583 case actSnapping: return ACTION_SNAPPING;
7584 case actCollecting: return ACTION_COLLECTING;
7585 case actPassing: return ACTION_PASSING;
7586 case actPushing: return ACTION_PUSHING;
7587 case actDropping: return ACTION_DROPPING;
7589 default: return ACTION_DEFAULT;
7593 int map_element_RND_to_MM(int element_rnd)
7595 return (element_rnd >= EL_MM_START_1 &&
7596 element_rnd <= EL_MM_END_1 ?
7597 EL_MM_START_1_NATIVE + element_rnd - EL_MM_START_1 :
7599 element_rnd >= EL_MM_START_2 &&
7600 element_rnd <= EL_MM_END_2 ?
7601 EL_MM_START_2_NATIVE + element_rnd - EL_MM_START_2 :
7603 element_rnd >= EL_CHAR_START &&
7604 element_rnd <= EL_CHAR_END ?
7605 EL_MM_CHAR_START_NATIVE + element_rnd - EL_CHAR_START :
7607 element_rnd >= EL_MM_RUNTIME_START &&
7608 element_rnd <= EL_MM_RUNTIME_END ?
7609 EL_MM_RUNTIME_START_NATIVE + element_rnd - EL_MM_RUNTIME_START :
7611 element_rnd >= EL_MM_DUMMY_START &&
7612 element_rnd <= EL_MM_DUMMY_END ?
7613 EL_MM_DUMMY_START_NATIVE + element_rnd - EL_MM_DUMMY_START :
7615 EL_MM_EMPTY_NATIVE);
7618 int map_element_MM_to_RND(int element_mm)
7620 return (element_mm == EL_MM_EMPTY_NATIVE ||
7621 element_mm == EL_DF_EMPTY_NATIVE ?
7624 element_mm >= EL_MM_START_1_NATIVE &&
7625 element_mm <= EL_MM_END_1_NATIVE ?
7626 EL_MM_START_1 + element_mm - EL_MM_START_1_NATIVE :
7628 element_mm >= EL_MM_START_2_NATIVE &&
7629 element_mm <= EL_MM_END_2_NATIVE ?
7630 EL_MM_START_2 + element_mm - EL_MM_START_2_NATIVE :
7632 element_mm >= EL_MM_CHAR_START_NATIVE &&
7633 element_mm <= EL_MM_CHAR_END_NATIVE ?
7634 EL_CHAR_START + element_mm - EL_MM_CHAR_START_NATIVE :
7636 element_mm >= EL_MM_RUNTIME_START_NATIVE &&
7637 element_mm <= EL_MM_RUNTIME_END_NATIVE ?
7638 EL_MM_RUNTIME_START + element_mm - EL_MM_RUNTIME_START_NATIVE :
7640 element_mm >= EL_MM_DUMMY_START_NATIVE &&
7641 element_mm <= EL_MM_DUMMY_END_NATIVE ?
7642 EL_MM_DUMMY_START + element_mm - EL_MM_DUMMY_START_NATIVE :
7647 int map_action_MM_to_RND(int action_mm)
7649 /* all MM actions are defined to exactly match their RND counterparts */
7653 int map_sound_MM_to_RND(int sound_mm)
7657 case SND_MM_GAME_LEVELTIME_CHARGING:
7658 return SND_GAME_LEVELTIME_CHARGING;
7660 case SND_MM_GAME_HEALTH_CHARGING:
7661 return SND_GAME_HEALTH_CHARGING;
7664 return SND_UNDEFINED;
7668 int map_mm_wall_element(int element)
7670 return (element >= EL_MM_STEEL_WALL_START &&
7671 element <= EL_MM_STEEL_WALL_END ?
7674 element >= EL_MM_WOODEN_WALL_START &&
7675 element <= EL_MM_WOODEN_WALL_END ?
7678 element >= EL_MM_ICE_WALL_START &&
7679 element <= EL_MM_ICE_WALL_END ?
7682 element >= EL_MM_AMOEBA_WALL_START &&
7683 element <= EL_MM_AMOEBA_WALL_END ?
7686 element >= EL_DF_STEEL_WALL_START &&
7687 element <= EL_DF_STEEL_WALL_END ?
7690 element >= EL_DF_WOODEN_WALL_START &&
7691 element <= EL_DF_WOODEN_WALL_END ?
7697 int map_mm_wall_element_editor(int element)
7701 case EL_MM_STEEL_WALL: return EL_MM_STEEL_WALL_START;
7702 case EL_MM_WOODEN_WALL: return EL_MM_WOODEN_WALL_START;
7703 case EL_MM_ICE_WALL: return EL_MM_ICE_WALL_START;
7704 case EL_MM_AMOEBA_WALL: return EL_MM_AMOEBA_WALL_START;
7705 case EL_DF_STEEL_WALL: return EL_DF_STEEL_WALL_START;
7706 case EL_DF_WOODEN_WALL: return EL_DF_WOODEN_WALL_START;
7708 default: return element;
7712 int get_next_element(int element)
7716 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
7717 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
7718 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
7719 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
7720 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
7721 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
7722 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
7723 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
7724 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
7725 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
7726 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
7728 default: return element;
7732 int el2img_mm(int element_mm)
7734 return el2img(map_element_MM_to_RND(element_mm));
7737 int el_act_dir2img(int element, int action, int direction)
7739 element = GFX_ELEMENT(element);
7740 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
7742 /* direction_graphic[][] == graphic[] for undefined direction graphics */
7743 return element_info[element].direction_graphic[action][direction];
7746 static int el_act_dir2crm(int element, int action, int direction)
7748 element = GFX_ELEMENT(element);
7749 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
7751 /* direction_graphic[][] == graphic[] for undefined direction graphics */
7752 return element_info[element].direction_crumbled[action][direction];
7755 int el_act2img(int element, int action)
7757 element = GFX_ELEMENT(element);
7759 return element_info[element].graphic[action];
7762 int el_act2crm(int element, int action)
7764 element = GFX_ELEMENT(element);
7766 return element_info[element].crumbled[action];
7769 int el_dir2img(int element, int direction)
7771 element = GFX_ELEMENT(element);
7773 return el_act_dir2img(element, ACTION_DEFAULT, direction);
7776 int el2baseimg(int element)
7778 return element_info[element].graphic[ACTION_DEFAULT];
7781 int el2img(int element)
7783 element = GFX_ELEMENT(element);
7785 return element_info[element].graphic[ACTION_DEFAULT];
7788 int el2edimg(int element)
7790 element = GFX_ELEMENT(element);
7792 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
7795 int el2preimg(int element)
7797 element = GFX_ELEMENT(element);
7799 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
7802 int el2panelimg(int element)
7804 element = GFX_ELEMENT(element);
7806 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL];
7809 int font2baseimg(int font_nr)
7811 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
7814 int getBeltNrFromBeltElement(int element)
7816 return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
7817 element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
7818 element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
7821 int getBeltNrFromBeltActiveElement(int element)
7823 return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
7824 element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
7825 element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
7828 int getBeltNrFromBeltSwitchElement(int element)
7830 return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
7831 element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
7832 element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
7835 int getBeltDirNrFromBeltElement(int element)
7837 static int belt_base_element[4] =
7839 EL_CONVEYOR_BELT_1_LEFT,
7840 EL_CONVEYOR_BELT_2_LEFT,
7841 EL_CONVEYOR_BELT_3_LEFT,
7842 EL_CONVEYOR_BELT_4_LEFT
7845 int belt_nr = getBeltNrFromBeltElement(element);
7846 int belt_dir_nr = element - belt_base_element[belt_nr];
7848 return (belt_dir_nr % 3);
7851 int getBeltDirNrFromBeltSwitchElement(int element)
7853 static int belt_base_element[4] =
7855 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
7856 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
7857 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
7858 EL_CONVEYOR_BELT_4_SWITCH_LEFT
7861 int belt_nr = getBeltNrFromBeltSwitchElement(element);
7862 int belt_dir_nr = element - belt_base_element[belt_nr];
7864 return (belt_dir_nr % 3);
7867 int getBeltDirFromBeltElement(int element)
7869 static int belt_move_dir[3] =
7876 int belt_dir_nr = getBeltDirNrFromBeltElement(element);
7878 return belt_move_dir[belt_dir_nr];
7881 int getBeltDirFromBeltSwitchElement(int element)
7883 static int belt_move_dir[3] =
7890 int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
7892 return belt_move_dir[belt_dir_nr];
7895 int getBeltElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
7897 static int belt_base_element[4] =
7899 EL_CONVEYOR_BELT_1_LEFT,
7900 EL_CONVEYOR_BELT_2_LEFT,
7901 EL_CONVEYOR_BELT_3_LEFT,
7902 EL_CONVEYOR_BELT_4_LEFT
7905 return belt_base_element[belt_nr] + belt_dir_nr;
7908 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
7910 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
7912 return getBeltElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
7915 int getBeltSwitchElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
7917 static int belt_base_element[4] =
7919 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
7920 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
7921 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
7922 EL_CONVEYOR_BELT_4_SWITCH_LEFT
7925 return belt_base_element[belt_nr] + belt_dir_nr;
7928 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
7930 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
7932 return getBeltSwitchElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
7935 boolean getTeamMode_EM()
7937 return game.team_mode;
7940 int getGameFrameDelay_EM(int native_em_game_frame_delay)
7942 int game_frame_delay_value;
7944 game_frame_delay_value =
7945 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
7946 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
7949 if (tape.playing && tape.warp_forward && !tape.pausing)
7950 game_frame_delay_value = 0;
7952 return game_frame_delay_value;
7955 unsigned int InitRND(int seed)
7957 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
7958 return InitEngineRandom_EM(seed);
7959 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
7960 return InitEngineRandom_SP(seed);
7961 else if (level.game_engine_type == GAME_ENGINE_TYPE_MM)
7962 return InitEngineRandom_MM(seed);
7964 return InitEngineRandom_RND(seed);
7967 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
7968 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
7970 inline static int get_effective_element_EM(int tile, int frame_em)
7972 int element = object_mapping[tile].element_rnd;
7973 int action = object_mapping[tile].action;
7974 boolean is_backside = object_mapping[tile].is_backside;
7975 boolean action_removing = (action == ACTION_DIGGING ||
7976 action == ACTION_SNAPPING ||
7977 action == ACTION_COLLECTING);
7983 case Yacid_splash_eB:
7984 case Yacid_splash_wB:
7985 return (frame_em > 5 ? EL_EMPTY : element);
7991 else /* frame_em == 7 */
7995 case Yacid_splash_eB:
7996 case Yacid_splash_wB:
7999 case Yemerald_stone:
8002 case Ydiamond_stone:
8006 case Xdrip_stretchB:
8025 case Xsand_stonein_1:
8026 case Xsand_stonein_2:
8027 case Xsand_stonein_3:
8028 case Xsand_stonein_4:
8032 return (is_backside || action_removing ? EL_EMPTY : element);
8037 inline static boolean check_linear_animation_EM(int tile)
8041 case Xsand_stonesand_1:
8042 case Xsand_stonesand_quickout_1:
8043 case Xsand_sandstone_1:
8044 case Xsand_stonein_1:
8045 case Xsand_stoneout_1:
8064 case Yacid_splash_eB:
8065 case Yacid_splash_wB:
8066 case Yemerald_stone:
8073 inline static void set_crumbled_graphics_EM(struct GraphicInfo_EM *g_em,
8074 boolean has_crumbled_graphics,
8075 int crumbled, int sync_frame)
8077 /* if element can be crumbled, but certain action graphics are just empty
8078 space (like instantly snapping sand to empty space in 1 frame), do not
8079 treat these empty space graphics as crumbled graphics in EMC engine */
8080 if (crumbled == IMG_EMPTY_SPACE)
8081 has_crumbled_graphics = FALSE;
8083 if (has_crumbled_graphics)
8085 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
8086 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
8087 g_crumbled->anim_delay,
8088 g_crumbled->anim_mode,
8089 g_crumbled->anim_start_frame,
8092 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
8093 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
8095 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
8096 g_em->crumbled_tile_size = graphic_info[crumbled].tile_size;
8098 g_em->has_crumbled_graphics = TRUE;
8102 g_em->crumbled_bitmap = NULL;
8103 g_em->crumbled_src_x = 0;
8104 g_em->crumbled_src_y = 0;
8105 g_em->crumbled_border_size = 0;
8106 g_em->crumbled_tile_size = 0;
8108 g_em->has_crumbled_graphics = FALSE;
8112 void ResetGfxAnimation_EM(int x, int y, int tile)
8117 void SetGfxAnimation_EM(struct GraphicInfo_EM *g_em,
8118 int tile, int frame_em, int x, int y)
8120 int action = object_mapping[tile].action;
8121 int direction = object_mapping[tile].direction;
8122 int effective_element = get_effective_element_EM(tile, frame_em);
8123 int graphic = (direction == MV_NONE ?
8124 el_act2img(effective_element, action) :
8125 el_act_dir2img(effective_element, action, direction));
8126 struct GraphicInfo *g = &graphic_info[graphic];
8128 boolean action_removing = (action == ACTION_DIGGING ||
8129 action == ACTION_SNAPPING ||
8130 action == ACTION_COLLECTING);
8131 boolean action_moving = (action == ACTION_FALLING ||
8132 action == ACTION_MOVING ||
8133 action == ACTION_PUSHING ||
8134 action == ACTION_EATING ||
8135 action == ACTION_FILLING ||
8136 action == ACTION_EMPTYING);
8137 boolean action_falling = (action == ACTION_FALLING ||
8138 action == ACTION_FILLING ||
8139 action == ACTION_EMPTYING);
8141 /* special case: graphic uses "2nd movement tile" and has defined
8142 7 frames for movement animation (or less) => use default graphic
8143 for last (8th) frame which ends the movement animation */
8144 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
8146 action = ACTION_DEFAULT; /* (keep action_* unchanged for now) */
8147 graphic = (direction == MV_NONE ?
8148 el_act2img(effective_element, action) :
8149 el_act_dir2img(effective_element, action, direction));
8151 g = &graphic_info[graphic];
8154 if ((action_removing || check_linear_animation_EM(tile)) && frame_em == 0)
8158 else if (action_moving)
8160 boolean is_backside = object_mapping[tile].is_backside;
8164 int direction = object_mapping[tile].direction;
8165 int move_dir = (action_falling ? MV_DOWN : direction);
8170 /* !!! TEST !!! NEW !!! DOES NOT WORK RIGHT YET !!! */
8171 if (g->double_movement && frame_em == 0)
8175 if (move_dir == MV_LEFT)
8176 GfxFrame[x - 1][y] = GfxFrame[x][y];
8177 else if (move_dir == MV_RIGHT)
8178 GfxFrame[x + 1][y] = GfxFrame[x][y];
8179 else if (move_dir == MV_UP)
8180 GfxFrame[x][y - 1] = GfxFrame[x][y];
8181 else if (move_dir == MV_DOWN)
8182 GfxFrame[x][y + 1] = GfxFrame[x][y];
8189 /* special case: animation for Xsand_stonesand_quickout_1/2 twice as fast */
8190 if (tile == Xsand_stonesand_quickout_1 ||
8191 tile == Xsand_stonesand_quickout_2)
8195 if (graphic_info[graphic].anim_global_sync)
8196 sync_frame = FrameCounter;
8197 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
8198 sync_frame = GfxFrame[x][y];
8200 sync_frame = 0; /* playfield border (pseudo steel) */
8202 SetRandomAnimationValue(x, y);
8204 int frame = getAnimationFrame(g->anim_frames,
8207 g->anim_start_frame,
8210 g_em->unique_identifier =
8211 (graphic << 16) | ((frame % 8) << 12) | (g_em->width << 6) | g_em->height;
8214 void getGraphicSourceObjectExt_EM(struct GraphicInfo_EM *g_em,
8215 int tile, int frame_em, int x, int y)
8217 int action = object_mapping[tile].action;
8218 int direction = object_mapping[tile].direction;
8219 boolean is_backside = object_mapping[tile].is_backside;
8220 int effective_element = get_effective_element_EM(tile, frame_em);
8221 int effective_action = action;
8222 int graphic = (direction == MV_NONE ?
8223 el_act2img(effective_element, effective_action) :
8224 el_act_dir2img(effective_element, effective_action,
8226 int crumbled = (direction == MV_NONE ?
8227 el_act2crm(effective_element, effective_action) :
8228 el_act_dir2crm(effective_element, effective_action,
8230 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
8231 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
8232 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
8233 struct GraphicInfo *g = &graphic_info[graphic];
8236 /* special case: graphic uses "2nd movement tile" and has defined
8237 7 frames for movement animation (or less) => use default graphic
8238 for last (8th) frame which ends the movement animation */
8239 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
8241 effective_action = ACTION_DEFAULT;
8242 graphic = (direction == MV_NONE ?
8243 el_act2img(effective_element, effective_action) :
8244 el_act_dir2img(effective_element, effective_action,
8246 crumbled = (direction == MV_NONE ?
8247 el_act2crm(effective_element, effective_action) :
8248 el_act_dir2crm(effective_element, effective_action,
8251 g = &graphic_info[graphic];
8254 if (graphic_info[graphic].anim_global_sync)
8255 sync_frame = FrameCounter;
8256 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
8257 sync_frame = GfxFrame[x][y];
8259 sync_frame = 0; /* playfield border (pseudo steel) */
8261 SetRandomAnimationValue(x, y);
8263 int frame = getAnimationFrame(g->anim_frames,
8266 g->anim_start_frame,
8269 getGraphicSourceExt(graphic, frame, &g_em->bitmap, &g_em->src_x, &g_em->src_y,
8270 g->double_movement && is_backside);
8272 /* (updating the "crumbled" graphic definitions is probably not really needed,
8273 as animations for crumbled graphics can't be longer than one EMC cycle) */
8274 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
8278 void getGraphicSourcePlayerExt_EM(struct GraphicInfo_EM *g_em,
8279 int player_nr, int anim, int frame_em)
8281 int element = player_mapping[player_nr][anim].element_rnd;
8282 int action = player_mapping[player_nr][anim].action;
8283 int direction = player_mapping[player_nr][anim].direction;
8284 int graphic = (direction == MV_NONE ?
8285 el_act2img(element, action) :
8286 el_act_dir2img(element, action, direction));
8287 struct GraphicInfo *g = &graphic_info[graphic];
8290 InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
8292 stored_player[player_nr].StepFrame = frame_em;
8294 sync_frame = stored_player[player_nr].Frame;
8296 int frame = getAnimationFrame(g->anim_frames,
8299 g->anim_start_frame,
8302 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
8303 &g_em->src_x, &g_em->src_y, FALSE);
8306 void InitGraphicInfo_EM(void)
8311 int num_em_gfx_errors = 0;
8313 if (graphic_info_em_object[0][0].bitmap == NULL)
8315 /* EM graphics not yet initialized in em_open_all() */
8320 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
8323 /* always start with reliable default values */
8324 for (i = 0; i < TILE_MAX; i++)
8326 object_mapping[i].element_rnd = EL_UNKNOWN;
8327 object_mapping[i].is_backside = FALSE;
8328 object_mapping[i].action = ACTION_DEFAULT;
8329 object_mapping[i].direction = MV_NONE;
8332 /* always start with reliable default values */
8333 for (p = 0; p < MAX_PLAYERS; p++)
8335 for (i = 0; i < SPR_MAX; i++)
8337 player_mapping[p][i].element_rnd = EL_UNKNOWN;
8338 player_mapping[p][i].action = ACTION_DEFAULT;
8339 player_mapping[p][i].direction = MV_NONE;
8343 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
8345 int e = em_object_mapping_list[i].element_em;
8347 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
8348 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
8350 if (em_object_mapping_list[i].action != -1)
8351 object_mapping[e].action = em_object_mapping_list[i].action;
8353 if (em_object_mapping_list[i].direction != -1)
8354 object_mapping[e].direction =
8355 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
8358 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
8360 int a = em_player_mapping_list[i].action_em;
8361 int p = em_player_mapping_list[i].player_nr;
8363 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
8365 if (em_player_mapping_list[i].action != -1)
8366 player_mapping[p][a].action = em_player_mapping_list[i].action;
8368 if (em_player_mapping_list[i].direction != -1)
8369 player_mapping[p][a].direction =
8370 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
8373 for (i = 0; i < TILE_MAX; i++)
8375 int element = object_mapping[i].element_rnd;
8376 int action = object_mapping[i].action;
8377 int direction = object_mapping[i].direction;
8378 boolean is_backside = object_mapping[i].is_backside;
8379 boolean action_exploding = ((action == ACTION_EXPLODING ||
8380 action == ACTION_SMASHED_BY_ROCK ||
8381 action == ACTION_SMASHED_BY_SPRING) &&
8382 element != EL_DIAMOND);
8383 boolean action_active = (action == ACTION_ACTIVE);
8384 boolean action_other = (action == ACTION_OTHER);
8386 for (j = 0; j < 8; j++)
8388 int effective_element = get_effective_element_EM(i, j);
8389 int effective_action = (j < 7 ? action :
8390 i == Xdrip_stretch ? action :
8391 i == Xdrip_stretchB ? action :
8392 i == Ydrip_s1 ? action :
8393 i == Ydrip_s1B ? action :
8394 i == Xball_1B ? action :
8395 i == Xball_2 ? action :
8396 i == Xball_2B ? action :
8397 i == Yball_eat ? action :
8398 i == Ykey_1_eat ? action :
8399 i == Ykey_2_eat ? action :
8400 i == Ykey_3_eat ? action :
8401 i == Ykey_4_eat ? action :
8402 i == Ykey_5_eat ? action :
8403 i == Ykey_6_eat ? action :
8404 i == Ykey_7_eat ? action :
8405 i == Ykey_8_eat ? action :
8406 i == Ylenses_eat ? action :
8407 i == Ymagnify_eat ? action :
8408 i == Ygrass_eat ? action :
8409 i == Ydirt_eat ? action :
8410 i == Xsand_stonein_1 ? action :
8411 i == Xsand_stonein_2 ? action :
8412 i == Xsand_stonein_3 ? action :
8413 i == Xsand_stonein_4 ? action :
8414 i == Xsand_stoneout_1 ? action :
8415 i == Xsand_stoneout_2 ? action :
8416 i == Xboom_android ? ACTION_EXPLODING :
8417 action_exploding ? ACTION_EXPLODING :
8418 action_active ? action :
8419 action_other ? action :
8421 int graphic = (el_act_dir2img(effective_element, effective_action,
8423 int crumbled = (el_act_dir2crm(effective_element, effective_action,
8425 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
8426 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
8427 boolean has_action_graphics = (graphic != base_graphic);
8428 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
8429 struct GraphicInfo *g = &graphic_info[graphic];
8430 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
8433 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
8434 boolean special_animation = (action != ACTION_DEFAULT &&
8435 g->anim_frames == 3 &&
8436 g->anim_delay == 2 &&
8437 g->anim_mode & ANIM_LINEAR);
8438 int sync_frame = (i == Xdrip_stretch ? 7 :
8439 i == Xdrip_stretchB ? 7 :
8440 i == Ydrip_s2 ? j + 8 :
8441 i == Ydrip_s2B ? j + 8 :
8450 i == Xfake_acid_1 ? 0 :
8451 i == Xfake_acid_2 ? 10 :
8452 i == Xfake_acid_3 ? 20 :
8453 i == Xfake_acid_4 ? 30 :
8454 i == Xfake_acid_5 ? 40 :
8455 i == Xfake_acid_6 ? 50 :
8456 i == Xfake_acid_7 ? 60 :
8457 i == Xfake_acid_8 ? 70 :
8459 i == Xball_2B ? j + 8 :
8460 i == Yball_eat ? j + 1 :
8461 i == Ykey_1_eat ? j + 1 :
8462 i == Ykey_2_eat ? j + 1 :
8463 i == Ykey_3_eat ? j + 1 :
8464 i == Ykey_4_eat ? j + 1 :
8465 i == Ykey_5_eat ? j + 1 :
8466 i == Ykey_6_eat ? j + 1 :
8467 i == Ykey_7_eat ? j + 1 :
8468 i == Ykey_8_eat ? j + 1 :
8469 i == Ylenses_eat ? j + 1 :
8470 i == Ymagnify_eat ? j + 1 :
8471 i == Ygrass_eat ? j + 1 :
8472 i == Ydirt_eat ? j + 1 :
8473 i == Xamoeba_1 ? 0 :
8474 i == Xamoeba_2 ? 1 :
8475 i == Xamoeba_3 ? 2 :
8476 i == Xamoeba_4 ? 3 :
8477 i == Xamoeba_5 ? 0 :
8478 i == Xamoeba_6 ? 1 :
8479 i == Xamoeba_7 ? 2 :
8480 i == Xamoeba_8 ? 3 :
8481 i == Xexit_2 ? j + 8 :
8482 i == Xexit_3 ? j + 16 :
8483 i == Xdynamite_1 ? 0 :
8484 i == Xdynamite_2 ? 8 :
8485 i == Xdynamite_3 ? 16 :
8486 i == Xdynamite_4 ? 24 :
8487 i == Xsand_stonein_1 ? j + 1 :
8488 i == Xsand_stonein_2 ? j + 9 :
8489 i == Xsand_stonein_3 ? j + 17 :
8490 i == Xsand_stonein_4 ? j + 25 :
8491 i == Xsand_stoneout_1 && j == 0 ? 0 :
8492 i == Xsand_stoneout_1 && j == 1 ? 0 :
8493 i == Xsand_stoneout_1 && j == 2 ? 1 :
8494 i == Xsand_stoneout_1 && j == 3 ? 2 :
8495 i == Xsand_stoneout_1 && j == 4 ? 2 :
8496 i == Xsand_stoneout_1 && j == 5 ? 3 :
8497 i == Xsand_stoneout_1 && j == 6 ? 4 :
8498 i == Xsand_stoneout_1 && j == 7 ? 4 :
8499 i == Xsand_stoneout_2 && j == 0 ? 5 :
8500 i == Xsand_stoneout_2 && j == 1 ? 6 :
8501 i == Xsand_stoneout_2 && j == 2 ? 7 :
8502 i == Xsand_stoneout_2 && j == 3 ? 8 :
8503 i == Xsand_stoneout_2 && j == 4 ? 9 :
8504 i == Xsand_stoneout_2 && j == 5 ? 11 :
8505 i == Xsand_stoneout_2 && j == 6 ? 13 :
8506 i == Xsand_stoneout_2 && j == 7 ? 15 :
8507 i == Xboom_bug && j == 1 ? 2 :
8508 i == Xboom_bug && j == 2 ? 2 :
8509 i == Xboom_bug && j == 3 ? 4 :
8510 i == Xboom_bug && j == 4 ? 4 :
8511 i == Xboom_bug && j == 5 ? 2 :
8512 i == Xboom_bug && j == 6 ? 2 :
8513 i == Xboom_bug && j == 7 ? 0 :
8514 i == Xboom_bomb && j == 1 ? 2 :
8515 i == Xboom_bomb && j == 2 ? 2 :
8516 i == Xboom_bomb && j == 3 ? 4 :
8517 i == Xboom_bomb && j == 4 ? 4 :
8518 i == Xboom_bomb && j == 5 ? 2 :
8519 i == Xboom_bomb && j == 6 ? 2 :
8520 i == Xboom_bomb && j == 7 ? 0 :
8521 i == Xboom_android && j == 7 ? 6 :
8522 i == Xboom_1 && j == 1 ? 2 :
8523 i == Xboom_1 && j == 2 ? 2 :
8524 i == Xboom_1 && j == 3 ? 4 :
8525 i == Xboom_1 && j == 4 ? 4 :
8526 i == Xboom_1 && j == 5 ? 6 :
8527 i == Xboom_1 && j == 6 ? 6 :
8528 i == Xboom_1 && j == 7 ? 8 :
8529 i == Xboom_2 && j == 0 ? 8 :
8530 i == Xboom_2 && j == 1 ? 8 :
8531 i == Xboom_2 && j == 2 ? 10 :
8532 i == Xboom_2 && j == 3 ? 10 :
8533 i == Xboom_2 && j == 4 ? 10 :
8534 i == Xboom_2 && j == 5 ? 12 :
8535 i == Xboom_2 && j == 6 ? 12 :
8536 i == Xboom_2 && j == 7 ? 12 :
8537 special_animation && j == 4 ? 3 :
8538 effective_action != action ? 0 :
8542 Bitmap *debug_bitmap = g_em->bitmap;
8543 int debug_src_x = g_em->src_x;
8544 int debug_src_y = g_em->src_y;
8547 int frame = getAnimationFrame(g->anim_frames,
8550 g->anim_start_frame,
8553 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
8554 g->double_movement && is_backside);
8556 g_em->bitmap = src_bitmap;
8557 g_em->src_x = src_x;
8558 g_em->src_y = src_y;
8559 g_em->src_offset_x = 0;
8560 g_em->src_offset_y = 0;
8561 g_em->dst_offset_x = 0;
8562 g_em->dst_offset_y = 0;
8563 g_em->width = TILEX;
8564 g_em->height = TILEY;
8566 g_em->preserve_background = FALSE;
8568 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
8571 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
8572 effective_action == ACTION_MOVING ||
8573 effective_action == ACTION_PUSHING ||
8574 effective_action == ACTION_EATING)) ||
8575 (!has_action_graphics && (effective_action == ACTION_FILLING ||
8576 effective_action == ACTION_EMPTYING)))
8579 (effective_action == ACTION_FALLING ||
8580 effective_action == ACTION_FILLING ||
8581 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
8582 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
8583 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
8584 int num_steps = (i == Ydrip_s1 ? 16 :
8585 i == Ydrip_s1B ? 16 :
8586 i == Ydrip_s2 ? 16 :
8587 i == Ydrip_s2B ? 16 :
8588 i == Xsand_stonein_1 ? 32 :
8589 i == Xsand_stonein_2 ? 32 :
8590 i == Xsand_stonein_3 ? 32 :
8591 i == Xsand_stonein_4 ? 32 :
8592 i == Xsand_stoneout_1 ? 16 :
8593 i == Xsand_stoneout_2 ? 16 : 8);
8594 int cx = ABS(dx) * (TILEX / num_steps);
8595 int cy = ABS(dy) * (TILEY / num_steps);
8596 int step_frame = (i == Ydrip_s2 ? j + 8 :
8597 i == Ydrip_s2B ? j + 8 :
8598 i == Xsand_stonein_2 ? j + 8 :
8599 i == Xsand_stonein_3 ? j + 16 :
8600 i == Xsand_stonein_4 ? j + 24 :
8601 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
8602 int step = (is_backside ? step_frame : num_steps - step_frame);
8604 if (is_backside) /* tile where movement starts */
8606 if (dx < 0 || dy < 0)
8608 g_em->src_offset_x = cx * step;
8609 g_em->src_offset_y = cy * step;
8613 g_em->dst_offset_x = cx * step;
8614 g_em->dst_offset_y = cy * step;
8617 else /* tile where movement ends */
8619 if (dx < 0 || dy < 0)
8621 g_em->dst_offset_x = cx * step;
8622 g_em->dst_offset_y = cy * step;
8626 g_em->src_offset_x = cx * step;
8627 g_em->src_offset_y = cy * step;
8631 g_em->width = TILEX - cx * step;
8632 g_em->height = TILEY - cy * step;
8635 /* create unique graphic identifier to decide if tile must be redrawn */
8636 /* bit 31 - 16 (16 bit): EM style graphic
8637 bit 15 - 12 ( 4 bit): EM style frame
8638 bit 11 - 6 ( 6 bit): graphic width
8639 bit 5 - 0 ( 6 bit): graphic height */
8640 g_em->unique_identifier =
8641 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
8645 /* skip check for EMC elements not contained in original EMC artwork */
8646 if (element == EL_EMC_FAKE_ACID)
8649 if (g_em->bitmap != debug_bitmap ||
8650 g_em->src_x != debug_src_x ||
8651 g_em->src_y != debug_src_y ||
8652 g_em->src_offset_x != 0 ||
8653 g_em->src_offset_y != 0 ||
8654 g_em->dst_offset_x != 0 ||
8655 g_em->dst_offset_y != 0 ||
8656 g_em->width != TILEX ||
8657 g_em->height != TILEY)
8659 static int last_i = -1;
8667 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
8668 i, element, element_info[element].token_name,
8669 element_action_info[effective_action].suffix, direction);
8671 if (element != effective_element)
8672 printf(" [%d ('%s')]",
8674 element_info[effective_element].token_name);
8678 if (g_em->bitmap != debug_bitmap)
8679 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
8680 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
8682 if (g_em->src_x != debug_src_x ||
8683 g_em->src_y != debug_src_y)
8684 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
8685 j, (is_backside ? 'B' : 'F'),
8686 g_em->src_x, g_em->src_y,
8687 g_em->src_x / 32, g_em->src_y / 32,
8688 debug_src_x, debug_src_y,
8689 debug_src_x / 32, debug_src_y / 32);
8691 if (g_em->src_offset_x != 0 ||
8692 g_em->src_offset_y != 0 ||
8693 g_em->dst_offset_x != 0 ||
8694 g_em->dst_offset_y != 0)
8695 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
8697 g_em->src_offset_x, g_em->src_offset_y,
8698 g_em->dst_offset_x, g_em->dst_offset_y);
8700 if (g_em->width != TILEX ||
8701 g_em->height != TILEY)
8702 printf(" %d (%d): size %d,%d should be %d,%d\n",
8704 g_em->width, g_em->height, TILEX, TILEY);
8706 num_em_gfx_errors++;
8713 for (i = 0; i < TILE_MAX; i++)
8715 for (j = 0; j < 8; j++)
8717 int element = object_mapping[i].element_rnd;
8718 int action = object_mapping[i].action;
8719 int direction = object_mapping[i].direction;
8720 boolean is_backside = object_mapping[i].is_backside;
8721 int graphic_action = el_act_dir2img(element, action, direction);
8722 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
8724 if ((action == ACTION_SMASHED_BY_ROCK ||
8725 action == ACTION_SMASHED_BY_SPRING ||
8726 action == ACTION_EATING) &&
8727 graphic_action == graphic_default)
8729 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
8730 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
8731 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
8732 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
8735 /* no separate animation for "smashed by rock" -- use rock instead */
8736 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
8737 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
8739 g_em->bitmap = g_xx->bitmap;
8740 g_em->src_x = g_xx->src_x;
8741 g_em->src_y = g_xx->src_y;
8742 g_em->src_offset_x = g_xx->src_offset_x;
8743 g_em->src_offset_y = g_xx->src_offset_y;
8744 g_em->dst_offset_x = g_xx->dst_offset_x;
8745 g_em->dst_offset_y = g_xx->dst_offset_y;
8746 g_em->width = g_xx->width;
8747 g_em->height = g_xx->height;
8748 g_em->unique_identifier = g_xx->unique_identifier;
8751 g_em->preserve_background = TRUE;
8756 for (p = 0; p < MAX_PLAYERS; p++)
8758 for (i = 0; i < SPR_MAX; i++)
8760 int element = player_mapping[p][i].element_rnd;
8761 int action = player_mapping[p][i].action;
8762 int direction = player_mapping[p][i].direction;
8764 for (j = 0; j < 8; j++)
8766 int effective_element = element;
8767 int effective_action = action;
8768 int graphic = (direction == MV_NONE ?
8769 el_act2img(effective_element, effective_action) :
8770 el_act_dir2img(effective_element, effective_action,
8772 struct GraphicInfo *g = &graphic_info[graphic];
8773 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
8779 Bitmap *debug_bitmap = g_em->bitmap;
8780 int debug_src_x = g_em->src_x;
8781 int debug_src_y = g_em->src_y;
8784 int frame = getAnimationFrame(g->anim_frames,
8787 g->anim_start_frame,
8790 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
8792 g_em->bitmap = src_bitmap;
8793 g_em->src_x = src_x;
8794 g_em->src_y = src_y;
8795 g_em->src_offset_x = 0;
8796 g_em->src_offset_y = 0;
8797 g_em->dst_offset_x = 0;
8798 g_em->dst_offset_y = 0;
8799 g_em->width = TILEX;
8800 g_em->height = TILEY;
8804 /* skip check for EMC elements not contained in original EMC artwork */
8805 if (element == EL_PLAYER_3 ||
8806 element == EL_PLAYER_4)
8809 if (g_em->bitmap != debug_bitmap ||
8810 g_em->src_x != debug_src_x ||
8811 g_em->src_y != debug_src_y)
8813 static int last_i = -1;
8821 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
8822 p, i, element, element_info[element].token_name,
8823 element_action_info[effective_action].suffix, direction);
8825 if (element != effective_element)
8826 printf(" [%d ('%s')]",
8828 element_info[effective_element].token_name);
8832 if (g_em->bitmap != debug_bitmap)
8833 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
8834 j, (int)(g_em->bitmap), (int)(debug_bitmap));
8836 if (g_em->src_x != debug_src_x ||
8837 g_em->src_y != debug_src_y)
8838 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
8840 g_em->src_x, g_em->src_y,
8841 g_em->src_x / 32, g_em->src_y / 32,
8842 debug_src_x, debug_src_y,
8843 debug_src_x / 32, debug_src_y / 32);
8845 num_em_gfx_errors++;
8855 printf("::: [%d errors found]\n", num_em_gfx_errors);
8861 void CheckSaveEngineSnapshot_EM(byte action[MAX_PLAYERS], int frame,
8862 boolean any_player_moving,
8863 boolean any_player_snapping,
8864 boolean any_player_dropping)
8866 if (frame == 0 && !any_player_dropping)
8868 if (!local_player->was_waiting)
8870 if (!CheckSaveEngineSnapshotToList())
8873 local_player->was_waiting = TRUE;
8876 else if (any_player_moving || any_player_snapping || any_player_dropping)
8878 local_player->was_waiting = FALSE;
8882 void CheckSaveEngineSnapshot_SP(boolean murphy_is_waiting,
8883 boolean murphy_is_dropping)
8885 if (murphy_is_waiting)
8887 if (!local_player->was_waiting)
8889 if (!CheckSaveEngineSnapshotToList())
8892 local_player->was_waiting = TRUE;
8897 local_player->was_waiting = FALSE;
8901 void CheckSaveEngineSnapshot_MM(boolean element_clicked,
8902 boolean button_released)
8904 if (button_released)
8906 if (game.snapshot.mode == SNAPSHOT_MODE_EVERY_MOVE)
8907 CheckSaveEngineSnapshotToList();
8909 else if (element_clicked)
8911 if (game.snapshot.mode != SNAPSHOT_MODE_EVERY_MOVE)
8912 CheckSaveEngineSnapshotToList();
8914 game.snapshot.changed_action = TRUE;
8918 void CheckSingleStepMode_EM(byte action[MAX_PLAYERS], int frame,
8919 boolean any_player_moving,
8920 boolean any_player_snapping,
8921 boolean any_player_dropping)
8923 if (tape.single_step && tape.recording && !tape.pausing)
8924 if (frame == 0 && !any_player_dropping)
8925 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
8927 CheckSaveEngineSnapshot_EM(action, frame, any_player_moving,
8928 any_player_snapping, any_player_dropping);
8931 void CheckSingleStepMode_SP(boolean murphy_is_waiting,
8932 boolean murphy_is_dropping)
8934 boolean murphy_starts_dropping = FALSE;
8937 for (i = 0; i < MAX_PLAYERS; i++)
8938 if (stored_player[i].force_dropping)
8939 murphy_starts_dropping = TRUE;
8941 if (tape.single_step && tape.recording && !tape.pausing)
8942 if (murphy_is_waiting && !murphy_starts_dropping)
8943 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
8945 CheckSaveEngineSnapshot_SP(murphy_is_waiting, murphy_is_dropping);
8948 void CheckSingleStepMode_MM(boolean element_clicked,
8949 boolean button_released)
8951 if (tape.single_step && tape.recording && !tape.pausing)
8952 if (button_released)
8953 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
8955 CheckSaveEngineSnapshot_MM(element_clicked, button_released);
8958 void getGraphicSource_SP(struct GraphicInfo_SP *g_sp,
8959 int graphic, int sync_frame, int x, int y)
8961 int frame = getGraphicAnimationFrame(graphic, sync_frame);
8963 getGraphicSource(graphic, frame, &g_sp->bitmap, &g_sp->src_x, &g_sp->src_y);
8966 boolean isNextAnimationFrame_SP(int graphic, int sync_frame)
8968 return (IS_NEXT_FRAME(sync_frame, graphic));
8971 int getGraphicInfo_Delay(int graphic)
8973 return graphic_info[graphic].anim_delay;
8976 void PlayMenuSoundExt(int sound)
8978 if (sound == SND_UNDEFINED)
8981 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8982 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8985 if (IS_LOOP_SOUND(sound))
8986 PlaySoundLoop(sound);
8991 void PlayMenuSound()
8993 PlayMenuSoundExt(menu.sound[game_status]);
8996 void PlayMenuSoundStereo(int sound, int stereo_position)
8998 if (sound == SND_UNDEFINED)
9001 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
9002 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
9005 if (IS_LOOP_SOUND(sound))
9006 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
9008 PlaySoundStereo(sound, stereo_position);
9011 void PlayMenuSoundIfLoopExt(int sound)
9013 if (sound == SND_UNDEFINED)
9016 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
9017 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
9020 if (IS_LOOP_SOUND(sound))
9021 PlaySoundLoop(sound);
9024 void PlayMenuSoundIfLoop()
9026 PlayMenuSoundIfLoopExt(menu.sound[game_status]);
9029 void PlayMenuMusicExt(int music)
9031 if (music == MUS_UNDEFINED)
9034 if (!setup.sound_music)
9040 void PlayMenuMusic()
9042 char *curr_music = getCurrentlyPlayingMusicFilename();
9043 char *next_music = getMusicInfoEntryFilename(menu.music[game_status]);
9045 if (!strEqual(curr_music, next_music))
9046 PlayMenuMusicExt(menu.music[game_status]);
9049 void PlayMenuSoundsAndMusic()
9055 static void FadeMenuSounds()
9060 static void FadeMenuMusic()
9062 char *curr_music = getCurrentlyPlayingMusicFilename();
9063 char *next_music = getMusicInfoEntryFilename(menu.music[game_status]);
9065 if (!strEqual(curr_music, next_music))
9069 void FadeMenuSoundsAndMusic()
9075 void PlaySoundActivating()
9078 PlaySound(SND_MENU_ITEM_ACTIVATING);
9082 void PlaySoundSelecting()
9085 PlaySound(SND_MENU_ITEM_SELECTING);
9089 void ToggleFullscreenOrChangeWindowScalingIfNeeded()
9091 boolean change_fullscreen = (setup.fullscreen !=
9092 video.fullscreen_enabled);
9093 boolean change_window_scaling_percent = (!video.fullscreen_enabled &&
9094 setup.window_scaling_percent !=
9095 video.window_scaling_percent);
9097 if (change_window_scaling_percent && video.fullscreen_enabled)
9100 if (!change_window_scaling_percent && !video.fullscreen_available)
9103 #if defined(TARGET_SDL2)
9104 if (change_window_scaling_percent)
9106 SDLSetWindowScaling(setup.window_scaling_percent);
9110 else if (change_fullscreen)
9112 SDLSetWindowFullscreen(setup.fullscreen);
9114 /* set setup value according to successfully changed fullscreen mode */
9115 setup.fullscreen = video.fullscreen_enabled;
9121 if (change_fullscreen ||
9122 change_window_scaling_percent)
9124 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
9126 /* save backbuffer content which gets lost when toggling fullscreen mode */
9127 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
9129 if (change_window_scaling_percent)
9131 /* keep window mode, but change window scaling */
9132 video.fullscreen_enabled = TRUE; /* force new window scaling */
9135 /* toggle fullscreen */
9136 ChangeVideoModeIfNeeded(setup.fullscreen);
9138 /* set setup value according to successfully changed fullscreen mode */
9139 setup.fullscreen = video.fullscreen_enabled;
9141 /* restore backbuffer content from temporary backbuffer backup bitmap */
9142 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
9144 FreeBitmap(tmp_backbuffer);
9146 /* update visible window/screen */
9147 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
9151 void JoinRectangles(int *x, int *y, int *width, int *height,
9152 int x2, int y2, int width2, int height2)
9154 // do not join with "off-screen" rectangle
9155 if (x2 == -1 || y2 == -1)
9160 *width = MAX(*width, width2);
9161 *height = MAX(*height, height2);
9164 void SetAnimStatus(int anim_status_new)
9166 if (anim_status_new == GAME_MODE_MAIN)
9167 anim_status_new = GAME_MODE_PSEUDO_MAINONLY;
9168 else if (anim_status_new == GAME_MODE_SCORES)
9169 anim_status_new = GAME_MODE_PSEUDO_SCORESOLD;
9171 global.anim_status_next = anim_status_new;
9173 // directly set screen modes that are entered without fading
9174 if ((global.anim_status == GAME_MODE_PSEUDO_MAINONLY &&
9175 global.anim_status_next == GAME_MODE_PSEUDO_TYPENAME) ||
9176 (global.anim_status == GAME_MODE_PSEUDO_TYPENAME &&
9177 global.anim_status_next == GAME_MODE_PSEUDO_MAINONLY))
9178 global.anim_status = global.anim_status_next;
9181 void SetGameStatus(int game_status_new)
9183 if (game_status_new != game_status)
9184 game_status_last_screen = game_status;
9186 game_status = game_status_new;
9188 SetAnimStatus(game_status_new);
9191 void SetFontStatus(int game_status_new)
9193 static int last_game_status = -1;
9195 if (game_status_new != -1)
9197 // set game status for font use after storing last game status
9198 last_game_status = game_status;
9199 game_status = game_status_new;
9203 // reset game status after font use from last stored game status
9204 game_status = last_game_status;
9208 void ResetFontStatus()
9213 boolean CheckIfPlayfieldViewportHasChanged()
9215 // if game status has not changed, playfield viewport has not changed either
9216 if (game_status == game_status_last)
9219 // check if playfield viewport has changed with current game status
9220 struct RectWithBorder *vp_playfield = &viewport.playfield[game_status];
9221 int new_real_sx = vp_playfield->x;
9222 int new_real_sy = vp_playfield->y;
9223 int new_full_sxsize = vp_playfield->width;
9224 int new_full_sysize = vp_playfield->height;
9226 return (new_real_sx != REAL_SX ||
9227 new_real_sy != REAL_SY ||
9228 new_full_sxsize != FULL_SXSIZE ||
9229 new_full_sysize != FULL_SYSIZE);
9232 boolean CheckIfGlobalBorderOrPlayfieldViewportHasChanged()
9234 return (CheckIfGlobalBorderHasChanged() ||
9235 CheckIfPlayfieldViewportHasChanged());
9238 void ChangeViewportPropertiesIfNeeded()
9240 boolean use_mini_tilesize = (level.game_engine_type == GAME_ENGINE_TYPE_MM ?
9241 FALSE : setup.small_game_graphics);
9242 int gfx_game_mode = game_status;
9243 int gfx_game_mode2 = (game_status == GAME_MODE_EDITOR ? GAME_MODE_DEFAULT :
9245 struct RectWithBorder *vp_window = &viewport.window[gfx_game_mode];
9246 struct RectWithBorder *vp_playfield = &viewport.playfield[gfx_game_mode];
9247 struct RectWithBorder *vp_door_1 = &viewport.door_1[gfx_game_mode];
9248 struct RectWithBorder *vp_door_2 = &viewport.door_2[gfx_game_mode2];
9249 struct RectWithBorder *vp_door_3 = &viewport.door_2[GAME_MODE_EDITOR];
9250 int new_win_xsize = vp_window->width;
9251 int new_win_ysize = vp_window->height;
9252 int border_size = vp_playfield->border_size;
9253 int new_sx = vp_playfield->x + border_size;
9254 int new_sy = vp_playfield->y + border_size;
9255 int new_sxsize = vp_playfield->width - 2 * border_size;
9256 int new_sysize = vp_playfield->height - 2 * border_size;
9257 int new_real_sx = vp_playfield->x;
9258 int new_real_sy = vp_playfield->y;
9259 int new_full_sxsize = vp_playfield->width;
9260 int new_full_sysize = vp_playfield->height;
9261 int new_dx = vp_door_1->x;
9262 int new_dy = vp_door_1->y;
9263 int new_dxsize = vp_door_1->width;
9264 int new_dysize = vp_door_1->height;
9265 int new_vx = vp_door_2->x;
9266 int new_vy = vp_door_2->y;
9267 int new_vxsize = vp_door_2->width;
9268 int new_vysize = vp_door_2->height;
9269 int new_ex = vp_door_3->x;
9270 int new_ey = vp_door_3->y;
9271 int new_exsize = vp_door_3->width;
9272 int new_eysize = vp_door_3->height;
9273 int new_tilesize_var = (use_mini_tilesize ? MINI_TILESIZE : game.tile_size);
9274 int tilesize = (gfx_game_mode == GAME_MODE_PLAYING ? new_tilesize_var :
9275 gfx_game_mode == GAME_MODE_EDITOR ? MINI_TILESIZE : TILESIZE);
9276 int new_scr_fieldx = new_sxsize / tilesize;
9277 int new_scr_fieldy = new_sysize / tilesize;
9278 int new_scr_fieldx_buffers = new_sxsize / new_tilesize_var;
9279 int new_scr_fieldy_buffers = new_sysize / new_tilesize_var;
9280 boolean init_gfx_buffers = FALSE;
9281 boolean init_video_buffer = FALSE;
9282 boolean init_gadgets_and_anims = FALSE;
9283 boolean init_em_graphics = FALSE;
9285 if (new_win_xsize != WIN_XSIZE ||
9286 new_win_ysize != WIN_YSIZE)
9288 WIN_XSIZE = new_win_xsize;
9289 WIN_YSIZE = new_win_ysize;
9291 init_video_buffer = TRUE;
9292 init_gfx_buffers = TRUE;
9293 init_gadgets_and_anims = TRUE;
9295 // printf("::: video: init_video_buffer, init_gfx_buffers\n");
9298 if (new_scr_fieldx != SCR_FIELDX ||
9299 new_scr_fieldy != SCR_FIELDY)
9301 /* this always toggles between MAIN and GAME when using small tile size */
9303 SCR_FIELDX = new_scr_fieldx;
9304 SCR_FIELDY = new_scr_fieldy;
9306 // printf("::: new_scr_fieldx != SCR_FIELDX ...\n");
9317 new_sxsize != SXSIZE ||
9318 new_sysize != SYSIZE ||
9319 new_dxsize != DXSIZE ||
9320 new_dysize != DYSIZE ||
9321 new_vxsize != VXSIZE ||
9322 new_vysize != VYSIZE ||
9323 new_exsize != EXSIZE ||
9324 new_eysize != EYSIZE ||
9325 new_real_sx != REAL_SX ||
9326 new_real_sy != REAL_SY ||
9327 new_full_sxsize != FULL_SXSIZE ||
9328 new_full_sysize != FULL_SYSIZE ||
9329 new_tilesize_var != TILESIZE_VAR
9332 // ------------------------------------------------------------------------
9333 // determine next fading area for changed viewport definitions
9334 // ------------------------------------------------------------------------
9336 // start with current playfield area (default fading area)
9339 FADE_SXSIZE = FULL_SXSIZE;
9340 FADE_SYSIZE = FULL_SYSIZE;
9342 // add new playfield area if position or size has changed
9343 if (new_real_sx != REAL_SX || new_real_sy != REAL_SY ||
9344 new_full_sxsize != FULL_SXSIZE || new_full_sysize != FULL_SYSIZE)
9346 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
9347 new_real_sx, new_real_sy, new_full_sxsize,new_full_sysize);
9350 // add current and new door 1 area if position or size has changed
9351 if (new_dx != DX || new_dy != DY ||
9352 new_dxsize != DXSIZE || new_dysize != DYSIZE)
9354 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
9355 DX, DY, DXSIZE, DYSIZE);
9356 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
9357 new_dx, new_dy, new_dxsize, new_dysize);
9360 // add current and new door 2 area if position or size has changed
9361 if (new_dx != VX || new_dy != VY ||
9362 new_dxsize != VXSIZE || new_dysize != VYSIZE)
9364 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
9365 VX, VY, VXSIZE, VYSIZE);
9366 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
9367 new_vx, new_vy, new_vxsize, new_vysize);
9370 // ------------------------------------------------------------------------
9371 // handle changed tile size
9372 // ------------------------------------------------------------------------
9374 if (new_tilesize_var != TILESIZE_VAR)
9376 // printf("::: new_tilesize_var != TILESIZE_VAR\n");
9378 // changing tile size invalidates scroll values of engine snapshots
9379 FreeEngineSnapshotSingle();
9381 // changing tile size requires update of graphic mapping for EM engine
9382 init_em_graphics = TRUE;
9393 SXSIZE = new_sxsize;
9394 SYSIZE = new_sysize;
9395 DXSIZE = new_dxsize;
9396 DYSIZE = new_dysize;
9397 VXSIZE = new_vxsize;
9398 VYSIZE = new_vysize;
9399 EXSIZE = new_exsize;
9400 EYSIZE = new_eysize;
9401 REAL_SX = new_real_sx;
9402 REAL_SY = new_real_sy;
9403 FULL_SXSIZE = new_full_sxsize;
9404 FULL_SYSIZE = new_full_sysize;
9405 TILESIZE_VAR = new_tilesize_var;
9407 init_gfx_buffers = TRUE;
9408 init_gadgets_and_anims = TRUE;
9410 // printf("::: viewports: init_gfx_buffers\n");
9411 // printf("::: viewports: init_gadgets_and_anims\n");
9414 if (init_gfx_buffers)
9416 // printf("::: init_gfx_buffers\n");
9418 SCR_FIELDX = new_scr_fieldx_buffers;
9419 SCR_FIELDY = new_scr_fieldy_buffers;
9423 SCR_FIELDX = new_scr_fieldx;
9424 SCR_FIELDY = new_scr_fieldy;
9426 SetDrawDeactivationMask(REDRAW_NONE);
9427 SetDrawBackgroundMask(REDRAW_FIELD);
9430 if (init_video_buffer)
9432 // printf("::: init_video_buffer\n");
9434 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
9435 InitImageTextures();
9438 if (init_gadgets_and_anims)
9440 // printf("::: init_gadgets_and_anims\n");
9443 InitGlobalAnimations();
9446 if (init_em_graphics)
9448 InitGraphicInfo_EM();