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 #if defined(NETWORK_AVALIABLE)
4396 /* pause network game while waiting for request to answer */
4397 if (options.network &&
4398 game_status == GAME_MODE_PLAYING &&
4399 req_state & REQUEST_WAIT_FOR_INPUT)
4400 SendToServer_PausePlaying();
4403 old_door_state = GetDoorState();
4405 /* simulate releasing mouse button over last gadget, if still pressed */
4407 HandleGadgets(-1, -1, 0);
4411 /* draw released gadget before proceeding */
4414 if (old_door_state & DOOR_OPEN_1)
4416 CloseDoor(DOOR_CLOSE_1);
4418 /* save old door content */
4419 BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
4420 0 * DXSIZE, 0, DXSIZE, DYSIZE, 1 * DXSIZE, 0);
4423 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
4424 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4426 /* clear door drawing field */
4427 DrawBackground(DX, DY, DXSIZE, DYSIZE);
4429 /* force DOOR font inside door area */
4430 SetFontStatus(GAME_MODE_PSEUDO_DOOR);
4432 /* write text for request */
4433 for (text_ptr = text, ty = 0; ty < MAX_REQUEST_LINES; ty++)
4435 char text_line[max_request_line_len + 1];
4441 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
4443 tc = *(text_ptr + tx);
4444 // if (!tc || tc == ' ')
4445 if (!tc || tc == ' ' || tc == '?' || tc == '!')
4449 if ((tc == '?' || tc == '!') && tl == 0)
4459 strncpy(text_line, text_ptr, tl);
4462 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
4463 DY + 8 + ty * (getFontHeight(font_nr) + 2),
4464 text_line, font_nr);
4466 text_ptr += tl + (tc == ' ' ? 1 : 0);
4467 // text_ptr += tl + (tc == ' ' || tc == '?' || tc == '!' ? 1 : 0);
4472 if (req_state & REQ_ASK)
4474 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
4475 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
4477 else if (req_state & REQ_CONFIRM)
4479 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
4481 else if (req_state & REQ_PLAYER)
4483 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
4484 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
4485 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
4486 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
4489 /* copy request gadgets to door backbuffer */
4490 BlitBitmap(drawto, bitmap_db_door_1, DX, DY, DXSIZE, DYSIZE, 0, 0);
4492 OpenDoor(DOOR_OPEN_1);
4494 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
4496 if (game_status == GAME_MODE_PLAYING)
4498 SetPanelBackground();
4499 SetDrawBackgroundMask(REDRAW_DOOR_1);
4503 SetDrawBackgroundMask(REDRAW_FIELD);
4509 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4511 // ---------- handle request buttons ----------
4512 result = RequestHandleEvents(req_state);
4516 if (!(req_state & REQ_STAY_OPEN))
4518 CloseDoor(DOOR_CLOSE_1);
4520 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
4521 (req_state & REQ_REOPEN))
4522 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
4527 if (game_status == GAME_MODE_PLAYING)
4529 SetPanelBackground();
4530 SetDrawBackgroundMask(REDRAW_DOOR_1);
4534 SetDrawBackgroundMask(REDRAW_FIELD);
4537 #if defined(NETWORK_AVALIABLE)
4538 /* continue network game after request */
4539 if (options.network &&
4540 game_status == GAME_MODE_PLAYING &&
4541 req_state & REQUEST_WAIT_FOR_INPUT)
4542 SendToServer_ContinuePlaying();
4545 /* restore deactivated drawing when quick-loading level tape recording */
4546 if (tape.playing && tape.deactivate_display)
4547 TapeDeactivateDisplayOn();
4552 static boolean RequestEnvelope(char *text, unsigned int req_state)
4556 if (game_status == GAME_MODE_PLAYING)
4557 BlitScreenToBitmap(backbuffer);
4559 /* disable deactivated drawing when quick-loading level tape recording */
4560 if (tape.playing && tape.deactivate_display)
4561 TapeDeactivateDisplayOff(TRUE);
4563 SetMouseCursor(CURSOR_DEFAULT);
4565 #if defined(NETWORK_AVALIABLE)
4566 /* pause network game while waiting for request to answer */
4567 if (options.network &&
4568 game_status == GAME_MODE_PLAYING &&
4569 req_state & REQUEST_WAIT_FOR_INPUT)
4570 SendToServer_PausePlaying();
4573 /* simulate releasing mouse button over last gadget, if still pressed */
4575 HandleGadgets(-1, -1, 0);
4579 // (replace with setting corresponding request background)
4580 // SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
4581 // SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4583 /* clear door drawing field */
4584 // DrawBackground(DX, DY, DXSIZE, DYSIZE);
4586 ShowEnvelopeRequest(text, req_state, ACTION_OPENING);
4588 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
4590 if (game_status == GAME_MODE_PLAYING)
4592 SetPanelBackground();
4593 SetDrawBackgroundMask(REDRAW_DOOR_1);
4597 SetDrawBackgroundMask(REDRAW_FIELD);
4603 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4605 // ---------- handle request buttons ----------
4606 result = RequestHandleEvents(req_state);
4610 ShowEnvelopeRequest(text, req_state, ACTION_CLOSING);
4614 if (game_status == GAME_MODE_PLAYING)
4616 SetPanelBackground();
4617 SetDrawBackgroundMask(REDRAW_DOOR_1);
4621 SetDrawBackgroundMask(REDRAW_FIELD);
4624 #if defined(NETWORK_AVALIABLE)
4625 /* continue network game after request */
4626 if (options.network &&
4627 game_status == GAME_MODE_PLAYING &&
4628 req_state & REQUEST_WAIT_FOR_INPUT)
4629 SendToServer_ContinuePlaying();
4632 /* restore deactivated drawing when quick-loading level tape recording */
4633 if (tape.playing && tape.deactivate_display)
4634 TapeDeactivateDisplayOn();
4639 boolean Request(char *text, unsigned int req_state)
4641 boolean overlay_active = GetOverlayActive();
4644 SetOverlayActive(FALSE);
4646 if (global.use_envelope_request)
4647 result = RequestEnvelope(text, req_state);
4649 result = RequestDoor(text, req_state);
4651 SetOverlayActive(overlay_active);
4656 static int compareDoorPartOrderInfo(const void *object1, const void *object2)
4658 const struct DoorPartOrderInfo *dpo1 = (struct DoorPartOrderInfo *)object1;
4659 const struct DoorPartOrderInfo *dpo2 = (struct DoorPartOrderInfo *)object2;
4662 if (dpo1->sort_priority != dpo2->sort_priority)
4663 compare_result = dpo1->sort_priority - dpo2->sort_priority;
4665 compare_result = dpo1->nr - dpo2->nr;
4667 return compare_result;
4670 void InitGraphicCompatibilityInfo_Doors()
4676 struct DoorInfo *door;
4680 { DOOR_1, IMG_GFX_DOOR_1_PART_1, IMG_GFX_DOOR_1_PART_8, &door_1 },
4681 { DOOR_2, IMG_GFX_DOOR_2_PART_1, IMG_GFX_DOOR_2_PART_8, &door_2 },
4683 { -1, -1, -1, NULL }
4685 struct Rect door_rect_list[] =
4687 { DX, DY, DXSIZE, DYSIZE },
4688 { VX, VY, VXSIZE, VYSIZE }
4692 for (i = 0; doors[i].door_token != -1; i++)
4694 int door_token = doors[i].door_token;
4695 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
4696 int part_1 = doors[i].part_1;
4697 int part_8 = doors[i].part_8;
4698 int part_2 = part_1 + 1;
4699 int part_3 = part_1 + 2;
4700 struct DoorInfo *door = doors[i].door;
4701 struct Rect *door_rect = &door_rect_list[door_index];
4702 boolean door_gfx_redefined = FALSE;
4704 /* check if any door part graphic definitions have been redefined */
4706 for (j = 0; door_part_controls[j].door_token != -1; j++)
4708 struct DoorPartControlInfo *dpc = &door_part_controls[j];
4709 struct FileInfo *fi = getImageListEntryFromImageID(dpc->graphic);
4711 if (dpc->door_token == door_token && fi->redefined)
4712 door_gfx_redefined = TRUE;
4715 /* check for old-style door graphic/animation modifications */
4717 if (!door_gfx_redefined)
4719 if (door->anim_mode & ANIM_STATIC_PANEL)
4721 door->panel.step_xoffset = 0;
4722 door->panel.step_yoffset = 0;
4725 if (door->anim_mode & (ANIM_HORIZONTAL | ANIM_VERTICAL))
4727 struct GraphicInfo *g_part_1 = &graphic_info[part_1];
4728 struct GraphicInfo *g_part_2 = &graphic_info[part_2];
4729 int num_door_steps, num_panel_steps;
4731 /* remove door part graphics other than the two default wings */
4733 for (j = 0; door_part_controls[j].door_token != -1; j++)
4735 struct DoorPartControlInfo *dpc = &door_part_controls[j];
4736 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4738 if (dpc->graphic >= part_3 &&
4739 dpc->graphic <= part_8)
4743 /* set graphics and screen positions of the default wings */
4745 g_part_1->width = door_rect->width;
4746 g_part_1->height = door_rect->height;
4747 g_part_2->width = door_rect->width;
4748 g_part_2->height = door_rect->height;
4749 g_part_2->src_x = door_rect->width;
4750 g_part_2->src_y = g_part_1->src_y;
4752 door->part_2.x = door->part_1.x;
4753 door->part_2.y = door->part_1.y;
4755 if (door->width != -1)
4757 g_part_1->width = door->width;
4758 g_part_2->width = door->width;
4760 // special treatment for graphics and screen position of right wing
4761 g_part_2->src_x += door_rect->width - door->width;
4762 door->part_2.x += door_rect->width - door->width;
4765 if (door->height != -1)
4767 g_part_1->height = door->height;
4768 g_part_2->height = door->height;
4770 // special treatment for graphics and screen position of bottom wing
4771 g_part_2->src_y += door_rect->height - door->height;
4772 door->part_2.y += door_rect->height - door->height;
4775 /* set animation delays for the default wings and panels */
4777 door->part_1.step_delay = door->step_delay;
4778 door->part_2.step_delay = door->step_delay;
4779 door->panel.step_delay = door->step_delay;
4781 /* set animation draw order for the default wings */
4783 door->part_1.sort_priority = 2; /* draw left wing over ... */
4784 door->part_2.sort_priority = 1; /* ... right wing */
4786 /* set animation draw offset for the default wings */
4788 if (door->anim_mode & ANIM_HORIZONTAL)
4790 door->part_1.step_xoffset = door->step_offset;
4791 door->part_1.step_yoffset = 0;
4792 door->part_2.step_xoffset = door->step_offset * -1;
4793 door->part_2.step_yoffset = 0;
4795 num_door_steps = g_part_1->width / door->step_offset;
4797 else // ANIM_VERTICAL
4799 door->part_1.step_xoffset = 0;
4800 door->part_1.step_yoffset = door->step_offset;
4801 door->part_2.step_xoffset = 0;
4802 door->part_2.step_yoffset = door->step_offset * -1;
4804 num_door_steps = g_part_1->height / door->step_offset;
4807 /* set animation draw offset for the default panels */
4809 if (door->step_offset > 1)
4811 num_panel_steps = 2 * door_rect->height / door->step_offset;
4812 door->panel.start_step = num_panel_steps - num_door_steps;
4813 door->panel.start_step_closing = door->panel.start_step;
4817 num_panel_steps = door_rect->height / door->step_offset;
4818 door->panel.start_step = num_panel_steps - num_door_steps / 2;
4819 door->panel.start_step_closing = door->panel.start_step;
4820 door->panel.step_delay *= 2;
4831 for (i = 0; door_part_controls[i].door_token != -1; i++)
4833 struct DoorPartControlInfo *dpc = &door_part_controls[i];
4834 struct DoorPartOrderInfo *dpo = &door_part_order[i];
4836 /* initialize "start_step_opening" and "start_step_closing", if needed */
4837 if (dpc->pos->start_step_opening == 0 &&
4838 dpc->pos->start_step_closing == 0)
4840 // dpc->pos->start_step_opening = dpc->pos->start_step;
4841 dpc->pos->start_step_closing = dpc->pos->start_step;
4844 /* fill structure for door part draw order (sorted below) */
4846 dpo->sort_priority = dpc->pos->sort_priority;
4849 /* sort door part controls according to sort_priority and graphic number */
4850 qsort(door_part_order, MAX_DOOR_PARTS,
4851 sizeof(struct DoorPartOrderInfo), compareDoorPartOrderInfo);
4854 unsigned int OpenDoor(unsigned int door_state)
4856 if (door_state & DOOR_COPY_BACK)
4858 if (door_state & DOOR_OPEN_1)
4859 BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
4860 1 * DXSIZE, 0, DXSIZE, DYSIZE, 0 * DXSIZE, 0);
4862 if (door_state & DOOR_OPEN_2)
4863 BlitBitmap(bitmap_db_door_2, bitmap_db_door_2,
4864 1 * VXSIZE, 0, VXSIZE, VYSIZE, 0 * VXSIZE, 0);
4866 door_state &= ~DOOR_COPY_BACK;
4869 return MoveDoor(door_state);
4872 unsigned int CloseDoor(unsigned int door_state)
4874 unsigned int old_door_state = GetDoorState();
4876 if (!(door_state & DOOR_NO_COPY_BACK))
4878 if (old_door_state & DOOR_OPEN_1)
4879 BlitBitmap(backbuffer, bitmap_db_door_1,
4880 DX, DY, DXSIZE, DYSIZE, 0, 0);
4882 if (old_door_state & DOOR_OPEN_2)
4883 BlitBitmap(backbuffer, bitmap_db_door_2,
4884 VX, VY, VXSIZE, VYSIZE, 0, 0);
4886 door_state &= ~DOOR_NO_COPY_BACK;
4889 return MoveDoor(door_state);
4892 unsigned int GetDoorState()
4894 return MoveDoor(DOOR_GET_STATE);
4897 unsigned int SetDoorState(unsigned int door_state)
4899 return MoveDoor(door_state | DOOR_SET_STATE);
4902 int euclid(int a, int b)
4904 return (b ? euclid(b, a % b) : a);
4907 unsigned int MoveDoor(unsigned int door_state)
4909 struct Rect door_rect_list[] =
4911 { DX, DY, DXSIZE, DYSIZE },
4912 { VX, VY, VXSIZE, VYSIZE }
4914 static int door1 = DOOR_CLOSE_1;
4915 static int door2 = DOOR_CLOSE_2;
4916 unsigned int door_delay = 0;
4917 unsigned int door_delay_value;
4920 if (door_state == DOOR_GET_STATE)
4921 return (door1 | door2);
4923 if (door_state & DOOR_SET_STATE)
4925 if (door_state & DOOR_ACTION_1)
4926 door1 = door_state & DOOR_ACTION_1;
4927 if (door_state & DOOR_ACTION_2)
4928 door2 = door_state & DOOR_ACTION_2;
4930 return (door1 | door2);
4933 if (!(door_state & DOOR_FORCE_REDRAW))
4935 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
4936 door_state &= ~DOOR_OPEN_1;
4937 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
4938 door_state &= ~DOOR_CLOSE_1;
4939 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
4940 door_state &= ~DOOR_OPEN_2;
4941 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
4942 door_state &= ~DOOR_CLOSE_2;
4945 if (global.autoplay_leveldir)
4947 door_state |= DOOR_NO_DELAY;
4948 door_state &= ~DOOR_CLOSE_ALL;
4951 if (game_status == GAME_MODE_EDITOR && !(door_state & DOOR_FORCE_ANIM))
4952 door_state |= DOOR_NO_DELAY;
4954 if (door_state & DOOR_ACTION)
4956 boolean door_panel_drawn[NUM_DOORS];
4957 boolean panel_has_doors[NUM_DOORS];
4958 boolean door_part_skip[MAX_DOOR_PARTS];
4959 boolean door_part_done[MAX_DOOR_PARTS];
4960 boolean door_part_done_all;
4961 int num_steps[MAX_DOOR_PARTS];
4962 int max_move_delay = 0; // delay for complete animations of all doors
4963 int max_step_delay = 0; // delay (ms) between two animation frames
4964 int num_move_steps = 0; // number of animation steps for all doors
4965 int max_move_delay_doors_only = 0; // delay for doors only (no panel)
4966 int num_move_steps_doors_only = 0; // steps for doors only (no panel)
4967 int current_move_delay = 0;
4971 for (i = 0; i < NUM_DOORS; i++)
4972 panel_has_doors[i] = FALSE;
4974 for (i = 0; i < MAX_DOOR_PARTS; i++)
4976 struct DoorPartControlInfo *dpc = &door_part_controls[i];
4977 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4978 int door_token = dpc->door_token;
4980 door_part_done[i] = FALSE;
4981 door_part_skip[i] = (!(door_state & door_token) ||
4985 for (i = 0; i < MAX_DOOR_PARTS; i++)
4987 int nr = door_part_order[i].nr;
4988 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
4989 struct DoorPartPosInfo *pos = dpc->pos;
4990 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4991 int door_token = dpc->door_token;
4992 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
4993 boolean is_panel = DOOR_PART_IS_PANEL(nr);
4994 int step_xoffset = ABS(pos->step_xoffset);
4995 int step_yoffset = ABS(pos->step_yoffset);
4996 int step_delay = pos->step_delay;
4997 int current_door_state = door_state & door_token;
4998 boolean door_opening = ((current_door_state & DOOR_OPEN) != 0);
4999 boolean door_closing = ((current_door_state & DOOR_CLOSE) != 0);
5000 boolean part_opening = (is_panel ? door_closing : door_opening);
5001 int start_step = (part_opening ? pos->start_step_opening :
5002 pos->start_step_closing);
5003 float move_xsize = (step_xoffset ? g->width : 0);
5004 float move_ysize = (step_yoffset ? g->height : 0);
5005 int move_xsteps = (step_xoffset ? ceil(move_xsize / step_xoffset) : 0);
5006 int move_ysteps = (step_yoffset ? ceil(move_ysize / step_yoffset) : 0);
5007 int move_steps = (move_xsteps && move_ysteps ?
5008 MIN(move_xsteps, move_ysteps) :
5009 move_xsteps ? move_xsteps : move_ysteps) - start_step;
5010 int move_delay = move_steps * step_delay;
5012 if (door_part_skip[nr])
5015 max_move_delay = MAX(max_move_delay, move_delay);
5016 max_step_delay = (max_step_delay == 0 ? step_delay :
5017 euclid(max_step_delay, step_delay));
5018 num_steps[nr] = move_steps;
5022 max_move_delay_doors_only = MAX(max_move_delay_doors_only, move_delay);
5024 panel_has_doors[door_index] = TRUE;
5028 max_step_delay = MAX(1, max_step_delay); // prevent division by zero
5030 num_move_steps = max_move_delay / max_step_delay;
5031 num_move_steps_doors_only = max_move_delay_doors_only / max_step_delay;
5033 door_delay_value = max_step_delay;
5035 if ((door_state & DOOR_NO_DELAY) || setup.quick_doors)
5037 start = num_move_steps - 1;
5041 /* opening door sound has priority over simultaneously closing door */
5042 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
5044 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
5046 if (door_state & DOOR_OPEN_1)
5047 PlayMenuSoundStereo(SND_DOOR_1_OPENING, SOUND_MIDDLE);
5048 if (door_state & DOOR_OPEN_2)
5049 PlayMenuSoundStereo(SND_DOOR_2_OPENING, SOUND_MIDDLE);
5051 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
5053 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
5055 if (door_state & DOOR_CLOSE_1)
5056 PlayMenuSoundStereo(SND_DOOR_1_CLOSING, SOUND_MIDDLE);
5057 if (door_state & DOOR_CLOSE_2)
5058 PlayMenuSoundStereo(SND_DOOR_2_CLOSING, SOUND_MIDDLE);
5062 for (k = start; k < num_move_steps; k++)
5064 int last_frame = num_move_steps - 1; // last frame of this "for" loop
5066 door_part_done_all = TRUE;
5068 for (i = 0; i < NUM_DOORS; i++)
5069 door_panel_drawn[i] = FALSE;
5071 for (i = 0; i < MAX_DOOR_PARTS; i++)
5073 int nr = door_part_order[i].nr;
5074 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
5075 struct DoorPartPosInfo *pos = dpc->pos;
5076 struct GraphicInfo *g = &graphic_info[dpc->graphic];
5077 int door_token = dpc->door_token;
5078 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
5079 boolean is_panel = DOOR_PART_IS_PANEL(nr);
5080 boolean is_panel_and_door_has_closed = FALSE;
5081 struct Rect *door_rect = &door_rect_list[door_index];
5082 Bitmap *bitmap_db_door = (door_token == DOOR_1 ? bitmap_db_door_1 :
5084 Bitmap *bitmap = (is_panel ? bitmap_db_door : g->bitmap);
5085 int current_door_state = door_state & door_token;
5086 boolean door_opening = ((current_door_state & DOOR_OPEN) != 0);
5087 boolean door_closing = !door_opening;
5088 boolean part_opening = (is_panel ? door_closing : door_opening);
5089 boolean part_closing = !part_opening;
5090 int start_step = (part_opening ? pos->start_step_opening :
5091 pos->start_step_closing);
5092 int step_delay = pos->step_delay;
5093 int step_factor = step_delay / max_step_delay;
5094 int k1 = (step_factor ? k / step_factor + 1 : k);
5095 int k2 = (part_opening ? k1 + start_step : num_steps[nr] - k1);
5096 int kk = MAX(0, k2);
5099 int src_x, src_y, src_xx, src_yy;
5100 int dst_x, dst_y, dst_xx, dst_yy;
5103 if (door_part_skip[nr])
5106 if (!(door_state & door_token))
5114 int k2_door = (door_opening ? k : num_move_steps_doors_only - k - 1);
5115 int kk_door = MAX(0, k2_door);
5116 int sync_frame = kk_door * door_delay_value;
5117 int frame = getGraphicAnimationFrame(dpc->graphic, sync_frame);
5119 getFixedGraphicSource(dpc->graphic, frame, &bitmap,
5120 &g_src_x, &g_src_y);
5125 if (!door_panel_drawn[door_index])
5127 ClearRectangle(drawto, door_rect->x, door_rect->y,
5128 door_rect->width, door_rect->height);
5130 door_panel_drawn[door_index] = TRUE;
5133 // draw opening or closing door parts
5135 if (pos->step_xoffset < 0) // door part on right side
5138 dst_xx = pos->x + ABS(kk * pos->step_xoffset);
5141 if (dst_xx + width > door_rect->width)
5142 width = door_rect->width - dst_xx;
5144 else // door part on left side
5147 dst_xx = pos->x - kk * pos->step_xoffset;
5151 src_xx = ABS(dst_xx);
5155 width = g->width - src_xx;
5157 if (width > door_rect->width)
5158 width = door_rect->width;
5160 // printf("::: k == %d [%d] \n", k, start_step);
5163 if (pos->step_yoffset < 0) // door part on bottom side
5166 dst_yy = pos->y + ABS(kk * pos->step_yoffset);
5169 if (dst_yy + height > door_rect->height)
5170 height = door_rect->height - dst_yy;
5172 else // door part on top side
5175 dst_yy = pos->y - kk * pos->step_yoffset;
5179 src_yy = ABS(dst_yy);
5183 height = g->height - src_yy;
5186 src_x = g_src_x + src_xx;
5187 src_y = g_src_y + src_yy;
5189 dst_x = door_rect->x + dst_xx;
5190 dst_y = door_rect->y + dst_yy;
5192 is_panel_and_door_has_closed =
5195 panel_has_doors[door_index] &&
5196 k >= num_move_steps_doors_only - 1);
5198 if (width >= 0 && width <= g->width &&
5199 height >= 0 && height <= g->height &&
5200 !is_panel_and_door_has_closed)
5202 if (is_panel || !pos->draw_masked)
5203 BlitBitmap(bitmap, drawto, src_x, src_y, width, height,
5206 BlitBitmapMasked(bitmap, drawto, src_x, src_y, width, height,
5210 redraw_mask |= REDRAW_DOOR_FROM_TOKEN(door_token);
5212 if ((part_opening && (width < 0 || height < 0)) ||
5213 (part_closing && (width >= g->width && height >= g->height)))
5214 door_part_done[nr] = TRUE;
5216 // continue door part animations, but not panel after door has closed
5217 if (!door_part_done[nr] && !is_panel_and_door_has_closed)
5218 door_part_done_all = FALSE;
5221 if (!(door_state & DOOR_NO_DELAY))
5225 SkipUntilDelayReached(&door_delay, door_delay_value, &k, last_frame);
5227 current_move_delay += max_step_delay;
5229 /* prevent OS (Windows) from complaining about program not responding */
5233 if (door_part_done_all)
5237 if (!(door_state & DOOR_NO_DELAY))
5239 /* wait for specified door action post delay */
5240 if (door_state & DOOR_ACTION_1 && door_state & DOOR_ACTION_2)
5241 door_delay_value = MAX(door_1.post_delay, door_2.post_delay);
5242 else if (door_state & DOOR_ACTION_1)
5243 door_delay_value = door_1.post_delay;
5244 else if (door_state & DOOR_ACTION_2)
5245 door_delay_value = door_2.post_delay;
5247 while (!DelayReached(&door_delay, door_delay_value))
5252 if (door_state & DOOR_ACTION_1)
5253 door1 = door_state & DOOR_ACTION_1;
5254 if (door_state & DOOR_ACTION_2)
5255 door2 = door_state & DOOR_ACTION_2;
5257 // draw masked border over door area
5258 DrawMaskedBorder(REDRAW_DOOR_1);
5259 DrawMaskedBorder(REDRAW_DOOR_2);
5261 return (door1 | door2);
5264 static boolean useSpecialEditorDoor()
5266 int graphic = IMG_GLOBAL_BORDER_EDITOR;
5267 boolean redefined = getImageListEntryFromImageID(graphic)->redefined;
5269 // do not draw special editor door if editor border defined or redefined
5270 if (graphic_info[graphic].bitmap != NULL || redefined)
5273 // do not draw special editor door if global border defined to be empty
5274 if (graphic_info[IMG_GLOBAL_BORDER].bitmap == NULL)
5277 // do not draw special editor door if viewport definitions do not match
5281 EY + EYSIZE != VY + VYSIZE)
5287 void DrawSpecialEditorDoor()
5289 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
5290 int top_border_width = gfx1->width;
5291 int top_border_height = gfx1->height;
5292 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
5293 int ex = EX - outer_border;
5294 int ey = EY - outer_border;
5295 int vy = VY - outer_border;
5296 int exsize = EXSIZE + 2 * outer_border;
5298 if (!useSpecialEditorDoor())
5301 /* draw bigger level editor toolbox window */
5302 BlitBitmap(gfx1->bitmap, drawto, gfx1->src_x, gfx1->src_y,
5303 top_border_width, top_border_height, ex, ey - top_border_height);
5304 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto, ex, vy,
5305 exsize, EYSIZE - VYSIZE + outer_border, ex, ey);
5307 redraw_mask |= REDRAW_ALL;
5310 void UndrawSpecialEditorDoor()
5312 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
5313 int top_border_width = gfx1->width;
5314 int top_border_height = gfx1->height;
5315 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
5316 int ex = EX - outer_border;
5317 int ey = EY - outer_border;
5318 int ey_top = ey - top_border_height;
5319 int exsize = EXSIZE + 2 * outer_border;
5320 int eysize = EYSIZE + 2 * outer_border;
5322 if (!useSpecialEditorDoor())
5325 /* draw normal tape recorder window */
5326 if (graphic_info[IMG_GLOBAL_BORDER].bitmap)
5328 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
5329 ex, ey_top, top_border_width, top_border_height,
5331 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
5332 ex, ey, exsize, eysize, ex, ey);
5336 // if screen background is set to "[NONE]", clear editor toolbox window
5337 ClearRectangle(drawto, ex, ey_top, top_border_width, top_border_height);
5338 ClearRectangle(drawto, ex, ey, exsize, eysize);
5341 redraw_mask |= REDRAW_ALL;
5345 /* ---------- new tool button stuff ---------------------------------------- */
5350 struct TextPosInfo *pos;
5353 } toolbutton_info[NUM_TOOL_BUTTONS] =
5356 IMG_GFX_REQUEST_BUTTON_YES, &request.button.yes,
5357 TOOL_CTRL_ID_YES, "yes"
5360 IMG_GFX_REQUEST_BUTTON_NO, &request.button.no,
5361 TOOL_CTRL_ID_NO, "no"
5364 IMG_GFX_REQUEST_BUTTON_CONFIRM, &request.button.confirm,
5365 TOOL_CTRL_ID_CONFIRM, "confirm"
5368 IMG_GFX_REQUEST_BUTTON_PLAYER_1, &request.button.player_1,
5369 TOOL_CTRL_ID_PLAYER_1, "player 1"
5372 IMG_GFX_REQUEST_BUTTON_PLAYER_2, &request.button.player_2,
5373 TOOL_CTRL_ID_PLAYER_2, "player 2"
5376 IMG_GFX_REQUEST_BUTTON_PLAYER_3, &request.button.player_3,
5377 TOOL_CTRL_ID_PLAYER_3, "player 3"
5380 IMG_GFX_REQUEST_BUTTON_PLAYER_4, &request.button.player_4,
5381 TOOL_CTRL_ID_PLAYER_4, "player 4"
5385 void CreateToolButtons()
5389 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
5391 int graphic = toolbutton_info[i].graphic;
5392 struct GraphicInfo *gfx = &graphic_info[graphic];
5393 struct TextPosInfo *pos = toolbutton_info[i].pos;
5394 struct GadgetInfo *gi;
5395 Bitmap *deco_bitmap = None;
5396 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
5397 unsigned int event_mask = GD_EVENT_RELEASED;
5400 int gd_x = gfx->src_x;
5401 int gd_y = gfx->src_y;
5402 int gd_xp = gfx->src_x + gfx->pressed_xoffset;
5403 int gd_yp = gfx->src_y + gfx->pressed_yoffset;
5408 if (global.use_envelope_request)
5410 setRequestPosition(&dx, &dy, TRUE);
5412 // check if request buttons are outside of envelope and fix, if needed
5413 if (x < 0 || x + gfx->width > request.width ||
5414 y < 0 || y + gfx->height > request.height)
5416 if (id == TOOL_CTRL_ID_YES)
5419 y = request.height - 2 * request.border_size - gfx->height;
5421 else if (id == TOOL_CTRL_ID_NO)
5423 x = request.width - 2 * request.border_size - gfx->width;
5424 y = request.height - 2 * request.border_size - gfx->height;
5426 else if (id == TOOL_CTRL_ID_CONFIRM)
5428 x = (request.width - 2 * request.border_size - gfx->width) / 2;
5429 y = request.height - 2 * request.border_size - gfx->height;
5431 else if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
5433 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
5435 x = (request.width - 2 * request.border_size - gfx->width) / 2;
5436 y = request.height - 2 * request.border_size - gfx->height * 2;
5438 x += (player_nr == 3 ? -1 : player_nr == 1 ? +1 : 0) * gfx->width;
5439 y += (player_nr == 0 ? -1 : player_nr == 2 ? +1 : 0) * gfx->height;
5444 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
5446 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
5448 getSizedGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr), 0,
5449 pos->size, &deco_bitmap, &deco_x, &deco_y);
5450 deco_xpos = (gfx->width - pos->size) / 2;
5451 deco_ypos = (gfx->height - pos->size) / 2;
5454 gi = CreateGadget(GDI_CUSTOM_ID, id,
5455 GDI_IMAGE_ID, graphic,
5456 GDI_INFO_TEXT, toolbutton_info[i].infotext,
5459 GDI_WIDTH, gfx->width,
5460 GDI_HEIGHT, gfx->height,
5461 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
5462 GDI_STATE, GD_BUTTON_UNPRESSED,
5463 GDI_DESIGN_UNPRESSED, gfx->bitmap, gd_x, gd_y,
5464 GDI_DESIGN_PRESSED, gfx->bitmap, gd_xp, gd_yp,
5465 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
5466 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
5467 GDI_DECORATION_SIZE, pos->size, pos->size,
5468 GDI_DECORATION_SHIFTING, 1, 1,
5469 GDI_DIRECT_DRAW, FALSE,
5470 GDI_EVENT_MASK, event_mask,
5471 GDI_CALLBACK_ACTION, HandleToolButtons,
5475 Error(ERR_EXIT, "cannot create gadget");
5477 tool_gadget[id] = gi;
5481 void FreeToolButtons()
5485 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
5486 FreeGadget(tool_gadget[i]);
5489 static void UnmapToolButtons()
5493 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
5494 UnmapGadget(tool_gadget[i]);
5497 static void HandleToolButtons(struct GadgetInfo *gi)
5499 request_gadget_id = gi->custom_id;
5502 static struct Mapping_EM_to_RND_object
5505 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
5506 boolean is_backside; /* backside of moving element */
5512 em_object_mapping_list[] =
5515 Xblank, TRUE, FALSE,
5519 Yacid_splash_eB, FALSE, FALSE,
5520 EL_ACID_SPLASH_RIGHT, -1, -1
5523 Yacid_splash_wB, FALSE, FALSE,
5524 EL_ACID_SPLASH_LEFT, -1, -1
5527 #ifdef EM_ENGINE_BAD_ROLL
5529 Xstone_force_e, FALSE, FALSE,
5530 EL_ROCK, -1, MV_BIT_RIGHT
5533 Xstone_force_w, FALSE, FALSE,
5534 EL_ROCK, -1, MV_BIT_LEFT
5537 Xnut_force_e, FALSE, FALSE,
5538 EL_NUT, -1, MV_BIT_RIGHT
5541 Xnut_force_w, FALSE, FALSE,
5542 EL_NUT, -1, MV_BIT_LEFT
5545 Xspring_force_e, FALSE, FALSE,
5546 EL_SPRING, -1, MV_BIT_RIGHT
5549 Xspring_force_w, FALSE, FALSE,
5550 EL_SPRING, -1, MV_BIT_LEFT
5553 Xemerald_force_e, FALSE, FALSE,
5554 EL_EMERALD, -1, MV_BIT_RIGHT
5557 Xemerald_force_w, FALSE, FALSE,
5558 EL_EMERALD, -1, MV_BIT_LEFT
5561 Xdiamond_force_e, FALSE, FALSE,
5562 EL_DIAMOND, -1, MV_BIT_RIGHT
5565 Xdiamond_force_w, FALSE, FALSE,
5566 EL_DIAMOND, -1, MV_BIT_LEFT
5569 Xbomb_force_e, FALSE, FALSE,
5570 EL_BOMB, -1, MV_BIT_RIGHT
5573 Xbomb_force_w, FALSE, FALSE,
5574 EL_BOMB, -1, MV_BIT_LEFT
5576 #endif /* EM_ENGINE_BAD_ROLL */
5579 Xstone, TRUE, FALSE,
5583 Xstone_pause, FALSE, FALSE,
5587 Xstone_fall, FALSE, FALSE,
5591 Ystone_s, FALSE, FALSE,
5592 EL_ROCK, ACTION_FALLING, -1
5595 Ystone_sB, FALSE, TRUE,
5596 EL_ROCK, ACTION_FALLING, -1
5599 Ystone_e, FALSE, FALSE,
5600 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
5603 Ystone_eB, FALSE, TRUE,
5604 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
5607 Ystone_w, FALSE, FALSE,
5608 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
5611 Ystone_wB, FALSE, TRUE,
5612 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
5619 Xnut_pause, FALSE, FALSE,
5623 Xnut_fall, FALSE, FALSE,
5627 Ynut_s, FALSE, FALSE,
5628 EL_NUT, ACTION_FALLING, -1
5631 Ynut_sB, FALSE, TRUE,
5632 EL_NUT, ACTION_FALLING, -1
5635 Ynut_e, FALSE, FALSE,
5636 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
5639 Ynut_eB, FALSE, TRUE,
5640 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
5643 Ynut_w, FALSE, FALSE,
5644 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
5647 Ynut_wB, FALSE, TRUE,
5648 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
5651 Xbug_n, TRUE, FALSE,
5655 Xbug_e, TRUE, FALSE,
5656 EL_BUG_RIGHT, -1, -1
5659 Xbug_s, TRUE, FALSE,
5663 Xbug_w, TRUE, FALSE,
5667 Xbug_gon, FALSE, FALSE,
5671 Xbug_goe, FALSE, FALSE,
5672 EL_BUG_RIGHT, -1, -1
5675 Xbug_gos, FALSE, FALSE,
5679 Xbug_gow, FALSE, FALSE,
5683 Ybug_n, FALSE, FALSE,
5684 EL_BUG, ACTION_MOVING, MV_BIT_UP
5687 Ybug_nB, FALSE, TRUE,
5688 EL_BUG, ACTION_MOVING, MV_BIT_UP
5691 Ybug_e, FALSE, FALSE,
5692 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
5695 Ybug_eB, FALSE, TRUE,
5696 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
5699 Ybug_s, FALSE, FALSE,
5700 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
5703 Ybug_sB, FALSE, TRUE,
5704 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
5707 Ybug_w, FALSE, FALSE,
5708 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
5711 Ybug_wB, FALSE, TRUE,
5712 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
5715 Ybug_w_n, FALSE, FALSE,
5716 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
5719 Ybug_n_e, FALSE, FALSE,
5720 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
5723 Ybug_e_s, FALSE, FALSE,
5724 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
5727 Ybug_s_w, FALSE, FALSE,
5728 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
5731 Ybug_e_n, FALSE, FALSE,
5732 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
5735 Ybug_s_e, FALSE, FALSE,
5736 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
5739 Ybug_w_s, FALSE, FALSE,
5740 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
5743 Ybug_n_w, FALSE, FALSE,
5744 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
5747 Ybug_stone, FALSE, FALSE,
5748 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
5751 Ybug_spring, FALSE, FALSE,
5752 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
5755 Xtank_n, TRUE, FALSE,
5756 EL_SPACESHIP_UP, -1, -1
5759 Xtank_e, TRUE, FALSE,
5760 EL_SPACESHIP_RIGHT, -1, -1
5763 Xtank_s, TRUE, FALSE,
5764 EL_SPACESHIP_DOWN, -1, -1
5767 Xtank_w, TRUE, FALSE,
5768 EL_SPACESHIP_LEFT, -1, -1
5771 Xtank_gon, FALSE, FALSE,
5772 EL_SPACESHIP_UP, -1, -1
5775 Xtank_goe, FALSE, FALSE,
5776 EL_SPACESHIP_RIGHT, -1, -1
5779 Xtank_gos, FALSE, FALSE,
5780 EL_SPACESHIP_DOWN, -1, -1
5783 Xtank_gow, FALSE, FALSE,
5784 EL_SPACESHIP_LEFT, -1, -1
5787 Ytank_n, FALSE, FALSE,
5788 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
5791 Ytank_nB, FALSE, TRUE,
5792 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
5795 Ytank_e, FALSE, FALSE,
5796 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
5799 Ytank_eB, FALSE, TRUE,
5800 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
5803 Ytank_s, FALSE, FALSE,
5804 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
5807 Ytank_sB, FALSE, TRUE,
5808 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
5811 Ytank_w, FALSE, FALSE,
5812 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
5815 Ytank_wB, FALSE, TRUE,
5816 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
5819 Ytank_w_n, FALSE, FALSE,
5820 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
5823 Ytank_n_e, FALSE, FALSE,
5824 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
5827 Ytank_e_s, FALSE, FALSE,
5828 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
5831 Ytank_s_w, FALSE, FALSE,
5832 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
5835 Ytank_e_n, FALSE, FALSE,
5836 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
5839 Ytank_s_e, FALSE, FALSE,
5840 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
5843 Ytank_w_s, FALSE, FALSE,
5844 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
5847 Ytank_n_w, FALSE, FALSE,
5848 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
5851 Ytank_stone, FALSE, FALSE,
5852 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
5855 Ytank_spring, FALSE, FALSE,
5856 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
5859 Xandroid, TRUE, FALSE,
5860 EL_EMC_ANDROID, ACTION_ACTIVE, -1
5863 Xandroid_1_n, FALSE, FALSE,
5864 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
5867 Xandroid_2_n, FALSE, FALSE,
5868 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
5871 Xandroid_1_e, FALSE, FALSE,
5872 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
5875 Xandroid_2_e, FALSE, FALSE,
5876 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
5879 Xandroid_1_w, FALSE, FALSE,
5880 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
5883 Xandroid_2_w, FALSE, FALSE,
5884 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
5887 Xandroid_1_s, FALSE, FALSE,
5888 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
5891 Xandroid_2_s, FALSE, FALSE,
5892 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
5895 Yandroid_n, FALSE, FALSE,
5896 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
5899 Yandroid_nB, FALSE, TRUE,
5900 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
5903 Yandroid_ne, FALSE, FALSE,
5904 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
5907 Yandroid_neB, FALSE, TRUE,
5908 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
5911 Yandroid_e, FALSE, FALSE,
5912 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
5915 Yandroid_eB, FALSE, TRUE,
5916 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
5919 Yandroid_se, FALSE, FALSE,
5920 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
5923 Yandroid_seB, FALSE, TRUE,
5924 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
5927 Yandroid_s, FALSE, FALSE,
5928 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
5931 Yandroid_sB, FALSE, TRUE,
5932 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
5935 Yandroid_sw, FALSE, FALSE,
5936 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
5939 Yandroid_swB, FALSE, TRUE,
5940 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
5943 Yandroid_w, FALSE, FALSE,
5944 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
5947 Yandroid_wB, FALSE, TRUE,
5948 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
5951 Yandroid_nw, FALSE, FALSE,
5952 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
5955 Yandroid_nwB, FALSE, TRUE,
5956 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
5959 Xspring, TRUE, FALSE,
5963 Xspring_pause, FALSE, FALSE,
5967 Xspring_e, FALSE, FALSE,
5971 Xspring_w, FALSE, FALSE,
5975 Xspring_fall, FALSE, FALSE,
5979 Yspring_s, FALSE, FALSE,
5980 EL_SPRING, ACTION_FALLING, -1
5983 Yspring_sB, FALSE, TRUE,
5984 EL_SPRING, ACTION_FALLING, -1
5987 Yspring_e, FALSE, FALSE,
5988 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
5991 Yspring_eB, FALSE, TRUE,
5992 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
5995 Yspring_w, FALSE, FALSE,
5996 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
5999 Yspring_wB, FALSE, TRUE,
6000 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
6003 Yspring_kill_e, FALSE, FALSE,
6004 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
6007 Yspring_kill_eB, FALSE, TRUE,
6008 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
6011 Yspring_kill_w, FALSE, FALSE,
6012 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
6015 Yspring_kill_wB, FALSE, TRUE,
6016 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
6019 Xeater_n, TRUE, FALSE,
6020 EL_YAMYAM_UP, -1, -1
6023 Xeater_e, TRUE, FALSE,
6024 EL_YAMYAM_RIGHT, -1, -1
6027 Xeater_w, TRUE, FALSE,
6028 EL_YAMYAM_LEFT, -1, -1
6031 Xeater_s, TRUE, FALSE,
6032 EL_YAMYAM_DOWN, -1, -1
6035 Yeater_n, FALSE, FALSE,
6036 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
6039 Yeater_nB, FALSE, TRUE,
6040 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
6043 Yeater_e, FALSE, FALSE,
6044 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
6047 Yeater_eB, FALSE, TRUE,
6048 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
6051 Yeater_s, FALSE, FALSE,
6052 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
6055 Yeater_sB, FALSE, TRUE,
6056 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
6059 Yeater_w, FALSE, FALSE,
6060 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
6063 Yeater_wB, FALSE, TRUE,
6064 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
6067 Yeater_stone, FALSE, FALSE,
6068 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
6071 Yeater_spring, FALSE, FALSE,
6072 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
6075 Xalien, TRUE, FALSE,
6079 Xalien_pause, FALSE, FALSE,
6083 Yalien_n, FALSE, FALSE,
6084 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
6087 Yalien_nB, FALSE, TRUE,
6088 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
6091 Yalien_e, FALSE, FALSE,
6092 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
6095 Yalien_eB, FALSE, TRUE,
6096 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
6099 Yalien_s, FALSE, FALSE,
6100 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
6103 Yalien_sB, FALSE, TRUE,
6104 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
6107 Yalien_w, FALSE, FALSE,
6108 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
6111 Yalien_wB, FALSE, TRUE,
6112 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
6115 Yalien_stone, FALSE, FALSE,
6116 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
6119 Yalien_spring, FALSE, FALSE,
6120 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
6123 Xemerald, TRUE, FALSE,
6127 Xemerald_pause, FALSE, FALSE,
6131 Xemerald_fall, FALSE, FALSE,
6135 Xemerald_shine, FALSE, FALSE,
6136 EL_EMERALD, ACTION_TWINKLING, -1
6139 Yemerald_s, FALSE, FALSE,
6140 EL_EMERALD, ACTION_FALLING, -1
6143 Yemerald_sB, FALSE, TRUE,
6144 EL_EMERALD, ACTION_FALLING, -1
6147 Yemerald_e, FALSE, FALSE,
6148 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
6151 Yemerald_eB, FALSE, TRUE,
6152 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
6155 Yemerald_w, FALSE, FALSE,
6156 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
6159 Yemerald_wB, FALSE, TRUE,
6160 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
6163 Yemerald_eat, FALSE, FALSE,
6164 EL_EMERALD, ACTION_COLLECTING, -1
6167 Yemerald_stone, FALSE, FALSE,
6168 EL_NUT, ACTION_BREAKING, -1
6171 Xdiamond, TRUE, FALSE,
6175 Xdiamond_pause, FALSE, FALSE,
6179 Xdiamond_fall, FALSE, FALSE,
6183 Xdiamond_shine, FALSE, FALSE,
6184 EL_DIAMOND, ACTION_TWINKLING, -1
6187 Ydiamond_s, FALSE, FALSE,
6188 EL_DIAMOND, ACTION_FALLING, -1
6191 Ydiamond_sB, FALSE, TRUE,
6192 EL_DIAMOND, ACTION_FALLING, -1
6195 Ydiamond_e, FALSE, FALSE,
6196 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
6199 Ydiamond_eB, FALSE, TRUE,
6200 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
6203 Ydiamond_w, FALSE, FALSE,
6204 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
6207 Ydiamond_wB, FALSE, TRUE,
6208 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
6211 Ydiamond_eat, FALSE, FALSE,
6212 EL_DIAMOND, ACTION_COLLECTING, -1
6215 Ydiamond_stone, FALSE, FALSE,
6216 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
6219 Xdrip_fall, TRUE, FALSE,
6220 EL_AMOEBA_DROP, -1, -1
6223 Xdrip_stretch, FALSE, FALSE,
6224 EL_AMOEBA_DROP, ACTION_FALLING, -1
6227 Xdrip_stretchB, FALSE, TRUE,
6228 EL_AMOEBA_DROP, ACTION_FALLING, -1
6231 Xdrip_eat, FALSE, FALSE,
6232 EL_AMOEBA_DROP, ACTION_GROWING, -1
6235 Ydrip_s1, FALSE, FALSE,
6236 EL_AMOEBA_DROP, ACTION_FALLING, -1
6239 Ydrip_s1B, FALSE, TRUE,
6240 EL_AMOEBA_DROP, ACTION_FALLING, -1
6243 Ydrip_s2, FALSE, FALSE,
6244 EL_AMOEBA_DROP, ACTION_FALLING, -1
6247 Ydrip_s2B, FALSE, TRUE,
6248 EL_AMOEBA_DROP, ACTION_FALLING, -1
6255 Xbomb_pause, FALSE, FALSE,
6259 Xbomb_fall, FALSE, FALSE,
6263 Ybomb_s, FALSE, FALSE,
6264 EL_BOMB, ACTION_FALLING, -1
6267 Ybomb_sB, FALSE, TRUE,
6268 EL_BOMB, ACTION_FALLING, -1
6271 Ybomb_e, FALSE, FALSE,
6272 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
6275 Ybomb_eB, FALSE, TRUE,
6276 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
6279 Ybomb_w, FALSE, FALSE,
6280 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
6283 Ybomb_wB, FALSE, TRUE,
6284 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
6287 Ybomb_eat, FALSE, FALSE,
6288 EL_BOMB, ACTION_ACTIVATING, -1
6291 Xballoon, TRUE, FALSE,
6295 Yballoon_n, FALSE, FALSE,
6296 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
6299 Yballoon_nB, FALSE, TRUE,
6300 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
6303 Yballoon_e, FALSE, FALSE,
6304 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
6307 Yballoon_eB, FALSE, TRUE,
6308 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
6311 Yballoon_s, FALSE, FALSE,
6312 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
6315 Yballoon_sB, FALSE, TRUE,
6316 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
6319 Yballoon_w, FALSE, FALSE,
6320 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
6323 Yballoon_wB, FALSE, TRUE,
6324 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
6327 Xgrass, TRUE, FALSE,
6328 EL_EMC_GRASS, -1, -1
6331 Ygrass_nB, FALSE, FALSE,
6332 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
6335 Ygrass_eB, FALSE, FALSE,
6336 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
6339 Ygrass_sB, FALSE, FALSE,
6340 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
6343 Ygrass_wB, FALSE, FALSE,
6344 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
6351 Ydirt_nB, FALSE, FALSE,
6352 EL_SAND, ACTION_DIGGING, MV_BIT_UP
6355 Ydirt_eB, FALSE, FALSE,
6356 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
6359 Ydirt_sB, FALSE, FALSE,
6360 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
6363 Ydirt_wB, FALSE, FALSE,
6364 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
6367 Xacid_ne, TRUE, FALSE,
6368 EL_ACID_POOL_TOPRIGHT, -1, -1
6371 Xacid_se, TRUE, FALSE,
6372 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
6375 Xacid_s, TRUE, FALSE,
6376 EL_ACID_POOL_BOTTOM, -1, -1
6379 Xacid_sw, TRUE, FALSE,
6380 EL_ACID_POOL_BOTTOMLEFT, -1, -1
6383 Xacid_nw, TRUE, FALSE,
6384 EL_ACID_POOL_TOPLEFT, -1, -1
6387 Xacid_1, TRUE, FALSE,
6391 Xacid_2, FALSE, FALSE,
6395 Xacid_3, FALSE, FALSE,
6399 Xacid_4, FALSE, FALSE,
6403 Xacid_5, FALSE, FALSE,
6407 Xacid_6, FALSE, FALSE,
6411 Xacid_7, FALSE, FALSE,
6415 Xacid_8, FALSE, FALSE,
6419 Xball_1, TRUE, FALSE,
6420 EL_EMC_MAGIC_BALL, -1, -1
6423 Xball_1B, FALSE, FALSE,
6424 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
6427 Xball_2, FALSE, FALSE,
6428 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
6431 Xball_2B, FALSE, FALSE,
6432 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
6435 Yball_eat, FALSE, FALSE,
6436 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
6439 Ykey_1_eat, FALSE, FALSE,
6440 EL_EM_KEY_1, ACTION_COLLECTING, -1
6443 Ykey_2_eat, FALSE, FALSE,
6444 EL_EM_KEY_2, ACTION_COLLECTING, -1
6447 Ykey_3_eat, FALSE, FALSE,
6448 EL_EM_KEY_3, ACTION_COLLECTING, -1
6451 Ykey_4_eat, FALSE, FALSE,
6452 EL_EM_KEY_4, ACTION_COLLECTING, -1
6455 Ykey_5_eat, FALSE, FALSE,
6456 EL_EMC_KEY_5, ACTION_COLLECTING, -1
6459 Ykey_6_eat, FALSE, FALSE,
6460 EL_EMC_KEY_6, ACTION_COLLECTING, -1
6463 Ykey_7_eat, FALSE, FALSE,
6464 EL_EMC_KEY_7, ACTION_COLLECTING, -1
6467 Ykey_8_eat, FALSE, FALSE,
6468 EL_EMC_KEY_8, ACTION_COLLECTING, -1
6471 Ylenses_eat, FALSE, FALSE,
6472 EL_EMC_LENSES, ACTION_COLLECTING, -1
6475 Ymagnify_eat, FALSE, FALSE,
6476 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
6479 Ygrass_eat, FALSE, FALSE,
6480 EL_EMC_GRASS, ACTION_SNAPPING, -1
6483 Ydirt_eat, FALSE, FALSE,
6484 EL_SAND, ACTION_SNAPPING, -1
6487 Xgrow_ns, TRUE, FALSE,
6488 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
6491 Ygrow_ns_eat, FALSE, FALSE,
6492 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
6495 Xgrow_ew, TRUE, FALSE,
6496 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
6499 Ygrow_ew_eat, FALSE, FALSE,
6500 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
6503 Xwonderwall, TRUE, FALSE,
6504 EL_MAGIC_WALL, -1, -1
6507 XwonderwallB, FALSE, FALSE,
6508 EL_MAGIC_WALL, ACTION_ACTIVE, -1
6511 Xamoeba_1, TRUE, FALSE,
6512 EL_AMOEBA_DRY, ACTION_OTHER, -1
6515 Xamoeba_2, FALSE, FALSE,
6516 EL_AMOEBA_DRY, ACTION_OTHER, -1
6519 Xamoeba_3, FALSE, FALSE,
6520 EL_AMOEBA_DRY, ACTION_OTHER, -1
6523 Xamoeba_4, FALSE, FALSE,
6524 EL_AMOEBA_DRY, ACTION_OTHER, -1
6527 Xamoeba_5, TRUE, FALSE,
6528 EL_AMOEBA_WET, ACTION_OTHER, -1
6531 Xamoeba_6, FALSE, FALSE,
6532 EL_AMOEBA_WET, ACTION_OTHER, -1
6535 Xamoeba_7, FALSE, FALSE,
6536 EL_AMOEBA_WET, ACTION_OTHER, -1
6539 Xamoeba_8, FALSE, FALSE,
6540 EL_AMOEBA_WET, ACTION_OTHER, -1
6543 Xdoor_1, TRUE, FALSE,
6544 EL_EM_GATE_1, -1, -1
6547 Xdoor_2, TRUE, FALSE,
6548 EL_EM_GATE_2, -1, -1
6551 Xdoor_3, TRUE, FALSE,
6552 EL_EM_GATE_3, -1, -1
6555 Xdoor_4, TRUE, FALSE,
6556 EL_EM_GATE_4, -1, -1
6559 Xdoor_5, TRUE, FALSE,
6560 EL_EMC_GATE_5, -1, -1
6563 Xdoor_6, TRUE, FALSE,
6564 EL_EMC_GATE_6, -1, -1
6567 Xdoor_7, TRUE, FALSE,
6568 EL_EMC_GATE_7, -1, -1
6571 Xdoor_8, TRUE, FALSE,
6572 EL_EMC_GATE_8, -1, -1
6575 Xkey_1, TRUE, FALSE,
6579 Xkey_2, TRUE, FALSE,
6583 Xkey_3, TRUE, FALSE,
6587 Xkey_4, TRUE, FALSE,
6591 Xkey_5, TRUE, FALSE,
6592 EL_EMC_KEY_5, -1, -1
6595 Xkey_6, TRUE, FALSE,
6596 EL_EMC_KEY_6, -1, -1
6599 Xkey_7, TRUE, FALSE,
6600 EL_EMC_KEY_7, -1, -1
6603 Xkey_8, TRUE, FALSE,
6604 EL_EMC_KEY_8, -1, -1
6607 Xwind_n, TRUE, FALSE,
6608 EL_BALLOON_SWITCH_UP, -1, -1
6611 Xwind_e, TRUE, FALSE,
6612 EL_BALLOON_SWITCH_RIGHT, -1, -1
6615 Xwind_s, TRUE, FALSE,
6616 EL_BALLOON_SWITCH_DOWN, -1, -1
6619 Xwind_w, TRUE, FALSE,
6620 EL_BALLOON_SWITCH_LEFT, -1, -1
6623 Xwind_nesw, TRUE, FALSE,
6624 EL_BALLOON_SWITCH_ANY, -1, -1
6627 Xwind_stop, TRUE, FALSE,
6628 EL_BALLOON_SWITCH_NONE, -1, -1
6632 EL_EM_EXIT_CLOSED, -1, -1
6635 Xexit_1, TRUE, FALSE,
6636 EL_EM_EXIT_OPEN, -1, -1
6639 Xexit_2, FALSE, FALSE,
6640 EL_EM_EXIT_OPEN, -1, -1
6643 Xexit_3, FALSE, FALSE,
6644 EL_EM_EXIT_OPEN, -1, -1
6647 Xdynamite, TRUE, FALSE,
6648 EL_EM_DYNAMITE, -1, -1
6651 Ydynamite_eat, FALSE, FALSE,
6652 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
6655 Xdynamite_1, TRUE, FALSE,
6656 EL_EM_DYNAMITE_ACTIVE, -1, -1
6659 Xdynamite_2, FALSE, FALSE,
6660 EL_EM_DYNAMITE_ACTIVE, -1, -1
6663 Xdynamite_3, FALSE, FALSE,
6664 EL_EM_DYNAMITE_ACTIVE, -1, -1
6667 Xdynamite_4, FALSE, FALSE,
6668 EL_EM_DYNAMITE_ACTIVE, -1, -1
6671 Xbumper, TRUE, FALSE,
6672 EL_EMC_SPRING_BUMPER, -1, -1
6675 XbumperB, FALSE, FALSE,
6676 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
6679 Xwheel, TRUE, FALSE,
6680 EL_ROBOT_WHEEL, -1, -1
6683 XwheelB, FALSE, FALSE,
6684 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
6687 Xswitch, TRUE, FALSE,
6688 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
6691 XswitchB, FALSE, FALSE,
6692 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
6696 EL_QUICKSAND_EMPTY, -1, -1
6699 Xsand_stone, TRUE, FALSE,
6700 EL_QUICKSAND_FULL, -1, -1
6703 Xsand_stonein_1, FALSE, TRUE,
6704 EL_ROCK, ACTION_FILLING, -1
6707 Xsand_stonein_2, FALSE, TRUE,
6708 EL_ROCK, ACTION_FILLING, -1
6711 Xsand_stonein_3, FALSE, TRUE,
6712 EL_ROCK, ACTION_FILLING, -1
6715 Xsand_stonein_4, FALSE, TRUE,
6716 EL_ROCK, ACTION_FILLING, -1
6719 Xsand_stonesand_1, FALSE, FALSE,
6720 EL_QUICKSAND_EMPTYING, -1, -1
6723 Xsand_stonesand_2, FALSE, FALSE,
6724 EL_QUICKSAND_EMPTYING, -1, -1
6727 Xsand_stonesand_3, FALSE, FALSE,
6728 EL_QUICKSAND_EMPTYING, -1, -1
6731 Xsand_stonesand_4, FALSE, FALSE,
6732 EL_QUICKSAND_EMPTYING, -1, -1
6735 Xsand_stonesand_quickout_1, FALSE, FALSE,
6736 EL_QUICKSAND_EMPTYING, -1, -1
6739 Xsand_stonesand_quickout_2, FALSE, FALSE,
6740 EL_QUICKSAND_EMPTYING, -1, -1
6743 Xsand_stoneout_1, FALSE, FALSE,
6744 EL_ROCK, ACTION_EMPTYING, -1
6747 Xsand_stoneout_2, FALSE, FALSE,
6748 EL_ROCK, ACTION_EMPTYING, -1
6751 Xsand_sandstone_1, FALSE, FALSE,
6752 EL_QUICKSAND_FILLING, -1, -1
6755 Xsand_sandstone_2, FALSE, FALSE,
6756 EL_QUICKSAND_FILLING, -1, -1
6759 Xsand_sandstone_3, FALSE, FALSE,
6760 EL_QUICKSAND_FILLING, -1, -1
6763 Xsand_sandstone_4, FALSE, FALSE,
6764 EL_QUICKSAND_FILLING, -1, -1
6767 Xplant, TRUE, FALSE,
6768 EL_EMC_PLANT, -1, -1
6771 Yplant, FALSE, FALSE,
6772 EL_EMC_PLANT, -1, -1
6775 Xlenses, TRUE, FALSE,
6776 EL_EMC_LENSES, -1, -1
6779 Xmagnify, TRUE, FALSE,
6780 EL_EMC_MAGNIFIER, -1, -1
6783 Xdripper, TRUE, FALSE,
6784 EL_EMC_DRIPPER, -1, -1
6787 XdripperB, FALSE, FALSE,
6788 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
6791 Xfake_blank, TRUE, FALSE,
6792 EL_INVISIBLE_WALL, -1, -1
6795 Xfake_blankB, FALSE, FALSE,
6796 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
6799 Xfake_grass, TRUE, FALSE,
6800 EL_EMC_FAKE_GRASS, -1, -1
6803 Xfake_grassB, FALSE, FALSE,
6804 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
6807 Xfake_door_1, TRUE, FALSE,
6808 EL_EM_GATE_1_GRAY, -1, -1
6811 Xfake_door_2, TRUE, FALSE,
6812 EL_EM_GATE_2_GRAY, -1, -1
6815 Xfake_door_3, TRUE, FALSE,
6816 EL_EM_GATE_3_GRAY, -1, -1
6819 Xfake_door_4, TRUE, FALSE,
6820 EL_EM_GATE_4_GRAY, -1, -1
6823 Xfake_door_5, TRUE, FALSE,
6824 EL_EMC_GATE_5_GRAY, -1, -1
6827 Xfake_door_6, TRUE, FALSE,
6828 EL_EMC_GATE_6_GRAY, -1, -1
6831 Xfake_door_7, TRUE, FALSE,
6832 EL_EMC_GATE_7_GRAY, -1, -1
6835 Xfake_door_8, TRUE, FALSE,
6836 EL_EMC_GATE_8_GRAY, -1, -1
6839 Xfake_acid_1, TRUE, FALSE,
6840 EL_EMC_FAKE_ACID, -1, -1
6843 Xfake_acid_2, FALSE, FALSE,
6844 EL_EMC_FAKE_ACID, -1, -1
6847 Xfake_acid_3, FALSE, FALSE,
6848 EL_EMC_FAKE_ACID, -1, -1
6851 Xfake_acid_4, FALSE, FALSE,
6852 EL_EMC_FAKE_ACID, -1, -1
6855 Xfake_acid_5, FALSE, FALSE,
6856 EL_EMC_FAKE_ACID, -1, -1
6859 Xfake_acid_6, FALSE, FALSE,
6860 EL_EMC_FAKE_ACID, -1, -1
6863 Xfake_acid_7, FALSE, FALSE,
6864 EL_EMC_FAKE_ACID, -1, -1
6867 Xfake_acid_8, FALSE, FALSE,
6868 EL_EMC_FAKE_ACID, -1, -1
6871 Xsteel_1, TRUE, FALSE,
6872 EL_STEELWALL, -1, -1
6875 Xsteel_2, TRUE, FALSE,
6876 EL_EMC_STEELWALL_2, -1, -1
6879 Xsteel_3, TRUE, FALSE,
6880 EL_EMC_STEELWALL_3, -1, -1
6883 Xsteel_4, TRUE, FALSE,
6884 EL_EMC_STEELWALL_4, -1, -1
6887 Xwall_1, TRUE, FALSE,
6891 Xwall_2, TRUE, FALSE,
6892 EL_EMC_WALL_14, -1, -1
6895 Xwall_3, TRUE, FALSE,
6896 EL_EMC_WALL_15, -1, -1
6899 Xwall_4, TRUE, FALSE,
6900 EL_EMC_WALL_16, -1, -1
6903 Xround_wall_1, TRUE, FALSE,
6904 EL_WALL_SLIPPERY, -1, -1
6907 Xround_wall_2, TRUE, FALSE,
6908 EL_EMC_WALL_SLIPPERY_2, -1, -1
6911 Xround_wall_3, TRUE, FALSE,
6912 EL_EMC_WALL_SLIPPERY_3, -1, -1
6915 Xround_wall_4, TRUE, FALSE,
6916 EL_EMC_WALL_SLIPPERY_4, -1, -1
6919 Xdecor_1, TRUE, FALSE,
6920 EL_EMC_WALL_8, -1, -1
6923 Xdecor_2, TRUE, FALSE,
6924 EL_EMC_WALL_6, -1, -1
6927 Xdecor_3, TRUE, FALSE,
6928 EL_EMC_WALL_4, -1, -1
6931 Xdecor_4, TRUE, FALSE,
6932 EL_EMC_WALL_7, -1, -1
6935 Xdecor_5, TRUE, FALSE,
6936 EL_EMC_WALL_5, -1, -1
6939 Xdecor_6, TRUE, FALSE,
6940 EL_EMC_WALL_9, -1, -1
6943 Xdecor_7, TRUE, FALSE,
6944 EL_EMC_WALL_10, -1, -1
6947 Xdecor_8, TRUE, FALSE,
6948 EL_EMC_WALL_1, -1, -1
6951 Xdecor_9, TRUE, FALSE,
6952 EL_EMC_WALL_2, -1, -1
6955 Xdecor_10, TRUE, FALSE,
6956 EL_EMC_WALL_3, -1, -1
6959 Xdecor_11, TRUE, FALSE,
6960 EL_EMC_WALL_11, -1, -1
6963 Xdecor_12, TRUE, FALSE,
6964 EL_EMC_WALL_12, -1, -1
6967 Xalpha_0, TRUE, FALSE,
6968 EL_CHAR('0'), -1, -1
6971 Xalpha_1, TRUE, FALSE,
6972 EL_CHAR('1'), -1, -1
6975 Xalpha_2, TRUE, FALSE,
6976 EL_CHAR('2'), -1, -1
6979 Xalpha_3, TRUE, FALSE,
6980 EL_CHAR('3'), -1, -1
6983 Xalpha_4, TRUE, FALSE,
6984 EL_CHAR('4'), -1, -1
6987 Xalpha_5, TRUE, FALSE,
6988 EL_CHAR('5'), -1, -1
6991 Xalpha_6, TRUE, FALSE,
6992 EL_CHAR('6'), -1, -1
6995 Xalpha_7, TRUE, FALSE,
6996 EL_CHAR('7'), -1, -1
6999 Xalpha_8, TRUE, FALSE,
7000 EL_CHAR('8'), -1, -1
7003 Xalpha_9, TRUE, FALSE,
7004 EL_CHAR('9'), -1, -1
7007 Xalpha_excla, TRUE, FALSE,
7008 EL_CHAR('!'), -1, -1
7011 Xalpha_quote, TRUE, FALSE,
7012 EL_CHAR('"'), -1, -1
7015 Xalpha_comma, TRUE, FALSE,
7016 EL_CHAR(','), -1, -1
7019 Xalpha_minus, TRUE, FALSE,
7020 EL_CHAR('-'), -1, -1
7023 Xalpha_perio, TRUE, FALSE,
7024 EL_CHAR('.'), -1, -1
7027 Xalpha_colon, TRUE, FALSE,
7028 EL_CHAR(':'), -1, -1
7031 Xalpha_quest, TRUE, FALSE,
7032 EL_CHAR('?'), -1, -1
7035 Xalpha_a, TRUE, FALSE,
7036 EL_CHAR('A'), -1, -1
7039 Xalpha_b, TRUE, FALSE,
7040 EL_CHAR('B'), -1, -1
7043 Xalpha_c, TRUE, FALSE,
7044 EL_CHAR('C'), -1, -1
7047 Xalpha_d, TRUE, FALSE,
7048 EL_CHAR('D'), -1, -1
7051 Xalpha_e, TRUE, FALSE,
7052 EL_CHAR('E'), -1, -1
7055 Xalpha_f, TRUE, FALSE,
7056 EL_CHAR('F'), -1, -1
7059 Xalpha_g, TRUE, FALSE,
7060 EL_CHAR('G'), -1, -1
7063 Xalpha_h, TRUE, FALSE,
7064 EL_CHAR('H'), -1, -1
7067 Xalpha_i, TRUE, FALSE,
7068 EL_CHAR('I'), -1, -1
7071 Xalpha_j, TRUE, FALSE,
7072 EL_CHAR('J'), -1, -1
7075 Xalpha_k, TRUE, FALSE,
7076 EL_CHAR('K'), -1, -1
7079 Xalpha_l, TRUE, FALSE,
7080 EL_CHAR('L'), -1, -1
7083 Xalpha_m, TRUE, FALSE,
7084 EL_CHAR('M'), -1, -1
7087 Xalpha_n, TRUE, FALSE,
7088 EL_CHAR('N'), -1, -1
7091 Xalpha_o, TRUE, FALSE,
7092 EL_CHAR('O'), -1, -1
7095 Xalpha_p, TRUE, FALSE,
7096 EL_CHAR('P'), -1, -1
7099 Xalpha_q, TRUE, FALSE,
7100 EL_CHAR('Q'), -1, -1
7103 Xalpha_r, TRUE, FALSE,
7104 EL_CHAR('R'), -1, -1
7107 Xalpha_s, TRUE, FALSE,
7108 EL_CHAR('S'), -1, -1
7111 Xalpha_t, TRUE, FALSE,
7112 EL_CHAR('T'), -1, -1
7115 Xalpha_u, TRUE, FALSE,
7116 EL_CHAR('U'), -1, -1
7119 Xalpha_v, TRUE, FALSE,
7120 EL_CHAR('V'), -1, -1
7123 Xalpha_w, TRUE, FALSE,
7124 EL_CHAR('W'), -1, -1
7127 Xalpha_x, TRUE, FALSE,
7128 EL_CHAR('X'), -1, -1
7131 Xalpha_y, TRUE, FALSE,
7132 EL_CHAR('Y'), -1, -1
7135 Xalpha_z, TRUE, FALSE,
7136 EL_CHAR('Z'), -1, -1
7139 Xalpha_arrow_e, TRUE, FALSE,
7140 EL_CHAR('>'), -1, -1
7143 Xalpha_arrow_w, TRUE, FALSE,
7144 EL_CHAR('<'), -1, -1
7147 Xalpha_copyr, TRUE, FALSE,
7148 EL_CHAR(CHAR_BYTE_COPYRIGHT), -1, -1
7152 Xboom_bug, FALSE, FALSE,
7153 EL_BUG, ACTION_EXPLODING, -1
7156 Xboom_bomb, FALSE, FALSE,
7157 EL_BOMB, ACTION_EXPLODING, -1
7160 Xboom_android, FALSE, FALSE,
7161 EL_EMC_ANDROID, ACTION_OTHER, -1
7164 Xboom_1, FALSE, FALSE,
7165 EL_DEFAULT, ACTION_EXPLODING, -1
7168 Xboom_2, FALSE, FALSE,
7169 EL_DEFAULT, ACTION_EXPLODING, -1
7172 Znormal, FALSE, FALSE,
7176 Zdynamite, FALSE, FALSE,
7180 Zplayer, FALSE, FALSE,
7184 ZBORDER, FALSE, FALSE,
7194 static struct Mapping_EM_to_RND_player
7203 em_player_mapping_list[] =
7207 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
7211 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
7215 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
7219 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
7223 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
7227 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
7231 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
7235 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
7239 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
7243 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
7247 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
7251 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
7255 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
7259 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
7263 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
7267 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
7271 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
7275 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
7279 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
7283 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
7287 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
7291 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
7295 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
7299 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
7303 EL_PLAYER_1, ACTION_DEFAULT, -1,
7307 EL_PLAYER_2, ACTION_DEFAULT, -1,
7311 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
7315 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
7319 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
7323 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
7327 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
7331 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
7335 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
7339 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
7343 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
7347 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
7351 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
7355 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
7359 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
7363 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
7367 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
7371 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
7375 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
7379 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
7383 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
7387 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
7391 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
7395 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
7399 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
7403 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
7407 EL_PLAYER_3, ACTION_DEFAULT, -1,
7411 EL_PLAYER_4, ACTION_DEFAULT, -1,
7420 int map_element_RND_to_EM(int element_rnd)
7422 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
7423 static boolean mapping_initialized = FALSE;
7425 if (!mapping_initialized)
7429 /* return "Xalpha_quest" for all undefined elements in mapping array */
7430 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
7431 mapping_RND_to_EM[i] = Xalpha_quest;
7433 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
7434 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
7435 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
7436 em_object_mapping_list[i].element_em;
7438 mapping_initialized = TRUE;
7441 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
7442 return mapping_RND_to_EM[element_rnd];
7444 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
7449 int map_element_EM_to_RND(int element_em)
7451 static unsigned short mapping_EM_to_RND[TILE_MAX];
7452 static boolean mapping_initialized = FALSE;
7454 if (!mapping_initialized)
7458 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
7459 for (i = 0; i < TILE_MAX; i++)
7460 mapping_EM_to_RND[i] = EL_UNKNOWN;
7462 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
7463 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
7464 em_object_mapping_list[i].element_rnd;
7466 mapping_initialized = TRUE;
7469 if (element_em >= 0 && element_em < TILE_MAX)
7470 return mapping_EM_to_RND[element_em];
7472 Error(ERR_WARN, "invalid EM level element %d", element_em);
7477 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
7479 struct LevelInfo_EM *level_em = level->native_em_level;
7480 struct LEVEL *lev = level_em->lev;
7483 for (i = 0; i < TILE_MAX; i++)
7484 lev->android_array[i] = Xblank;
7486 for (i = 0; i < level->num_android_clone_elements; i++)
7488 int element_rnd = level->android_clone_element[i];
7489 int element_em = map_element_RND_to_EM(element_rnd);
7491 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
7492 if (em_object_mapping_list[j].element_rnd == element_rnd)
7493 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
7497 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
7499 struct LevelInfo_EM *level_em = level->native_em_level;
7500 struct LEVEL *lev = level_em->lev;
7503 level->num_android_clone_elements = 0;
7505 for (i = 0; i < TILE_MAX; i++)
7507 int element_em = lev->android_array[i];
7509 boolean element_found = FALSE;
7511 if (element_em == Xblank)
7514 element_rnd = map_element_EM_to_RND(element_em);
7516 for (j = 0; j < level->num_android_clone_elements; j++)
7517 if (level->android_clone_element[j] == element_rnd)
7518 element_found = TRUE;
7522 level->android_clone_element[level->num_android_clone_elements++] =
7525 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
7530 if (level->num_android_clone_elements == 0)
7532 level->num_android_clone_elements = 1;
7533 level->android_clone_element[0] = EL_EMPTY;
7537 int map_direction_RND_to_EM(int direction)
7539 return (direction == MV_UP ? 0 :
7540 direction == MV_RIGHT ? 1 :
7541 direction == MV_DOWN ? 2 :
7542 direction == MV_LEFT ? 3 :
7546 int map_direction_EM_to_RND(int direction)
7548 return (direction == 0 ? MV_UP :
7549 direction == 1 ? MV_RIGHT :
7550 direction == 2 ? MV_DOWN :
7551 direction == 3 ? MV_LEFT :
7555 int map_element_RND_to_SP(int element_rnd)
7557 int element_sp = 0x20; /* map unknown elements to yellow "hardware" */
7559 if (element_rnd >= EL_SP_START &&
7560 element_rnd <= EL_SP_END)
7561 element_sp = element_rnd - EL_SP_START;
7562 else if (element_rnd == EL_EMPTY_SPACE)
7564 else if (element_rnd == EL_INVISIBLE_WALL)
7570 int map_element_SP_to_RND(int element_sp)
7572 int element_rnd = EL_UNKNOWN;
7574 if (element_sp >= 0x00 &&
7576 element_rnd = EL_SP_START + element_sp;
7577 else if (element_sp == 0x28)
7578 element_rnd = EL_INVISIBLE_WALL;
7583 int map_action_SP_to_RND(int action_sp)
7587 case actActive: return ACTION_ACTIVE;
7588 case actImpact: return ACTION_IMPACT;
7589 case actExploding: return ACTION_EXPLODING;
7590 case actDigging: return ACTION_DIGGING;
7591 case actSnapping: return ACTION_SNAPPING;
7592 case actCollecting: return ACTION_COLLECTING;
7593 case actPassing: return ACTION_PASSING;
7594 case actPushing: return ACTION_PUSHING;
7595 case actDropping: return ACTION_DROPPING;
7597 default: return ACTION_DEFAULT;
7601 int map_element_RND_to_MM(int element_rnd)
7603 return (element_rnd >= EL_MM_START_1 &&
7604 element_rnd <= EL_MM_END_1 ?
7605 EL_MM_START_1_NATIVE + element_rnd - EL_MM_START_1 :
7607 element_rnd >= EL_MM_START_2 &&
7608 element_rnd <= EL_MM_END_2 ?
7609 EL_MM_START_2_NATIVE + element_rnd - EL_MM_START_2 :
7611 element_rnd >= EL_CHAR_START &&
7612 element_rnd <= EL_CHAR_END ?
7613 EL_MM_CHAR_START_NATIVE + element_rnd - EL_CHAR_START :
7615 element_rnd >= EL_MM_RUNTIME_START &&
7616 element_rnd <= EL_MM_RUNTIME_END ?
7617 EL_MM_RUNTIME_START_NATIVE + element_rnd - EL_MM_RUNTIME_START :
7619 element_rnd >= EL_MM_DUMMY_START &&
7620 element_rnd <= EL_MM_DUMMY_END ?
7621 EL_MM_DUMMY_START_NATIVE + element_rnd - EL_MM_DUMMY_START :
7623 EL_MM_EMPTY_NATIVE);
7626 int map_element_MM_to_RND(int element_mm)
7628 return (element_mm == EL_MM_EMPTY_NATIVE ||
7629 element_mm == EL_DF_EMPTY_NATIVE ?
7632 element_mm >= EL_MM_START_1_NATIVE &&
7633 element_mm <= EL_MM_END_1_NATIVE ?
7634 EL_MM_START_1 + element_mm - EL_MM_START_1_NATIVE :
7636 element_mm >= EL_MM_START_2_NATIVE &&
7637 element_mm <= EL_MM_END_2_NATIVE ?
7638 EL_MM_START_2 + element_mm - EL_MM_START_2_NATIVE :
7640 element_mm >= EL_MM_CHAR_START_NATIVE &&
7641 element_mm <= EL_MM_CHAR_END_NATIVE ?
7642 EL_CHAR_START + element_mm - EL_MM_CHAR_START_NATIVE :
7644 element_mm >= EL_MM_RUNTIME_START_NATIVE &&
7645 element_mm <= EL_MM_RUNTIME_END_NATIVE ?
7646 EL_MM_RUNTIME_START + element_mm - EL_MM_RUNTIME_START_NATIVE :
7648 element_mm >= EL_MM_DUMMY_START_NATIVE &&
7649 element_mm <= EL_MM_DUMMY_END_NATIVE ?
7650 EL_MM_DUMMY_START + element_mm - EL_MM_DUMMY_START_NATIVE :
7655 int map_action_MM_to_RND(int action_mm)
7657 /* all MM actions are defined to exactly match their RND counterparts */
7661 int map_sound_MM_to_RND(int sound_mm)
7665 case SND_MM_GAME_LEVELTIME_CHARGING:
7666 return SND_GAME_LEVELTIME_CHARGING;
7668 case SND_MM_GAME_HEALTH_CHARGING:
7669 return SND_GAME_HEALTH_CHARGING;
7672 return SND_UNDEFINED;
7676 int map_mm_wall_element(int element)
7678 return (element >= EL_MM_STEEL_WALL_START &&
7679 element <= EL_MM_STEEL_WALL_END ?
7682 element >= EL_MM_WOODEN_WALL_START &&
7683 element <= EL_MM_WOODEN_WALL_END ?
7686 element >= EL_MM_ICE_WALL_START &&
7687 element <= EL_MM_ICE_WALL_END ?
7690 element >= EL_MM_AMOEBA_WALL_START &&
7691 element <= EL_MM_AMOEBA_WALL_END ?
7694 element >= EL_DF_STEEL_WALL_START &&
7695 element <= EL_DF_STEEL_WALL_END ?
7698 element >= EL_DF_WOODEN_WALL_START &&
7699 element <= EL_DF_WOODEN_WALL_END ?
7705 int map_mm_wall_element_editor(int element)
7709 case EL_MM_STEEL_WALL: return EL_MM_STEEL_WALL_START;
7710 case EL_MM_WOODEN_WALL: return EL_MM_WOODEN_WALL_START;
7711 case EL_MM_ICE_WALL: return EL_MM_ICE_WALL_START;
7712 case EL_MM_AMOEBA_WALL: return EL_MM_AMOEBA_WALL_START;
7713 case EL_DF_STEEL_WALL: return EL_DF_STEEL_WALL_START;
7714 case EL_DF_WOODEN_WALL: return EL_DF_WOODEN_WALL_START;
7716 default: return element;
7720 int get_next_element(int element)
7724 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
7725 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
7726 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
7727 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
7728 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
7729 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
7730 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
7731 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
7732 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
7733 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
7734 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
7736 default: return element;
7740 int el2img_mm(int element_mm)
7742 return el2img(map_element_MM_to_RND(element_mm));
7745 int el_act_dir2img(int element, int action, int direction)
7747 element = GFX_ELEMENT(element);
7748 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
7750 /* direction_graphic[][] == graphic[] for undefined direction graphics */
7751 return element_info[element].direction_graphic[action][direction];
7754 static int el_act_dir2crm(int element, int action, int direction)
7756 element = GFX_ELEMENT(element);
7757 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
7759 /* direction_graphic[][] == graphic[] for undefined direction graphics */
7760 return element_info[element].direction_crumbled[action][direction];
7763 int el_act2img(int element, int action)
7765 element = GFX_ELEMENT(element);
7767 return element_info[element].graphic[action];
7770 int el_act2crm(int element, int action)
7772 element = GFX_ELEMENT(element);
7774 return element_info[element].crumbled[action];
7777 int el_dir2img(int element, int direction)
7779 element = GFX_ELEMENT(element);
7781 return el_act_dir2img(element, ACTION_DEFAULT, direction);
7784 int el2baseimg(int element)
7786 return element_info[element].graphic[ACTION_DEFAULT];
7789 int el2img(int element)
7791 element = GFX_ELEMENT(element);
7793 return element_info[element].graphic[ACTION_DEFAULT];
7796 int el2edimg(int element)
7798 element = GFX_ELEMENT(element);
7800 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
7803 int el2preimg(int element)
7805 element = GFX_ELEMENT(element);
7807 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
7810 int el2panelimg(int element)
7812 element = GFX_ELEMENT(element);
7814 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL];
7817 int font2baseimg(int font_nr)
7819 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
7822 int getBeltNrFromBeltElement(int element)
7824 return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
7825 element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
7826 element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
7829 int getBeltNrFromBeltActiveElement(int element)
7831 return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
7832 element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
7833 element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
7836 int getBeltNrFromBeltSwitchElement(int element)
7838 return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
7839 element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
7840 element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
7843 int getBeltDirNrFromBeltElement(int element)
7845 static int belt_base_element[4] =
7847 EL_CONVEYOR_BELT_1_LEFT,
7848 EL_CONVEYOR_BELT_2_LEFT,
7849 EL_CONVEYOR_BELT_3_LEFT,
7850 EL_CONVEYOR_BELT_4_LEFT
7853 int belt_nr = getBeltNrFromBeltElement(element);
7854 int belt_dir_nr = element - belt_base_element[belt_nr];
7856 return (belt_dir_nr % 3);
7859 int getBeltDirNrFromBeltSwitchElement(int element)
7861 static int belt_base_element[4] =
7863 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
7864 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
7865 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
7866 EL_CONVEYOR_BELT_4_SWITCH_LEFT
7869 int belt_nr = getBeltNrFromBeltSwitchElement(element);
7870 int belt_dir_nr = element - belt_base_element[belt_nr];
7872 return (belt_dir_nr % 3);
7875 int getBeltDirFromBeltElement(int element)
7877 static int belt_move_dir[3] =
7884 int belt_dir_nr = getBeltDirNrFromBeltElement(element);
7886 return belt_move_dir[belt_dir_nr];
7889 int getBeltDirFromBeltSwitchElement(int element)
7891 static int belt_move_dir[3] =
7898 int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
7900 return belt_move_dir[belt_dir_nr];
7903 int getBeltElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
7905 static int belt_base_element[4] =
7907 EL_CONVEYOR_BELT_1_LEFT,
7908 EL_CONVEYOR_BELT_2_LEFT,
7909 EL_CONVEYOR_BELT_3_LEFT,
7910 EL_CONVEYOR_BELT_4_LEFT
7913 return belt_base_element[belt_nr] + belt_dir_nr;
7916 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
7918 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
7920 return getBeltElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
7923 int getBeltSwitchElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
7925 static int belt_base_element[4] =
7927 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
7928 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
7929 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
7930 EL_CONVEYOR_BELT_4_SWITCH_LEFT
7933 return belt_base_element[belt_nr] + belt_dir_nr;
7936 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
7938 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
7940 return getBeltSwitchElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
7943 boolean getTeamMode_EM()
7945 return game.team_mode;
7948 int getGameFrameDelay_EM(int native_em_game_frame_delay)
7950 int game_frame_delay_value;
7952 game_frame_delay_value =
7953 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
7954 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
7957 if (tape.playing && tape.warp_forward && !tape.pausing)
7958 game_frame_delay_value = 0;
7960 return game_frame_delay_value;
7963 unsigned int InitRND(int seed)
7965 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
7966 return InitEngineRandom_EM(seed);
7967 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
7968 return InitEngineRandom_SP(seed);
7969 else if (level.game_engine_type == GAME_ENGINE_TYPE_MM)
7970 return InitEngineRandom_MM(seed);
7972 return InitEngineRandom_RND(seed);
7975 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
7976 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
7978 inline static int get_effective_element_EM(int tile, int frame_em)
7980 int element = object_mapping[tile].element_rnd;
7981 int action = object_mapping[tile].action;
7982 boolean is_backside = object_mapping[tile].is_backside;
7983 boolean action_removing = (action == ACTION_DIGGING ||
7984 action == ACTION_SNAPPING ||
7985 action == ACTION_COLLECTING);
7991 case Yacid_splash_eB:
7992 case Yacid_splash_wB:
7993 return (frame_em > 5 ? EL_EMPTY : element);
7999 else /* frame_em == 7 */
8003 case Yacid_splash_eB:
8004 case Yacid_splash_wB:
8007 case Yemerald_stone:
8010 case Ydiamond_stone:
8014 case Xdrip_stretchB:
8033 case Xsand_stonein_1:
8034 case Xsand_stonein_2:
8035 case Xsand_stonein_3:
8036 case Xsand_stonein_4:
8040 return (is_backside || action_removing ? EL_EMPTY : element);
8045 inline static boolean check_linear_animation_EM(int tile)
8049 case Xsand_stonesand_1:
8050 case Xsand_stonesand_quickout_1:
8051 case Xsand_sandstone_1:
8052 case Xsand_stonein_1:
8053 case Xsand_stoneout_1:
8072 case Yacid_splash_eB:
8073 case Yacid_splash_wB:
8074 case Yemerald_stone:
8081 inline static void set_crumbled_graphics_EM(struct GraphicInfo_EM *g_em,
8082 boolean has_crumbled_graphics,
8083 int crumbled, int sync_frame)
8085 /* if element can be crumbled, but certain action graphics are just empty
8086 space (like instantly snapping sand to empty space in 1 frame), do not
8087 treat these empty space graphics as crumbled graphics in EMC engine */
8088 if (crumbled == IMG_EMPTY_SPACE)
8089 has_crumbled_graphics = FALSE;
8091 if (has_crumbled_graphics)
8093 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
8094 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
8095 g_crumbled->anim_delay,
8096 g_crumbled->anim_mode,
8097 g_crumbled->anim_start_frame,
8100 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
8101 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
8103 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
8104 g_em->crumbled_tile_size = graphic_info[crumbled].tile_size;
8106 g_em->has_crumbled_graphics = TRUE;
8110 g_em->crumbled_bitmap = NULL;
8111 g_em->crumbled_src_x = 0;
8112 g_em->crumbled_src_y = 0;
8113 g_em->crumbled_border_size = 0;
8114 g_em->crumbled_tile_size = 0;
8116 g_em->has_crumbled_graphics = FALSE;
8120 void ResetGfxAnimation_EM(int x, int y, int tile)
8125 void SetGfxAnimation_EM(struct GraphicInfo_EM *g_em,
8126 int tile, int frame_em, int x, int y)
8128 int action = object_mapping[tile].action;
8129 int direction = object_mapping[tile].direction;
8130 int effective_element = get_effective_element_EM(tile, frame_em);
8131 int graphic = (direction == MV_NONE ?
8132 el_act2img(effective_element, action) :
8133 el_act_dir2img(effective_element, action, direction));
8134 struct GraphicInfo *g = &graphic_info[graphic];
8136 boolean action_removing = (action == ACTION_DIGGING ||
8137 action == ACTION_SNAPPING ||
8138 action == ACTION_COLLECTING);
8139 boolean action_moving = (action == ACTION_FALLING ||
8140 action == ACTION_MOVING ||
8141 action == ACTION_PUSHING ||
8142 action == ACTION_EATING ||
8143 action == ACTION_FILLING ||
8144 action == ACTION_EMPTYING);
8145 boolean action_falling = (action == ACTION_FALLING ||
8146 action == ACTION_FILLING ||
8147 action == ACTION_EMPTYING);
8149 /* special case: graphic uses "2nd movement tile" and has defined
8150 7 frames for movement animation (or less) => use default graphic
8151 for last (8th) frame which ends the movement animation */
8152 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
8154 action = ACTION_DEFAULT; /* (keep action_* unchanged for now) */
8155 graphic = (direction == MV_NONE ?
8156 el_act2img(effective_element, action) :
8157 el_act_dir2img(effective_element, action, direction));
8159 g = &graphic_info[graphic];
8162 if ((action_removing || check_linear_animation_EM(tile)) && frame_em == 0)
8166 else if (action_moving)
8168 boolean is_backside = object_mapping[tile].is_backside;
8172 int direction = object_mapping[tile].direction;
8173 int move_dir = (action_falling ? MV_DOWN : direction);
8178 /* !!! TEST !!! NEW !!! DOES NOT WORK RIGHT YET !!! */
8179 if (g->double_movement && frame_em == 0)
8183 if (move_dir == MV_LEFT)
8184 GfxFrame[x - 1][y] = GfxFrame[x][y];
8185 else if (move_dir == MV_RIGHT)
8186 GfxFrame[x + 1][y] = GfxFrame[x][y];
8187 else if (move_dir == MV_UP)
8188 GfxFrame[x][y - 1] = GfxFrame[x][y];
8189 else if (move_dir == MV_DOWN)
8190 GfxFrame[x][y + 1] = GfxFrame[x][y];
8197 /* special case: animation for Xsand_stonesand_quickout_1/2 twice as fast */
8198 if (tile == Xsand_stonesand_quickout_1 ||
8199 tile == Xsand_stonesand_quickout_2)
8203 if (graphic_info[graphic].anim_global_sync)
8204 sync_frame = FrameCounter;
8205 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
8206 sync_frame = GfxFrame[x][y];
8208 sync_frame = 0; /* playfield border (pseudo steel) */
8210 SetRandomAnimationValue(x, y);
8212 int frame = getAnimationFrame(g->anim_frames,
8215 g->anim_start_frame,
8218 g_em->unique_identifier =
8219 (graphic << 16) | ((frame % 8) << 12) | (g_em->width << 6) | g_em->height;
8222 void getGraphicSourceObjectExt_EM(struct GraphicInfo_EM *g_em,
8223 int tile, int frame_em, int x, int y)
8225 int action = object_mapping[tile].action;
8226 int direction = object_mapping[tile].direction;
8227 boolean is_backside = object_mapping[tile].is_backside;
8228 int effective_element = get_effective_element_EM(tile, frame_em);
8229 int effective_action = action;
8230 int graphic = (direction == MV_NONE ?
8231 el_act2img(effective_element, effective_action) :
8232 el_act_dir2img(effective_element, effective_action,
8234 int crumbled = (direction == MV_NONE ?
8235 el_act2crm(effective_element, effective_action) :
8236 el_act_dir2crm(effective_element, effective_action,
8238 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
8239 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
8240 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
8241 struct GraphicInfo *g = &graphic_info[graphic];
8244 /* special case: graphic uses "2nd movement tile" and has defined
8245 7 frames for movement animation (or less) => use default graphic
8246 for last (8th) frame which ends the movement animation */
8247 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
8249 effective_action = ACTION_DEFAULT;
8250 graphic = (direction == MV_NONE ?
8251 el_act2img(effective_element, effective_action) :
8252 el_act_dir2img(effective_element, effective_action,
8254 crumbled = (direction == MV_NONE ?
8255 el_act2crm(effective_element, effective_action) :
8256 el_act_dir2crm(effective_element, effective_action,
8259 g = &graphic_info[graphic];
8262 if (graphic_info[graphic].anim_global_sync)
8263 sync_frame = FrameCounter;
8264 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
8265 sync_frame = GfxFrame[x][y];
8267 sync_frame = 0; /* playfield border (pseudo steel) */
8269 SetRandomAnimationValue(x, y);
8271 int frame = getAnimationFrame(g->anim_frames,
8274 g->anim_start_frame,
8277 getGraphicSourceExt(graphic, frame, &g_em->bitmap, &g_em->src_x, &g_em->src_y,
8278 g->double_movement && is_backside);
8280 /* (updating the "crumbled" graphic definitions is probably not really needed,
8281 as animations for crumbled graphics can't be longer than one EMC cycle) */
8282 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
8286 void getGraphicSourcePlayerExt_EM(struct GraphicInfo_EM *g_em,
8287 int player_nr, int anim, int frame_em)
8289 int element = player_mapping[player_nr][anim].element_rnd;
8290 int action = player_mapping[player_nr][anim].action;
8291 int direction = player_mapping[player_nr][anim].direction;
8292 int graphic = (direction == MV_NONE ?
8293 el_act2img(element, action) :
8294 el_act_dir2img(element, action, direction));
8295 struct GraphicInfo *g = &graphic_info[graphic];
8298 InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
8300 stored_player[player_nr].StepFrame = frame_em;
8302 sync_frame = stored_player[player_nr].Frame;
8304 int frame = getAnimationFrame(g->anim_frames,
8307 g->anim_start_frame,
8310 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
8311 &g_em->src_x, &g_em->src_y, FALSE);
8314 void InitGraphicInfo_EM(void)
8319 int num_em_gfx_errors = 0;
8321 if (graphic_info_em_object[0][0].bitmap == NULL)
8323 /* EM graphics not yet initialized in em_open_all() */
8328 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
8331 /* always start with reliable default values */
8332 for (i = 0; i < TILE_MAX; i++)
8334 object_mapping[i].element_rnd = EL_UNKNOWN;
8335 object_mapping[i].is_backside = FALSE;
8336 object_mapping[i].action = ACTION_DEFAULT;
8337 object_mapping[i].direction = MV_NONE;
8340 /* always start with reliable default values */
8341 for (p = 0; p < MAX_PLAYERS; p++)
8343 for (i = 0; i < SPR_MAX; i++)
8345 player_mapping[p][i].element_rnd = EL_UNKNOWN;
8346 player_mapping[p][i].action = ACTION_DEFAULT;
8347 player_mapping[p][i].direction = MV_NONE;
8351 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
8353 int e = em_object_mapping_list[i].element_em;
8355 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
8356 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
8358 if (em_object_mapping_list[i].action != -1)
8359 object_mapping[e].action = em_object_mapping_list[i].action;
8361 if (em_object_mapping_list[i].direction != -1)
8362 object_mapping[e].direction =
8363 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
8366 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
8368 int a = em_player_mapping_list[i].action_em;
8369 int p = em_player_mapping_list[i].player_nr;
8371 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
8373 if (em_player_mapping_list[i].action != -1)
8374 player_mapping[p][a].action = em_player_mapping_list[i].action;
8376 if (em_player_mapping_list[i].direction != -1)
8377 player_mapping[p][a].direction =
8378 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
8381 for (i = 0; i < TILE_MAX; i++)
8383 int element = object_mapping[i].element_rnd;
8384 int action = object_mapping[i].action;
8385 int direction = object_mapping[i].direction;
8386 boolean is_backside = object_mapping[i].is_backside;
8387 boolean action_exploding = ((action == ACTION_EXPLODING ||
8388 action == ACTION_SMASHED_BY_ROCK ||
8389 action == ACTION_SMASHED_BY_SPRING) &&
8390 element != EL_DIAMOND);
8391 boolean action_active = (action == ACTION_ACTIVE);
8392 boolean action_other = (action == ACTION_OTHER);
8394 for (j = 0; j < 8; j++)
8396 int effective_element = get_effective_element_EM(i, j);
8397 int effective_action = (j < 7 ? action :
8398 i == Xdrip_stretch ? action :
8399 i == Xdrip_stretchB ? action :
8400 i == Ydrip_s1 ? action :
8401 i == Ydrip_s1B ? action :
8402 i == Xball_1B ? action :
8403 i == Xball_2 ? action :
8404 i == Xball_2B ? action :
8405 i == Yball_eat ? action :
8406 i == Ykey_1_eat ? action :
8407 i == Ykey_2_eat ? action :
8408 i == Ykey_3_eat ? action :
8409 i == Ykey_4_eat ? action :
8410 i == Ykey_5_eat ? action :
8411 i == Ykey_6_eat ? action :
8412 i == Ykey_7_eat ? action :
8413 i == Ykey_8_eat ? action :
8414 i == Ylenses_eat ? action :
8415 i == Ymagnify_eat ? action :
8416 i == Ygrass_eat ? action :
8417 i == Ydirt_eat ? action :
8418 i == Xsand_stonein_1 ? action :
8419 i == Xsand_stonein_2 ? action :
8420 i == Xsand_stonein_3 ? action :
8421 i == Xsand_stonein_4 ? action :
8422 i == Xsand_stoneout_1 ? action :
8423 i == Xsand_stoneout_2 ? action :
8424 i == Xboom_android ? ACTION_EXPLODING :
8425 action_exploding ? ACTION_EXPLODING :
8426 action_active ? action :
8427 action_other ? action :
8429 int graphic = (el_act_dir2img(effective_element, effective_action,
8431 int crumbled = (el_act_dir2crm(effective_element, effective_action,
8433 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
8434 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
8435 boolean has_action_graphics = (graphic != base_graphic);
8436 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
8437 struct GraphicInfo *g = &graphic_info[graphic];
8438 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
8441 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
8442 boolean special_animation = (action != ACTION_DEFAULT &&
8443 g->anim_frames == 3 &&
8444 g->anim_delay == 2 &&
8445 g->anim_mode & ANIM_LINEAR);
8446 int sync_frame = (i == Xdrip_stretch ? 7 :
8447 i == Xdrip_stretchB ? 7 :
8448 i == Ydrip_s2 ? j + 8 :
8449 i == Ydrip_s2B ? j + 8 :
8458 i == Xfake_acid_1 ? 0 :
8459 i == Xfake_acid_2 ? 10 :
8460 i == Xfake_acid_3 ? 20 :
8461 i == Xfake_acid_4 ? 30 :
8462 i == Xfake_acid_5 ? 40 :
8463 i == Xfake_acid_6 ? 50 :
8464 i == Xfake_acid_7 ? 60 :
8465 i == Xfake_acid_8 ? 70 :
8467 i == Xball_2B ? j + 8 :
8468 i == Yball_eat ? j + 1 :
8469 i == Ykey_1_eat ? j + 1 :
8470 i == Ykey_2_eat ? j + 1 :
8471 i == Ykey_3_eat ? j + 1 :
8472 i == Ykey_4_eat ? j + 1 :
8473 i == Ykey_5_eat ? j + 1 :
8474 i == Ykey_6_eat ? j + 1 :
8475 i == Ykey_7_eat ? j + 1 :
8476 i == Ykey_8_eat ? j + 1 :
8477 i == Ylenses_eat ? j + 1 :
8478 i == Ymagnify_eat ? j + 1 :
8479 i == Ygrass_eat ? j + 1 :
8480 i == Ydirt_eat ? j + 1 :
8481 i == Xamoeba_1 ? 0 :
8482 i == Xamoeba_2 ? 1 :
8483 i == Xamoeba_3 ? 2 :
8484 i == Xamoeba_4 ? 3 :
8485 i == Xamoeba_5 ? 0 :
8486 i == Xamoeba_6 ? 1 :
8487 i == Xamoeba_7 ? 2 :
8488 i == Xamoeba_8 ? 3 :
8489 i == Xexit_2 ? j + 8 :
8490 i == Xexit_3 ? j + 16 :
8491 i == Xdynamite_1 ? 0 :
8492 i == Xdynamite_2 ? 8 :
8493 i == Xdynamite_3 ? 16 :
8494 i == Xdynamite_4 ? 24 :
8495 i == Xsand_stonein_1 ? j + 1 :
8496 i == Xsand_stonein_2 ? j + 9 :
8497 i == Xsand_stonein_3 ? j + 17 :
8498 i == Xsand_stonein_4 ? j + 25 :
8499 i == Xsand_stoneout_1 && j == 0 ? 0 :
8500 i == Xsand_stoneout_1 && j == 1 ? 0 :
8501 i == Xsand_stoneout_1 && j == 2 ? 1 :
8502 i == Xsand_stoneout_1 && j == 3 ? 2 :
8503 i == Xsand_stoneout_1 && j == 4 ? 2 :
8504 i == Xsand_stoneout_1 && j == 5 ? 3 :
8505 i == Xsand_stoneout_1 && j == 6 ? 4 :
8506 i == Xsand_stoneout_1 && j == 7 ? 4 :
8507 i == Xsand_stoneout_2 && j == 0 ? 5 :
8508 i == Xsand_stoneout_2 && j == 1 ? 6 :
8509 i == Xsand_stoneout_2 && j == 2 ? 7 :
8510 i == Xsand_stoneout_2 && j == 3 ? 8 :
8511 i == Xsand_stoneout_2 && j == 4 ? 9 :
8512 i == Xsand_stoneout_2 && j == 5 ? 11 :
8513 i == Xsand_stoneout_2 && j == 6 ? 13 :
8514 i == Xsand_stoneout_2 && j == 7 ? 15 :
8515 i == Xboom_bug && j == 1 ? 2 :
8516 i == Xboom_bug && j == 2 ? 2 :
8517 i == Xboom_bug && j == 3 ? 4 :
8518 i == Xboom_bug && j == 4 ? 4 :
8519 i == Xboom_bug && j == 5 ? 2 :
8520 i == Xboom_bug && j == 6 ? 2 :
8521 i == Xboom_bug && j == 7 ? 0 :
8522 i == Xboom_bomb && j == 1 ? 2 :
8523 i == Xboom_bomb && j == 2 ? 2 :
8524 i == Xboom_bomb && j == 3 ? 4 :
8525 i == Xboom_bomb && j == 4 ? 4 :
8526 i == Xboom_bomb && j == 5 ? 2 :
8527 i == Xboom_bomb && j == 6 ? 2 :
8528 i == Xboom_bomb && j == 7 ? 0 :
8529 i == Xboom_android && j == 7 ? 6 :
8530 i == Xboom_1 && j == 1 ? 2 :
8531 i == Xboom_1 && j == 2 ? 2 :
8532 i == Xboom_1 && j == 3 ? 4 :
8533 i == Xboom_1 && j == 4 ? 4 :
8534 i == Xboom_1 && j == 5 ? 6 :
8535 i == Xboom_1 && j == 6 ? 6 :
8536 i == Xboom_1 && j == 7 ? 8 :
8537 i == Xboom_2 && j == 0 ? 8 :
8538 i == Xboom_2 && j == 1 ? 8 :
8539 i == Xboom_2 && j == 2 ? 10 :
8540 i == Xboom_2 && j == 3 ? 10 :
8541 i == Xboom_2 && j == 4 ? 10 :
8542 i == Xboom_2 && j == 5 ? 12 :
8543 i == Xboom_2 && j == 6 ? 12 :
8544 i == Xboom_2 && j == 7 ? 12 :
8545 special_animation && j == 4 ? 3 :
8546 effective_action != action ? 0 :
8550 Bitmap *debug_bitmap = g_em->bitmap;
8551 int debug_src_x = g_em->src_x;
8552 int debug_src_y = g_em->src_y;
8555 int frame = getAnimationFrame(g->anim_frames,
8558 g->anim_start_frame,
8561 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
8562 g->double_movement && is_backside);
8564 g_em->bitmap = src_bitmap;
8565 g_em->src_x = src_x;
8566 g_em->src_y = src_y;
8567 g_em->src_offset_x = 0;
8568 g_em->src_offset_y = 0;
8569 g_em->dst_offset_x = 0;
8570 g_em->dst_offset_y = 0;
8571 g_em->width = TILEX;
8572 g_em->height = TILEY;
8574 g_em->preserve_background = FALSE;
8576 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
8579 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
8580 effective_action == ACTION_MOVING ||
8581 effective_action == ACTION_PUSHING ||
8582 effective_action == ACTION_EATING)) ||
8583 (!has_action_graphics && (effective_action == ACTION_FILLING ||
8584 effective_action == ACTION_EMPTYING)))
8587 (effective_action == ACTION_FALLING ||
8588 effective_action == ACTION_FILLING ||
8589 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
8590 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
8591 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
8592 int num_steps = (i == Ydrip_s1 ? 16 :
8593 i == Ydrip_s1B ? 16 :
8594 i == Ydrip_s2 ? 16 :
8595 i == Ydrip_s2B ? 16 :
8596 i == Xsand_stonein_1 ? 32 :
8597 i == Xsand_stonein_2 ? 32 :
8598 i == Xsand_stonein_3 ? 32 :
8599 i == Xsand_stonein_4 ? 32 :
8600 i == Xsand_stoneout_1 ? 16 :
8601 i == Xsand_stoneout_2 ? 16 : 8);
8602 int cx = ABS(dx) * (TILEX / num_steps);
8603 int cy = ABS(dy) * (TILEY / num_steps);
8604 int step_frame = (i == Ydrip_s2 ? j + 8 :
8605 i == Ydrip_s2B ? j + 8 :
8606 i == Xsand_stonein_2 ? j + 8 :
8607 i == Xsand_stonein_3 ? j + 16 :
8608 i == Xsand_stonein_4 ? j + 24 :
8609 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
8610 int step = (is_backside ? step_frame : num_steps - step_frame);
8612 if (is_backside) /* tile where movement starts */
8614 if (dx < 0 || dy < 0)
8616 g_em->src_offset_x = cx * step;
8617 g_em->src_offset_y = cy * step;
8621 g_em->dst_offset_x = cx * step;
8622 g_em->dst_offset_y = cy * step;
8625 else /* tile where movement ends */
8627 if (dx < 0 || dy < 0)
8629 g_em->dst_offset_x = cx * step;
8630 g_em->dst_offset_y = cy * step;
8634 g_em->src_offset_x = cx * step;
8635 g_em->src_offset_y = cy * step;
8639 g_em->width = TILEX - cx * step;
8640 g_em->height = TILEY - cy * step;
8643 /* create unique graphic identifier to decide if tile must be redrawn */
8644 /* bit 31 - 16 (16 bit): EM style graphic
8645 bit 15 - 12 ( 4 bit): EM style frame
8646 bit 11 - 6 ( 6 bit): graphic width
8647 bit 5 - 0 ( 6 bit): graphic height */
8648 g_em->unique_identifier =
8649 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
8653 /* skip check for EMC elements not contained in original EMC artwork */
8654 if (element == EL_EMC_FAKE_ACID)
8657 if (g_em->bitmap != debug_bitmap ||
8658 g_em->src_x != debug_src_x ||
8659 g_em->src_y != debug_src_y ||
8660 g_em->src_offset_x != 0 ||
8661 g_em->src_offset_y != 0 ||
8662 g_em->dst_offset_x != 0 ||
8663 g_em->dst_offset_y != 0 ||
8664 g_em->width != TILEX ||
8665 g_em->height != TILEY)
8667 static int last_i = -1;
8675 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
8676 i, element, element_info[element].token_name,
8677 element_action_info[effective_action].suffix, direction);
8679 if (element != effective_element)
8680 printf(" [%d ('%s')]",
8682 element_info[effective_element].token_name);
8686 if (g_em->bitmap != debug_bitmap)
8687 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
8688 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
8690 if (g_em->src_x != debug_src_x ||
8691 g_em->src_y != debug_src_y)
8692 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
8693 j, (is_backside ? 'B' : 'F'),
8694 g_em->src_x, g_em->src_y,
8695 g_em->src_x / 32, g_em->src_y / 32,
8696 debug_src_x, debug_src_y,
8697 debug_src_x / 32, debug_src_y / 32);
8699 if (g_em->src_offset_x != 0 ||
8700 g_em->src_offset_y != 0 ||
8701 g_em->dst_offset_x != 0 ||
8702 g_em->dst_offset_y != 0)
8703 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
8705 g_em->src_offset_x, g_em->src_offset_y,
8706 g_em->dst_offset_x, g_em->dst_offset_y);
8708 if (g_em->width != TILEX ||
8709 g_em->height != TILEY)
8710 printf(" %d (%d): size %d,%d should be %d,%d\n",
8712 g_em->width, g_em->height, TILEX, TILEY);
8714 num_em_gfx_errors++;
8721 for (i = 0; i < TILE_MAX; i++)
8723 for (j = 0; j < 8; j++)
8725 int element = object_mapping[i].element_rnd;
8726 int action = object_mapping[i].action;
8727 int direction = object_mapping[i].direction;
8728 boolean is_backside = object_mapping[i].is_backside;
8729 int graphic_action = el_act_dir2img(element, action, direction);
8730 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
8732 if ((action == ACTION_SMASHED_BY_ROCK ||
8733 action == ACTION_SMASHED_BY_SPRING ||
8734 action == ACTION_EATING) &&
8735 graphic_action == graphic_default)
8737 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
8738 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
8739 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
8740 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
8743 /* no separate animation for "smashed by rock" -- use rock instead */
8744 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
8745 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
8747 g_em->bitmap = g_xx->bitmap;
8748 g_em->src_x = g_xx->src_x;
8749 g_em->src_y = g_xx->src_y;
8750 g_em->src_offset_x = g_xx->src_offset_x;
8751 g_em->src_offset_y = g_xx->src_offset_y;
8752 g_em->dst_offset_x = g_xx->dst_offset_x;
8753 g_em->dst_offset_y = g_xx->dst_offset_y;
8754 g_em->width = g_xx->width;
8755 g_em->height = g_xx->height;
8756 g_em->unique_identifier = g_xx->unique_identifier;
8759 g_em->preserve_background = TRUE;
8764 for (p = 0; p < MAX_PLAYERS; p++)
8766 for (i = 0; i < SPR_MAX; i++)
8768 int element = player_mapping[p][i].element_rnd;
8769 int action = player_mapping[p][i].action;
8770 int direction = player_mapping[p][i].direction;
8772 for (j = 0; j < 8; j++)
8774 int effective_element = element;
8775 int effective_action = action;
8776 int graphic = (direction == MV_NONE ?
8777 el_act2img(effective_element, effective_action) :
8778 el_act_dir2img(effective_element, effective_action,
8780 struct GraphicInfo *g = &graphic_info[graphic];
8781 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
8787 Bitmap *debug_bitmap = g_em->bitmap;
8788 int debug_src_x = g_em->src_x;
8789 int debug_src_y = g_em->src_y;
8792 int frame = getAnimationFrame(g->anim_frames,
8795 g->anim_start_frame,
8798 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
8800 g_em->bitmap = src_bitmap;
8801 g_em->src_x = src_x;
8802 g_em->src_y = src_y;
8803 g_em->src_offset_x = 0;
8804 g_em->src_offset_y = 0;
8805 g_em->dst_offset_x = 0;
8806 g_em->dst_offset_y = 0;
8807 g_em->width = TILEX;
8808 g_em->height = TILEY;
8812 /* skip check for EMC elements not contained in original EMC artwork */
8813 if (element == EL_PLAYER_3 ||
8814 element == EL_PLAYER_4)
8817 if (g_em->bitmap != debug_bitmap ||
8818 g_em->src_x != debug_src_x ||
8819 g_em->src_y != debug_src_y)
8821 static int last_i = -1;
8829 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
8830 p, i, element, element_info[element].token_name,
8831 element_action_info[effective_action].suffix, direction);
8833 if (element != effective_element)
8834 printf(" [%d ('%s')]",
8836 element_info[effective_element].token_name);
8840 if (g_em->bitmap != debug_bitmap)
8841 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
8842 j, (int)(g_em->bitmap), (int)(debug_bitmap));
8844 if (g_em->src_x != debug_src_x ||
8845 g_em->src_y != debug_src_y)
8846 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
8848 g_em->src_x, g_em->src_y,
8849 g_em->src_x / 32, g_em->src_y / 32,
8850 debug_src_x, debug_src_y,
8851 debug_src_x / 32, debug_src_y / 32);
8853 num_em_gfx_errors++;
8863 printf("::: [%d errors found]\n", num_em_gfx_errors);
8869 void CheckSaveEngineSnapshot_EM(byte action[MAX_PLAYERS], int frame,
8870 boolean any_player_moving,
8871 boolean any_player_snapping,
8872 boolean any_player_dropping)
8874 if (frame == 0 && !any_player_dropping)
8876 if (!local_player->was_waiting)
8878 if (!CheckSaveEngineSnapshotToList())
8881 local_player->was_waiting = TRUE;
8884 else if (any_player_moving || any_player_snapping || any_player_dropping)
8886 local_player->was_waiting = FALSE;
8890 void CheckSaveEngineSnapshot_SP(boolean murphy_is_waiting,
8891 boolean murphy_is_dropping)
8893 if (murphy_is_waiting)
8895 if (!local_player->was_waiting)
8897 if (!CheckSaveEngineSnapshotToList())
8900 local_player->was_waiting = TRUE;
8905 local_player->was_waiting = FALSE;
8909 void CheckSaveEngineSnapshot_MM(boolean element_clicked,
8910 boolean button_released)
8912 if (button_released)
8914 if (game.snapshot.mode == SNAPSHOT_MODE_EVERY_MOVE)
8915 CheckSaveEngineSnapshotToList();
8917 else if (element_clicked)
8919 if (game.snapshot.mode != SNAPSHOT_MODE_EVERY_MOVE)
8920 CheckSaveEngineSnapshotToList();
8922 game.snapshot.changed_action = TRUE;
8926 void CheckSingleStepMode_EM(byte action[MAX_PLAYERS], int frame,
8927 boolean any_player_moving,
8928 boolean any_player_snapping,
8929 boolean any_player_dropping)
8931 if (tape.single_step && tape.recording && !tape.pausing)
8932 if (frame == 0 && !any_player_dropping)
8933 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
8935 CheckSaveEngineSnapshot_EM(action, frame, any_player_moving,
8936 any_player_snapping, any_player_dropping);
8939 void CheckSingleStepMode_SP(boolean murphy_is_waiting,
8940 boolean murphy_is_dropping)
8942 boolean murphy_starts_dropping = FALSE;
8945 for (i = 0; i < MAX_PLAYERS; i++)
8946 if (stored_player[i].force_dropping)
8947 murphy_starts_dropping = TRUE;
8949 if (tape.single_step && tape.recording && !tape.pausing)
8950 if (murphy_is_waiting && !murphy_starts_dropping)
8951 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
8953 CheckSaveEngineSnapshot_SP(murphy_is_waiting, murphy_is_dropping);
8956 void CheckSingleStepMode_MM(boolean element_clicked,
8957 boolean button_released)
8959 if (tape.single_step && tape.recording && !tape.pausing)
8960 if (button_released)
8961 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
8963 CheckSaveEngineSnapshot_MM(element_clicked, button_released);
8966 void getGraphicSource_SP(struct GraphicInfo_SP *g_sp,
8967 int graphic, int sync_frame, int x, int y)
8969 int frame = getGraphicAnimationFrame(graphic, sync_frame);
8971 getGraphicSource(graphic, frame, &g_sp->bitmap, &g_sp->src_x, &g_sp->src_y);
8974 boolean isNextAnimationFrame_SP(int graphic, int sync_frame)
8976 return (IS_NEXT_FRAME(sync_frame, graphic));
8979 int getGraphicInfo_Delay(int graphic)
8981 return graphic_info[graphic].anim_delay;
8984 void PlayMenuSoundExt(int sound)
8986 if (sound == SND_UNDEFINED)
8989 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8990 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8993 if (IS_LOOP_SOUND(sound))
8994 PlaySoundLoop(sound);
8999 void PlayMenuSound()
9001 PlayMenuSoundExt(menu.sound[game_status]);
9004 void PlayMenuSoundStereo(int sound, int stereo_position)
9006 if (sound == SND_UNDEFINED)
9009 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
9010 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
9013 if (IS_LOOP_SOUND(sound))
9014 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
9016 PlaySoundStereo(sound, stereo_position);
9019 void PlayMenuSoundIfLoopExt(int sound)
9021 if (sound == SND_UNDEFINED)
9024 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
9025 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
9028 if (IS_LOOP_SOUND(sound))
9029 PlaySoundLoop(sound);
9032 void PlayMenuSoundIfLoop()
9034 PlayMenuSoundIfLoopExt(menu.sound[game_status]);
9037 void PlayMenuMusicExt(int music)
9039 if (music == MUS_UNDEFINED)
9042 if (!setup.sound_music)
9048 void PlayMenuMusic()
9050 char *curr_music = getCurrentlyPlayingMusicFilename();
9051 char *next_music = getMusicInfoEntryFilename(menu.music[game_status]);
9053 if (!strEqual(curr_music, next_music))
9054 PlayMenuMusicExt(menu.music[game_status]);
9057 void PlayMenuSoundsAndMusic()
9063 static void FadeMenuSounds()
9068 static void FadeMenuMusic()
9070 char *curr_music = getCurrentlyPlayingMusicFilename();
9071 char *next_music = getMusicInfoEntryFilename(menu.music[game_status]);
9073 if (!strEqual(curr_music, next_music))
9077 void FadeMenuSoundsAndMusic()
9083 void PlaySoundActivating()
9086 PlaySound(SND_MENU_ITEM_ACTIVATING);
9090 void PlaySoundSelecting()
9093 PlaySound(SND_MENU_ITEM_SELECTING);
9097 void ToggleFullscreenOrChangeWindowScalingIfNeeded()
9099 boolean change_fullscreen = (setup.fullscreen !=
9100 video.fullscreen_enabled);
9101 boolean change_window_scaling_percent = (!video.fullscreen_enabled &&
9102 setup.window_scaling_percent !=
9103 video.window_scaling_percent);
9105 if (change_window_scaling_percent && video.fullscreen_enabled)
9108 if (!change_window_scaling_percent && !video.fullscreen_available)
9111 #if defined(TARGET_SDL2)
9112 if (change_window_scaling_percent)
9114 SDLSetWindowScaling(setup.window_scaling_percent);
9118 else if (change_fullscreen)
9120 SDLSetWindowFullscreen(setup.fullscreen);
9122 /* set setup value according to successfully changed fullscreen mode */
9123 setup.fullscreen = video.fullscreen_enabled;
9129 if (change_fullscreen ||
9130 change_window_scaling_percent)
9132 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
9134 /* save backbuffer content which gets lost when toggling fullscreen mode */
9135 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
9137 if (change_window_scaling_percent)
9139 /* keep window mode, but change window scaling */
9140 video.fullscreen_enabled = TRUE; /* force new window scaling */
9143 /* toggle fullscreen */
9144 ChangeVideoModeIfNeeded(setup.fullscreen);
9146 /* set setup value according to successfully changed fullscreen mode */
9147 setup.fullscreen = video.fullscreen_enabled;
9149 /* restore backbuffer content from temporary backbuffer backup bitmap */
9150 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
9152 FreeBitmap(tmp_backbuffer);
9154 /* update visible window/screen */
9155 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
9159 void JoinRectangles(int *x, int *y, int *width, int *height,
9160 int x2, int y2, int width2, int height2)
9162 // do not join with "off-screen" rectangle
9163 if (x2 == -1 || y2 == -1)
9168 *width = MAX(*width, width2);
9169 *height = MAX(*height, height2);
9172 void SetAnimStatus(int anim_status_new)
9174 if (anim_status_new == GAME_MODE_MAIN)
9175 anim_status_new = GAME_MODE_PSEUDO_MAINONLY;
9176 else if (anim_status_new == GAME_MODE_SCORES)
9177 anim_status_new = GAME_MODE_PSEUDO_SCORESOLD;
9179 global.anim_status_next = anim_status_new;
9181 // directly set screen modes that are entered without fading
9182 if ((global.anim_status == GAME_MODE_PSEUDO_MAINONLY &&
9183 global.anim_status_next == GAME_MODE_PSEUDO_TYPENAME) ||
9184 (global.anim_status == GAME_MODE_PSEUDO_TYPENAME &&
9185 global.anim_status_next == GAME_MODE_PSEUDO_MAINONLY))
9186 global.anim_status = global.anim_status_next;
9189 void SetGameStatus(int game_status_new)
9191 if (game_status_new != game_status)
9192 game_status_last_screen = game_status;
9194 game_status = game_status_new;
9196 SetAnimStatus(game_status_new);
9199 void SetFontStatus(int game_status_new)
9201 static int last_game_status = -1;
9203 if (game_status_new != -1)
9205 // set game status for font use after storing last game status
9206 last_game_status = game_status;
9207 game_status = game_status_new;
9211 // reset game status after font use from last stored game status
9212 game_status = last_game_status;
9216 void ResetFontStatus()
9221 boolean CheckIfPlayfieldViewportHasChanged()
9223 // if game status has not changed, playfield viewport has not changed either
9224 if (game_status == game_status_last)
9227 // check if playfield viewport has changed with current game status
9228 struct RectWithBorder *vp_playfield = &viewport.playfield[game_status];
9229 int new_real_sx = vp_playfield->x;
9230 int new_real_sy = vp_playfield->y;
9231 int new_full_sxsize = vp_playfield->width;
9232 int new_full_sysize = vp_playfield->height;
9234 return (new_real_sx != REAL_SX ||
9235 new_real_sy != REAL_SY ||
9236 new_full_sxsize != FULL_SXSIZE ||
9237 new_full_sysize != FULL_SYSIZE);
9240 boolean CheckIfGlobalBorderOrPlayfieldViewportHasChanged()
9242 return (CheckIfGlobalBorderHasChanged() ||
9243 CheckIfPlayfieldViewportHasChanged());
9246 void ChangeViewportPropertiesIfNeeded()
9248 boolean use_mini_tilesize = (level.game_engine_type == GAME_ENGINE_TYPE_MM ?
9249 FALSE : setup.small_game_graphics);
9250 int gfx_game_mode = game_status;
9251 int gfx_game_mode2 = (game_status == GAME_MODE_EDITOR ? GAME_MODE_DEFAULT :
9253 struct RectWithBorder *vp_window = &viewport.window[gfx_game_mode];
9254 struct RectWithBorder *vp_playfield = &viewport.playfield[gfx_game_mode];
9255 struct RectWithBorder *vp_door_1 = &viewport.door_1[gfx_game_mode];
9256 struct RectWithBorder *vp_door_2 = &viewport.door_2[gfx_game_mode2];
9257 struct RectWithBorder *vp_door_3 = &viewport.door_2[GAME_MODE_EDITOR];
9258 int new_win_xsize = vp_window->width;
9259 int new_win_ysize = vp_window->height;
9260 int border_size = vp_playfield->border_size;
9261 int new_sx = vp_playfield->x + border_size;
9262 int new_sy = vp_playfield->y + border_size;
9263 int new_sxsize = vp_playfield->width - 2 * border_size;
9264 int new_sysize = vp_playfield->height - 2 * border_size;
9265 int new_real_sx = vp_playfield->x;
9266 int new_real_sy = vp_playfield->y;
9267 int new_full_sxsize = vp_playfield->width;
9268 int new_full_sysize = vp_playfield->height;
9269 int new_dx = vp_door_1->x;
9270 int new_dy = vp_door_1->y;
9271 int new_dxsize = vp_door_1->width;
9272 int new_dysize = vp_door_1->height;
9273 int new_vx = vp_door_2->x;
9274 int new_vy = vp_door_2->y;
9275 int new_vxsize = vp_door_2->width;
9276 int new_vysize = vp_door_2->height;
9277 int new_ex = vp_door_3->x;
9278 int new_ey = vp_door_3->y;
9279 int new_exsize = vp_door_3->width;
9280 int new_eysize = vp_door_3->height;
9281 int new_tilesize_var = (use_mini_tilesize ? MINI_TILESIZE : game.tile_size);
9282 int tilesize = (gfx_game_mode == GAME_MODE_PLAYING ? new_tilesize_var :
9283 gfx_game_mode == GAME_MODE_EDITOR ? MINI_TILESIZE : TILESIZE);
9284 int new_scr_fieldx = new_sxsize / tilesize;
9285 int new_scr_fieldy = new_sysize / tilesize;
9286 int new_scr_fieldx_buffers = new_sxsize / new_tilesize_var;
9287 int new_scr_fieldy_buffers = new_sysize / new_tilesize_var;
9288 boolean init_gfx_buffers = FALSE;
9289 boolean init_video_buffer = FALSE;
9290 boolean init_gadgets_and_anims = FALSE;
9291 boolean init_em_graphics = FALSE;
9293 if (new_win_xsize != WIN_XSIZE ||
9294 new_win_ysize != WIN_YSIZE)
9296 WIN_XSIZE = new_win_xsize;
9297 WIN_YSIZE = new_win_ysize;
9299 init_video_buffer = TRUE;
9300 init_gfx_buffers = TRUE;
9301 init_gadgets_and_anims = TRUE;
9303 // printf("::: video: init_video_buffer, init_gfx_buffers\n");
9306 if (new_scr_fieldx != SCR_FIELDX ||
9307 new_scr_fieldy != SCR_FIELDY)
9309 /* this always toggles between MAIN and GAME when using small tile size */
9311 SCR_FIELDX = new_scr_fieldx;
9312 SCR_FIELDY = new_scr_fieldy;
9314 // printf("::: new_scr_fieldx != SCR_FIELDX ...\n");
9325 new_sxsize != SXSIZE ||
9326 new_sysize != SYSIZE ||
9327 new_dxsize != DXSIZE ||
9328 new_dysize != DYSIZE ||
9329 new_vxsize != VXSIZE ||
9330 new_vysize != VYSIZE ||
9331 new_exsize != EXSIZE ||
9332 new_eysize != EYSIZE ||
9333 new_real_sx != REAL_SX ||
9334 new_real_sy != REAL_SY ||
9335 new_full_sxsize != FULL_SXSIZE ||
9336 new_full_sysize != FULL_SYSIZE ||
9337 new_tilesize_var != TILESIZE_VAR
9340 // ------------------------------------------------------------------------
9341 // determine next fading area for changed viewport definitions
9342 // ------------------------------------------------------------------------
9344 // start with current playfield area (default fading area)
9347 FADE_SXSIZE = FULL_SXSIZE;
9348 FADE_SYSIZE = FULL_SYSIZE;
9350 // add new playfield area if position or size has changed
9351 if (new_real_sx != REAL_SX || new_real_sy != REAL_SY ||
9352 new_full_sxsize != FULL_SXSIZE || new_full_sysize != FULL_SYSIZE)
9354 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
9355 new_real_sx, new_real_sy, new_full_sxsize,new_full_sysize);
9358 // add current and new door 1 area if position or size has changed
9359 if (new_dx != DX || new_dy != DY ||
9360 new_dxsize != DXSIZE || new_dysize != DYSIZE)
9362 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
9363 DX, DY, DXSIZE, DYSIZE);
9364 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
9365 new_dx, new_dy, new_dxsize, new_dysize);
9368 // add current and new door 2 area if position or size has changed
9369 if (new_dx != VX || new_dy != VY ||
9370 new_dxsize != VXSIZE || new_dysize != VYSIZE)
9372 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
9373 VX, VY, VXSIZE, VYSIZE);
9374 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
9375 new_vx, new_vy, new_vxsize, new_vysize);
9378 // ------------------------------------------------------------------------
9379 // handle changed tile size
9380 // ------------------------------------------------------------------------
9382 if (new_tilesize_var != TILESIZE_VAR)
9384 // printf("::: new_tilesize_var != TILESIZE_VAR\n");
9386 // changing tile size invalidates scroll values of engine snapshots
9387 FreeEngineSnapshotSingle();
9389 // changing tile size requires update of graphic mapping for EM engine
9390 init_em_graphics = TRUE;
9401 SXSIZE = new_sxsize;
9402 SYSIZE = new_sysize;
9403 DXSIZE = new_dxsize;
9404 DYSIZE = new_dysize;
9405 VXSIZE = new_vxsize;
9406 VYSIZE = new_vysize;
9407 EXSIZE = new_exsize;
9408 EYSIZE = new_eysize;
9409 REAL_SX = new_real_sx;
9410 REAL_SY = new_real_sy;
9411 FULL_SXSIZE = new_full_sxsize;
9412 FULL_SYSIZE = new_full_sysize;
9413 TILESIZE_VAR = new_tilesize_var;
9415 init_gfx_buffers = TRUE;
9416 init_gadgets_and_anims = TRUE;
9418 // printf("::: viewports: init_gfx_buffers\n");
9419 // printf("::: viewports: init_gadgets_and_anims\n");
9422 if (init_gfx_buffers)
9424 // printf("::: init_gfx_buffers\n");
9426 SCR_FIELDX = new_scr_fieldx_buffers;
9427 SCR_FIELDY = new_scr_fieldy_buffers;
9431 SCR_FIELDX = new_scr_fieldx;
9432 SCR_FIELDY = new_scr_fieldy;
9434 SetDrawDeactivationMask(REDRAW_NONE);
9435 SetDrawBackgroundMask(REDRAW_FIELD);
9438 if (init_video_buffer)
9440 // printf("::: init_video_buffer\n");
9442 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
9443 InitImageTextures();
9446 if (init_gadgets_and_anims)
9448 // printf("::: init_gadgets_and_anims\n");
9451 InitGlobalAnimations();
9454 if (init_em_graphics)
9456 InitGraphicInfo_EM();