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 // store new target screen (to use correct masked border for fading)
743 gfx.fade_border_target_status = game_status;
745 // set screen mode for animations to fading
746 global.anim_status = GAME_MODE_PSEUDO_FADING;
748 // store backbuffer with all animations that will be stopped for fading out
749 PrepareFadeBitmap(DRAW_TO_FADE_SOURCE);
752 static void SetScreenStates_AfterFadingOut()
754 global.border_status = game_status;
757 void FadeIn(int fade_mask)
759 SetScreenStates_BeforeFadingIn();
762 DrawMaskedBorder(REDRAW_ALL);
765 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
766 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_IN);
768 FadeExt(fade_mask, FADE_MODE_FADE_IN, FADE_TYPE_FADE_IN);
772 FADE_SXSIZE = FULL_SXSIZE;
773 FADE_SYSIZE = FULL_SYSIZE;
775 SetScreenStates_AfterFadingIn();
778 void FadeOut(int fade_mask)
780 SetScreenStates_BeforeFadingOut();
783 DrawMaskedBorder(REDRAW_ALL);
786 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
787 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_OUT);
789 FadeExt(fade_mask, FADE_MODE_FADE_OUT, FADE_TYPE_FADE_OUT);
791 SetScreenStates_AfterFadingOut();
794 static void FadeSetLeaveNext(struct TitleFadingInfo fading_leave, boolean set)
796 static struct TitleFadingInfo fading_leave_stored;
799 fading_leave_stored = fading_leave;
801 fading = fading_leave_stored;
804 void FadeSetEnterMenu()
806 fading = menu.enter_menu;
808 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
811 void FadeSetLeaveMenu()
813 fading = menu.leave_menu;
815 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
818 void FadeSetEnterScreen()
820 fading = menu.enter_screen[game_status];
822 FadeSetLeaveNext(menu.leave_screen[game_status], TRUE); /* store */
825 void FadeSetNextScreen()
827 fading = menu.next_screen[game_status];
829 // (do not overwrite fade mode set by FadeSetEnterScreen)
830 // FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
833 void FadeSetLeaveScreen()
835 FadeSetLeaveNext(menu.leave_screen[game_status], FALSE); /* recall */
838 void FadeSetFromType(int type)
840 if (type & TYPE_ENTER_SCREEN)
841 FadeSetEnterScreen();
842 else if (type & TYPE_ENTER)
844 else if (type & TYPE_LEAVE)
848 void FadeSetDisabled()
850 static struct TitleFadingInfo fading_none = { FADE_MODE_NONE, -1, -1, -1 };
852 fading = fading_none;
855 void FadeSkipNextFadeIn()
857 FadeExt(0, FADE_MODE_SKIP_FADE_IN, FADE_TYPE_SKIP);
860 void FadeSkipNextFadeOut()
862 FadeExt(0, FADE_MODE_SKIP_FADE_OUT, FADE_TYPE_SKIP);
865 Bitmap *getBitmapFromGraphicOrDefault(int graphic, int default_graphic)
867 boolean redefined = getImageListEntryFromImageID(graphic)->redefined;
869 return (graphic == IMG_UNDEFINED ? NULL :
870 graphic_info[graphic].bitmap != NULL || redefined ?
871 graphic_info[graphic].bitmap :
872 graphic_info[default_graphic].bitmap);
875 Bitmap *getBackgroundBitmap(int graphic)
877 return getBitmapFromGraphicOrDefault(graphic, IMG_BACKGROUND);
880 Bitmap *getGlobalBorderBitmap(int graphic)
882 return getBitmapFromGraphicOrDefault(graphic, IMG_GLOBAL_BORDER);
885 Bitmap *getGlobalBorderBitmapFromStatus(int status)
888 (status == GAME_MODE_MAIN ||
889 status == GAME_MODE_PSEUDO_TYPENAME ? IMG_GLOBAL_BORDER_MAIN :
890 status == GAME_MODE_SCORES ? IMG_GLOBAL_BORDER_SCORES :
891 status == GAME_MODE_EDITOR ? IMG_GLOBAL_BORDER_EDITOR :
892 status == GAME_MODE_PLAYING ? IMG_GLOBAL_BORDER_PLAYING :
895 return getGlobalBorderBitmap(graphic);
898 void SetWindowBackgroundImageIfDefined(int graphic)
900 if (graphic_info[graphic].bitmap)
901 SetWindowBackgroundBitmap(graphic_info[graphic].bitmap);
904 void SetMainBackgroundImageIfDefined(int graphic)
906 if (graphic_info[graphic].bitmap)
907 SetMainBackgroundBitmap(graphic_info[graphic].bitmap);
910 void SetDoorBackgroundImageIfDefined(int graphic)
912 if (graphic_info[graphic].bitmap)
913 SetDoorBackgroundBitmap(graphic_info[graphic].bitmap);
916 void SetWindowBackgroundImage(int graphic)
918 SetWindowBackgroundBitmap(getBackgroundBitmap(graphic));
921 void SetMainBackgroundImage(int graphic)
923 SetMainBackgroundBitmap(getBackgroundBitmap(graphic));
926 void SetDoorBackgroundImage(int graphic)
928 SetDoorBackgroundBitmap(getBackgroundBitmap(graphic));
931 void SetPanelBackground()
933 struct GraphicInfo *gfx = &graphic_info[IMG_BACKGROUND_PANEL];
935 BlitBitmapTiled(gfx->bitmap, bitmap_db_panel, gfx->src_x, gfx->src_y,
936 gfx->width, gfx->height, 0, 0, DXSIZE, DYSIZE);
938 SetDoorBackgroundBitmap(bitmap_db_panel);
941 void DrawBackground(int x, int y, int width, int height)
943 /* "drawto" might still point to playfield buffer here (hall of fame) */
944 ClearRectangleOnBackground(backbuffer, x, y, width, height);
946 if (IN_GFX_FIELD_FULL(x, y))
947 redraw_mask |= REDRAW_FIELD;
948 else if (IN_GFX_DOOR_1(x, y))
949 redraw_mask |= REDRAW_DOOR_1;
950 else if (IN_GFX_DOOR_2(x, y))
951 redraw_mask |= REDRAW_DOOR_2;
952 else if (IN_GFX_DOOR_3(x, y))
953 redraw_mask |= REDRAW_DOOR_3;
956 void DrawBackgroundForFont(int x, int y, int width, int height, int font_nr)
958 struct FontBitmapInfo *font = getFontBitmapInfo(font_nr);
960 if (font->bitmap == NULL)
963 DrawBackground(x, y, width, height);
966 void DrawBackgroundForGraphic(int x, int y, int width, int height, int graphic)
968 struct GraphicInfo *g = &graphic_info[graphic];
970 if (g->bitmap == NULL)
973 DrawBackground(x, y, width, height);
976 static int game_status_last = -1;
977 static Bitmap *global_border_bitmap_last = NULL;
978 static Bitmap *global_border_bitmap = NULL;
979 static int real_sx_last = -1, real_sy_last = -1;
980 static int full_sxsize_last = -1, full_sysize_last = -1;
981 static int dx_last = -1, dy_last = -1;
982 static int dxsize_last = -1, dysize_last = -1;
983 static int vx_last = -1, vy_last = -1;
984 static int vxsize_last = -1, vysize_last = -1;
986 boolean CheckIfGlobalBorderHasChanged()
988 // if game status has not changed, global border has not changed either
989 if (game_status == game_status_last)
992 // determine and store new global border bitmap for current game status
993 global_border_bitmap = getGlobalBorderBitmapFromStatus(game_status);
995 return (global_border_bitmap_last != global_border_bitmap);
998 boolean CheckIfGlobalBorderRedrawIsNeeded()
1000 // if game status has not changed, nothing has to be redrawn
1001 if (game_status == game_status_last)
1004 // redraw if last screen was title screen
1005 if (game_status_last == GAME_MODE_TITLE)
1008 // redraw if global screen border has changed
1009 if (CheckIfGlobalBorderHasChanged())
1012 // redraw if position or size of playfield area has changed
1013 if (real_sx_last != REAL_SX || real_sy_last != REAL_SY ||
1014 full_sxsize_last != FULL_SXSIZE || full_sysize_last != FULL_SYSIZE)
1017 // redraw if position or size of door area has changed
1018 if (dx_last != DX || dy_last != DY ||
1019 dxsize_last != DXSIZE || dysize_last != DYSIZE)
1022 // redraw if position or size of tape area has changed
1023 if (vx_last != VX || vy_last != VY ||
1024 vxsize_last != VXSIZE || vysize_last != VYSIZE)
1030 void RedrawGlobalBorderFromBitmap(Bitmap *bitmap)
1033 BlitBitmap(bitmap, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
1035 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
1038 void RedrawGlobalBorder()
1040 Bitmap *bitmap = getGlobalBorderBitmapFromStatus(game_status);
1042 RedrawGlobalBorderFromBitmap(bitmap);
1044 redraw_mask = REDRAW_ALL;
1047 static void RedrawGlobalBorderIfNeeded()
1049 if (game_status == game_status_last)
1052 // copy current draw buffer to later copy back areas that have not changed
1053 if (game_status_last != GAME_MODE_TITLE)
1054 BlitBitmap(backbuffer, bitmap_db_store_1, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
1056 if (CheckIfGlobalBorderRedrawIsNeeded())
1058 // redraw global screen border (or clear, if defined to be empty)
1059 RedrawGlobalBorderFromBitmap(global_border_bitmap);
1061 // copy previous playfield and door areas, if they are defined on both
1062 // previous and current screen and if they still have the same size
1064 if (real_sx_last != -1 && real_sy_last != -1 &&
1065 REAL_SX != -1 && REAL_SY != -1 &&
1066 full_sxsize_last == FULL_SXSIZE && full_sysize_last == FULL_SYSIZE)
1067 BlitBitmap(bitmap_db_store_1, backbuffer,
1068 real_sx_last, real_sy_last, FULL_SXSIZE, FULL_SYSIZE,
1071 if (dx_last != -1 && dy_last != -1 &&
1072 DX != -1 && DY != -1 &&
1073 dxsize_last == DXSIZE && dysize_last == DYSIZE)
1074 BlitBitmap(bitmap_db_store_1, backbuffer,
1075 dx_last, dy_last, DXSIZE, DYSIZE, DX, DY);
1077 if (vx_last != -1 && vy_last != -1 &&
1078 VX != -1 && VY != -1 &&
1079 vxsize_last == VXSIZE && vysize_last == VYSIZE)
1080 BlitBitmap(bitmap_db_store_1, backbuffer,
1081 vx_last, vy_last, VXSIZE, VYSIZE, VX, VY);
1083 redraw_mask = REDRAW_ALL;
1086 game_status_last = game_status;
1088 global_border_bitmap_last = global_border_bitmap;
1090 real_sx_last = REAL_SX;
1091 real_sy_last = REAL_SY;
1092 full_sxsize_last = FULL_SXSIZE;
1093 full_sysize_last = FULL_SYSIZE;
1096 dxsize_last = DXSIZE;
1097 dysize_last = DYSIZE;
1100 vxsize_last = VXSIZE;
1101 vysize_last = VYSIZE;
1106 RedrawGlobalBorderIfNeeded();
1108 /* !!! "drawto" might still point to playfield buffer here (see above) !!! */
1109 /* (when entering hall of fame after playing) */
1110 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
1112 /* !!! maybe this should be done before clearing the background !!! */
1113 if (game_status == GAME_MODE_PLAYING)
1115 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
1116 SetDrawtoField(DRAW_TO_FIELDBUFFER);
1120 SetDrawtoField(DRAW_TO_BACKBUFFER);
1124 void MarkTileDirty(int x, int y)
1126 redraw_mask |= REDRAW_FIELD;
1129 void SetBorderElement()
1133 BorderElement = EL_EMPTY;
1135 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
1137 for (x = 0; x < lev_fieldx; x++)
1139 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
1140 BorderElement = EL_STEELWALL;
1142 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
1148 void FloodFillLevel(int from_x, int from_y, int fill_element,
1149 short field[MAX_LEV_FIELDX][MAX_LEV_FIELDY],
1150 int max_fieldx, int max_fieldy)
1154 static int check[4][2] = { { -1, 0 }, { 0, -1 }, { 1, 0 }, { 0, 1 } };
1155 static int safety = 0;
1157 /* check if starting field still has the desired content */
1158 if (field[from_x][from_y] == fill_element)
1163 if (safety > max_fieldx * max_fieldy)
1164 Error(ERR_EXIT, "Something went wrong in 'FloodFill()'. Please debug.");
1166 old_element = field[from_x][from_y];
1167 field[from_x][from_y] = fill_element;
1169 for (i = 0; i < 4; i++)
1171 x = from_x + check[i][0];
1172 y = from_y + check[i][1];
1174 if (IN_FIELD(x, y, max_fieldx, max_fieldy) && field[x][y] == old_element)
1175 FloodFillLevel(x, y, fill_element, field, max_fieldx, max_fieldy);
1181 void SetRandomAnimationValue(int x, int y)
1183 gfx.anim_random_frame = GfxRandom[x][y];
1186 int getGraphicAnimationFrame(int graphic, int sync_frame)
1188 /* animation synchronized with global frame counter, not move position */
1189 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
1190 sync_frame = FrameCounter;
1192 return getAnimationFrame(graphic_info[graphic].anim_frames,
1193 graphic_info[graphic].anim_delay,
1194 graphic_info[graphic].anim_mode,
1195 graphic_info[graphic].anim_start_frame,
1199 void getSizedGraphicSourceExt(int graphic, int frame, int tilesize,
1200 Bitmap **bitmap, int *x, int *y,
1201 boolean get_backside)
1203 struct GraphicInfo *g = &graphic_info[graphic];
1204 Bitmap *src_bitmap = g->bitmap;
1205 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
1206 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
1207 int tilesize_capped = MIN(MAX(1, tilesize), TILESIZE);
1209 // if no in-game graphics defined, always use standard graphic size
1210 if (g->bitmaps[IMG_BITMAP_GAME] == NULL)
1211 tilesize = TILESIZE;
1213 if (tilesize == gfx.standard_tile_size)
1214 src_bitmap = g->bitmaps[IMG_BITMAP_STANDARD];
1215 else if (tilesize == game.tile_size)
1216 src_bitmap = g->bitmaps[IMG_BITMAP_GAME];
1218 src_bitmap = g->bitmaps[IMG_BITMAP_1x1 - log_2(tilesize_capped)];
1220 if (g->offset_y == 0) /* frames are ordered horizontally */
1222 int max_width = g->anim_frames_per_line * g->width;
1223 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
1225 src_x = pos % max_width;
1226 src_y = src_y % g->height + pos / max_width * g->height;
1228 else if (g->offset_x == 0) /* frames are ordered vertically */
1230 int max_height = g->anim_frames_per_line * g->height;
1231 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
1233 src_x = src_x % g->width + pos / max_height * g->width;
1234 src_y = pos % max_height;
1236 else /* frames are ordered diagonally */
1238 src_x = src_x + frame * g->offset_x;
1239 src_y = src_y + frame * g->offset_y;
1242 *bitmap = src_bitmap;
1243 *x = src_x * tilesize / g->tile_size;
1244 *y = src_y * tilesize / g->tile_size;
1247 void getFixedGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1248 int *x, int *y, boolean get_backside)
1250 getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y,
1254 void getSizedGraphicSource(int graphic, int frame, int tilesize,
1255 Bitmap **bitmap, int *x, int *y)
1257 getSizedGraphicSourceExt(graphic, frame, tilesize, bitmap, x, y, FALSE);
1260 void getFixedGraphicSource(int graphic, int frame,
1261 Bitmap **bitmap, int *x, int *y)
1263 getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y, FALSE);
1266 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1268 getSizedGraphicSource(graphic, 0, MINI_TILESIZE, bitmap, x, y);
1271 inline static void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1272 int *x, int *y, boolean get_backside)
1274 struct GraphicInfo *g = &graphic_info[graphic];
1275 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
1276 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
1278 if (TILESIZE_VAR != TILESIZE)
1279 return getSizedGraphicSourceExt(graphic, frame, TILESIZE_VAR, bitmap, x, y,
1282 *bitmap = g->bitmap;
1284 if (g->offset_y == 0) /* frames are ordered horizontally */
1286 int max_width = g->anim_frames_per_line * g->width;
1287 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
1289 *x = pos % max_width;
1290 *y = src_y % g->height + pos / max_width * g->height;
1292 else if (g->offset_x == 0) /* frames are ordered vertically */
1294 int max_height = g->anim_frames_per_line * g->height;
1295 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
1297 *x = src_x % g->width + pos / max_height * g->width;
1298 *y = pos % max_height;
1300 else /* frames are ordered diagonally */
1302 *x = src_x + frame * g->offset_x;
1303 *y = src_y + frame * g->offset_y;
1306 *x = *x * TILESIZE_VAR / g->tile_size;
1307 *y = *y * TILESIZE_VAR / g->tile_size;
1310 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
1312 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
1315 void DrawGraphic(int x, int y, int graphic, int frame)
1318 if (!IN_SCR_FIELD(x, y))
1320 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1321 printf("DrawGraphic(): This should never happen!\n");
1326 DrawGraphicExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR, graphic,
1329 MarkTileDirty(x, y);
1332 void DrawFixedGraphic(int x, int y, int graphic, int frame)
1335 if (!IN_SCR_FIELD(x, y))
1337 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1338 printf("DrawGraphic(): This should never happen!\n");
1343 DrawFixedGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic,
1345 MarkTileDirty(x, y);
1348 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1354 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1356 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX_VAR, TILEY_VAR, x, y);
1359 void DrawFixedGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1365 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1366 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
1369 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
1372 if (!IN_SCR_FIELD(x, y))
1374 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1375 printf("DrawGraphicThruMask(): This should never happen!\n");
1380 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
1383 MarkTileDirty(x, y);
1386 void DrawFixedGraphicThruMask(int x, int y, int graphic, int frame)
1389 if (!IN_SCR_FIELD(x, y))
1391 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1392 printf("DrawGraphicThruMask(): This should never happen!\n");
1397 DrawFixedGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
1399 MarkTileDirty(x, y);
1402 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
1408 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1410 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX_VAR, TILEY_VAR,
1414 void DrawFixedGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y,
1415 int graphic, int frame)
1420 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1422 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY,
1426 void DrawSizedGraphic(int x, int y, int graphic, int frame, int tilesize)
1428 DrawSizedGraphicExt(drawto, SX + x * tilesize, SY + y * tilesize, graphic,
1430 MarkTileDirty(x / tilesize, y / tilesize);
1433 void DrawSizedGraphicExt(DrawBuffer *d, int x, int y, int graphic, int frame,
1439 getSizedGraphicSource(graphic, frame, tilesize, &src_bitmap, &src_x, &src_y);
1440 BlitBitmap(src_bitmap, d, src_x, src_y, tilesize, tilesize, x, y);
1443 void DrawMiniGraphic(int x, int y, int graphic)
1445 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
1446 MarkTileDirty(x / 2, y / 2);
1449 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
1454 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1455 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
1458 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
1459 int graphic, int frame,
1460 int cut_mode, int mask_mode)
1465 int width = TILEX, height = TILEY;
1468 if (dx || dy) /* shifted graphic */
1470 if (x < BX1) /* object enters playfield from the left */
1477 else if (x > BX2) /* object enters playfield from the right */
1483 else if (x == BX1 && dx < 0) /* object leaves playfield to the left */
1489 else if (x == BX2 && dx > 0) /* object leaves playfield to the right */
1491 else if (dx) /* general horizontal movement */
1492 MarkTileDirty(x + SIGN(dx), y);
1494 if (y < BY1) /* object enters playfield from the top */
1496 if (cut_mode == CUT_BELOW) /* object completely above top border */
1504 else if (y > BY2) /* object enters playfield from the bottom */
1510 else if (y == BY1 && dy < 0) /* object leaves playfield to the top */
1516 else if (dy > 0 && cut_mode == CUT_ABOVE)
1518 if (y == BY2) /* object completely above bottom border */
1524 MarkTileDirty(x, y + 1);
1525 } /* object leaves playfield to the bottom */
1526 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1528 else if (dy) /* general vertical movement */
1529 MarkTileDirty(x, y + SIGN(dy));
1533 if (!IN_SCR_FIELD(x, y))
1535 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1536 printf("DrawGraphicShifted(): This should never happen!\n");
1541 width = width * TILESIZE_VAR / TILESIZE;
1542 height = height * TILESIZE_VAR / TILESIZE;
1543 cx = cx * TILESIZE_VAR / TILESIZE;
1544 cy = cy * TILESIZE_VAR / TILESIZE;
1545 dx = dx * TILESIZE_VAR / TILESIZE;
1546 dy = dy * TILESIZE_VAR / TILESIZE;
1548 if (width > 0 && height > 0)
1550 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1555 dst_x = FX + x * TILEX_VAR + dx;
1556 dst_y = FY + y * TILEY_VAR + dy;
1558 if (mask_mode == USE_MASKING)
1559 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1562 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1565 MarkTileDirty(x, y);
1569 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
1570 int graphic, int frame,
1571 int cut_mode, int mask_mode)
1576 int width = TILEX_VAR, height = TILEY_VAR;
1579 int x2 = x + SIGN(dx);
1580 int y2 = y + SIGN(dy);
1582 /* movement with two-tile animations must be sync'ed with movement position,
1583 not with current GfxFrame (which can be higher when using slow movement) */
1584 int anim_pos = (dx ? ABS(dx) : ABS(dy));
1585 int anim_frames = graphic_info[graphic].anim_frames;
1587 /* (we also need anim_delay here for movement animations with less frames) */
1588 int anim_delay = graphic_info[graphic].anim_delay;
1589 int sync_frame = anim_pos * anim_frames * anim_delay / TILESIZE;
1591 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
1592 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
1594 /* re-calculate animation frame for two-tile movement animation */
1595 frame = getGraphicAnimationFrame(graphic, sync_frame);
1597 /* check if movement start graphic inside screen area and should be drawn */
1598 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
1600 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
1602 dst_x = FX + x1 * TILEX_VAR;
1603 dst_y = FY + y1 * TILEY_VAR;
1605 if (mask_mode == USE_MASKING)
1606 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1609 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1612 MarkTileDirty(x1, y1);
1615 /* check if movement end graphic inside screen area and should be drawn */
1616 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
1618 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
1620 dst_x = FX + x2 * TILEX_VAR;
1621 dst_y = FY + y2 * TILEY_VAR;
1623 if (mask_mode == USE_MASKING)
1624 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1627 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1630 MarkTileDirty(x2, y2);
1634 static void DrawGraphicShifted(int x, int y, int dx, int dy,
1635 int graphic, int frame,
1636 int cut_mode, int mask_mode)
1640 DrawGraphic(x, y, graphic, frame);
1645 if (graphic_info[graphic].double_movement) /* EM style movement images */
1646 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1648 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1651 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1652 int frame, int cut_mode)
1654 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
1657 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1658 int cut_mode, int mask_mode)
1660 int lx = LEVELX(x), ly = LEVELY(y);
1664 if (IN_LEV_FIELD(lx, ly))
1666 SetRandomAnimationValue(lx, ly);
1668 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
1669 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1671 /* do not use double (EM style) movement graphic when not moving */
1672 if (graphic_info[graphic].double_movement && !dx && !dy)
1674 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
1675 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1678 else /* border element */
1680 graphic = el2img(element);
1681 frame = getGraphicAnimationFrame(graphic, -1);
1684 if (element == EL_EXPANDABLE_WALL)
1686 boolean left_stopped = FALSE, right_stopped = FALSE;
1688 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1689 left_stopped = TRUE;
1690 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1691 right_stopped = TRUE;
1693 if (left_stopped && right_stopped)
1695 else if (left_stopped)
1697 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1698 frame = graphic_info[graphic].anim_frames - 1;
1700 else if (right_stopped)
1702 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1703 frame = graphic_info[graphic].anim_frames - 1;
1708 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1709 else if (mask_mode == USE_MASKING)
1710 DrawGraphicThruMask(x, y, graphic, frame);
1712 DrawGraphic(x, y, graphic, frame);
1715 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1716 int cut_mode, int mask_mode)
1718 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1719 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1720 cut_mode, mask_mode);
1723 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1726 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1729 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1732 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1735 void DrawLevelElementThruMask(int x, int y, int element)
1737 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1740 void DrawLevelFieldThruMask(int x, int y)
1742 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1745 /* !!! implementation of quicksand is totally broken !!! */
1746 #define IS_CRUMBLED_TILE(x, y, e) \
1747 (GFX_CRUMBLED(e) && (!IN_LEV_FIELD(x, y) || \
1748 !IS_MOVING(x, y) || \
1749 (e) == EL_QUICKSAND_EMPTYING || \
1750 (e) == EL_QUICKSAND_FAST_EMPTYING))
1752 static void DrawLevelFieldCrumbledInnerCorners(int x, int y, int dx, int dy,
1757 int width, height, cx, cy;
1758 int sx = SCREENX(x), sy = SCREENY(y);
1759 int crumbled_border_size = graphic_info[graphic].border_size;
1762 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1764 for (i = 1; i < 4; i++)
1766 int dxx = (i & 1 ? dx : 0);
1767 int dyy = (i & 2 ? dy : 0);
1770 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1773 /* check if neighbour field is of same crumble type */
1774 boolean same = (IS_CRUMBLED_TILE(xx, yy, element) &&
1775 graphic_info[graphic].class ==
1776 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class);
1778 /* return if check prevents inner corner */
1779 if (same == (dxx == dx && dyy == dy))
1783 /* if we reach this point, we have an inner corner */
1785 getGraphicSource(graphic, 1, &src_bitmap, &src_x, &src_y);
1787 width = crumbled_border_size * TILESIZE_VAR / TILESIZE;
1788 height = crumbled_border_size * TILESIZE_VAR / TILESIZE;
1789 cx = (dx > 0 ? TILESIZE_VAR - width : 0);
1790 cy = (dy > 0 ? TILESIZE_VAR - height : 0);
1792 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1793 width, height, FX + sx * TILEX_VAR + cx, FY + sy * TILEY_VAR + cy);
1796 static void DrawLevelFieldCrumbledBorders(int x, int y, int graphic, int frame,
1801 int width, height, bx, by, cx, cy;
1802 int sx = SCREENX(x), sy = SCREENY(y);
1803 int crumbled_border_size = graphic_info[graphic].border_size;
1804 int crumbled_border_size_var = crumbled_border_size * TILESIZE_VAR / TILESIZE;
1805 int crumbled_border_pos_var = TILESIZE_VAR - crumbled_border_size_var;
1808 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1810 /* draw simple, sloppy, non-corner-accurate crumbled border */
1812 width = (dir == 1 || dir == 2 ? crumbled_border_size_var : TILESIZE_VAR);
1813 height = (dir == 0 || dir == 3 ? crumbled_border_size_var : TILESIZE_VAR);
1814 cx = (dir == 2 ? crumbled_border_pos_var : 0);
1815 cy = (dir == 3 ? crumbled_border_pos_var : 0);
1817 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy, width, height,
1818 FX + sx * TILEX_VAR + cx,
1819 FY + sy * TILEY_VAR + cy);
1821 /* (remaining middle border part must be at least as big as corner part) */
1822 if (!(graphic_info[graphic].style & STYLE_ACCURATE_BORDERS) ||
1823 crumbled_border_size >= TILESIZE / 3)
1826 /* correct corners of crumbled border, if needed */
1828 for (i = -1; i <= 1; i += 2)
1830 int xx = x + (dir == 0 || dir == 3 ? i : 0);
1831 int yy = y + (dir == 1 || dir == 2 ? i : 0);
1832 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1835 /* check if neighbour field is of same crumble type */
1836 if (IS_CRUMBLED_TILE(xx, yy, element) &&
1837 graphic_info[graphic].class ==
1838 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1840 /* no crumbled corner, but continued crumbled border */
1842 int c1 = (dir == 2 || dir == 3 ? crumbled_border_pos_var : 0);
1843 int c2 = (i == 1 ? crumbled_border_pos_var : 0);
1844 int b1 = (i == 1 ? crumbled_border_size_var :
1845 TILESIZE_VAR - 2 * crumbled_border_size_var);
1847 width = crumbled_border_size_var;
1848 height = crumbled_border_size_var;
1850 if (dir == 1 || dir == 2)
1865 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
1867 FX + sx * TILEX_VAR + cx,
1868 FY + sy * TILEY_VAR + cy);
1873 static void DrawLevelFieldCrumbledExt(int x, int y, int graphic, int frame)
1875 int sx = SCREENX(x), sy = SCREENY(y);
1878 static int xy[4][2] =
1886 if (!IN_LEV_FIELD(x, y))
1889 element = TILE_GFX_ELEMENT(x, y);
1891 /* crumble field itself */
1892 if (IS_CRUMBLED_TILE(x, y, element))
1894 if (!IN_SCR_FIELD(sx, sy))
1897 for (i = 0; i < 4; i++)
1899 int xx = x + xy[i][0];
1900 int yy = y + xy[i][1];
1902 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1905 /* check if neighbour field is of same crumble type */
1906 if (IS_CRUMBLED_TILE(xx, yy, element) &&
1907 graphic_info[graphic].class ==
1908 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1911 DrawLevelFieldCrumbledBorders(x, y, graphic, frame, i);
1914 if ((graphic_info[graphic].style & STYLE_INNER_CORNERS) &&
1915 graphic_info[graphic].anim_frames == 2)
1917 for (i = 0; i < 4; i++)
1919 int dx = (i & 1 ? +1 : -1);
1920 int dy = (i & 2 ? +1 : -1);
1922 DrawLevelFieldCrumbledInnerCorners(x, y, dx, dy, graphic);
1926 MarkTileDirty(sx, sy);
1928 else /* center field not crumbled -- crumble neighbour fields */
1930 for (i = 0; i < 4; i++)
1932 int xx = x + xy[i][0];
1933 int yy = y + xy[i][1];
1934 int sxx = sx + xy[i][0];
1935 int syy = sy + xy[i][1];
1937 if (!IN_LEV_FIELD(xx, yy) ||
1938 !IN_SCR_FIELD(sxx, syy))
1941 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
1944 element = TILE_GFX_ELEMENT(xx, yy);
1946 if (!IS_CRUMBLED_TILE(xx, yy, element))
1949 graphic = el_act2crm(element, ACTION_DEFAULT);
1951 DrawLevelFieldCrumbledBorders(xx, yy, graphic, 0, 3 - i);
1953 MarkTileDirty(sxx, syy);
1958 void DrawLevelFieldCrumbled(int x, int y)
1962 if (!IN_LEV_FIELD(x, y))
1965 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1966 GfxElement[x][y] != EL_UNDEFINED &&
1967 GFX_CRUMBLED(GfxElement[x][y]))
1969 DrawLevelFieldCrumbledDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
1974 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
1976 DrawLevelFieldCrumbledExt(x, y, graphic, 0);
1979 void DrawLevelFieldCrumbledDigging(int x, int y, int direction,
1982 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1983 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1984 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1985 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1986 int sx = SCREENX(x), sy = SCREENY(y);
1988 DrawGraphic(sx, sy, graphic1, frame1);
1989 DrawLevelFieldCrumbledExt(x, y, graphic2, frame2);
1992 void DrawLevelFieldCrumbledNeighbours(int x, int y)
1994 int sx = SCREENX(x), sy = SCREENY(y);
1995 static int xy[4][2] =
2004 for (i = 0; i < 4; i++)
2006 int xx = x + xy[i][0];
2007 int yy = y + xy[i][1];
2008 int sxx = sx + xy[i][0];
2009 int syy = sy + xy[i][1];
2011 if (!IN_LEV_FIELD(xx, yy) ||
2012 !IN_SCR_FIELD(sxx, syy) ||
2013 !GFX_CRUMBLED(Feld[xx][yy]) ||
2017 DrawLevelField(xx, yy);
2021 static int getBorderElement(int x, int y)
2025 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
2026 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
2027 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
2028 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
2029 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
2030 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
2031 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
2033 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
2034 int steel_position = (x == -1 && y == -1 ? 0 :
2035 x == lev_fieldx && y == -1 ? 1 :
2036 x == -1 && y == lev_fieldy ? 2 :
2037 x == lev_fieldx && y == lev_fieldy ? 3 :
2038 x == -1 || x == lev_fieldx ? 4 :
2039 y == -1 || y == lev_fieldy ? 5 : 6);
2041 return border[steel_position][steel_type];
2044 void DrawScreenElement(int x, int y, int element)
2046 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
2047 DrawLevelFieldCrumbled(LEVELX(x), LEVELY(y));
2050 void DrawLevelElement(int x, int y, int element)
2052 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2053 DrawScreenElement(SCREENX(x), SCREENY(y), element);
2056 void DrawScreenField(int x, int y)
2058 int lx = LEVELX(x), ly = LEVELY(y);
2059 int element, content;
2061 if (!IN_LEV_FIELD(lx, ly))
2063 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
2066 element = getBorderElement(lx, ly);
2068 DrawScreenElement(x, y, element);
2073 element = Feld[lx][ly];
2074 content = Store[lx][ly];
2076 if (IS_MOVING(lx, ly))
2078 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
2079 boolean cut_mode = NO_CUTTING;
2081 if (element == EL_QUICKSAND_EMPTYING ||
2082 element == EL_QUICKSAND_FAST_EMPTYING ||
2083 element == EL_MAGIC_WALL_EMPTYING ||
2084 element == EL_BD_MAGIC_WALL_EMPTYING ||
2085 element == EL_DC_MAGIC_WALL_EMPTYING ||
2086 element == EL_AMOEBA_DROPPING)
2087 cut_mode = CUT_ABOVE;
2088 else if (element == EL_QUICKSAND_FILLING ||
2089 element == EL_QUICKSAND_FAST_FILLING ||
2090 element == EL_MAGIC_WALL_FILLING ||
2091 element == EL_BD_MAGIC_WALL_FILLING ||
2092 element == EL_DC_MAGIC_WALL_FILLING)
2093 cut_mode = CUT_BELOW;
2095 if (cut_mode == CUT_ABOVE)
2096 DrawScreenElement(x, y, element);
2098 DrawScreenElement(x, y, EL_EMPTY);
2101 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
2102 else if (cut_mode == NO_CUTTING)
2103 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
2106 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
2108 if (cut_mode == CUT_BELOW &&
2109 IN_LEV_FIELD(lx, ly + 1) && IN_SCR_FIELD(x, y + 1))
2110 DrawLevelElement(lx, ly + 1, element);
2113 if (content == EL_ACID)
2115 int dir = MovDir[lx][ly];
2116 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
2117 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
2119 DrawLevelElementThruMask(newlx, newly, EL_ACID);
2122 else if (IS_BLOCKED(lx, ly))
2127 boolean cut_mode = NO_CUTTING;
2128 int element_old, content_old;
2130 Blocked2Moving(lx, ly, &oldx, &oldy);
2133 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
2134 MovDir[oldx][oldy] == MV_RIGHT);
2136 element_old = Feld[oldx][oldy];
2137 content_old = Store[oldx][oldy];
2139 if (element_old == EL_QUICKSAND_EMPTYING ||
2140 element_old == EL_QUICKSAND_FAST_EMPTYING ||
2141 element_old == EL_MAGIC_WALL_EMPTYING ||
2142 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
2143 element_old == EL_DC_MAGIC_WALL_EMPTYING ||
2144 element_old == EL_AMOEBA_DROPPING)
2145 cut_mode = CUT_ABOVE;
2147 DrawScreenElement(x, y, EL_EMPTY);
2150 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
2152 else if (cut_mode == NO_CUTTING)
2153 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
2156 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
2159 else if (IS_DRAWABLE(element))
2160 DrawScreenElement(x, y, element);
2162 DrawScreenElement(x, y, EL_EMPTY);
2165 void DrawLevelField(int x, int y)
2167 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2168 DrawScreenField(SCREENX(x), SCREENY(y));
2169 else if (IS_MOVING(x, y))
2173 Moving2Blocked(x, y, &newx, &newy);
2174 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
2175 DrawScreenField(SCREENX(newx), SCREENY(newy));
2177 else if (IS_BLOCKED(x, y))
2181 Blocked2Moving(x, y, &oldx, &oldy);
2182 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
2183 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
2187 void DrawSizedElement(int x, int y, int element, int tilesize)
2191 graphic = el2edimg(element);
2192 DrawSizedGraphic(x, y, graphic, 0, tilesize);
2195 void DrawMiniElement(int x, int y, int element)
2199 graphic = el2edimg(element);
2200 DrawMiniGraphic(x, y, graphic);
2203 void DrawSizedElementOrWall(int sx, int sy, int scroll_x, int scroll_y,
2206 int x = sx + scroll_x, y = sy + scroll_y;
2208 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
2209 DrawSizedElement(sx, sy, EL_EMPTY, tilesize);
2210 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
2211 DrawSizedElement(sx, sy, Feld[x][y], tilesize);
2213 DrawSizedGraphic(sx, sy, el2edimg(getBorderElement(x, y)), 0, tilesize);
2216 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
2218 int x = sx + scroll_x, y = sy + scroll_y;
2220 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
2221 DrawMiniElement(sx, sy, EL_EMPTY);
2222 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
2223 DrawMiniElement(sx, sy, Feld[x][y]);
2225 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
2228 void DrawEnvelopeBackgroundTiles(int graphic, int startx, int starty,
2229 int x, int y, int xsize, int ysize,
2230 int tile_width, int tile_height)
2234 int dst_x = startx + x * tile_width;
2235 int dst_y = starty + y * tile_height;
2236 int width = graphic_info[graphic].width;
2237 int height = graphic_info[graphic].height;
2238 int inner_width_raw = MAX(width - 2 * tile_width, tile_width);
2239 int inner_height_raw = MAX(height - 2 * tile_height, tile_height);
2240 int inner_width = inner_width_raw - (inner_width_raw % tile_width);
2241 int inner_height = inner_height_raw - (inner_height_raw % tile_height);
2242 int inner_sx = (width >= 3 * tile_width ? tile_width : 0);
2243 int inner_sy = (height >= 3 * tile_height ? tile_height : 0);
2244 boolean draw_masked = graphic_info[graphic].draw_masked;
2246 getFixedGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
2248 if (src_bitmap == NULL || width < tile_width || height < tile_height)
2250 ClearRectangle(drawto, dst_x, dst_y, tile_width, tile_height);
2254 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - tile_width :
2255 inner_sx + (x - 1) * tile_width % inner_width);
2256 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - tile_height :
2257 inner_sy + (y - 1) * tile_height % inner_height);
2260 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
2263 BlitBitmap(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
2267 void DrawEnvelopeBackground(int graphic, int startx, int starty,
2268 int x, int y, int xsize, int ysize, int font_nr)
2270 int font_width = getFontWidth(font_nr);
2271 int font_height = getFontHeight(font_nr);
2273 DrawEnvelopeBackgroundTiles(graphic, startx, starty, x, y, xsize, ysize,
2274 font_width, font_height);
2277 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
2279 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2280 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2281 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2282 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2283 boolean no_delay = (tape.warp_forward);
2284 unsigned int anim_delay = 0;
2285 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
2286 int anim_delay_value = (no_delay ? 0 : frame_delay_value) / 2;
2287 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
2288 int font_width = getFontWidth(font_nr);
2289 int font_height = getFontHeight(font_nr);
2290 int max_xsize = level.envelope[envelope_nr].xsize;
2291 int max_ysize = level.envelope[envelope_nr].ysize;
2292 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
2293 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
2294 int xend = max_xsize;
2295 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
2296 int xstep = (xstart < xend ? 1 : 0);
2297 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2299 int end = MAX(xend - xstart, yend - ystart);
2302 for (i = start; i <= end; i++)
2304 int last_frame = end; // last frame of this "for" loop
2305 int x = xstart + i * xstep;
2306 int y = ystart + i * ystep;
2307 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2308 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2309 int sx = SX + (SXSIZE - xsize * font_width) / 2;
2310 int sy = SY + (SYSIZE - ysize * font_height) / 2;
2313 SetDrawtoField(DRAW_TO_FIELDBUFFER);
2315 BlitScreenToBitmap(backbuffer);
2317 SetDrawtoField(DRAW_TO_BACKBUFFER);
2319 for (yy = 0; yy < ysize; yy++)
2320 for (xx = 0; xx < xsize; xx++)
2321 DrawEnvelopeBackground(graphic, sx, sy, xx, yy, xsize, ysize, font_nr);
2323 DrawTextBuffer(sx + font_width, sy + font_height,
2324 level.envelope[envelope_nr].text, font_nr, max_xsize,
2325 xsize - 2, ysize - 2, 0, mask_mode,
2326 level.envelope[envelope_nr].autowrap,
2327 level.envelope[envelope_nr].centered, FALSE);
2329 redraw_mask |= REDRAW_FIELD;
2332 SkipUntilDelayReached(&anim_delay, anim_delay_value, &i, last_frame);
2336 void ShowEnvelope(int envelope_nr)
2338 int element = EL_ENVELOPE_1 + envelope_nr;
2339 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2340 int sound_opening = element_info[element].sound[ACTION_OPENING];
2341 int sound_closing = element_info[element].sound[ACTION_CLOSING];
2342 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2343 boolean no_delay = (tape.warp_forward);
2344 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
2345 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
2346 int anim_mode = graphic_info[graphic].anim_mode;
2347 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2348 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2350 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
2352 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2354 if (anim_mode == ANIM_DEFAULT)
2355 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
2357 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
2360 Delay(wait_delay_value);
2362 WaitForEventToContinue();
2364 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2366 if (anim_mode != ANIM_NONE)
2367 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
2369 if (anim_mode == ANIM_DEFAULT)
2370 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
2372 game.envelope_active = FALSE;
2374 SetDrawtoField(DRAW_TO_FIELDBUFFER);
2376 redraw_mask |= REDRAW_FIELD;
2380 static void setRequestBasePosition(int *x, int *y)
2382 int sx_base, sy_base;
2384 if (request.x != -1)
2385 sx_base = request.x;
2386 else if (request.align == ALIGN_LEFT)
2388 else if (request.align == ALIGN_RIGHT)
2389 sx_base = SX + SXSIZE;
2391 sx_base = SX + SXSIZE / 2;
2393 if (request.y != -1)
2394 sy_base = request.y;
2395 else if (request.valign == VALIGN_TOP)
2397 else if (request.valign == VALIGN_BOTTOM)
2398 sy_base = SY + SYSIZE;
2400 sy_base = SY + SYSIZE / 2;
2406 static void setRequestPositionExt(int *x, int *y, int width, int height,
2407 boolean add_border_size)
2409 int border_size = request.border_size;
2410 int sx_base, sy_base;
2413 setRequestBasePosition(&sx_base, &sy_base);
2415 if (request.align == ALIGN_LEFT)
2417 else if (request.align == ALIGN_RIGHT)
2418 sx = sx_base - width;
2420 sx = sx_base - width / 2;
2422 if (request.valign == VALIGN_TOP)
2424 else if (request.valign == VALIGN_BOTTOM)
2425 sy = sy_base - height;
2427 sy = sy_base - height / 2;
2429 sx = MAX(0, MIN(sx, WIN_XSIZE - width));
2430 sy = MAX(0, MIN(sy, WIN_YSIZE - height));
2432 if (add_border_size)
2442 static void setRequestPosition(int *x, int *y, boolean add_border_size)
2444 setRequestPositionExt(x, y, request.width, request.height, add_border_size);
2447 void DrawEnvelopeRequest(char *text)
2449 char *text_final = text;
2450 char *text_door_style = NULL;
2451 int graphic = IMG_BACKGROUND_REQUEST;
2452 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2453 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2454 int font_nr = FONT_REQUEST;
2455 int font_width = getFontWidth(font_nr);
2456 int font_height = getFontHeight(font_nr);
2457 int border_size = request.border_size;
2458 int line_spacing = request.line_spacing;
2459 int line_height = font_height + line_spacing;
2460 int max_text_width = request.width - 2 * border_size;
2461 int max_text_height = request.height - 2 * border_size;
2462 int line_length = max_text_width / font_width;
2463 int max_lines = max_text_height / line_height;
2464 int text_width = line_length * font_width;
2465 int width = request.width;
2466 int height = request.height;
2467 int tile_size = MAX(request.step_offset, 1);
2468 int x_steps = width / tile_size;
2469 int y_steps = height / tile_size;
2470 int sx_offset = border_size;
2471 int sy_offset = border_size;
2475 if (request.centered)
2476 sx_offset = (request.width - text_width) / 2;
2478 if (request.wrap_single_words && !request.autowrap)
2480 char *src_text_ptr, *dst_text_ptr;
2482 text_door_style = checked_malloc(2 * strlen(text) + 1);
2484 src_text_ptr = text;
2485 dst_text_ptr = text_door_style;
2487 while (*src_text_ptr)
2489 if (*src_text_ptr == ' ' ||
2490 *src_text_ptr == '?' ||
2491 *src_text_ptr == '!')
2492 *dst_text_ptr++ = '\n';
2494 if (*src_text_ptr != ' ')
2495 *dst_text_ptr++ = *src_text_ptr;
2500 *dst_text_ptr = '\0';
2502 text_final = text_door_style;
2505 setRequestPosition(&sx, &sy, FALSE);
2507 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
2509 for (y = 0; y < y_steps; y++)
2510 for (x = 0; x < x_steps; x++)
2511 DrawEnvelopeBackgroundTiles(graphic, sx, sy,
2512 x, y, x_steps, y_steps,
2513 tile_size, tile_size);
2515 /* force DOOR font inside door area */
2516 SetFontStatus(GAME_MODE_PSEUDO_DOOR);
2518 DrawTextBuffer(sx + sx_offset, sy + sy_offset, text_final, font_nr,
2519 line_length, -1, max_lines, line_spacing, mask_mode,
2520 request.autowrap, request.centered, FALSE);
2524 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2525 RedrawGadget(tool_gadget[i]);
2527 // store readily prepared envelope request for later use when animating
2528 BlitBitmap(backbuffer, bitmap_db_store_2, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2530 if (text_door_style)
2531 free(text_door_style);
2534 void AnimateEnvelopeRequest(int anim_mode, int action)
2536 int graphic = IMG_BACKGROUND_REQUEST;
2537 boolean draw_masked = graphic_info[graphic].draw_masked;
2538 int delay_value_normal = request.step_delay;
2539 int delay_value_fast = delay_value_normal / 2;
2540 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2541 boolean no_delay = (tape.warp_forward);
2542 int delay_value = (ffwd_delay ? delay_value_fast : delay_value_normal);
2543 int anim_delay_value = (no_delay ? 0 : delay_value + 500 * 0) / 2;
2544 unsigned int anim_delay = 0;
2546 int tile_size = MAX(request.step_offset, 1);
2547 int max_xsize = request.width / tile_size;
2548 int max_ysize = request.height / tile_size;
2549 int max_xsize_inner = max_xsize - 2;
2550 int max_ysize_inner = max_ysize - 2;
2552 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize_inner : 0);
2553 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize_inner : 0);
2554 int xend = max_xsize_inner;
2555 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize_inner : 0);
2556 int xstep = (xstart < xend ? 1 : 0);
2557 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2559 int end = MAX(xend - xstart, yend - ystart);
2562 if (setup.quick_doors)
2569 for (i = start; i <= end; i++)
2571 int last_frame = end; // last frame of this "for" loop
2572 int x = xstart + i * xstep;
2573 int y = ystart + i * ystep;
2574 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2575 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2576 int xsize_size_left = (xsize - 1) * tile_size;
2577 int ysize_size_top = (ysize - 1) * tile_size;
2578 int max_xsize_pos = (max_xsize - 1) * tile_size;
2579 int max_ysize_pos = (max_ysize - 1) * tile_size;
2580 int width = xsize * tile_size;
2581 int height = ysize * tile_size;
2586 setRequestPosition(&src_x, &src_y, FALSE);
2587 setRequestPositionExt(&dst_x, &dst_y, width, height, FALSE);
2589 BlitBitmap(bitmap_db_store_1, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2591 for (yy = 0; yy < 2; yy++)
2593 for (xx = 0; xx < 2; xx++)
2595 int src_xx = src_x + xx * max_xsize_pos;
2596 int src_yy = src_y + yy * max_ysize_pos;
2597 int dst_xx = dst_x + xx * xsize_size_left;
2598 int dst_yy = dst_y + yy * ysize_size_top;
2599 int xx_size = (xx ? tile_size : xsize_size_left);
2600 int yy_size = (yy ? tile_size : ysize_size_top);
2603 BlitBitmapMasked(bitmap_db_store_2, backbuffer,
2604 src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
2606 BlitBitmap(bitmap_db_store_2, backbuffer,
2607 src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
2611 redraw_mask |= REDRAW_FIELD;
2615 SkipUntilDelayReached(&anim_delay, anim_delay_value, &i, last_frame);
2619 void ShowEnvelopeRequest(char *text, unsigned int req_state, int action)
2621 int graphic = IMG_BACKGROUND_REQUEST;
2622 int sound_opening = SND_REQUEST_OPENING;
2623 int sound_closing = SND_REQUEST_CLOSING;
2624 int anim_mode_1 = request.anim_mode; /* (higher priority) */
2625 int anim_mode_2 = graphic_info[graphic].anim_mode; /* (lower priority) */
2626 int anim_mode = (anim_mode_1 != ANIM_DEFAULT ? anim_mode_1 : anim_mode_2);
2627 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2628 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2630 if (game_status == GAME_MODE_PLAYING)
2631 BlitScreenToBitmap(backbuffer);
2633 SetDrawtoField(DRAW_TO_BACKBUFFER);
2635 // SetDrawBackgroundMask(REDRAW_NONE);
2637 if (action == ACTION_OPENING)
2639 BlitBitmap(backbuffer, bitmap_db_store_1, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2641 if (req_state & REQ_ASK)
2643 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2644 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2646 else if (req_state & REQ_CONFIRM)
2648 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2650 else if (req_state & REQ_PLAYER)
2652 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2653 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2654 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2655 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2658 DrawEnvelopeRequest(text);
2661 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
2663 if (action == ACTION_OPENING)
2665 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2667 if (anim_mode == ANIM_DEFAULT)
2668 AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_OPENING);
2670 AnimateEnvelopeRequest(main_anim_mode, ACTION_OPENING);
2674 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2676 if (anim_mode != ANIM_NONE)
2677 AnimateEnvelopeRequest(main_anim_mode, ACTION_CLOSING);
2679 if (anim_mode == ANIM_DEFAULT)
2680 AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_CLOSING);
2683 game.envelope_active = FALSE;
2685 if (action == ACTION_CLOSING)
2686 BlitBitmap(bitmap_db_store_1, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2688 // SetDrawBackgroundMask(last_draw_background_mask);
2690 redraw_mask |= REDRAW_FIELD;
2694 if (action == ACTION_CLOSING &&
2695 game_status == GAME_MODE_PLAYING &&
2696 level.game_engine_type == GAME_ENGINE_TYPE_RND)
2697 SetDrawtoField(DRAW_TO_FIELDBUFFER);
2700 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
2704 int graphic = el2preimg(element);
2706 getSizedGraphicSource(graphic, 0, tilesize, &src_bitmap, &src_x, &src_y);
2707 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
2710 void DrawLevel(int draw_background_mask)
2714 SetMainBackgroundImage(IMG_BACKGROUND_PLAYING);
2715 SetDrawBackgroundMask(draw_background_mask);
2719 for (x = BX1; x <= BX2; x++)
2720 for (y = BY1; y <= BY2; y++)
2721 DrawScreenField(x, y);
2723 redraw_mask |= REDRAW_FIELD;
2726 void DrawSizedLevel(int size_x, int size_y, int scroll_x, int scroll_y,
2731 for (x = 0; x < size_x; x++)
2732 for (y = 0; y < size_y; y++)
2733 DrawSizedElementOrWall(x, y, scroll_x, scroll_y, tilesize);
2735 redraw_mask |= REDRAW_FIELD;
2738 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
2742 for (x = 0; x < size_x; x++)
2743 for (y = 0; y < size_y; y++)
2744 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
2746 redraw_mask |= REDRAW_FIELD;
2749 static void DrawPreviewLevelPlayfieldExt(int from_x, int from_y)
2751 boolean show_level_border = (BorderElement != EL_EMPTY);
2752 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2753 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2754 int tile_size = preview.tile_size;
2755 int preview_width = preview.xsize * tile_size;
2756 int preview_height = preview.ysize * tile_size;
2757 int real_preview_xsize = MIN(level_xsize, preview.xsize);
2758 int real_preview_ysize = MIN(level_ysize, preview.ysize);
2759 int real_preview_width = real_preview_xsize * tile_size;
2760 int real_preview_height = real_preview_ysize * tile_size;
2761 int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
2762 int dst_y = SY + ALIGNED_YPOS(preview.y, preview_height, preview.valign);
2765 if (!IN_GFX_FIELD_FULL(dst_x, dst_y + preview_height - 1))
2768 DrawBackground(dst_x, dst_y, preview_width, preview_height);
2770 dst_x += (preview_width - real_preview_width) / 2;
2771 dst_y += (preview_height - real_preview_height) / 2;
2773 for (x = 0; x < real_preview_xsize; x++)
2775 for (y = 0; y < real_preview_ysize; y++)
2777 int lx = from_x + x + (show_level_border ? -1 : 0);
2778 int ly = from_y + y + (show_level_border ? -1 : 0);
2779 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
2780 getBorderElement(lx, ly));
2782 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
2783 element, tile_size);
2787 redraw_mask |= REDRAW_FIELD;
2790 #define MICROLABEL_EMPTY 0
2791 #define MICROLABEL_LEVEL_NAME 1
2792 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
2793 #define MICROLABEL_LEVEL_AUTHOR 3
2794 #define MICROLABEL_IMPORTED_FROM_HEAD 4
2795 #define MICROLABEL_IMPORTED_FROM 5
2796 #define MICROLABEL_IMPORTED_BY_HEAD 6
2797 #define MICROLABEL_IMPORTED_BY 7
2799 static int getMaxTextLength(struct TextPosInfo *pos, int font_nr)
2801 int max_text_width = SXSIZE;
2802 int font_width = getFontWidth(font_nr);
2804 if (pos->align == ALIGN_CENTER)
2805 max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
2806 else if (pos->align == ALIGN_RIGHT)
2807 max_text_width = pos->x;
2809 max_text_width = SXSIZE - pos->x;
2811 return max_text_width / font_width;
2814 static void DrawPreviewLevelLabelExt(int mode)
2816 struct TextPosInfo *pos = &menu.main.text.level_info_2;
2817 char label_text[MAX_OUTPUT_LINESIZE + 1];
2818 int max_len_label_text;
2819 int font_nr = pos->font;
2822 if (!IN_GFX_FIELD_FULL(pos->x, pos->y + getFontHeight(pos->font)))
2825 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
2826 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
2827 mode == MICROLABEL_IMPORTED_BY_HEAD)
2828 font_nr = pos->font_alt;
2830 max_len_label_text = getMaxTextLength(pos, font_nr);
2832 if (pos->size != -1)
2833 max_len_label_text = pos->size;
2835 for (i = 0; i < max_len_label_text; i++)
2836 label_text[i] = ' ';
2837 label_text[max_len_label_text] = '\0';
2839 if (strlen(label_text) > 0)
2840 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2843 (mode == MICROLABEL_LEVEL_NAME ? level.name :
2844 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
2845 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
2846 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
2847 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
2848 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
2849 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
2850 max_len_label_text);
2851 label_text[max_len_label_text] = '\0';
2853 if (strlen(label_text) > 0)
2854 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2856 redraw_mask |= REDRAW_FIELD;
2859 static void DrawPreviewLevelExt(boolean restart)
2861 static unsigned int scroll_delay = 0;
2862 static unsigned int label_delay = 0;
2863 static int from_x, from_y, scroll_direction;
2864 static int label_state, label_counter;
2865 unsigned int scroll_delay_value = preview.step_delay;
2866 boolean show_level_border = (BorderElement != EL_EMPTY);
2867 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2868 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2875 if (preview.anim_mode == ANIM_CENTERED)
2877 if (level_xsize > preview.xsize)
2878 from_x = (level_xsize - preview.xsize) / 2;
2879 if (level_ysize > preview.ysize)
2880 from_y = (level_ysize - preview.ysize) / 2;
2883 from_x += preview.xoffset;
2884 from_y += preview.yoffset;
2886 scroll_direction = MV_RIGHT;
2890 DrawPreviewLevelPlayfieldExt(from_x, from_y);
2891 DrawPreviewLevelLabelExt(label_state);
2893 /* initialize delay counters */
2894 DelayReached(&scroll_delay, 0);
2895 DelayReached(&label_delay, 0);
2897 if (leveldir_current->name)
2899 struct TextPosInfo *pos = &menu.main.text.level_info_1;
2900 char label_text[MAX_OUTPUT_LINESIZE + 1];
2901 int font_nr = pos->font;
2902 int max_len_label_text = getMaxTextLength(pos, font_nr);
2904 if (pos->size != -1)
2905 max_len_label_text = pos->size;
2907 strncpy(label_text, leveldir_current->name, max_len_label_text);
2908 label_text[max_len_label_text] = '\0';
2910 if (IN_GFX_FIELD_FULL(pos->x, pos->y + getFontHeight(pos->font)))
2911 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2917 /* scroll preview level, if needed */
2918 if (preview.anim_mode != ANIM_NONE &&
2919 (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
2920 DelayReached(&scroll_delay, scroll_delay_value))
2922 switch (scroll_direction)
2927 from_x -= preview.step_offset;
2928 from_x = (from_x < 0 ? 0 : from_x);
2931 scroll_direction = MV_UP;
2935 if (from_x < level_xsize - preview.xsize)
2937 from_x += preview.step_offset;
2938 from_x = (from_x > level_xsize - preview.xsize ?
2939 level_xsize - preview.xsize : from_x);
2942 scroll_direction = MV_DOWN;
2948 from_y -= preview.step_offset;
2949 from_y = (from_y < 0 ? 0 : from_y);
2952 scroll_direction = MV_RIGHT;
2956 if (from_y < level_ysize - preview.ysize)
2958 from_y += preview.step_offset;
2959 from_y = (from_y > level_ysize - preview.ysize ?
2960 level_ysize - preview.ysize : from_y);
2963 scroll_direction = MV_LEFT;
2970 DrawPreviewLevelPlayfieldExt(from_x, from_y);
2973 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
2974 /* redraw micro level label, if needed */
2975 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
2976 !strEqual(level.author, ANONYMOUS_NAME) &&
2977 !strEqual(level.author, leveldir_current->name) &&
2978 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
2980 int max_label_counter = 23;
2982 if (leveldir_current->imported_from != NULL &&
2983 strlen(leveldir_current->imported_from) > 0)
2984 max_label_counter += 14;
2985 if (leveldir_current->imported_by != NULL &&
2986 strlen(leveldir_current->imported_by) > 0)
2987 max_label_counter += 14;
2989 label_counter = (label_counter + 1) % max_label_counter;
2990 label_state = (label_counter >= 0 && label_counter <= 7 ?
2991 MICROLABEL_LEVEL_NAME :
2992 label_counter >= 9 && label_counter <= 12 ?
2993 MICROLABEL_LEVEL_AUTHOR_HEAD :
2994 label_counter >= 14 && label_counter <= 21 ?
2995 MICROLABEL_LEVEL_AUTHOR :
2996 label_counter >= 23 && label_counter <= 26 ?
2997 MICROLABEL_IMPORTED_FROM_HEAD :
2998 label_counter >= 28 && label_counter <= 35 ?
2999 MICROLABEL_IMPORTED_FROM :
3000 label_counter >= 37 && label_counter <= 40 ?
3001 MICROLABEL_IMPORTED_BY_HEAD :
3002 label_counter >= 42 && label_counter <= 49 ?
3003 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
3005 if (leveldir_current->imported_from == NULL &&
3006 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
3007 label_state == MICROLABEL_IMPORTED_FROM))
3008 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
3009 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
3011 DrawPreviewLevelLabelExt(label_state);
3015 void DrawPreviewLevelInitial()
3017 DrawPreviewLevelExt(TRUE);
3020 void DrawPreviewLevelAnimation()
3022 DrawPreviewLevelExt(FALSE);
3025 inline static void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
3026 int graphic, int sync_frame,
3029 int frame = getGraphicAnimationFrame(graphic, sync_frame);
3031 if (mask_mode == USE_MASKING)
3032 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
3034 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
3037 void DrawFixedGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
3038 int graphic, int sync_frame, int mask_mode)
3040 int frame = getGraphicAnimationFrame(graphic, sync_frame);
3042 if (mask_mode == USE_MASKING)
3043 DrawFixedGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
3045 DrawFixedGraphicExt(dst_bitmap, x, y, graphic, frame);
3048 inline static void DrawGraphicAnimation(int x, int y, int graphic)
3050 int lx = LEVELX(x), ly = LEVELY(y);
3052 if (!IN_SCR_FIELD(x, y))
3055 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
3056 graphic, GfxFrame[lx][ly], NO_MASKING);
3058 MarkTileDirty(x, y);
3061 void DrawFixedGraphicAnimation(int x, int y, int graphic)
3063 int lx = LEVELX(x), ly = LEVELY(y);
3065 if (!IN_SCR_FIELD(x, y))
3068 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
3069 graphic, GfxFrame[lx][ly], NO_MASKING);
3070 MarkTileDirty(x, y);
3073 void DrawLevelGraphicAnimation(int x, int y, int graphic)
3075 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
3078 void DrawLevelElementAnimation(int x, int y, int element)
3080 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
3082 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
3085 void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
3087 int sx = SCREENX(x), sy = SCREENY(y);
3089 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
3092 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
3095 DrawGraphicAnimation(sx, sy, graphic);
3098 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
3099 DrawLevelFieldCrumbled(x, y);
3101 if (GFX_CRUMBLED(Feld[x][y]))
3102 DrawLevelFieldCrumbled(x, y);
3106 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
3108 int sx = SCREENX(x), sy = SCREENY(y);
3111 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
3114 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
3116 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
3119 DrawGraphicAnimation(sx, sy, graphic);
3121 if (GFX_CRUMBLED(element))
3122 DrawLevelFieldCrumbled(x, y);
3125 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
3127 if (player->use_murphy)
3129 /* this works only because currently only one player can be "murphy" ... */
3130 static int last_horizontal_dir = MV_LEFT;
3131 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
3133 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3134 last_horizontal_dir = move_dir;
3136 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
3138 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
3140 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
3146 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
3149 static boolean equalGraphics(int graphic1, int graphic2)
3151 struct GraphicInfo *g1 = &graphic_info[graphic1];
3152 struct GraphicInfo *g2 = &graphic_info[graphic2];
3154 return (g1->bitmap == g2->bitmap &&
3155 g1->src_x == g2->src_x &&
3156 g1->src_y == g2->src_y &&
3157 g1->anim_frames == g2->anim_frames &&
3158 g1->anim_delay == g2->anim_delay &&
3159 g1->anim_mode == g2->anim_mode);
3162 void DrawAllPlayers()
3166 for (i = 0; i < MAX_PLAYERS; i++)
3167 if (stored_player[i].active)
3168 DrawPlayer(&stored_player[i]);
3171 void DrawPlayerField(int x, int y)
3173 if (!IS_PLAYER(x, y))
3176 DrawPlayer(PLAYERINFO(x, y));
3179 #define DRAW_PLAYER_OVER_PUSHED_ELEMENT 1
3181 void DrawPlayer(struct PlayerInfo *player)
3183 int jx = player->jx;
3184 int jy = player->jy;
3185 int move_dir = player->MovDir;
3186 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
3187 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
3188 int last_jx = (player->is_moving ? jx - dx : jx);
3189 int last_jy = (player->is_moving ? jy - dy : jy);
3190 int next_jx = jx + dx;
3191 int next_jy = jy + dy;
3192 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
3193 boolean player_is_opaque = FALSE;
3194 int sx = SCREENX(jx), sy = SCREENY(jy);
3195 int sxx = 0, syy = 0;
3196 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
3198 int action = ACTION_DEFAULT;
3199 int last_player_graphic = getPlayerGraphic(player, move_dir);
3200 int last_player_frame = player->Frame;
3203 /* GfxElement[][] is set to the element the player is digging or collecting;
3204 remove also for off-screen player if the player is not moving anymore */
3205 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
3206 GfxElement[jx][jy] = EL_UNDEFINED;
3208 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
3212 if (!IN_LEV_FIELD(jx, jy))
3214 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
3215 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
3216 printf("DrawPlayerField(): This should never happen!\n");
3221 if (element == EL_EXPLOSION)
3224 action = (player->is_pushing ? ACTION_PUSHING :
3225 player->is_digging ? ACTION_DIGGING :
3226 player->is_collecting ? ACTION_COLLECTING :
3227 player->is_moving ? ACTION_MOVING :
3228 player->is_snapping ? ACTION_SNAPPING :
3229 player->is_dropping ? ACTION_DROPPING :
3230 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
3232 if (player->is_waiting)
3233 move_dir = player->dir_waiting;
3235 InitPlayerGfxAnimation(player, action, move_dir);
3237 /* ----------------------------------------------------------------------- */
3238 /* draw things in the field the player is leaving, if needed */
3239 /* ----------------------------------------------------------------------- */
3241 if (player->is_moving)
3243 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
3245 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
3247 if (last_element == EL_DYNAMITE_ACTIVE ||
3248 last_element == EL_EM_DYNAMITE_ACTIVE ||
3249 last_element == EL_SP_DISK_RED_ACTIVE)
3250 DrawDynamite(last_jx, last_jy);
3252 DrawLevelFieldThruMask(last_jx, last_jy);
3254 else if (last_element == EL_DYNAMITE_ACTIVE ||
3255 last_element == EL_EM_DYNAMITE_ACTIVE ||
3256 last_element == EL_SP_DISK_RED_ACTIVE)
3257 DrawDynamite(last_jx, last_jy);
3259 /* !!! this is not enough to prevent flickering of players which are
3260 moving next to each others without a free tile between them -- this
3261 can only be solved by drawing all players layer by layer (first the
3262 background, then the foreground etc.) !!! => TODO */
3263 else if (!IS_PLAYER(last_jx, last_jy))
3264 DrawLevelField(last_jx, last_jy);
3267 DrawLevelField(last_jx, last_jy);
3270 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
3271 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
3274 if (!IN_SCR_FIELD(sx, sy))
3277 /* ----------------------------------------------------------------------- */
3278 /* draw things behind the player, if needed */
3279 /* ----------------------------------------------------------------------- */
3282 DrawLevelElement(jx, jy, Back[jx][jy]);
3283 else if (IS_ACTIVE_BOMB(element))
3284 DrawLevelElement(jx, jy, EL_EMPTY);
3287 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
3289 int old_element = GfxElement[jx][jy];
3290 int old_graphic = el_act_dir2img(old_element, action, move_dir);
3291 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
3293 if (GFX_CRUMBLED(old_element))
3294 DrawLevelFieldCrumbledDigging(jx, jy, move_dir, player->StepFrame);
3296 DrawGraphic(sx, sy, old_graphic, frame);
3298 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
3299 player_is_opaque = TRUE;
3303 GfxElement[jx][jy] = EL_UNDEFINED;
3305 /* make sure that pushed elements are drawn with correct frame rate */
3306 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
3308 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
3309 GfxFrame[jx][jy] = player->StepFrame;
3311 DrawLevelField(jx, jy);
3315 #if !DRAW_PLAYER_OVER_PUSHED_ELEMENT
3316 /* ----------------------------------------------------------------------- */
3317 /* draw player himself */
3318 /* ----------------------------------------------------------------------- */
3320 graphic = getPlayerGraphic(player, move_dir);
3322 /* in the case of changed player action or direction, prevent the current
3323 animation frame from being restarted for identical animations */
3324 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
3325 player->Frame = last_player_frame;
3327 frame = getGraphicAnimationFrame(graphic, player->Frame);
3331 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3332 sxx = player->GfxPos;
3334 syy = player->GfxPos;
3337 if (player_is_opaque)
3338 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
3340 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3342 if (SHIELD_ON(player))
3344 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
3345 IMG_SHIELD_NORMAL_ACTIVE);
3346 int frame = getGraphicAnimationFrame(graphic, -1);
3348 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3352 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
3355 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3356 sxx = player->GfxPos;
3358 syy = player->GfxPos;
3362 /* ----------------------------------------------------------------------- */
3363 /* draw things the player is pushing, if needed */
3364 /* ----------------------------------------------------------------------- */
3366 if (player->is_pushing && player->is_moving)
3368 int px = SCREENX(jx), py = SCREENY(jy);
3369 int pxx = (TILEX - ABS(sxx)) * dx;
3370 int pyy = (TILEY - ABS(syy)) * dy;
3371 int gfx_frame = GfxFrame[jx][jy];
3377 if (!IS_MOVING(jx, jy)) /* push movement already finished */
3379 element = Feld[next_jx][next_jy];
3380 gfx_frame = GfxFrame[next_jx][next_jy];
3383 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
3385 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
3386 frame = getGraphicAnimationFrame(graphic, sync_frame);
3388 /* draw background element under pushed element (like the Sokoban field) */
3389 if (game.use_masked_pushing && IS_MOVING(jx, jy))
3391 /* this allows transparent pushing animation over non-black background */
3394 DrawLevelElement(jx, jy, Back[jx][jy]);
3396 DrawLevelElement(jx, jy, EL_EMPTY);
3398 if (Back[next_jx][next_jy])
3399 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3401 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
3403 else if (Back[next_jx][next_jy])
3404 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3407 /* do not draw (EM style) pushing animation when pushing is finished */
3408 /* (two-tile animations usually do not contain start and end frame) */
3409 if (graphic_info[graphic].double_movement && !IS_MOVING(jx, jy))
3410 DrawLevelElement(next_jx, next_jy, Feld[next_jx][next_jy]);
3412 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3414 /* masked drawing is needed for EMC style (double) movement graphics */
3415 /* !!! (ONLY WHEN DRAWING PUSHED ELEMENT OVER THE PLAYER) !!! */
3416 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3420 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
3421 /* ----------------------------------------------------------------------- */
3422 /* draw player himself */
3423 /* ----------------------------------------------------------------------- */
3425 graphic = getPlayerGraphic(player, move_dir);
3427 /* in the case of changed player action or direction, prevent the current
3428 animation frame from being restarted for identical animations */
3429 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
3430 player->Frame = last_player_frame;
3432 frame = getGraphicAnimationFrame(graphic, player->Frame);
3436 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3437 sxx = player->GfxPos;
3439 syy = player->GfxPos;
3442 if (player_is_opaque)
3443 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
3445 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3447 if (SHIELD_ON(player))
3449 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
3450 IMG_SHIELD_NORMAL_ACTIVE);
3451 int frame = getGraphicAnimationFrame(graphic, -1);
3453 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3457 /* ----------------------------------------------------------------------- */
3458 /* draw things in front of player (active dynamite or dynabombs) */
3459 /* ----------------------------------------------------------------------- */
3461 if (IS_ACTIVE_BOMB(element))
3463 graphic = el2img(element);
3464 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
3466 if (game.emulation == EMU_SUPAPLEX)
3467 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
3469 DrawGraphicThruMask(sx, sy, graphic, frame);
3472 if (player_is_moving && last_element == EL_EXPLOSION)
3474 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
3475 GfxElement[last_jx][last_jy] : EL_EMPTY);
3476 int graphic = el_act2img(element, ACTION_EXPLODING);
3477 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
3478 int phase = ExplodePhase[last_jx][last_jy] - 1;
3479 int frame = getGraphicAnimationFrame(graphic, phase - delay);
3482 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
3485 /* ----------------------------------------------------------------------- */
3486 /* draw elements the player is just walking/passing through/under */
3487 /* ----------------------------------------------------------------------- */
3489 if (player_is_moving)
3491 /* handle the field the player is leaving ... */
3492 if (IS_ACCESSIBLE_INSIDE(last_element))
3493 DrawLevelField(last_jx, last_jy);
3494 else if (IS_ACCESSIBLE_UNDER(last_element))
3495 DrawLevelFieldThruMask(last_jx, last_jy);
3498 /* do not redraw accessible elements if the player is just pushing them */
3499 if (!player_is_moving || !player->is_pushing)
3501 /* ... and the field the player is entering */
3502 if (IS_ACCESSIBLE_INSIDE(element))
3503 DrawLevelField(jx, jy);
3504 else if (IS_ACCESSIBLE_UNDER(element))
3505 DrawLevelFieldThruMask(jx, jy);
3508 MarkTileDirty(sx, sy);
3511 /* ------------------------------------------------------------------------- */
3513 void WaitForEventToContinue()
3515 boolean still_wait = TRUE;
3517 /* simulate releasing mouse button over last gadget, if still pressed */
3519 HandleGadgets(-1, -1, 0);
3521 button_status = MB_RELEASED;
3535 case EVENT_BUTTONPRESS:
3536 case EVENT_KEYPRESS:
3540 case EVENT_KEYRELEASE:
3541 ClearPlayerAction();
3545 HandleOtherEvents(&event);
3549 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3558 #define MAX_REQUEST_LINES 13
3559 #define MAX_REQUEST_LINE_FONT1_LEN 7
3560 #define MAX_REQUEST_LINE_FONT2_LEN 10
3562 static int RequestHandleEvents(unsigned int req_state)
3564 boolean level_solved = (game_status == GAME_MODE_PLAYING &&
3565 local_player->LevelSolved_GameEnd);
3566 int width = request.width;
3567 int height = request.height;
3571 setRequestPosition(&sx, &sy, FALSE);
3573 button_status = MB_RELEASED;
3575 request_gadget_id = -1;
3582 SetDrawtoField(DRAW_TO_FIELDBUFFER);
3584 HandleGameActions();
3586 SetDrawtoField(DRAW_TO_BACKBUFFER);
3588 if (global.use_envelope_request)
3590 /* copy current state of request area to middle of playfield area */
3591 BlitBitmap(bitmap_db_store_2, drawto, sx, sy, width, height, sx, sy);
3599 while (NextValidEvent(&event))
3603 case EVENT_BUTTONPRESS:
3604 case EVENT_BUTTONRELEASE:
3605 case EVENT_MOTIONNOTIFY:
3609 if (event.type == EVENT_MOTIONNOTIFY)
3614 motion_status = TRUE;
3615 mx = ((MotionEvent *) &event)->x;
3616 my = ((MotionEvent *) &event)->y;
3620 motion_status = FALSE;
3621 mx = ((ButtonEvent *) &event)->x;
3622 my = ((ButtonEvent *) &event)->y;
3623 if (event.type == EVENT_BUTTONPRESS)
3624 button_status = ((ButtonEvent *) &event)->button;
3626 button_status = MB_RELEASED;
3629 /* this sets 'request_gadget_id' */
3630 HandleGadgets(mx, my, button_status);
3632 switch (request_gadget_id)
3634 case TOOL_CTRL_ID_YES:
3637 case TOOL_CTRL_ID_NO:
3640 case TOOL_CTRL_ID_CONFIRM:
3641 result = TRUE | FALSE;
3644 case TOOL_CTRL_ID_PLAYER_1:
3647 case TOOL_CTRL_ID_PLAYER_2:
3650 case TOOL_CTRL_ID_PLAYER_3:
3653 case TOOL_CTRL_ID_PLAYER_4:
3664 case EVENT_KEYPRESS:
3665 switch (GetEventKey((KeyEvent *)&event, TRUE))
3668 if (req_state & REQ_CONFIRM)
3673 #if defined(TARGET_SDL2)
3680 #if defined(TARGET_SDL2)
3690 if (req_state & REQ_PLAYER)
3694 case EVENT_KEYRELEASE:
3695 ClearPlayerAction();
3699 HandleOtherEvents(&event);
3704 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3706 int joy = AnyJoystick();
3708 if (joy & JOY_BUTTON_1)
3710 else if (joy & JOY_BUTTON_2)
3716 if (global.use_envelope_request)
3718 /* copy back current state of pressed buttons inside request area */
3719 BlitBitmap(drawto, bitmap_db_store_2, sx, sy, width, height, sx, sy);
3729 static boolean RequestDoor(char *text, unsigned int req_state)
3731 unsigned int old_door_state;
3732 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
3733 int font_nr = FONT_TEXT_2;
3738 if (maxWordLengthInString(text) > MAX_REQUEST_LINE_FONT1_LEN)
3740 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
3741 font_nr = FONT_TEXT_1;
3744 if (game_status == GAME_MODE_PLAYING)
3745 BlitScreenToBitmap(backbuffer);
3747 /* disable deactivated drawing when quick-loading level tape recording */
3748 if (tape.playing && tape.deactivate_display)
3749 TapeDeactivateDisplayOff(TRUE);
3751 SetMouseCursor(CURSOR_DEFAULT);
3753 #if defined(NETWORK_AVALIABLE)
3754 /* pause network game while waiting for request to answer */
3755 if (options.network &&
3756 game_status == GAME_MODE_PLAYING &&
3757 req_state & REQUEST_WAIT_FOR_INPUT)
3758 SendToServer_PausePlaying();
3761 old_door_state = GetDoorState();
3763 /* simulate releasing mouse button over last gadget, if still pressed */
3765 HandleGadgets(-1, -1, 0);
3769 /* draw released gadget before proceeding */
3772 if (old_door_state & DOOR_OPEN_1)
3774 CloseDoor(DOOR_CLOSE_1);
3776 /* save old door content */
3777 BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
3778 0 * DXSIZE, 0, DXSIZE, DYSIZE, 1 * DXSIZE, 0);
3781 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
3782 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3784 /* clear door drawing field */
3785 DrawBackground(DX, DY, DXSIZE, DYSIZE);
3787 /* force DOOR font inside door area */
3788 SetFontStatus(GAME_MODE_PSEUDO_DOOR);
3790 /* write text for request */
3791 for (text_ptr = text, ty = 0; ty < MAX_REQUEST_LINES; ty++)
3793 char text_line[max_request_line_len + 1];
3799 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
3801 tc = *(text_ptr + tx);
3802 // if (!tc || tc == ' ')
3803 if (!tc || tc == ' ' || tc == '?' || tc == '!')
3807 if ((tc == '?' || tc == '!') && tl == 0)
3817 strncpy(text_line, text_ptr, tl);
3820 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
3821 DY + 8 + ty * (getFontHeight(font_nr) + 2),
3822 text_line, font_nr);
3824 text_ptr += tl + (tc == ' ' ? 1 : 0);
3825 // text_ptr += tl + (tc == ' ' || tc == '?' || tc == '!' ? 1 : 0);
3830 if (req_state & REQ_ASK)
3832 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
3833 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
3835 else if (req_state & REQ_CONFIRM)
3837 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
3839 else if (req_state & REQ_PLAYER)
3841 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
3842 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
3843 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
3844 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
3847 /* copy request gadgets to door backbuffer */
3848 BlitBitmap(drawto, bitmap_db_door_1, DX, DY, DXSIZE, DYSIZE, 0, 0);
3850 OpenDoor(DOOR_OPEN_1);
3852 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
3854 if (game_status == GAME_MODE_PLAYING)
3856 SetPanelBackground();
3857 SetDrawBackgroundMask(REDRAW_DOOR_1);
3861 SetDrawBackgroundMask(REDRAW_FIELD);
3867 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3869 // ---------- handle request buttons ----------
3870 result = RequestHandleEvents(req_state);
3874 if (!(req_state & REQ_STAY_OPEN))
3876 CloseDoor(DOOR_CLOSE_1);
3878 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
3879 (req_state & REQ_REOPEN))
3880 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
3885 if (game_status == GAME_MODE_PLAYING)
3887 SetPanelBackground();
3888 SetDrawBackgroundMask(REDRAW_DOOR_1);
3892 SetDrawBackgroundMask(REDRAW_FIELD);
3895 #if defined(NETWORK_AVALIABLE)
3896 /* continue network game after request */
3897 if (options.network &&
3898 game_status == GAME_MODE_PLAYING &&
3899 req_state & REQUEST_WAIT_FOR_INPUT)
3900 SendToServer_ContinuePlaying();
3903 /* restore deactivated drawing when quick-loading level tape recording */
3904 if (tape.playing && tape.deactivate_display)
3905 TapeDeactivateDisplayOn();
3910 static boolean RequestEnvelope(char *text, unsigned int req_state)
3914 if (game_status == GAME_MODE_PLAYING)
3915 BlitScreenToBitmap(backbuffer);
3917 /* disable deactivated drawing when quick-loading level tape recording */
3918 if (tape.playing && tape.deactivate_display)
3919 TapeDeactivateDisplayOff(TRUE);
3921 SetMouseCursor(CURSOR_DEFAULT);
3923 #if defined(NETWORK_AVALIABLE)
3924 /* pause network game while waiting for request to answer */
3925 if (options.network &&
3926 game_status == GAME_MODE_PLAYING &&
3927 req_state & REQUEST_WAIT_FOR_INPUT)
3928 SendToServer_PausePlaying();
3931 /* simulate releasing mouse button over last gadget, if still pressed */
3933 HandleGadgets(-1, -1, 0);
3937 // (replace with setting corresponding request background)
3938 // SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
3939 // SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3941 /* clear door drawing field */
3942 // DrawBackground(DX, DY, DXSIZE, DYSIZE);
3944 ShowEnvelopeRequest(text, req_state, ACTION_OPENING);
3946 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
3948 if (game_status == GAME_MODE_PLAYING)
3950 SetPanelBackground();
3951 SetDrawBackgroundMask(REDRAW_DOOR_1);
3955 SetDrawBackgroundMask(REDRAW_FIELD);
3961 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3963 // ---------- handle request buttons ----------
3964 result = RequestHandleEvents(req_state);
3968 ShowEnvelopeRequest(text, req_state, ACTION_CLOSING);
3972 if (game_status == GAME_MODE_PLAYING)
3974 SetPanelBackground();
3975 SetDrawBackgroundMask(REDRAW_DOOR_1);
3979 SetDrawBackgroundMask(REDRAW_FIELD);
3982 #if defined(NETWORK_AVALIABLE)
3983 /* continue network game after request */
3984 if (options.network &&
3985 game_status == GAME_MODE_PLAYING &&
3986 req_state & REQUEST_WAIT_FOR_INPUT)
3987 SendToServer_ContinuePlaying();
3990 /* restore deactivated drawing when quick-loading level tape recording */
3991 if (tape.playing && tape.deactivate_display)
3992 TapeDeactivateDisplayOn();
3997 boolean Request(char *text, unsigned int req_state)
3999 if (global.use_envelope_request)
4000 return RequestEnvelope(text, req_state);
4002 return RequestDoor(text, req_state);
4005 static int compareDoorPartOrderInfo(const void *object1, const void *object2)
4007 const struct DoorPartOrderInfo *dpo1 = (struct DoorPartOrderInfo *)object1;
4008 const struct DoorPartOrderInfo *dpo2 = (struct DoorPartOrderInfo *)object2;
4011 if (dpo1->sort_priority != dpo2->sort_priority)
4012 compare_result = dpo1->sort_priority - dpo2->sort_priority;
4014 compare_result = dpo1->nr - dpo2->nr;
4016 return compare_result;
4019 void InitGraphicCompatibilityInfo_Doors()
4025 struct DoorInfo *door;
4029 { DOOR_1, IMG_GFX_DOOR_1_PART_1, IMG_GFX_DOOR_1_PART_8, &door_1 },
4030 { DOOR_2, IMG_GFX_DOOR_2_PART_1, IMG_GFX_DOOR_2_PART_8, &door_2 },
4032 { -1, -1, -1, NULL }
4034 struct Rect door_rect_list[] =
4036 { DX, DY, DXSIZE, DYSIZE },
4037 { VX, VY, VXSIZE, VYSIZE }
4041 for (i = 0; doors[i].door_token != -1; i++)
4043 int door_token = doors[i].door_token;
4044 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
4045 int part_1 = doors[i].part_1;
4046 int part_8 = doors[i].part_8;
4047 int part_2 = part_1 + 1;
4048 int part_3 = part_1 + 2;
4049 struct DoorInfo *door = doors[i].door;
4050 struct Rect *door_rect = &door_rect_list[door_index];
4051 boolean door_gfx_redefined = FALSE;
4053 /* check if any door part graphic definitions have been redefined */
4055 for (j = 0; door_part_controls[j].door_token != -1; j++)
4057 struct DoorPartControlInfo *dpc = &door_part_controls[j];
4058 struct FileInfo *fi = getImageListEntryFromImageID(dpc->graphic);
4060 if (dpc->door_token == door_token && fi->redefined)
4061 door_gfx_redefined = TRUE;
4064 /* check for old-style door graphic/animation modifications */
4066 if (!door_gfx_redefined)
4068 if (door->anim_mode & ANIM_STATIC_PANEL)
4070 door->panel.step_xoffset = 0;
4071 door->panel.step_yoffset = 0;
4074 if (door->anim_mode & (ANIM_HORIZONTAL | ANIM_VERTICAL))
4076 struct GraphicInfo *g_part_1 = &graphic_info[part_1];
4077 struct GraphicInfo *g_part_2 = &graphic_info[part_2];
4078 int num_door_steps, num_panel_steps;
4080 /* remove door part graphics other than the two default wings */
4082 for (j = 0; door_part_controls[j].door_token != -1; j++)
4084 struct DoorPartControlInfo *dpc = &door_part_controls[j];
4085 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4087 if (dpc->graphic >= part_3 &&
4088 dpc->graphic <= part_8)
4092 /* set graphics and screen positions of the default wings */
4094 g_part_1->width = door_rect->width;
4095 g_part_1->height = door_rect->height;
4096 g_part_2->width = door_rect->width;
4097 g_part_2->height = door_rect->height;
4098 g_part_2->src_x = door_rect->width;
4099 g_part_2->src_y = g_part_1->src_y;
4101 door->part_2.x = door->part_1.x;
4102 door->part_2.y = door->part_1.y;
4104 if (door->width != -1)
4106 g_part_1->width = door->width;
4107 g_part_2->width = door->width;
4109 // special treatment for graphics and screen position of right wing
4110 g_part_2->src_x += door_rect->width - door->width;
4111 door->part_2.x += door_rect->width - door->width;
4114 if (door->height != -1)
4116 g_part_1->height = door->height;
4117 g_part_2->height = door->height;
4119 // special treatment for graphics and screen position of bottom wing
4120 g_part_2->src_y += door_rect->height - door->height;
4121 door->part_2.y += door_rect->height - door->height;
4124 /* set animation delays for the default wings and panels */
4126 door->part_1.step_delay = door->step_delay;
4127 door->part_2.step_delay = door->step_delay;
4128 door->panel.step_delay = door->step_delay;
4130 /* set animation draw order for the default wings */
4132 door->part_1.sort_priority = 2; /* draw left wing over ... */
4133 door->part_2.sort_priority = 1; /* ... right wing */
4135 /* set animation draw offset for the default wings */
4137 if (door->anim_mode & ANIM_HORIZONTAL)
4139 door->part_1.step_xoffset = door->step_offset;
4140 door->part_1.step_yoffset = 0;
4141 door->part_2.step_xoffset = door->step_offset * -1;
4142 door->part_2.step_yoffset = 0;
4144 num_door_steps = g_part_1->width / door->step_offset;
4146 else // ANIM_VERTICAL
4148 door->part_1.step_xoffset = 0;
4149 door->part_1.step_yoffset = door->step_offset;
4150 door->part_2.step_xoffset = 0;
4151 door->part_2.step_yoffset = door->step_offset * -1;
4153 num_door_steps = g_part_1->height / door->step_offset;
4156 /* set animation draw offset for the default panels */
4158 if (door->step_offset > 1)
4160 num_panel_steps = 2 * door_rect->height / door->step_offset;
4161 door->panel.start_step = num_panel_steps - num_door_steps;
4162 door->panel.start_step_closing = door->panel.start_step;
4166 num_panel_steps = door_rect->height / door->step_offset;
4167 door->panel.start_step = num_panel_steps - num_door_steps / 2;
4168 door->panel.start_step_closing = door->panel.start_step;
4169 door->panel.step_delay *= 2;
4180 for (i = 0; door_part_controls[i].door_token != -1; i++)
4182 struct DoorPartControlInfo *dpc = &door_part_controls[i];
4183 struct DoorPartOrderInfo *dpo = &door_part_order[i];
4185 /* initialize "start_step_opening" and "start_step_closing", if needed */
4186 if (dpc->pos->start_step_opening == 0 &&
4187 dpc->pos->start_step_closing == 0)
4189 // dpc->pos->start_step_opening = dpc->pos->start_step;
4190 dpc->pos->start_step_closing = dpc->pos->start_step;
4193 /* fill structure for door part draw order (sorted below) */
4195 dpo->sort_priority = dpc->pos->sort_priority;
4198 /* sort door part controls according to sort_priority and graphic number */
4199 qsort(door_part_order, MAX_DOOR_PARTS,
4200 sizeof(struct DoorPartOrderInfo), compareDoorPartOrderInfo);
4203 unsigned int OpenDoor(unsigned int door_state)
4205 if (door_state & DOOR_COPY_BACK)
4207 if (door_state & DOOR_OPEN_1)
4208 BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
4209 1 * DXSIZE, 0, DXSIZE, DYSIZE, 0 * DXSIZE, 0);
4211 if (door_state & DOOR_OPEN_2)
4212 BlitBitmap(bitmap_db_door_2, bitmap_db_door_2,
4213 1 * VXSIZE, 0, VXSIZE, VYSIZE, 0 * VXSIZE, 0);
4215 door_state &= ~DOOR_COPY_BACK;
4218 return MoveDoor(door_state);
4221 unsigned int CloseDoor(unsigned int door_state)
4223 unsigned int old_door_state = GetDoorState();
4225 if (!(door_state & DOOR_NO_COPY_BACK))
4227 if (old_door_state & DOOR_OPEN_1)
4228 BlitBitmap(backbuffer, bitmap_db_door_1,
4229 DX, DY, DXSIZE, DYSIZE, 0, 0);
4231 if (old_door_state & DOOR_OPEN_2)
4232 BlitBitmap(backbuffer, bitmap_db_door_2,
4233 VX, VY, VXSIZE, VYSIZE, 0, 0);
4235 door_state &= ~DOOR_NO_COPY_BACK;
4238 return MoveDoor(door_state);
4241 unsigned int GetDoorState()
4243 return MoveDoor(DOOR_GET_STATE);
4246 unsigned int SetDoorState(unsigned int door_state)
4248 return MoveDoor(door_state | DOOR_SET_STATE);
4251 int euclid(int a, int b)
4253 return (b ? euclid(b, a % b) : a);
4256 unsigned int MoveDoor(unsigned int door_state)
4258 struct Rect door_rect_list[] =
4260 { DX, DY, DXSIZE, DYSIZE },
4261 { VX, VY, VXSIZE, VYSIZE }
4263 static int door1 = DOOR_CLOSE_1;
4264 static int door2 = DOOR_CLOSE_2;
4265 unsigned int door_delay = 0;
4266 unsigned int door_delay_value;
4269 if (door_state == DOOR_GET_STATE)
4270 return (door1 | door2);
4272 if (door_state & DOOR_SET_STATE)
4274 if (door_state & DOOR_ACTION_1)
4275 door1 = door_state & DOOR_ACTION_1;
4276 if (door_state & DOOR_ACTION_2)
4277 door2 = door_state & DOOR_ACTION_2;
4279 return (door1 | door2);
4282 if (!(door_state & DOOR_FORCE_REDRAW))
4284 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
4285 door_state &= ~DOOR_OPEN_1;
4286 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
4287 door_state &= ~DOOR_CLOSE_1;
4288 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
4289 door_state &= ~DOOR_OPEN_2;
4290 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
4291 door_state &= ~DOOR_CLOSE_2;
4294 if (global.autoplay_leveldir)
4296 door_state |= DOOR_NO_DELAY;
4297 door_state &= ~DOOR_CLOSE_ALL;
4300 if (game_status == GAME_MODE_EDITOR)
4301 door_state |= DOOR_NO_DELAY;
4303 if (door_state & DOOR_ACTION)
4305 boolean door_panel_drawn[NUM_DOORS];
4306 boolean panel_has_doors[NUM_DOORS];
4307 boolean door_part_skip[MAX_DOOR_PARTS];
4308 boolean door_part_done[MAX_DOOR_PARTS];
4309 boolean door_part_done_all;
4310 int num_steps[MAX_DOOR_PARTS];
4311 int max_move_delay = 0; // delay for complete animations of all doors
4312 int max_step_delay = 0; // delay (ms) between two animation frames
4313 int num_move_steps = 0; // number of animation steps for all doors
4314 int max_move_delay_doors_only = 0; // delay for doors only (no panel)
4315 int num_move_steps_doors_only = 0; // steps for doors only (no panel)
4316 int current_move_delay = 0;
4320 for (i = 0; i < NUM_DOORS; i++)
4321 panel_has_doors[i] = FALSE;
4323 for (i = 0; i < MAX_DOOR_PARTS; i++)
4325 struct DoorPartControlInfo *dpc = &door_part_controls[i];
4326 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4327 int door_token = dpc->door_token;
4329 door_part_done[i] = FALSE;
4330 door_part_skip[i] = (!(door_state & door_token) ||
4334 for (i = 0; i < MAX_DOOR_PARTS; i++)
4336 int nr = door_part_order[i].nr;
4337 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
4338 struct DoorPartPosInfo *pos = dpc->pos;
4339 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4340 int door_token = dpc->door_token;
4341 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
4342 boolean is_panel = DOOR_PART_IS_PANEL(nr);
4343 int step_xoffset = ABS(pos->step_xoffset);
4344 int step_yoffset = ABS(pos->step_yoffset);
4345 int step_delay = pos->step_delay;
4346 int current_door_state = door_state & door_token;
4347 boolean door_opening = ((current_door_state & DOOR_OPEN) != 0);
4348 boolean door_closing = ((current_door_state & DOOR_CLOSE) != 0);
4349 boolean part_opening = (is_panel ? door_closing : door_opening);
4350 int start_step = (part_opening ? pos->start_step_opening :
4351 pos->start_step_closing);
4352 float move_xsize = (step_xoffset ? g->width : 0);
4353 float move_ysize = (step_yoffset ? g->height : 0);
4354 int move_xsteps = (step_xoffset ? ceil(move_xsize / step_xoffset) : 0);
4355 int move_ysteps = (step_yoffset ? ceil(move_ysize / step_yoffset) : 0);
4356 int move_steps = (move_xsteps && move_ysteps ?
4357 MIN(move_xsteps, move_ysteps) :
4358 move_xsteps ? move_xsteps : move_ysteps) - start_step;
4359 int move_delay = move_steps * step_delay;
4361 if (door_part_skip[nr])
4364 max_move_delay = MAX(max_move_delay, move_delay);
4365 max_step_delay = (max_step_delay == 0 ? step_delay :
4366 euclid(max_step_delay, step_delay));
4367 num_steps[nr] = move_steps;
4371 max_move_delay_doors_only = MAX(max_move_delay_doors_only, move_delay);
4373 panel_has_doors[door_index] = TRUE;
4377 max_step_delay = MAX(1, max_step_delay); // prevent division by zero
4379 num_move_steps = max_move_delay / max_step_delay;
4380 num_move_steps_doors_only = max_move_delay_doors_only / max_step_delay;
4382 door_delay_value = max_step_delay;
4384 if ((door_state & DOOR_NO_DELAY) || setup.quick_doors)
4386 start = num_move_steps - 1;
4390 /* opening door sound has priority over simultaneously closing door */
4391 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
4392 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
4393 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
4394 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
4397 for (k = start; k < num_move_steps; k++)
4399 int last_frame = num_move_steps - 1; // last frame of this "for" loop
4401 door_part_done_all = TRUE;
4403 for (i = 0; i < NUM_DOORS; i++)
4404 door_panel_drawn[i] = FALSE;
4406 for (i = 0; i < MAX_DOOR_PARTS; i++)
4408 int nr = door_part_order[i].nr;
4409 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
4410 struct DoorPartPosInfo *pos = dpc->pos;
4411 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4412 int door_token = dpc->door_token;
4413 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
4414 boolean is_panel = DOOR_PART_IS_PANEL(nr);
4415 boolean is_panel_and_door_has_closed = FALSE;
4416 struct Rect *door_rect = &door_rect_list[door_index];
4417 Bitmap *bitmap_db_door = (door_token == DOOR_1 ? bitmap_db_door_1 :
4419 Bitmap *bitmap = (is_panel ? bitmap_db_door : g->bitmap);
4420 int current_door_state = door_state & door_token;
4421 boolean door_opening = ((current_door_state & DOOR_OPEN) != 0);
4422 boolean door_closing = !door_opening;
4423 boolean part_opening = (is_panel ? door_closing : door_opening);
4424 boolean part_closing = !part_opening;
4425 int start_step = (part_opening ? pos->start_step_opening :
4426 pos->start_step_closing);
4427 int step_delay = pos->step_delay;
4428 int step_factor = step_delay / max_step_delay;
4429 int k1 = (step_factor ? k / step_factor + 1 : k);
4430 int k2 = (part_opening ? k1 + start_step : num_steps[nr] - k1);
4431 int kk = MAX(0, k2);
4434 int src_x, src_y, src_xx, src_yy;
4435 int dst_x, dst_y, dst_xx, dst_yy;
4438 if (door_part_skip[nr])
4441 if (!(door_state & door_token))
4449 int k2_door = (door_opening ? k : num_move_steps_doors_only - k - 1);
4450 int kk_door = MAX(0, k2_door);
4451 int sync_frame = kk_door * door_delay_value;
4452 int frame = getGraphicAnimationFrame(dpc->graphic, sync_frame);
4454 getGraphicSource(dpc->graphic, frame, &bitmap, &g_src_x, &g_src_y);
4459 if (!door_panel_drawn[door_index])
4461 ClearRectangle(drawto, door_rect->x, door_rect->y,
4462 door_rect->width, door_rect->height);
4464 door_panel_drawn[door_index] = TRUE;
4467 // draw opening or closing door parts
4469 if (pos->step_xoffset < 0) // door part on right side
4472 dst_xx = pos->x + ABS(kk * pos->step_xoffset);
4475 if (dst_xx + width > door_rect->width)
4476 width = door_rect->width - dst_xx;
4478 else // door part on left side
4481 dst_xx = pos->x - kk * pos->step_xoffset;
4485 src_xx = ABS(dst_xx);
4489 width = g->width - src_xx;
4491 if (width > door_rect->width)
4492 width = door_rect->width;
4494 // printf("::: k == %d [%d] \n", k, start_step);
4497 if (pos->step_yoffset < 0) // door part on bottom side
4500 dst_yy = pos->y + ABS(kk * pos->step_yoffset);
4503 if (dst_yy + height > door_rect->height)
4504 height = door_rect->height - dst_yy;
4506 else // door part on top side
4509 dst_yy = pos->y - kk * pos->step_yoffset;
4513 src_yy = ABS(dst_yy);
4517 height = g->height - src_yy;
4520 src_x = g_src_x + src_xx;
4521 src_y = g_src_y + src_yy;
4523 dst_x = door_rect->x + dst_xx;
4524 dst_y = door_rect->y + dst_yy;
4526 is_panel_and_door_has_closed =
4529 panel_has_doors[door_index] &&
4530 k >= num_move_steps_doors_only - 1);
4532 if (width >= 0 && width <= g->width &&
4533 height >= 0 && height <= g->height &&
4534 !is_panel_and_door_has_closed)
4536 if (is_panel || !pos->draw_masked)
4537 BlitBitmap(bitmap, drawto, src_x, src_y, width, height,
4540 BlitBitmapMasked(bitmap, drawto, src_x, src_y, width, height,
4544 redraw_mask |= REDRAW_DOOR_FROM_TOKEN(door_token);
4546 if ((part_opening && (width < 0 || height < 0)) ||
4547 (part_closing && (width >= g->width && height >= g->height)))
4548 door_part_done[nr] = TRUE;
4550 // continue door part animations, but not panel after door has closed
4551 if (!door_part_done[nr] && !is_panel_and_door_has_closed)
4552 door_part_done_all = FALSE;
4555 if (!(door_state & DOOR_NO_DELAY))
4559 SkipUntilDelayReached(&door_delay, door_delay_value, &k, last_frame);
4561 current_move_delay += max_step_delay;
4564 if (door_part_done_all)
4569 if (door_state & DOOR_ACTION_1)
4570 door1 = door_state & DOOR_ACTION_1;
4571 if (door_state & DOOR_ACTION_2)
4572 door2 = door_state & DOOR_ACTION_2;
4574 // draw masked border over door area
4575 DrawMaskedBorder(REDRAW_DOOR_1);
4576 DrawMaskedBorder(REDRAW_DOOR_2);
4578 return (door1 | door2);
4581 static boolean useSpecialEditorDoor()
4583 int graphic = IMG_GLOBAL_BORDER_EDITOR;
4584 boolean redefined = getImageListEntryFromImageID(graphic)->redefined;
4586 // do not draw special editor door if editor border defined or redefined
4587 if (graphic_info[graphic].bitmap != NULL || redefined)
4590 // do not draw special editor door if global border defined to be empty
4591 if (graphic_info[IMG_GLOBAL_BORDER].bitmap == NULL)
4594 // do not draw special editor door if viewport definitions do not match
4598 EY + EYSIZE != VY + VYSIZE)
4604 void DrawSpecialEditorDoor()
4606 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
4607 int top_border_width = gfx1->width;
4608 int top_border_height = gfx1->height;
4609 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
4610 int ex = EX - outer_border;
4611 int ey = EY - outer_border;
4612 int vy = VY - outer_border;
4613 int exsize = EXSIZE + 2 * outer_border;
4615 if (!useSpecialEditorDoor())
4618 /* draw bigger level editor toolbox window */
4619 BlitBitmap(gfx1->bitmap, drawto, gfx1->src_x, gfx1->src_y,
4620 top_border_width, top_border_height, ex, ey - top_border_height);
4621 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto, ex, vy,
4622 exsize, EYSIZE - VYSIZE + outer_border, ex, ey);
4624 redraw_mask |= REDRAW_ALL;
4627 void UndrawSpecialEditorDoor()
4629 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
4630 int top_border_width = gfx1->width;
4631 int top_border_height = gfx1->height;
4632 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
4633 int ex = EX - outer_border;
4634 int ey = EY - outer_border;
4635 int ey_top = ey - top_border_height;
4636 int exsize = EXSIZE + 2 * outer_border;
4637 int eysize = EYSIZE + 2 * outer_border;
4639 if (!useSpecialEditorDoor())
4642 /* draw normal tape recorder window */
4643 if (graphic_info[IMG_GLOBAL_BORDER].bitmap)
4645 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
4646 ex, ey_top, top_border_width, top_border_height,
4648 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
4649 ex, ey, exsize, eysize, ex, ey);
4653 // if screen background is set to "[NONE]", clear editor toolbox window
4654 ClearRectangle(drawto, ex, ey_top, top_border_width, top_border_height);
4655 ClearRectangle(drawto, ex, ey, exsize, eysize);
4658 redraw_mask |= REDRAW_ALL;
4662 /* ---------- new tool button stuff ---------------------------------------- */
4667 struct TextPosInfo *pos;
4670 } toolbutton_info[NUM_TOOL_BUTTONS] =
4673 IMG_GFX_REQUEST_BUTTON_YES, &request.button.yes,
4674 TOOL_CTRL_ID_YES, "yes"
4677 IMG_GFX_REQUEST_BUTTON_NO, &request.button.no,
4678 TOOL_CTRL_ID_NO, "no"
4681 IMG_GFX_REQUEST_BUTTON_CONFIRM, &request.button.confirm,
4682 TOOL_CTRL_ID_CONFIRM, "confirm"
4685 IMG_GFX_REQUEST_BUTTON_PLAYER_1, &request.button.player_1,
4686 TOOL_CTRL_ID_PLAYER_1, "player 1"
4689 IMG_GFX_REQUEST_BUTTON_PLAYER_2, &request.button.player_2,
4690 TOOL_CTRL_ID_PLAYER_2, "player 2"
4693 IMG_GFX_REQUEST_BUTTON_PLAYER_3, &request.button.player_3,
4694 TOOL_CTRL_ID_PLAYER_3, "player 3"
4697 IMG_GFX_REQUEST_BUTTON_PLAYER_4, &request.button.player_4,
4698 TOOL_CTRL_ID_PLAYER_4, "player 4"
4702 void CreateToolButtons()
4706 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4708 struct GraphicInfo *gfx = &graphic_info[toolbutton_info[i].graphic];
4709 struct TextPosInfo *pos = toolbutton_info[i].pos;
4710 struct GadgetInfo *gi;
4711 Bitmap *deco_bitmap = None;
4712 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
4713 unsigned int event_mask = GD_EVENT_RELEASED;
4716 int gd_x = gfx->src_x;
4717 int gd_y = gfx->src_y;
4718 int gd_xp = gfx->src_x + gfx->pressed_xoffset;
4719 int gd_yp = gfx->src_y + gfx->pressed_yoffset;
4722 if (global.use_envelope_request)
4723 setRequestPosition(&dx, &dy, TRUE);
4725 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
4727 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
4729 getSizedGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr), 0,
4730 pos->size, &deco_bitmap, &deco_x, &deco_y);
4731 deco_xpos = (gfx->width - pos->size) / 2;
4732 deco_ypos = (gfx->height - pos->size) / 2;
4735 gi = CreateGadget(GDI_CUSTOM_ID, id,
4736 GDI_INFO_TEXT, toolbutton_info[i].infotext,
4737 GDI_X, dx + GDI_ACTIVE_POS(pos->x),
4738 GDI_Y, dy + GDI_ACTIVE_POS(pos->y),
4739 GDI_WIDTH, gfx->width,
4740 GDI_HEIGHT, gfx->height,
4741 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
4742 GDI_STATE, GD_BUTTON_UNPRESSED,
4743 GDI_DESIGN_UNPRESSED, gfx->bitmap, gd_x, gd_y,
4744 GDI_DESIGN_PRESSED, gfx->bitmap, gd_xp, gd_yp,
4745 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
4746 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
4747 GDI_DECORATION_SIZE, pos->size, pos->size,
4748 GDI_DECORATION_SHIFTING, 1, 1,
4749 GDI_DIRECT_DRAW, FALSE,
4750 GDI_EVENT_MASK, event_mask,
4751 GDI_CALLBACK_ACTION, HandleToolButtons,
4755 Error(ERR_EXIT, "cannot create gadget");
4757 tool_gadget[id] = gi;
4761 void FreeToolButtons()
4765 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4766 FreeGadget(tool_gadget[i]);
4769 static void UnmapToolButtons()
4773 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4774 UnmapGadget(tool_gadget[i]);
4777 static void HandleToolButtons(struct GadgetInfo *gi)
4779 request_gadget_id = gi->custom_id;
4782 static struct Mapping_EM_to_RND_object
4785 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
4786 boolean is_backside; /* backside of moving element */
4792 em_object_mapping_list[] =
4795 Xblank, TRUE, FALSE,
4799 Yacid_splash_eB, FALSE, FALSE,
4800 EL_ACID_SPLASH_RIGHT, -1, -1
4803 Yacid_splash_wB, FALSE, FALSE,
4804 EL_ACID_SPLASH_LEFT, -1, -1
4807 #ifdef EM_ENGINE_BAD_ROLL
4809 Xstone_force_e, FALSE, FALSE,
4810 EL_ROCK, -1, MV_BIT_RIGHT
4813 Xstone_force_w, FALSE, FALSE,
4814 EL_ROCK, -1, MV_BIT_LEFT
4817 Xnut_force_e, FALSE, FALSE,
4818 EL_NUT, -1, MV_BIT_RIGHT
4821 Xnut_force_w, FALSE, FALSE,
4822 EL_NUT, -1, MV_BIT_LEFT
4825 Xspring_force_e, FALSE, FALSE,
4826 EL_SPRING, -1, MV_BIT_RIGHT
4829 Xspring_force_w, FALSE, FALSE,
4830 EL_SPRING, -1, MV_BIT_LEFT
4833 Xemerald_force_e, FALSE, FALSE,
4834 EL_EMERALD, -1, MV_BIT_RIGHT
4837 Xemerald_force_w, FALSE, FALSE,
4838 EL_EMERALD, -1, MV_BIT_LEFT
4841 Xdiamond_force_e, FALSE, FALSE,
4842 EL_DIAMOND, -1, MV_BIT_RIGHT
4845 Xdiamond_force_w, FALSE, FALSE,
4846 EL_DIAMOND, -1, MV_BIT_LEFT
4849 Xbomb_force_e, FALSE, FALSE,
4850 EL_BOMB, -1, MV_BIT_RIGHT
4853 Xbomb_force_w, FALSE, FALSE,
4854 EL_BOMB, -1, MV_BIT_LEFT
4856 #endif /* EM_ENGINE_BAD_ROLL */
4859 Xstone, TRUE, FALSE,
4863 Xstone_pause, FALSE, FALSE,
4867 Xstone_fall, FALSE, FALSE,
4871 Ystone_s, FALSE, FALSE,
4872 EL_ROCK, ACTION_FALLING, -1
4875 Ystone_sB, FALSE, TRUE,
4876 EL_ROCK, ACTION_FALLING, -1
4879 Ystone_e, FALSE, FALSE,
4880 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
4883 Ystone_eB, FALSE, TRUE,
4884 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
4887 Ystone_w, FALSE, FALSE,
4888 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
4891 Ystone_wB, FALSE, TRUE,
4892 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
4899 Xnut_pause, FALSE, FALSE,
4903 Xnut_fall, FALSE, FALSE,
4907 Ynut_s, FALSE, FALSE,
4908 EL_NUT, ACTION_FALLING, -1
4911 Ynut_sB, FALSE, TRUE,
4912 EL_NUT, ACTION_FALLING, -1
4915 Ynut_e, FALSE, FALSE,
4916 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
4919 Ynut_eB, FALSE, TRUE,
4920 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
4923 Ynut_w, FALSE, FALSE,
4924 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
4927 Ynut_wB, FALSE, TRUE,
4928 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
4931 Xbug_n, TRUE, FALSE,
4935 Xbug_e, TRUE, FALSE,
4936 EL_BUG_RIGHT, -1, -1
4939 Xbug_s, TRUE, FALSE,
4943 Xbug_w, TRUE, FALSE,
4947 Xbug_gon, FALSE, FALSE,
4951 Xbug_goe, FALSE, FALSE,
4952 EL_BUG_RIGHT, -1, -1
4955 Xbug_gos, FALSE, FALSE,
4959 Xbug_gow, FALSE, FALSE,
4963 Ybug_n, FALSE, FALSE,
4964 EL_BUG, ACTION_MOVING, MV_BIT_UP
4967 Ybug_nB, FALSE, TRUE,
4968 EL_BUG, ACTION_MOVING, MV_BIT_UP
4971 Ybug_e, FALSE, FALSE,
4972 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
4975 Ybug_eB, FALSE, TRUE,
4976 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
4979 Ybug_s, FALSE, FALSE,
4980 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
4983 Ybug_sB, FALSE, TRUE,
4984 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
4987 Ybug_w, FALSE, FALSE,
4988 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
4991 Ybug_wB, FALSE, TRUE,
4992 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
4995 Ybug_w_n, FALSE, FALSE,
4996 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
4999 Ybug_n_e, FALSE, FALSE,
5000 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
5003 Ybug_e_s, FALSE, FALSE,
5004 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
5007 Ybug_s_w, FALSE, FALSE,
5008 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
5011 Ybug_e_n, FALSE, FALSE,
5012 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
5015 Ybug_s_e, FALSE, FALSE,
5016 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
5019 Ybug_w_s, FALSE, FALSE,
5020 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
5023 Ybug_n_w, FALSE, FALSE,
5024 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
5027 Ybug_stone, FALSE, FALSE,
5028 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
5031 Ybug_spring, FALSE, FALSE,
5032 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
5035 Xtank_n, TRUE, FALSE,
5036 EL_SPACESHIP_UP, -1, -1
5039 Xtank_e, TRUE, FALSE,
5040 EL_SPACESHIP_RIGHT, -1, -1
5043 Xtank_s, TRUE, FALSE,
5044 EL_SPACESHIP_DOWN, -1, -1
5047 Xtank_w, TRUE, FALSE,
5048 EL_SPACESHIP_LEFT, -1, -1
5051 Xtank_gon, FALSE, FALSE,
5052 EL_SPACESHIP_UP, -1, -1
5055 Xtank_goe, FALSE, FALSE,
5056 EL_SPACESHIP_RIGHT, -1, -1
5059 Xtank_gos, FALSE, FALSE,
5060 EL_SPACESHIP_DOWN, -1, -1
5063 Xtank_gow, FALSE, FALSE,
5064 EL_SPACESHIP_LEFT, -1, -1
5067 Ytank_n, FALSE, FALSE,
5068 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
5071 Ytank_nB, FALSE, TRUE,
5072 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
5075 Ytank_e, FALSE, FALSE,
5076 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
5079 Ytank_eB, FALSE, TRUE,
5080 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
5083 Ytank_s, FALSE, FALSE,
5084 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
5087 Ytank_sB, FALSE, TRUE,
5088 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
5091 Ytank_w, FALSE, FALSE,
5092 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
5095 Ytank_wB, FALSE, TRUE,
5096 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
5099 Ytank_w_n, FALSE, FALSE,
5100 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
5103 Ytank_n_e, FALSE, FALSE,
5104 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
5107 Ytank_e_s, FALSE, FALSE,
5108 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
5111 Ytank_s_w, FALSE, FALSE,
5112 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
5115 Ytank_e_n, FALSE, FALSE,
5116 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
5119 Ytank_s_e, FALSE, FALSE,
5120 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
5123 Ytank_w_s, FALSE, FALSE,
5124 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
5127 Ytank_n_w, FALSE, FALSE,
5128 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
5131 Ytank_stone, FALSE, FALSE,
5132 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
5135 Ytank_spring, FALSE, FALSE,
5136 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
5139 Xandroid, TRUE, FALSE,
5140 EL_EMC_ANDROID, ACTION_ACTIVE, -1
5143 Xandroid_1_n, FALSE, FALSE,
5144 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
5147 Xandroid_2_n, FALSE, FALSE,
5148 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
5151 Xandroid_1_e, FALSE, FALSE,
5152 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
5155 Xandroid_2_e, FALSE, FALSE,
5156 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
5159 Xandroid_1_w, FALSE, FALSE,
5160 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
5163 Xandroid_2_w, FALSE, FALSE,
5164 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
5167 Xandroid_1_s, FALSE, FALSE,
5168 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
5171 Xandroid_2_s, FALSE, FALSE,
5172 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
5175 Yandroid_n, FALSE, FALSE,
5176 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
5179 Yandroid_nB, FALSE, TRUE,
5180 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
5183 Yandroid_ne, FALSE, FALSE,
5184 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
5187 Yandroid_neB, FALSE, TRUE,
5188 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
5191 Yandroid_e, FALSE, FALSE,
5192 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
5195 Yandroid_eB, FALSE, TRUE,
5196 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
5199 Yandroid_se, FALSE, FALSE,
5200 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
5203 Yandroid_seB, FALSE, TRUE,
5204 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
5207 Yandroid_s, FALSE, FALSE,
5208 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
5211 Yandroid_sB, FALSE, TRUE,
5212 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
5215 Yandroid_sw, FALSE, FALSE,
5216 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
5219 Yandroid_swB, FALSE, TRUE,
5220 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
5223 Yandroid_w, FALSE, FALSE,
5224 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
5227 Yandroid_wB, FALSE, TRUE,
5228 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
5231 Yandroid_nw, FALSE, FALSE,
5232 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
5235 Yandroid_nwB, FALSE, TRUE,
5236 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
5239 Xspring, TRUE, FALSE,
5243 Xspring_pause, FALSE, FALSE,
5247 Xspring_e, FALSE, FALSE,
5251 Xspring_w, FALSE, FALSE,
5255 Xspring_fall, FALSE, FALSE,
5259 Yspring_s, FALSE, FALSE,
5260 EL_SPRING, ACTION_FALLING, -1
5263 Yspring_sB, FALSE, TRUE,
5264 EL_SPRING, ACTION_FALLING, -1
5267 Yspring_e, FALSE, FALSE,
5268 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
5271 Yspring_eB, FALSE, TRUE,
5272 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
5275 Yspring_w, FALSE, FALSE,
5276 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
5279 Yspring_wB, FALSE, TRUE,
5280 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
5283 Yspring_kill_e, FALSE, FALSE,
5284 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
5287 Yspring_kill_eB, FALSE, TRUE,
5288 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
5291 Yspring_kill_w, FALSE, FALSE,
5292 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
5295 Yspring_kill_wB, FALSE, TRUE,
5296 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
5299 Xeater_n, TRUE, FALSE,
5300 EL_YAMYAM_UP, -1, -1
5303 Xeater_e, TRUE, FALSE,
5304 EL_YAMYAM_RIGHT, -1, -1
5307 Xeater_w, TRUE, FALSE,
5308 EL_YAMYAM_LEFT, -1, -1
5311 Xeater_s, TRUE, FALSE,
5312 EL_YAMYAM_DOWN, -1, -1
5315 Yeater_n, FALSE, FALSE,
5316 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
5319 Yeater_nB, FALSE, TRUE,
5320 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
5323 Yeater_e, FALSE, FALSE,
5324 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
5327 Yeater_eB, FALSE, TRUE,
5328 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
5331 Yeater_s, FALSE, FALSE,
5332 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
5335 Yeater_sB, FALSE, TRUE,
5336 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
5339 Yeater_w, FALSE, FALSE,
5340 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
5343 Yeater_wB, FALSE, TRUE,
5344 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
5347 Yeater_stone, FALSE, FALSE,
5348 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
5351 Yeater_spring, FALSE, FALSE,
5352 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
5355 Xalien, TRUE, FALSE,
5359 Xalien_pause, FALSE, FALSE,
5363 Yalien_n, FALSE, FALSE,
5364 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
5367 Yalien_nB, FALSE, TRUE,
5368 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
5371 Yalien_e, FALSE, FALSE,
5372 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
5375 Yalien_eB, FALSE, TRUE,
5376 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
5379 Yalien_s, FALSE, FALSE,
5380 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
5383 Yalien_sB, FALSE, TRUE,
5384 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
5387 Yalien_w, FALSE, FALSE,
5388 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
5391 Yalien_wB, FALSE, TRUE,
5392 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
5395 Yalien_stone, FALSE, FALSE,
5396 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
5399 Yalien_spring, FALSE, FALSE,
5400 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
5403 Xemerald, TRUE, FALSE,
5407 Xemerald_pause, FALSE, FALSE,
5411 Xemerald_fall, FALSE, FALSE,
5415 Xemerald_shine, FALSE, FALSE,
5416 EL_EMERALD, ACTION_TWINKLING, -1
5419 Yemerald_s, FALSE, FALSE,
5420 EL_EMERALD, ACTION_FALLING, -1
5423 Yemerald_sB, FALSE, TRUE,
5424 EL_EMERALD, ACTION_FALLING, -1
5427 Yemerald_e, FALSE, FALSE,
5428 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
5431 Yemerald_eB, FALSE, TRUE,
5432 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
5435 Yemerald_w, FALSE, FALSE,
5436 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
5439 Yemerald_wB, FALSE, TRUE,
5440 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
5443 Yemerald_eat, FALSE, FALSE,
5444 EL_EMERALD, ACTION_COLLECTING, -1
5447 Yemerald_stone, FALSE, FALSE,
5448 EL_NUT, ACTION_BREAKING, -1
5451 Xdiamond, TRUE, FALSE,
5455 Xdiamond_pause, FALSE, FALSE,
5459 Xdiamond_fall, FALSE, FALSE,
5463 Xdiamond_shine, FALSE, FALSE,
5464 EL_DIAMOND, ACTION_TWINKLING, -1
5467 Ydiamond_s, FALSE, FALSE,
5468 EL_DIAMOND, ACTION_FALLING, -1
5471 Ydiamond_sB, FALSE, TRUE,
5472 EL_DIAMOND, ACTION_FALLING, -1
5475 Ydiamond_e, FALSE, FALSE,
5476 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
5479 Ydiamond_eB, FALSE, TRUE,
5480 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
5483 Ydiamond_w, FALSE, FALSE,
5484 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
5487 Ydiamond_wB, FALSE, TRUE,
5488 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
5491 Ydiamond_eat, FALSE, FALSE,
5492 EL_DIAMOND, ACTION_COLLECTING, -1
5495 Ydiamond_stone, FALSE, FALSE,
5496 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
5499 Xdrip_fall, TRUE, FALSE,
5500 EL_AMOEBA_DROP, -1, -1
5503 Xdrip_stretch, FALSE, FALSE,
5504 EL_AMOEBA_DROP, ACTION_FALLING, -1
5507 Xdrip_stretchB, FALSE, TRUE,
5508 EL_AMOEBA_DROP, ACTION_FALLING, -1
5511 Xdrip_eat, FALSE, FALSE,
5512 EL_AMOEBA_DROP, ACTION_GROWING, -1
5515 Ydrip_s1, FALSE, FALSE,
5516 EL_AMOEBA_DROP, ACTION_FALLING, -1
5519 Ydrip_s1B, FALSE, TRUE,
5520 EL_AMOEBA_DROP, ACTION_FALLING, -1
5523 Ydrip_s2, FALSE, FALSE,
5524 EL_AMOEBA_DROP, ACTION_FALLING, -1
5527 Ydrip_s2B, FALSE, TRUE,
5528 EL_AMOEBA_DROP, ACTION_FALLING, -1
5535 Xbomb_pause, FALSE, FALSE,
5539 Xbomb_fall, FALSE, FALSE,
5543 Ybomb_s, FALSE, FALSE,
5544 EL_BOMB, ACTION_FALLING, -1
5547 Ybomb_sB, FALSE, TRUE,
5548 EL_BOMB, ACTION_FALLING, -1
5551 Ybomb_e, FALSE, FALSE,
5552 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
5555 Ybomb_eB, FALSE, TRUE,
5556 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
5559 Ybomb_w, FALSE, FALSE,
5560 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
5563 Ybomb_wB, FALSE, TRUE,
5564 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
5567 Ybomb_eat, FALSE, FALSE,
5568 EL_BOMB, ACTION_ACTIVATING, -1
5571 Xballoon, TRUE, FALSE,
5575 Yballoon_n, FALSE, FALSE,
5576 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
5579 Yballoon_nB, FALSE, TRUE,
5580 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
5583 Yballoon_e, FALSE, FALSE,
5584 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
5587 Yballoon_eB, FALSE, TRUE,
5588 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
5591 Yballoon_s, FALSE, FALSE,
5592 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
5595 Yballoon_sB, FALSE, TRUE,
5596 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
5599 Yballoon_w, FALSE, FALSE,
5600 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
5603 Yballoon_wB, FALSE, TRUE,
5604 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
5607 Xgrass, TRUE, FALSE,
5608 EL_EMC_GRASS, -1, -1
5611 Ygrass_nB, FALSE, FALSE,
5612 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
5615 Ygrass_eB, FALSE, FALSE,
5616 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
5619 Ygrass_sB, FALSE, FALSE,
5620 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
5623 Ygrass_wB, FALSE, FALSE,
5624 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
5631 Ydirt_nB, FALSE, FALSE,
5632 EL_SAND, ACTION_DIGGING, MV_BIT_UP
5635 Ydirt_eB, FALSE, FALSE,
5636 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
5639 Ydirt_sB, FALSE, FALSE,
5640 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
5643 Ydirt_wB, FALSE, FALSE,
5644 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
5647 Xacid_ne, TRUE, FALSE,
5648 EL_ACID_POOL_TOPRIGHT, -1, -1
5651 Xacid_se, TRUE, FALSE,
5652 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
5655 Xacid_s, TRUE, FALSE,
5656 EL_ACID_POOL_BOTTOM, -1, -1
5659 Xacid_sw, TRUE, FALSE,
5660 EL_ACID_POOL_BOTTOMLEFT, -1, -1
5663 Xacid_nw, TRUE, FALSE,
5664 EL_ACID_POOL_TOPLEFT, -1, -1
5667 Xacid_1, TRUE, FALSE,
5671 Xacid_2, FALSE, FALSE,
5675 Xacid_3, FALSE, FALSE,
5679 Xacid_4, FALSE, FALSE,
5683 Xacid_5, FALSE, FALSE,
5687 Xacid_6, FALSE, FALSE,
5691 Xacid_7, FALSE, FALSE,
5695 Xacid_8, FALSE, FALSE,
5699 Xball_1, TRUE, FALSE,
5700 EL_EMC_MAGIC_BALL, -1, -1
5703 Xball_1B, FALSE, FALSE,
5704 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5707 Xball_2, FALSE, FALSE,
5708 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5711 Xball_2B, FALSE, FALSE,
5712 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5715 Yball_eat, FALSE, FALSE,
5716 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
5719 Ykey_1_eat, FALSE, FALSE,
5720 EL_EM_KEY_1, ACTION_COLLECTING, -1
5723 Ykey_2_eat, FALSE, FALSE,
5724 EL_EM_KEY_2, ACTION_COLLECTING, -1
5727 Ykey_3_eat, FALSE, FALSE,
5728 EL_EM_KEY_3, ACTION_COLLECTING, -1
5731 Ykey_4_eat, FALSE, FALSE,
5732 EL_EM_KEY_4, ACTION_COLLECTING, -1
5735 Ykey_5_eat, FALSE, FALSE,
5736 EL_EMC_KEY_5, ACTION_COLLECTING, -1
5739 Ykey_6_eat, FALSE, FALSE,
5740 EL_EMC_KEY_6, ACTION_COLLECTING, -1
5743 Ykey_7_eat, FALSE, FALSE,
5744 EL_EMC_KEY_7, ACTION_COLLECTING, -1
5747 Ykey_8_eat, FALSE, FALSE,
5748 EL_EMC_KEY_8, ACTION_COLLECTING, -1
5751 Ylenses_eat, FALSE, FALSE,
5752 EL_EMC_LENSES, ACTION_COLLECTING, -1
5755 Ymagnify_eat, FALSE, FALSE,
5756 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
5759 Ygrass_eat, FALSE, FALSE,
5760 EL_EMC_GRASS, ACTION_SNAPPING, -1
5763 Ydirt_eat, FALSE, FALSE,
5764 EL_SAND, ACTION_SNAPPING, -1
5767 Xgrow_ns, TRUE, FALSE,
5768 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
5771 Ygrow_ns_eat, FALSE, FALSE,
5772 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
5775 Xgrow_ew, TRUE, FALSE,
5776 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
5779 Ygrow_ew_eat, FALSE, FALSE,
5780 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
5783 Xwonderwall, TRUE, FALSE,
5784 EL_MAGIC_WALL, -1, -1
5787 XwonderwallB, FALSE, FALSE,
5788 EL_MAGIC_WALL, ACTION_ACTIVE, -1
5791 Xamoeba_1, TRUE, FALSE,
5792 EL_AMOEBA_DRY, ACTION_OTHER, -1
5795 Xamoeba_2, FALSE, FALSE,
5796 EL_AMOEBA_DRY, ACTION_OTHER, -1
5799 Xamoeba_3, FALSE, FALSE,
5800 EL_AMOEBA_DRY, ACTION_OTHER, -1
5803 Xamoeba_4, FALSE, FALSE,
5804 EL_AMOEBA_DRY, ACTION_OTHER, -1
5807 Xamoeba_5, TRUE, FALSE,
5808 EL_AMOEBA_WET, ACTION_OTHER, -1
5811 Xamoeba_6, FALSE, FALSE,
5812 EL_AMOEBA_WET, ACTION_OTHER, -1
5815 Xamoeba_7, FALSE, FALSE,
5816 EL_AMOEBA_WET, ACTION_OTHER, -1
5819 Xamoeba_8, FALSE, FALSE,
5820 EL_AMOEBA_WET, ACTION_OTHER, -1
5823 Xdoor_1, TRUE, FALSE,
5824 EL_EM_GATE_1, -1, -1
5827 Xdoor_2, TRUE, FALSE,
5828 EL_EM_GATE_2, -1, -1
5831 Xdoor_3, TRUE, FALSE,
5832 EL_EM_GATE_3, -1, -1
5835 Xdoor_4, TRUE, FALSE,
5836 EL_EM_GATE_4, -1, -1
5839 Xdoor_5, TRUE, FALSE,
5840 EL_EMC_GATE_5, -1, -1
5843 Xdoor_6, TRUE, FALSE,
5844 EL_EMC_GATE_6, -1, -1
5847 Xdoor_7, TRUE, FALSE,
5848 EL_EMC_GATE_7, -1, -1
5851 Xdoor_8, TRUE, FALSE,
5852 EL_EMC_GATE_8, -1, -1
5855 Xkey_1, TRUE, FALSE,
5859 Xkey_2, TRUE, FALSE,
5863 Xkey_3, TRUE, FALSE,
5867 Xkey_4, TRUE, FALSE,
5871 Xkey_5, TRUE, FALSE,
5872 EL_EMC_KEY_5, -1, -1
5875 Xkey_6, TRUE, FALSE,
5876 EL_EMC_KEY_6, -1, -1
5879 Xkey_7, TRUE, FALSE,
5880 EL_EMC_KEY_7, -1, -1
5883 Xkey_8, TRUE, FALSE,
5884 EL_EMC_KEY_8, -1, -1
5887 Xwind_n, TRUE, FALSE,
5888 EL_BALLOON_SWITCH_UP, -1, -1
5891 Xwind_e, TRUE, FALSE,
5892 EL_BALLOON_SWITCH_RIGHT, -1, -1
5895 Xwind_s, TRUE, FALSE,
5896 EL_BALLOON_SWITCH_DOWN, -1, -1
5899 Xwind_w, TRUE, FALSE,
5900 EL_BALLOON_SWITCH_LEFT, -1, -1
5903 Xwind_nesw, TRUE, FALSE,
5904 EL_BALLOON_SWITCH_ANY, -1, -1
5907 Xwind_stop, TRUE, FALSE,
5908 EL_BALLOON_SWITCH_NONE, -1, -1
5912 EL_EM_EXIT_CLOSED, -1, -1
5915 Xexit_1, TRUE, FALSE,
5916 EL_EM_EXIT_OPEN, -1, -1
5919 Xexit_2, FALSE, FALSE,
5920 EL_EM_EXIT_OPEN, -1, -1
5923 Xexit_3, FALSE, FALSE,
5924 EL_EM_EXIT_OPEN, -1, -1
5927 Xdynamite, TRUE, FALSE,
5928 EL_EM_DYNAMITE, -1, -1
5931 Ydynamite_eat, FALSE, FALSE,
5932 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
5935 Xdynamite_1, TRUE, FALSE,
5936 EL_EM_DYNAMITE_ACTIVE, -1, -1
5939 Xdynamite_2, FALSE, FALSE,
5940 EL_EM_DYNAMITE_ACTIVE, -1, -1
5943 Xdynamite_3, FALSE, FALSE,
5944 EL_EM_DYNAMITE_ACTIVE, -1, -1
5947 Xdynamite_4, FALSE, FALSE,
5948 EL_EM_DYNAMITE_ACTIVE, -1, -1
5951 Xbumper, TRUE, FALSE,
5952 EL_EMC_SPRING_BUMPER, -1, -1
5955 XbumperB, FALSE, FALSE,
5956 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
5959 Xwheel, TRUE, FALSE,
5960 EL_ROBOT_WHEEL, -1, -1
5963 XwheelB, FALSE, FALSE,
5964 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
5967 Xswitch, TRUE, FALSE,
5968 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
5971 XswitchB, FALSE, FALSE,
5972 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
5976 EL_QUICKSAND_EMPTY, -1, -1
5979 Xsand_stone, TRUE, FALSE,
5980 EL_QUICKSAND_FULL, -1, -1
5983 Xsand_stonein_1, FALSE, TRUE,
5984 EL_ROCK, ACTION_FILLING, -1
5987 Xsand_stonein_2, FALSE, TRUE,
5988 EL_ROCK, ACTION_FILLING, -1
5991 Xsand_stonein_3, FALSE, TRUE,
5992 EL_ROCK, ACTION_FILLING, -1
5995 Xsand_stonein_4, FALSE, TRUE,
5996 EL_ROCK, ACTION_FILLING, -1
5999 Xsand_stonesand_1, FALSE, FALSE,
6000 EL_QUICKSAND_EMPTYING, -1, -1
6003 Xsand_stonesand_2, FALSE, FALSE,
6004 EL_QUICKSAND_EMPTYING, -1, -1
6007 Xsand_stonesand_3, FALSE, FALSE,
6008 EL_QUICKSAND_EMPTYING, -1, -1
6011 Xsand_stonesand_4, FALSE, FALSE,
6012 EL_QUICKSAND_EMPTYING, -1, -1
6015 Xsand_stonesand_quickout_1, FALSE, FALSE,
6016 EL_QUICKSAND_EMPTYING, -1, -1
6019 Xsand_stonesand_quickout_2, FALSE, FALSE,
6020 EL_QUICKSAND_EMPTYING, -1, -1
6023 Xsand_stoneout_1, FALSE, FALSE,
6024 EL_ROCK, ACTION_EMPTYING, -1
6027 Xsand_stoneout_2, FALSE, FALSE,
6028 EL_ROCK, ACTION_EMPTYING, -1
6031 Xsand_sandstone_1, FALSE, FALSE,
6032 EL_QUICKSAND_FILLING, -1, -1
6035 Xsand_sandstone_2, FALSE, FALSE,
6036 EL_QUICKSAND_FILLING, -1, -1
6039 Xsand_sandstone_3, FALSE, FALSE,
6040 EL_QUICKSAND_FILLING, -1, -1
6043 Xsand_sandstone_4, FALSE, FALSE,
6044 EL_QUICKSAND_FILLING, -1, -1
6047 Xplant, TRUE, FALSE,
6048 EL_EMC_PLANT, -1, -1
6051 Yplant, FALSE, FALSE,
6052 EL_EMC_PLANT, -1, -1
6055 Xlenses, TRUE, FALSE,
6056 EL_EMC_LENSES, -1, -1
6059 Xmagnify, TRUE, FALSE,
6060 EL_EMC_MAGNIFIER, -1, -1
6063 Xdripper, TRUE, FALSE,
6064 EL_EMC_DRIPPER, -1, -1
6067 XdripperB, FALSE, FALSE,
6068 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
6071 Xfake_blank, TRUE, FALSE,
6072 EL_INVISIBLE_WALL, -1, -1
6075 Xfake_blankB, FALSE, FALSE,
6076 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
6079 Xfake_grass, TRUE, FALSE,
6080 EL_EMC_FAKE_GRASS, -1, -1
6083 Xfake_grassB, FALSE, FALSE,
6084 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
6087 Xfake_door_1, TRUE, FALSE,
6088 EL_EM_GATE_1_GRAY, -1, -1
6091 Xfake_door_2, TRUE, FALSE,
6092 EL_EM_GATE_2_GRAY, -1, -1
6095 Xfake_door_3, TRUE, FALSE,
6096 EL_EM_GATE_3_GRAY, -1, -1
6099 Xfake_door_4, TRUE, FALSE,
6100 EL_EM_GATE_4_GRAY, -1, -1
6103 Xfake_door_5, TRUE, FALSE,
6104 EL_EMC_GATE_5_GRAY, -1, -1
6107 Xfake_door_6, TRUE, FALSE,
6108 EL_EMC_GATE_6_GRAY, -1, -1
6111 Xfake_door_7, TRUE, FALSE,
6112 EL_EMC_GATE_7_GRAY, -1, -1
6115 Xfake_door_8, TRUE, FALSE,
6116 EL_EMC_GATE_8_GRAY, -1, -1
6119 Xfake_acid_1, TRUE, FALSE,
6120 EL_EMC_FAKE_ACID, -1, -1
6123 Xfake_acid_2, FALSE, FALSE,
6124 EL_EMC_FAKE_ACID, -1, -1
6127 Xfake_acid_3, FALSE, FALSE,
6128 EL_EMC_FAKE_ACID, -1, -1
6131 Xfake_acid_4, FALSE, FALSE,
6132 EL_EMC_FAKE_ACID, -1, -1
6135 Xfake_acid_5, FALSE, FALSE,
6136 EL_EMC_FAKE_ACID, -1, -1
6139 Xfake_acid_6, FALSE, FALSE,
6140 EL_EMC_FAKE_ACID, -1, -1
6143 Xfake_acid_7, FALSE, FALSE,
6144 EL_EMC_FAKE_ACID, -1, -1
6147 Xfake_acid_8, FALSE, FALSE,
6148 EL_EMC_FAKE_ACID, -1, -1
6151 Xsteel_1, TRUE, FALSE,
6152 EL_STEELWALL, -1, -1
6155 Xsteel_2, TRUE, FALSE,
6156 EL_EMC_STEELWALL_2, -1, -1
6159 Xsteel_3, TRUE, FALSE,
6160 EL_EMC_STEELWALL_3, -1, -1
6163 Xsteel_4, TRUE, FALSE,
6164 EL_EMC_STEELWALL_4, -1, -1
6167 Xwall_1, TRUE, FALSE,
6171 Xwall_2, TRUE, FALSE,
6172 EL_EMC_WALL_14, -1, -1
6175 Xwall_3, TRUE, FALSE,
6176 EL_EMC_WALL_15, -1, -1
6179 Xwall_4, TRUE, FALSE,
6180 EL_EMC_WALL_16, -1, -1
6183 Xround_wall_1, TRUE, FALSE,
6184 EL_WALL_SLIPPERY, -1, -1
6187 Xround_wall_2, TRUE, FALSE,
6188 EL_EMC_WALL_SLIPPERY_2, -1, -1
6191 Xround_wall_3, TRUE, FALSE,
6192 EL_EMC_WALL_SLIPPERY_3, -1, -1
6195 Xround_wall_4, TRUE, FALSE,
6196 EL_EMC_WALL_SLIPPERY_4, -1, -1
6199 Xdecor_1, TRUE, FALSE,
6200 EL_EMC_WALL_8, -1, -1
6203 Xdecor_2, TRUE, FALSE,
6204 EL_EMC_WALL_6, -1, -1
6207 Xdecor_3, TRUE, FALSE,
6208 EL_EMC_WALL_4, -1, -1
6211 Xdecor_4, TRUE, FALSE,
6212 EL_EMC_WALL_7, -1, -1
6215 Xdecor_5, TRUE, FALSE,
6216 EL_EMC_WALL_5, -1, -1
6219 Xdecor_6, TRUE, FALSE,
6220 EL_EMC_WALL_9, -1, -1
6223 Xdecor_7, TRUE, FALSE,
6224 EL_EMC_WALL_10, -1, -1
6227 Xdecor_8, TRUE, FALSE,
6228 EL_EMC_WALL_1, -1, -1
6231 Xdecor_9, TRUE, FALSE,
6232 EL_EMC_WALL_2, -1, -1
6235 Xdecor_10, TRUE, FALSE,
6236 EL_EMC_WALL_3, -1, -1
6239 Xdecor_11, TRUE, FALSE,
6240 EL_EMC_WALL_11, -1, -1
6243 Xdecor_12, TRUE, FALSE,
6244 EL_EMC_WALL_12, -1, -1
6247 Xalpha_0, TRUE, FALSE,
6248 EL_CHAR('0'), -1, -1
6251 Xalpha_1, TRUE, FALSE,
6252 EL_CHAR('1'), -1, -1
6255 Xalpha_2, TRUE, FALSE,
6256 EL_CHAR('2'), -1, -1
6259 Xalpha_3, TRUE, FALSE,
6260 EL_CHAR('3'), -1, -1
6263 Xalpha_4, TRUE, FALSE,
6264 EL_CHAR('4'), -1, -1
6267 Xalpha_5, TRUE, FALSE,
6268 EL_CHAR('5'), -1, -1
6271 Xalpha_6, TRUE, FALSE,
6272 EL_CHAR('6'), -1, -1
6275 Xalpha_7, TRUE, FALSE,
6276 EL_CHAR('7'), -1, -1
6279 Xalpha_8, TRUE, FALSE,
6280 EL_CHAR('8'), -1, -1
6283 Xalpha_9, TRUE, FALSE,
6284 EL_CHAR('9'), -1, -1
6287 Xalpha_excla, TRUE, FALSE,
6288 EL_CHAR('!'), -1, -1
6291 Xalpha_quote, TRUE, FALSE,
6292 EL_CHAR('"'), -1, -1
6295 Xalpha_comma, TRUE, FALSE,
6296 EL_CHAR(','), -1, -1
6299 Xalpha_minus, TRUE, FALSE,
6300 EL_CHAR('-'), -1, -1
6303 Xalpha_perio, TRUE, FALSE,
6304 EL_CHAR('.'), -1, -1
6307 Xalpha_colon, TRUE, FALSE,
6308 EL_CHAR(':'), -1, -1
6311 Xalpha_quest, TRUE, FALSE,
6312 EL_CHAR('?'), -1, -1
6315 Xalpha_a, TRUE, FALSE,
6316 EL_CHAR('A'), -1, -1
6319 Xalpha_b, TRUE, FALSE,
6320 EL_CHAR('B'), -1, -1
6323 Xalpha_c, TRUE, FALSE,
6324 EL_CHAR('C'), -1, -1
6327 Xalpha_d, TRUE, FALSE,
6328 EL_CHAR('D'), -1, -1
6331 Xalpha_e, TRUE, FALSE,
6332 EL_CHAR('E'), -1, -1
6335 Xalpha_f, TRUE, FALSE,
6336 EL_CHAR('F'), -1, -1
6339 Xalpha_g, TRUE, FALSE,
6340 EL_CHAR('G'), -1, -1
6343 Xalpha_h, TRUE, FALSE,
6344 EL_CHAR('H'), -1, -1
6347 Xalpha_i, TRUE, FALSE,
6348 EL_CHAR('I'), -1, -1
6351 Xalpha_j, TRUE, FALSE,
6352 EL_CHAR('J'), -1, -1
6355 Xalpha_k, TRUE, FALSE,
6356 EL_CHAR('K'), -1, -1
6359 Xalpha_l, TRUE, FALSE,
6360 EL_CHAR('L'), -1, -1
6363 Xalpha_m, TRUE, FALSE,
6364 EL_CHAR('M'), -1, -1
6367 Xalpha_n, TRUE, FALSE,
6368 EL_CHAR('N'), -1, -1
6371 Xalpha_o, TRUE, FALSE,
6372 EL_CHAR('O'), -1, -1
6375 Xalpha_p, TRUE, FALSE,
6376 EL_CHAR('P'), -1, -1
6379 Xalpha_q, TRUE, FALSE,
6380 EL_CHAR('Q'), -1, -1
6383 Xalpha_r, TRUE, FALSE,
6384 EL_CHAR('R'), -1, -1
6387 Xalpha_s, TRUE, FALSE,
6388 EL_CHAR('S'), -1, -1
6391 Xalpha_t, TRUE, FALSE,
6392 EL_CHAR('T'), -1, -1
6395 Xalpha_u, TRUE, FALSE,
6396 EL_CHAR('U'), -1, -1
6399 Xalpha_v, TRUE, FALSE,
6400 EL_CHAR('V'), -1, -1
6403 Xalpha_w, TRUE, FALSE,
6404 EL_CHAR('W'), -1, -1
6407 Xalpha_x, TRUE, FALSE,
6408 EL_CHAR('X'), -1, -1
6411 Xalpha_y, TRUE, FALSE,
6412 EL_CHAR('Y'), -1, -1
6415 Xalpha_z, TRUE, FALSE,
6416 EL_CHAR('Z'), -1, -1
6419 Xalpha_arrow_e, TRUE, FALSE,
6420 EL_CHAR('>'), -1, -1
6423 Xalpha_arrow_w, TRUE, FALSE,
6424 EL_CHAR('<'), -1, -1
6427 Xalpha_copyr, TRUE, FALSE,
6428 EL_CHAR(CHAR_BYTE_COPYRIGHT), -1, -1
6432 Xboom_bug, FALSE, FALSE,
6433 EL_BUG, ACTION_EXPLODING, -1
6436 Xboom_bomb, FALSE, FALSE,
6437 EL_BOMB, ACTION_EXPLODING, -1
6440 Xboom_android, FALSE, FALSE,
6441 EL_EMC_ANDROID, ACTION_OTHER, -1
6444 Xboom_1, FALSE, FALSE,
6445 EL_DEFAULT, ACTION_EXPLODING, -1
6448 Xboom_2, FALSE, FALSE,
6449 EL_DEFAULT, ACTION_EXPLODING, -1
6452 Znormal, FALSE, FALSE,
6456 Zdynamite, FALSE, FALSE,
6460 Zplayer, FALSE, FALSE,
6464 ZBORDER, FALSE, FALSE,
6474 static struct Mapping_EM_to_RND_player
6483 em_player_mapping_list[] =
6487 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
6491 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
6495 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
6499 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
6503 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
6507 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
6511 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
6515 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
6519 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
6523 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
6527 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
6531 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
6535 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
6539 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
6543 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
6547 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
6551 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
6555 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
6559 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
6563 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
6567 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
6571 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
6575 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
6579 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
6583 EL_PLAYER_1, ACTION_DEFAULT, -1,
6587 EL_PLAYER_2, ACTION_DEFAULT, -1,
6591 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
6595 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
6599 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
6603 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
6607 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
6611 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
6615 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
6619 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
6623 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
6627 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
6631 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
6635 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
6639 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
6643 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
6647 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
6651 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
6655 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
6659 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
6663 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
6667 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
6671 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
6675 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
6679 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
6683 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
6687 EL_PLAYER_3, ACTION_DEFAULT, -1,
6691 EL_PLAYER_4, ACTION_DEFAULT, -1,
6700 int map_element_RND_to_EM(int element_rnd)
6702 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
6703 static boolean mapping_initialized = FALSE;
6705 if (!mapping_initialized)
6709 /* return "Xalpha_quest" for all undefined elements in mapping array */
6710 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
6711 mapping_RND_to_EM[i] = Xalpha_quest;
6713 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6714 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
6715 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
6716 em_object_mapping_list[i].element_em;
6718 mapping_initialized = TRUE;
6721 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
6722 return mapping_RND_to_EM[element_rnd];
6724 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
6729 int map_element_EM_to_RND(int element_em)
6731 static unsigned short mapping_EM_to_RND[TILE_MAX];
6732 static boolean mapping_initialized = FALSE;
6734 if (!mapping_initialized)
6738 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
6739 for (i = 0; i < TILE_MAX; i++)
6740 mapping_EM_to_RND[i] = EL_UNKNOWN;
6742 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6743 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
6744 em_object_mapping_list[i].element_rnd;
6746 mapping_initialized = TRUE;
6749 if (element_em >= 0 && element_em < TILE_MAX)
6750 return mapping_EM_to_RND[element_em];
6752 Error(ERR_WARN, "invalid EM level element %d", element_em);
6757 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
6759 struct LevelInfo_EM *level_em = level->native_em_level;
6760 struct LEVEL *lev = level_em->lev;
6763 for (i = 0; i < TILE_MAX; i++)
6764 lev->android_array[i] = Xblank;
6766 for (i = 0; i < level->num_android_clone_elements; i++)
6768 int element_rnd = level->android_clone_element[i];
6769 int element_em = map_element_RND_to_EM(element_rnd);
6771 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
6772 if (em_object_mapping_list[j].element_rnd == element_rnd)
6773 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
6777 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
6779 struct LevelInfo_EM *level_em = level->native_em_level;
6780 struct LEVEL *lev = level_em->lev;
6783 level->num_android_clone_elements = 0;
6785 for (i = 0; i < TILE_MAX; i++)
6787 int element_em = lev->android_array[i];
6789 boolean element_found = FALSE;
6791 if (element_em == Xblank)
6794 element_rnd = map_element_EM_to_RND(element_em);
6796 for (j = 0; j < level->num_android_clone_elements; j++)
6797 if (level->android_clone_element[j] == element_rnd)
6798 element_found = TRUE;
6802 level->android_clone_element[level->num_android_clone_elements++] =
6805 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
6810 if (level->num_android_clone_elements == 0)
6812 level->num_android_clone_elements = 1;
6813 level->android_clone_element[0] = EL_EMPTY;
6817 int map_direction_RND_to_EM(int direction)
6819 return (direction == MV_UP ? 0 :
6820 direction == MV_RIGHT ? 1 :
6821 direction == MV_DOWN ? 2 :
6822 direction == MV_LEFT ? 3 :
6826 int map_direction_EM_to_RND(int direction)
6828 return (direction == 0 ? MV_UP :
6829 direction == 1 ? MV_RIGHT :
6830 direction == 2 ? MV_DOWN :
6831 direction == 3 ? MV_LEFT :
6835 int map_element_RND_to_SP(int element_rnd)
6837 int element_sp = 0x20; /* map unknown elements to yellow "hardware" */
6839 if (element_rnd >= EL_SP_START &&
6840 element_rnd <= EL_SP_END)
6841 element_sp = element_rnd - EL_SP_START;
6842 else if (element_rnd == EL_EMPTY_SPACE)
6844 else if (element_rnd == EL_INVISIBLE_WALL)
6850 int map_element_SP_to_RND(int element_sp)
6852 int element_rnd = EL_UNKNOWN;
6854 if (element_sp >= 0x00 &&
6856 element_rnd = EL_SP_START + element_sp;
6857 else if (element_sp == 0x28)
6858 element_rnd = EL_INVISIBLE_WALL;
6863 int map_action_SP_to_RND(int action_sp)
6867 case actActive: return ACTION_ACTIVE;
6868 case actImpact: return ACTION_IMPACT;
6869 case actExploding: return ACTION_EXPLODING;
6870 case actDigging: return ACTION_DIGGING;
6871 case actSnapping: return ACTION_SNAPPING;
6872 case actCollecting: return ACTION_COLLECTING;
6873 case actPassing: return ACTION_PASSING;
6874 case actPushing: return ACTION_PUSHING;
6875 case actDropping: return ACTION_DROPPING;
6877 default: return ACTION_DEFAULT;
6881 int get_next_element(int element)
6885 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
6886 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
6887 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
6888 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
6889 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
6890 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
6891 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
6892 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
6893 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
6894 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
6895 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
6897 default: return element;
6901 int el_act_dir2img(int element, int action, int direction)
6903 element = GFX_ELEMENT(element);
6904 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
6906 /* direction_graphic[][] == graphic[] for undefined direction graphics */
6907 return element_info[element].direction_graphic[action][direction];
6910 static int el_act_dir2crm(int element, int action, int direction)
6912 element = GFX_ELEMENT(element);
6913 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
6915 /* direction_graphic[][] == graphic[] for undefined direction graphics */
6916 return element_info[element].direction_crumbled[action][direction];
6919 int el_act2img(int element, int action)
6921 element = GFX_ELEMENT(element);
6923 return element_info[element].graphic[action];
6926 int el_act2crm(int element, int action)
6928 element = GFX_ELEMENT(element);
6930 return element_info[element].crumbled[action];
6933 int el_dir2img(int element, int direction)
6935 element = GFX_ELEMENT(element);
6937 return el_act_dir2img(element, ACTION_DEFAULT, direction);
6940 int el2baseimg(int element)
6942 return element_info[element].graphic[ACTION_DEFAULT];
6945 int el2img(int element)
6947 element = GFX_ELEMENT(element);
6949 return element_info[element].graphic[ACTION_DEFAULT];
6952 int el2edimg(int element)
6954 element = GFX_ELEMENT(element);
6956 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
6959 int el2preimg(int element)
6961 element = GFX_ELEMENT(element);
6963 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
6966 int el2panelimg(int element)
6968 element = GFX_ELEMENT(element);
6970 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL];
6973 int font2baseimg(int font_nr)
6975 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
6978 int getBeltNrFromBeltElement(int element)
6980 return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
6981 element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
6982 element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
6985 int getBeltNrFromBeltActiveElement(int element)
6987 return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
6988 element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
6989 element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
6992 int getBeltNrFromBeltSwitchElement(int element)
6994 return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
6995 element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
6996 element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
6999 int getBeltDirNrFromBeltElement(int element)
7001 static int belt_base_element[4] =
7003 EL_CONVEYOR_BELT_1_LEFT,
7004 EL_CONVEYOR_BELT_2_LEFT,
7005 EL_CONVEYOR_BELT_3_LEFT,
7006 EL_CONVEYOR_BELT_4_LEFT
7009 int belt_nr = getBeltNrFromBeltElement(element);
7010 int belt_dir_nr = element - belt_base_element[belt_nr];
7012 return (belt_dir_nr % 3);
7015 int getBeltDirNrFromBeltSwitchElement(int element)
7017 static int belt_base_element[4] =
7019 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
7020 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
7021 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
7022 EL_CONVEYOR_BELT_4_SWITCH_LEFT
7025 int belt_nr = getBeltNrFromBeltSwitchElement(element);
7026 int belt_dir_nr = element - belt_base_element[belt_nr];
7028 return (belt_dir_nr % 3);
7031 int getBeltDirFromBeltElement(int element)
7033 static int belt_move_dir[3] =
7040 int belt_dir_nr = getBeltDirNrFromBeltElement(element);
7042 return belt_move_dir[belt_dir_nr];
7045 int getBeltDirFromBeltSwitchElement(int element)
7047 static int belt_move_dir[3] =
7054 int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
7056 return belt_move_dir[belt_dir_nr];
7059 int getBeltElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
7061 static int belt_base_element[4] =
7063 EL_CONVEYOR_BELT_1_LEFT,
7064 EL_CONVEYOR_BELT_2_LEFT,
7065 EL_CONVEYOR_BELT_3_LEFT,
7066 EL_CONVEYOR_BELT_4_LEFT
7069 return belt_base_element[belt_nr] + belt_dir_nr;
7072 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
7074 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
7076 return getBeltElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
7079 int getBeltSwitchElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
7081 static int belt_base_element[4] =
7083 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
7084 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
7085 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
7086 EL_CONVEYOR_BELT_4_SWITCH_LEFT
7089 return belt_base_element[belt_nr] + belt_dir_nr;
7092 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
7094 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
7096 return getBeltSwitchElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
7099 boolean getTeamMode_EM()
7101 return game.team_mode;
7104 int getGameFrameDelay_EM(int native_em_game_frame_delay)
7106 int game_frame_delay_value;
7108 game_frame_delay_value =
7109 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
7110 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
7113 if (tape.playing && tape.warp_forward && !tape.pausing)
7114 game_frame_delay_value = 0;
7116 return game_frame_delay_value;
7119 unsigned int InitRND(int seed)
7121 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
7122 return InitEngineRandom_EM(seed);
7123 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
7124 return InitEngineRandom_SP(seed);
7126 return InitEngineRandom_RND(seed);
7129 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
7130 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
7132 inline static int get_effective_element_EM(int tile, int frame_em)
7134 int element = object_mapping[tile].element_rnd;
7135 int action = object_mapping[tile].action;
7136 boolean is_backside = object_mapping[tile].is_backside;
7137 boolean action_removing = (action == ACTION_DIGGING ||
7138 action == ACTION_SNAPPING ||
7139 action == ACTION_COLLECTING);
7145 case Yacid_splash_eB:
7146 case Yacid_splash_wB:
7147 return (frame_em > 5 ? EL_EMPTY : element);
7153 else /* frame_em == 7 */
7157 case Yacid_splash_eB:
7158 case Yacid_splash_wB:
7161 case Yemerald_stone:
7164 case Ydiamond_stone:
7168 case Xdrip_stretchB:
7187 case Xsand_stonein_1:
7188 case Xsand_stonein_2:
7189 case Xsand_stonein_3:
7190 case Xsand_stonein_4:
7194 return (is_backside || action_removing ? EL_EMPTY : element);
7199 inline static boolean check_linear_animation_EM(int tile)
7203 case Xsand_stonesand_1:
7204 case Xsand_stonesand_quickout_1:
7205 case Xsand_sandstone_1:
7206 case Xsand_stonein_1:
7207 case Xsand_stoneout_1:
7226 case Yacid_splash_eB:
7227 case Yacid_splash_wB:
7228 case Yemerald_stone:
7235 inline static void set_crumbled_graphics_EM(struct GraphicInfo_EM *g_em,
7236 boolean has_crumbled_graphics,
7237 int crumbled, int sync_frame)
7239 /* if element can be crumbled, but certain action graphics are just empty
7240 space (like instantly snapping sand to empty space in 1 frame), do not
7241 treat these empty space graphics as crumbled graphics in EMC engine */
7242 if (crumbled == IMG_EMPTY_SPACE)
7243 has_crumbled_graphics = FALSE;
7245 if (has_crumbled_graphics)
7247 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
7248 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
7249 g_crumbled->anim_delay,
7250 g_crumbled->anim_mode,
7251 g_crumbled->anim_start_frame,
7254 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
7255 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
7257 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
7259 g_em->has_crumbled_graphics = TRUE;
7263 g_em->crumbled_bitmap = NULL;
7264 g_em->crumbled_src_x = 0;
7265 g_em->crumbled_src_y = 0;
7266 g_em->crumbled_border_size = 0;
7268 g_em->has_crumbled_graphics = FALSE;
7272 void ResetGfxAnimation_EM(int x, int y, int tile)
7277 void SetGfxAnimation_EM(struct GraphicInfo_EM *g_em,
7278 int tile, int frame_em, int x, int y)
7280 int action = object_mapping[tile].action;
7281 int direction = object_mapping[tile].direction;
7282 int effective_element = get_effective_element_EM(tile, frame_em);
7283 int graphic = (direction == MV_NONE ?
7284 el_act2img(effective_element, action) :
7285 el_act_dir2img(effective_element, action, direction));
7286 struct GraphicInfo *g = &graphic_info[graphic];
7288 boolean action_removing = (action == ACTION_DIGGING ||
7289 action == ACTION_SNAPPING ||
7290 action == ACTION_COLLECTING);
7291 boolean action_moving = (action == ACTION_FALLING ||
7292 action == ACTION_MOVING ||
7293 action == ACTION_PUSHING ||
7294 action == ACTION_EATING ||
7295 action == ACTION_FILLING ||
7296 action == ACTION_EMPTYING);
7297 boolean action_falling = (action == ACTION_FALLING ||
7298 action == ACTION_FILLING ||
7299 action == ACTION_EMPTYING);
7301 /* special case: graphic uses "2nd movement tile" and has defined
7302 7 frames for movement animation (or less) => use default graphic
7303 for last (8th) frame which ends the movement animation */
7304 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
7306 action = ACTION_DEFAULT; /* (keep action_* unchanged for now) */
7307 graphic = (direction == MV_NONE ?
7308 el_act2img(effective_element, action) :
7309 el_act_dir2img(effective_element, action, direction));
7311 g = &graphic_info[graphic];
7314 if ((action_removing || check_linear_animation_EM(tile)) && frame_em == 0)
7318 else if (action_moving)
7320 boolean is_backside = object_mapping[tile].is_backside;
7324 int direction = object_mapping[tile].direction;
7325 int move_dir = (action_falling ? MV_DOWN : direction);
7330 /* !!! TEST !!! NEW !!! DOES NOT WORK RIGHT YET !!! */
7331 if (g->double_movement && frame_em == 0)
7335 if (move_dir == MV_LEFT)
7336 GfxFrame[x - 1][y] = GfxFrame[x][y];
7337 else if (move_dir == MV_RIGHT)
7338 GfxFrame[x + 1][y] = GfxFrame[x][y];
7339 else if (move_dir == MV_UP)
7340 GfxFrame[x][y - 1] = GfxFrame[x][y];
7341 else if (move_dir == MV_DOWN)
7342 GfxFrame[x][y + 1] = GfxFrame[x][y];
7349 /* special case: animation for Xsand_stonesand_quickout_1/2 twice as fast */
7350 if (tile == Xsand_stonesand_quickout_1 ||
7351 tile == Xsand_stonesand_quickout_2)
7355 if (graphic_info[graphic].anim_global_sync)
7356 sync_frame = FrameCounter;
7357 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
7358 sync_frame = GfxFrame[x][y];
7360 sync_frame = 0; /* playfield border (pseudo steel) */
7362 SetRandomAnimationValue(x, y);
7364 int frame = getAnimationFrame(g->anim_frames,
7367 g->anim_start_frame,
7370 g_em->unique_identifier =
7371 (graphic << 16) | ((frame % 8) << 12) | (g_em->width << 6) | g_em->height;
7374 void getGraphicSourceObjectExt_EM(struct GraphicInfo_EM *g_em,
7375 int tile, int frame_em, int x, int y)
7377 int action = object_mapping[tile].action;
7378 int direction = object_mapping[tile].direction;
7379 boolean is_backside = object_mapping[tile].is_backside;
7380 int effective_element = get_effective_element_EM(tile, frame_em);
7381 int effective_action = action;
7382 int graphic = (direction == MV_NONE ?
7383 el_act2img(effective_element, effective_action) :
7384 el_act_dir2img(effective_element, effective_action,
7386 int crumbled = (direction == MV_NONE ?
7387 el_act2crm(effective_element, effective_action) :
7388 el_act_dir2crm(effective_element, effective_action,
7390 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7391 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7392 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7393 struct GraphicInfo *g = &graphic_info[graphic];
7396 /* special case: graphic uses "2nd movement tile" and has defined
7397 7 frames for movement animation (or less) => use default graphic
7398 for last (8th) frame which ends the movement animation */
7399 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
7401 effective_action = ACTION_DEFAULT;
7402 graphic = (direction == MV_NONE ?
7403 el_act2img(effective_element, effective_action) :
7404 el_act_dir2img(effective_element, effective_action,
7406 crumbled = (direction == MV_NONE ?
7407 el_act2crm(effective_element, effective_action) :
7408 el_act_dir2crm(effective_element, effective_action,
7411 g = &graphic_info[graphic];
7414 if (graphic_info[graphic].anim_global_sync)
7415 sync_frame = FrameCounter;
7416 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
7417 sync_frame = GfxFrame[x][y];
7419 sync_frame = 0; /* playfield border (pseudo steel) */
7421 SetRandomAnimationValue(x, y);
7423 int frame = getAnimationFrame(g->anim_frames,
7426 g->anim_start_frame,
7429 getGraphicSourceExt(graphic, frame, &g_em->bitmap, &g_em->src_x, &g_em->src_y,
7430 g->double_movement && is_backside);
7432 /* (updating the "crumbled" graphic definitions is probably not really needed,
7433 as animations for crumbled graphics can't be longer than one EMC cycle) */
7434 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
7438 void getGraphicSourcePlayerExt_EM(struct GraphicInfo_EM *g_em,
7439 int player_nr, int anim, int frame_em)
7441 int element = player_mapping[player_nr][anim].element_rnd;
7442 int action = player_mapping[player_nr][anim].action;
7443 int direction = player_mapping[player_nr][anim].direction;
7444 int graphic = (direction == MV_NONE ?
7445 el_act2img(element, action) :
7446 el_act_dir2img(element, action, direction));
7447 struct GraphicInfo *g = &graphic_info[graphic];
7450 InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
7452 stored_player[player_nr].StepFrame = frame_em;
7454 sync_frame = stored_player[player_nr].Frame;
7456 int frame = getAnimationFrame(g->anim_frames,
7459 g->anim_start_frame,
7462 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
7463 &g_em->src_x, &g_em->src_y, FALSE);
7466 void InitGraphicInfo_EM(void)
7471 int num_em_gfx_errors = 0;
7473 if (graphic_info_em_object[0][0].bitmap == NULL)
7475 /* EM graphics not yet initialized in em_open_all() */
7480 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
7483 /* always start with reliable default values */
7484 for (i = 0; i < TILE_MAX; i++)
7486 object_mapping[i].element_rnd = EL_UNKNOWN;
7487 object_mapping[i].is_backside = FALSE;
7488 object_mapping[i].action = ACTION_DEFAULT;
7489 object_mapping[i].direction = MV_NONE;
7492 /* always start with reliable default values */
7493 for (p = 0; p < MAX_PLAYERS; p++)
7495 for (i = 0; i < SPR_MAX; i++)
7497 player_mapping[p][i].element_rnd = EL_UNKNOWN;
7498 player_mapping[p][i].action = ACTION_DEFAULT;
7499 player_mapping[p][i].direction = MV_NONE;
7503 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
7505 int e = em_object_mapping_list[i].element_em;
7507 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
7508 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
7510 if (em_object_mapping_list[i].action != -1)
7511 object_mapping[e].action = em_object_mapping_list[i].action;
7513 if (em_object_mapping_list[i].direction != -1)
7514 object_mapping[e].direction =
7515 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
7518 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
7520 int a = em_player_mapping_list[i].action_em;
7521 int p = em_player_mapping_list[i].player_nr;
7523 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
7525 if (em_player_mapping_list[i].action != -1)
7526 player_mapping[p][a].action = em_player_mapping_list[i].action;
7528 if (em_player_mapping_list[i].direction != -1)
7529 player_mapping[p][a].direction =
7530 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
7533 for (i = 0; i < TILE_MAX; i++)
7535 int element = object_mapping[i].element_rnd;
7536 int action = object_mapping[i].action;
7537 int direction = object_mapping[i].direction;
7538 boolean is_backside = object_mapping[i].is_backside;
7539 boolean action_exploding = ((action == ACTION_EXPLODING ||
7540 action == ACTION_SMASHED_BY_ROCK ||
7541 action == ACTION_SMASHED_BY_SPRING) &&
7542 element != EL_DIAMOND);
7543 boolean action_active = (action == ACTION_ACTIVE);
7544 boolean action_other = (action == ACTION_OTHER);
7546 for (j = 0; j < 8; j++)
7548 int effective_element = get_effective_element_EM(i, j);
7549 int effective_action = (j < 7 ? action :
7550 i == Xdrip_stretch ? action :
7551 i == Xdrip_stretchB ? action :
7552 i == Ydrip_s1 ? action :
7553 i == Ydrip_s1B ? action :
7554 i == Xball_1B ? action :
7555 i == Xball_2 ? action :
7556 i == Xball_2B ? action :
7557 i == Yball_eat ? action :
7558 i == Ykey_1_eat ? action :
7559 i == Ykey_2_eat ? action :
7560 i == Ykey_3_eat ? action :
7561 i == Ykey_4_eat ? action :
7562 i == Ykey_5_eat ? action :
7563 i == Ykey_6_eat ? action :
7564 i == Ykey_7_eat ? action :
7565 i == Ykey_8_eat ? action :
7566 i == Ylenses_eat ? action :
7567 i == Ymagnify_eat ? action :
7568 i == Ygrass_eat ? action :
7569 i == Ydirt_eat ? action :
7570 i == Xsand_stonein_1 ? action :
7571 i == Xsand_stonein_2 ? action :
7572 i == Xsand_stonein_3 ? action :
7573 i == Xsand_stonein_4 ? action :
7574 i == Xsand_stoneout_1 ? action :
7575 i == Xsand_stoneout_2 ? action :
7576 i == Xboom_android ? ACTION_EXPLODING :
7577 action_exploding ? ACTION_EXPLODING :
7578 action_active ? action :
7579 action_other ? action :
7581 int graphic = (el_act_dir2img(effective_element, effective_action,
7583 int crumbled = (el_act_dir2crm(effective_element, effective_action,
7585 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7586 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7587 boolean has_action_graphics = (graphic != base_graphic);
7588 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7589 struct GraphicInfo *g = &graphic_info[graphic];
7590 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7593 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
7594 boolean special_animation = (action != ACTION_DEFAULT &&
7595 g->anim_frames == 3 &&
7596 g->anim_delay == 2 &&
7597 g->anim_mode & ANIM_LINEAR);
7598 int sync_frame = (i == Xdrip_stretch ? 7 :
7599 i == Xdrip_stretchB ? 7 :
7600 i == Ydrip_s2 ? j + 8 :
7601 i == Ydrip_s2B ? j + 8 :
7610 i == Xfake_acid_1 ? 0 :
7611 i == Xfake_acid_2 ? 10 :
7612 i == Xfake_acid_3 ? 20 :
7613 i == Xfake_acid_4 ? 30 :
7614 i == Xfake_acid_5 ? 40 :
7615 i == Xfake_acid_6 ? 50 :
7616 i == Xfake_acid_7 ? 60 :
7617 i == Xfake_acid_8 ? 70 :
7619 i == Xball_2B ? j + 8 :
7620 i == Yball_eat ? j + 1 :
7621 i == Ykey_1_eat ? j + 1 :
7622 i == Ykey_2_eat ? j + 1 :
7623 i == Ykey_3_eat ? j + 1 :
7624 i == Ykey_4_eat ? j + 1 :
7625 i == Ykey_5_eat ? j + 1 :
7626 i == Ykey_6_eat ? j + 1 :
7627 i == Ykey_7_eat ? j + 1 :
7628 i == Ykey_8_eat ? j + 1 :
7629 i == Ylenses_eat ? j + 1 :
7630 i == Ymagnify_eat ? j + 1 :
7631 i == Ygrass_eat ? j + 1 :
7632 i == Ydirt_eat ? j + 1 :
7633 i == Xamoeba_1 ? 0 :
7634 i == Xamoeba_2 ? 1 :
7635 i == Xamoeba_3 ? 2 :
7636 i == Xamoeba_4 ? 3 :
7637 i == Xamoeba_5 ? 0 :
7638 i == Xamoeba_6 ? 1 :
7639 i == Xamoeba_7 ? 2 :
7640 i == Xamoeba_8 ? 3 :
7641 i == Xexit_2 ? j + 8 :
7642 i == Xexit_3 ? j + 16 :
7643 i == Xdynamite_1 ? 0 :
7644 i == Xdynamite_2 ? 8 :
7645 i == Xdynamite_3 ? 16 :
7646 i == Xdynamite_4 ? 24 :
7647 i == Xsand_stonein_1 ? j + 1 :
7648 i == Xsand_stonein_2 ? j + 9 :
7649 i == Xsand_stonein_3 ? j + 17 :
7650 i == Xsand_stonein_4 ? j + 25 :
7651 i == Xsand_stoneout_1 && j == 0 ? 0 :
7652 i == Xsand_stoneout_1 && j == 1 ? 0 :
7653 i == Xsand_stoneout_1 && j == 2 ? 1 :
7654 i == Xsand_stoneout_1 && j == 3 ? 2 :
7655 i == Xsand_stoneout_1 && j == 4 ? 2 :
7656 i == Xsand_stoneout_1 && j == 5 ? 3 :
7657 i == Xsand_stoneout_1 && j == 6 ? 4 :
7658 i == Xsand_stoneout_1 && j == 7 ? 4 :
7659 i == Xsand_stoneout_2 && j == 0 ? 5 :
7660 i == Xsand_stoneout_2 && j == 1 ? 6 :
7661 i == Xsand_stoneout_2 && j == 2 ? 7 :
7662 i == Xsand_stoneout_2 && j == 3 ? 8 :
7663 i == Xsand_stoneout_2 && j == 4 ? 9 :
7664 i == Xsand_stoneout_2 && j == 5 ? 11 :
7665 i == Xsand_stoneout_2 && j == 6 ? 13 :
7666 i == Xsand_stoneout_2 && j == 7 ? 15 :
7667 i == Xboom_bug && j == 1 ? 2 :
7668 i == Xboom_bug && j == 2 ? 2 :
7669 i == Xboom_bug && j == 3 ? 4 :
7670 i == Xboom_bug && j == 4 ? 4 :
7671 i == Xboom_bug && j == 5 ? 2 :
7672 i == Xboom_bug && j == 6 ? 2 :
7673 i == Xboom_bug && j == 7 ? 0 :
7674 i == Xboom_bomb && j == 1 ? 2 :
7675 i == Xboom_bomb && j == 2 ? 2 :
7676 i == Xboom_bomb && j == 3 ? 4 :
7677 i == Xboom_bomb && j == 4 ? 4 :
7678 i == Xboom_bomb && j == 5 ? 2 :
7679 i == Xboom_bomb && j == 6 ? 2 :
7680 i == Xboom_bomb && j == 7 ? 0 :
7681 i == Xboom_android && j == 7 ? 6 :
7682 i == Xboom_1 && j == 1 ? 2 :
7683 i == Xboom_1 && j == 2 ? 2 :
7684 i == Xboom_1 && j == 3 ? 4 :
7685 i == Xboom_1 && j == 4 ? 4 :
7686 i == Xboom_1 && j == 5 ? 6 :
7687 i == Xboom_1 && j == 6 ? 6 :
7688 i == Xboom_1 && j == 7 ? 8 :
7689 i == Xboom_2 && j == 0 ? 8 :
7690 i == Xboom_2 && j == 1 ? 8 :
7691 i == Xboom_2 && j == 2 ? 10 :
7692 i == Xboom_2 && j == 3 ? 10 :
7693 i == Xboom_2 && j == 4 ? 10 :
7694 i == Xboom_2 && j == 5 ? 12 :
7695 i == Xboom_2 && j == 6 ? 12 :
7696 i == Xboom_2 && j == 7 ? 12 :
7697 special_animation && j == 4 ? 3 :
7698 effective_action != action ? 0 :
7702 Bitmap *debug_bitmap = g_em->bitmap;
7703 int debug_src_x = g_em->src_x;
7704 int debug_src_y = g_em->src_y;
7707 int frame = getAnimationFrame(g->anim_frames,
7710 g->anim_start_frame,
7713 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
7714 g->double_movement && is_backside);
7716 g_em->bitmap = src_bitmap;
7717 g_em->src_x = src_x;
7718 g_em->src_y = src_y;
7719 g_em->src_offset_x = 0;
7720 g_em->src_offset_y = 0;
7721 g_em->dst_offset_x = 0;
7722 g_em->dst_offset_y = 0;
7723 g_em->width = TILEX;
7724 g_em->height = TILEY;
7726 g_em->preserve_background = FALSE;
7728 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
7731 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
7732 effective_action == ACTION_MOVING ||
7733 effective_action == ACTION_PUSHING ||
7734 effective_action == ACTION_EATING)) ||
7735 (!has_action_graphics && (effective_action == ACTION_FILLING ||
7736 effective_action == ACTION_EMPTYING)))
7739 (effective_action == ACTION_FALLING ||
7740 effective_action == ACTION_FILLING ||
7741 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
7742 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
7743 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
7744 int num_steps = (i == Ydrip_s1 ? 16 :
7745 i == Ydrip_s1B ? 16 :
7746 i == Ydrip_s2 ? 16 :
7747 i == Ydrip_s2B ? 16 :
7748 i == Xsand_stonein_1 ? 32 :
7749 i == Xsand_stonein_2 ? 32 :
7750 i == Xsand_stonein_3 ? 32 :
7751 i == Xsand_stonein_4 ? 32 :
7752 i == Xsand_stoneout_1 ? 16 :
7753 i == Xsand_stoneout_2 ? 16 : 8);
7754 int cx = ABS(dx) * (TILEX / num_steps);
7755 int cy = ABS(dy) * (TILEY / num_steps);
7756 int step_frame = (i == Ydrip_s2 ? j + 8 :
7757 i == Ydrip_s2B ? j + 8 :
7758 i == Xsand_stonein_2 ? j + 8 :
7759 i == Xsand_stonein_3 ? j + 16 :
7760 i == Xsand_stonein_4 ? j + 24 :
7761 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
7762 int step = (is_backside ? step_frame : num_steps - step_frame);
7764 if (is_backside) /* tile where movement starts */
7766 if (dx < 0 || dy < 0)
7768 g_em->src_offset_x = cx * step;
7769 g_em->src_offset_y = cy * step;
7773 g_em->dst_offset_x = cx * step;
7774 g_em->dst_offset_y = cy * step;
7777 else /* tile where movement ends */
7779 if (dx < 0 || dy < 0)
7781 g_em->dst_offset_x = cx * step;
7782 g_em->dst_offset_y = cy * step;
7786 g_em->src_offset_x = cx * step;
7787 g_em->src_offset_y = cy * step;
7791 g_em->width = TILEX - cx * step;
7792 g_em->height = TILEY - cy * step;
7795 /* create unique graphic identifier to decide if tile must be redrawn */
7796 /* bit 31 - 16 (16 bit): EM style graphic
7797 bit 15 - 12 ( 4 bit): EM style frame
7798 bit 11 - 6 ( 6 bit): graphic width
7799 bit 5 - 0 ( 6 bit): graphic height */
7800 g_em->unique_identifier =
7801 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
7805 /* skip check for EMC elements not contained in original EMC artwork */
7806 if (element == EL_EMC_FAKE_ACID)
7809 if (g_em->bitmap != debug_bitmap ||
7810 g_em->src_x != debug_src_x ||
7811 g_em->src_y != debug_src_y ||
7812 g_em->src_offset_x != 0 ||
7813 g_em->src_offset_y != 0 ||
7814 g_em->dst_offset_x != 0 ||
7815 g_em->dst_offset_y != 0 ||
7816 g_em->width != TILEX ||
7817 g_em->height != TILEY)
7819 static int last_i = -1;
7827 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
7828 i, element, element_info[element].token_name,
7829 element_action_info[effective_action].suffix, direction);
7831 if (element != effective_element)
7832 printf(" [%d ('%s')]",
7834 element_info[effective_element].token_name);
7838 if (g_em->bitmap != debug_bitmap)
7839 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
7840 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
7842 if (g_em->src_x != debug_src_x ||
7843 g_em->src_y != debug_src_y)
7844 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
7845 j, (is_backside ? 'B' : 'F'),
7846 g_em->src_x, g_em->src_y,
7847 g_em->src_x / 32, g_em->src_y / 32,
7848 debug_src_x, debug_src_y,
7849 debug_src_x / 32, debug_src_y / 32);
7851 if (g_em->src_offset_x != 0 ||
7852 g_em->src_offset_y != 0 ||
7853 g_em->dst_offset_x != 0 ||
7854 g_em->dst_offset_y != 0)
7855 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
7857 g_em->src_offset_x, g_em->src_offset_y,
7858 g_em->dst_offset_x, g_em->dst_offset_y);
7860 if (g_em->width != TILEX ||
7861 g_em->height != TILEY)
7862 printf(" %d (%d): size %d,%d should be %d,%d\n",
7864 g_em->width, g_em->height, TILEX, TILEY);
7866 num_em_gfx_errors++;
7873 for (i = 0; i < TILE_MAX; i++)
7875 for (j = 0; j < 8; j++)
7877 int element = object_mapping[i].element_rnd;
7878 int action = object_mapping[i].action;
7879 int direction = object_mapping[i].direction;
7880 boolean is_backside = object_mapping[i].is_backside;
7881 int graphic_action = el_act_dir2img(element, action, direction);
7882 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
7884 if ((action == ACTION_SMASHED_BY_ROCK ||
7885 action == ACTION_SMASHED_BY_SPRING ||
7886 action == ACTION_EATING) &&
7887 graphic_action == graphic_default)
7889 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
7890 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
7891 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
7892 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
7895 /* no separate animation for "smashed by rock" -- use rock instead */
7896 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7897 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
7899 g_em->bitmap = g_xx->bitmap;
7900 g_em->src_x = g_xx->src_x;
7901 g_em->src_y = g_xx->src_y;
7902 g_em->src_offset_x = g_xx->src_offset_x;
7903 g_em->src_offset_y = g_xx->src_offset_y;
7904 g_em->dst_offset_x = g_xx->dst_offset_x;
7905 g_em->dst_offset_y = g_xx->dst_offset_y;
7906 g_em->width = g_xx->width;
7907 g_em->height = g_xx->height;
7908 g_em->unique_identifier = g_xx->unique_identifier;
7911 g_em->preserve_background = TRUE;
7916 for (p = 0; p < MAX_PLAYERS; p++)
7918 for (i = 0; i < SPR_MAX; i++)
7920 int element = player_mapping[p][i].element_rnd;
7921 int action = player_mapping[p][i].action;
7922 int direction = player_mapping[p][i].direction;
7924 for (j = 0; j < 8; j++)
7926 int effective_element = element;
7927 int effective_action = action;
7928 int graphic = (direction == MV_NONE ?
7929 el_act2img(effective_element, effective_action) :
7930 el_act_dir2img(effective_element, effective_action,
7932 struct GraphicInfo *g = &graphic_info[graphic];
7933 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
7939 Bitmap *debug_bitmap = g_em->bitmap;
7940 int debug_src_x = g_em->src_x;
7941 int debug_src_y = g_em->src_y;
7944 int frame = getAnimationFrame(g->anim_frames,
7947 g->anim_start_frame,
7950 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
7952 g_em->bitmap = src_bitmap;
7953 g_em->src_x = src_x;
7954 g_em->src_y = src_y;
7955 g_em->src_offset_x = 0;
7956 g_em->src_offset_y = 0;
7957 g_em->dst_offset_x = 0;
7958 g_em->dst_offset_y = 0;
7959 g_em->width = TILEX;
7960 g_em->height = TILEY;
7964 /* skip check for EMC elements not contained in original EMC artwork */
7965 if (element == EL_PLAYER_3 ||
7966 element == EL_PLAYER_4)
7969 if (g_em->bitmap != debug_bitmap ||
7970 g_em->src_x != debug_src_x ||
7971 g_em->src_y != debug_src_y)
7973 static int last_i = -1;
7981 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
7982 p, i, element, element_info[element].token_name,
7983 element_action_info[effective_action].suffix, direction);
7985 if (element != effective_element)
7986 printf(" [%d ('%s')]",
7988 element_info[effective_element].token_name);
7992 if (g_em->bitmap != debug_bitmap)
7993 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
7994 j, (int)(g_em->bitmap), (int)(debug_bitmap));
7996 if (g_em->src_x != debug_src_x ||
7997 g_em->src_y != debug_src_y)
7998 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
8000 g_em->src_x, g_em->src_y,
8001 g_em->src_x / 32, g_em->src_y / 32,
8002 debug_src_x, debug_src_y,
8003 debug_src_x / 32, debug_src_y / 32);
8005 num_em_gfx_errors++;
8015 printf("::: [%d errors found]\n", num_em_gfx_errors);
8021 void CheckSaveEngineSnapshot_EM(byte action[MAX_PLAYERS], int frame,
8022 boolean any_player_moving,
8023 boolean any_player_snapping,
8024 boolean any_player_dropping)
8026 static boolean player_was_waiting = TRUE;
8028 if (frame == 0 && !any_player_dropping)
8030 if (!player_was_waiting)
8032 if (!SaveEngineSnapshotToList())
8035 player_was_waiting = TRUE;
8038 else if (any_player_moving || any_player_snapping || any_player_dropping)
8040 player_was_waiting = FALSE;
8044 void CheckSaveEngineSnapshot_SP(boolean murphy_is_waiting,
8045 boolean murphy_is_dropping)
8047 static boolean player_was_waiting = TRUE;
8049 if (murphy_is_waiting)
8051 if (!player_was_waiting)
8053 if (!SaveEngineSnapshotToList())
8056 player_was_waiting = TRUE;
8061 player_was_waiting = FALSE;
8065 void CheckSingleStepMode_EM(byte action[MAX_PLAYERS], int frame,
8066 boolean any_player_moving,
8067 boolean any_player_snapping,
8068 boolean any_player_dropping)
8070 if (tape.single_step && tape.recording && !tape.pausing)
8071 if (frame == 0 && !any_player_dropping)
8072 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
8074 CheckSaveEngineSnapshot_EM(action, frame, any_player_moving,
8075 any_player_snapping, any_player_dropping);
8078 void CheckSingleStepMode_SP(boolean murphy_is_waiting,
8079 boolean murphy_is_dropping)
8081 if (tape.single_step && tape.recording && !tape.pausing)
8082 if (murphy_is_waiting)
8083 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
8085 CheckSaveEngineSnapshot_SP(murphy_is_waiting, murphy_is_dropping);
8088 void getGraphicSource_SP(struct GraphicInfo_SP *g_sp,
8089 int graphic, int sync_frame, int x, int y)
8091 int frame = getGraphicAnimationFrame(graphic, sync_frame);
8093 getGraphicSource(graphic, frame, &g_sp->bitmap, &g_sp->src_x, &g_sp->src_y);
8096 boolean isNextAnimationFrame_SP(int graphic, int sync_frame)
8098 return (IS_NEXT_FRAME(sync_frame, graphic));
8101 int getGraphicInfo_Delay(int graphic)
8103 return graphic_info[graphic].anim_delay;
8106 void PlayMenuSoundExt(int sound)
8108 if (sound == SND_UNDEFINED)
8111 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8112 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8115 if (IS_LOOP_SOUND(sound))
8116 PlaySoundLoop(sound);
8121 void PlayMenuSound()
8123 PlayMenuSoundExt(menu.sound[game_status]);
8126 void PlayMenuSoundStereo(int sound, int stereo_position)
8128 if (sound == SND_UNDEFINED)
8131 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8132 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8135 if (IS_LOOP_SOUND(sound))
8136 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
8138 PlaySoundStereo(sound, stereo_position);
8141 void PlayMenuSoundIfLoopExt(int sound)
8143 if (sound == SND_UNDEFINED)
8146 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8147 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8150 if (IS_LOOP_SOUND(sound))
8151 PlaySoundLoop(sound);
8154 void PlayMenuSoundIfLoop()
8156 PlayMenuSoundIfLoopExt(menu.sound[game_status]);
8159 void PlayMenuMusicExt(int music)
8161 if (music == MUS_UNDEFINED)
8164 if (!setup.sound_music)
8170 void PlayMenuMusic()
8172 PlayMenuMusicExt(menu.music[game_status]);
8175 void PlaySoundActivating()
8178 PlaySound(SND_MENU_ITEM_ACTIVATING);
8182 void PlaySoundSelecting()
8185 PlaySound(SND_MENU_ITEM_SELECTING);
8189 void ToggleFullscreenOrChangeWindowScalingIfNeeded()
8191 boolean change_fullscreen = (setup.fullscreen !=
8192 video.fullscreen_enabled);
8193 boolean change_window_scaling_percent = (!video.fullscreen_enabled &&
8194 setup.window_scaling_percent !=
8195 video.window_scaling_percent);
8197 if (change_window_scaling_percent && video.fullscreen_enabled)
8200 if (!change_window_scaling_percent && !video.fullscreen_available)
8203 #if defined(TARGET_SDL2)
8204 if (change_window_scaling_percent)
8206 SDLSetWindowScaling(setup.window_scaling_percent);
8210 else if (change_fullscreen)
8212 SDLSetWindowFullscreen(setup.fullscreen);
8214 /* set setup value according to successfully changed fullscreen mode */
8215 setup.fullscreen = video.fullscreen_enabled;
8221 if (change_fullscreen ||
8222 change_window_scaling_percent)
8224 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
8226 /* save backbuffer content which gets lost when toggling fullscreen mode */
8227 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8229 if (change_window_scaling_percent)
8231 /* keep window mode, but change window scaling */
8232 video.fullscreen_enabled = TRUE; /* force new window scaling */
8235 /* toggle fullscreen */
8236 ChangeVideoModeIfNeeded(setup.fullscreen);
8238 /* set setup value according to successfully changed fullscreen mode */
8239 setup.fullscreen = video.fullscreen_enabled;
8241 /* restore backbuffer content from temporary backbuffer backup bitmap */
8242 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8244 FreeBitmap(tmp_backbuffer);
8246 /* update visible window/screen */
8247 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8251 void JoinRectangles(int *x, int *y, int *width, int *height,
8252 int x2, int y2, int width2, int height2)
8254 // do not join with "off-screen" rectangle
8255 if (x2 == -1 || y2 == -1)
8260 *width = MAX(*width, width2);
8261 *height = MAX(*height, height2);
8264 void SetAnimStatus(int anim_status_new)
8266 if (anim_status_new == GAME_MODE_MAIN)
8267 anim_status_new = GAME_MODE_PSEUDO_MAINONLY;
8269 global.anim_status_next = anim_status_new;
8271 // directly set screen modes that are entered without fading
8272 if ((global.anim_status == GAME_MODE_PSEUDO_MAINONLY &&
8273 global.anim_status_next == GAME_MODE_PSEUDO_TYPENAME) ||
8274 (global.anim_status == GAME_MODE_PSEUDO_TYPENAME &&
8275 global.anim_status_next == GAME_MODE_PSEUDO_MAINONLY))
8276 global.anim_status = global.anim_status_next;
8279 void SetGameStatus(int game_status_new)
8281 game_status = game_status_new;
8283 SetAnimStatus(game_status_new);
8286 void SetFontStatus(int game_status_new)
8288 static int last_game_status = -1;
8290 if (game_status_new != -1)
8292 // set game status for font use after storing last game status
8293 last_game_status = game_status;
8294 game_status = game_status_new;
8298 // reset game status after font use from last stored game status
8299 game_status = last_game_status;
8303 void ResetFontStatus()
8308 void ChangeViewportPropertiesIfNeeded()
8310 int gfx_game_mode = game_status;
8311 int gfx_game_mode2 = (game_status == GAME_MODE_EDITOR ? GAME_MODE_DEFAULT :
8313 struct RectWithBorder *vp_window = &viewport.window[gfx_game_mode];
8314 struct RectWithBorder *vp_playfield = &viewport.playfield[gfx_game_mode];
8315 struct RectWithBorder *vp_door_1 = &viewport.door_1[gfx_game_mode];
8316 struct RectWithBorder *vp_door_2 = &viewport.door_2[gfx_game_mode2];
8317 struct RectWithBorder *vp_door_3 = &viewport.door_2[GAME_MODE_EDITOR];
8318 int new_win_xsize = vp_window->width;
8319 int new_win_ysize = vp_window->height;
8320 int border_size = vp_playfield->border_size;
8321 int new_sx = vp_playfield->x + border_size;
8322 int new_sy = vp_playfield->y + border_size;
8323 int new_sxsize = vp_playfield->width - 2 * border_size;
8324 int new_sysize = vp_playfield->height - 2 * border_size;
8325 int new_real_sx = vp_playfield->x;
8326 int new_real_sy = vp_playfield->y;
8327 int new_full_sxsize = vp_playfield->width;
8328 int new_full_sysize = vp_playfield->height;
8329 int new_dx = vp_door_1->x;
8330 int new_dy = vp_door_1->y;
8331 int new_dxsize = vp_door_1->width;
8332 int new_dysize = vp_door_1->height;
8333 int new_vx = vp_door_2->x;
8334 int new_vy = vp_door_2->y;
8335 int new_vxsize = vp_door_2->width;
8336 int new_vysize = vp_door_2->height;
8337 int new_ex = vp_door_3->x;
8338 int new_ey = vp_door_3->y;
8339 int new_exsize = vp_door_3->width;
8340 int new_eysize = vp_door_3->height;
8341 int new_tilesize_var =
8342 (setup.small_game_graphics ? MINI_TILESIZE : game.tile_size);
8344 int tilesize = (gfx_game_mode == GAME_MODE_PLAYING ? new_tilesize_var :
8345 gfx_game_mode == GAME_MODE_EDITOR ? MINI_TILESIZE : TILESIZE);
8346 int new_scr_fieldx = new_sxsize / tilesize;
8347 int new_scr_fieldy = new_sysize / tilesize;
8348 int new_scr_fieldx_buffers = new_sxsize / new_tilesize_var;
8349 int new_scr_fieldy_buffers = new_sysize / new_tilesize_var;
8350 boolean init_gfx_buffers = FALSE;
8351 boolean init_video_buffer = FALSE;
8352 boolean init_gadgets_and_anims = FALSE;
8353 boolean init_em_graphics = FALSE;
8355 if (new_win_xsize != WIN_XSIZE ||
8356 new_win_ysize != WIN_YSIZE)
8358 WIN_XSIZE = new_win_xsize;
8359 WIN_YSIZE = new_win_ysize;
8361 init_video_buffer = TRUE;
8362 init_gfx_buffers = TRUE;
8363 init_gadgets_and_anims = TRUE;
8365 // printf("::: video: init_video_buffer, init_gfx_buffers\n");
8368 if (new_scr_fieldx != SCR_FIELDX ||
8369 new_scr_fieldy != SCR_FIELDY)
8371 /* this always toggles between MAIN and GAME when using small tile size */
8373 SCR_FIELDX = new_scr_fieldx;
8374 SCR_FIELDY = new_scr_fieldy;
8376 // printf("::: new_scr_fieldx != SCR_FIELDX ...\n");
8387 new_sxsize != SXSIZE ||
8388 new_sysize != SYSIZE ||
8389 new_dxsize != DXSIZE ||
8390 new_dysize != DYSIZE ||
8391 new_vxsize != VXSIZE ||
8392 new_vysize != VYSIZE ||
8393 new_exsize != EXSIZE ||
8394 new_eysize != EYSIZE ||
8395 new_real_sx != REAL_SX ||
8396 new_real_sy != REAL_SY ||
8397 new_full_sxsize != FULL_SXSIZE ||
8398 new_full_sysize != FULL_SYSIZE ||
8399 new_tilesize_var != TILESIZE_VAR
8402 // ------------------------------------------------------------------------
8403 // determine next fading area for changed viewport definitions
8404 // ------------------------------------------------------------------------
8406 // start with current playfield area (default fading area)
8409 FADE_SXSIZE = FULL_SXSIZE;
8410 FADE_SYSIZE = FULL_SYSIZE;
8412 // add new playfield area if position or size has changed
8413 if (new_real_sx != REAL_SX || new_real_sy != REAL_SY ||
8414 new_full_sxsize != FULL_SXSIZE || new_full_sysize != FULL_SYSIZE)
8416 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
8417 new_real_sx, new_real_sy, new_full_sxsize,new_full_sysize);
8420 // add current and new door 1 area if position or size has changed
8421 if (new_dx != DX || new_dy != DY ||
8422 new_dxsize != DXSIZE || new_dysize != DYSIZE)
8424 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
8425 DX, DY, DXSIZE, DYSIZE);
8426 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
8427 new_dx, new_dy, new_dxsize, new_dysize);
8430 // add current and new door 2 area if position or size has changed
8431 if (new_dx != VX || new_dy != VY ||
8432 new_dxsize != VXSIZE || new_dysize != VYSIZE)
8434 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
8435 VX, VY, VXSIZE, VYSIZE);
8436 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
8437 new_vx, new_vy, new_vxsize, new_vysize);
8440 // ------------------------------------------------------------------------
8441 // handle changed tile size
8442 // ------------------------------------------------------------------------
8444 if (new_tilesize_var != TILESIZE_VAR)
8446 // printf("::: new_tilesize_var != TILESIZE_VAR\n");
8448 // changing tile size invalidates scroll values of engine snapshots
8449 FreeEngineSnapshotSingle();
8451 // changing tile size requires update of graphic mapping for EM engine
8452 init_em_graphics = TRUE;
8463 SXSIZE = new_sxsize;
8464 SYSIZE = new_sysize;
8465 DXSIZE = new_dxsize;
8466 DYSIZE = new_dysize;
8467 VXSIZE = new_vxsize;
8468 VYSIZE = new_vysize;
8469 EXSIZE = new_exsize;
8470 EYSIZE = new_eysize;
8471 REAL_SX = new_real_sx;
8472 REAL_SY = new_real_sy;
8473 FULL_SXSIZE = new_full_sxsize;
8474 FULL_SYSIZE = new_full_sysize;
8475 TILESIZE_VAR = new_tilesize_var;
8477 init_gfx_buffers = TRUE;
8478 init_gadgets_and_anims = TRUE;
8480 // printf("::: viewports: init_gfx_buffers\n");
8481 // printf("::: viewports: init_gadgets_and_anims\n");
8484 if (init_gfx_buffers)
8486 // printf("::: init_gfx_buffers\n");
8488 SCR_FIELDX = new_scr_fieldx_buffers;
8489 SCR_FIELDY = new_scr_fieldy_buffers;
8493 SCR_FIELDX = new_scr_fieldx;
8494 SCR_FIELDY = new_scr_fieldy;
8496 SetDrawDeactivationMask(REDRAW_NONE);
8497 SetDrawBackgroundMask(REDRAW_FIELD);
8500 if (init_video_buffer)
8502 // printf("::: init_video_buffer\n");
8504 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
8505 InitImageTextures();
8508 if (init_gadgets_and_anims)
8510 // printf("::: init_gadgets_and_anims\n");
8513 InitGlobalAnimations();
8516 if (init_em_graphics)
8518 InitGraphicInfo_EM();