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 void DumpTile(int x, int y)
200 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
206 printf_line("-", 79);
207 printf("Field Info: SCREEN(%d, %d), LEVEL(%d, %d)\n", sx, sy, x, y);
208 printf_line("-", 79);
210 if (!IN_LEV_FIELD(x, y))
212 printf("(not in level field)\n");
218 printf(" Feld: %d\t['%s']\n", Feld[x][y],
219 element_info[Feld[x][y]].token_name);
220 printf(" Back: %s\n", print_if_not_empty(Back[x][y]));
221 printf(" Store: %s\n", print_if_not_empty(Store[x][y]));
222 printf(" Store2: %s\n", print_if_not_empty(Store2[x][y]));
223 printf(" StorePlayer: %s\n", print_if_not_empty(StorePlayer[x][y]));
224 printf(" MovPos: %d\n", MovPos[x][y]);
225 printf(" MovDir: %d\n", MovDir[x][y]);
226 printf(" MovDelay: %d\n", MovDelay[x][y]);
227 printf(" ChangeDelay: %d\n", ChangeDelay[x][y]);
228 printf(" CustomValue: %d\n", CustomValue[x][y]);
229 printf(" GfxElement: %d\n", GfxElement[x][y]);
230 printf(" GfxAction: %d\n", GfxAction[x][y]);
231 printf(" GfxFrame: %d [%d]\n", GfxFrame[x][y], FrameCounter);
235 void SetDrawtoField(int mode)
237 if (mode == DRAW_TO_FIELDBUFFER)
243 BX2 = SCR_FIELDX + 1;
244 BY2 = SCR_FIELDY + 1;
246 drawto_field = fieldbuffer;
248 else /* DRAW_TO_BACKBUFFER */
254 BX2 = SCR_FIELDX - 1;
255 BY2 = SCR_FIELDY - 1;
257 drawto_field = backbuffer;
261 static void RedrawPlayfield_RND()
263 if (game.envelope_active)
266 DrawLevel(REDRAW_ALL);
270 void RedrawPlayfield()
272 if (game_status != GAME_MODE_PLAYING)
275 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
276 RedrawPlayfield_EM(TRUE);
277 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
278 RedrawPlayfield_SP(TRUE);
279 else if (level.game_engine_type == GAME_ENGINE_TYPE_RND)
280 RedrawPlayfield_RND();
282 BlitScreenToBitmap(backbuffer);
284 BlitBitmap(drawto, window, gfx.sx, gfx.sy, gfx.sxsize, gfx.sysize,
288 static void DrawMaskedBorderExt_Rect(int x, int y, int width, int height,
291 Bitmap *src_bitmap = getGlobalBorderBitmapFromStatus(global.border_status);
292 Bitmap *dst_bitmap = gfx.masked_border_bitmap_ptr;
294 if (x == -1 && y == -1)
297 if (draw_target == DRAW_TO_SCREEN)
298 BlitToScreenMasked(src_bitmap, x, y, width, height, x, y);
300 BlitBitmapMasked(src_bitmap, dst_bitmap, x, y, width, height, x, y);
303 static void DrawMaskedBorderExt_FIELD(int draw_target)
305 if (global.border_status >= GAME_MODE_MAIN &&
306 global.border_status <= GAME_MODE_PLAYING &&
307 border.draw_masked[global.border_status])
308 DrawMaskedBorderExt_Rect(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
312 static void DrawMaskedBorderExt_DOOR_1(int draw_target)
314 // when drawing to backbuffer, never draw border over open doors
315 if (draw_target == DRAW_TO_BACKBUFFER &&
316 (GetDoorState() & DOOR_OPEN_1))
319 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
320 (global.border_status != GAME_MODE_EDITOR ||
321 border.draw_masked[GFX_SPECIAL_ARG_EDITOR]))
322 DrawMaskedBorderExt_Rect(DX, DY, DXSIZE, DYSIZE, draw_target);
325 static void DrawMaskedBorderExt_DOOR_2(int draw_target)
327 // when drawing to backbuffer, never draw border over open doors
328 if (draw_target == DRAW_TO_BACKBUFFER &&
329 (GetDoorState() & DOOR_OPEN_2))
332 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
333 global.border_status != GAME_MODE_EDITOR)
334 DrawMaskedBorderExt_Rect(VX, VY, VXSIZE, VYSIZE, draw_target);
337 static void DrawMaskedBorderExt_DOOR_3(int draw_target)
339 /* currently not available */
342 static void DrawMaskedBorderExt_ALL(int draw_target)
344 DrawMaskedBorderExt_FIELD(draw_target);
345 DrawMaskedBorderExt_DOOR_1(draw_target);
346 DrawMaskedBorderExt_DOOR_2(draw_target);
347 DrawMaskedBorderExt_DOOR_3(draw_target);
350 static void DrawMaskedBorderExt(int redraw_mask, int draw_target)
352 /* never draw masked screen borders on borderless screens */
353 if (global.border_status == GAME_MODE_LOADING ||
354 global.border_status == GAME_MODE_TITLE)
357 if (redraw_mask & REDRAW_ALL)
358 DrawMaskedBorderExt_ALL(draw_target);
361 if (redraw_mask & REDRAW_FIELD)
362 DrawMaskedBorderExt_FIELD(draw_target);
363 if (redraw_mask & REDRAW_DOOR_1)
364 DrawMaskedBorderExt_DOOR_1(draw_target);
365 if (redraw_mask & REDRAW_DOOR_2)
366 DrawMaskedBorderExt_DOOR_2(draw_target);
367 if (redraw_mask & REDRAW_DOOR_3)
368 DrawMaskedBorderExt_DOOR_3(draw_target);
372 void DrawMaskedBorder_FIELD()
374 DrawMaskedBorderExt_FIELD(DRAW_TO_BACKBUFFER);
377 void DrawMaskedBorder(int redraw_mask)
379 DrawMaskedBorderExt(redraw_mask, DRAW_TO_BACKBUFFER);
382 void DrawMaskedBorderToTarget(int draw_target)
384 if (draw_target == DRAW_TO_BACKBUFFER ||
385 draw_target == DRAW_TO_SCREEN)
387 DrawMaskedBorderExt(REDRAW_ALL, draw_target);
391 int last_border_status = global.border_status;
393 if (draw_target == DRAW_TO_FADE_SOURCE)
395 global.border_status = gfx.fade_border_source_status;
396 gfx.masked_border_bitmap_ptr = gfx.fade_bitmap_source;
398 else if (draw_target == DRAW_TO_FADE_TARGET)
400 global.border_status = gfx.fade_border_target_status;
401 gfx.masked_border_bitmap_ptr = gfx.fade_bitmap_target;
404 DrawMaskedBorderExt(REDRAW_ALL, draw_target);
406 global.border_status = last_border_status;
407 gfx.masked_border_bitmap_ptr = backbuffer;
411 void BlitScreenToBitmap_RND(Bitmap *target_bitmap)
413 int fx = FX, fy = FY;
414 int full_lev_fieldx = lev_fieldx + (BorderElement != EL_EMPTY ? 2 : 0);
415 int full_lev_fieldy = lev_fieldy + (BorderElement != EL_EMPTY ? 2 : 0);
417 int dx = (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
418 int dy = (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
419 int dx_var = dx * TILESIZE_VAR / TILESIZE;
420 int dy_var = dy * TILESIZE_VAR / TILESIZE;
423 ffx = (scroll_x - SBX_Left) * TILEX_VAR + dx_var;
424 ffy = (scroll_y - SBY_Upper) * TILEY_VAR + dy_var;
426 if (EVEN(SCR_FIELDX))
428 if (ffx < SBX_Right * TILEX_VAR + TILEX_VAR / 2 + TILEX_VAR)
429 fx += dx_var - MIN(ffx, TILEX_VAR / 2) + TILEX_VAR;
431 fx += (dx_var > 0 ? TILEX_VAR : 0);
438 if (EVEN(SCR_FIELDY))
440 if (ffy < SBY_Lower * TILEY_VAR + TILEY_VAR / 2 + TILEY_VAR)
441 fy += dy_var - MIN(ffy, TILEY_VAR / 2) + TILEY_VAR;
443 fy += (dy_var > 0 ? TILEY_VAR : 0);
450 if (full_lev_fieldx <= SCR_FIELDX)
452 if (EVEN(SCR_FIELDX))
453 fx = 2 * TILEX_VAR - (ODD(lev_fieldx) ? TILEX_VAR / 2 : 0);
455 fx = 2 * TILEX_VAR - (EVEN(lev_fieldx) ? TILEX_VAR / 2 : 0);
458 if (full_lev_fieldy <= SCR_FIELDY)
460 if (EVEN(SCR_FIELDY))
461 fy = 2 * TILEY_VAR - (ODD(lev_fieldy) ? TILEY_VAR / 2 : 0);
463 fy = 2 * TILEY_VAR - (EVEN(lev_fieldy) ? TILEY_VAR / 2 : 0);
466 BlitBitmap(drawto_field, target_bitmap, fx, fy, SXSIZE, SYSIZE, SX, SY);
469 void BlitScreenToBitmap(Bitmap *target_bitmap)
471 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
472 BlitScreenToBitmap_EM(target_bitmap);
473 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
474 BlitScreenToBitmap_SP(target_bitmap);
475 else if (level.game_engine_type == GAME_ENGINE_TYPE_RND)
476 BlitScreenToBitmap_RND(target_bitmap);
478 redraw_mask |= REDRAW_FIELD;
481 void DrawFramesPerSecond()
484 int font_nr = FONT_TEXT_2;
485 int font_width = getFontWidth(font_nr);
487 sprintf(text, "%04.1f fps", global.frames_per_second);
489 DrawTextExt(backbuffer, WIN_XSIZE - font_width * strlen(text), 0, text,
490 font_nr, BLIT_OPAQUE);
494 static void PrintFrameTimeDebugging()
496 static unsigned int last_counter = 0;
497 unsigned int counter = Counter();
498 int diff_1 = counter - last_counter;
499 int diff_2 = diff_1 - GAME_FRAME_DELAY;
501 int diff_2_cut = MIN(ABS(diff_2), diff_2_max);
502 char diff_bar[2 * diff_2_max + 5];
506 diff_bar[pos++] = (diff_2 < -diff_2_max ? '<' : ' ');
508 for (i = 0; i < diff_2_max; i++)
509 diff_bar[pos++] = (diff_2 >= 0 ? ' ' :
510 i >= diff_2_max - diff_2_cut ? '-' : ' ');
512 diff_bar[pos++] = '|';
514 for (i = 0; i < diff_2_max; i++)
515 diff_bar[pos++] = (diff_2 <= 0 ? ' ' : i < diff_2_cut ? '+' : ' ');
517 diff_bar[pos++] = (diff_2 > diff_2_max ? '>' : ' ');
519 diff_bar[pos++] = '\0';
521 Error(ERR_INFO, "%06d [%02d] [%c%02d] %s",
524 (diff_2 < 0 ? '-' : diff_2 > 0 ? '+' : ' '), ABS(diff_2),
527 last_counter = counter;
533 static int last_redraw_mask = REDRAW_NONE;
535 // force screen redraw in every frame to continue drawing global animations
536 // (but always use the last redraw mask to prevent unwanted side effects)
537 if (redraw_mask == REDRAW_NONE)
538 redraw_mask = last_redraw_mask;
540 last_redraw_mask = redraw_mask;
543 // masked border now drawn immediately when blitting backbuffer to window
545 // draw masked border to all viewports, if defined
546 DrawMaskedBorder(redraw_mask);
549 // draw frames per second (only if debug mode is enabled)
550 if (redraw_mask & REDRAW_FPS)
551 DrawFramesPerSecond();
553 // remove playfield redraw before potentially merging with doors redraw
554 if (DrawingDeactivated(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE))
555 redraw_mask &= ~REDRAW_FIELD;
557 // redraw complete window if both playfield and (some) doors need redraw
558 if (redraw_mask & REDRAW_FIELD && redraw_mask & REDRAW_DOORS)
559 redraw_mask = REDRAW_ALL;
561 /* although redrawing the whole window would be fine for normal gameplay,
562 being able to only redraw the playfield is required for deactivating
563 certain drawing areas (mainly playfield) to work, which is needed for
564 warp-forward to be fast enough (by skipping redraw of most frames) */
566 if (redraw_mask & REDRAW_ALL)
568 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
570 else if (redraw_mask & REDRAW_FIELD)
572 BlitBitmap(backbuffer, window,
573 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
575 else if (redraw_mask & REDRAW_DOORS)
577 // merge door areas to prevent calling screen redraw more than once
583 if (redraw_mask & REDRAW_DOOR_1)
587 x2 = MAX(x2, DX + DXSIZE);
588 y2 = MAX(y2, DY + DYSIZE);
591 if (redraw_mask & REDRAW_DOOR_2)
595 x2 = MAX(x2, VX + VXSIZE);
596 y2 = MAX(y2, VY + VYSIZE);
599 if (redraw_mask & REDRAW_DOOR_3)
603 x2 = MAX(x2, EX + EXSIZE);
604 y2 = MAX(y2, EY + EYSIZE);
607 BlitBitmap(backbuffer, window, x1, y1, x2 - x1, y2 - y1, x1, y1);
610 redraw_mask = REDRAW_NONE;
613 PrintFrameTimeDebugging();
617 void BackToFront_WithFrameDelay(unsigned int frame_delay_value)
619 unsigned int frame_delay_value_old = GetVideoFrameDelay();
621 SetVideoFrameDelay(frame_delay_value);
625 SetVideoFrameDelay(frame_delay_value_old);
628 static void FadeExt(int fade_mask, int fade_mode, int fade_type)
630 static int fade_type_skip = FADE_TYPE_NONE;
631 void (*draw_border_function)(void) = NULL;
632 int x, y, width, height;
633 int fade_delay, post_delay;
635 if (fade_type == FADE_TYPE_FADE_OUT)
637 if (fade_type_skip != FADE_TYPE_NONE)
639 /* skip all fade operations until specified fade operation */
640 if (fade_type & fade_type_skip)
641 fade_type_skip = FADE_TYPE_NONE;
646 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
650 redraw_mask |= fade_mask;
652 if (fade_type == FADE_TYPE_SKIP)
654 fade_type_skip = fade_mode;
659 fade_delay = fading.fade_delay;
660 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
662 if (fade_type_skip != FADE_TYPE_NONE)
664 /* skip all fade operations until specified fade operation */
665 if (fade_type & fade_type_skip)
666 fade_type_skip = FADE_TYPE_NONE;
671 if (global.autoplay_leveldir)
676 if (fade_mask == REDRAW_FIELD)
681 height = FADE_SYSIZE;
683 if (border.draw_masked_when_fading)
684 draw_border_function = DrawMaskedBorder_FIELD; /* update when fading */
686 DrawMaskedBorder_FIELD(); /* draw once */
688 else /* REDRAW_ALL */
696 if (!setup.fade_screens ||
698 fading.fade_mode == FADE_MODE_NONE)
700 if (fade_mode == FADE_MODE_FADE_OUT)
703 BlitBitmap(backbuffer, window, x, y, width, height, x, y);
705 redraw_mask &= ~fade_mask;
710 FadeRectangle(x, y, width, height, fade_mode, fade_delay, post_delay,
711 draw_border_function);
713 redraw_mask &= ~fade_mask;
716 static void SetScreenStates_BeforeFadingIn()
718 // temporarily set screen mode for animations to screen after fading in
719 global.anim_status = global.anim_status_next;
721 // store backbuffer with all animations that will be started after fading in
722 PrepareFadeBitmap(DRAW_TO_FADE_TARGET);
724 // set screen mode for animations back to fading
725 global.anim_status = GAME_MODE_PSEUDO_FADING;
728 static void SetScreenStates_AfterFadingIn()
730 // store new source screen (to use correct masked border for fading)
731 gfx.fade_border_source_status = global.border_status;
733 global.anim_status = global.anim_status_next;
735 // force update of global animation status in case of rapid screen changes
736 redraw_mask = REDRAW_ALL;
740 static void SetScreenStates_BeforeFadingOut()
742 // required if "fade_mask != redraw_mask" (fading only affects fade area)
745 // store new target screen (to use correct masked border for fading)
746 gfx.fade_border_target_status = game_status;
748 // set screen mode for animations to fading
749 global.anim_status = GAME_MODE_PSEUDO_FADING;
751 // store backbuffer with all animations that will be stopped for fading out
752 PrepareFadeBitmap(DRAW_TO_FADE_SOURCE);
755 static void SetScreenStates_AfterFadingOut()
757 global.border_status = game_status;
760 void FadeIn(int fade_mask)
762 SetScreenStates_BeforeFadingIn();
765 DrawMaskedBorder(REDRAW_ALL);
768 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
769 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_IN);
771 FadeExt(fade_mask, FADE_MODE_FADE_IN, FADE_TYPE_FADE_IN);
775 FADE_SXSIZE = FULL_SXSIZE;
776 FADE_SYSIZE = FULL_SYSIZE;
778 SetScreenStates_AfterFadingIn();
781 void FadeOut(int fade_mask)
783 SetScreenStates_BeforeFadingOut();
786 DrawMaskedBorder(REDRAW_ALL);
789 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
790 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_OUT);
792 FadeExt(fade_mask, FADE_MODE_FADE_OUT, FADE_TYPE_FADE_OUT);
794 SetScreenStates_AfterFadingOut();
797 static void FadeSetLeaveNext(struct TitleFadingInfo fading_leave, boolean set)
799 static struct TitleFadingInfo fading_leave_stored;
802 fading_leave_stored = fading_leave;
804 fading = fading_leave_stored;
807 void FadeSetEnterMenu()
809 fading = menu.enter_menu;
811 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
814 void FadeSetLeaveMenu()
816 fading = menu.leave_menu;
818 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
821 void FadeSetEnterScreen()
823 fading = menu.enter_screen[game_status];
825 FadeSetLeaveNext(menu.leave_screen[game_status], TRUE); /* store */
828 void FadeSetNextScreen()
830 fading = menu.next_screen[game_status];
832 // (do not overwrite fade mode set by FadeSetEnterScreen)
833 // FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
836 void FadeSetLeaveScreen()
838 FadeSetLeaveNext(menu.leave_screen[game_status], FALSE); /* recall */
841 void FadeSetFromType(int type)
843 if (type & TYPE_ENTER_SCREEN)
844 FadeSetEnterScreen();
845 else if (type & TYPE_ENTER)
847 else if (type & TYPE_LEAVE)
851 void FadeSetDisabled()
853 static struct TitleFadingInfo fading_none = { FADE_MODE_NONE, -1, -1, -1 };
855 fading = fading_none;
858 void FadeSkipNextFadeIn()
860 FadeExt(0, FADE_MODE_SKIP_FADE_IN, FADE_TYPE_SKIP);
863 void FadeSkipNextFadeOut()
865 FadeExt(0, FADE_MODE_SKIP_FADE_OUT, FADE_TYPE_SKIP);
868 Bitmap *getBitmapFromGraphicOrDefault(int graphic, int default_graphic)
870 boolean redefined = getImageListEntryFromImageID(graphic)->redefined;
872 return (graphic == IMG_UNDEFINED ? NULL :
873 graphic_info[graphic].bitmap != NULL || redefined ?
874 graphic_info[graphic].bitmap :
875 graphic_info[default_graphic].bitmap);
878 Bitmap *getBackgroundBitmap(int graphic)
880 return getBitmapFromGraphicOrDefault(graphic, IMG_BACKGROUND);
883 Bitmap *getGlobalBorderBitmap(int graphic)
885 return getBitmapFromGraphicOrDefault(graphic, IMG_GLOBAL_BORDER);
888 Bitmap *getGlobalBorderBitmapFromStatus(int status)
891 (status == GAME_MODE_MAIN ||
892 status == GAME_MODE_PSEUDO_TYPENAME ? IMG_GLOBAL_BORDER_MAIN :
893 status == GAME_MODE_SCORES ? IMG_GLOBAL_BORDER_SCORES :
894 status == GAME_MODE_EDITOR ? IMG_GLOBAL_BORDER_EDITOR :
895 status == GAME_MODE_PLAYING ? IMG_GLOBAL_BORDER_PLAYING :
898 return getGlobalBorderBitmap(graphic);
901 void SetWindowBackgroundImageIfDefined(int graphic)
903 if (graphic_info[graphic].bitmap)
904 SetWindowBackgroundBitmap(graphic_info[graphic].bitmap);
907 void SetMainBackgroundImageIfDefined(int graphic)
909 if (graphic_info[graphic].bitmap)
910 SetMainBackgroundBitmap(graphic_info[graphic].bitmap);
913 void SetDoorBackgroundImageIfDefined(int graphic)
915 if (graphic_info[graphic].bitmap)
916 SetDoorBackgroundBitmap(graphic_info[graphic].bitmap);
919 void SetWindowBackgroundImage(int graphic)
921 SetWindowBackgroundBitmap(getBackgroundBitmap(graphic));
924 void SetMainBackgroundImage(int graphic)
926 SetMainBackgroundBitmap(getBackgroundBitmap(graphic));
929 void SetDoorBackgroundImage(int graphic)
931 SetDoorBackgroundBitmap(getBackgroundBitmap(graphic));
934 void SetPanelBackground()
936 struct GraphicInfo *gfx = &graphic_info[IMG_BACKGROUND_PANEL];
938 BlitBitmapTiled(gfx->bitmap, bitmap_db_panel, gfx->src_x, gfx->src_y,
939 gfx->width, gfx->height, 0, 0, DXSIZE, DYSIZE);
941 SetDoorBackgroundBitmap(bitmap_db_panel);
944 void DrawBackground(int x, int y, int width, int height)
946 /* "drawto" might still point to playfield buffer here (hall of fame) */
947 ClearRectangleOnBackground(backbuffer, x, y, width, height);
949 if (IN_GFX_FIELD_FULL(x, y))
950 redraw_mask |= REDRAW_FIELD;
951 else if (IN_GFX_DOOR_1(x, y))
952 redraw_mask |= REDRAW_DOOR_1;
953 else if (IN_GFX_DOOR_2(x, y))
954 redraw_mask |= REDRAW_DOOR_2;
955 else if (IN_GFX_DOOR_3(x, y))
956 redraw_mask |= REDRAW_DOOR_3;
959 void DrawBackgroundForFont(int x, int y, int width, int height, int font_nr)
961 struct FontBitmapInfo *font = getFontBitmapInfo(font_nr);
963 if (font->bitmap == NULL)
966 DrawBackground(x, y, width, height);
969 void DrawBackgroundForGraphic(int x, int y, int width, int height, int graphic)
971 struct GraphicInfo *g = &graphic_info[graphic];
973 if (g->bitmap == NULL)
976 DrawBackground(x, y, width, height);
979 static int game_status_last = -1;
980 static Bitmap *global_border_bitmap_last = NULL;
981 static Bitmap *global_border_bitmap = NULL;
982 static int real_sx_last = -1, real_sy_last = -1;
983 static int full_sxsize_last = -1, full_sysize_last = -1;
984 static int dx_last = -1, dy_last = -1;
985 static int dxsize_last = -1, dysize_last = -1;
986 static int vx_last = -1, vy_last = -1;
987 static int vxsize_last = -1, vysize_last = -1;
989 boolean CheckIfGlobalBorderHasChanged()
991 // if game status has not changed, global border has not changed either
992 if (game_status == game_status_last)
995 // determine and store new global border bitmap for current game status
996 global_border_bitmap = getGlobalBorderBitmapFromStatus(game_status);
998 return (global_border_bitmap_last != global_border_bitmap);
1001 boolean CheckIfGlobalBorderRedrawIsNeeded()
1003 // if game status has not changed, nothing has to be redrawn
1004 if (game_status == game_status_last)
1007 // redraw if last screen was title screen
1008 if (game_status_last == GAME_MODE_TITLE)
1011 // redraw if global screen border has changed
1012 if (CheckIfGlobalBorderHasChanged())
1015 // redraw if position or size of playfield area has changed
1016 if (real_sx_last != REAL_SX || real_sy_last != REAL_SY ||
1017 full_sxsize_last != FULL_SXSIZE || full_sysize_last != FULL_SYSIZE)
1020 // redraw if position or size of door area has changed
1021 if (dx_last != DX || dy_last != DY ||
1022 dxsize_last != DXSIZE || dysize_last != DYSIZE)
1025 // redraw if position or size of tape area has changed
1026 if (vx_last != VX || vy_last != VY ||
1027 vxsize_last != VXSIZE || vysize_last != VYSIZE)
1033 void RedrawGlobalBorderFromBitmap(Bitmap *bitmap)
1036 BlitBitmap(bitmap, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
1038 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
1041 void RedrawGlobalBorder()
1043 Bitmap *bitmap = getGlobalBorderBitmapFromStatus(game_status);
1045 RedrawGlobalBorderFromBitmap(bitmap);
1047 redraw_mask = REDRAW_ALL;
1050 static void RedrawGlobalBorderIfNeeded()
1052 if (game_status == game_status_last)
1055 // copy current draw buffer to later copy back areas that have not changed
1056 if (game_status_last != GAME_MODE_TITLE)
1057 BlitBitmap(backbuffer, bitmap_db_store_1, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
1059 if (CheckIfGlobalBorderRedrawIsNeeded())
1061 // redraw global screen border (or clear, if defined to be empty)
1062 RedrawGlobalBorderFromBitmap(global_border_bitmap);
1064 // copy previous playfield and door areas, if they are defined on both
1065 // previous and current screen and if they still have the same size
1067 if (real_sx_last != -1 && real_sy_last != -1 &&
1068 REAL_SX != -1 && REAL_SY != -1 &&
1069 full_sxsize_last == FULL_SXSIZE && full_sysize_last == FULL_SYSIZE)
1070 BlitBitmap(bitmap_db_store_1, backbuffer,
1071 real_sx_last, real_sy_last, FULL_SXSIZE, FULL_SYSIZE,
1074 if (dx_last != -1 && dy_last != -1 &&
1075 DX != -1 && DY != -1 &&
1076 dxsize_last == DXSIZE && dysize_last == DYSIZE)
1077 BlitBitmap(bitmap_db_store_1, backbuffer,
1078 dx_last, dy_last, DXSIZE, DYSIZE, DX, DY);
1080 if (vx_last != -1 && vy_last != -1 &&
1081 VX != -1 && VY != -1 &&
1082 vxsize_last == VXSIZE && vysize_last == VYSIZE)
1083 BlitBitmap(bitmap_db_store_1, backbuffer,
1084 vx_last, vy_last, VXSIZE, VYSIZE, VX, VY);
1086 redraw_mask = REDRAW_ALL;
1089 game_status_last = game_status;
1091 global_border_bitmap_last = global_border_bitmap;
1093 real_sx_last = REAL_SX;
1094 real_sy_last = REAL_SY;
1095 full_sxsize_last = FULL_SXSIZE;
1096 full_sysize_last = FULL_SYSIZE;
1099 dxsize_last = DXSIZE;
1100 dysize_last = DYSIZE;
1103 vxsize_last = VXSIZE;
1104 vysize_last = VYSIZE;
1109 RedrawGlobalBorderIfNeeded();
1111 /* !!! "drawto" might still point to playfield buffer here (see above) !!! */
1112 /* (when entering hall of fame after playing) */
1113 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
1115 /* !!! maybe this should be done before clearing the background !!! */
1116 if (game_status == GAME_MODE_PLAYING)
1118 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
1119 SetDrawtoField(DRAW_TO_FIELDBUFFER);
1123 SetDrawtoField(DRAW_TO_BACKBUFFER);
1127 void MarkTileDirty(int x, int y)
1129 redraw_mask |= REDRAW_FIELD;
1132 void SetBorderElement()
1136 BorderElement = EL_EMPTY;
1138 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
1140 for (x = 0; x < lev_fieldx; x++)
1142 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
1143 BorderElement = EL_STEELWALL;
1145 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
1151 void FloodFillLevel(int from_x, int from_y, int fill_element,
1152 short field[MAX_LEV_FIELDX][MAX_LEV_FIELDY],
1153 int max_fieldx, int max_fieldy)
1157 static int check[4][2] = { { -1, 0 }, { 0, -1 }, { 1, 0 }, { 0, 1 } };
1158 static int safety = 0;
1160 /* check if starting field still has the desired content */
1161 if (field[from_x][from_y] == fill_element)
1166 if (safety > max_fieldx * max_fieldy)
1167 Error(ERR_EXIT, "Something went wrong in 'FloodFill()'. Please debug.");
1169 old_element = field[from_x][from_y];
1170 field[from_x][from_y] = fill_element;
1172 for (i = 0; i < 4; i++)
1174 x = from_x + check[i][0];
1175 y = from_y + check[i][1];
1177 if (IN_FIELD(x, y, max_fieldx, max_fieldy) && field[x][y] == old_element)
1178 FloodFillLevel(x, y, fill_element, field, max_fieldx, max_fieldy);
1184 void SetRandomAnimationValue(int x, int y)
1186 gfx.anim_random_frame = GfxRandom[x][y];
1189 int getGraphicAnimationFrame(int graphic, int sync_frame)
1191 /* animation synchronized with global frame counter, not move position */
1192 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
1193 sync_frame = FrameCounter;
1195 return getAnimationFrame(graphic_info[graphic].anim_frames,
1196 graphic_info[graphic].anim_delay,
1197 graphic_info[graphic].anim_mode,
1198 graphic_info[graphic].anim_start_frame,
1202 void getSizedGraphicSourceExt(int graphic, int frame, int tilesize,
1203 Bitmap **bitmap, int *x, int *y,
1204 boolean get_backside)
1206 struct GraphicInfo *g = &graphic_info[graphic];
1207 Bitmap *src_bitmap = g->bitmap;
1208 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
1209 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
1210 int tilesize_capped = MIN(MAX(1, tilesize), TILESIZE);
1212 // if no in-game graphics defined, always use standard graphic size
1213 if (g->bitmaps[IMG_BITMAP_GAME] == NULL)
1214 tilesize = TILESIZE;
1216 if (tilesize == gfx.standard_tile_size)
1217 src_bitmap = g->bitmaps[IMG_BITMAP_STANDARD];
1218 else if (tilesize == game.tile_size)
1219 src_bitmap = g->bitmaps[IMG_BITMAP_GAME];
1221 src_bitmap = g->bitmaps[IMG_BITMAP_1x1 - log_2(tilesize_capped)];
1223 if (g->offset_y == 0) /* frames are ordered horizontally */
1225 int max_width = g->anim_frames_per_line * g->width;
1226 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
1228 src_x = pos % max_width;
1229 src_y = src_y % g->height + pos / max_width * g->height;
1231 else if (g->offset_x == 0) /* frames are ordered vertically */
1233 int max_height = g->anim_frames_per_line * g->height;
1234 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
1236 src_x = src_x % g->width + pos / max_height * g->width;
1237 src_y = pos % max_height;
1239 else /* frames are ordered diagonally */
1241 src_x = src_x + frame * g->offset_x;
1242 src_y = src_y + frame * g->offset_y;
1245 *bitmap = src_bitmap;
1246 *x = src_x * tilesize / g->tile_size;
1247 *y = src_y * tilesize / g->tile_size;
1250 void getFixedGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1251 int *x, int *y, boolean get_backside)
1253 getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y,
1257 void getSizedGraphicSource(int graphic, int frame, int tilesize,
1258 Bitmap **bitmap, int *x, int *y)
1260 getSizedGraphicSourceExt(graphic, frame, tilesize, bitmap, x, y, FALSE);
1263 void getFixedGraphicSource(int graphic, int frame,
1264 Bitmap **bitmap, int *x, int *y)
1266 getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y, FALSE);
1269 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1271 getSizedGraphicSource(graphic, 0, MINI_TILESIZE, bitmap, x, y);
1274 inline static void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1275 int *x, int *y, boolean get_backside)
1277 struct GraphicInfo *g = &graphic_info[graphic];
1278 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
1279 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
1281 if (TILESIZE_VAR != TILESIZE)
1282 return getSizedGraphicSourceExt(graphic, frame, TILESIZE_VAR, bitmap, x, y,
1285 *bitmap = g->bitmap;
1287 if (g->offset_y == 0) /* frames are ordered horizontally */
1289 int max_width = g->anim_frames_per_line * g->width;
1290 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
1292 *x = pos % max_width;
1293 *y = src_y % g->height + pos / max_width * g->height;
1295 else if (g->offset_x == 0) /* frames are ordered vertically */
1297 int max_height = g->anim_frames_per_line * g->height;
1298 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
1300 *x = src_x % g->width + pos / max_height * g->width;
1301 *y = pos % max_height;
1303 else /* frames are ordered diagonally */
1305 *x = src_x + frame * g->offset_x;
1306 *y = src_y + frame * g->offset_y;
1309 *x = *x * TILESIZE_VAR / g->tile_size;
1310 *y = *y * TILESIZE_VAR / g->tile_size;
1313 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
1315 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
1318 void DrawGraphic(int x, int y, int graphic, int frame)
1321 if (!IN_SCR_FIELD(x, y))
1323 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1324 printf("DrawGraphic(): This should never happen!\n");
1329 DrawGraphicExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR, graphic,
1332 MarkTileDirty(x, y);
1335 void DrawFixedGraphic(int x, int y, int graphic, int frame)
1338 if (!IN_SCR_FIELD(x, y))
1340 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1341 printf("DrawGraphic(): This should never happen!\n");
1346 DrawFixedGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic,
1348 MarkTileDirty(x, y);
1351 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1357 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1359 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX_VAR, TILEY_VAR, x, y);
1362 void DrawFixedGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1368 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1369 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
1372 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
1375 if (!IN_SCR_FIELD(x, y))
1377 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1378 printf("DrawGraphicThruMask(): This should never happen!\n");
1383 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
1386 MarkTileDirty(x, y);
1389 void DrawFixedGraphicThruMask(int x, int y, int graphic, int frame)
1392 if (!IN_SCR_FIELD(x, y))
1394 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1395 printf("DrawGraphicThruMask(): This should never happen!\n");
1400 DrawFixedGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
1402 MarkTileDirty(x, y);
1405 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
1411 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1413 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX_VAR, TILEY_VAR,
1417 void DrawFixedGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y,
1418 int graphic, int frame)
1423 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1425 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY,
1429 void DrawSizedGraphic(int x, int y, int graphic, int frame, int tilesize)
1431 DrawSizedGraphicExt(drawto, SX + x * tilesize, SY + y * tilesize, graphic,
1433 MarkTileDirty(x / tilesize, y / tilesize);
1436 void DrawSizedGraphicExt(DrawBuffer *d, int x, int y, int graphic, int frame,
1442 getSizedGraphicSource(graphic, frame, tilesize, &src_bitmap, &src_x, &src_y);
1443 BlitBitmap(src_bitmap, d, src_x, src_y, tilesize, tilesize, x, y);
1446 void DrawMiniGraphic(int x, int y, int graphic)
1448 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
1449 MarkTileDirty(x / 2, y / 2);
1452 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
1457 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1458 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
1461 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
1462 int graphic, int frame,
1463 int cut_mode, int mask_mode)
1468 int width = TILEX, height = TILEY;
1471 if (dx || dy) /* shifted graphic */
1473 if (x < BX1) /* object enters playfield from the left */
1480 else if (x > BX2) /* object enters playfield from the right */
1486 else if (x == BX1 && dx < 0) /* object leaves playfield to the left */
1492 else if (x == BX2 && dx > 0) /* object leaves playfield to the right */
1494 else if (dx) /* general horizontal movement */
1495 MarkTileDirty(x + SIGN(dx), y);
1497 if (y < BY1) /* object enters playfield from the top */
1499 if (cut_mode == CUT_BELOW) /* object completely above top border */
1507 else if (y > BY2) /* object enters playfield from the bottom */
1513 else if (y == BY1 && dy < 0) /* object leaves playfield to the top */
1519 else if (dy > 0 && cut_mode == CUT_ABOVE)
1521 if (y == BY2) /* object completely above bottom border */
1527 MarkTileDirty(x, y + 1);
1528 } /* object leaves playfield to the bottom */
1529 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1531 else if (dy) /* general vertical movement */
1532 MarkTileDirty(x, y + SIGN(dy));
1536 if (!IN_SCR_FIELD(x, y))
1538 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1539 printf("DrawGraphicShifted(): This should never happen!\n");
1544 width = width * TILESIZE_VAR / TILESIZE;
1545 height = height * TILESIZE_VAR / TILESIZE;
1546 cx = cx * TILESIZE_VAR / TILESIZE;
1547 cy = cy * TILESIZE_VAR / TILESIZE;
1548 dx = dx * TILESIZE_VAR / TILESIZE;
1549 dy = dy * TILESIZE_VAR / TILESIZE;
1551 if (width > 0 && height > 0)
1553 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1558 dst_x = FX + x * TILEX_VAR + dx;
1559 dst_y = FY + y * TILEY_VAR + dy;
1561 if (mask_mode == USE_MASKING)
1562 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1565 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1568 MarkTileDirty(x, y);
1572 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
1573 int graphic, int frame,
1574 int cut_mode, int mask_mode)
1579 int width = TILEX_VAR, height = TILEY_VAR;
1582 int x2 = x + SIGN(dx);
1583 int y2 = y + SIGN(dy);
1585 /* movement with two-tile animations must be sync'ed with movement position,
1586 not with current GfxFrame (which can be higher when using slow movement) */
1587 int anim_pos = (dx ? ABS(dx) : ABS(dy));
1588 int anim_frames = graphic_info[graphic].anim_frames;
1590 /* (we also need anim_delay here for movement animations with less frames) */
1591 int anim_delay = graphic_info[graphic].anim_delay;
1592 int sync_frame = anim_pos * anim_frames * anim_delay / TILESIZE;
1594 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
1595 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
1597 /* re-calculate animation frame for two-tile movement animation */
1598 frame = getGraphicAnimationFrame(graphic, sync_frame);
1600 /* check if movement start graphic inside screen area and should be drawn */
1601 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
1603 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
1605 dst_x = FX + x1 * TILEX_VAR;
1606 dst_y = FY + y1 * TILEY_VAR;
1608 if (mask_mode == USE_MASKING)
1609 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1612 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1615 MarkTileDirty(x1, y1);
1618 /* check if movement end graphic inside screen area and should be drawn */
1619 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
1621 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
1623 dst_x = FX + x2 * TILEX_VAR;
1624 dst_y = FY + y2 * TILEY_VAR;
1626 if (mask_mode == USE_MASKING)
1627 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1630 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1633 MarkTileDirty(x2, y2);
1637 static void DrawGraphicShifted(int x, int y, int dx, int dy,
1638 int graphic, int frame,
1639 int cut_mode, int mask_mode)
1643 DrawGraphic(x, y, graphic, frame);
1648 if (graphic_info[graphic].double_movement) /* EM style movement images */
1649 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1651 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1654 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1655 int frame, int cut_mode)
1657 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
1660 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1661 int cut_mode, int mask_mode)
1663 int lx = LEVELX(x), ly = LEVELY(y);
1667 if (IN_LEV_FIELD(lx, ly))
1669 SetRandomAnimationValue(lx, ly);
1671 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
1672 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1674 /* do not use double (EM style) movement graphic when not moving */
1675 if (graphic_info[graphic].double_movement && !dx && !dy)
1677 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
1678 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1681 else /* border element */
1683 graphic = el2img(element);
1684 frame = getGraphicAnimationFrame(graphic, -1);
1687 if (element == EL_EXPANDABLE_WALL)
1689 boolean left_stopped = FALSE, right_stopped = FALSE;
1691 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1692 left_stopped = TRUE;
1693 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1694 right_stopped = TRUE;
1696 if (left_stopped && right_stopped)
1698 else if (left_stopped)
1700 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1701 frame = graphic_info[graphic].anim_frames - 1;
1703 else if (right_stopped)
1705 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1706 frame = graphic_info[graphic].anim_frames - 1;
1711 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1712 else if (mask_mode == USE_MASKING)
1713 DrawGraphicThruMask(x, y, graphic, frame);
1715 DrawGraphic(x, y, graphic, frame);
1718 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1719 int cut_mode, int mask_mode)
1721 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1722 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1723 cut_mode, mask_mode);
1726 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1729 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1732 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1735 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1738 void DrawLevelElementThruMask(int x, int y, int element)
1740 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1743 void DrawLevelFieldThruMask(int x, int y)
1745 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1748 /* !!! implementation of quicksand is totally broken !!! */
1749 #define IS_CRUMBLED_TILE(x, y, e) \
1750 (GFX_CRUMBLED(e) && (!IN_LEV_FIELD(x, y) || \
1751 !IS_MOVING(x, y) || \
1752 (e) == EL_QUICKSAND_EMPTYING || \
1753 (e) == EL_QUICKSAND_FAST_EMPTYING))
1755 static void DrawLevelFieldCrumbledInnerCorners(int x, int y, int dx, int dy,
1760 int width, height, cx, cy;
1761 int sx = SCREENX(x), sy = SCREENY(y);
1762 int crumbled_border_size = graphic_info[graphic].border_size;
1765 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1767 for (i = 1; i < 4; i++)
1769 int dxx = (i & 1 ? dx : 0);
1770 int dyy = (i & 2 ? dy : 0);
1773 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1776 /* check if neighbour field is of same crumble type */
1777 boolean same = (IS_CRUMBLED_TILE(xx, yy, element) &&
1778 graphic_info[graphic].class ==
1779 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class);
1781 /* return if check prevents inner corner */
1782 if (same == (dxx == dx && dyy == dy))
1786 /* if we reach this point, we have an inner corner */
1788 getGraphicSource(graphic, 1, &src_bitmap, &src_x, &src_y);
1790 width = crumbled_border_size * TILESIZE_VAR / TILESIZE;
1791 height = crumbled_border_size * TILESIZE_VAR / TILESIZE;
1792 cx = (dx > 0 ? TILESIZE_VAR - width : 0);
1793 cy = (dy > 0 ? TILESIZE_VAR - height : 0);
1795 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1796 width, height, FX + sx * TILEX_VAR + cx, FY + sy * TILEY_VAR + cy);
1799 static void DrawLevelFieldCrumbledBorders(int x, int y, int graphic, int frame,
1804 int width, height, bx, by, cx, cy;
1805 int sx = SCREENX(x), sy = SCREENY(y);
1806 int crumbled_border_size = graphic_info[graphic].border_size;
1807 int crumbled_border_size_var = crumbled_border_size * TILESIZE_VAR / TILESIZE;
1808 int crumbled_border_pos_var = TILESIZE_VAR - crumbled_border_size_var;
1811 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1813 /* draw simple, sloppy, non-corner-accurate crumbled border */
1815 width = (dir == 1 || dir == 2 ? crumbled_border_size_var : TILESIZE_VAR);
1816 height = (dir == 0 || dir == 3 ? crumbled_border_size_var : TILESIZE_VAR);
1817 cx = (dir == 2 ? crumbled_border_pos_var : 0);
1818 cy = (dir == 3 ? crumbled_border_pos_var : 0);
1820 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy, width, height,
1821 FX + sx * TILEX_VAR + cx,
1822 FY + sy * TILEY_VAR + cy);
1824 /* (remaining middle border part must be at least as big as corner part) */
1825 if (!(graphic_info[graphic].style & STYLE_ACCURATE_BORDERS) ||
1826 crumbled_border_size >= TILESIZE / 3)
1829 /* correct corners of crumbled border, if needed */
1831 for (i = -1; i <= 1; i += 2)
1833 int xx = x + (dir == 0 || dir == 3 ? i : 0);
1834 int yy = y + (dir == 1 || dir == 2 ? i : 0);
1835 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1838 /* check if neighbour field is of same crumble type */
1839 if (IS_CRUMBLED_TILE(xx, yy, element) &&
1840 graphic_info[graphic].class ==
1841 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1843 /* no crumbled corner, but continued crumbled border */
1845 int c1 = (dir == 2 || dir == 3 ? crumbled_border_pos_var : 0);
1846 int c2 = (i == 1 ? crumbled_border_pos_var : 0);
1847 int b1 = (i == 1 ? crumbled_border_size_var :
1848 TILESIZE_VAR - 2 * crumbled_border_size_var);
1850 width = crumbled_border_size_var;
1851 height = crumbled_border_size_var;
1853 if (dir == 1 || dir == 2)
1868 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
1870 FX + sx * TILEX_VAR + cx,
1871 FY + sy * TILEY_VAR + cy);
1876 static void DrawLevelFieldCrumbledExt(int x, int y, int graphic, int frame)
1878 int sx = SCREENX(x), sy = SCREENY(y);
1881 static int xy[4][2] =
1889 if (!IN_LEV_FIELD(x, y))
1892 element = TILE_GFX_ELEMENT(x, y);
1894 /* crumble field itself */
1895 if (IS_CRUMBLED_TILE(x, y, element))
1897 if (!IN_SCR_FIELD(sx, sy))
1900 for (i = 0; i < 4; i++)
1902 int xx = x + xy[i][0];
1903 int yy = y + xy[i][1];
1905 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1908 /* check if neighbour field is of same crumble type */
1909 if (IS_CRUMBLED_TILE(xx, yy, element) &&
1910 graphic_info[graphic].class ==
1911 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1914 DrawLevelFieldCrumbledBorders(x, y, graphic, frame, i);
1917 if ((graphic_info[graphic].style & STYLE_INNER_CORNERS) &&
1918 graphic_info[graphic].anim_frames == 2)
1920 for (i = 0; i < 4; i++)
1922 int dx = (i & 1 ? +1 : -1);
1923 int dy = (i & 2 ? +1 : -1);
1925 DrawLevelFieldCrumbledInnerCorners(x, y, dx, dy, graphic);
1929 MarkTileDirty(sx, sy);
1931 else /* center field not crumbled -- crumble neighbour fields */
1933 for (i = 0; i < 4; i++)
1935 int xx = x + xy[i][0];
1936 int yy = y + xy[i][1];
1937 int sxx = sx + xy[i][0];
1938 int syy = sy + xy[i][1];
1940 if (!IN_LEV_FIELD(xx, yy) ||
1941 !IN_SCR_FIELD(sxx, syy))
1944 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
1947 element = TILE_GFX_ELEMENT(xx, yy);
1949 if (!IS_CRUMBLED_TILE(xx, yy, element))
1952 graphic = el_act2crm(element, ACTION_DEFAULT);
1954 DrawLevelFieldCrumbledBorders(xx, yy, graphic, 0, 3 - i);
1956 MarkTileDirty(sxx, syy);
1961 void DrawLevelFieldCrumbled(int x, int y)
1965 if (!IN_LEV_FIELD(x, y))
1968 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1969 GfxElement[x][y] != EL_UNDEFINED &&
1970 GFX_CRUMBLED(GfxElement[x][y]))
1972 DrawLevelFieldCrumbledDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
1977 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
1979 DrawLevelFieldCrumbledExt(x, y, graphic, 0);
1982 void DrawLevelFieldCrumbledDigging(int x, int y, int direction,
1985 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1986 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1987 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1988 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1989 int sx = SCREENX(x), sy = SCREENY(y);
1991 DrawGraphic(sx, sy, graphic1, frame1);
1992 DrawLevelFieldCrumbledExt(x, y, graphic2, frame2);
1995 void DrawLevelFieldCrumbledNeighbours(int x, int y)
1997 int sx = SCREENX(x), sy = SCREENY(y);
1998 static int xy[4][2] =
2007 for (i = 0; i < 4; i++)
2009 int xx = x + xy[i][0];
2010 int yy = y + xy[i][1];
2011 int sxx = sx + xy[i][0];
2012 int syy = sy + xy[i][1];
2014 if (!IN_LEV_FIELD(xx, yy) ||
2015 !IN_SCR_FIELD(sxx, syy) ||
2016 !GFX_CRUMBLED(Feld[xx][yy]) ||
2020 DrawLevelField(xx, yy);
2024 static int getBorderElement(int x, int y)
2028 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
2029 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
2030 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
2031 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
2032 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
2033 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
2034 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
2036 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
2037 int steel_position = (x == -1 && y == -1 ? 0 :
2038 x == lev_fieldx && y == -1 ? 1 :
2039 x == -1 && y == lev_fieldy ? 2 :
2040 x == lev_fieldx && y == lev_fieldy ? 3 :
2041 x == -1 || x == lev_fieldx ? 4 :
2042 y == -1 || y == lev_fieldy ? 5 : 6);
2044 return border[steel_position][steel_type];
2047 void DrawScreenElement(int x, int y, int element)
2049 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
2050 DrawLevelFieldCrumbled(LEVELX(x), LEVELY(y));
2053 void DrawLevelElement(int x, int y, int element)
2055 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2056 DrawScreenElement(SCREENX(x), SCREENY(y), element);
2059 void DrawScreenField(int x, int y)
2061 int lx = LEVELX(x), ly = LEVELY(y);
2062 int element, content;
2064 if (!IN_LEV_FIELD(lx, ly))
2066 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
2069 element = getBorderElement(lx, ly);
2071 DrawScreenElement(x, y, element);
2076 element = Feld[lx][ly];
2077 content = Store[lx][ly];
2079 if (IS_MOVING(lx, ly))
2081 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
2082 boolean cut_mode = NO_CUTTING;
2084 if (element == EL_QUICKSAND_EMPTYING ||
2085 element == EL_QUICKSAND_FAST_EMPTYING ||
2086 element == EL_MAGIC_WALL_EMPTYING ||
2087 element == EL_BD_MAGIC_WALL_EMPTYING ||
2088 element == EL_DC_MAGIC_WALL_EMPTYING ||
2089 element == EL_AMOEBA_DROPPING)
2090 cut_mode = CUT_ABOVE;
2091 else if (element == EL_QUICKSAND_FILLING ||
2092 element == EL_QUICKSAND_FAST_FILLING ||
2093 element == EL_MAGIC_WALL_FILLING ||
2094 element == EL_BD_MAGIC_WALL_FILLING ||
2095 element == EL_DC_MAGIC_WALL_FILLING)
2096 cut_mode = CUT_BELOW;
2098 if (cut_mode == CUT_ABOVE)
2099 DrawScreenElement(x, y, element);
2101 DrawScreenElement(x, y, EL_EMPTY);
2104 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
2105 else if (cut_mode == NO_CUTTING)
2106 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
2109 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
2111 if (cut_mode == CUT_BELOW &&
2112 IN_LEV_FIELD(lx, ly + 1) && IN_SCR_FIELD(x, y + 1))
2113 DrawLevelElement(lx, ly + 1, element);
2116 if (content == EL_ACID)
2118 int dir = MovDir[lx][ly];
2119 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
2120 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
2122 DrawLevelElementThruMask(newlx, newly, EL_ACID);
2125 else if (IS_BLOCKED(lx, ly))
2130 boolean cut_mode = NO_CUTTING;
2131 int element_old, content_old;
2133 Blocked2Moving(lx, ly, &oldx, &oldy);
2136 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
2137 MovDir[oldx][oldy] == MV_RIGHT);
2139 element_old = Feld[oldx][oldy];
2140 content_old = Store[oldx][oldy];
2142 if (element_old == EL_QUICKSAND_EMPTYING ||
2143 element_old == EL_QUICKSAND_FAST_EMPTYING ||
2144 element_old == EL_MAGIC_WALL_EMPTYING ||
2145 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
2146 element_old == EL_DC_MAGIC_WALL_EMPTYING ||
2147 element_old == EL_AMOEBA_DROPPING)
2148 cut_mode = CUT_ABOVE;
2150 DrawScreenElement(x, y, EL_EMPTY);
2153 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
2155 else if (cut_mode == NO_CUTTING)
2156 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
2159 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
2162 else if (IS_DRAWABLE(element))
2163 DrawScreenElement(x, y, element);
2165 DrawScreenElement(x, y, EL_EMPTY);
2168 void DrawLevelField(int x, int y)
2170 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2171 DrawScreenField(SCREENX(x), SCREENY(y));
2172 else if (IS_MOVING(x, y))
2176 Moving2Blocked(x, y, &newx, &newy);
2177 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
2178 DrawScreenField(SCREENX(newx), SCREENY(newy));
2180 else if (IS_BLOCKED(x, y))
2184 Blocked2Moving(x, y, &oldx, &oldy);
2185 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
2186 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
2190 void DrawSizedElement(int x, int y, int element, int tilesize)
2194 graphic = el2edimg(element);
2195 DrawSizedGraphic(x, y, graphic, 0, tilesize);
2198 void DrawMiniElement(int x, int y, int element)
2202 graphic = el2edimg(element);
2203 DrawMiniGraphic(x, y, graphic);
2206 void DrawSizedElementOrWall(int sx, int sy, int scroll_x, int scroll_y,
2209 int x = sx + scroll_x, y = sy + scroll_y;
2211 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
2212 DrawSizedElement(sx, sy, EL_EMPTY, tilesize);
2213 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
2214 DrawSizedElement(sx, sy, Feld[x][y], tilesize);
2216 DrawSizedGraphic(sx, sy, el2edimg(getBorderElement(x, y)), 0, tilesize);
2219 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
2221 int x = sx + scroll_x, y = sy + scroll_y;
2223 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
2224 DrawMiniElement(sx, sy, EL_EMPTY);
2225 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
2226 DrawMiniElement(sx, sy, Feld[x][y]);
2228 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
2231 void DrawEnvelopeBackgroundTiles(int graphic, int startx, int starty,
2232 int x, int y, int xsize, int ysize,
2233 int tile_width, int tile_height)
2237 int dst_x = startx + x * tile_width;
2238 int dst_y = starty + y * tile_height;
2239 int width = graphic_info[graphic].width;
2240 int height = graphic_info[graphic].height;
2241 int inner_width_raw = MAX(width - 2 * tile_width, tile_width);
2242 int inner_height_raw = MAX(height - 2 * tile_height, tile_height);
2243 int inner_width = inner_width_raw - (inner_width_raw % tile_width);
2244 int inner_height = inner_height_raw - (inner_height_raw % tile_height);
2245 int inner_sx = (width >= 3 * tile_width ? tile_width : 0);
2246 int inner_sy = (height >= 3 * tile_height ? tile_height : 0);
2247 boolean draw_masked = graphic_info[graphic].draw_masked;
2249 getFixedGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
2251 if (src_bitmap == NULL || width < tile_width || height < tile_height)
2253 ClearRectangle(drawto, dst_x, dst_y, tile_width, tile_height);
2257 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - tile_width :
2258 inner_sx + (x - 1) * tile_width % inner_width);
2259 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - tile_height :
2260 inner_sy + (y - 1) * tile_height % inner_height);
2263 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
2266 BlitBitmap(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
2270 void DrawEnvelopeBackground(int graphic, int startx, int starty,
2271 int x, int y, int xsize, int ysize, int font_nr)
2273 int font_width = getFontWidth(font_nr);
2274 int font_height = getFontHeight(font_nr);
2276 DrawEnvelopeBackgroundTiles(graphic, startx, starty, x, y, xsize, ysize,
2277 font_width, font_height);
2280 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
2282 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2283 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2284 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2285 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2286 boolean no_delay = (tape.warp_forward);
2287 unsigned int anim_delay = 0;
2288 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
2289 int anim_delay_value = (no_delay ? 0 : frame_delay_value) / 2;
2290 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
2291 int font_width = getFontWidth(font_nr);
2292 int font_height = getFontHeight(font_nr);
2293 int max_xsize = level.envelope[envelope_nr].xsize;
2294 int max_ysize = level.envelope[envelope_nr].ysize;
2295 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
2296 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
2297 int xend = max_xsize;
2298 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
2299 int xstep = (xstart < xend ? 1 : 0);
2300 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2302 int end = MAX(xend - xstart, yend - ystart);
2305 for (i = start; i <= end; i++)
2307 int last_frame = end; // last frame of this "for" loop
2308 int x = xstart + i * xstep;
2309 int y = ystart + i * ystep;
2310 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2311 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2312 int sx = SX + (SXSIZE - xsize * font_width) / 2;
2313 int sy = SY + (SYSIZE - ysize * font_height) / 2;
2316 SetDrawtoField(DRAW_TO_FIELDBUFFER);
2318 BlitScreenToBitmap(backbuffer);
2320 SetDrawtoField(DRAW_TO_BACKBUFFER);
2322 for (yy = 0; yy < ysize; yy++)
2323 for (xx = 0; xx < xsize; xx++)
2324 DrawEnvelopeBackground(graphic, sx, sy, xx, yy, xsize, ysize, font_nr);
2326 DrawTextBuffer(sx + font_width, sy + font_height,
2327 level.envelope[envelope_nr].text, font_nr, max_xsize,
2328 xsize - 2, ysize - 2, 0, mask_mode,
2329 level.envelope[envelope_nr].autowrap,
2330 level.envelope[envelope_nr].centered, FALSE);
2332 redraw_mask |= REDRAW_FIELD;
2335 SkipUntilDelayReached(&anim_delay, anim_delay_value, &i, last_frame);
2339 void ShowEnvelope(int envelope_nr)
2341 int element = EL_ENVELOPE_1 + envelope_nr;
2342 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2343 int sound_opening = element_info[element].sound[ACTION_OPENING];
2344 int sound_closing = element_info[element].sound[ACTION_CLOSING];
2345 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2346 boolean no_delay = (tape.warp_forward);
2347 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
2348 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
2349 int anim_mode = graphic_info[graphic].anim_mode;
2350 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2351 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2353 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
2355 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2357 if (anim_mode == ANIM_DEFAULT)
2358 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
2360 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
2363 Delay(wait_delay_value);
2365 WaitForEventToContinue();
2367 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2369 if (anim_mode != ANIM_NONE)
2370 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
2372 if (anim_mode == ANIM_DEFAULT)
2373 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
2375 game.envelope_active = FALSE;
2377 SetDrawtoField(DRAW_TO_FIELDBUFFER);
2379 redraw_mask |= REDRAW_FIELD;
2383 static void setRequestBasePosition(int *x, int *y)
2385 int sx_base, sy_base;
2387 if (request.x != -1)
2388 sx_base = request.x;
2389 else if (request.align == ALIGN_LEFT)
2391 else if (request.align == ALIGN_RIGHT)
2392 sx_base = SX + SXSIZE;
2394 sx_base = SX + SXSIZE / 2;
2396 if (request.y != -1)
2397 sy_base = request.y;
2398 else if (request.valign == VALIGN_TOP)
2400 else if (request.valign == VALIGN_BOTTOM)
2401 sy_base = SY + SYSIZE;
2403 sy_base = SY + SYSIZE / 2;
2409 static void setRequestPositionExt(int *x, int *y, int width, int height,
2410 boolean add_border_size)
2412 int border_size = request.border_size;
2413 int sx_base, sy_base;
2416 setRequestBasePosition(&sx_base, &sy_base);
2418 if (request.align == ALIGN_LEFT)
2420 else if (request.align == ALIGN_RIGHT)
2421 sx = sx_base - width;
2423 sx = sx_base - width / 2;
2425 if (request.valign == VALIGN_TOP)
2427 else if (request.valign == VALIGN_BOTTOM)
2428 sy = sy_base - height;
2430 sy = sy_base - height / 2;
2432 sx = MAX(0, MIN(sx, WIN_XSIZE - width));
2433 sy = MAX(0, MIN(sy, WIN_YSIZE - height));
2435 if (add_border_size)
2445 static void setRequestPosition(int *x, int *y, boolean add_border_size)
2447 setRequestPositionExt(x, y, request.width, request.height, add_border_size);
2450 void DrawEnvelopeRequest(char *text)
2452 char *text_final = text;
2453 char *text_door_style = NULL;
2454 int graphic = IMG_BACKGROUND_REQUEST;
2455 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2456 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2457 int font_nr = FONT_REQUEST;
2458 int font_width = getFontWidth(font_nr);
2459 int font_height = getFontHeight(font_nr);
2460 int border_size = request.border_size;
2461 int line_spacing = request.line_spacing;
2462 int line_height = font_height + line_spacing;
2463 int max_text_width = request.width - 2 * border_size;
2464 int max_text_height = request.height - 2 * border_size;
2465 int line_length = max_text_width / font_width;
2466 int max_lines = max_text_height / line_height;
2467 int text_width = line_length * font_width;
2468 int width = request.width;
2469 int height = request.height;
2470 int tile_size = MAX(request.step_offset, 1);
2471 int x_steps = width / tile_size;
2472 int y_steps = height / tile_size;
2473 int sx_offset = border_size;
2474 int sy_offset = border_size;
2478 if (request.centered)
2479 sx_offset = (request.width - text_width) / 2;
2481 if (request.wrap_single_words && !request.autowrap)
2483 char *src_text_ptr, *dst_text_ptr;
2485 text_door_style = checked_malloc(2 * strlen(text) + 1);
2487 src_text_ptr = text;
2488 dst_text_ptr = text_door_style;
2490 while (*src_text_ptr)
2492 if (*src_text_ptr == ' ' ||
2493 *src_text_ptr == '?' ||
2494 *src_text_ptr == '!')
2495 *dst_text_ptr++ = '\n';
2497 if (*src_text_ptr != ' ')
2498 *dst_text_ptr++ = *src_text_ptr;
2503 *dst_text_ptr = '\0';
2505 text_final = text_door_style;
2508 setRequestPosition(&sx, &sy, FALSE);
2510 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
2512 for (y = 0; y < y_steps; y++)
2513 for (x = 0; x < x_steps; x++)
2514 DrawEnvelopeBackgroundTiles(graphic, sx, sy,
2515 x, y, x_steps, y_steps,
2516 tile_size, tile_size);
2518 /* force DOOR font inside door area */
2519 SetFontStatus(GAME_MODE_PSEUDO_DOOR);
2521 DrawTextBuffer(sx + sx_offset, sy + sy_offset, text_final, font_nr,
2522 line_length, -1, max_lines, line_spacing, mask_mode,
2523 request.autowrap, request.centered, FALSE);
2527 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2528 RedrawGadget(tool_gadget[i]);
2530 // store readily prepared envelope request for later use when animating
2531 BlitBitmap(backbuffer, bitmap_db_store_2, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2533 if (text_door_style)
2534 free(text_door_style);
2537 void AnimateEnvelopeRequest(int anim_mode, int action)
2539 int graphic = IMG_BACKGROUND_REQUEST;
2540 boolean draw_masked = graphic_info[graphic].draw_masked;
2541 int delay_value_normal = request.step_delay;
2542 int delay_value_fast = delay_value_normal / 2;
2543 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2544 boolean no_delay = (tape.warp_forward);
2545 int delay_value = (ffwd_delay ? delay_value_fast : delay_value_normal);
2546 int anim_delay_value = (no_delay ? 0 : delay_value + 500 * 0) / 2;
2547 unsigned int anim_delay = 0;
2549 int tile_size = MAX(request.step_offset, 1);
2550 int max_xsize = request.width / tile_size;
2551 int max_ysize = request.height / tile_size;
2552 int max_xsize_inner = max_xsize - 2;
2553 int max_ysize_inner = max_ysize - 2;
2555 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize_inner : 0);
2556 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize_inner : 0);
2557 int xend = max_xsize_inner;
2558 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize_inner : 0);
2559 int xstep = (xstart < xend ? 1 : 0);
2560 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2562 int end = MAX(xend - xstart, yend - ystart);
2565 if (setup.quick_doors)
2572 for (i = start; i <= end; i++)
2574 int last_frame = end; // last frame of this "for" loop
2575 int x = xstart + i * xstep;
2576 int y = ystart + i * ystep;
2577 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2578 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2579 int xsize_size_left = (xsize - 1) * tile_size;
2580 int ysize_size_top = (ysize - 1) * tile_size;
2581 int max_xsize_pos = (max_xsize - 1) * tile_size;
2582 int max_ysize_pos = (max_ysize - 1) * tile_size;
2583 int width = xsize * tile_size;
2584 int height = ysize * tile_size;
2589 setRequestPosition(&src_x, &src_y, FALSE);
2590 setRequestPositionExt(&dst_x, &dst_y, width, height, FALSE);
2592 BlitBitmap(bitmap_db_store_1, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2594 for (yy = 0; yy < 2; yy++)
2596 for (xx = 0; xx < 2; xx++)
2598 int src_xx = src_x + xx * max_xsize_pos;
2599 int src_yy = src_y + yy * max_ysize_pos;
2600 int dst_xx = dst_x + xx * xsize_size_left;
2601 int dst_yy = dst_y + yy * ysize_size_top;
2602 int xx_size = (xx ? tile_size : xsize_size_left);
2603 int yy_size = (yy ? tile_size : ysize_size_top);
2606 BlitBitmapMasked(bitmap_db_store_2, backbuffer,
2607 src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
2609 BlitBitmap(bitmap_db_store_2, backbuffer,
2610 src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
2614 redraw_mask |= REDRAW_FIELD;
2618 SkipUntilDelayReached(&anim_delay, anim_delay_value, &i, last_frame);
2622 void ShowEnvelopeRequest(char *text, unsigned int req_state, int action)
2624 int graphic = IMG_BACKGROUND_REQUEST;
2625 int sound_opening = SND_REQUEST_OPENING;
2626 int sound_closing = SND_REQUEST_CLOSING;
2627 int anim_mode_1 = request.anim_mode; /* (higher priority) */
2628 int anim_mode_2 = graphic_info[graphic].anim_mode; /* (lower priority) */
2629 int anim_mode = (anim_mode_1 != ANIM_DEFAULT ? anim_mode_1 : anim_mode_2);
2630 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2631 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2633 if (game_status == GAME_MODE_PLAYING)
2634 BlitScreenToBitmap(backbuffer);
2636 SetDrawtoField(DRAW_TO_BACKBUFFER);
2638 // SetDrawBackgroundMask(REDRAW_NONE);
2640 if (action == ACTION_OPENING)
2642 BlitBitmap(backbuffer, bitmap_db_store_1, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2644 if (req_state & REQ_ASK)
2646 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2647 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2649 else if (req_state & REQ_CONFIRM)
2651 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2653 else if (req_state & REQ_PLAYER)
2655 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2656 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2657 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2658 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2661 DrawEnvelopeRequest(text);
2664 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
2666 if (action == ACTION_OPENING)
2668 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2670 if (anim_mode == ANIM_DEFAULT)
2671 AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_OPENING);
2673 AnimateEnvelopeRequest(main_anim_mode, ACTION_OPENING);
2677 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2679 if (anim_mode != ANIM_NONE)
2680 AnimateEnvelopeRequest(main_anim_mode, ACTION_CLOSING);
2682 if (anim_mode == ANIM_DEFAULT)
2683 AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_CLOSING);
2686 game.envelope_active = FALSE;
2688 if (action == ACTION_CLOSING)
2689 BlitBitmap(bitmap_db_store_1, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2691 // SetDrawBackgroundMask(last_draw_background_mask);
2693 redraw_mask |= REDRAW_FIELD;
2697 if (action == ACTION_CLOSING &&
2698 game_status == GAME_MODE_PLAYING &&
2699 level.game_engine_type == GAME_ENGINE_TYPE_RND)
2700 SetDrawtoField(DRAW_TO_FIELDBUFFER);
2703 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
2707 int graphic = el2preimg(element);
2709 getSizedGraphicSource(graphic, 0, tilesize, &src_bitmap, &src_x, &src_y);
2710 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
2713 void DrawLevel(int draw_background_mask)
2717 SetMainBackgroundImage(IMG_BACKGROUND_PLAYING);
2718 SetDrawBackgroundMask(draw_background_mask);
2722 for (x = BX1; x <= BX2; x++)
2723 for (y = BY1; y <= BY2; y++)
2724 DrawScreenField(x, y);
2726 redraw_mask |= REDRAW_FIELD;
2729 void DrawSizedLevel(int size_x, int size_y, int scroll_x, int scroll_y,
2734 for (x = 0; x < size_x; x++)
2735 for (y = 0; y < size_y; y++)
2736 DrawSizedElementOrWall(x, y, scroll_x, scroll_y, tilesize);
2738 redraw_mask |= REDRAW_FIELD;
2741 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
2745 for (x = 0; x < size_x; x++)
2746 for (y = 0; y < size_y; y++)
2747 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
2749 redraw_mask |= REDRAW_FIELD;
2752 static void DrawPreviewLevelPlayfieldExt(int from_x, int from_y)
2754 boolean show_level_border = (BorderElement != EL_EMPTY);
2755 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2756 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2757 int tile_size = preview.tile_size;
2758 int preview_width = preview.xsize * tile_size;
2759 int preview_height = preview.ysize * tile_size;
2760 int real_preview_xsize = MIN(level_xsize, preview.xsize);
2761 int real_preview_ysize = MIN(level_ysize, preview.ysize);
2762 int real_preview_width = real_preview_xsize * tile_size;
2763 int real_preview_height = real_preview_ysize * tile_size;
2764 int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
2765 int dst_y = SY + ALIGNED_YPOS(preview.y, preview_height, preview.valign);
2768 if (!IN_GFX_FIELD_FULL(dst_x, dst_y + preview_height - 1))
2771 DrawBackground(dst_x, dst_y, preview_width, preview_height);
2773 dst_x += (preview_width - real_preview_width) / 2;
2774 dst_y += (preview_height - real_preview_height) / 2;
2776 for (x = 0; x < real_preview_xsize; x++)
2778 for (y = 0; y < real_preview_ysize; y++)
2780 int lx = from_x + x + (show_level_border ? -1 : 0);
2781 int ly = from_y + y + (show_level_border ? -1 : 0);
2782 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
2783 getBorderElement(lx, ly));
2785 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
2786 element, tile_size);
2790 redraw_mask |= REDRAW_FIELD;
2793 #define MICROLABEL_EMPTY 0
2794 #define MICROLABEL_LEVEL_NAME 1
2795 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
2796 #define MICROLABEL_LEVEL_AUTHOR 3
2797 #define MICROLABEL_IMPORTED_FROM_HEAD 4
2798 #define MICROLABEL_IMPORTED_FROM 5
2799 #define MICROLABEL_IMPORTED_BY_HEAD 6
2800 #define MICROLABEL_IMPORTED_BY 7
2802 static int getMaxTextLength(struct TextPosInfo *pos, int font_nr)
2804 int max_text_width = SXSIZE;
2805 int font_width = getFontWidth(font_nr);
2807 if (pos->align == ALIGN_CENTER)
2808 max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
2809 else if (pos->align == ALIGN_RIGHT)
2810 max_text_width = pos->x;
2812 max_text_width = SXSIZE - pos->x;
2814 return max_text_width / font_width;
2817 static void DrawPreviewLevelLabelExt(int mode)
2819 struct TextPosInfo *pos = &menu.main.text.level_info_2;
2820 char label_text[MAX_OUTPUT_LINESIZE + 1];
2821 int max_len_label_text;
2822 int font_nr = pos->font;
2825 if (!IN_GFX_FIELD_FULL(pos->x, pos->y + getFontHeight(pos->font)))
2828 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
2829 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
2830 mode == MICROLABEL_IMPORTED_BY_HEAD)
2831 font_nr = pos->font_alt;
2833 max_len_label_text = getMaxTextLength(pos, font_nr);
2835 if (pos->size != -1)
2836 max_len_label_text = pos->size;
2838 for (i = 0; i < max_len_label_text; i++)
2839 label_text[i] = ' ';
2840 label_text[max_len_label_text] = '\0';
2842 if (strlen(label_text) > 0)
2843 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2846 (mode == MICROLABEL_LEVEL_NAME ? level.name :
2847 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
2848 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
2849 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
2850 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
2851 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
2852 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
2853 max_len_label_text);
2854 label_text[max_len_label_text] = '\0';
2856 if (strlen(label_text) > 0)
2857 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2859 redraw_mask |= REDRAW_FIELD;
2862 static void DrawPreviewLevelExt(boolean restart)
2864 static unsigned int scroll_delay = 0;
2865 static unsigned int label_delay = 0;
2866 static int from_x, from_y, scroll_direction;
2867 static int label_state, label_counter;
2868 unsigned int scroll_delay_value = preview.step_delay;
2869 boolean show_level_border = (BorderElement != EL_EMPTY);
2870 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2871 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2878 if (preview.anim_mode == ANIM_CENTERED)
2880 if (level_xsize > preview.xsize)
2881 from_x = (level_xsize - preview.xsize) / 2;
2882 if (level_ysize > preview.ysize)
2883 from_y = (level_ysize - preview.ysize) / 2;
2886 from_x += preview.xoffset;
2887 from_y += preview.yoffset;
2889 scroll_direction = MV_RIGHT;
2893 DrawPreviewLevelPlayfieldExt(from_x, from_y);
2894 DrawPreviewLevelLabelExt(label_state);
2896 /* initialize delay counters */
2897 DelayReached(&scroll_delay, 0);
2898 DelayReached(&label_delay, 0);
2900 if (leveldir_current->name)
2902 struct TextPosInfo *pos = &menu.main.text.level_info_1;
2903 char label_text[MAX_OUTPUT_LINESIZE + 1];
2904 int font_nr = pos->font;
2905 int max_len_label_text = getMaxTextLength(pos, font_nr);
2907 if (pos->size != -1)
2908 max_len_label_text = pos->size;
2910 strncpy(label_text, leveldir_current->name, max_len_label_text);
2911 label_text[max_len_label_text] = '\0';
2913 if (IN_GFX_FIELD_FULL(pos->x, pos->y + getFontHeight(pos->font)))
2914 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2920 /* scroll preview level, if needed */
2921 if (preview.anim_mode != ANIM_NONE &&
2922 (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
2923 DelayReached(&scroll_delay, scroll_delay_value))
2925 switch (scroll_direction)
2930 from_x -= preview.step_offset;
2931 from_x = (from_x < 0 ? 0 : from_x);
2934 scroll_direction = MV_UP;
2938 if (from_x < level_xsize - preview.xsize)
2940 from_x += preview.step_offset;
2941 from_x = (from_x > level_xsize - preview.xsize ?
2942 level_xsize - preview.xsize : from_x);
2945 scroll_direction = MV_DOWN;
2951 from_y -= preview.step_offset;
2952 from_y = (from_y < 0 ? 0 : from_y);
2955 scroll_direction = MV_RIGHT;
2959 if (from_y < level_ysize - preview.ysize)
2961 from_y += preview.step_offset;
2962 from_y = (from_y > level_ysize - preview.ysize ?
2963 level_ysize - preview.ysize : from_y);
2966 scroll_direction = MV_LEFT;
2973 DrawPreviewLevelPlayfieldExt(from_x, from_y);
2976 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
2977 /* redraw micro level label, if needed */
2978 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
2979 !strEqual(level.author, ANONYMOUS_NAME) &&
2980 !strEqual(level.author, leveldir_current->name) &&
2981 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
2983 int max_label_counter = 23;
2985 if (leveldir_current->imported_from != NULL &&
2986 strlen(leveldir_current->imported_from) > 0)
2987 max_label_counter += 14;
2988 if (leveldir_current->imported_by != NULL &&
2989 strlen(leveldir_current->imported_by) > 0)
2990 max_label_counter += 14;
2992 label_counter = (label_counter + 1) % max_label_counter;
2993 label_state = (label_counter >= 0 && label_counter <= 7 ?
2994 MICROLABEL_LEVEL_NAME :
2995 label_counter >= 9 && label_counter <= 12 ?
2996 MICROLABEL_LEVEL_AUTHOR_HEAD :
2997 label_counter >= 14 && label_counter <= 21 ?
2998 MICROLABEL_LEVEL_AUTHOR :
2999 label_counter >= 23 && label_counter <= 26 ?
3000 MICROLABEL_IMPORTED_FROM_HEAD :
3001 label_counter >= 28 && label_counter <= 35 ?
3002 MICROLABEL_IMPORTED_FROM :
3003 label_counter >= 37 && label_counter <= 40 ?
3004 MICROLABEL_IMPORTED_BY_HEAD :
3005 label_counter >= 42 && label_counter <= 49 ?
3006 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
3008 if (leveldir_current->imported_from == NULL &&
3009 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
3010 label_state == MICROLABEL_IMPORTED_FROM))
3011 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
3012 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
3014 DrawPreviewLevelLabelExt(label_state);
3018 void DrawPreviewLevelInitial()
3020 DrawPreviewLevelExt(TRUE);
3023 void DrawPreviewLevelAnimation()
3025 DrawPreviewLevelExt(FALSE);
3028 inline static void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
3029 int graphic, int sync_frame,
3032 int frame = getGraphicAnimationFrame(graphic, sync_frame);
3034 if (mask_mode == USE_MASKING)
3035 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
3037 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
3040 void DrawFixedGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
3041 int graphic, int sync_frame, int mask_mode)
3043 int frame = getGraphicAnimationFrame(graphic, sync_frame);
3045 if (mask_mode == USE_MASKING)
3046 DrawFixedGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
3048 DrawFixedGraphicExt(dst_bitmap, x, y, graphic, frame);
3051 inline static void DrawGraphicAnimation(int x, int y, int graphic)
3053 int lx = LEVELX(x), ly = LEVELY(y);
3055 if (!IN_SCR_FIELD(x, y))
3058 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
3059 graphic, GfxFrame[lx][ly], NO_MASKING);
3061 MarkTileDirty(x, y);
3064 void DrawFixedGraphicAnimation(int x, int y, int graphic)
3066 int lx = LEVELX(x), ly = LEVELY(y);
3068 if (!IN_SCR_FIELD(x, y))
3071 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
3072 graphic, GfxFrame[lx][ly], NO_MASKING);
3073 MarkTileDirty(x, y);
3076 void DrawLevelGraphicAnimation(int x, int y, int graphic)
3078 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
3081 void DrawLevelElementAnimation(int x, int y, int element)
3083 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
3085 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
3088 void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
3090 int sx = SCREENX(x), sy = SCREENY(y);
3092 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
3095 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
3098 DrawGraphicAnimation(sx, sy, graphic);
3101 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
3102 DrawLevelFieldCrumbled(x, y);
3104 if (GFX_CRUMBLED(Feld[x][y]))
3105 DrawLevelFieldCrumbled(x, y);
3109 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
3111 int sx = SCREENX(x), sy = SCREENY(y);
3114 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
3117 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
3119 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
3122 DrawGraphicAnimation(sx, sy, graphic);
3124 if (GFX_CRUMBLED(element))
3125 DrawLevelFieldCrumbled(x, y);
3128 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
3130 if (player->use_murphy)
3132 /* this works only because currently only one player can be "murphy" ... */
3133 static int last_horizontal_dir = MV_LEFT;
3134 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
3136 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3137 last_horizontal_dir = move_dir;
3139 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
3141 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
3143 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
3149 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
3152 static boolean equalGraphics(int graphic1, int graphic2)
3154 struct GraphicInfo *g1 = &graphic_info[graphic1];
3155 struct GraphicInfo *g2 = &graphic_info[graphic2];
3157 return (g1->bitmap == g2->bitmap &&
3158 g1->src_x == g2->src_x &&
3159 g1->src_y == g2->src_y &&
3160 g1->anim_frames == g2->anim_frames &&
3161 g1->anim_delay == g2->anim_delay &&
3162 g1->anim_mode == g2->anim_mode);
3165 void DrawAllPlayers()
3169 for (i = 0; i < MAX_PLAYERS; i++)
3170 if (stored_player[i].active)
3171 DrawPlayer(&stored_player[i]);
3174 void DrawPlayerField(int x, int y)
3176 if (!IS_PLAYER(x, y))
3179 DrawPlayer(PLAYERINFO(x, y));
3182 #define DRAW_PLAYER_OVER_PUSHED_ELEMENT 1
3184 void DrawPlayer(struct PlayerInfo *player)
3186 int jx = player->jx;
3187 int jy = player->jy;
3188 int move_dir = player->MovDir;
3189 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
3190 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
3191 int last_jx = (player->is_moving ? jx - dx : jx);
3192 int last_jy = (player->is_moving ? jy - dy : jy);
3193 int next_jx = jx + dx;
3194 int next_jy = jy + dy;
3195 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
3196 boolean player_is_opaque = FALSE;
3197 int sx = SCREENX(jx), sy = SCREENY(jy);
3198 int sxx = 0, syy = 0;
3199 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
3201 int action = ACTION_DEFAULT;
3202 int last_player_graphic = getPlayerGraphic(player, move_dir);
3203 int last_player_frame = player->Frame;
3206 /* GfxElement[][] is set to the element the player is digging or collecting;
3207 remove also for off-screen player if the player is not moving anymore */
3208 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
3209 GfxElement[jx][jy] = EL_UNDEFINED;
3211 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
3215 if (!IN_LEV_FIELD(jx, jy))
3217 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
3218 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
3219 printf("DrawPlayerField(): This should never happen!\n");
3224 if (element == EL_EXPLOSION)
3227 action = (player->is_pushing ? ACTION_PUSHING :
3228 player->is_digging ? ACTION_DIGGING :
3229 player->is_collecting ? ACTION_COLLECTING :
3230 player->is_moving ? ACTION_MOVING :
3231 player->is_snapping ? ACTION_SNAPPING :
3232 player->is_dropping ? ACTION_DROPPING :
3233 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
3235 if (player->is_waiting)
3236 move_dir = player->dir_waiting;
3238 InitPlayerGfxAnimation(player, action, move_dir);
3240 /* ----------------------------------------------------------------------- */
3241 /* draw things in the field the player is leaving, if needed */
3242 /* ----------------------------------------------------------------------- */
3244 if (player->is_moving)
3246 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
3248 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
3250 if (last_element == EL_DYNAMITE_ACTIVE ||
3251 last_element == EL_EM_DYNAMITE_ACTIVE ||
3252 last_element == EL_SP_DISK_RED_ACTIVE)
3253 DrawDynamite(last_jx, last_jy);
3255 DrawLevelFieldThruMask(last_jx, last_jy);
3257 else if (last_element == EL_DYNAMITE_ACTIVE ||
3258 last_element == EL_EM_DYNAMITE_ACTIVE ||
3259 last_element == EL_SP_DISK_RED_ACTIVE)
3260 DrawDynamite(last_jx, last_jy);
3262 /* !!! this is not enough to prevent flickering of players which are
3263 moving next to each others without a free tile between them -- this
3264 can only be solved by drawing all players layer by layer (first the
3265 background, then the foreground etc.) !!! => TODO */
3266 else if (!IS_PLAYER(last_jx, last_jy))
3267 DrawLevelField(last_jx, last_jy);
3270 DrawLevelField(last_jx, last_jy);
3273 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
3274 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
3277 if (!IN_SCR_FIELD(sx, sy))
3280 /* ----------------------------------------------------------------------- */
3281 /* draw things behind the player, if needed */
3282 /* ----------------------------------------------------------------------- */
3285 DrawLevelElement(jx, jy, Back[jx][jy]);
3286 else if (IS_ACTIVE_BOMB(element))
3287 DrawLevelElement(jx, jy, EL_EMPTY);
3290 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
3292 int old_element = GfxElement[jx][jy];
3293 int old_graphic = el_act_dir2img(old_element, action, move_dir);
3294 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
3296 if (GFX_CRUMBLED(old_element))
3297 DrawLevelFieldCrumbledDigging(jx, jy, move_dir, player->StepFrame);
3299 DrawGraphic(sx, sy, old_graphic, frame);
3301 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
3302 player_is_opaque = TRUE;
3306 GfxElement[jx][jy] = EL_UNDEFINED;
3308 /* make sure that pushed elements are drawn with correct frame rate */
3309 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
3311 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
3312 GfxFrame[jx][jy] = player->StepFrame;
3314 DrawLevelField(jx, jy);
3318 #if !DRAW_PLAYER_OVER_PUSHED_ELEMENT
3319 /* ----------------------------------------------------------------------- */
3320 /* draw player himself */
3321 /* ----------------------------------------------------------------------- */
3323 graphic = getPlayerGraphic(player, move_dir);
3325 /* in the case of changed player action or direction, prevent the current
3326 animation frame from being restarted for identical animations */
3327 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
3328 player->Frame = last_player_frame;
3330 frame = getGraphicAnimationFrame(graphic, player->Frame);
3334 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3335 sxx = player->GfxPos;
3337 syy = player->GfxPos;
3340 if (player_is_opaque)
3341 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
3343 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3345 if (SHIELD_ON(player))
3347 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
3348 IMG_SHIELD_NORMAL_ACTIVE);
3349 int frame = getGraphicAnimationFrame(graphic, -1);
3351 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3355 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
3358 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3359 sxx = player->GfxPos;
3361 syy = player->GfxPos;
3365 /* ----------------------------------------------------------------------- */
3366 /* draw things the player is pushing, if needed */
3367 /* ----------------------------------------------------------------------- */
3369 if (player->is_pushing && player->is_moving)
3371 int px = SCREENX(jx), py = SCREENY(jy);
3372 int pxx = (TILEX - ABS(sxx)) * dx;
3373 int pyy = (TILEY - ABS(syy)) * dy;
3374 int gfx_frame = GfxFrame[jx][jy];
3380 if (!IS_MOVING(jx, jy)) /* push movement already finished */
3382 element = Feld[next_jx][next_jy];
3383 gfx_frame = GfxFrame[next_jx][next_jy];
3386 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
3388 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
3389 frame = getGraphicAnimationFrame(graphic, sync_frame);
3391 /* draw background element under pushed element (like the Sokoban field) */
3392 if (game.use_masked_pushing && IS_MOVING(jx, jy))
3394 /* this allows transparent pushing animation over non-black background */
3397 DrawLevelElement(jx, jy, Back[jx][jy]);
3399 DrawLevelElement(jx, jy, EL_EMPTY);
3401 if (Back[next_jx][next_jy])
3402 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3404 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
3406 else if (Back[next_jx][next_jy])
3407 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3410 /* do not draw (EM style) pushing animation when pushing is finished */
3411 /* (two-tile animations usually do not contain start and end frame) */
3412 if (graphic_info[graphic].double_movement && !IS_MOVING(jx, jy))
3413 DrawLevelElement(next_jx, next_jy, Feld[next_jx][next_jy]);
3415 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3417 /* masked drawing is needed for EMC style (double) movement graphics */
3418 /* !!! (ONLY WHEN DRAWING PUSHED ELEMENT OVER THE PLAYER) !!! */
3419 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3423 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
3424 /* ----------------------------------------------------------------------- */
3425 /* draw player himself */
3426 /* ----------------------------------------------------------------------- */
3428 graphic = getPlayerGraphic(player, move_dir);
3430 /* in the case of changed player action or direction, prevent the current
3431 animation frame from being restarted for identical animations */
3432 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
3433 player->Frame = last_player_frame;
3435 frame = getGraphicAnimationFrame(graphic, player->Frame);
3439 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3440 sxx = player->GfxPos;
3442 syy = player->GfxPos;
3445 if (player_is_opaque)
3446 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
3448 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3450 if (SHIELD_ON(player))
3452 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
3453 IMG_SHIELD_NORMAL_ACTIVE);
3454 int frame = getGraphicAnimationFrame(graphic, -1);
3456 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3460 /* ----------------------------------------------------------------------- */
3461 /* draw things in front of player (active dynamite or dynabombs) */
3462 /* ----------------------------------------------------------------------- */
3464 if (IS_ACTIVE_BOMB(element))
3466 graphic = el2img(element);
3467 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
3469 if (game.emulation == EMU_SUPAPLEX)
3470 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
3472 DrawGraphicThruMask(sx, sy, graphic, frame);
3475 if (player_is_moving && last_element == EL_EXPLOSION)
3477 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
3478 GfxElement[last_jx][last_jy] : EL_EMPTY);
3479 int graphic = el_act2img(element, ACTION_EXPLODING);
3480 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
3481 int phase = ExplodePhase[last_jx][last_jy] - 1;
3482 int frame = getGraphicAnimationFrame(graphic, phase - delay);
3485 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
3488 /* ----------------------------------------------------------------------- */
3489 /* draw elements the player is just walking/passing through/under */
3490 /* ----------------------------------------------------------------------- */
3492 if (player_is_moving)
3494 /* handle the field the player is leaving ... */
3495 if (IS_ACCESSIBLE_INSIDE(last_element))
3496 DrawLevelField(last_jx, last_jy);
3497 else if (IS_ACCESSIBLE_UNDER(last_element))
3498 DrawLevelFieldThruMask(last_jx, last_jy);
3501 /* do not redraw accessible elements if the player is just pushing them */
3502 if (!player_is_moving || !player->is_pushing)
3504 /* ... and the field the player is entering */
3505 if (IS_ACCESSIBLE_INSIDE(element))
3506 DrawLevelField(jx, jy);
3507 else if (IS_ACCESSIBLE_UNDER(element))
3508 DrawLevelFieldThruMask(jx, jy);
3511 MarkTileDirty(sx, sy);
3514 /* ------------------------------------------------------------------------- */
3516 void WaitForEventToContinue()
3518 boolean still_wait = TRUE;
3520 /* simulate releasing mouse button over last gadget, if still pressed */
3522 HandleGadgets(-1, -1, 0);
3524 button_status = MB_RELEASED;
3538 case EVENT_BUTTONPRESS:
3539 case EVENT_KEYPRESS:
3543 case EVENT_KEYRELEASE:
3544 ClearPlayerAction();
3548 HandleOtherEvents(&event);
3552 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3561 #define MAX_REQUEST_LINES 13
3562 #define MAX_REQUEST_LINE_FONT1_LEN 7
3563 #define MAX_REQUEST_LINE_FONT2_LEN 10
3565 static int RequestHandleEvents(unsigned int req_state)
3567 boolean level_solved = (game_status == GAME_MODE_PLAYING &&
3568 local_player->LevelSolved_GameEnd);
3569 int width = request.width;
3570 int height = request.height;
3574 setRequestPosition(&sx, &sy, FALSE);
3576 button_status = MB_RELEASED;
3578 request_gadget_id = -1;
3585 SetDrawtoField(DRAW_TO_FIELDBUFFER);
3587 HandleGameActions();
3589 SetDrawtoField(DRAW_TO_BACKBUFFER);
3591 if (global.use_envelope_request)
3593 /* copy current state of request area to middle of playfield area */
3594 BlitBitmap(bitmap_db_store_2, drawto, sx, sy, width, height, sx, sy);
3602 while (NextValidEvent(&event))
3606 case EVENT_BUTTONPRESS:
3607 case EVENT_BUTTONRELEASE:
3608 case EVENT_MOTIONNOTIFY:
3612 if (event.type == EVENT_MOTIONNOTIFY)
3617 motion_status = TRUE;
3618 mx = ((MotionEvent *) &event)->x;
3619 my = ((MotionEvent *) &event)->y;
3623 motion_status = FALSE;
3624 mx = ((ButtonEvent *) &event)->x;
3625 my = ((ButtonEvent *) &event)->y;
3626 if (event.type == EVENT_BUTTONPRESS)
3627 button_status = ((ButtonEvent *) &event)->button;
3629 button_status = MB_RELEASED;
3632 /* this sets 'request_gadget_id' */
3633 HandleGadgets(mx, my, button_status);
3635 switch (request_gadget_id)
3637 case TOOL_CTRL_ID_YES:
3640 case TOOL_CTRL_ID_NO:
3643 case TOOL_CTRL_ID_CONFIRM:
3644 result = TRUE | FALSE;
3647 case TOOL_CTRL_ID_PLAYER_1:
3650 case TOOL_CTRL_ID_PLAYER_2:
3653 case TOOL_CTRL_ID_PLAYER_3:
3656 case TOOL_CTRL_ID_PLAYER_4:
3667 case EVENT_KEYPRESS:
3668 switch (GetEventKey((KeyEvent *)&event, TRUE))
3671 if (req_state & REQ_CONFIRM)
3676 #if defined(TARGET_SDL2)
3683 #if defined(TARGET_SDL2)
3693 if (req_state & REQ_PLAYER)
3697 case EVENT_KEYRELEASE:
3698 ClearPlayerAction();
3702 HandleOtherEvents(&event);
3707 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3709 int joy = AnyJoystick();
3711 if (joy & JOY_BUTTON_1)
3713 else if (joy & JOY_BUTTON_2)
3719 if (global.use_envelope_request)
3721 /* copy back current state of pressed buttons inside request area */
3722 BlitBitmap(drawto, bitmap_db_store_2, sx, sy, width, height, sx, sy);
3732 static boolean RequestDoor(char *text, unsigned int req_state)
3734 unsigned int old_door_state;
3735 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
3736 int font_nr = FONT_TEXT_2;
3741 if (maxWordLengthInString(text) > MAX_REQUEST_LINE_FONT1_LEN)
3743 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
3744 font_nr = FONT_TEXT_1;
3747 if (game_status == GAME_MODE_PLAYING)
3748 BlitScreenToBitmap(backbuffer);
3750 /* disable deactivated drawing when quick-loading level tape recording */
3751 if (tape.playing && tape.deactivate_display)
3752 TapeDeactivateDisplayOff(TRUE);
3754 SetMouseCursor(CURSOR_DEFAULT);
3756 #if defined(NETWORK_AVALIABLE)
3757 /* pause network game while waiting for request to answer */
3758 if (options.network &&
3759 game_status == GAME_MODE_PLAYING &&
3760 req_state & REQUEST_WAIT_FOR_INPUT)
3761 SendToServer_PausePlaying();
3764 old_door_state = GetDoorState();
3766 /* simulate releasing mouse button over last gadget, if still pressed */
3768 HandleGadgets(-1, -1, 0);
3772 /* draw released gadget before proceeding */
3775 if (old_door_state & DOOR_OPEN_1)
3777 CloseDoor(DOOR_CLOSE_1);
3779 /* save old door content */
3780 BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
3781 0 * DXSIZE, 0, DXSIZE, DYSIZE, 1 * DXSIZE, 0);
3784 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
3785 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3787 /* clear door drawing field */
3788 DrawBackground(DX, DY, DXSIZE, DYSIZE);
3790 /* force DOOR font inside door area */
3791 SetFontStatus(GAME_MODE_PSEUDO_DOOR);
3793 /* write text for request */
3794 for (text_ptr = text, ty = 0; ty < MAX_REQUEST_LINES; ty++)
3796 char text_line[max_request_line_len + 1];
3802 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
3804 tc = *(text_ptr + tx);
3805 // if (!tc || tc == ' ')
3806 if (!tc || tc == ' ' || tc == '?' || tc == '!')
3810 if ((tc == '?' || tc == '!') && tl == 0)
3820 strncpy(text_line, text_ptr, tl);
3823 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
3824 DY + 8 + ty * (getFontHeight(font_nr) + 2),
3825 text_line, font_nr);
3827 text_ptr += tl + (tc == ' ' ? 1 : 0);
3828 // text_ptr += tl + (tc == ' ' || tc == '?' || tc == '!' ? 1 : 0);
3833 if (req_state & REQ_ASK)
3835 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
3836 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
3838 else if (req_state & REQ_CONFIRM)
3840 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
3842 else if (req_state & REQ_PLAYER)
3844 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
3845 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
3846 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
3847 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
3850 /* copy request gadgets to door backbuffer */
3851 BlitBitmap(drawto, bitmap_db_door_1, DX, DY, DXSIZE, DYSIZE, 0, 0);
3853 OpenDoor(DOOR_OPEN_1);
3855 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
3857 if (game_status == GAME_MODE_PLAYING)
3859 SetPanelBackground();
3860 SetDrawBackgroundMask(REDRAW_DOOR_1);
3864 SetDrawBackgroundMask(REDRAW_FIELD);
3870 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3872 // ---------- handle request buttons ----------
3873 result = RequestHandleEvents(req_state);
3877 if (!(req_state & REQ_STAY_OPEN))
3879 CloseDoor(DOOR_CLOSE_1);
3881 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
3882 (req_state & REQ_REOPEN))
3883 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
3888 if (game_status == GAME_MODE_PLAYING)
3890 SetPanelBackground();
3891 SetDrawBackgroundMask(REDRAW_DOOR_1);
3895 SetDrawBackgroundMask(REDRAW_FIELD);
3898 #if defined(NETWORK_AVALIABLE)
3899 /* continue network game after request */
3900 if (options.network &&
3901 game_status == GAME_MODE_PLAYING &&
3902 req_state & REQUEST_WAIT_FOR_INPUT)
3903 SendToServer_ContinuePlaying();
3906 /* restore deactivated drawing when quick-loading level tape recording */
3907 if (tape.playing && tape.deactivate_display)
3908 TapeDeactivateDisplayOn();
3913 static boolean RequestEnvelope(char *text, unsigned int req_state)
3917 if (game_status == GAME_MODE_PLAYING)
3918 BlitScreenToBitmap(backbuffer);
3920 /* disable deactivated drawing when quick-loading level tape recording */
3921 if (tape.playing && tape.deactivate_display)
3922 TapeDeactivateDisplayOff(TRUE);
3924 SetMouseCursor(CURSOR_DEFAULT);
3926 #if defined(NETWORK_AVALIABLE)
3927 /* pause network game while waiting for request to answer */
3928 if (options.network &&
3929 game_status == GAME_MODE_PLAYING &&
3930 req_state & REQUEST_WAIT_FOR_INPUT)
3931 SendToServer_PausePlaying();
3934 /* simulate releasing mouse button over last gadget, if still pressed */
3936 HandleGadgets(-1, -1, 0);
3940 // (replace with setting corresponding request background)
3941 // SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
3942 // SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3944 /* clear door drawing field */
3945 // DrawBackground(DX, DY, DXSIZE, DYSIZE);
3947 ShowEnvelopeRequest(text, req_state, ACTION_OPENING);
3949 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
3951 if (game_status == GAME_MODE_PLAYING)
3953 SetPanelBackground();
3954 SetDrawBackgroundMask(REDRAW_DOOR_1);
3958 SetDrawBackgroundMask(REDRAW_FIELD);
3964 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3966 // ---------- handle request buttons ----------
3967 result = RequestHandleEvents(req_state);
3971 ShowEnvelopeRequest(text, req_state, ACTION_CLOSING);
3975 if (game_status == GAME_MODE_PLAYING)
3977 SetPanelBackground();
3978 SetDrawBackgroundMask(REDRAW_DOOR_1);
3982 SetDrawBackgroundMask(REDRAW_FIELD);
3985 #if defined(NETWORK_AVALIABLE)
3986 /* continue network game after request */
3987 if (options.network &&
3988 game_status == GAME_MODE_PLAYING &&
3989 req_state & REQUEST_WAIT_FOR_INPUT)
3990 SendToServer_ContinuePlaying();
3993 /* restore deactivated drawing when quick-loading level tape recording */
3994 if (tape.playing && tape.deactivate_display)
3995 TapeDeactivateDisplayOn();
4000 boolean Request(char *text, unsigned int req_state)
4002 if (global.use_envelope_request)
4003 return RequestEnvelope(text, req_state);
4005 return RequestDoor(text, req_state);
4008 static int compareDoorPartOrderInfo(const void *object1, const void *object2)
4010 const struct DoorPartOrderInfo *dpo1 = (struct DoorPartOrderInfo *)object1;
4011 const struct DoorPartOrderInfo *dpo2 = (struct DoorPartOrderInfo *)object2;
4014 if (dpo1->sort_priority != dpo2->sort_priority)
4015 compare_result = dpo1->sort_priority - dpo2->sort_priority;
4017 compare_result = dpo1->nr - dpo2->nr;
4019 return compare_result;
4022 void InitGraphicCompatibilityInfo_Doors()
4028 struct DoorInfo *door;
4032 { DOOR_1, IMG_GFX_DOOR_1_PART_1, IMG_GFX_DOOR_1_PART_8, &door_1 },
4033 { DOOR_2, IMG_GFX_DOOR_2_PART_1, IMG_GFX_DOOR_2_PART_8, &door_2 },
4035 { -1, -1, -1, NULL }
4037 struct Rect door_rect_list[] =
4039 { DX, DY, DXSIZE, DYSIZE },
4040 { VX, VY, VXSIZE, VYSIZE }
4044 for (i = 0; doors[i].door_token != -1; i++)
4046 int door_token = doors[i].door_token;
4047 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
4048 int part_1 = doors[i].part_1;
4049 int part_8 = doors[i].part_8;
4050 int part_2 = part_1 + 1;
4051 int part_3 = part_1 + 2;
4052 struct DoorInfo *door = doors[i].door;
4053 struct Rect *door_rect = &door_rect_list[door_index];
4054 boolean door_gfx_redefined = FALSE;
4056 /* check if any door part graphic definitions have been redefined */
4058 for (j = 0; door_part_controls[j].door_token != -1; j++)
4060 struct DoorPartControlInfo *dpc = &door_part_controls[j];
4061 struct FileInfo *fi = getImageListEntryFromImageID(dpc->graphic);
4063 if (dpc->door_token == door_token && fi->redefined)
4064 door_gfx_redefined = TRUE;
4067 /* check for old-style door graphic/animation modifications */
4069 if (!door_gfx_redefined)
4071 if (door->anim_mode & ANIM_STATIC_PANEL)
4073 door->panel.step_xoffset = 0;
4074 door->panel.step_yoffset = 0;
4077 if (door->anim_mode & (ANIM_HORIZONTAL | ANIM_VERTICAL))
4079 struct GraphicInfo *g_part_1 = &graphic_info[part_1];
4080 struct GraphicInfo *g_part_2 = &graphic_info[part_2];
4081 int num_door_steps, num_panel_steps;
4083 /* remove door part graphics other than the two default wings */
4085 for (j = 0; door_part_controls[j].door_token != -1; j++)
4087 struct DoorPartControlInfo *dpc = &door_part_controls[j];
4088 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4090 if (dpc->graphic >= part_3 &&
4091 dpc->graphic <= part_8)
4095 /* set graphics and screen positions of the default wings */
4097 g_part_1->width = door_rect->width;
4098 g_part_1->height = door_rect->height;
4099 g_part_2->width = door_rect->width;
4100 g_part_2->height = door_rect->height;
4101 g_part_2->src_x = door_rect->width;
4102 g_part_2->src_y = g_part_1->src_y;
4104 door->part_2.x = door->part_1.x;
4105 door->part_2.y = door->part_1.y;
4107 if (door->width != -1)
4109 g_part_1->width = door->width;
4110 g_part_2->width = door->width;
4112 // special treatment for graphics and screen position of right wing
4113 g_part_2->src_x += door_rect->width - door->width;
4114 door->part_2.x += door_rect->width - door->width;
4117 if (door->height != -1)
4119 g_part_1->height = door->height;
4120 g_part_2->height = door->height;
4122 // special treatment for graphics and screen position of bottom wing
4123 g_part_2->src_y += door_rect->height - door->height;
4124 door->part_2.y += door_rect->height - door->height;
4127 /* set animation delays for the default wings and panels */
4129 door->part_1.step_delay = door->step_delay;
4130 door->part_2.step_delay = door->step_delay;
4131 door->panel.step_delay = door->step_delay;
4133 /* set animation draw order for the default wings */
4135 door->part_1.sort_priority = 2; /* draw left wing over ... */
4136 door->part_2.sort_priority = 1; /* ... right wing */
4138 /* set animation draw offset for the default wings */
4140 if (door->anim_mode & ANIM_HORIZONTAL)
4142 door->part_1.step_xoffset = door->step_offset;
4143 door->part_1.step_yoffset = 0;
4144 door->part_2.step_xoffset = door->step_offset * -1;
4145 door->part_2.step_yoffset = 0;
4147 num_door_steps = g_part_1->width / door->step_offset;
4149 else // ANIM_VERTICAL
4151 door->part_1.step_xoffset = 0;
4152 door->part_1.step_yoffset = door->step_offset;
4153 door->part_2.step_xoffset = 0;
4154 door->part_2.step_yoffset = door->step_offset * -1;
4156 num_door_steps = g_part_1->height / door->step_offset;
4159 /* set animation draw offset for the default panels */
4161 if (door->step_offset > 1)
4163 num_panel_steps = 2 * door_rect->height / door->step_offset;
4164 door->panel.start_step = num_panel_steps - num_door_steps;
4165 door->panel.start_step_closing = door->panel.start_step;
4169 num_panel_steps = door_rect->height / door->step_offset;
4170 door->panel.start_step = num_panel_steps - num_door_steps / 2;
4171 door->panel.start_step_closing = door->panel.start_step;
4172 door->panel.step_delay *= 2;
4183 for (i = 0; door_part_controls[i].door_token != -1; i++)
4185 struct DoorPartControlInfo *dpc = &door_part_controls[i];
4186 struct DoorPartOrderInfo *dpo = &door_part_order[i];
4188 /* initialize "start_step_opening" and "start_step_closing", if needed */
4189 if (dpc->pos->start_step_opening == 0 &&
4190 dpc->pos->start_step_closing == 0)
4192 // dpc->pos->start_step_opening = dpc->pos->start_step;
4193 dpc->pos->start_step_closing = dpc->pos->start_step;
4196 /* fill structure for door part draw order (sorted below) */
4198 dpo->sort_priority = dpc->pos->sort_priority;
4201 /* sort door part controls according to sort_priority and graphic number */
4202 qsort(door_part_order, MAX_DOOR_PARTS,
4203 sizeof(struct DoorPartOrderInfo), compareDoorPartOrderInfo);
4206 unsigned int OpenDoor(unsigned int door_state)
4208 if (door_state & DOOR_COPY_BACK)
4210 if (door_state & DOOR_OPEN_1)
4211 BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
4212 1 * DXSIZE, 0, DXSIZE, DYSIZE, 0 * DXSIZE, 0);
4214 if (door_state & DOOR_OPEN_2)
4215 BlitBitmap(bitmap_db_door_2, bitmap_db_door_2,
4216 1 * VXSIZE, 0, VXSIZE, VYSIZE, 0 * VXSIZE, 0);
4218 door_state &= ~DOOR_COPY_BACK;
4221 return MoveDoor(door_state);
4224 unsigned int CloseDoor(unsigned int door_state)
4226 unsigned int old_door_state = GetDoorState();
4228 if (!(door_state & DOOR_NO_COPY_BACK))
4230 if (old_door_state & DOOR_OPEN_1)
4231 BlitBitmap(backbuffer, bitmap_db_door_1,
4232 DX, DY, DXSIZE, DYSIZE, 0, 0);
4234 if (old_door_state & DOOR_OPEN_2)
4235 BlitBitmap(backbuffer, bitmap_db_door_2,
4236 VX, VY, VXSIZE, VYSIZE, 0, 0);
4238 door_state &= ~DOOR_NO_COPY_BACK;
4241 return MoveDoor(door_state);
4244 unsigned int GetDoorState()
4246 return MoveDoor(DOOR_GET_STATE);
4249 unsigned int SetDoorState(unsigned int door_state)
4251 return MoveDoor(door_state | DOOR_SET_STATE);
4254 int euclid(int a, int b)
4256 return (b ? euclid(b, a % b) : a);
4259 unsigned int MoveDoor(unsigned int door_state)
4261 struct Rect door_rect_list[] =
4263 { DX, DY, DXSIZE, DYSIZE },
4264 { VX, VY, VXSIZE, VYSIZE }
4266 static int door1 = DOOR_CLOSE_1;
4267 static int door2 = DOOR_CLOSE_2;
4268 unsigned int door_delay = 0;
4269 unsigned int door_delay_value;
4272 if (door_state == DOOR_GET_STATE)
4273 return (door1 | door2);
4275 if (door_state & DOOR_SET_STATE)
4277 if (door_state & DOOR_ACTION_1)
4278 door1 = door_state & DOOR_ACTION_1;
4279 if (door_state & DOOR_ACTION_2)
4280 door2 = door_state & DOOR_ACTION_2;
4282 return (door1 | door2);
4285 if (!(door_state & DOOR_FORCE_REDRAW))
4287 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
4288 door_state &= ~DOOR_OPEN_1;
4289 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
4290 door_state &= ~DOOR_CLOSE_1;
4291 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
4292 door_state &= ~DOOR_OPEN_2;
4293 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
4294 door_state &= ~DOOR_CLOSE_2;
4297 if (global.autoplay_leveldir)
4299 door_state |= DOOR_NO_DELAY;
4300 door_state &= ~DOOR_CLOSE_ALL;
4303 if (game_status == GAME_MODE_EDITOR)
4304 door_state |= DOOR_NO_DELAY;
4306 if (door_state & DOOR_ACTION)
4308 boolean door_panel_drawn[NUM_DOORS];
4309 boolean panel_has_doors[NUM_DOORS];
4310 boolean door_part_skip[MAX_DOOR_PARTS];
4311 boolean door_part_done[MAX_DOOR_PARTS];
4312 boolean door_part_done_all;
4313 int num_steps[MAX_DOOR_PARTS];
4314 int max_move_delay = 0; // delay for complete animations of all doors
4315 int max_step_delay = 0; // delay (ms) between two animation frames
4316 int num_move_steps = 0; // number of animation steps for all doors
4317 int max_move_delay_doors_only = 0; // delay for doors only (no panel)
4318 int num_move_steps_doors_only = 0; // steps for doors only (no panel)
4319 int current_move_delay = 0;
4323 for (i = 0; i < NUM_DOORS; i++)
4324 panel_has_doors[i] = FALSE;
4326 for (i = 0; i < MAX_DOOR_PARTS; i++)
4328 struct DoorPartControlInfo *dpc = &door_part_controls[i];
4329 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4330 int door_token = dpc->door_token;
4332 door_part_done[i] = FALSE;
4333 door_part_skip[i] = (!(door_state & door_token) ||
4337 for (i = 0; i < MAX_DOOR_PARTS; i++)
4339 int nr = door_part_order[i].nr;
4340 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
4341 struct DoorPartPosInfo *pos = dpc->pos;
4342 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4343 int door_token = dpc->door_token;
4344 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
4345 boolean is_panel = DOOR_PART_IS_PANEL(nr);
4346 int step_xoffset = ABS(pos->step_xoffset);
4347 int step_yoffset = ABS(pos->step_yoffset);
4348 int step_delay = pos->step_delay;
4349 int current_door_state = door_state & door_token;
4350 boolean door_opening = ((current_door_state & DOOR_OPEN) != 0);
4351 boolean door_closing = ((current_door_state & DOOR_CLOSE) != 0);
4352 boolean part_opening = (is_panel ? door_closing : door_opening);
4353 int start_step = (part_opening ? pos->start_step_opening :
4354 pos->start_step_closing);
4355 float move_xsize = (step_xoffset ? g->width : 0);
4356 float move_ysize = (step_yoffset ? g->height : 0);
4357 int move_xsteps = (step_xoffset ? ceil(move_xsize / step_xoffset) : 0);
4358 int move_ysteps = (step_yoffset ? ceil(move_ysize / step_yoffset) : 0);
4359 int move_steps = (move_xsteps && move_ysteps ?
4360 MIN(move_xsteps, move_ysteps) :
4361 move_xsteps ? move_xsteps : move_ysteps) - start_step;
4362 int move_delay = move_steps * step_delay;
4364 if (door_part_skip[nr])
4367 max_move_delay = MAX(max_move_delay, move_delay);
4368 max_step_delay = (max_step_delay == 0 ? step_delay :
4369 euclid(max_step_delay, step_delay));
4370 num_steps[nr] = move_steps;
4374 max_move_delay_doors_only = MAX(max_move_delay_doors_only, move_delay);
4376 panel_has_doors[door_index] = TRUE;
4380 max_step_delay = MAX(1, max_step_delay); // prevent division by zero
4382 num_move_steps = max_move_delay / max_step_delay;
4383 num_move_steps_doors_only = max_move_delay_doors_only / max_step_delay;
4385 door_delay_value = max_step_delay;
4387 if ((door_state & DOOR_NO_DELAY) || setup.quick_doors)
4389 start = num_move_steps - 1;
4393 /* opening door sound has priority over simultaneously closing door */
4394 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
4395 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
4396 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
4397 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
4400 for (k = start; k < num_move_steps; k++)
4402 int last_frame = num_move_steps - 1; // last frame of this "for" loop
4404 door_part_done_all = TRUE;
4406 for (i = 0; i < NUM_DOORS; i++)
4407 door_panel_drawn[i] = FALSE;
4409 for (i = 0; i < MAX_DOOR_PARTS; i++)
4411 int nr = door_part_order[i].nr;
4412 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
4413 struct DoorPartPosInfo *pos = dpc->pos;
4414 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4415 int door_token = dpc->door_token;
4416 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
4417 boolean is_panel = DOOR_PART_IS_PANEL(nr);
4418 boolean is_panel_and_door_has_closed = FALSE;
4419 struct Rect *door_rect = &door_rect_list[door_index];
4420 Bitmap *bitmap_db_door = (door_token == DOOR_1 ? bitmap_db_door_1 :
4422 Bitmap *bitmap = (is_panel ? bitmap_db_door : g->bitmap);
4423 int current_door_state = door_state & door_token;
4424 boolean door_opening = ((current_door_state & DOOR_OPEN) != 0);
4425 boolean door_closing = !door_opening;
4426 boolean part_opening = (is_panel ? door_closing : door_opening);
4427 boolean part_closing = !part_opening;
4428 int start_step = (part_opening ? pos->start_step_opening :
4429 pos->start_step_closing);
4430 int step_delay = pos->step_delay;
4431 int step_factor = step_delay / max_step_delay;
4432 int k1 = (step_factor ? k / step_factor + 1 : k);
4433 int k2 = (part_opening ? k1 + start_step : num_steps[nr] - k1);
4434 int kk = MAX(0, k2);
4437 int src_x, src_y, src_xx, src_yy;
4438 int dst_x, dst_y, dst_xx, dst_yy;
4441 if (door_part_skip[nr])
4444 if (!(door_state & door_token))
4452 int k2_door = (door_opening ? k : num_move_steps_doors_only - k - 1);
4453 int kk_door = MAX(0, k2_door);
4454 int sync_frame = kk_door * door_delay_value;
4455 int frame = getGraphicAnimationFrame(dpc->graphic, sync_frame);
4457 getGraphicSource(dpc->graphic, frame, &bitmap, &g_src_x, &g_src_y);
4462 if (!door_panel_drawn[door_index])
4464 ClearRectangle(drawto, door_rect->x, door_rect->y,
4465 door_rect->width, door_rect->height);
4467 door_panel_drawn[door_index] = TRUE;
4470 // draw opening or closing door parts
4472 if (pos->step_xoffset < 0) // door part on right side
4475 dst_xx = pos->x + ABS(kk * pos->step_xoffset);
4478 if (dst_xx + width > door_rect->width)
4479 width = door_rect->width - dst_xx;
4481 else // door part on left side
4484 dst_xx = pos->x - kk * pos->step_xoffset;
4488 src_xx = ABS(dst_xx);
4492 width = g->width - src_xx;
4494 if (width > door_rect->width)
4495 width = door_rect->width;
4497 // printf("::: k == %d [%d] \n", k, start_step);
4500 if (pos->step_yoffset < 0) // door part on bottom side
4503 dst_yy = pos->y + ABS(kk * pos->step_yoffset);
4506 if (dst_yy + height > door_rect->height)
4507 height = door_rect->height - dst_yy;
4509 else // door part on top side
4512 dst_yy = pos->y - kk * pos->step_yoffset;
4516 src_yy = ABS(dst_yy);
4520 height = g->height - src_yy;
4523 src_x = g_src_x + src_xx;
4524 src_y = g_src_y + src_yy;
4526 dst_x = door_rect->x + dst_xx;
4527 dst_y = door_rect->y + dst_yy;
4529 is_panel_and_door_has_closed =
4532 panel_has_doors[door_index] &&
4533 k >= num_move_steps_doors_only - 1);
4535 if (width >= 0 && width <= g->width &&
4536 height >= 0 && height <= g->height &&
4537 !is_panel_and_door_has_closed)
4539 if (is_panel || !pos->draw_masked)
4540 BlitBitmap(bitmap, drawto, src_x, src_y, width, height,
4543 BlitBitmapMasked(bitmap, drawto, src_x, src_y, width, height,
4547 redraw_mask |= REDRAW_DOOR_FROM_TOKEN(door_token);
4549 if ((part_opening && (width < 0 || height < 0)) ||
4550 (part_closing && (width >= g->width && height >= g->height)))
4551 door_part_done[nr] = TRUE;
4553 // continue door part animations, but not panel after door has closed
4554 if (!door_part_done[nr] && !is_panel_and_door_has_closed)
4555 door_part_done_all = FALSE;
4558 if (!(door_state & DOOR_NO_DELAY))
4562 SkipUntilDelayReached(&door_delay, door_delay_value, &k, last_frame);
4564 current_move_delay += max_step_delay;
4567 if (door_part_done_all)
4572 if (door_state & DOOR_ACTION_1)
4573 door1 = door_state & DOOR_ACTION_1;
4574 if (door_state & DOOR_ACTION_2)
4575 door2 = door_state & DOOR_ACTION_2;
4577 // draw masked border over door area
4578 DrawMaskedBorder(REDRAW_DOOR_1);
4579 DrawMaskedBorder(REDRAW_DOOR_2);
4581 return (door1 | door2);
4584 static boolean useSpecialEditorDoor()
4586 int graphic = IMG_GLOBAL_BORDER_EDITOR;
4587 boolean redefined = getImageListEntryFromImageID(graphic)->redefined;
4589 // do not draw special editor door if editor border defined or redefined
4590 if (graphic_info[graphic].bitmap != NULL || redefined)
4593 // do not draw special editor door if global border defined to be empty
4594 if (graphic_info[IMG_GLOBAL_BORDER].bitmap == NULL)
4597 // do not draw special editor door if viewport definitions do not match
4601 EY + EYSIZE != VY + VYSIZE)
4607 void DrawSpecialEditorDoor()
4609 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
4610 int top_border_width = gfx1->width;
4611 int top_border_height = gfx1->height;
4612 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
4613 int ex = EX - outer_border;
4614 int ey = EY - outer_border;
4615 int vy = VY - outer_border;
4616 int exsize = EXSIZE + 2 * outer_border;
4618 if (!useSpecialEditorDoor())
4621 /* draw bigger level editor toolbox window */
4622 BlitBitmap(gfx1->bitmap, drawto, gfx1->src_x, gfx1->src_y,
4623 top_border_width, top_border_height, ex, ey - top_border_height);
4624 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto, ex, vy,
4625 exsize, EYSIZE - VYSIZE + outer_border, ex, ey);
4627 redraw_mask |= REDRAW_ALL;
4630 void UndrawSpecialEditorDoor()
4632 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
4633 int top_border_width = gfx1->width;
4634 int top_border_height = gfx1->height;
4635 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
4636 int ex = EX - outer_border;
4637 int ey = EY - outer_border;
4638 int ey_top = ey - top_border_height;
4639 int exsize = EXSIZE + 2 * outer_border;
4640 int eysize = EYSIZE + 2 * outer_border;
4642 if (!useSpecialEditorDoor())
4645 /* draw normal tape recorder window */
4646 if (graphic_info[IMG_GLOBAL_BORDER].bitmap)
4648 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
4649 ex, ey_top, top_border_width, top_border_height,
4651 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
4652 ex, ey, exsize, eysize, ex, ey);
4656 // if screen background is set to "[NONE]", clear editor toolbox window
4657 ClearRectangle(drawto, ex, ey_top, top_border_width, top_border_height);
4658 ClearRectangle(drawto, ex, ey, exsize, eysize);
4661 redraw_mask |= REDRAW_ALL;
4665 /* ---------- new tool button stuff ---------------------------------------- */
4670 struct TextPosInfo *pos;
4673 } toolbutton_info[NUM_TOOL_BUTTONS] =
4676 IMG_GFX_REQUEST_BUTTON_YES, &request.button.yes,
4677 TOOL_CTRL_ID_YES, "yes"
4680 IMG_GFX_REQUEST_BUTTON_NO, &request.button.no,
4681 TOOL_CTRL_ID_NO, "no"
4684 IMG_GFX_REQUEST_BUTTON_CONFIRM, &request.button.confirm,
4685 TOOL_CTRL_ID_CONFIRM, "confirm"
4688 IMG_GFX_REQUEST_BUTTON_PLAYER_1, &request.button.player_1,
4689 TOOL_CTRL_ID_PLAYER_1, "player 1"
4692 IMG_GFX_REQUEST_BUTTON_PLAYER_2, &request.button.player_2,
4693 TOOL_CTRL_ID_PLAYER_2, "player 2"
4696 IMG_GFX_REQUEST_BUTTON_PLAYER_3, &request.button.player_3,
4697 TOOL_CTRL_ID_PLAYER_3, "player 3"
4700 IMG_GFX_REQUEST_BUTTON_PLAYER_4, &request.button.player_4,
4701 TOOL_CTRL_ID_PLAYER_4, "player 4"
4705 void CreateToolButtons()
4709 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4711 struct GraphicInfo *gfx = &graphic_info[toolbutton_info[i].graphic];
4712 struct TextPosInfo *pos = toolbutton_info[i].pos;
4713 struct GadgetInfo *gi;
4714 Bitmap *deco_bitmap = None;
4715 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
4716 unsigned int event_mask = GD_EVENT_RELEASED;
4719 int gd_x = gfx->src_x;
4720 int gd_y = gfx->src_y;
4721 int gd_xp = gfx->src_x + gfx->pressed_xoffset;
4722 int gd_yp = gfx->src_y + gfx->pressed_yoffset;
4725 if (global.use_envelope_request)
4726 setRequestPosition(&dx, &dy, TRUE);
4728 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
4730 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
4732 getSizedGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr), 0,
4733 pos->size, &deco_bitmap, &deco_x, &deco_y);
4734 deco_xpos = (gfx->width - pos->size) / 2;
4735 deco_ypos = (gfx->height - pos->size) / 2;
4738 gi = CreateGadget(GDI_CUSTOM_ID, id,
4739 GDI_INFO_TEXT, toolbutton_info[i].infotext,
4740 GDI_X, dx + GDI_ACTIVE_POS(pos->x),
4741 GDI_Y, dy + GDI_ACTIVE_POS(pos->y),
4742 GDI_WIDTH, gfx->width,
4743 GDI_HEIGHT, gfx->height,
4744 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
4745 GDI_STATE, GD_BUTTON_UNPRESSED,
4746 GDI_DESIGN_UNPRESSED, gfx->bitmap, gd_x, gd_y,
4747 GDI_DESIGN_PRESSED, gfx->bitmap, gd_xp, gd_yp,
4748 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
4749 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
4750 GDI_DECORATION_SIZE, pos->size, pos->size,
4751 GDI_DECORATION_SHIFTING, 1, 1,
4752 GDI_DIRECT_DRAW, FALSE,
4753 GDI_EVENT_MASK, event_mask,
4754 GDI_CALLBACK_ACTION, HandleToolButtons,
4758 Error(ERR_EXIT, "cannot create gadget");
4760 tool_gadget[id] = gi;
4764 void FreeToolButtons()
4768 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4769 FreeGadget(tool_gadget[i]);
4772 static void UnmapToolButtons()
4776 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4777 UnmapGadget(tool_gadget[i]);
4780 static void HandleToolButtons(struct GadgetInfo *gi)
4782 request_gadget_id = gi->custom_id;
4785 static struct Mapping_EM_to_RND_object
4788 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
4789 boolean is_backside; /* backside of moving element */
4795 em_object_mapping_list[] =
4798 Xblank, TRUE, FALSE,
4802 Yacid_splash_eB, FALSE, FALSE,
4803 EL_ACID_SPLASH_RIGHT, -1, -1
4806 Yacid_splash_wB, FALSE, FALSE,
4807 EL_ACID_SPLASH_LEFT, -1, -1
4810 #ifdef EM_ENGINE_BAD_ROLL
4812 Xstone_force_e, FALSE, FALSE,
4813 EL_ROCK, -1, MV_BIT_RIGHT
4816 Xstone_force_w, FALSE, FALSE,
4817 EL_ROCK, -1, MV_BIT_LEFT
4820 Xnut_force_e, FALSE, FALSE,
4821 EL_NUT, -1, MV_BIT_RIGHT
4824 Xnut_force_w, FALSE, FALSE,
4825 EL_NUT, -1, MV_BIT_LEFT
4828 Xspring_force_e, FALSE, FALSE,
4829 EL_SPRING, -1, MV_BIT_RIGHT
4832 Xspring_force_w, FALSE, FALSE,
4833 EL_SPRING, -1, MV_BIT_LEFT
4836 Xemerald_force_e, FALSE, FALSE,
4837 EL_EMERALD, -1, MV_BIT_RIGHT
4840 Xemerald_force_w, FALSE, FALSE,
4841 EL_EMERALD, -1, MV_BIT_LEFT
4844 Xdiamond_force_e, FALSE, FALSE,
4845 EL_DIAMOND, -1, MV_BIT_RIGHT
4848 Xdiamond_force_w, FALSE, FALSE,
4849 EL_DIAMOND, -1, MV_BIT_LEFT
4852 Xbomb_force_e, FALSE, FALSE,
4853 EL_BOMB, -1, MV_BIT_RIGHT
4856 Xbomb_force_w, FALSE, FALSE,
4857 EL_BOMB, -1, MV_BIT_LEFT
4859 #endif /* EM_ENGINE_BAD_ROLL */
4862 Xstone, TRUE, FALSE,
4866 Xstone_pause, FALSE, FALSE,
4870 Xstone_fall, FALSE, FALSE,
4874 Ystone_s, FALSE, FALSE,
4875 EL_ROCK, ACTION_FALLING, -1
4878 Ystone_sB, FALSE, TRUE,
4879 EL_ROCK, ACTION_FALLING, -1
4882 Ystone_e, FALSE, FALSE,
4883 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
4886 Ystone_eB, FALSE, TRUE,
4887 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
4890 Ystone_w, FALSE, FALSE,
4891 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
4894 Ystone_wB, FALSE, TRUE,
4895 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
4902 Xnut_pause, FALSE, FALSE,
4906 Xnut_fall, FALSE, FALSE,
4910 Ynut_s, FALSE, FALSE,
4911 EL_NUT, ACTION_FALLING, -1
4914 Ynut_sB, FALSE, TRUE,
4915 EL_NUT, ACTION_FALLING, -1
4918 Ynut_e, FALSE, FALSE,
4919 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
4922 Ynut_eB, FALSE, TRUE,
4923 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
4926 Ynut_w, FALSE, FALSE,
4927 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
4930 Ynut_wB, FALSE, TRUE,
4931 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
4934 Xbug_n, TRUE, FALSE,
4938 Xbug_e, TRUE, FALSE,
4939 EL_BUG_RIGHT, -1, -1
4942 Xbug_s, TRUE, FALSE,
4946 Xbug_w, TRUE, FALSE,
4950 Xbug_gon, FALSE, FALSE,
4954 Xbug_goe, FALSE, FALSE,
4955 EL_BUG_RIGHT, -1, -1
4958 Xbug_gos, FALSE, FALSE,
4962 Xbug_gow, FALSE, FALSE,
4966 Ybug_n, FALSE, FALSE,
4967 EL_BUG, ACTION_MOVING, MV_BIT_UP
4970 Ybug_nB, FALSE, TRUE,
4971 EL_BUG, ACTION_MOVING, MV_BIT_UP
4974 Ybug_e, FALSE, FALSE,
4975 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
4978 Ybug_eB, FALSE, TRUE,
4979 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
4982 Ybug_s, FALSE, FALSE,
4983 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
4986 Ybug_sB, FALSE, TRUE,
4987 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
4990 Ybug_w, FALSE, FALSE,
4991 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
4994 Ybug_wB, FALSE, TRUE,
4995 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
4998 Ybug_w_n, FALSE, FALSE,
4999 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
5002 Ybug_n_e, FALSE, FALSE,
5003 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
5006 Ybug_e_s, FALSE, FALSE,
5007 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
5010 Ybug_s_w, FALSE, FALSE,
5011 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
5014 Ybug_e_n, FALSE, FALSE,
5015 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
5018 Ybug_s_e, FALSE, FALSE,
5019 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
5022 Ybug_w_s, FALSE, FALSE,
5023 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
5026 Ybug_n_w, FALSE, FALSE,
5027 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
5030 Ybug_stone, FALSE, FALSE,
5031 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
5034 Ybug_spring, FALSE, FALSE,
5035 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
5038 Xtank_n, TRUE, FALSE,
5039 EL_SPACESHIP_UP, -1, -1
5042 Xtank_e, TRUE, FALSE,
5043 EL_SPACESHIP_RIGHT, -1, -1
5046 Xtank_s, TRUE, FALSE,
5047 EL_SPACESHIP_DOWN, -1, -1
5050 Xtank_w, TRUE, FALSE,
5051 EL_SPACESHIP_LEFT, -1, -1
5054 Xtank_gon, FALSE, FALSE,
5055 EL_SPACESHIP_UP, -1, -1
5058 Xtank_goe, FALSE, FALSE,
5059 EL_SPACESHIP_RIGHT, -1, -1
5062 Xtank_gos, FALSE, FALSE,
5063 EL_SPACESHIP_DOWN, -1, -1
5066 Xtank_gow, FALSE, FALSE,
5067 EL_SPACESHIP_LEFT, -1, -1
5070 Ytank_n, FALSE, FALSE,
5071 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
5074 Ytank_nB, FALSE, TRUE,
5075 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
5078 Ytank_e, FALSE, FALSE,
5079 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
5082 Ytank_eB, FALSE, TRUE,
5083 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
5086 Ytank_s, FALSE, FALSE,
5087 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
5090 Ytank_sB, FALSE, TRUE,
5091 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
5094 Ytank_w, FALSE, FALSE,
5095 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
5098 Ytank_wB, FALSE, TRUE,
5099 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
5102 Ytank_w_n, FALSE, FALSE,
5103 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
5106 Ytank_n_e, FALSE, FALSE,
5107 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
5110 Ytank_e_s, FALSE, FALSE,
5111 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
5114 Ytank_s_w, FALSE, FALSE,
5115 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
5118 Ytank_e_n, FALSE, FALSE,
5119 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
5122 Ytank_s_e, FALSE, FALSE,
5123 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
5126 Ytank_w_s, FALSE, FALSE,
5127 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
5130 Ytank_n_w, FALSE, FALSE,
5131 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
5134 Ytank_stone, FALSE, FALSE,
5135 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
5138 Ytank_spring, FALSE, FALSE,
5139 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
5142 Xandroid, TRUE, FALSE,
5143 EL_EMC_ANDROID, ACTION_ACTIVE, -1
5146 Xandroid_1_n, FALSE, FALSE,
5147 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
5150 Xandroid_2_n, FALSE, FALSE,
5151 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
5154 Xandroid_1_e, FALSE, FALSE,
5155 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
5158 Xandroid_2_e, FALSE, FALSE,
5159 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
5162 Xandroid_1_w, FALSE, FALSE,
5163 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
5166 Xandroid_2_w, FALSE, FALSE,
5167 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
5170 Xandroid_1_s, FALSE, FALSE,
5171 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
5174 Xandroid_2_s, FALSE, FALSE,
5175 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
5178 Yandroid_n, FALSE, FALSE,
5179 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
5182 Yandroid_nB, FALSE, TRUE,
5183 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
5186 Yandroid_ne, FALSE, FALSE,
5187 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
5190 Yandroid_neB, FALSE, TRUE,
5191 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
5194 Yandroid_e, FALSE, FALSE,
5195 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
5198 Yandroid_eB, FALSE, TRUE,
5199 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
5202 Yandroid_se, FALSE, FALSE,
5203 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
5206 Yandroid_seB, FALSE, TRUE,
5207 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
5210 Yandroid_s, FALSE, FALSE,
5211 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
5214 Yandroid_sB, FALSE, TRUE,
5215 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
5218 Yandroid_sw, FALSE, FALSE,
5219 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
5222 Yandroid_swB, FALSE, TRUE,
5223 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
5226 Yandroid_w, FALSE, FALSE,
5227 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
5230 Yandroid_wB, FALSE, TRUE,
5231 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
5234 Yandroid_nw, FALSE, FALSE,
5235 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
5238 Yandroid_nwB, FALSE, TRUE,
5239 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
5242 Xspring, TRUE, FALSE,
5246 Xspring_pause, FALSE, FALSE,
5250 Xspring_e, FALSE, FALSE,
5254 Xspring_w, FALSE, FALSE,
5258 Xspring_fall, FALSE, FALSE,
5262 Yspring_s, FALSE, FALSE,
5263 EL_SPRING, ACTION_FALLING, -1
5266 Yspring_sB, FALSE, TRUE,
5267 EL_SPRING, ACTION_FALLING, -1
5270 Yspring_e, FALSE, FALSE,
5271 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
5274 Yspring_eB, FALSE, TRUE,
5275 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
5278 Yspring_w, FALSE, FALSE,
5279 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
5282 Yspring_wB, FALSE, TRUE,
5283 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
5286 Yspring_kill_e, FALSE, FALSE,
5287 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
5290 Yspring_kill_eB, FALSE, TRUE,
5291 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
5294 Yspring_kill_w, FALSE, FALSE,
5295 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
5298 Yspring_kill_wB, FALSE, TRUE,
5299 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
5302 Xeater_n, TRUE, FALSE,
5303 EL_YAMYAM_UP, -1, -1
5306 Xeater_e, TRUE, FALSE,
5307 EL_YAMYAM_RIGHT, -1, -1
5310 Xeater_w, TRUE, FALSE,
5311 EL_YAMYAM_LEFT, -1, -1
5314 Xeater_s, TRUE, FALSE,
5315 EL_YAMYAM_DOWN, -1, -1
5318 Yeater_n, FALSE, FALSE,
5319 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
5322 Yeater_nB, FALSE, TRUE,
5323 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
5326 Yeater_e, FALSE, FALSE,
5327 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
5330 Yeater_eB, FALSE, TRUE,
5331 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
5334 Yeater_s, FALSE, FALSE,
5335 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
5338 Yeater_sB, FALSE, TRUE,
5339 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
5342 Yeater_w, FALSE, FALSE,
5343 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
5346 Yeater_wB, FALSE, TRUE,
5347 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
5350 Yeater_stone, FALSE, FALSE,
5351 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
5354 Yeater_spring, FALSE, FALSE,
5355 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
5358 Xalien, TRUE, FALSE,
5362 Xalien_pause, FALSE, FALSE,
5366 Yalien_n, FALSE, FALSE,
5367 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
5370 Yalien_nB, FALSE, TRUE,
5371 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
5374 Yalien_e, FALSE, FALSE,
5375 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
5378 Yalien_eB, FALSE, TRUE,
5379 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
5382 Yalien_s, FALSE, FALSE,
5383 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
5386 Yalien_sB, FALSE, TRUE,
5387 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
5390 Yalien_w, FALSE, FALSE,
5391 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
5394 Yalien_wB, FALSE, TRUE,
5395 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
5398 Yalien_stone, FALSE, FALSE,
5399 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
5402 Yalien_spring, FALSE, FALSE,
5403 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
5406 Xemerald, TRUE, FALSE,
5410 Xemerald_pause, FALSE, FALSE,
5414 Xemerald_fall, FALSE, FALSE,
5418 Xemerald_shine, FALSE, FALSE,
5419 EL_EMERALD, ACTION_TWINKLING, -1
5422 Yemerald_s, FALSE, FALSE,
5423 EL_EMERALD, ACTION_FALLING, -1
5426 Yemerald_sB, FALSE, TRUE,
5427 EL_EMERALD, ACTION_FALLING, -1
5430 Yemerald_e, FALSE, FALSE,
5431 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
5434 Yemerald_eB, FALSE, TRUE,
5435 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
5438 Yemerald_w, FALSE, FALSE,
5439 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
5442 Yemerald_wB, FALSE, TRUE,
5443 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
5446 Yemerald_eat, FALSE, FALSE,
5447 EL_EMERALD, ACTION_COLLECTING, -1
5450 Yemerald_stone, FALSE, FALSE,
5451 EL_NUT, ACTION_BREAKING, -1
5454 Xdiamond, TRUE, FALSE,
5458 Xdiamond_pause, FALSE, FALSE,
5462 Xdiamond_fall, FALSE, FALSE,
5466 Xdiamond_shine, FALSE, FALSE,
5467 EL_DIAMOND, ACTION_TWINKLING, -1
5470 Ydiamond_s, FALSE, FALSE,
5471 EL_DIAMOND, ACTION_FALLING, -1
5474 Ydiamond_sB, FALSE, TRUE,
5475 EL_DIAMOND, ACTION_FALLING, -1
5478 Ydiamond_e, FALSE, FALSE,
5479 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
5482 Ydiamond_eB, FALSE, TRUE,
5483 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
5486 Ydiamond_w, FALSE, FALSE,
5487 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
5490 Ydiamond_wB, FALSE, TRUE,
5491 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
5494 Ydiamond_eat, FALSE, FALSE,
5495 EL_DIAMOND, ACTION_COLLECTING, -1
5498 Ydiamond_stone, FALSE, FALSE,
5499 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
5502 Xdrip_fall, TRUE, FALSE,
5503 EL_AMOEBA_DROP, -1, -1
5506 Xdrip_stretch, FALSE, FALSE,
5507 EL_AMOEBA_DROP, ACTION_FALLING, -1
5510 Xdrip_stretchB, FALSE, TRUE,
5511 EL_AMOEBA_DROP, ACTION_FALLING, -1
5514 Xdrip_eat, FALSE, FALSE,
5515 EL_AMOEBA_DROP, ACTION_GROWING, -1
5518 Ydrip_s1, FALSE, FALSE,
5519 EL_AMOEBA_DROP, ACTION_FALLING, -1
5522 Ydrip_s1B, FALSE, TRUE,
5523 EL_AMOEBA_DROP, ACTION_FALLING, -1
5526 Ydrip_s2, FALSE, FALSE,
5527 EL_AMOEBA_DROP, ACTION_FALLING, -1
5530 Ydrip_s2B, FALSE, TRUE,
5531 EL_AMOEBA_DROP, ACTION_FALLING, -1
5538 Xbomb_pause, FALSE, FALSE,
5542 Xbomb_fall, FALSE, FALSE,
5546 Ybomb_s, FALSE, FALSE,
5547 EL_BOMB, ACTION_FALLING, -1
5550 Ybomb_sB, FALSE, TRUE,
5551 EL_BOMB, ACTION_FALLING, -1
5554 Ybomb_e, FALSE, FALSE,
5555 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
5558 Ybomb_eB, FALSE, TRUE,
5559 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
5562 Ybomb_w, FALSE, FALSE,
5563 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
5566 Ybomb_wB, FALSE, TRUE,
5567 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
5570 Ybomb_eat, FALSE, FALSE,
5571 EL_BOMB, ACTION_ACTIVATING, -1
5574 Xballoon, TRUE, FALSE,
5578 Yballoon_n, FALSE, FALSE,
5579 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
5582 Yballoon_nB, FALSE, TRUE,
5583 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
5586 Yballoon_e, FALSE, FALSE,
5587 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
5590 Yballoon_eB, FALSE, TRUE,
5591 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
5594 Yballoon_s, FALSE, FALSE,
5595 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
5598 Yballoon_sB, FALSE, TRUE,
5599 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
5602 Yballoon_w, FALSE, FALSE,
5603 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
5606 Yballoon_wB, FALSE, TRUE,
5607 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
5610 Xgrass, TRUE, FALSE,
5611 EL_EMC_GRASS, -1, -1
5614 Ygrass_nB, FALSE, FALSE,
5615 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
5618 Ygrass_eB, FALSE, FALSE,
5619 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
5622 Ygrass_sB, FALSE, FALSE,
5623 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
5626 Ygrass_wB, FALSE, FALSE,
5627 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
5634 Ydirt_nB, FALSE, FALSE,
5635 EL_SAND, ACTION_DIGGING, MV_BIT_UP
5638 Ydirt_eB, FALSE, FALSE,
5639 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
5642 Ydirt_sB, FALSE, FALSE,
5643 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
5646 Ydirt_wB, FALSE, FALSE,
5647 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
5650 Xacid_ne, TRUE, FALSE,
5651 EL_ACID_POOL_TOPRIGHT, -1, -1
5654 Xacid_se, TRUE, FALSE,
5655 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
5658 Xacid_s, TRUE, FALSE,
5659 EL_ACID_POOL_BOTTOM, -1, -1
5662 Xacid_sw, TRUE, FALSE,
5663 EL_ACID_POOL_BOTTOMLEFT, -1, -1
5666 Xacid_nw, TRUE, FALSE,
5667 EL_ACID_POOL_TOPLEFT, -1, -1
5670 Xacid_1, TRUE, FALSE,
5674 Xacid_2, FALSE, FALSE,
5678 Xacid_3, FALSE, FALSE,
5682 Xacid_4, FALSE, FALSE,
5686 Xacid_5, FALSE, FALSE,
5690 Xacid_6, FALSE, FALSE,
5694 Xacid_7, FALSE, FALSE,
5698 Xacid_8, FALSE, FALSE,
5702 Xball_1, TRUE, FALSE,
5703 EL_EMC_MAGIC_BALL, -1, -1
5706 Xball_1B, FALSE, FALSE,
5707 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5710 Xball_2, FALSE, FALSE,
5711 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5714 Xball_2B, FALSE, FALSE,
5715 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5718 Yball_eat, FALSE, FALSE,
5719 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
5722 Ykey_1_eat, FALSE, FALSE,
5723 EL_EM_KEY_1, ACTION_COLLECTING, -1
5726 Ykey_2_eat, FALSE, FALSE,
5727 EL_EM_KEY_2, ACTION_COLLECTING, -1
5730 Ykey_3_eat, FALSE, FALSE,
5731 EL_EM_KEY_3, ACTION_COLLECTING, -1
5734 Ykey_4_eat, FALSE, FALSE,
5735 EL_EM_KEY_4, ACTION_COLLECTING, -1
5738 Ykey_5_eat, FALSE, FALSE,
5739 EL_EMC_KEY_5, ACTION_COLLECTING, -1
5742 Ykey_6_eat, FALSE, FALSE,
5743 EL_EMC_KEY_6, ACTION_COLLECTING, -1
5746 Ykey_7_eat, FALSE, FALSE,
5747 EL_EMC_KEY_7, ACTION_COLLECTING, -1
5750 Ykey_8_eat, FALSE, FALSE,
5751 EL_EMC_KEY_8, ACTION_COLLECTING, -1
5754 Ylenses_eat, FALSE, FALSE,
5755 EL_EMC_LENSES, ACTION_COLLECTING, -1
5758 Ymagnify_eat, FALSE, FALSE,
5759 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
5762 Ygrass_eat, FALSE, FALSE,
5763 EL_EMC_GRASS, ACTION_SNAPPING, -1
5766 Ydirt_eat, FALSE, FALSE,
5767 EL_SAND, ACTION_SNAPPING, -1
5770 Xgrow_ns, TRUE, FALSE,
5771 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
5774 Ygrow_ns_eat, FALSE, FALSE,
5775 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
5778 Xgrow_ew, TRUE, FALSE,
5779 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
5782 Ygrow_ew_eat, FALSE, FALSE,
5783 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
5786 Xwonderwall, TRUE, FALSE,
5787 EL_MAGIC_WALL, -1, -1
5790 XwonderwallB, FALSE, FALSE,
5791 EL_MAGIC_WALL, ACTION_ACTIVE, -1
5794 Xamoeba_1, TRUE, FALSE,
5795 EL_AMOEBA_DRY, ACTION_OTHER, -1
5798 Xamoeba_2, FALSE, FALSE,
5799 EL_AMOEBA_DRY, ACTION_OTHER, -1
5802 Xamoeba_3, FALSE, FALSE,
5803 EL_AMOEBA_DRY, ACTION_OTHER, -1
5806 Xamoeba_4, FALSE, FALSE,
5807 EL_AMOEBA_DRY, ACTION_OTHER, -1
5810 Xamoeba_5, TRUE, FALSE,
5811 EL_AMOEBA_WET, ACTION_OTHER, -1
5814 Xamoeba_6, FALSE, FALSE,
5815 EL_AMOEBA_WET, ACTION_OTHER, -1
5818 Xamoeba_7, FALSE, FALSE,
5819 EL_AMOEBA_WET, ACTION_OTHER, -1
5822 Xamoeba_8, FALSE, FALSE,
5823 EL_AMOEBA_WET, ACTION_OTHER, -1
5826 Xdoor_1, TRUE, FALSE,
5827 EL_EM_GATE_1, -1, -1
5830 Xdoor_2, TRUE, FALSE,
5831 EL_EM_GATE_2, -1, -1
5834 Xdoor_3, TRUE, FALSE,
5835 EL_EM_GATE_3, -1, -1
5838 Xdoor_4, TRUE, FALSE,
5839 EL_EM_GATE_4, -1, -1
5842 Xdoor_5, TRUE, FALSE,
5843 EL_EMC_GATE_5, -1, -1
5846 Xdoor_6, TRUE, FALSE,
5847 EL_EMC_GATE_6, -1, -1
5850 Xdoor_7, TRUE, FALSE,
5851 EL_EMC_GATE_7, -1, -1
5854 Xdoor_8, TRUE, FALSE,
5855 EL_EMC_GATE_8, -1, -1
5858 Xkey_1, TRUE, FALSE,
5862 Xkey_2, TRUE, FALSE,
5866 Xkey_3, TRUE, FALSE,
5870 Xkey_4, TRUE, FALSE,
5874 Xkey_5, TRUE, FALSE,
5875 EL_EMC_KEY_5, -1, -1
5878 Xkey_6, TRUE, FALSE,
5879 EL_EMC_KEY_6, -1, -1
5882 Xkey_7, TRUE, FALSE,
5883 EL_EMC_KEY_7, -1, -1
5886 Xkey_8, TRUE, FALSE,
5887 EL_EMC_KEY_8, -1, -1
5890 Xwind_n, TRUE, FALSE,
5891 EL_BALLOON_SWITCH_UP, -1, -1
5894 Xwind_e, TRUE, FALSE,
5895 EL_BALLOON_SWITCH_RIGHT, -1, -1
5898 Xwind_s, TRUE, FALSE,
5899 EL_BALLOON_SWITCH_DOWN, -1, -1
5902 Xwind_w, TRUE, FALSE,
5903 EL_BALLOON_SWITCH_LEFT, -1, -1
5906 Xwind_nesw, TRUE, FALSE,
5907 EL_BALLOON_SWITCH_ANY, -1, -1
5910 Xwind_stop, TRUE, FALSE,
5911 EL_BALLOON_SWITCH_NONE, -1, -1
5915 EL_EM_EXIT_CLOSED, -1, -1
5918 Xexit_1, TRUE, FALSE,
5919 EL_EM_EXIT_OPEN, -1, -1
5922 Xexit_2, FALSE, FALSE,
5923 EL_EM_EXIT_OPEN, -1, -1
5926 Xexit_3, FALSE, FALSE,
5927 EL_EM_EXIT_OPEN, -1, -1
5930 Xdynamite, TRUE, FALSE,
5931 EL_EM_DYNAMITE, -1, -1
5934 Ydynamite_eat, FALSE, FALSE,
5935 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
5938 Xdynamite_1, TRUE, FALSE,
5939 EL_EM_DYNAMITE_ACTIVE, -1, -1
5942 Xdynamite_2, FALSE, FALSE,
5943 EL_EM_DYNAMITE_ACTIVE, -1, -1
5946 Xdynamite_3, FALSE, FALSE,
5947 EL_EM_DYNAMITE_ACTIVE, -1, -1
5950 Xdynamite_4, FALSE, FALSE,
5951 EL_EM_DYNAMITE_ACTIVE, -1, -1
5954 Xbumper, TRUE, FALSE,
5955 EL_EMC_SPRING_BUMPER, -1, -1
5958 XbumperB, FALSE, FALSE,
5959 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
5962 Xwheel, TRUE, FALSE,
5963 EL_ROBOT_WHEEL, -1, -1
5966 XwheelB, FALSE, FALSE,
5967 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
5970 Xswitch, TRUE, FALSE,
5971 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
5974 XswitchB, FALSE, FALSE,
5975 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
5979 EL_QUICKSAND_EMPTY, -1, -1
5982 Xsand_stone, TRUE, FALSE,
5983 EL_QUICKSAND_FULL, -1, -1
5986 Xsand_stonein_1, FALSE, TRUE,
5987 EL_ROCK, ACTION_FILLING, -1
5990 Xsand_stonein_2, FALSE, TRUE,
5991 EL_ROCK, ACTION_FILLING, -1
5994 Xsand_stonein_3, FALSE, TRUE,
5995 EL_ROCK, ACTION_FILLING, -1
5998 Xsand_stonein_4, FALSE, TRUE,
5999 EL_ROCK, ACTION_FILLING, -1
6002 Xsand_stonesand_1, FALSE, FALSE,
6003 EL_QUICKSAND_EMPTYING, -1, -1
6006 Xsand_stonesand_2, FALSE, FALSE,
6007 EL_QUICKSAND_EMPTYING, -1, -1
6010 Xsand_stonesand_3, FALSE, FALSE,
6011 EL_QUICKSAND_EMPTYING, -1, -1
6014 Xsand_stonesand_4, FALSE, FALSE,
6015 EL_QUICKSAND_EMPTYING, -1, -1
6018 Xsand_stonesand_quickout_1, FALSE, FALSE,
6019 EL_QUICKSAND_EMPTYING, -1, -1
6022 Xsand_stonesand_quickout_2, FALSE, FALSE,
6023 EL_QUICKSAND_EMPTYING, -1, -1
6026 Xsand_stoneout_1, FALSE, FALSE,
6027 EL_ROCK, ACTION_EMPTYING, -1
6030 Xsand_stoneout_2, FALSE, FALSE,
6031 EL_ROCK, ACTION_EMPTYING, -1
6034 Xsand_sandstone_1, FALSE, FALSE,
6035 EL_QUICKSAND_FILLING, -1, -1
6038 Xsand_sandstone_2, FALSE, FALSE,
6039 EL_QUICKSAND_FILLING, -1, -1
6042 Xsand_sandstone_3, FALSE, FALSE,
6043 EL_QUICKSAND_FILLING, -1, -1
6046 Xsand_sandstone_4, FALSE, FALSE,
6047 EL_QUICKSAND_FILLING, -1, -1
6050 Xplant, TRUE, FALSE,
6051 EL_EMC_PLANT, -1, -1
6054 Yplant, FALSE, FALSE,
6055 EL_EMC_PLANT, -1, -1
6058 Xlenses, TRUE, FALSE,
6059 EL_EMC_LENSES, -1, -1
6062 Xmagnify, TRUE, FALSE,
6063 EL_EMC_MAGNIFIER, -1, -1
6066 Xdripper, TRUE, FALSE,
6067 EL_EMC_DRIPPER, -1, -1
6070 XdripperB, FALSE, FALSE,
6071 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
6074 Xfake_blank, TRUE, FALSE,
6075 EL_INVISIBLE_WALL, -1, -1
6078 Xfake_blankB, FALSE, FALSE,
6079 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
6082 Xfake_grass, TRUE, FALSE,
6083 EL_EMC_FAKE_GRASS, -1, -1
6086 Xfake_grassB, FALSE, FALSE,
6087 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
6090 Xfake_door_1, TRUE, FALSE,
6091 EL_EM_GATE_1_GRAY, -1, -1
6094 Xfake_door_2, TRUE, FALSE,
6095 EL_EM_GATE_2_GRAY, -1, -1
6098 Xfake_door_3, TRUE, FALSE,
6099 EL_EM_GATE_3_GRAY, -1, -1
6102 Xfake_door_4, TRUE, FALSE,
6103 EL_EM_GATE_4_GRAY, -1, -1
6106 Xfake_door_5, TRUE, FALSE,
6107 EL_EMC_GATE_5_GRAY, -1, -1
6110 Xfake_door_6, TRUE, FALSE,
6111 EL_EMC_GATE_6_GRAY, -1, -1
6114 Xfake_door_7, TRUE, FALSE,
6115 EL_EMC_GATE_7_GRAY, -1, -1
6118 Xfake_door_8, TRUE, FALSE,
6119 EL_EMC_GATE_8_GRAY, -1, -1
6122 Xfake_acid_1, TRUE, FALSE,
6123 EL_EMC_FAKE_ACID, -1, -1
6126 Xfake_acid_2, FALSE, FALSE,
6127 EL_EMC_FAKE_ACID, -1, -1
6130 Xfake_acid_3, FALSE, FALSE,
6131 EL_EMC_FAKE_ACID, -1, -1
6134 Xfake_acid_4, FALSE, FALSE,
6135 EL_EMC_FAKE_ACID, -1, -1
6138 Xfake_acid_5, FALSE, FALSE,
6139 EL_EMC_FAKE_ACID, -1, -1
6142 Xfake_acid_6, FALSE, FALSE,
6143 EL_EMC_FAKE_ACID, -1, -1
6146 Xfake_acid_7, FALSE, FALSE,
6147 EL_EMC_FAKE_ACID, -1, -1
6150 Xfake_acid_8, FALSE, FALSE,
6151 EL_EMC_FAKE_ACID, -1, -1
6154 Xsteel_1, TRUE, FALSE,
6155 EL_STEELWALL, -1, -1
6158 Xsteel_2, TRUE, FALSE,
6159 EL_EMC_STEELWALL_2, -1, -1
6162 Xsteel_3, TRUE, FALSE,
6163 EL_EMC_STEELWALL_3, -1, -1
6166 Xsteel_4, TRUE, FALSE,
6167 EL_EMC_STEELWALL_4, -1, -1
6170 Xwall_1, TRUE, FALSE,
6174 Xwall_2, TRUE, FALSE,
6175 EL_EMC_WALL_14, -1, -1
6178 Xwall_3, TRUE, FALSE,
6179 EL_EMC_WALL_15, -1, -1
6182 Xwall_4, TRUE, FALSE,
6183 EL_EMC_WALL_16, -1, -1
6186 Xround_wall_1, TRUE, FALSE,
6187 EL_WALL_SLIPPERY, -1, -1
6190 Xround_wall_2, TRUE, FALSE,
6191 EL_EMC_WALL_SLIPPERY_2, -1, -1
6194 Xround_wall_3, TRUE, FALSE,
6195 EL_EMC_WALL_SLIPPERY_3, -1, -1
6198 Xround_wall_4, TRUE, FALSE,
6199 EL_EMC_WALL_SLIPPERY_4, -1, -1
6202 Xdecor_1, TRUE, FALSE,
6203 EL_EMC_WALL_8, -1, -1
6206 Xdecor_2, TRUE, FALSE,
6207 EL_EMC_WALL_6, -1, -1
6210 Xdecor_3, TRUE, FALSE,
6211 EL_EMC_WALL_4, -1, -1
6214 Xdecor_4, TRUE, FALSE,
6215 EL_EMC_WALL_7, -1, -1
6218 Xdecor_5, TRUE, FALSE,
6219 EL_EMC_WALL_5, -1, -1
6222 Xdecor_6, TRUE, FALSE,
6223 EL_EMC_WALL_9, -1, -1
6226 Xdecor_7, TRUE, FALSE,
6227 EL_EMC_WALL_10, -1, -1
6230 Xdecor_8, TRUE, FALSE,
6231 EL_EMC_WALL_1, -1, -1
6234 Xdecor_9, TRUE, FALSE,
6235 EL_EMC_WALL_2, -1, -1
6238 Xdecor_10, TRUE, FALSE,
6239 EL_EMC_WALL_3, -1, -1
6242 Xdecor_11, TRUE, FALSE,
6243 EL_EMC_WALL_11, -1, -1
6246 Xdecor_12, TRUE, FALSE,
6247 EL_EMC_WALL_12, -1, -1
6250 Xalpha_0, TRUE, FALSE,
6251 EL_CHAR('0'), -1, -1
6254 Xalpha_1, TRUE, FALSE,
6255 EL_CHAR('1'), -1, -1
6258 Xalpha_2, TRUE, FALSE,
6259 EL_CHAR('2'), -1, -1
6262 Xalpha_3, TRUE, FALSE,
6263 EL_CHAR('3'), -1, -1
6266 Xalpha_4, TRUE, FALSE,
6267 EL_CHAR('4'), -1, -1
6270 Xalpha_5, TRUE, FALSE,
6271 EL_CHAR('5'), -1, -1
6274 Xalpha_6, TRUE, FALSE,
6275 EL_CHAR('6'), -1, -1
6278 Xalpha_7, TRUE, FALSE,
6279 EL_CHAR('7'), -1, -1
6282 Xalpha_8, TRUE, FALSE,
6283 EL_CHAR('8'), -1, -1
6286 Xalpha_9, TRUE, FALSE,
6287 EL_CHAR('9'), -1, -1
6290 Xalpha_excla, TRUE, FALSE,
6291 EL_CHAR('!'), -1, -1
6294 Xalpha_quote, TRUE, FALSE,
6295 EL_CHAR('"'), -1, -1
6298 Xalpha_comma, TRUE, FALSE,
6299 EL_CHAR(','), -1, -1
6302 Xalpha_minus, TRUE, FALSE,
6303 EL_CHAR('-'), -1, -1
6306 Xalpha_perio, TRUE, FALSE,
6307 EL_CHAR('.'), -1, -1
6310 Xalpha_colon, TRUE, FALSE,
6311 EL_CHAR(':'), -1, -1
6314 Xalpha_quest, TRUE, FALSE,
6315 EL_CHAR('?'), -1, -1
6318 Xalpha_a, TRUE, FALSE,
6319 EL_CHAR('A'), -1, -1
6322 Xalpha_b, TRUE, FALSE,
6323 EL_CHAR('B'), -1, -1
6326 Xalpha_c, TRUE, FALSE,
6327 EL_CHAR('C'), -1, -1
6330 Xalpha_d, TRUE, FALSE,
6331 EL_CHAR('D'), -1, -1
6334 Xalpha_e, TRUE, FALSE,
6335 EL_CHAR('E'), -1, -1
6338 Xalpha_f, TRUE, FALSE,
6339 EL_CHAR('F'), -1, -1
6342 Xalpha_g, TRUE, FALSE,
6343 EL_CHAR('G'), -1, -1
6346 Xalpha_h, TRUE, FALSE,
6347 EL_CHAR('H'), -1, -1
6350 Xalpha_i, TRUE, FALSE,
6351 EL_CHAR('I'), -1, -1
6354 Xalpha_j, TRUE, FALSE,
6355 EL_CHAR('J'), -1, -1
6358 Xalpha_k, TRUE, FALSE,
6359 EL_CHAR('K'), -1, -1
6362 Xalpha_l, TRUE, FALSE,
6363 EL_CHAR('L'), -1, -1
6366 Xalpha_m, TRUE, FALSE,
6367 EL_CHAR('M'), -1, -1
6370 Xalpha_n, TRUE, FALSE,
6371 EL_CHAR('N'), -1, -1
6374 Xalpha_o, TRUE, FALSE,
6375 EL_CHAR('O'), -1, -1
6378 Xalpha_p, TRUE, FALSE,
6379 EL_CHAR('P'), -1, -1
6382 Xalpha_q, TRUE, FALSE,
6383 EL_CHAR('Q'), -1, -1
6386 Xalpha_r, TRUE, FALSE,
6387 EL_CHAR('R'), -1, -1
6390 Xalpha_s, TRUE, FALSE,
6391 EL_CHAR('S'), -1, -1
6394 Xalpha_t, TRUE, FALSE,
6395 EL_CHAR('T'), -1, -1
6398 Xalpha_u, TRUE, FALSE,
6399 EL_CHAR('U'), -1, -1
6402 Xalpha_v, TRUE, FALSE,
6403 EL_CHAR('V'), -1, -1
6406 Xalpha_w, TRUE, FALSE,
6407 EL_CHAR('W'), -1, -1
6410 Xalpha_x, TRUE, FALSE,
6411 EL_CHAR('X'), -1, -1
6414 Xalpha_y, TRUE, FALSE,
6415 EL_CHAR('Y'), -1, -1
6418 Xalpha_z, TRUE, FALSE,
6419 EL_CHAR('Z'), -1, -1
6422 Xalpha_arrow_e, TRUE, FALSE,
6423 EL_CHAR('>'), -1, -1
6426 Xalpha_arrow_w, TRUE, FALSE,
6427 EL_CHAR('<'), -1, -1
6430 Xalpha_copyr, TRUE, FALSE,
6431 EL_CHAR(CHAR_BYTE_COPYRIGHT), -1, -1
6435 Xboom_bug, FALSE, FALSE,
6436 EL_BUG, ACTION_EXPLODING, -1
6439 Xboom_bomb, FALSE, FALSE,
6440 EL_BOMB, ACTION_EXPLODING, -1
6443 Xboom_android, FALSE, FALSE,
6444 EL_EMC_ANDROID, ACTION_OTHER, -1
6447 Xboom_1, FALSE, FALSE,
6448 EL_DEFAULT, ACTION_EXPLODING, -1
6451 Xboom_2, FALSE, FALSE,
6452 EL_DEFAULT, ACTION_EXPLODING, -1
6455 Znormal, FALSE, FALSE,
6459 Zdynamite, FALSE, FALSE,
6463 Zplayer, FALSE, FALSE,
6467 ZBORDER, FALSE, FALSE,
6477 static struct Mapping_EM_to_RND_player
6486 em_player_mapping_list[] =
6490 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
6494 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
6498 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
6502 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
6506 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
6510 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
6514 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
6518 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
6522 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
6526 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
6530 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
6534 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
6538 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
6542 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
6546 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
6550 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
6554 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
6558 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
6562 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
6566 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
6570 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
6574 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
6578 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
6582 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
6586 EL_PLAYER_1, ACTION_DEFAULT, -1,
6590 EL_PLAYER_2, ACTION_DEFAULT, -1,
6594 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
6598 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
6602 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
6606 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
6610 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
6614 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
6618 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
6622 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
6626 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
6630 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
6634 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
6638 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
6642 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
6646 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
6650 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
6654 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
6658 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
6662 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
6666 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
6670 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
6674 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
6678 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
6682 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
6686 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
6690 EL_PLAYER_3, ACTION_DEFAULT, -1,
6694 EL_PLAYER_4, ACTION_DEFAULT, -1,
6703 int map_element_RND_to_EM(int element_rnd)
6705 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
6706 static boolean mapping_initialized = FALSE;
6708 if (!mapping_initialized)
6712 /* return "Xalpha_quest" for all undefined elements in mapping array */
6713 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
6714 mapping_RND_to_EM[i] = Xalpha_quest;
6716 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6717 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
6718 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
6719 em_object_mapping_list[i].element_em;
6721 mapping_initialized = TRUE;
6724 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
6725 return mapping_RND_to_EM[element_rnd];
6727 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
6732 int map_element_EM_to_RND(int element_em)
6734 static unsigned short mapping_EM_to_RND[TILE_MAX];
6735 static boolean mapping_initialized = FALSE;
6737 if (!mapping_initialized)
6741 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
6742 for (i = 0; i < TILE_MAX; i++)
6743 mapping_EM_to_RND[i] = EL_UNKNOWN;
6745 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6746 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
6747 em_object_mapping_list[i].element_rnd;
6749 mapping_initialized = TRUE;
6752 if (element_em >= 0 && element_em < TILE_MAX)
6753 return mapping_EM_to_RND[element_em];
6755 Error(ERR_WARN, "invalid EM level element %d", element_em);
6760 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
6762 struct LevelInfo_EM *level_em = level->native_em_level;
6763 struct LEVEL *lev = level_em->lev;
6766 for (i = 0; i < TILE_MAX; i++)
6767 lev->android_array[i] = Xblank;
6769 for (i = 0; i < level->num_android_clone_elements; i++)
6771 int element_rnd = level->android_clone_element[i];
6772 int element_em = map_element_RND_to_EM(element_rnd);
6774 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
6775 if (em_object_mapping_list[j].element_rnd == element_rnd)
6776 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
6780 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
6782 struct LevelInfo_EM *level_em = level->native_em_level;
6783 struct LEVEL *lev = level_em->lev;
6786 level->num_android_clone_elements = 0;
6788 for (i = 0; i < TILE_MAX; i++)
6790 int element_em = lev->android_array[i];
6792 boolean element_found = FALSE;
6794 if (element_em == Xblank)
6797 element_rnd = map_element_EM_to_RND(element_em);
6799 for (j = 0; j < level->num_android_clone_elements; j++)
6800 if (level->android_clone_element[j] == element_rnd)
6801 element_found = TRUE;
6805 level->android_clone_element[level->num_android_clone_elements++] =
6808 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
6813 if (level->num_android_clone_elements == 0)
6815 level->num_android_clone_elements = 1;
6816 level->android_clone_element[0] = EL_EMPTY;
6820 int map_direction_RND_to_EM(int direction)
6822 return (direction == MV_UP ? 0 :
6823 direction == MV_RIGHT ? 1 :
6824 direction == MV_DOWN ? 2 :
6825 direction == MV_LEFT ? 3 :
6829 int map_direction_EM_to_RND(int direction)
6831 return (direction == 0 ? MV_UP :
6832 direction == 1 ? MV_RIGHT :
6833 direction == 2 ? MV_DOWN :
6834 direction == 3 ? MV_LEFT :
6838 int map_element_RND_to_SP(int element_rnd)
6840 int element_sp = 0x20; /* map unknown elements to yellow "hardware" */
6842 if (element_rnd >= EL_SP_START &&
6843 element_rnd <= EL_SP_END)
6844 element_sp = element_rnd - EL_SP_START;
6845 else if (element_rnd == EL_EMPTY_SPACE)
6847 else if (element_rnd == EL_INVISIBLE_WALL)
6853 int map_element_SP_to_RND(int element_sp)
6855 int element_rnd = EL_UNKNOWN;
6857 if (element_sp >= 0x00 &&
6859 element_rnd = EL_SP_START + element_sp;
6860 else if (element_sp == 0x28)
6861 element_rnd = EL_INVISIBLE_WALL;
6866 int map_action_SP_to_RND(int action_sp)
6870 case actActive: return ACTION_ACTIVE;
6871 case actImpact: return ACTION_IMPACT;
6872 case actExploding: return ACTION_EXPLODING;
6873 case actDigging: return ACTION_DIGGING;
6874 case actSnapping: return ACTION_SNAPPING;
6875 case actCollecting: return ACTION_COLLECTING;
6876 case actPassing: return ACTION_PASSING;
6877 case actPushing: return ACTION_PUSHING;
6878 case actDropping: return ACTION_DROPPING;
6880 default: return ACTION_DEFAULT;
6884 int get_next_element(int element)
6888 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
6889 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
6890 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
6891 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
6892 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
6893 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
6894 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
6895 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
6896 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
6897 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
6898 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
6900 default: return element;
6904 int el_act_dir2img(int element, int action, int direction)
6906 element = GFX_ELEMENT(element);
6907 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
6909 /* direction_graphic[][] == graphic[] for undefined direction graphics */
6910 return element_info[element].direction_graphic[action][direction];
6913 static int el_act_dir2crm(int element, int action, int direction)
6915 element = GFX_ELEMENT(element);
6916 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
6918 /* direction_graphic[][] == graphic[] for undefined direction graphics */
6919 return element_info[element].direction_crumbled[action][direction];
6922 int el_act2img(int element, int action)
6924 element = GFX_ELEMENT(element);
6926 return element_info[element].graphic[action];
6929 int el_act2crm(int element, int action)
6931 element = GFX_ELEMENT(element);
6933 return element_info[element].crumbled[action];
6936 int el_dir2img(int element, int direction)
6938 element = GFX_ELEMENT(element);
6940 return el_act_dir2img(element, ACTION_DEFAULT, direction);
6943 int el2baseimg(int element)
6945 return element_info[element].graphic[ACTION_DEFAULT];
6948 int el2img(int element)
6950 element = GFX_ELEMENT(element);
6952 return element_info[element].graphic[ACTION_DEFAULT];
6955 int el2edimg(int element)
6957 element = GFX_ELEMENT(element);
6959 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
6962 int el2preimg(int element)
6964 element = GFX_ELEMENT(element);
6966 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
6969 int el2panelimg(int element)
6971 element = GFX_ELEMENT(element);
6973 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL];
6976 int font2baseimg(int font_nr)
6978 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
6981 int getBeltNrFromBeltElement(int element)
6983 return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
6984 element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
6985 element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
6988 int getBeltNrFromBeltActiveElement(int element)
6990 return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
6991 element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
6992 element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
6995 int getBeltNrFromBeltSwitchElement(int element)
6997 return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
6998 element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
6999 element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
7002 int getBeltDirNrFromBeltElement(int element)
7004 static int belt_base_element[4] =
7006 EL_CONVEYOR_BELT_1_LEFT,
7007 EL_CONVEYOR_BELT_2_LEFT,
7008 EL_CONVEYOR_BELT_3_LEFT,
7009 EL_CONVEYOR_BELT_4_LEFT
7012 int belt_nr = getBeltNrFromBeltElement(element);
7013 int belt_dir_nr = element - belt_base_element[belt_nr];
7015 return (belt_dir_nr % 3);
7018 int getBeltDirNrFromBeltSwitchElement(int element)
7020 static int belt_base_element[4] =
7022 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
7023 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
7024 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
7025 EL_CONVEYOR_BELT_4_SWITCH_LEFT
7028 int belt_nr = getBeltNrFromBeltSwitchElement(element);
7029 int belt_dir_nr = element - belt_base_element[belt_nr];
7031 return (belt_dir_nr % 3);
7034 int getBeltDirFromBeltElement(int element)
7036 static int belt_move_dir[3] =
7043 int belt_dir_nr = getBeltDirNrFromBeltElement(element);
7045 return belt_move_dir[belt_dir_nr];
7048 int getBeltDirFromBeltSwitchElement(int element)
7050 static int belt_move_dir[3] =
7057 int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
7059 return belt_move_dir[belt_dir_nr];
7062 int getBeltElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
7064 static int belt_base_element[4] =
7066 EL_CONVEYOR_BELT_1_LEFT,
7067 EL_CONVEYOR_BELT_2_LEFT,
7068 EL_CONVEYOR_BELT_3_LEFT,
7069 EL_CONVEYOR_BELT_4_LEFT
7072 return belt_base_element[belt_nr] + belt_dir_nr;
7075 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
7077 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
7079 return getBeltElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
7082 int getBeltSwitchElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
7084 static int belt_base_element[4] =
7086 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
7087 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
7088 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
7089 EL_CONVEYOR_BELT_4_SWITCH_LEFT
7092 return belt_base_element[belt_nr] + belt_dir_nr;
7095 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
7097 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
7099 return getBeltSwitchElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
7102 boolean getTeamMode_EM()
7104 return game.team_mode;
7107 int getGameFrameDelay_EM(int native_em_game_frame_delay)
7109 int game_frame_delay_value;
7111 game_frame_delay_value =
7112 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
7113 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
7116 if (tape.playing && tape.warp_forward && !tape.pausing)
7117 game_frame_delay_value = 0;
7119 return game_frame_delay_value;
7122 unsigned int InitRND(int seed)
7124 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
7125 return InitEngineRandom_EM(seed);
7126 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
7127 return InitEngineRandom_SP(seed);
7129 return InitEngineRandom_RND(seed);
7132 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
7133 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
7135 inline static int get_effective_element_EM(int tile, int frame_em)
7137 int element = object_mapping[tile].element_rnd;
7138 int action = object_mapping[tile].action;
7139 boolean is_backside = object_mapping[tile].is_backside;
7140 boolean action_removing = (action == ACTION_DIGGING ||
7141 action == ACTION_SNAPPING ||
7142 action == ACTION_COLLECTING);
7148 case Yacid_splash_eB:
7149 case Yacid_splash_wB:
7150 return (frame_em > 5 ? EL_EMPTY : element);
7156 else /* frame_em == 7 */
7160 case Yacid_splash_eB:
7161 case Yacid_splash_wB:
7164 case Yemerald_stone:
7167 case Ydiamond_stone:
7171 case Xdrip_stretchB:
7190 case Xsand_stonein_1:
7191 case Xsand_stonein_2:
7192 case Xsand_stonein_3:
7193 case Xsand_stonein_4:
7197 return (is_backside || action_removing ? EL_EMPTY : element);
7202 inline static boolean check_linear_animation_EM(int tile)
7206 case Xsand_stonesand_1:
7207 case Xsand_stonesand_quickout_1:
7208 case Xsand_sandstone_1:
7209 case Xsand_stonein_1:
7210 case Xsand_stoneout_1:
7229 case Yacid_splash_eB:
7230 case Yacid_splash_wB:
7231 case Yemerald_stone:
7238 inline static void set_crumbled_graphics_EM(struct GraphicInfo_EM *g_em,
7239 boolean has_crumbled_graphics,
7240 int crumbled, int sync_frame)
7242 /* if element can be crumbled, but certain action graphics are just empty
7243 space (like instantly snapping sand to empty space in 1 frame), do not
7244 treat these empty space graphics as crumbled graphics in EMC engine */
7245 if (crumbled == IMG_EMPTY_SPACE)
7246 has_crumbled_graphics = FALSE;
7248 if (has_crumbled_graphics)
7250 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
7251 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
7252 g_crumbled->anim_delay,
7253 g_crumbled->anim_mode,
7254 g_crumbled->anim_start_frame,
7257 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
7258 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
7260 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
7262 g_em->has_crumbled_graphics = TRUE;
7266 g_em->crumbled_bitmap = NULL;
7267 g_em->crumbled_src_x = 0;
7268 g_em->crumbled_src_y = 0;
7269 g_em->crumbled_border_size = 0;
7271 g_em->has_crumbled_graphics = FALSE;
7275 void ResetGfxAnimation_EM(int x, int y, int tile)
7280 void SetGfxAnimation_EM(struct GraphicInfo_EM *g_em,
7281 int tile, int frame_em, int x, int y)
7283 int action = object_mapping[tile].action;
7284 int direction = object_mapping[tile].direction;
7285 int effective_element = get_effective_element_EM(tile, frame_em);
7286 int graphic = (direction == MV_NONE ?
7287 el_act2img(effective_element, action) :
7288 el_act_dir2img(effective_element, action, direction));
7289 struct GraphicInfo *g = &graphic_info[graphic];
7291 boolean action_removing = (action == ACTION_DIGGING ||
7292 action == ACTION_SNAPPING ||
7293 action == ACTION_COLLECTING);
7294 boolean action_moving = (action == ACTION_FALLING ||
7295 action == ACTION_MOVING ||
7296 action == ACTION_PUSHING ||
7297 action == ACTION_EATING ||
7298 action == ACTION_FILLING ||
7299 action == ACTION_EMPTYING);
7300 boolean action_falling = (action == ACTION_FALLING ||
7301 action == ACTION_FILLING ||
7302 action == ACTION_EMPTYING);
7304 /* special case: graphic uses "2nd movement tile" and has defined
7305 7 frames for movement animation (or less) => use default graphic
7306 for last (8th) frame which ends the movement animation */
7307 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
7309 action = ACTION_DEFAULT; /* (keep action_* unchanged for now) */
7310 graphic = (direction == MV_NONE ?
7311 el_act2img(effective_element, action) :
7312 el_act_dir2img(effective_element, action, direction));
7314 g = &graphic_info[graphic];
7317 if ((action_removing || check_linear_animation_EM(tile)) && frame_em == 0)
7321 else if (action_moving)
7323 boolean is_backside = object_mapping[tile].is_backside;
7327 int direction = object_mapping[tile].direction;
7328 int move_dir = (action_falling ? MV_DOWN : direction);
7333 /* !!! TEST !!! NEW !!! DOES NOT WORK RIGHT YET !!! */
7334 if (g->double_movement && frame_em == 0)
7338 if (move_dir == MV_LEFT)
7339 GfxFrame[x - 1][y] = GfxFrame[x][y];
7340 else if (move_dir == MV_RIGHT)
7341 GfxFrame[x + 1][y] = GfxFrame[x][y];
7342 else if (move_dir == MV_UP)
7343 GfxFrame[x][y - 1] = GfxFrame[x][y];
7344 else if (move_dir == MV_DOWN)
7345 GfxFrame[x][y + 1] = GfxFrame[x][y];
7352 /* special case: animation for Xsand_stonesand_quickout_1/2 twice as fast */
7353 if (tile == Xsand_stonesand_quickout_1 ||
7354 tile == Xsand_stonesand_quickout_2)
7358 if (graphic_info[graphic].anim_global_sync)
7359 sync_frame = FrameCounter;
7360 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
7361 sync_frame = GfxFrame[x][y];
7363 sync_frame = 0; /* playfield border (pseudo steel) */
7365 SetRandomAnimationValue(x, y);
7367 int frame = getAnimationFrame(g->anim_frames,
7370 g->anim_start_frame,
7373 g_em->unique_identifier =
7374 (graphic << 16) | ((frame % 8) << 12) | (g_em->width << 6) | g_em->height;
7377 void getGraphicSourceObjectExt_EM(struct GraphicInfo_EM *g_em,
7378 int tile, int frame_em, int x, int y)
7380 int action = object_mapping[tile].action;
7381 int direction = object_mapping[tile].direction;
7382 boolean is_backside = object_mapping[tile].is_backside;
7383 int effective_element = get_effective_element_EM(tile, frame_em);
7384 int effective_action = action;
7385 int graphic = (direction == MV_NONE ?
7386 el_act2img(effective_element, effective_action) :
7387 el_act_dir2img(effective_element, effective_action,
7389 int crumbled = (direction == MV_NONE ?
7390 el_act2crm(effective_element, effective_action) :
7391 el_act_dir2crm(effective_element, effective_action,
7393 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7394 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7395 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7396 struct GraphicInfo *g = &graphic_info[graphic];
7399 /* special case: graphic uses "2nd movement tile" and has defined
7400 7 frames for movement animation (or less) => use default graphic
7401 for last (8th) frame which ends the movement animation */
7402 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
7404 effective_action = ACTION_DEFAULT;
7405 graphic = (direction == MV_NONE ?
7406 el_act2img(effective_element, effective_action) :
7407 el_act_dir2img(effective_element, effective_action,
7409 crumbled = (direction == MV_NONE ?
7410 el_act2crm(effective_element, effective_action) :
7411 el_act_dir2crm(effective_element, effective_action,
7414 g = &graphic_info[graphic];
7417 if (graphic_info[graphic].anim_global_sync)
7418 sync_frame = FrameCounter;
7419 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
7420 sync_frame = GfxFrame[x][y];
7422 sync_frame = 0; /* playfield border (pseudo steel) */
7424 SetRandomAnimationValue(x, y);
7426 int frame = getAnimationFrame(g->anim_frames,
7429 g->anim_start_frame,
7432 getGraphicSourceExt(graphic, frame, &g_em->bitmap, &g_em->src_x, &g_em->src_y,
7433 g->double_movement && is_backside);
7435 /* (updating the "crumbled" graphic definitions is probably not really needed,
7436 as animations for crumbled graphics can't be longer than one EMC cycle) */
7437 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
7441 void getGraphicSourcePlayerExt_EM(struct GraphicInfo_EM *g_em,
7442 int player_nr, int anim, int frame_em)
7444 int element = player_mapping[player_nr][anim].element_rnd;
7445 int action = player_mapping[player_nr][anim].action;
7446 int direction = player_mapping[player_nr][anim].direction;
7447 int graphic = (direction == MV_NONE ?
7448 el_act2img(element, action) :
7449 el_act_dir2img(element, action, direction));
7450 struct GraphicInfo *g = &graphic_info[graphic];
7453 InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
7455 stored_player[player_nr].StepFrame = frame_em;
7457 sync_frame = stored_player[player_nr].Frame;
7459 int frame = getAnimationFrame(g->anim_frames,
7462 g->anim_start_frame,
7465 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
7466 &g_em->src_x, &g_em->src_y, FALSE);
7469 void InitGraphicInfo_EM(void)
7474 int num_em_gfx_errors = 0;
7476 if (graphic_info_em_object[0][0].bitmap == NULL)
7478 /* EM graphics not yet initialized in em_open_all() */
7483 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
7486 /* always start with reliable default values */
7487 for (i = 0; i < TILE_MAX; i++)
7489 object_mapping[i].element_rnd = EL_UNKNOWN;
7490 object_mapping[i].is_backside = FALSE;
7491 object_mapping[i].action = ACTION_DEFAULT;
7492 object_mapping[i].direction = MV_NONE;
7495 /* always start with reliable default values */
7496 for (p = 0; p < MAX_PLAYERS; p++)
7498 for (i = 0; i < SPR_MAX; i++)
7500 player_mapping[p][i].element_rnd = EL_UNKNOWN;
7501 player_mapping[p][i].action = ACTION_DEFAULT;
7502 player_mapping[p][i].direction = MV_NONE;
7506 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
7508 int e = em_object_mapping_list[i].element_em;
7510 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
7511 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
7513 if (em_object_mapping_list[i].action != -1)
7514 object_mapping[e].action = em_object_mapping_list[i].action;
7516 if (em_object_mapping_list[i].direction != -1)
7517 object_mapping[e].direction =
7518 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
7521 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
7523 int a = em_player_mapping_list[i].action_em;
7524 int p = em_player_mapping_list[i].player_nr;
7526 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
7528 if (em_player_mapping_list[i].action != -1)
7529 player_mapping[p][a].action = em_player_mapping_list[i].action;
7531 if (em_player_mapping_list[i].direction != -1)
7532 player_mapping[p][a].direction =
7533 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
7536 for (i = 0; i < TILE_MAX; i++)
7538 int element = object_mapping[i].element_rnd;
7539 int action = object_mapping[i].action;
7540 int direction = object_mapping[i].direction;
7541 boolean is_backside = object_mapping[i].is_backside;
7542 boolean action_exploding = ((action == ACTION_EXPLODING ||
7543 action == ACTION_SMASHED_BY_ROCK ||
7544 action == ACTION_SMASHED_BY_SPRING) &&
7545 element != EL_DIAMOND);
7546 boolean action_active = (action == ACTION_ACTIVE);
7547 boolean action_other = (action == ACTION_OTHER);
7549 for (j = 0; j < 8; j++)
7551 int effective_element = get_effective_element_EM(i, j);
7552 int effective_action = (j < 7 ? action :
7553 i == Xdrip_stretch ? action :
7554 i == Xdrip_stretchB ? action :
7555 i == Ydrip_s1 ? action :
7556 i == Ydrip_s1B ? action :
7557 i == Xball_1B ? action :
7558 i == Xball_2 ? action :
7559 i == Xball_2B ? action :
7560 i == Yball_eat ? action :
7561 i == Ykey_1_eat ? action :
7562 i == Ykey_2_eat ? action :
7563 i == Ykey_3_eat ? action :
7564 i == Ykey_4_eat ? action :
7565 i == Ykey_5_eat ? action :
7566 i == Ykey_6_eat ? action :
7567 i == Ykey_7_eat ? action :
7568 i == Ykey_8_eat ? action :
7569 i == Ylenses_eat ? action :
7570 i == Ymagnify_eat ? action :
7571 i == Ygrass_eat ? action :
7572 i == Ydirt_eat ? action :
7573 i == Xsand_stonein_1 ? action :
7574 i == Xsand_stonein_2 ? action :
7575 i == Xsand_stonein_3 ? action :
7576 i == Xsand_stonein_4 ? action :
7577 i == Xsand_stoneout_1 ? action :
7578 i == Xsand_stoneout_2 ? action :
7579 i == Xboom_android ? ACTION_EXPLODING :
7580 action_exploding ? ACTION_EXPLODING :
7581 action_active ? action :
7582 action_other ? action :
7584 int graphic = (el_act_dir2img(effective_element, effective_action,
7586 int crumbled = (el_act_dir2crm(effective_element, effective_action,
7588 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7589 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7590 boolean has_action_graphics = (graphic != base_graphic);
7591 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7592 struct GraphicInfo *g = &graphic_info[graphic];
7593 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7596 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
7597 boolean special_animation = (action != ACTION_DEFAULT &&
7598 g->anim_frames == 3 &&
7599 g->anim_delay == 2 &&
7600 g->anim_mode & ANIM_LINEAR);
7601 int sync_frame = (i == Xdrip_stretch ? 7 :
7602 i == Xdrip_stretchB ? 7 :
7603 i == Ydrip_s2 ? j + 8 :
7604 i == Ydrip_s2B ? j + 8 :
7613 i == Xfake_acid_1 ? 0 :
7614 i == Xfake_acid_2 ? 10 :
7615 i == Xfake_acid_3 ? 20 :
7616 i == Xfake_acid_4 ? 30 :
7617 i == Xfake_acid_5 ? 40 :
7618 i == Xfake_acid_6 ? 50 :
7619 i == Xfake_acid_7 ? 60 :
7620 i == Xfake_acid_8 ? 70 :
7622 i == Xball_2B ? j + 8 :
7623 i == Yball_eat ? j + 1 :
7624 i == Ykey_1_eat ? j + 1 :
7625 i == Ykey_2_eat ? j + 1 :
7626 i == Ykey_3_eat ? j + 1 :
7627 i == Ykey_4_eat ? j + 1 :
7628 i == Ykey_5_eat ? j + 1 :
7629 i == Ykey_6_eat ? j + 1 :
7630 i == Ykey_7_eat ? j + 1 :
7631 i == Ykey_8_eat ? j + 1 :
7632 i == Ylenses_eat ? j + 1 :
7633 i == Ymagnify_eat ? j + 1 :
7634 i == Ygrass_eat ? j + 1 :
7635 i == Ydirt_eat ? j + 1 :
7636 i == Xamoeba_1 ? 0 :
7637 i == Xamoeba_2 ? 1 :
7638 i == Xamoeba_3 ? 2 :
7639 i == Xamoeba_4 ? 3 :
7640 i == Xamoeba_5 ? 0 :
7641 i == Xamoeba_6 ? 1 :
7642 i == Xamoeba_7 ? 2 :
7643 i == Xamoeba_8 ? 3 :
7644 i == Xexit_2 ? j + 8 :
7645 i == Xexit_3 ? j + 16 :
7646 i == Xdynamite_1 ? 0 :
7647 i == Xdynamite_2 ? 8 :
7648 i == Xdynamite_3 ? 16 :
7649 i == Xdynamite_4 ? 24 :
7650 i == Xsand_stonein_1 ? j + 1 :
7651 i == Xsand_stonein_2 ? j + 9 :
7652 i == Xsand_stonein_3 ? j + 17 :
7653 i == Xsand_stonein_4 ? j + 25 :
7654 i == Xsand_stoneout_1 && j == 0 ? 0 :
7655 i == Xsand_stoneout_1 && j == 1 ? 0 :
7656 i == Xsand_stoneout_1 && j == 2 ? 1 :
7657 i == Xsand_stoneout_1 && j == 3 ? 2 :
7658 i == Xsand_stoneout_1 && j == 4 ? 2 :
7659 i == Xsand_stoneout_1 && j == 5 ? 3 :
7660 i == Xsand_stoneout_1 && j == 6 ? 4 :
7661 i == Xsand_stoneout_1 && j == 7 ? 4 :
7662 i == Xsand_stoneout_2 && j == 0 ? 5 :
7663 i == Xsand_stoneout_2 && j == 1 ? 6 :
7664 i == Xsand_stoneout_2 && j == 2 ? 7 :
7665 i == Xsand_stoneout_2 && j == 3 ? 8 :
7666 i == Xsand_stoneout_2 && j == 4 ? 9 :
7667 i == Xsand_stoneout_2 && j == 5 ? 11 :
7668 i == Xsand_stoneout_2 && j == 6 ? 13 :
7669 i == Xsand_stoneout_2 && j == 7 ? 15 :
7670 i == Xboom_bug && j == 1 ? 2 :
7671 i == Xboom_bug && j == 2 ? 2 :
7672 i == Xboom_bug && j == 3 ? 4 :
7673 i == Xboom_bug && j == 4 ? 4 :
7674 i == Xboom_bug && j == 5 ? 2 :
7675 i == Xboom_bug && j == 6 ? 2 :
7676 i == Xboom_bug && j == 7 ? 0 :
7677 i == Xboom_bomb && j == 1 ? 2 :
7678 i == Xboom_bomb && j == 2 ? 2 :
7679 i == Xboom_bomb && j == 3 ? 4 :
7680 i == Xboom_bomb && j == 4 ? 4 :
7681 i == Xboom_bomb && j == 5 ? 2 :
7682 i == Xboom_bomb && j == 6 ? 2 :
7683 i == Xboom_bomb && j == 7 ? 0 :
7684 i == Xboom_android && j == 7 ? 6 :
7685 i == Xboom_1 && j == 1 ? 2 :
7686 i == Xboom_1 && j == 2 ? 2 :
7687 i == Xboom_1 && j == 3 ? 4 :
7688 i == Xboom_1 && j == 4 ? 4 :
7689 i == Xboom_1 && j == 5 ? 6 :
7690 i == Xboom_1 && j == 6 ? 6 :
7691 i == Xboom_1 && j == 7 ? 8 :
7692 i == Xboom_2 && j == 0 ? 8 :
7693 i == Xboom_2 && j == 1 ? 8 :
7694 i == Xboom_2 && j == 2 ? 10 :
7695 i == Xboom_2 && j == 3 ? 10 :
7696 i == Xboom_2 && j == 4 ? 10 :
7697 i == Xboom_2 && j == 5 ? 12 :
7698 i == Xboom_2 && j == 6 ? 12 :
7699 i == Xboom_2 && j == 7 ? 12 :
7700 special_animation && j == 4 ? 3 :
7701 effective_action != action ? 0 :
7705 Bitmap *debug_bitmap = g_em->bitmap;
7706 int debug_src_x = g_em->src_x;
7707 int debug_src_y = g_em->src_y;
7710 int frame = getAnimationFrame(g->anim_frames,
7713 g->anim_start_frame,
7716 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
7717 g->double_movement && is_backside);
7719 g_em->bitmap = src_bitmap;
7720 g_em->src_x = src_x;
7721 g_em->src_y = src_y;
7722 g_em->src_offset_x = 0;
7723 g_em->src_offset_y = 0;
7724 g_em->dst_offset_x = 0;
7725 g_em->dst_offset_y = 0;
7726 g_em->width = TILEX;
7727 g_em->height = TILEY;
7729 g_em->preserve_background = FALSE;
7731 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
7734 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
7735 effective_action == ACTION_MOVING ||
7736 effective_action == ACTION_PUSHING ||
7737 effective_action == ACTION_EATING)) ||
7738 (!has_action_graphics && (effective_action == ACTION_FILLING ||
7739 effective_action == ACTION_EMPTYING)))
7742 (effective_action == ACTION_FALLING ||
7743 effective_action == ACTION_FILLING ||
7744 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
7745 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
7746 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
7747 int num_steps = (i == Ydrip_s1 ? 16 :
7748 i == Ydrip_s1B ? 16 :
7749 i == Ydrip_s2 ? 16 :
7750 i == Ydrip_s2B ? 16 :
7751 i == Xsand_stonein_1 ? 32 :
7752 i == Xsand_stonein_2 ? 32 :
7753 i == Xsand_stonein_3 ? 32 :
7754 i == Xsand_stonein_4 ? 32 :
7755 i == Xsand_stoneout_1 ? 16 :
7756 i == Xsand_stoneout_2 ? 16 : 8);
7757 int cx = ABS(dx) * (TILEX / num_steps);
7758 int cy = ABS(dy) * (TILEY / num_steps);
7759 int step_frame = (i == Ydrip_s2 ? j + 8 :
7760 i == Ydrip_s2B ? j + 8 :
7761 i == Xsand_stonein_2 ? j + 8 :
7762 i == Xsand_stonein_3 ? j + 16 :
7763 i == Xsand_stonein_4 ? j + 24 :
7764 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
7765 int step = (is_backside ? step_frame : num_steps - step_frame);
7767 if (is_backside) /* tile where movement starts */
7769 if (dx < 0 || dy < 0)
7771 g_em->src_offset_x = cx * step;
7772 g_em->src_offset_y = cy * step;
7776 g_em->dst_offset_x = cx * step;
7777 g_em->dst_offset_y = cy * step;
7780 else /* tile where movement ends */
7782 if (dx < 0 || dy < 0)
7784 g_em->dst_offset_x = cx * step;
7785 g_em->dst_offset_y = cy * step;
7789 g_em->src_offset_x = cx * step;
7790 g_em->src_offset_y = cy * step;
7794 g_em->width = TILEX - cx * step;
7795 g_em->height = TILEY - cy * step;
7798 /* create unique graphic identifier to decide if tile must be redrawn */
7799 /* bit 31 - 16 (16 bit): EM style graphic
7800 bit 15 - 12 ( 4 bit): EM style frame
7801 bit 11 - 6 ( 6 bit): graphic width
7802 bit 5 - 0 ( 6 bit): graphic height */
7803 g_em->unique_identifier =
7804 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
7808 /* skip check for EMC elements not contained in original EMC artwork */
7809 if (element == EL_EMC_FAKE_ACID)
7812 if (g_em->bitmap != debug_bitmap ||
7813 g_em->src_x != debug_src_x ||
7814 g_em->src_y != debug_src_y ||
7815 g_em->src_offset_x != 0 ||
7816 g_em->src_offset_y != 0 ||
7817 g_em->dst_offset_x != 0 ||
7818 g_em->dst_offset_y != 0 ||
7819 g_em->width != TILEX ||
7820 g_em->height != TILEY)
7822 static int last_i = -1;
7830 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
7831 i, element, element_info[element].token_name,
7832 element_action_info[effective_action].suffix, direction);
7834 if (element != effective_element)
7835 printf(" [%d ('%s')]",
7837 element_info[effective_element].token_name);
7841 if (g_em->bitmap != debug_bitmap)
7842 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
7843 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
7845 if (g_em->src_x != debug_src_x ||
7846 g_em->src_y != debug_src_y)
7847 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
7848 j, (is_backside ? 'B' : 'F'),
7849 g_em->src_x, g_em->src_y,
7850 g_em->src_x / 32, g_em->src_y / 32,
7851 debug_src_x, debug_src_y,
7852 debug_src_x / 32, debug_src_y / 32);
7854 if (g_em->src_offset_x != 0 ||
7855 g_em->src_offset_y != 0 ||
7856 g_em->dst_offset_x != 0 ||
7857 g_em->dst_offset_y != 0)
7858 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
7860 g_em->src_offset_x, g_em->src_offset_y,
7861 g_em->dst_offset_x, g_em->dst_offset_y);
7863 if (g_em->width != TILEX ||
7864 g_em->height != TILEY)
7865 printf(" %d (%d): size %d,%d should be %d,%d\n",
7867 g_em->width, g_em->height, TILEX, TILEY);
7869 num_em_gfx_errors++;
7876 for (i = 0; i < TILE_MAX; i++)
7878 for (j = 0; j < 8; j++)
7880 int element = object_mapping[i].element_rnd;
7881 int action = object_mapping[i].action;
7882 int direction = object_mapping[i].direction;
7883 boolean is_backside = object_mapping[i].is_backside;
7884 int graphic_action = el_act_dir2img(element, action, direction);
7885 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
7887 if ((action == ACTION_SMASHED_BY_ROCK ||
7888 action == ACTION_SMASHED_BY_SPRING ||
7889 action == ACTION_EATING) &&
7890 graphic_action == graphic_default)
7892 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
7893 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
7894 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
7895 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
7898 /* no separate animation for "smashed by rock" -- use rock instead */
7899 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7900 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
7902 g_em->bitmap = g_xx->bitmap;
7903 g_em->src_x = g_xx->src_x;
7904 g_em->src_y = g_xx->src_y;
7905 g_em->src_offset_x = g_xx->src_offset_x;
7906 g_em->src_offset_y = g_xx->src_offset_y;
7907 g_em->dst_offset_x = g_xx->dst_offset_x;
7908 g_em->dst_offset_y = g_xx->dst_offset_y;
7909 g_em->width = g_xx->width;
7910 g_em->height = g_xx->height;
7911 g_em->unique_identifier = g_xx->unique_identifier;
7914 g_em->preserve_background = TRUE;
7919 for (p = 0; p < MAX_PLAYERS; p++)
7921 for (i = 0; i < SPR_MAX; i++)
7923 int element = player_mapping[p][i].element_rnd;
7924 int action = player_mapping[p][i].action;
7925 int direction = player_mapping[p][i].direction;
7927 for (j = 0; j < 8; j++)
7929 int effective_element = element;
7930 int effective_action = action;
7931 int graphic = (direction == MV_NONE ?
7932 el_act2img(effective_element, effective_action) :
7933 el_act_dir2img(effective_element, effective_action,
7935 struct GraphicInfo *g = &graphic_info[graphic];
7936 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
7942 Bitmap *debug_bitmap = g_em->bitmap;
7943 int debug_src_x = g_em->src_x;
7944 int debug_src_y = g_em->src_y;
7947 int frame = getAnimationFrame(g->anim_frames,
7950 g->anim_start_frame,
7953 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
7955 g_em->bitmap = src_bitmap;
7956 g_em->src_x = src_x;
7957 g_em->src_y = src_y;
7958 g_em->src_offset_x = 0;
7959 g_em->src_offset_y = 0;
7960 g_em->dst_offset_x = 0;
7961 g_em->dst_offset_y = 0;
7962 g_em->width = TILEX;
7963 g_em->height = TILEY;
7967 /* skip check for EMC elements not contained in original EMC artwork */
7968 if (element == EL_PLAYER_3 ||
7969 element == EL_PLAYER_4)
7972 if (g_em->bitmap != debug_bitmap ||
7973 g_em->src_x != debug_src_x ||
7974 g_em->src_y != debug_src_y)
7976 static int last_i = -1;
7984 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
7985 p, i, element, element_info[element].token_name,
7986 element_action_info[effective_action].suffix, direction);
7988 if (element != effective_element)
7989 printf(" [%d ('%s')]",
7991 element_info[effective_element].token_name);
7995 if (g_em->bitmap != debug_bitmap)
7996 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
7997 j, (int)(g_em->bitmap), (int)(debug_bitmap));
7999 if (g_em->src_x != debug_src_x ||
8000 g_em->src_y != debug_src_y)
8001 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
8003 g_em->src_x, g_em->src_y,
8004 g_em->src_x / 32, g_em->src_y / 32,
8005 debug_src_x, debug_src_y,
8006 debug_src_x / 32, debug_src_y / 32);
8008 num_em_gfx_errors++;
8018 printf("::: [%d errors found]\n", num_em_gfx_errors);
8024 void CheckSaveEngineSnapshot_EM(byte action[MAX_PLAYERS], int frame,
8025 boolean any_player_moving,
8026 boolean any_player_snapping,
8027 boolean any_player_dropping)
8029 static boolean player_was_waiting = TRUE;
8031 if (frame == 0 && !any_player_dropping)
8033 if (!player_was_waiting)
8035 if (!SaveEngineSnapshotToList())
8038 player_was_waiting = TRUE;
8041 else if (any_player_moving || any_player_snapping || any_player_dropping)
8043 player_was_waiting = FALSE;
8047 void CheckSaveEngineSnapshot_SP(boolean murphy_is_waiting,
8048 boolean murphy_is_dropping)
8050 static boolean player_was_waiting = TRUE;
8052 if (murphy_is_waiting)
8054 if (!player_was_waiting)
8056 if (!SaveEngineSnapshotToList())
8059 player_was_waiting = TRUE;
8064 player_was_waiting = FALSE;
8068 void CheckSingleStepMode_EM(byte action[MAX_PLAYERS], int frame,
8069 boolean any_player_moving,
8070 boolean any_player_snapping,
8071 boolean any_player_dropping)
8073 if (tape.single_step && tape.recording && !tape.pausing)
8074 if (frame == 0 && !any_player_dropping)
8075 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
8077 CheckSaveEngineSnapshot_EM(action, frame, any_player_moving,
8078 any_player_snapping, any_player_dropping);
8081 void CheckSingleStepMode_SP(boolean murphy_is_waiting,
8082 boolean murphy_is_dropping)
8084 if (tape.single_step && tape.recording && !tape.pausing)
8085 if (murphy_is_waiting)
8086 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
8088 CheckSaveEngineSnapshot_SP(murphy_is_waiting, murphy_is_dropping);
8091 void getGraphicSource_SP(struct GraphicInfo_SP *g_sp,
8092 int graphic, int sync_frame, int x, int y)
8094 int frame = getGraphicAnimationFrame(graphic, sync_frame);
8096 getGraphicSource(graphic, frame, &g_sp->bitmap, &g_sp->src_x, &g_sp->src_y);
8099 boolean isNextAnimationFrame_SP(int graphic, int sync_frame)
8101 return (IS_NEXT_FRAME(sync_frame, graphic));
8104 int getGraphicInfo_Delay(int graphic)
8106 return graphic_info[graphic].anim_delay;
8109 void PlayMenuSoundExt(int sound)
8111 if (sound == SND_UNDEFINED)
8114 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8115 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8118 if (IS_LOOP_SOUND(sound))
8119 PlaySoundLoop(sound);
8124 void PlayMenuSound()
8126 PlayMenuSoundExt(menu.sound[game_status]);
8129 void PlayMenuSoundStereo(int sound, int stereo_position)
8131 if (sound == SND_UNDEFINED)
8134 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8135 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8138 if (IS_LOOP_SOUND(sound))
8139 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
8141 PlaySoundStereo(sound, stereo_position);
8144 void PlayMenuSoundIfLoopExt(int sound)
8146 if (sound == SND_UNDEFINED)
8149 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8150 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8153 if (IS_LOOP_SOUND(sound))
8154 PlaySoundLoop(sound);
8157 void PlayMenuSoundIfLoop()
8159 PlayMenuSoundIfLoopExt(menu.sound[game_status]);
8162 void PlayMenuMusicExt(int music)
8164 if (music == MUS_UNDEFINED)
8167 if (!setup.sound_music)
8173 void PlayMenuMusic()
8175 PlayMenuMusicExt(menu.music[game_status]);
8178 void PlaySoundActivating()
8181 PlaySound(SND_MENU_ITEM_ACTIVATING);
8185 void PlaySoundSelecting()
8188 PlaySound(SND_MENU_ITEM_SELECTING);
8192 void ToggleFullscreenOrChangeWindowScalingIfNeeded()
8194 boolean change_fullscreen = (setup.fullscreen !=
8195 video.fullscreen_enabled);
8196 boolean change_window_scaling_percent = (!video.fullscreen_enabled &&
8197 setup.window_scaling_percent !=
8198 video.window_scaling_percent);
8200 if (change_window_scaling_percent && video.fullscreen_enabled)
8203 if (!change_window_scaling_percent && !video.fullscreen_available)
8206 #if defined(TARGET_SDL2)
8207 if (change_window_scaling_percent)
8209 SDLSetWindowScaling(setup.window_scaling_percent);
8213 else if (change_fullscreen)
8215 SDLSetWindowFullscreen(setup.fullscreen);
8217 /* set setup value according to successfully changed fullscreen mode */
8218 setup.fullscreen = video.fullscreen_enabled;
8224 if (change_fullscreen ||
8225 change_window_scaling_percent)
8227 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
8229 /* save backbuffer content which gets lost when toggling fullscreen mode */
8230 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8232 if (change_window_scaling_percent)
8234 /* keep window mode, but change window scaling */
8235 video.fullscreen_enabled = TRUE; /* force new window scaling */
8238 /* toggle fullscreen */
8239 ChangeVideoModeIfNeeded(setup.fullscreen);
8241 /* set setup value according to successfully changed fullscreen mode */
8242 setup.fullscreen = video.fullscreen_enabled;
8244 /* restore backbuffer content from temporary backbuffer backup bitmap */
8245 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8247 FreeBitmap(tmp_backbuffer);
8249 /* update visible window/screen */
8250 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8254 void JoinRectangles(int *x, int *y, int *width, int *height,
8255 int x2, int y2, int width2, int height2)
8257 // do not join with "off-screen" rectangle
8258 if (x2 == -1 || y2 == -1)
8263 *width = MAX(*width, width2);
8264 *height = MAX(*height, height2);
8267 void SetAnimStatus(int anim_status_new)
8269 if (anim_status_new == GAME_MODE_MAIN)
8270 anim_status_new = GAME_MODE_PSEUDO_MAINONLY;
8272 global.anim_status_next = anim_status_new;
8274 // directly set screen modes that are entered without fading
8275 if ((global.anim_status == GAME_MODE_PSEUDO_MAINONLY &&
8276 global.anim_status_next == GAME_MODE_PSEUDO_TYPENAME) ||
8277 (global.anim_status == GAME_MODE_PSEUDO_TYPENAME &&
8278 global.anim_status_next == GAME_MODE_PSEUDO_MAINONLY))
8279 global.anim_status = global.anim_status_next;
8282 void SetGameStatus(int game_status_new)
8284 game_status = game_status_new;
8286 SetAnimStatus(game_status_new);
8289 void SetFontStatus(int game_status_new)
8291 static int last_game_status = -1;
8293 if (game_status_new != -1)
8295 // set game status for font use after storing last game status
8296 last_game_status = game_status;
8297 game_status = game_status_new;
8301 // reset game status after font use from last stored game status
8302 game_status = last_game_status;
8306 void ResetFontStatus()
8311 void ChangeViewportPropertiesIfNeeded()
8313 int gfx_game_mode = game_status;
8314 int gfx_game_mode2 = (game_status == GAME_MODE_EDITOR ? GAME_MODE_DEFAULT :
8316 struct RectWithBorder *vp_window = &viewport.window[gfx_game_mode];
8317 struct RectWithBorder *vp_playfield = &viewport.playfield[gfx_game_mode];
8318 struct RectWithBorder *vp_door_1 = &viewport.door_1[gfx_game_mode];
8319 struct RectWithBorder *vp_door_2 = &viewport.door_2[gfx_game_mode2];
8320 struct RectWithBorder *vp_door_3 = &viewport.door_2[GAME_MODE_EDITOR];
8321 int new_win_xsize = vp_window->width;
8322 int new_win_ysize = vp_window->height;
8323 int border_size = vp_playfield->border_size;
8324 int new_sx = vp_playfield->x + border_size;
8325 int new_sy = vp_playfield->y + border_size;
8326 int new_sxsize = vp_playfield->width - 2 * border_size;
8327 int new_sysize = vp_playfield->height - 2 * border_size;
8328 int new_real_sx = vp_playfield->x;
8329 int new_real_sy = vp_playfield->y;
8330 int new_full_sxsize = vp_playfield->width;
8331 int new_full_sysize = vp_playfield->height;
8332 int new_dx = vp_door_1->x;
8333 int new_dy = vp_door_1->y;
8334 int new_dxsize = vp_door_1->width;
8335 int new_dysize = vp_door_1->height;
8336 int new_vx = vp_door_2->x;
8337 int new_vy = vp_door_2->y;
8338 int new_vxsize = vp_door_2->width;
8339 int new_vysize = vp_door_2->height;
8340 int new_ex = vp_door_3->x;
8341 int new_ey = vp_door_3->y;
8342 int new_exsize = vp_door_3->width;
8343 int new_eysize = vp_door_3->height;
8344 int new_tilesize_var =
8345 (setup.small_game_graphics ? MINI_TILESIZE : game.tile_size);
8347 int tilesize = (gfx_game_mode == GAME_MODE_PLAYING ? new_tilesize_var :
8348 gfx_game_mode == GAME_MODE_EDITOR ? MINI_TILESIZE : TILESIZE);
8349 int new_scr_fieldx = new_sxsize / tilesize;
8350 int new_scr_fieldy = new_sysize / tilesize;
8351 int new_scr_fieldx_buffers = new_sxsize / new_tilesize_var;
8352 int new_scr_fieldy_buffers = new_sysize / new_tilesize_var;
8353 boolean init_gfx_buffers = FALSE;
8354 boolean init_video_buffer = FALSE;
8355 boolean init_gadgets_and_anims = FALSE;
8356 boolean init_em_graphics = FALSE;
8358 if (new_win_xsize != WIN_XSIZE ||
8359 new_win_ysize != WIN_YSIZE)
8361 WIN_XSIZE = new_win_xsize;
8362 WIN_YSIZE = new_win_ysize;
8364 init_video_buffer = TRUE;
8365 init_gfx_buffers = TRUE;
8366 init_gadgets_and_anims = TRUE;
8368 // printf("::: video: init_video_buffer, init_gfx_buffers\n");
8371 if (new_scr_fieldx != SCR_FIELDX ||
8372 new_scr_fieldy != SCR_FIELDY)
8374 /* this always toggles between MAIN and GAME when using small tile size */
8376 SCR_FIELDX = new_scr_fieldx;
8377 SCR_FIELDY = new_scr_fieldy;
8379 // printf("::: new_scr_fieldx != SCR_FIELDX ...\n");
8390 new_sxsize != SXSIZE ||
8391 new_sysize != SYSIZE ||
8392 new_dxsize != DXSIZE ||
8393 new_dysize != DYSIZE ||
8394 new_vxsize != VXSIZE ||
8395 new_vysize != VYSIZE ||
8396 new_exsize != EXSIZE ||
8397 new_eysize != EYSIZE ||
8398 new_real_sx != REAL_SX ||
8399 new_real_sy != REAL_SY ||
8400 new_full_sxsize != FULL_SXSIZE ||
8401 new_full_sysize != FULL_SYSIZE ||
8402 new_tilesize_var != TILESIZE_VAR
8405 // ------------------------------------------------------------------------
8406 // determine next fading area for changed viewport definitions
8407 // ------------------------------------------------------------------------
8409 // start with current playfield area (default fading area)
8412 FADE_SXSIZE = FULL_SXSIZE;
8413 FADE_SYSIZE = FULL_SYSIZE;
8415 // add new playfield area if position or size has changed
8416 if (new_real_sx != REAL_SX || new_real_sy != REAL_SY ||
8417 new_full_sxsize != FULL_SXSIZE || new_full_sysize != FULL_SYSIZE)
8419 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
8420 new_real_sx, new_real_sy, new_full_sxsize,new_full_sysize);
8423 // add current and new door 1 area if position or size has changed
8424 if (new_dx != DX || new_dy != DY ||
8425 new_dxsize != DXSIZE || new_dysize != DYSIZE)
8427 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
8428 DX, DY, DXSIZE, DYSIZE);
8429 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
8430 new_dx, new_dy, new_dxsize, new_dysize);
8433 // add current and new door 2 area if position or size has changed
8434 if (new_dx != VX || new_dy != VY ||
8435 new_dxsize != VXSIZE || new_dysize != VYSIZE)
8437 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
8438 VX, VY, VXSIZE, VYSIZE);
8439 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
8440 new_vx, new_vy, new_vxsize, new_vysize);
8443 // ------------------------------------------------------------------------
8444 // handle changed tile size
8445 // ------------------------------------------------------------------------
8447 if (new_tilesize_var != TILESIZE_VAR)
8449 // printf("::: new_tilesize_var != TILESIZE_VAR\n");
8451 // changing tile size invalidates scroll values of engine snapshots
8452 FreeEngineSnapshotSingle();
8454 // changing tile size requires update of graphic mapping for EM engine
8455 init_em_graphics = TRUE;
8466 SXSIZE = new_sxsize;
8467 SYSIZE = new_sysize;
8468 DXSIZE = new_dxsize;
8469 DYSIZE = new_dysize;
8470 VXSIZE = new_vxsize;
8471 VYSIZE = new_vysize;
8472 EXSIZE = new_exsize;
8473 EYSIZE = new_eysize;
8474 REAL_SX = new_real_sx;
8475 REAL_SY = new_real_sy;
8476 FULL_SXSIZE = new_full_sxsize;
8477 FULL_SYSIZE = new_full_sysize;
8478 TILESIZE_VAR = new_tilesize_var;
8480 init_gfx_buffers = TRUE;
8481 init_gadgets_and_anims = TRUE;
8483 // printf("::: viewports: init_gfx_buffers\n");
8484 // printf("::: viewports: init_gadgets_and_anims\n");
8487 if (init_gfx_buffers)
8489 // printf("::: init_gfx_buffers\n");
8491 SCR_FIELDX = new_scr_fieldx_buffers;
8492 SCR_FIELDY = new_scr_fieldy_buffers;
8496 SCR_FIELDX = new_scr_fieldx;
8497 SCR_FIELDY = new_scr_fieldy;
8499 SetDrawDeactivationMask(REDRAW_NONE);
8500 SetDrawBackgroundMask(REDRAW_FIELD);
8503 if (init_video_buffer)
8505 // printf("::: init_video_buffer\n");
8507 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
8508 InitImageTextures();
8511 if (init_gadgets_and_anims)
8513 // printf("::: init_gadgets_and_anims\n");
8516 InitGlobalAnimations();
8519 if (init_em_graphics)
8521 InitGraphicInfo_EM();