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.x != tile_cursor.target_x ||
658 tile_cursor.y != tile_cursor.target_y)
660 int step = TILESIZE_VAR / (GADGET_FRAME_DELAY / video.frame_delay_value);
661 int dx = tile_cursor.target_x - tile_cursor.x;
662 int dy = tile_cursor.target_y - tile_cursor.y;
665 tile_cursor.x = tile_cursor.target_x;
667 tile_cursor.x += SIGN(dx) * step;
670 tile_cursor.y = tile_cursor.target_y;
672 tile_cursor.y += SIGN(dy) * step;
675 dst_x = tile_cursor.x;
676 dst_y = tile_cursor.y;
678 frame = getGraphicAnimationFrame(graphic, -1);
680 getSizedGraphicSource(graphic, frame, tilesize, &src_bitmap, &src_x, &src_y);
683 (draw_target == DRAW_TO_FADE_SOURCE ? gfx.fade_bitmap_source :
684 draw_target == DRAW_TO_FADE_TARGET ? gfx.fade_bitmap_target : NULL);
686 if (draw_target == DRAW_TO_SCREEN)
687 BlitToScreenMasked(src_bitmap, src_x, src_y, width, height, dst_x, dst_y);
689 BlitBitmapMasked(src_bitmap, fade_bitmap, src_x, src_y, width, height,
693 void BlitScreenToBitmap_RND(Bitmap *target_bitmap)
695 int fx = getFieldbufferOffsetX_RND();
696 int fy = getFieldbufferOffsetY_RND();
698 BlitBitmap(drawto_field, target_bitmap, fx, fy, SXSIZE, SYSIZE, SX, SY);
701 void BlitScreenToBitmap(Bitmap *target_bitmap)
703 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
704 BlitScreenToBitmap_EM(target_bitmap);
705 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
706 BlitScreenToBitmap_SP(target_bitmap);
707 else if (level.game_engine_type == GAME_ENGINE_TYPE_MM)
708 BlitScreenToBitmap_MM(target_bitmap);
709 else if (level.game_engine_type == GAME_ENGINE_TYPE_RND)
710 BlitScreenToBitmap_RND(target_bitmap);
712 redraw_mask |= REDRAW_FIELD;
715 void DrawFramesPerSecond()
718 int font_nr = FONT_TEXT_2;
719 int font_width = getFontWidth(font_nr);
720 int draw_deactivation_mask = GetDrawDeactivationMask();
721 boolean draw_masked = (draw_deactivation_mask == REDRAW_NONE);
723 /* draw FPS with leading space (needed if field buffer deactivated) */
724 sprintf(text, " %04.1f fps", global.frames_per_second);
726 /* override draw deactivation mask (required for invisible warp mode) */
727 SetDrawDeactivationMask(REDRAW_NONE);
729 /* draw opaque FPS if field buffer deactivated, else draw masked FPS */
730 DrawTextExt(backbuffer, SX + SXSIZE - font_width * strlen(text), SY, text,
731 font_nr, (draw_masked ? BLIT_MASKED : BLIT_OPAQUE));
733 /* set draw deactivation mask to previous value */
734 SetDrawDeactivationMask(draw_deactivation_mask);
736 /* force full-screen redraw in this frame */
737 redraw_mask = REDRAW_ALL;
741 static void PrintFrameTimeDebugging()
743 static unsigned int last_counter = 0;
744 unsigned int counter = Counter();
745 int diff_1 = counter - last_counter;
746 int diff_2 = diff_1 - GAME_FRAME_DELAY;
748 int diff_2_cut = MIN(ABS(diff_2), diff_2_max);
749 char diff_bar[2 * diff_2_max + 5];
753 diff_bar[pos++] = (diff_2 < -diff_2_max ? '<' : ' ');
755 for (i = 0; i < diff_2_max; i++)
756 diff_bar[pos++] = (diff_2 >= 0 ? ' ' :
757 i >= diff_2_max - diff_2_cut ? '-' : ' ');
759 diff_bar[pos++] = '|';
761 for (i = 0; i < diff_2_max; i++)
762 diff_bar[pos++] = (diff_2 <= 0 ? ' ' : i < diff_2_cut ? '+' : ' ');
764 diff_bar[pos++] = (diff_2 > diff_2_max ? '>' : ' ');
766 diff_bar[pos++] = '\0';
768 Error(ERR_INFO, "%06d [%02d] [%c%02d] %s",
771 (diff_2 < 0 ? '-' : diff_2 > 0 ? '+' : ' '), ABS(diff_2),
774 last_counter = counter;
778 static int unifiedRedrawMask(int mask)
780 if (mask & REDRAW_ALL)
783 if (mask & REDRAW_FIELD && mask & REDRAW_DOORS)
789 static boolean equalRedrawMasks(int mask_1, int mask_2)
791 return unifiedRedrawMask(mask_1) == unifiedRedrawMask(mask_2);
796 static int last_redraw_mask = REDRAW_NONE;
798 // force screen redraw in every frame to continue drawing global animations
799 // (but always use the last redraw mask to prevent unwanted side effects)
800 if (redraw_mask == REDRAW_NONE)
801 redraw_mask = last_redraw_mask;
803 last_redraw_mask = redraw_mask;
806 // masked border now drawn immediately when blitting backbuffer to window
808 // draw masked border to all viewports, if defined
809 DrawMaskedBorder(redraw_mask);
812 // draw frames per second (only if debug mode is enabled)
813 if (redraw_mask & REDRAW_FPS)
814 DrawFramesPerSecond();
816 // remove playfield redraw before potentially merging with doors redraw
817 if (DrawingDeactivated(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE))
818 redraw_mask &= ~REDRAW_FIELD;
820 // redraw complete window if both playfield and (some) doors need redraw
821 if (redraw_mask & REDRAW_FIELD && redraw_mask & REDRAW_DOORS)
822 redraw_mask = REDRAW_ALL;
824 /* although redrawing the whole window would be fine for normal gameplay,
825 being able to only redraw the playfield is required for deactivating
826 certain drawing areas (mainly playfield) to work, which is needed for
827 warp-forward to be fast enough (by skipping redraw of most frames) */
829 if (redraw_mask & REDRAW_ALL)
831 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
833 else if (redraw_mask & REDRAW_FIELD)
835 BlitBitmap(backbuffer, window,
836 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
838 else if (redraw_mask & REDRAW_DOORS)
840 // merge door areas to prevent calling screen redraw more than once
846 if (redraw_mask & REDRAW_DOOR_1)
850 x2 = MAX(x2, DX + DXSIZE);
851 y2 = MAX(y2, DY + DYSIZE);
854 if (redraw_mask & REDRAW_DOOR_2)
858 x2 = MAX(x2, VX + VXSIZE);
859 y2 = MAX(y2, VY + VYSIZE);
862 if (redraw_mask & REDRAW_DOOR_3)
866 x2 = MAX(x2, EX + EXSIZE);
867 y2 = MAX(y2, EY + EYSIZE);
870 // make sure that at least one pixel is blitted, and inside the screen
871 // (else nothing is blitted, causing the animations not to be updated)
872 x1 = MIN(MAX(0, x1), WIN_XSIZE - 1);
873 y1 = MIN(MAX(0, y1), WIN_YSIZE - 1);
874 x2 = MIN(MAX(1, x2), WIN_XSIZE);
875 y2 = MIN(MAX(1, y2), WIN_YSIZE);
877 BlitBitmap(backbuffer, window, x1, y1, x2 - x1, y2 - y1, x1, y1);
880 redraw_mask = REDRAW_NONE;
883 PrintFrameTimeDebugging();
887 void BackToFront_WithFrameDelay(unsigned int frame_delay_value)
889 unsigned int frame_delay_value_old = GetVideoFrameDelay();
891 SetVideoFrameDelay(frame_delay_value);
895 SetVideoFrameDelay(frame_delay_value_old);
898 static int fade_type_skip = FADE_TYPE_NONE;
900 static void FadeExt(int fade_mask, int fade_mode, int fade_type)
902 void (*draw_border_function)(void) = NULL;
903 int x, y, width, height;
904 int fade_delay, post_delay;
906 if (fade_type == FADE_TYPE_FADE_OUT)
908 if (fade_type_skip != FADE_TYPE_NONE)
910 /* skip all fade operations until specified fade operation */
911 if (fade_type & fade_type_skip)
912 fade_type_skip = FADE_TYPE_NONE;
917 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
921 redraw_mask |= fade_mask;
923 if (fade_type == FADE_TYPE_SKIP)
925 fade_type_skip = fade_mode;
930 fade_delay = fading.fade_delay;
931 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
933 if (fade_type_skip != FADE_TYPE_NONE)
935 /* skip all fade operations until specified fade operation */
936 if (fade_type & fade_type_skip)
937 fade_type_skip = FADE_TYPE_NONE;
942 if (global.autoplay_leveldir)
947 if (fade_mask == REDRAW_FIELD)
952 height = FADE_SYSIZE;
954 if (border.draw_masked_when_fading)
955 draw_border_function = DrawMaskedBorder_FIELD; /* update when fading */
957 DrawMaskedBorder_FIELD(); /* draw once */
959 else /* REDRAW_ALL */
967 if (!setup.fade_screens ||
969 fading.fade_mode == FADE_MODE_NONE)
971 if (fade_mode == FADE_MODE_FADE_OUT)
974 BlitBitmap(backbuffer, window, x, y, width, height, x, y);
976 redraw_mask &= ~fade_mask;
981 FadeRectangle(x, y, width, height, fade_mode, fade_delay, post_delay,
982 draw_border_function);
984 redraw_mask &= ~fade_mask;
987 static void SetScreenStates_BeforeFadingIn()
989 // temporarily set screen mode for animations to screen after fading in
990 global.anim_status = global.anim_status_next;
992 // store backbuffer with all animations that will be started after fading in
993 if (fade_type_skip != FADE_MODE_SKIP_FADE_IN)
994 PrepareFadeBitmap(DRAW_TO_FADE_TARGET);
996 // set screen mode for animations back to fading
997 global.anim_status = GAME_MODE_PSEUDO_FADING;
1000 static void SetScreenStates_AfterFadingIn()
1002 // store new source screen (to use correct masked border for fading)
1003 gfx.fade_border_source_status = global.border_status;
1005 global.anim_status = global.anim_status_next;
1008 static void SetScreenStates_BeforeFadingOut()
1010 // store new target screen (to use correct masked border for fading)
1011 gfx.fade_border_target_status = game_status;
1013 // set screen mode for animations to fading
1014 global.anim_status = GAME_MODE_PSEUDO_FADING;
1016 // store backbuffer with all animations that will be stopped for fading out
1017 if (fade_type_skip != FADE_MODE_SKIP_FADE_OUT)
1018 PrepareFadeBitmap(DRAW_TO_FADE_SOURCE);
1021 static void SetScreenStates_AfterFadingOut()
1023 global.border_status = game_status;
1026 void FadeIn(int fade_mask)
1028 SetScreenStates_BeforeFadingIn();
1031 DrawMaskedBorder(REDRAW_ALL);
1034 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
1035 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_IN);
1037 FadeExt(fade_mask, FADE_MODE_FADE_IN, FADE_TYPE_FADE_IN);
1041 FADE_SXSIZE = FULL_SXSIZE;
1042 FADE_SYSIZE = FULL_SYSIZE;
1044 if (game_status == GAME_MODE_PLAYING &&
1045 strEqual(setup.touch.control_type, TOUCH_CONTROL_VIRTUAL_BUTTONS))
1046 SetOverlayActive(TRUE);
1048 SetScreenStates_AfterFadingIn();
1050 // force update of global animation status in case of rapid screen changes
1051 redraw_mask = REDRAW_ALL;
1055 void FadeOut(int fade_mask)
1057 // update screen if areas covered by "fade_mask" and "redraw_mask" differ
1058 if (!equalRedrawMasks(fade_mask, redraw_mask))
1061 SetScreenStates_BeforeFadingOut();
1063 SetTileCursorActive(FALSE);
1064 SetOverlayActive(FALSE);
1067 DrawMaskedBorder(REDRAW_ALL);
1070 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
1071 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_OUT);
1073 FadeExt(fade_mask, FADE_MODE_FADE_OUT, FADE_TYPE_FADE_OUT);
1075 SetScreenStates_AfterFadingOut();
1078 static void FadeSetLeaveNext(struct TitleFadingInfo fading_leave, boolean set)
1080 static struct TitleFadingInfo fading_leave_stored;
1083 fading_leave_stored = fading_leave;
1085 fading = fading_leave_stored;
1088 void FadeSetEnterMenu()
1090 fading = menu.enter_menu;
1092 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
1095 void FadeSetLeaveMenu()
1097 fading = menu.leave_menu;
1099 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
1102 void FadeSetEnterScreen()
1104 fading = menu.enter_screen[game_status];
1106 FadeSetLeaveNext(menu.leave_screen[game_status], TRUE); /* store */
1109 void FadeSetNextScreen()
1111 fading = menu.next_screen[game_status];
1113 // (do not overwrite fade mode set by FadeSetEnterScreen)
1114 // FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
1117 void FadeSetLeaveScreen()
1119 FadeSetLeaveNext(menu.leave_screen[game_status], FALSE); /* recall */
1122 void FadeSetFromType(int type)
1124 if (type & TYPE_ENTER_SCREEN)
1125 FadeSetEnterScreen();
1126 else if (type & TYPE_ENTER)
1128 else if (type & TYPE_LEAVE)
1132 void FadeSetDisabled()
1134 static struct TitleFadingInfo fading_none = { FADE_MODE_NONE, -1, -1, -1 };
1136 fading = fading_none;
1139 void FadeSkipNextFadeIn()
1141 FadeExt(0, FADE_MODE_SKIP_FADE_IN, FADE_TYPE_SKIP);
1144 void FadeSkipNextFadeOut()
1146 FadeExt(0, FADE_MODE_SKIP_FADE_OUT, FADE_TYPE_SKIP);
1149 Bitmap *getBitmapFromGraphicOrDefault(int graphic, int default_graphic)
1151 boolean redefined = getImageListEntryFromImageID(graphic)->redefined;
1153 return (graphic == IMG_UNDEFINED ? NULL :
1154 graphic_info[graphic].bitmap != NULL || redefined ?
1155 graphic_info[graphic].bitmap :
1156 graphic_info[default_graphic].bitmap);
1159 Bitmap *getBackgroundBitmap(int graphic)
1161 return getBitmapFromGraphicOrDefault(graphic, IMG_BACKGROUND);
1164 Bitmap *getGlobalBorderBitmap(int graphic)
1166 return getBitmapFromGraphicOrDefault(graphic, IMG_GLOBAL_BORDER);
1169 Bitmap *getGlobalBorderBitmapFromStatus(int status)
1172 (status == GAME_MODE_MAIN ||
1173 status == GAME_MODE_PSEUDO_TYPENAME ? IMG_GLOBAL_BORDER_MAIN :
1174 status == GAME_MODE_SCORES ? IMG_GLOBAL_BORDER_SCORES :
1175 status == GAME_MODE_EDITOR ? IMG_GLOBAL_BORDER_EDITOR :
1176 status == GAME_MODE_PLAYING ? IMG_GLOBAL_BORDER_PLAYING :
1179 return getGlobalBorderBitmap(graphic);
1182 void SetWindowBackgroundImageIfDefined(int graphic)
1184 if (graphic_info[graphic].bitmap)
1185 SetWindowBackgroundBitmap(graphic_info[graphic].bitmap);
1188 void SetMainBackgroundImageIfDefined(int graphic)
1190 if (graphic_info[graphic].bitmap)
1191 SetMainBackgroundBitmap(graphic_info[graphic].bitmap);
1194 void SetDoorBackgroundImageIfDefined(int graphic)
1196 if (graphic_info[graphic].bitmap)
1197 SetDoorBackgroundBitmap(graphic_info[graphic].bitmap);
1200 void SetWindowBackgroundImage(int graphic)
1202 SetWindowBackgroundBitmap(getBackgroundBitmap(graphic));
1205 void SetMainBackgroundImage(int graphic)
1207 SetMainBackgroundBitmap(getBackgroundBitmap(graphic));
1210 void SetDoorBackgroundImage(int graphic)
1212 SetDoorBackgroundBitmap(getBackgroundBitmap(graphic));
1215 void SetPanelBackground()
1217 struct GraphicInfo *gfx = &graphic_info[IMG_BACKGROUND_PANEL];
1219 BlitBitmapTiled(gfx->bitmap, bitmap_db_panel, gfx->src_x, gfx->src_y,
1220 gfx->width, gfx->height, 0, 0, DXSIZE, DYSIZE);
1222 SetDoorBackgroundBitmap(bitmap_db_panel);
1225 void DrawBackground(int x, int y, int width, int height)
1227 /* "drawto" might still point to playfield buffer here (hall of fame) */
1228 ClearRectangleOnBackground(backbuffer, x, y, width, height);
1230 if (IN_GFX_FIELD_FULL(x, y))
1231 redraw_mask |= REDRAW_FIELD;
1232 else if (IN_GFX_DOOR_1(x, y))
1233 redraw_mask |= REDRAW_DOOR_1;
1234 else if (IN_GFX_DOOR_2(x, y))
1235 redraw_mask |= REDRAW_DOOR_2;
1236 else if (IN_GFX_DOOR_3(x, y))
1237 redraw_mask |= REDRAW_DOOR_3;
1240 void DrawBackgroundForFont(int x, int y, int width, int height, int font_nr)
1242 struct FontBitmapInfo *font = getFontBitmapInfo(font_nr);
1244 if (font->bitmap == NULL)
1247 DrawBackground(x, y, width, height);
1250 void DrawBackgroundForGraphic(int x, int y, int width, int height, int graphic)
1252 struct GraphicInfo *g = &graphic_info[graphic];
1254 if (g->bitmap == NULL)
1257 DrawBackground(x, y, width, height);
1260 static int game_status_last = -1;
1261 static Bitmap *global_border_bitmap_last = NULL;
1262 static Bitmap *global_border_bitmap = NULL;
1263 static int real_sx_last = -1, real_sy_last = -1;
1264 static int full_sxsize_last = -1, full_sysize_last = -1;
1265 static int dx_last = -1, dy_last = -1;
1266 static int dxsize_last = -1, dysize_last = -1;
1267 static int vx_last = -1, vy_last = -1;
1268 static int vxsize_last = -1, vysize_last = -1;
1270 boolean CheckIfGlobalBorderHasChanged()
1272 // if game status has not changed, global border has not changed either
1273 if (game_status == game_status_last)
1276 // determine and store new global border bitmap for current game status
1277 global_border_bitmap = getGlobalBorderBitmapFromStatus(game_status);
1279 return (global_border_bitmap_last != global_border_bitmap);
1282 boolean CheckIfGlobalBorderRedrawIsNeeded()
1284 // if game status has not changed, nothing has to be redrawn
1285 if (game_status == game_status_last)
1288 // redraw if last screen was title screen
1289 if (game_status_last == GAME_MODE_TITLE)
1292 // redraw if global screen border has changed
1293 if (CheckIfGlobalBorderHasChanged())
1296 // redraw if position or size of playfield area has changed
1297 if (real_sx_last != REAL_SX || real_sy_last != REAL_SY ||
1298 full_sxsize_last != FULL_SXSIZE || full_sysize_last != FULL_SYSIZE)
1301 // redraw if position or size of door area has changed
1302 if (dx_last != DX || dy_last != DY ||
1303 dxsize_last != DXSIZE || dysize_last != DYSIZE)
1306 // redraw if position or size of tape area has changed
1307 if (vx_last != VX || vy_last != VY ||
1308 vxsize_last != VXSIZE || vysize_last != VYSIZE)
1314 void RedrawGlobalBorderFromBitmap(Bitmap *bitmap)
1317 BlitBitmap(bitmap, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
1319 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
1322 void RedrawGlobalBorder()
1324 Bitmap *bitmap = getGlobalBorderBitmapFromStatus(game_status);
1326 RedrawGlobalBorderFromBitmap(bitmap);
1328 redraw_mask = REDRAW_ALL;
1331 static void RedrawGlobalBorderIfNeeded()
1333 if (game_status == game_status_last)
1336 // copy current draw buffer to later copy back areas that have not changed
1337 if (game_status_last != GAME_MODE_TITLE)
1338 BlitBitmap(backbuffer, bitmap_db_store_1, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
1340 if (CheckIfGlobalBorderRedrawIsNeeded())
1342 // redraw global screen border (or clear, if defined to be empty)
1343 RedrawGlobalBorderFromBitmap(global_border_bitmap);
1345 // copy previous playfield and door areas, if they are defined on both
1346 // previous and current screen and if they still have the same size
1348 if (real_sx_last != -1 && real_sy_last != -1 &&
1349 REAL_SX != -1 && REAL_SY != -1 &&
1350 full_sxsize_last == FULL_SXSIZE && full_sysize_last == FULL_SYSIZE)
1351 BlitBitmap(bitmap_db_store_1, backbuffer,
1352 real_sx_last, real_sy_last, FULL_SXSIZE, FULL_SYSIZE,
1355 if (dx_last != -1 && dy_last != -1 &&
1356 DX != -1 && DY != -1 &&
1357 dxsize_last == DXSIZE && dysize_last == DYSIZE)
1358 BlitBitmap(bitmap_db_store_1, backbuffer,
1359 dx_last, dy_last, DXSIZE, DYSIZE, DX, DY);
1361 if (vx_last != -1 && vy_last != -1 &&
1362 VX != -1 && VY != -1 &&
1363 vxsize_last == VXSIZE && vysize_last == VYSIZE)
1364 BlitBitmap(bitmap_db_store_1, backbuffer,
1365 vx_last, vy_last, VXSIZE, VYSIZE, VX, VY);
1367 redraw_mask = REDRAW_ALL;
1370 game_status_last = game_status;
1372 global_border_bitmap_last = global_border_bitmap;
1374 real_sx_last = REAL_SX;
1375 real_sy_last = REAL_SY;
1376 full_sxsize_last = FULL_SXSIZE;
1377 full_sysize_last = FULL_SYSIZE;
1380 dxsize_last = DXSIZE;
1381 dysize_last = DYSIZE;
1384 vxsize_last = VXSIZE;
1385 vysize_last = VYSIZE;
1390 RedrawGlobalBorderIfNeeded();
1392 /* !!! "drawto" might still point to playfield buffer here (see above) !!! */
1393 /* (when entering hall of fame after playing) */
1394 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
1396 /* !!! maybe this should be done before clearing the background !!! */
1397 if (game_status == GAME_MODE_PLAYING)
1399 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
1400 SetDrawtoField(DRAW_TO_FIELDBUFFER);
1404 SetDrawtoField(DRAW_TO_BACKBUFFER);
1408 void MarkTileDirty(int x, int y)
1410 redraw_mask |= REDRAW_FIELD;
1413 void SetBorderElement()
1417 BorderElement = EL_EMPTY;
1419 /* the MM game engine does not use a visible border element */
1420 if (level.game_engine_type == GAME_ENGINE_TYPE_MM)
1423 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
1425 for (x = 0; x < lev_fieldx; x++)
1427 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
1428 BorderElement = EL_STEELWALL;
1430 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
1436 void FloodFillLevelExt(int from_x, int from_y, int fill_element,
1437 int max_array_fieldx, int max_array_fieldy,
1438 short field[max_array_fieldx][max_array_fieldy],
1439 int max_fieldx, int max_fieldy)
1443 static int check[4][2] = { { -1, 0 }, { 0, -1 }, { 1, 0 }, { 0, 1 } };
1444 static int safety = 0;
1446 /* check if starting field still has the desired content */
1447 if (field[from_x][from_y] == fill_element)
1452 if (safety > max_fieldx * max_fieldy)
1453 Error(ERR_EXIT, "Something went wrong in 'FloodFill()'. Please debug.");
1455 old_element = field[from_x][from_y];
1456 field[from_x][from_y] = fill_element;
1458 for (i = 0; i < 4; i++)
1460 x = from_x + check[i][0];
1461 y = from_y + check[i][1];
1463 if (IN_FIELD(x, y, max_fieldx, max_fieldy) && field[x][y] == old_element)
1464 FloodFillLevelExt(x, y, fill_element, max_array_fieldx, max_array_fieldy,
1465 field, max_fieldx, max_fieldy);
1471 void FloodFillLevel(int from_x, int from_y, int fill_element,
1472 short field[MAX_LEV_FIELDX][MAX_LEV_FIELDY],
1473 int max_fieldx, int max_fieldy)
1475 FloodFillLevelExt(from_x, from_y, fill_element,
1476 MAX_LEV_FIELDX, MAX_LEV_FIELDY, field,
1477 max_fieldx, max_fieldy);
1480 void SetRandomAnimationValue(int x, int y)
1482 gfx.anim_random_frame = GfxRandom[x][y];
1485 int getGraphicAnimationFrame(int graphic, int sync_frame)
1487 /* animation synchronized with global frame counter, not move position */
1488 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
1489 sync_frame = FrameCounter;
1491 return getAnimationFrame(graphic_info[graphic].anim_frames,
1492 graphic_info[graphic].anim_delay,
1493 graphic_info[graphic].anim_mode,
1494 graphic_info[graphic].anim_start_frame,
1498 void getGraphicSourceBitmap(int graphic, int tilesize, Bitmap **bitmap)
1500 struct GraphicInfo *g = &graphic_info[graphic];
1501 int tilesize_capped = MIN(MAX(1, tilesize), TILESIZE);
1503 if (tilesize == gfx.standard_tile_size)
1504 *bitmap = g->bitmaps[IMG_BITMAP_STANDARD];
1505 else if (tilesize == game.tile_size)
1506 *bitmap = g->bitmaps[IMG_BITMAP_GAME];
1508 *bitmap = g->bitmaps[IMG_BITMAP_1x1 - log_2(tilesize_capped)];
1511 void getGraphicSourceXY(int graphic, int frame, int *x, int *y,
1512 boolean get_backside)
1514 struct GraphicInfo *g = &graphic_info[graphic];
1515 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
1516 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
1518 if (g->offset_y == 0) /* frames are ordered horizontally */
1520 int max_width = g->anim_frames_per_line * g->width;
1521 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
1523 *x = pos % max_width;
1524 *y = src_y % g->height + pos / max_width * g->height;
1526 else if (g->offset_x == 0) /* frames are ordered vertically */
1528 int max_height = g->anim_frames_per_line * g->height;
1529 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
1531 *x = src_x % g->width + pos / max_height * g->width;
1532 *y = pos % max_height;
1534 else /* frames are ordered diagonally */
1536 *x = src_x + frame * g->offset_x;
1537 *y = src_y + frame * g->offset_y;
1541 void getSizedGraphicSourceExt(int graphic, int frame, int tilesize,
1542 Bitmap **bitmap, int *x, int *y,
1543 boolean get_backside)
1545 struct GraphicInfo *g = &graphic_info[graphic];
1547 // if no in-game graphics defined, always use standard graphic size
1548 if (g->bitmaps[IMG_BITMAP_GAME] == NULL)
1549 tilesize = TILESIZE;
1551 getGraphicSourceBitmap(graphic, tilesize, bitmap);
1552 getGraphicSourceXY(graphic, frame, x, y, get_backside);
1554 *x = *x * tilesize / g->tile_size;
1555 *y = *y * tilesize / g->tile_size;
1558 void getSizedGraphicSource(int graphic, int frame, int tilesize,
1559 Bitmap **bitmap, int *x, int *y)
1561 getSizedGraphicSourceExt(graphic, frame, tilesize, bitmap, x, y, FALSE);
1564 void getFixedGraphicSource(int graphic, int frame,
1565 Bitmap **bitmap, int *x, int *y)
1567 getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y, FALSE);
1570 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1572 getSizedGraphicSource(graphic, 0, MINI_TILESIZE, bitmap, x, y);
1575 inline static void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1576 int *x, int *y, boolean get_backside)
1578 getSizedGraphicSourceExt(graphic, frame, TILESIZE_VAR, bitmap, x, y,
1582 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
1584 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
1587 void DrawGraphic(int x, int y, int graphic, int frame)
1590 if (!IN_SCR_FIELD(x, y))
1592 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1593 printf("DrawGraphic(): This should never happen!\n");
1598 DrawGraphicExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR, graphic,
1601 MarkTileDirty(x, y);
1604 void DrawFixedGraphic(int x, int y, int graphic, int frame)
1607 if (!IN_SCR_FIELD(x, y))
1609 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1610 printf("DrawGraphic(): This should never happen!\n");
1615 DrawFixedGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic,
1617 MarkTileDirty(x, y);
1620 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1626 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1628 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX_VAR, TILEY_VAR, x, y);
1631 void DrawFixedGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1637 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1638 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
1641 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
1644 if (!IN_SCR_FIELD(x, y))
1646 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1647 printf("DrawGraphicThruMask(): This should never happen!\n");
1652 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
1655 MarkTileDirty(x, y);
1658 void DrawFixedGraphicThruMask(int x, int y, int graphic, int frame)
1661 if (!IN_SCR_FIELD(x, y))
1663 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1664 printf("DrawGraphicThruMask(): This should never happen!\n");
1669 DrawFixedGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
1671 MarkTileDirty(x, y);
1674 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
1680 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1682 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX_VAR, TILEY_VAR,
1686 void DrawFixedGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y,
1687 int graphic, int frame)
1692 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1694 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY,
1698 void DrawSizedGraphic(int x, int y, int graphic, int frame, int tilesize)
1700 DrawSizedGraphicExt(drawto, SX + x * tilesize, SY + y * tilesize, graphic,
1702 MarkTileDirty(x / tilesize, y / tilesize);
1705 void DrawSizedGraphicThruMask(int x, int y, int graphic, int frame,
1708 DrawSizedGraphicThruMaskExt(drawto, SX + x * tilesize, SY + y * tilesize,
1709 graphic, frame, tilesize);
1710 MarkTileDirty(x / tilesize, y / tilesize);
1713 void DrawSizedGraphicExt(DrawBuffer *d, int x, int y, int graphic, int frame,
1719 getSizedGraphicSource(graphic, frame, tilesize, &src_bitmap, &src_x, &src_y);
1720 BlitBitmap(src_bitmap, d, src_x, src_y, tilesize, tilesize, x, y);
1723 void DrawSizedGraphicThruMaskExt(DrawBuffer *d, int x, int y, int graphic,
1724 int frame, int tilesize)
1729 getSizedGraphicSource(graphic, frame, tilesize, &src_bitmap, &src_x, &src_y);
1730 BlitBitmapMasked(src_bitmap, d, src_x, src_y, tilesize, tilesize, x, y);
1733 void DrawMiniGraphic(int x, int y, int graphic)
1735 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
1736 MarkTileDirty(x / 2, y / 2);
1739 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
1744 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1745 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
1748 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
1749 int graphic, int frame,
1750 int cut_mode, int mask_mode)
1755 int width = TILEX, height = TILEY;
1758 if (dx || dy) /* shifted graphic */
1760 if (x < BX1) /* object enters playfield from the left */
1767 else if (x > BX2) /* object enters playfield from the right */
1773 else if (x == BX1 && dx < 0) /* object leaves playfield to the left */
1779 else if (x == BX2 && dx > 0) /* object leaves playfield to the right */
1781 else if (dx) /* general horizontal movement */
1782 MarkTileDirty(x + SIGN(dx), y);
1784 if (y < BY1) /* object enters playfield from the top */
1786 if (cut_mode == CUT_BELOW) /* object completely above top border */
1794 else if (y > BY2) /* object enters playfield from the bottom */
1800 else if (y == BY1 && dy < 0) /* object leaves playfield to the top */
1806 else if (dy > 0 && cut_mode == CUT_ABOVE)
1808 if (y == BY2) /* object completely above bottom border */
1814 MarkTileDirty(x, y + 1);
1815 } /* object leaves playfield to the bottom */
1816 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1818 else if (dy) /* general vertical movement */
1819 MarkTileDirty(x, y + SIGN(dy));
1823 if (!IN_SCR_FIELD(x, y))
1825 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1826 printf("DrawGraphicShifted(): This should never happen!\n");
1831 width = width * TILESIZE_VAR / TILESIZE;
1832 height = height * TILESIZE_VAR / TILESIZE;
1833 cx = cx * TILESIZE_VAR / TILESIZE;
1834 cy = cy * TILESIZE_VAR / TILESIZE;
1835 dx = dx * TILESIZE_VAR / TILESIZE;
1836 dy = dy * TILESIZE_VAR / TILESIZE;
1838 if (width > 0 && height > 0)
1840 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1845 dst_x = FX + x * TILEX_VAR + dx;
1846 dst_y = FY + y * TILEY_VAR + dy;
1848 if (mask_mode == USE_MASKING)
1849 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1852 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1855 MarkTileDirty(x, y);
1859 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
1860 int graphic, int frame,
1861 int cut_mode, int mask_mode)
1866 int width = TILEX_VAR, height = TILEY_VAR;
1869 int x2 = x + SIGN(dx);
1870 int y2 = y + SIGN(dy);
1872 /* movement with two-tile animations must be sync'ed with movement position,
1873 not with current GfxFrame (which can be higher when using slow movement) */
1874 int anim_pos = (dx ? ABS(dx) : ABS(dy));
1875 int anim_frames = graphic_info[graphic].anim_frames;
1877 /* (we also need anim_delay here for movement animations with less frames) */
1878 int anim_delay = graphic_info[graphic].anim_delay;
1879 int sync_frame = anim_pos * anim_frames * anim_delay / TILESIZE;
1881 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
1882 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
1884 /* re-calculate animation frame for two-tile movement animation */
1885 frame = getGraphicAnimationFrame(graphic, sync_frame);
1887 /* check if movement start graphic inside screen area and should be drawn */
1888 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
1890 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
1892 dst_x = FX + x1 * TILEX_VAR;
1893 dst_y = FY + y1 * TILEY_VAR;
1895 if (mask_mode == USE_MASKING)
1896 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1899 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1902 MarkTileDirty(x1, y1);
1905 /* check if movement end graphic inside screen area and should be drawn */
1906 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
1908 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
1910 dst_x = FX + x2 * TILEX_VAR;
1911 dst_y = FY + y2 * TILEY_VAR;
1913 if (mask_mode == USE_MASKING)
1914 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1917 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1920 MarkTileDirty(x2, y2);
1924 static void DrawGraphicShifted(int x, int y, int dx, int dy,
1925 int graphic, int frame,
1926 int cut_mode, int mask_mode)
1930 DrawGraphic(x, y, graphic, frame);
1935 if (graphic_info[graphic].double_movement) /* EM style movement images */
1936 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1938 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1941 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1942 int frame, int cut_mode)
1944 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
1947 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1948 int cut_mode, int mask_mode)
1950 int lx = LEVELX(x), ly = LEVELY(y);
1954 if (IN_LEV_FIELD(lx, ly))
1956 SetRandomAnimationValue(lx, ly);
1958 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
1959 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1961 /* do not use double (EM style) movement graphic when not moving */
1962 if (graphic_info[graphic].double_movement && !dx && !dy)
1964 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
1965 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1968 else /* border element */
1970 graphic = el2img(element);
1971 frame = getGraphicAnimationFrame(graphic, -1);
1974 if (element == EL_EXPANDABLE_WALL)
1976 boolean left_stopped = FALSE, right_stopped = FALSE;
1978 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1979 left_stopped = TRUE;
1980 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1981 right_stopped = TRUE;
1983 if (left_stopped && right_stopped)
1985 else if (left_stopped)
1987 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1988 frame = graphic_info[graphic].anim_frames - 1;
1990 else if (right_stopped)
1992 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1993 frame = graphic_info[graphic].anim_frames - 1;
1998 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1999 else if (mask_mode == USE_MASKING)
2000 DrawGraphicThruMask(x, y, graphic, frame);
2002 DrawGraphic(x, y, graphic, frame);
2005 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
2006 int cut_mode, int mask_mode)
2008 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2009 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
2010 cut_mode, mask_mode);
2013 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
2016 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
2019 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
2022 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
2025 void DrawLevelElementThruMask(int x, int y, int element)
2027 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
2030 void DrawLevelFieldThruMask(int x, int y)
2032 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
2035 /* !!! implementation of quicksand is totally broken !!! */
2036 #define IS_CRUMBLED_TILE(x, y, e) \
2037 (GFX_CRUMBLED(e) && (!IN_LEV_FIELD(x, y) || \
2038 !IS_MOVING(x, y) || \
2039 (e) == EL_QUICKSAND_EMPTYING || \
2040 (e) == EL_QUICKSAND_FAST_EMPTYING))
2042 static void DrawLevelFieldCrumbledInnerCorners(int x, int y, int dx, int dy,
2047 int width, height, cx, cy;
2048 int sx = SCREENX(x), sy = SCREENY(y);
2049 int crumbled_border_size = graphic_info[graphic].border_size;
2050 int crumbled_tile_size = graphic_info[graphic].tile_size;
2051 int crumbled_border_size_var =
2052 crumbled_border_size * TILESIZE_VAR / crumbled_tile_size;
2055 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
2057 for (i = 1; i < 4; i++)
2059 int dxx = (i & 1 ? dx : 0);
2060 int dyy = (i & 2 ? dy : 0);
2063 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
2066 /* check if neighbour field is of same crumble type */
2067 boolean same = (IS_CRUMBLED_TILE(xx, yy, element) &&
2068 graphic_info[graphic].class ==
2069 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class);
2071 /* return if check prevents inner corner */
2072 if (same == (dxx == dx && dyy == dy))
2076 /* if we reach this point, we have an inner corner */
2078 getGraphicSource(graphic, 1, &src_bitmap, &src_x, &src_y);
2080 width = crumbled_border_size_var;
2081 height = crumbled_border_size_var;
2082 cx = (dx > 0 ? TILESIZE_VAR - width : 0);
2083 cy = (dy > 0 ? TILESIZE_VAR - height : 0);
2085 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
2086 width, height, FX + sx * TILEX_VAR + cx, FY + sy * TILEY_VAR + cy);
2089 static void DrawLevelFieldCrumbledBorders(int x, int y, int graphic, int frame,
2094 int width, height, bx, by, cx, cy;
2095 int sx = SCREENX(x), sy = SCREENY(y);
2096 int crumbled_border_size = graphic_info[graphic].border_size;
2097 int crumbled_tile_size = graphic_info[graphic].tile_size;
2098 int crumbled_border_size_var =
2099 crumbled_border_size * TILESIZE_VAR / crumbled_tile_size;
2100 int crumbled_border_pos_var = TILESIZE_VAR - crumbled_border_size_var;
2103 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
2105 /* draw simple, sloppy, non-corner-accurate crumbled border */
2107 width = (dir == 1 || dir == 2 ? crumbled_border_size_var : TILESIZE_VAR);
2108 height = (dir == 0 || dir == 3 ? crumbled_border_size_var : TILESIZE_VAR);
2109 cx = (dir == 2 ? crumbled_border_pos_var : 0);
2110 cy = (dir == 3 ? crumbled_border_pos_var : 0);
2112 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy, width, height,
2113 FX + sx * TILEX_VAR + cx,
2114 FY + sy * TILEY_VAR + cy);
2116 /* (remaining middle border part must be at least as big as corner part) */
2117 if (!(graphic_info[graphic].style & STYLE_ACCURATE_BORDERS) ||
2118 crumbled_border_size_var >= TILESIZE_VAR / 3)
2121 /* correct corners of crumbled border, if needed */
2123 for (i = -1; i <= 1; i += 2)
2125 int xx = x + (dir == 0 || dir == 3 ? i : 0);
2126 int yy = y + (dir == 1 || dir == 2 ? i : 0);
2127 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
2130 /* check if neighbour field is of same crumble type */
2131 if (IS_CRUMBLED_TILE(xx, yy, element) &&
2132 graphic_info[graphic].class ==
2133 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
2135 /* no crumbled corner, but continued crumbled border */
2137 int c1 = (dir == 2 || dir == 3 ? crumbled_border_pos_var : 0);
2138 int c2 = (i == 1 ? crumbled_border_pos_var : 0);
2139 int b1 = (i == 1 ? crumbled_border_size_var :
2140 TILESIZE_VAR - 2 * crumbled_border_size_var);
2142 width = crumbled_border_size_var;
2143 height = crumbled_border_size_var;
2145 if (dir == 1 || dir == 2)
2160 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
2162 FX + sx * TILEX_VAR + cx,
2163 FY + sy * TILEY_VAR + cy);
2168 static void DrawLevelFieldCrumbledExt(int x, int y, int graphic, int frame)
2170 int sx = SCREENX(x), sy = SCREENY(y);
2173 static int xy[4][2] =
2181 if (!IN_LEV_FIELD(x, y))
2184 element = TILE_GFX_ELEMENT(x, y);
2186 if (IS_CRUMBLED_TILE(x, y, element)) /* crumble field itself */
2188 if (!IN_SCR_FIELD(sx, sy))
2191 /* crumble field borders towards direct neighbour fields */
2192 for (i = 0; i < 4; i++)
2194 int xx = x + xy[i][0];
2195 int yy = y + xy[i][1];
2197 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
2200 /* check if neighbour field is of same crumble type */
2201 if (IS_CRUMBLED_TILE(xx, yy, element) &&
2202 graphic_info[graphic].class ==
2203 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
2206 DrawLevelFieldCrumbledBorders(x, y, graphic, frame, i);
2209 /* crumble inner field corners towards corner neighbour fields */
2210 if ((graphic_info[graphic].style & STYLE_INNER_CORNERS) &&
2211 graphic_info[graphic].anim_frames == 2)
2213 for (i = 0; i < 4; i++)
2215 int dx = (i & 1 ? +1 : -1);
2216 int dy = (i & 2 ? +1 : -1);
2218 DrawLevelFieldCrumbledInnerCorners(x, y, dx, dy, graphic);
2222 MarkTileDirty(sx, sy);
2224 else /* center field is not crumbled -- crumble neighbour fields */
2226 /* crumble field borders of direct neighbour fields */
2227 for (i = 0; i < 4; i++)
2229 int xx = x + xy[i][0];
2230 int yy = y + xy[i][1];
2231 int sxx = sx + xy[i][0];
2232 int syy = sy + xy[i][1];
2234 if (!IN_LEV_FIELD(xx, yy) ||
2235 !IN_SCR_FIELD(sxx, syy))
2238 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
2241 element = TILE_GFX_ELEMENT(xx, yy);
2243 if (!IS_CRUMBLED_TILE(xx, yy, element))
2246 graphic = el_act2crm(element, ACTION_DEFAULT);
2248 DrawLevelFieldCrumbledBorders(xx, yy, graphic, 0, 3 - i);
2250 MarkTileDirty(sxx, syy);
2253 /* crumble inner field corners of corner neighbour fields */
2254 for (i = 0; i < 4; i++)
2256 int dx = (i & 1 ? +1 : -1);
2257 int dy = (i & 2 ? +1 : -1);
2263 if (!IN_LEV_FIELD(xx, yy) ||
2264 !IN_SCR_FIELD(sxx, syy))
2267 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
2270 element = TILE_GFX_ELEMENT(xx, yy);
2272 if (!IS_CRUMBLED_TILE(xx, yy, element))
2275 graphic = el_act2crm(element, ACTION_DEFAULT);
2277 if ((graphic_info[graphic].style & STYLE_INNER_CORNERS) &&
2278 graphic_info[graphic].anim_frames == 2)
2279 DrawLevelFieldCrumbledInnerCorners(xx, yy, -dx, -dy, graphic);
2281 MarkTileDirty(sxx, syy);
2286 void DrawLevelFieldCrumbled(int x, int y)
2290 if (!IN_LEV_FIELD(x, y))
2293 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
2294 GfxElement[x][y] != EL_UNDEFINED &&
2295 GFX_CRUMBLED(GfxElement[x][y]))
2297 DrawLevelFieldCrumbledDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
2302 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
2304 DrawLevelFieldCrumbledExt(x, y, graphic, 0);
2307 void DrawLevelFieldCrumbledDigging(int x, int y, int direction,
2310 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
2311 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
2312 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
2313 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
2314 int sx = SCREENX(x), sy = SCREENY(y);
2316 DrawGraphic(sx, sy, graphic1, frame1);
2317 DrawLevelFieldCrumbledExt(x, y, graphic2, frame2);
2320 void DrawLevelFieldCrumbledNeighbours(int x, int y)
2322 int sx = SCREENX(x), sy = SCREENY(y);
2323 static int xy[4][2] =
2332 /* crumble direct neighbour fields (required for field borders) */
2333 for (i = 0; i < 4; i++)
2335 int xx = x + xy[i][0];
2336 int yy = y + xy[i][1];
2337 int sxx = sx + xy[i][0];
2338 int syy = sy + xy[i][1];
2340 if (!IN_LEV_FIELD(xx, yy) ||
2341 !IN_SCR_FIELD(sxx, syy) ||
2342 !GFX_CRUMBLED(Feld[xx][yy]) ||
2346 DrawLevelField(xx, yy);
2349 /* crumble corner neighbour fields (required for inner field corners) */
2350 for (i = 0; i < 4; i++)
2352 int dx = (i & 1 ? +1 : -1);
2353 int dy = (i & 2 ? +1 : -1);
2359 if (!IN_LEV_FIELD(xx, yy) ||
2360 !IN_SCR_FIELD(sxx, syy) ||
2361 !GFX_CRUMBLED(Feld[xx][yy]) ||
2365 int element = TILE_GFX_ELEMENT(xx, yy);
2366 int graphic = el_act2crm(element, ACTION_DEFAULT);
2368 if ((graphic_info[graphic].style & STYLE_INNER_CORNERS) &&
2369 graphic_info[graphic].anim_frames == 2)
2370 DrawLevelField(xx, yy);
2374 static int getBorderElement(int x, int y)
2378 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
2379 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
2380 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
2381 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
2382 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
2383 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
2384 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
2386 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
2387 int steel_position = (x == -1 && y == -1 ? 0 :
2388 x == lev_fieldx && y == -1 ? 1 :
2389 x == -1 && y == lev_fieldy ? 2 :
2390 x == lev_fieldx && y == lev_fieldy ? 3 :
2391 x == -1 || x == lev_fieldx ? 4 :
2392 y == -1 || y == lev_fieldy ? 5 : 6);
2394 return border[steel_position][steel_type];
2397 void DrawScreenElement(int x, int y, int element)
2399 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
2400 DrawLevelFieldCrumbled(LEVELX(x), LEVELY(y));
2403 void DrawLevelElement(int x, int y, int element)
2405 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2406 DrawScreenElement(SCREENX(x), SCREENY(y), element);
2409 void DrawScreenField(int x, int y)
2411 int lx = LEVELX(x), ly = LEVELY(y);
2412 int element, content;
2414 if (!IN_LEV_FIELD(lx, ly))
2416 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
2419 element = getBorderElement(lx, ly);
2421 DrawScreenElement(x, y, element);
2426 element = Feld[lx][ly];
2427 content = Store[lx][ly];
2429 if (IS_MOVING(lx, ly))
2431 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
2432 boolean cut_mode = NO_CUTTING;
2434 if (element == EL_QUICKSAND_EMPTYING ||
2435 element == EL_QUICKSAND_FAST_EMPTYING ||
2436 element == EL_MAGIC_WALL_EMPTYING ||
2437 element == EL_BD_MAGIC_WALL_EMPTYING ||
2438 element == EL_DC_MAGIC_WALL_EMPTYING ||
2439 element == EL_AMOEBA_DROPPING)
2440 cut_mode = CUT_ABOVE;
2441 else if (element == EL_QUICKSAND_FILLING ||
2442 element == EL_QUICKSAND_FAST_FILLING ||
2443 element == EL_MAGIC_WALL_FILLING ||
2444 element == EL_BD_MAGIC_WALL_FILLING ||
2445 element == EL_DC_MAGIC_WALL_FILLING)
2446 cut_mode = CUT_BELOW;
2448 if (cut_mode == CUT_ABOVE)
2449 DrawScreenElement(x, y, element);
2451 DrawScreenElement(x, y, EL_EMPTY);
2454 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
2455 else if (cut_mode == NO_CUTTING)
2456 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
2459 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
2461 if (cut_mode == CUT_BELOW &&
2462 IN_LEV_FIELD(lx, ly + 1) && IN_SCR_FIELD(x, y + 1))
2463 DrawLevelElement(lx, ly + 1, element);
2466 if (content == EL_ACID)
2468 int dir = MovDir[lx][ly];
2469 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
2470 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
2472 DrawLevelElementThruMask(newlx, newly, EL_ACID);
2474 // prevent target field from being drawn again (but without masking)
2475 // (this would happen if target field is scanned after moving element)
2476 Stop[newlx][newly] = TRUE;
2479 else if (IS_BLOCKED(lx, ly))
2484 boolean cut_mode = NO_CUTTING;
2485 int element_old, content_old;
2487 Blocked2Moving(lx, ly, &oldx, &oldy);
2490 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
2491 MovDir[oldx][oldy] == MV_RIGHT);
2493 element_old = Feld[oldx][oldy];
2494 content_old = Store[oldx][oldy];
2496 if (element_old == EL_QUICKSAND_EMPTYING ||
2497 element_old == EL_QUICKSAND_FAST_EMPTYING ||
2498 element_old == EL_MAGIC_WALL_EMPTYING ||
2499 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
2500 element_old == EL_DC_MAGIC_WALL_EMPTYING ||
2501 element_old == EL_AMOEBA_DROPPING)
2502 cut_mode = CUT_ABOVE;
2504 DrawScreenElement(x, y, EL_EMPTY);
2507 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
2509 else if (cut_mode == NO_CUTTING)
2510 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
2513 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
2516 else if (IS_DRAWABLE(element))
2517 DrawScreenElement(x, y, element);
2519 DrawScreenElement(x, y, EL_EMPTY);
2522 void DrawLevelField(int x, int y)
2524 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2525 DrawScreenField(SCREENX(x), SCREENY(y));
2526 else if (IS_MOVING(x, y))
2530 Moving2Blocked(x, y, &newx, &newy);
2531 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
2532 DrawScreenField(SCREENX(newx), SCREENY(newy));
2534 else if (IS_BLOCKED(x, y))
2538 Blocked2Moving(x, y, &oldx, &oldy);
2539 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
2540 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
2544 static void DrawSizedWallExt_MM(int dst_x, int dst_y, int element, int tilesize,
2545 int (*el2img_function)(int), boolean masked,
2546 int element_bits_draw)
2548 int element_base = map_mm_wall_element(element);
2549 int element_bits = (IS_DF_WALL(element) ?
2550 element - EL_DF_WALL_START :
2551 IS_MM_WALL(element) ?
2552 element - EL_MM_WALL_START : EL_EMPTY) & 0x000f;
2553 int graphic = el2img_function(element_base);
2554 int tilesize_draw = tilesize / 2;
2559 getSizedGraphicSource(graphic, 0, tilesize_draw, &src_bitmap, &src_x, &src_y);
2561 for (i = 0; i < 4; i++)
2563 int dst_draw_x = dst_x + (i % 2) * tilesize_draw;
2564 int dst_draw_y = dst_y + (i / 2) * tilesize_draw;
2566 if (!(element_bits_draw & (1 << i)))
2569 if (element_bits & (1 << i))
2572 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y,
2573 tilesize_draw, tilesize_draw, dst_draw_x, dst_draw_y);
2575 BlitBitmap(src_bitmap, drawto, src_x, src_y,
2576 tilesize_draw, tilesize_draw, dst_draw_x, dst_draw_y);
2581 ClearRectangle(drawto, dst_draw_x, dst_draw_y,
2582 tilesize_draw, tilesize_draw);
2587 void DrawSizedWallParts_MM(int x, int y, int element, int tilesize,
2588 boolean masked, int element_bits_draw)
2590 DrawSizedWallExt_MM(SX + x * tilesize, SY + y * tilesize,
2591 element, tilesize, el2edimg, masked, element_bits_draw);
2594 void DrawSizedWall_MM(int dst_x, int dst_y, int element, int tilesize,
2595 int (*el2img_function)(int))
2597 DrawSizedWallExt_MM(dst_x, dst_y, element, tilesize, el2img_function, FALSE,
2601 void DrawSizedElementExt(int x, int y, int element, int tilesize,
2604 if (IS_MM_WALL(element))
2606 DrawSizedWallExt_MM(SX + x * tilesize, SY + y * tilesize,
2607 element, tilesize, el2edimg, masked, 0x000f);
2611 int graphic = el2edimg(element);
2614 DrawSizedGraphicThruMask(x, y, graphic, 0, tilesize);
2616 DrawSizedGraphic(x, y, graphic, 0, tilesize);
2620 void DrawSizedElement(int x, int y, int element, int tilesize)
2622 DrawSizedElementExt(x, y, element, tilesize, FALSE);
2625 void DrawSizedElementThruMask(int x, int y, int element, int tilesize)
2627 DrawSizedElementExt(x, y, element, tilesize, TRUE);
2630 void DrawMiniElement(int x, int y, int element)
2634 graphic = el2edimg(element);
2635 DrawMiniGraphic(x, y, graphic);
2638 void DrawSizedElementOrWall(int sx, int sy, int scroll_x, int scroll_y,
2641 int x = sx + scroll_x, y = sy + scroll_y;
2643 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
2644 DrawSizedElement(sx, sy, EL_EMPTY, tilesize);
2645 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
2646 DrawSizedElement(sx, sy, Feld[x][y], tilesize);
2648 DrawSizedGraphic(sx, sy, el2edimg(getBorderElement(x, y)), 0, tilesize);
2651 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
2653 int x = sx + scroll_x, y = sy + scroll_y;
2655 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
2656 DrawMiniElement(sx, sy, EL_EMPTY);
2657 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
2658 DrawMiniElement(sx, sy, Feld[x][y]);
2660 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
2663 void DrawEnvelopeBackgroundTiles(int graphic, int startx, int starty,
2664 int x, int y, int xsize, int ysize,
2665 int tile_width, int tile_height)
2669 int dst_x = startx + x * tile_width;
2670 int dst_y = starty + y * tile_height;
2671 int width = graphic_info[graphic].width;
2672 int height = graphic_info[graphic].height;
2673 int inner_width_raw = MAX(width - 2 * tile_width, tile_width);
2674 int inner_height_raw = MAX(height - 2 * tile_height, tile_height);
2675 int inner_width = inner_width_raw - (inner_width_raw % tile_width);
2676 int inner_height = inner_height_raw - (inner_height_raw % tile_height);
2677 int inner_sx = (width >= 3 * tile_width ? tile_width : 0);
2678 int inner_sy = (height >= 3 * tile_height ? tile_height : 0);
2679 boolean draw_masked = graphic_info[graphic].draw_masked;
2681 getFixedGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
2683 if (src_bitmap == NULL || width < tile_width || height < tile_height)
2685 ClearRectangle(drawto, dst_x, dst_y, tile_width, tile_height);
2689 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - tile_width :
2690 inner_sx + (x - 1) * tile_width % inner_width);
2691 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - tile_height :
2692 inner_sy + (y - 1) * tile_height % inner_height);
2695 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
2698 BlitBitmap(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
2702 void DrawEnvelopeBackground(int graphic, int startx, int starty,
2703 int x, int y, int xsize, int ysize, int font_nr)
2705 int font_width = getFontWidth(font_nr);
2706 int font_height = getFontHeight(font_nr);
2708 DrawEnvelopeBackgroundTiles(graphic, startx, starty, x, y, xsize, ysize,
2709 font_width, font_height);
2712 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
2714 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2715 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2716 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2717 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2718 boolean no_delay = (tape.warp_forward);
2719 unsigned int anim_delay = 0;
2720 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
2721 int anim_delay_value = MAX(1, (no_delay ? 0 : frame_delay_value) / 2);
2722 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
2723 int font_width = getFontWidth(font_nr);
2724 int font_height = getFontHeight(font_nr);
2725 int max_xsize = level.envelope[envelope_nr].xsize;
2726 int max_ysize = level.envelope[envelope_nr].ysize;
2727 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
2728 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
2729 int xend = max_xsize;
2730 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
2731 int xstep = (xstart < xend ? 1 : 0);
2732 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2734 int end = MAX(xend - xstart, yend - ystart);
2737 for (i = start; i <= end; i++)
2739 int last_frame = end; // last frame of this "for" loop
2740 int x = xstart + i * xstep;
2741 int y = ystart + i * ystep;
2742 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2743 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2744 int sx = SX + (SXSIZE - xsize * font_width) / 2;
2745 int sy = SY + (SYSIZE - ysize * font_height) / 2;
2748 SetDrawtoField(DRAW_TO_FIELDBUFFER);
2750 BlitScreenToBitmap(backbuffer);
2752 SetDrawtoField(DRAW_TO_BACKBUFFER);
2754 for (yy = 0; yy < ysize; yy++)
2755 for (xx = 0; xx < xsize; xx++)
2756 DrawEnvelopeBackground(graphic, sx, sy, xx, yy, xsize, ysize, font_nr);
2758 DrawTextBuffer(sx + font_width, sy + font_height,
2759 level.envelope[envelope_nr].text, font_nr, max_xsize,
2760 xsize - 2, ysize - 2, 0, mask_mode,
2761 level.envelope[envelope_nr].autowrap,
2762 level.envelope[envelope_nr].centered, FALSE);
2764 redraw_mask |= REDRAW_FIELD;
2767 SkipUntilDelayReached(&anim_delay, anim_delay_value, &i, last_frame);
2771 void ShowEnvelope(int envelope_nr)
2773 int element = EL_ENVELOPE_1 + envelope_nr;
2774 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2775 int sound_opening = element_info[element].sound[ACTION_OPENING];
2776 int sound_closing = element_info[element].sound[ACTION_CLOSING];
2777 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2778 boolean no_delay = (tape.warp_forward);
2779 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
2780 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
2781 int anim_mode = graphic_info[graphic].anim_mode;
2782 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2783 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2785 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
2787 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2789 if (anim_mode == ANIM_DEFAULT)
2790 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
2792 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
2795 Delay(wait_delay_value);
2797 WaitForEventToContinue();
2799 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2801 if (anim_mode != ANIM_NONE)
2802 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
2804 if (anim_mode == ANIM_DEFAULT)
2805 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
2807 game.envelope_active = FALSE;
2809 SetDrawtoField(DRAW_TO_FIELDBUFFER);
2811 redraw_mask |= REDRAW_FIELD;
2815 static void setRequestBasePosition(int *x, int *y)
2817 int sx_base, sy_base;
2819 if (request.x != -1)
2820 sx_base = request.x;
2821 else if (request.align == ALIGN_LEFT)
2823 else if (request.align == ALIGN_RIGHT)
2824 sx_base = SX + SXSIZE;
2826 sx_base = SX + SXSIZE / 2;
2828 if (request.y != -1)
2829 sy_base = request.y;
2830 else if (request.valign == VALIGN_TOP)
2832 else if (request.valign == VALIGN_BOTTOM)
2833 sy_base = SY + SYSIZE;
2835 sy_base = SY + SYSIZE / 2;
2841 static void setRequestPositionExt(int *x, int *y, int width, int height,
2842 boolean add_border_size)
2844 int border_size = request.border_size;
2845 int sx_base, sy_base;
2848 setRequestBasePosition(&sx_base, &sy_base);
2850 if (request.align == ALIGN_LEFT)
2852 else if (request.align == ALIGN_RIGHT)
2853 sx = sx_base - width;
2855 sx = sx_base - width / 2;
2857 if (request.valign == VALIGN_TOP)
2859 else if (request.valign == VALIGN_BOTTOM)
2860 sy = sy_base - height;
2862 sy = sy_base - height / 2;
2864 sx = MAX(0, MIN(sx, WIN_XSIZE - width));
2865 sy = MAX(0, MIN(sy, WIN_YSIZE - height));
2867 if (add_border_size)
2877 static void setRequestPosition(int *x, int *y, boolean add_border_size)
2879 setRequestPositionExt(x, y, request.width, request.height, add_border_size);
2882 void DrawEnvelopeRequest(char *text)
2884 char *text_final = text;
2885 char *text_door_style = NULL;
2886 int graphic = IMG_BACKGROUND_REQUEST;
2887 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2888 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2889 int font_nr = FONT_REQUEST;
2890 int font_width = getFontWidth(font_nr);
2891 int font_height = getFontHeight(font_nr);
2892 int border_size = request.border_size;
2893 int line_spacing = request.line_spacing;
2894 int line_height = font_height + line_spacing;
2895 int max_text_width = request.width - 2 * border_size;
2896 int max_text_height = request.height - 2 * border_size;
2897 int line_length = max_text_width / font_width;
2898 int max_lines = max_text_height / line_height;
2899 int text_width = line_length * font_width;
2900 int width = request.width;
2901 int height = request.height;
2902 int tile_size = MAX(request.step_offset, 1);
2903 int x_steps = width / tile_size;
2904 int y_steps = height / tile_size;
2905 int sx_offset = border_size;
2906 int sy_offset = border_size;
2910 if (request.centered)
2911 sx_offset = (request.width - text_width) / 2;
2913 if (request.wrap_single_words && !request.autowrap)
2915 char *src_text_ptr, *dst_text_ptr;
2917 text_door_style = checked_malloc(2 * strlen(text) + 1);
2919 src_text_ptr = text;
2920 dst_text_ptr = text_door_style;
2922 while (*src_text_ptr)
2924 if (*src_text_ptr == ' ' ||
2925 *src_text_ptr == '?' ||
2926 *src_text_ptr == '!')
2927 *dst_text_ptr++ = '\n';
2929 if (*src_text_ptr != ' ')
2930 *dst_text_ptr++ = *src_text_ptr;
2935 *dst_text_ptr = '\0';
2937 text_final = text_door_style;
2940 setRequestPosition(&sx, &sy, FALSE);
2942 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
2944 for (y = 0; y < y_steps; y++)
2945 for (x = 0; x < x_steps; x++)
2946 DrawEnvelopeBackgroundTiles(graphic, sx, sy,
2947 x, y, x_steps, y_steps,
2948 tile_size, tile_size);
2950 /* force DOOR font inside door area */
2951 SetFontStatus(GAME_MODE_PSEUDO_DOOR);
2953 DrawTextBuffer(sx + sx_offset, sy + sy_offset, text_final, font_nr,
2954 line_length, -1, max_lines, line_spacing, mask_mode,
2955 request.autowrap, request.centered, FALSE);
2959 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2960 RedrawGadget(tool_gadget[i]);
2962 // store readily prepared envelope request for later use when animating
2963 BlitBitmap(backbuffer, bitmap_db_store_2, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2965 if (text_door_style)
2966 free(text_door_style);
2969 void AnimateEnvelopeRequest(int anim_mode, int action)
2971 int graphic = IMG_BACKGROUND_REQUEST;
2972 boolean draw_masked = graphic_info[graphic].draw_masked;
2973 int delay_value_normal = request.step_delay;
2974 int delay_value_fast = delay_value_normal / 2;
2975 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2976 boolean no_delay = (tape.warp_forward);
2977 int delay_value = (ffwd_delay ? delay_value_fast : delay_value_normal);
2978 int anim_delay_value = MAX(1, (no_delay ? 0 : delay_value + 500 * 0) / 2);
2979 unsigned int anim_delay = 0;
2981 int tile_size = MAX(request.step_offset, 1);
2982 int max_xsize = request.width / tile_size;
2983 int max_ysize = request.height / tile_size;
2984 int max_xsize_inner = max_xsize - 2;
2985 int max_ysize_inner = max_ysize - 2;
2987 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize_inner : 0);
2988 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize_inner : 0);
2989 int xend = max_xsize_inner;
2990 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize_inner : 0);
2991 int xstep = (xstart < xend ? 1 : 0);
2992 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2994 int end = MAX(xend - xstart, yend - ystart);
2997 if (setup.quick_doors)
3004 for (i = start; i <= end; i++)
3006 int last_frame = end; // last frame of this "for" loop
3007 int x = xstart + i * xstep;
3008 int y = ystart + i * ystep;
3009 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
3010 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
3011 int xsize_size_left = (xsize - 1) * tile_size;
3012 int ysize_size_top = (ysize - 1) * tile_size;
3013 int max_xsize_pos = (max_xsize - 1) * tile_size;
3014 int max_ysize_pos = (max_ysize - 1) * tile_size;
3015 int width = xsize * tile_size;
3016 int height = ysize * tile_size;
3021 setRequestPosition(&src_x, &src_y, FALSE);
3022 setRequestPositionExt(&dst_x, &dst_y, width, height, FALSE);
3024 BlitBitmap(bitmap_db_store_1, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
3026 for (yy = 0; yy < 2; yy++)
3028 for (xx = 0; xx < 2; xx++)
3030 int src_xx = src_x + xx * max_xsize_pos;
3031 int src_yy = src_y + yy * max_ysize_pos;
3032 int dst_xx = dst_x + xx * xsize_size_left;
3033 int dst_yy = dst_y + yy * ysize_size_top;
3034 int xx_size = (xx ? tile_size : xsize_size_left);
3035 int yy_size = (yy ? tile_size : ysize_size_top);
3038 BlitBitmapMasked(bitmap_db_store_2, backbuffer,
3039 src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
3041 BlitBitmap(bitmap_db_store_2, backbuffer,
3042 src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
3046 redraw_mask |= REDRAW_FIELD;
3050 SkipUntilDelayReached(&anim_delay, anim_delay_value, &i, last_frame);
3054 void ShowEnvelopeRequest(char *text, unsigned int req_state, int action)
3056 int graphic = IMG_BACKGROUND_REQUEST;
3057 int sound_opening = SND_REQUEST_OPENING;
3058 int sound_closing = SND_REQUEST_CLOSING;
3059 int anim_mode_1 = request.anim_mode; /* (higher priority) */
3060 int anim_mode_2 = graphic_info[graphic].anim_mode; /* (lower priority) */
3061 int anim_mode = (anim_mode_1 != ANIM_DEFAULT ? anim_mode_1 : anim_mode_2);
3062 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
3063 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
3065 if (game_status == GAME_MODE_PLAYING)
3066 BlitScreenToBitmap(backbuffer);
3068 SetDrawtoField(DRAW_TO_BACKBUFFER);
3070 // SetDrawBackgroundMask(REDRAW_NONE);
3072 if (action == ACTION_OPENING)
3074 BlitBitmap(backbuffer, bitmap_db_store_1, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
3076 if (req_state & REQ_ASK)
3078 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
3079 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
3081 else if (req_state & REQ_CONFIRM)
3083 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
3085 else if (req_state & REQ_PLAYER)
3087 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
3088 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
3089 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
3090 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
3093 DrawEnvelopeRequest(text);
3096 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
3098 if (action == ACTION_OPENING)
3100 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
3102 if (anim_mode == ANIM_DEFAULT)
3103 AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_OPENING);
3105 AnimateEnvelopeRequest(main_anim_mode, ACTION_OPENING);
3109 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
3111 if (anim_mode != ANIM_NONE)
3112 AnimateEnvelopeRequest(main_anim_mode, ACTION_CLOSING);
3114 if (anim_mode == ANIM_DEFAULT)
3115 AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_CLOSING);
3118 game.envelope_active = FALSE;
3120 if (action == ACTION_CLOSING)
3121 BlitBitmap(bitmap_db_store_1, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
3123 // SetDrawBackgroundMask(last_draw_background_mask);
3125 redraw_mask |= REDRAW_FIELD;
3129 if (action == ACTION_CLOSING &&
3130 game_status == GAME_MODE_PLAYING &&
3131 level.game_engine_type == GAME_ENGINE_TYPE_RND)
3132 SetDrawtoField(DRAW_TO_FIELDBUFFER);
3135 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
3137 if (IS_MM_WALL(element))
3139 DrawSizedWall_MM(dst_x, dst_y, element, tilesize, el2preimg);
3145 int graphic = el2preimg(element);
3147 getSizedGraphicSource(graphic, 0, tilesize, &src_bitmap, &src_x, &src_y);
3148 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize,
3153 void DrawLevel(int draw_background_mask)
3157 SetMainBackgroundImage(IMG_BACKGROUND_PLAYING);
3158 SetDrawBackgroundMask(draw_background_mask);
3162 for (x = BX1; x <= BX2; x++)
3163 for (y = BY1; y <= BY2; y++)
3164 DrawScreenField(x, y);
3166 redraw_mask |= REDRAW_FIELD;
3169 void DrawSizedLevel(int size_x, int size_y, int scroll_x, int scroll_y,
3174 for (x = 0; x < size_x; x++)
3175 for (y = 0; y < size_y; y++)
3176 DrawSizedElementOrWall(x, y, scroll_x, scroll_y, tilesize);
3178 redraw_mask |= REDRAW_FIELD;
3181 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
3185 for (x = 0; x < size_x; x++)
3186 for (y = 0; y < size_y; y++)
3187 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
3189 redraw_mask |= REDRAW_FIELD;
3192 static void DrawPreviewLevelPlayfield(int from_x, int from_y)
3194 boolean show_level_border = (BorderElement != EL_EMPTY);
3195 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
3196 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
3197 int tile_size = preview.tile_size;
3198 int preview_width = preview.xsize * tile_size;
3199 int preview_height = preview.ysize * tile_size;
3200 int real_preview_xsize = MIN(level_xsize, preview.xsize);
3201 int real_preview_ysize = MIN(level_ysize, preview.ysize);
3202 int real_preview_width = real_preview_xsize * tile_size;
3203 int real_preview_height = real_preview_ysize * tile_size;
3204 int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
3205 int dst_y = SY + ALIGNED_YPOS(preview.y, preview_height, preview.valign);
3208 if (!IN_GFX_FIELD_FULL(dst_x, dst_y + preview_height - 1))
3211 DrawBackground(dst_x, dst_y, preview_width, preview_height);
3213 dst_x += (preview_width - real_preview_width) / 2;
3214 dst_y += (preview_height - real_preview_height) / 2;
3216 for (x = 0; x < real_preview_xsize; x++)
3218 for (y = 0; y < real_preview_ysize; y++)
3220 int lx = from_x + x + (show_level_border ? -1 : 0);
3221 int ly = from_y + y + (show_level_border ? -1 : 0);
3222 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
3223 getBorderElement(lx, ly));
3225 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
3226 element, tile_size);
3230 redraw_mask |= REDRAW_FIELD;
3233 #define MICROLABEL_EMPTY 0
3234 #define MICROLABEL_LEVEL_NAME 1
3235 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
3236 #define MICROLABEL_LEVEL_AUTHOR 3
3237 #define MICROLABEL_IMPORTED_FROM_HEAD 4
3238 #define MICROLABEL_IMPORTED_FROM 5
3239 #define MICROLABEL_IMPORTED_BY_HEAD 6
3240 #define MICROLABEL_IMPORTED_BY 7
3242 static int getMaxTextLength(struct TextPosInfo *pos, int font_nr)
3244 int max_text_width = SXSIZE;
3245 int font_width = getFontWidth(font_nr);
3247 if (pos->align == ALIGN_CENTER)
3248 max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
3249 else if (pos->align == ALIGN_RIGHT)
3250 max_text_width = pos->x;
3252 max_text_width = SXSIZE - pos->x;
3254 return max_text_width / font_width;
3257 static void DrawPreviewLevelLabelExt(int mode, struct TextPosInfo *pos)
3259 char label_text[MAX_OUTPUT_LINESIZE + 1];
3260 int max_len_label_text;
3261 int font_nr = pos->font;
3264 if (!IN_GFX_FIELD_FULL(pos->x, pos->y + getFontHeight(pos->font)))
3267 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
3268 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
3269 mode == MICROLABEL_IMPORTED_BY_HEAD)
3270 font_nr = pos->font_alt;
3272 max_len_label_text = getMaxTextLength(pos, font_nr);
3274 if (pos->size != -1)
3275 max_len_label_text = pos->size;
3277 for (i = 0; i < max_len_label_text; i++)
3278 label_text[i] = ' ';
3279 label_text[max_len_label_text] = '\0';
3281 if (strlen(label_text) > 0)
3282 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
3285 (mode == MICROLABEL_LEVEL_NAME ? level.name :
3286 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
3287 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
3288 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
3289 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
3290 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
3291 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
3292 max_len_label_text);
3293 label_text[max_len_label_text] = '\0';
3295 if (strlen(label_text) > 0)
3296 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
3298 redraw_mask |= REDRAW_FIELD;
3301 static void DrawPreviewLevelLabel(int mode)
3303 DrawPreviewLevelLabelExt(mode, &menu.main.text.level_info_2);
3306 static void DrawPreviewLevelInfo(int mode)
3308 if (mode == MICROLABEL_LEVEL_NAME)
3309 DrawPreviewLevelLabelExt(mode, &menu.main.text.level_name);
3310 else if (mode == MICROLABEL_LEVEL_AUTHOR)
3311 DrawPreviewLevelLabelExt(mode, &menu.main.text.level_author);
3314 static void DrawPreviewLevelExt(boolean restart)
3316 static unsigned int scroll_delay = 0;
3317 static unsigned int label_delay = 0;
3318 static int from_x, from_y, scroll_direction;
3319 static int label_state, label_counter;
3320 unsigned int scroll_delay_value = preview.step_delay;
3321 boolean show_level_border = (BorderElement != EL_EMPTY);
3322 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
3323 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
3330 if (preview.anim_mode == ANIM_CENTERED)
3332 if (level_xsize > preview.xsize)
3333 from_x = (level_xsize - preview.xsize) / 2;
3334 if (level_ysize > preview.ysize)
3335 from_y = (level_ysize - preview.ysize) / 2;
3338 from_x += preview.xoffset;
3339 from_y += preview.yoffset;
3341 scroll_direction = MV_RIGHT;
3345 DrawPreviewLevelPlayfield(from_x, from_y);
3346 DrawPreviewLevelLabel(label_state);
3348 DrawPreviewLevelInfo(MICROLABEL_LEVEL_NAME);
3349 DrawPreviewLevelInfo(MICROLABEL_LEVEL_AUTHOR);
3351 /* initialize delay counters */
3352 DelayReached(&scroll_delay, 0);
3353 DelayReached(&label_delay, 0);
3355 if (leveldir_current->name)
3357 struct TextPosInfo *pos = &menu.main.text.level_info_1;
3358 char label_text[MAX_OUTPUT_LINESIZE + 1];
3359 int font_nr = pos->font;
3360 int max_len_label_text = getMaxTextLength(pos, font_nr);
3362 if (pos->size != -1)
3363 max_len_label_text = pos->size;
3365 strncpy(label_text, leveldir_current->name, max_len_label_text);
3366 label_text[max_len_label_text] = '\0';
3368 if (IN_GFX_FIELD_FULL(pos->x, pos->y + getFontHeight(pos->font)))
3369 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
3375 /* scroll preview level, if needed */
3376 if (preview.anim_mode != ANIM_NONE &&
3377 (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
3378 DelayReached(&scroll_delay, scroll_delay_value))
3380 switch (scroll_direction)
3385 from_x -= preview.step_offset;
3386 from_x = (from_x < 0 ? 0 : from_x);
3389 scroll_direction = MV_UP;
3393 if (from_x < level_xsize - preview.xsize)
3395 from_x += preview.step_offset;
3396 from_x = (from_x > level_xsize - preview.xsize ?
3397 level_xsize - preview.xsize : from_x);
3400 scroll_direction = MV_DOWN;
3406 from_y -= preview.step_offset;
3407 from_y = (from_y < 0 ? 0 : from_y);
3410 scroll_direction = MV_RIGHT;
3414 if (from_y < level_ysize - preview.ysize)
3416 from_y += preview.step_offset;
3417 from_y = (from_y > level_ysize - preview.ysize ?
3418 level_ysize - preview.ysize : from_y);
3421 scroll_direction = MV_LEFT;
3428 DrawPreviewLevelPlayfield(from_x, from_y);
3431 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
3432 /* redraw micro level label, if needed */
3433 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
3434 !strEqual(level.author, ANONYMOUS_NAME) &&
3435 !strEqual(level.author, leveldir_current->name) &&
3436 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
3438 int max_label_counter = 23;
3440 if (leveldir_current->imported_from != NULL &&
3441 strlen(leveldir_current->imported_from) > 0)
3442 max_label_counter += 14;
3443 if (leveldir_current->imported_by != NULL &&
3444 strlen(leveldir_current->imported_by) > 0)
3445 max_label_counter += 14;
3447 label_counter = (label_counter + 1) % max_label_counter;
3448 label_state = (label_counter >= 0 && label_counter <= 7 ?
3449 MICROLABEL_LEVEL_NAME :
3450 label_counter >= 9 && label_counter <= 12 ?
3451 MICROLABEL_LEVEL_AUTHOR_HEAD :
3452 label_counter >= 14 && label_counter <= 21 ?
3453 MICROLABEL_LEVEL_AUTHOR :
3454 label_counter >= 23 && label_counter <= 26 ?
3455 MICROLABEL_IMPORTED_FROM_HEAD :
3456 label_counter >= 28 && label_counter <= 35 ?
3457 MICROLABEL_IMPORTED_FROM :
3458 label_counter >= 37 && label_counter <= 40 ?
3459 MICROLABEL_IMPORTED_BY_HEAD :
3460 label_counter >= 42 && label_counter <= 49 ?
3461 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
3463 if (leveldir_current->imported_from == NULL &&
3464 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
3465 label_state == MICROLABEL_IMPORTED_FROM))
3466 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
3467 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
3469 DrawPreviewLevelLabel(label_state);
3473 void DrawPreviewLevelInitial()
3475 DrawPreviewLevelExt(TRUE);
3478 void DrawPreviewLevelAnimation()
3480 DrawPreviewLevelExt(FALSE);
3483 inline static void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
3484 int graphic, int sync_frame,
3487 int frame = getGraphicAnimationFrame(graphic, sync_frame);
3489 if (mask_mode == USE_MASKING)
3490 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
3492 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
3495 void DrawFixedGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
3496 int graphic, int sync_frame, int mask_mode)
3498 int frame = getGraphicAnimationFrame(graphic, sync_frame);
3500 if (mask_mode == USE_MASKING)
3501 DrawFixedGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
3503 DrawFixedGraphicExt(dst_bitmap, x, y, graphic, frame);
3506 inline static void DrawGraphicAnimation(int x, int y, int graphic)
3508 int lx = LEVELX(x), ly = LEVELY(y);
3510 if (!IN_SCR_FIELD(x, y))
3513 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
3514 graphic, GfxFrame[lx][ly], NO_MASKING);
3516 MarkTileDirty(x, y);
3519 void DrawFixedGraphicAnimation(int x, int y, int graphic)
3521 int lx = LEVELX(x), ly = LEVELY(y);
3523 if (!IN_SCR_FIELD(x, y))
3526 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
3527 graphic, GfxFrame[lx][ly], NO_MASKING);
3528 MarkTileDirty(x, y);
3531 void DrawLevelGraphicAnimation(int x, int y, int graphic)
3533 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
3536 void DrawLevelElementAnimation(int x, int y, int element)
3538 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
3540 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
3543 void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
3545 int sx = SCREENX(x), sy = SCREENY(y);
3547 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
3550 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
3553 DrawGraphicAnimation(sx, sy, graphic);
3556 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
3557 DrawLevelFieldCrumbled(x, y);
3559 if (GFX_CRUMBLED(Feld[x][y]))
3560 DrawLevelFieldCrumbled(x, y);
3564 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
3566 int sx = SCREENX(x), sy = SCREENY(y);
3569 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
3572 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
3574 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
3577 DrawGraphicAnimation(sx, sy, graphic);
3579 if (GFX_CRUMBLED(element))
3580 DrawLevelFieldCrumbled(x, y);
3583 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
3585 if (player->use_murphy)
3587 /* this works only because currently only one player can be "murphy" ... */
3588 static int last_horizontal_dir = MV_LEFT;
3589 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
3591 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3592 last_horizontal_dir = move_dir;
3594 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
3596 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
3598 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
3604 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
3607 static boolean equalGraphics(int graphic1, int graphic2)
3609 struct GraphicInfo *g1 = &graphic_info[graphic1];
3610 struct GraphicInfo *g2 = &graphic_info[graphic2];
3612 return (g1->bitmap == g2->bitmap &&
3613 g1->src_x == g2->src_x &&
3614 g1->src_y == g2->src_y &&
3615 g1->anim_frames == g2->anim_frames &&
3616 g1->anim_delay == g2->anim_delay &&
3617 g1->anim_mode == g2->anim_mode);
3620 void DrawAllPlayers()
3624 for (i = 0; i < MAX_PLAYERS; i++)
3625 if (stored_player[i].active)
3626 DrawPlayer(&stored_player[i]);
3629 void DrawPlayerField(int x, int y)
3631 if (!IS_PLAYER(x, y))
3634 DrawPlayer(PLAYERINFO(x, y));
3637 #define DRAW_PLAYER_OVER_PUSHED_ELEMENT 1
3639 void DrawPlayer(struct PlayerInfo *player)
3641 int jx = player->jx;
3642 int jy = player->jy;
3643 int move_dir = player->MovDir;
3644 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
3645 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
3646 int last_jx = (player->is_moving ? jx - dx : jx);
3647 int last_jy = (player->is_moving ? jy - dy : jy);
3648 int next_jx = jx + dx;
3649 int next_jy = jy + dy;
3650 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
3651 boolean player_is_opaque = FALSE;
3652 int sx = SCREENX(jx), sy = SCREENY(jy);
3653 int sxx = 0, syy = 0;
3654 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
3656 int action = ACTION_DEFAULT;
3657 int last_player_graphic = getPlayerGraphic(player, move_dir);
3658 int last_player_frame = player->Frame;
3661 /* GfxElement[][] is set to the element the player is digging or collecting;
3662 remove also for off-screen player if the player is not moving anymore */
3663 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
3664 GfxElement[jx][jy] = EL_UNDEFINED;
3666 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
3670 if (!IN_LEV_FIELD(jx, jy))
3672 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
3673 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
3674 printf("DrawPlayerField(): This should never happen!\n");
3679 if (element == EL_EXPLOSION)
3682 action = (player->is_pushing ? ACTION_PUSHING :
3683 player->is_digging ? ACTION_DIGGING :
3684 player->is_collecting ? ACTION_COLLECTING :
3685 player->is_moving ? ACTION_MOVING :
3686 player->is_snapping ? ACTION_SNAPPING :
3687 player->is_dropping ? ACTION_DROPPING :
3688 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
3690 if (player->is_waiting)
3691 move_dir = player->dir_waiting;
3693 InitPlayerGfxAnimation(player, action, move_dir);
3695 /* ----------------------------------------------------------------------- */
3696 /* draw things in the field the player is leaving, if needed */
3697 /* ----------------------------------------------------------------------- */
3699 if (player->is_moving)
3701 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
3703 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
3705 if (last_element == EL_DYNAMITE_ACTIVE ||
3706 last_element == EL_EM_DYNAMITE_ACTIVE ||
3707 last_element == EL_SP_DISK_RED_ACTIVE)
3708 DrawDynamite(last_jx, last_jy);
3710 DrawLevelFieldThruMask(last_jx, last_jy);
3712 else if (last_element == EL_DYNAMITE_ACTIVE ||
3713 last_element == EL_EM_DYNAMITE_ACTIVE ||
3714 last_element == EL_SP_DISK_RED_ACTIVE)
3715 DrawDynamite(last_jx, last_jy);
3717 /* !!! this is not enough to prevent flickering of players which are
3718 moving next to each others without a free tile between them -- this
3719 can only be solved by drawing all players layer by layer (first the
3720 background, then the foreground etc.) !!! => TODO */
3721 else if (!IS_PLAYER(last_jx, last_jy))
3722 DrawLevelField(last_jx, last_jy);
3725 DrawLevelField(last_jx, last_jy);
3728 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
3729 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
3732 if (!IN_SCR_FIELD(sx, sy))
3735 /* ----------------------------------------------------------------------- */
3736 /* draw things behind the player, if needed */
3737 /* ----------------------------------------------------------------------- */
3740 DrawLevelElement(jx, jy, Back[jx][jy]);
3741 else if (IS_ACTIVE_BOMB(element))
3742 DrawLevelElement(jx, jy, EL_EMPTY);
3745 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
3747 int old_element = GfxElement[jx][jy];
3748 int old_graphic = el_act_dir2img(old_element, action, move_dir);
3749 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
3751 if (GFX_CRUMBLED(old_element))
3752 DrawLevelFieldCrumbledDigging(jx, jy, move_dir, player->StepFrame);
3754 DrawGraphic(sx, sy, old_graphic, frame);
3756 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
3757 player_is_opaque = TRUE;
3761 GfxElement[jx][jy] = EL_UNDEFINED;
3763 /* make sure that pushed elements are drawn with correct frame rate */
3764 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
3766 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
3767 GfxFrame[jx][jy] = player->StepFrame;
3769 DrawLevelField(jx, jy);
3773 #if !DRAW_PLAYER_OVER_PUSHED_ELEMENT
3774 /* ----------------------------------------------------------------------- */
3775 /* draw player himself */
3776 /* ----------------------------------------------------------------------- */
3778 graphic = getPlayerGraphic(player, move_dir);
3780 /* in the case of changed player action or direction, prevent the current
3781 animation frame from being restarted for identical animations */
3782 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
3783 player->Frame = last_player_frame;
3785 frame = getGraphicAnimationFrame(graphic, player->Frame);
3789 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3790 sxx = player->GfxPos;
3792 syy = player->GfxPos;
3795 if (player_is_opaque)
3796 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
3798 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3800 if (SHIELD_ON(player))
3802 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
3803 IMG_SHIELD_NORMAL_ACTIVE);
3804 int frame = getGraphicAnimationFrame(graphic, -1);
3806 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3810 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
3813 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3814 sxx = player->GfxPos;
3816 syy = player->GfxPos;
3820 /* ----------------------------------------------------------------------- */
3821 /* draw things the player is pushing, if needed */
3822 /* ----------------------------------------------------------------------- */
3824 if (player->is_pushing && player->is_moving)
3826 int px = SCREENX(jx), py = SCREENY(jy);
3827 int pxx = (TILEX - ABS(sxx)) * dx;
3828 int pyy = (TILEY - ABS(syy)) * dy;
3829 int gfx_frame = GfxFrame[jx][jy];
3835 if (!IS_MOVING(jx, jy)) /* push movement already finished */
3837 element = Feld[next_jx][next_jy];
3838 gfx_frame = GfxFrame[next_jx][next_jy];
3841 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
3843 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
3844 frame = getGraphicAnimationFrame(graphic, sync_frame);
3846 /* draw background element under pushed element (like the Sokoban field) */
3847 if (game.use_masked_pushing && IS_MOVING(jx, jy))
3849 /* this allows transparent pushing animation over non-black background */
3852 DrawLevelElement(jx, jy, Back[jx][jy]);
3854 DrawLevelElement(jx, jy, EL_EMPTY);
3856 if (Back[next_jx][next_jy])
3857 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3859 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
3861 else if (Back[next_jx][next_jy])
3862 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3865 /* do not draw (EM style) pushing animation when pushing is finished */
3866 /* (two-tile animations usually do not contain start and end frame) */
3867 if (graphic_info[graphic].double_movement && !IS_MOVING(jx, jy))
3868 DrawLevelElement(next_jx, next_jy, Feld[next_jx][next_jy]);
3870 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3872 /* masked drawing is needed for EMC style (double) movement graphics */
3873 /* !!! (ONLY WHEN DRAWING PUSHED ELEMENT OVER THE PLAYER) !!! */
3874 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3878 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
3879 /* ----------------------------------------------------------------------- */
3880 /* draw player himself */
3881 /* ----------------------------------------------------------------------- */
3883 graphic = getPlayerGraphic(player, move_dir);
3885 /* in the case of changed player action or direction, prevent the current
3886 animation frame from being restarted for identical animations */
3887 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
3888 player->Frame = last_player_frame;
3890 frame = getGraphicAnimationFrame(graphic, player->Frame);
3894 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3895 sxx = player->GfxPos;
3897 syy = player->GfxPos;
3900 if (player_is_opaque)
3901 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
3903 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3905 if (SHIELD_ON(player))
3907 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
3908 IMG_SHIELD_NORMAL_ACTIVE);
3909 int frame = getGraphicAnimationFrame(graphic, -1);
3911 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3915 /* ----------------------------------------------------------------------- */
3916 /* draw things in front of player (active dynamite or dynabombs) */
3917 /* ----------------------------------------------------------------------- */
3919 if (IS_ACTIVE_BOMB(element))
3921 graphic = el2img(element);
3922 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
3924 if (game.emulation == EMU_SUPAPLEX)
3925 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
3927 DrawGraphicThruMask(sx, sy, graphic, frame);
3930 if (player_is_moving && last_element == EL_EXPLOSION)
3932 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
3933 GfxElement[last_jx][last_jy] : EL_EMPTY);
3934 int graphic = el_act2img(element, ACTION_EXPLODING);
3935 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
3936 int phase = ExplodePhase[last_jx][last_jy] - 1;
3937 int frame = getGraphicAnimationFrame(graphic, phase - delay);
3940 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
3943 /* ----------------------------------------------------------------------- */
3944 /* draw elements the player is just walking/passing through/under */
3945 /* ----------------------------------------------------------------------- */
3947 if (player_is_moving)
3949 /* handle the field the player is leaving ... */
3950 if (IS_ACCESSIBLE_INSIDE(last_element))
3951 DrawLevelField(last_jx, last_jy);
3952 else if (IS_ACCESSIBLE_UNDER(last_element))
3953 DrawLevelFieldThruMask(last_jx, last_jy);
3956 /* do not redraw accessible elements if the player is just pushing them */
3957 if (!player_is_moving || !player->is_pushing)
3959 /* ... and the field the player is entering */
3960 if (IS_ACCESSIBLE_INSIDE(element))
3961 DrawLevelField(jx, jy);
3962 else if (IS_ACCESSIBLE_UNDER(element))
3963 DrawLevelFieldThruMask(jx, jy);
3966 MarkTileDirty(sx, sy);
3969 /* ------------------------------------------------------------------------- */
3971 void WaitForEventToContinue()
3973 boolean still_wait = TRUE;
3975 if (program.headless)
3978 /* simulate releasing mouse button over last gadget, if still pressed */
3980 HandleGadgets(-1, -1, 0);
3982 button_status = MB_RELEASED;
3990 if (NextValidEvent(&event))
3994 case EVENT_BUTTONPRESS:
3995 case EVENT_KEYPRESS:
3996 #if defined(TARGET_SDL2)
3997 case SDL_CONTROLLERBUTTONDOWN:
3999 case SDL_JOYBUTTONDOWN:
4003 case EVENT_KEYRELEASE:
4004 ClearPlayerAction();
4008 HandleOtherEvents(&event);
4012 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
4021 #define MAX_REQUEST_LINES 13
4022 #define MAX_REQUEST_LINE_FONT1_LEN 7
4023 #define MAX_REQUEST_LINE_FONT2_LEN 10
4025 static int RequestHandleEvents(unsigned int req_state)
4027 boolean level_solved = (game_status == GAME_MODE_PLAYING &&
4028 local_player->LevelSolved_GameEnd);
4029 int width = request.width;
4030 int height = request.height;
4034 setRequestPosition(&sx, &sy, FALSE);
4036 button_status = MB_RELEASED;
4038 request_gadget_id = -1;
4045 /* the MM game engine does not use a special (scrollable) field buffer */
4046 if (level.game_engine_type != GAME_ENGINE_TYPE_MM)
4047 SetDrawtoField(DRAW_TO_FIELDBUFFER);
4049 HandleGameActions();
4051 SetDrawtoField(DRAW_TO_BACKBUFFER);
4053 if (global.use_envelope_request)
4055 /* copy current state of request area to middle of playfield area */
4056 BlitBitmap(bitmap_db_store_2, drawto, sx, sy, width, height, sx, sy);
4064 while (NextValidEvent(&event))
4068 case EVENT_BUTTONPRESS:
4069 case EVENT_BUTTONRELEASE:
4070 case EVENT_MOTIONNOTIFY:
4074 if (event.type == EVENT_MOTIONNOTIFY)
4079 motion_status = TRUE;
4080 mx = ((MotionEvent *) &event)->x;
4081 my = ((MotionEvent *) &event)->y;
4085 motion_status = FALSE;
4086 mx = ((ButtonEvent *) &event)->x;
4087 my = ((ButtonEvent *) &event)->y;
4088 if (event.type == EVENT_BUTTONPRESS)
4089 button_status = ((ButtonEvent *) &event)->button;
4091 button_status = MB_RELEASED;
4094 /* this sets 'request_gadget_id' */
4095 HandleGadgets(mx, my, button_status);
4097 switch (request_gadget_id)
4099 case TOOL_CTRL_ID_YES:
4102 case TOOL_CTRL_ID_NO:
4105 case TOOL_CTRL_ID_CONFIRM:
4106 result = TRUE | FALSE;
4109 case TOOL_CTRL_ID_PLAYER_1:
4112 case TOOL_CTRL_ID_PLAYER_2:
4115 case TOOL_CTRL_ID_PLAYER_3:
4118 case TOOL_CTRL_ID_PLAYER_4:
4129 #if defined(TARGET_SDL2)
4130 case SDL_WINDOWEVENT:
4131 HandleWindowEvent((WindowEvent *) &event);
4134 case SDL_APP_WILLENTERBACKGROUND:
4135 case SDL_APP_DIDENTERBACKGROUND:
4136 case SDL_APP_WILLENTERFOREGROUND:
4137 case SDL_APP_DIDENTERFOREGROUND:
4138 HandlePauseResumeEvent((PauseResumeEvent *) &event);
4142 case EVENT_KEYPRESS:
4144 Key key = GetEventKey((KeyEvent *)&event, TRUE);
4149 if (req_state & REQ_CONFIRM)
4154 #if defined(TARGET_SDL2)
4157 #if defined(KSYM_Rewind)
4158 case KSYM_Rewind: /* for Amazon Fire TV remote */
4165 #if defined(TARGET_SDL2)
4167 #if defined(KSYM_FastForward)
4168 case KSYM_FastForward: /* for Amazon Fire TV remote */
4175 HandleKeysDebug(key);
4179 if (req_state & REQ_PLAYER)
4185 case EVENT_KEYRELEASE:
4186 ClearPlayerAction();
4189 #if defined(TARGET_SDL2)
4190 case SDL_CONTROLLERBUTTONDOWN:
4191 switch (event.cbutton.button)
4193 case SDL_CONTROLLER_BUTTON_A:
4194 case SDL_CONTROLLER_BUTTON_X:
4195 case SDL_CONTROLLER_BUTTON_LEFTSHOULDER:
4199 case SDL_CONTROLLER_BUTTON_B:
4200 case SDL_CONTROLLER_BUTTON_Y:
4201 case SDL_CONTROLLER_BUTTON_RIGHTSHOULDER:
4202 case SDL_CONTROLLER_BUTTON_BACK:
4207 if (req_state & REQ_PLAYER)
4212 case SDL_CONTROLLERBUTTONUP:
4213 HandleJoystickEvent(&event);
4214 ClearPlayerAction();
4219 HandleOtherEvents(&event);
4224 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
4226 int joy = AnyJoystick();
4228 if (joy & JOY_BUTTON_1)
4230 else if (joy & JOY_BUTTON_2)
4236 if (global.use_envelope_request)
4238 /* copy back current state of pressed buttons inside request area */
4239 BlitBitmap(drawto, bitmap_db_store_2, sx, sy, width, height, sx, sy);
4249 static boolean RequestDoor(char *text, unsigned int req_state)
4251 unsigned int old_door_state;
4252 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
4253 int font_nr = FONT_TEXT_2;
4258 if (maxWordLengthInString(text) > MAX_REQUEST_LINE_FONT1_LEN)
4260 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
4261 font_nr = FONT_TEXT_1;
4264 if (game_status == GAME_MODE_PLAYING)
4265 BlitScreenToBitmap(backbuffer);
4267 /* disable deactivated drawing when quick-loading level tape recording */
4268 if (tape.playing && tape.deactivate_display)
4269 TapeDeactivateDisplayOff(TRUE);
4271 SetMouseCursor(CURSOR_DEFAULT);
4273 #if defined(NETWORK_AVALIABLE)
4274 /* pause network game while waiting for request to answer */
4275 if (options.network &&
4276 game_status == GAME_MODE_PLAYING &&
4277 req_state & REQUEST_WAIT_FOR_INPUT)
4278 SendToServer_PausePlaying();
4281 old_door_state = GetDoorState();
4283 /* simulate releasing mouse button over last gadget, if still pressed */
4285 HandleGadgets(-1, -1, 0);
4289 /* draw released gadget before proceeding */
4292 if (old_door_state & DOOR_OPEN_1)
4294 CloseDoor(DOOR_CLOSE_1);
4296 /* save old door content */
4297 BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
4298 0 * DXSIZE, 0, DXSIZE, DYSIZE, 1 * DXSIZE, 0);
4301 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
4302 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4304 /* clear door drawing field */
4305 DrawBackground(DX, DY, DXSIZE, DYSIZE);
4307 /* force DOOR font inside door area */
4308 SetFontStatus(GAME_MODE_PSEUDO_DOOR);
4310 /* write text for request */
4311 for (text_ptr = text, ty = 0; ty < MAX_REQUEST_LINES; ty++)
4313 char text_line[max_request_line_len + 1];
4319 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
4321 tc = *(text_ptr + tx);
4322 // if (!tc || tc == ' ')
4323 if (!tc || tc == ' ' || tc == '?' || tc == '!')
4327 if ((tc == '?' || tc == '!') && tl == 0)
4337 strncpy(text_line, text_ptr, tl);
4340 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
4341 DY + 8 + ty * (getFontHeight(font_nr) + 2),
4342 text_line, font_nr);
4344 text_ptr += tl + (tc == ' ' ? 1 : 0);
4345 // text_ptr += tl + (tc == ' ' || tc == '?' || tc == '!' ? 1 : 0);
4350 if (req_state & REQ_ASK)
4352 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
4353 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
4355 else if (req_state & REQ_CONFIRM)
4357 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
4359 else if (req_state & REQ_PLAYER)
4361 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
4362 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
4363 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
4364 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
4367 /* copy request gadgets to door backbuffer */
4368 BlitBitmap(drawto, bitmap_db_door_1, DX, DY, DXSIZE, DYSIZE, 0, 0);
4370 OpenDoor(DOOR_OPEN_1);
4372 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
4374 if (game_status == GAME_MODE_PLAYING)
4376 SetPanelBackground();
4377 SetDrawBackgroundMask(REDRAW_DOOR_1);
4381 SetDrawBackgroundMask(REDRAW_FIELD);
4387 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4389 // ---------- handle request buttons ----------
4390 result = RequestHandleEvents(req_state);
4394 if (!(req_state & REQ_STAY_OPEN))
4396 CloseDoor(DOOR_CLOSE_1);
4398 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
4399 (req_state & REQ_REOPEN))
4400 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
4405 if (game_status == GAME_MODE_PLAYING)
4407 SetPanelBackground();
4408 SetDrawBackgroundMask(REDRAW_DOOR_1);
4412 SetDrawBackgroundMask(REDRAW_FIELD);
4415 #if defined(NETWORK_AVALIABLE)
4416 /* continue network game after request */
4417 if (options.network &&
4418 game_status == GAME_MODE_PLAYING &&
4419 req_state & REQUEST_WAIT_FOR_INPUT)
4420 SendToServer_ContinuePlaying();
4423 /* restore deactivated drawing when quick-loading level tape recording */
4424 if (tape.playing && tape.deactivate_display)
4425 TapeDeactivateDisplayOn();
4430 static boolean RequestEnvelope(char *text, unsigned int req_state)
4434 if (game_status == GAME_MODE_PLAYING)
4435 BlitScreenToBitmap(backbuffer);
4437 /* disable deactivated drawing when quick-loading level tape recording */
4438 if (tape.playing && tape.deactivate_display)
4439 TapeDeactivateDisplayOff(TRUE);
4441 SetMouseCursor(CURSOR_DEFAULT);
4443 #if defined(NETWORK_AVALIABLE)
4444 /* pause network game while waiting for request to answer */
4445 if (options.network &&
4446 game_status == GAME_MODE_PLAYING &&
4447 req_state & REQUEST_WAIT_FOR_INPUT)
4448 SendToServer_PausePlaying();
4451 /* simulate releasing mouse button over last gadget, if still pressed */
4453 HandleGadgets(-1, -1, 0);
4457 // (replace with setting corresponding request background)
4458 // SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
4459 // SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4461 /* clear door drawing field */
4462 // DrawBackground(DX, DY, DXSIZE, DYSIZE);
4464 ShowEnvelopeRequest(text, req_state, ACTION_OPENING);
4466 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
4468 if (game_status == GAME_MODE_PLAYING)
4470 SetPanelBackground();
4471 SetDrawBackgroundMask(REDRAW_DOOR_1);
4475 SetDrawBackgroundMask(REDRAW_FIELD);
4481 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4483 // ---------- handle request buttons ----------
4484 result = RequestHandleEvents(req_state);
4488 ShowEnvelopeRequest(text, req_state, ACTION_CLOSING);
4492 if (game_status == GAME_MODE_PLAYING)
4494 SetPanelBackground();
4495 SetDrawBackgroundMask(REDRAW_DOOR_1);
4499 SetDrawBackgroundMask(REDRAW_FIELD);
4502 #if defined(NETWORK_AVALIABLE)
4503 /* continue network game after request */
4504 if (options.network &&
4505 game_status == GAME_MODE_PLAYING &&
4506 req_state & REQUEST_WAIT_FOR_INPUT)
4507 SendToServer_ContinuePlaying();
4510 /* restore deactivated drawing when quick-loading level tape recording */
4511 if (tape.playing && tape.deactivate_display)
4512 TapeDeactivateDisplayOn();
4517 boolean Request(char *text, unsigned int req_state)
4519 boolean overlay_active = GetOverlayActive();
4522 SetOverlayActive(FALSE);
4524 if (global.use_envelope_request)
4525 result = RequestEnvelope(text, req_state);
4527 result = RequestDoor(text, req_state);
4529 SetOverlayActive(overlay_active);
4534 static int compareDoorPartOrderInfo(const void *object1, const void *object2)
4536 const struct DoorPartOrderInfo *dpo1 = (struct DoorPartOrderInfo *)object1;
4537 const struct DoorPartOrderInfo *dpo2 = (struct DoorPartOrderInfo *)object2;
4540 if (dpo1->sort_priority != dpo2->sort_priority)
4541 compare_result = dpo1->sort_priority - dpo2->sort_priority;
4543 compare_result = dpo1->nr - dpo2->nr;
4545 return compare_result;
4548 void InitGraphicCompatibilityInfo_Doors()
4554 struct DoorInfo *door;
4558 { DOOR_1, IMG_GFX_DOOR_1_PART_1, IMG_GFX_DOOR_1_PART_8, &door_1 },
4559 { DOOR_2, IMG_GFX_DOOR_2_PART_1, IMG_GFX_DOOR_2_PART_8, &door_2 },
4561 { -1, -1, -1, NULL }
4563 struct Rect door_rect_list[] =
4565 { DX, DY, DXSIZE, DYSIZE },
4566 { VX, VY, VXSIZE, VYSIZE }
4570 for (i = 0; doors[i].door_token != -1; i++)
4572 int door_token = doors[i].door_token;
4573 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
4574 int part_1 = doors[i].part_1;
4575 int part_8 = doors[i].part_8;
4576 int part_2 = part_1 + 1;
4577 int part_3 = part_1 + 2;
4578 struct DoorInfo *door = doors[i].door;
4579 struct Rect *door_rect = &door_rect_list[door_index];
4580 boolean door_gfx_redefined = FALSE;
4582 /* check if any door part graphic definitions have been redefined */
4584 for (j = 0; door_part_controls[j].door_token != -1; j++)
4586 struct DoorPartControlInfo *dpc = &door_part_controls[j];
4587 struct FileInfo *fi = getImageListEntryFromImageID(dpc->graphic);
4589 if (dpc->door_token == door_token && fi->redefined)
4590 door_gfx_redefined = TRUE;
4593 /* check for old-style door graphic/animation modifications */
4595 if (!door_gfx_redefined)
4597 if (door->anim_mode & ANIM_STATIC_PANEL)
4599 door->panel.step_xoffset = 0;
4600 door->panel.step_yoffset = 0;
4603 if (door->anim_mode & (ANIM_HORIZONTAL | ANIM_VERTICAL))
4605 struct GraphicInfo *g_part_1 = &graphic_info[part_1];
4606 struct GraphicInfo *g_part_2 = &graphic_info[part_2];
4607 int num_door_steps, num_panel_steps;
4609 /* remove door part graphics other than the two default wings */
4611 for (j = 0; door_part_controls[j].door_token != -1; j++)
4613 struct DoorPartControlInfo *dpc = &door_part_controls[j];
4614 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4616 if (dpc->graphic >= part_3 &&
4617 dpc->graphic <= part_8)
4621 /* set graphics and screen positions of the default wings */
4623 g_part_1->width = door_rect->width;
4624 g_part_1->height = door_rect->height;
4625 g_part_2->width = door_rect->width;
4626 g_part_2->height = door_rect->height;
4627 g_part_2->src_x = door_rect->width;
4628 g_part_2->src_y = g_part_1->src_y;
4630 door->part_2.x = door->part_1.x;
4631 door->part_2.y = door->part_1.y;
4633 if (door->width != -1)
4635 g_part_1->width = door->width;
4636 g_part_2->width = door->width;
4638 // special treatment for graphics and screen position of right wing
4639 g_part_2->src_x += door_rect->width - door->width;
4640 door->part_2.x += door_rect->width - door->width;
4643 if (door->height != -1)
4645 g_part_1->height = door->height;
4646 g_part_2->height = door->height;
4648 // special treatment for graphics and screen position of bottom wing
4649 g_part_2->src_y += door_rect->height - door->height;
4650 door->part_2.y += door_rect->height - door->height;
4653 /* set animation delays for the default wings and panels */
4655 door->part_1.step_delay = door->step_delay;
4656 door->part_2.step_delay = door->step_delay;
4657 door->panel.step_delay = door->step_delay;
4659 /* set animation draw order for the default wings */
4661 door->part_1.sort_priority = 2; /* draw left wing over ... */
4662 door->part_2.sort_priority = 1; /* ... right wing */
4664 /* set animation draw offset for the default wings */
4666 if (door->anim_mode & ANIM_HORIZONTAL)
4668 door->part_1.step_xoffset = door->step_offset;
4669 door->part_1.step_yoffset = 0;
4670 door->part_2.step_xoffset = door->step_offset * -1;
4671 door->part_2.step_yoffset = 0;
4673 num_door_steps = g_part_1->width / door->step_offset;
4675 else // ANIM_VERTICAL
4677 door->part_1.step_xoffset = 0;
4678 door->part_1.step_yoffset = door->step_offset;
4679 door->part_2.step_xoffset = 0;
4680 door->part_2.step_yoffset = door->step_offset * -1;
4682 num_door_steps = g_part_1->height / door->step_offset;
4685 /* set animation draw offset for the default panels */
4687 if (door->step_offset > 1)
4689 num_panel_steps = 2 * door_rect->height / door->step_offset;
4690 door->panel.start_step = num_panel_steps - num_door_steps;
4691 door->panel.start_step_closing = door->panel.start_step;
4695 num_panel_steps = door_rect->height / door->step_offset;
4696 door->panel.start_step = num_panel_steps - num_door_steps / 2;
4697 door->panel.start_step_closing = door->panel.start_step;
4698 door->panel.step_delay *= 2;
4709 for (i = 0; door_part_controls[i].door_token != -1; i++)
4711 struct DoorPartControlInfo *dpc = &door_part_controls[i];
4712 struct DoorPartOrderInfo *dpo = &door_part_order[i];
4714 /* initialize "start_step_opening" and "start_step_closing", if needed */
4715 if (dpc->pos->start_step_opening == 0 &&
4716 dpc->pos->start_step_closing == 0)
4718 // dpc->pos->start_step_opening = dpc->pos->start_step;
4719 dpc->pos->start_step_closing = dpc->pos->start_step;
4722 /* fill structure for door part draw order (sorted below) */
4724 dpo->sort_priority = dpc->pos->sort_priority;
4727 /* sort door part controls according to sort_priority and graphic number */
4728 qsort(door_part_order, MAX_DOOR_PARTS,
4729 sizeof(struct DoorPartOrderInfo), compareDoorPartOrderInfo);
4732 unsigned int OpenDoor(unsigned int door_state)
4734 if (door_state & DOOR_COPY_BACK)
4736 if (door_state & DOOR_OPEN_1)
4737 BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
4738 1 * DXSIZE, 0, DXSIZE, DYSIZE, 0 * DXSIZE, 0);
4740 if (door_state & DOOR_OPEN_2)
4741 BlitBitmap(bitmap_db_door_2, bitmap_db_door_2,
4742 1 * VXSIZE, 0, VXSIZE, VYSIZE, 0 * VXSIZE, 0);
4744 door_state &= ~DOOR_COPY_BACK;
4747 return MoveDoor(door_state);
4750 unsigned int CloseDoor(unsigned int door_state)
4752 unsigned int old_door_state = GetDoorState();
4754 if (!(door_state & DOOR_NO_COPY_BACK))
4756 if (old_door_state & DOOR_OPEN_1)
4757 BlitBitmap(backbuffer, bitmap_db_door_1,
4758 DX, DY, DXSIZE, DYSIZE, 0, 0);
4760 if (old_door_state & DOOR_OPEN_2)
4761 BlitBitmap(backbuffer, bitmap_db_door_2,
4762 VX, VY, VXSIZE, VYSIZE, 0, 0);
4764 door_state &= ~DOOR_NO_COPY_BACK;
4767 return MoveDoor(door_state);
4770 unsigned int GetDoorState()
4772 return MoveDoor(DOOR_GET_STATE);
4775 unsigned int SetDoorState(unsigned int door_state)
4777 return MoveDoor(door_state | DOOR_SET_STATE);
4780 int euclid(int a, int b)
4782 return (b ? euclid(b, a % b) : a);
4785 unsigned int MoveDoor(unsigned int door_state)
4787 struct Rect door_rect_list[] =
4789 { DX, DY, DXSIZE, DYSIZE },
4790 { VX, VY, VXSIZE, VYSIZE }
4792 static int door1 = DOOR_CLOSE_1;
4793 static int door2 = DOOR_CLOSE_2;
4794 unsigned int door_delay = 0;
4795 unsigned int door_delay_value;
4798 if (door_state == DOOR_GET_STATE)
4799 return (door1 | door2);
4801 if (door_state & DOOR_SET_STATE)
4803 if (door_state & DOOR_ACTION_1)
4804 door1 = door_state & DOOR_ACTION_1;
4805 if (door_state & DOOR_ACTION_2)
4806 door2 = door_state & DOOR_ACTION_2;
4808 return (door1 | door2);
4811 if (!(door_state & DOOR_FORCE_REDRAW))
4813 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
4814 door_state &= ~DOOR_OPEN_1;
4815 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
4816 door_state &= ~DOOR_CLOSE_1;
4817 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
4818 door_state &= ~DOOR_OPEN_2;
4819 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
4820 door_state &= ~DOOR_CLOSE_2;
4823 if (global.autoplay_leveldir)
4825 door_state |= DOOR_NO_DELAY;
4826 door_state &= ~DOOR_CLOSE_ALL;
4829 if (game_status == GAME_MODE_EDITOR && !(door_state & DOOR_FORCE_ANIM))
4830 door_state |= DOOR_NO_DELAY;
4832 if (door_state & DOOR_ACTION)
4834 boolean door_panel_drawn[NUM_DOORS];
4835 boolean panel_has_doors[NUM_DOORS];
4836 boolean door_part_skip[MAX_DOOR_PARTS];
4837 boolean door_part_done[MAX_DOOR_PARTS];
4838 boolean door_part_done_all;
4839 int num_steps[MAX_DOOR_PARTS];
4840 int max_move_delay = 0; // delay for complete animations of all doors
4841 int max_step_delay = 0; // delay (ms) between two animation frames
4842 int num_move_steps = 0; // number of animation steps for all doors
4843 int max_move_delay_doors_only = 0; // delay for doors only (no panel)
4844 int num_move_steps_doors_only = 0; // steps for doors only (no panel)
4845 int current_move_delay = 0;
4849 for (i = 0; i < NUM_DOORS; i++)
4850 panel_has_doors[i] = FALSE;
4852 for (i = 0; i < MAX_DOOR_PARTS; i++)
4854 struct DoorPartControlInfo *dpc = &door_part_controls[i];
4855 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4856 int door_token = dpc->door_token;
4858 door_part_done[i] = FALSE;
4859 door_part_skip[i] = (!(door_state & door_token) ||
4863 for (i = 0; i < MAX_DOOR_PARTS; i++)
4865 int nr = door_part_order[i].nr;
4866 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
4867 struct DoorPartPosInfo *pos = dpc->pos;
4868 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4869 int door_token = dpc->door_token;
4870 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
4871 boolean is_panel = DOOR_PART_IS_PANEL(nr);
4872 int step_xoffset = ABS(pos->step_xoffset);
4873 int step_yoffset = ABS(pos->step_yoffset);
4874 int step_delay = pos->step_delay;
4875 int current_door_state = door_state & door_token;
4876 boolean door_opening = ((current_door_state & DOOR_OPEN) != 0);
4877 boolean door_closing = ((current_door_state & DOOR_CLOSE) != 0);
4878 boolean part_opening = (is_panel ? door_closing : door_opening);
4879 int start_step = (part_opening ? pos->start_step_opening :
4880 pos->start_step_closing);
4881 float move_xsize = (step_xoffset ? g->width : 0);
4882 float move_ysize = (step_yoffset ? g->height : 0);
4883 int move_xsteps = (step_xoffset ? ceil(move_xsize / step_xoffset) : 0);
4884 int move_ysteps = (step_yoffset ? ceil(move_ysize / step_yoffset) : 0);
4885 int move_steps = (move_xsteps && move_ysteps ?
4886 MIN(move_xsteps, move_ysteps) :
4887 move_xsteps ? move_xsteps : move_ysteps) - start_step;
4888 int move_delay = move_steps * step_delay;
4890 if (door_part_skip[nr])
4893 max_move_delay = MAX(max_move_delay, move_delay);
4894 max_step_delay = (max_step_delay == 0 ? step_delay :
4895 euclid(max_step_delay, step_delay));
4896 num_steps[nr] = move_steps;
4900 max_move_delay_doors_only = MAX(max_move_delay_doors_only, move_delay);
4902 panel_has_doors[door_index] = TRUE;
4906 max_step_delay = MAX(1, max_step_delay); // prevent division by zero
4908 num_move_steps = max_move_delay / max_step_delay;
4909 num_move_steps_doors_only = max_move_delay_doors_only / max_step_delay;
4911 door_delay_value = max_step_delay;
4913 if ((door_state & DOOR_NO_DELAY) || setup.quick_doors)
4915 start = num_move_steps - 1;
4919 /* opening door sound has priority over simultaneously closing door */
4920 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
4922 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
4924 if (door_state & DOOR_OPEN_1)
4925 PlayMenuSoundStereo(SND_DOOR_1_OPENING, SOUND_MIDDLE);
4926 if (door_state & DOOR_OPEN_2)
4927 PlayMenuSoundStereo(SND_DOOR_2_OPENING, SOUND_MIDDLE);
4929 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
4931 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
4933 if (door_state & DOOR_CLOSE_1)
4934 PlayMenuSoundStereo(SND_DOOR_1_CLOSING, SOUND_MIDDLE);
4935 if (door_state & DOOR_CLOSE_2)
4936 PlayMenuSoundStereo(SND_DOOR_2_CLOSING, SOUND_MIDDLE);
4940 for (k = start; k < num_move_steps; k++)
4942 int last_frame = num_move_steps - 1; // last frame of this "for" loop
4944 door_part_done_all = TRUE;
4946 for (i = 0; i < NUM_DOORS; i++)
4947 door_panel_drawn[i] = FALSE;
4949 for (i = 0; i < MAX_DOOR_PARTS; i++)
4951 int nr = door_part_order[i].nr;
4952 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
4953 struct DoorPartPosInfo *pos = dpc->pos;
4954 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4955 int door_token = dpc->door_token;
4956 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
4957 boolean is_panel = DOOR_PART_IS_PANEL(nr);
4958 boolean is_panel_and_door_has_closed = FALSE;
4959 struct Rect *door_rect = &door_rect_list[door_index];
4960 Bitmap *bitmap_db_door = (door_token == DOOR_1 ? bitmap_db_door_1 :
4962 Bitmap *bitmap = (is_panel ? bitmap_db_door : g->bitmap);
4963 int current_door_state = door_state & door_token;
4964 boolean door_opening = ((current_door_state & DOOR_OPEN) != 0);
4965 boolean door_closing = !door_opening;
4966 boolean part_opening = (is_panel ? door_closing : door_opening);
4967 boolean part_closing = !part_opening;
4968 int start_step = (part_opening ? pos->start_step_opening :
4969 pos->start_step_closing);
4970 int step_delay = pos->step_delay;
4971 int step_factor = step_delay / max_step_delay;
4972 int k1 = (step_factor ? k / step_factor + 1 : k);
4973 int k2 = (part_opening ? k1 + start_step : num_steps[nr] - k1);
4974 int kk = MAX(0, k2);
4977 int src_x, src_y, src_xx, src_yy;
4978 int dst_x, dst_y, dst_xx, dst_yy;
4981 if (door_part_skip[nr])
4984 if (!(door_state & door_token))
4992 int k2_door = (door_opening ? k : num_move_steps_doors_only - k - 1);
4993 int kk_door = MAX(0, k2_door);
4994 int sync_frame = kk_door * door_delay_value;
4995 int frame = getGraphicAnimationFrame(dpc->graphic, sync_frame);
4997 getFixedGraphicSource(dpc->graphic, frame, &bitmap,
4998 &g_src_x, &g_src_y);
5003 if (!door_panel_drawn[door_index])
5005 ClearRectangle(drawto, door_rect->x, door_rect->y,
5006 door_rect->width, door_rect->height);
5008 door_panel_drawn[door_index] = TRUE;
5011 // draw opening or closing door parts
5013 if (pos->step_xoffset < 0) // door part on right side
5016 dst_xx = pos->x + ABS(kk * pos->step_xoffset);
5019 if (dst_xx + width > door_rect->width)
5020 width = door_rect->width - dst_xx;
5022 else // door part on left side
5025 dst_xx = pos->x - kk * pos->step_xoffset;
5029 src_xx = ABS(dst_xx);
5033 width = g->width - src_xx;
5035 if (width > door_rect->width)
5036 width = door_rect->width;
5038 // printf("::: k == %d [%d] \n", k, start_step);
5041 if (pos->step_yoffset < 0) // door part on bottom side
5044 dst_yy = pos->y + ABS(kk * pos->step_yoffset);
5047 if (dst_yy + height > door_rect->height)
5048 height = door_rect->height - dst_yy;
5050 else // door part on top side
5053 dst_yy = pos->y - kk * pos->step_yoffset;
5057 src_yy = ABS(dst_yy);
5061 height = g->height - src_yy;
5064 src_x = g_src_x + src_xx;
5065 src_y = g_src_y + src_yy;
5067 dst_x = door_rect->x + dst_xx;
5068 dst_y = door_rect->y + dst_yy;
5070 is_panel_and_door_has_closed =
5073 panel_has_doors[door_index] &&
5074 k >= num_move_steps_doors_only - 1);
5076 if (width >= 0 && width <= g->width &&
5077 height >= 0 && height <= g->height &&
5078 !is_panel_and_door_has_closed)
5080 if (is_panel || !pos->draw_masked)
5081 BlitBitmap(bitmap, drawto, src_x, src_y, width, height,
5084 BlitBitmapMasked(bitmap, drawto, src_x, src_y, width, height,
5088 redraw_mask |= REDRAW_DOOR_FROM_TOKEN(door_token);
5090 if ((part_opening && (width < 0 || height < 0)) ||
5091 (part_closing && (width >= g->width && height >= g->height)))
5092 door_part_done[nr] = TRUE;
5094 // continue door part animations, but not panel after door has closed
5095 if (!door_part_done[nr] && !is_panel_and_door_has_closed)
5096 door_part_done_all = FALSE;
5099 if (!(door_state & DOOR_NO_DELAY))
5103 SkipUntilDelayReached(&door_delay, door_delay_value, &k, last_frame);
5105 current_move_delay += max_step_delay;
5107 /* prevent OS (Windows) from complaining about program not responding */
5111 if (door_part_done_all)
5115 if (!(door_state & DOOR_NO_DELAY))
5117 /* wait for specified door action post delay */
5118 if (door_state & DOOR_ACTION_1 && door_state & DOOR_ACTION_2)
5119 Delay(MAX(door_1.post_delay, door_2.post_delay));
5120 else if (door_state & DOOR_ACTION_1)
5121 Delay(door_1.post_delay);
5122 else if (door_state & DOOR_ACTION_2)
5123 Delay(door_2.post_delay);
5127 if (door_state & DOOR_ACTION_1)
5128 door1 = door_state & DOOR_ACTION_1;
5129 if (door_state & DOOR_ACTION_2)
5130 door2 = door_state & DOOR_ACTION_2;
5132 // draw masked border over door area
5133 DrawMaskedBorder(REDRAW_DOOR_1);
5134 DrawMaskedBorder(REDRAW_DOOR_2);
5136 return (door1 | door2);
5139 static boolean useSpecialEditorDoor()
5141 int graphic = IMG_GLOBAL_BORDER_EDITOR;
5142 boolean redefined = getImageListEntryFromImageID(graphic)->redefined;
5144 // do not draw special editor door if editor border defined or redefined
5145 if (graphic_info[graphic].bitmap != NULL || redefined)
5148 // do not draw special editor door if global border defined to be empty
5149 if (graphic_info[IMG_GLOBAL_BORDER].bitmap == NULL)
5152 // do not draw special editor door if viewport definitions do not match
5156 EY + EYSIZE != VY + VYSIZE)
5162 void DrawSpecialEditorDoor()
5164 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
5165 int top_border_width = gfx1->width;
5166 int top_border_height = gfx1->height;
5167 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
5168 int ex = EX - outer_border;
5169 int ey = EY - outer_border;
5170 int vy = VY - outer_border;
5171 int exsize = EXSIZE + 2 * outer_border;
5173 if (!useSpecialEditorDoor())
5176 /* draw bigger level editor toolbox window */
5177 BlitBitmap(gfx1->bitmap, drawto, gfx1->src_x, gfx1->src_y,
5178 top_border_width, top_border_height, ex, ey - top_border_height);
5179 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto, ex, vy,
5180 exsize, EYSIZE - VYSIZE + outer_border, ex, ey);
5182 redraw_mask |= REDRAW_ALL;
5185 void UndrawSpecialEditorDoor()
5187 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
5188 int top_border_width = gfx1->width;
5189 int top_border_height = gfx1->height;
5190 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
5191 int ex = EX - outer_border;
5192 int ey = EY - outer_border;
5193 int ey_top = ey - top_border_height;
5194 int exsize = EXSIZE + 2 * outer_border;
5195 int eysize = EYSIZE + 2 * outer_border;
5197 if (!useSpecialEditorDoor())
5200 /* draw normal tape recorder window */
5201 if (graphic_info[IMG_GLOBAL_BORDER].bitmap)
5203 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
5204 ex, ey_top, top_border_width, top_border_height,
5206 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
5207 ex, ey, exsize, eysize, ex, ey);
5211 // if screen background is set to "[NONE]", clear editor toolbox window
5212 ClearRectangle(drawto, ex, ey_top, top_border_width, top_border_height);
5213 ClearRectangle(drawto, ex, ey, exsize, eysize);
5216 redraw_mask |= REDRAW_ALL;
5220 /* ---------- new tool button stuff ---------------------------------------- */
5225 struct TextPosInfo *pos;
5228 } toolbutton_info[NUM_TOOL_BUTTONS] =
5231 IMG_GFX_REQUEST_BUTTON_YES, &request.button.yes,
5232 TOOL_CTRL_ID_YES, "yes"
5235 IMG_GFX_REQUEST_BUTTON_NO, &request.button.no,
5236 TOOL_CTRL_ID_NO, "no"
5239 IMG_GFX_REQUEST_BUTTON_CONFIRM, &request.button.confirm,
5240 TOOL_CTRL_ID_CONFIRM, "confirm"
5243 IMG_GFX_REQUEST_BUTTON_PLAYER_1, &request.button.player_1,
5244 TOOL_CTRL_ID_PLAYER_1, "player 1"
5247 IMG_GFX_REQUEST_BUTTON_PLAYER_2, &request.button.player_2,
5248 TOOL_CTRL_ID_PLAYER_2, "player 2"
5251 IMG_GFX_REQUEST_BUTTON_PLAYER_3, &request.button.player_3,
5252 TOOL_CTRL_ID_PLAYER_3, "player 3"
5255 IMG_GFX_REQUEST_BUTTON_PLAYER_4, &request.button.player_4,
5256 TOOL_CTRL_ID_PLAYER_4, "player 4"
5260 void CreateToolButtons()
5264 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
5266 struct GraphicInfo *gfx = &graphic_info[toolbutton_info[i].graphic];
5267 struct TextPosInfo *pos = toolbutton_info[i].pos;
5268 struct GadgetInfo *gi;
5269 Bitmap *deco_bitmap = None;
5270 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
5271 unsigned int event_mask = GD_EVENT_RELEASED;
5274 int gd_x = gfx->src_x;
5275 int gd_y = gfx->src_y;
5276 int gd_xp = gfx->src_x + gfx->pressed_xoffset;
5277 int gd_yp = gfx->src_y + gfx->pressed_yoffset;
5280 if (global.use_envelope_request)
5281 setRequestPosition(&dx, &dy, TRUE);
5283 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
5285 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
5287 getSizedGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr), 0,
5288 pos->size, &deco_bitmap, &deco_x, &deco_y);
5289 deco_xpos = (gfx->width - pos->size) / 2;
5290 deco_ypos = (gfx->height - pos->size) / 2;
5293 gi = CreateGadget(GDI_CUSTOM_ID, id,
5294 GDI_INFO_TEXT, toolbutton_info[i].infotext,
5295 GDI_X, dx + GDI_ACTIVE_POS(pos->x),
5296 GDI_Y, dy + GDI_ACTIVE_POS(pos->y),
5297 GDI_WIDTH, gfx->width,
5298 GDI_HEIGHT, gfx->height,
5299 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
5300 GDI_STATE, GD_BUTTON_UNPRESSED,
5301 GDI_DESIGN_UNPRESSED, gfx->bitmap, gd_x, gd_y,
5302 GDI_DESIGN_PRESSED, gfx->bitmap, gd_xp, gd_yp,
5303 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
5304 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
5305 GDI_DECORATION_SIZE, pos->size, pos->size,
5306 GDI_DECORATION_SHIFTING, 1, 1,
5307 GDI_DIRECT_DRAW, FALSE,
5308 GDI_EVENT_MASK, event_mask,
5309 GDI_CALLBACK_ACTION, HandleToolButtons,
5313 Error(ERR_EXIT, "cannot create gadget");
5315 tool_gadget[id] = gi;
5319 void FreeToolButtons()
5323 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
5324 FreeGadget(tool_gadget[i]);
5327 static void UnmapToolButtons()
5331 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
5332 UnmapGadget(tool_gadget[i]);
5335 static void HandleToolButtons(struct GadgetInfo *gi)
5337 request_gadget_id = gi->custom_id;
5340 static struct Mapping_EM_to_RND_object
5343 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
5344 boolean is_backside; /* backside of moving element */
5350 em_object_mapping_list[] =
5353 Xblank, TRUE, FALSE,
5357 Yacid_splash_eB, FALSE, FALSE,
5358 EL_ACID_SPLASH_RIGHT, -1, -1
5361 Yacid_splash_wB, FALSE, FALSE,
5362 EL_ACID_SPLASH_LEFT, -1, -1
5365 #ifdef EM_ENGINE_BAD_ROLL
5367 Xstone_force_e, FALSE, FALSE,
5368 EL_ROCK, -1, MV_BIT_RIGHT
5371 Xstone_force_w, FALSE, FALSE,
5372 EL_ROCK, -1, MV_BIT_LEFT
5375 Xnut_force_e, FALSE, FALSE,
5376 EL_NUT, -1, MV_BIT_RIGHT
5379 Xnut_force_w, FALSE, FALSE,
5380 EL_NUT, -1, MV_BIT_LEFT
5383 Xspring_force_e, FALSE, FALSE,
5384 EL_SPRING, -1, MV_BIT_RIGHT
5387 Xspring_force_w, FALSE, FALSE,
5388 EL_SPRING, -1, MV_BIT_LEFT
5391 Xemerald_force_e, FALSE, FALSE,
5392 EL_EMERALD, -1, MV_BIT_RIGHT
5395 Xemerald_force_w, FALSE, FALSE,
5396 EL_EMERALD, -1, MV_BIT_LEFT
5399 Xdiamond_force_e, FALSE, FALSE,
5400 EL_DIAMOND, -1, MV_BIT_RIGHT
5403 Xdiamond_force_w, FALSE, FALSE,
5404 EL_DIAMOND, -1, MV_BIT_LEFT
5407 Xbomb_force_e, FALSE, FALSE,
5408 EL_BOMB, -1, MV_BIT_RIGHT
5411 Xbomb_force_w, FALSE, FALSE,
5412 EL_BOMB, -1, MV_BIT_LEFT
5414 #endif /* EM_ENGINE_BAD_ROLL */
5417 Xstone, TRUE, FALSE,
5421 Xstone_pause, FALSE, FALSE,
5425 Xstone_fall, FALSE, FALSE,
5429 Ystone_s, FALSE, FALSE,
5430 EL_ROCK, ACTION_FALLING, -1
5433 Ystone_sB, FALSE, TRUE,
5434 EL_ROCK, ACTION_FALLING, -1
5437 Ystone_e, FALSE, FALSE,
5438 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
5441 Ystone_eB, FALSE, TRUE,
5442 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
5445 Ystone_w, FALSE, FALSE,
5446 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
5449 Ystone_wB, FALSE, TRUE,
5450 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
5457 Xnut_pause, FALSE, FALSE,
5461 Xnut_fall, FALSE, FALSE,
5465 Ynut_s, FALSE, FALSE,
5466 EL_NUT, ACTION_FALLING, -1
5469 Ynut_sB, FALSE, TRUE,
5470 EL_NUT, ACTION_FALLING, -1
5473 Ynut_e, FALSE, FALSE,
5474 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
5477 Ynut_eB, FALSE, TRUE,
5478 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
5481 Ynut_w, FALSE, FALSE,
5482 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
5485 Ynut_wB, FALSE, TRUE,
5486 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
5489 Xbug_n, TRUE, FALSE,
5493 Xbug_e, TRUE, FALSE,
5494 EL_BUG_RIGHT, -1, -1
5497 Xbug_s, TRUE, FALSE,
5501 Xbug_w, TRUE, FALSE,
5505 Xbug_gon, FALSE, FALSE,
5509 Xbug_goe, FALSE, FALSE,
5510 EL_BUG_RIGHT, -1, -1
5513 Xbug_gos, FALSE, FALSE,
5517 Xbug_gow, FALSE, FALSE,
5521 Ybug_n, FALSE, FALSE,
5522 EL_BUG, ACTION_MOVING, MV_BIT_UP
5525 Ybug_nB, FALSE, TRUE,
5526 EL_BUG, ACTION_MOVING, MV_BIT_UP
5529 Ybug_e, FALSE, FALSE,
5530 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
5533 Ybug_eB, FALSE, TRUE,
5534 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
5537 Ybug_s, FALSE, FALSE,
5538 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
5541 Ybug_sB, FALSE, TRUE,
5542 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
5545 Ybug_w, FALSE, FALSE,
5546 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
5549 Ybug_wB, FALSE, TRUE,
5550 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
5553 Ybug_w_n, FALSE, FALSE,
5554 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
5557 Ybug_n_e, FALSE, FALSE,
5558 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
5561 Ybug_e_s, FALSE, FALSE,
5562 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
5565 Ybug_s_w, FALSE, FALSE,
5566 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
5569 Ybug_e_n, FALSE, FALSE,
5570 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
5573 Ybug_s_e, FALSE, FALSE,
5574 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
5577 Ybug_w_s, FALSE, FALSE,
5578 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
5581 Ybug_n_w, FALSE, FALSE,
5582 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
5585 Ybug_stone, FALSE, FALSE,
5586 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
5589 Ybug_spring, FALSE, FALSE,
5590 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
5593 Xtank_n, TRUE, FALSE,
5594 EL_SPACESHIP_UP, -1, -1
5597 Xtank_e, TRUE, FALSE,
5598 EL_SPACESHIP_RIGHT, -1, -1
5601 Xtank_s, TRUE, FALSE,
5602 EL_SPACESHIP_DOWN, -1, -1
5605 Xtank_w, TRUE, FALSE,
5606 EL_SPACESHIP_LEFT, -1, -1
5609 Xtank_gon, FALSE, FALSE,
5610 EL_SPACESHIP_UP, -1, -1
5613 Xtank_goe, FALSE, FALSE,
5614 EL_SPACESHIP_RIGHT, -1, -1
5617 Xtank_gos, FALSE, FALSE,
5618 EL_SPACESHIP_DOWN, -1, -1
5621 Xtank_gow, FALSE, FALSE,
5622 EL_SPACESHIP_LEFT, -1, -1
5625 Ytank_n, FALSE, FALSE,
5626 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
5629 Ytank_nB, FALSE, TRUE,
5630 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
5633 Ytank_e, FALSE, FALSE,
5634 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
5637 Ytank_eB, FALSE, TRUE,
5638 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
5641 Ytank_s, FALSE, FALSE,
5642 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
5645 Ytank_sB, FALSE, TRUE,
5646 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
5649 Ytank_w, FALSE, FALSE,
5650 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
5653 Ytank_wB, FALSE, TRUE,
5654 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
5657 Ytank_w_n, FALSE, FALSE,
5658 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
5661 Ytank_n_e, FALSE, FALSE,
5662 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
5665 Ytank_e_s, FALSE, FALSE,
5666 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
5669 Ytank_s_w, FALSE, FALSE,
5670 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
5673 Ytank_e_n, FALSE, FALSE,
5674 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
5677 Ytank_s_e, FALSE, FALSE,
5678 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
5681 Ytank_w_s, FALSE, FALSE,
5682 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
5685 Ytank_n_w, FALSE, FALSE,
5686 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
5689 Ytank_stone, FALSE, FALSE,
5690 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
5693 Ytank_spring, FALSE, FALSE,
5694 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
5697 Xandroid, TRUE, FALSE,
5698 EL_EMC_ANDROID, ACTION_ACTIVE, -1
5701 Xandroid_1_n, FALSE, FALSE,
5702 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
5705 Xandroid_2_n, FALSE, FALSE,
5706 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
5709 Xandroid_1_e, FALSE, FALSE,
5710 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
5713 Xandroid_2_e, FALSE, FALSE,
5714 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
5717 Xandroid_1_w, FALSE, FALSE,
5718 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
5721 Xandroid_2_w, FALSE, FALSE,
5722 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
5725 Xandroid_1_s, FALSE, FALSE,
5726 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
5729 Xandroid_2_s, FALSE, FALSE,
5730 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
5733 Yandroid_n, FALSE, FALSE,
5734 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
5737 Yandroid_nB, FALSE, TRUE,
5738 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
5741 Yandroid_ne, FALSE, FALSE,
5742 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
5745 Yandroid_neB, FALSE, TRUE,
5746 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
5749 Yandroid_e, FALSE, FALSE,
5750 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
5753 Yandroid_eB, FALSE, TRUE,
5754 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
5757 Yandroid_se, FALSE, FALSE,
5758 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
5761 Yandroid_seB, FALSE, TRUE,
5762 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
5765 Yandroid_s, FALSE, FALSE,
5766 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
5769 Yandroid_sB, FALSE, TRUE,
5770 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
5773 Yandroid_sw, FALSE, FALSE,
5774 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
5777 Yandroid_swB, FALSE, TRUE,
5778 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
5781 Yandroid_w, FALSE, FALSE,
5782 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
5785 Yandroid_wB, FALSE, TRUE,
5786 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
5789 Yandroid_nw, FALSE, FALSE,
5790 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
5793 Yandroid_nwB, FALSE, TRUE,
5794 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
5797 Xspring, TRUE, FALSE,
5801 Xspring_pause, FALSE, FALSE,
5805 Xspring_e, FALSE, FALSE,
5809 Xspring_w, FALSE, FALSE,
5813 Xspring_fall, FALSE, FALSE,
5817 Yspring_s, FALSE, FALSE,
5818 EL_SPRING, ACTION_FALLING, -1
5821 Yspring_sB, FALSE, TRUE,
5822 EL_SPRING, ACTION_FALLING, -1
5825 Yspring_e, FALSE, FALSE,
5826 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
5829 Yspring_eB, FALSE, TRUE,
5830 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
5833 Yspring_w, FALSE, FALSE,
5834 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
5837 Yspring_wB, FALSE, TRUE,
5838 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
5841 Yspring_kill_e, FALSE, FALSE,
5842 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
5845 Yspring_kill_eB, FALSE, TRUE,
5846 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
5849 Yspring_kill_w, FALSE, FALSE,
5850 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
5853 Yspring_kill_wB, FALSE, TRUE,
5854 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
5857 Xeater_n, TRUE, FALSE,
5858 EL_YAMYAM_UP, -1, -1
5861 Xeater_e, TRUE, FALSE,
5862 EL_YAMYAM_RIGHT, -1, -1
5865 Xeater_w, TRUE, FALSE,
5866 EL_YAMYAM_LEFT, -1, -1
5869 Xeater_s, TRUE, FALSE,
5870 EL_YAMYAM_DOWN, -1, -1
5873 Yeater_n, FALSE, FALSE,
5874 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
5877 Yeater_nB, FALSE, TRUE,
5878 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
5881 Yeater_e, FALSE, FALSE,
5882 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
5885 Yeater_eB, FALSE, TRUE,
5886 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
5889 Yeater_s, FALSE, FALSE,
5890 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
5893 Yeater_sB, FALSE, TRUE,
5894 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
5897 Yeater_w, FALSE, FALSE,
5898 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
5901 Yeater_wB, FALSE, TRUE,
5902 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
5905 Yeater_stone, FALSE, FALSE,
5906 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
5909 Yeater_spring, FALSE, FALSE,
5910 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
5913 Xalien, TRUE, FALSE,
5917 Xalien_pause, FALSE, FALSE,
5921 Yalien_n, FALSE, FALSE,
5922 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
5925 Yalien_nB, FALSE, TRUE,
5926 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
5929 Yalien_e, FALSE, FALSE,
5930 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
5933 Yalien_eB, FALSE, TRUE,
5934 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
5937 Yalien_s, FALSE, FALSE,
5938 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
5941 Yalien_sB, FALSE, TRUE,
5942 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
5945 Yalien_w, FALSE, FALSE,
5946 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
5949 Yalien_wB, FALSE, TRUE,
5950 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
5953 Yalien_stone, FALSE, FALSE,
5954 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
5957 Yalien_spring, FALSE, FALSE,
5958 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
5961 Xemerald, TRUE, FALSE,
5965 Xemerald_pause, FALSE, FALSE,
5969 Xemerald_fall, FALSE, FALSE,
5973 Xemerald_shine, FALSE, FALSE,
5974 EL_EMERALD, ACTION_TWINKLING, -1
5977 Yemerald_s, FALSE, FALSE,
5978 EL_EMERALD, ACTION_FALLING, -1
5981 Yemerald_sB, FALSE, TRUE,
5982 EL_EMERALD, ACTION_FALLING, -1
5985 Yemerald_e, FALSE, FALSE,
5986 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
5989 Yemerald_eB, FALSE, TRUE,
5990 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
5993 Yemerald_w, FALSE, FALSE,
5994 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
5997 Yemerald_wB, FALSE, TRUE,
5998 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
6001 Yemerald_eat, FALSE, FALSE,
6002 EL_EMERALD, ACTION_COLLECTING, -1
6005 Yemerald_stone, FALSE, FALSE,
6006 EL_NUT, ACTION_BREAKING, -1
6009 Xdiamond, TRUE, FALSE,
6013 Xdiamond_pause, FALSE, FALSE,
6017 Xdiamond_fall, FALSE, FALSE,
6021 Xdiamond_shine, FALSE, FALSE,
6022 EL_DIAMOND, ACTION_TWINKLING, -1
6025 Ydiamond_s, FALSE, FALSE,
6026 EL_DIAMOND, ACTION_FALLING, -1
6029 Ydiamond_sB, FALSE, TRUE,
6030 EL_DIAMOND, ACTION_FALLING, -1
6033 Ydiamond_e, FALSE, FALSE,
6034 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
6037 Ydiamond_eB, FALSE, TRUE,
6038 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
6041 Ydiamond_w, FALSE, FALSE,
6042 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
6045 Ydiamond_wB, FALSE, TRUE,
6046 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
6049 Ydiamond_eat, FALSE, FALSE,
6050 EL_DIAMOND, ACTION_COLLECTING, -1
6053 Ydiamond_stone, FALSE, FALSE,
6054 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
6057 Xdrip_fall, TRUE, FALSE,
6058 EL_AMOEBA_DROP, -1, -1
6061 Xdrip_stretch, FALSE, FALSE,
6062 EL_AMOEBA_DROP, ACTION_FALLING, -1
6065 Xdrip_stretchB, FALSE, TRUE,
6066 EL_AMOEBA_DROP, ACTION_FALLING, -1
6069 Xdrip_eat, FALSE, FALSE,
6070 EL_AMOEBA_DROP, ACTION_GROWING, -1
6073 Ydrip_s1, FALSE, FALSE,
6074 EL_AMOEBA_DROP, ACTION_FALLING, -1
6077 Ydrip_s1B, FALSE, TRUE,
6078 EL_AMOEBA_DROP, ACTION_FALLING, -1
6081 Ydrip_s2, FALSE, FALSE,
6082 EL_AMOEBA_DROP, ACTION_FALLING, -1
6085 Ydrip_s2B, FALSE, TRUE,
6086 EL_AMOEBA_DROP, ACTION_FALLING, -1
6093 Xbomb_pause, FALSE, FALSE,
6097 Xbomb_fall, FALSE, FALSE,
6101 Ybomb_s, FALSE, FALSE,
6102 EL_BOMB, ACTION_FALLING, -1
6105 Ybomb_sB, FALSE, TRUE,
6106 EL_BOMB, ACTION_FALLING, -1
6109 Ybomb_e, FALSE, FALSE,
6110 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
6113 Ybomb_eB, FALSE, TRUE,
6114 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
6117 Ybomb_w, FALSE, FALSE,
6118 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
6121 Ybomb_wB, FALSE, TRUE,
6122 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
6125 Ybomb_eat, FALSE, FALSE,
6126 EL_BOMB, ACTION_ACTIVATING, -1
6129 Xballoon, TRUE, FALSE,
6133 Yballoon_n, FALSE, FALSE,
6134 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
6137 Yballoon_nB, FALSE, TRUE,
6138 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
6141 Yballoon_e, FALSE, FALSE,
6142 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
6145 Yballoon_eB, FALSE, TRUE,
6146 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
6149 Yballoon_s, FALSE, FALSE,
6150 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
6153 Yballoon_sB, FALSE, TRUE,
6154 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
6157 Yballoon_w, FALSE, FALSE,
6158 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
6161 Yballoon_wB, FALSE, TRUE,
6162 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
6165 Xgrass, TRUE, FALSE,
6166 EL_EMC_GRASS, -1, -1
6169 Ygrass_nB, FALSE, FALSE,
6170 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
6173 Ygrass_eB, FALSE, FALSE,
6174 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
6177 Ygrass_sB, FALSE, FALSE,
6178 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
6181 Ygrass_wB, FALSE, FALSE,
6182 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
6189 Ydirt_nB, FALSE, FALSE,
6190 EL_SAND, ACTION_DIGGING, MV_BIT_UP
6193 Ydirt_eB, FALSE, FALSE,
6194 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
6197 Ydirt_sB, FALSE, FALSE,
6198 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
6201 Ydirt_wB, FALSE, FALSE,
6202 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
6205 Xacid_ne, TRUE, FALSE,
6206 EL_ACID_POOL_TOPRIGHT, -1, -1
6209 Xacid_se, TRUE, FALSE,
6210 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
6213 Xacid_s, TRUE, FALSE,
6214 EL_ACID_POOL_BOTTOM, -1, -1
6217 Xacid_sw, TRUE, FALSE,
6218 EL_ACID_POOL_BOTTOMLEFT, -1, -1
6221 Xacid_nw, TRUE, FALSE,
6222 EL_ACID_POOL_TOPLEFT, -1, -1
6225 Xacid_1, TRUE, FALSE,
6229 Xacid_2, FALSE, FALSE,
6233 Xacid_3, FALSE, FALSE,
6237 Xacid_4, FALSE, FALSE,
6241 Xacid_5, FALSE, FALSE,
6245 Xacid_6, FALSE, FALSE,
6249 Xacid_7, FALSE, FALSE,
6253 Xacid_8, FALSE, FALSE,
6257 Xball_1, TRUE, FALSE,
6258 EL_EMC_MAGIC_BALL, -1, -1
6261 Xball_1B, FALSE, FALSE,
6262 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
6265 Xball_2, FALSE, FALSE,
6266 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
6269 Xball_2B, FALSE, FALSE,
6270 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
6273 Yball_eat, FALSE, FALSE,
6274 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
6277 Ykey_1_eat, FALSE, FALSE,
6278 EL_EM_KEY_1, ACTION_COLLECTING, -1
6281 Ykey_2_eat, FALSE, FALSE,
6282 EL_EM_KEY_2, ACTION_COLLECTING, -1
6285 Ykey_3_eat, FALSE, FALSE,
6286 EL_EM_KEY_3, ACTION_COLLECTING, -1
6289 Ykey_4_eat, FALSE, FALSE,
6290 EL_EM_KEY_4, ACTION_COLLECTING, -1
6293 Ykey_5_eat, FALSE, FALSE,
6294 EL_EMC_KEY_5, ACTION_COLLECTING, -1
6297 Ykey_6_eat, FALSE, FALSE,
6298 EL_EMC_KEY_6, ACTION_COLLECTING, -1
6301 Ykey_7_eat, FALSE, FALSE,
6302 EL_EMC_KEY_7, ACTION_COLLECTING, -1
6305 Ykey_8_eat, FALSE, FALSE,
6306 EL_EMC_KEY_8, ACTION_COLLECTING, -1
6309 Ylenses_eat, FALSE, FALSE,
6310 EL_EMC_LENSES, ACTION_COLLECTING, -1
6313 Ymagnify_eat, FALSE, FALSE,
6314 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
6317 Ygrass_eat, FALSE, FALSE,
6318 EL_EMC_GRASS, ACTION_SNAPPING, -1
6321 Ydirt_eat, FALSE, FALSE,
6322 EL_SAND, ACTION_SNAPPING, -1
6325 Xgrow_ns, TRUE, FALSE,
6326 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
6329 Ygrow_ns_eat, FALSE, FALSE,
6330 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
6333 Xgrow_ew, TRUE, FALSE,
6334 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
6337 Ygrow_ew_eat, FALSE, FALSE,
6338 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
6341 Xwonderwall, TRUE, FALSE,
6342 EL_MAGIC_WALL, -1, -1
6345 XwonderwallB, FALSE, FALSE,
6346 EL_MAGIC_WALL, ACTION_ACTIVE, -1
6349 Xamoeba_1, TRUE, FALSE,
6350 EL_AMOEBA_DRY, ACTION_OTHER, -1
6353 Xamoeba_2, FALSE, FALSE,
6354 EL_AMOEBA_DRY, ACTION_OTHER, -1
6357 Xamoeba_3, FALSE, FALSE,
6358 EL_AMOEBA_DRY, ACTION_OTHER, -1
6361 Xamoeba_4, FALSE, FALSE,
6362 EL_AMOEBA_DRY, ACTION_OTHER, -1
6365 Xamoeba_5, TRUE, FALSE,
6366 EL_AMOEBA_WET, ACTION_OTHER, -1
6369 Xamoeba_6, FALSE, FALSE,
6370 EL_AMOEBA_WET, ACTION_OTHER, -1
6373 Xamoeba_7, FALSE, FALSE,
6374 EL_AMOEBA_WET, ACTION_OTHER, -1
6377 Xamoeba_8, FALSE, FALSE,
6378 EL_AMOEBA_WET, ACTION_OTHER, -1
6381 Xdoor_1, TRUE, FALSE,
6382 EL_EM_GATE_1, -1, -1
6385 Xdoor_2, TRUE, FALSE,
6386 EL_EM_GATE_2, -1, -1
6389 Xdoor_3, TRUE, FALSE,
6390 EL_EM_GATE_3, -1, -1
6393 Xdoor_4, TRUE, FALSE,
6394 EL_EM_GATE_4, -1, -1
6397 Xdoor_5, TRUE, FALSE,
6398 EL_EMC_GATE_5, -1, -1
6401 Xdoor_6, TRUE, FALSE,
6402 EL_EMC_GATE_6, -1, -1
6405 Xdoor_7, TRUE, FALSE,
6406 EL_EMC_GATE_7, -1, -1
6409 Xdoor_8, TRUE, FALSE,
6410 EL_EMC_GATE_8, -1, -1
6413 Xkey_1, TRUE, FALSE,
6417 Xkey_2, TRUE, FALSE,
6421 Xkey_3, TRUE, FALSE,
6425 Xkey_4, TRUE, FALSE,
6429 Xkey_5, TRUE, FALSE,
6430 EL_EMC_KEY_5, -1, -1
6433 Xkey_6, TRUE, FALSE,
6434 EL_EMC_KEY_6, -1, -1
6437 Xkey_7, TRUE, FALSE,
6438 EL_EMC_KEY_7, -1, -1
6441 Xkey_8, TRUE, FALSE,
6442 EL_EMC_KEY_8, -1, -1
6445 Xwind_n, TRUE, FALSE,
6446 EL_BALLOON_SWITCH_UP, -1, -1
6449 Xwind_e, TRUE, FALSE,
6450 EL_BALLOON_SWITCH_RIGHT, -1, -1
6453 Xwind_s, TRUE, FALSE,
6454 EL_BALLOON_SWITCH_DOWN, -1, -1
6457 Xwind_w, TRUE, FALSE,
6458 EL_BALLOON_SWITCH_LEFT, -1, -1
6461 Xwind_nesw, TRUE, FALSE,
6462 EL_BALLOON_SWITCH_ANY, -1, -1
6465 Xwind_stop, TRUE, FALSE,
6466 EL_BALLOON_SWITCH_NONE, -1, -1
6470 EL_EM_EXIT_CLOSED, -1, -1
6473 Xexit_1, TRUE, FALSE,
6474 EL_EM_EXIT_OPEN, -1, -1
6477 Xexit_2, FALSE, FALSE,
6478 EL_EM_EXIT_OPEN, -1, -1
6481 Xexit_3, FALSE, FALSE,
6482 EL_EM_EXIT_OPEN, -1, -1
6485 Xdynamite, TRUE, FALSE,
6486 EL_EM_DYNAMITE, -1, -1
6489 Ydynamite_eat, FALSE, FALSE,
6490 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
6493 Xdynamite_1, TRUE, FALSE,
6494 EL_EM_DYNAMITE_ACTIVE, -1, -1
6497 Xdynamite_2, FALSE, FALSE,
6498 EL_EM_DYNAMITE_ACTIVE, -1, -1
6501 Xdynamite_3, FALSE, FALSE,
6502 EL_EM_DYNAMITE_ACTIVE, -1, -1
6505 Xdynamite_4, FALSE, FALSE,
6506 EL_EM_DYNAMITE_ACTIVE, -1, -1
6509 Xbumper, TRUE, FALSE,
6510 EL_EMC_SPRING_BUMPER, -1, -1
6513 XbumperB, FALSE, FALSE,
6514 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
6517 Xwheel, TRUE, FALSE,
6518 EL_ROBOT_WHEEL, -1, -1
6521 XwheelB, FALSE, FALSE,
6522 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
6525 Xswitch, TRUE, FALSE,
6526 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
6529 XswitchB, FALSE, FALSE,
6530 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
6534 EL_QUICKSAND_EMPTY, -1, -1
6537 Xsand_stone, TRUE, FALSE,
6538 EL_QUICKSAND_FULL, -1, -1
6541 Xsand_stonein_1, FALSE, TRUE,
6542 EL_ROCK, ACTION_FILLING, -1
6545 Xsand_stonein_2, FALSE, TRUE,
6546 EL_ROCK, ACTION_FILLING, -1
6549 Xsand_stonein_3, FALSE, TRUE,
6550 EL_ROCK, ACTION_FILLING, -1
6553 Xsand_stonein_4, FALSE, TRUE,
6554 EL_ROCK, ACTION_FILLING, -1
6557 Xsand_stonesand_1, FALSE, FALSE,
6558 EL_QUICKSAND_EMPTYING, -1, -1
6561 Xsand_stonesand_2, FALSE, FALSE,
6562 EL_QUICKSAND_EMPTYING, -1, -1
6565 Xsand_stonesand_3, FALSE, FALSE,
6566 EL_QUICKSAND_EMPTYING, -1, -1
6569 Xsand_stonesand_4, FALSE, FALSE,
6570 EL_QUICKSAND_EMPTYING, -1, -1
6573 Xsand_stonesand_quickout_1, FALSE, FALSE,
6574 EL_QUICKSAND_EMPTYING, -1, -1
6577 Xsand_stonesand_quickout_2, FALSE, FALSE,
6578 EL_QUICKSAND_EMPTYING, -1, -1
6581 Xsand_stoneout_1, FALSE, FALSE,
6582 EL_ROCK, ACTION_EMPTYING, -1
6585 Xsand_stoneout_2, FALSE, FALSE,
6586 EL_ROCK, ACTION_EMPTYING, -1
6589 Xsand_sandstone_1, FALSE, FALSE,
6590 EL_QUICKSAND_FILLING, -1, -1
6593 Xsand_sandstone_2, FALSE, FALSE,
6594 EL_QUICKSAND_FILLING, -1, -1
6597 Xsand_sandstone_3, FALSE, FALSE,
6598 EL_QUICKSAND_FILLING, -1, -1
6601 Xsand_sandstone_4, FALSE, FALSE,
6602 EL_QUICKSAND_FILLING, -1, -1
6605 Xplant, TRUE, FALSE,
6606 EL_EMC_PLANT, -1, -1
6609 Yplant, FALSE, FALSE,
6610 EL_EMC_PLANT, -1, -1
6613 Xlenses, TRUE, FALSE,
6614 EL_EMC_LENSES, -1, -1
6617 Xmagnify, TRUE, FALSE,
6618 EL_EMC_MAGNIFIER, -1, -1
6621 Xdripper, TRUE, FALSE,
6622 EL_EMC_DRIPPER, -1, -1
6625 XdripperB, FALSE, FALSE,
6626 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
6629 Xfake_blank, TRUE, FALSE,
6630 EL_INVISIBLE_WALL, -1, -1
6633 Xfake_blankB, FALSE, FALSE,
6634 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
6637 Xfake_grass, TRUE, FALSE,
6638 EL_EMC_FAKE_GRASS, -1, -1
6641 Xfake_grassB, FALSE, FALSE,
6642 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
6645 Xfake_door_1, TRUE, FALSE,
6646 EL_EM_GATE_1_GRAY, -1, -1
6649 Xfake_door_2, TRUE, FALSE,
6650 EL_EM_GATE_2_GRAY, -1, -1
6653 Xfake_door_3, TRUE, FALSE,
6654 EL_EM_GATE_3_GRAY, -1, -1
6657 Xfake_door_4, TRUE, FALSE,
6658 EL_EM_GATE_4_GRAY, -1, -1
6661 Xfake_door_5, TRUE, FALSE,
6662 EL_EMC_GATE_5_GRAY, -1, -1
6665 Xfake_door_6, TRUE, FALSE,
6666 EL_EMC_GATE_6_GRAY, -1, -1
6669 Xfake_door_7, TRUE, FALSE,
6670 EL_EMC_GATE_7_GRAY, -1, -1
6673 Xfake_door_8, TRUE, FALSE,
6674 EL_EMC_GATE_8_GRAY, -1, -1
6677 Xfake_acid_1, TRUE, FALSE,
6678 EL_EMC_FAKE_ACID, -1, -1
6681 Xfake_acid_2, FALSE, FALSE,
6682 EL_EMC_FAKE_ACID, -1, -1
6685 Xfake_acid_3, FALSE, FALSE,
6686 EL_EMC_FAKE_ACID, -1, -1
6689 Xfake_acid_4, FALSE, FALSE,
6690 EL_EMC_FAKE_ACID, -1, -1
6693 Xfake_acid_5, FALSE, FALSE,
6694 EL_EMC_FAKE_ACID, -1, -1
6697 Xfake_acid_6, FALSE, FALSE,
6698 EL_EMC_FAKE_ACID, -1, -1
6701 Xfake_acid_7, FALSE, FALSE,
6702 EL_EMC_FAKE_ACID, -1, -1
6705 Xfake_acid_8, FALSE, FALSE,
6706 EL_EMC_FAKE_ACID, -1, -1
6709 Xsteel_1, TRUE, FALSE,
6710 EL_STEELWALL, -1, -1
6713 Xsteel_2, TRUE, FALSE,
6714 EL_EMC_STEELWALL_2, -1, -1
6717 Xsteel_3, TRUE, FALSE,
6718 EL_EMC_STEELWALL_3, -1, -1
6721 Xsteel_4, TRUE, FALSE,
6722 EL_EMC_STEELWALL_4, -1, -1
6725 Xwall_1, TRUE, FALSE,
6729 Xwall_2, TRUE, FALSE,
6730 EL_EMC_WALL_14, -1, -1
6733 Xwall_3, TRUE, FALSE,
6734 EL_EMC_WALL_15, -1, -1
6737 Xwall_4, TRUE, FALSE,
6738 EL_EMC_WALL_16, -1, -1
6741 Xround_wall_1, TRUE, FALSE,
6742 EL_WALL_SLIPPERY, -1, -1
6745 Xround_wall_2, TRUE, FALSE,
6746 EL_EMC_WALL_SLIPPERY_2, -1, -1
6749 Xround_wall_3, TRUE, FALSE,
6750 EL_EMC_WALL_SLIPPERY_3, -1, -1
6753 Xround_wall_4, TRUE, FALSE,
6754 EL_EMC_WALL_SLIPPERY_4, -1, -1
6757 Xdecor_1, TRUE, FALSE,
6758 EL_EMC_WALL_8, -1, -1
6761 Xdecor_2, TRUE, FALSE,
6762 EL_EMC_WALL_6, -1, -1
6765 Xdecor_3, TRUE, FALSE,
6766 EL_EMC_WALL_4, -1, -1
6769 Xdecor_4, TRUE, FALSE,
6770 EL_EMC_WALL_7, -1, -1
6773 Xdecor_5, TRUE, FALSE,
6774 EL_EMC_WALL_5, -1, -1
6777 Xdecor_6, TRUE, FALSE,
6778 EL_EMC_WALL_9, -1, -1
6781 Xdecor_7, TRUE, FALSE,
6782 EL_EMC_WALL_10, -1, -1
6785 Xdecor_8, TRUE, FALSE,
6786 EL_EMC_WALL_1, -1, -1
6789 Xdecor_9, TRUE, FALSE,
6790 EL_EMC_WALL_2, -1, -1
6793 Xdecor_10, TRUE, FALSE,
6794 EL_EMC_WALL_3, -1, -1
6797 Xdecor_11, TRUE, FALSE,
6798 EL_EMC_WALL_11, -1, -1
6801 Xdecor_12, TRUE, FALSE,
6802 EL_EMC_WALL_12, -1, -1
6805 Xalpha_0, TRUE, FALSE,
6806 EL_CHAR('0'), -1, -1
6809 Xalpha_1, TRUE, FALSE,
6810 EL_CHAR('1'), -1, -1
6813 Xalpha_2, TRUE, FALSE,
6814 EL_CHAR('2'), -1, -1
6817 Xalpha_3, TRUE, FALSE,
6818 EL_CHAR('3'), -1, -1
6821 Xalpha_4, TRUE, FALSE,
6822 EL_CHAR('4'), -1, -1
6825 Xalpha_5, TRUE, FALSE,
6826 EL_CHAR('5'), -1, -1
6829 Xalpha_6, TRUE, FALSE,
6830 EL_CHAR('6'), -1, -1
6833 Xalpha_7, TRUE, FALSE,
6834 EL_CHAR('7'), -1, -1
6837 Xalpha_8, TRUE, FALSE,
6838 EL_CHAR('8'), -1, -1
6841 Xalpha_9, TRUE, FALSE,
6842 EL_CHAR('9'), -1, -1
6845 Xalpha_excla, TRUE, FALSE,
6846 EL_CHAR('!'), -1, -1
6849 Xalpha_quote, TRUE, FALSE,
6850 EL_CHAR('"'), -1, -1
6853 Xalpha_comma, TRUE, FALSE,
6854 EL_CHAR(','), -1, -1
6857 Xalpha_minus, TRUE, FALSE,
6858 EL_CHAR('-'), -1, -1
6861 Xalpha_perio, TRUE, FALSE,
6862 EL_CHAR('.'), -1, -1
6865 Xalpha_colon, TRUE, FALSE,
6866 EL_CHAR(':'), -1, -1
6869 Xalpha_quest, TRUE, FALSE,
6870 EL_CHAR('?'), -1, -1
6873 Xalpha_a, TRUE, FALSE,
6874 EL_CHAR('A'), -1, -1
6877 Xalpha_b, TRUE, FALSE,
6878 EL_CHAR('B'), -1, -1
6881 Xalpha_c, TRUE, FALSE,
6882 EL_CHAR('C'), -1, -1
6885 Xalpha_d, TRUE, FALSE,
6886 EL_CHAR('D'), -1, -1
6889 Xalpha_e, TRUE, FALSE,
6890 EL_CHAR('E'), -1, -1
6893 Xalpha_f, TRUE, FALSE,
6894 EL_CHAR('F'), -1, -1
6897 Xalpha_g, TRUE, FALSE,
6898 EL_CHAR('G'), -1, -1
6901 Xalpha_h, TRUE, FALSE,
6902 EL_CHAR('H'), -1, -1
6905 Xalpha_i, TRUE, FALSE,
6906 EL_CHAR('I'), -1, -1
6909 Xalpha_j, TRUE, FALSE,
6910 EL_CHAR('J'), -1, -1
6913 Xalpha_k, TRUE, FALSE,
6914 EL_CHAR('K'), -1, -1
6917 Xalpha_l, TRUE, FALSE,
6918 EL_CHAR('L'), -1, -1
6921 Xalpha_m, TRUE, FALSE,
6922 EL_CHAR('M'), -1, -1
6925 Xalpha_n, TRUE, FALSE,
6926 EL_CHAR('N'), -1, -1
6929 Xalpha_o, TRUE, FALSE,
6930 EL_CHAR('O'), -1, -1
6933 Xalpha_p, TRUE, FALSE,
6934 EL_CHAR('P'), -1, -1
6937 Xalpha_q, TRUE, FALSE,
6938 EL_CHAR('Q'), -1, -1
6941 Xalpha_r, TRUE, FALSE,
6942 EL_CHAR('R'), -1, -1
6945 Xalpha_s, TRUE, FALSE,
6946 EL_CHAR('S'), -1, -1
6949 Xalpha_t, TRUE, FALSE,
6950 EL_CHAR('T'), -1, -1
6953 Xalpha_u, TRUE, FALSE,
6954 EL_CHAR('U'), -1, -1
6957 Xalpha_v, TRUE, FALSE,
6958 EL_CHAR('V'), -1, -1
6961 Xalpha_w, TRUE, FALSE,
6962 EL_CHAR('W'), -1, -1
6965 Xalpha_x, TRUE, FALSE,
6966 EL_CHAR('X'), -1, -1
6969 Xalpha_y, TRUE, FALSE,
6970 EL_CHAR('Y'), -1, -1
6973 Xalpha_z, TRUE, FALSE,
6974 EL_CHAR('Z'), -1, -1
6977 Xalpha_arrow_e, TRUE, FALSE,
6978 EL_CHAR('>'), -1, -1
6981 Xalpha_arrow_w, TRUE, FALSE,
6982 EL_CHAR('<'), -1, -1
6985 Xalpha_copyr, TRUE, FALSE,
6986 EL_CHAR(CHAR_BYTE_COPYRIGHT), -1, -1
6990 Xboom_bug, FALSE, FALSE,
6991 EL_BUG, ACTION_EXPLODING, -1
6994 Xboom_bomb, FALSE, FALSE,
6995 EL_BOMB, ACTION_EXPLODING, -1
6998 Xboom_android, FALSE, FALSE,
6999 EL_EMC_ANDROID, ACTION_OTHER, -1
7002 Xboom_1, FALSE, FALSE,
7003 EL_DEFAULT, ACTION_EXPLODING, -1
7006 Xboom_2, FALSE, FALSE,
7007 EL_DEFAULT, ACTION_EXPLODING, -1
7010 Znormal, FALSE, FALSE,
7014 Zdynamite, FALSE, FALSE,
7018 Zplayer, FALSE, FALSE,
7022 ZBORDER, FALSE, FALSE,
7032 static struct Mapping_EM_to_RND_player
7041 em_player_mapping_list[] =
7045 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
7049 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
7053 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
7057 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
7061 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
7065 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
7069 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
7073 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
7077 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
7081 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
7085 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
7089 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
7093 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
7097 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
7101 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
7105 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
7109 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
7113 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
7117 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
7121 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
7125 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
7129 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
7133 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
7137 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
7141 EL_PLAYER_1, ACTION_DEFAULT, -1,
7145 EL_PLAYER_2, ACTION_DEFAULT, -1,
7149 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
7153 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
7157 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
7161 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
7165 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
7169 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
7173 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
7177 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
7181 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
7185 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
7189 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
7193 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
7197 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
7201 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
7205 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
7209 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
7213 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
7217 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
7221 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
7225 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
7229 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
7233 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
7237 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
7241 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
7245 EL_PLAYER_3, ACTION_DEFAULT, -1,
7249 EL_PLAYER_4, ACTION_DEFAULT, -1,
7258 int map_element_RND_to_EM(int element_rnd)
7260 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
7261 static boolean mapping_initialized = FALSE;
7263 if (!mapping_initialized)
7267 /* return "Xalpha_quest" for all undefined elements in mapping array */
7268 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
7269 mapping_RND_to_EM[i] = Xalpha_quest;
7271 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
7272 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
7273 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
7274 em_object_mapping_list[i].element_em;
7276 mapping_initialized = TRUE;
7279 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
7280 return mapping_RND_to_EM[element_rnd];
7282 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
7287 int map_element_EM_to_RND(int element_em)
7289 static unsigned short mapping_EM_to_RND[TILE_MAX];
7290 static boolean mapping_initialized = FALSE;
7292 if (!mapping_initialized)
7296 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
7297 for (i = 0; i < TILE_MAX; i++)
7298 mapping_EM_to_RND[i] = EL_UNKNOWN;
7300 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
7301 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
7302 em_object_mapping_list[i].element_rnd;
7304 mapping_initialized = TRUE;
7307 if (element_em >= 0 && element_em < TILE_MAX)
7308 return mapping_EM_to_RND[element_em];
7310 Error(ERR_WARN, "invalid EM level element %d", element_em);
7315 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
7317 struct LevelInfo_EM *level_em = level->native_em_level;
7318 struct LEVEL *lev = level_em->lev;
7321 for (i = 0; i < TILE_MAX; i++)
7322 lev->android_array[i] = Xblank;
7324 for (i = 0; i < level->num_android_clone_elements; i++)
7326 int element_rnd = level->android_clone_element[i];
7327 int element_em = map_element_RND_to_EM(element_rnd);
7329 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
7330 if (em_object_mapping_list[j].element_rnd == element_rnd)
7331 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
7335 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
7337 struct LevelInfo_EM *level_em = level->native_em_level;
7338 struct LEVEL *lev = level_em->lev;
7341 level->num_android_clone_elements = 0;
7343 for (i = 0; i < TILE_MAX; i++)
7345 int element_em = lev->android_array[i];
7347 boolean element_found = FALSE;
7349 if (element_em == Xblank)
7352 element_rnd = map_element_EM_to_RND(element_em);
7354 for (j = 0; j < level->num_android_clone_elements; j++)
7355 if (level->android_clone_element[j] == element_rnd)
7356 element_found = TRUE;
7360 level->android_clone_element[level->num_android_clone_elements++] =
7363 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
7368 if (level->num_android_clone_elements == 0)
7370 level->num_android_clone_elements = 1;
7371 level->android_clone_element[0] = EL_EMPTY;
7375 int map_direction_RND_to_EM(int direction)
7377 return (direction == MV_UP ? 0 :
7378 direction == MV_RIGHT ? 1 :
7379 direction == MV_DOWN ? 2 :
7380 direction == MV_LEFT ? 3 :
7384 int map_direction_EM_to_RND(int direction)
7386 return (direction == 0 ? MV_UP :
7387 direction == 1 ? MV_RIGHT :
7388 direction == 2 ? MV_DOWN :
7389 direction == 3 ? MV_LEFT :
7393 int map_element_RND_to_SP(int element_rnd)
7395 int element_sp = 0x20; /* map unknown elements to yellow "hardware" */
7397 if (element_rnd >= EL_SP_START &&
7398 element_rnd <= EL_SP_END)
7399 element_sp = element_rnd - EL_SP_START;
7400 else if (element_rnd == EL_EMPTY_SPACE)
7402 else if (element_rnd == EL_INVISIBLE_WALL)
7408 int map_element_SP_to_RND(int element_sp)
7410 int element_rnd = EL_UNKNOWN;
7412 if (element_sp >= 0x00 &&
7414 element_rnd = EL_SP_START + element_sp;
7415 else if (element_sp == 0x28)
7416 element_rnd = EL_INVISIBLE_WALL;
7421 int map_action_SP_to_RND(int action_sp)
7425 case actActive: return ACTION_ACTIVE;
7426 case actImpact: return ACTION_IMPACT;
7427 case actExploding: return ACTION_EXPLODING;
7428 case actDigging: return ACTION_DIGGING;
7429 case actSnapping: return ACTION_SNAPPING;
7430 case actCollecting: return ACTION_COLLECTING;
7431 case actPassing: return ACTION_PASSING;
7432 case actPushing: return ACTION_PUSHING;
7433 case actDropping: return ACTION_DROPPING;
7435 default: return ACTION_DEFAULT;
7439 int map_element_RND_to_MM(int element_rnd)
7441 return (element_rnd >= EL_MM_START_1 &&
7442 element_rnd <= EL_MM_END_1 ?
7443 EL_MM_START_1_NATIVE + element_rnd - EL_MM_START_1 :
7445 element_rnd >= EL_MM_START_2 &&
7446 element_rnd <= EL_MM_END_2 ?
7447 EL_MM_START_2_NATIVE + element_rnd - EL_MM_START_2 :
7449 element_rnd >= EL_CHAR_START &&
7450 element_rnd <= EL_CHAR_END ?
7451 EL_MM_CHAR_START_NATIVE + element_rnd - EL_CHAR_START :
7453 element_rnd >= EL_MM_RUNTIME_START &&
7454 element_rnd <= EL_MM_RUNTIME_END ?
7455 EL_MM_RUNTIME_START_NATIVE + element_rnd - EL_MM_RUNTIME_START :
7457 element_rnd >= EL_MM_DUMMY_START &&
7458 element_rnd <= EL_MM_DUMMY_END ?
7459 EL_MM_DUMMY_START_NATIVE + element_rnd - EL_MM_DUMMY_START :
7461 EL_MM_EMPTY_NATIVE);
7464 int map_element_MM_to_RND(int element_mm)
7466 return (element_mm == EL_MM_EMPTY_NATIVE ||
7467 element_mm == EL_DF_EMPTY_NATIVE ?
7470 element_mm >= EL_MM_START_1_NATIVE &&
7471 element_mm <= EL_MM_END_1_NATIVE ?
7472 EL_MM_START_1 + element_mm - EL_MM_START_1_NATIVE :
7474 element_mm >= EL_MM_START_2_NATIVE &&
7475 element_mm <= EL_MM_END_2_NATIVE ?
7476 EL_MM_START_2 + element_mm - EL_MM_START_2_NATIVE :
7478 element_mm >= EL_MM_CHAR_START_NATIVE &&
7479 element_mm <= EL_MM_CHAR_END_NATIVE ?
7480 EL_CHAR_START + element_mm - EL_MM_CHAR_START_NATIVE :
7482 element_mm >= EL_MM_RUNTIME_START_NATIVE &&
7483 element_mm <= EL_MM_RUNTIME_END_NATIVE ?
7484 EL_MM_RUNTIME_START + element_mm - EL_MM_RUNTIME_START_NATIVE :
7486 element_mm >= EL_MM_DUMMY_START_NATIVE &&
7487 element_mm <= EL_MM_DUMMY_END_NATIVE ?
7488 EL_MM_DUMMY_START + element_mm - EL_MM_DUMMY_START_NATIVE :
7493 int map_action_MM_to_RND(int action_mm)
7495 /* all MM actions are defined to exactly match their RND counterparts */
7499 int map_sound_MM_to_RND(int sound_mm)
7503 case SND_MM_GAME_LEVELTIME_CHARGING:
7504 return SND_GAME_LEVELTIME_CHARGING;
7506 case SND_MM_GAME_HEALTH_CHARGING:
7507 return SND_GAME_HEALTH_CHARGING;
7510 return SND_UNDEFINED;
7514 int map_mm_wall_element(int element)
7516 return (element >= EL_MM_STEEL_WALL_START &&
7517 element <= EL_MM_STEEL_WALL_END ?
7520 element >= EL_MM_WOODEN_WALL_START &&
7521 element <= EL_MM_WOODEN_WALL_END ?
7524 element >= EL_MM_ICE_WALL_START &&
7525 element <= EL_MM_ICE_WALL_END ?
7528 element >= EL_MM_AMOEBA_WALL_START &&
7529 element <= EL_MM_AMOEBA_WALL_END ?
7532 element >= EL_DF_STEEL_WALL_START &&
7533 element <= EL_DF_STEEL_WALL_END ?
7536 element >= EL_DF_WOODEN_WALL_START &&
7537 element <= EL_DF_WOODEN_WALL_END ?
7543 int map_mm_wall_element_editor(int element)
7547 case EL_MM_STEEL_WALL: return EL_MM_STEEL_WALL_START;
7548 case EL_MM_WOODEN_WALL: return EL_MM_WOODEN_WALL_START;
7549 case EL_MM_ICE_WALL: return EL_MM_ICE_WALL_START;
7550 case EL_MM_AMOEBA_WALL: return EL_MM_AMOEBA_WALL_START;
7551 case EL_DF_STEEL_WALL: return EL_DF_STEEL_WALL_START;
7552 case EL_DF_WOODEN_WALL: return EL_DF_WOODEN_WALL_START;
7554 default: return element;
7558 int get_next_element(int element)
7562 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
7563 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
7564 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
7565 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
7566 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
7567 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
7568 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
7569 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
7570 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
7571 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
7572 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
7574 default: return element;
7578 int el2img_mm(int element_mm)
7580 return el2img(map_element_MM_to_RND(element_mm));
7583 int el_act_dir2img(int element, int action, int direction)
7585 element = GFX_ELEMENT(element);
7586 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
7588 /* direction_graphic[][] == graphic[] for undefined direction graphics */
7589 return element_info[element].direction_graphic[action][direction];
7592 static int el_act_dir2crm(int element, int action, int direction)
7594 element = GFX_ELEMENT(element);
7595 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
7597 /* direction_graphic[][] == graphic[] for undefined direction graphics */
7598 return element_info[element].direction_crumbled[action][direction];
7601 int el_act2img(int element, int action)
7603 element = GFX_ELEMENT(element);
7605 return element_info[element].graphic[action];
7608 int el_act2crm(int element, int action)
7610 element = GFX_ELEMENT(element);
7612 return element_info[element].crumbled[action];
7615 int el_dir2img(int element, int direction)
7617 element = GFX_ELEMENT(element);
7619 return el_act_dir2img(element, ACTION_DEFAULT, direction);
7622 int el2baseimg(int element)
7624 return element_info[element].graphic[ACTION_DEFAULT];
7627 int el2img(int element)
7629 element = GFX_ELEMENT(element);
7631 return element_info[element].graphic[ACTION_DEFAULT];
7634 int el2edimg(int element)
7636 element = GFX_ELEMENT(element);
7638 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
7641 int el2preimg(int element)
7643 element = GFX_ELEMENT(element);
7645 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
7648 int el2panelimg(int element)
7650 element = GFX_ELEMENT(element);
7652 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL];
7655 int font2baseimg(int font_nr)
7657 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
7660 int getBeltNrFromBeltElement(int element)
7662 return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
7663 element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
7664 element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
7667 int getBeltNrFromBeltActiveElement(int element)
7669 return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
7670 element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
7671 element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
7674 int getBeltNrFromBeltSwitchElement(int element)
7676 return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
7677 element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
7678 element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
7681 int getBeltDirNrFromBeltElement(int element)
7683 static int belt_base_element[4] =
7685 EL_CONVEYOR_BELT_1_LEFT,
7686 EL_CONVEYOR_BELT_2_LEFT,
7687 EL_CONVEYOR_BELT_3_LEFT,
7688 EL_CONVEYOR_BELT_4_LEFT
7691 int belt_nr = getBeltNrFromBeltElement(element);
7692 int belt_dir_nr = element - belt_base_element[belt_nr];
7694 return (belt_dir_nr % 3);
7697 int getBeltDirNrFromBeltSwitchElement(int element)
7699 static int belt_base_element[4] =
7701 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
7702 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
7703 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
7704 EL_CONVEYOR_BELT_4_SWITCH_LEFT
7707 int belt_nr = getBeltNrFromBeltSwitchElement(element);
7708 int belt_dir_nr = element - belt_base_element[belt_nr];
7710 return (belt_dir_nr % 3);
7713 int getBeltDirFromBeltElement(int element)
7715 static int belt_move_dir[3] =
7722 int belt_dir_nr = getBeltDirNrFromBeltElement(element);
7724 return belt_move_dir[belt_dir_nr];
7727 int getBeltDirFromBeltSwitchElement(int element)
7729 static int belt_move_dir[3] =
7736 int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
7738 return belt_move_dir[belt_dir_nr];
7741 int getBeltElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
7743 static int belt_base_element[4] =
7745 EL_CONVEYOR_BELT_1_LEFT,
7746 EL_CONVEYOR_BELT_2_LEFT,
7747 EL_CONVEYOR_BELT_3_LEFT,
7748 EL_CONVEYOR_BELT_4_LEFT
7751 return belt_base_element[belt_nr] + belt_dir_nr;
7754 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
7756 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
7758 return getBeltElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
7761 int getBeltSwitchElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
7763 static int belt_base_element[4] =
7765 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
7766 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
7767 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
7768 EL_CONVEYOR_BELT_4_SWITCH_LEFT
7771 return belt_base_element[belt_nr] + belt_dir_nr;
7774 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
7776 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
7778 return getBeltSwitchElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
7781 boolean getTeamMode_EM()
7783 return game.team_mode;
7786 int getGameFrameDelay_EM(int native_em_game_frame_delay)
7788 int game_frame_delay_value;
7790 game_frame_delay_value =
7791 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
7792 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
7795 if (tape.playing && tape.warp_forward && !tape.pausing)
7796 game_frame_delay_value = 0;
7798 return game_frame_delay_value;
7801 unsigned int InitRND(int seed)
7803 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
7804 return InitEngineRandom_EM(seed);
7805 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
7806 return InitEngineRandom_SP(seed);
7807 else if (level.game_engine_type == GAME_ENGINE_TYPE_MM)
7808 return InitEngineRandom_MM(seed);
7810 return InitEngineRandom_RND(seed);
7813 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
7814 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
7816 inline static int get_effective_element_EM(int tile, int frame_em)
7818 int element = object_mapping[tile].element_rnd;
7819 int action = object_mapping[tile].action;
7820 boolean is_backside = object_mapping[tile].is_backside;
7821 boolean action_removing = (action == ACTION_DIGGING ||
7822 action == ACTION_SNAPPING ||
7823 action == ACTION_COLLECTING);
7829 case Yacid_splash_eB:
7830 case Yacid_splash_wB:
7831 return (frame_em > 5 ? EL_EMPTY : element);
7837 else /* frame_em == 7 */
7841 case Yacid_splash_eB:
7842 case Yacid_splash_wB:
7845 case Yemerald_stone:
7848 case Ydiamond_stone:
7852 case Xdrip_stretchB:
7871 case Xsand_stonein_1:
7872 case Xsand_stonein_2:
7873 case Xsand_stonein_3:
7874 case Xsand_stonein_4:
7878 return (is_backside || action_removing ? EL_EMPTY : element);
7883 inline static boolean check_linear_animation_EM(int tile)
7887 case Xsand_stonesand_1:
7888 case Xsand_stonesand_quickout_1:
7889 case Xsand_sandstone_1:
7890 case Xsand_stonein_1:
7891 case Xsand_stoneout_1:
7910 case Yacid_splash_eB:
7911 case Yacid_splash_wB:
7912 case Yemerald_stone:
7919 inline static void set_crumbled_graphics_EM(struct GraphicInfo_EM *g_em,
7920 boolean has_crumbled_graphics,
7921 int crumbled, int sync_frame)
7923 /* if element can be crumbled, but certain action graphics are just empty
7924 space (like instantly snapping sand to empty space in 1 frame), do not
7925 treat these empty space graphics as crumbled graphics in EMC engine */
7926 if (crumbled == IMG_EMPTY_SPACE)
7927 has_crumbled_graphics = FALSE;
7929 if (has_crumbled_graphics)
7931 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
7932 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
7933 g_crumbled->anim_delay,
7934 g_crumbled->anim_mode,
7935 g_crumbled->anim_start_frame,
7938 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
7939 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
7941 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
7942 g_em->crumbled_tile_size = graphic_info[crumbled].tile_size;
7944 g_em->has_crumbled_graphics = TRUE;
7948 g_em->crumbled_bitmap = NULL;
7949 g_em->crumbled_src_x = 0;
7950 g_em->crumbled_src_y = 0;
7951 g_em->crumbled_border_size = 0;
7952 g_em->crumbled_tile_size = 0;
7954 g_em->has_crumbled_graphics = FALSE;
7958 void ResetGfxAnimation_EM(int x, int y, int tile)
7963 void SetGfxAnimation_EM(struct GraphicInfo_EM *g_em,
7964 int tile, int frame_em, int x, int y)
7966 int action = object_mapping[tile].action;
7967 int direction = object_mapping[tile].direction;
7968 int effective_element = get_effective_element_EM(tile, frame_em);
7969 int graphic = (direction == MV_NONE ?
7970 el_act2img(effective_element, action) :
7971 el_act_dir2img(effective_element, action, direction));
7972 struct GraphicInfo *g = &graphic_info[graphic];
7974 boolean action_removing = (action == ACTION_DIGGING ||
7975 action == ACTION_SNAPPING ||
7976 action == ACTION_COLLECTING);
7977 boolean action_moving = (action == ACTION_FALLING ||
7978 action == ACTION_MOVING ||
7979 action == ACTION_PUSHING ||
7980 action == ACTION_EATING ||
7981 action == ACTION_FILLING ||
7982 action == ACTION_EMPTYING);
7983 boolean action_falling = (action == ACTION_FALLING ||
7984 action == ACTION_FILLING ||
7985 action == ACTION_EMPTYING);
7987 /* special case: graphic uses "2nd movement tile" and has defined
7988 7 frames for movement animation (or less) => use default graphic
7989 for last (8th) frame which ends the movement animation */
7990 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
7992 action = ACTION_DEFAULT; /* (keep action_* unchanged for now) */
7993 graphic = (direction == MV_NONE ?
7994 el_act2img(effective_element, action) :
7995 el_act_dir2img(effective_element, action, direction));
7997 g = &graphic_info[graphic];
8000 if ((action_removing || check_linear_animation_EM(tile)) && frame_em == 0)
8004 else if (action_moving)
8006 boolean is_backside = object_mapping[tile].is_backside;
8010 int direction = object_mapping[tile].direction;
8011 int move_dir = (action_falling ? MV_DOWN : direction);
8016 /* !!! TEST !!! NEW !!! DOES NOT WORK RIGHT YET !!! */
8017 if (g->double_movement && frame_em == 0)
8021 if (move_dir == MV_LEFT)
8022 GfxFrame[x - 1][y] = GfxFrame[x][y];
8023 else if (move_dir == MV_RIGHT)
8024 GfxFrame[x + 1][y] = GfxFrame[x][y];
8025 else if (move_dir == MV_UP)
8026 GfxFrame[x][y - 1] = GfxFrame[x][y];
8027 else if (move_dir == MV_DOWN)
8028 GfxFrame[x][y + 1] = GfxFrame[x][y];
8035 /* special case: animation for Xsand_stonesand_quickout_1/2 twice as fast */
8036 if (tile == Xsand_stonesand_quickout_1 ||
8037 tile == Xsand_stonesand_quickout_2)
8041 if (graphic_info[graphic].anim_global_sync)
8042 sync_frame = FrameCounter;
8043 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
8044 sync_frame = GfxFrame[x][y];
8046 sync_frame = 0; /* playfield border (pseudo steel) */
8048 SetRandomAnimationValue(x, y);
8050 int frame = getAnimationFrame(g->anim_frames,
8053 g->anim_start_frame,
8056 g_em->unique_identifier =
8057 (graphic << 16) | ((frame % 8) << 12) | (g_em->width << 6) | g_em->height;
8060 void getGraphicSourceObjectExt_EM(struct GraphicInfo_EM *g_em,
8061 int tile, int frame_em, int x, int y)
8063 int action = object_mapping[tile].action;
8064 int direction = object_mapping[tile].direction;
8065 boolean is_backside = object_mapping[tile].is_backside;
8066 int effective_element = get_effective_element_EM(tile, frame_em);
8067 int effective_action = action;
8068 int graphic = (direction == MV_NONE ?
8069 el_act2img(effective_element, effective_action) :
8070 el_act_dir2img(effective_element, effective_action,
8072 int crumbled = (direction == MV_NONE ?
8073 el_act2crm(effective_element, effective_action) :
8074 el_act_dir2crm(effective_element, effective_action,
8076 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
8077 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
8078 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
8079 struct GraphicInfo *g = &graphic_info[graphic];
8082 /* special case: graphic uses "2nd movement tile" and has defined
8083 7 frames for movement animation (or less) => use default graphic
8084 for last (8th) frame which ends the movement animation */
8085 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
8087 effective_action = ACTION_DEFAULT;
8088 graphic = (direction == MV_NONE ?
8089 el_act2img(effective_element, effective_action) :
8090 el_act_dir2img(effective_element, effective_action,
8092 crumbled = (direction == MV_NONE ?
8093 el_act2crm(effective_element, effective_action) :
8094 el_act_dir2crm(effective_element, effective_action,
8097 g = &graphic_info[graphic];
8100 if (graphic_info[graphic].anim_global_sync)
8101 sync_frame = FrameCounter;
8102 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
8103 sync_frame = GfxFrame[x][y];
8105 sync_frame = 0; /* playfield border (pseudo steel) */
8107 SetRandomAnimationValue(x, y);
8109 int frame = getAnimationFrame(g->anim_frames,
8112 g->anim_start_frame,
8115 getGraphicSourceExt(graphic, frame, &g_em->bitmap, &g_em->src_x, &g_em->src_y,
8116 g->double_movement && is_backside);
8118 /* (updating the "crumbled" graphic definitions is probably not really needed,
8119 as animations for crumbled graphics can't be longer than one EMC cycle) */
8120 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
8124 void getGraphicSourcePlayerExt_EM(struct GraphicInfo_EM *g_em,
8125 int player_nr, int anim, int frame_em)
8127 int element = player_mapping[player_nr][anim].element_rnd;
8128 int action = player_mapping[player_nr][anim].action;
8129 int direction = player_mapping[player_nr][anim].direction;
8130 int graphic = (direction == MV_NONE ?
8131 el_act2img(element, action) :
8132 el_act_dir2img(element, action, direction));
8133 struct GraphicInfo *g = &graphic_info[graphic];
8136 InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
8138 stored_player[player_nr].StepFrame = frame_em;
8140 sync_frame = stored_player[player_nr].Frame;
8142 int frame = getAnimationFrame(g->anim_frames,
8145 g->anim_start_frame,
8148 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
8149 &g_em->src_x, &g_em->src_y, FALSE);
8152 void InitGraphicInfo_EM(void)
8157 int num_em_gfx_errors = 0;
8159 if (graphic_info_em_object[0][0].bitmap == NULL)
8161 /* EM graphics not yet initialized in em_open_all() */
8166 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
8169 /* always start with reliable default values */
8170 for (i = 0; i < TILE_MAX; i++)
8172 object_mapping[i].element_rnd = EL_UNKNOWN;
8173 object_mapping[i].is_backside = FALSE;
8174 object_mapping[i].action = ACTION_DEFAULT;
8175 object_mapping[i].direction = MV_NONE;
8178 /* always start with reliable default values */
8179 for (p = 0; p < MAX_PLAYERS; p++)
8181 for (i = 0; i < SPR_MAX; i++)
8183 player_mapping[p][i].element_rnd = EL_UNKNOWN;
8184 player_mapping[p][i].action = ACTION_DEFAULT;
8185 player_mapping[p][i].direction = MV_NONE;
8189 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
8191 int e = em_object_mapping_list[i].element_em;
8193 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
8194 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
8196 if (em_object_mapping_list[i].action != -1)
8197 object_mapping[e].action = em_object_mapping_list[i].action;
8199 if (em_object_mapping_list[i].direction != -1)
8200 object_mapping[e].direction =
8201 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
8204 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
8206 int a = em_player_mapping_list[i].action_em;
8207 int p = em_player_mapping_list[i].player_nr;
8209 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
8211 if (em_player_mapping_list[i].action != -1)
8212 player_mapping[p][a].action = em_player_mapping_list[i].action;
8214 if (em_player_mapping_list[i].direction != -1)
8215 player_mapping[p][a].direction =
8216 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
8219 for (i = 0; i < TILE_MAX; i++)
8221 int element = object_mapping[i].element_rnd;
8222 int action = object_mapping[i].action;
8223 int direction = object_mapping[i].direction;
8224 boolean is_backside = object_mapping[i].is_backside;
8225 boolean action_exploding = ((action == ACTION_EXPLODING ||
8226 action == ACTION_SMASHED_BY_ROCK ||
8227 action == ACTION_SMASHED_BY_SPRING) &&
8228 element != EL_DIAMOND);
8229 boolean action_active = (action == ACTION_ACTIVE);
8230 boolean action_other = (action == ACTION_OTHER);
8232 for (j = 0; j < 8; j++)
8234 int effective_element = get_effective_element_EM(i, j);
8235 int effective_action = (j < 7 ? action :
8236 i == Xdrip_stretch ? action :
8237 i == Xdrip_stretchB ? action :
8238 i == Ydrip_s1 ? action :
8239 i == Ydrip_s1B ? action :
8240 i == Xball_1B ? action :
8241 i == Xball_2 ? action :
8242 i == Xball_2B ? action :
8243 i == Yball_eat ? action :
8244 i == Ykey_1_eat ? action :
8245 i == Ykey_2_eat ? action :
8246 i == Ykey_3_eat ? action :
8247 i == Ykey_4_eat ? action :
8248 i == Ykey_5_eat ? action :
8249 i == Ykey_6_eat ? action :
8250 i == Ykey_7_eat ? action :
8251 i == Ykey_8_eat ? action :
8252 i == Ylenses_eat ? action :
8253 i == Ymagnify_eat ? action :
8254 i == Ygrass_eat ? action :
8255 i == Ydirt_eat ? action :
8256 i == Xsand_stonein_1 ? action :
8257 i == Xsand_stonein_2 ? action :
8258 i == Xsand_stonein_3 ? action :
8259 i == Xsand_stonein_4 ? action :
8260 i == Xsand_stoneout_1 ? action :
8261 i == Xsand_stoneout_2 ? action :
8262 i == Xboom_android ? ACTION_EXPLODING :
8263 action_exploding ? ACTION_EXPLODING :
8264 action_active ? action :
8265 action_other ? action :
8267 int graphic = (el_act_dir2img(effective_element, effective_action,
8269 int crumbled = (el_act_dir2crm(effective_element, effective_action,
8271 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
8272 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
8273 boolean has_action_graphics = (graphic != base_graphic);
8274 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
8275 struct GraphicInfo *g = &graphic_info[graphic];
8276 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
8279 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
8280 boolean special_animation = (action != ACTION_DEFAULT &&
8281 g->anim_frames == 3 &&
8282 g->anim_delay == 2 &&
8283 g->anim_mode & ANIM_LINEAR);
8284 int sync_frame = (i == Xdrip_stretch ? 7 :
8285 i == Xdrip_stretchB ? 7 :
8286 i == Ydrip_s2 ? j + 8 :
8287 i == Ydrip_s2B ? j + 8 :
8296 i == Xfake_acid_1 ? 0 :
8297 i == Xfake_acid_2 ? 10 :
8298 i == Xfake_acid_3 ? 20 :
8299 i == Xfake_acid_4 ? 30 :
8300 i == Xfake_acid_5 ? 40 :
8301 i == Xfake_acid_6 ? 50 :
8302 i == Xfake_acid_7 ? 60 :
8303 i == Xfake_acid_8 ? 70 :
8305 i == Xball_2B ? j + 8 :
8306 i == Yball_eat ? j + 1 :
8307 i == Ykey_1_eat ? j + 1 :
8308 i == Ykey_2_eat ? j + 1 :
8309 i == Ykey_3_eat ? j + 1 :
8310 i == Ykey_4_eat ? j + 1 :
8311 i == Ykey_5_eat ? j + 1 :
8312 i == Ykey_6_eat ? j + 1 :
8313 i == Ykey_7_eat ? j + 1 :
8314 i == Ykey_8_eat ? j + 1 :
8315 i == Ylenses_eat ? j + 1 :
8316 i == Ymagnify_eat ? j + 1 :
8317 i == Ygrass_eat ? j + 1 :
8318 i == Ydirt_eat ? j + 1 :
8319 i == Xamoeba_1 ? 0 :
8320 i == Xamoeba_2 ? 1 :
8321 i == Xamoeba_3 ? 2 :
8322 i == Xamoeba_4 ? 3 :
8323 i == Xamoeba_5 ? 0 :
8324 i == Xamoeba_6 ? 1 :
8325 i == Xamoeba_7 ? 2 :
8326 i == Xamoeba_8 ? 3 :
8327 i == Xexit_2 ? j + 8 :
8328 i == Xexit_3 ? j + 16 :
8329 i == Xdynamite_1 ? 0 :
8330 i == Xdynamite_2 ? 8 :
8331 i == Xdynamite_3 ? 16 :
8332 i == Xdynamite_4 ? 24 :
8333 i == Xsand_stonein_1 ? j + 1 :
8334 i == Xsand_stonein_2 ? j + 9 :
8335 i == Xsand_stonein_3 ? j + 17 :
8336 i == Xsand_stonein_4 ? j + 25 :
8337 i == Xsand_stoneout_1 && j == 0 ? 0 :
8338 i == Xsand_stoneout_1 && j == 1 ? 0 :
8339 i == Xsand_stoneout_1 && j == 2 ? 1 :
8340 i == Xsand_stoneout_1 && j == 3 ? 2 :
8341 i == Xsand_stoneout_1 && j == 4 ? 2 :
8342 i == Xsand_stoneout_1 && j == 5 ? 3 :
8343 i == Xsand_stoneout_1 && j == 6 ? 4 :
8344 i == Xsand_stoneout_1 && j == 7 ? 4 :
8345 i == Xsand_stoneout_2 && j == 0 ? 5 :
8346 i == Xsand_stoneout_2 && j == 1 ? 6 :
8347 i == Xsand_stoneout_2 && j == 2 ? 7 :
8348 i == Xsand_stoneout_2 && j == 3 ? 8 :
8349 i == Xsand_stoneout_2 && j == 4 ? 9 :
8350 i == Xsand_stoneout_2 && j == 5 ? 11 :
8351 i == Xsand_stoneout_2 && j == 6 ? 13 :
8352 i == Xsand_stoneout_2 && j == 7 ? 15 :
8353 i == Xboom_bug && j == 1 ? 2 :
8354 i == Xboom_bug && j == 2 ? 2 :
8355 i == Xboom_bug && j == 3 ? 4 :
8356 i == Xboom_bug && j == 4 ? 4 :
8357 i == Xboom_bug && j == 5 ? 2 :
8358 i == Xboom_bug && j == 6 ? 2 :
8359 i == Xboom_bug && j == 7 ? 0 :
8360 i == Xboom_bomb && j == 1 ? 2 :
8361 i == Xboom_bomb && j == 2 ? 2 :
8362 i == Xboom_bomb && j == 3 ? 4 :
8363 i == Xboom_bomb && j == 4 ? 4 :
8364 i == Xboom_bomb && j == 5 ? 2 :
8365 i == Xboom_bomb && j == 6 ? 2 :
8366 i == Xboom_bomb && j == 7 ? 0 :
8367 i == Xboom_android && j == 7 ? 6 :
8368 i == Xboom_1 && j == 1 ? 2 :
8369 i == Xboom_1 && j == 2 ? 2 :
8370 i == Xboom_1 && j == 3 ? 4 :
8371 i == Xboom_1 && j == 4 ? 4 :
8372 i == Xboom_1 && j == 5 ? 6 :
8373 i == Xboom_1 && j == 6 ? 6 :
8374 i == Xboom_1 && j == 7 ? 8 :
8375 i == Xboom_2 && j == 0 ? 8 :
8376 i == Xboom_2 && j == 1 ? 8 :
8377 i == Xboom_2 && j == 2 ? 10 :
8378 i == Xboom_2 && j == 3 ? 10 :
8379 i == Xboom_2 && j == 4 ? 10 :
8380 i == Xboom_2 && j == 5 ? 12 :
8381 i == Xboom_2 && j == 6 ? 12 :
8382 i == Xboom_2 && j == 7 ? 12 :
8383 special_animation && j == 4 ? 3 :
8384 effective_action != action ? 0 :
8388 Bitmap *debug_bitmap = g_em->bitmap;
8389 int debug_src_x = g_em->src_x;
8390 int debug_src_y = g_em->src_y;
8393 int frame = getAnimationFrame(g->anim_frames,
8396 g->anim_start_frame,
8399 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
8400 g->double_movement && is_backside);
8402 g_em->bitmap = src_bitmap;
8403 g_em->src_x = src_x;
8404 g_em->src_y = src_y;
8405 g_em->src_offset_x = 0;
8406 g_em->src_offset_y = 0;
8407 g_em->dst_offset_x = 0;
8408 g_em->dst_offset_y = 0;
8409 g_em->width = TILEX;
8410 g_em->height = TILEY;
8412 g_em->preserve_background = FALSE;
8414 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
8417 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
8418 effective_action == ACTION_MOVING ||
8419 effective_action == ACTION_PUSHING ||
8420 effective_action == ACTION_EATING)) ||
8421 (!has_action_graphics && (effective_action == ACTION_FILLING ||
8422 effective_action == ACTION_EMPTYING)))
8425 (effective_action == ACTION_FALLING ||
8426 effective_action == ACTION_FILLING ||
8427 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
8428 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
8429 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
8430 int num_steps = (i == Ydrip_s1 ? 16 :
8431 i == Ydrip_s1B ? 16 :
8432 i == Ydrip_s2 ? 16 :
8433 i == Ydrip_s2B ? 16 :
8434 i == Xsand_stonein_1 ? 32 :
8435 i == Xsand_stonein_2 ? 32 :
8436 i == Xsand_stonein_3 ? 32 :
8437 i == Xsand_stonein_4 ? 32 :
8438 i == Xsand_stoneout_1 ? 16 :
8439 i == Xsand_stoneout_2 ? 16 : 8);
8440 int cx = ABS(dx) * (TILEX / num_steps);
8441 int cy = ABS(dy) * (TILEY / num_steps);
8442 int step_frame = (i == Ydrip_s2 ? j + 8 :
8443 i == Ydrip_s2B ? j + 8 :
8444 i == Xsand_stonein_2 ? j + 8 :
8445 i == Xsand_stonein_3 ? j + 16 :
8446 i == Xsand_stonein_4 ? j + 24 :
8447 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
8448 int step = (is_backside ? step_frame : num_steps - step_frame);
8450 if (is_backside) /* tile where movement starts */
8452 if (dx < 0 || dy < 0)
8454 g_em->src_offset_x = cx * step;
8455 g_em->src_offset_y = cy * step;
8459 g_em->dst_offset_x = cx * step;
8460 g_em->dst_offset_y = cy * step;
8463 else /* tile where movement ends */
8465 if (dx < 0 || dy < 0)
8467 g_em->dst_offset_x = cx * step;
8468 g_em->dst_offset_y = cy * step;
8472 g_em->src_offset_x = cx * step;
8473 g_em->src_offset_y = cy * step;
8477 g_em->width = TILEX - cx * step;
8478 g_em->height = TILEY - cy * step;
8481 /* create unique graphic identifier to decide if tile must be redrawn */
8482 /* bit 31 - 16 (16 bit): EM style graphic
8483 bit 15 - 12 ( 4 bit): EM style frame
8484 bit 11 - 6 ( 6 bit): graphic width
8485 bit 5 - 0 ( 6 bit): graphic height */
8486 g_em->unique_identifier =
8487 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
8491 /* skip check for EMC elements not contained in original EMC artwork */
8492 if (element == EL_EMC_FAKE_ACID)
8495 if (g_em->bitmap != debug_bitmap ||
8496 g_em->src_x != debug_src_x ||
8497 g_em->src_y != debug_src_y ||
8498 g_em->src_offset_x != 0 ||
8499 g_em->src_offset_y != 0 ||
8500 g_em->dst_offset_x != 0 ||
8501 g_em->dst_offset_y != 0 ||
8502 g_em->width != TILEX ||
8503 g_em->height != TILEY)
8505 static int last_i = -1;
8513 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
8514 i, element, element_info[element].token_name,
8515 element_action_info[effective_action].suffix, direction);
8517 if (element != effective_element)
8518 printf(" [%d ('%s')]",
8520 element_info[effective_element].token_name);
8524 if (g_em->bitmap != debug_bitmap)
8525 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
8526 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
8528 if (g_em->src_x != debug_src_x ||
8529 g_em->src_y != debug_src_y)
8530 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
8531 j, (is_backside ? 'B' : 'F'),
8532 g_em->src_x, g_em->src_y,
8533 g_em->src_x / 32, g_em->src_y / 32,
8534 debug_src_x, debug_src_y,
8535 debug_src_x / 32, debug_src_y / 32);
8537 if (g_em->src_offset_x != 0 ||
8538 g_em->src_offset_y != 0 ||
8539 g_em->dst_offset_x != 0 ||
8540 g_em->dst_offset_y != 0)
8541 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
8543 g_em->src_offset_x, g_em->src_offset_y,
8544 g_em->dst_offset_x, g_em->dst_offset_y);
8546 if (g_em->width != TILEX ||
8547 g_em->height != TILEY)
8548 printf(" %d (%d): size %d,%d should be %d,%d\n",
8550 g_em->width, g_em->height, TILEX, TILEY);
8552 num_em_gfx_errors++;
8559 for (i = 0; i < TILE_MAX; i++)
8561 for (j = 0; j < 8; j++)
8563 int element = object_mapping[i].element_rnd;
8564 int action = object_mapping[i].action;
8565 int direction = object_mapping[i].direction;
8566 boolean is_backside = object_mapping[i].is_backside;
8567 int graphic_action = el_act_dir2img(element, action, direction);
8568 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
8570 if ((action == ACTION_SMASHED_BY_ROCK ||
8571 action == ACTION_SMASHED_BY_SPRING ||
8572 action == ACTION_EATING) &&
8573 graphic_action == graphic_default)
8575 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
8576 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
8577 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
8578 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
8581 /* no separate animation for "smashed by rock" -- use rock instead */
8582 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
8583 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
8585 g_em->bitmap = g_xx->bitmap;
8586 g_em->src_x = g_xx->src_x;
8587 g_em->src_y = g_xx->src_y;
8588 g_em->src_offset_x = g_xx->src_offset_x;
8589 g_em->src_offset_y = g_xx->src_offset_y;
8590 g_em->dst_offset_x = g_xx->dst_offset_x;
8591 g_em->dst_offset_y = g_xx->dst_offset_y;
8592 g_em->width = g_xx->width;
8593 g_em->height = g_xx->height;
8594 g_em->unique_identifier = g_xx->unique_identifier;
8597 g_em->preserve_background = TRUE;
8602 for (p = 0; p < MAX_PLAYERS; p++)
8604 for (i = 0; i < SPR_MAX; i++)
8606 int element = player_mapping[p][i].element_rnd;
8607 int action = player_mapping[p][i].action;
8608 int direction = player_mapping[p][i].direction;
8610 for (j = 0; j < 8; j++)
8612 int effective_element = element;
8613 int effective_action = action;
8614 int graphic = (direction == MV_NONE ?
8615 el_act2img(effective_element, effective_action) :
8616 el_act_dir2img(effective_element, effective_action,
8618 struct GraphicInfo *g = &graphic_info[graphic];
8619 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
8625 Bitmap *debug_bitmap = g_em->bitmap;
8626 int debug_src_x = g_em->src_x;
8627 int debug_src_y = g_em->src_y;
8630 int frame = getAnimationFrame(g->anim_frames,
8633 g->anim_start_frame,
8636 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
8638 g_em->bitmap = src_bitmap;
8639 g_em->src_x = src_x;
8640 g_em->src_y = src_y;
8641 g_em->src_offset_x = 0;
8642 g_em->src_offset_y = 0;
8643 g_em->dst_offset_x = 0;
8644 g_em->dst_offset_y = 0;
8645 g_em->width = TILEX;
8646 g_em->height = TILEY;
8650 /* skip check for EMC elements not contained in original EMC artwork */
8651 if (element == EL_PLAYER_3 ||
8652 element == EL_PLAYER_4)
8655 if (g_em->bitmap != debug_bitmap ||
8656 g_em->src_x != debug_src_x ||
8657 g_em->src_y != debug_src_y)
8659 static int last_i = -1;
8667 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
8668 p, i, element, element_info[element].token_name,
8669 element_action_info[effective_action].suffix, direction);
8671 if (element != effective_element)
8672 printf(" [%d ('%s')]",
8674 element_info[effective_element].token_name);
8678 if (g_em->bitmap != debug_bitmap)
8679 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
8680 j, (int)(g_em->bitmap), (int)(debug_bitmap));
8682 if (g_em->src_x != debug_src_x ||
8683 g_em->src_y != debug_src_y)
8684 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
8686 g_em->src_x, g_em->src_y,
8687 g_em->src_x / 32, g_em->src_y / 32,
8688 debug_src_x, debug_src_y,
8689 debug_src_x / 32, debug_src_y / 32);
8691 num_em_gfx_errors++;
8701 printf("::: [%d errors found]\n", num_em_gfx_errors);
8707 void CheckSaveEngineSnapshot_EM(byte action[MAX_PLAYERS], int frame,
8708 boolean any_player_moving,
8709 boolean any_player_snapping,
8710 boolean any_player_dropping)
8712 if (frame == 0 && !any_player_dropping)
8714 if (!local_player->was_waiting)
8716 if (!CheckSaveEngineSnapshotToList())
8719 local_player->was_waiting = TRUE;
8722 else if (any_player_moving || any_player_snapping || any_player_dropping)
8724 local_player->was_waiting = FALSE;
8728 void CheckSaveEngineSnapshot_SP(boolean murphy_is_waiting,
8729 boolean murphy_is_dropping)
8731 if (murphy_is_waiting)
8733 if (!local_player->was_waiting)
8735 if (!CheckSaveEngineSnapshotToList())
8738 local_player->was_waiting = TRUE;
8743 local_player->was_waiting = FALSE;
8747 void CheckSingleStepMode_EM(byte action[MAX_PLAYERS], int frame,
8748 boolean any_player_moving,
8749 boolean any_player_snapping,
8750 boolean any_player_dropping)
8752 if (tape.single_step && tape.recording && !tape.pausing)
8753 if (frame == 0 && !any_player_dropping)
8754 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
8756 CheckSaveEngineSnapshot_EM(action, frame, any_player_moving,
8757 any_player_snapping, any_player_dropping);
8760 void CheckSingleStepMode_SP(boolean murphy_is_waiting,
8761 boolean murphy_is_dropping)
8763 boolean murphy_starts_dropping = FALSE;
8766 for (i = 0; i < MAX_PLAYERS; i++)
8767 if (stored_player[i].force_dropping)
8768 murphy_starts_dropping = TRUE;
8770 if (tape.single_step && tape.recording && !tape.pausing)
8771 if (murphy_is_waiting && !murphy_starts_dropping)
8772 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
8774 CheckSaveEngineSnapshot_SP(murphy_is_waiting, murphy_is_dropping);
8777 void getGraphicSource_SP(struct GraphicInfo_SP *g_sp,
8778 int graphic, int sync_frame, int x, int y)
8780 int frame = getGraphicAnimationFrame(graphic, sync_frame);
8782 getGraphicSource(graphic, frame, &g_sp->bitmap, &g_sp->src_x, &g_sp->src_y);
8785 boolean isNextAnimationFrame_SP(int graphic, int sync_frame)
8787 return (IS_NEXT_FRAME(sync_frame, graphic));
8790 int getGraphicInfo_Delay(int graphic)
8792 return graphic_info[graphic].anim_delay;
8795 void PlayMenuSoundExt(int sound)
8797 if (sound == SND_UNDEFINED)
8800 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8801 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8804 if (IS_LOOP_SOUND(sound))
8805 PlaySoundLoop(sound);
8810 void PlayMenuSound()
8812 PlayMenuSoundExt(menu.sound[game_status]);
8815 void PlayMenuSoundStereo(int sound, int stereo_position)
8817 if (sound == SND_UNDEFINED)
8820 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8821 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8824 if (IS_LOOP_SOUND(sound))
8825 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
8827 PlaySoundStereo(sound, stereo_position);
8830 void PlayMenuSoundIfLoopExt(int sound)
8832 if (sound == SND_UNDEFINED)
8835 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8836 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8839 if (IS_LOOP_SOUND(sound))
8840 PlaySoundLoop(sound);
8843 void PlayMenuSoundIfLoop()
8845 PlayMenuSoundIfLoopExt(menu.sound[game_status]);
8848 void PlayMenuMusicExt(int music)
8850 if (music == MUS_UNDEFINED)
8853 if (!setup.sound_music)
8859 void PlayMenuMusic()
8861 char *curr_music = getCurrentlyPlayingMusicFilename();
8862 char *next_music = getMusicInfoEntryFilename(menu.music[game_status]);
8864 if (!strEqual(curr_music, next_music))
8865 PlayMenuMusicExt(menu.music[game_status]);
8868 void PlayMenuSoundsAndMusic()
8874 static void FadeMenuSounds()
8879 static void FadeMenuMusic()
8881 char *curr_music = getCurrentlyPlayingMusicFilename();
8882 char *next_music = getMusicInfoEntryFilename(menu.music[game_status]);
8884 if (!strEqual(curr_music, next_music))
8888 void FadeMenuSoundsAndMusic()
8894 void PlaySoundActivating()
8897 PlaySound(SND_MENU_ITEM_ACTIVATING);
8901 void PlaySoundSelecting()
8904 PlaySound(SND_MENU_ITEM_SELECTING);
8908 void ToggleFullscreenOrChangeWindowScalingIfNeeded()
8910 boolean change_fullscreen = (setup.fullscreen !=
8911 video.fullscreen_enabled);
8912 boolean change_window_scaling_percent = (!video.fullscreen_enabled &&
8913 setup.window_scaling_percent !=
8914 video.window_scaling_percent);
8916 if (change_window_scaling_percent && video.fullscreen_enabled)
8919 if (!change_window_scaling_percent && !video.fullscreen_available)
8922 #if defined(TARGET_SDL2)
8923 if (change_window_scaling_percent)
8925 SDLSetWindowScaling(setup.window_scaling_percent);
8929 else if (change_fullscreen)
8931 SDLSetWindowFullscreen(setup.fullscreen);
8933 /* set setup value according to successfully changed fullscreen mode */
8934 setup.fullscreen = video.fullscreen_enabled;
8940 if (change_fullscreen ||
8941 change_window_scaling_percent)
8943 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
8945 /* save backbuffer content which gets lost when toggling fullscreen mode */
8946 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8948 if (change_window_scaling_percent)
8950 /* keep window mode, but change window scaling */
8951 video.fullscreen_enabled = TRUE; /* force new window scaling */
8954 /* toggle fullscreen */
8955 ChangeVideoModeIfNeeded(setup.fullscreen);
8957 /* set setup value according to successfully changed fullscreen mode */
8958 setup.fullscreen = video.fullscreen_enabled;
8960 /* restore backbuffer content from temporary backbuffer backup bitmap */
8961 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8963 FreeBitmap(tmp_backbuffer);
8965 /* update visible window/screen */
8966 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8970 void JoinRectangles(int *x, int *y, int *width, int *height,
8971 int x2, int y2, int width2, int height2)
8973 // do not join with "off-screen" rectangle
8974 if (x2 == -1 || y2 == -1)
8979 *width = MAX(*width, width2);
8980 *height = MAX(*height, height2);
8983 void SetAnimStatus(int anim_status_new)
8985 if (anim_status_new == GAME_MODE_MAIN)
8986 anim_status_new = GAME_MODE_PSEUDO_MAINONLY;
8987 else if (anim_status_new == GAME_MODE_SCORES)
8988 anim_status_new = GAME_MODE_PSEUDO_SCORESOLD;
8990 global.anim_status_next = anim_status_new;
8992 // directly set screen modes that are entered without fading
8993 if ((global.anim_status == GAME_MODE_PSEUDO_MAINONLY &&
8994 global.anim_status_next == GAME_MODE_PSEUDO_TYPENAME) ||
8995 (global.anim_status == GAME_MODE_PSEUDO_TYPENAME &&
8996 global.anim_status_next == GAME_MODE_PSEUDO_MAINONLY))
8997 global.anim_status = global.anim_status_next;
9000 void SetGameStatus(int game_status_new)
9002 if (game_status_new != game_status)
9003 game_status_last_screen = game_status;
9005 game_status = game_status_new;
9007 SetAnimStatus(game_status_new);
9010 void SetFontStatus(int game_status_new)
9012 static int last_game_status = -1;
9014 if (game_status_new != -1)
9016 // set game status for font use after storing last game status
9017 last_game_status = game_status;
9018 game_status = game_status_new;
9022 // reset game status after font use from last stored game status
9023 game_status = last_game_status;
9027 void ResetFontStatus()
9032 boolean CheckIfPlayfieldViewportHasChanged()
9034 // if game status has not changed, playfield viewport has not changed either
9035 if (game_status == game_status_last)
9038 // check if playfield viewport has changed with current game status
9039 struct RectWithBorder *vp_playfield = &viewport.playfield[game_status];
9040 int new_real_sx = vp_playfield->x;
9041 int new_real_sy = vp_playfield->y;
9042 int new_full_sxsize = vp_playfield->width;
9043 int new_full_sysize = vp_playfield->height;
9045 return (new_real_sx != REAL_SX ||
9046 new_real_sy != REAL_SY ||
9047 new_full_sxsize != FULL_SXSIZE ||
9048 new_full_sysize != FULL_SYSIZE);
9051 boolean CheckIfGlobalBorderOrPlayfieldViewportHasChanged()
9053 return (CheckIfGlobalBorderHasChanged() ||
9054 CheckIfPlayfieldViewportHasChanged());
9057 void ChangeViewportPropertiesIfNeeded()
9059 boolean use_mini_tilesize = (level.game_engine_type == GAME_ENGINE_TYPE_MM ?
9060 FALSE : setup.small_game_graphics);
9061 int gfx_game_mode = game_status;
9062 int gfx_game_mode2 = (game_status == GAME_MODE_EDITOR ? GAME_MODE_DEFAULT :
9064 struct RectWithBorder *vp_window = &viewport.window[gfx_game_mode];
9065 struct RectWithBorder *vp_playfield = &viewport.playfield[gfx_game_mode];
9066 struct RectWithBorder *vp_door_1 = &viewport.door_1[gfx_game_mode];
9067 struct RectWithBorder *vp_door_2 = &viewport.door_2[gfx_game_mode2];
9068 struct RectWithBorder *vp_door_3 = &viewport.door_2[GAME_MODE_EDITOR];
9069 int new_win_xsize = vp_window->width;
9070 int new_win_ysize = vp_window->height;
9071 int border_size = vp_playfield->border_size;
9072 int new_sx = vp_playfield->x + border_size;
9073 int new_sy = vp_playfield->y + border_size;
9074 int new_sxsize = vp_playfield->width - 2 * border_size;
9075 int new_sysize = vp_playfield->height - 2 * border_size;
9076 int new_real_sx = vp_playfield->x;
9077 int new_real_sy = vp_playfield->y;
9078 int new_full_sxsize = vp_playfield->width;
9079 int new_full_sysize = vp_playfield->height;
9080 int new_dx = vp_door_1->x;
9081 int new_dy = vp_door_1->y;
9082 int new_dxsize = vp_door_1->width;
9083 int new_dysize = vp_door_1->height;
9084 int new_vx = vp_door_2->x;
9085 int new_vy = vp_door_2->y;
9086 int new_vxsize = vp_door_2->width;
9087 int new_vysize = vp_door_2->height;
9088 int new_ex = vp_door_3->x;
9089 int new_ey = vp_door_3->y;
9090 int new_exsize = vp_door_3->width;
9091 int new_eysize = vp_door_3->height;
9092 int new_tilesize_var = (use_mini_tilesize ? MINI_TILESIZE : game.tile_size);
9093 int tilesize = (gfx_game_mode == GAME_MODE_PLAYING ? new_tilesize_var :
9094 gfx_game_mode == GAME_MODE_EDITOR ? MINI_TILESIZE : TILESIZE);
9095 int new_scr_fieldx = new_sxsize / tilesize;
9096 int new_scr_fieldy = new_sysize / tilesize;
9097 int new_scr_fieldx_buffers = new_sxsize / new_tilesize_var;
9098 int new_scr_fieldy_buffers = new_sysize / new_tilesize_var;
9099 boolean init_gfx_buffers = FALSE;
9100 boolean init_video_buffer = FALSE;
9101 boolean init_gadgets_and_anims = FALSE;
9102 boolean init_em_graphics = FALSE;
9104 if (new_win_xsize != WIN_XSIZE ||
9105 new_win_ysize != WIN_YSIZE)
9107 WIN_XSIZE = new_win_xsize;
9108 WIN_YSIZE = new_win_ysize;
9110 init_video_buffer = TRUE;
9111 init_gfx_buffers = TRUE;
9112 init_gadgets_and_anims = TRUE;
9114 // printf("::: video: init_video_buffer, init_gfx_buffers\n");
9117 if (new_scr_fieldx != SCR_FIELDX ||
9118 new_scr_fieldy != SCR_FIELDY)
9120 /* this always toggles between MAIN and GAME when using small tile size */
9122 SCR_FIELDX = new_scr_fieldx;
9123 SCR_FIELDY = new_scr_fieldy;
9125 // printf("::: new_scr_fieldx != SCR_FIELDX ...\n");
9136 new_sxsize != SXSIZE ||
9137 new_sysize != SYSIZE ||
9138 new_dxsize != DXSIZE ||
9139 new_dysize != DYSIZE ||
9140 new_vxsize != VXSIZE ||
9141 new_vysize != VYSIZE ||
9142 new_exsize != EXSIZE ||
9143 new_eysize != EYSIZE ||
9144 new_real_sx != REAL_SX ||
9145 new_real_sy != REAL_SY ||
9146 new_full_sxsize != FULL_SXSIZE ||
9147 new_full_sysize != FULL_SYSIZE ||
9148 new_tilesize_var != TILESIZE_VAR
9151 // ------------------------------------------------------------------------
9152 // determine next fading area for changed viewport definitions
9153 // ------------------------------------------------------------------------
9155 // start with current playfield area (default fading area)
9158 FADE_SXSIZE = FULL_SXSIZE;
9159 FADE_SYSIZE = FULL_SYSIZE;
9161 // add new playfield area if position or size has changed
9162 if (new_real_sx != REAL_SX || new_real_sy != REAL_SY ||
9163 new_full_sxsize != FULL_SXSIZE || new_full_sysize != FULL_SYSIZE)
9165 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
9166 new_real_sx, new_real_sy, new_full_sxsize,new_full_sysize);
9169 // add current and new door 1 area if position or size has changed
9170 if (new_dx != DX || new_dy != DY ||
9171 new_dxsize != DXSIZE || new_dysize != DYSIZE)
9173 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
9174 DX, DY, DXSIZE, DYSIZE);
9175 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
9176 new_dx, new_dy, new_dxsize, new_dysize);
9179 // add current and new door 2 area if position or size has changed
9180 if (new_dx != VX || new_dy != VY ||
9181 new_dxsize != VXSIZE || new_dysize != VYSIZE)
9183 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
9184 VX, VY, VXSIZE, VYSIZE);
9185 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
9186 new_vx, new_vy, new_vxsize, new_vysize);
9189 // ------------------------------------------------------------------------
9190 // handle changed tile size
9191 // ------------------------------------------------------------------------
9193 if (new_tilesize_var != TILESIZE_VAR)
9195 // printf("::: new_tilesize_var != TILESIZE_VAR\n");
9197 // changing tile size invalidates scroll values of engine snapshots
9198 FreeEngineSnapshotSingle();
9200 // changing tile size requires update of graphic mapping for EM engine
9201 init_em_graphics = TRUE;
9212 SXSIZE = new_sxsize;
9213 SYSIZE = new_sysize;
9214 DXSIZE = new_dxsize;
9215 DYSIZE = new_dysize;
9216 VXSIZE = new_vxsize;
9217 VYSIZE = new_vysize;
9218 EXSIZE = new_exsize;
9219 EYSIZE = new_eysize;
9220 REAL_SX = new_real_sx;
9221 REAL_SY = new_real_sy;
9222 FULL_SXSIZE = new_full_sxsize;
9223 FULL_SYSIZE = new_full_sysize;
9224 TILESIZE_VAR = new_tilesize_var;
9226 init_gfx_buffers = TRUE;
9227 init_gadgets_and_anims = TRUE;
9229 // printf("::: viewports: init_gfx_buffers\n");
9230 // printf("::: viewports: init_gadgets_and_anims\n");
9233 if (init_gfx_buffers)
9235 // printf("::: init_gfx_buffers\n");
9237 SCR_FIELDX = new_scr_fieldx_buffers;
9238 SCR_FIELDY = new_scr_fieldy_buffers;
9242 SCR_FIELDX = new_scr_fieldx;
9243 SCR_FIELDY = new_scr_fieldy;
9245 SetDrawDeactivationMask(REDRAW_NONE);
9246 SetDrawBackgroundMask(REDRAW_FIELD);
9249 if (init_video_buffer)
9251 // printf("::: init_video_buffer\n");
9253 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
9254 InitImageTextures();
9257 if (init_gadgets_and_anims)
9259 // printf("::: init_gadgets_and_anims\n");
9262 InitGlobalAnimations();
9265 if (init_em_graphics)
9267 InitGraphicInfo_EM();