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;
1269 boolean CheckIfGlobalBorderHasChanged()
1271 // if game status has not changed, global border has not changed either
1272 if (game_status == game_status_last)
1275 // determine and store new global border bitmap for current game status
1276 global_border_bitmap = getGlobalBorderBitmapFromStatus(game_status);
1278 return (global_border_bitmap_last != global_border_bitmap);
1281 boolean CheckIfGlobalBorderRedrawIsNeeded()
1283 // if game status has not changed, nothing has to be redrawn
1284 if (game_status == game_status_last)
1287 // redraw if last screen was title screen
1288 if (game_status_last == GAME_MODE_TITLE)
1291 // redraw if global screen border has changed
1292 if (CheckIfGlobalBorderHasChanged())
1295 // redraw if position or size of playfield area has changed
1296 if (real_sx_last != REAL_SX || real_sy_last != REAL_SY ||
1297 full_sxsize_last != FULL_SXSIZE || full_sysize_last != FULL_SYSIZE)
1300 // redraw if position or size of door area has changed
1301 if (dx_last != DX || dy_last != DY ||
1302 dxsize_last != DXSIZE || dysize_last != DYSIZE)
1305 // redraw if position or size of tape area has changed
1306 if (vx_last != VX || vy_last != VY ||
1307 vxsize_last != VXSIZE || vysize_last != VYSIZE)
1313 void RedrawGlobalBorderFromBitmap(Bitmap *bitmap)
1316 BlitBitmap(bitmap, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
1318 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
1321 void RedrawGlobalBorder()
1323 Bitmap *bitmap = getGlobalBorderBitmapFromStatus(game_status);
1325 RedrawGlobalBorderFromBitmap(bitmap);
1327 redraw_mask = REDRAW_ALL;
1330 static void RedrawGlobalBorderIfNeeded()
1332 if (game_status == game_status_last)
1335 // copy current draw buffer to later copy back areas that have not changed
1336 if (game_status_last != GAME_MODE_TITLE)
1337 BlitBitmap(backbuffer, bitmap_db_store_1, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
1339 if (CheckIfGlobalBorderRedrawIsNeeded())
1341 // redraw global screen border (or clear, if defined to be empty)
1342 RedrawGlobalBorderFromBitmap(global_border_bitmap);
1344 // copy previous playfield and door areas, if they are defined on both
1345 // previous and current screen and if they still have the same size
1347 if (real_sx_last != -1 && real_sy_last != -1 &&
1348 REAL_SX != -1 && REAL_SY != -1 &&
1349 full_sxsize_last == FULL_SXSIZE && full_sysize_last == FULL_SYSIZE)
1350 BlitBitmap(bitmap_db_store_1, backbuffer,
1351 real_sx_last, real_sy_last, FULL_SXSIZE, FULL_SYSIZE,
1354 if (dx_last != -1 && dy_last != -1 &&
1355 DX != -1 && DY != -1 &&
1356 dxsize_last == DXSIZE && dysize_last == DYSIZE)
1357 BlitBitmap(bitmap_db_store_1, backbuffer,
1358 dx_last, dy_last, DXSIZE, DYSIZE, DX, DY);
1360 if (vx_last != -1 && vy_last != -1 &&
1361 VX != -1 && VY != -1 &&
1362 vxsize_last == VXSIZE && vysize_last == VYSIZE)
1363 BlitBitmap(bitmap_db_store_1, backbuffer,
1364 vx_last, vy_last, VXSIZE, VYSIZE, VX, VY);
1366 redraw_mask = REDRAW_ALL;
1369 game_status_last = game_status;
1371 global_border_bitmap_last = global_border_bitmap;
1373 real_sx_last = REAL_SX;
1374 real_sy_last = REAL_SY;
1375 full_sxsize_last = FULL_SXSIZE;
1376 full_sysize_last = FULL_SYSIZE;
1379 dxsize_last = DXSIZE;
1380 dysize_last = DYSIZE;
1383 vxsize_last = VXSIZE;
1384 vysize_last = VYSIZE;
1389 RedrawGlobalBorderIfNeeded();
1391 /* !!! "drawto" might still point to playfield buffer here (see above) !!! */
1392 /* (when entering hall of fame after playing) */
1393 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
1395 /* !!! maybe this should be done before clearing the background !!! */
1396 if (game_status == GAME_MODE_PLAYING)
1398 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
1399 SetDrawtoField(DRAW_TO_FIELDBUFFER);
1403 SetDrawtoField(DRAW_TO_BACKBUFFER);
1407 void MarkTileDirty(int x, int y)
1409 redraw_mask |= REDRAW_FIELD;
1412 void SetBorderElement()
1416 BorderElement = EL_EMPTY;
1418 /* the MM game engine does not use a visible border element */
1419 if (level.game_engine_type == GAME_ENGINE_TYPE_MM)
1422 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
1424 for (x = 0; x < lev_fieldx; x++)
1426 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
1427 BorderElement = EL_STEELWALL;
1429 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
1435 void FloodFillLevelExt(int from_x, int from_y, int fill_element,
1436 int max_array_fieldx, int max_array_fieldy,
1437 short field[max_array_fieldx][max_array_fieldy],
1438 int max_fieldx, int max_fieldy)
1442 static int check[4][2] = { { -1, 0 }, { 0, -1 }, { 1, 0 }, { 0, 1 } };
1443 static int safety = 0;
1445 /* check if starting field still has the desired content */
1446 if (field[from_x][from_y] == fill_element)
1451 if (safety > max_fieldx * max_fieldy)
1452 Error(ERR_EXIT, "Something went wrong in 'FloodFill()'. Please debug.");
1454 old_element = field[from_x][from_y];
1455 field[from_x][from_y] = fill_element;
1457 for (i = 0; i < 4; i++)
1459 x = from_x + check[i][0];
1460 y = from_y + check[i][1];
1462 if (IN_FIELD(x, y, max_fieldx, max_fieldy) && field[x][y] == old_element)
1463 FloodFillLevelExt(x, y, fill_element, max_array_fieldx, max_array_fieldy,
1464 field, max_fieldx, max_fieldy);
1470 void FloodFillLevel(int from_x, int from_y, int fill_element,
1471 short field[MAX_LEV_FIELDX][MAX_LEV_FIELDY],
1472 int max_fieldx, int max_fieldy)
1474 FloodFillLevelExt(from_x, from_y, fill_element,
1475 MAX_LEV_FIELDX, MAX_LEV_FIELDY, field,
1476 max_fieldx, max_fieldy);
1479 void SetRandomAnimationValue(int x, int y)
1481 gfx.anim_random_frame = GfxRandom[x][y];
1484 int getGraphicAnimationFrame(int graphic, int sync_frame)
1486 /* animation synchronized with global frame counter, not move position */
1487 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
1488 sync_frame = FrameCounter;
1490 return getAnimationFrame(graphic_info[graphic].anim_frames,
1491 graphic_info[graphic].anim_delay,
1492 graphic_info[graphic].anim_mode,
1493 graphic_info[graphic].anim_start_frame,
1497 void getGraphicSourceBitmap(int graphic, int tilesize, Bitmap **bitmap)
1499 struct GraphicInfo *g = &graphic_info[graphic];
1500 int tilesize_capped = MIN(MAX(1, tilesize), TILESIZE);
1502 if (tilesize == gfx.standard_tile_size)
1503 *bitmap = g->bitmaps[IMG_BITMAP_STANDARD];
1504 else if (tilesize == game.tile_size)
1505 *bitmap = g->bitmaps[IMG_BITMAP_GAME];
1507 *bitmap = g->bitmaps[IMG_BITMAP_1x1 - log_2(tilesize_capped)];
1510 void getGraphicSourceXY(int graphic, int frame, int *x, int *y,
1511 boolean get_backside)
1513 struct GraphicInfo *g = &graphic_info[graphic];
1514 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
1515 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
1517 if (g->offset_y == 0) /* frames are ordered horizontally */
1519 int max_width = g->anim_frames_per_line * g->width;
1520 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
1522 *x = pos % max_width;
1523 *y = src_y % g->height + pos / max_width * g->height;
1525 else if (g->offset_x == 0) /* frames are ordered vertically */
1527 int max_height = g->anim_frames_per_line * g->height;
1528 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
1530 *x = src_x % g->width + pos / max_height * g->width;
1531 *y = pos % max_height;
1533 else /* frames are ordered diagonally */
1535 *x = src_x + frame * g->offset_x;
1536 *y = src_y + frame * g->offset_y;
1540 void getSizedGraphicSourceExt(int graphic, int frame, int tilesize,
1541 Bitmap **bitmap, int *x, int *y,
1542 boolean get_backside)
1544 struct GraphicInfo *g = &graphic_info[graphic];
1546 // if no in-game graphics defined, always use standard graphic size
1547 if (g->bitmaps[IMG_BITMAP_GAME] == NULL)
1548 tilesize = TILESIZE;
1550 getGraphicSourceBitmap(graphic, tilesize, bitmap);
1551 getGraphicSourceXY(graphic, frame, x, y, get_backside);
1553 *x = *x * tilesize / g->tile_size;
1554 *y = *y * tilesize / g->tile_size;
1557 void getSizedGraphicSource(int graphic, int frame, int tilesize,
1558 Bitmap **bitmap, int *x, int *y)
1560 getSizedGraphicSourceExt(graphic, frame, tilesize, bitmap, x, y, FALSE);
1563 void getFixedGraphicSource(int graphic, int frame,
1564 Bitmap **bitmap, int *x, int *y)
1566 getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y, FALSE);
1569 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1571 getSizedGraphicSource(graphic, 0, MINI_TILESIZE, bitmap, x, y);
1574 inline static void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1575 int *x, int *y, boolean get_backside)
1577 getSizedGraphicSourceExt(graphic, frame, TILESIZE_VAR, bitmap, x, y,
1581 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
1583 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
1586 void DrawGraphic(int x, int y, int graphic, int frame)
1589 if (!IN_SCR_FIELD(x, y))
1591 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1592 printf("DrawGraphic(): This should never happen!\n");
1597 DrawGraphicExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR, graphic,
1600 MarkTileDirty(x, y);
1603 void DrawFixedGraphic(int x, int y, int graphic, int frame)
1606 if (!IN_SCR_FIELD(x, y))
1608 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1609 printf("DrawGraphic(): This should never happen!\n");
1614 DrawFixedGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic,
1616 MarkTileDirty(x, y);
1619 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1625 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1627 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX_VAR, TILEY_VAR, x, y);
1630 void DrawFixedGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1636 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1637 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
1640 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
1643 if (!IN_SCR_FIELD(x, y))
1645 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1646 printf("DrawGraphicThruMask(): This should never happen!\n");
1651 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
1654 MarkTileDirty(x, y);
1657 void DrawFixedGraphicThruMask(int x, int y, int graphic, int frame)
1660 if (!IN_SCR_FIELD(x, y))
1662 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1663 printf("DrawGraphicThruMask(): This should never happen!\n");
1668 DrawFixedGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
1670 MarkTileDirty(x, y);
1673 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
1679 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1681 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX_VAR, TILEY_VAR,
1685 void DrawFixedGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y,
1686 int graphic, int frame)
1691 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1693 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY,
1697 void DrawSizedGraphic(int x, int y, int graphic, int frame, int tilesize)
1699 DrawSizedGraphicExt(drawto, SX + x * tilesize, SY + y * tilesize, graphic,
1701 MarkTileDirty(x / tilesize, y / tilesize);
1704 void DrawSizedGraphicThruMask(int x, int y, int graphic, int frame,
1707 DrawSizedGraphicThruMaskExt(drawto, SX + x * tilesize, SY + y * tilesize,
1708 graphic, frame, tilesize);
1709 MarkTileDirty(x / tilesize, y / tilesize);
1712 void DrawSizedGraphicExt(DrawBuffer *d, int x, int y, int graphic, int frame,
1718 getSizedGraphicSource(graphic, frame, tilesize, &src_bitmap, &src_x, &src_y);
1719 BlitBitmap(src_bitmap, d, src_x, src_y, tilesize, tilesize, x, y);
1722 void DrawSizedGraphicThruMaskExt(DrawBuffer *d, int x, int y, int graphic,
1723 int frame, int tilesize)
1728 getSizedGraphicSource(graphic, frame, tilesize, &src_bitmap, &src_x, &src_y);
1729 BlitBitmapMasked(src_bitmap, d, src_x, src_y, tilesize, tilesize, x, y);
1732 void DrawMiniGraphic(int x, int y, int graphic)
1734 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
1735 MarkTileDirty(x / 2, y / 2);
1738 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
1743 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1744 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
1747 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
1748 int graphic, int frame,
1749 int cut_mode, int mask_mode)
1754 int width = TILEX, height = TILEY;
1757 if (dx || dy) /* shifted graphic */
1759 if (x < BX1) /* object enters playfield from the left */
1766 else if (x > BX2) /* object enters playfield from the right */
1772 else if (x == BX1 && dx < 0) /* object leaves playfield to the left */
1778 else if (x == BX2 && dx > 0) /* object leaves playfield to the right */
1780 else if (dx) /* general horizontal movement */
1781 MarkTileDirty(x + SIGN(dx), y);
1783 if (y < BY1) /* object enters playfield from the top */
1785 if (cut_mode == CUT_BELOW) /* object completely above top border */
1793 else if (y > BY2) /* object enters playfield from the bottom */
1799 else if (y == BY1 && dy < 0) /* object leaves playfield to the top */
1805 else if (dy > 0 && cut_mode == CUT_ABOVE)
1807 if (y == BY2) /* object completely above bottom border */
1813 MarkTileDirty(x, y + 1);
1814 } /* object leaves playfield to the bottom */
1815 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1817 else if (dy) /* general vertical movement */
1818 MarkTileDirty(x, y + SIGN(dy));
1822 if (!IN_SCR_FIELD(x, y))
1824 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1825 printf("DrawGraphicShifted(): This should never happen!\n");
1830 width = width * TILESIZE_VAR / TILESIZE;
1831 height = height * TILESIZE_VAR / TILESIZE;
1832 cx = cx * TILESIZE_VAR / TILESIZE;
1833 cy = cy * TILESIZE_VAR / TILESIZE;
1834 dx = dx * TILESIZE_VAR / TILESIZE;
1835 dy = dy * TILESIZE_VAR / TILESIZE;
1837 if (width > 0 && height > 0)
1839 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1844 dst_x = FX + x * TILEX_VAR + dx;
1845 dst_y = FY + y * TILEY_VAR + dy;
1847 if (mask_mode == USE_MASKING)
1848 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1851 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1854 MarkTileDirty(x, y);
1858 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
1859 int graphic, int frame,
1860 int cut_mode, int mask_mode)
1865 int width = TILEX_VAR, height = TILEY_VAR;
1868 int x2 = x + SIGN(dx);
1869 int y2 = y + SIGN(dy);
1871 /* movement with two-tile animations must be sync'ed with movement position,
1872 not with current GfxFrame (which can be higher when using slow movement) */
1873 int anim_pos = (dx ? ABS(dx) : ABS(dy));
1874 int anim_frames = graphic_info[graphic].anim_frames;
1876 /* (we also need anim_delay here for movement animations with less frames) */
1877 int anim_delay = graphic_info[graphic].anim_delay;
1878 int sync_frame = anim_pos * anim_frames * anim_delay / TILESIZE;
1880 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
1881 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
1883 /* re-calculate animation frame for two-tile movement animation */
1884 frame = getGraphicAnimationFrame(graphic, sync_frame);
1886 /* check if movement start graphic inside screen area and should be drawn */
1887 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
1889 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
1891 dst_x = FX + x1 * TILEX_VAR;
1892 dst_y = FY + y1 * TILEY_VAR;
1894 if (mask_mode == USE_MASKING)
1895 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1898 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1901 MarkTileDirty(x1, y1);
1904 /* check if movement end graphic inside screen area and should be drawn */
1905 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
1907 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
1909 dst_x = FX + x2 * TILEX_VAR;
1910 dst_y = FY + y2 * TILEY_VAR;
1912 if (mask_mode == USE_MASKING)
1913 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1916 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1919 MarkTileDirty(x2, y2);
1923 static void DrawGraphicShifted(int x, int y, int dx, int dy,
1924 int graphic, int frame,
1925 int cut_mode, int mask_mode)
1929 DrawGraphic(x, y, graphic, frame);
1934 if (graphic_info[graphic].double_movement) /* EM style movement images */
1935 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1937 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1940 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1941 int frame, int cut_mode)
1943 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
1946 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1947 int cut_mode, int mask_mode)
1949 int lx = LEVELX(x), ly = LEVELY(y);
1953 if (IN_LEV_FIELD(lx, ly))
1955 SetRandomAnimationValue(lx, ly);
1957 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
1958 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1960 /* do not use double (EM style) movement graphic when not moving */
1961 if (graphic_info[graphic].double_movement && !dx && !dy)
1963 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
1964 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1967 else /* border element */
1969 graphic = el2img(element);
1970 frame = getGraphicAnimationFrame(graphic, -1);
1973 if (element == EL_EXPANDABLE_WALL)
1975 boolean left_stopped = FALSE, right_stopped = FALSE;
1977 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1978 left_stopped = TRUE;
1979 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1980 right_stopped = TRUE;
1982 if (left_stopped && right_stopped)
1984 else if (left_stopped)
1986 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1987 frame = graphic_info[graphic].anim_frames - 1;
1989 else if (right_stopped)
1991 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1992 frame = graphic_info[graphic].anim_frames - 1;
1997 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1998 else if (mask_mode == USE_MASKING)
1999 DrawGraphicThruMask(x, y, graphic, frame);
2001 DrawGraphic(x, y, graphic, frame);
2004 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
2005 int cut_mode, int mask_mode)
2007 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2008 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
2009 cut_mode, mask_mode);
2012 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
2015 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
2018 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
2021 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
2024 void DrawLevelElementThruMask(int x, int y, int element)
2026 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
2029 void DrawLevelFieldThruMask(int x, int y)
2031 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
2034 /* !!! implementation of quicksand is totally broken !!! */
2035 #define IS_CRUMBLED_TILE(x, y, e) \
2036 (GFX_CRUMBLED(e) && (!IN_LEV_FIELD(x, y) || \
2037 !IS_MOVING(x, y) || \
2038 (e) == EL_QUICKSAND_EMPTYING || \
2039 (e) == EL_QUICKSAND_FAST_EMPTYING))
2041 static void DrawLevelFieldCrumbledInnerCorners(int x, int y, int dx, int dy,
2046 int width, height, cx, cy;
2047 int sx = SCREENX(x), sy = SCREENY(y);
2048 int crumbled_border_size = graphic_info[graphic].border_size;
2049 int crumbled_tile_size = graphic_info[graphic].tile_size;
2050 int crumbled_border_size_var =
2051 crumbled_border_size * TILESIZE_VAR / crumbled_tile_size;
2054 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
2056 for (i = 1; i < 4; i++)
2058 int dxx = (i & 1 ? dx : 0);
2059 int dyy = (i & 2 ? dy : 0);
2062 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
2065 /* check if neighbour field is of same crumble type */
2066 boolean same = (IS_CRUMBLED_TILE(xx, yy, element) &&
2067 graphic_info[graphic].class ==
2068 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class);
2070 /* return if check prevents inner corner */
2071 if (same == (dxx == dx && dyy == dy))
2075 /* if we reach this point, we have an inner corner */
2077 getGraphicSource(graphic, 1, &src_bitmap, &src_x, &src_y);
2079 width = crumbled_border_size_var;
2080 height = crumbled_border_size_var;
2081 cx = (dx > 0 ? TILESIZE_VAR - width : 0);
2082 cy = (dy > 0 ? TILESIZE_VAR - height : 0);
2084 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
2085 width, height, FX + sx * TILEX_VAR + cx, FY + sy * TILEY_VAR + cy);
2088 static void DrawLevelFieldCrumbledBorders(int x, int y, int graphic, int frame,
2093 int width, height, bx, by, cx, cy;
2094 int sx = SCREENX(x), sy = SCREENY(y);
2095 int crumbled_border_size = graphic_info[graphic].border_size;
2096 int crumbled_tile_size = graphic_info[graphic].tile_size;
2097 int crumbled_border_size_var =
2098 crumbled_border_size * TILESIZE_VAR / crumbled_tile_size;
2099 int crumbled_border_pos_var = TILESIZE_VAR - crumbled_border_size_var;
2102 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
2104 /* draw simple, sloppy, non-corner-accurate crumbled border */
2106 width = (dir == 1 || dir == 2 ? crumbled_border_size_var : TILESIZE_VAR);
2107 height = (dir == 0 || dir == 3 ? crumbled_border_size_var : TILESIZE_VAR);
2108 cx = (dir == 2 ? crumbled_border_pos_var : 0);
2109 cy = (dir == 3 ? crumbled_border_pos_var : 0);
2111 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy, width, height,
2112 FX + sx * TILEX_VAR + cx,
2113 FY + sy * TILEY_VAR + cy);
2115 /* (remaining middle border part must be at least as big as corner part) */
2116 if (!(graphic_info[graphic].style & STYLE_ACCURATE_BORDERS) ||
2117 crumbled_border_size_var >= TILESIZE_VAR / 3)
2120 /* correct corners of crumbled border, if needed */
2122 for (i = -1; i <= 1; i += 2)
2124 int xx = x + (dir == 0 || dir == 3 ? i : 0);
2125 int yy = y + (dir == 1 || dir == 2 ? i : 0);
2126 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
2129 /* check if neighbour field is of same crumble type */
2130 if (IS_CRUMBLED_TILE(xx, yy, element) &&
2131 graphic_info[graphic].class ==
2132 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
2134 /* no crumbled corner, but continued crumbled border */
2136 int c1 = (dir == 2 || dir == 3 ? crumbled_border_pos_var : 0);
2137 int c2 = (i == 1 ? crumbled_border_pos_var : 0);
2138 int b1 = (i == 1 ? crumbled_border_size_var :
2139 TILESIZE_VAR - 2 * crumbled_border_size_var);
2141 width = crumbled_border_size_var;
2142 height = crumbled_border_size_var;
2144 if (dir == 1 || dir == 2)
2159 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
2161 FX + sx * TILEX_VAR + cx,
2162 FY + sy * TILEY_VAR + cy);
2167 static void DrawLevelFieldCrumbledExt(int x, int y, int graphic, int frame)
2169 int sx = SCREENX(x), sy = SCREENY(y);
2172 static int xy[4][2] =
2180 if (!IN_LEV_FIELD(x, y))
2183 element = TILE_GFX_ELEMENT(x, y);
2185 if (IS_CRUMBLED_TILE(x, y, element)) /* crumble field itself */
2187 if (!IN_SCR_FIELD(sx, sy))
2190 /* crumble field borders towards direct neighbour fields */
2191 for (i = 0; i < 4; i++)
2193 int xx = x + xy[i][0];
2194 int yy = y + xy[i][1];
2196 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
2199 /* check if neighbour field is of same crumble type */
2200 if (IS_CRUMBLED_TILE(xx, yy, element) &&
2201 graphic_info[graphic].class ==
2202 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
2205 DrawLevelFieldCrumbledBorders(x, y, graphic, frame, i);
2208 /* crumble inner field corners towards corner neighbour fields */
2209 if ((graphic_info[graphic].style & STYLE_INNER_CORNERS) &&
2210 graphic_info[graphic].anim_frames == 2)
2212 for (i = 0; i < 4; i++)
2214 int dx = (i & 1 ? +1 : -1);
2215 int dy = (i & 2 ? +1 : -1);
2217 DrawLevelFieldCrumbledInnerCorners(x, y, dx, dy, graphic);
2221 MarkTileDirty(sx, sy);
2223 else /* center field is not crumbled -- crumble neighbour fields */
2225 /* crumble field borders of direct neighbour fields */
2226 for (i = 0; i < 4; i++)
2228 int xx = x + xy[i][0];
2229 int yy = y + xy[i][1];
2230 int sxx = sx + xy[i][0];
2231 int syy = sy + xy[i][1];
2233 if (!IN_LEV_FIELD(xx, yy) ||
2234 !IN_SCR_FIELD(sxx, syy))
2237 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
2240 element = TILE_GFX_ELEMENT(xx, yy);
2242 if (!IS_CRUMBLED_TILE(xx, yy, element))
2245 graphic = el_act2crm(element, ACTION_DEFAULT);
2247 DrawLevelFieldCrumbledBorders(xx, yy, graphic, 0, 3 - i);
2249 MarkTileDirty(sxx, syy);
2252 /* crumble inner field corners of corner neighbour fields */
2253 for (i = 0; i < 4; i++)
2255 int dx = (i & 1 ? +1 : -1);
2256 int dy = (i & 2 ? +1 : -1);
2262 if (!IN_LEV_FIELD(xx, yy) ||
2263 !IN_SCR_FIELD(sxx, syy))
2266 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
2269 element = TILE_GFX_ELEMENT(xx, yy);
2271 if (!IS_CRUMBLED_TILE(xx, yy, element))
2274 graphic = el_act2crm(element, ACTION_DEFAULT);
2276 if ((graphic_info[graphic].style & STYLE_INNER_CORNERS) &&
2277 graphic_info[graphic].anim_frames == 2)
2278 DrawLevelFieldCrumbledInnerCorners(xx, yy, -dx, -dy, graphic);
2280 MarkTileDirty(sxx, syy);
2285 void DrawLevelFieldCrumbled(int x, int y)
2289 if (!IN_LEV_FIELD(x, y))
2292 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
2293 GfxElement[x][y] != EL_UNDEFINED &&
2294 GFX_CRUMBLED(GfxElement[x][y]))
2296 DrawLevelFieldCrumbledDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
2301 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
2303 DrawLevelFieldCrumbledExt(x, y, graphic, 0);
2306 void DrawLevelFieldCrumbledDigging(int x, int y, int direction,
2309 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
2310 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
2311 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
2312 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
2313 int sx = SCREENX(x), sy = SCREENY(y);
2315 DrawGraphic(sx, sy, graphic1, frame1);
2316 DrawLevelFieldCrumbledExt(x, y, graphic2, frame2);
2319 void DrawLevelFieldCrumbledNeighbours(int x, int y)
2321 int sx = SCREENX(x), sy = SCREENY(y);
2322 static int xy[4][2] =
2331 /* crumble direct neighbour fields (required for field borders) */
2332 for (i = 0; i < 4; i++)
2334 int xx = x + xy[i][0];
2335 int yy = y + xy[i][1];
2336 int sxx = sx + xy[i][0];
2337 int syy = sy + xy[i][1];
2339 if (!IN_LEV_FIELD(xx, yy) ||
2340 !IN_SCR_FIELD(sxx, syy) ||
2341 !GFX_CRUMBLED(Feld[xx][yy]) ||
2345 DrawLevelField(xx, yy);
2348 /* crumble corner neighbour fields (required for inner field corners) */
2349 for (i = 0; i < 4; i++)
2351 int dx = (i & 1 ? +1 : -1);
2352 int dy = (i & 2 ? +1 : -1);
2358 if (!IN_LEV_FIELD(xx, yy) ||
2359 !IN_SCR_FIELD(sxx, syy) ||
2360 !GFX_CRUMBLED(Feld[xx][yy]) ||
2364 int element = TILE_GFX_ELEMENT(xx, yy);
2365 int graphic = el_act2crm(element, ACTION_DEFAULT);
2367 if ((graphic_info[graphic].style & STYLE_INNER_CORNERS) &&
2368 graphic_info[graphic].anim_frames == 2)
2369 DrawLevelField(xx, yy);
2373 static int getBorderElement(int x, int y)
2377 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
2378 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
2379 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
2380 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
2381 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
2382 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
2383 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
2385 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
2386 int steel_position = (x == -1 && y == -1 ? 0 :
2387 x == lev_fieldx && y == -1 ? 1 :
2388 x == -1 && y == lev_fieldy ? 2 :
2389 x == lev_fieldx && y == lev_fieldy ? 3 :
2390 x == -1 || x == lev_fieldx ? 4 :
2391 y == -1 || y == lev_fieldy ? 5 : 6);
2393 return border[steel_position][steel_type];
2396 void DrawScreenElement(int x, int y, int element)
2398 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
2399 DrawLevelFieldCrumbled(LEVELX(x), LEVELY(y));
2402 void DrawLevelElement(int x, int y, int element)
2404 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2405 DrawScreenElement(SCREENX(x), SCREENY(y), element);
2408 void DrawScreenField(int x, int y)
2410 int lx = LEVELX(x), ly = LEVELY(y);
2411 int element, content;
2413 if (!IN_LEV_FIELD(lx, ly))
2415 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
2418 element = getBorderElement(lx, ly);
2420 DrawScreenElement(x, y, element);
2425 element = Feld[lx][ly];
2426 content = Store[lx][ly];
2428 if (IS_MOVING(lx, ly))
2430 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
2431 boolean cut_mode = NO_CUTTING;
2433 if (element == EL_QUICKSAND_EMPTYING ||
2434 element == EL_QUICKSAND_FAST_EMPTYING ||
2435 element == EL_MAGIC_WALL_EMPTYING ||
2436 element == EL_BD_MAGIC_WALL_EMPTYING ||
2437 element == EL_DC_MAGIC_WALL_EMPTYING ||
2438 element == EL_AMOEBA_DROPPING)
2439 cut_mode = CUT_ABOVE;
2440 else if (element == EL_QUICKSAND_FILLING ||
2441 element == EL_QUICKSAND_FAST_FILLING ||
2442 element == EL_MAGIC_WALL_FILLING ||
2443 element == EL_BD_MAGIC_WALL_FILLING ||
2444 element == EL_DC_MAGIC_WALL_FILLING)
2445 cut_mode = CUT_BELOW;
2447 if (cut_mode == CUT_ABOVE)
2448 DrawScreenElement(x, y, element);
2450 DrawScreenElement(x, y, EL_EMPTY);
2453 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
2454 else if (cut_mode == NO_CUTTING)
2455 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
2458 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
2460 if (cut_mode == CUT_BELOW &&
2461 IN_LEV_FIELD(lx, ly + 1) && IN_SCR_FIELD(x, y + 1))
2462 DrawLevelElement(lx, ly + 1, element);
2465 if (content == EL_ACID)
2467 int dir = MovDir[lx][ly];
2468 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
2469 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
2471 DrawLevelElementThruMask(newlx, newly, EL_ACID);
2473 // prevent target field from being drawn again (but without masking)
2474 // (this would happen if target field is scanned after moving element)
2475 Stop[newlx][newly] = TRUE;
2478 else if (IS_BLOCKED(lx, ly))
2483 boolean cut_mode = NO_CUTTING;
2484 int element_old, content_old;
2486 Blocked2Moving(lx, ly, &oldx, &oldy);
2489 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
2490 MovDir[oldx][oldy] == MV_RIGHT);
2492 element_old = Feld[oldx][oldy];
2493 content_old = Store[oldx][oldy];
2495 if (element_old == EL_QUICKSAND_EMPTYING ||
2496 element_old == EL_QUICKSAND_FAST_EMPTYING ||
2497 element_old == EL_MAGIC_WALL_EMPTYING ||
2498 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
2499 element_old == EL_DC_MAGIC_WALL_EMPTYING ||
2500 element_old == EL_AMOEBA_DROPPING)
2501 cut_mode = CUT_ABOVE;
2503 DrawScreenElement(x, y, EL_EMPTY);
2506 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
2508 else if (cut_mode == NO_CUTTING)
2509 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
2512 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
2515 else if (IS_DRAWABLE(element))
2516 DrawScreenElement(x, y, element);
2518 DrawScreenElement(x, y, EL_EMPTY);
2521 void DrawLevelField(int x, int y)
2523 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2524 DrawScreenField(SCREENX(x), SCREENY(y));
2525 else if (IS_MOVING(x, y))
2529 Moving2Blocked(x, y, &newx, &newy);
2530 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
2531 DrawScreenField(SCREENX(newx), SCREENY(newy));
2533 else if (IS_BLOCKED(x, y))
2537 Blocked2Moving(x, y, &oldx, &oldy);
2538 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
2539 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
2543 static void DrawSizedWallExt_MM(int dst_x, int dst_y, int element, int tilesize,
2544 int (*el2img_function)(int), boolean masked,
2545 int element_bits_draw)
2547 int element_base = map_mm_wall_element(element);
2548 int element_bits = (IS_DF_WALL(element) ?
2549 element - EL_DF_WALL_START :
2550 IS_MM_WALL(element) ?
2551 element - EL_MM_WALL_START : EL_EMPTY) & 0x000f;
2552 int graphic = el2img_function(element_base);
2553 int tilesize_draw = tilesize / 2;
2558 getSizedGraphicSource(graphic, 0, tilesize_draw, &src_bitmap, &src_x, &src_y);
2560 for (i = 0; i < 4; i++)
2562 int dst_draw_x = dst_x + (i % 2) * tilesize_draw;
2563 int dst_draw_y = dst_y + (i / 2) * tilesize_draw;
2565 if (!(element_bits_draw & (1 << i)))
2568 if (element_bits & (1 << i))
2571 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y,
2572 tilesize_draw, tilesize_draw, dst_draw_x, dst_draw_y);
2574 BlitBitmap(src_bitmap, drawto, src_x, src_y,
2575 tilesize_draw, tilesize_draw, dst_draw_x, dst_draw_y);
2580 ClearRectangle(drawto, dst_draw_x, dst_draw_y,
2581 tilesize_draw, tilesize_draw);
2586 void DrawSizedWallParts_MM(int x, int y, int element, int tilesize,
2587 boolean masked, int element_bits_draw)
2589 DrawSizedWallExt_MM(SX + x * tilesize, SY + y * tilesize,
2590 element, tilesize, el2edimg, masked, element_bits_draw);
2593 void DrawSizedWall_MM(int dst_x, int dst_y, int element, int tilesize,
2594 int (*el2img_function)(int))
2596 DrawSizedWallExt_MM(dst_x, dst_y, element, tilesize, el2img_function, FALSE,
2600 void DrawSizedElementExt(int x, int y, int element, int tilesize,
2603 if (IS_MM_WALL(element))
2605 DrawSizedWallExt_MM(SX + x * tilesize, SY + y * tilesize,
2606 element, tilesize, el2edimg, masked, 0x000f);
2610 int graphic = el2edimg(element);
2613 DrawSizedGraphicThruMask(x, y, graphic, 0, tilesize);
2615 DrawSizedGraphic(x, y, graphic, 0, tilesize);
2619 void DrawSizedElement(int x, int y, int element, int tilesize)
2621 DrawSizedElementExt(x, y, element, tilesize, FALSE);
2624 void DrawSizedElementThruMask(int x, int y, int element, int tilesize)
2626 DrawSizedElementExt(x, y, element, tilesize, TRUE);
2629 void DrawMiniElement(int x, int y, int element)
2633 graphic = el2edimg(element);
2634 DrawMiniGraphic(x, y, graphic);
2637 void DrawSizedElementOrWall(int sx, int sy, int scroll_x, int scroll_y,
2640 int x = sx + scroll_x, y = sy + scroll_y;
2642 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
2643 DrawSizedElement(sx, sy, EL_EMPTY, tilesize);
2644 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
2645 DrawSizedElement(sx, sy, Feld[x][y], tilesize);
2647 DrawSizedGraphic(sx, sy, el2edimg(getBorderElement(x, y)), 0, tilesize);
2650 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
2652 int x = sx + scroll_x, y = sy + scroll_y;
2654 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
2655 DrawMiniElement(sx, sy, EL_EMPTY);
2656 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
2657 DrawMiniElement(sx, sy, Feld[x][y]);
2659 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
2662 void DrawEnvelopeBackgroundTiles(int graphic, int startx, int starty,
2663 int x, int y, int xsize, int ysize,
2664 int tile_width, int tile_height)
2668 int dst_x = startx + x * tile_width;
2669 int dst_y = starty + y * tile_height;
2670 int width = graphic_info[graphic].width;
2671 int height = graphic_info[graphic].height;
2672 int inner_width_raw = MAX(width - 2 * tile_width, tile_width);
2673 int inner_height_raw = MAX(height - 2 * tile_height, tile_height);
2674 int inner_width = inner_width_raw - (inner_width_raw % tile_width);
2675 int inner_height = inner_height_raw - (inner_height_raw % tile_height);
2676 int inner_sx = (width >= 3 * tile_width ? tile_width : 0);
2677 int inner_sy = (height >= 3 * tile_height ? tile_height : 0);
2678 boolean draw_masked = graphic_info[graphic].draw_masked;
2680 getFixedGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
2682 if (src_bitmap == NULL || width < tile_width || height < tile_height)
2684 ClearRectangle(drawto, dst_x, dst_y, tile_width, tile_height);
2688 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - tile_width :
2689 inner_sx + (x - 1) * tile_width % inner_width);
2690 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - tile_height :
2691 inner_sy + (y - 1) * tile_height % inner_height);
2694 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
2697 BlitBitmap(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
2701 void DrawEnvelopeBackground(int graphic, int startx, int starty,
2702 int x, int y, int xsize, int ysize, int font_nr)
2704 int font_width = getFontWidth(font_nr);
2705 int font_height = getFontHeight(font_nr);
2707 DrawEnvelopeBackgroundTiles(graphic, startx, starty, x, y, xsize, ysize,
2708 font_width, font_height);
2711 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
2713 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2714 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2715 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2716 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2717 boolean no_delay = (tape.warp_forward);
2718 unsigned int anim_delay = 0;
2719 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
2720 int anim_delay_value = MAX(1, (no_delay ? 0 : frame_delay_value) / 2);
2721 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
2722 int font_width = getFontWidth(font_nr);
2723 int font_height = getFontHeight(font_nr);
2724 int max_xsize = level.envelope[envelope_nr].xsize;
2725 int max_ysize = level.envelope[envelope_nr].ysize;
2726 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
2727 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
2728 int xend = max_xsize;
2729 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
2730 int xstep = (xstart < xend ? 1 : 0);
2731 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2733 int end = MAX(xend - xstart, yend - ystart);
2736 for (i = start; i <= end; i++)
2738 int last_frame = end; // last frame of this "for" loop
2739 int x = xstart + i * xstep;
2740 int y = ystart + i * ystep;
2741 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2742 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2743 int sx = SX + (SXSIZE - xsize * font_width) / 2;
2744 int sy = SY + (SYSIZE - ysize * font_height) / 2;
2747 SetDrawtoField(DRAW_TO_FIELDBUFFER);
2749 BlitScreenToBitmap(backbuffer);
2751 SetDrawtoField(DRAW_TO_BACKBUFFER);
2753 for (yy = 0; yy < ysize; yy++)
2754 for (xx = 0; xx < xsize; xx++)
2755 DrawEnvelopeBackground(graphic, sx, sy, xx, yy, xsize, ysize, font_nr);
2757 DrawTextBuffer(sx + font_width, sy + font_height,
2758 level.envelope[envelope_nr].text, font_nr, max_xsize,
2759 xsize - 2, ysize - 2, 0, mask_mode,
2760 level.envelope[envelope_nr].autowrap,
2761 level.envelope[envelope_nr].centered, FALSE);
2763 redraw_mask |= REDRAW_FIELD;
2766 SkipUntilDelayReached(&anim_delay, anim_delay_value, &i, last_frame);
2770 void ShowEnvelope(int envelope_nr)
2772 int element = EL_ENVELOPE_1 + envelope_nr;
2773 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2774 int sound_opening = element_info[element].sound[ACTION_OPENING];
2775 int sound_closing = element_info[element].sound[ACTION_CLOSING];
2776 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2777 boolean no_delay = (tape.warp_forward);
2778 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
2779 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
2780 int anim_mode = graphic_info[graphic].anim_mode;
2781 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2782 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2784 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
2786 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2788 if (anim_mode == ANIM_DEFAULT)
2789 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
2791 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
2794 Delay(wait_delay_value);
2796 WaitForEventToContinue();
2798 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2800 if (anim_mode != ANIM_NONE)
2801 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
2803 if (anim_mode == ANIM_DEFAULT)
2804 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
2806 game.envelope_active = FALSE;
2808 SetDrawtoField(DRAW_TO_FIELDBUFFER);
2810 redraw_mask |= REDRAW_FIELD;
2814 static void setRequestBasePosition(int *x, int *y)
2816 int sx_base, sy_base;
2818 if (request.x != -1)
2819 sx_base = request.x;
2820 else if (request.align == ALIGN_LEFT)
2822 else if (request.align == ALIGN_RIGHT)
2823 sx_base = SX + SXSIZE;
2825 sx_base = SX + SXSIZE / 2;
2827 if (request.y != -1)
2828 sy_base = request.y;
2829 else if (request.valign == VALIGN_TOP)
2831 else if (request.valign == VALIGN_BOTTOM)
2832 sy_base = SY + SYSIZE;
2834 sy_base = SY + SYSIZE / 2;
2840 static void setRequestPositionExt(int *x, int *y, int width, int height,
2841 boolean add_border_size)
2843 int border_size = request.border_size;
2844 int sx_base, sy_base;
2847 setRequestBasePosition(&sx_base, &sy_base);
2849 if (request.align == ALIGN_LEFT)
2851 else if (request.align == ALIGN_RIGHT)
2852 sx = sx_base - width;
2854 sx = sx_base - width / 2;
2856 if (request.valign == VALIGN_TOP)
2858 else if (request.valign == VALIGN_BOTTOM)
2859 sy = sy_base - height;
2861 sy = sy_base - height / 2;
2863 sx = MAX(0, MIN(sx, WIN_XSIZE - width));
2864 sy = MAX(0, MIN(sy, WIN_YSIZE - height));
2866 if (add_border_size)
2876 static void setRequestPosition(int *x, int *y, boolean add_border_size)
2878 setRequestPositionExt(x, y, request.width, request.height, add_border_size);
2881 void DrawEnvelopeRequest(char *text)
2883 char *text_final = text;
2884 char *text_door_style = NULL;
2885 int graphic = IMG_BACKGROUND_REQUEST;
2886 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2887 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2888 int font_nr = FONT_REQUEST;
2889 int font_width = getFontWidth(font_nr);
2890 int font_height = getFontHeight(font_nr);
2891 int border_size = request.border_size;
2892 int line_spacing = request.line_spacing;
2893 int line_height = font_height + line_spacing;
2894 int max_text_width = request.width - 2 * border_size;
2895 int max_text_height = request.height - 2 * border_size;
2896 int line_length = max_text_width / font_width;
2897 int max_lines = max_text_height / line_height;
2898 int text_width = line_length * font_width;
2899 int width = request.width;
2900 int height = request.height;
2901 int tile_size = MAX(request.step_offset, 1);
2902 int x_steps = width / tile_size;
2903 int y_steps = height / tile_size;
2904 int sx_offset = border_size;
2905 int sy_offset = border_size;
2909 if (request.centered)
2910 sx_offset = (request.width - text_width) / 2;
2912 if (request.wrap_single_words && !request.autowrap)
2914 char *src_text_ptr, *dst_text_ptr;
2916 text_door_style = checked_malloc(2 * strlen(text) + 1);
2918 src_text_ptr = text;
2919 dst_text_ptr = text_door_style;
2921 while (*src_text_ptr)
2923 if (*src_text_ptr == ' ' ||
2924 *src_text_ptr == '?' ||
2925 *src_text_ptr == '!')
2926 *dst_text_ptr++ = '\n';
2928 if (*src_text_ptr != ' ')
2929 *dst_text_ptr++ = *src_text_ptr;
2934 *dst_text_ptr = '\0';
2936 text_final = text_door_style;
2939 setRequestPosition(&sx, &sy, FALSE);
2941 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
2943 for (y = 0; y < y_steps; y++)
2944 for (x = 0; x < x_steps; x++)
2945 DrawEnvelopeBackgroundTiles(graphic, sx, sy,
2946 x, y, x_steps, y_steps,
2947 tile_size, tile_size);
2949 /* force DOOR font inside door area */
2950 SetFontStatus(GAME_MODE_PSEUDO_DOOR);
2952 DrawTextBuffer(sx + sx_offset, sy + sy_offset, text_final, font_nr,
2953 line_length, -1, max_lines, line_spacing, mask_mode,
2954 request.autowrap, request.centered, FALSE);
2958 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2959 RedrawGadget(tool_gadget[i]);
2961 // store readily prepared envelope request for later use when animating
2962 BlitBitmap(backbuffer, bitmap_db_store_2, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2964 if (text_door_style)
2965 free(text_door_style);
2968 void AnimateEnvelopeRequest(int anim_mode, int action)
2970 int graphic = IMG_BACKGROUND_REQUEST;
2971 boolean draw_masked = graphic_info[graphic].draw_masked;
2972 int delay_value_normal = request.step_delay;
2973 int delay_value_fast = delay_value_normal / 2;
2974 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2975 boolean no_delay = (tape.warp_forward);
2976 int delay_value = (ffwd_delay ? delay_value_fast : delay_value_normal);
2977 int anim_delay_value = MAX(1, (no_delay ? 0 : delay_value + 500 * 0) / 2);
2978 unsigned int anim_delay = 0;
2980 int tile_size = MAX(request.step_offset, 1);
2981 int max_xsize = request.width / tile_size;
2982 int max_ysize = request.height / tile_size;
2983 int max_xsize_inner = max_xsize - 2;
2984 int max_ysize_inner = max_ysize - 2;
2986 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize_inner : 0);
2987 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize_inner : 0);
2988 int xend = max_xsize_inner;
2989 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize_inner : 0);
2990 int xstep = (xstart < xend ? 1 : 0);
2991 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2993 int end = MAX(xend - xstart, yend - ystart);
2996 if (setup.quick_doors)
3003 for (i = start; i <= end; i++)
3005 int last_frame = end; // last frame of this "for" loop
3006 int x = xstart + i * xstep;
3007 int y = ystart + i * ystep;
3008 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
3009 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
3010 int xsize_size_left = (xsize - 1) * tile_size;
3011 int ysize_size_top = (ysize - 1) * tile_size;
3012 int max_xsize_pos = (max_xsize - 1) * tile_size;
3013 int max_ysize_pos = (max_ysize - 1) * tile_size;
3014 int width = xsize * tile_size;
3015 int height = ysize * tile_size;
3020 setRequestPosition(&src_x, &src_y, FALSE);
3021 setRequestPositionExt(&dst_x, &dst_y, width, height, FALSE);
3023 BlitBitmap(bitmap_db_store_1, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
3025 for (yy = 0; yy < 2; yy++)
3027 for (xx = 0; xx < 2; xx++)
3029 int src_xx = src_x + xx * max_xsize_pos;
3030 int src_yy = src_y + yy * max_ysize_pos;
3031 int dst_xx = dst_x + xx * xsize_size_left;
3032 int dst_yy = dst_y + yy * ysize_size_top;
3033 int xx_size = (xx ? tile_size : xsize_size_left);
3034 int yy_size = (yy ? tile_size : ysize_size_top);
3037 BlitBitmapMasked(bitmap_db_store_2, backbuffer,
3038 src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
3040 BlitBitmap(bitmap_db_store_2, backbuffer,
3041 src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
3045 redraw_mask |= REDRAW_FIELD;
3049 SkipUntilDelayReached(&anim_delay, anim_delay_value, &i, last_frame);
3053 void ShowEnvelopeRequest(char *text, unsigned int req_state, int action)
3055 int graphic = IMG_BACKGROUND_REQUEST;
3056 int sound_opening = SND_REQUEST_OPENING;
3057 int sound_closing = SND_REQUEST_CLOSING;
3058 int anim_mode_1 = request.anim_mode; /* (higher priority) */
3059 int anim_mode_2 = graphic_info[graphic].anim_mode; /* (lower priority) */
3060 int anim_mode = (anim_mode_1 != ANIM_DEFAULT ? anim_mode_1 : anim_mode_2);
3061 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
3062 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
3064 if (game_status == GAME_MODE_PLAYING)
3065 BlitScreenToBitmap(backbuffer);
3067 SetDrawtoField(DRAW_TO_BACKBUFFER);
3069 // SetDrawBackgroundMask(REDRAW_NONE);
3071 if (action == ACTION_OPENING)
3073 BlitBitmap(backbuffer, bitmap_db_store_1, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
3075 if (req_state & REQ_ASK)
3077 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
3078 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
3080 else if (req_state & REQ_CONFIRM)
3082 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
3084 else if (req_state & REQ_PLAYER)
3086 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
3087 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
3088 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
3089 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
3092 DrawEnvelopeRequest(text);
3095 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
3097 if (action == ACTION_OPENING)
3099 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
3101 if (anim_mode == ANIM_DEFAULT)
3102 AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_OPENING);
3104 AnimateEnvelopeRequest(main_anim_mode, ACTION_OPENING);
3108 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
3110 if (anim_mode != ANIM_NONE)
3111 AnimateEnvelopeRequest(main_anim_mode, ACTION_CLOSING);
3113 if (anim_mode == ANIM_DEFAULT)
3114 AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_CLOSING);
3117 game.envelope_active = FALSE;
3119 if (action == ACTION_CLOSING)
3120 BlitBitmap(bitmap_db_store_1, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
3122 // SetDrawBackgroundMask(last_draw_background_mask);
3124 redraw_mask |= REDRAW_FIELD;
3128 if (action == ACTION_CLOSING &&
3129 game_status == GAME_MODE_PLAYING &&
3130 level.game_engine_type == GAME_ENGINE_TYPE_RND)
3131 SetDrawtoField(DRAW_TO_FIELDBUFFER);
3134 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
3136 if (IS_MM_WALL(element))
3138 DrawSizedWall_MM(dst_x, dst_y, element, tilesize, el2preimg);
3144 int graphic = el2preimg(element);
3146 getSizedGraphicSource(graphic, 0, tilesize, &src_bitmap, &src_x, &src_y);
3147 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize,
3152 void DrawLevel(int draw_background_mask)
3156 SetMainBackgroundImage(IMG_BACKGROUND_PLAYING);
3157 SetDrawBackgroundMask(draw_background_mask);
3161 for (x = BX1; x <= BX2; x++)
3162 for (y = BY1; y <= BY2; y++)
3163 DrawScreenField(x, y);
3165 redraw_mask |= REDRAW_FIELD;
3168 void DrawSizedLevel(int size_x, int size_y, int scroll_x, int scroll_y,
3173 for (x = 0; x < size_x; x++)
3174 for (y = 0; y < size_y; y++)
3175 DrawSizedElementOrWall(x, y, scroll_x, scroll_y, tilesize);
3177 redraw_mask |= REDRAW_FIELD;
3180 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
3184 for (x = 0; x < size_x; x++)
3185 for (y = 0; y < size_y; y++)
3186 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
3188 redraw_mask |= REDRAW_FIELD;
3191 static void DrawPreviewLevelPlayfield(int from_x, int from_y)
3193 boolean show_level_border = (BorderElement != EL_EMPTY);
3194 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
3195 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
3196 int tile_size = preview.tile_size;
3197 int preview_width = preview.xsize * tile_size;
3198 int preview_height = preview.ysize * tile_size;
3199 int real_preview_xsize = MIN(level_xsize, preview.xsize);
3200 int real_preview_ysize = MIN(level_ysize, preview.ysize);
3201 int real_preview_width = real_preview_xsize * tile_size;
3202 int real_preview_height = real_preview_ysize * tile_size;
3203 int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
3204 int dst_y = SY + ALIGNED_YPOS(preview.y, preview_height, preview.valign);
3207 if (!IN_GFX_FIELD_FULL(dst_x, dst_y + preview_height - 1))
3210 DrawBackground(dst_x, dst_y, preview_width, preview_height);
3212 dst_x += (preview_width - real_preview_width) / 2;
3213 dst_y += (preview_height - real_preview_height) / 2;
3215 for (x = 0; x < real_preview_xsize; x++)
3217 for (y = 0; y < real_preview_ysize; y++)
3219 int lx = from_x + x + (show_level_border ? -1 : 0);
3220 int ly = from_y + y + (show_level_border ? -1 : 0);
3221 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
3222 getBorderElement(lx, ly));
3224 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
3225 element, tile_size);
3229 redraw_mask |= REDRAW_FIELD;
3232 #define MICROLABEL_EMPTY 0
3233 #define MICROLABEL_LEVEL_NAME 1
3234 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
3235 #define MICROLABEL_LEVEL_AUTHOR 3
3236 #define MICROLABEL_IMPORTED_FROM_HEAD 4
3237 #define MICROLABEL_IMPORTED_FROM 5
3238 #define MICROLABEL_IMPORTED_BY_HEAD 6
3239 #define MICROLABEL_IMPORTED_BY 7
3241 static int getMaxTextLength(struct TextPosInfo *pos, int font_nr)
3243 int max_text_width = SXSIZE;
3244 int font_width = getFontWidth(font_nr);
3246 if (pos->align == ALIGN_CENTER)
3247 max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
3248 else if (pos->align == ALIGN_RIGHT)
3249 max_text_width = pos->x;
3251 max_text_width = SXSIZE - pos->x;
3253 return max_text_width / font_width;
3256 static void DrawPreviewLevelLabelExt(int mode, struct TextPosInfo *pos)
3258 char label_text[MAX_OUTPUT_LINESIZE + 1];
3259 int max_len_label_text;
3260 int font_nr = pos->font;
3263 if (!IN_GFX_FIELD_FULL(pos->x, pos->y + getFontHeight(pos->font)))
3266 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
3267 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
3268 mode == MICROLABEL_IMPORTED_BY_HEAD)
3269 font_nr = pos->font_alt;
3271 max_len_label_text = getMaxTextLength(pos, font_nr);
3273 if (pos->size != -1)
3274 max_len_label_text = pos->size;
3276 for (i = 0; i < max_len_label_text; i++)
3277 label_text[i] = ' ';
3278 label_text[max_len_label_text] = '\0';
3280 if (strlen(label_text) > 0)
3281 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
3284 (mode == MICROLABEL_LEVEL_NAME ? level.name :
3285 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
3286 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
3287 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
3288 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
3289 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
3290 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
3291 max_len_label_text);
3292 label_text[max_len_label_text] = '\0';
3294 if (strlen(label_text) > 0)
3295 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
3297 redraw_mask |= REDRAW_FIELD;
3300 static void DrawPreviewLevelLabel(int mode)
3302 DrawPreviewLevelLabelExt(mode, &menu.main.text.level_info_2);
3305 static void DrawPreviewLevelInfo(int mode)
3307 if (mode == MICROLABEL_LEVEL_NAME)
3308 DrawPreviewLevelLabelExt(mode, &menu.main.text.level_name);
3309 else if (mode == MICROLABEL_LEVEL_AUTHOR)
3310 DrawPreviewLevelLabelExt(mode, &menu.main.text.level_author);
3313 static void DrawPreviewLevelExt(boolean restart)
3315 static unsigned int scroll_delay = 0;
3316 static unsigned int label_delay = 0;
3317 static int from_x, from_y, scroll_direction;
3318 static int label_state, label_counter;
3319 unsigned int scroll_delay_value = preview.step_delay;
3320 boolean show_level_border = (BorderElement != EL_EMPTY);
3321 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
3322 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
3329 if (preview.anim_mode == ANIM_CENTERED)
3331 if (level_xsize > preview.xsize)
3332 from_x = (level_xsize - preview.xsize) / 2;
3333 if (level_ysize > preview.ysize)
3334 from_y = (level_ysize - preview.ysize) / 2;
3337 from_x += preview.xoffset;
3338 from_y += preview.yoffset;
3340 scroll_direction = MV_RIGHT;
3344 DrawPreviewLevelPlayfield(from_x, from_y);
3345 DrawPreviewLevelLabel(label_state);
3347 DrawPreviewLevelInfo(MICROLABEL_LEVEL_NAME);
3348 DrawPreviewLevelInfo(MICROLABEL_LEVEL_AUTHOR);
3350 /* initialize delay counters */
3351 DelayReached(&scroll_delay, 0);
3352 DelayReached(&label_delay, 0);
3354 if (leveldir_current->name)
3356 struct TextPosInfo *pos = &menu.main.text.level_info_1;
3357 char label_text[MAX_OUTPUT_LINESIZE + 1];
3358 int font_nr = pos->font;
3359 int max_len_label_text = getMaxTextLength(pos, font_nr);
3361 if (pos->size != -1)
3362 max_len_label_text = pos->size;
3364 strncpy(label_text, leveldir_current->name, max_len_label_text);
3365 label_text[max_len_label_text] = '\0';
3367 if (IN_GFX_FIELD_FULL(pos->x, pos->y + getFontHeight(pos->font)))
3368 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
3374 /* scroll preview level, if needed */
3375 if (preview.anim_mode != ANIM_NONE &&
3376 (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
3377 DelayReached(&scroll_delay, scroll_delay_value))
3379 switch (scroll_direction)
3384 from_x -= preview.step_offset;
3385 from_x = (from_x < 0 ? 0 : from_x);
3388 scroll_direction = MV_UP;
3392 if (from_x < level_xsize - preview.xsize)
3394 from_x += preview.step_offset;
3395 from_x = (from_x > level_xsize - preview.xsize ?
3396 level_xsize - preview.xsize : from_x);
3399 scroll_direction = MV_DOWN;
3405 from_y -= preview.step_offset;
3406 from_y = (from_y < 0 ? 0 : from_y);
3409 scroll_direction = MV_RIGHT;
3413 if (from_y < level_ysize - preview.ysize)
3415 from_y += preview.step_offset;
3416 from_y = (from_y > level_ysize - preview.ysize ?
3417 level_ysize - preview.ysize : from_y);
3420 scroll_direction = MV_LEFT;
3427 DrawPreviewLevelPlayfield(from_x, from_y);
3430 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
3431 /* redraw micro level label, if needed */
3432 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
3433 !strEqual(level.author, ANONYMOUS_NAME) &&
3434 !strEqual(level.author, leveldir_current->name) &&
3435 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
3437 int max_label_counter = 23;
3439 if (leveldir_current->imported_from != NULL &&
3440 strlen(leveldir_current->imported_from) > 0)
3441 max_label_counter += 14;
3442 if (leveldir_current->imported_by != NULL &&
3443 strlen(leveldir_current->imported_by) > 0)
3444 max_label_counter += 14;
3446 label_counter = (label_counter + 1) % max_label_counter;
3447 label_state = (label_counter >= 0 && label_counter <= 7 ?
3448 MICROLABEL_LEVEL_NAME :
3449 label_counter >= 9 && label_counter <= 12 ?
3450 MICROLABEL_LEVEL_AUTHOR_HEAD :
3451 label_counter >= 14 && label_counter <= 21 ?
3452 MICROLABEL_LEVEL_AUTHOR :
3453 label_counter >= 23 && label_counter <= 26 ?
3454 MICROLABEL_IMPORTED_FROM_HEAD :
3455 label_counter >= 28 && label_counter <= 35 ?
3456 MICROLABEL_IMPORTED_FROM :
3457 label_counter >= 37 && label_counter <= 40 ?
3458 MICROLABEL_IMPORTED_BY_HEAD :
3459 label_counter >= 42 && label_counter <= 49 ?
3460 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
3462 if (leveldir_current->imported_from == NULL &&
3463 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
3464 label_state == MICROLABEL_IMPORTED_FROM))
3465 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
3466 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
3468 DrawPreviewLevelLabel(label_state);
3472 void DrawPreviewLevelInitial()
3474 DrawPreviewLevelExt(TRUE);
3477 void DrawPreviewLevelAnimation()
3479 DrawPreviewLevelExt(FALSE);
3482 inline static void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
3483 int graphic, int sync_frame,
3486 int frame = getGraphicAnimationFrame(graphic, sync_frame);
3488 if (mask_mode == USE_MASKING)
3489 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
3491 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
3494 void DrawFixedGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
3495 int graphic, int sync_frame, int mask_mode)
3497 int frame = getGraphicAnimationFrame(graphic, sync_frame);
3499 if (mask_mode == USE_MASKING)
3500 DrawFixedGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
3502 DrawFixedGraphicExt(dst_bitmap, x, y, graphic, frame);
3505 inline static void DrawGraphicAnimation(int x, int y, int graphic)
3507 int lx = LEVELX(x), ly = LEVELY(y);
3509 if (!IN_SCR_FIELD(x, y))
3512 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
3513 graphic, GfxFrame[lx][ly], NO_MASKING);
3515 MarkTileDirty(x, y);
3518 void DrawFixedGraphicAnimation(int x, int y, int graphic)
3520 int lx = LEVELX(x), ly = LEVELY(y);
3522 if (!IN_SCR_FIELD(x, y))
3525 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
3526 graphic, GfxFrame[lx][ly], NO_MASKING);
3527 MarkTileDirty(x, y);
3530 void DrawLevelGraphicAnimation(int x, int y, int graphic)
3532 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
3535 void DrawLevelElementAnimation(int x, int y, int element)
3537 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
3539 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
3542 void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
3544 int sx = SCREENX(x), sy = SCREENY(y);
3546 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
3549 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
3552 DrawGraphicAnimation(sx, sy, graphic);
3555 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
3556 DrawLevelFieldCrumbled(x, y);
3558 if (GFX_CRUMBLED(Feld[x][y]))
3559 DrawLevelFieldCrumbled(x, y);
3563 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
3565 int sx = SCREENX(x), sy = SCREENY(y);
3568 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
3571 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
3573 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
3576 DrawGraphicAnimation(sx, sy, graphic);
3578 if (GFX_CRUMBLED(element))
3579 DrawLevelFieldCrumbled(x, y);
3582 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
3584 if (player->use_murphy)
3586 /* this works only because currently only one player can be "murphy" ... */
3587 static int last_horizontal_dir = MV_LEFT;
3588 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
3590 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3591 last_horizontal_dir = move_dir;
3593 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
3595 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
3597 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
3603 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
3606 static boolean equalGraphics(int graphic1, int graphic2)
3608 struct GraphicInfo *g1 = &graphic_info[graphic1];
3609 struct GraphicInfo *g2 = &graphic_info[graphic2];
3611 return (g1->bitmap == g2->bitmap &&
3612 g1->src_x == g2->src_x &&
3613 g1->src_y == g2->src_y &&
3614 g1->anim_frames == g2->anim_frames &&
3615 g1->anim_delay == g2->anim_delay &&
3616 g1->anim_mode == g2->anim_mode);
3619 void DrawAllPlayers()
3623 for (i = 0; i < MAX_PLAYERS; i++)
3624 if (stored_player[i].active)
3625 DrawPlayer(&stored_player[i]);
3628 void DrawPlayerField(int x, int y)
3630 if (!IS_PLAYER(x, y))
3633 DrawPlayer(PLAYERINFO(x, y));
3636 #define DRAW_PLAYER_OVER_PUSHED_ELEMENT 1
3638 void DrawPlayer(struct PlayerInfo *player)
3640 int jx = player->jx;
3641 int jy = player->jy;
3642 int move_dir = player->MovDir;
3643 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
3644 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
3645 int last_jx = (player->is_moving ? jx - dx : jx);
3646 int last_jy = (player->is_moving ? jy - dy : jy);
3647 int next_jx = jx + dx;
3648 int next_jy = jy + dy;
3649 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
3650 boolean player_is_opaque = FALSE;
3651 int sx = SCREENX(jx), sy = SCREENY(jy);
3652 int sxx = 0, syy = 0;
3653 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
3655 int action = ACTION_DEFAULT;
3656 int last_player_graphic = getPlayerGraphic(player, move_dir);
3657 int last_player_frame = player->Frame;
3660 /* GfxElement[][] is set to the element the player is digging or collecting;
3661 remove also for off-screen player if the player is not moving anymore */
3662 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
3663 GfxElement[jx][jy] = EL_UNDEFINED;
3665 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
3669 if (!IN_LEV_FIELD(jx, jy))
3671 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
3672 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
3673 printf("DrawPlayerField(): This should never happen!\n");
3678 if (element == EL_EXPLOSION)
3681 action = (player->is_pushing ? ACTION_PUSHING :
3682 player->is_digging ? ACTION_DIGGING :
3683 player->is_collecting ? ACTION_COLLECTING :
3684 player->is_moving ? ACTION_MOVING :
3685 player->is_snapping ? ACTION_SNAPPING :
3686 player->is_dropping ? ACTION_DROPPING :
3687 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
3689 if (player->is_waiting)
3690 move_dir = player->dir_waiting;
3692 InitPlayerGfxAnimation(player, action, move_dir);
3694 /* ----------------------------------------------------------------------- */
3695 /* draw things in the field the player is leaving, if needed */
3696 /* ----------------------------------------------------------------------- */
3698 if (player->is_moving)
3700 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
3702 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
3704 if (last_element == EL_DYNAMITE_ACTIVE ||
3705 last_element == EL_EM_DYNAMITE_ACTIVE ||
3706 last_element == EL_SP_DISK_RED_ACTIVE)
3707 DrawDynamite(last_jx, last_jy);
3709 DrawLevelFieldThruMask(last_jx, last_jy);
3711 else if (last_element == EL_DYNAMITE_ACTIVE ||
3712 last_element == EL_EM_DYNAMITE_ACTIVE ||
3713 last_element == EL_SP_DISK_RED_ACTIVE)
3714 DrawDynamite(last_jx, last_jy);
3716 /* !!! this is not enough to prevent flickering of players which are
3717 moving next to each others without a free tile between them -- this
3718 can only be solved by drawing all players layer by layer (first the
3719 background, then the foreground etc.) !!! => TODO */
3720 else if (!IS_PLAYER(last_jx, last_jy))
3721 DrawLevelField(last_jx, last_jy);
3724 DrawLevelField(last_jx, last_jy);
3727 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
3728 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
3731 if (!IN_SCR_FIELD(sx, sy))
3734 /* ----------------------------------------------------------------------- */
3735 /* draw things behind the player, if needed */
3736 /* ----------------------------------------------------------------------- */
3739 DrawLevelElement(jx, jy, Back[jx][jy]);
3740 else if (IS_ACTIVE_BOMB(element))
3741 DrawLevelElement(jx, jy, EL_EMPTY);
3744 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
3746 int old_element = GfxElement[jx][jy];
3747 int old_graphic = el_act_dir2img(old_element, action, move_dir);
3748 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
3750 if (GFX_CRUMBLED(old_element))
3751 DrawLevelFieldCrumbledDigging(jx, jy, move_dir, player->StepFrame);
3753 DrawGraphic(sx, sy, old_graphic, frame);
3755 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
3756 player_is_opaque = TRUE;
3760 GfxElement[jx][jy] = EL_UNDEFINED;
3762 /* make sure that pushed elements are drawn with correct frame rate */
3763 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
3765 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
3766 GfxFrame[jx][jy] = player->StepFrame;
3768 DrawLevelField(jx, jy);
3772 #if !DRAW_PLAYER_OVER_PUSHED_ELEMENT
3773 /* ----------------------------------------------------------------------- */
3774 /* draw player himself */
3775 /* ----------------------------------------------------------------------- */
3777 graphic = getPlayerGraphic(player, move_dir);
3779 /* in the case of changed player action or direction, prevent the current
3780 animation frame from being restarted for identical animations */
3781 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
3782 player->Frame = last_player_frame;
3784 frame = getGraphicAnimationFrame(graphic, player->Frame);
3788 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3789 sxx = player->GfxPos;
3791 syy = player->GfxPos;
3794 if (player_is_opaque)
3795 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
3797 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3799 if (SHIELD_ON(player))
3801 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
3802 IMG_SHIELD_NORMAL_ACTIVE);
3803 int frame = getGraphicAnimationFrame(graphic, -1);
3805 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3809 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
3812 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3813 sxx = player->GfxPos;
3815 syy = player->GfxPos;
3819 /* ----------------------------------------------------------------------- */
3820 /* draw things the player is pushing, if needed */
3821 /* ----------------------------------------------------------------------- */
3823 if (player->is_pushing && player->is_moving)
3825 int px = SCREENX(jx), py = SCREENY(jy);
3826 int pxx = (TILEX - ABS(sxx)) * dx;
3827 int pyy = (TILEY - ABS(syy)) * dy;
3828 int gfx_frame = GfxFrame[jx][jy];
3834 if (!IS_MOVING(jx, jy)) /* push movement already finished */
3836 element = Feld[next_jx][next_jy];
3837 gfx_frame = GfxFrame[next_jx][next_jy];
3840 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
3842 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
3843 frame = getGraphicAnimationFrame(graphic, sync_frame);
3845 /* draw background element under pushed element (like the Sokoban field) */
3846 if (game.use_masked_pushing && IS_MOVING(jx, jy))
3848 /* this allows transparent pushing animation over non-black background */
3851 DrawLevelElement(jx, jy, Back[jx][jy]);
3853 DrawLevelElement(jx, jy, EL_EMPTY);
3855 if (Back[next_jx][next_jy])
3856 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3858 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
3860 else if (Back[next_jx][next_jy])
3861 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3864 /* do not draw (EM style) pushing animation when pushing is finished */
3865 /* (two-tile animations usually do not contain start and end frame) */
3866 if (graphic_info[graphic].double_movement && !IS_MOVING(jx, jy))
3867 DrawLevelElement(next_jx, next_jy, Feld[next_jx][next_jy]);
3869 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3871 /* masked drawing is needed for EMC style (double) movement graphics */
3872 /* !!! (ONLY WHEN DRAWING PUSHED ELEMENT OVER THE PLAYER) !!! */
3873 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3877 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
3878 /* ----------------------------------------------------------------------- */
3879 /* draw player himself */
3880 /* ----------------------------------------------------------------------- */
3882 graphic = getPlayerGraphic(player, move_dir);
3884 /* in the case of changed player action or direction, prevent the current
3885 animation frame from being restarted for identical animations */
3886 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
3887 player->Frame = last_player_frame;
3889 frame = getGraphicAnimationFrame(graphic, player->Frame);
3893 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3894 sxx = player->GfxPos;
3896 syy = player->GfxPos;
3899 if (player_is_opaque)
3900 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
3902 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3904 if (SHIELD_ON(player))
3906 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
3907 IMG_SHIELD_NORMAL_ACTIVE);
3908 int frame = getGraphicAnimationFrame(graphic, -1);
3910 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3914 /* ----------------------------------------------------------------------- */
3915 /* draw things in front of player (active dynamite or dynabombs) */
3916 /* ----------------------------------------------------------------------- */
3918 if (IS_ACTIVE_BOMB(element))
3920 graphic = el2img(element);
3921 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
3923 if (game.emulation == EMU_SUPAPLEX)
3924 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
3926 DrawGraphicThruMask(sx, sy, graphic, frame);
3929 if (player_is_moving && last_element == EL_EXPLOSION)
3931 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
3932 GfxElement[last_jx][last_jy] : EL_EMPTY);
3933 int graphic = el_act2img(element, ACTION_EXPLODING);
3934 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
3935 int phase = ExplodePhase[last_jx][last_jy] - 1;
3936 int frame = getGraphicAnimationFrame(graphic, phase - delay);
3939 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
3942 /* ----------------------------------------------------------------------- */
3943 /* draw elements the player is just walking/passing through/under */
3944 /* ----------------------------------------------------------------------- */
3946 if (player_is_moving)
3948 /* handle the field the player is leaving ... */
3949 if (IS_ACCESSIBLE_INSIDE(last_element))
3950 DrawLevelField(last_jx, last_jy);
3951 else if (IS_ACCESSIBLE_UNDER(last_element))
3952 DrawLevelFieldThruMask(last_jx, last_jy);
3955 /* do not redraw accessible elements if the player is just pushing them */
3956 if (!player_is_moving || !player->is_pushing)
3958 /* ... and the field the player is entering */
3959 if (IS_ACCESSIBLE_INSIDE(element))
3960 DrawLevelField(jx, jy);
3961 else if (IS_ACCESSIBLE_UNDER(element))
3962 DrawLevelFieldThruMask(jx, jy);
3965 MarkTileDirty(sx, sy);
3968 /* ------------------------------------------------------------------------- */
3970 void WaitForEventToContinue()
3972 boolean still_wait = TRUE;
3974 if (program.headless)
3977 /* simulate releasing mouse button over last gadget, if still pressed */
3979 HandleGadgets(-1, -1, 0);
3981 button_status = MB_RELEASED;
3989 if (NextValidEvent(&event))
3993 case EVENT_BUTTONPRESS:
3994 case EVENT_KEYPRESS:
3995 #if defined(TARGET_SDL2)
3996 case SDL_CONTROLLERBUTTONDOWN:
3998 case SDL_JOYBUTTONDOWN:
4002 case EVENT_KEYRELEASE:
4003 ClearPlayerAction();
4007 HandleOtherEvents(&event);
4011 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
4020 #define MAX_REQUEST_LINES 13
4021 #define MAX_REQUEST_LINE_FONT1_LEN 7
4022 #define MAX_REQUEST_LINE_FONT2_LEN 10
4024 static int RequestHandleEvents(unsigned int req_state)
4026 boolean level_solved = (game_status == GAME_MODE_PLAYING &&
4027 local_player->LevelSolved_GameEnd);
4028 int width = request.width;
4029 int height = request.height;
4033 setRequestPosition(&sx, &sy, FALSE);
4035 button_status = MB_RELEASED;
4037 request_gadget_id = -1;
4044 /* the MM game engine does not use a special (scrollable) field buffer */
4045 if (level.game_engine_type != GAME_ENGINE_TYPE_MM)
4046 SetDrawtoField(DRAW_TO_FIELDBUFFER);
4048 HandleGameActions();
4050 SetDrawtoField(DRAW_TO_BACKBUFFER);
4052 if (global.use_envelope_request)
4054 /* copy current state of request area to middle of playfield area */
4055 BlitBitmap(bitmap_db_store_2, drawto, sx, sy, width, height, sx, sy);
4063 while (NextValidEvent(&event))
4067 case EVENT_BUTTONPRESS:
4068 case EVENT_BUTTONRELEASE:
4069 case EVENT_MOTIONNOTIFY:
4073 if (event.type == EVENT_MOTIONNOTIFY)
4078 motion_status = TRUE;
4079 mx = ((MotionEvent *) &event)->x;
4080 my = ((MotionEvent *) &event)->y;
4084 motion_status = FALSE;
4085 mx = ((ButtonEvent *) &event)->x;
4086 my = ((ButtonEvent *) &event)->y;
4087 if (event.type == EVENT_BUTTONPRESS)
4088 button_status = ((ButtonEvent *) &event)->button;
4090 button_status = MB_RELEASED;
4093 /* this sets 'request_gadget_id' */
4094 HandleGadgets(mx, my, button_status);
4096 switch (request_gadget_id)
4098 case TOOL_CTRL_ID_YES:
4101 case TOOL_CTRL_ID_NO:
4104 case TOOL_CTRL_ID_CONFIRM:
4105 result = TRUE | FALSE;
4108 case TOOL_CTRL_ID_PLAYER_1:
4111 case TOOL_CTRL_ID_PLAYER_2:
4114 case TOOL_CTRL_ID_PLAYER_3:
4117 case TOOL_CTRL_ID_PLAYER_4:
4128 #if defined(TARGET_SDL2)
4129 case SDL_WINDOWEVENT:
4130 HandleWindowEvent((WindowEvent *) &event);
4133 case SDL_APP_WILLENTERBACKGROUND:
4134 case SDL_APP_DIDENTERBACKGROUND:
4135 case SDL_APP_WILLENTERFOREGROUND:
4136 case SDL_APP_DIDENTERFOREGROUND:
4137 HandlePauseResumeEvent((PauseResumeEvent *) &event);
4141 case EVENT_KEYPRESS:
4143 Key key = GetEventKey((KeyEvent *)&event, TRUE);
4148 if (req_state & REQ_CONFIRM)
4153 #if defined(TARGET_SDL2)
4156 #if defined(KSYM_Rewind)
4157 case KSYM_Rewind: /* for Amazon Fire TV remote */
4164 #if defined(TARGET_SDL2)
4166 #if defined(KSYM_FastForward)
4167 case KSYM_FastForward: /* for Amazon Fire TV remote */
4174 HandleKeysDebug(key);
4178 if (req_state & REQ_PLAYER)
4184 case EVENT_KEYRELEASE:
4185 ClearPlayerAction();
4188 #if defined(TARGET_SDL2)
4189 case SDL_CONTROLLERBUTTONDOWN:
4190 switch (event.cbutton.button)
4192 case SDL_CONTROLLER_BUTTON_A:
4193 case SDL_CONTROLLER_BUTTON_X:
4194 case SDL_CONTROLLER_BUTTON_LEFTSHOULDER:
4198 case SDL_CONTROLLER_BUTTON_B:
4199 case SDL_CONTROLLER_BUTTON_Y:
4200 case SDL_CONTROLLER_BUTTON_RIGHTSHOULDER:
4201 case SDL_CONTROLLER_BUTTON_BACK:
4206 if (req_state & REQ_PLAYER)
4211 case SDL_CONTROLLERBUTTONUP:
4212 HandleJoystickEvent(&event);
4213 ClearPlayerAction();
4218 HandleOtherEvents(&event);
4223 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
4225 int joy = AnyJoystick();
4227 if (joy & JOY_BUTTON_1)
4229 else if (joy & JOY_BUTTON_2)
4235 if (global.use_envelope_request)
4237 /* copy back current state of pressed buttons inside request area */
4238 BlitBitmap(drawto, bitmap_db_store_2, sx, sy, width, height, sx, sy);
4248 static boolean RequestDoor(char *text, unsigned int req_state)
4250 unsigned int old_door_state;
4251 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
4252 int font_nr = FONT_TEXT_2;
4257 if (maxWordLengthInString(text) > MAX_REQUEST_LINE_FONT1_LEN)
4259 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
4260 font_nr = FONT_TEXT_1;
4263 if (game_status == GAME_MODE_PLAYING)
4264 BlitScreenToBitmap(backbuffer);
4266 /* disable deactivated drawing when quick-loading level tape recording */
4267 if (tape.playing && tape.deactivate_display)
4268 TapeDeactivateDisplayOff(TRUE);
4270 SetMouseCursor(CURSOR_DEFAULT);
4272 #if defined(NETWORK_AVALIABLE)
4273 /* pause network game while waiting for request to answer */
4274 if (options.network &&
4275 game_status == GAME_MODE_PLAYING &&
4276 req_state & REQUEST_WAIT_FOR_INPUT)
4277 SendToServer_PausePlaying();
4280 old_door_state = GetDoorState();
4282 /* simulate releasing mouse button over last gadget, if still pressed */
4284 HandleGadgets(-1, -1, 0);
4288 /* draw released gadget before proceeding */
4291 if (old_door_state & DOOR_OPEN_1)
4293 CloseDoor(DOOR_CLOSE_1);
4295 /* save old door content */
4296 BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
4297 0 * DXSIZE, 0, DXSIZE, DYSIZE, 1 * DXSIZE, 0);
4300 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
4301 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4303 /* clear door drawing field */
4304 DrawBackground(DX, DY, DXSIZE, DYSIZE);
4306 /* force DOOR font inside door area */
4307 SetFontStatus(GAME_MODE_PSEUDO_DOOR);
4309 /* write text for request */
4310 for (text_ptr = text, ty = 0; ty < MAX_REQUEST_LINES; ty++)
4312 char text_line[max_request_line_len + 1];
4318 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
4320 tc = *(text_ptr + tx);
4321 // if (!tc || tc == ' ')
4322 if (!tc || tc == ' ' || tc == '?' || tc == '!')
4326 if ((tc == '?' || tc == '!') && tl == 0)
4336 strncpy(text_line, text_ptr, tl);
4339 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
4340 DY + 8 + ty * (getFontHeight(font_nr) + 2),
4341 text_line, font_nr);
4343 text_ptr += tl + (tc == ' ' ? 1 : 0);
4344 // text_ptr += tl + (tc == ' ' || tc == '?' || tc == '!' ? 1 : 0);
4349 if (req_state & REQ_ASK)
4351 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
4352 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
4354 else if (req_state & REQ_CONFIRM)
4356 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
4358 else if (req_state & REQ_PLAYER)
4360 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
4361 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
4362 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
4363 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
4366 /* copy request gadgets to door backbuffer */
4367 BlitBitmap(drawto, bitmap_db_door_1, DX, DY, DXSIZE, DYSIZE, 0, 0);
4369 OpenDoor(DOOR_OPEN_1);
4371 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
4373 if (game_status == GAME_MODE_PLAYING)
4375 SetPanelBackground();
4376 SetDrawBackgroundMask(REDRAW_DOOR_1);
4380 SetDrawBackgroundMask(REDRAW_FIELD);
4386 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4388 // ---------- handle request buttons ----------
4389 result = RequestHandleEvents(req_state);
4393 if (!(req_state & REQ_STAY_OPEN))
4395 CloseDoor(DOOR_CLOSE_1);
4397 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
4398 (req_state & REQ_REOPEN))
4399 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
4404 if (game_status == GAME_MODE_PLAYING)
4406 SetPanelBackground();
4407 SetDrawBackgroundMask(REDRAW_DOOR_1);
4411 SetDrawBackgroundMask(REDRAW_FIELD);
4414 #if defined(NETWORK_AVALIABLE)
4415 /* continue network game after request */
4416 if (options.network &&
4417 game_status == GAME_MODE_PLAYING &&
4418 req_state & REQUEST_WAIT_FOR_INPUT)
4419 SendToServer_ContinuePlaying();
4422 /* restore deactivated drawing when quick-loading level tape recording */
4423 if (tape.playing && tape.deactivate_display)
4424 TapeDeactivateDisplayOn();
4429 static boolean RequestEnvelope(char *text, unsigned int req_state)
4433 if (game_status == GAME_MODE_PLAYING)
4434 BlitScreenToBitmap(backbuffer);
4436 /* disable deactivated drawing when quick-loading level tape recording */
4437 if (tape.playing && tape.deactivate_display)
4438 TapeDeactivateDisplayOff(TRUE);
4440 SetMouseCursor(CURSOR_DEFAULT);
4442 #if defined(NETWORK_AVALIABLE)
4443 /* pause network game while waiting for request to answer */
4444 if (options.network &&
4445 game_status == GAME_MODE_PLAYING &&
4446 req_state & REQUEST_WAIT_FOR_INPUT)
4447 SendToServer_PausePlaying();
4450 /* simulate releasing mouse button over last gadget, if still pressed */
4452 HandleGadgets(-1, -1, 0);
4456 // (replace with setting corresponding request background)
4457 // SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
4458 // SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4460 /* clear door drawing field */
4461 // DrawBackground(DX, DY, DXSIZE, DYSIZE);
4463 ShowEnvelopeRequest(text, req_state, ACTION_OPENING);
4465 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
4467 if (game_status == GAME_MODE_PLAYING)
4469 SetPanelBackground();
4470 SetDrawBackgroundMask(REDRAW_DOOR_1);
4474 SetDrawBackgroundMask(REDRAW_FIELD);
4480 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4482 // ---------- handle request buttons ----------
4483 result = RequestHandleEvents(req_state);
4487 ShowEnvelopeRequest(text, req_state, ACTION_CLOSING);
4491 if (game_status == GAME_MODE_PLAYING)
4493 SetPanelBackground();
4494 SetDrawBackgroundMask(REDRAW_DOOR_1);
4498 SetDrawBackgroundMask(REDRAW_FIELD);
4501 #if defined(NETWORK_AVALIABLE)
4502 /* continue network game after request */
4503 if (options.network &&
4504 game_status == GAME_MODE_PLAYING &&
4505 req_state & REQUEST_WAIT_FOR_INPUT)
4506 SendToServer_ContinuePlaying();
4509 /* restore deactivated drawing when quick-loading level tape recording */
4510 if (tape.playing && tape.deactivate_display)
4511 TapeDeactivateDisplayOn();
4516 boolean Request(char *text, unsigned int req_state)
4518 boolean overlay_active = GetOverlayActive();
4521 SetOverlayActive(FALSE);
4523 if (global.use_envelope_request)
4524 result = RequestEnvelope(text, req_state);
4526 result = RequestDoor(text, req_state);
4528 SetOverlayActive(overlay_active);
4533 static int compareDoorPartOrderInfo(const void *object1, const void *object2)
4535 const struct DoorPartOrderInfo *dpo1 = (struct DoorPartOrderInfo *)object1;
4536 const struct DoorPartOrderInfo *dpo2 = (struct DoorPartOrderInfo *)object2;
4539 if (dpo1->sort_priority != dpo2->sort_priority)
4540 compare_result = dpo1->sort_priority - dpo2->sort_priority;
4542 compare_result = dpo1->nr - dpo2->nr;
4544 return compare_result;
4547 void InitGraphicCompatibilityInfo_Doors()
4553 struct DoorInfo *door;
4557 { DOOR_1, IMG_GFX_DOOR_1_PART_1, IMG_GFX_DOOR_1_PART_8, &door_1 },
4558 { DOOR_2, IMG_GFX_DOOR_2_PART_1, IMG_GFX_DOOR_2_PART_8, &door_2 },
4560 { -1, -1, -1, NULL }
4562 struct Rect door_rect_list[] =
4564 { DX, DY, DXSIZE, DYSIZE },
4565 { VX, VY, VXSIZE, VYSIZE }
4569 for (i = 0; doors[i].door_token != -1; i++)
4571 int door_token = doors[i].door_token;
4572 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
4573 int part_1 = doors[i].part_1;
4574 int part_8 = doors[i].part_8;
4575 int part_2 = part_1 + 1;
4576 int part_3 = part_1 + 2;
4577 struct DoorInfo *door = doors[i].door;
4578 struct Rect *door_rect = &door_rect_list[door_index];
4579 boolean door_gfx_redefined = FALSE;
4581 /* check if any door part graphic definitions have been redefined */
4583 for (j = 0; door_part_controls[j].door_token != -1; j++)
4585 struct DoorPartControlInfo *dpc = &door_part_controls[j];
4586 struct FileInfo *fi = getImageListEntryFromImageID(dpc->graphic);
4588 if (dpc->door_token == door_token && fi->redefined)
4589 door_gfx_redefined = TRUE;
4592 /* check for old-style door graphic/animation modifications */
4594 if (!door_gfx_redefined)
4596 if (door->anim_mode & ANIM_STATIC_PANEL)
4598 door->panel.step_xoffset = 0;
4599 door->panel.step_yoffset = 0;
4602 if (door->anim_mode & (ANIM_HORIZONTAL | ANIM_VERTICAL))
4604 struct GraphicInfo *g_part_1 = &graphic_info[part_1];
4605 struct GraphicInfo *g_part_2 = &graphic_info[part_2];
4606 int num_door_steps, num_panel_steps;
4608 /* remove door part graphics other than the two default wings */
4610 for (j = 0; door_part_controls[j].door_token != -1; j++)
4612 struct DoorPartControlInfo *dpc = &door_part_controls[j];
4613 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4615 if (dpc->graphic >= part_3 &&
4616 dpc->graphic <= part_8)
4620 /* set graphics and screen positions of the default wings */
4622 g_part_1->width = door_rect->width;
4623 g_part_1->height = door_rect->height;
4624 g_part_2->width = door_rect->width;
4625 g_part_2->height = door_rect->height;
4626 g_part_2->src_x = door_rect->width;
4627 g_part_2->src_y = g_part_1->src_y;
4629 door->part_2.x = door->part_1.x;
4630 door->part_2.y = door->part_1.y;
4632 if (door->width != -1)
4634 g_part_1->width = door->width;
4635 g_part_2->width = door->width;
4637 // special treatment for graphics and screen position of right wing
4638 g_part_2->src_x += door_rect->width - door->width;
4639 door->part_2.x += door_rect->width - door->width;
4642 if (door->height != -1)
4644 g_part_1->height = door->height;
4645 g_part_2->height = door->height;
4647 // special treatment for graphics and screen position of bottom wing
4648 g_part_2->src_y += door_rect->height - door->height;
4649 door->part_2.y += door_rect->height - door->height;
4652 /* set animation delays for the default wings and panels */
4654 door->part_1.step_delay = door->step_delay;
4655 door->part_2.step_delay = door->step_delay;
4656 door->panel.step_delay = door->step_delay;
4658 /* set animation draw order for the default wings */
4660 door->part_1.sort_priority = 2; /* draw left wing over ... */
4661 door->part_2.sort_priority = 1; /* ... right wing */
4663 /* set animation draw offset for the default wings */
4665 if (door->anim_mode & ANIM_HORIZONTAL)
4667 door->part_1.step_xoffset = door->step_offset;
4668 door->part_1.step_yoffset = 0;
4669 door->part_2.step_xoffset = door->step_offset * -1;
4670 door->part_2.step_yoffset = 0;
4672 num_door_steps = g_part_1->width / door->step_offset;
4674 else // ANIM_VERTICAL
4676 door->part_1.step_xoffset = 0;
4677 door->part_1.step_yoffset = door->step_offset;
4678 door->part_2.step_xoffset = 0;
4679 door->part_2.step_yoffset = door->step_offset * -1;
4681 num_door_steps = g_part_1->height / door->step_offset;
4684 /* set animation draw offset for the default panels */
4686 if (door->step_offset > 1)
4688 num_panel_steps = 2 * door_rect->height / door->step_offset;
4689 door->panel.start_step = num_panel_steps - num_door_steps;
4690 door->panel.start_step_closing = door->panel.start_step;
4694 num_panel_steps = door_rect->height / door->step_offset;
4695 door->panel.start_step = num_panel_steps - num_door_steps / 2;
4696 door->panel.start_step_closing = door->panel.start_step;
4697 door->panel.step_delay *= 2;
4708 for (i = 0; door_part_controls[i].door_token != -1; i++)
4710 struct DoorPartControlInfo *dpc = &door_part_controls[i];
4711 struct DoorPartOrderInfo *dpo = &door_part_order[i];
4713 /* initialize "start_step_opening" and "start_step_closing", if needed */
4714 if (dpc->pos->start_step_opening == 0 &&
4715 dpc->pos->start_step_closing == 0)
4717 // dpc->pos->start_step_opening = dpc->pos->start_step;
4718 dpc->pos->start_step_closing = dpc->pos->start_step;
4721 /* fill structure for door part draw order (sorted below) */
4723 dpo->sort_priority = dpc->pos->sort_priority;
4726 /* sort door part controls according to sort_priority and graphic number */
4727 qsort(door_part_order, MAX_DOOR_PARTS,
4728 sizeof(struct DoorPartOrderInfo), compareDoorPartOrderInfo);
4731 unsigned int OpenDoor(unsigned int door_state)
4733 if (door_state & DOOR_COPY_BACK)
4735 if (door_state & DOOR_OPEN_1)
4736 BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
4737 1 * DXSIZE, 0, DXSIZE, DYSIZE, 0 * DXSIZE, 0);
4739 if (door_state & DOOR_OPEN_2)
4740 BlitBitmap(bitmap_db_door_2, bitmap_db_door_2,
4741 1 * VXSIZE, 0, VXSIZE, VYSIZE, 0 * VXSIZE, 0);
4743 door_state &= ~DOOR_COPY_BACK;
4746 return MoveDoor(door_state);
4749 unsigned int CloseDoor(unsigned int door_state)
4751 unsigned int old_door_state = GetDoorState();
4753 if (!(door_state & DOOR_NO_COPY_BACK))
4755 if (old_door_state & DOOR_OPEN_1)
4756 BlitBitmap(backbuffer, bitmap_db_door_1,
4757 DX, DY, DXSIZE, DYSIZE, 0, 0);
4759 if (old_door_state & DOOR_OPEN_2)
4760 BlitBitmap(backbuffer, bitmap_db_door_2,
4761 VX, VY, VXSIZE, VYSIZE, 0, 0);
4763 door_state &= ~DOOR_NO_COPY_BACK;
4766 return MoveDoor(door_state);
4769 unsigned int GetDoorState()
4771 return MoveDoor(DOOR_GET_STATE);
4774 unsigned int SetDoorState(unsigned int door_state)
4776 return MoveDoor(door_state | DOOR_SET_STATE);
4779 int euclid(int a, int b)
4781 return (b ? euclid(b, a % b) : a);
4784 unsigned int MoveDoor(unsigned int door_state)
4786 struct Rect door_rect_list[] =
4788 { DX, DY, DXSIZE, DYSIZE },
4789 { VX, VY, VXSIZE, VYSIZE }
4791 static int door1 = DOOR_CLOSE_1;
4792 static int door2 = DOOR_CLOSE_2;
4793 unsigned int door_delay = 0;
4794 unsigned int door_delay_value;
4797 if (door_state == DOOR_GET_STATE)
4798 return (door1 | door2);
4800 if (door_state & DOOR_SET_STATE)
4802 if (door_state & DOOR_ACTION_1)
4803 door1 = door_state & DOOR_ACTION_1;
4804 if (door_state & DOOR_ACTION_2)
4805 door2 = door_state & DOOR_ACTION_2;
4807 return (door1 | door2);
4810 if (!(door_state & DOOR_FORCE_REDRAW))
4812 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
4813 door_state &= ~DOOR_OPEN_1;
4814 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
4815 door_state &= ~DOOR_CLOSE_1;
4816 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
4817 door_state &= ~DOOR_OPEN_2;
4818 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
4819 door_state &= ~DOOR_CLOSE_2;
4822 if (global.autoplay_leveldir)
4824 door_state |= DOOR_NO_DELAY;
4825 door_state &= ~DOOR_CLOSE_ALL;
4828 if (game_status == GAME_MODE_EDITOR && !(door_state & DOOR_FORCE_ANIM))
4829 door_state |= DOOR_NO_DELAY;
4831 if (door_state & DOOR_ACTION)
4833 boolean door_panel_drawn[NUM_DOORS];
4834 boolean panel_has_doors[NUM_DOORS];
4835 boolean door_part_skip[MAX_DOOR_PARTS];
4836 boolean door_part_done[MAX_DOOR_PARTS];
4837 boolean door_part_done_all;
4838 int num_steps[MAX_DOOR_PARTS];
4839 int max_move_delay = 0; // delay for complete animations of all doors
4840 int max_step_delay = 0; // delay (ms) between two animation frames
4841 int num_move_steps = 0; // number of animation steps for all doors
4842 int max_move_delay_doors_only = 0; // delay for doors only (no panel)
4843 int num_move_steps_doors_only = 0; // steps for doors only (no panel)
4844 int current_move_delay = 0;
4848 for (i = 0; i < NUM_DOORS; i++)
4849 panel_has_doors[i] = FALSE;
4851 for (i = 0; i < MAX_DOOR_PARTS; i++)
4853 struct DoorPartControlInfo *dpc = &door_part_controls[i];
4854 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4855 int door_token = dpc->door_token;
4857 door_part_done[i] = FALSE;
4858 door_part_skip[i] = (!(door_state & door_token) ||
4862 for (i = 0; i < MAX_DOOR_PARTS; i++)
4864 int nr = door_part_order[i].nr;
4865 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
4866 struct DoorPartPosInfo *pos = dpc->pos;
4867 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4868 int door_token = dpc->door_token;
4869 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
4870 boolean is_panel = DOOR_PART_IS_PANEL(nr);
4871 int step_xoffset = ABS(pos->step_xoffset);
4872 int step_yoffset = ABS(pos->step_yoffset);
4873 int step_delay = pos->step_delay;
4874 int current_door_state = door_state & door_token;
4875 boolean door_opening = ((current_door_state & DOOR_OPEN) != 0);
4876 boolean door_closing = ((current_door_state & DOOR_CLOSE) != 0);
4877 boolean part_opening = (is_panel ? door_closing : door_opening);
4878 int start_step = (part_opening ? pos->start_step_opening :
4879 pos->start_step_closing);
4880 float move_xsize = (step_xoffset ? g->width : 0);
4881 float move_ysize = (step_yoffset ? g->height : 0);
4882 int move_xsteps = (step_xoffset ? ceil(move_xsize / step_xoffset) : 0);
4883 int move_ysteps = (step_yoffset ? ceil(move_ysize / step_yoffset) : 0);
4884 int move_steps = (move_xsteps && move_ysteps ?
4885 MIN(move_xsteps, move_ysteps) :
4886 move_xsteps ? move_xsteps : move_ysteps) - start_step;
4887 int move_delay = move_steps * step_delay;
4889 if (door_part_skip[nr])
4892 max_move_delay = MAX(max_move_delay, move_delay);
4893 max_step_delay = (max_step_delay == 0 ? step_delay :
4894 euclid(max_step_delay, step_delay));
4895 num_steps[nr] = move_steps;
4899 max_move_delay_doors_only = MAX(max_move_delay_doors_only, move_delay);
4901 panel_has_doors[door_index] = TRUE;
4905 max_step_delay = MAX(1, max_step_delay); // prevent division by zero
4907 num_move_steps = max_move_delay / max_step_delay;
4908 num_move_steps_doors_only = max_move_delay_doors_only / max_step_delay;
4910 door_delay_value = max_step_delay;
4912 if ((door_state & DOOR_NO_DELAY) || setup.quick_doors)
4914 start = num_move_steps - 1;
4918 /* opening door sound has priority over simultaneously closing door */
4919 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
4921 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
4923 if (door_state & DOOR_OPEN_1)
4924 PlayMenuSoundStereo(SND_DOOR_1_OPENING, SOUND_MIDDLE);
4925 if (door_state & DOOR_OPEN_2)
4926 PlayMenuSoundStereo(SND_DOOR_2_OPENING, SOUND_MIDDLE);
4928 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
4930 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
4932 if (door_state & DOOR_CLOSE_1)
4933 PlayMenuSoundStereo(SND_DOOR_1_CLOSING, SOUND_MIDDLE);
4934 if (door_state & DOOR_CLOSE_2)
4935 PlayMenuSoundStereo(SND_DOOR_2_CLOSING, SOUND_MIDDLE);
4939 for (k = start; k < num_move_steps; k++)
4941 int last_frame = num_move_steps - 1; // last frame of this "for" loop
4943 door_part_done_all = TRUE;
4945 for (i = 0; i < NUM_DOORS; i++)
4946 door_panel_drawn[i] = FALSE;
4948 for (i = 0; i < MAX_DOOR_PARTS; i++)
4950 int nr = door_part_order[i].nr;
4951 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
4952 struct DoorPartPosInfo *pos = dpc->pos;
4953 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4954 int door_token = dpc->door_token;
4955 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
4956 boolean is_panel = DOOR_PART_IS_PANEL(nr);
4957 boolean is_panel_and_door_has_closed = FALSE;
4958 struct Rect *door_rect = &door_rect_list[door_index];
4959 Bitmap *bitmap_db_door = (door_token == DOOR_1 ? bitmap_db_door_1 :
4961 Bitmap *bitmap = (is_panel ? bitmap_db_door : g->bitmap);
4962 int current_door_state = door_state & door_token;
4963 boolean door_opening = ((current_door_state & DOOR_OPEN) != 0);
4964 boolean door_closing = !door_opening;
4965 boolean part_opening = (is_panel ? door_closing : door_opening);
4966 boolean part_closing = !part_opening;
4967 int start_step = (part_opening ? pos->start_step_opening :
4968 pos->start_step_closing);
4969 int step_delay = pos->step_delay;
4970 int step_factor = step_delay / max_step_delay;
4971 int k1 = (step_factor ? k / step_factor + 1 : k);
4972 int k2 = (part_opening ? k1 + start_step : num_steps[nr] - k1);
4973 int kk = MAX(0, k2);
4976 int src_x, src_y, src_xx, src_yy;
4977 int dst_x, dst_y, dst_xx, dst_yy;
4980 if (door_part_skip[nr])
4983 if (!(door_state & door_token))
4991 int k2_door = (door_opening ? k : num_move_steps_doors_only - k - 1);
4992 int kk_door = MAX(0, k2_door);
4993 int sync_frame = kk_door * door_delay_value;
4994 int frame = getGraphicAnimationFrame(dpc->graphic, sync_frame);
4996 getFixedGraphicSource(dpc->graphic, frame, &bitmap,
4997 &g_src_x, &g_src_y);
5002 if (!door_panel_drawn[door_index])
5004 ClearRectangle(drawto, door_rect->x, door_rect->y,
5005 door_rect->width, door_rect->height);
5007 door_panel_drawn[door_index] = TRUE;
5010 // draw opening or closing door parts
5012 if (pos->step_xoffset < 0) // door part on right side
5015 dst_xx = pos->x + ABS(kk * pos->step_xoffset);
5018 if (dst_xx + width > door_rect->width)
5019 width = door_rect->width - dst_xx;
5021 else // door part on left side
5024 dst_xx = pos->x - kk * pos->step_xoffset;
5028 src_xx = ABS(dst_xx);
5032 width = g->width - src_xx;
5034 if (width > door_rect->width)
5035 width = door_rect->width;
5037 // printf("::: k == %d [%d] \n", k, start_step);
5040 if (pos->step_yoffset < 0) // door part on bottom side
5043 dst_yy = pos->y + ABS(kk * pos->step_yoffset);
5046 if (dst_yy + height > door_rect->height)
5047 height = door_rect->height - dst_yy;
5049 else // door part on top side
5052 dst_yy = pos->y - kk * pos->step_yoffset;
5056 src_yy = ABS(dst_yy);
5060 height = g->height - src_yy;
5063 src_x = g_src_x + src_xx;
5064 src_y = g_src_y + src_yy;
5066 dst_x = door_rect->x + dst_xx;
5067 dst_y = door_rect->y + dst_yy;
5069 is_panel_and_door_has_closed =
5072 panel_has_doors[door_index] &&
5073 k >= num_move_steps_doors_only - 1);
5075 if (width >= 0 && width <= g->width &&
5076 height >= 0 && height <= g->height &&
5077 !is_panel_and_door_has_closed)
5079 if (is_panel || !pos->draw_masked)
5080 BlitBitmap(bitmap, drawto, src_x, src_y, width, height,
5083 BlitBitmapMasked(bitmap, drawto, src_x, src_y, width, height,
5087 redraw_mask |= REDRAW_DOOR_FROM_TOKEN(door_token);
5089 if ((part_opening && (width < 0 || height < 0)) ||
5090 (part_closing && (width >= g->width && height >= g->height)))
5091 door_part_done[nr] = TRUE;
5093 // continue door part animations, but not panel after door has closed
5094 if (!door_part_done[nr] && !is_panel_and_door_has_closed)
5095 door_part_done_all = FALSE;
5098 if (!(door_state & DOOR_NO_DELAY))
5102 SkipUntilDelayReached(&door_delay, door_delay_value, &k, last_frame);
5104 current_move_delay += max_step_delay;
5106 /* prevent OS (Windows) from complaining about program not responding */
5110 if (door_part_done_all)
5114 if (!(door_state & DOOR_NO_DELAY))
5116 /* wait for specified door action post delay */
5117 if (door_state & DOOR_ACTION_1 && door_state & DOOR_ACTION_2)
5118 Delay(MAX(door_1.post_delay, door_2.post_delay));
5119 else if (door_state & DOOR_ACTION_1)
5120 Delay(door_1.post_delay);
5121 else if (door_state & DOOR_ACTION_2)
5122 Delay(door_2.post_delay);
5126 if (door_state & DOOR_ACTION_1)
5127 door1 = door_state & DOOR_ACTION_1;
5128 if (door_state & DOOR_ACTION_2)
5129 door2 = door_state & DOOR_ACTION_2;
5131 // draw masked border over door area
5132 DrawMaskedBorder(REDRAW_DOOR_1);
5133 DrawMaskedBorder(REDRAW_DOOR_2);
5135 return (door1 | door2);
5138 static boolean useSpecialEditorDoor()
5140 int graphic = IMG_GLOBAL_BORDER_EDITOR;
5141 boolean redefined = getImageListEntryFromImageID(graphic)->redefined;
5143 // do not draw special editor door if editor border defined or redefined
5144 if (graphic_info[graphic].bitmap != NULL || redefined)
5147 // do not draw special editor door if global border defined to be empty
5148 if (graphic_info[IMG_GLOBAL_BORDER].bitmap == NULL)
5151 // do not draw special editor door if viewport definitions do not match
5155 EY + EYSIZE != VY + VYSIZE)
5161 void DrawSpecialEditorDoor()
5163 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
5164 int top_border_width = gfx1->width;
5165 int top_border_height = gfx1->height;
5166 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
5167 int ex = EX - outer_border;
5168 int ey = EY - outer_border;
5169 int vy = VY - outer_border;
5170 int exsize = EXSIZE + 2 * outer_border;
5172 if (!useSpecialEditorDoor())
5175 /* draw bigger level editor toolbox window */
5176 BlitBitmap(gfx1->bitmap, drawto, gfx1->src_x, gfx1->src_y,
5177 top_border_width, top_border_height, ex, ey - top_border_height);
5178 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto, ex, vy,
5179 exsize, EYSIZE - VYSIZE + outer_border, ex, ey);
5181 redraw_mask |= REDRAW_ALL;
5184 void UndrawSpecialEditorDoor()
5186 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
5187 int top_border_width = gfx1->width;
5188 int top_border_height = gfx1->height;
5189 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
5190 int ex = EX - outer_border;
5191 int ey = EY - outer_border;
5192 int ey_top = ey - top_border_height;
5193 int exsize = EXSIZE + 2 * outer_border;
5194 int eysize = EYSIZE + 2 * outer_border;
5196 if (!useSpecialEditorDoor())
5199 /* draw normal tape recorder window */
5200 if (graphic_info[IMG_GLOBAL_BORDER].bitmap)
5202 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
5203 ex, ey_top, top_border_width, top_border_height,
5205 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
5206 ex, ey, exsize, eysize, ex, ey);
5210 // if screen background is set to "[NONE]", clear editor toolbox window
5211 ClearRectangle(drawto, ex, ey_top, top_border_width, top_border_height);
5212 ClearRectangle(drawto, ex, ey, exsize, eysize);
5215 redraw_mask |= REDRAW_ALL;
5219 /* ---------- new tool button stuff ---------------------------------------- */
5224 struct TextPosInfo *pos;
5227 } toolbutton_info[NUM_TOOL_BUTTONS] =
5230 IMG_GFX_REQUEST_BUTTON_YES, &request.button.yes,
5231 TOOL_CTRL_ID_YES, "yes"
5234 IMG_GFX_REQUEST_BUTTON_NO, &request.button.no,
5235 TOOL_CTRL_ID_NO, "no"
5238 IMG_GFX_REQUEST_BUTTON_CONFIRM, &request.button.confirm,
5239 TOOL_CTRL_ID_CONFIRM, "confirm"
5242 IMG_GFX_REQUEST_BUTTON_PLAYER_1, &request.button.player_1,
5243 TOOL_CTRL_ID_PLAYER_1, "player 1"
5246 IMG_GFX_REQUEST_BUTTON_PLAYER_2, &request.button.player_2,
5247 TOOL_CTRL_ID_PLAYER_2, "player 2"
5250 IMG_GFX_REQUEST_BUTTON_PLAYER_3, &request.button.player_3,
5251 TOOL_CTRL_ID_PLAYER_3, "player 3"
5254 IMG_GFX_REQUEST_BUTTON_PLAYER_4, &request.button.player_4,
5255 TOOL_CTRL_ID_PLAYER_4, "player 4"
5259 void CreateToolButtons()
5263 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
5265 struct GraphicInfo *gfx = &graphic_info[toolbutton_info[i].graphic];
5266 struct TextPosInfo *pos = toolbutton_info[i].pos;
5267 struct GadgetInfo *gi;
5268 Bitmap *deco_bitmap = None;
5269 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
5270 unsigned int event_mask = GD_EVENT_RELEASED;
5273 int gd_x = gfx->src_x;
5274 int gd_y = gfx->src_y;
5275 int gd_xp = gfx->src_x + gfx->pressed_xoffset;
5276 int gd_yp = gfx->src_y + gfx->pressed_yoffset;
5279 if (global.use_envelope_request)
5280 setRequestPosition(&dx, &dy, TRUE);
5282 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
5284 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
5286 getSizedGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr), 0,
5287 pos->size, &deco_bitmap, &deco_x, &deco_y);
5288 deco_xpos = (gfx->width - pos->size) / 2;
5289 deco_ypos = (gfx->height - pos->size) / 2;
5292 gi = CreateGadget(GDI_CUSTOM_ID, id,
5293 GDI_INFO_TEXT, toolbutton_info[i].infotext,
5294 GDI_X, dx + GDI_ACTIVE_POS(pos->x),
5295 GDI_Y, dy + GDI_ACTIVE_POS(pos->y),
5296 GDI_WIDTH, gfx->width,
5297 GDI_HEIGHT, gfx->height,
5298 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
5299 GDI_STATE, GD_BUTTON_UNPRESSED,
5300 GDI_DESIGN_UNPRESSED, gfx->bitmap, gd_x, gd_y,
5301 GDI_DESIGN_PRESSED, gfx->bitmap, gd_xp, gd_yp,
5302 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
5303 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
5304 GDI_DECORATION_SIZE, pos->size, pos->size,
5305 GDI_DECORATION_SHIFTING, 1, 1,
5306 GDI_DIRECT_DRAW, FALSE,
5307 GDI_EVENT_MASK, event_mask,
5308 GDI_CALLBACK_ACTION, HandleToolButtons,
5312 Error(ERR_EXIT, "cannot create gadget");
5314 tool_gadget[id] = gi;
5318 void FreeToolButtons()
5322 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
5323 FreeGadget(tool_gadget[i]);
5326 static void UnmapToolButtons()
5330 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
5331 UnmapGadget(tool_gadget[i]);
5334 static void HandleToolButtons(struct GadgetInfo *gi)
5336 request_gadget_id = gi->custom_id;
5339 static struct Mapping_EM_to_RND_object
5342 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
5343 boolean is_backside; /* backside of moving element */
5349 em_object_mapping_list[] =
5352 Xblank, TRUE, FALSE,
5356 Yacid_splash_eB, FALSE, FALSE,
5357 EL_ACID_SPLASH_RIGHT, -1, -1
5360 Yacid_splash_wB, FALSE, FALSE,
5361 EL_ACID_SPLASH_LEFT, -1, -1
5364 #ifdef EM_ENGINE_BAD_ROLL
5366 Xstone_force_e, FALSE, FALSE,
5367 EL_ROCK, -1, MV_BIT_RIGHT
5370 Xstone_force_w, FALSE, FALSE,
5371 EL_ROCK, -1, MV_BIT_LEFT
5374 Xnut_force_e, FALSE, FALSE,
5375 EL_NUT, -1, MV_BIT_RIGHT
5378 Xnut_force_w, FALSE, FALSE,
5379 EL_NUT, -1, MV_BIT_LEFT
5382 Xspring_force_e, FALSE, FALSE,
5383 EL_SPRING, -1, MV_BIT_RIGHT
5386 Xspring_force_w, FALSE, FALSE,
5387 EL_SPRING, -1, MV_BIT_LEFT
5390 Xemerald_force_e, FALSE, FALSE,
5391 EL_EMERALD, -1, MV_BIT_RIGHT
5394 Xemerald_force_w, FALSE, FALSE,
5395 EL_EMERALD, -1, MV_BIT_LEFT
5398 Xdiamond_force_e, FALSE, FALSE,
5399 EL_DIAMOND, -1, MV_BIT_RIGHT
5402 Xdiamond_force_w, FALSE, FALSE,
5403 EL_DIAMOND, -1, MV_BIT_LEFT
5406 Xbomb_force_e, FALSE, FALSE,
5407 EL_BOMB, -1, MV_BIT_RIGHT
5410 Xbomb_force_w, FALSE, FALSE,
5411 EL_BOMB, -1, MV_BIT_LEFT
5413 #endif /* EM_ENGINE_BAD_ROLL */
5416 Xstone, TRUE, FALSE,
5420 Xstone_pause, FALSE, FALSE,
5424 Xstone_fall, FALSE, FALSE,
5428 Ystone_s, FALSE, FALSE,
5429 EL_ROCK, ACTION_FALLING, -1
5432 Ystone_sB, FALSE, TRUE,
5433 EL_ROCK, ACTION_FALLING, -1
5436 Ystone_e, FALSE, FALSE,
5437 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
5440 Ystone_eB, FALSE, TRUE,
5441 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
5444 Ystone_w, FALSE, FALSE,
5445 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
5448 Ystone_wB, FALSE, TRUE,
5449 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
5456 Xnut_pause, FALSE, FALSE,
5460 Xnut_fall, FALSE, FALSE,
5464 Ynut_s, FALSE, FALSE,
5465 EL_NUT, ACTION_FALLING, -1
5468 Ynut_sB, FALSE, TRUE,
5469 EL_NUT, ACTION_FALLING, -1
5472 Ynut_e, FALSE, FALSE,
5473 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
5476 Ynut_eB, FALSE, TRUE,
5477 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
5480 Ynut_w, FALSE, FALSE,
5481 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
5484 Ynut_wB, FALSE, TRUE,
5485 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
5488 Xbug_n, TRUE, FALSE,
5492 Xbug_e, TRUE, FALSE,
5493 EL_BUG_RIGHT, -1, -1
5496 Xbug_s, TRUE, FALSE,
5500 Xbug_w, TRUE, FALSE,
5504 Xbug_gon, FALSE, FALSE,
5508 Xbug_goe, FALSE, FALSE,
5509 EL_BUG_RIGHT, -1, -1
5512 Xbug_gos, FALSE, FALSE,
5516 Xbug_gow, FALSE, FALSE,
5520 Ybug_n, FALSE, FALSE,
5521 EL_BUG, ACTION_MOVING, MV_BIT_UP
5524 Ybug_nB, FALSE, TRUE,
5525 EL_BUG, ACTION_MOVING, MV_BIT_UP
5528 Ybug_e, FALSE, FALSE,
5529 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
5532 Ybug_eB, FALSE, TRUE,
5533 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
5536 Ybug_s, FALSE, FALSE,
5537 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
5540 Ybug_sB, FALSE, TRUE,
5541 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
5544 Ybug_w, FALSE, FALSE,
5545 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
5548 Ybug_wB, FALSE, TRUE,
5549 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
5552 Ybug_w_n, FALSE, FALSE,
5553 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
5556 Ybug_n_e, FALSE, FALSE,
5557 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
5560 Ybug_e_s, FALSE, FALSE,
5561 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
5564 Ybug_s_w, FALSE, FALSE,
5565 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
5568 Ybug_e_n, FALSE, FALSE,
5569 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
5572 Ybug_s_e, FALSE, FALSE,
5573 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
5576 Ybug_w_s, FALSE, FALSE,
5577 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
5580 Ybug_n_w, FALSE, FALSE,
5581 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
5584 Ybug_stone, FALSE, FALSE,
5585 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
5588 Ybug_spring, FALSE, FALSE,
5589 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
5592 Xtank_n, TRUE, FALSE,
5593 EL_SPACESHIP_UP, -1, -1
5596 Xtank_e, TRUE, FALSE,
5597 EL_SPACESHIP_RIGHT, -1, -1
5600 Xtank_s, TRUE, FALSE,
5601 EL_SPACESHIP_DOWN, -1, -1
5604 Xtank_w, TRUE, FALSE,
5605 EL_SPACESHIP_LEFT, -1, -1
5608 Xtank_gon, FALSE, FALSE,
5609 EL_SPACESHIP_UP, -1, -1
5612 Xtank_goe, FALSE, FALSE,
5613 EL_SPACESHIP_RIGHT, -1, -1
5616 Xtank_gos, FALSE, FALSE,
5617 EL_SPACESHIP_DOWN, -1, -1
5620 Xtank_gow, FALSE, FALSE,
5621 EL_SPACESHIP_LEFT, -1, -1
5624 Ytank_n, FALSE, FALSE,
5625 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
5628 Ytank_nB, FALSE, TRUE,
5629 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
5632 Ytank_e, FALSE, FALSE,
5633 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
5636 Ytank_eB, FALSE, TRUE,
5637 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
5640 Ytank_s, FALSE, FALSE,
5641 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
5644 Ytank_sB, FALSE, TRUE,
5645 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
5648 Ytank_w, FALSE, FALSE,
5649 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
5652 Ytank_wB, FALSE, TRUE,
5653 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
5656 Ytank_w_n, FALSE, FALSE,
5657 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
5660 Ytank_n_e, FALSE, FALSE,
5661 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
5664 Ytank_e_s, FALSE, FALSE,
5665 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
5668 Ytank_s_w, FALSE, FALSE,
5669 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
5672 Ytank_e_n, FALSE, FALSE,
5673 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
5676 Ytank_s_e, FALSE, FALSE,
5677 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
5680 Ytank_w_s, FALSE, FALSE,
5681 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
5684 Ytank_n_w, FALSE, FALSE,
5685 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
5688 Ytank_stone, FALSE, FALSE,
5689 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
5692 Ytank_spring, FALSE, FALSE,
5693 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
5696 Xandroid, TRUE, FALSE,
5697 EL_EMC_ANDROID, ACTION_ACTIVE, -1
5700 Xandroid_1_n, FALSE, FALSE,
5701 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
5704 Xandroid_2_n, FALSE, FALSE,
5705 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
5708 Xandroid_1_e, FALSE, FALSE,
5709 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
5712 Xandroid_2_e, FALSE, FALSE,
5713 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
5716 Xandroid_1_w, FALSE, FALSE,
5717 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
5720 Xandroid_2_w, FALSE, FALSE,
5721 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
5724 Xandroid_1_s, FALSE, FALSE,
5725 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
5728 Xandroid_2_s, FALSE, FALSE,
5729 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
5732 Yandroid_n, FALSE, FALSE,
5733 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
5736 Yandroid_nB, FALSE, TRUE,
5737 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
5740 Yandroid_ne, FALSE, FALSE,
5741 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
5744 Yandroid_neB, FALSE, TRUE,
5745 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
5748 Yandroid_e, FALSE, FALSE,
5749 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
5752 Yandroid_eB, FALSE, TRUE,
5753 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
5756 Yandroid_se, FALSE, FALSE,
5757 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
5760 Yandroid_seB, FALSE, TRUE,
5761 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
5764 Yandroid_s, FALSE, FALSE,
5765 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
5768 Yandroid_sB, FALSE, TRUE,
5769 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
5772 Yandroid_sw, FALSE, FALSE,
5773 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
5776 Yandroid_swB, FALSE, TRUE,
5777 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
5780 Yandroid_w, FALSE, FALSE,
5781 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
5784 Yandroid_wB, FALSE, TRUE,
5785 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
5788 Yandroid_nw, FALSE, FALSE,
5789 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
5792 Yandroid_nwB, FALSE, TRUE,
5793 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
5796 Xspring, TRUE, FALSE,
5800 Xspring_pause, FALSE, FALSE,
5804 Xspring_e, FALSE, FALSE,
5808 Xspring_w, FALSE, FALSE,
5812 Xspring_fall, FALSE, FALSE,
5816 Yspring_s, FALSE, FALSE,
5817 EL_SPRING, ACTION_FALLING, -1
5820 Yspring_sB, FALSE, TRUE,
5821 EL_SPRING, ACTION_FALLING, -1
5824 Yspring_e, FALSE, FALSE,
5825 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
5828 Yspring_eB, FALSE, TRUE,
5829 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
5832 Yspring_w, FALSE, FALSE,
5833 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
5836 Yspring_wB, FALSE, TRUE,
5837 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
5840 Yspring_kill_e, FALSE, FALSE,
5841 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
5844 Yspring_kill_eB, FALSE, TRUE,
5845 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
5848 Yspring_kill_w, FALSE, FALSE,
5849 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
5852 Yspring_kill_wB, FALSE, TRUE,
5853 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
5856 Xeater_n, TRUE, FALSE,
5857 EL_YAMYAM_UP, -1, -1
5860 Xeater_e, TRUE, FALSE,
5861 EL_YAMYAM_RIGHT, -1, -1
5864 Xeater_w, TRUE, FALSE,
5865 EL_YAMYAM_LEFT, -1, -1
5868 Xeater_s, TRUE, FALSE,
5869 EL_YAMYAM_DOWN, -1, -1
5872 Yeater_n, FALSE, FALSE,
5873 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
5876 Yeater_nB, FALSE, TRUE,
5877 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
5880 Yeater_e, FALSE, FALSE,
5881 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
5884 Yeater_eB, FALSE, TRUE,
5885 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
5888 Yeater_s, FALSE, FALSE,
5889 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
5892 Yeater_sB, FALSE, TRUE,
5893 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
5896 Yeater_w, FALSE, FALSE,
5897 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
5900 Yeater_wB, FALSE, TRUE,
5901 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
5904 Yeater_stone, FALSE, FALSE,
5905 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
5908 Yeater_spring, FALSE, FALSE,
5909 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
5912 Xalien, TRUE, FALSE,
5916 Xalien_pause, FALSE, FALSE,
5920 Yalien_n, FALSE, FALSE,
5921 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
5924 Yalien_nB, FALSE, TRUE,
5925 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
5928 Yalien_e, FALSE, FALSE,
5929 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
5932 Yalien_eB, FALSE, TRUE,
5933 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
5936 Yalien_s, FALSE, FALSE,
5937 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
5940 Yalien_sB, FALSE, TRUE,
5941 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
5944 Yalien_w, FALSE, FALSE,
5945 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
5948 Yalien_wB, FALSE, TRUE,
5949 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
5952 Yalien_stone, FALSE, FALSE,
5953 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
5956 Yalien_spring, FALSE, FALSE,
5957 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
5960 Xemerald, TRUE, FALSE,
5964 Xemerald_pause, FALSE, FALSE,
5968 Xemerald_fall, FALSE, FALSE,
5972 Xemerald_shine, FALSE, FALSE,
5973 EL_EMERALD, ACTION_TWINKLING, -1
5976 Yemerald_s, FALSE, FALSE,
5977 EL_EMERALD, ACTION_FALLING, -1
5980 Yemerald_sB, FALSE, TRUE,
5981 EL_EMERALD, ACTION_FALLING, -1
5984 Yemerald_e, FALSE, FALSE,
5985 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
5988 Yemerald_eB, FALSE, TRUE,
5989 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
5992 Yemerald_w, FALSE, FALSE,
5993 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
5996 Yemerald_wB, FALSE, TRUE,
5997 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
6000 Yemerald_eat, FALSE, FALSE,
6001 EL_EMERALD, ACTION_COLLECTING, -1
6004 Yemerald_stone, FALSE, FALSE,
6005 EL_NUT, ACTION_BREAKING, -1
6008 Xdiamond, TRUE, FALSE,
6012 Xdiamond_pause, FALSE, FALSE,
6016 Xdiamond_fall, FALSE, FALSE,
6020 Xdiamond_shine, FALSE, FALSE,
6021 EL_DIAMOND, ACTION_TWINKLING, -1
6024 Ydiamond_s, FALSE, FALSE,
6025 EL_DIAMOND, ACTION_FALLING, -1
6028 Ydiamond_sB, FALSE, TRUE,
6029 EL_DIAMOND, ACTION_FALLING, -1
6032 Ydiamond_e, FALSE, FALSE,
6033 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
6036 Ydiamond_eB, FALSE, TRUE,
6037 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
6040 Ydiamond_w, FALSE, FALSE,
6041 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
6044 Ydiamond_wB, FALSE, TRUE,
6045 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
6048 Ydiamond_eat, FALSE, FALSE,
6049 EL_DIAMOND, ACTION_COLLECTING, -1
6052 Ydiamond_stone, FALSE, FALSE,
6053 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
6056 Xdrip_fall, TRUE, FALSE,
6057 EL_AMOEBA_DROP, -1, -1
6060 Xdrip_stretch, FALSE, FALSE,
6061 EL_AMOEBA_DROP, ACTION_FALLING, -1
6064 Xdrip_stretchB, FALSE, TRUE,
6065 EL_AMOEBA_DROP, ACTION_FALLING, -1
6068 Xdrip_eat, FALSE, FALSE,
6069 EL_AMOEBA_DROP, ACTION_GROWING, -1
6072 Ydrip_s1, FALSE, FALSE,
6073 EL_AMOEBA_DROP, ACTION_FALLING, -1
6076 Ydrip_s1B, FALSE, TRUE,
6077 EL_AMOEBA_DROP, ACTION_FALLING, -1
6080 Ydrip_s2, FALSE, FALSE,
6081 EL_AMOEBA_DROP, ACTION_FALLING, -1
6084 Ydrip_s2B, FALSE, TRUE,
6085 EL_AMOEBA_DROP, ACTION_FALLING, -1
6092 Xbomb_pause, FALSE, FALSE,
6096 Xbomb_fall, FALSE, FALSE,
6100 Ybomb_s, FALSE, FALSE,
6101 EL_BOMB, ACTION_FALLING, -1
6104 Ybomb_sB, FALSE, TRUE,
6105 EL_BOMB, ACTION_FALLING, -1
6108 Ybomb_e, FALSE, FALSE,
6109 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
6112 Ybomb_eB, FALSE, TRUE,
6113 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
6116 Ybomb_w, FALSE, FALSE,
6117 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
6120 Ybomb_wB, FALSE, TRUE,
6121 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
6124 Ybomb_eat, FALSE, FALSE,
6125 EL_BOMB, ACTION_ACTIVATING, -1
6128 Xballoon, TRUE, FALSE,
6132 Yballoon_n, FALSE, FALSE,
6133 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
6136 Yballoon_nB, FALSE, TRUE,
6137 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
6140 Yballoon_e, FALSE, FALSE,
6141 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
6144 Yballoon_eB, FALSE, TRUE,
6145 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
6148 Yballoon_s, FALSE, FALSE,
6149 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
6152 Yballoon_sB, FALSE, TRUE,
6153 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
6156 Yballoon_w, FALSE, FALSE,
6157 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
6160 Yballoon_wB, FALSE, TRUE,
6161 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
6164 Xgrass, TRUE, FALSE,
6165 EL_EMC_GRASS, -1, -1
6168 Ygrass_nB, FALSE, FALSE,
6169 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
6172 Ygrass_eB, FALSE, FALSE,
6173 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
6176 Ygrass_sB, FALSE, FALSE,
6177 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
6180 Ygrass_wB, FALSE, FALSE,
6181 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
6188 Ydirt_nB, FALSE, FALSE,
6189 EL_SAND, ACTION_DIGGING, MV_BIT_UP
6192 Ydirt_eB, FALSE, FALSE,
6193 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
6196 Ydirt_sB, FALSE, FALSE,
6197 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
6200 Ydirt_wB, FALSE, FALSE,
6201 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
6204 Xacid_ne, TRUE, FALSE,
6205 EL_ACID_POOL_TOPRIGHT, -1, -1
6208 Xacid_se, TRUE, FALSE,
6209 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
6212 Xacid_s, TRUE, FALSE,
6213 EL_ACID_POOL_BOTTOM, -1, -1
6216 Xacid_sw, TRUE, FALSE,
6217 EL_ACID_POOL_BOTTOMLEFT, -1, -1
6220 Xacid_nw, TRUE, FALSE,
6221 EL_ACID_POOL_TOPLEFT, -1, -1
6224 Xacid_1, TRUE, FALSE,
6228 Xacid_2, FALSE, FALSE,
6232 Xacid_3, FALSE, FALSE,
6236 Xacid_4, FALSE, FALSE,
6240 Xacid_5, FALSE, FALSE,
6244 Xacid_6, FALSE, FALSE,
6248 Xacid_7, FALSE, FALSE,
6252 Xacid_8, FALSE, FALSE,
6256 Xball_1, TRUE, FALSE,
6257 EL_EMC_MAGIC_BALL, -1, -1
6260 Xball_1B, FALSE, FALSE,
6261 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
6264 Xball_2, FALSE, FALSE,
6265 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
6268 Xball_2B, FALSE, FALSE,
6269 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
6272 Yball_eat, FALSE, FALSE,
6273 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
6276 Ykey_1_eat, FALSE, FALSE,
6277 EL_EM_KEY_1, ACTION_COLLECTING, -1
6280 Ykey_2_eat, FALSE, FALSE,
6281 EL_EM_KEY_2, ACTION_COLLECTING, -1
6284 Ykey_3_eat, FALSE, FALSE,
6285 EL_EM_KEY_3, ACTION_COLLECTING, -1
6288 Ykey_4_eat, FALSE, FALSE,
6289 EL_EM_KEY_4, ACTION_COLLECTING, -1
6292 Ykey_5_eat, FALSE, FALSE,
6293 EL_EMC_KEY_5, ACTION_COLLECTING, -1
6296 Ykey_6_eat, FALSE, FALSE,
6297 EL_EMC_KEY_6, ACTION_COLLECTING, -1
6300 Ykey_7_eat, FALSE, FALSE,
6301 EL_EMC_KEY_7, ACTION_COLLECTING, -1
6304 Ykey_8_eat, FALSE, FALSE,
6305 EL_EMC_KEY_8, ACTION_COLLECTING, -1
6308 Ylenses_eat, FALSE, FALSE,
6309 EL_EMC_LENSES, ACTION_COLLECTING, -1
6312 Ymagnify_eat, FALSE, FALSE,
6313 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
6316 Ygrass_eat, FALSE, FALSE,
6317 EL_EMC_GRASS, ACTION_SNAPPING, -1
6320 Ydirt_eat, FALSE, FALSE,
6321 EL_SAND, ACTION_SNAPPING, -1
6324 Xgrow_ns, TRUE, FALSE,
6325 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
6328 Ygrow_ns_eat, FALSE, FALSE,
6329 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
6332 Xgrow_ew, TRUE, FALSE,
6333 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
6336 Ygrow_ew_eat, FALSE, FALSE,
6337 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
6340 Xwonderwall, TRUE, FALSE,
6341 EL_MAGIC_WALL, -1, -1
6344 XwonderwallB, FALSE, FALSE,
6345 EL_MAGIC_WALL, ACTION_ACTIVE, -1
6348 Xamoeba_1, TRUE, FALSE,
6349 EL_AMOEBA_DRY, ACTION_OTHER, -1
6352 Xamoeba_2, FALSE, FALSE,
6353 EL_AMOEBA_DRY, ACTION_OTHER, -1
6356 Xamoeba_3, FALSE, FALSE,
6357 EL_AMOEBA_DRY, ACTION_OTHER, -1
6360 Xamoeba_4, FALSE, FALSE,
6361 EL_AMOEBA_DRY, ACTION_OTHER, -1
6364 Xamoeba_5, TRUE, FALSE,
6365 EL_AMOEBA_WET, ACTION_OTHER, -1
6368 Xamoeba_6, FALSE, FALSE,
6369 EL_AMOEBA_WET, ACTION_OTHER, -1
6372 Xamoeba_7, FALSE, FALSE,
6373 EL_AMOEBA_WET, ACTION_OTHER, -1
6376 Xamoeba_8, FALSE, FALSE,
6377 EL_AMOEBA_WET, ACTION_OTHER, -1
6380 Xdoor_1, TRUE, FALSE,
6381 EL_EM_GATE_1, -1, -1
6384 Xdoor_2, TRUE, FALSE,
6385 EL_EM_GATE_2, -1, -1
6388 Xdoor_3, TRUE, FALSE,
6389 EL_EM_GATE_3, -1, -1
6392 Xdoor_4, TRUE, FALSE,
6393 EL_EM_GATE_4, -1, -1
6396 Xdoor_5, TRUE, FALSE,
6397 EL_EMC_GATE_5, -1, -1
6400 Xdoor_6, TRUE, FALSE,
6401 EL_EMC_GATE_6, -1, -1
6404 Xdoor_7, TRUE, FALSE,
6405 EL_EMC_GATE_7, -1, -1
6408 Xdoor_8, TRUE, FALSE,
6409 EL_EMC_GATE_8, -1, -1
6412 Xkey_1, TRUE, FALSE,
6416 Xkey_2, TRUE, FALSE,
6420 Xkey_3, TRUE, FALSE,
6424 Xkey_4, TRUE, FALSE,
6428 Xkey_5, TRUE, FALSE,
6429 EL_EMC_KEY_5, -1, -1
6432 Xkey_6, TRUE, FALSE,
6433 EL_EMC_KEY_6, -1, -1
6436 Xkey_7, TRUE, FALSE,
6437 EL_EMC_KEY_7, -1, -1
6440 Xkey_8, TRUE, FALSE,
6441 EL_EMC_KEY_8, -1, -1
6444 Xwind_n, TRUE, FALSE,
6445 EL_BALLOON_SWITCH_UP, -1, -1
6448 Xwind_e, TRUE, FALSE,
6449 EL_BALLOON_SWITCH_RIGHT, -1, -1
6452 Xwind_s, TRUE, FALSE,
6453 EL_BALLOON_SWITCH_DOWN, -1, -1
6456 Xwind_w, TRUE, FALSE,
6457 EL_BALLOON_SWITCH_LEFT, -1, -1
6460 Xwind_nesw, TRUE, FALSE,
6461 EL_BALLOON_SWITCH_ANY, -1, -1
6464 Xwind_stop, TRUE, FALSE,
6465 EL_BALLOON_SWITCH_NONE, -1, -1
6469 EL_EM_EXIT_CLOSED, -1, -1
6472 Xexit_1, TRUE, FALSE,
6473 EL_EM_EXIT_OPEN, -1, -1
6476 Xexit_2, FALSE, FALSE,
6477 EL_EM_EXIT_OPEN, -1, -1
6480 Xexit_3, FALSE, FALSE,
6481 EL_EM_EXIT_OPEN, -1, -1
6484 Xdynamite, TRUE, FALSE,
6485 EL_EM_DYNAMITE, -1, -1
6488 Ydynamite_eat, FALSE, FALSE,
6489 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
6492 Xdynamite_1, TRUE, FALSE,
6493 EL_EM_DYNAMITE_ACTIVE, -1, -1
6496 Xdynamite_2, FALSE, FALSE,
6497 EL_EM_DYNAMITE_ACTIVE, -1, -1
6500 Xdynamite_3, FALSE, FALSE,
6501 EL_EM_DYNAMITE_ACTIVE, -1, -1
6504 Xdynamite_4, FALSE, FALSE,
6505 EL_EM_DYNAMITE_ACTIVE, -1, -1
6508 Xbumper, TRUE, FALSE,
6509 EL_EMC_SPRING_BUMPER, -1, -1
6512 XbumperB, FALSE, FALSE,
6513 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
6516 Xwheel, TRUE, FALSE,
6517 EL_ROBOT_WHEEL, -1, -1
6520 XwheelB, FALSE, FALSE,
6521 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
6524 Xswitch, TRUE, FALSE,
6525 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
6528 XswitchB, FALSE, FALSE,
6529 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
6533 EL_QUICKSAND_EMPTY, -1, -1
6536 Xsand_stone, TRUE, FALSE,
6537 EL_QUICKSAND_FULL, -1, -1
6540 Xsand_stonein_1, FALSE, TRUE,
6541 EL_ROCK, ACTION_FILLING, -1
6544 Xsand_stonein_2, FALSE, TRUE,
6545 EL_ROCK, ACTION_FILLING, -1
6548 Xsand_stonein_3, FALSE, TRUE,
6549 EL_ROCK, ACTION_FILLING, -1
6552 Xsand_stonein_4, FALSE, TRUE,
6553 EL_ROCK, ACTION_FILLING, -1
6556 Xsand_stonesand_1, FALSE, FALSE,
6557 EL_QUICKSAND_EMPTYING, -1, -1
6560 Xsand_stonesand_2, FALSE, FALSE,
6561 EL_QUICKSAND_EMPTYING, -1, -1
6564 Xsand_stonesand_3, FALSE, FALSE,
6565 EL_QUICKSAND_EMPTYING, -1, -1
6568 Xsand_stonesand_4, FALSE, FALSE,
6569 EL_QUICKSAND_EMPTYING, -1, -1
6572 Xsand_stonesand_quickout_1, FALSE, FALSE,
6573 EL_QUICKSAND_EMPTYING, -1, -1
6576 Xsand_stonesand_quickout_2, FALSE, FALSE,
6577 EL_QUICKSAND_EMPTYING, -1, -1
6580 Xsand_stoneout_1, FALSE, FALSE,
6581 EL_ROCK, ACTION_EMPTYING, -1
6584 Xsand_stoneout_2, FALSE, FALSE,
6585 EL_ROCK, ACTION_EMPTYING, -1
6588 Xsand_sandstone_1, FALSE, FALSE,
6589 EL_QUICKSAND_FILLING, -1, -1
6592 Xsand_sandstone_2, FALSE, FALSE,
6593 EL_QUICKSAND_FILLING, -1, -1
6596 Xsand_sandstone_3, FALSE, FALSE,
6597 EL_QUICKSAND_FILLING, -1, -1
6600 Xsand_sandstone_4, FALSE, FALSE,
6601 EL_QUICKSAND_FILLING, -1, -1
6604 Xplant, TRUE, FALSE,
6605 EL_EMC_PLANT, -1, -1
6608 Yplant, FALSE, FALSE,
6609 EL_EMC_PLANT, -1, -1
6612 Xlenses, TRUE, FALSE,
6613 EL_EMC_LENSES, -1, -1
6616 Xmagnify, TRUE, FALSE,
6617 EL_EMC_MAGNIFIER, -1, -1
6620 Xdripper, TRUE, FALSE,
6621 EL_EMC_DRIPPER, -1, -1
6624 XdripperB, FALSE, FALSE,
6625 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
6628 Xfake_blank, TRUE, FALSE,
6629 EL_INVISIBLE_WALL, -1, -1
6632 Xfake_blankB, FALSE, FALSE,
6633 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
6636 Xfake_grass, TRUE, FALSE,
6637 EL_EMC_FAKE_GRASS, -1, -1
6640 Xfake_grassB, FALSE, FALSE,
6641 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
6644 Xfake_door_1, TRUE, FALSE,
6645 EL_EM_GATE_1_GRAY, -1, -1
6648 Xfake_door_2, TRUE, FALSE,
6649 EL_EM_GATE_2_GRAY, -1, -1
6652 Xfake_door_3, TRUE, FALSE,
6653 EL_EM_GATE_3_GRAY, -1, -1
6656 Xfake_door_4, TRUE, FALSE,
6657 EL_EM_GATE_4_GRAY, -1, -1
6660 Xfake_door_5, TRUE, FALSE,
6661 EL_EMC_GATE_5_GRAY, -1, -1
6664 Xfake_door_6, TRUE, FALSE,
6665 EL_EMC_GATE_6_GRAY, -1, -1
6668 Xfake_door_7, TRUE, FALSE,
6669 EL_EMC_GATE_7_GRAY, -1, -1
6672 Xfake_door_8, TRUE, FALSE,
6673 EL_EMC_GATE_8_GRAY, -1, -1
6676 Xfake_acid_1, TRUE, FALSE,
6677 EL_EMC_FAKE_ACID, -1, -1
6680 Xfake_acid_2, FALSE, FALSE,
6681 EL_EMC_FAKE_ACID, -1, -1
6684 Xfake_acid_3, FALSE, FALSE,
6685 EL_EMC_FAKE_ACID, -1, -1
6688 Xfake_acid_4, FALSE, FALSE,
6689 EL_EMC_FAKE_ACID, -1, -1
6692 Xfake_acid_5, FALSE, FALSE,
6693 EL_EMC_FAKE_ACID, -1, -1
6696 Xfake_acid_6, FALSE, FALSE,
6697 EL_EMC_FAKE_ACID, -1, -1
6700 Xfake_acid_7, FALSE, FALSE,
6701 EL_EMC_FAKE_ACID, -1, -1
6704 Xfake_acid_8, FALSE, FALSE,
6705 EL_EMC_FAKE_ACID, -1, -1
6708 Xsteel_1, TRUE, FALSE,
6709 EL_STEELWALL, -1, -1
6712 Xsteel_2, TRUE, FALSE,
6713 EL_EMC_STEELWALL_2, -1, -1
6716 Xsteel_3, TRUE, FALSE,
6717 EL_EMC_STEELWALL_3, -1, -1
6720 Xsteel_4, TRUE, FALSE,
6721 EL_EMC_STEELWALL_4, -1, -1
6724 Xwall_1, TRUE, FALSE,
6728 Xwall_2, TRUE, FALSE,
6729 EL_EMC_WALL_14, -1, -1
6732 Xwall_3, TRUE, FALSE,
6733 EL_EMC_WALL_15, -1, -1
6736 Xwall_4, TRUE, FALSE,
6737 EL_EMC_WALL_16, -1, -1
6740 Xround_wall_1, TRUE, FALSE,
6741 EL_WALL_SLIPPERY, -1, -1
6744 Xround_wall_2, TRUE, FALSE,
6745 EL_EMC_WALL_SLIPPERY_2, -1, -1
6748 Xround_wall_3, TRUE, FALSE,
6749 EL_EMC_WALL_SLIPPERY_3, -1, -1
6752 Xround_wall_4, TRUE, FALSE,
6753 EL_EMC_WALL_SLIPPERY_4, -1, -1
6756 Xdecor_1, TRUE, FALSE,
6757 EL_EMC_WALL_8, -1, -1
6760 Xdecor_2, TRUE, FALSE,
6761 EL_EMC_WALL_6, -1, -1
6764 Xdecor_3, TRUE, FALSE,
6765 EL_EMC_WALL_4, -1, -1
6768 Xdecor_4, TRUE, FALSE,
6769 EL_EMC_WALL_7, -1, -1
6772 Xdecor_5, TRUE, FALSE,
6773 EL_EMC_WALL_5, -1, -1
6776 Xdecor_6, TRUE, FALSE,
6777 EL_EMC_WALL_9, -1, -1
6780 Xdecor_7, TRUE, FALSE,
6781 EL_EMC_WALL_10, -1, -1
6784 Xdecor_8, TRUE, FALSE,
6785 EL_EMC_WALL_1, -1, -1
6788 Xdecor_9, TRUE, FALSE,
6789 EL_EMC_WALL_2, -1, -1
6792 Xdecor_10, TRUE, FALSE,
6793 EL_EMC_WALL_3, -1, -1
6796 Xdecor_11, TRUE, FALSE,
6797 EL_EMC_WALL_11, -1, -1
6800 Xdecor_12, TRUE, FALSE,
6801 EL_EMC_WALL_12, -1, -1
6804 Xalpha_0, TRUE, FALSE,
6805 EL_CHAR('0'), -1, -1
6808 Xalpha_1, TRUE, FALSE,
6809 EL_CHAR('1'), -1, -1
6812 Xalpha_2, TRUE, FALSE,
6813 EL_CHAR('2'), -1, -1
6816 Xalpha_3, TRUE, FALSE,
6817 EL_CHAR('3'), -1, -1
6820 Xalpha_4, TRUE, FALSE,
6821 EL_CHAR('4'), -1, -1
6824 Xalpha_5, TRUE, FALSE,
6825 EL_CHAR('5'), -1, -1
6828 Xalpha_6, TRUE, FALSE,
6829 EL_CHAR('6'), -1, -1
6832 Xalpha_7, TRUE, FALSE,
6833 EL_CHAR('7'), -1, -1
6836 Xalpha_8, TRUE, FALSE,
6837 EL_CHAR('8'), -1, -1
6840 Xalpha_9, TRUE, FALSE,
6841 EL_CHAR('9'), -1, -1
6844 Xalpha_excla, TRUE, FALSE,
6845 EL_CHAR('!'), -1, -1
6848 Xalpha_quote, TRUE, FALSE,
6849 EL_CHAR('"'), -1, -1
6852 Xalpha_comma, TRUE, FALSE,
6853 EL_CHAR(','), -1, -1
6856 Xalpha_minus, TRUE, FALSE,
6857 EL_CHAR('-'), -1, -1
6860 Xalpha_perio, TRUE, FALSE,
6861 EL_CHAR('.'), -1, -1
6864 Xalpha_colon, TRUE, FALSE,
6865 EL_CHAR(':'), -1, -1
6868 Xalpha_quest, TRUE, FALSE,
6869 EL_CHAR('?'), -1, -1
6872 Xalpha_a, TRUE, FALSE,
6873 EL_CHAR('A'), -1, -1
6876 Xalpha_b, TRUE, FALSE,
6877 EL_CHAR('B'), -1, -1
6880 Xalpha_c, TRUE, FALSE,
6881 EL_CHAR('C'), -1, -1
6884 Xalpha_d, TRUE, FALSE,
6885 EL_CHAR('D'), -1, -1
6888 Xalpha_e, TRUE, FALSE,
6889 EL_CHAR('E'), -1, -1
6892 Xalpha_f, TRUE, FALSE,
6893 EL_CHAR('F'), -1, -1
6896 Xalpha_g, TRUE, FALSE,
6897 EL_CHAR('G'), -1, -1
6900 Xalpha_h, TRUE, FALSE,
6901 EL_CHAR('H'), -1, -1
6904 Xalpha_i, TRUE, FALSE,
6905 EL_CHAR('I'), -1, -1
6908 Xalpha_j, TRUE, FALSE,
6909 EL_CHAR('J'), -1, -1
6912 Xalpha_k, TRUE, FALSE,
6913 EL_CHAR('K'), -1, -1
6916 Xalpha_l, TRUE, FALSE,
6917 EL_CHAR('L'), -1, -1
6920 Xalpha_m, TRUE, FALSE,
6921 EL_CHAR('M'), -1, -1
6924 Xalpha_n, TRUE, FALSE,
6925 EL_CHAR('N'), -1, -1
6928 Xalpha_o, TRUE, FALSE,
6929 EL_CHAR('O'), -1, -1
6932 Xalpha_p, TRUE, FALSE,
6933 EL_CHAR('P'), -1, -1
6936 Xalpha_q, TRUE, FALSE,
6937 EL_CHAR('Q'), -1, -1
6940 Xalpha_r, TRUE, FALSE,
6941 EL_CHAR('R'), -1, -1
6944 Xalpha_s, TRUE, FALSE,
6945 EL_CHAR('S'), -1, -1
6948 Xalpha_t, TRUE, FALSE,
6949 EL_CHAR('T'), -1, -1
6952 Xalpha_u, TRUE, FALSE,
6953 EL_CHAR('U'), -1, -1
6956 Xalpha_v, TRUE, FALSE,
6957 EL_CHAR('V'), -1, -1
6960 Xalpha_w, TRUE, FALSE,
6961 EL_CHAR('W'), -1, -1
6964 Xalpha_x, TRUE, FALSE,
6965 EL_CHAR('X'), -1, -1
6968 Xalpha_y, TRUE, FALSE,
6969 EL_CHAR('Y'), -1, -1
6972 Xalpha_z, TRUE, FALSE,
6973 EL_CHAR('Z'), -1, -1
6976 Xalpha_arrow_e, TRUE, FALSE,
6977 EL_CHAR('>'), -1, -1
6980 Xalpha_arrow_w, TRUE, FALSE,
6981 EL_CHAR('<'), -1, -1
6984 Xalpha_copyr, TRUE, FALSE,
6985 EL_CHAR(CHAR_BYTE_COPYRIGHT), -1, -1
6989 Xboom_bug, FALSE, FALSE,
6990 EL_BUG, ACTION_EXPLODING, -1
6993 Xboom_bomb, FALSE, FALSE,
6994 EL_BOMB, ACTION_EXPLODING, -1
6997 Xboom_android, FALSE, FALSE,
6998 EL_EMC_ANDROID, ACTION_OTHER, -1
7001 Xboom_1, FALSE, FALSE,
7002 EL_DEFAULT, ACTION_EXPLODING, -1
7005 Xboom_2, FALSE, FALSE,
7006 EL_DEFAULT, ACTION_EXPLODING, -1
7009 Znormal, FALSE, FALSE,
7013 Zdynamite, FALSE, FALSE,
7017 Zplayer, FALSE, FALSE,
7021 ZBORDER, FALSE, FALSE,
7031 static struct Mapping_EM_to_RND_player
7040 em_player_mapping_list[] =
7044 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
7048 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
7052 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
7056 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
7060 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
7064 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
7068 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
7072 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
7076 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
7080 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
7084 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
7088 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
7092 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
7096 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
7100 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
7104 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
7108 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
7112 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
7116 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
7120 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
7124 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
7128 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
7132 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
7136 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
7140 EL_PLAYER_1, ACTION_DEFAULT, -1,
7144 EL_PLAYER_2, ACTION_DEFAULT, -1,
7148 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
7152 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
7156 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
7160 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
7164 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
7168 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
7172 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
7176 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
7180 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
7184 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
7188 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
7192 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
7196 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
7200 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
7204 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
7208 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
7212 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
7216 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
7220 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
7224 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
7228 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
7232 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
7236 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
7240 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
7244 EL_PLAYER_3, ACTION_DEFAULT, -1,
7248 EL_PLAYER_4, ACTION_DEFAULT, -1,
7257 int map_element_RND_to_EM(int element_rnd)
7259 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
7260 static boolean mapping_initialized = FALSE;
7262 if (!mapping_initialized)
7266 /* return "Xalpha_quest" for all undefined elements in mapping array */
7267 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
7268 mapping_RND_to_EM[i] = Xalpha_quest;
7270 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
7271 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
7272 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
7273 em_object_mapping_list[i].element_em;
7275 mapping_initialized = TRUE;
7278 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
7279 return mapping_RND_to_EM[element_rnd];
7281 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
7286 int map_element_EM_to_RND(int element_em)
7288 static unsigned short mapping_EM_to_RND[TILE_MAX];
7289 static boolean mapping_initialized = FALSE;
7291 if (!mapping_initialized)
7295 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
7296 for (i = 0; i < TILE_MAX; i++)
7297 mapping_EM_to_RND[i] = EL_UNKNOWN;
7299 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
7300 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
7301 em_object_mapping_list[i].element_rnd;
7303 mapping_initialized = TRUE;
7306 if (element_em >= 0 && element_em < TILE_MAX)
7307 return mapping_EM_to_RND[element_em];
7309 Error(ERR_WARN, "invalid EM level element %d", element_em);
7314 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
7316 struct LevelInfo_EM *level_em = level->native_em_level;
7317 struct LEVEL *lev = level_em->lev;
7320 for (i = 0; i < TILE_MAX; i++)
7321 lev->android_array[i] = Xblank;
7323 for (i = 0; i < level->num_android_clone_elements; i++)
7325 int element_rnd = level->android_clone_element[i];
7326 int element_em = map_element_RND_to_EM(element_rnd);
7328 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
7329 if (em_object_mapping_list[j].element_rnd == element_rnd)
7330 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
7334 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
7336 struct LevelInfo_EM *level_em = level->native_em_level;
7337 struct LEVEL *lev = level_em->lev;
7340 level->num_android_clone_elements = 0;
7342 for (i = 0; i < TILE_MAX; i++)
7344 int element_em = lev->android_array[i];
7346 boolean element_found = FALSE;
7348 if (element_em == Xblank)
7351 element_rnd = map_element_EM_to_RND(element_em);
7353 for (j = 0; j < level->num_android_clone_elements; j++)
7354 if (level->android_clone_element[j] == element_rnd)
7355 element_found = TRUE;
7359 level->android_clone_element[level->num_android_clone_elements++] =
7362 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
7367 if (level->num_android_clone_elements == 0)
7369 level->num_android_clone_elements = 1;
7370 level->android_clone_element[0] = EL_EMPTY;
7374 int map_direction_RND_to_EM(int direction)
7376 return (direction == MV_UP ? 0 :
7377 direction == MV_RIGHT ? 1 :
7378 direction == MV_DOWN ? 2 :
7379 direction == MV_LEFT ? 3 :
7383 int map_direction_EM_to_RND(int direction)
7385 return (direction == 0 ? MV_UP :
7386 direction == 1 ? MV_RIGHT :
7387 direction == 2 ? MV_DOWN :
7388 direction == 3 ? MV_LEFT :
7392 int map_element_RND_to_SP(int element_rnd)
7394 int element_sp = 0x20; /* map unknown elements to yellow "hardware" */
7396 if (element_rnd >= EL_SP_START &&
7397 element_rnd <= EL_SP_END)
7398 element_sp = element_rnd - EL_SP_START;
7399 else if (element_rnd == EL_EMPTY_SPACE)
7401 else if (element_rnd == EL_INVISIBLE_WALL)
7407 int map_element_SP_to_RND(int element_sp)
7409 int element_rnd = EL_UNKNOWN;
7411 if (element_sp >= 0x00 &&
7413 element_rnd = EL_SP_START + element_sp;
7414 else if (element_sp == 0x28)
7415 element_rnd = EL_INVISIBLE_WALL;
7420 int map_action_SP_to_RND(int action_sp)
7424 case actActive: return ACTION_ACTIVE;
7425 case actImpact: return ACTION_IMPACT;
7426 case actExploding: return ACTION_EXPLODING;
7427 case actDigging: return ACTION_DIGGING;
7428 case actSnapping: return ACTION_SNAPPING;
7429 case actCollecting: return ACTION_COLLECTING;
7430 case actPassing: return ACTION_PASSING;
7431 case actPushing: return ACTION_PUSHING;
7432 case actDropping: return ACTION_DROPPING;
7434 default: return ACTION_DEFAULT;
7438 int map_element_RND_to_MM(int element_rnd)
7440 return (element_rnd >= EL_MM_START_1 &&
7441 element_rnd <= EL_MM_END_1 ?
7442 EL_MM_START_1_NATIVE + element_rnd - EL_MM_START_1 :
7444 element_rnd >= EL_MM_START_2 &&
7445 element_rnd <= EL_MM_END_2 ?
7446 EL_MM_START_2_NATIVE + element_rnd - EL_MM_START_2 :
7448 element_rnd >= EL_CHAR_START &&
7449 element_rnd <= EL_CHAR_END ?
7450 EL_MM_CHAR_START_NATIVE + element_rnd - EL_CHAR_START :
7452 element_rnd >= EL_MM_RUNTIME_START &&
7453 element_rnd <= EL_MM_RUNTIME_END ?
7454 EL_MM_RUNTIME_START_NATIVE + element_rnd - EL_MM_RUNTIME_START :
7456 element_rnd >= EL_MM_DUMMY_START &&
7457 element_rnd <= EL_MM_DUMMY_END ?
7458 EL_MM_DUMMY_START_NATIVE + element_rnd - EL_MM_DUMMY_START :
7460 EL_MM_EMPTY_NATIVE);
7463 int map_element_MM_to_RND(int element_mm)
7465 return (element_mm == EL_MM_EMPTY_NATIVE ||
7466 element_mm == EL_DF_EMPTY_NATIVE ?
7469 element_mm >= EL_MM_START_1_NATIVE &&
7470 element_mm <= EL_MM_END_1_NATIVE ?
7471 EL_MM_START_1 + element_mm - EL_MM_START_1_NATIVE :
7473 element_mm >= EL_MM_START_2_NATIVE &&
7474 element_mm <= EL_MM_END_2_NATIVE ?
7475 EL_MM_START_2 + element_mm - EL_MM_START_2_NATIVE :
7477 element_mm >= EL_MM_CHAR_START_NATIVE &&
7478 element_mm <= EL_MM_CHAR_END_NATIVE ?
7479 EL_CHAR_START + element_mm - EL_MM_CHAR_START_NATIVE :
7481 element_mm >= EL_MM_RUNTIME_START_NATIVE &&
7482 element_mm <= EL_MM_RUNTIME_END_NATIVE ?
7483 EL_MM_RUNTIME_START + element_mm - EL_MM_RUNTIME_START_NATIVE :
7485 element_mm >= EL_MM_DUMMY_START_NATIVE &&
7486 element_mm <= EL_MM_DUMMY_END_NATIVE ?
7487 EL_MM_DUMMY_START + element_mm - EL_MM_DUMMY_START_NATIVE :
7492 int map_action_MM_to_RND(int action_mm)
7494 /* all MM actions are defined to exactly match their RND counterparts */
7498 int map_sound_MM_to_RND(int sound_mm)
7502 case SND_MM_GAME_LEVELTIME_CHARGING:
7503 return SND_GAME_LEVELTIME_CHARGING;
7505 case SND_MM_GAME_HEALTH_CHARGING:
7506 return SND_GAME_HEALTH_CHARGING;
7509 return SND_UNDEFINED;
7513 int map_mm_wall_element(int element)
7515 return (element >= EL_MM_STEEL_WALL_START &&
7516 element <= EL_MM_STEEL_WALL_END ?
7519 element >= EL_MM_WOODEN_WALL_START &&
7520 element <= EL_MM_WOODEN_WALL_END ?
7523 element >= EL_MM_ICE_WALL_START &&
7524 element <= EL_MM_ICE_WALL_END ?
7527 element >= EL_MM_AMOEBA_WALL_START &&
7528 element <= EL_MM_AMOEBA_WALL_END ?
7531 element >= EL_DF_STEEL_WALL_START &&
7532 element <= EL_DF_STEEL_WALL_END ?
7535 element >= EL_DF_WOODEN_WALL_START &&
7536 element <= EL_DF_WOODEN_WALL_END ?
7542 int map_mm_wall_element_editor(int element)
7546 case EL_MM_STEEL_WALL: return EL_MM_STEEL_WALL_START;
7547 case EL_MM_WOODEN_WALL: return EL_MM_WOODEN_WALL_START;
7548 case EL_MM_ICE_WALL: return EL_MM_ICE_WALL_START;
7549 case EL_MM_AMOEBA_WALL: return EL_MM_AMOEBA_WALL_START;
7550 case EL_DF_STEEL_WALL: return EL_DF_STEEL_WALL_START;
7551 case EL_DF_WOODEN_WALL: return EL_DF_WOODEN_WALL_START;
7553 default: return element;
7557 int get_next_element(int element)
7561 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
7562 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
7563 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
7564 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
7565 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
7566 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
7567 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
7568 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
7569 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
7570 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
7571 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
7573 default: return element;
7577 int el2img_mm(int element_mm)
7579 return el2img(map_element_MM_to_RND(element_mm));
7582 int el_act_dir2img(int element, int action, int direction)
7584 element = GFX_ELEMENT(element);
7585 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
7587 /* direction_graphic[][] == graphic[] for undefined direction graphics */
7588 return element_info[element].direction_graphic[action][direction];
7591 static int el_act_dir2crm(int element, int action, int direction)
7593 element = GFX_ELEMENT(element);
7594 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
7596 /* direction_graphic[][] == graphic[] for undefined direction graphics */
7597 return element_info[element].direction_crumbled[action][direction];
7600 int el_act2img(int element, int action)
7602 element = GFX_ELEMENT(element);
7604 return element_info[element].graphic[action];
7607 int el_act2crm(int element, int action)
7609 element = GFX_ELEMENT(element);
7611 return element_info[element].crumbled[action];
7614 int el_dir2img(int element, int direction)
7616 element = GFX_ELEMENT(element);
7618 return el_act_dir2img(element, ACTION_DEFAULT, direction);
7621 int el2baseimg(int element)
7623 return element_info[element].graphic[ACTION_DEFAULT];
7626 int el2img(int element)
7628 element = GFX_ELEMENT(element);
7630 return element_info[element].graphic[ACTION_DEFAULT];
7633 int el2edimg(int element)
7635 element = GFX_ELEMENT(element);
7637 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
7640 int el2preimg(int element)
7642 element = GFX_ELEMENT(element);
7644 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
7647 int el2panelimg(int element)
7649 element = GFX_ELEMENT(element);
7651 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL];
7654 int font2baseimg(int font_nr)
7656 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
7659 int getBeltNrFromBeltElement(int element)
7661 return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
7662 element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
7663 element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
7666 int getBeltNrFromBeltActiveElement(int element)
7668 return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
7669 element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
7670 element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
7673 int getBeltNrFromBeltSwitchElement(int element)
7675 return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
7676 element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
7677 element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
7680 int getBeltDirNrFromBeltElement(int element)
7682 static int belt_base_element[4] =
7684 EL_CONVEYOR_BELT_1_LEFT,
7685 EL_CONVEYOR_BELT_2_LEFT,
7686 EL_CONVEYOR_BELT_3_LEFT,
7687 EL_CONVEYOR_BELT_4_LEFT
7690 int belt_nr = getBeltNrFromBeltElement(element);
7691 int belt_dir_nr = element - belt_base_element[belt_nr];
7693 return (belt_dir_nr % 3);
7696 int getBeltDirNrFromBeltSwitchElement(int element)
7698 static int belt_base_element[4] =
7700 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
7701 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
7702 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
7703 EL_CONVEYOR_BELT_4_SWITCH_LEFT
7706 int belt_nr = getBeltNrFromBeltSwitchElement(element);
7707 int belt_dir_nr = element - belt_base_element[belt_nr];
7709 return (belt_dir_nr % 3);
7712 int getBeltDirFromBeltElement(int element)
7714 static int belt_move_dir[3] =
7721 int belt_dir_nr = getBeltDirNrFromBeltElement(element);
7723 return belt_move_dir[belt_dir_nr];
7726 int getBeltDirFromBeltSwitchElement(int element)
7728 static int belt_move_dir[3] =
7735 int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
7737 return belt_move_dir[belt_dir_nr];
7740 int getBeltElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
7742 static int belt_base_element[4] =
7744 EL_CONVEYOR_BELT_1_LEFT,
7745 EL_CONVEYOR_BELT_2_LEFT,
7746 EL_CONVEYOR_BELT_3_LEFT,
7747 EL_CONVEYOR_BELT_4_LEFT
7750 return belt_base_element[belt_nr] + belt_dir_nr;
7753 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
7755 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
7757 return getBeltElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
7760 int getBeltSwitchElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
7762 static int belt_base_element[4] =
7764 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
7765 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
7766 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
7767 EL_CONVEYOR_BELT_4_SWITCH_LEFT
7770 return belt_base_element[belt_nr] + belt_dir_nr;
7773 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
7775 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
7777 return getBeltSwitchElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
7780 boolean getTeamMode_EM()
7782 return game.team_mode;
7785 int getGameFrameDelay_EM(int native_em_game_frame_delay)
7787 int game_frame_delay_value;
7789 game_frame_delay_value =
7790 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
7791 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
7794 if (tape.playing && tape.warp_forward && !tape.pausing)
7795 game_frame_delay_value = 0;
7797 return game_frame_delay_value;
7800 unsigned int InitRND(int seed)
7802 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
7803 return InitEngineRandom_EM(seed);
7804 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
7805 return InitEngineRandom_SP(seed);
7806 else if (level.game_engine_type == GAME_ENGINE_TYPE_MM)
7807 return InitEngineRandom_MM(seed);
7809 return InitEngineRandom_RND(seed);
7812 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
7813 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
7815 inline static int get_effective_element_EM(int tile, int frame_em)
7817 int element = object_mapping[tile].element_rnd;
7818 int action = object_mapping[tile].action;
7819 boolean is_backside = object_mapping[tile].is_backside;
7820 boolean action_removing = (action == ACTION_DIGGING ||
7821 action == ACTION_SNAPPING ||
7822 action == ACTION_COLLECTING);
7828 case Yacid_splash_eB:
7829 case Yacid_splash_wB:
7830 return (frame_em > 5 ? EL_EMPTY : element);
7836 else /* frame_em == 7 */
7840 case Yacid_splash_eB:
7841 case Yacid_splash_wB:
7844 case Yemerald_stone:
7847 case Ydiamond_stone:
7851 case Xdrip_stretchB:
7870 case Xsand_stonein_1:
7871 case Xsand_stonein_2:
7872 case Xsand_stonein_3:
7873 case Xsand_stonein_4:
7877 return (is_backside || action_removing ? EL_EMPTY : element);
7882 inline static boolean check_linear_animation_EM(int tile)
7886 case Xsand_stonesand_1:
7887 case Xsand_stonesand_quickout_1:
7888 case Xsand_sandstone_1:
7889 case Xsand_stonein_1:
7890 case Xsand_stoneout_1:
7909 case Yacid_splash_eB:
7910 case Yacid_splash_wB:
7911 case Yemerald_stone:
7918 inline static void set_crumbled_graphics_EM(struct GraphicInfo_EM *g_em,
7919 boolean has_crumbled_graphics,
7920 int crumbled, int sync_frame)
7922 /* if element can be crumbled, but certain action graphics are just empty
7923 space (like instantly snapping sand to empty space in 1 frame), do not
7924 treat these empty space graphics as crumbled graphics in EMC engine */
7925 if (crumbled == IMG_EMPTY_SPACE)
7926 has_crumbled_graphics = FALSE;
7928 if (has_crumbled_graphics)
7930 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
7931 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
7932 g_crumbled->anim_delay,
7933 g_crumbled->anim_mode,
7934 g_crumbled->anim_start_frame,
7937 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
7938 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
7940 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
7941 g_em->crumbled_tile_size = graphic_info[crumbled].tile_size;
7943 g_em->has_crumbled_graphics = TRUE;
7947 g_em->crumbled_bitmap = NULL;
7948 g_em->crumbled_src_x = 0;
7949 g_em->crumbled_src_y = 0;
7950 g_em->crumbled_border_size = 0;
7951 g_em->crumbled_tile_size = 0;
7953 g_em->has_crumbled_graphics = FALSE;
7957 void ResetGfxAnimation_EM(int x, int y, int tile)
7962 void SetGfxAnimation_EM(struct GraphicInfo_EM *g_em,
7963 int tile, int frame_em, int x, int y)
7965 int action = object_mapping[tile].action;
7966 int direction = object_mapping[tile].direction;
7967 int effective_element = get_effective_element_EM(tile, frame_em);
7968 int graphic = (direction == MV_NONE ?
7969 el_act2img(effective_element, action) :
7970 el_act_dir2img(effective_element, action, direction));
7971 struct GraphicInfo *g = &graphic_info[graphic];
7973 boolean action_removing = (action == ACTION_DIGGING ||
7974 action == ACTION_SNAPPING ||
7975 action == ACTION_COLLECTING);
7976 boolean action_moving = (action == ACTION_FALLING ||
7977 action == ACTION_MOVING ||
7978 action == ACTION_PUSHING ||
7979 action == ACTION_EATING ||
7980 action == ACTION_FILLING ||
7981 action == ACTION_EMPTYING);
7982 boolean action_falling = (action == ACTION_FALLING ||
7983 action == ACTION_FILLING ||
7984 action == ACTION_EMPTYING);
7986 /* special case: graphic uses "2nd movement tile" and has defined
7987 7 frames for movement animation (or less) => use default graphic
7988 for last (8th) frame which ends the movement animation */
7989 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
7991 action = ACTION_DEFAULT; /* (keep action_* unchanged for now) */
7992 graphic = (direction == MV_NONE ?
7993 el_act2img(effective_element, action) :
7994 el_act_dir2img(effective_element, action, direction));
7996 g = &graphic_info[graphic];
7999 if ((action_removing || check_linear_animation_EM(tile)) && frame_em == 0)
8003 else if (action_moving)
8005 boolean is_backside = object_mapping[tile].is_backside;
8009 int direction = object_mapping[tile].direction;
8010 int move_dir = (action_falling ? MV_DOWN : direction);
8015 /* !!! TEST !!! NEW !!! DOES NOT WORK RIGHT YET !!! */
8016 if (g->double_movement && frame_em == 0)
8020 if (move_dir == MV_LEFT)
8021 GfxFrame[x - 1][y] = GfxFrame[x][y];
8022 else if (move_dir == MV_RIGHT)
8023 GfxFrame[x + 1][y] = GfxFrame[x][y];
8024 else if (move_dir == MV_UP)
8025 GfxFrame[x][y - 1] = GfxFrame[x][y];
8026 else if (move_dir == MV_DOWN)
8027 GfxFrame[x][y + 1] = GfxFrame[x][y];
8034 /* special case: animation for Xsand_stonesand_quickout_1/2 twice as fast */
8035 if (tile == Xsand_stonesand_quickout_1 ||
8036 tile == Xsand_stonesand_quickout_2)
8040 if (graphic_info[graphic].anim_global_sync)
8041 sync_frame = FrameCounter;
8042 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
8043 sync_frame = GfxFrame[x][y];
8045 sync_frame = 0; /* playfield border (pseudo steel) */
8047 SetRandomAnimationValue(x, y);
8049 int frame = getAnimationFrame(g->anim_frames,
8052 g->anim_start_frame,
8055 g_em->unique_identifier =
8056 (graphic << 16) | ((frame % 8) << 12) | (g_em->width << 6) | g_em->height;
8059 void getGraphicSourceObjectExt_EM(struct GraphicInfo_EM *g_em,
8060 int tile, int frame_em, int x, int y)
8062 int action = object_mapping[tile].action;
8063 int direction = object_mapping[tile].direction;
8064 boolean is_backside = object_mapping[tile].is_backside;
8065 int effective_element = get_effective_element_EM(tile, frame_em);
8066 int effective_action = action;
8067 int graphic = (direction == MV_NONE ?
8068 el_act2img(effective_element, effective_action) :
8069 el_act_dir2img(effective_element, effective_action,
8071 int crumbled = (direction == MV_NONE ?
8072 el_act2crm(effective_element, effective_action) :
8073 el_act_dir2crm(effective_element, effective_action,
8075 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
8076 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
8077 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
8078 struct GraphicInfo *g = &graphic_info[graphic];
8081 /* special case: graphic uses "2nd movement tile" and has defined
8082 7 frames for movement animation (or less) => use default graphic
8083 for last (8th) frame which ends the movement animation */
8084 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
8086 effective_action = ACTION_DEFAULT;
8087 graphic = (direction == MV_NONE ?
8088 el_act2img(effective_element, effective_action) :
8089 el_act_dir2img(effective_element, effective_action,
8091 crumbled = (direction == MV_NONE ?
8092 el_act2crm(effective_element, effective_action) :
8093 el_act_dir2crm(effective_element, effective_action,
8096 g = &graphic_info[graphic];
8099 if (graphic_info[graphic].anim_global_sync)
8100 sync_frame = FrameCounter;
8101 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
8102 sync_frame = GfxFrame[x][y];
8104 sync_frame = 0; /* playfield border (pseudo steel) */
8106 SetRandomAnimationValue(x, y);
8108 int frame = getAnimationFrame(g->anim_frames,
8111 g->anim_start_frame,
8114 getGraphicSourceExt(graphic, frame, &g_em->bitmap, &g_em->src_x, &g_em->src_y,
8115 g->double_movement && is_backside);
8117 /* (updating the "crumbled" graphic definitions is probably not really needed,
8118 as animations for crumbled graphics can't be longer than one EMC cycle) */
8119 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
8123 void getGraphicSourcePlayerExt_EM(struct GraphicInfo_EM *g_em,
8124 int player_nr, int anim, int frame_em)
8126 int element = player_mapping[player_nr][anim].element_rnd;
8127 int action = player_mapping[player_nr][anim].action;
8128 int direction = player_mapping[player_nr][anim].direction;
8129 int graphic = (direction == MV_NONE ?
8130 el_act2img(element, action) :
8131 el_act_dir2img(element, action, direction));
8132 struct GraphicInfo *g = &graphic_info[graphic];
8135 InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
8137 stored_player[player_nr].StepFrame = frame_em;
8139 sync_frame = stored_player[player_nr].Frame;
8141 int frame = getAnimationFrame(g->anim_frames,
8144 g->anim_start_frame,
8147 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
8148 &g_em->src_x, &g_em->src_y, FALSE);
8151 void InitGraphicInfo_EM(void)
8156 int num_em_gfx_errors = 0;
8158 if (graphic_info_em_object[0][0].bitmap == NULL)
8160 /* EM graphics not yet initialized in em_open_all() */
8165 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
8168 /* always start with reliable default values */
8169 for (i = 0; i < TILE_MAX; i++)
8171 object_mapping[i].element_rnd = EL_UNKNOWN;
8172 object_mapping[i].is_backside = FALSE;
8173 object_mapping[i].action = ACTION_DEFAULT;
8174 object_mapping[i].direction = MV_NONE;
8177 /* always start with reliable default values */
8178 for (p = 0; p < MAX_PLAYERS; p++)
8180 for (i = 0; i < SPR_MAX; i++)
8182 player_mapping[p][i].element_rnd = EL_UNKNOWN;
8183 player_mapping[p][i].action = ACTION_DEFAULT;
8184 player_mapping[p][i].direction = MV_NONE;
8188 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
8190 int e = em_object_mapping_list[i].element_em;
8192 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
8193 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
8195 if (em_object_mapping_list[i].action != -1)
8196 object_mapping[e].action = em_object_mapping_list[i].action;
8198 if (em_object_mapping_list[i].direction != -1)
8199 object_mapping[e].direction =
8200 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
8203 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
8205 int a = em_player_mapping_list[i].action_em;
8206 int p = em_player_mapping_list[i].player_nr;
8208 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
8210 if (em_player_mapping_list[i].action != -1)
8211 player_mapping[p][a].action = em_player_mapping_list[i].action;
8213 if (em_player_mapping_list[i].direction != -1)
8214 player_mapping[p][a].direction =
8215 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
8218 for (i = 0; i < TILE_MAX; i++)
8220 int element = object_mapping[i].element_rnd;
8221 int action = object_mapping[i].action;
8222 int direction = object_mapping[i].direction;
8223 boolean is_backside = object_mapping[i].is_backside;
8224 boolean action_exploding = ((action == ACTION_EXPLODING ||
8225 action == ACTION_SMASHED_BY_ROCK ||
8226 action == ACTION_SMASHED_BY_SPRING) &&
8227 element != EL_DIAMOND);
8228 boolean action_active = (action == ACTION_ACTIVE);
8229 boolean action_other = (action == ACTION_OTHER);
8231 for (j = 0; j < 8; j++)
8233 int effective_element = get_effective_element_EM(i, j);
8234 int effective_action = (j < 7 ? action :
8235 i == Xdrip_stretch ? action :
8236 i == Xdrip_stretchB ? action :
8237 i == Ydrip_s1 ? action :
8238 i == Ydrip_s1B ? action :
8239 i == Xball_1B ? action :
8240 i == Xball_2 ? action :
8241 i == Xball_2B ? action :
8242 i == Yball_eat ? action :
8243 i == Ykey_1_eat ? action :
8244 i == Ykey_2_eat ? action :
8245 i == Ykey_3_eat ? action :
8246 i == Ykey_4_eat ? action :
8247 i == Ykey_5_eat ? action :
8248 i == Ykey_6_eat ? action :
8249 i == Ykey_7_eat ? action :
8250 i == Ykey_8_eat ? action :
8251 i == Ylenses_eat ? action :
8252 i == Ymagnify_eat ? action :
8253 i == Ygrass_eat ? action :
8254 i == Ydirt_eat ? action :
8255 i == Xsand_stonein_1 ? action :
8256 i == Xsand_stonein_2 ? action :
8257 i == Xsand_stonein_3 ? action :
8258 i == Xsand_stonein_4 ? action :
8259 i == Xsand_stoneout_1 ? action :
8260 i == Xsand_stoneout_2 ? action :
8261 i == Xboom_android ? ACTION_EXPLODING :
8262 action_exploding ? ACTION_EXPLODING :
8263 action_active ? action :
8264 action_other ? action :
8266 int graphic = (el_act_dir2img(effective_element, effective_action,
8268 int crumbled = (el_act_dir2crm(effective_element, effective_action,
8270 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
8271 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
8272 boolean has_action_graphics = (graphic != base_graphic);
8273 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
8274 struct GraphicInfo *g = &graphic_info[graphic];
8275 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
8278 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
8279 boolean special_animation = (action != ACTION_DEFAULT &&
8280 g->anim_frames == 3 &&
8281 g->anim_delay == 2 &&
8282 g->anim_mode & ANIM_LINEAR);
8283 int sync_frame = (i == Xdrip_stretch ? 7 :
8284 i == Xdrip_stretchB ? 7 :
8285 i == Ydrip_s2 ? j + 8 :
8286 i == Ydrip_s2B ? j + 8 :
8295 i == Xfake_acid_1 ? 0 :
8296 i == Xfake_acid_2 ? 10 :
8297 i == Xfake_acid_3 ? 20 :
8298 i == Xfake_acid_4 ? 30 :
8299 i == Xfake_acid_5 ? 40 :
8300 i == Xfake_acid_6 ? 50 :
8301 i == Xfake_acid_7 ? 60 :
8302 i == Xfake_acid_8 ? 70 :
8304 i == Xball_2B ? j + 8 :
8305 i == Yball_eat ? j + 1 :
8306 i == Ykey_1_eat ? j + 1 :
8307 i == Ykey_2_eat ? j + 1 :
8308 i == Ykey_3_eat ? j + 1 :
8309 i == Ykey_4_eat ? j + 1 :
8310 i == Ykey_5_eat ? j + 1 :
8311 i == Ykey_6_eat ? j + 1 :
8312 i == Ykey_7_eat ? j + 1 :
8313 i == Ykey_8_eat ? j + 1 :
8314 i == Ylenses_eat ? j + 1 :
8315 i == Ymagnify_eat ? j + 1 :
8316 i == Ygrass_eat ? j + 1 :
8317 i == Ydirt_eat ? j + 1 :
8318 i == Xamoeba_1 ? 0 :
8319 i == Xamoeba_2 ? 1 :
8320 i == Xamoeba_3 ? 2 :
8321 i == Xamoeba_4 ? 3 :
8322 i == Xamoeba_5 ? 0 :
8323 i == Xamoeba_6 ? 1 :
8324 i == Xamoeba_7 ? 2 :
8325 i == Xamoeba_8 ? 3 :
8326 i == Xexit_2 ? j + 8 :
8327 i == Xexit_3 ? j + 16 :
8328 i == Xdynamite_1 ? 0 :
8329 i == Xdynamite_2 ? 8 :
8330 i == Xdynamite_3 ? 16 :
8331 i == Xdynamite_4 ? 24 :
8332 i == Xsand_stonein_1 ? j + 1 :
8333 i == Xsand_stonein_2 ? j + 9 :
8334 i == Xsand_stonein_3 ? j + 17 :
8335 i == Xsand_stonein_4 ? j + 25 :
8336 i == Xsand_stoneout_1 && j == 0 ? 0 :
8337 i == Xsand_stoneout_1 && j == 1 ? 0 :
8338 i == Xsand_stoneout_1 && j == 2 ? 1 :
8339 i == Xsand_stoneout_1 && j == 3 ? 2 :
8340 i == Xsand_stoneout_1 && j == 4 ? 2 :
8341 i == Xsand_stoneout_1 && j == 5 ? 3 :
8342 i == Xsand_stoneout_1 && j == 6 ? 4 :
8343 i == Xsand_stoneout_1 && j == 7 ? 4 :
8344 i == Xsand_stoneout_2 && j == 0 ? 5 :
8345 i == Xsand_stoneout_2 && j == 1 ? 6 :
8346 i == Xsand_stoneout_2 && j == 2 ? 7 :
8347 i == Xsand_stoneout_2 && j == 3 ? 8 :
8348 i == Xsand_stoneout_2 && j == 4 ? 9 :
8349 i == Xsand_stoneout_2 && j == 5 ? 11 :
8350 i == Xsand_stoneout_2 && j == 6 ? 13 :
8351 i == Xsand_stoneout_2 && j == 7 ? 15 :
8352 i == Xboom_bug && j == 1 ? 2 :
8353 i == Xboom_bug && j == 2 ? 2 :
8354 i == Xboom_bug && j == 3 ? 4 :
8355 i == Xboom_bug && j == 4 ? 4 :
8356 i == Xboom_bug && j == 5 ? 2 :
8357 i == Xboom_bug && j == 6 ? 2 :
8358 i == Xboom_bug && j == 7 ? 0 :
8359 i == Xboom_bomb && j == 1 ? 2 :
8360 i == Xboom_bomb && j == 2 ? 2 :
8361 i == Xboom_bomb && j == 3 ? 4 :
8362 i == Xboom_bomb && j == 4 ? 4 :
8363 i == Xboom_bomb && j == 5 ? 2 :
8364 i == Xboom_bomb && j == 6 ? 2 :
8365 i == Xboom_bomb && j == 7 ? 0 :
8366 i == Xboom_android && j == 7 ? 6 :
8367 i == Xboom_1 && j == 1 ? 2 :
8368 i == Xboom_1 && j == 2 ? 2 :
8369 i == Xboom_1 && j == 3 ? 4 :
8370 i == Xboom_1 && j == 4 ? 4 :
8371 i == Xboom_1 && j == 5 ? 6 :
8372 i == Xboom_1 && j == 6 ? 6 :
8373 i == Xboom_1 && j == 7 ? 8 :
8374 i == Xboom_2 && j == 0 ? 8 :
8375 i == Xboom_2 && j == 1 ? 8 :
8376 i == Xboom_2 && j == 2 ? 10 :
8377 i == Xboom_2 && j == 3 ? 10 :
8378 i == Xboom_2 && j == 4 ? 10 :
8379 i == Xboom_2 && j == 5 ? 12 :
8380 i == Xboom_2 && j == 6 ? 12 :
8381 i == Xboom_2 && j == 7 ? 12 :
8382 special_animation && j == 4 ? 3 :
8383 effective_action != action ? 0 :
8387 Bitmap *debug_bitmap = g_em->bitmap;
8388 int debug_src_x = g_em->src_x;
8389 int debug_src_y = g_em->src_y;
8392 int frame = getAnimationFrame(g->anim_frames,
8395 g->anim_start_frame,
8398 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
8399 g->double_movement && is_backside);
8401 g_em->bitmap = src_bitmap;
8402 g_em->src_x = src_x;
8403 g_em->src_y = src_y;
8404 g_em->src_offset_x = 0;
8405 g_em->src_offset_y = 0;
8406 g_em->dst_offset_x = 0;
8407 g_em->dst_offset_y = 0;
8408 g_em->width = TILEX;
8409 g_em->height = TILEY;
8411 g_em->preserve_background = FALSE;
8413 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
8416 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
8417 effective_action == ACTION_MOVING ||
8418 effective_action == ACTION_PUSHING ||
8419 effective_action == ACTION_EATING)) ||
8420 (!has_action_graphics && (effective_action == ACTION_FILLING ||
8421 effective_action == ACTION_EMPTYING)))
8424 (effective_action == ACTION_FALLING ||
8425 effective_action == ACTION_FILLING ||
8426 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
8427 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
8428 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
8429 int num_steps = (i == Ydrip_s1 ? 16 :
8430 i == Ydrip_s1B ? 16 :
8431 i == Ydrip_s2 ? 16 :
8432 i == Ydrip_s2B ? 16 :
8433 i == Xsand_stonein_1 ? 32 :
8434 i == Xsand_stonein_2 ? 32 :
8435 i == Xsand_stonein_3 ? 32 :
8436 i == Xsand_stonein_4 ? 32 :
8437 i == Xsand_stoneout_1 ? 16 :
8438 i == Xsand_stoneout_2 ? 16 : 8);
8439 int cx = ABS(dx) * (TILEX / num_steps);
8440 int cy = ABS(dy) * (TILEY / num_steps);
8441 int step_frame = (i == Ydrip_s2 ? j + 8 :
8442 i == Ydrip_s2B ? j + 8 :
8443 i == Xsand_stonein_2 ? j + 8 :
8444 i == Xsand_stonein_3 ? j + 16 :
8445 i == Xsand_stonein_4 ? j + 24 :
8446 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
8447 int step = (is_backside ? step_frame : num_steps - step_frame);
8449 if (is_backside) /* tile where movement starts */
8451 if (dx < 0 || dy < 0)
8453 g_em->src_offset_x = cx * step;
8454 g_em->src_offset_y = cy * step;
8458 g_em->dst_offset_x = cx * step;
8459 g_em->dst_offset_y = cy * step;
8462 else /* tile where movement ends */
8464 if (dx < 0 || dy < 0)
8466 g_em->dst_offset_x = cx * step;
8467 g_em->dst_offset_y = cy * step;
8471 g_em->src_offset_x = cx * step;
8472 g_em->src_offset_y = cy * step;
8476 g_em->width = TILEX - cx * step;
8477 g_em->height = TILEY - cy * step;
8480 /* create unique graphic identifier to decide if tile must be redrawn */
8481 /* bit 31 - 16 (16 bit): EM style graphic
8482 bit 15 - 12 ( 4 bit): EM style frame
8483 bit 11 - 6 ( 6 bit): graphic width
8484 bit 5 - 0 ( 6 bit): graphic height */
8485 g_em->unique_identifier =
8486 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
8490 /* skip check for EMC elements not contained in original EMC artwork */
8491 if (element == EL_EMC_FAKE_ACID)
8494 if (g_em->bitmap != debug_bitmap ||
8495 g_em->src_x != debug_src_x ||
8496 g_em->src_y != debug_src_y ||
8497 g_em->src_offset_x != 0 ||
8498 g_em->src_offset_y != 0 ||
8499 g_em->dst_offset_x != 0 ||
8500 g_em->dst_offset_y != 0 ||
8501 g_em->width != TILEX ||
8502 g_em->height != TILEY)
8504 static int last_i = -1;
8512 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
8513 i, element, element_info[element].token_name,
8514 element_action_info[effective_action].suffix, direction);
8516 if (element != effective_element)
8517 printf(" [%d ('%s')]",
8519 element_info[effective_element].token_name);
8523 if (g_em->bitmap != debug_bitmap)
8524 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
8525 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
8527 if (g_em->src_x != debug_src_x ||
8528 g_em->src_y != debug_src_y)
8529 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
8530 j, (is_backside ? 'B' : 'F'),
8531 g_em->src_x, g_em->src_y,
8532 g_em->src_x / 32, g_em->src_y / 32,
8533 debug_src_x, debug_src_y,
8534 debug_src_x / 32, debug_src_y / 32);
8536 if (g_em->src_offset_x != 0 ||
8537 g_em->src_offset_y != 0 ||
8538 g_em->dst_offset_x != 0 ||
8539 g_em->dst_offset_y != 0)
8540 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
8542 g_em->src_offset_x, g_em->src_offset_y,
8543 g_em->dst_offset_x, g_em->dst_offset_y);
8545 if (g_em->width != TILEX ||
8546 g_em->height != TILEY)
8547 printf(" %d (%d): size %d,%d should be %d,%d\n",
8549 g_em->width, g_em->height, TILEX, TILEY);
8551 num_em_gfx_errors++;
8558 for (i = 0; i < TILE_MAX; i++)
8560 for (j = 0; j < 8; j++)
8562 int element = object_mapping[i].element_rnd;
8563 int action = object_mapping[i].action;
8564 int direction = object_mapping[i].direction;
8565 boolean is_backside = object_mapping[i].is_backside;
8566 int graphic_action = el_act_dir2img(element, action, direction);
8567 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
8569 if ((action == ACTION_SMASHED_BY_ROCK ||
8570 action == ACTION_SMASHED_BY_SPRING ||
8571 action == ACTION_EATING) &&
8572 graphic_action == graphic_default)
8574 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
8575 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
8576 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
8577 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
8580 /* no separate animation for "smashed by rock" -- use rock instead */
8581 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
8582 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
8584 g_em->bitmap = g_xx->bitmap;
8585 g_em->src_x = g_xx->src_x;
8586 g_em->src_y = g_xx->src_y;
8587 g_em->src_offset_x = g_xx->src_offset_x;
8588 g_em->src_offset_y = g_xx->src_offset_y;
8589 g_em->dst_offset_x = g_xx->dst_offset_x;
8590 g_em->dst_offset_y = g_xx->dst_offset_y;
8591 g_em->width = g_xx->width;
8592 g_em->height = g_xx->height;
8593 g_em->unique_identifier = g_xx->unique_identifier;
8596 g_em->preserve_background = TRUE;
8601 for (p = 0; p < MAX_PLAYERS; p++)
8603 for (i = 0; i < SPR_MAX; i++)
8605 int element = player_mapping[p][i].element_rnd;
8606 int action = player_mapping[p][i].action;
8607 int direction = player_mapping[p][i].direction;
8609 for (j = 0; j < 8; j++)
8611 int effective_element = element;
8612 int effective_action = action;
8613 int graphic = (direction == MV_NONE ?
8614 el_act2img(effective_element, effective_action) :
8615 el_act_dir2img(effective_element, effective_action,
8617 struct GraphicInfo *g = &graphic_info[graphic];
8618 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
8624 Bitmap *debug_bitmap = g_em->bitmap;
8625 int debug_src_x = g_em->src_x;
8626 int debug_src_y = g_em->src_y;
8629 int frame = getAnimationFrame(g->anim_frames,
8632 g->anim_start_frame,
8635 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
8637 g_em->bitmap = src_bitmap;
8638 g_em->src_x = src_x;
8639 g_em->src_y = src_y;
8640 g_em->src_offset_x = 0;
8641 g_em->src_offset_y = 0;
8642 g_em->dst_offset_x = 0;
8643 g_em->dst_offset_y = 0;
8644 g_em->width = TILEX;
8645 g_em->height = TILEY;
8649 /* skip check for EMC elements not contained in original EMC artwork */
8650 if (element == EL_PLAYER_3 ||
8651 element == EL_PLAYER_4)
8654 if (g_em->bitmap != debug_bitmap ||
8655 g_em->src_x != debug_src_x ||
8656 g_em->src_y != debug_src_y)
8658 static int last_i = -1;
8666 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
8667 p, i, element, element_info[element].token_name,
8668 element_action_info[effective_action].suffix, direction);
8670 if (element != effective_element)
8671 printf(" [%d ('%s')]",
8673 element_info[effective_element].token_name);
8677 if (g_em->bitmap != debug_bitmap)
8678 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
8679 j, (int)(g_em->bitmap), (int)(debug_bitmap));
8681 if (g_em->src_x != debug_src_x ||
8682 g_em->src_y != debug_src_y)
8683 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
8685 g_em->src_x, g_em->src_y,
8686 g_em->src_x / 32, g_em->src_y / 32,
8687 debug_src_x, debug_src_y,
8688 debug_src_x / 32, debug_src_y / 32);
8690 num_em_gfx_errors++;
8700 printf("::: [%d errors found]\n", num_em_gfx_errors);
8706 void CheckSaveEngineSnapshot_EM(byte action[MAX_PLAYERS], int frame,
8707 boolean any_player_moving,
8708 boolean any_player_snapping,
8709 boolean any_player_dropping)
8711 if (frame == 0 && !any_player_dropping)
8713 if (!local_player->was_waiting)
8715 if (!CheckSaveEngineSnapshotToList())
8718 local_player->was_waiting = TRUE;
8721 else if (any_player_moving || any_player_snapping || any_player_dropping)
8723 local_player->was_waiting = FALSE;
8727 void CheckSaveEngineSnapshot_SP(boolean murphy_is_waiting,
8728 boolean murphy_is_dropping)
8730 if (murphy_is_waiting)
8732 if (!local_player->was_waiting)
8734 if (!CheckSaveEngineSnapshotToList())
8737 local_player->was_waiting = TRUE;
8742 local_player->was_waiting = FALSE;
8746 void CheckSaveEngineSnapshot_MM(boolean element_clicked,
8747 boolean button_released)
8749 if (button_released)
8751 if (game.snapshot.mode == SNAPSHOT_MODE_EVERY_MOVE)
8752 CheckSaveEngineSnapshotToList();
8754 else if (element_clicked)
8756 if (game.snapshot.mode != SNAPSHOT_MODE_EVERY_MOVE)
8757 CheckSaveEngineSnapshotToList();
8759 game.snapshot.changed_action = TRUE;
8763 void CheckSingleStepMode_EM(byte action[MAX_PLAYERS], int frame,
8764 boolean any_player_moving,
8765 boolean any_player_snapping,
8766 boolean any_player_dropping)
8768 if (tape.single_step && tape.recording && !tape.pausing)
8769 if (frame == 0 && !any_player_dropping)
8770 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
8772 CheckSaveEngineSnapshot_EM(action, frame, any_player_moving,
8773 any_player_snapping, any_player_dropping);
8776 void CheckSingleStepMode_SP(boolean murphy_is_waiting,
8777 boolean murphy_is_dropping)
8779 boolean murphy_starts_dropping = FALSE;
8782 for (i = 0; i < MAX_PLAYERS; i++)
8783 if (stored_player[i].force_dropping)
8784 murphy_starts_dropping = TRUE;
8786 if (tape.single_step && tape.recording && !tape.pausing)
8787 if (murphy_is_waiting && !murphy_starts_dropping)
8788 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
8790 CheckSaveEngineSnapshot_SP(murphy_is_waiting, murphy_is_dropping);
8793 void CheckSingleStepMode_MM(boolean element_clicked,
8794 boolean button_released)
8796 if (tape.single_step && tape.recording && !tape.pausing)
8797 if (button_released)
8798 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
8800 CheckSaveEngineSnapshot_MM(element_clicked, button_released);
8803 void getGraphicSource_SP(struct GraphicInfo_SP *g_sp,
8804 int graphic, int sync_frame, int x, int y)
8806 int frame = getGraphicAnimationFrame(graphic, sync_frame);
8808 getGraphicSource(graphic, frame, &g_sp->bitmap, &g_sp->src_x, &g_sp->src_y);
8811 boolean isNextAnimationFrame_SP(int graphic, int sync_frame)
8813 return (IS_NEXT_FRAME(sync_frame, graphic));
8816 int getGraphicInfo_Delay(int graphic)
8818 return graphic_info[graphic].anim_delay;
8821 void PlayMenuSoundExt(int sound)
8823 if (sound == SND_UNDEFINED)
8826 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8827 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8830 if (IS_LOOP_SOUND(sound))
8831 PlaySoundLoop(sound);
8836 void PlayMenuSound()
8838 PlayMenuSoundExt(menu.sound[game_status]);
8841 void PlayMenuSoundStereo(int sound, int stereo_position)
8843 if (sound == SND_UNDEFINED)
8846 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8847 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8850 if (IS_LOOP_SOUND(sound))
8851 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
8853 PlaySoundStereo(sound, stereo_position);
8856 void PlayMenuSoundIfLoopExt(int sound)
8858 if (sound == SND_UNDEFINED)
8861 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8862 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8865 if (IS_LOOP_SOUND(sound))
8866 PlaySoundLoop(sound);
8869 void PlayMenuSoundIfLoop()
8871 PlayMenuSoundIfLoopExt(menu.sound[game_status]);
8874 void PlayMenuMusicExt(int music)
8876 if (music == MUS_UNDEFINED)
8879 if (!setup.sound_music)
8885 void PlayMenuMusic()
8887 char *curr_music = getCurrentlyPlayingMusicFilename();
8888 char *next_music = getMusicInfoEntryFilename(menu.music[game_status]);
8890 if (!strEqual(curr_music, next_music))
8891 PlayMenuMusicExt(menu.music[game_status]);
8894 void PlayMenuSoundsAndMusic()
8900 static void FadeMenuSounds()
8905 static void FadeMenuMusic()
8907 char *curr_music = getCurrentlyPlayingMusicFilename();
8908 char *next_music = getMusicInfoEntryFilename(menu.music[game_status]);
8910 if (!strEqual(curr_music, next_music))
8914 void FadeMenuSoundsAndMusic()
8920 void PlaySoundActivating()
8923 PlaySound(SND_MENU_ITEM_ACTIVATING);
8927 void PlaySoundSelecting()
8930 PlaySound(SND_MENU_ITEM_SELECTING);
8934 void ToggleFullscreenOrChangeWindowScalingIfNeeded()
8936 boolean change_fullscreen = (setup.fullscreen !=
8937 video.fullscreen_enabled);
8938 boolean change_window_scaling_percent = (!video.fullscreen_enabled &&
8939 setup.window_scaling_percent !=
8940 video.window_scaling_percent);
8942 if (change_window_scaling_percent && video.fullscreen_enabled)
8945 if (!change_window_scaling_percent && !video.fullscreen_available)
8948 #if defined(TARGET_SDL2)
8949 if (change_window_scaling_percent)
8951 SDLSetWindowScaling(setup.window_scaling_percent);
8955 else if (change_fullscreen)
8957 SDLSetWindowFullscreen(setup.fullscreen);
8959 /* set setup value according to successfully changed fullscreen mode */
8960 setup.fullscreen = video.fullscreen_enabled;
8966 if (change_fullscreen ||
8967 change_window_scaling_percent)
8969 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
8971 /* save backbuffer content which gets lost when toggling fullscreen mode */
8972 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8974 if (change_window_scaling_percent)
8976 /* keep window mode, but change window scaling */
8977 video.fullscreen_enabled = TRUE; /* force new window scaling */
8980 /* toggle fullscreen */
8981 ChangeVideoModeIfNeeded(setup.fullscreen);
8983 /* set setup value according to successfully changed fullscreen mode */
8984 setup.fullscreen = video.fullscreen_enabled;
8986 /* restore backbuffer content from temporary backbuffer backup bitmap */
8987 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8989 FreeBitmap(tmp_backbuffer);
8991 /* update visible window/screen */
8992 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8996 void JoinRectangles(int *x, int *y, int *width, int *height,
8997 int x2, int y2, int width2, int height2)
8999 // do not join with "off-screen" rectangle
9000 if (x2 == -1 || y2 == -1)
9005 *width = MAX(*width, width2);
9006 *height = MAX(*height, height2);
9009 void SetAnimStatus(int anim_status_new)
9011 if (anim_status_new == GAME_MODE_MAIN)
9012 anim_status_new = GAME_MODE_PSEUDO_MAINONLY;
9013 else if (anim_status_new == GAME_MODE_SCORES)
9014 anim_status_new = GAME_MODE_PSEUDO_SCORESOLD;
9016 global.anim_status_next = anim_status_new;
9018 // directly set screen modes that are entered without fading
9019 if ((global.anim_status == GAME_MODE_PSEUDO_MAINONLY &&
9020 global.anim_status_next == GAME_MODE_PSEUDO_TYPENAME) ||
9021 (global.anim_status == GAME_MODE_PSEUDO_TYPENAME &&
9022 global.anim_status_next == GAME_MODE_PSEUDO_MAINONLY))
9023 global.anim_status = global.anim_status_next;
9026 void SetGameStatus(int game_status_new)
9028 if (game_status_new != game_status)
9029 game_status_last_screen = game_status;
9031 game_status = game_status_new;
9033 SetAnimStatus(game_status_new);
9036 void SetFontStatus(int game_status_new)
9038 static int last_game_status = -1;
9040 if (game_status_new != -1)
9042 // set game status for font use after storing last game status
9043 last_game_status = game_status;
9044 game_status = game_status_new;
9048 // reset game status after font use from last stored game status
9049 game_status = last_game_status;
9053 void ResetFontStatus()
9058 boolean CheckIfPlayfieldViewportHasChanged()
9060 // if game status has not changed, playfield viewport has not changed either
9061 if (game_status == game_status_last)
9064 // check if playfield viewport has changed with current game status
9065 struct RectWithBorder *vp_playfield = &viewport.playfield[game_status];
9066 int new_real_sx = vp_playfield->x;
9067 int new_real_sy = vp_playfield->y;
9068 int new_full_sxsize = vp_playfield->width;
9069 int new_full_sysize = vp_playfield->height;
9071 return (new_real_sx != REAL_SX ||
9072 new_real_sy != REAL_SY ||
9073 new_full_sxsize != FULL_SXSIZE ||
9074 new_full_sysize != FULL_SYSIZE);
9077 boolean CheckIfGlobalBorderOrPlayfieldViewportHasChanged()
9079 return (CheckIfGlobalBorderHasChanged() ||
9080 CheckIfPlayfieldViewportHasChanged());
9083 void ChangeViewportPropertiesIfNeeded()
9085 boolean use_mini_tilesize = (level.game_engine_type == GAME_ENGINE_TYPE_MM ?
9086 FALSE : setup.small_game_graphics);
9087 int gfx_game_mode = game_status;
9088 int gfx_game_mode2 = (game_status == GAME_MODE_EDITOR ? GAME_MODE_DEFAULT :
9090 struct RectWithBorder *vp_window = &viewport.window[gfx_game_mode];
9091 struct RectWithBorder *vp_playfield = &viewport.playfield[gfx_game_mode];
9092 struct RectWithBorder *vp_door_1 = &viewport.door_1[gfx_game_mode];
9093 struct RectWithBorder *vp_door_2 = &viewport.door_2[gfx_game_mode2];
9094 struct RectWithBorder *vp_door_3 = &viewport.door_2[GAME_MODE_EDITOR];
9095 int new_win_xsize = vp_window->width;
9096 int new_win_ysize = vp_window->height;
9097 int border_size = vp_playfield->border_size;
9098 int new_sx = vp_playfield->x + border_size;
9099 int new_sy = vp_playfield->y + border_size;
9100 int new_sxsize = vp_playfield->width - 2 * border_size;
9101 int new_sysize = vp_playfield->height - 2 * border_size;
9102 int new_real_sx = vp_playfield->x;
9103 int new_real_sy = vp_playfield->y;
9104 int new_full_sxsize = vp_playfield->width;
9105 int new_full_sysize = vp_playfield->height;
9106 int new_dx = vp_door_1->x;
9107 int new_dy = vp_door_1->y;
9108 int new_dxsize = vp_door_1->width;
9109 int new_dysize = vp_door_1->height;
9110 int new_vx = vp_door_2->x;
9111 int new_vy = vp_door_2->y;
9112 int new_vxsize = vp_door_2->width;
9113 int new_vysize = vp_door_2->height;
9114 int new_ex = vp_door_3->x;
9115 int new_ey = vp_door_3->y;
9116 int new_exsize = vp_door_3->width;
9117 int new_eysize = vp_door_3->height;
9118 int new_tilesize_var = (use_mini_tilesize ? MINI_TILESIZE : game.tile_size);
9119 int tilesize = (gfx_game_mode == GAME_MODE_PLAYING ? new_tilesize_var :
9120 gfx_game_mode == GAME_MODE_EDITOR ? MINI_TILESIZE : TILESIZE);
9121 int new_scr_fieldx = new_sxsize / tilesize;
9122 int new_scr_fieldy = new_sysize / tilesize;
9123 int new_scr_fieldx_buffers = new_sxsize / new_tilesize_var;
9124 int new_scr_fieldy_buffers = new_sysize / new_tilesize_var;
9125 boolean init_gfx_buffers = FALSE;
9126 boolean init_video_buffer = FALSE;
9127 boolean init_gadgets_and_anims = FALSE;
9128 boolean init_em_graphics = FALSE;
9130 if (new_win_xsize != WIN_XSIZE ||
9131 new_win_ysize != WIN_YSIZE)
9133 WIN_XSIZE = new_win_xsize;
9134 WIN_YSIZE = new_win_ysize;
9136 init_video_buffer = TRUE;
9137 init_gfx_buffers = TRUE;
9138 init_gadgets_and_anims = TRUE;
9140 // printf("::: video: init_video_buffer, init_gfx_buffers\n");
9143 if (new_scr_fieldx != SCR_FIELDX ||
9144 new_scr_fieldy != SCR_FIELDY)
9146 /* this always toggles between MAIN and GAME when using small tile size */
9148 SCR_FIELDX = new_scr_fieldx;
9149 SCR_FIELDY = new_scr_fieldy;
9151 // printf("::: new_scr_fieldx != SCR_FIELDX ...\n");
9162 new_sxsize != SXSIZE ||
9163 new_sysize != SYSIZE ||
9164 new_dxsize != DXSIZE ||
9165 new_dysize != DYSIZE ||
9166 new_vxsize != VXSIZE ||
9167 new_vysize != VYSIZE ||
9168 new_exsize != EXSIZE ||
9169 new_eysize != EYSIZE ||
9170 new_real_sx != REAL_SX ||
9171 new_real_sy != REAL_SY ||
9172 new_full_sxsize != FULL_SXSIZE ||
9173 new_full_sysize != FULL_SYSIZE ||
9174 new_tilesize_var != TILESIZE_VAR
9177 // ------------------------------------------------------------------------
9178 // determine next fading area for changed viewport definitions
9179 // ------------------------------------------------------------------------
9181 // start with current playfield area (default fading area)
9184 FADE_SXSIZE = FULL_SXSIZE;
9185 FADE_SYSIZE = FULL_SYSIZE;
9187 // add new playfield area if position or size has changed
9188 if (new_real_sx != REAL_SX || new_real_sy != REAL_SY ||
9189 new_full_sxsize != FULL_SXSIZE || new_full_sysize != FULL_SYSIZE)
9191 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
9192 new_real_sx, new_real_sy, new_full_sxsize,new_full_sysize);
9195 // add current and new door 1 area if position or size has changed
9196 if (new_dx != DX || new_dy != DY ||
9197 new_dxsize != DXSIZE || new_dysize != DYSIZE)
9199 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
9200 DX, DY, DXSIZE, DYSIZE);
9201 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
9202 new_dx, new_dy, new_dxsize, new_dysize);
9205 // add current and new door 2 area if position or size has changed
9206 if (new_dx != VX || new_dy != VY ||
9207 new_dxsize != VXSIZE || new_dysize != VYSIZE)
9209 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
9210 VX, VY, VXSIZE, VYSIZE);
9211 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
9212 new_vx, new_vy, new_vxsize, new_vysize);
9215 // ------------------------------------------------------------------------
9216 // handle changed tile size
9217 // ------------------------------------------------------------------------
9219 if (new_tilesize_var != TILESIZE_VAR)
9221 // printf("::: new_tilesize_var != TILESIZE_VAR\n");
9223 // changing tile size invalidates scroll values of engine snapshots
9224 FreeEngineSnapshotSingle();
9226 // changing tile size requires update of graphic mapping for EM engine
9227 init_em_graphics = TRUE;
9238 SXSIZE = new_sxsize;
9239 SYSIZE = new_sysize;
9240 DXSIZE = new_dxsize;
9241 DYSIZE = new_dysize;
9242 VXSIZE = new_vxsize;
9243 VYSIZE = new_vysize;
9244 EXSIZE = new_exsize;
9245 EYSIZE = new_eysize;
9246 REAL_SX = new_real_sx;
9247 REAL_SY = new_real_sy;
9248 FULL_SXSIZE = new_full_sxsize;
9249 FULL_SYSIZE = new_full_sysize;
9250 TILESIZE_VAR = new_tilesize_var;
9252 init_gfx_buffers = TRUE;
9253 init_gadgets_and_anims = TRUE;
9255 // printf("::: viewports: init_gfx_buffers\n");
9256 // printf("::: viewports: init_gadgets_and_anims\n");
9259 if (init_gfx_buffers)
9261 // printf("::: init_gfx_buffers\n");
9263 SCR_FIELDX = new_scr_fieldx_buffers;
9264 SCR_FIELDY = new_scr_fieldy_buffers;
9268 SCR_FIELDX = new_scr_fieldx;
9269 SCR_FIELDY = new_scr_fieldy;
9271 SetDrawDeactivationMask(REDRAW_NONE);
9272 SetDrawBackgroundMask(REDRAW_FIELD);
9275 if (init_video_buffer)
9277 // printf("::: init_video_buffer\n");
9279 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
9280 InitImageTextures();
9283 if (init_gadgets_and_anims)
9285 // printf("::: init_gadgets_and_anims\n");
9288 InitGlobalAnimations();
9291 if (init_em_graphics)
9293 InitGraphicInfo_EM();