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)
364 int level_xsize = level.native_mm_level->fieldx;
365 int full_xsize = level_xsize * TILESIZE_VAR;
367 sx -= (full_xsize < SXSIZE ? (SXSIZE - full_xsize) / 2 : 0);
371 int lx = px / TILESIZE_VAR;
376 static int getLevelFromScreenY_MM(int sy)
379 int level_ysize = level.native_mm_level->fieldy;
380 int full_ysize = level_ysize * TILESIZE_VAR;
382 sy -= (full_ysize < SYSIZE ? (SYSIZE - full_ysize) / 2 : 0);
386 int ly = py / TILESIZE_VAR;
391 int getLevelFromScreenX(int x)
393 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
394 return getLevelFromScreenX_EM(x);
395 if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
396 return getLevelFromScreenX_SP(x);
397 if (level.game_engine_type == GAME_ENGINE_TYPE_MM)
398 return getLevelFromScreenX_MM(x);
400 return getLevelFromScreenX_RND(x);
403 int getLevelFromScreenY(int y)
405 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
406 return getLevelFromScreenY_EM(y);
407 if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
408 return getLevelFromScreenY_SP(y);
409 if (level.game_engine_type == GAME_ENGINE_TYPE_MM)
410 return getLevelFromScreenY_MM(y);
412 return getLevelFromScreenY_RND(y);
415 void DumpTile(int x, int y)
421 printf_line("-", 79);
422 printf("Field Info: SCREEN(%d, %d), LEVEL(%d, %d)\n", sx, sy, x, y);
423 printf_line("-", 79);
425 if (!IN_LEV_FIELD(x, y))
427 printf("(not in level field)\n");
433 token_name = element_info[Feld[x][y]].token_name;
435 printf(" Feld: %d\t['%s']\n", Feld[x][y], token_name);
436 printf(" Back: %s\n", print_if_not_empty(Back[x][y]));
437 printf(" Store: %s\n", print_if_not_empty(Store[x][y]));
438 printf(" Store2: %s\n", print_if_not_empty(Store2[x][y]));
439 printf(" StorePlayer: %s\n", print_if_not_empty(StorePlayer[x][y]));
440 printf(" MovPos: %d\n", MovPos[x][y]);
441 printf(" MovDir: %d\n", MovDir[x][y]);
442 printf(" MovDelay: %d\n", MovDelay[x][y]);
443 printf(" ChangeDelay: %d\n", ChangeDelay[x][y]);
444 printf(" CustomValue: %d\n", CustomValue[x][y]);
445 printf(" GfxElement: %d\n", GfxElement[x][y]);
446 printf(" GfxAction: %d\n", GfxAction[x][y]);
447 printf(" GfxFrame: %d [%d]\n", GfxFrame[x][y], FrameCounter);
448 printf(" Player x/y: %d, %d\n", local_player->jx, local_player->jy);
452 void DumpTileFromScreen(int sx, int sy)
454 int lx = getLevelFromScreenX(sx);
455 int ly = getLevelFromScreenY(sy);
460 void SetDrawtoField(int mode)
462 if (mode == DRAW_TO_FIELDBUFFER)
468 BX2 = SCR_FIELDX + 1;
469 BY2 = SCR_FIELDY + 1;
471 drawto_field = fieldbuffer;
473 else /* DRAW_TO_BACKBUFFER */
479 BX2 = SCR_FIELDX - 1;
480 BY2 = SCR_FIELDY - 1;
482 drawto_field = backbuffer;
486 static void RedrawPlayfield_RND()
488 if (game.envelope_active)
491 DrawLevel(REDRAW_ALL);
495 void RedrawPlayfield()
497 if (game_status != GAME_MODE_PLAYING)
500 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
501 RedrawPlayfield_EM(TRUE);
502 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
503 RedrawPlayfield_SP(TRUE);
504 else if (level.game_engine_type == GAME_ENGINE_TYPE_MM)
505 RedrawPlayfield_MM();
506 else if (level.game_engine_type == GAME_ENGINE_TYPE_RND)
507 RedrawPlayfield_RND();
509 BlitScreenToBitmap(backbuffer);
511 BlitBitmap(drawto, window, gfx.sx, gfx.sy, gfx.sxsize, gfx.sysize,
515 static void DrawMaskedBorderExt_Rect(int x, int y, int width, int height,
518 Bitmap *src_bitmap = getGlobalBorderBitmapFromStatus(global.border_status);
519 Bitmap *dst_bitmap = gfx.masked_border_bitmap_ptr;
521 if (x == -1 && y == -1)
524 if (draw_target == DRAW_TO_SCREEN)
525 BlitToScreenMasked(src_bitmap, x, y, width, height, x, y);
527 BlitBitmapMasked(src_bitmap, dst_bitmap, x, y, width, height, x, y);
530 static void DrawMaskedBorderExt_FIELD(int draw_target)
532 if (global.border_status >= GAME_MODE_MAIN &&
533 global.border_status <= GAME_MODE_PLAYING &&
534 border.draw_masked[global.border_status])
535 DrawMaskedBorderExt_Rect(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
539 static void DrawMaskedBorderExt_DOOR_1(int draw_target)
541 // when drawing to backbuffer, never draw border over open doors
542 if (draw_target == DRAW_TO_BACKBUFFER &&
543 (GetDoorState() & DOOR_OPEN_1))
546 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
547 (global.border_status != GAME_MODE_EDITOR ||
548 border.draw_masked[GFX_SPECIAL_ARG_EDITOR]))
549 DrawMaskedBorderExt_Rect(DX, DY, DXSIZE, DYSIZE, draw_target);
552 static void DrawMaskedBorderExt_DOOR_2(int draw_target)
554 // when drawing to backbuffer, never draw border over open doors
555 if (draw_target == DRAW_TO_BACKBUFFER &&
556 (GetDoorState() & DOOR_OPEN_2))
559 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
560 global.border_status != GAME_MODE_EDITOR)
561 DrawMaskedBorderExt_Rect(VX, VY, VXSIZE, VYSIZE, draw_target);
564 static void DrawMaskedBorderExt_DOOR_3(int draw_target)
566 /* currently not available */
569 static void DrawMaskedBorderExt_ALL(int draw_target)
571 DrawMaskedBorderExt_FIELD(draw_target);
572 DrawMaskedBorderExt_DOOR_1(draw_target);
573 DrawMaskedBorderExt_DOOR_2(draw_target);
574 DrawMaskedBorderExt_DOOR_3(draw_target);
577 static void DrawMaskedBorderExt(int redraw_mask, int draw_target)
579 /* never draw masked screen borders on borderless screens */
580 if (global.border_status == GAME_MODE_LOADING ||
581 global.border_status == GAME_MODE_TITLE)
584 if (redraw_mask & REDRAW_ALL)
585 DrawMaskedBorderExt_ALL(draw_target);
588 if (redraw_mask & REDRAW_FIELD)
589 DrawMaskedBorderExt_FIELD(draw_target);
590 if (redraw_mask & REDRAW_DOOR_1)
591 DrawMaskedBorderExt_DOOR_1(draw_target);
592 if (redraw_mask & REDRAW_DOOR_2)
593 DrawMaskedBorderExt_DOOR_2(draw_target);
594 if (redraw_mask & REDRAW_DOOR_3)
595 DrawMaskedBorderExt_DOOR_3(draw_target);
599 void DrawMaskedBorder_FIELD()
601 DrawMaskedBorderExt_FIELD(DRAW_TO_BACKBUFFER);
604 void DrawMaskedBorder(int redraw_mask)
606 DrawMaskedBorderExt(redraw_mask, DRAW_TO_BACKBUFFER);
609 void DrawMaskedBorderToTarget(int draw_target)
611 if (draw_target == DRAW_TO_BACKBUFFER ||
612 draw_target == DRAW_TO_SCREEN)
614 DrawMaskedBorderExt(REDRAW_ALL, draw_target);
618 int last_border_status = global.border_status;
620 if (draw_target == DRAW_TO_FADE_SOURCE)
622 global.border_status = gfx.fade_border_source_status;
623 gfx.masked_border_bitmap_ptr = gfx.fade_bitmap_source;
625 else if (draw_target == DRAW_TO_FADE_TARGET)
627 global.border_status = gfx.fade_border_target_status;
628 gfx.masked_border_bitmap_ptr = gfx.fade_bitmap_target;
631 DrawMaskedBorderExt(REDRAW_ALL, draw_target);
633 global.border_status = last_border_status;
634 gfx.masked_border_bitmap_ptr = backbuffer;
638 void DrawTileCursor(int draw_target)
644 int graphic = IMG_GLOBAL_TILE_CURSOR;
646 int tilesize = TILESIZE_VAR;
647 int width = tilesize;
648 int height = tilesize;
650 if (game_status != GAME_MODE_PLAYING)
653 if (!tile_cursor.enabled ||
657 if (tile_cursor.moving)
659 int step = TILESIZE_VAR / 4;
660 int dx = tile_cursor.target_x - tile_cursor.x;
661 int dy = tile_cursor.target_y - tile_cursor.y;
664 tile_cursor.x = tile_cursor.target_x;
666 tile_cursor.x += SIGN(dx) * step;
669 tile_cursor.y = tile_cursor.target_y;
671 tile_cursor.y += SIGN(dy) * step;
673 if (tile_cursor.x == tile_cursor.target_x &&
674 tile_cursor.y == tile_cursor.target_y)
675 tile_cursor.moving = FALSE;
678 dst_x = tile_cursor.x;
679 dst_y = tile_cursor.y;
681 frame = getGraphicAnimationFrame(graphic, -1);
683 getSizedGraphicSource(graphic, frame, tilesize, &src_bitmap, &src_x, &src_y);
686 (draw_target == DRAW_TO_FADE_SOURCE ? gfx.fade_bitmap_source :
687 draw_target == DRAW_TO_FADE_TARGET ? gfx.fade_bitmap_target : NULL);
689 if (draw_target == DRAW_TO_SCREEN)
690 BlitToScreenMasked(src_bitmap, src_x, src_y, width, height, dst_x, dst_y);
692 BlitBitmapMasked(src_bitmap, fade_bitmap, src_x, src_y, width, height,
696 void BlitScreenToBitmap_RND(Bitmap *target_bitmap)
698 int fx = getFieldbufferOffsetX_RND();
699 int fy = getFieldbufferOffsetY_RND();
701 BlitBitmap(drawto_field, target_bitmap, fx, fy, SXSIZE, SYSIZE, SX, SY);
704 void BlitScreenToBitmap(Bitmap *target_bitmap)
706 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
707 BlitScreenToBitmap_EM(target_bitmap);
708 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
709 BlitScreenToBitmap_SP(target_bitmap);
710 else if (level.game_engine_type == GAME_ENGINE_TYPE_MM)
711 BlitScreenToBitmap_MM(target_bitmap);
712 else if (level.game_engine_type == GAME_ENGINE_TYPE_RND)
713 BlitScreenToBitmap_RND(target_bitmap);
715 redraw_mask |= REDRAW_FIELD;
718 void DrawFramesPerSecond()
721 int font_nr = FONT_TEXT_2;
722 int font_width = getFontWidth(font_nr);
723 int draw_deactivation_mask = GetDrawDeactivationMask();
724 boolean draw_masked = (draw_deactivation_mask == REDRAW_NONE);
726 /* draw FPS with leading space (needed if field buffer deactivated) */
727 sprintf(text, " %04.1f fps", global.frames_per_second);
729 /* override draw deactivation mask (required for invisible warp mode) */
730 SetDrawDeactivationMask(REDRAW_NONE);
732 /* draw opaque FPS if field buffer deactivated, else draw masked FPS */
733 DrawTextExt(backbuffer, SX + SXSIZE - font_width * strlen(text), SY, text,
734 font_nr, (draw_masked ? BLIT_MASKED : BLIT_OPAQUE));
736 /* set draw deactivation mask to previous value */
737 SetDrawDeactivationMask(draw_deactivation_mask);
739 /* force full-screen redraw in this frame */
740 redraw_mask = REDRAW_ALL;
744 static void PrintFrameTimeDebugging()
746 static unsigned int last_counter = 0;
747 unsigned int counter = Counter();
748 int diff_1 = counter - last_counter;
749 int diff_2 = diff_1 - GAME_FRAME_DELAY;
751 int diff_2_cut = MIN(ABS(diff_2), diff_2_max);
752 char diff_bar[2 * diff_2_max + 5];
756 diff_bar[pos++] = (diff_2 < -diff_2_max ? '<' : ' ');
758 for (i = 0; i < diff_2_max; i++)
759 diff_bar[pos++] = (diff_2 >= 0 ? ' ' :
760 i >= diff_2_max - diff_2_cut ? '-' : ' ');
762 diff_bar[pos++] = '|';
764 for (i = 0; i < diff_2_max; i++)
765 diff_bar[pos++] = (diff_2 <= 0 ? ' ' : i < diff_2_cut ? '+' : ' ');
767 diff_bar[pos++] = (diff_2 > diff_2_max ? '>' : ' ');
769 diff_bar[pos++] = '\0';
771 Error(ERR_INFO, "%06d [%02d] [%c%02d] %s",
774 (diff_2 < 0 ? '-' : diff_2 > 0 ? '+' : ' '), ABS(diff_2),
777 last_counter = counter;
781 static int unifiedRedrawMask(int mask)
783 if (mask & REDRAW_ALL)
786 if (mask & REDRAW_FIELD && mask & REDRAW_DOORS)
792 static boolean equalRedrawMasks(int mask_1, int mask_2)
794 return unifiedRedrawMask(mask_1) == unifiedRedrawMask(mask_2);
799 static int last_redraw_mask = REDRAW_NONE;
801 // force screen redraw in every frame to continue drawing global animations
802 // (but always use the last redraw mask to prevent unwanted side effects)
803 if (redraw_mask == REDRAW_NONE)
804 redraw_mask = last_redraw_mask;
806 last_redraw_mask = redraw_mask;
809 // masked border now drawn immediately when blitting backbuffer to window
811 // draw masked border to all viewports, if defined
812 DrawMaskedBorder(redraw_mask);
815 // draw frames per second (only if debug mode is enabled)
816 if (redraw_mask & REDRAW_FPS)
817 DrawFramesPerSecond();
819 // remove playfield redraw before potentially merging with doors redraw
820 if (DrawingDeactivated(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE))
821 redraw_mask &= ~REDRAW_FIELD;
823 // redraw complete window if both playfield and (some) doors need redraw
824 if (redraw_mask & REDRAW_FIELD && redraw_mask & REDRAW_DOORS)
825 redraw_mask = REDRAW_ALL;
827 /* although redrawing the whole window would be fine for normal gameplay,
828 being able to only redraw the playfield is required for deactivating
829 certain drawing areas (mainly playfield) to work, which is needed for
830 warp-forward to be fast enough (by skipping redraw of most frames) */
832 if (redraw_mask & REDRAW_ALL)
834 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
836 else if (redraw_mask & REDRAW_FIELD)
838 BlitBitmap(backbuffer, window,
839 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
841 else if (redraw_mask & REDRAW_DOORS)
843 // merge door areas to prevent calling screen redraw more than once
849 if (redraw_mask & REDRAW_DOOR_1)
853 x2 = MAX(x2, DX + DXSIZE);
854 y2 = MAX(y2, DY + DYSIZE);
857 if (redraw_mask & REDRAW_DOOR_2)
861 x2 = MAX(x2, VX + VXSIZE);
862 y2 = MAX(y2, VY + VYSIZE);
865 if (redraw_mask & REDRAW_DOOR_3)
869 x2 = MAX(x2, EX + EXSIZE);
870 y2 = MAX(y2, EY + EYSIZE);
873 // make sure that at least one pixel is blitted, and inside the screen
874 // (else nothing is blitted, causing the animations not to be updated)
875 x1 = MIN(MAX(0, x1), WIN_XSIZE - 1);
876 y1 = MIN(MAX(0, y1), WIN_YSIZE - 1);
877 x2 = MIN(MAX(1, x2), WIN_XSIZE);
878 y2 = MIN(MAX(1, y2), WIN_YSIZE);
880 BlitBitmap(backbuffer, window, x1, y1, x2 - x1, y2 - y1, x1, y1);
883 redraw_mask = REDRAW_NONE;
886 PrintFrameTimeDebugging();
890 void BackToFront_WithFrameDelay(unsigned int frame_delay_value)
892 unsigned int frame_delay_value_old = GetVideoFrameDelay();
894 SetVideoFrameDelay(frame_delay_value);
898 SetVideoFrameDelay(frame_delay_value_old);
901 static int fade_type_skip = FADE_TYPE_NONE;
903 static void FadeExt(int fade_mask, int fade_mode, int fade_type)
905 void (*draw_border_function)(void) = NULL;
906 int x, y, width, height;
907 int fade_delay, post_delay;
909 if (fade_type == FADE_TYPE_FADE_OUT)
911 if (fade_type_skip != FADE_TYPE_NONE)
913 /* skip all fade operations until specified fade operation */
914 if (fade_type & fade_type_skip)
915 fade_type_skip = FADE_TYPE_NONE;
920 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
924 redraw_mask |= fade_mask;
926 if (fade_type == FADE_TYPE_SKIP)
928 fade_type_skip = fade_mode;
933 fade_delay = fading.fade_delay;
934 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
936 if (fade_type_skip != FADE_TYPE_NONE)
938 /* skip all fade operations until specified fade operation */
939 if (fade_type & fade_type_skip)
940 fade_type_skip = FADE_TYPE_NONE;
945 if (global.autoplay_leveldir)
950 if (fade_mask == REDRAW_FIELD)
955 height = FADE_SYSIZE;
957 if (border.draw_masked_when_fading)
958 draw_border_function = DrawMaskedBorder_FIELD; /* update when fading */
960 DrawMaskedBorder_FIELD(); /* draw once */
962 else /* REDRAW_ALL */
970 if (!setup.fade_screens ||
972 fading.fade_mode == FADE_MODE_NONE)
974 if (fade_mode == FADE_MODE_FADE_OUT)
977 BlitBitmap(backbuffer, window, x, y, width, height, x, y);
979 redraw_mask &= ~fade_mask;
984 FadeRectangle(x, y, width, height, fade_mode, fade_delay, post_delay,
985 draw_border_function);
987 redraw_mask &= ~fade_mask;
990 static void SetScreenStates_BeforeFadingIn()
992 // temporarily set screen mode for animations to screen after fading in
993 global.anim_status = global.anim_status_next;
995 // store backbuffer with all animations that will be started after fading in
996 if (fade_type_skip != FADE_MODE_SKIP_FADE_IN)
997 PrepareFadeBitmap(DRAW_TO_FADE_TARGET);
999 // set screen mode for animations back to fading
1000 global.anim_status = GAME_MODE_PSEUDO_FADING;
1003 static void SetScreenStates_AfterFadingIn()
1005 // store new source screen (to use correct masked border for fading)
1006 gfx.fade_border_source_status = global.border_status;
1008 global.anim_status = global.anim_status_next;
1011 static void SetScreenStates_BeforeFadingOut()
1013 // store new target screen (to use correct masked border for fading)
1014 gfx.fade_border_target_status = game_status;
1016 // set screen mode for animations to fading
1017 global.anim_status = GAME_MODE_PSEUDO_FADING;
1019 // store backbuffer with all animations that will be stopped for fading out
1020 if (fade_type_skip != FADE_MODE_SKIP_FADE_OUT)
1021 PrepareFadeBitmap(DRAW_TO_FADE_SOURCE);
1024 static void SetScreenStates_AfterFadingOut()
1026 global.border_status = game_status;
1029 void FadeIn(int fade_mask)
1031 SetScreenStates_BeforeFadingIn();
1034 DrawMaskedBorder(REDRAW_ALL);
1037 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
1038 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_IN);
1040 FadeExt(fade_mask, FADE_MODE_FADE_IN, FADE_TYPE_FADE_IN);
1044 FADE_SXSIZE = FULL_SXSIZE;
1045 FADE_SYSIZE = FULL_SYSIZE;
1047 if (game_status == GAME_MODE_PLAYING &&
1048 strEqual(setup.touch.control_type, TOUCH_CONTROL_VIRTUAL_BUTTONS))
1049 SetOverlayActive(TRUE);
1051 SetScreenStates_AfterFadingIn();
1053 // force update of global animation status in case of rapid screen changes
1054 redraw_mask = REDRAW_ALL;
1058 void FadeOut(int fade_mask)
1060 // update screen if areas covered by "fade_mask" and "redraw_mask" differ
1061 if (!equalRedrawMasks(fade_mask, redraw_mask))
1064 SetScreenStates_BeforeFadingOut();
1066 SetTileCursorActive(FALSE);
1067 SetOverlayActive(FALSE);
1070 DrawMaskedBorder(REDRAW_ALL);
1073 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
1074 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_OUT);
1076 FadeExt(fade_mask, FADE_MODE_FADE_OUT, FADE_TYPE_FADE_OUT);
1078 SetScreenStates_AfterFadingOut();
1081 static void FadeSetLeaveNext(struct TitleFadingInfo fading_leave, boolean set)
1083 static struct TitleFadingInfo fading_leave_stored;
1086 fading_leave_stored = fading_leave;
1088 fading = fading_leave_stored;
1091 void FadeSetEnterMenu()
1093 fading = menu.enter_menu;
1095 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
1098 void FadeSetLeaveMenu()
1100 fading = menu.leave_menu;
1102 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
1105 void FadeSetEnterScreen()
1107 fading = menu.enter_screen[game_status];
1109 FadeSetLeaveNext(menu.leave_screen[game_status], TRUE); /* store */
1112 void FadeSetNextScreen()
1114 fading = menu.next_screen[game_status];
1116 // (do not overwrite fade mode set by FadeSetEnterScreen)
1117 // FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
1120 void FadeSetLeaveScreen()
1122 FadeSetLeaveNext(menu.leave_screen[game_status], FALSE); /* recall */
1125 void FadeSetFromType(int type)
1127 if (type & TYPE_ENTER_SCREEN)
1128 FadeSetEnterScreen();
1129 else if (type & TYPE_ENTER)
1131 else if (type & TYPE_LEAVE)
1135 void FadeSetDisabled()
1137 static struct TitleFadingInfo fading_none = { FADE_MODE_NONE, -1, -1, -1 };
1139 fading = fading_none;
1142 void FadeSkipNextFadeIn()
1144 FadeExt(0, FADE_MODE_SKIP_FADE_IN, FADE_TYPE_SKIP);
1147 void FadeSkipNextFadeOut()
1149 FadeExt(0, FADE_MODE_SKIP_FADE_OUT, FADE_TYPE_SKIP);
1152 Bitmap *getBitmapFromGraphicOrDefault(int graphic, int default_graphic)
1154 boolean redefined = getImageListEntryFromImageID(graphic)->redefined;
1156 return (graphic == IMG_UNDEFINED ? NULL :
1157 graphic_info[graphic].bitmap != NULL || redefined ?
1158 graphic_info[graphic].bitmap :
1159 graphic_info[default_graphic].bitmap);
1162 Bitmap *getBackgroundBitmap(int graphic)
1164 return getBitmapFromGraphicOrDefault(graphic, IMG_BACKGROUND);
1167 Bitmap *getGlobalBorderBitmap(int graphic)
1169 return getBitmapFromGraphicOrDefault(graphic, IMG_GLOBAL_BORDER);
1172 Bitmap *getGlobalBorderBitmapFromStatus(int status)
1175 (status == GAME_MODE_MAIN ||
1176 status == GAME_MODE_PSEUDO_TYPENAME ? IMG_GLOBAL_BORDER_MAIN :
1177 status == GAME_MODE_SCORES ? IMG_GLOBAL_BORDER_SCORES :
1178 status == GAME_MODE_EDITOR ? IMG_GLOBAL_BORDER_EDITOR :
1179 status == GAME_MODE_PLAYING ? IMG_GLOBAL_BORDER_PLAYING :
1182 return getGlobalBorderBitmap(graphic);
1185 void SetWindowBackgroundImageIfDefined(int graphic)
1187 if (graphic_info[graphic].bitmap)
1188 SetWindowBackgroundBitmap(graphic_info[graphic].bitmap);
1191 void SetMainBackgroundImageIfDefined(int graphic)
1193 if (graphic_info[graphic].bitmap)
1194 SetMainBackgroundBitmap(graphic_info[graphic].bitmap);
1197 void SetDoorBackgroundImageIfDefined(int graphic)
1199 if (graphic_info[graphic].bitmap)
1200 SetDoorBackgroundBitmap(graphic_info[graphic].bitmap);
1203 void SetWindowBackgroundImage(int graphic)
1205 SetWindowBackgroundBitmap(getBackgroundBitmap(graphic));
1208 void SetMainBackgroundImage(int graphic)
1210 SetMainBackgroundBitmap(getBackgroundBitmap(graphic));
1213 void SetDoorBackgroundImage(int graphic)
1215 SetDoorBackgroundBitmap(getBackgroundBitmap(graphic));
1218 void SetPanelBackground()
1220 struct GraphicInfo *gfx = &graphic_info[IMG_BACKGROUND_PANEL];
1222 BlitBitmapTiled(gfx->bitmap, bitmap_db_panel, gfx->src_x, gfx->src_y,
1223 gfx->width, gfx->height, 0, 0, DXSIZE, DYSIZE);
1225 SetDoorBackgroundBitmap(bitmap_db_panel);
1228 void DrawBackground(int x, int y, int width, int height)
1230 /* "drawto" might still point to playfield buffer here (hall of fame) */
1231 ClearRectangleOnBackground(backbuffer, x, y, width, height);
1233 if (IN_GFX_FIELD_FULL(x, y))
1234 redraw_mask |= REDRAW_FIELD;
1235 else if (IN_GFX_DOOR_1(x, y))
1236 redraw_mask |= REDRAW_DOOR_1;
1237 else if (IN_GFX_DOOR_2(x, y))
1238 redraw_mask |= REDRAW_DOOR_2;
1239 else if (IN_GFX_DOOR_3(x, y))
1240 redraw_mask |= REDRAW_DOOR_3;
1243 void DrawBackgroundForFont(int x, int y, int width, int height, int font_nr)
1245 struct FontBitmapInfo *font = getFontBitmapInfo(font_nr);
1247 if (font->bitmap == NULL)
1250 DrawBackground(x, y, width, height);
1253 void DrawBackgroundForGraphic(int x, int y, int width, int height, int graphic)
1255 struct GraphicInfo *g = &graphic_info[graphic];
1257 if (g->bitmap == NULL)
1260 DrawBackground(x, y, width, height);
1263 static int game_status_last = -1;
1264 static Bitmap *global_border_bitmap_last = NULL;
1265 static Bitmap *global_border_bitmap = NULL;
1266 static int real_sx_last = -1, real_sy_last = -1;
1267 static int full_sxsize_last = -1, full_sysize_last = -1;
1268 static int dx_last = -1, dy_last = -1;
1269 static int dxsize_last = -1, dysize_last = -1;
1270 static int vx_last = -1, vy_last = -1;
1271 static int vxsize_last = -1, vysize_last = -1;
1273 boolean CheckIfGlobalBorderHasChanged()
1275 // if game status has not changed, global border has not changed either
1276 if (game_status == game_status_last)
1279 // determine and store new global border bitmap for current game status
1280 global_border_bitmap = getGlobalBorderBitmapFromStatus(game_status);
1282 return (global_border_bitmap_last != global_border_bitmap);
1285 boolean CheckIfGlobalBorderRedrawIsNeeded()
1287 // if game status has not changed, nothing has to be redrawn
1288 if (game_status == game_status_last)
1291 // redraw if last screen was title screen
1292 if (game_status_last == GAME_MODE_TITLE)
1295 // redraw if global screen border has changed
1296 if (CheckIfGlobalBorderHasChanged())
1299 // redraw if position or size of playfield area has changed
1300 if (real_sx_last != REAL_SX || real_sy_last != REAL_SY ||
1301 full_sxsize_last != FULL_SXSIZE || full_sysize_last != FULL_SYSIZE)
1304 // redraw if position or size of door area has changed
1305 if (dx_last != DX || dy_last != DY ||
1306 dxsize_last != DXSIZE || dysize_last != DYSIZE)
1309 // redraw if position or size of tape area has changed
1310 if (vx_last != VX || vy_last != VY ||
1311 vxsize_last != VXSIZE || vysize_last != VYSIZE)
1317 void RedrawGlobalBorderFromBitmap(Bitmap *bitmap)
1320 BlitBitmap(bitmap, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
1322 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
1325 void RedrawGlobalBorder()
1327 Bitmap *bitmap = getGlobalBorderBitmapFromStatus(game_status);
1329 RedrawGlobalBorderFromBitmap(bitmap);
1331 redraw_mask = REDRAW_ALL;
1334 static void RedrawGlobalBorderIfNeeded()
1336 if (game_status == game_status_last)
1339 // copy current draw buffer to later copy back areas that have not changed
1340 if (game_status_last != GAME_MODE_TITLE)
1341 BlitBitmap(backbuffer, bitmap_db_store_1, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
1343 if (CheckIfGlobalBorderRedrawIsNeeded())
1345 // redraw global screen border (or clear, if defined to be empty)
1346 RedrawGlobalBorderFromBitmap(global_border_bitmap);
1348 // copy previous playfield and door areas, if they are defined on both
1349 // previous and current screen and if they still have the same size
1351 if (real_sx_last != -1 && real_sy_last != -1 &&
1352 REAL_SX != -1 && REAL_SY != -1 &&
1353 full_sxsize_last == FULL_SXSIZE && full_sysize_last == FULL_SYSIZE)
1354 BlitBitmap(bitmap_db_store_1, backbuffer,
1355 real_sx_last, real_sy_last, FULL_SXSIZE, FULL_SYSIZE,
1358 if (dx_last != -1 && dy_last != -1 &&
1359 DX != -1 && DY != -1 &&
1360 dxsize_last == DXSIZE && dysize_last == DYSIZE)
1361 BlitBitmap(bitmap_db_store_1, backbuffer,
1362 dx_last, dy_last, DXSIZE, DYSIZE, DX, DY);
1364 if (vx_last != -1 && vy_last != -1 &&
1365 VX != -1 && VY != -1 &&
1366 vxsize_last == VXSIZE && vysize_last == VYSIZE)
1367 BlitBitmap(bitmap_db_store_1, backbuffer,
1368 vx_last, vy_last, VXSIZE, VYSIZE, VX, VY);
1370 redraw_mask = REDRAW_ALL;
1373 game_status_last = game_status;
1375 global_border_bitmap_last = global_border_bitmap;
1377 real_sx_last = REAL_SX;
1378 real_sy_last = REAL_SY;
1379 full_sxsize_last = FULL_SXSIZE;
1380 full_sysize_last = FULL_SYSIZE;
1383 dxsize_last = DXSIZE;
1384 dysize_last = DYSIZE;
1387 vxsize_last = VXSIZE;
1388 vysize_last = VYSIZE;
1393 RedrawGlobalBorderIfNeeded();
1395 /* !!! "drawto" might still point to playfield buffer here (see above) !!! */
1396 /* (when entering hall of fame after playing) */
1397 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
1399 /* !!! maybe this should be done before clearing the background !!! */
1400 if (game_status == GAME_MODE_PLAYING)
1402 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
1403 SetDrawtoField(DRAW_TO_FIELDBUFFER);
1407 SetDrawtoField(DRAW_TO_BACKBUFFER);
1411 void MarkTileDirty(int x, int y)
1413 redraw_mask |= REDRAW_FIELD;
1416 void SetBorderElement()
1420 BorderElement = EL_EMPTY;
1422 /* the MM game engine does not use a visible border element */
1423 if (level.game_engine_type == GAME_ENGINE_TYPE_MM)
1426 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
1428 for (x = 0; x < lev_fieldx; x++)
1430 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
1431 BorderElement = EL_STEELWALL;
1433 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
1439 void FloodFillLevelExt(int from_x, int from_y, int fill_element,
1440 int max_array_fieldx, int max_array_fieldy,
1441 short field[max_array_fieldx][max_array_fieldy],
1442 int max_fieldx, int max_fieldy)
1446 static int check[4][2] = { { -1, 0 }, { 0, -1 }, { 1, 0 }, { 0, 1 } };
1447 static int safety = 0;
1449 /* check if starting field still has the desired content */
1450 if (field[from_x][from_y] == fill_element)
1455 if (safety > max_fieldx * max_fieldy)
1456 Error(ERR_EXIT, "Something went wrong in 'FloodFill()'. Please debug.");
1458 old_element = field[from_x][from_y];
1459 field[from_x][from_y] = fill_element;
1461 for (i = 0; i < 4; i++)
1463 x = from_x + check[i][0];
1464 y = from_y + check[i][1];
1466 if (IN_FIELD(x, y, max_fieldx, max_fieldy) && field[x][y] == old_element)
1467 FloodFillLevelExt(x, y, fill_element, max_array_fieldx, max_array_fieldy,
1468 field, max_fieldx, max_fieldy);
1474 void FloodFillLevel(int from_x, int from_y, int fill_element,
1475 short field[MAX_LEV_FIELDX][MAX_LEV_FIELDY],
1476 int max_fieldx, int max_fieldy)
1478 FloodFillLevelExt(from_x, from_y, fill_element,
1479 MAX_LEV_FIELDX, MAX_LEV_FIELDY, field,
1480 max_fieldx, max_fieldy);
1483 void SetRandomAnimationValue(int x, int y)
1485 gfx.anim_random_frame = GfxRandom[x][y];
1488 int getGraphicAnimationFrame(int graphic, int sync_frame)
1490 /* animation synchronized with global frame counter, not move position */
1491 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
1492 sync_frame = FrameCounter;
1494 return getAnimationFrame(graphic_info[graphic].anim_frames,
1495 graphic_info[graphic].anim_delay,
1496 graphic_info[graphic].anim_mode,
1497 graphic_info[graphic].anim_start_frame,
1501 void getGraphicSourceBitmap(int graphic, int tilesize, Bitmap **bitmap)
1503 struct GraphicInfo *g = &graphic_info[graphic];
1504 int tilesize_capped = MIN(MAX(1, tilesize), TILESIZE);
1506 if (tilesize == gfx.standard_tile_size)
1507 *bitmap = g->bitmaps[IMG_BITMAP_STANDARD];
1508 else if (tilesize == game.tile_size)
1509 *bitmap = g->bitmaps[IMG_BITMAP_GAME];
1511 *bitmap = g->bitmaps[IMG_BITMAP_1x1 - log_2(tilesize_capped)];
1514 void getGraphicSourceXY(int graphic, int frame, int *x, int *y,
1515 boolean get_backside)
1517 struct GraphicInfo *g = &graphic_info[graphic];
1518 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
1519 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
1521 if (g->offset_y == 0) /* frames are ordered horizontally */
1523 int max_width = g->anim_frames_per_line * g->width;
1524 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
1526 *x = pos % max_width;
1527 *y = src_y % g->height + pos / max_width * g->height;
1529 else if (g->offset_x == 0) /* frames are ordered vertically */
1531 int max_height = g->anim_frames_per_line * g->height;
1532 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
1534 *x = src_x % g->width + pos / max_height * g->width;
1535 *y = pos % max_height;
1537 else /* frames are ordered diagonally */
1539 *x = src_x + frame * g->offset_x;
1540 *y = src_y + frame * g->offset_y;
1544 void getSizedGraphicSourceExt(int graphic, int frame, int tilesize,
1545 Bitmap **bitmap, int *x, int *y,
1546 boolean get_backside)
1548 struct GraphicInfo *g = &graphic_info[graphic];
1550 // if no in-game graphics defined, always use standard graphic size
1551 if (g->bitmaps[IMG_BITMAP_GAME] == NULL)
1552 tilesize = TILESIZE;
1554 getGraphicSourceBitmap(graphic, tilesize, bitmap);
1555 getGraphicSourceXY(graphic, frame, x, y, get_backside);
1557 *x = *x * tilesize / g->tile_size;
1558 *y = *y * tilesize / g->tile_size;
1561 void getSizedGraphicSource(int graphic, int frame, int tilesize,
1562 Bitmap **bitmap, int *x, int *y)
1564 getSizedGraphicSourceExt(graphic, frame, tilesize, bitmap, x, y, FALSE);
1567 void getFixedGraphicSource(int graphic, int frame,
1568 Bitmap **bitmap, int *x, int *y)
1570 getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y, FALSE);
1573 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1575 getSizedGraphicSource(graphic, 0, MINI_TILESIZE, bitmap, x, y);
1578 inline static void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1579 int *x, int *y, boolean get_backside)
1581 getSizedGraphicSourceExt(graphic, frame, TILESIZE_VAR, bitmap, x, y,
1585 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
1587 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
1590 void DrawGraphic(int x, int y, int graphic, int frame)
1593 if (!IN_SCR_FIELD(x, y))
1595 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1596 printf("DrawGraphic(): This should never happen!\n");
1601 DrawGraphicExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR, graphic,
1604 MarkTileDirty(x, y);
1607 void DrawFixedGraphic(int x, int y, int graphic, int frame)
1610 if (!IN_SCR_FIELD(x, y))
1612 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1613 printf("DrawGraphic(): This should never happen!\n");
1618 DrawFixedGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic,
1620 MarkTileDirty(x, y);
1623 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1629 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1631 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX_VAR, TILEY_VAR, x, y);
1634 void DrawFixedGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1640 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1641 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
1644 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
1647 if (!IN_SCR_FIELD(x, y))
1649 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1650 printf("DrawGraphicThruMask(): This should never happen!\n");
1655 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
1658 MarkTileDirty(x, y);
1661 void DrawFixedGraphicThruMask(int x, int y, int graphic, int frame)
1664 if (!IN_SCR_FIELD(x, y))
1666 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1667 printf("DrawGraphicThruMask(): This should never happen!\n");
1672 DrawFixedGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
1674 MarkTileDirty(x, y);
1677 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
1683 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1685 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX_VAR, TILEY_VAR,
1689 void DrawFixedGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y,
1690 int graphic, int frame)
1695 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1697 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY,
1701 void DrawSizedGraphic(int x, int y, int graphic, int frame, int tilesize)
1703 DrawSizedGraphicExt(drawto, SX + x * tilesize, SY + y * tilesize, graphic,
1705 MarkTileDirty(x / tilesize, y / tilesize);
1708 void DrawSizedGraphicThruMask(int x, int y, int graphic, int frame,
1711 DrawSizedGraphicThruMaskExt(drawto, SX + x * tilesize, SY + y * tilesize,
1712 graphic, frame, tilesize);
1713 MarkTileDirty(x / tilesize, y / tilesize);
1716 void DrawSizedGraphicExt(DrawBuffer *d, int x, int y, int graphic, int frame,
1722 getSizedGraphicSource(graphic, frame, tilesize, &src_bitmap, &src_x, &src_y);
1723 BlitBitmap(src_bitmap, d, src_x, src_y, tilesize, tilesize, x, y);
1726 void DrawSizedGraphicThruMaskExt(DrawBuffer *d, int x, int y, int graphic,
1727 int frame, int tilesize)
1732 getSizedGraphicSource(graphic, frame, tilesize, &src_bitmap, &src_x, &src_y);
1733 BlitBitmapMasked(src_bitmap, d, src_x, src_y, tilesize, tilesize, x, y);
1736 void DrawMiniGraphic(int x, int y, int graphic)
1738 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
1739 MarkTileDirty(x / 2, y / 2);
1742 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
1747 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1748 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
1751 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
1752 int graphic, int frame,
1753 int cut_mode, int mask_mode)
1758 int width = TILEX, height = TILEY;
1761 if (dx || dy) /* shifted graphic */
1763 if (x < BX1) /* object enters playfield from the left */
1770 else if (x > BX2) /* object enters playfield from the right */
1776 else if (x == BX1 && dx < 0) /* object leaves playfield to the left */
1782 else if (x == BX2 && dx > 0) /* object leaves playfield to the right */
1784 else if (dx) /* general horizontal movement */
1785 MarkTileDirty(x + SIGN(dx), y);
1787 if (y < BY1) /* object enters playfield from the top */
1789 if (cut_mode == CUT_BELOW) /* object completely above top border */
1797 else if (y > BY2) /* object enters playfield from the bottom */
1803 else if (y == BY1 && dy < 0) /* object leaves playfield to the top */
1809 else if (dy > 0 && cut_mode == CUT_ABOVE)
1811 if (y == BY2) /* object completely above bottom border */
1817 MarkTileDirty(x, y + 1);
1818 } /* object leaves playfield to the bottom */
1819 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1821 else if (dy) /* general vertical movement */
1822 MarkTileDirty(x, y + SIGN(dy));
1826 if (!IN_SCR_FIELD(x, y))
1828 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1829 printf("DrawGraphicShifted(): This should never happen!\n");
1834 width = width * TILESIZE_VAR / TILESIZE;
1835 height = height * TILESIZE_VAR / TILESIZE;
1836 cx = cx * TILESIZE_VAR / TILESIZE;
1837 cy = cy * TILESIZE_VAR / TILESIZE;
1838 dx = dx * TILESIZE_VAR / TILESIZE;
1839 dy = dy * TILESIZE_VAR / TILESIZE;
1841 if (width > 0 && height > 0)
1843 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1848 dst_x = FX + x * TILEX_VAR + dx;
1849 dst_y = FY + y * TILEY_VAR + dy;
1851 if (mask_mode == USE_MASKING)
1852 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1855 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1858 MarkTileDirty(x, y);
1862 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
1863 int graphic, int frame,
1864 int cut_mode, int mask_mode)
1869 int width = TILEX_VAR, height = TILEY_VAR;
1872 int x2 = x + SIGN(dx);
1873 int y2 = y + SIGN(dy);
1875 /* movement with two-tile animations must be sync'ed with movement position,
1876 not with current GfxFrame (which can be higher when using slow movement) */
1877 int anim_pos = (dx ? ABS(dx) : ABS(dy));
1878 int anim_frames = graphic_info[graphic].anim_frames;
1880 /* (we also need anim_delay here for movement animations with less frames) */
1881 int anim_delay = graphic_info[graphic].anim_delay;
1882 int sync_frame = anim_pos * anim_frames * anim_delay / TILESIZE;
1884 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
1885 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
1887 /* re-calculate animation frame for two-tile movement animation */
1888 frame = getGraphicAnimationFrame(graphic, sync_frame);
1890 /* check if movement start graphic inside screen area and should be drawn */
1891 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
1893 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
1895 dst_x = FX + x1 * TILEX_VAR;
1896 dst_y = FY + y1 * TILEY_VAR;
1898 if (mask_mode == USE_MASKING)
1899 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1902 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1905 MarkTileDirty(x1, y1);
1908 /* check if movement end graphic inside screen area and should be drawn */
1909 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
1911 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
1913 dst_x = FX + x2 * TILEX_VAR;
1914 dst_y = FY + y2 * TILEY_VAR;
1916 if (mask_mode == USE_MASKING)
1917 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1920 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1923 MarkTileDirty(x2, y2);
1927 static void DrawGraphicShifted(int x, int y, int dx, int dy,
1928 int graphic, int frame,
1929 int cut_mode, int mask_mode)
1933 DrawGraphic(x, y, graphic, frame);
1938 if (graphic_info[graphic].double_movement) /* EM style movement images */
1939 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1941 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1944 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1945 int frame, int cut_mode)
1947 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
1950 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1951 int cut_mode, int mask_mode)
1953 int lx = LEVELX(x), ly = LEVELY(y);
1957 if (IN_LEV_FIELD(lx, ly))
1959 SetRandomAnimationValue(lx, ly);
1961 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
1962 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1964 /* do not use double (EM style) movement graphic when not moving */
1965 if (graphic_info[graphic].double_movement && !dx && !dy)
1967 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
1968 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1971 else /* border element */
1973 graphic = el2img(element);
1974 frame = getGraphicAnimationFrame(graphic, -1);
1977 if (element == EL_EXPANDABLE_WALL)
1979 boolean left_stopped = FALSE, right_stopped = FALSE;
1981 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1982 left_stopped = TRUE;
1983 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1984 right_stopped = TRUE;
1986 if (left_stopped && right_stopped)
1988 else if (left_stopped)
1990 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1991 frame = graphic_info[graphic].anim_frames - 1;
1993 else if (right_stopped)
1995 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1996 frame = graphic_info[graphic].anim_frames - 1;
2001 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
2002 else if (mask_mode == USE_MASKING)
2003 DrawGraphicThruMask(x, y, graphic, frame);
2005 DrawGraphic(x, y, graphic, frame);
2008 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
2009 int cut_mode, int mask_mode)
2011 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2012 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
2013 cut_mode, mask_mode);
2016 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
2019 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
2022 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
2025 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
2028 void DrawLevelElementThruMask(int x, int y, int element)
2030 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
2033 void DrawLevelFieldThruMask(int x, int y)
2035 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
2038 /* !!! implementation of quicksand is totally broken !!! */
2039 #define IS_CRUMBLED_TILE(x, y, e) \
2040 (GFX_CRUMBLED(e) && (!IN_LEV_FIELD(x, y) || \
2041 !IS_MOVING(x, y) || \
2042 (e) == EL_QUICKSAND_EMPTYING || \
2043 (e) == EL_QUICKSAND_FAST_EMPTYING))
2045 static void DrawLevelFieldCrumbledInnerCorners(int x, int y, int dx, int dy,
2050 int width, height, cx, cy;
2051 int sx = SCREENX(x), sy = SCREENY(y);
2052 int crumbled_border_size = graphic_info[graphic].border_size;
2053 int crumbled_tile_size = graphic_info[graphic].tile_size;
2054 int crumbled_border_size_var =
2055 crumbled_border_size * TILESIZE_VAR / crumbled_tile_size;
2058 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
2060 for (i = 1; i < 4; i++)
2062 int dxx = (i & 1 ? dx : 0);
2063 int dyy = (i & 2 ? dy : 0);
2066 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
2069 /* check if neighbour field is of same crumble type */
2070 boolean same = (IS_CRUMBLED_TILE(xx, yy, element) &&
2071 graphic_info[graphic].class ==
2072 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class);
2074 /* return if check prevents inner corner */
2075 if (same == (dxx == dx && dyy == dy))
2079 /* if we reach this point, we have an inner corner */
2081 getGraphicSource(graphic, 1, &src_bitmap, &src_x, &src_y);
2083 width = crumbled_border_size_var;
2084 height = crumbled_border_size_var;
2085 cx = (dx > 0 ? TILESIZE_VAR - width : 0);
2086 cy = (dy > 0 ? TILESIZE_VAR - height : 0);
2088 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
2089 width, height, FX + sx * TILEX_VAR + cx, FY + sy * TILEY_VAR + cy);
2092 static void DrawLevelFieldCrumbledBorders(int x, int y, int graphic, int frame,
2097 int width, height, bx, by, cx, cy;
2098 int sx = SCREENX(x), sy = SCREENY(y);
2099 int crumbled_border_size = graphic_info[graphic].border_size;
2100 int crumbled_tile_size = graphic_info[graphic].tile_size;
2101 int crumbled_border_size_var =
2102 crumbled_border_size * TILESIZE_VAR / crumbled_tile_size;
2103 int crumbled_border_pos_var = TILESIZE_VAR - crumbled_border_size_var;
2106 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
2108 /* draw simple, sloppy, non-corner-accurate crumbled border */
2110 width = (dir == 1 || dir == 2 ? crumbled_border_size_var : TILESIZE_VAR);
2111 height = (dir == 0 || dir == 3 ? crumbled_border_size_var : TILESIZE_VAR);
2112 cx = (dir == 2 ? crumbled_border_pos_var : 0);
2113 cy = (dir == 3 ? crumbled_border_pos_var : 0);
2115 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy, width, height,
2116 FX + sx * TILEX_VAR + cx,
2117 FY + sy * TILEY_VAR + cy);
2119 /* (remaining middle border part must be at least as big as corner part) */
2120 if (!(graphic_info[graphic].style & STYLE_ACCURATE_BORDERS) ||
2121 crumbled_border_size_var >= TILESIZE_VAR / 3)
2124 /* correct corners of crumbled border, if needed */
2126 for (i = -1; i <= 1; i += 2)
2128 int xx = x + (dir == 0 || dir == 3 ? i : 0);
2129 int yy = y + (dir == 1 || dir == 2 ? i : 0);
2130 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
2133 /* check if neighbour field is of same crumble type */
2134 if (IS_CRUMBLED_TILE(xx, yy, element) &&
2135 graphic_info[graphic].class ==
2136 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
2138 /* no crumbled corner, but continued crumbled border */
2140 int c1 = (dir == 2 || dir == 3 ? crumbled_border_pos_var : 0);
2141 int c2 = (i == 1 ? crumbled_border_pos_var : 0);
2142 int b1 = (i == 1 ? crumbled_border_size_var :
2143 TILESIZE_VAR - 2 * crumbled_border_size_var);
2145 width = crumbled_border_size_var;
2146 height = crumbled_border_size_var;
2148 if (dir == 1 || dir == 2)
2163 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
2165 FX + sx * TILEX_VAR + cx,
2166 FY + sy * TILEY_VAR + cy);
2171 static void DrawLevelFieldCrumbledExt(int x, int y, int graphic, int frame)
2173 int sx = SCREENX(x), sy = SCREENY(y);
2176 static int xy[4][2] =
2184 if (!IN_LEV_FIELD(x, y))
2187 element = TILE_GFX_ELEMENT(x, y);
2189 if (IS_CRUMBLED_TILE(x, y, element)) /* crumble field itself */
2191 if (!IN_SCR_FIELD(sx, sy))
2194 /* crumble field borders towards direct neighbour fields */
2195 for (i = 0; i < 4; i++)
2197 int xx = x + xy[i][0];
2198 int yy = y + xy[i][1];
2200 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
2203 /* check if neighbour field is of same crumble type */
2204 if (IS_CRUMBLED_TILE(xx, yy, element) &&
2205 graphic_info[graphic].class ==
2206 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
2209 DrawLevelFieldCrumbledBorders(x, y, graphic, frame, i);
2212 /* crumble inner field corners towards corner neighbour fields */
2213 if ((graphic_info[graphic].style & STYLE_INNER_CORNERS) &&
2214 graphic_info[graphic].anim_frames == 2)
2216 for (i = 0; i < 4; i++)
2218 int dx = (i & 1 ? +1 : -1);
2219 int dy = (i & 2 ? +1 : -1);
2221 DrawLevelFieldCrumbledInnerCorners(x, y, dx, dy, graphic);
2225 MarkTileDirty(sx, sy);
2227 else /* center field is not crumbled -- crumble neighbour fields */
2229 /* crumble field borders of direct neighbour fields */
2230 for (i = 0; i < 4; i++)
2232 int xx = x + xy[i][0];
2233 int yy = y + xy[i][1];
2234 int sxx = sx + xy[i][0];
2235 int syy = sy + xy[i][1];
2237 if (!IN_LEV_FIELD(xx, yy) ||
2238 !IN_SCR_FIELD(sxx, syy))
2241 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
2244 element = TILE_GFX_ELEMENT(xx, yy);
2246 if (!IS_CRUMBLED_TILE(xx, yy, element))
2249 graphic = el_act2crm(element, ACTION_DEFAULT);
2251 DrawLevelFieldCrumbledBorders(xx, yy, graphic, 0, 3 - i);
2253 MarkTileDirty(sxx, syy);
2256 /* crumble inner field corners of corner neighbour fields */
2257 for (i = 0; i < 4; i++)
2259 int dx = (i & 1 ? +1 : -1);
2260 int dy = (i & 2 ? +1 : -1);
2266 if (!IN_LEV_FIELD(xx, yy) ||
2267 !IN_SCR_FIELD(sxx, syy))
2270 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
2273 element = TILE_GFX_ELEMENT(xx, yy);
2275 if (!IS_CRUMBLED_TILE(xx, yy, element))
2278 graphic = el_act2crm(element, ACTION_DEFAULT);
2280 if ((graphic_info[graphic].style & STYLE_INNER_CORNERS) &&
2281 graphic_info[graphic].anim_frames == 2)
2282 DrawLevelFieldCrumbledInnerCorners(xx, yy, -dx, -dy, graphic);
2284 MarkTileDirty(sxx, syy);
2289 void DrawLevelFieldCrumbled(int x, int y)
2293 if (!IN_LEV_FIELD(x, y))
2296 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
2297 GfxElement[x][y] != EL_UNDEFINED &&
2298 GFX_CRUMBLED(GfxElement[x][y]))
2300 DrawLevelFieldCrumbledDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
2305 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
2307 DrawLevelFieldCrumbledExt(x, y, graphic, 0);
2310 void DrawLevelFieldCrumbledDigging(int x, int y, int direction,
2313 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
2314 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
2315 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
2316 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
2317 int sx = SCREENX(x), sy = SCREENY(y);
2319 DrawGraphic(sx, sy, graphic1, frame1);
2320 DrawLevelFieldCrumbledExt(x, y, graphic2, frame2);
2323 void DrawLevelFieldCrumbledNeighbours(int x, int y)
2325 int sx = SCREENX(x), sy = SCREENY(y);
2326 static int xy[4][2] =
2335 /* crumble direct neighbour fields (required for field borders) */
2336 for (i = 0; i < 4; i++)
2338 int xx = x + xy[i][0];
2339 int yy = y + xy[i][1];
2340 int sxx = sx + xy[i][0];
2341 int syy = sy + xy[i][1];
2343 if (!IN_LEV_FIELD(xx, yy) ||
2344 !IN_SCR_FIELD(sxx, syy) ||
2345 !GFX_CRUMBLED(Feld[xx][yy]) ||
2349 DrawLevelField(xx, yy);
2352 /* crumble corner neighbour fields (required for inner field corners) */
2353 for (i = 0; i < 4; i++)
2355 int dx = (i & 1 ? +1 : -1);
2356 int dy = (i & 2 ? +1 : -1);
2362 if (!IN_LEV_FIELD(xx, yy) ||
2363 !IN_SCR_FIELD(sxx, syy) ||
2364 !GFX_CRUMBLED(Feld[xx][yy]) ||
2368 int element = TILE_GFX_ELEMENT(xx, yy);
2369 int graphic = el_act2crm(element, ACTION_DEFAULT);
2371 if ((graphic_info[graphic].style & STYLE_INNER_CORNERS) &&
2372 graphic_info[graphic].anim_frames == 2)
2373 DrawLevelField(xx, yy);
2377 static int getBorderElement(int x, int y)
2381 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
2382 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
2383 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
2384 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
2385 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
2386 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
2387 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
2389 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
2390 int steel_position = (x == -1 && y == -1 ? 0 :
2391 x == lev_fieldx && y == -1 ? 1 :
2392 x == -1 && y == lev_fieldy ? 2 :
2393 x == lev_fieldx && y == lev_fieldy ? 3 :
2394 x == -1 || x == lev_fieldx ? 4 :
2395 y == -1 || y == lev_fieldy ? 5 : 6);
2397 return border[steel_position][steel_type];
2400 void DrawScreenElement(int x, int y, int element)
2402 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
2403 DrawLevelFieldCrumbled(LEVELX(x), LEVELY(y));
2406 void DrawLevelElement(int x, int y, int element)
2408 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2409 DrawScreenElement(SCREENX(x), SCREENY(y), element);
2412 void DrawScreenField(int x, int y)
2414 int lx = LEVELX(x), ly = LEVELY(y);
2415 int element, content;
2417 if (!IN_LEV_FIELD(lx, ly))
2419 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
2422 element = getBorderElement(lx, ly);
2424 DrawScreenElement(x, y, element);
2429 element = Feld[lx][ly];
2430 content = Store[lx][ly];
2432 if (IS_MOVING(lx, ly))
2434 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
2435 boolean cut_mode = NO_CUTTING;
2437 if (element == EL_QUICKSAND_EMPTYING ||
2438 element == EL_QUICKSAND_FAST_EMPTYING ||
2439 element == EL_MAGIC_WALL_EMPTYING ||
2440 element == EL_BD_MAGIC_WALL_EMPTYING ||
2441 element == EL_DC_MAGIC_WALL_EMPTYING ||
2442 element == EL_AMOEBA_DROPPING)
2443 cut_mode = CUT_ABOVE;
2444 else if (element == EL_QUICKSAND_FILLING ||
2445 element == EL_QUICKSAND_FAST_FILLING ||
2446 element == EL_MAGIC_WALL_FILLING ||
2447 element == EL_BD_MAGIC_WALL_FILLING ||
2448 element == EL_DC_MAGIC_WALL_FILLING)
2449 cut_mode = CUT_BELOW;
2451 if (cut_mode == CUT_ABOVE)
2452 DrawScreenElement(x, y, element);
2454 DrawScreenElement(x, y, EL_EMPTY);
2457 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
2458 else if (cut_mode == NO_CUTTING)
2459 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
2462 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
2464 if (cut_mode == CUT_BELOW &&
2465 IN_LEV_FIELD(lx, ly + 1) && IN_SCR_FIELD(x, y + 1))
2466 DrawLevelElement(lx, ly + 1, element);
2469 if (content == EL_ACID)
2471 int dir = MovDir[lx][ly];
2472 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
2473 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
2475 DrawLevelElementThruMask(newlx, newly, EL_ACID);
2477 // prevent target field from being drawn again (but without masking)
2478 // (this would happen if target field is scanned after moving element)
2479 Stop[newlx][newly] = TRUE;
2482 else if (IS_BLOCKED(lx, ly))
2487 boolean cut_mode = NO_CUTTING;
2488 int element_old, content_old;
2490 Blocked2Moving(lx, ly, &oldx, &oldy);
2493 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
2494 MovDir[oldx][oldy] == MV_RIGHT);
2496 element_old = Feld[oldx][oldy];
2497 content_old = Store[oldx][oldy];
2499 if (element_old == EL_QUICKSAND_EMPTYING ||
2500 element_old == EL_QUICKSAND_FAST_EMPTYING ||
2501 element_old == EL_MAGIC_WALL_EMPTYING ||
2502 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
2503 element_old == EL_DC_MAGIC_WALL_EMPTYING ||
2504 element_old == EL_AMOEBA_DROPPING)
2505 cut_mode = CUT_ABOVE;
2507 DrawScreenElement(x, y, EL_EMPTY);
2510 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
2512 else if (cut_mode == NO_CUTTING)
2513 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
2516 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
2519 else if (IS_DRAWABLE(element))
2520 DrawScreenElement(x, y, element);
2522 DrawScreenElement(x, y, EL_EMPTY);
2525 void DrawLevelField(int x, int y)
2527 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2528 DrawScreenField(SCREENX(x), SCREENY(y));
2529 else if (IS_MOVING(x, y))
2533 Moving2Blocked(x, y, &newx, &newy);
2534 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
2535 DrawScreenField(SCREENX(newx), SCREENY(newy));
2537 else if (IS_BLOCKED(x, y))
2541 Blocked2Moving(x, y, &oldx, &oldy);
2542 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
2543 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
2547 static void DrawSizedWallExt_MM(int dst_x, int dst_y, int element, int tilesize,
2548 int (*el2img_function)(int), boolean masked,
2549 int element_bits_draw)
2551 int element_base = map_mm_wall_element(element);
2552 int element_bits = (IS_DF_WALL(element) ?
2553 element - EL_DF_WALL_START :
2554 IS_MM_WALL(element) ?
2555 element - EL_MM_WALL_START : EL_EMPTY) & 0x000f;
2556 int graphic = el2img_function(element_base);
2557 int tilesize_draw = tilesize / 2;
2562 getSizedGraphicSource(graphic, 0, tilesize_draw, &src_bitmap, &src_x, &src_y);
2564 for (i = 0; i < 4; i++)
2566 int dst_draw_x = dst_x + (i % 2) * tilesize_draw;
2567 int dst_draw_y = dst_y + (i / 2) * tilesize_draw;
2569 if (!(element_bits_draw & (1 << i)))
2572 if (element_bits & (1 << i))
2575 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y,
2576 tilesize_draw, tilesize_draw, dst_draw_x, dst_draw_y);
2578 BlitBitmap(src_bitmap, drawto, src_x, src_y,
2579 tilesize_draw, tilesize_draw, dst_draw_x, dst_draw_y);
2584 ClearRectangle(drawto, dst_draw_x, dst_draw_y,
2585 tilesize_draw, tilesize_draw);
2590 void DrawSizedWallParts_MM(int x, int y, int element, int tilesize,
2591 boolean masked, int element_bits_draw)
2593 DrawSizedWallExt_MM(SX + x * tilesize, SY + y * tilesize,
2594 element, tilesize, el2edimg, masked, element_bits_draw);
2597 void DrawSizedWall_MM(int dst_x, int dst_y, int element, int tilesize,
2598 int (*el2img_function)(int))
2600 DrawSizedWallExt_MM(dst_x, dst_y, element, tilesize, el2img_function, FALSE,
2604 void DrawSizedElementExt(int x, int y, int element, int tilesize,
2607 if (IS_MM_WALL(element))
2609 DrawSizedWallExt_MM(SX + x * tilesize, SY + y * tilesize,
2610 element, tilesize, el2edimg, masked, 0x000f);
2614 int graphic = el2edimg(element);
2617 DrawSizedGraphicThruMask(x, y, graphic, 0, tilesize);
2619 DrawSizedGraphic(x, y, graphic, 0, tilesize);
2623 void DrawSizedElement(int x, int y, int element, int tilesize)
2625 DrawSizedElementExt(x, y, element, tilesize, FALSE);
2628 void DrawSizedElementThruMask(int x, int y, int element, int tilesize)
2630 DrawSizedElementExt(x, y, element, tilesize, TRUE);
2633 void DrawMiniElement(int x, int y, int element)
2637 graphic = el2edimg(element);
2638 DrawMiniGraphic(x, y, graphic);
2641 void DrawSizedElementOrWall(int sx, int sy, int scroll_x, int scroll_y,
2644 int x = sx + scroll_x, y = sy + scroll_y;
2646 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
2647 DrawSizedElement(sx, sy, EL_EMPTY, tilesize);
2648 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
2649 DrawSizedElement(sx, sy, Feld[x][y], tilesize);
2651 DrawSizedGraphic(sx, sy, el2edimg(getBorderElement(x, y)), 0, tilesize);
2654 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
2656 int x = sx + scroll_x, y = sy + scroll_y;
2658 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
2659 DrawMiniElement(sx, sy, EL_EMPTY);
2660 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
2661 DrawMiniElement(sx, sy, Feld[x][y]);
2663 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
2666 void DrawEnvelopeBackgroundTiles(int graphic, int startx, int starty,
2667 int x, int y, int xsize, int ysize,
2668 int tile_width, int tile_height)
2672 int dst_x = startx + x * tile_width;
2673 int dst_y = starty + y * tile_height;
2674 int width = graphic_info[graphic].width;
2675 int height = graphic_info[graphic].height;
2676 int inner_width_raw = MAX(width - 2 * tile_width, tile_width);
2677 int inner_height_raw = MAX(height - 2 * tile_height, tile_height);
2678 int inner_width = inner_width_raw - (inner_width_raw % tile_width);
2679 int inner_height = inner_height_raw - (inner_height_raw % tile_height);
2680 int inner_sx = (width >= 3 * tile_width ? tile_width : 0);
2681 int inner_sy = (height >= 3 * tile_height ? tile_height : 0);
2682 boolean draw_masked = graphic_info[graphic].draw_masked;
2684 getFixedGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
2686 if (src_bitmap == NULL || width < tile_width || height < tile_height)
2688 ClearRectangle(drawto, dst_x, dst_y, tile_width, tile_height);
2692 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - tile_width :
2693 inner_sx + (x - 1) * tile_width % inner_width);
2694 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - tile_height :
2695 inner_sy + (y - 1) * tile_height % inner_height);
2698 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
2701 BlitBitmap(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
2705 void DrawEnvelopeBackground(int graphic, int startx, int starty,
2706 int x, int y, int xsize, int ysize, int font_nr)
2708 int font_width = getFontWidth(font_nr);
2709 int font_height = getFontHeight(font_nr);
2711 DrawEnvelopeBackgroundTiles(graphic, startx, starty, x, y, xsize, ysize,
2712 font_width, font_height);
2715 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
2717 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2718 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2719 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2720 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2721 boolean no_delay = (tape.warp_forward);
2722 unsigned int anim_delay = 0;
2723 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
2724 int anim_delay_value = MAX(1, (no_delay ? 0 : frame_delay_value) / 2);
2725 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
2726 int font_width = getFontWidth(font_nr);
2727 int font_height = getFontHeight(font_nr);
2728 int max_xsize = level.envelope[envelope_nr].xsize;
2729 int max_ysize = level.envelope[envelope_nr].ysize;
2730 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
2731 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
2732 int xend = max_xsize;
2733 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
2734 int xstep = (xstart < xend ? 1 : 0);
2735 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2737 int end = MAX(xend - xstart, yend - ystart);
2740 for (i = start; i <= end; i++)
2742 int last_frame = end; // last frame of this "for" loop
2743 int x = xstart + i * xstep;
2744 int y = ystart + i * ystep;
2745 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2746 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2747 int sx = SX + (SXSIZE - xsize * font_width) / 2;
2748 int sy = SY + (SYSIZE - ysize * font_height) / 2;
2751 SetDrawtoField(DRAW_TO_FIELDBUFFER);
2753 BlitScreenToBitmap(backbuffer);
2755 SetDrawtoField(DRAW_TO_BACKBUFFER);
2757 for (yy = 0; yy < ysize; yy++)
2758 for (xx = 0; xx < xsize; xx++)
2759 DrawEnvelopeBackground(graphic, sx, sy, xx, yy, xsize, ysize, font_nr);
2761 DrawTextBuffer(sx + font_width, sy + font_height,
2762 level.envelope[envelope_nr].text, font_nr, max_xsize,
2763 xsize - 2, ysize - 2, 0, mask_mode,
2764 level.envelope[envelope_nr].autowrap,
2765 level.envelope[envelope_nr].centered, FALSE);
2767 redraw_mask |= REDRAW_FIELD;
2770 SkipUntilDelayReached(&anim_delay, anim_delay_value, &i, last_frame);
2774 void ShowEnvelope(int envelope_nr)
2776 int element = EL_ENVELOPE_1 + envelope_nr;
2777 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2778 int sound_opening = element_info[element].sound[ACTION_OPENING];
2779 int sound_closing = element_info[element].sound[ACTION_CLOSING];
2780 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2781 boolean no_delay = (tape.warp_forward);
2782 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
2783 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
2784 int anim_mode = graphic_info[graphic].anim_mode;
2785 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2786 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2788 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
2790 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2792 if (anim_mode == ANIM_DEFAULT)
2793 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
2795 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
2798 Delay(wait_delay_value);
2800 WaitForEventToContinue();
2802 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2804 if (anim_mode != ANIM_NONE)
2805 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
2807 if (anim_mode == ANIM_DEFAULT)
2808 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
2810 game.envelope_active = FALSE;
2812 SetDrawtoField(DRAW_TO_FIELDBUFFER);
2814 redraw_mask |= REDRAW_FIELD;
2818 static void setRequestBasePosition(int *x, int *y)
2820 int sx_base, sy_base;
2822 if (request.x != -1)
2823 sx_base = request.x;
2824 else if (request.align == ALIGN_LEFT)
2826 else if (request.align == ALIGN_RIGHT)
2827 sx_base = SX + SXSIZE;
2829 sx_base = SX + SXSIZE / 2;
2831 if (request.y != -1)
2832 sy_base = request.y;
2833 else if (request.valign == VALIGN_TOP)
2835 else if (request.valign == VALIGN_BOTTOM)
2836 sy_base = SY + SYSIZE;
2838 sy_base = SY + SYSIZE / 2;
2844 static void setRequestPositionExt(int *x, int *y, int width, int height,
2845 boolean add_border_size)
2847 int border_size = request.border_size;
2848 int sx_base, sy_base;
2851 setRequestBasePosition(&sx_base, &sy_base);
2853 if (request.align == ALIGN_LEFT)
2855 else if (request.align == ALIGN_RIGHT)
2856 sx = sx_base - width;
2858 sx = sx_base - width / 2;
2860 if (request.valign == VALIGN_TOP)
2862 else if (request.valign == VALIGN_BOTTOM)
2863 sy = sy_base - height;
2865 sy = sy_base - height / 2;
2867 sx = MAX(0, MIN(sx, WIN_XSIZE - width));
2868 sy = MAX(0, MIN(sy, WIN_YSIZE - height));
2870 if (add_border_size)
2880 static void setRequestPosition(int *x, int *y, boolean add_border_size)
2882 setRequestPositionExt(x, y, request.width, request.height, add_border_size);
2885 void DrawEnvelopeRequest(char *text)
2887 char *text_final = text;
2888 char *text_door_style = NULL;
2889 int graphic = IMG_BACKGROUND_REQUEST;
2890 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2891 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2892 int font_nr = FONT_REQUEST;
2893 int font_width = getFontWidth(font_nr);
2894 int font_height = getFontHeight(font_nr);
2895 int border_size = request.border_size;
2896 int line_spacing = request.line_spacing;
2897 int line_height = font_height + line_spacing;
2898 int max_text_width = request.width - 2 * border_size;
2899 int max_text_height = request.height - 2 * border_size;
2900 int line_length = max_text_width / font_width;
2901 int max_lines = max_text_height / line_height;
2902 int text_width = line_length * font_width;
2903 int width = request.width;
2904 int height = request.height;
2905 int tile_size = MAX(request.step_offset, 1);
2906 int x_steps = width / tile_size;
2907 int y_steps = height / tile_size;
2908 int sx_offset = border_size;
2909 int sy_offset = border_size;
2913 if (request.centered)
2914 sx_offset = (request.width - text_width) / 2;
2916 if (request.wrap_single_words && !request.autowrap)
2918 char *src_text_ptr, *dst_text_ptr;
2920 text_door_style = checked_malloc(2 * strlen(text) + 1);
2922 src_text_ptr = text;
2923 dst_text_ptr = text_door_style;
2925 while (*src_text_ptr)
2927 if (*src_text_ptr == ' ' ||
2928 *src_text_ptr == '?' ||
2929 *src_text_ptr == '!')
2930 *dst_text_ptr++ = '\n';
2932 if (*src_text_ptr != ' ')
2933 *dst_text_ptr++ = *src_text_ptr;
2938 *dst_text_ptr = '\0';
2940 text_final = text_door_style;
2943 setRequestPosition(&sx, &sy, FALSE);
2945 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
2947 for (y = 0; y < y_steps; y++)
2948 for (x = 0; x < x_steps; x++)
2949 DrawEnvelopeBackgroundTiles(graphic, sx, sy,
2950 x, y, x_steps, y_steps,
2951 tile_size, tile_size);
2953 /* force DOOR font inside door area */
2954 SetFontStatus(GAME_MODE_PSEUDO_DOOR);
2956 DrawTextBuffer(sx + sx_offset, sy + sy_offset, text_final, font_nr,
2957 line_length, -1, max_lines, line_spacing, mask_mode,
2958 request.autowrap, request.centered, FALSE);
2962 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2963 RedrawGadget(tool_gadget[i]);
2965 // store readily prepared envelope request for later use when animating
2966 BlitBitmap(backbuffer, bitmap_db_store_2, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2968 if (text_door_style)
2969 free(text_door_style);
2972 void AnimateEnvelopeRequest(int anim_mode, int action)
2974 int graphic = IMG_BACKGROUND_REQUEST;
2975 boolean draw_masked = graphic_info[graphic].draw_masked;
2976 int delay_value_normal = request.step_delay;
2977 int delay_value_fast = delay_value_normal / 2;
2978 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2979 boolean no_delay = (tape.warp_forward);
2980 int delay_value = (ffwd_delay ? delay_value_fast : delay_value_normal);
2981 int anim_delay_value = MAX(1, (no_delay ? 0 : delay_value + 500 * 0) / 2);
2982 unsigned int anim_delay = 0;
2984 int tile_size = MAX(request.step_offset, 1);
2985 int max_xsize = request.width / tile_size;
2986 int max_ysize = request.height / tile_size;
2987 int max_xsize_inner = max_xsize - 2;
2988 int max_ysize_inner = max_ysize - 2;
2990 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize_inner : 0);
2991 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize_inner : 0);
2992 int xend = max_xsize_inner;
2993 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize_inner : 0);
2994 int xstep = (xstart < xend ? 1 : 0);
2995 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2997 int end = MAX(xend - xstart, yend - ystart);
3000 if (setup.quick_doors)
3007 for (i = start; i <= end; i++)
3009 int last_frame = end; // last frame of this "for" loop
3010 int x = xstart + i * xstep;
3011 int y = ystart + i * ystep;
3012 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
3013 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
3014 int xsize_size_left = (xsize - 1) * tile_size;
3015 int ysize_size_top = (ysize - 1) * tile_size;
3016 int max_xsize_pos = (max_xsize - 1) * tile_size;
3017 int max_ysize_pos = (max_ysize - 1) * tile_size;
3018 int width = xsize * tile_size;
3019 int height = ysize * tile_size;
3024 setRequestPosition(&src_x, &src_y, FALSE);
3025 setRequestPositionExt(&dst_x, &dst_y, width, height, FALSE);
3027 BlitBitmap(bitmap_db_store_1, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
3029 for (yy = 0; yy < 2; yy++)
3031 for (xx = 0; xx < 2; xx++)
3033 int src_xx = src_x + xx * max_xsize_pos;
3034 int src_yy = src_y + yy * max_ysize_pos;
3035 int dst_xx = dst_x + xx * xsize_size_left;
3036 int dst_yy = dst_y + yy * ysize_size_top;
3037 int xx_size = (xx ? tile_size : xsize_size_left);
3038 int yy_size = (yy ? tile_size : ysize_size_top);
3041 BlitBitmapMasked(bitmap_db_store_2, backbuffer,
3042 src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
3044 BlitBitmap(bitmap_db_store_2, backbuffer,
3045 src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
3049 redraw_mask |= REDRAW_FIELD;
3053 SkipUntilDelayReached(&anim_delay, anim_delay_value, &i, last_frame);
3057 void ShowEnvelopeRequest(char *text, unsigned int req_state, int action)
3059 int graphic = IMG_BACKGROUND_REQUEST;
3060 int sound_opening = SND_REQUEST_OPENING;
3061 int sound_closing = SND_REQUEST_CLOSING;
3062 int anim_mode_1 = request.anim_mode; /* (higher priority) */
3063 int anim_mode_2 = graphic_info[graphic].anim_mode; /* (lower priority) */
3064 int anim_mode = (anim_mode_1 != ANIM_DEFAULT ? anim_mode_1 : anim_mode_2);
3065 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
3066 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
3068 if (game_status == GAME_MODE_PLAYING)
3069 BlitScreenToBitmap(backbuffer);
3071 SetDrawtoField(DRAW_TO_BACKBUFFER);
3073 // SetDrawBackgroundMask(REDRAW_NONE);
3075 if (action == ACTION_OPENING)
3077 BlitBitmap(backbuffer, bitmap_db_store_1, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
3079 if (req_state & REQ_ASK)
3081 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
3082 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
3084 else if (req_state & REQ_CONFIRM)
3086 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
3088 else if (req_state & REQ_PLAYER)
3090 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
3091 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
3092 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
3093 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
3096 DrawEnvelopeRequest(text);
3099 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
3101 if (action == ACTION_OPENING)
3103 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
3105 if (anim_mode == ANIM_DEFAULT)
3106 AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_OPENING);
3108 AnimateEnvelopeRequest(main_anim_mode, ACTION_OPENING);
3112 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
3114 if (anim_mode != ANIM_NONE)
3115 AnimateEnvelopeRequest(main_anim_mode, ACTION_CLOSING);
3117 if (anim_mode == ANIM_DEFAULT)
3118 AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_CLOSING);
3121 game.envelope_active = FALSE;
3123 if (action == ACTION_CLOSING)
3124 BlitBitmap(bitmap_db_store_1, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
3126 // SetDrawBackgroundMask(last_draw_background_mask);
3128 redraw_mask |= REDRAW_FIELD;
3132 if (action == ACTION_CLOSING &&
3133 game_status == GAME_MODE_PLAYING &&
3134 level.game_engine_type == GAME_ENGINE_TYPE_RND)
3135 SetDrawtoField(DRAW_TO_FIELDBUFFER);
3138 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
3140 if (IS_MM_WALL(element))
3142 DrawSizedWall_MM(dst_x, dst_y, element, tilesize, el2preimg);
3148 int graphic = el2preimg(element);
3150 getSizedGraphicSource(graphic, 0, tilesize, &src_bitmap, &src_x, &src_y);
3151 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize,
3156 void DrawLevel(int draw_background_mask)
3160 SetMainBackgroundImage(IMG_BACKGROUND_PLAYING);
3161 SetDrawBackgroundMask(draw_background_mask);
3165 for (x = BX1; x <= BX2; x++)
3166 for (y = BY1; y <= BY2; y++)
3167 DrawScreenField(x, y);
3169 redraw_mask |= REDRAW_FIELD;
3172 void DrawSizedLevel(int size_x, int size_y, int scroll_x, int scroll_y,
3177 for (x = 0; x < size_x; x++)
3178 for (y = 0; y < size_y; y++)
3179 DrawSizedElementOrWall(x, y, scroll_x, scroll_y, tilesize);
3181 redraw_mask |= REDRAW_FIELD;
3184 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
3188 for (x = 0; x < size_x; x++)
3189 for (y = 0; y < size_y; y++)
3190 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
3192 redraw_mask |= REDRAW_FIELD;
3195 static void DrawPreviewLevelPlayfield(int from_x, int from_y)
3197 boolean show_level_border = (BorderElement != EL_EMPTY);
3198 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
3199 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
3200 int tile_size = preview.tile_size;
3201 int preview_width = preview.xsize * tile_size;
3202 int preview_height = preview.ysize * tile_size;
3203 int real_preview_xsize = MIN(level_xsize, preview.xsize);
3204 int real_preview_ysize = MIN(level_ysize, preview.ysize);
3205 int real_preview_width = real_preview_xsize * tile_size;
3206 int real_preview_height = real_preview_ysize * tile_size;
3207 int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
3208 int dst_y = SY + ALIGNED_YPOS(preview.y, preview_height, preview.valign);
3211 if (!IN_GFX_FIELD_FULL(dst_x, dst_y + preview_height - 1))
3214 DrawBackground(dst_x, dst_y, preview_width, preview_height);
3216 dst_x += (preview_width - real_preview_width) / 2;
3217 dst_y += (preview_height - real_preview_height) / 2;
3219 for (x = 0; x < real_preview_xsize; x++)
3221 for (y = 0; y < real_preview_ysize; y++)
3223 int lx = from_x + x + (show_level_border ? -1 : 0);
3224 int ly = from_y + y + (show_level_border ? -1 : 0);
3225 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
3226 getBorderElement(lx, ly));
3228 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
3229 element, tile_size);
3233 redraw_mask |= REDRAW_FIELD;
3236 #define MICROLABEL_EMPTY 0
3237 #define MICROLABEL_LEVEL_NAME 1
3238 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
3239 #define MICROLABEL_LEVEL_AUTHOR 3
3240 #define MICROLABEL_IMPORTED_FROM_HEAD 4
3241 #define MICROLABEL_IMPORTED_FROM 5
3242 #define MICROLABEL_IMPORTED_BY_HEAD 6
3243 #define MICROLABEL_IMPORTED_BY 7
3245 static int getMaxTextLength(struct TextPosInfo *pos, int font_nr)
3247 int max_text_width = SXSIZE;
3248 int font_width = getFontWidth(font_nr);
3250 if (pos->align == ALIGN_CENTER)
3251 max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
3252 else if (pos->align == ALIGN_RIGHT)
3253 max_text_width = pos->x;
3255 max_text_width = SXSIZE - pos->x;
3257 return max_text_width / font_width;
3260 static void DrawPreviewLevelLabelExt(int mode, struct TextPosInfo *pos)
3262 char label_text[MAX_OUTPUT_LINESIZE + 1];
3263 int max_len_label_text;
3264 int font_nr = pos->font;
3267 if (!IN_GFX_FIELD_FULL(pos->x, pos->y + getFontHeight(pos->font)))
3270 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
3271 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
3272 mode == MICROLABEL_IMPORTED_BY_HEAD)
3273 font_nr = pos->font_alt;
3275 max_len_label_text = getMaxTextLength(pos, font_nr);
3277 if (pos->size != -1)
3278 max_len_label_text = pos->size;
3280 for (i = 0; i < max_len_label_text; i++)
3281 label_text[i] = ' ';
3282 label_text[max_len_label_text] = '\0';
3284 if (strlen(label_text) > 0)
3285 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
3288 (mode == MICROLABEL_LEVEL_NAME ? level.name :
3289 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
3290 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
3291 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
3292 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
3293 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
3294 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
3295 max_len_label_text);
3296 label_text[max_len_label_text] = '\0';
3298 if (strlen(label_text) > 0)
3299 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
3301 redraw_mask |= REDRAW_FIELD;
3304 static void DrawPreviewLevelLabel(int mode)
3306 DrawPreviewLevelLabelExt(mode, &menu.main.text.level_info_2);
3309 static void DrawPreviewLevelInfo(int mode)
3311 if (mode == MICROLABEL_LEVEL_NAME)
3312 DrawPreviewLevelLabelExt(mode, &menu.main.text.level_name);
3313 else if (mode == MICROLABEL_LEVEL_AUTHOR)
3314 DrawPreviewLevelLabelExt(mode, &menu.main.text.level_author);
3317 static void DrawPreviewLevelExt(boolean restart)
3319 static unsigned int scroll_delay = 0;
3320 static unsigned int label_delay = 0;
3321 static int from_x, from_y, scroll_direction;
3322 static int label_state, label_counter;
3323 unsigned int scroll_delay_value = preview.step_delay;
3324 boolean show_level_border = (BorderElement != EL_EMPTY);
3325 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
3326 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
3333 if (preview.anim_mode == ANIM_CENTERED)
3335 if (level_xsize > preview.xsize)
3336 from_x = (level_xsize - preview.xsize) / 2;
3337 if (level_ysize > preview.ysize)
3338 from_y = (level_ysize - preview.ysize) / 2;
3341 from_x += preview.xoffset;
3342 from_y += preview.yoffset;
3344 scroll_direction = MV_RIGHT;
3348 DrawPreviewLevelPlayfield(from_x, from_y);
3349 DrawPreviewLevelLabel(label_state);
3351 DrawPreviewLevelInfo(MICROLABEL_LEVEL_NAME);
3352 DrawPreviewLevelInfo(MICROLABEL_LEVEL_AUTHOR);
3354 /* initialize delay counters */
3355 DelayReached(&scroll_delay, 0);
3356 DelayReached(&label_delay, 0);
3358 if (leveldir_current->name)
3360 struct TextPosInfo *pos = &menu.main.text.level_info_1;
3361 char label_text[MAX_OUTPUT_LINESIZE + 1];
3362 int font_nr = pos->font;
3363 int max_len_label_text = getMaxTextLength(pos, font_nr);
3365 if (pos->size != -1)
3366 max_len_label_text = pos->size;
3368 strncpy(label_text, leveldir_current->name, max_len_label_text);
3369 label_text[max_len_label_text] = '\0';
3371 if (IN_GFX_FIELD_FULL(pos->x, pos->y + getFontHeight(pos->font)))
3372 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
3378 /* scroll preview level, if needed */
3379 if (preview.anim_mode != ANIM_NONE &&
3380 (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
3381 DelayReached(&scroll_delay, scroll_delay_value))
3383 switch (scroll_direction)
3388 from_x -= preview.step_offset;
3389 from_x = (from_x < 0 ? 0 : from_x);
3392 scroll_direction = MV_UP;
3396 if (from_x < level_xsize - preview.xsize)
3398 from_x += preview.step_offset;
3399 from_x = (from_x > level_xsize - preview.xsize ?
3400 level_xsize - preview.xsize : from_x);
3403 scroll_direction = MV_DOWN;
3409 from_y -= preview.step_offset;
3410 from_y = (from_y < 0 ? 0 : from_y);
3413 scroll_direction = MV_RIGHT;
3417 if (from_y < level_ysize - preview.ysize)
3419 from_y += preview.step_offset;
3420 from_y = (from_y > level_ysize - preview.ysize ?
3421 level_ysize - preview.ysize : from_y);
3424 scroll_direction = MV_LEFT;
3431 DrawPreviewLevelPlayfield(from_x, from_y);
3434 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
3435 /* redraw micro level label, if needed */
3436 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
3437 !strEqual(level.author, ANONYMOUS_NAME) &&
3438 !strEqual(level.author, leveldir_current->name) &&
3439 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
3441 int max_label_counter = 23;
3443 if (leveldir_current->imported_from != NULL &&
3444 strlen(leveldir_current->imported_from) > 0)
3445 max_label_counter += 14;
3446 if (leveldir_current->imported_by != NULL &&
3447 strlen(leveldir_current->imported_by) > 0)
3448 max_label_counter += 14;
3450 label_counter = (label_counter + 1) % max_label_counter;
3451 label_state = (label_counter >= 0 && label_counter <= 7 ?
3452 MICROLABEL_LEVEL_NAME :
3453 label_counter >= 9 && label_counter <= 12 ?
3454 MICROLABEL_LEVEL_AUTHOR_HEAD :
3455 label_counter >= 14 && label_counter <= 21 ?
3456 MICROLABEL_LEVEL_AUTHOR :
3457 label_counter >= 23 && label_counter <= 26 ?
3458 MICROLABEL_IMPORTED_FROM_HEAD :
3459 label_counter >= 28 && label_counter <= 35 ?
3460 MICROLABEL_IMPORTED_FROM :
3461 label_counter >= 37 && label_counter <= 40 ?
3462 MICROLABEL_IMPORTED_BY_HEAD :
3463 label_counter >= 42 && label_counter <= 49 ?
3464 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
3466 if (leveldir_current->imported_from == NULL &&
3467 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
3468 label_state == MICROLABEL_IMPORTED_FROM))
3469 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
3470 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
3472 DrawPreviewLevelLabel(label_state);
3476 void DrawPreviewLevelInitial()
3478 DrawPreviewLevelExt(TRUE);
3481 void DrawPreviewLevelAnimation()
3483 DrawPreviewLevelExt(FALSE);
3486 inline static void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
3487 int graphic, int sync_frame,
3490 int frame = getGraphicAnimationFrame(graphic, sync_frame);
3492 if (mask_mode == USE_MASKING)
3493 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
3495 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
3498 void DrawFixedGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
3499 int graphic, int sync_frame, int mask_mode)
3501 int frame = getGraphicAnimationFrame(graphic, sync_frame);
3503 if (mask_mode == USE_MASKING)
3504 DrawFixedGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
3506 DrawFixedGraphicExt(dst_bitmap, x, y, graphic, frame);
3509 inline static void DrawGraphicAnimation(int x, int y, int graphic)
3511 int lx = LEVELX(x), ly = LEVELY(y);
3513 if (!IN_SCR_FIELD(x, y))
3516 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
3517 graphic, GfxFrame[lx][ly], NO_MASKING);
3519 MarkTileDirty(x, y);
3522 void DrawFixedGraphicAnimation(int x, int y, int graphic)
3524 int lx = LEVELX(x), ly = LEVELY(y);
3526 if (!IN_SCR_FIELD(x, y))
3529 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
3530 graphic, GfxFrame[lx][ly], NO_MASKING);
3531 MarkTileDirty(x, y);
3534 void DrawLevelGraphicAnimation(int x, int y, int graphic)
3536 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
3539 void DrawLevelElementAnimation(int x, int y, int element)
3541 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
3543 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
3546 void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
3548 int sx = SCREENX(x), sy = SCREENY(y);
3550 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
3553 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
3556 DrawGraphicAnimation(sx, sy, graphic);
3559 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
3560 DrawLevelFieldCrumbled(x, y);
3562 if (GFX_CRUMBLED(Feld[x][y]))
3563 DrawLevelFieldCrumbled(x, y);
3567 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
3569 int sx = SCREENX(x), sy = SCREENY(y);
3572 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
3575 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
3577 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
3580 DrawGraphicAnimation(sx, sy, graphic);
3582 if (GFX_CRUMBLED(element))
3583 DrawLevelFieldCrumbled(x, y);
3586 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
3588 if (player->use_murphy)
3590 /* this works only because currently only one player can be "murphy" ... */
3591 static int last_horizontal_dir = MV_LEFT;
3592 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
3594 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3595 last_horizontal_dir = move_dir;
3597 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
3599 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
3601 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
3607 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
3610 static boolean equalGraphics(int graphic1, int graphic2)
3612 struct GraphicInfo *g1 = &graphic_info[graphic1];
3613 struct GraphicInfo *g2 = &graphic_info[graphic2];
3615 return (g1->bitmap == g2->bitmap &&
3616 g1->src_x == g2->src_x &&
3617 g1->src_y == g2->src_y &&
3618 g1->anim_frames == g2->anim_frames &&
3619 g1->anim_delay == g2->anim_delay &&
3620 g1->anim_mode == g2->anim_mode);
3623 void DrawAllPlayers()
3627 for (i = 0; i < MAX_PLAYERS; i++)
3628 if (stored_player[i].active)
3629 DrawPlayer(&stored_player[i]);
3632 void DrawPlayerField(int x, int y)
3634 if (!IS_PLAYER(x, y))
3637 DrawPlayer(PLAYERINFO(x, y));
3640 #define DRAW_PLAYER_OVER_PUSHED_ELEMENT 1
3642 void DrawPlayer(struct PlayerInfo *player)
3644 int jx = player->jx;
3645 int jy = player->jy;
3646 int move_dir = player->MovDir;
3647 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
3648 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
3649 int last_jx = (player->is_moving ? jx - dx : jx);
3650 int last_jy = (player->is_moving ? jy - dy : jy);
3651 int next_jx = jx + dx;
3652 int next_jy = jy + dy;
3653 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
3654 boolean player_is_opaque = FALSE;
3655 int sx = SCREENX(jx), sy = SCREENY(jy);
3656 int sxx = 0, syy = 0;
3657 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
3659 int action = ACTION_DEFAULT;
3660 int last_player_graphic = getPlayerGraphic(player, move_dir);
3661 int last_player_frame = player->Frame;
3664 /* GfxElement[][] is set to the element the player is digging or collecting;
3665 remove also for off-screen player if the player is not moving anymore */
3666 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
3667 GfxElement[jx][jy] = EL_UNDEFINED;
3669 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
3673 if (!IN_LEV_FIELD(jx, jy))
3675 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
3676 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
3677 printf("DrawPlayerField(): This should never happen!\n");
3682 if (element == EL_EXPLOSION)
3685 action = (player->is_pushing ? ACTION_PUSHING :
3686 player->is_digging ? ACTION_DIGGING :
3687 player->is_collecting ? ACTION_COLLECTING :
3688 player->is_moving ? ACTION_MOVING :
3689 player->is_snapping ? ACTION_SNAPPING :
3690 player->is_dropping ? ACTION_DROPPING :
3691 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
3693 if (player->is_waiting)
3694 move_dir = player->dir_waiting;
3696 InitPlayerGfxAnimation(player, action, move_dir);
3698 /* ----------------------------------------------------------------------- */
3699 /* draw things in the field the player is leaving, if needed */
3700 /* ----------------------------------------------------------------------- */
3702 if (player->is_moving)
3704 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
3706 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
3708 if (last_element == EL_DYNAMITE_ACTIVE ||
3709 last_element == EL_EM_DYNAMITE_ACTIVE ||
3710 last_element == EL_SP_DISK_RED_ACTIVE)
3711 DrawDynamite(last_jx, last_jy);
3713 DrawLevelFieldThruMask(last_jx, last_jy);
3715 else if (last_element == EL_DYNAMITE_ACTIVE ||
3716 last_element == EL_EM_DYNAMITE_ACTIVE ||
3717 last_element == EL_SP_DISK_RED_ACTIVE)
3718 DrawDynamite(last_jx, last_jy);
3720 /* !!! this is not enough to prevent flickering of players which are
3721 moving next to each others without a free tile between them -- this
3722 can only be solved by drawing all players layer by layer (first the
3723 background, then the foreground etc.) !!! => TODO */
3724 else if (!IS_PLAYER(last_jx, last_jy))
3725 DrawLevelField(last_jx, last_jy);
3728 DrawLevelField(last_jx, last_jy);
3731 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
3732 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
3735 if (!IN_SCR_FIELD(sx, sy))
3738 /* ----------------------------------------------------------------------- */
3739 /* draw things behind the player, if needed */
3740 /* ----------------------------------------------------------------------- */
3743 DrawLevelElement(jx, jy, Back[jx][jy]);
3744 else if (IS_ACTIVE_BOMB(element))
3745 DrawLevelElement(jx, jy, EL_EMPTY);
3748 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
3750 int old_element = GfxElement[jx][jy];
3751 int old_graphic = el_act_dir2img(old_element, action, move_dir);
3752 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
3754 if (GFX_CRUMBLED(old_element))
3755 DrawLevelFieldCrumbledDigging(jx, jy, move_dir, player->StepFrame);
3757 DrawGraphic(sx, sy, old_graphic, frame);
3759 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
3760 player_is_opaque = TRUE;
3764 GfxElement[jx][jy] = EL_UNDEFINED;
3766 /* make sure that pushed elements are drawn with correct frame rate */
3767 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
3769 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
3770 GfxFrame[jx][jy] = player->StepFrame;
3772 DrawLevelField(jx, jy);
3776 #if !DRAW_PLAYER_OVER_PUSHED_ELEMENT
3777 /* ----------------------------------------------------------------------- */
3778 /* draw player himself */
3779 /* ----------------------------------------------------------------------- */
3781 graphic = getPlayerGraphic(player, move_dir);
3783 /* in the case of changed player action or direction, prevent the current
3784 animation frame from being restarted for identical animations */
3785 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
3786 player->Frame = last_player_frame;
3788 frame = getGraphicAnimationFrame(graphic, player->Frame);
3792 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3793 sxx = player->GfxPos;
3795 syy = player->GfxPos;
3798 if (player_is_opaque)
3799 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
3801 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3803 if (SHIELD_ON(player))
3805 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
3806 IMG_SHIELD_NORMAL_ACTIVE);
3807 int frame = getGraphicAnimationFrame(graphic, -1);
3809 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3813 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
3816 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3817 sxx = player->GfxPos;
3819 syy = player->GfxPos;
3823 /* ----------------------------------------------------------------------- */
3824 /* draw things the player is pushing, if needed */
3825 /* ----------------------------------------------------------------------- */
3827 if (player->is_pushing && player->is_moving)
3829 int px = SCREENX(jx), py = SCREENY(jy);
3830 int pxx = (TILEX - ABS(sxx)) * dx;
3831 int pyy = (TILEY - ABS(syy)) * dy;
3832 int gfx_frame = GfxFrame[jx][jy];
3838 if (!IS_MOVING(jx, jy)) /* push movement already finished */
3840 element = Feld[next_jx][next_jy];
3841 gfx_frame = GfxFrame[next_jx][next_jy];
3844 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
3846 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
3847 frame = getGraphicAnimationFrame(graphic, sync_frame);
3849 /* draw background element under pushed element (like the Sokoban field) */
3850 if (game.use_masked_pushing && IS_MOVING(jx, jy))
3852 /* this allows transparent pushing animation over non-black background */
3855 DrawLevelElement(jx, jy, Back[jx][jy]);
3857 DrawLevelElement(jx, jy, EL_EMPTY);
3859 if (Back[next_jx][next_jy])
3860 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3862 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
3864 else if (Back[next_jx][next_jy])
3865 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3868 /* do not draw (EM style) pushing animation when pushing is finished */
3869 /* (two-tile animations usually do not contain start and end frame) */
3870 if (graphic_info[graphic].double_movement && !IS_MOVING(jx, jy))
3871 DrawLevelElement(next_jx, next_jy, Feld[next_jx][next_jy]);
3873 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3875 /* masked drawing is needed for EMC style (double) movement graphics */
3876 /* !!! (ONLY WHEN DRAWING PUSHED ELEMENT OVER THE PLAYER) !!! */
3877 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3881 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
3882 /* ----------------------------------------------------------------------- */
3883 /* draw player himself */
3884 /* ----------------------------------------------------------------------- */
3886 graphic = getPlayerGraphic(player, move_dir);
3888 /* in the case of changed player action or direction, prevent the current
3889 animation frame from being restarted for identical animations */
3890 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
3891 player->Frame = last_player_frame;
3893 frame = getGraphicAnimationFrame(graphic, player->Frame);
3897 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3898 sxx = player->GfxPos;
3900 syy = player->GfxPos;
3903 if (player_is_opaque)
3904 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
3906 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3908 if (SHIELD_ON(player))
3910 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
3911 IMG_SHIELD_NORMAL_ACTIVE);
3912 int frame = getGraphicAnimationFrame(graphic, -1);
3914 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3918 /* ----------------------------------------------------------------------- */
3919 /* draw things in front of player (active dynamite or dynabombs) */
3920 /* ----------------------------------------------------------------------- */
3922 if (IS_ACTIVE_BOMB(element))
3924 graphic = el2img(element);
3925 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
3927 if (game.emulation == EMU_SUPAPLEX)
3928 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
3930 DrawGraphicThruMask(sx, sy, graphic, frame);
3933 if (player_is_moving && last_element == EL_EXPLOSION)
3935 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
3936 GfxElement[last_jx][last_jy] : EL_EMPTY);
3937 int graphic = el_act2img(element, ACTION_EXPLODING);
3938 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
3939 int phase = ExplodePhase[last_jx][last_jy] - 1;
3940 int frame = getGraphicAnimationFrame(graphic, phase - delay);
3943 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
3946 /* ----------------------------------------------------------------------- */
3947 /* draw elements the player is just walking/passing through/under */
3948 /* ----------------------------------------------------------------------- */
3950 if (player_is_moving)
3952 /* handle the field the player is leaving ... */
3953 if (IS_ACCESSIBLE_INSIDE(last_element))
3954 DrawLevelField(last_jx, last_jy);
3955 else if (IS_ACCESSIBLE_UNDER(last_element))
3956 DrawLevelFieldThruMask(last_jx, last_jy);
3959 /* do not redraw accessible elements if the player is just pushing them */
3960 if (!player_is_moving || !player->is_pushing)
3962 /* ... and the field the player is entering */
3963 if (IS_ACCESSIBLE_INSIDE(element))
3964 DrawLevelField(jx, jy);
3965 else if (IS_ACCESSIBLE_UNDER(element))
3966 DrawLevelFieldThruMask(jx, jy);
3969 MarkTileDirty(sx, sy);
3972 /* ------------------------------------------------------------------------- */
3974 void WaitForEventToContinue()
3976 boolean still_wait = TRUE;
3978 if (program.headless)
3981 /* simulate releasing mouse button over last gadget, if still pressed */
3983 HandleGadgets(-1, -1, 0);
3985 button_status = MB_RELEASED;
3993 if (NextValidEvent(&event))
3997 case EVENT_BUTTONPRESS:
3998 case EVENT_KEYPRESS:
3999 #if defined(TARGET_SDL2)
4000 case SDL_CONTROLLERBUTTONDOWN:
4002 case SDL_JOYBUTTONDOWN:
4006 case EVENT_KEYRELEASE:
4007 ClearPlayerAction();
4011 HandleOtherEvents(&event);
4015 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
4024 #define MAX_REQUEST_LINES 13
4025 #define MAX_REQUEST_LINE_FONT1_LEN 7
4026 #define MAX_REQUEST_LINE_FONT2_LEN 10
4028 static int RequestHandleEvents(unsigned int req_state)
4030 boolean level_solved = (game_status == GAME_MODE_PLAYING &&
4031 local_player->LevelSolved_GameEnd);
4032 int width = request.width;
4033 int height = request.height;
4037 setRequestPosition(&sx, &sy, FALSE);
4039 button_status = MB_RELEASED;
4041 request_gadget_id = -1;
4048 /* the MM game engine does not use a special (scrollable) field buffer */
4049 if (level.game_engine_type != GAME_ENGINE_TYPE_MM)
4050 SetDrawtoField(DRAW_TO_FIELDBUFFER);
4052 HandleGameActions();
4054 SetDrawtoField(DRAW_TO_BACKBUFFER);
4056 if (global.use_envelope_request)
4058 /* copy current state of request area to middle of playfield area */
4059 BlitBitmap(bitmap_db_store_2, drawto, sx, sy, width, height, sx, sy);
4067 while (NextValidEvent(&event))
4071 case EVENT_BUTTONPRESS:
4072 case EVENT_BUTTONRELEASE:
4073 case EVENT_MOTIONNOTIFY:
4077 if (event.type == EVENT_MOTIONNOTIFY)
4082 motion_status = TRUE;
4083 mx = ((MotionEvent *) &event)->x;
4084 my = ((MotionEvent *) &event)->y;
4088 motion_status = FALSE;
4089 mx = ((ButtonEvent *) &event)->x;
4090 my = ((ButtonEvent *) &event)->y;
4091 if (event.type == EVENT_BUTTONPRESS)
4092 button_status = ((ButtonEvent *) &event)->button;
4094 button_status = MB_RELEASED;
4097 /* this sets 'request_gadget_id' */
4098 HandleGadgets(mx, my, button_status);
4100 switch (request_gadget_id)
4102 case TOOL_CTRL_ID_YES:
4105 case TOOL_CTRL_ID_NO:
4108 case TOOL_CTRL_ID_CONFIRM:
4109 result = TRUE | FALSE;
4112 case TOOL_CTRL_ID_PLAYER_1:
4115 case TOOL_CTRL_ID_PLAYER_2:
4118 case TOOL_CTRL_ID_PLAYER_3:
4121 case TOOL_CTRL_ID_PLAYER_4:
4132 #if defined(TARGET_SDL2)
4133 case SDL_WINDOWEVENT:
4134 HandleWindowEvent((WindowEvent *) &event);
4137 case SDL_APP_WILLENTERBACKGROUND:
4138 case SDL_APP_DIDENTERBACKGROUND:
4139 case SDL_APP_WILLENTERFOREGROUND:
4140 case SDL_APP_DIDENTERFOREGROUND:
4141 HandlePauseResumeEvent((PauseResumeEvent *) &event);
4145 case EVENT_KEYPRESS:
4147 Key key = GetEventKey((KeyEvent *)&event, TRUE);
4152 if (req_state & REQ_CONFIRM)
4157 #if defined(TARGET_SDL2)
4160 #if defined(KSYM_Rewind)
4161 case KSYM_Rewind: /* for Amazon Fire TV remote */
4168 #if defined(TARGET_SDL2)
4170 #if defined(KSYM_FastForward)
4171 case KSYM_FastForward: /* for Amazon Fire TV remote */
4178 HandleKeysDebug(key);
4182 if (req_state & REQ_PLAYER)
4188 case EVENT_KEYRELEASE:
4189 ClearPlayerAction();
4192 #if defined(TARGET_SDL2)
4193 case SDL_CONTROLLERBUTTONDOWN:
4194 switch (event.cbutton.button)
4196 case SDL_CONTROLLER_BUTTON_A:
4197 case SDL_CONTROLLER_BUTTON_X:
4198 case SDL_CONTROLLER_BUTTON_LEFTSHOULDER:
4202 case SDL_CONTROLLER_BUTTON_B:
4203 case SDL_CONTROLLER_BUTTON_Y:
4204 case SDL_CONTROLLER_BUTTON_RIGHTSHOULDER:
4205 case SDL_CONTROLLER_BUTTON_BACK:
4210 if (req_state & REQ_PLAYER)
4215 case SDL_CONTROLLERBUTTONUP:
4216 HandleJoystickEvent(&event);
4217 ClearPlayerAction();
4222 HandleOtherEvents(&event);
4227 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
4229 int joy = AnyJoystick();
4231 if (joy & JOY_BUTTON_1)
4233 else if (joy & JOY_BUTTON_2)
4239 if (global.use_envelope_request)
4241 /* copy back current state of pressed buttons inside request area */
4242 BlitBitmap(drawto, bitmap_db_store_2, sx, sy, width, height, sx, sy);
4252 static boolean RequestDoor(char *text, unsigned int req_state)
4254 unsigned int old_door_state;
4255 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
4256 int font_nr = FONT_TEXT_2;
4261 if (maxWordLengthInString(text) > MAX_REQUEST_LINE_FONT1_LEN)
4263 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
4264 font_nr = FONT_TEXT_1;
4267 if (game_status == GAME_MODE_PLAYING)
4268 BlitScreenToBitmap(backbuffer);
4270 /* disable deactivated drawing when quick-loading level tape recording */
4271 if (tape.playing && tape.deactivate_display)
4272 TapeDeactivateDisplayOff(TRUE);
4274 SetMouseCursor(CURSOR_DEFAULT);
4276 #if defined(NETWORK_AVALIABLE)
4277 /* pause network game while waiting for request to answer */
4278 if (options.network &&
4279 game_status == GAME_MODE_PLAYING &&
4280 req_state & REQUEST_WAIT_FOR_INPUT)
4281 SendToServer_PausePlaying();
4284 old_door_state = GetDoorState();
4286 /* simulate releasing mouse button over last gadget, if still pressed */
4288 HandleGadgets(-1, -1, 0);
4292 /* draw released gadget before proceeding */
4295 if (old_door_state & DOOR_OPEN_1)
4297 CloseDoor(DOOR_CLOSE_1);
4299 /* save old door content */
4300 BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
4301 0 * DXSIZE, 0, DXSIZE, DYSIZE, 1 * DXSIZE, 0);
4304 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
4305 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4307 /* clear door drawing field */
4308 DrawBackground(DX, DY, DXSIZE, DYSIZE);
4310 /* force DOOR font inside door area */
4311 SetFontStatus(GAME_MODE_PSEUDO_DOOR);
4313 /* write text for request */
4314 for (text_ptr = text, ty = 0; ty < MAX_REQUEST_LINES; ty++)
4316 char text_line[max_request_line_len + 1];
4322 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
4324 tc = *(text_ptr + tx);
4325 // if (!tc || tc == ' ')
4326 if (!tc || tc == ' ' || tc == '?' || tc == '!')
4330 if ((tc == '?' || tc == '!') && tl == 0)
4340 strncpy(text_line, text_ptr, tl);
4343 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
4344 DY + 8 + ty * (getFontHeight(font_nr) + 2),
4345 text_line, font_nr);
4347 text_ptr += tl + (tc == ' ' ? 1 : 0);
4348 // text_ptr += tl + (tc == ' ' || tc == '?' || tc == '!' ? 1 : 0);
4353 if (req_state & REQ_ASK)
4355 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
4356 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
4358 else if (req_state & REQ_CONFIRM)
4360 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
4362 else if (req_state & REQ_PLAYER)
4364 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
4365 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
4366 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
4367 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
4370 /* copy request gadgets to door backbuffer */
4371 BlitBitmap(drawto, bitmap_db_door_1, DX, DY, DXSIZE, DYSIZE, 0, 0);
4373 OpenDoor(DOOR_OPEN_1);
4375 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
4377 if (game_status == GAME_MODE_PLAYING)
4379 SetPanelBackground();
4380 SetDrawBackgroundMask(REDRAW_DOOR_1);
4384 SetDrawBackgroundMask(REDRAW_FIELD);
4390 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4392 // ---------- handle request buttons ----------
4393 result = RequestHandleEvents(req_state);
4397 if (!(req_state & REQ_STAY_OPEN))
4399 CloseDoor(DOOR_CLOSE_1);
4401 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
4402 (req_state & REQ_REOPEN))
4403 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
4408 if (game_status == GAME_MODE_PLAYING)
4410 SetPanelBackground();
4411 SetDrawBackgroundMask(REDRAW_DOOR_1);
4415 SetDrawBackgroundMask(REDRAW_FIELD);
4418 #if defined(NETWORK_AVALIABLE)
4419 /* continue network game after request */
4420 if (options.network &&
4421 game_status == GAME_MODE_PLAYING &&
4422 req_state & REQUEST_WAIT_FOR_INPUT)
4423 SendToServer_ContinuePlaying();
4426 /* restore deactivated drawing when quick-loading level tape recording */
4427 if (tape.playing && tape.deactivate_display)
4428 TapeDeactivateDisplayOn();
4433 static boolean RequestEnvelope(char *text, unsigned int req_state)
4437 if (game_status == GAME_MODE_PLAYING)
4438 BlitScreenToBitmap(backbuffer);
4440 /* disable deactivated drawing when quick-loading level tape recording */
4441 if (tape.playing && tape.deactivate_display)
4442 TapeDeactivateDisplayOff(TRUE);
4444 SetMouseCursor(CURSOR_DEFAULT);
4446 #if defined(NETWORK_AVALIABLE)
4447 /* pause network game while waiting for request to answer */
4448 if (options.network &&
4449 game_status == GAME_MODE_PLAYING &&
4450 req_state & REQUEST_WAIT_FOR_INPUT)
4451 SendToServer_PausePlaying();
4454 /* simulate releasing mouse button over last gadget, if still pressed */
4456 HandleGadgets(-1, -1, 0);
4460 // (replace with setting corresponding request background)
4461 // SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
4462 // SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4464 /* clear door drawing field */
4465 // DrawBackground(DX, DY, DXSIZE, DYSIZE);
4467 ShowEnvelopeRequest(text, req_state, ACTION_OPENING);
4469 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
4471 if (game_status == GAME_MODE_PLAYING)
4473 SetPanelBackground();
4474 SetDrawBackgroundMask(REDRAW_DOOR_1);
4478 SetDrawBackgroundMask(REDRAW_FIELD);
4484 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4486 // ---------- handle request buttons ----------
4487 result = RequestHandleEvents(req_state);
4491 ShowEnvelopeRequest(text, req_state, ACTION_CLOSING);
4495 if (game_status == GAME_MODE_PLAYING)
4497 SetPanelBackground();
4498 SetDrawBackgroundMask(REDRAW_DOOR_1);
4502 SetDrawBackgroundMask(REDRAW_FIELD);
4505 #if defined(NETWORK_AVALIABLE)
4506 /* continue network game after request */
4507 if (options.network &&
4508 game_status == GAME_MODE_PLAYING &&
4509 req_state & REQUEST_WAIT_FOR_INPUT)
4510 SendToServer_ContinuePlaying();
4513 /* restore deactivated drawing when quick-loading level tape recording */
4514 if (tape.playing && tape.deactivate_display)
4515 TapeDeactivateDisplayOn();
4520 boolean Request(char *text, unsigned int req_state)
4522 boolean overlay_active = GetOverlayActive();
4525 SetOverlayActive(FALSE);
4527 if (global.use_envelope_request)
4528 result = RequestEnvelope(text, req_state);
4530 result = RequestDoor(text, req_state);
4532 SetOverlayActive(overlay_active);
4537 static int compareDoorPartOrderInfo(const void *object1, const void *object2)
4539 const struct DoorPartOrderInfo *dpo1 = (struct DoorPartOrderInfo *)object1;
4540 const struct DoorPartOrderInfo *dpo2 = (struct DoorPartOrderInfo *)object2;
4543 if (dpo1->sort_priority != dpo2->sort_priority)
4544 compare_result = dpo1->sort_priority - dpo2->sort_priority;
4546 compare_result = dpo1->nr - dpo2->nr;
4548 return compare_result;
4551 void InitGraphicCompatibilityInfo_Doors()
4557 struct DoorInfo *door;
4561 { DOOR_1, IMG_GFX_DOOR_1_PART_1, IMG_GFX_DOOR_1_PART_8, &door_1 },
4562 { DOOR_2, IMG_GFX_DOOR_2_PART_1, IMG_GFX_DOOR_2_PART_8, &door_2 },
4564 { -1, -1, -1, NULL }
4566 struct Rect door_rect_list[] =
4568 { DX, DY, DXSIZE, DYSIZE },
4569 { VX, VY, VXSIZE, VYSIZE }
4573 for (i = 0; doors[i].door_token != -1; i++)
4575 int door_token = doors[i].door_token;
4576 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
4577 int part_1 = doors[i].part_1;
4578 int part_8 = doors[i].part_8;
4579 int part_2 = part_1 + 1;
4580 int part_3 = part_1 + 2;
4581 struct DoorInfo *door = doors[i].door;
4582 struct Rect *door_rect = &door_rect_list[door_index];
4583 boolean door_gfx_redefined = FALSE;
4585 /* check if any door part graphic definitions have been redefined */
4587 for (j = 0; door_part_controls[j].door_token != -1; j++)
4589 struct DoorPartControlInfo *dpc = &door_part_controls[j];
4590 struct FileInfo *fi = getImageListEntryFromImageID(dpc->graphic);
4592 if (dpc->door_token == door_token && fi->redefined)
4593 door_gfx_redefined = TRUE;
4596 /* check for old-style door graphic/animation modifications */
4598 if (!door_gfx_redefined)
4600 if (door->anim_mode & ANIM_STATIC_PANEL)
4602 door->panel.step_xoffset = 0;
4603 door->panel.step_yoffset = 0;
4606 if (door->anim_mode & (ANIM_HORIZONTAL | ANIM_VERTICAL))
4608 struct GraphicInfo *g_part_1 = &graphic_info[part_1];
4609 struct GraphicInfo *g_part_2 = &graphic_info[part_2];
4610 int num_door_steps, num_panel_steps;
4612 /* remove door part graphics other than the two default wings */
4614 for (j = 0; door_part_controls[j].door_token != -1; j++)
4616 struct DoorPartControlInfo *dpc = &door_part_controls[j];
4617 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4619 if (dpc->graphic >= part_3 &&
4620 dpc->graphic <= part_8)
4624 /* set graphics and screen positions of the default wings */
4626 g_part_1->width = door_rect->width;
4627 g_part_1->height = door_rect->height;
4628 g_part_2->width = door_rect->width;
4629 g_part_2->height = door_rect->height;
4630 g_part_2->src_x = door_rect->width;
4631 g_part_2->src_y = g_part_1->src_y;
4633 door->part_2.x = door->part_1.x;
4634 door->part_2.y = door->part_1.y;
4636 if (door->width != -1)
4638 g_part_1->width = door->width;
4639 g_part_2->width = door->width;
4641 // special treatment for graphics and screen position of right wing
4642 g_part_2->src_x += door_rect->width - door->width;
4643 door->part_2.x += door_rect->width - door->width;
4646 if (door->height != -1)
4648 g_part_1->height = door->height;
4649 g_part_2->height = door->height;
4651 // special treatment for graphics and screen position of bottom wing
4652 g_part_2->src_y += door_rect->height - door->height;
4653 door->part_2.y += door_rect->height - door->height;
4656 /* set animation delays for the default wings and panels */
4658 door->part_1.step_delay = door->step_delay;
4659 door->part_2.step_delay = door->step_delay;
4660 door->panel.step_delay = door->step_delay;
4662 /* set animation draw order for the default wings */
4664 door->part_1.sort_priority = 2; /* draw left wing over ... */
4665 door->part_2.sort_priority = 1; /* ... right wing */
4667 /* set animation draw offset for the default wings */
4669 if (door->anim_mode & ANIM_HORIZONTAL)
4671 door->part_1.step_xoffset = door->step_offset;
4672 door->part_1.step_yoffset = 0;
4673 door->part_2.step_xoffset = door->step_offset * -1;
4674 door->part_2.step_yoffset = 0;
4676 num_door_steps = g_part_1->width / door->step_offset;
4678 else // ANIM_VERTICAL
4680 door->part_1.step_xoffset = 0;
4681 door->part_1.step_yoffset = door->step_offset;
4682 door->part_2.step_xoffset = 0;
4683 door->part_2.step_yoffset = door->step_offset * -1;
4685 num_door_steps = g_part_1->height / door->step_offset;
4688 /* set animation draw offset for the default panels */
4690 if (door->step_offset > 1)
4692 num_panel_steps = 2 * door_rect->height / door->step_offset;
4693 door->panel.start_step = num_panel_steps - num_door_steps;
4694 door->panel.start_step_closing = door->panel.start_step;
4698 num_panel_steps = door_rect->height / door->step_offset;
4699 door->panel.start_step = num_panel_steps - num_door_steps / 2;
4700 door->panel.start_step_closing = door->panel.start_step;
4701 door->panel.step_delay *= 2;
4712 for (i = 0; door_part_controls[i].door_token != -1; i++)
4714 struct DoorPartControlInfo *dpc = &door_part_controls[i];
4715 struct DoorPartOrderInfo *dpo = &door_part_order[i];
4717 /* initialize "start_step_opening" and "start_step_closing", if needed */
4718 if (dpc->pos->start_step_opening == 0 &&
4719 dpc->pos->start_step_closing == 0)
4721 // dpc->pos->start_step_opening = dpc->pos->start_step;
4722 dpc->pos->start_step_closing = dpc->pos->start_step;
4725 /* fill structure for door part draw order (sorted below) */
4727 dpo->sort_priority = dpc->pos->sort_priority;
4730 /* sort door part controls according to sort_priority and graphic number */
4731 qsort(door_part_order, MAX_DOOR_PARTS,
4732 sizeof(struct DoorPartOrderInfo), compareDoorPartOrderInfo);
4735 unsigned int OpenDoor(unsigned int door_state)
4737 if (door_state & DOOR_COPY_BACK)
4739 if (door_state & DOOR_OPEN_1)
4740 BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
4741 1 * DXSIZE, 0, DXSIZE, DYSIZE, 0 * DXSIZE, 0);
4743 if (door_state & DOOR_OPEN_2)
4744 BlitBitmap(bitmap_db_door_2, bitmap_db_door_2,
4745 1 * VXSIZE, 0, VXSIZE, VYSIZE, 0 * VXSIZE, 0);
4747 door_state &= ~DOOR_COPY_BACK;
4750 return MoveDoor(door_state);
4753 unsigned int CloseDoor(unsigned int door_state)
4755 unsigned int old_door_state = GetDoorState();
4757 if (!(door_state & DOOR_NO_COPY_BACK))
4759 if (old_door_state & DOOR_OPEN_1)
4760 BlitBitmap(backbuffer, bitmap_db_door_1,
4761 DX, DY, DXSIZE, DYSIZE, 0, 0);
4763 if (old_door_state & DOOR_OPEN_2)
4764 BlitBitmap(backbuffer, bitmap_db_door_2,
4765 VX, VY, VXSIZE, VYSIZE, 0, 0);
4767 door_state &= ~DOOR_NO_COPY_BACK;
4770 return MoveDoor(door_state);
4773 unsigned int GetDoorState()
4775 return MoveDoor(DOOR_GET_STATE);
4778 unsigned int SetDoorState(unsigned int door_state)
4780 return MoveDoor(door_state | DOOR_SET_STATE);
4783 int euclid(int a, int b)
4785 return (b ? euclid(b, a % b) : a);
4788 unsigned int MoveDoor(unsigned int door_state)
4790 struct Rect door_rect_list[] =
4792 { DX, DY, DXSIZE, DYSIZE },
4793 { VX, VY, VXSIZE, VYSIZE }
4795 static int door1 = DOOR_CLOSE_1;
4796 static int door2 = DOOR_CLOSE_2;
4797 unsigned int door_delay = 0;
4798 unsigned int door_delay_value;
4801 if (door_state == DOOR_GET_STATE)
4802 return (door1 | door2);
4804 if (door_state & DOOR_SET_STATE)
4806 if (door_state & DOOR_ACTION_1)
4807 door1 = door_state & DOOR_ACTION_1;
4808 if (door_state & DOOR_ACTION_2)
4809 door2 = door_state & DOOR_ACTION_2;
4811 return (door1 | door2);
4814 if (!(door_state & DOOR_FORCE_REDRAW))
4816 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
4817 door_state &= ~DOOR_OPEN_1;
4818 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
4819 door_state &= ~DOOR_CLOSE_1;
4820 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
4821 door_state &= ~DOOR_OPEN_2;
4822 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
4823 door_state &= ~DOOR_CLOSE_2;
4826 if (global.autoplay_leveldir)
4828 door_state |= DOOR_NO_DELAY;
4829 door_state &= ~DOOR_CLOSE_ALL;
4832 if (game_status == GAME_MODE_EDITOR && !(door_state & DOOR_FORCE_ANIM))
4833 door_state |= DOOR_NO_DELAY;
4835 if (door_state & DOOR_ACTION)
4837 boolean door_panel_drawn[NUM_DOORS];
4838 boolean panel_has_doors[NUM_DOORS];
4839 boolean door_part_skip[MAX_DOOR_PARTS];
4840 boolean door_part_done[MAX_DOOR_PARTS];
4841 boolean door_part_done_all;
4842 int num_steps[MAX_DOOR_PARTS];
4843 int max_move_delay = 0; // delay for complete animations of all doors
4844 int max_step_delay = 0; // delay (ms) between two animation frames
4845 int num_move_steps = 0; // number of animation steps for all doors
4846 int max_move_delay_doors_only = 0; // delay for doors only (no panel)
4847 int num_move_steps_doors_only = 0; // steps for doors only (no panel)
4848 int current_move_delay = 0;
4852 for (i = 0; i < NUM_DOORS; i++)
4853 panel_has_doors[i] = FALSE;
4855 for (i = 0; i < MAX_DOOR_PARTS; i++)
4857 struct DoorPartControlInfo *dpc = &door_part_controls[i];
4858 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4859 int door_token = dpc->door_token;
4861 door_part_done[i] = FALSE;
4862 door_part_skip[i] = (!(door_state & door_token) ||
4866 for (i = 0; i < MAX_DOOR_PARTS; i++)
4868 int nr = door_part_order[i].nr;
4869 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
4870 struct DoorPartPosInfo *pos = dpc->pos;
4871 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4872 int door_token = dpc->door_token;
4873 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
4874 boolean is_panel = DOOR_PART_IS_PANEL(nr);
4875 int step_xoffset = ABS(pos->step_xoffset);
4876 int step_yoffset = ABS(pos->step_yoffset);
4877 int step_delay = pos->step_delay;
4878 int current_door_state = door_state & door_token;
4879 boolean door_opening = ((current_door_state & DOOR_OPEN) != 0);
4880 boolean door_closing = ((current_door_state & DOOR_CLOSE) != 0);
4881 boolean part_opening = (is_panel ? door_closing : door_opening);
4882 int start_step = (part_opening ? pos->start_step_opening :
4883 pos->start_step_closing);
4884 float move_xsize = (step_xoffset ? g->width : 0);
4885 float move_ysize = (step_yoffset ? g->height : 0);
4886 int move_xsteps = (step_xoffset ? ceil(move_xsize / step_xoffset) : 0);
4887 int move_ysteps = (step_yoffset ? ceil(move_ysize / step_yoffset) : 0);
4888 int move_steps = (move_xsteps && move_ysteps ?
4889 MIN(move_xsteps, move_ysteps) :
4890 move_xsteps ? move_xsteps : move_ysteps) - start_step;
4891 int move_delay = move_steps * step_delay;
4893 if (door_part_skip[nr])
4896 max_move_delay = MAX(max_move_delay, move_delay);
4897 max_step_delay = (max_step_delay == 0 ? step_delay :
4898 euclid(max_step_delay, step_delay));
4899 num_steps[nr] = move_steps;
4903 max_move_delay_doors_only = MAX(max_move_delay_doors_only, move_delay);
4905 panel_has_doors[door_index] = TRUE;
4909 max_step_delay = MAX(1, max_step_delay); // prevent division by zero
4911 num_move_steps = max_move_delay / max_step_delay;
4912 num_move_steps_doors_only = max_move_delay_doors_only / max_step_delay;
4914 door_delay_value = max_step_delay;
4916 if ((door_state & DOOR_NO_DELAY) || setup.quick_doors)
4918 start = num_move_steps - 1;
4922 /* opening door sound has priority over simultaneously closing door */
4923 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
4925 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
4927 if (door_state & DOOR_OPEN_1)
4928 PlayMenuSoundStereo(SND_DOOR_1_OPENING, SOUND_MIDDLE);
4929 if (door_state & DOOR_OPEN_2)
4930 PlayMenuSoundStereo(SND_DOOR_2_OPENING, SOUND_MIDDLE);
4932 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
4934 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
4936 if (door_state & DOOR_CLOSE_1)
4937 PlayMenuSoundStereo(SND_DOOR_1_CLOSING, SOUND_MIDDLE);
4938 if (door_state & DOOR_CLOSE_2)
4939 PlayMenuSoundStereo(SND_DOOR_2_CLOSING, SOUND_MIDDLE);
4943 for (k = start; k < num_move_steps; k++)
4945 int last_frame = num_move_steps - 1; // last frame of this "for" loop
4947 door_part_done_all = TRUE;
4949 for (i = 0; i < NUM_DOORS; i++)
4950 door_panel_drawn[i] = FALSE;
4952 for (i = 0; i < MAX_DOOR_PARTS; i++)
4954 int nr = door_part_order[i].nr;
4955 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
4956 struct DoorPartPosInfo *pos = dpc->pos;
4957 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4958 int door_token = dpc->door_token;
4959 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
4960 boolean is_panel = DOOR_PART_IS_PANEL(nr);
4961 boolean is_panel_and_door_has_closed = FALSE;
4962 struct Rect *door_rect = &door_rect_list[door_index];
4963 Bitmap *bitmap_db_door = (door_token == DOOR_1 ? bitmap_db_door_1 :
4965 Bitmap *bitmap = (is_panel ? bitmap_db_door : g->bitmap);
4966 int current_door_state = door_state & door_token;
4967 boolean door_opening = ((current_door_state & DOOR_OPEN) != 0);
4968 boolean door_closing = !door_opening;
4969 boolean part_opening = (is_panel ? door_closing : door_opening);
4970 boolean part_closing = !part_opening;
4971 int start_step = (part_opening ? pos->start_step_opening :
4972 pos->start_step_closing);
4973 int step_delay = pos->step_delay;
4974 int step_factor = step_delay / max_step_delay;
4975 int k1 = (step_factor ? k / step_factor + 1 : k);
4976 int k2 = (part_opening ? k1 + start_step : num_steps[nr] - k1);
4977 int kk = MAX(0, k2);
4980 int src_x, src_y, src_xx, src_yy;
4981 int dst_x, dst_y, dst_xx, dst_yy;
4984 if (door_part_skip[nr])
4987 if (!(door_state & door_token))
4995 int k2_door = (door_opening ? k : num_move_steps_doors_only - k - 1);
4996 int kk_door = MAX(0, k2_door);
4997 int sync_frame = kk_door * door_delay_value;
4998 int frame = getGraphicAnimationFrame(dpc->graphic, sync_frame);
5000 getFixedGraphicSource(dpc->graphic, frame, &bitmap,
5001 &g_src_x, &g_src_y);
5006 if (!door_panel_drawn[door_index])
5008 ClearRectangle(drawto, door_rect->x, door_rect->y,
5009 door_rect->width, door_rect->height);
5011 door_panel_drawn[door_index] = TRUE;
5014 // draw opening or closing door parts
5016 if (pos->step_xoffset < 0) // door part on right side
5019 dst_xx = pos->x + ABS(kk * pos->step_xoffset);
5022 if (dst_xx + width > door_rect->width)
5023 width = door_rect->width - dst_xx;
5025 else // door part on left side
5028 dst_xx = pos->x - kk * pos->step_xoffset;
5032 src_xx = ABS(dst_xx);
5036 width = g->width - src_xx;
5038 if (width > door_rect->width)
5039 width = door_rect->width;
5041 // printf("::: k == %d [%d] \n", k, start_step);
5044 if (pos->step_yoffset < 0) // door part on bottom side
5047 dst_yy = pos->y + ABS(kk * pos->step_yoffset);
5050 if (dst_yy + height > door_rect->height)
5051 height = door_rect->height - dst_yy;
5053 else // door part on top side
5056 dst_yy = pos->y - kk * pos->step_yoffset;
5060 src_yy = ABS(dst_yy);
5064 height = g->height - src_yy;
5067 src_x = g_src_x + src_xx;
5068 src_y = g_src_y + src_yy;
5070 dst_x = door_rect->x + dst_xx;
5071 dst_y = door_rect->y + dst_yy;
5073 is_panel_and_door_has_closed =
5076 panel_has_doors[door_index] &&
5077 k >= num_move_steps_doors_only - 1);
5079 if (width >= 0 && width <= g->width &&
5080 height >= 0 && height <= g->height &&
5081 !is_panel_and_door_has_closed)
5083 if (is_panel || !pos->draw_masked)
5084 BlitBitmap(bitmap, drawto, src_x, src_y, width, height,
5087 BlitBitmapMasked(bitmap, drawto, src_x, src_y, width, height,
5091 redraw_mask |= REDRAW_DOOR_FROM_TOKEN(door_token);
5093 if ((part_opening && (width < 0 || height < 0)) ||
5094 (part_closing && (width >= g->width && height >= g->height)))
5095 door_part_done[nr] = TRUE;
5097 // continue door part animations, but not panel after door has closed
5098 if (!door_part_done[nr] && !is_panel_and_door_has_closed)
5099 door_part_done_all = FALSE;
5102 if (!(door_state & DOOR_NO_DELAY))
5106 SkipUntilDelayReached(&door_delay, door_delay_value, &k, last_frame);
5108 current_move_delay += max_step_delay;
5110 /* prevent OS (Windows) from complaining about program not responding */
5114 if (door_part_done_all)
5118 if (!(door_state & DOOR_NO_DELAY))
5120 /* wait for specified door action post delay */
5121 if (door_state & DOOR_ACTION_1 && door_state & DOOR_ACTION_2)
5122 Delay(MAX(door_1.post_delay, door_2.post_delay));
5123 else if (door_state & DOOR_ACTION_1)
5124 Delay(door_1.post_delay);
5125 else if (door_state & DOOR_ACTION_2)
5126 Delay(door_2.post_delay);
5130 if (door_state & DOOR_ACTION_1)
5131 door1 = door_state & DOOR_ACTION_1;
5132 if (door_state & DOOR_ACTION_2)
5133 door2 = door_state & DOOR_ACTION_2;
5135 // draw masked border over door area
5136 DrawMaskedBorder(REDRAW_DOOR_1);
5137 DrawMaskedBorder(REDRAW_DOOR_2);
5139 return (door1 | door2);
5142 static boolean useSpecialEditorDoor()
5144 int graphic = IMG_GLOBAL_BORDER_EDITOR;
5145 boolean redefined = getImageListEntryFromImageID(graphic)->redefined;
5147 // do not draw special editor door if editor border defined or redefined
5148 if (graphic_info[graphic].bitmap != NULL || redefined)
5151 // do not draw special editor door if global border defined to be empty
5152 if (graphic_info[IMG_GLOBAL_BORDER].bitmap == NULL)
5155 // do not draw special editor door if viewport definitions do not match
5159 EY + EYSIZE != VY + VYSIZE)
5165 void DrawSpecialEditorDoor()
5167 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
5168 int top_border_width = gfx1->width;
5169 int top_border_height = gfx1->height;
5170 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
5171 int ex = EX - outer_border;
5172 int ey = EY - outer_border;
5173 int vy = VY - outer_border;
5174 int exsize = EXSIZE + 2 * outer_border;
5176 if (!useSpecialEditorDoor())
5179 /* draw bigger level editor toolbox window */
5180 BlitBitmap(gfx1->bitmap, drawto, gfx1->src_x, gfx1->src_y,
5181 top_border_width, top_border_height, ex, ey - top_border_height);
5182 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto, ex, vy,
5183 exsize, EYSIZE - VYSIZE + outer_border, ex, ey);
5185 redraw_mask |= REDRAW_ALL;
5188 void UndrawSpecialEditorDoor()
5190 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
5191 int top_border_width = gfx1->width;
5192 int top_border_height = gfx1->height;
5193 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
5194 int ex = EX - outer_border;
5195 int ey = EY - outer_border;
5196 int ey_top = ey - top_border_height;
5197 int exsize = EXSIZE + 2 * outer_border;
5198 int eysize = EYSIZE + 2 * outer_border;
5200 if (!useSpecialEditorDoor())
5203 /* draw normal tape recorder window */
5204 if (graphic_info[IMG_GLOBAL_BORDER].bitmap)
5206 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
5207 ex, ey_top, top_border_width, top_border_height,
5209 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
5210 ex, ey, exsize, eysize, ex, ey);
5214 // if screen background is set to "[NONE]", clear editor toolbox window
5215 ClearRectangle(drawto, ex, ey_top, top_border_width, top_border_height);
5216 ClearRectangle(drawto, ex, ey, exsize, eysize);
5219 redraw_mask |= REDRAW_ALL;
5223 /* ---------- new tool button stuff ---------------------------------------- */
5228 struct TextPosInfo *pos;
5231 } toolbutton_info[NUM_TOOL_BUTTONS] =
5234 IMG_GFX_REQUEST_BUTTON_YES, &request.button.yes,
5235 TOOL_CTRL_ID_YES, "yes"
5238 IMG_GFX_REQUEST_BUTTON_NO, &request.button.no,
5239 TOOL_CTRL_ID_NO, "no"
5242 IMG_GFX_REQUEST_BUTTON_CONFIRM, &request.button.confirm,
5243 TOOL_CTRL_ID_CONFIRM, "confirm"
5246 IMG_GFX_REQUEST_BUTTON_PLAYER_1, &request.button.player_1,
5247 TOOL_CTRL_ID_PLAYER_1, "player 1"
5250 IMG_GFX_REQUEST_BUTTON_PLAYER_2, &request.button.player_2,
5251 TOOL_CTRL_ID_PLAYER_2, "player 2"
5254 IMG_GFX_REQUEST_BUTTON_PLAYER_3, &request.button.player_3,
5255 TOOL_CTRL_ID_PLAYER_3, "player 3"
5258 IMG_GFX_REQUEST_BUTTON_PLAYER_4, &request.button.player_4,
5259 TOOL_CTRL_ID_PLAYER_4, "player 4"
5263 void CreateToolButtons()
5267 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
5269 struct GraphicInfo *gfx = &graphic_info[toolbutton_info[i].graphic];
5270 struct TextPosInfo *pos = toolbutton_info[i].pos;
5271 struct GadgetInfo *gi;
5272 Bitmap *deco_bitmap = None;
5273 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
5274 unsigned int event_mask = GD_EVENT_RELEASED;
5277 int gd_x = gfx->src_x;
5278 int gd_y = gfx->src_y;
5279 int gd_xp = gfx->src_x + gfx->pressed_xoffset;
5280 int gd_yp = gfx->src_y + gfx->pressed_yoffset;
5283 if (global.use_envelope_request)
5284 setRequestPosition(&dx, &dy, TRUE);
5286 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
5288 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
5290 getSizedGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr), 0,
5291 pos->size, &deco_bitmap, &deco_x, &deco_y);
5292 deco_xpos = (gfx->width - pos->size) / 2;
5293 deco_ypos = (gfx->height - pos->size) / 2;
5296 gi = CreateGadget(GDI_CUSTOM_ID, id,
5297 GDI_INFO_TEXT, toolbutton_info[i].infotext,
5298 GDI_X, dx + GDI_ACTIVE_POS(pos->x),
5299 GDI_Y, dy + GDI_ACTIVE_POS(pos->y),
5300 GDI_WIDTH, gfx->width,
5301 GDI_HEIGHT, gfx->height,
5302 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
5303 GDI_STATE, GD_BUTTON_UNPRESSED,
5304 GDI_DESIGN_UNPRESSED, gfx->bitmap, gd_x, gd_y,
5305 GDI_DESIGN_PRESSED, gfx->bitmap, gd_xp, gd_yp,
5306 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
5307 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
5308 GDI_DECORATION_SIZE, pos->size, pos->size,
5309 GDI_DECORATION_SHIFTING, 1, 1,
5310 GDI_DIRECT_DRAW, FALSE,
5311 GDI_EVENT_MASK, event_mask,
5312 GDI_CALLBACK_ACTION, HandleToolButtons,
5316 Error(ERR_EXIT, "cannot create gadget");
5318 tool_gadget[id] = gi;
5322 void FreeToolButtons()
5326 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
5327 FreeGadget(tool_gadget[i]);
5330 static void UnmapToolButtons()
5334 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
5335 UnmapGadget(tool_gadget[i]);
5338 static void HandleToolButtons(struct GadgetInfo *gi)
5340 request_gadget_id = gi->custom_id;
5343 static struct Mapping_EM_to_RND_object
5346 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
5347 boolean is_backside; /* backside of moving element */
5353 em_object_mapping_list[] =
5356 Xblank, TRUE, FALSE,
5360 Yacid_splash_eB, FALSE, FALSE,
5361 EL_ACID_SPLASH_RIGHT, -1, -1
5364 Yacid_splash_wB, FALSE, FALSE,
5365 EL_ACID_SPLASH_LEFT, -1, -1
5368 #ifdef EM_ENGINE_BAD_ROLL
5370 Xstone_force_e, FALSE, FALSE,
5371 EL_ROCK, -1, MV_BIT_RIGHT
5374 Xstone_force_w, FALSE, FALSE,
5375 EL_ROCK, -1, MV_BIT_LEFT
5378 Xnut_force_e, FALSE, FALSE,
5379 EL_NUT, -1, MV_BIT_RIGHT
5382 Xnut_force_w, FALSE, FALSE,
5383 EL_NUT, -1, MV_BIT_LEFT
5386 Xspring_force_e, FALSE, FALSE,
5387 EL_SPRING, -1, MV_BIT_RIGHT
5390 Xspring_force_w, FALSE, FALSE,
5391 EL_SPRING, -1, MV_BIT_LEFT
5394 Xemerald_force_e, FALSE, FALSE,
5395 EL_EMERALD, -1, MV_BIT_RIGHT
5398 Xemerald_force_w, FALSE, FALSE,
5399 EL_EMERALD, -1, MV_BIT_LEFT
5402 Xdiamond_force_e, FALSE, FALSE,
5403 EL_DIAMOND, -1, MV_BIT_RIGHT
5406 Xdiamond_force_w, FALSE, FALSE,
5407 EL_DIAMOND, -1, MV_BIT_LEFT
5410 Xbomb_force_e, FALSE, FALSE,
5411 EL_BOMB, -1, MV_BIT_RIGHT
5414 Xbomb_force_w, FALSE, FALSE,
5415 EL_BOMB, -1, MV_BIT_LEFT
5417 #endif /* EM_ENGINE_BAD_ROLL */
5420 Xstone, TRUE, FALSE,
5424 Xstone_pause, FALSE, FALSE,
5428 Xstone_fall, FALSE, FALSE,
5432 Ystone_s, FALSE, FALSE,
5433 EL_ROCK, ACTION_FALLING, -1
5436 Ystone_sB, FALSE, TRUE,
5437 EL_ROCK, ACTION_FALLING, -1
5440 Ystone_e, FALSE, FALSE,
5441 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
5444 Ystone_eB, FALSE, TRUE,
5445 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
5448 Ystone_w, FALSE, FALSE,
5449 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
5452 Ystone_wB, FALSE, TRUE,
5453 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
5460 Xnut_pause, FALSE, FALSE,
5464 Xnut_fall, FALSE, FALSE,
5468 Ynut_s, FALSE, FALSE,
5469 EL_NUT, ACTION_FALLING, -1
5472 Ynut_sB, FALSE, TRUE,
5473 EL_NUT, ACTION_FALLING, -1
5476 Ynut_e, FALSE, FALSE,
5477 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
5480 Ynut_eB, FALSE, TRUE,
5481 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
5484 Ynut_w, FALSE, FALSE,
5485 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
5488 Ynut_wB, FALSE, TRUE,
5489 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
5492 Xbug_n, TRUE, FALSE,
5496 Xbug_e, TRUE, FALSE,
5497 EL_BUG_RIGHT, -1, -1
5500 Xbug_s, TRUE, FALSE,
5504 Xbug_w, TRUE, FALSE,
5508 Xbug_gon, FALSE, FALSE,
5512 Xbug_goe, FALSE, FALSE,
5513 EL_BUG_RIGHT, -1, -1
5516 Xbug_gos, FALSE, FALSE,
5520 Xbug_gow, FALSE, FALSE,
5524 Ybug_n, FALSE, FALSE,
5525 EL_BUG, ACTION_MOVING, MV_BIT_UP
5528 Ybug_nB, FALSE, TRUE,
5529 EL_BUG, ACTION_MOVING, MV_BIT_UP
5532 Ybug_e, FALSE, FALSE,
5533 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
5536 Ybug_eB, FALSE, TRUE,
5537 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
5540 Ybug_s, FALSE, FALSE,
5541 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
5544 Ybug_sB, FALSE, TRUE,
5545 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
5548 Ybug_w, FALSE, FALSE,
5549 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
5552 Ybug_wB, FALSE, TRUE,
5553 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
5556 Ybug_w_n, FALSE, FALSE,
5557 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
5560 Ybug_n_e, FALSE, FALSE,
5561 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
5564 Ybug_e_s, FALSE, FALSE,
5565 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
5568 Ybug_s_w, FALSE, FALSE,
5569 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
5572 Ybug_e_n, FALSE, FALSE,
5573 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
5576 Ybug_s_e, FALSE, FALSE,
5577 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
5580 Ybug_w_s, FALSE, FALSE,
5581 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
5584 Ybug_n_w, FALSE, FALSE,
5585 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
5588 Ybug_stone, FALSE, FALSE,
5589 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
5592 Ybug_spring, FALSE, FALSE,
5593 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
5596 Xtank_n, TRUE, FALSE,
5597 EL_SPACESHIP_UP, -1, -1
5600 Xtank_e, TRUE, FALSE,
5601 EL_SPACESHIP_RIGHT, -1, -1
5604 Xtank_s, TRUE, FALSE,
5605 EL_SPACESHIP_DOWN, -1, -1
5608 Xtank_w, TRUE, FALSE,
5609 EL_SPACESHIP_LEFT, -1, -1
5612 Xtank_gon, FALSE, FALSE,
5613 EL_SPACESHIP_UP, -1, -1
5616 Xtank_goe, FALSE, FALSE,
5617 EL_SPACESHIP_RIGHT, -1, -1
5620 Xtank_gos, FALSE, FALSE,
5621 EL_SPACESHIP_DOWN, -1, -1
5624 Xtank_gow, FALSE, FALSE,
5625 EL_SPACESHIP_LEFT, -1, -1
5628 Ytank_n, FALSE, FALSE,
5629 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
5632 Ytank_nB, FALSE, TRUE,
5633 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
5636 Ytank_e, FALSE, FALSE,
5637 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
5640 Ytank_eB, FALSE, TRUE,
5641 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
5644 Ytank_s, FALSE, FALSE,
5645 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
5648 Ytank_sB, FALSE, TRUE,
5649 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
5652 Ytank_w, FALSE, FALSE,
5653 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
5656 Ytank_wB, FALSE, TRUE,
5657 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
5660 Ytank_w_n, FALSE, FALSE,
5661 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
5664 Ytank_n_e, FALSE, FALSE,
5665 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
5668 Ytank_e_s, FALSE, FALSE,
5669 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
5672 Ytank_s_w, FALSE, FALSE,
5673 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
5676 Ytank_e_n, FALSE, FALSE,
5677 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
5680 Ytank_s_e, FALSE, FALSE,
5681 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
5684 Ytank_w_s, FALSE, FALSE,
5685 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
5688 Ytank_n_w, FALSE, FALSE,
5689 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
5692 Ytank_stone, FALSE, FALSE,
5693 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
5696 Ytank_spring, FALSE, FALSE,
5697 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
5700 Xandroid, TRUE, FALSE,
5701 EL_EMC_ANDROID, ACTION_ACTIVE, -1
5704 Xandroid_1_n, FALSE, FALSE,
5705 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
5708 Xandroid_2_n, FALSE, FALSE,
5709 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
5712 Xandroid_1_e, FALSE, FALSE,
5713 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
5716 Xandroid_2_e, FALSE, FALSE,
5717 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
5720 Xandroid_1_w, FALSE, FALSE,
5721 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
5724 Xandroid_2_w, FALSE, FALSE,
5725 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
5728 Xandroid_1_s, FALSE, FALSE,
5729 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
5732 Xandroid_2_s, FALSE, FALSE,
5733 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
5736 Yandroid_n, FALSE, FALSE,
5737 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
5740 Yandroid_nB, FALSE, TRUE,
5741 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
5744 Yandroid_ne, FALSE, FALSE,
5745 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
5748 Yandroid_neB, FALSE, TRUE,
5749 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
5752 Yandroid_e, FALSE, FALSE,
5753 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
5756 Yandroid_eB, FALSE, TRUE,
5757 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
5760 Yandroid_se, FALSE, FALSE,
5761 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
5764 Yandroid_seB, FALSE, TRUE,
5765 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
5768 Yandroid_s, FALSE, FALSE,
5769 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
5772 Yandroid_sB, FALSE, TRUE,
5773 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
5776 Yandroid_sw, FALSE, FALSE,
5777 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
5780 Yandroid_swB, FALSE, TRUE,
5781 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
5784 Yandroid_w, FALSE, FALSE,
5785 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
5788 Yandroid_wB, FALSE, TRUE,
5789 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
5792 Yandroid_nw, FALSE, FALSE,
5793 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
5796 Yandroid_nwB, FALSE, TRUE,
5797 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
5800 Xspring, TRUE, FALSE,
5804 Xspring_pause, FALSE, FALSE,
5808 Xspring_e, FALSE, FALSE,
5812 Xspring_w, FALSE, FALSE,
5816 Xspring_fall, FALSE, FALSE,
5820 Yspring_s, FALSE, FALSE,
5821 EL_SPRING, ACTION_FALLING, -1
5824 Yspring_sB, FALSE, TRUE,
5825 EL_SPRING, ACTION_FALLING, -1
5828 Yspring_e, FALSE, FALSE,
5829 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
5832 Yspring_eB, FALSE, TRUE,
5833 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
5836 Yspring_w, FALSE, FALSE,
5837 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
5840 Yspring_wB, FALSE, TRUE,
5841 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
5844 Yspring_kill_e, FALSE, FALSE,
5845 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
5848 Yspring_kill_eB, FALSE, TRUE,
5849 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
5852 Yspring_kill_w, FALSE, FALSE,
5853 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
5856 Yspring_kill_wB, FALSE, TRUE,
5857 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
5860 Xeater_n, TRUE, FALSE,
5861 EL_YAMYAM_UP, -1, -1
5864 Xeater_e, TRUE, FALSE,
5865 EL_YAMYAM_RIGHT, -1, -1
5868 Xeater_w, TRUE, FALSE,
5869 EL_YAMYAM_LEFT, -1, -1
5872 Xeater_s, TRUE, FALSE,
5873 EL_YAMYAM_DOWN, -1, -1
5876 Yeater_n, FALSE, FALSE,
5877 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
5880 Yeater_nB, FALSE, TRUE,
5881 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
5884 Yeater_e, FALSE, FALSE,
5885 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
5888 Yeater_eB, FALSE, TRUE,
5889 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
5892 Yeater_s, FALSE, FALSE,
5893 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
5896 Yeater_sB, FALSE, TRUE,
5897 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
5900 Yeater_w, FALSE, FALSE,
5901 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
5904 Yeater_wB, FALSE, TRUE,
5905 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
5908 Yeater_stone, FALSE, FALSE,
5909 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
5912 Yeater_spring, FALSE, FALSE,
5913 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
5916 Xalien, TRUE, FALSE,
5920 Xalien_pause, FALSE, FALSE,
5924 Yalien_n, FALSE, FALSE,
5925 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
5928 Yalien_nB, FALSE, TRUE,
5929 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
5932 Yalien_e, FALSE, FALSE,
5933 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
5936 Yalien_eB, FALSE, TRUE,
5937 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
5940 Yalien_s, FALSE, FALSE,
5941 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
5944 Yalien_sB, FALSE, TRUE,
5945 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
5948 Yalien_w, FALSE, FALSE,
5949 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
5952 Yalien_wB, FALSE, TRUE,
5953 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
5956 Yalien_stone, FALSE, FALSE,
5957 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
5960 Yalien_spring, FALSE, FALSE,
5961 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
5964 Xemerald, TRUE, FALSE,
5968 Xemerald_pause, FALSE, FALSE,
5972 Xemerald_fall, FALSE, FALSE,
5976 Xemerald_shine, FALSE, FALSE,
5977 EL_EMERALD, ACTION_TWINKLING, -1
5980 Yemerald_s, FALSE, FALSE,
5981 EL_EMERALD, ACTION_FALLING, -1
5984 Yemerald_sB, FALSE, TRUE,
5985 EL_EMERALD, ACTION_FALLING, -1
5988 Yemerald_e, FALSE, FALSE,
5989 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
5992 Yemerald_eB, FALSE, TRUE,
5993 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
5996 Yemerald_w, FALSE, FALSE,
5997 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
6000 Yemerald_wB, FALSE, TRUE,
6001 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
6004 Yemerald_eat, FALSE, FALSE,
6005 EL_EMERALD, ACTION_COLLECTING, -1
6008 Yemerald_stone, FALSE, FALSE,
6009 EL_NUT, ACTION_BREAKING, -1
6012 Xdiamond, TRUE, FALSE,
6016 Xdiamond_pause, FALSE, FALSE,
6020 Xdiamond_fall, FALSE, FALSE,
6024 Xdiamond_shine, FALSE, FALSE,
6025 EL_DIAMOND, ACTION_TWINKLING, -1
6028 Ydiamond_s, FALSE, FALSE,
6029 EL_DIAMOND, ACTION_FALLING, -1
6032 Ydiamond_sB, FALSE, TRUE,
6033 EL_DIAMOND, ACTION_FALLING, -1
6036 Ydiamond_e, FALSE, FALSE,
6037 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
6040 Ydiamond_eB, FALSE, TRUE,
6041 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
6044 Ydiamond_w, FALSE, FALSE,
6045 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
6048 Ydiamond_wB, FALSE, TRUE,
6049 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
6052 Ydiamond_eat, FALSE, FALSE,
6053 EL_DIAMOND, ACTION_COLLECTING, -1
6056 Ydiamond_stone, FALSE, FALSE,
6057 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
6060 Xdrip_fall, TRUE, FALSE,
6061 EL_AMOEBA_DROP, -1, -1
6064 Xdrip_stretch, FALSE, FALSE,
6065 EL_AMOEBA_DROP, ACTION_FALLING, -1
6068 Xdrip_stretchB, FALSE, TRUE,
6069 EL_AMOEBA_DROP, ACTION_FALLING, -1
6072 Xdrip_eat, FALSE, FALSE,
6073 EL_AMOEBA_DROP, ACTION_GROWING, -1
6076 Ydrip_s1, FALSE, FALSE,
6077 EL_AMOEBA_DROP, ACTION_FALLING, -1
6080 Ydrip_s1B, FALSE, TRUE,
6081 EL_AMOEBA_DROP, ACTION_FALLING, -1
6084 Ydrip_s2, FALSE, FALSE,
6085 EL_AMOEBA_DROP, ACTION_FALLING, -1
6088 Ydrip_s2B, FALSE, TRUE,
6089 EL_AMOEBA_DROP, ACTION_FALLING, -1
6096 Xbomb_pause, FALSE, FALSE,
6100 Xbomb_fall, FALSE, FALSE,
6104 Ybomb_s, FALSE, FALSE,
6105 EL_BOMB, ACTION_FALLING, -1
6108 Ybomb_sB, FALSE, TRUE,
6109 EL_BOMB, ACTION_FALLING, -1
6112 Ybomb_e, FALSE, FALSE,
6113 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
6116 Ybomb_eB, FALSE, TRUE,
6117 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
6120 Ybomb_w, FALSE, FALSE,
6121 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
6124 Ybomb_wB, FALSE, TRUE,
6125 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
6128 Ybomb_eat, FALSE, FALSE,
6129 EL_BOMB, ACTION_ACTIVATING, -1
6132 Xballoon, TRUE, FALSE,
6136 Yballoon_n, FALSE, FALSE,
6137 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
6140 Yballoon_nB, FALSE, TRUE,
6141 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
6144 Yballoon_e, FALSE, FALSE,
6145 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
6148 Yballoon_eB, FALSE, TRUE,
6149 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
6152 Yballoon_s, FALSE, FALSE,
6153 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
6156 Yballoon_sB, FALSE, TRUE,
6157 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
6160 Yballoon_w, FALSE, FALSE,
6161 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
6164 Yballoon_wB, FALSE, TRUE,
6165 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
6168 Xgrass, TRUE, FALSE,
6169 EL_EMC_GRASS, -1, -1
6172 Ygrass_nB, FALSE, FALSE,
6173 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
6176 Ygrass_eB, FALSE, FALSE,
6177 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
6180 Ygrass_sB, FALSE, FALSE,
6181 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
6184 Ygrass_wB, FALSE, FALSE,
6185 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
6192 Ydirt_nB, FALSE, FALSE,
6193 EL_SAND, ACTION_DIGGING, MV_BIT_UP
6196 Ydirt_eB, FALSE, FALSE,
6197 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
6200 Ydirt_sB, FALSE, FALSE,
6201 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
6204 Ydirt_wB, FALSE, FALSE,
6205 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
6208 Xacid_ne, TRUE, FALSE,
6209 EL_ACID_POOL_TOPRIGHT, -1, -1
6212 Xacid_se, TRUE, FALSE,
6213 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
6216 Xacid_s, TRUE, FALSE,
6217 EL_ACID_POOL_BOTTOM, -1, -1
6220 Xacid_sw, TRUE, FALSE,
6221 EL_ACID_POOL_BOTTOMLEFT, -1, -1
6224 Xacid_nw, TRUE, FALSE,
6225 EL_ACID_POOL_TOPLEFT, -1, -1
6228 Xacid_1, TRUE, FALSE,
6232 Xacid_2, FALSE, FALSE,
6236 Xacid_3, FALSE, FALSE,
6240 Xacid_4, FALSE, FALSE,
6244 Xacid_5, FALSE, FALSE,
6248 Xacid_6, FALSE, FALSE,
6252 Xacid_7, FALSE, FALSE,
6256 Xacid_8, FALSE, FALSE,
6260 Xball_1, TRUE, FALSE,
6261 EL_EMC_MAGIC_BALL, -1, -1
6264 Xball_1B, FALSE, FALSE,
6265 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
6268 Xball_2, FALSE, FALSE,
6269 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
6272 Xball_2B, FALSE, FALSE,
6273 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
6276 Yball_eat, FALSE, FALSE,
6277 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
6280 Ykey_1_eat, FALSE, FALSE,
6281 EL_EM_KEY_1, ACTION_COLLECTING, -1
6284 Ykey_2_eat, FALSE, FALSE,
6285 EL_EM_KEY_2, ACTION_COLLECTING, -1
6288 Ykey_3_eat, FALSE, FALSE,
6289 EL_EM_KEY_3, ACTION_COLLECTING, -1
6292 Ykey_4_eat, FALSE, FALSE,
6293 EL_EM_KEY_4, ACTION_COLLECTING, -1
6296 Ykey_5_eat, FALSE, FALSE,
6297 EL_EMC_KEY_5, ACTION_COLLECTING, -1
6300 Ykey_6_eat, FALSE, FALSE,
6301 EL_EMC_KEY_6, ACTION_COLLECTING, -1
6304 Ykey_7_eat, FALSE, FALSE,
6305 EL_EMC_KEY_7, ACTION_COLLECTING, -1
6308 Ykey_8_eat, FALSE, FALSE,
6309 EL_EMC_KEY_8, ACTION_COLLECTING, -1
6312 Ylenses_eat, FALSE, FALSE,
6313 EL_EMC_LENSES, ACTION_COLLECTING, -1
6316 Ymagnify_eat, FALSE, FALSE,
6317 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
6320 Ygrass_eat, FALSE, FALSE,
6321 EL_EMC_GRASS, ACTION_SNAPPING, -1
6324 Ydirt_eat, FALSE, FALSE,
6325 EL_SAND, ACTION_SNAPPING, -1
6328 Xgrow_ns, TRUE, FALSE,
6329 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
6332 Ygrow_ns_eat, FALSE, FALSE,
6333 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
6336 Xgrow_ew, TRUE, FALSE,
6337 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
6340 Ygrow_ew_eat, FALSE, FALSE,
6341 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
6344 Xwonderwall, TRUE, FALSE,
6345 EL_MAGIC_WALL, -1, -1
6348 XwonderwallB, FALSE, FALSE,
6349 EL_MAGIC_WALL, ACTION_ACTIVE, -1
6352 Xamoeba_1, TRUE, FALSE,
6353 EL_AMOEBA_DRY, ACTION_OTHER, -1
6356 Xamoeba_2, FALSE, FALSE,
6357 EL_AMOEBA_DRY, ACTION_OTHER, -1
6360 Xamoeba_3, FALSE, FALSE,
6361 EL_AMOEBA_DRY, ACTION_OTHER, -1
6364 Xamoeba_4, FALSE, FALSE,
6365 EL_AMOEBA_DRY, ACTION_OTHER, -1
6368 Xamoeba_5, TRUE, FALSE,
6369 EL_AMOEBA_WET, ACTION_OTHER, -1
6372 Xamoeba_6, FALSE, FALSE,
6373 EL_AMOEBA_WET, ACTION_OTHER, -1
6376 Xamoeba_7, FALSE, FALSE,
6377 EL_AMOEBA_WET, ACTION_OTHER, -1
6380 Xamoeba_8, FALSE, FALSE,
6381 EL_AMOEBA_WET, ACTION_OTHER, -1
6384 Xdoor_1, TRUE, FALSE,
6385 EL_EM_GATE_1, -1, -1
6388 Xdoor_2, TRUE, FALSE,
6389 EL_EM_GATE_2, -1, -1
6392 Xdoor_3, TRUE, FALSE,
6393 EL_EM_GATE_3, -1, -1
6396 Xdoor_4, TRUE, FALSE,
6397 EL_EM_GATE_4, -1, -1
6400 Xdoor_5, TRUE, FALSE,
6401 EL_EMC_GATE_5, -1, -1
6404 Xdoor_6, TRUE, FALSE,
6405 EL_EMC_GATE_6, -1, -1
6408 Xdoor_7, TRUE, FALSE,
6409 EL_EMC_GATE_7, -1, -1
6412 Xdoor_8, TRUE, FALSE,
6413 EL_EMC_GATE_8, -1, -1
6416 Xkey_1, TRUE, FALSE,
6420 Xkey_2, TRUE, FALSE,
6424 Xkey_3, TRUE, FALSE,
6428 Xkey_4, TRUE, FALSE,
6432 Xkey_5, TRUE, FALSE,
6433 EL_EMC_KEY_5, -1, -1
6436 Xkey_6, TRUE, FALSE,
6437 EL_EMC_KEY_6, -1, -1
6440 Xkey_7, TRUE, FALSE,
6441 EL_EMC_KEY_7, -1, -1
6444 Xkey_8, TRUE, FALSE,
6445 EL_EMC_KEY_8, -1, -1
6448 Xwind_n, TRUE, FALSE,
6449 EL_BALLOON_SWITCH_UP, -1, -1
6452 Xwind_e, TRUE, FALSE,
6453 EL_BALLOON_SWITCH_RIGHT, -1, -1
6456 Xwind_s, TRUE, FALSE,
6457 EL_BALLOON_SWITCH_DOWN, -1, -1
6460 Xwind_w, TRUE, FALSE,
6461 EL_BALLOON_SWITCH_LEFT, -1, -1
6464 Xwind_nesw, TRUE, FALSE,
6465 EL_BALLOON_SWITCH_ANY, -1, -1
6468 Xwind_stop, TRUE, FALSE,
6469 EL_BALLOON_SWITCH_NONE, -1, -1
6473 EL_EM_EXIT_CLOSED, -1, -1
6476 Xexit_1, TRUE, FALSE,
6477 EL_EM_EXIT_OPEN, -1, -1
6480 Xexit_2, FALSE, FALSE,
6481 EL_EM_EXIT_OPEN, -1, -1
6484 Xexit_3, FALSE, FALSE,
6485 EL_EM_EXIT_OPEN, -1, -1
6488 Xdynamite, TRUE, FALSE,
6489 EL_EM_DYNAMITE, -1, -1
6492 Ydynamite_eat, FALSE, FALSE,
6493 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
6496 Xdynamite_1, TRUE, FALSE,
6497 EL_EM_DYNAMITE_ACTIVE, -1, -1
6500 Xdynamite_2, FALSE, FALSE,
6501 EL_EM_DYNAMITE_ACTIVE, -1, -1
6504 Xdynamite_3, FALSE, FALSE,
6505 EL_EM_DYNAMITE_ACTIVE, -1, -1
6508 Xdynamite_4, FALSE, FALSE,
6509 EL_EM_DYNAMITE_ACTIVE, -1, -1
6512 Xbumper, TRUE, FALSE,
6513 EL_EMC_SPRING_BUMPER, -1, -1
6516 XbumperB, FALSE, FALSE,
6517 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
6520 Xwheel, TRUE, FALSE,
6521 EL_ROBOT_WHEEL, -1, -1
6524 XwheelB, FALSE, FALSE,
6525 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
6528 Xswitch, TRUE, FALSE,
6529 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
6532 XswitchB, FALSE, FALSE,
6533 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
6537 EL_QUICKSAND_EMPTY, -1, -1
6540 Xsand_stone, TRUE, FALSE,
6541 EL_QUICKSAND_FULL, -1, -1
6544 Xsand_stonein_1, FALSE, TRUE,
6545 EL_ROCK, ACTION_FILLING, -1
6548 Xsand_stonein_2, FALSE, TRUE,
6549 EL_ROCK, ACTION_FILLING, -1
6552 Xsand_stonein_3, FALSE, TRUE,
6553 EL_ROCK, ACTION_FILLING, -1
6556 Xsand_stonein_4, FALSE, TRUE,
6557 EL_ROCK, ACTION_FILLING, -1
6560 Xsand_stonesand_1, FALSE, FALSE,
6561 EL_QUICKSAND_EMPTYING, -1, -1
6564 Xsand_stonesand_2, FALSE, FALSE,
6565 EL_QUICKSAND_EMPTYING, -1, -1
6568 Xsand_stonesand_3, FALSE, FALSE,
6569 EL_QUICKSAND_EMPTYING, -1, -1
6572 Xsand_stonesand_4, FALSE, FALSE,
6573 EL_QUICKSAND_EMPTYING, -1, -1
6576 Xsand_stonesand_quickout_1, FALSE, FALSE,
6577 EL_QUICKSAND_EMPTYING, -1, -1
6580 Xsand_stonesand_quickout_2, FALSE, FALSE,
6581 EL_QUICKSAND_EMPTYING, -1, -1
6584 Xsand_stoneout_1, FALSE, FALSE,
6585 EL_ROCK, ACTION_EMPTYING, -1
6588 Xsand_stoneout_2, FALSE, FALSE,
6589 EL_ROCK, ACTION_EMPTYING, -1
6592 Xsand_sandstone_1, FALSE, FALSE,
6593 EL_QUICKSAND_FILLING, -1, -1
6596 Xsand_sandstone_2, FALSE, FALSE,
6597 EL_QUICKSAND_FILLING, -1, -1
6600 Xsand_sandstone_3, FALSE, FALSE,
6601 EL_QUICKSAND_FILLING, -1, -1
6604 Xsand_sandstone_4, FALSE, FALSE,
6605 EL_QUICKSAND_FILLING, -1, -1
6608 Xplant, TRUE, FALSE,
6609 EL_EMC_PLANT, -1, -1
6612 Yplant, FALSE, FALSE,
6613 EL_EMC_PLANT, -1, -1
6616 Xlenses, TRUE, FALSE,
6617 EL_EMC_LENSES, -1, -1
6620 Xmagnify, TRUE, FALSE,
6621 EL_EMC_MAGNIFIER, -1, -1
6624 Xdripper, TRUE, FALSE,
6625 EL_EMC_DRIPPER, -1, -1
6628 XdripperB, FALSE, FALSE,
6629 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
6632 Xfake_blank, TRUE, FALSE,
6633 EL_INVISIBLE_WALL, -1, -1
6636 Xfake_blankB, FALSE, FALSE,
6637 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
6640 Xfake_grass, TRUE, FALSE,
6641 EL_EMC_FAKE_GRASS, -1, -1
6644 Xfake_grassB, FALSE, FALSE,
6645 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
6648 Xfake_door_1, TRUE, FALSE,
6649 EL_EM_GATE_1_GRAY, -1, -1
6652 Xfake_door_2, TRUE, FALSE,
6653 EL_EM_GATE_2_GRAY, -1, -1
6656 Xfake_door_3, TRUE, FALSE,
6657 EL_EM_GATE_3_GRAY, -1, -1
6660 Xfake_door_4, TRUE, FALSE,
6661 EL_EM_GATE_4_GRAY, -1, -1
6664 Xfake_door_5, TRUE, FALSE,
6665 EL_EMC_GATE_5_GRAY, -1, -1
6668 Xfake_door_6, TRUE, FALSE,
6669 EL_EMC_GATE_6_GRAY, -1, -1
6672 Xfake_door_7, TRUE, FALSE,
6673 EL_EMC_GATE_7_GRAY, -1, -1
6676 Xfake_door_8, TRUE, FALSE,
6677 EL_EMC_GATE_8_GRAY, -1, -1
6680 Xfake_acid_1, TRUE, FALSE,
6681 EL_EMC_FAKE_ACID, -1, -1
6684 Xfake_acid_2, FALSE, FALSE,
6685 EL_EMC_FAKE_ACID, -1, -1
6688 Xfake_acid_3, FALSE, FALSE,
6689 EL_EMC_FAKE_ACID, -1, -1
6692 Xfake_acid_4, FALSE, FALSE,
6693 EL_EMC_FAKE_ACID, -1, -1
6696 Xfake_acid_5, FALSE, FALSE,
6697 EL_EMC_FAKE_ACID, -1, -1
6700 Xfake_acid_6, FALSE, FALSE,
6701 EL_EMC_FAKE_ACID, -1, -1
6704 Xfake_acid_7, FALSE, FALSE,
6705 EL_EMC_FAKE_ACID, -1, -1
6708 Xfake_acid_8, FALSE, FALSE,
6709 EL_EMC_FAKE_ACID, -1, -1
6712 Xsteel_1, TRUE, FALSE,
6713 EL_STEELWALL, -1, -1
6716 Xsteel_2, TRUE, FALSE,
6717 EL_EMC_STEELWALL_2, -1, -1
6720 Xsteel_3, TRUE, FALSE,
6721 EL_EMC_STEELWALL_3, -1, -1
6724 Xsteel_4, TRUE, FALSE,
6725 EL_EMC_STEELWALL_4, -1, -1
6728 Xwall_1, TRUE, FALSE,
6732 Xwall_2, TRUE, FALSE,
6733 EL_EMC_WALL_14, -1, -1
6736 Xwall_3, TRUE, FALSE,
6737 EL_EMC_WALL_15, -1, -1
6740 Xwall_4, TRUE, FALSE,
6741 EL_EMC_WALL_16, -1, -1
6744 Xround_wall_1, TRUE, FALSE,
6745 EL_WALL_SLIPPERY, -1, -1
6748 Xround_wall_2, TRUE, FALSE,
6749 EL_EMC_WALL_SLIPPERY_2, -1, -1
6752 Xround_wall_3, TRUE, FALSE,
6753 EL_EMC_WALL_SLIPPERY_3, -1, -1
6756 Xround_wall_4, TRUE, FALSE,
6757 EL_EMC_WALL_SLIPPERY_4, -1, -1
6760 Xdecor_1, TRUE, FALSE,
6761 EL_EMC_WALL_8, -1, -1
6764 Xdecor_2, TRUE, FALSE,
6765 EL_EMC_WALL_6, -1, -1
6768 Xdecor_3, TRUE, FALSE,
6769 EL_EMC_WALL_4, -1, -1
6772 Xdecor_4, TRUE, FALSE,
6773 EL_EMC_WALL_7, -1, -1
6776 Xdecor_5, TRUE, FALSE,
6777 EL_EMC_WALL_5, -1, -1
6780 Xdecor_6, TRUE, FALSE,
6781 EL_EMC_WALL_9, -1, -1
6784 Xdecor_7, TRUE, FALSE,
6785 EL_EMC_WALL_10, -1, -1
6788 Xdecor_8, TRUE, FALSE,
6789 EL_EMC_WALL_1, -1, -1
6792 Xdecor_9, TRUE, FALSE,
6793 EL_EMC_WALL_2, -1, -1
6796 Xdecor_10, TRUE, FALSE,
6797 EL_EMC_WALL_3, -1, -1
6800 Xdecor_11, TRUE, FALSE,
6801 EL_EMC_WALL_11, -1, -1
6804 Xdecor_12, TRUE, FALSE,
6805 EL_EMC_WALL_12, -1, -1
6808 Xalpha_0, TRUE, FALSE,
6809 EL_CHAR('0'), -1, -1
6812 Xalpha_1, TRUE, FALSE,
6813 EL_CHAR('1'), -1, -1
6816 Xalpha_2, TRUE, FALSE,
6817 EL_CHAR('2'), -1, -1
6820 Xalpha_3, TRUE, FALSE,
6821 EL_CHAR('3'), -1, -1
6824 Xalpha_4, TRUE, FALSE,
6825 EL_CHAR('4'), -1, -1
6828 Xalpha_5, TRUE, FALSE,
6829 EL_CHAR('5'), -1, -1
6832 Xalpha_6, TRUE, FALSE,
6833 EL_CHAR('6'), -1, -1
6836 Xalpha_7, TRUE, FALSE,
6837 EL_CHAR('7'), -1, -1
6840 Xalpha_8, TRUE, FALSE,
6841 EL_CHAR('8'), -1, -1
6844 Xalpha_9, TRUE, FALSE,
6845 EL_CHAR('9'), -1, -1
6848 Xalpha_excla, TRUE, FALSE,
6849 EL_CHAR('!'), -1, -1
6852 Xalpha_quote, TRUE, FALSE,
6853 EL_CHAR('"'), -1, -1
6856 Xalpha_comma, TRUE, FALSE,
6857 EL_CHAR(','), -1, -1
6860 Xalpha_minus, TRUE, FALSE,
6861 EL_CHAR('-'), -1, -1
6864 Xalpha_perio, TRUE, FALSE,
6865 EL_CHAR('.'), -1, -1
6868 Xalpha_colon, TRUE, FALSE,
6869 EL_CHAR(':'), -1, -1
6872 Xalpha_quest, TRUE, FALSE,
6873 EL_CHAR('?'), -1, -1
6876 Xalpha_a, TRUE, FALSE,
6877 EL_CHAR('A'), -1, -1
6880 Xalpha_b, TRUE, FALSE,
6881 EL_CHAR('B'), -1, -1
6884 Xalpha_c, TRUE, FALSE,
6885 EL_CHAR('C'), -1, -1
6888 Xalpha_d, TRUE, FALSE,
6889 EL_CHAR('D'), -1, -1
6892 Xalpha_e, TRUE, FALSE,
6893 EL_CHAR('E'), -1, -1
6896 Xalpha_f, TRUE, FALSE,
6897 EL_CHAR('F'), -1, -1
6900 Xalpha_g, TRUE, FALSE,
6901 EL_CHAR('G'), -1, -1
6904 Xalpha_h, TRUE, FALSE,
6905 EL_CHAR('H'), -1, -1
6908 Xalpha_i, TRUE, FALSE,
6909 EL_CHAR('I'), -1, -1
6912 Xalpha_j, TRUE, FALSE,
6913 EL_CHAR('J'), -1, -1
6916 Xalpha_k, TRUE, FALSE,
6917 EL_CHAR('K'), -1, -1
6920 Xalpha_l, TRUE, FALSE,
6921 EL_CHAR('L'), -1, -1
6924 Xalpha_m, TRUE, FALSE,
6925 EL_CHAR('M'), -1, -1
6928 Xalpha_n, TRUE, FALSE,
6929 EL_CHAR('N'), -1, -1
6932 Xalpha_o, TRUE, FALSE,
6933 EL_CHAR('O'), -1, -1
6936 Xalpha_p, TRUE, FALSE,
6937 EL_CHAR('P'), -1, -1
6940 Xalpha_q, TRUE, FALSE,
6941 EL_CHAR('Q'), -1, -1
6944 Xalpha_r, TRUE, FALSE,
6945 EL_CHAR('R'), -1, -1
6948 Xalpha_s, TRUE, FALSE,
6949 EL_CHAR('S'), -1, -1
6952 Xalpha_t, TRUE, FALSE,
6953 EL_CHAR('T'), -1, -1
6956 Xalpha_u, TRUE, FALSE,
6957 EL_CHAR('U'), -1, -1
6960 Xalpha_v, TRUE, FALSE,
6961 EL_CHAR('V'), -1, -1
6964 Xalpha_w, TRUE, FALSE,
6965 EL_CHAR('W'), -1, -1
6968 Xalpha_x, TRUE, FALSE,
6969 EL_CHAR('X'), -1, -1
6972 Xalpha_y, TRUE, FALSE,
6973 EL_CHAR('Y'), -1, -1
6976 Xalpha_z, TRUE, FALSE,
6977 EL_CHAR('Z'), -1, -1
6980 Xalpha_arrow_e, TRUE, FALSE,
6981 EL_CHAR('>'), -1, -1
6984 Xalpha_arrow_w, TRUE, FALSE,
6985 EL_CHAR('<'), -1, -1
6988 Xalpha_copyr, TRUE, FALSE,
6989 EL_CHAR(CHAR_BYTE_COPYRIGHT), -1, -1
6993 Xboom_bug, FALSE, FALSE,
6994 EL_BUG, ACTION_EXPLODING, -1
6997 Xboom_bomb, FALSE, FALSE,
6998 EL_BOMB, ACTION_EXPLODING, -1
7001 Xboom_android, FALSE, FALSE,
7002 EL_EMC_ANDROID, ACTION_OTHER, -1
7005 Xboom_1, FALSE, FALSE,
7006 EL_DEFAULT, ACTION_EXPLODING, -1
7009 Xboom_2, FALSE, FALSE,
7010 EL_DEFAULT, ACTION_EXPLODING, -1
7013 Znormal, FALSE, FALSE,
7017 Zdynamite, FALSE, FALSE,
7021 Zplayer, FALSE, FALSE,
7025 ZBORDER, FALSE, FALSE,
7035 static struct Mapping_EM_to_RND_player
7044 em_player_mapping_list[] =
7048 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
7052 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
7056 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
7060 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
7064 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
7068 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
7072 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
7076 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
7080 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
7084 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
7088 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
7092 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
7096 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
7100 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
7104 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
7108 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
7112 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
7116 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
7120 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
7124 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
7128 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
7132 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
7136 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
7140 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
7144 EL_PLAYER_1, ACTION_DEFAULT, -1,
7148 EL_PLAYER_2, ACTION_DEFAULT, -1,
7152 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
7156 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
7160 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
7164 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
7168 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
7172 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
7176 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
7180 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
7184 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
7188 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
7192 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
7196 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
7200 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
7204 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
7208 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
7212 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
7216 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
7220 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
7224 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
7228 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
7232 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
7236 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
7240 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
7244 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
7248 EL_PLAYER_3, ACTION_DEFAULT, -1,
7252 EL_PLAYER_4, ACTION_DEFAULT, -1,
7261 int map_element_RND_to_EM(int element_rnd)
7263 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
7264 static boolean mapping_initialized = FALSE;
7266 if (!mapping_initialized)
7270 /* return "Xalpha_quest" for all undefined elements in mapping array */
7271 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
7272 mapping_RND_to_EM[i] = Xalpha_quest;
7274 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
7275 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
7276 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
7277 em_object_mapping_list[i].element_em;
7279 mapping_initialized = TRUE;
7282 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
7283 return mapping_RND_to_EM[element_rnd];
7285 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
7290 int map_element_EM_to_RND(int element_em)
7292 static unsigned short mapping_EM_to_RND[TILE_MAX];
7293 static boolean mapping_initialized = FALSE;
7295 if (!mapping_initialized)
7299 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
7300 for (i = 0; i < TILE_MAX; i++)
7301 mapping_EM_to_RND[i] = EL_UNKNOWN;
7303 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
7304 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
7305 em_object_mapping_list[i].element_rnd;
7307 mapping_initialized = TRUE;
7310 if (element_em >= 0 && element_em < TILE_MAX)
7311 return mapping_EM_to_RND[element_em];
7313 Error(ERR_WARN, "invalid EM level element %d", element_em);
7318 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
7320 struct LevelInfo_EM *level_em = level->native_em_level;
7321 struct LEVEL *lev = level_em->lev;
7324 for (i = 0; i < TILE_MAX; i++)
7325 lev->android_array[i] = Xblank;
7327 for (i = 0; i < level->num_android_clone_elements; i++)
7329 int element_rnd = level->android_clone_element[i];
7330 int element_em = map_element_RND_to_EM(element_rnd);
7332 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
7333 if (em_object_mapping_list[j].element_rnd == element_rnd)
7334 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
7338 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
7340 struct LevelInfo_EM *level_em = level->native_em_level;
7341 struct LEVEL *lev = level_em->lev;
7344 level->num_android_clone_elements = 0;
7346 for (i = 0; i < TILE_MAX; i++)
7348 int element_em = lev->android_array[i];
7350 boolean element_found = FALSE;
7352 if (element_em == Xblank)
7355 element_rnd = map_element_EM_to_RND(element_em);
7357 for (j = 0; j < level->num_android_clone_elements; j++)
7358 if (level->android_clone_element[j] == element_rnd)
7359 element_found = TRUE;
7363 level->android_clone_element[level->num_android_clone_elements++] =
7366 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
7371 if (level->num_android_clone_elements == 0)
7373 level->num_android_clone_elements = 1;
7374 level->android_clone_element[0] = EL_EMPTY;
7378 int map_direction_RND_to_EM(int direction)
7380 return (direction == MV_UP ? 0 :
7381 direction == MV_RIGHT ? 1 :
7382 direction == MV_DOWN ? 2 :
7383 direction == MV_LEFT ? 3 :
7387 int map_direction_EM_to_RND(int direction)
7389 return (direction == 0 ? MV_UP :
7390 direction == 1 ? MV_RIGHT :
7391 direction == 2 ? MV_DOWN :
7392 direction == 3 ? MV_LEFT :
7396 int map_element_RND_to_SP(int element_rnd)
7398 int element_sp = 0x20; /* map unknown elements to yellow "hardware" */
7400 if (element_rnd >= EL_SP_START &&
7401 element_rnd <= EL_SP_END)
7402 element_sp = element_rnd - EL_SP_START;
7403 else if (element_rnd == EL_EMPTY_SPACE)
7405 else if (element_rnd == EL_INVISIBLE_WALL)
7411 int map_element_SP_to_RND(int element_sp)
7413 int element_rnd = EL_UNKNOWN;
7415 if (element_sp >= 0x00 &&
7417 element_rnd = EL_SP_START + element_sp;
7418 else if (element_sp == 0x28)
7419 element_rnd = EL_INVISIBLE_WALL;
7424 int map_action_SP_to_RND(int action_sp)
7428 case actActive: return ACTION_ACTIVE;
7429 case actImpact: return ACTION_IMPACT;
7430 case actExploding: return ACTION_EXPLODING;
7431 case actDigging: return ACTION_DIGGING;
7432 case actSnapping: return ACTION_SNAPPING;
7433 case actCollecting: return ACTION_COLLECTING;
7434 case actPassing: return ACTION_PASSING;
7435 case actPushing: return ACTION_PUSHING;
7436 case actDropping: return ACTION_DROPPING;
7438 default: return ACTION_DEFAULT;
7442 int map_element_RND_to_MM(int element_rnd)
7444 return (element_rnd >= EL_MM_START_1 &&
7445 element_rnd <= EL_MM_END_1 ?
7446 EL_MM_START_1_NATIVE + element_rnd - EL_MM_START_1 :
7448 element_rnd >= EL_MM_START_2 &&
7449 element_rnd <= EL_MM_END_2 ?
7450 EL_MM_START_2_NATIVE + element_rnd - EL_MM_START_2 :
7452 element_rnd >= EL_CHAR_START &&
7453 element_rnd <= EL_CHAR_END ?
7454 EL_MM_CHAR_START_NATIVE + element_rnd - EL_CHAR_START :
7456 element_rnd >= EL_MM_RUNTIME_START &&
7457 element_rnd <= EL_MM_RUNTIME_END ?
7458 EL_MM_RUNTIME_START_NATIVE + element_rnd - EL_MM_RUNTIME_START :
7460 element_rnd >= EL_MM_DUMMY_START &&
7461 element_rnd <= EL_MM_DUMMY_END ?
7462 EL_MM_DUMMY_START_NATIVE + element_rnd - EL_MM_DUMMY_START :
7464 EL_MM_EMPTY_NATIVE);
7467 int map_element_MM_to_RND(int element_mm)
7469 return (element_mm == EL_MM_EMPTY_NATIVE ||
7470 element_mm == EL_DF_EMPTY_NATIVE ?
7473 element_mm >= EL_MM_START_1_NATIVE &&
7474 element_mm <= EL_MM_END_1_NATIVE ?
7475 EL_MM_START_1 + element_mm - EL_MM_START_1_NATIVE :
7477 element_mm >= EL_MM_START_2_NATIVE &&
7478 element_mm <= EL_MM_END_2_NATIVE ?
7479 EL_MM_START_2 + element_mm - EL_MM_START_2_NATIVE :
7481 element_mm >= EL_MM_CHAR_START_NATIVE &&
7482 element_mm <= EL_MM_CHAR_END_NATIVE ?
7483 EL_CHAR_START + element_mm - EL_MM_CHAR_START_NATIVE :
7485 element_mm >= EL_MM_RUNTIME_START_NATIVE &&
7486 element_mm <= EL_MM_RUNTIME_END_NATIVE ?
7487 EL_MM_RUNTIME_START + element_mm - EL_MM_RUNTIME_START_NATIVE :
7489 element_mm >= EL_MM_DUMMY_START_NATIVE &&
7490 element_mm <= EL_MM_DUMMY_END_NATIVE ?
7491 EL_MM_DUMMY_START + element_mm - EL_MM_DUMMY_START_NATIVE :
7496 int map_action_MM_to_RND(int action_mm)
7498 /* all MM actions are defined to exactly match their RND counterparts */
7502 int map_sound_MM_to_RND(int sound_mm)
7506 case SND_MM_GAME_LEVELTIME_CHARGING:
7507 return SND_GAME_LEVELTIME_CHARGING;
7509 case SND_MM_GAME_HEALTH_CHARGING:
7510 return SND_GAME_HEALTH_CHARGING;
7513 return SND_UNDEFINED;
7517 int map_mm_wall_element(int element)
7519 return (element >= EL_MM_STEEL_WALL_START &&
7520 element <= EL_MM_STEEL_WALL_END ?
7523 element >= EL_MM_WOODEN_WALL_START &&
7524 element <= EL_MM_WOODEN_WALL_END ?
7527 element >= EL_MM_ICE_WALL_START &&
7528 element <= EL_MM_ICE_WALL_END ?
7531 element >= EL_MM_AMOEBA_WALL_START &&
7532 element <= EL_MM_AMOEBA_WALL_END ?
7535 element >= EL_DF_STEEL_WALL_START &&
7536 element <= EL_DF_STEEL_WALL_END ?
7539 element >= EL_DF_WOODEN_WALL_START &&
7540 element <= EL_DF_WOODEN_WALL_END ?
7546 int map_mm_wall_element_editor(int element)
7550 case EL_MM_STEEL_WALL: return EL_MM_STEEL_WALL_START;
7551 case EL_MM_WOODEN_WALL: return EL_MM_WOODEN_WALL_START;
7552 case EL_MM_ICE_WALL: return EL_MM_ICE_WALL_START;
7553 case EL_MM_AMOEBA_WALL: return EL_MM_AMOEBA_WALL_START;
7554 case EL_DF_STEEL_WALL: return EL_DF_STEEL_WALL_START;
7555 case EL_DF_WOODEN_WALL: return EL_DF_WOODEN_WALL_START;
7557 default: return element;
7561 int get_next_element(int element)
7565 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
7566 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
7567 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
7568 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
7569 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
7570 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
7571 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
7572 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
7573 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
7574 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
7575 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
7577 default: return element;
7581 int el2img_mm(int element_mm)
7583 return el2img(map_element_MM_to_RND(element_mm));
7586 int el_act_dir2img(int element, int action, int direction)
7588 element = GFX_ELEMENT(element);
7589 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
7591 /* direction_graphic[][] == graphic[] for undefined direction graphics */
7592 return element_info[element].direction_graphic[action][direction];
7595 static int el_act_dir2crm(int element, int action, int direction)
7597 element = GFX_ELEMENT(element);
7598 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
7600 /* direction_graphic[][] == graphic[] for undefined direction graphics */
7601 return element_info[element].direction_crumbled[action][direction];
7604 int el_act2img(int element, int action)
7606 element = GFX_ELEMENT(element);
7608 return element_info[element].graphic[action];
7611 int el_act2crm(int element, int action)
7613 element = GFX_ELEMENT(element);
7615 return element_info[element].crumbled[action];
7618 int el_dir2img(int element, int direction)
7620 element = GFX_ELEMENT(element);
7622 return el_act_dir2img(element, ACTION_DEFAULT, direction);
7625 int el2baseimg(int element)
7627 return element_info[element].graphic[ACTION_DEFAULT];
7630 int el2img(int element)
7632 element = GFX_ELEMENT(element);
7634 return element_info[element].graphic[ACTION_DEFAULT];
7637 int el2edimg(int element)
7639 element = GFX_ELEMENT(element);
7641 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
7644 int el2preimg(int element)
7646 element = GFX_ELEMENT(element);
7648 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
7651 int el2panelimg(int element)
7653 element = GFX_ELEMENT(element);
7655 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL];
7658 int font2baseimg(int font_nr)
7660 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
7663 int getBeltNrFromBeltElement(int element)
7665 return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
7666 element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
7667 element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
7670 int getBeltNrFromBeltActiveElement(int element)
7672 return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
7673 element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
7674 element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
7677 int getBeltNrFromBeltSwitchElement(int element)
7679 return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
7680 element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
7681 element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
7684 int getBeltDirNrFromBeltElement(int element)
7686 static int belt_base_element[4] =
7688 EL_CONVEYOR_BELT_1_LEFT,
7689 EL_CONVEYOR_BELT_2_LEFT,
7690 EL_CONVEYOR_BELT_3_LEFT,
7691 EL_CONVEYOR_BELT_4_LEFT
7694 int belt_nr = getBeltNrFromBeltElement(element);
7695 int belt_dir_nr = element - belt_base_element[belt_nr];
7697 return (belt_dir_nr % 3);
7700 int getBeltDirNrFromBeltSwitchElement(int element)
7702 static int belt_base_element[4] =
7704 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
7705 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
7706 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
7707 EL_CONVEYOR_BELT_4_SWITCH_LEFT
7710 int belt_nr = getBeltNrFromBeltSwitchElement(element);
7711 int belt_dir_nr = element - belt_base_element[belt_nr];
7713 return (belt_dir_nr % 3);
7716 int getBeltDirFromBeltElement(int element)
7718 static int belt_move_dir[3] =
7725 int belt_dir_nr = getBeltDirNrFromBeltElement(element);
7727 return belt_move_dir[belt_dir_nr];
7730 int getBeltDirFromBeltSwitchElement(int element)
7732 static int belt_move_dir[3] =
7739 int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
7741 return belt_move_dir[belt_dir_nr];
7744 int getBeltElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
7746 static int belt_base_element[4] =
7748 EL_CONVEYOR_BELT_1_LEFT,
7749 EL_CONVEYOR_BELT_2_LEFT,
7750 EL_CONVEYOR_BELT_3_LEFT,
7751 EL_CONVEYOR_BELT_4_LEFT
7754 return belt_base_element[belt_nr] + belt_dir_nr;
7757 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
7759 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
7761 return getBeltElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
7764 int getBeltSwitchElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
7766 static int belt_base_element[4] =
7768 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
7769 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
7770 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
7771 EL_CONVEYOR_BELT_4_SWITCH_LEFT
7774 return belt_base_element[belt_nr] + belt_dir_nr;
7777 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
7779 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
7781 return getBeltSwitchElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
7784 boolean getTeamMode_EM()
7786 return game.team_mode;
7789 int getGameFrameDelay_EM(int native_em_game_frame_delay)
7791 int game_frame_delay_value;
7793 game_frame_delay_value =
7794 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
7795 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
7798 if (tape.playing && tape.warp_forward && !tape.pausing)
7799 game_frame_delay_value = 0;
7801 return game_frame_delay_value;
7804 unsigned int InitRND(int seed)
7806 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
7807 return InitEngineRandom_EM(seed);
7808 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
7809 return InitEngineRandom_SP(seed);
7810 else if (level.game_engine_type == GAME_ENGINE_TYPE_MM)
7811 return InitEngineRandom_MM(seed);
7813 return InitEngineRandom_RND(seed);
7816 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
7817 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
7819 inline static int get_effective_element_EM(int tile, int frame_em)
7821 int element = object_mapping[tile].element_rnd;
7822 int action = object_mapping[tile].action;
7823 boolean is_backside = object_mapping[tile].is_backside;
7824 boolean action_removing = (action == ACTION_DIGGING ||
7825 action == ACTION_SNAPPING ||
7826 action == ACTION_COLLECTING);
7832 case Yacid_splash_eB:
7833 case Yacid_splash_wB:
7834 return (frame_em > 5 ? EL_EMPTY : element);
7840 else /* frame_em == 7 */
7844 case Yacid_splash_eB:
7845 case Yacid_splash_wB:
7848 case Yemerald_stone:
7851 case Ydiamond_stone:
7855 case Xdrip_stretchB:
7874 case Xsand_stonein_1:
7875 case Xsand_stonein_2:
7876 case Xsand_stonein_3:
7877 case Xsand_stonein_4:
7881 return (is_backside || action_removing ? EL_EMPTY : element);
7886 inline static boolean check_linear_animation_EM(int tile)
7890 case Xsand_stonesand_1:
7891 case Xsand_stonesand_quickout_1:
7892 case Xsand_sandstone_1:
7893 case Xsand_stonein_1:
7894 case Xsand_stoneout_1:
7913 case Yacid_splash_eB:
7914 case Yacid_splash_wB:
7915 case Yemerald_stone:
7922 inline static void set_crumbled_graphics_EM(struct GraphicInfo_EM *g_em,
7923 boolean has_crumbled_graphics,
7924 int crumbled, int sync_frame)
7926 /* if element can be crumbled, but certain action graphics are just empty
7927 space (like instantly snapping sand to empty space in 1 frame), do not
7928 treat these empty space graphics as crumbled graphics in EMC engine */
7929 if (crumbled == IMG_EMPTY_SPACE)
7930 has_crumbled_graphics = FALSE;
7932 if (has_crumbled_graphics)
7934 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
7935 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
7936 g_crumbled->anim_delay,
7937 g_crumbled->anim_mode,
7938 g_crumbled->anim_start_frame,
7941 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
7942 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
7944 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
7945 g_em->crumbled_tile_size = graphic_info[crumbled].tile_size;
7947 g_em->has_crumbled_graphics = TRUE;
7951 g_em->crumbled_bitmap = NULL;
7952 g_em->crumbled_src_x = 0;
7953 g_em->crumbled_src_y = 0;
7954 g_em->crumbled_border_size = 0;
7955 g_em->crumbled_tile_size = 0;
7957 g_em->has_crumbled_graphics = FALSE;
7961 void ResetGfxAnimation_EM(int x, int y, int tile)
7966 void SetGfxAnimation_EM(struct GraphicInfo_EM *g_em,
7967 int tile, int frame_em, int x, int y)
7969 int action = object_mapping[tile].action;
7970 int direction = object_mapping[tile].direction;
7971 int effective_element = get_effective_element_EM(tile, frame_em);
7972 int graphic = (direction == MV_NONE ?
7973 el_act2img(effective_element, action) :
7974 el_act_dir2img(effective_element, action, direction));
7975 struct GraphicInfo *g = &graphic_info[graphic];
7977 boolean action_removing = (action == ACTION_DIGGING ||
7978 action == ACTION_SNAPPING ||
7979 action == ACTION_COLLECTING);
7980 boolean action_moving = (action == ACTION_FALLING ||
7981 action == ACTION_MOVING ||
7982 action == ACTION_PUSHING ||
7983 action == ACTION_EATING ||
7984 action == ACTION_FILLING ||
7985 action == ACTION_EMPTYING);
7986 boolean action_falling = (action == ACTION_FALLING ||
7987 action == ACTION_FILLING ||
7988 action == ACTION_EMPTYING);
7990 /* special case: graphic uses "2nd movement tile" and has defined
7991 7 frames for movement animation (or less) => use default graphic
7992 for last (8th) frame which ends the movement animation */
7993 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
7995 action = ACTION_DEFAULT; /* (keep action_* unchanged for now) */
7996 graphic = (direction == MV_NONE ?
7997 el_act2img(effective_element, action) :
7998 el_act_dir2img(effective_element, action, direction));
8000 g = &graphic_info[graphic];
8003 if ((action_removing || check_linear_animation_EM(tile)) && frame_em == 0)
8007 else if (action_moving)
8009 boolean is_backside = object_mapping[tile].is_backside;
8013 int direction = object_mapping[tile].direction;
8014 int move_dir = (action_falling ? MV_DOWN : direction);
8019 /* !!! TEST !!! NEW !!! DOES NOT WORK RIGHT YET !!! */
8020 if (g->double_movement && frame_em == 0)
8024 if (move_dir == MV_LEFT)
8025 GfxFrame[x - 1][y] = GfxFrame[x][y];
8026 else if (move_dir == MV_RIGHT)
8027 GfxFrame[x + 1][y] = GfxFrame[x][y];
8028 else if (move_dir == MV_UP)
8029 GfxFrame[x][y - 1] = GfxFrame[x][y];
8030 else if (move_dir == MV_DOWN)
8031 GfxFrame[x][y + 1] = GfxFrame[x][y];
8038 /* special case: animation for Xsand_stonesand_quickout_1/2 twice as fast */
8039 if (tile == Xsand_stonesand_quickout_1 ||
8040 tile == Xsand_stonesand_quickout_2)
8044 if (graphic_info[graphic].anim_global_sync)
8045 sync_frame = FrameCounter;
8046 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
8047 sync_frame = GfxFrame[x][y];
8049 sync_frame = 0; /* playfield border (pseudo steel) */
8051 SetRandomAnimationValue(x, y);
8053 int frame = getAnimationFrame(g->anim_frames,
8056 g->anim_start_frame,
8059 g_em->unique_identifier =
8060 (graphic << 16) | ((frame % 8) << 12) | (g_em->width << 6) | g_em->height;
8063 void getGraphicSourceObjectExt_EM(struct GraphicInfo_EM *g_em,
8064 int tile, int frame_em, int x, int y)
8066 int action = object_mapping[tile].action;
8067 int direction = object_mapping[tile].direction;
8068 boolean is_backside = object_mapping[tile].is_backside;
8069 int effective_element = get_effective_element_EM(tile, frame_em);
8070 int effective_action = action;
8071 int graphic = (direction == MV_NONE ?
8072 el_act2img(effective_element, effective_action) :
8073 el_act_dir2img(effective_element, effective_action,
8075 int crumbled = (direction == MV_NONE ?
8076 el_act2crm(effective_element, effective_action) :
8077 el_act_dir2crm(effective_element, effective_action,
8079 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
8080 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
8081 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
8082 struct GraphicInfo *g = &graphic_info[graphic];
8085 /* special case: graphic uses "2nd movement tile" and has defined
8086 7 frames for movement animation (or less) => use default graphic
8087 for last (8th) frame which ends the movement animation */
8088 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
8090 effective_action = ACTION_DEFAULT;
8091 graphic = (direction == MV_NONE ?
8092 el_act2img(effective_element, effective_action) :
8093 el_act_dir2img(effective_element, effective_action,
8095 crumbled = (direction == MV_NONE ?
8096 el_act2crm(effective_element, effective_action) :
8097 el_act_dir2crm(effective_element, effective_action,
8100 g = &graphic_info[graphic];
8103 if (graphic_info[graphic].anim_global_sync)
8104 sync_frame = FrameCounter;
8105 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
8106 sync_frame = GfxFrame[x][y];
8108 sync_frame = 0; /* playfield border (pseudo steel) */
8110 SetRandomAnimationValue(x, y);
8112 int frame = getAnimationFrame(g->anim_frames,
8115 g->anim_start_frame,
8118 getGraphicSourceExt(graphic, frame, &g_em->bitmap, &g_em->src_x, &g_em->src_y,
8119 g->double_movement && is_backside);
8121 /* (updating the "crumbled" graphic definitions is probably not really needed,
8122 as animations for crumbled graphics can't be longer than one EMC cycle) */
8123 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
8127 void getGraphicSourcePlayerExt_EM(struct GraphicInfo_EM *g_em,
8128 int player_nr, int anim, int frame_em)
8130 int element = player_mapping[player_nr][anim].element_rnd;
8131 int action = player_mapping[player_nr][anim].action;
8132 int direction = player_mapping[player_nr][anim].direction;
8133 int graphic = (direction == MV_NONE ?
8134 el_act2img(element, action) :
8135 el_act_dir2img(element, action, direction));
8136 struct GraphicInfo *g = &graphic_info[graphic];
8139 InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
8141 stored_player[player_nr].StepFrame = frame_em;
8143 sync_frame = stored_player[player_nr].Frame;
8145 int frame = getAnimationFrame(g->anim_frames,
8148 g->anim_start_frame,
8151 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
8152 &g_em->src_x, &g_em->src_y, FALSE);
8155 void InitGraphicInfo_EM(void)
8160 int num_em_gfx_errors = 0;
8162 if (graphic_info_em_object[0][0].bitmap == NULL)
8164 /* EM graphics not yet initialized in em_open_all() */
8169 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
8172 /* always start with reliable default values */
8173 for (i = 0; i < TILE_MAX; i++)
8175 object_mapping[i].element_rnd = EL_UNKNOWN;
8176 object_mapping[i].is_backside = FALSE;
8177 object_mapping[i].action = ACTION_DEFAULT;
8178 object_mapping[i].direction = MV_NONE;
8181 /* always start with reliable default values */
8182 for (p = 0; p < MAX_PLAYERS; p++)
8184 for (i = 0; i < SPR_MAX; i++)
8186 player_mapping[p][i].element_rnd = EL_UNKNOWN;
8187 player_mapping[p][i].action = ACTION_DEFAULT;
8188 player_mapping[p][i].direction = MV_NONE;
8192 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
8194 int e = em_object_mapping_list[i].element_em;
8196 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
8197 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
8199 if (em_object_mapping_list[i].action != -1)
8200 object_mapping[e].action = em_object_mapping_list[i].action;
8202 if (em_object_mapping_list[i].direction != -1)
8203 object_mapping[e].direction =
8204 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
8207 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
8209 int a = em_player_mapping_list[i].action_em;
8210 int p = em_player_mapping_list[i].player_nr;
8212 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
8214 if (em_player_mapping_list[i].action != -1)
8215 player_mapping[p][a].action = em_player_mapping_list[i].action;
8217 if (em_player_mapping_list[i].direction != -1)
8218 player_mapping[p][a].direction =
8219 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
8222 for (i = 0; i < TILE_MAX; i++)
8224 int element = object_mapping[i].element_rnd;
8225 int action = object_mapping[i].action;
8226 int direction = object_mapping[i].direction;
8227 boolean is_backside = object_mapping[i].is_backside;
8228 boolean action_exploding = ((action == ACTION_EXPLODING ||
8229 action == ACTION_SMASHED_BY_ROCK ||
8230 action == ACTION_SMASHED_BY_SPRING) &&
8231 element != EL_DIAMOND);
8232 boolean action_active = (action == ACTION_ACTIVE);
8233 boolean action_other = (action == ACTION_OTHER);
8235 for (j = 0; j < 8; j++)
8237 int effective_element = get_effective_element_EM(i, j);
8238 int effective_action = (j < 7 ? action :
8239 i == Xdrip_stretch ? action :
8240 i == Xdrip_stretchB ? action :
8241 i == Ydrip_s1 ? action :
8242 i == Ydrip_s1B ? action :
8243 i == Xball_1B ? action :
8244 i == Xball_2 ? action :
8245 i == Xball_2B ? action :
8246 i == Yball_eat ? action :
8247 i == Ykey_1_eat ? action :
8248 i == Ykey_2_eat ? action :
8249 i == Ykey_3_eat ? action :
8250 i == Ykey_4_eat ? action :
8251 i == Ykey_5_eat ? action :
8252 i == Ykey_6_eat ? action :
8253 i == Ykey_7_eat ? action :
8254 i == Ykey_8_eat ? action :
8255 i == Ylenses_eat ? action :
8256 i == Ymagnify_eat ? action :
8257 i == Ygrass_eat ? action :
8258 i == Ydirt_eat ? action :
8259 i == Xsand_stonein_1 ? action :
8260 i == Xsand_stonein_2 ? action :
8261 i == Xsand_stonein_3 ? action :
8262 i == Xsand_stonein_4 ? action :
8263 i == Xsand_stoneout_1 ? action :
8264 i == Xsand_stoneout_2 ? action :
8265 i == Xboom_android ? ACTION_EXPLODING :
8266 action_exploding ? ACTION_EXPLODING :
8267 action_active ? action :
8268 action_other ? action :
8270 int graphic = (el_act_dir2img(effective_element, effective_action,
8272 int crumbled = (el_act_dir2crm(effective_element, effective_action,
8274 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
8275 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
8276 boolean has_action_graphics = (graphic != base_graphic);
8277 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
8278 struct GraphicInfo *g = &graphic_info[graphic];
8279 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
8282 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
8283 boolean special_animation = (action != ACTION_DEFAULT &&
8284 g->anim_frames == 3 &&
8285 g->anim_delay == 2 &&
8286 g->anim_mode & ANIM_LINEAR);
8287 int sync_frame = (i == Xdrip_stretch ? 7 :
8288 i == Xdrip_stretchB ? 7 :
8289 i == Ydrip_s2 ? j + 8 :
8290 i == Ydrip_s2B ? j + 8 :
8299 i == Xfake_acid_1 ? 0 :
8300 i == Xfake_acid_2 ? 10 :
8301 i == Xfake_acid_3 ? 20 :
8302 i == Xfake_acid_4 ? 30 :
8303 i == Xfake_acid_5 ? 40 :
8304 i == Xfake_acid_6 ? 50 :
8305 i == Xfake_acid_7 ? 60 :
8306 i == Xfake_acid_8 ? 70 :
8308 i == Xball_2B ? j + 8 :
8309 i == Yball_eat ? j + 1 :
8310 i == Ykey_1_eat ? j + 1 :
8311 i == Ykey_2_eat ? j + 1 :
8312 i == Ykey_3_eat ? j + 1 :
8313 i == Ykey_4_eat ? j + 1 :
8314 i == Ykey_5_eat ? j + 1 :
8315 i == Ykey_6_eat ? j + 1 :
8316 i == Ykey_7_eat ? j + 1 :
8317 i == Ykey_8_eat ? j + 1 :
8318 i == Ylenses_eat ? j + 1 :
8319 i == Ymagnify_eat ? j + 1 :
8320 i == Ygrass_eat ? j + 1 :
8321 i == Ydirt_eat ? j + 1 :
8322 i == Xamoeba_1 ? 0 :
8323 i == Xamoeba_2 ? 1 :
8324 i == Xamoeba_3 ? 2 :
8325 i == Xamoeba_4 ? 3 :
8326 i == Xamoeba_5 ? 0 :
8327 i == Xamoeba_6 ? 1 :
8328 i == Xamoeba_7 ? 2 :
8329 i == Xamoeba_8 ? 3 :
8330 i == Xexit_2 ? j + 8 :
8331 i == Xexit_3 ? j + 16 :
8332 i == Xdynamite_1 ? 0 :
8333 i == Xdynamite_2 ? 8 :
8334 i == Xdynamite_3 ? 16 :
8335 i == Xdynamite_4 ? 24 :
8336 i == Xsand_stonein_1 ? j + 1 :
8337 i == Xsand_stonein_2 ? j + 9 :
8338 i == Xsand_stonein_3 ? j + 17 :
8339 i == Xsand_stonein_4 ? j + 25 :
8340 i == Xsand_stoneout_1 && j == 0 ? 0 :
8341 i == Xsand_stoneout_1 && j == 1 ? 0 :
8342 i == Xsand_stoneout_1 && j == 2 ? 1 :
8343 i == Xsand_stoneout_1 && j == 3 ? 2 :
8344 i == Xsand_stoneout_1 && j == 4 ? 2 :
8345 i == Xsand_stoneout_1 && j == 5 ? 3 :
8346 i == Xsand_stoneout_1 && j == 6 ? 4 :
8347 i == Xsand_stoneout_1 && j == 7 ? 4 :
8348 i == Xsand_stoneout_2 && j == 0 ? 5 :
8349 i == Xsand_stoneout_2 && j == 1 ? 6 :
8350 i == Xsand_stoneout_2 && j == 2 ? 7 :
8351 i == Xsand_stoneout_2 && j == 3 ? 8 :
8352 i == Xsand_stoneout_2 && j == 4 ? 9 :
8353 i == Xsand_stoneout_2 && j == 5 ? 11 :
8354 i == Xsand_stoneout_2 && j == 6 ? 13 :
8355 i == Xsand_stoneout_2 && j == 7 ? 15 :
8356 i == Xboom_bug && j == 1 ? 2 :
8357 i == Xboom_bug && j == 2 ? 2 :
8358 i == Xboom_bug && j == 3 ? 4 :
8359 i == Xboom_bug && j == 4 ? 4 :
8360 i == Xboom_bug && j == 5 ? 2 :
8361 i == Xboom_bug && j == 6 ? 2 :
8362 i == Xboom_bug && j == 7 ? 0 :
8363 i == Xboom_bomb && j == 1 ? 2 :
8364 i == Xboom_bomb && j == 2 ? 2 :
8365 i == Xboom_bomb && j == 3 ? 4 :
8366 i == Xboom_bomb && j == 4 ? 4 :
8367 i == Xboom_bomb && j == 5 ? 2 :
8368 i == Xboom_bomb && j == 6 ? 2 :
8369 i == Xboom_bomb && j == 7 ? 0 :
8370 i == Xboom_android && j == 7 ? 6 :
8371 i == Xboom_1 && j == 1 ? 2 :
8372 i == Xboom_1 && j == 2 ? 2 :
8373 i == Xboom_1 && j == 3 ? 4 :
8374 i == Xboom_1 && j == 4 ? 4 :
8375 i == Xboom_1 && j == 5 ? 6 :
8376 i == Xboom_1 && j == 6 ? 6 :
8377 i == Xboom_1 && j == 7 ? 8 :
8378 i == Xboom_2 && j == 0 ? 8 :
8379 i == Xboom_2 && j == 1 ? 8 :
8380 i == Xboom_2 && j == 2 ? 10 :
8381 i == Xboom_2 && j == 3 ? 10 :
8382 i == Xboom_2 && j == 4 ? 10 :
8383 i == Xboom_2 && j == 5 ? 12 :
8384 i == Xboom_2 && j == 6 ? 12 :
8385 i == Xboom_2 && j == 7 ? 12 :
8386 special_animation && j == 4 ? 3 :
8387 effective_action != action ? 0 :
8391 Bitmap *debug_bitmap = g_em->bitmap;
8392 int debug_src_x = g_em->src_x;
8393 int debug_src_y = g_em->src_y;
8396 int frame = getAnimationFrame(g->anim_frames,
8399 g->anim_start_frame,
8402 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
8403 g->double_movement && is_backside);
8405 g_em->bitmap = src_bitmap;
8406 g_em->src_x = src_x;
8407 g_em->src_y = src_y;
8408 g_em->src_offset_x = 0;
8409 g_em->src_offset_y = 0;
8410 g_em->dst_offset_x = 0;
8411 g_em->dst_offset_y = 0;
8412 g_em->width = TILEX;
8413 g_em->height = TILEY;
8415 g_em->preserve_background = FALSE;
8417 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
8420 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
8421 effective_action == ACTION_MOVING ||
8422 effective_action == ACTION_PUSHING ||
8423 effective_action == ACTION_EATING)) ||
8424 (!has_action_graphics && (effective_action == ACTION_FILLING ||
8425 effective_action == ACTION_EMPTYING)))
8428 (effective_action == ACTION_FALLING ||
8429 effective_action == ACTION_FILLING ||
8430 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
8431 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
8432 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
8433 int num_steps = (i == Ydrip_s1 ? 16 :
8434 i == Ydrip_s1B ? 16 :
8435 i == Ydrip_s2 ? 16 :
8436 i == Ydrip_s2B ? 16 :
8437 i == Xsand_stonein_1 ? 32 :
8438 i == Xsand_stonein_2 ? 32 :
8439 i == Xsand_stonein_3 ? 32 :
8440 i == Xsand_stonein_4 ? 32 :
8441 i == Xsand_stoneout_1 ? 16 :
8442 i == Xsand_stoneout_2 ? 16 : 8);
8443 int cx = ABS(dx) * (TILEX / num_steps);
8444 int cy = ABS(dy) * (TILEY / num_steps);
8445 int step_frame = (i == Ydrip_s2 ? j + 8 :
8446 i == Ydrip_s2B ? j + 8 :
8447 i == Xsand_stonein_2 ? j + 8 :
8448 i == Xsand_stonein_3 ? j + 16 :
8449 i == Xsand_stonein_4 ? j + 24 :
8450 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
8451 int step = (is_backside ? step_frame : num_steps - step_frame);
8453 if (is_backside) /* tile where movement starts */
8455 if (dx < 0 || dy < 0)
8457 g_em->src_offset_x = cx * step;
8458 g_em->src_offset_y = cy * step;
8462 g_em->dst_offset_x = cx * step;
8463 g_em->dst_offset_y = cy * step;
8466 else /* tile where movement ends */
8468 if (dx < 0 || dy < 0)
8470 g_em->dst_offset_x = cx * step;
8471 g_em->dst_offset_y = cy * step;
8475 g_em->src_offset_x = cx * step;
8476 g_em->src_offset_y = cy * step;
8480 g_em->width = TILEX - cx * step;
8481 g_em->height = TILEY - cy * step;
8484 /* create unique graphic identifier to decide if tile must be redrawn */
8485 /* bit 31 - 16 (16 bit): EM style graphic
8486 bit 15 - 12 ( 4 bit): EM style frame
8487 bit 11 - 6 ( 6 bit): graphic width
8488 bit 5 - 0 ( 6 bit): graphic height */
8489 g_em->unique_identifier =
8490 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
8494 /* skip check for EMC elements not contained in original EMC artwork */
8495 if (element == EL_EMC_FAKE_ACID)
8498 if (g_em->bitmap != debug_bitmap ||
8499 g_em->src_x != debug_src_x ||
8500 g_em->src_y != debug_src_y ||
8501 g_em->src_offset_x != 0 ||
8502 g_em->src_offset_y != 0 ||
8503 g_em->dst_offset_x != 0 ||
8504 g_em->dst_offset_y != 0 ||
8505 g_em->width != TILEX ||
8506 g_em->height != TILEY)
8508 static int last_i = -1;
8516 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
8517 i, element, element_info[element].token_name,
8518 element_action_info[effective_action].suffix, direction);
8520 if (element != effective_element)
8521 printf(" [%d ('%s')]",
8523 element_info[effective_element].token_name);
8527 if (g_em->bitmap != debug_bitmap)
8528 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
8529 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
8531 if (g_em->src_x != debug_src_x ||
8532 g_em->src_y != debug_src_y)
8533 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
8534 j, (is_backside ? 'B' : 'F'),
8535 g_em->src_x, g_em->src_y,
8536 g_em->src_x / 32, g_em->src_y / 32,
8537 debug_src_x, debug_src_y,
8538 debug_src_x / 32, debug_src_y / 32);
8540 if (g_em->src_offset_x != 0 ||
8541 g_em->src_offset_y != 0 ||
8542 g_em->dst_offset_x != 0 ||
8543 g_em->dst_offset_y != 0)
8544 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
8546 g_em->src_offset_x, g_em->src_offset_y,
8547 g_em->dst_offset_x, g_em->dst_offset_y);
8549 if (g_em->width != TILEX ||
8550 g_em->height != TILEY)
8551 printf(" %d (%d): size %d,%d should be %d,%d\n",
8553 g_em->width, g_em->height, TILEX, TILEY);
8555 num_em_gfx_errors++;
8562 for (i = 0; i < TILE_MAX; i++)
8564 for (j = 0; j < 8; j++)
8566 int element = object_mapping[i].element_rnd;
8567 int action = object_mapping[i].action;
8568 int direction = object_mapping[i].direction;
8569 boolean is_backside = object_mapping[i].is_backside;
8570 int graphic_action = el_act_dir2img(element, action, direction);
8571 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
8573 if ((action == ACTION_SMASHED_BY_ROCK ||
8574 action == ACTION_SMASHED_BY_SPRING ||
8575 action == ACTION_EATING) &&
8576 graphic_action == graphic_default)
8578 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
8579 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
8580 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
8581 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
8584 /* no separate animation for "smashed by rock" -- use rock instead */
8585 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
8586 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
8588 g_em->bitmap = g_xx->bitmap;
8589 g_em->src_x = g_xx->src_x;
8590 g_em->src_y = g_xx->src_y;
8591 g_em->src_offset_x = g_xx->src_offset_x;
8592 g_em->src_offset_y = g_xx->src_offset_y;
8593 g_em->dst_offset_x = g_xx->dst_offset_x;
8594 g_em->dst_offset_y = g_xx->dst_offset_y;
8595 g_em->width = g_xx->width;
8596 g_em->height = g_xx->height;
8597 g_em->unique_identifier = g_xx->unique_identifier;
8600 g_em->preserve_background = TRUE;
8605 for (p = 0; p < MAX_PLAYERS; p++)
8607 for (i = 0; i < SPR_MAX; i++)
8609 int element = player_mapping[p][i].element_rnd;
8610 int action = player_mapping[p][i].action;
8611 int direction = player_mapping[p][i].direction;
8613 for (j = 0; j < 8; j++)
8615 int effective_element = element;
8616 int effective_action = action;
8617 int graphic = (direction == MV_NONE ?
8618 el_act2img(effective_element, effective_action) :
8619 el_act_dir2img(effective_element, effective_action,
8621 struct GraphicInfo *g = &graphic_info[graphic];
8622 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
8628 Bitmap *debug_bitmap = g_em->bitmap;
8629 int debug_src_x = g_em->src_x;
8630 int debug_src_y = g_em->src_y;
8633 int frame = getAnimationFrame(g->anim_frames,
8636 g->anim_start_frame,
8639 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
8641 g_em->bitmap = src_bitmap;
8642 g_em->src_x = src_x;
8643 g_em->src_y = src_y;
8644 g_em->src_offset_x = 0;
8645 g_em->src_offset_y = 0;
8646 g_em->dst_offset_x = 0;
8647 g_em->dst_offset_y = 0;
8648 g_em->width = TILEX;
8649 g_em->height = TILEY;
8653 /* skip check for EMC elements not contained in original EMC artwork */
8654 if (element == EL_PLAYER_3 ||
8655 element == EL_PLAYER_4)
8658 if (g_em->bitmap != debug_bitmap ||
8659 g_em->src_x != debug_src_x ||
8660 g_em->src_y != debug_src_y)
8662 static int last_i = -1;
8670 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
8671 p, i, element, element_info[element].token_name,
8672 element_action_info[effective_action].suffix, direction);
8674 if (element != effective_element)
8675 printf(" [%d ('%s')]",
8677 element_info[effective_element].token_name);
8681 if (g_em->bitmap != debug_bitmap)
8682 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
8683 j, (int)(g_em->bitmap), (int)(debug_bitmap));
8685 if (g_em->src_x != debug_src_x ||
8686 g_em->src_y != debug_src_y)
8687 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
8689 g_em->src_x, g_em->src_y,
8690 g_em->src_x / 32, g_em->src_y / 32,
8691 debug_src_x, debug_src_y,
8692 debug_src_x / 32, debug_src_y / 32);
8694 num_em_gfx_errors++;
8704 printf("::: [%d errors found]\n", num_em_gfx_errors);
8710 void CheckSaveEngineSnapshot_EM(byte action[MAX_PLAYERS], int frame,
8711 boolean any_player_moving,
8712 boolean any_player_snapping,
8713 boolean any_player_dropping)
8715 if (frame == 0 && !any_player_dropping)
8717 if (!local_player->was_waiting)
8719 if (!CheckSaveEngineSnapshotToList())
8722 local_player->was_waiting = TRUE;
8725 else if (any_player_moving || any_player_snapping || any_player_dropping)
8727 local_player->was_waiting = FALSE;
8731 void CheckSaveEngineSnapshot_SP(boolean murphy_is_waiting,
8732 boolean murphy_is_dropping)
8734 if (murphy_is_waiting)
8736 if (!local_player->was_waiting)
8738 if (!CheckSaveEngineSnapshotToList())
8741 local_player->was_waiting = TRUE;
8746 local_player->was_waiting = FALSE;
8750 void CheckSingleStepMode_EM(byte action[MAX_PLAYERS], int frame,
8751 boolean any_player_moving,
8752 boolean any_player_snapping,
8753 boolean any_player_dropping)
8755 if (tape.single_step && tape.recording && !tape.pausing)
8756 if (frame == 0 && !any_player_dropping)
8757 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
8759 CheckSaveEngineSnapshot_EM(action, frame, any_player_moving,
8760 any_player_snapping, any_player_dropping);
8763 void CheckSingleStepMode_SP(boolean murphy_is_waiting,
8764 boolean murphy_is_dropping)
8766 boolean murphy_starts_dropping = FALSE;
8769 for (i = 0; i < MAX_PLAYERS; i++)
8770 if (stored_player[i].force_dropping)
8771 murphy_starts_dropping = TRUE;
8773 if (tape.single_step && tape.recording && !tape.pausing)
8774 if (murphy_is_waiting && !murphy_starts_dropping)
8775 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
8777 CheckSaveEngineSnapshot_SP(murphy_is_waiting, murphy_is_dropping);
8780 void getGraphicSource_SP(struct GraphicInfo_SP *g_sp,
8781 int graphic, int sync_frame, int x, int y)
8783 int frame = getGraphicAnimationFrame(graphic, sync_frame);
8785 getGraphicSource(graphic, frame, &g_sp->bitmap, &g_sp->src_x, &g_sp->src_y);
8788 boolean isNextAnimationFrame_SP(int graphic, int sync_frame)
8790 return (IS_NEXT_FRAME(sync_frame, graphic));
8793 int getGraphicInfo_Delay(int graphic)
8795 return graphic_info[graphic].anim_delay;
8798 void PlayMenuSoundExt(int sound)
8800 if (sound == SND_UNDEFINED)
8803 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8804 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8807 if (IS_LOOP_SOUND(sound))
8808 PlaySoundLoop(sound);
8813 void PlayMenuSound()
8815 PlayMenuSoundExt(menu.sound[game_status]);
8818 void PlayMenuSoundStereo(int sound, int stereo_position)
8820 if (sound == SND_UNDEFINED)
8823 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8824 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8827 if (IS_LOOP_SOUND(sound))
8828 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
8830 PlaySoundStereo(sound, stereo_position);
8833 void PlayMenuSoundIfLoopExt(int sound)
8835 if (sound == SND_UNDEFINED)
8838 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8839 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8842 if (IS_LOOP_SOUND(sound))
8843 PlaySoundLoop(sound);
8846 void PlayMenuSoundIfLoop()
8848 PlayMenuSoundIfLoopExt(menu.sound[game_status]);
8851 void PlayMenuMusicExt(int music)
8853 if (music == MUS_UNDEFINED)
8856 if (!setup.sound_music)
8862 void PlayMenuMusic()
8864 char *curr_music = getCurrentlyPlayingMusicFilename();
8865 char *next_music = getMusicInfoEntryFilename(menu.music[game_status]);
8867 if (!strEqual(curr_music, next_music))
8868 PlayMenuMusicExt(menu.music[game_status]);
8871 void PlayMenuSoundsAndMusic()
8877 static void FadeMenuSounds()
8882 static void FadeMenuMusic()
8884 char *curr_music = getCurrentlyPlayingMusicFilename();
8885 char *next_music = getMusicInfoEntryFilename(menu.music[game_status]);
8887 if (!strEqual(curr_music, next_music))
8891 void FadeMenuSoundsAndMusic()
8897 void PlaySoundActivating()
8900 PlaySound(SND_MENU_ITEM_ACTIVATING);
8904 void PlaySoundSelecting()
8907 PlaySound(SND_MENU_ITEM_SELECTING);
8911 void ToggleFullscreenOrChangeWindowScalingIfNeeded()
8913 boolean change_fullscreen = (setup.fullscreen !=
8914 video.fullscreen_enabled);
8915 boolean change_window_scaling_percent = (!video.fullscreen_enabled &&
8916 setup.window_scaling_percent !=
8917 video.window_scaling_percent);
8919 if (change_window_scaling_percent && video.fullscreen_enabled)
8922 if (!change_window_scaling_percent && !video.fullscreen_available)
8925 #if defined(TARGET_SDL2)
8926 if (change_window_scaling_percent)
8928 SDLSetWindowScaling(setup.window_scaling_percent);
8932 else if (change_fullscreen)
8934 SDLSetWindowFullscreen(setup.fullscreen);
8936 /* set setup value according to successfully changed fullscreen mode */
8937 setup.fullscreen = video.fullscreen_enabled;
8943 if (change_fullscreen ||
8944 change_window_scaling_percent)
8946 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
8948 /* save backbuffer content which gets lost when toggling fullscreen mode */
8949 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8951 if (change_window_scaling_percent)
8953 /* keep window mode, but change window scaling */
8954 video.fullscreen_enabled = TRUE; /* force new window scaling */
8957 /* toggle fullscreen */
8958 ChangeVideoModeIfNeeded(setup.fullscreen);
8960 /* set setup value according to successfully changed fullscreen mode */
8961 setup.fullscreen = video.fullscreen_enabled;
8963 /* restore backbuffer content from temporary backbuffer backup bitmap */
8964 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8966 FreeBitmap(tmp_backbuffer);
8968 /* update visible window/screen */
8969 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8973 void JoinRectangles(int *x, int *y, int *width, int *height,
8974 int x2, int y2, int width2, int height2)
8976 // do not join with "off-screen" rectangle
8977 if (x2 == -1 || y2 == -1)
8982 *width = MAX(*width, width2);
8983 *height = MAX(*height, height2);
8986 void SetAnimStatus(int anim_status_new)
8988 if (anim_status_new == GAME_MODE_MAIN)
8989 anim_status_new = GAME_MODE_PSEUDO_MAINONLY;
8990 else if (anim_status_new == GAME_MODE_SCORES)
8991 anim_status_new = GAME_MODE_PSEUDO_SCORESOLD;
8993 global.anim_status_next = anim_status_new;
8995 // directly set screen modes that are entered without fading
8996 if ((global.anim_status == GAME_MODE_PSEUDO_MAINONLY &&
8997 global.anim_status_next == GAME_MODE_PSEUDO_TYPENAME) ||
8998 (global.anim_status == GAME_MODE_PSEUDO_TYPENAME &&
8999 global.anim_status_next == GAME_MODE_PSEUDO_MAINONLY))
9000 global.anim_status = global.anim_status_next;
9003 void SetGameStatus(int game_status_new)
9005 if (game_status_new != game_status)
9006 game_status_last_screen = game_status;
9008 game_status = game_status_new;
9010 SetAnimStatus(game_status_new);
9013 void SetFontStatus(int game_status_new)
9015 static int last_game_status = -1;
9017 if (game_status_new != -1)
9019 // set game status for font use after storing last game status
9020 last_game_status = game_status;
9021 game_status = game_status_new;
9025 // reset game status after font use from last stored game status
9026 game_status = last_game_status;
9030 void ResetFontStatus()
9035 boolean CheckIfPlayfieldViewportHasChanged()
9037 // if game status has not changed, playfield viewport has not changed either
9038 if (game_status == game_status_last)
9041 // check if playfield viewport has changed with current game status
9042 struct RectWithBorder *vp_playfield = &viewport.playfield[game_status];
9043 int new_real_sx = vp_playfield->x;
9044 int new_real_sy = vp_playfield->y;
9045 int new_full_sxsize = vp_playfield->width;
9046 int new_full_sysize = vp_playfield->height;
9048 return (new_real_sx != REAL_SX ||
9049 new_real_sy != REAL_SY ||
9050 new_full_sxsize != FULL_SXSIZE ||
9051 new_full_sysize != FULL_SYSIZE);
9054 boolean CheckIfGlobalBorderOrPlayfieldViewportHasChanged()
9056 return (CheckIfGlobalBorderHasChanged() ||
9057 CheckIfPlayfieldViewportHasChanged());
9060 void ChangeViewportPropertiesIfNeeded()
9062 boolean use_mini_tilesize = (level.game_engine_type == GAME_ENGINE_TYPE_MM ?
9063 FALSE : setup.small_game_graphics);
9064 int gfx_game_mode = game_status;
9065 int gfx_game_mode2 = (game_status == GAME_MODE_EDITOR ? GAME_MODE_DEFAULT :
9067 struct RectWithBorder *vp_window = &viewport.window[gfx_game_mode];
9068 struct RectWithBorder *vp_playfield = &viewport.playfield[gfx_game_mode];
9069 struct RectWithBorder *vp_door_1 = &viewport.door_1[gfx_game_mode];
9070 struct RectWithBorder *vp_door_2 = &viewport.door_2[gfx_game_mode2];
9071 struct RectWithBorder *vp_door_3 = &viewport.door_2[GAME_MODE_EDITOR];
9072 int new_win_xsize = vp_window->width;
9073 int new_win_ysize = vp_window->height;
9074 int border_size = vp_playfield->border_size;
9075 int new_sx = vp_playfield->x + border_size;
9076 int new_sy = vp_playfield->y + border_size;
9077 int new_sxsize = vp_playfield->width - 2 * border_size;
9078 int new_sysize = vp_playfield->height - 2 * border_size;
9079 int new_real_sx = vp_playfield->x;
9080 int new_real_sy = vp_playfield->y;
9081 int new_full_sxsize = vp_playfield->width;
9082 int new_full_sysize = vp_playfield->height;
9083 int new_dx = vp_door_1->x;
9084 int new_dy = vp_door_1->y;
9085 int new_dxsize = vp_door_1->width;
9086 int new_dysize = vp_door_1->height;
9087 int new_vx = vp_door_2->x;
9088 int new_vy = vp_door_2->y;
9089 int new_vxsize = vp_door_2->width;
9090 int new_vysize = vp_door_2->height;
9091 int new_ex = vp_door_3->x;
9092 int new_ey = vp_door_3->y;
9093 int new_exsize = vp_door_3->width;
9094 int new_eysize = vp_door_3->height;
9095 int new_tilesize_var = (use_mini_tilesize ? MINI_TILESIZE : game.tile_size);
9096 int tilesize = (gfx_game_mode == GAME_MODE_PLAYING ? new_tilesize_var :
9097 gfx_game_mode == GAME_MODE_EDITOR ? MINI_TILESIZE : TILESIZE);
9098 int new_scr_fieldx = new_sxsize / tilesize;
9099 int new_scr_fieldy = new_sysize / tilesize;
9100 int new_scr_fieldx_buffers = new_sxsize / new_tilesize_var;
9101 int new_scr_fieldy_buffers = new_sysize / new_tilesize_var;
9102 boolean init_gfx_buffers = FALSE;
9103 boolean init_video_buffer = FALSE;
9104 boolean init_gadgets_and_anims = FALSE;
9105 boolean init_em_graphics = FALSE;
9107 if (new_win_xsize != WIN_XSIZE ||
9108 new_win_ysize != WIN_YSIZE)
9110 WIN_XSIZE = new_win_xsize;
9111 WIN_YSIZE = new_win_ysize;
9113 init_video_buffer = TRUE;
9114 init_gfx_buffers = TRUE;
9115 init_gadgets_and_anims = TRUE;
9117 // printf("::: video: init_video_buffer, init_gfx_buffers\n");
9120 if (new_scr_fieldx != SCR_FIELDX ||
9121 new_scr_fieldy != SCR_FIELDY)
9123 /* this always toggles between MAIN and GAME when using small tile size */
9125 SCR_FIELDX = new_scr_fieldx;
9126 SCR_FIELDY = new_scr_fieldy;
9128 // printf("::: new_scr_fieldx != SCR_FIELDX ...\n");
9139 new_sxsize != SXSIZE ||
9140 new_sysize != SYSIZE ||
9141 new_dxsize != DXSIZE ||
9142 new_dysize != DYSIZE ||
9143 new_vxsize != VXSIZE ||
9144 new_vysize != VYSIZE ||
9145 new_exsize != EXSIZE ||
9146 new_eysize != EYSIZE ||
9147 new_real_sx != REAL_SX ||
9148 new_real_sy != REAL_SY ||
9149 new_full_sxsize != FULL_SXSIZE ||
9150 new_full_sysize != FULL_SYSIZE ||
9151 new_tilesize_var != TILESIZE_VAR
9154 // ------------------------------------------------------------------------
9155 // determine next fading area for changed viewport definitions
9156 // ------------------------------------------------------------------------
9158 // start with current playfield area (default fading area)
9161 FADE_SXSIZE = FULL_SXSIZE;
9162 FADE_SYSIZE = FULL_SYSIZE;
9164 // add new playfield area if position or size has changed
9165 if (new_real_sx != REAL_SX || new_real_sy != REAL_SY ||
9166 new_full_sxsize != FULL_SXSIZE || new_full_sysize != FULL_SYSIZE)
9168 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
9169 new_real_sx, new_real_sy, new_full_sxsize,new_full_sysize);
9172 // add current and new door 1 area if position or size has changed
9173 if (new_dx != DX || new_dy != DY ||
9174 new_dxsize != DXSIZE || new_dysize != DYSIZE)
9176 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
9177 DX, DY, DXSIZE, DYSIZE);
9178 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
9179 new_dx, new_dy, new_dxsize, new_dysize);
9182 // add current and new door 2 area if position or size has changed
9183 if (new_dx != VX || new_dy != VY ||
9184 new_dxsize != VXSIZE || new_dysize != VYSIZE)
9186 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
9187 VX, VY, VXSIZE, VYSIZE);
9188 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
9189 new_vx, new_vy, new_vxsize, new_vysize);
9192 // ------------------------------------------------------------------------
9193 // handle changed tile size
9194 // ------------------------------------------------------------------------
9196 if (new_tilesize_var != TILESIZE_VAR)
9198 // printf("::: new_tilesize_var != TILESIZE_VAR\n");
9200 // changing tile size invalidates scroll values of engine snapshots
9201 FreeEngineSnapshotSingle();
9203 // changing tile size requires update of graphic mapping for EM engine
9204 init_em_graphics = TRUE;
9215 SXSIZE = new_sxsize;
9216 SYSIZE = new_sysize;
9217 DXSIZE = new_dxsize;
9218 DYSIZE = new_dysize;
9219 VXSIZE = new_vxsize;
9220 VYSIZE = new_vysize;
9221 EXSIZE = new_exsize;
9222 EYSIZE = new_eysize;
9223 REAL_SX = new_real_sx;
9224 REAL_SY = new_real_sy;
9225 FULL_SXSIZE = new_full_sxsize;
9226 FULL_SYSIZE = new_full_sysize;
9227 TILESIZE_VAR = new_tilesize_var;
9229 init_gfx_buffers = TRUE;
9230 init_gadgets_and_anims = TRUE;
9232 // printf("::: viewports: init_gfx_buffers\n");
9233 // printf("::: viewports: init_gadgets_and_anims\n");
9236 if (init_gfx_buffers)
9238 // printf("::: init_gfx_buffers\n");
9240 SCR_FIELDX = new_scr_fieldx_buffers;
9241 SCR_FIELDY = new_scr_fieldy_buffers;
9245 SCR_FIELDX = new_scr_fieldx;
9246 SCR_FIELDY = new_scr_fieldy;
9248 SetDrawDeactivationMask(REDRAW_NONE);
9249 SetDrawBackgroundMask(REDRAW_FIELD);
9252 if (init_video_buffer)
9254 // printf("::: init_video_buffer\n");
9256 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
9257 InitImageTextures();
9260 if (init_gadgets_and_anims)
9262 // printf("::: init_gadgets_and_anims\n");
9265 InitGlobalAnimations();
9268 if (init_em_graphics)
9270 InitGraphicInfo_EM();