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 // redraw complete window if both playfield and (some) doors need redraw
554 if (redraw_mask & REDRAW_FIELD && redraw_mask & REDRAW_DOORS)
555 redraw_mask = REDRAW_ALL;
557 /* although redrawing the whole window would be fine for normal gameplay,
558 being able to only redraw the playfield is required for deactivating
559 certain drawing areas (mainly playfield) to work, which is needed for
560 warp-forward to be fast enough (by skipping redraw of most frames) */
562 if (redraw_mask & REDRAW_ALL)
564 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
566 else if (redraw_mask & REDRAW_FIELD)
568 BlitBitmap(backbuffer, window,
569 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
571 else if (redraw_mask & REDRAW_DOORS)
573 // merge door areas to prevent calling screen redraw more than once
579 if (redraw_mask & REDRAW_DOOR_1)
583 x2 = MAX(x2, DX + DXSIZE);
584 y2 = MAX(y2, DY + DYSIZE);
586 else if (redraw_mask & REDRAW_DOOR_2)
590 x2 = MAX(x2, VX + VXSIZE);
591 y2 = MAX(y2, VY + VYSIZE);
593 else if (redraw_mask & REDRAW_DOOR_3)
597 x2 = MAX(x2, EX + EXSIZE);
598 y2 = MAX(y2, EY + EYSIZE);
601 BlitBitmap(backbuffer, window, x1, y1, x2 - x1, y2 - y1, x1, y1);
604 redraw_mask = REDRAW_NONE;
607 PrintFrameTimeDebugging();
611 void BackToFront_WithFrameDelay(unsigned int frame_delay_value)
613 unsigned int frame_delay_value_old = GetVideoFrameDelay();
615 SetVideoFrameDelay(frame_delay_value);
619 SetVideoFrameDelay(frame_delay_value_old);
622 static void FadeExt(int fade_mask, int fade_mode, int fade_type)
624 static int fade_type_skip = FADE_TYPE_NONE;
625 void (*draw_border_function)(void) = NULL;
626 int x, y, width, height;
627 int fade_delay, post_delay;
629 if (fade_type == FADE_TYPE_FADE_OUT)
631 if (fade_type_skip != FADE_TYPE_NONE)
633 /* skip all fade operations until specified fade operation */
634 if (fade_type & fade_type_skip)
635 fade_type_skip = FADE_TYPE_NONE;
640 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
644 redraw_mask |= fade_mask;
646 if (fade_type == FADE_TYPE_SKIP)
648 fade_type_skip = fade_mode;
653 fade_delay = fading.fade_delay;
654 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
656 if (fade_type_skip != FADE_TYPE_NONE)
658 /* skip all fade operations until specified fade operation */
659 if (fade_type & fade_type_skip)
660 fade_type_skip = FADE_TYPE_NONE;
665 if (global.autoplay_leveldir)
670 if (fade_mask == REDRAW_FIELD)
675 height = FADE_SYSIZE;
677 if (border.draw_masked_when_fading)
678 draw_border_function = DrawMaskedBorder_FIELD; /* update when fading */
680 DrawMaskedBorder_FIELD(); /* draw once */
682 else /* REDRAW_ALL */
690 if (!setup.fade_screens ||
692 fading.fade_mode == FADE_MODE_NONE)
694 if (fade_mode == FADE_MODE_FADE_OUT)
697 BlitBitmap(backbuffer, window, x, y, width, height, x, y);
699 redraw_mask &= ~fade_mask;
704 FadeRectangle(x, y, width, height, fade_mode, fade_delay, post_delay,
705 draw_border_function);
707 redraw_mask &= ~fade_mask;
710 static void SetScreenStates_BeforeFadingIn()
712 // temporarily set screen mode for animations to screen after fading in
713 global.anim_status = global.anim_status_next;
715 // store backbuffer with all animations that will be started after fading in
716 PrepareFadeBitmap(DRAW_TO_FADE_TARGET);
718 // set screen mode for animations back to fading
719 global.anim_status = GAME_MODE_PSEUDO_FADING;
722 static void SetScreenStates_AfterFadingIn()
724 // store new source screen (to use correct masked border for fading)
725 gfx.fade_border_source_status = global.border_status;
727 global.anim_status = global.anim_status_next;
729 // force update of global animation status in case of rapid screen changes
730 redraw_mask = REDRAW_ALL;
734 static void SetScreenStates_BeforeFadingOut()
736 // store new target screen (to use correct masked border for fading)
737 gfx.fade_border_target_status = game_status;
739 // set screen mode for animations to fading
740 global.anim_status = GAME_MODE_PSEUDO_FADING;
742 // store backbuffer with all animations that will be stopped for fading out
743 PrepareFadeBitmap(DRAW_TO_FADE_SOURCE);
746 static void SetScreenStates_AfterFadingOut()
748 global.border_status = game_status;
751 void FadeIn(int fade_mask)
753 SetScreenStates_BeforeFadingIn();
756 DrawMaskedBorder(REDRAW_ALL);
759 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
760 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_IN);
762 FadeExt(fade_mask, FADE_MODE_FADE_IN, FADE_TYPE_FADE_IN);
766 FADE_SXSIZE = FULL_SXSIZE;
767 FADE_SYSIZE = FULL_SYSIZE;
769 SetScreenStates_AfterFadingIn();
772 void FadeOut(int fade_mask)
774 SetScreenStates_BeforeFadingOut();
777 DrawMaskedBorder(REDRAW_ALL);
780 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
781 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_OUT);
783 FadeExt(fade_mask, FADE_MODE_FADE_OUT, FADE_TYPE_FADE_OUT);
785 SetScreenStates_AfterFadingOut();
788 static void FadeSetLeaveNext(struct TitleFadingInfo fading_leave, boolean set)
790 static struct TitleFadingInfo fading_leave_stored;
793 fading_leave_stored = fading_leave;
795 fading = fading_leave_stored;
798 void FadeSetEnterMenu()
800 fading = menu.enter_menu;
802 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
805 void FadeSetLeaveMenu()
807 fading = menu.leave_menu;
809 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
812 void FadeSetEnterScreen()
814 fading = menu.enter_screen[game_status];
816 FadeSetLeaveNext(menu.leave_screen[game_status], TRUE); /* store */
819 void FadeSetNextScreen()
821 fading = menu.next_screen[game_status];
823 // (do not overwrite fade mode set by FadeSetEnterScreen)
824 // FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
827 void FadeSetLeaveScreen()
829 FadeSetLeaveNext(menu.leave_screen[game_status], FALSE); /* recall */
832 void FadeSetFromType(int type)
834 if (type & TYPE_ENTER_SCREEN)
835 FadeSetEnterScreen();
836 else if (type & TYPE_ENTER)
838 else if (type & TYPE_LEAVE)
842 void FadeSetDisabled()
844 static struct TitleFadingInfo fading_none = { FADE_MODE_NONE, -1, -1, -1 };
846 fading = fading_none;
849 void FadeSkipNextFadeIn()
851 FadeExt(0, FADE_MODE_SKIP_FADE_IN, FADE_TYPE_SKIP);
854 void FadeSkipNextFadeOut()
856 FadeExt(0, FADE_MODE_SKIP_FADE_OUT, FADE_TYPE_SKIP);
859 Bitmap *getBitmapFromGraphicOrDefault(int graphic, int default_graphic)
861 boolean redefined = getImageListEntryFromImageID(graphic)->redefined;
863 return (graphic == IMG_UNDEFINED ? NULL :
864 graphic_info[graphic].bitmap != NULL || redefined ?
865 graphic_info[graphic].bitmap :
866 graphic_info[default_graphic].bitmap);
869 Bitmap *getBackgroundBitmap(int graphic)
871 return getBitmapFromGraphicOrDefault(graphic, IMG_BACKGROUND);
874 Bitmap *getGlobalBorderBitmap(int graphic)
876 return getBitmapFromGraphicOrDefault(graphic, IMG_GLOBAL_BORDER);
879 Bitmap *getGlobalBorderBitmapFromStatus(int status)
882 (status == GAME_MODE_MAIN ||
883 status == GAME_MODE_PSEUDO_TYPENAME ? IMG_GLOBAL_BORDER_MAIN :
884 status == GAME_MODE_SCORES ? IMG_GLOBAL_BORDER_SCORES :
885 status == GAME_MODE_EDITOR ? IMG_GLOBAL_BORDER_EDITOR :
886 status == GAME_MODE_PLAYING ? IMG_GLOBAL_BORDER_PLAYING :
889 return getGlobalBorderBitmap(graphic);
892 void SetWindowBackgroundImageIfDefined(int graphic)
894 if (graphic_info[graphic].bitmap)
895 SetWindowBackgroundBitmap(graphic_info[graphic].bitmap);
898 void SetMainBackgroundImageIfDefined(int graphic)
900 if (graphic_info[graphic].bitmap)
901 SetMainBackgroundBitmap(graphic_info[graphic].bitmap);
904 void SetDoorBackgroundImageIfDefined(int graphic)
906 if (graphic_info[graphic].bitmap)
907 SetDoorBackgroundBitmap(graphic_info[graphic].bitmap);
910 void SetWindowBackgroundImage(int graphic)
912 SetWindowBackgroundBitmap(getBackgroundBitmap(graphic));
915 void SetMainBackgroundImage(int graphic)
917 SetMainBackgroundBitmap(getBackgroundBitmap(graphic));
920 void SetDoorBackgroundImage(int graphic)
922 SetDoorBackgroundBitmap(getBackgroundBitmap(graphic));
925 void SetPanelBackground()
927 struct GraphicInfo *gfx = &graphic_info[IMG_BACKGROUND_PANEL];
929 BlitBitmapTiled(gfx->bitmap, bitmap_db_panel, gfx->src_x, gfx->src_y,
930 gfx->width, gfx->height, 0, 0, DXSIZE, DYSIZE);
932 SetDoorBackgroundBitmap(bitmap_db_panel);
935 void DrawBackground(int x, int y, int width, int height)
937 /* "drawto" might still point to playfield buffer here (hall of fame) */
938 ClearRectangleOnBackground(backbuffer, x, y, width, height);
940 if (IN_GFX_FIELD_FULL(x, y))
941 redraw_mask |= REDRAW_FIELD;
942 else if (IN_GFX_DOOR_1(x, y))
943 redraw_mask |= REDRAW_DOOR_1;
944 else if (IN_GFX_DOOR_2(x, y))
945 redraw_mask |= REDRAW_DOOR_2;
946 else if (IN_GFX_DOOR_3(x, y))
947 redraw_mask |= REDRAW_DOOR_3;
950 void DrawBackgroundForFont(int x, int y, int width, int height, int font_nr)
952 struct FontBitmapInfo *font = getFontBitmapInfo(font_nr);
954 if (font->bitmap == NULL)
957 DrawBackground(x, y, width, height);
960 void DrawBackgroundForGraphic(int x, int y, int width, int height, int graphic)
962 struct GraphicInfo *g = &graphic_info[graphic];
964 if (g->bitmap == NULL)
967 DrawBackground(x, y, width, height);
970 static int game_status_last = -1;
971 static Bitmap *global_border_bitmap_last = NULL;
972 static Bitmap *global_border_bitmap = NULL;
973 static int real_sx_last = -1, real_sy_last = -1;
974 static int full_sxsize_last = -1, full_sysize_last = -1;
975 static int dx_last = -1, dy_last = -1;
976 static int dxsize_last = -1, dysize_last = -1;
977 static int vx_last = -1, vy_last = -1;
978 static int vxsize_last = -1, vysize_last = -1;
980 boolean CheckIfGlobalBorderHasChanged()
982 // if game status has not changed, global border has not changed either
983 if (game_status == game_status_last)
986 // determine and store new global border bitmap for current game status
987 global_border_bitmap = getGlobalBorderBitmapFromStatus(game_status);
989 return (global_border_bitmap_last != global_border_bitmap);
992 boolean CheckIfGlobalBorderRedrawIsNeeded()
994 // if game status has not changed, nothing has to be redrawn
995 if (game_status == game_status_last)
998 // redraw if last screen was title screen
999 if (game_status_last == GAME_MODE_TITLE)
1002 // redraw if global screen border has changed
1003 if (CheckIfGlobalBorderHasChanged())
1006 // redraw if position or size of playfield area has changed
1007 if (real_sx_last != REAL_SX || real_sy_last != REAL_SY ||
1008 full_sxsize_last != FULL_SXSIZE || full_sysize_last != FULL_SYSIZE)
1011 // redraw if position or size of door area has changed
1012 if (dx_last != DX || dy_last != DY ||
1013 dxsize_last != DXSIZE || dysize_last != DYSIZE)
1016 // redraw if position or size of tape area has changed
1017 if (vx_last != VX || vy_last != VY ||
1018 vxsize_last != VXSIZE || vysize_last != VYSIZE)
1024 void RedrawGlobalBorderFromBitmap(Bitmap *bitmap)
1027 BlitBitmap(bitmap, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
1029 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
1032 void RedrawGlobalBorder()
1034 Bitmap *bitmap = getGlobalBorderBitmapFromStatus(game_status);
1036 RedrawGlobalBorderFromBitmap(bitmap);
1038 redraw_mask = REDRAW_ALL;
1041 static void RedrawGlobalBorderIfNeeded()
1043 if (game_status == game_status_last)
1046 // copy current draw buffer to later copy back areas that have not changed
1047 if (game_status_last != GAME_MODE_TITLE)
1048 BlitBitmap(backbuffer, bitmap_db_store_1, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
1050 if (CheckIfGlobalBorderRedrawIsNeeded())
1052 // redraw global screen border (or clear, if defined to be empty)
1053 RedrawGlobalBorderFromBitmap(global_border_bitmap);
1055 // copy previous playfield and door areas, if they are defined on both
1056 // previous and current screen and if they still have the same size
1058 if (real_sx_last != -1 && real_sy_last != -1 &&
1059 REAL_SX != -1 && REAL_SY != -1 &&
1060 full_sxsize_last == FULL_SXSIZE && full_sysize_last == FULL_SYSIZE)
1061 BlitBitmap(bitmap_db_store_1, backbuffer,
1062 real_sx_last, real_sy_last, FULL_SXSIZE, FULL_SYSIZE,
1065 if (dx_last != -1 && dy_last != -1 &&
1066 DX != -1 && DY != -1 &&
1067 dxsize_last == DXSIZE && dysize_last == DYSIZE)
1068 BlitBitmap(bitmap_db_store_1, backbuffer,
1069 dx_last, dy_last, DXSIZE, DYSIZE, DX, DY);
1071 if (vx_last != -1 && vy_last != -1 &&
1072 VX != -1 && VY != -1 &&
1073 vxsize_last == VXSIZE && vysize_last == VYSIZE)
1074 BlitBitmap(bitmap_db_store_1, backbuffer,
1075 vx_last, vy_last, VXSIZE, VYSIZE, VX, VY);
1077 redraw_mask = REDRAW_ALL;
1080 game_status_last = game_status;
1082 global_border_bitmap_last = global_border_bitmap;
1084 real_sx_last = REAL_SX;
1085 real_sy_last = REAL_SY;
1086 full_sxsize_last = FULL_SXSIZE;
1087 full_sysize_last = FULL_SYSIZE;
1090 dxsize_last = DXSIZE;
1091 dysize_last = DYSIZE;
1094 vxsize_last = VXSIZE;
1095 vysize_last = VYSIZE;
1100 RedrawGlobalBorderIfNeeded();
1102 /* !!! "drawto" might still point to playfield buffer here (see above) !!! */
1103 /* (when entering hall of fame after playing) */
1104 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
1106 /* !!! maybe this should be done before clearing the background !!! */
1107 if (game_status == GAME_MODE_PLAYING)
1109 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
1110 SetDrawtoField(DRAW_TO_FIELDBUFFER);
1114 SetDrawtoField(DRAW_TO_BACKBUFFER);
1118 void MarkTileDirty(int x, int y)
1120 redraw_mask |= REDRAW_FIELD;
1123 void SetBorderElement()
1127 BorderElement = EL_EMPTY;
1129 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
1131 for (x = 0; x < lev_fieldx; x++)
1133 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
1134 BorderElement = EL_STEELWALL;
1136 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
1142 void FloodFillLevel(int from_x, int from_y, int fill_element,
1143 short field[MAX_LEV_FIELDX][MAX_LEV_FIELDY],
1144 int max_fieldx, int max_fieldy)
1148 static int check[4][2] = { { -1, 0 }, { 0, -1 }, { 1, 0 }, { 0, 1 } };
1149 static int safety = 0;
1151 /* check if starting field still has the desired content */
1152 if (field[from_x][from_y] == fill_element)
1157 if (safety > max_fieldx * max_fieldy)
1158 Error(ERR_EXIT, "Something went wrong in 'FloodFill()'. Please debug.");
1160 old_element = field[from_x][from_y];
1161 field[from_x][from_y] = fill_element;
1163 for (i = 0; i < 4; i++)
1165 x = from_x + check[i][0];
1166 y = from_y + check[i][1];
1168 if (IN_FIELD(x, y, max_fieldx, max_fieldy) && field[x][y] == old_element)
1169 FloodFillLevel(x, y, fill_element, field, max_fieldx, max_fieldy);
1175 void SetRandomAnimationValue(int x, int y)
1177 gfx.anim_random_frame = GfxRandom[x][y];
1180 int getGraphicAnimationFrame(int graphic, int sync_frame)
1182 /* animation synchronized with global frame counter, not move position */
1183 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
1184 sync_frame = FrameCounter;
1186 return getAnimationFrame(graphic_info[graphic].anim_frames,
1187 graphic_info[graphic].anim_delay,
1188 graphic_info[graphic].anim_mode,
1189 graphic_info[graphic].anim_start_frame,
1193 void getSizedGraphicSourceExt(int graphic, int frame, int tilesize,
1194 Bitmap **bitmap, int *x, int *y,
1195 boolean get_backside)
1197 struct GraphicInfo *g = &graphic_info[graphic];
1198 Bitmap *src_bitmap = g->bitmap;
1199 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
1200 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
1201 int tilesize_capped = MIN(MAX(1, tilesize), TILESIZE);
1203 // if no in-game graphics defined, always use standard graphic size
1204 if (g->bitmaps[IMG_BITMAP_GAME] == NULL)
1205 tilesize = TILESIZE;
1207 if (tilesize == gfx.standard_tile_size)
1208 src_bitmap = g->bitmaps[IMG_BITMAP_STANDARD];
1209 else if (tilesize == game.tile_size)
1210 src_bitmap = g->bitmaps[IMG_BITMAP_GAME];
1212 src_bitmap = g->bitmaps[IMG_BITMAP_1x1 - log_2(tilesize_capped)];
1214 if (g->offset_y == 0) /* frames are ordered horizontally */
1216 int max_width = g->anim_frames_per_line * g->width;
1217 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
1219 src_x = pos % max_width;
1220 src_y = src_y % g->height + pos / max_width * g->height;
1222 else if (g->offset_x == 0) /* frames are ordered vertically */
1224 int max_height = g->anim_frames_per_line * g->height;
1225 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
1227 src_x = src_x % g->width + pos / max_height * g->width;
1228 src_y = pos % max_height;
1230 else /* frames are ordered diagonally */
1232 src_x = src_x + frame * g->offset_x;
1233 src_y = src_y + frame * g->offset_y;
1236 *bitmap = src_bitmap;
1237 *x = src_x * tilesize / g->tile_size;
1238 *y = src_y * tilesize / g->tile_size;
1241 void getFixedGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1242 int *x, int *y, boolean get_backside)
1244 getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y,
1248 void getSizedGraphicSource(int graphic, int frame, int tilesize,
1249 Bitmap **bitmap, int *x, int *y)
1251 getSizedGraphicSourceExt(graphic, frame, tilesize, bitmap, x, y, FALSE);
1254 void getFixedGraphicSource(int graphic, int frame,
1255 Bitmap **bitmap, int *x, int *y)
1257 getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y, FALSE);
1260 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1262 getSizedGraphicSource(graphic, 0, MINI_TILESIZE, bitmap, x, y);
1265 inline static void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1266 int *x, int *y, boolean get_backside)
1268 struct GraphicInfo *g = &graphic_info[graphic];
1269 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
1270 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
1272 if (TILESIZE_VAR != TILESIZE)
1273 return getSizedGraphicSourceExt(graphic, frame, TILESIZE_VAR, bitmap, x, y,
1276 *bitmap = g->bitmap;
1278 if (g->offset_y == 0) /* frames are ordered horizontally */
1280 int max_width = g->anim_frames_per_line * g->width;
1281 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
1283 *x = pos % max_width;
1284 *y = src_y % g->height + pos / max_width * g->height;
1286 else if (g->offset_x == 0) /* frames are ordered vertically */
1288 int max_height = g->anim_frames_per_line * g->height;
1289 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
1291 *x = src_x % g->width + pos / max_height * g->width;
1292 *y = pos % max_height;
1294 else /* frames are ordered diagonally */
1296 *x = src_x + frame * g->offset_x;
1297 *y = src_y + frame * g->offset_y;
1300 *x = *x * TILESIZE_VAR / g->tile_size;
1301 *y = *y * TILESIZE_VAR / g->tile_size;
1304 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
1306 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
1309 void DrawGraphic(int x, int y, int graphic, int frame)
1312 if (!IN_SCR_FIELD(x, y))
1314 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1315 printf("DrawGraphic(): This should never happen!\n");
1320 DrawGraphicExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR, graphic,
1323 MarkTileDirty(x, y);
1326 void DrawFixedGraphic(int x, int y, int graphic, int frame)
1329 if (!IN_SCR_FIELD(x, y))
1331 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1332 printf("DrawGraphic(): This should never happen!\n");
1337 DrawFixedGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic,
1339 MarkTileDirty(x, y);
1342 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1348 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1350 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX_VAR, TILEY_VAR, x, y);
1353 void DrawFixedGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1359 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1360 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
1363 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
1366 if (!IN_SCR_FIELD(x, y))
1368 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1369 printf("DrawGraphicThruMask(): This should never happen!\n");
1374 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
1377 MarkTileDirty(x, y);
1380 void DrawFixedGraphicThruMask(int x, int y, int graphic, int frame)
1383 if (!IN_SCR_FIELD(x, y))
1385 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1386 printf("DrawGraphicThruMask(): This should never happen!\n");
1391 DrawFixedGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
1393 MarkTileDirty(x, y);
1396 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
1402 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1404 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX_VAR, TILEY_VAR,
1408 void DrawFixedGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y,
1409 int graphic, int frame)
1414 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1416 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY,
1420 void DrawSizedGraphic(int x, int y, int graphic, int frame, int tilesize)
1422 DrawSizedGraphicExt(drawto, SX + x * tilesize, SY + y * tilesize, graphic,
1424 MarkTileDirty(x / tilesize, y / tilesize);
1427 void DrawSizedGraphicExt(DrawBuffer *d, int x, int y, int graphic, int frame,
1433 getSizedGraphicSource(graphic, frame, tilesize, &src_bitmap, &src_x, &src_y);
1434 BlitBitmap(src_bitmap, d, src_x, src_y, tilesize, tilesize, x, y);
1437 void DrawMiniGraphic(int x, int y, int graphic)
1439 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
1440 MarkTileDirty(x / 2, y / 2);
1443 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
1448 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1449 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
1452 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
1453 int graphic, int frame,
1454 int cut_mode, int mask_mode)
1459 int width = TILEX, height = TILEY;
1462 if (dx || dy) /* shifted graphic */
1464 if (x < BX1) /* object enters playfield from the left */
1471 else if (x > BX2) /* object enters playfield from the right */
1477 else if (x == BX1 && dx < 0) /* object leaves playfield to the left */
1483 else if (x == BX2 && dx > 0) /* object leaves playfield to the right */
1485 else if (dx) /* general horizontal movement */
1486 MarkTileDirty(x + SIGN(dx), y);
1488 if (y < BY1) /* object enters playfield from the top */
1490 if (cut_mode == CUT_BELOW) /* object completely above top border */
1498 else if (y > BY2) /* object enters playfield from the bottom */
1504 else if (y == BY1 && dy < 0) /* object leaves playfield to the top */
1510 else if (dy > 0 && cut_mode == CUT_ABOVE)
1512 if (y == BY2) /* object completely above bottom border */
1518 MarkTileDirty(x, y + 1);
1519 } /* object leaves playfield to the bottom */
1520 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1522 else if (dy) /* general vertical movement */
1523 MarkTileDirty(x, y + SIGN(dy));
1527 if (!IN_SCR_FIELD(x, y))
1529 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1530 printf("DrawGraphicShifted(): This should never happen!\n");
1535 width = width * TILESIZE_VAR / TILESIZE;
1536 height = height * TILESIZE_VAR / TILESIZE;
1537 cx = cx * TILESIZE_VAR / TILESIZE;
1538 cy = cy * TILESIZE_VAR / TILESIZE;
1539 dx = dx * TILESIZE_VAR / TILESIZE;
1540 dy = dy * TILESIZE_VAR / TILESIZE;
1542 if (width > 0 && height > 0)
1544 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1549 dst_x = FX + x * TILEX_VAR + dx;
1550 dst_y = FY + y * TILEY_VAR + dy;
1552 if (mask_mode == USE_MASKING)
1553 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1556 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1559 MarkTileDirty(x, y);
1563 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
1564 int graphic, int frame,
1565 int cut_mode, int mask_mode)
1570 int width = TILEX_VAR, height = TILEY_VAR;
1573 int x2 = x + SIGN(dx);
1574 int y2 = y + SIGN(dy);
1576 /* movement with two-tile animations must be sync'ed with movement position,
1577 not with current GfxFrame (which can be higher when using slow movement) */
1578 int anim_pos = (dx ? ABS(dx) : ABS(dy));
1579 int anim_frames = graphic_info[graphic].anim_frames;
1581 /* (we also need anim_delay here for movement animations with less frames) */
1582 int anim_delay = graphic_info[graphic].anim_delay;
1583 int sync_frame = anim_pos * anim_frames * anim_delay / TILESIZE;
1585 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
1586 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
1588 /* re-calculate animation frame for two-tile movement animation */
1589 frame = getGraphicAnimationFrame(graphic, sync_frame);
1591 /* check if movement start graphic inside screen area and should be drawn */
1592 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
1594 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
1596 dst_x = FX + x1 * TILEX_VAR;
1597 dst_y = FY + y1 * TILEY_VAR;
1599 if (mask_mode == USE_MASKING)
1600 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1603 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1606 MarkTileDirty(x1, y1);
1609 /* check if movement end graphic inside screen area and should be drawn */
1610 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
1612 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
1614 dst_x = FX + x2 * TILEX_VAR;
1615 dst_y = FY + y2 * TILEY_VAR;
1617 if (mask_mode == USE_MASKING)
1618 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1621 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1624 MarkTileDirty(x2, y2);
1628 static void DrawGraphicShifted(int x, int y, int dx, int dy,
1629 int graphic, int frame,
1630 int cut_mode, int mask_mode)
1634 DrawGraphic(x, y, graphic, frame);
1639 if (graphic_info[graphic].double_movement) /* EM style movement images */
1640 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1642 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1645 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1646 int frame, int cut_mode)
1648 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
1651 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1652 int cut_mode, int mask_mode)
1654 int lx = LEVELX(x), ly = LEVELY(y);
1658 if (IN_LEV_FIELD(lx, ly))
1660 SetRandomAnimationValue(lx, ly);
1662 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
1663 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1665 /* do not use double (EM style) movement graphic when not moving */
1666 if (graphic_info[graphic].double_movement && !dx && !dy)
1668 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
1669 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1672 else /* border element */
1674 graphic = el2img(element);
1675 frame = getGraphicAnimationFrame(graphic, -1);
1678 if (element == EL_EXPANDABLE_WALL)
1680 boolean left_stopped = FALSE, right_stopped = FALSE;
1682 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1683 left_stopped = TRUE;
1684 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1685 right_stopped = TRUE;
1687 if (left_stopped && right_stopped)
1689 else if (left_stopped)
1691 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1692 frame = graphic_info[graphic].anim_frames - 1;
1694 else if (right_stopped)
1696 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1697 frame = graphic_info[graphic].anim_frames - 1;
1702 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1703 else if (mask_mode == USE_MASKING)
1704 DrawGraphicThruMask(x, y, graphic, frame);
1706 DrawGraphic(x, y, graphic, frame);
1709 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1710 int cut_mode, int mask_mode)
1712 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1713 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1714 cut_mode, mask_mode);
1717 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1720 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1723 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1726 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1729 void DrawLevelElementThruMask(int x, int y, int element)
1731 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1734 void DrawLevelFieldThruMask(int x, int y)
1736 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1739 /* !!! implementation of quicksand is totally broken !!! */
1740 #define IS_CRUMBLED_TILE(x, y, e) \
1741 (GFX_CRUMBLED(e) && (!IN_LEV_FIELD(x, y) || \
1742 !IS_MOVING(x, y) || \
1743 (e) == EL_QUICKSAND_EMPTYING || \
1744 (e) == EL_QUICKSAND_FAST_EMPTYING))
1746 static void DrawLevelFieldCrumbledInnerCorners(int x, int y, int dx, int dy,
1751 int width, height, cx, cy;
1752 int sx = SCREENX(x), sy = SCREENY(y);
1753 int crumbled_border_size = graphic_info[graphic].border_size;
1756 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1758 for (i = 1; i < 4; i++)
1760 int dxx = (i & 1 ? dx : 0);
1761 int dyy = (i & 2 ? dy : 0);
1764 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1767 /* check if neighbour field is of same crumble type */
1768 boolean same = (IS_CRUMBLED_TILE(xx, yy, element) &&
1769 graphic_info[graphic].class ==
1770 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class);
1772 /* return if check prevents inner corner */
1773 if (same == (dxx == dx && dyy == dy))
1777 /* if we reach this point, we have an inner corner */
1779 getGraphicSource(graphic, 1, &src_bitmap, &src_x, &src_y);
1781 width = crumbled_border_size * TILESIZE_VAR / TILESIZE;
1782 height = crumbled_border_size * TILESIZE_VAR / TILESIZE;
1783 cx = (dx > 0 ? TILESIZE_VAR - width : 0);
1784 cy = (dy > 0 ? TILESIZE_VAR - height : 0);
1786 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1787 width, height, FX + sx * TILEX_VAR + cx, FY + sy * TILEY_VAR + cy);
1790 static void DrawLevelFieldCrumbledBorders(int x, int y, int graphic, int frame,
1795 int width, height, bx, by, cx, cy;
1796 int sx = SCREENX(x), sy = SCREENY(y);
1797 int crumbled_border_size = graphic_info[graphic].border_size;
1798 int crumbled_border_size_var = crumbled_border_size * TILESIZE_VAR / TILESIZE;
1799 int crumbled_border_pos_var = TILESIZE_VAR - crumbled_border_size_var;
1802 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1804 /* draw simple, sloppy, non-corner-accurate crumbled border */
1806 width = (dir == 1 || dir == 2 ? crumbled_border_size_var : TILESIZE_VAR);
1807 height = (dir == 0 || dir == 3 ? crumbled_border_size_var : TILESIZE_VAR);
1808 cx = (dir == 2 ? crumbled_border_pos_var : 0);
1809 cy = (dir == 3 ? crumbled_border_pos_var : 0);
1811 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy, width, height,
1812 FX + sx * TILEX_VAR + cx,
1813 FY + sy * TILEY_VAR + cy);
1815 /* (remaining middle border part must be at least as big as corner part) */
1816 if (!(graphic_info[graphic].style & STYLE_ACCURATE_BORDERS) ||
1817 crumbled_border_size >= TILESIZE / 3)
1820 /* correct corners of crumbled border, if needed */
1822 for (i = -1; i <= 1; i += 2)
1824 int xx = x + (dir == 0 || dir == 3 ? i : 0);
1825 int yy = y + (dir == 1 || dir == 2 ? i : 0);
1826 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1829 /* check if neighbour field is of same crumble type */
1830 if (IS_CRUMBLED_TILE(xx, yy, element) &&
1831 graphic_info[graphic].class ==
1832 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1834 /* no crumbled corner, but continued crumbled border */
1836 int c1 = (dir == 2 || dir == 3 ? crumbled_border_pos_var : 0);
1837 int c2 = (i == 1 ? crumbled_border_pos_var : 0);
1838 int b1 = (i == 1 ? crumbled_border_size_var :
1839 TILESIZE_VAR - 2 * crumbled_border_size_var);
1841 width = crumbled_border_size_var;
1842 height = crumbled_border_size_var;
1844 if (dir == 1 || dir == 2)
1859 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
1861 FX + sx * TILEX_VAR + cx,
1862 FY + sy * TILEY_VAR + cy);
1867 static void DrawLevelFieldCrumbledExt(int x, int y, int graphic, int frame)
1869 int sx = SCREENX(x), sy = SCREENY(y);
1872 static int xy[4][2] =
1880 if (!IN_LEV_FIELD(x, y))
1883 element = TILE_GFX_ELEMENT(x, y);
1885 /* crumble field itself */
1886 if (IS_CRUMBLED_TILE(x, y, element))
1888 if (!IN_SCR_FIELD(sx, sy))
1891 for (i = 0; i < 4; i++)
1893 int xx = x + xy[i][0];
1894 int yy = y + xy[i][1];
1896 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1899 /* check if neighbour field is of same crumble type */
1900 if (IS_CRUMBLED_TILE(xx, yy, element) &&
1901 graphic_info[graphic].class ==
1902 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1905 DrawLevelFieldCrumbledBorders(x, y, graphic, frame, i);
1908 if ((graphic_info[graphic].style & STYLE_INNER_CORNERS) &&
1909 graphic_info[graphic].anim_frames == 2)
1911 for (i = 0; i < 4; i++)
1913 int dx = (i & 1 ? +1 : -1);
1914 int dy = (i & 2 ? +1 : -1);
1916 DrawLevelFieldCrumbledInnerCorners(x, y, dx, dy, graphic);
1920 MarkTileDirty(sx, sy);
1922 else /* center field not crumbled -- crumble neighbour fields */
1924 for (i = 0; i < 4; i++)
1926 int xx = x + xy[i][0];
1927 int yy = y + xy[i][1];
1928 int sxx = sx + xy[i][0];
1929 int syy = sy + xy[i][1];
1931 if (!IN_LEV_FIELD(xx, yy) ||
1932 !IN_SCR_FIELD(sxx, syy))
1935 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
1938 element = TILE_GFX_ELEMENT(xx, yy);
1940 if (!IS_CRUMBLED_TILE(xx, yy, element))
1943 graphic = el_act2crm(element, ACTION_DEFAULT);
1945 DrawLevelFieldCrumbledBorders(xx, yy, graphic, 0, 3 - i);
1947 MarkTileDirty(sxx, syy);
1952 void DrawLevelFieldCrumbled(int x, int y)
1956 if (!IN_LEV_FIELD(x, y))
1959 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1960 GfxElement[x][y] != EL_UNDEFINED &&
1961 GFX_CRUMBLED(GfxElement[x][y]))
1963 DrawLevelFieldCrumbledDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
1968 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
1970 DrawLevelFieldCrumbledExt(x, y, graphic, 0);
1973 void DrawLevelFieldCrumbledDigging(int x, int y, int direction,
1976 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1977 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1978 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1979 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1980 int sx = SCREENX(x), sy = SCREENY(y);
1982 DrawGraphic(sx, sy, graphic1, frame1);
1983 DrawLevelFieldCrumbledExt(x, y, graphic2, frame2);
1986 void DrawLevelFieldCrumbledNeighbours(int x, int y)
1988 int sx = SCREENX(x), sy = SCREENY(y);
1989 static int xy[4][2] =
1998 for (i = 0; i < 4; i++)
2000 int xx = x + xy[i][0];
2001 int yy = y + xy[i][1];
2002 int sxx = sx + xy[i][0];
2003 int syy = sy + xy[i][1];
2005 if (!IN_LEV_FIELD(xx, yy) ||
2006 !IN_SCR_FIELD(sxx, syy) ||
2007 !GFX_CRUMBLED(Feld[xx][yy]) ||
2011 DrawLevelField(xx, yy);
2015 static int getBorderElement(int x, int y)
2019 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
2020 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
2021 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
2022 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
2023 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
2024 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
2025 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
2027 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
2028 int steel_position = (x == -1 && y == -1 ? 0 :
2029 x == lev_fieldx && y == -1 ? 1 :
2030 x == -1 && y == lev_fieldy ? 2 :
2031 x == lev_fieldx && y == lev_fieldy ? 3 :
2032 x == -1 || x == lev_fieldx ? 4 :
2033 y == -1 || y == lev_fieldy ? 5 : 6);
2035 return border[steel_position][steel_type];
2038 void DrawScreenElement(int x, int y, int element)
2040 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
2041 DrawLevelFieldCrumbled(LEVELX(x), LEVELY(y));
2044 void DrawLevelElement(int x, int y, int element)
2046 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2047 DrawScreenElement(SCREENX(x), SCREENY(y), element);
2050 void DrawScreenField(int x, int y)
2052 int lx = LEVELX(x), ly = LEVELY(y);
2053 int element, content;
2055 if (!IN_LEV_FIELD(lx, ly))
2057 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
2060 element = getBorderElement(lx, ly);
2062 DrawScreenElement(x, y, element);
2067 element = Feld[lx][ly];
2068 content = Store[lx][ly];
2070 if (IS_MOVING(lx, ly))
2072 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
2073 boolean cut_mode = NO_CUTTING;
2075 if (element == EL_QUICKSAND_EMPTYING ||
2076 element == EL_QUICKSAND_FAST_EMPTYING ||
2077 element == EL_MAGIC_WALL_EMPTYING ||
2078 element == EL_BD_MAGIC_WALL_EMPTYING ||
2079 element == EL_DC_MAGIC_WALL_EMPTYING ||
2080 element == EL_AMOEBA_DROPPING)
2081 cut_mode = CUT_ABOVE;
2082 else if (element == EL_QUICKSAND_FILLING ||
2083 element == EL_QUICKSAND_FAST_FILLING ||
2084 element == EL_MAGIC_WALL_FILLING ||
2085 element == EL_BD_MAGIC_WALL_FILLING ||
2086 element == EL_DC_MAGIC_WALL_FILLING)
2087 cut_mode = CUT_BELOW;
2089 if (cut_mode == CUT_ABOVE)
2090 DrawScreenElement(x, y, element);
2092 DrawScreenElement(x, y, EL_EMPTY);
2095 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
2096 else if (cut_mode == NO_CUTTING)
2097 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
2100 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
2102 if (cut_mode == CUT_BELOW &&
2103 IN_LEV_FIELD(lx, ly + 1) && IN_SCR_FIELD(x, y + 1))
2104 DrawLevelElement(lx, ly + 1, element);
2107 if (content == EL_ACID)
2109 int dir = MovDir[lx][ly];
2110 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
2111 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
2113 DrawLevelElementThruMask(newlx, newly, EL_ACID);
2116 else if (IS_BLOCKED(lx, ly))
2121 boolean cut_mode = NO_CUTTING;
2122 int element_old, content_old;
2124 Blocked2Moving(lx, ly, &oldx, &oldy);
2127 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
2128 MovDir[oldx][oldy] == MV_RIGHT);
2130 element_old = Feld[oldx][oldy];
2131 content_old = Store[oldx][oldy];
2133 if (element_old == EL_QUICKSAND_EMPTYING ||
2134 element_old == EL_QUICKSAND_FAST_EMPTYING ||
2135 element_old == EL_MAGIC_WALL_EMPTYING ||
2136 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
2137 element_old == EL_DC_MAGIC_WALL_EMPTYING ||
2138 element_old == EL_AMOEBA_DROPPING)
2139 cut_mode = CUT_ABOVE;
2141 DrawScreenElement(x, y, EL_EMPTY);
2144 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
2146 else if (cut_mode == NO_CUTTING)
2147 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
2150 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
2153 else if (IS_DRAWABLE(element))
2154 DrawScreenElement(x, y, element);
2156 DrawScreenElement(x, y, EL_EMPTY);
2159 void DrawLevelField(int x, int y)
2161 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2162 DrawScreenField(SCREENX(x), SCREENY(y));
2163 else if (IS_MOVING(x, y))
2167 Moving2Blocked(x, y, &newx, &newy);
2168 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
2169 DrawScreenField(SCREENX(newx), SCREENY(newy));
2171 else if (IS_BLOCKED(x, y))
2175 Blocked2Moving(x, y, &oldx, &oldy);
2176 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
2177 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
2181 void DrawSizedElement(int x, int y, int element, int tilesize)
2185 graphic = el2edimg(element);
2186 DrawSizedGraphic(x, y, graphic, 0, tilesize);
2189 void DrawMiniElement(int x, int y, int element)
2193 graphic = el2edimg(element);
2194 DrawMiniGraphic(x, y, graphic);
2197 void DrawSizedElementOrWall(int sx, int sy, int scroll_x, int scroll_y,
2200 int x = sx + scroll_x, y = sy + scroll_y;
2202 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
2203 DrawSizedElement(sx, sy, EL_EMPTY, tilesize);
2204 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
2205 DrawSizedElement(sx, sy, Feld[x][y], tilesize);
2207 DrawSizedGraphic(sx, sy, el2edimg(getBorderElement(x, y)), 0, tilesize);
2210 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
2212 int x = sx + scroll_x, y = sy + scroll_y;
2214 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
2215 DrawMiniElement(sx, sy, EL_EMPTY);
2216 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
2217 DrawMiniElement(sx, sy, Feld[x][y]);
2219 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
2222 void DrawEnvelopeBackgroundTiles(int graphic, int startx, int starty,
2223 int x, int y, int xsize, int ysize,
2224 int tile_width, int tile_height)
2228 int dst_x = startx + x * tile_width;
2229 int dst_y = starty + y * tile_height;
2230 int width = graphic_info[graphic].width;
2231 int height = graphic_info[graphic].height;
2232 int inner_width_raw = MAX(width - 2 * tile_width, tile_width);
2233 int inner_height_raw = MAX(height - 2 * tile_height, tile_height);
2234 int inner_width = inner_width_raw - (inner_width_raw % tile_width);
2235 int inner_height = inner_height_raw - (inner_height_raw % tile_height);
2236 int inner_sx = (width >= 3 * tile_width ? tile_width : 0);
2237 int inner_sy = (height >= 3 * tile_height ? tile_height : 0);
2238 boolean draw_masked = graphic_info[graphic].draw_masked;
2240 getFixedGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
2242 if (src_bitmap == NULL || width < tile_width || height < tile_height)
2244 ClearRectangle(drawto, dst_x, dst_y, tile_width, tile_height);
2248 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - tile_width :
2249 inner_sx + (x - 1) * tile_width % inner_width);
2250 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - tile_height :
2251 inner_sy + (y - 1) * tile_height % inner_height);
2254 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
2257 BlitBitmap(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
2261 void DrawEnvelopeBackground(int graphic, int startx, int starty,
2262 int x, int y, int xsize, int ysize, int font_nr)
2264 int font_width = getFontWidth(font_nr);
2265 int font_height = getFontHeight(font_nr);
2267 DrawEnvelopeBackgroundTiles(graphic, startx, starty, x, y, xsize, ysize,
2268 font_width, font_height);
2271 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
2273 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2274 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2275 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2276 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2277 boolean no_delay = (tape.warp_forward);
2278 unsigned int anim_delay = 0;
2279 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
2280 int anim_delay_value = (no_delay ? 0 : frame_delay_value) / 2;
2281 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
2282 int font_width = getFontWidth(font_nr);
2283 int font_height = getFontHeight(font_nr);
2284 int max_xsize = level.envelope[envelope_nr].xsize;
2285 int max_ysize = level.envelope[envelope_nr].ysize;
2286 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
2287 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
2288 int xend = max_xsize;
2289 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
2290 int xstep = (xstart < xend ? 1 : 0);
2291 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2293 int end = MAX(xend - xstart, yend - ystart);
2296 for (i = start; i <= end; i++)
2298 int last_frame = end; // last frame of this "for" loop
2299 int x = xstart + i * xstep;
2300 int y = ystart + i * ystep;
2301 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2302 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2303 int sx = SX + (SXSIZE - xsize * font_width) / 2;
2304 int sy = SY + (SYSIZE - ysize * font_height) / 2;
2307 SetDrawtoField(DRAW_TO_FIELDBUFFER);
2309 BlitScreenToBitmap(backbuffer);
2311 SetDrawtoField(DRAW_TO_BACKBUFFER);
2313 for (yy = 0; yy < ysize; yy++)
2314 for (xx = 0; xx < xsize; xx++)
2315 DrawEnvelopeBackground(graphic, sx, sy, xx, yy, xsize, ysize, font_nr);
2317 DrawTextBuffer(sx + font_width, sy + font_height,
2318 level.envelope[envelope_nr].text, font_nr, max_xsize,
2319 xsize - 2, ysize - 2, 0, mask_mode,
2320 level.envelope[envelope_nr].autowrap,
2321 level.envelope[envelope_nr].centered, FALSE);
2323 redraw_mask |= REDRAW_FIELD;
2326 SkipUntilDelayReached(&anim_delay, anim_delay_value, &i, last_frame);
2330 void ShowEnvelope(int envelope_nr)
2332 int element = EL_ENVELOPE_1 + envelope_nr;
2333 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2334 int sound_opening = element_info[element].sound[ACTION_OPENING];
2335 int sound_closing = element_info[element].sound[ACTION_CLOSING];
2336 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2337 boolean no_delay = (tape.warp_forward);
2338 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
2339 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
2340 int anim_mode = graphic_info[graphic].anim_mode;
2341 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2342 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2344 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
2346 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2348 if (anim_mode == ANIM_DEFAULT)
2349 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
2351 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
2354 Delay(wait_delay_value);
2356 WaitForEventToContinue();
2358 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2360 if (anim_mode != ANIM_NONE)
2361 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
2363 if (anim_mode == ANIM_DEFAULT)
2364 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
2366 game.envelope_active = FALSE;
2368 SetDrawtoField(DRAW_TO_FIELDBUFFER);
2370 redraw_mask |= REDRAW_FIELD;
2374 static void setRequestBasePosition(int *x, int *y)
2376 int sx_base, sy_base;
2378 if (request.x != -1)
2379 sx_base = request.x;
2380 else if (request.align == ALIGN_LEFT)
2382 else if (request.align == ALIGN_RIGHT)
2383 sx_base = SX + SXSIZE;
2385 sx_base = SX + SXSIZE / 2;
2387 if (request.y != -1)
2388 sy_base = request.y;
2389 else if (request.valign == VALIGN_TOP)
2391 else if (request.valign == VALIGN_BOTTOM)
2392 sy_base = SY + SYSIZE;
2394 sy_base = SY + SYSIZE / 2;
2400 static void setRequestPositionExt(int *x, int *y, int width, int height,
2401 boolean add_border_size)
2403 int border_size = request.border_size;
2404 int sx_base, sy_base;
2407 setRequestBasePosition(&sx_base, &sy_base);
2409 if (request.align == ALIGN_LEFT)
2411 else if (request.align == ALIGN_RIGHT)
2412 sx = sx_base - width;
2414 sx = sx_base - width / 2;
2416 if (request.valign == VALIGN_TOP)
2418 else if (request.valign == VALIGN_BOTTOM)
2419 sy = sy_base - height;
2421 sy = sy_base - height / 2;
2423 sx = MAX(0, MIN(sx, WIN_XSIZE - width));
2424 sy = MAX(0, MIN(sy, WIN_YSIZE - height));
2426 if (add_border_size)
2436 static void setRequestPosition(int *x, int *y, boolean add_border_size)
2438 setRequestPositionExt(x, y, request.width, request.height, add_border_size);
2441 void DrawEnvelopeRequest(char *text)
2443 char *text_final = text;
2444 char *text_door_style = NULL;
2445 int graphic = IMG_BACKGROUND_REQUEST;
2446 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2447 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2448 int font_nr = FONT_REQUEST;
2449 int font_width = getFontWidth(font_nr);
2450 int font_height = getFontHeight(font_nr);
2451 int border_size = request.border_size;
2452 int line_spacing = request.line_spacing;
2453 int line_height = font_height + line_spacing;
2454 int max_text_width = request.width - 2 * border_size;
2455 int max_text_height = request.height - 2 * border_size;
2456 int line_length = max_text_width / font_width;
2457 int max_lines = max_text_height / line_height;
2458 int text_width = line_length * font_width;
2459 int width = request.width;
2460 int height = request.height;
2461 int tile_size = MAX(request.step_offset, 1);
2462 int x_steps = width / tile_size;
2463 int y_steps = height / tile_size;
2464 int sx_offset = border_size;
2465 int sy_offset = border_size;
2469 if (request.centered)
2470 sx_offset = (request.width - text_width) / 2;
2472 if (request.wrap_single_words && !request.autowrap)
2474 char *src_text_ptr, *dst_text_ptr;
2476 text_door_style = checked_malloc(2 * strlen(text) + 1);
2478 src_text_ptr = text;
2479 dst_text_ptr = text_door_style;
2481 while (*src_text_ptr)
2483 if (*src_text_ptr == ' ' ||
2484 *src_text_ptr == '?' ||
2485 *src_text_ptr == '!')
2486 *dst_text_ptr++ = '\n';
2488 if (*src_text_ptr != ' ')
2489 *dst_text_ptr++ = *src_text_ptr;
2494 *dst_text_ptr = '\0';
2496 text_final = text_door_style;
2499 setRequestPosition(&sx, &sy, FALSE);
2501 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
2503 for (y = 0; y < y_steps; y++)
2504 for (x = 0; x < x_steps; x++)
2505 DrawEnvelopeBackgroundTiles(graphic, sx, sy,
2506 x, y, x_steps, y_steps,
2507 tile_size, tile_size);
2509 /* force DOOR font inside door area */
2510 SetFontStatus(GAME_MODE_PSEUDO_DOOR);
2512 DrawTextBuffer(sx + sx_offset, sy + sy_offset, text_final, font_nr,
2513 line_length, -1, max_lines, line_spacing, mask_mode,
2514 request.autowrap, request.centered, FALSE);
2518 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2519 RedrawGadget(tool_gadget[i]);
2521 // store readily prepared envelope request for later use when animating
2522 BlitBitmap(backbuffer, bitmap_db_store_2, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2524 if (text_door_style)
2525 free(text_door_style);
2528 void AnimateEnvelopeRequest(int anim_mode, int action)
2530 int graphic = IMG_BACKGROUND_REQUEST;
2531 boolean draw_masked = graphic_info[graphic].draw_masked;
2532 int delay_value_normal = request.step_delay;
2533 int delay_value_fast = delay_value_normal / 2;
2534 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2535 boolean no_delay = (tape.warp_forward);
2536 int delay_value = (ffwd_delay ? delay_value_fast : delay_value_normal);
2537 int anim_delay_value = (no_delay ? 0 : delay_value + 500 * 0) / 2;
2538 unsigned int anim_delay = 0;
2540 int tile_size = MAX(request.step_offset, 1);
2541 int max_xsize = request.width / tile_size;
2542 int max_ysize = request.height / tile_size;
2543 int max_xsize_inner = max_xsize - 2;
2544 int max_ysize_inner = max_ysize - 2;
2546 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize_inner : 0);
2547 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize_inner : 0);
2548 int xend = max_xsize_inner;
2549 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize_inner : 0);
2550 int xstep = (xstart < xend ? 1 : 0);
2551 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2553 int end = MAX(xend - xstart, yend - ystart);
2556 if (setup.quick_doors)
2563 for (i = start; i <= end; i++)
2565 int last_frame = end; // last frame of this "for" loop
2566 int x = xstart + i * xstep;
2567 int y = ystart + i * ystep;
2568 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2569 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2570 int xsize_size_left = (xsize - 1) * tile_size;
2571 int ysize_size_top = (ysize - 1) * tile_size;
2572 int max_xsize_pos = (max_xsize - 1) * tile_size;
2573 int max_ysize_pos = (max_ysize - 1) * tile_size;
2574 int width = xsize * tile_size;
2575 int height = ysize * tile_size;
2580 setRequestPosition(&src_x, &src_y, FALSE);
2581 setRequestPositionExt(&dst_x, &dst_y, width, height, FALSE);
2583 BlitBitmap(bitmap_db_store_1, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2585 for (yy = 0; yy < 2; yy++)
2587 for (xx = 0; xx < 2; xx++)
2589 int src_xx = src_x + xx * max_xsize_pos;
2590 int src_yy = src_y + yy * max_ysize_pos;
2591 int dst_xx = dst_x + xx * xsize_size_left;
2592 int dst_yy = dst_y + yy * ysize_size_top;
2593 int xx_size = (xx ? tile_size : xsize_size_left);
2594 int yy_size = (yy ? tile_size : ysize_size_top);
2597 BlitBitmapMasked(bitmap_db_store_2, backbuffer,
2598 src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
2600 BlitBitmap(bitmap_db_store_2, backbuffer,
2601 src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
2605 redraw_mask |= REDRAW_FIELD;
2609 SkipUntilDelayReached(&anim_delay, anim_delay_value, &i, last_frame);
2613 void ShowEnvelopeRequest(char *text, unsigned int req_state, int action)
2615 int graphic = IMG_BACKGROUND_REQUEST;
2616 int sound_opening = SND_REQUEST_OPENING;
2617 int sound_closing = SND_REQUEST_CLOSING;
2618 int anim_mode_1 = request.anim_mode; /* (higher priority) */
2619 int anim_mode_2 = graphic_info[graphic].anim_mode; /* (lower priority) */
2620 int anim_mode = (anim_mode_1 != ANIM_DEFAULT ? anim_mode_1 : anim_mode_2);
2621 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2622 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2624 if (game_status == GAME_MODE_PLAYING)
2625 BlitScreenToBitmap(backbuffer);
2627 SetDrawtoField(DRAW_TO_BACKBUFFER);
2629 // SetDrawBackgroundMask(REDRAW_NONE);
2631 if (action == ACTION_OPENING)
2633 BlitBitmap(backbuffer, bitmap_db_store_1, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2635 if (req_state & REQ_ASK)
2637 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2638 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2640 else if (req_state & REQ_CONFIRM)
2642 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2644 else if (req_state & REQ_PLAYER)
2646 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2647 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2648 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2649 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2652 DrawEnvelopeRequest(text);
2655 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
2657 if (action == ACTION_OPENING)
2659 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2661 if (anim_mode == ANIM_DEFAULT)
2662 AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_OPENING);
2664 AnimateEnvelopeRequest(main_anim_mode, ACTION_OPENING);
2668 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2670 if (anim_mode != ANIM_NONE)
2671 AnimateEnvelopeRequest(main_anim_mode, ACTION_CLOSING);
2673 if (anim_mode == ANIM_DEFAULT)
2674 AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_CLOSING);
2677 game.envelope_active = FALSE;
2679 if (action == ACTION_CLOSING)
2680 BlitBitmap(bitmap_db_store_1, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2682 // SetDrawBackgroundMask(last_draw_background_mask);
2684 redraw_mask |= REDRAW_FIELD;
2688 if (action == ACTION_CLOSING &&
2689 game_status == GAME_MODE_PLAYING &&
2690 level.game_engine_type == GAME_ENGINE_TYPE_RND)
2691 SetDrawtoField(DRAW_TO_FIELDBUFFER);
2694 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
2698 int graphic = el2preimg(element);
2700 getSizedGraphicSource(graphic, 0, tilesize, &src_bitmap, &src_x, &src_y);
2701 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
2704 void DrawLevel(int draw_background_mask)
2708 SetMainBackgroundImage(IMG_BACKGROUND_PLAYING);
2709 SetDrawBackgroundMask(draw_background_mask);
2713 for (x = BX1; x <= BX2; x++)
2714 for (y = BY1; y <= BY2; y++)
2715 DrawScreenField(x, y);
2717 redraw_mask |= REDRAW_FIELD;
2720 void DrawSizedLevel(int size_x, int size_y, int scroll_x, int scroll_y,
2725 for (x = 0; x < size_x; x++)
2726 for (y = 0; y < size_y; y++)
2727 DrawSizedElementOrWall(x, y, scroll_x, scroll_y, tilesize);
2729 redraw_mask |= REDRAW_FIELD;
2732 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
2736 for (x = 0; x < size_x; x++)
2737 for (y = 0; y < size_y; y++)
2738 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
2740 redraw_mask |= REDRAW_FIELD;
2743 static void DrawPreviewLevelPlayfieldExt(int from_x, int from_y)
2745 boolean show_level_border = (BorderElement != EL_EMPTY);
2746 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2747 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2748 int tile_size = preview.tile_size;
2749 int preview_width = preview.xsize * tile_size;
2750 int preview_height = preview.ysize * tile_size;
2751 int real_preview_xsize = MIN(level_xsize, preview.xsize);
2752 int real_preview_ysize = MIN(level_ysize, preview.ysize);
2753 int real_preview_width = real_preview_xsize * tile_size;
2754 int real_preview_height = real_preview_ysize * tile_size;
2755 int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
2756 int dst_y = SY + ALIGNED_YPOS(preview.y, preview_height, preview.valign);
2759 if (!IN_GFX_FIELD_FULL(dst_x, dst_y + preview_height - 1))
2762 DrawBackground(dst_x, dst_y, preview_width, preview_height);
2764 dst_x += (preview_width - real_preview_width) / 2;
2765 dst_y += (preview_height - real_preview_height) / 2;
2767 for (x = 0; x < real_preview_xsize; x++)
2769 for (y = 0; y < real_preview_ysize; y++)
2771 int lx = from_x + x + (show_level_border ? -1 : 0);
2772 int ly = from_y + y + (show_level_border ? -1 : 0);
2773 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
2774 getBorderElement(lx, ly));
2776 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
2777 element, tile_size);
2781 redraw_mask |= REDRAW_FIELD;
2784 #define MICROLABEL_EMPTY 0
2785 #define MICROLABEL_LEVEL_NAME 1
2786 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
2787 #define MICROLABEL_LEVEL_AUTHOR 3
2788 #define MICROLABEL_IMPORTED_FROM_HEAD 4
2789 #define MICROLABEL_IMPORTED_FROM 5
2790 #define MICROLABEL_IMPORTED_BY_HEAD 6
2791 #define MICROLABEL_IMPORTED_BY 7
2793 static int getMaxTextLength(struct TextPosInfo *pos, int font_nr)
2795 int max_text_width = SXSIZE;
2796 int font_width = getFontWidth(font_nr);
2798 if (pos->align == ALIGN_CENTER)
2799 max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
2800 else if (pos->align == ALIGN_RIGHT)
2801 max_text_width = pos->x;
2803 max_text_width = SXSIZE - pos->x;
2805 return max_text_width / font_width;
2808 static void DrawPreviewLevelLabelExt(int mode)
2810 struct TextPosInfo *pos = &menu.main.text.level_info_2;
2811 char label_text[MAX_OUTPUT_LINESIZE + 1];
2812 int max_len_label_text;
2813 int font_nr = pos->font;
2816 if (!IN_GFX_FIELD_FULL(pos->x, pos->y + getFontHeight(pos->font)))
2819 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
2820 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
2821 mode == MICROLABEL_IMPORTED_BY_HEAD)
2822 font_nr = pos->font_alt;
2824 max_len_label_text = getMaxTextLength(pos, font_nr);
2826 if (pos->size != -1)
2827 max_len_label_text = pos->size;
2829 for (i = 0; i < max_len_label_text; i++)
2830 label_text[i] = ' ';
2831 label_text[max_len_label_text] = '\0';
2833 if (strlen(label_text) > 0)
2834 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2837 (mode == MICROLABEL_LEVEL_NAME ? level.name :
2838 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
2839 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
2840 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
2841 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
2842 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
2843 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
2844 max_len_label_text);
2845 label_text[max_len_label_text] = '\0';
2847 if (strlen(label_text) > 0)
2848 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2850 redraw_mask |= REDRAW_FIELD;
2853 static void DrawPreviewLevelExt(boolean restart)
2855 static unsigned int scroll_delay = 0;
2856 static unsigned int label_delay = 0;
2857 static int from_x, from_y, scroll_direction;
2858 static int label_state, label_counter;
2859 unsigned int scroll_delay_value = preview.step_delay;
2860 boolean show_level_border = (BorderElement != EL_EMPTY);
2861 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2862 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2869 if (preview.anim_mode == ANIM_CENTERED)
2871 if (level_xsize > preview.xsize)
2872 from_x = (level_xsize - preview.xsize) / 2;
2873 if (level_ysize > preview.ysize)
2874 from_y = (level_ysize - preview.ysize) / 2;
2877 from_x += preview.xoffset;
2878 from_y += preview.yoffset;
2880 scroll_direction = MV_RIGHT;
2884 DrawPreviewLevelPlayfieldExt(from_x, from_y);
2885 DrawPreviewLevelLabelExt(label_state);
2887 /* initialize delay counters */
2888 DelayReached(&scroll_delay, 0);
2889 DelayReached(&label_delay, 0);
2891 if (leveldir_current->name)
2893 struct TextPosInfo *pos = &menu.main.text.level_info_1;
2894 char label_text[MAX_OUTPUT_LINESIZE + 1];
2895 int font_nr = pos->font;
2896 int max_len_label_text = getMaxTextLength(pos, font_nr);
2898 if (pos->size != -1)
2899 max_len_label_text = pos->size;
2901 strncpy(label_text, leveldir_current->name, max_len_label_text);
2902 label_text[max_len_label_text] = '\0';
2904 if (IN_GFX_FIELD_FULL(pos->x, pos->y + getFontHeight(pos->font)))
2905 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2911 /* scroll preview level, if needed */
2912 if (preview.anim_mode != ANIM_NONE &&
2913 (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
2914 DelayReached(&scroll_delay, scroll_delay_value))
2916 switch (scroll_direction)
2921 from_x -= preview.step_offset;
2922 from_x = (from_x < 0 ? 0 : from_x);
2925 scroll_direction = MV_UP;
2929 if (from_x < level_xsize - preview.xsize)
2931 from_x += preview.step_offset;
2932 from_x = (from_x > level_xsize - preview.xsize ?
2933 level_xsize - preview.xsize : from_x);
2936 scroll_direction = MV_DOWN;
2942 from_y -= preview.step_offset;
2943 from_y = (from_y < 0 ? 0 : from_y);
2946 scroll_direction = MV_RIGHT;
2950 if (from_y < level_ysize - preview.ysize)
2952 from_y += preview.step_offset;
2953 from_y = (from_y > level_ysize - preview.ysize ?
2954 level_ysize - preview.ysize : from_y);
2957 scroll_direction = MV_LEFT;
2964 DrawPreviewLevelPlayfieldExt(from_x, from_y);
2967 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
2968 /* redraw micro level label, if needed */
2969 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
2970 !strEqual(level.author, ANONYMOUS_NAME) &&
2971 !strEqual(level.author, leveldir_current->name) &&
2972 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
2974 int max_label_counter = 23;
2976 if (leveldir_current->imported_from != NULL &&
2977 strlen(leveldir_current->imported_from) > 0)
2978 max_label_counter += 14;
2979 if (leveldir_current->imported_by != NULL &&
2980 strlen(leveldir_current->imported_by) > 0)
2981 max_label_counter += 14;
2983 label_counter = (label_counter + 1) % max_label_counter;
2984 label_state = (label_counter >= 0 && label_counter <= 7 ?
2985 MICROLABEL_LEVEL_NAME :
2986 label_counter >= 9 && label_counter <= 12 ?
2987 MICROLABEL_LEVEL_AUTHOR_HEAD :
2988 label_counter >= 14 && label_counter <= 21 ?
2989 MICROLABEL_LEVEL_AUTHOR :
2990 label_counter >= 23 && label_counter <= 26 ?
2991 MICROLABEL_IMPORTED_FROM_HEAD :
2992 label_counter >= 28 && label_counter <= 35 ?
2993 MICROLABEL_IMPORTED_FROM :
2994 label_counter >= 37 && label_counter <= 40 ?
2995 MICROLABEL_IMPORTED_BY_HEAD :
2996 label_counter >= 42 && label_counter <= 49 ?
2997 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
2999 if (leveldir_current->imported_from == NULL &&
3000 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
3001 label_state == MICROLABEL_IMPORTED_FROM))
3002 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
3003 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
3005 DrawPreviewLevelLabelExt(label_state);
3009 void DrawPreviewLevelInitial()
3011 DrawPreviewLevelExt(TRUE);
3014 void DrawPreviewLevelAnimation()
3016 DrawPreviewLevelExt(FALSE);
3019 inline static void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
3020 int graphic, int sync_frame,
3023 int frame = getGraphicAnimationFrame(graphic, sync_frame);
3025 if (mask_mode == USE_MASKING)
3026 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
3028 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
3031 void DrawFixedGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
3032 int graphic, int sync_frame, int mask_mode)
3034 int frame = getGraphicAnimationFrame(graphic, sync_frame);
3036 if (mask_mode == USE_MASKING)
3037 DrawFixedGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
3039 DrawFixedGraphicExt(dst_bitmap, x, y, graphic, frame);
3042 inline static void DrawGraphicAnimation(int x, int y, int graphic)
3044 int lx = LEVELX(x), ly = LEVELY(y);
3046 if (!IN_SCR_FIELD(x, y))
3049 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
3050 graphic, GfxFrame[lx][ly], NO_MASKING);
3052 MarkTileDirty(x, y);
3055 void DrawFixedGraphicAnimation(int x, int y, int graphic)
3057 int lx = LEVELX(x), ly = LEVELY(y);
3059 if (!IN_SCR_FIELD(x, y))
3062 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
3063 graphic, GfxFrame[lx][ly], NO_MASKING);
3064 MarkTileDirty(x, y);
3067 void DrawLevelGraphicAnimation(int x, int y, int graphic)
3069 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
3072 void DrawLevelElementAnimation(int x, int y, int element)
3074 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
3076 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
3079 void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
3081 int sx = SCREENX(x), sy = SCREENY(y);
3083 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
3086 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
3089 DrawGraphicAnimation(sx, sy, graphic);
3092 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
3093 DrawLevelFieldCrumbled(x, y);
3095 if (GFX_CRUMBLED(Feld[x][y]))
3096 DrawLevelFieldCrumbled(x, y);
3100 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
3102 int sx = SCREENX(x), sy = SCREENY(y);
3105 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
3108 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
3110 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
3113 DrawGraphicAnimation(sx, sy, graphic);
3115 if (GFX_CRUMBLED(element))
3116 DrawLevelFieldCrumbled(x, y);
3119 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
3121 if (player->use_murphy)
3123 /* this works only because currently only one player can be "murphy" ... */
3124 static int last_horizontal_dir = MV_LEFT;
3125 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
3127 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3128 last_horizontal_dir = move_dir;
3130 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
3132 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
3134 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
3140 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
3143 static boolean equalGraphics(int graphic1, int graphic2)
3145 struct GraphicInfo *g1 = &graphic_info[graphic1];
3146 struct GraphicInfo *g2 = &graphic_info[graphic2];
3148 return (g1->bitmap == g2->bitmap &&
3149 g1->src_x == g2->src_x &&
3150 g1->src_y == g2->src_y &&
3151 g1->anim_frames == g2->anim_frames &&
3152 g1->anim_delay == g2->anim_delay &&
3153 g1->anim_mode == g2->anim_mode);
3156 void DrawAllPlayers()
3160 for (i = 0; i < MAX_PLAYERS; i++)
3161 if (stored_player[i].active)
3162 DrawPlayer(&stored_player[i]);
3165 void DrawPlayerField(int x, int y)
3167 if (!IS_PLAYER(x, y))
3170 DrawPlayer(PLAYERINFO(x, y));
3173 #define DRAW_PLAYER_OVER_PUSHED_ELEMENT 1
3175 void DrawPlayer(struct PlayerInfo *player)
3177 int jx = player->jx;
3178 int jy = player->jy;
3179 int move_dir = player->MovDir;
3180 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
3181 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
3182 int last_jx = (player->is_moving ? jx - dx : jx);
3183 int last_jy = (player->is_moving ? jy - dy : jy);
3184 int next_jx = jx + dx;
3185 int next_jy = jy + dy;
3186 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
3187 boolean player_is_opaque = FALSE;
3188 int sx = SCREENX(jx), sy = SCREENY(jy);
3189 int sxx = 0, syy = 0;
3190 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
3192 int action = ACTION_DEFAULT;
3193 int last_player_graphic = getPlayerGraphic(player, move_dir);
3194 int last_player_frame = player->Frame;
3197 /* GfxElement[][] is set to the element the player is digging or collecting;
3198 remove also for off-screen player if the player is not moving anymore */
3199 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
3200 GfxElement[jx][jy] = EL_UNDEFINED;
3202 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
3206 if (!IN_LEV_FIELD(jx, jy))
3208 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
3209 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
3210 printf("DrawPlayerField(): This should never happen!\n");
3215 if (element == EL_EXPLOSION)
3218 action = (player->is_pushing ? ACTION_PUSHING :
3219 player->is_digging ? ACTION_DIGGING :
3220 player->is_collecting ? ACTION_COLLECTING :
3221 player->is_moving ? ACTION_MOVING :
3222 player->is_snapping ? ACTION_SNAPPING :
3223 player->is_dropping ? ACTION_DROPPING :
3224 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
3226 if (player->is_waiting)
3227 move_dir = player->dir_waiting;
3229 InitPlayerGfxAnimation(player, action, move_dir);
3231 /* ----------------------------------------------------------------------- */
3232 /* draw things in the field the player is leaving, if needed */
3233 /* ----------------------------------------------------------------------- */
3235 if (player->is_moving)
3237 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
3239 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
3241 if (last_element == EL_DYNAMITE_ACTIVE ||
3242 last_element == EL_EM_DYNAMITE_ACTIVE ||
3243 last_element == EL_SP_DISK_RED_ACTIVE)
3244 DrawDynamite(last_jx, last_jy);
3246 DrawLevelFieldThruMask(last_jx, last_jy);
3248 else if (last_element == EL_DYNAMITE_ACTIVE ||
3249 last_element == EL_EM_DYNAMITE_ACTIVE ||
3250 last_element == EL_SP_DISK_RED_ACTIVE)
3251 DrawDynamite(last_jx, last_jy);
3253 /* !!! this is not enough to prevent flickering of players which are
3254 moving next to each others without a free tile between them -- this
3255 can only be solved by drawing all players layer by layer (first the
3256 background, then the foreground etc.) !!! => TODO */
3257 else if (!IS_PLAYER(last_jx, last_jy))
3258 DrawLevelField(last_jx, last_jy);
3261 DrawLevelField(last_jx, last_jy);
3264 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
3265 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
3268 if (!IN_SCR_FIELD(sx, sy))
3271 /* ----------------------------------------------------------------------- */
3272 /* draw things behind the player, if needed */
3273 /* ----------------------------------------------------------------------- */
3276 DrawLevelElement(jx, jy, Back[jx][jy]);
3277 else if (IS_ACTIVE_BOMB(element))
3278 DrawLevelElement(jx, jy, EL_EMPTY);
3281 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
3283 int old_element = GfxElement[jx][jy];
3284 int old_graphic = el_act_dir2img(old_element, action, move_dir);
3285 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
3287 if (GFX_CRUMBLED(old_element))
3288 DrawLevelFieldCrumbledDigging(jx, jy, move_dir, player->StepFrame);
3290 DrawGraphic(sx, sy, old_graphic, frame);
3292 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
3293 player_is_opaque = TRUE;
3297 GfxElement[jx][jy] = EL_UNDEFINED;
3299 /* make sure that pushed elements are drawn with correct frame rate */
3300 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
3302 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
3303 GfxFrame[jx][jy] = player->StepFrame;
3305 DrawLevelField(jx, jy);
3309 #if !DRAW_PLAYER_OVER_PUSHED_ELEMENT
3310 /* ----------------------------------------------------------------------- */
3311 /* draw player himself */
3312 /* ----------------------------------------------------------------------- */
3314 graphic = getPlayerGraphic(player, move_dir);
3316 /* in the case of changed player action or direction, prevent the current
3317 animation frame from being restarted for identical animations */
3318 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
3319 player->Frame = last_player_frame;
3321 frame = getGraphicAnimationFrame(graphic, player->Frame);
3325 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3326 sxx = player->GfxPos;
3328 syy = player->GfxPos;
3331 if (player_is_opaque)
3332 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
3334 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3336 if (SHIELD_ON(player))
3338 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
3339 IMG_SHIELD_NORMAL_ACTIVE);
3340 int frame = getGraphicAnimationFrame(graphic, -1);
3342 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3346 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
3349 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3350 sxx = player->GfxPos;
3352 syy = player->GfxPos;
3356 /* ----------------------------------------------------------------------- */
3357 /* draw things the player is pushing, if needed */
3358 /* ----------------------------------------------------------------------- */
3360 if (player->is_pushing && player->is_moving)
3362 int px = SCREENX(jx), py = SCREENY(jy);
3363 int pxx = (TILEX - ABS(sxx)) * dx;
3364 int pyy = (TILEY - ABS(syy)) * dy;
3365 int gfx_frame = GfxFrame[jx][jy];
3371 if (!IS_MOVING(jx, jy)) /* push movement already finished */
3373 element = Feld[next_jx][next_jy];
3374 gfx_frame = GfxFrame[next_jx][next_jy];
3377 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
3379 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
3380 frame = getGraphicAnimationFrame(graphic, sync_frame);
3382 /* draw background element under pushed element (like the Sokoban field) */
3383 if (game.use_masked_pushing && IS_MOVING(jx, jy))
3385 /* this allows transparent pushing animation over non-black background */
3388 DrawLevelElement(jx, jy, Back[jx][jy]);
3390 DrawLevelElement(jx, jy, EL_EMPTY);
3392 if (Back[next_jx][next_jy])
3393 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3395 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
3397 else if (Back[next_jx][next_jy])
3398 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3401 /* do not draw (EM style) pushing animation when pushing is finished */
3402 /* (two-tile animations usually do not contain start and end frame) */
3403 if (graphic_info[graphic].double_movement && !IS_MOVING(jx, jy))
3404 DrawLevelElement(next_jx, next_jy, Feld[next_jx][next_jy]);
3406 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3408 /* masked drawing is needed for EMC style (double) movement graphics */
3409 /* !!! (ONLY WHEN DRAWING PUSHED ELEMENT OVER THE PLAYER) !!! */
3410 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3414 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
3415 /* ----------------------------------------------------------------------- */
3416 /* draw player himself */
3417 /* ----------------------------------------------------------------------- */
3419 graphic = getPlayerGraphic(player, move_dir);
3421 /* in the case of changed player action or direction, prevent the current
3422 animation frame from being restarted for identical animations */
3423 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
3424 player->Frame = last_player_frame;
3426 frame = getGraphicAnimationFrame(graphic, player->Frame);
3430 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3431 sxx = player->GfxPos;
3433 syy = player->GfxPos;
3436 if (player_is_opaque)
3437 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
3439 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3441 if (SHIELD_ON(player))
3443 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
3444 IMG_SHIELD_NORMAL_ACTIVE);
3445 int frame = getGraphicAnimationFrame(graphic, -1);
3447 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3451 /* ----------------------------------------------------------------------- */
3452 /* draw things in front of player (active dynamite or dynabombs) */
3453 /* ----------------------------------------------------------------------- */
3455 if (IS_ACTIVE_BOMB(element))
3457 graphic = el2img(element);
3458 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
3460 if (game.emulation == EMU_SUPAPLEX)
3461 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
3463 DrawGraphicThruMask(sx, sy, graphic, frame);
3466 if (player_is_moving && last_element == EL_EXPLOSION)
3468 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
3469 GfxElement[last_jx][last_jy] : EL_EMPTY);
3470 int graphic = el_act2img(element, ACTION_EXPLODING);
3471 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
3472 int phase = ExplodePhase[last_jx][last_jy] - 1;
3473 int frame = getGraphicAnimationFrame(graphic, phase - delay);
3476 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
3479 /* ----------------------------------------------------------------------- */
3480 /* draw elements the player is just walking/passing through/under */
3481 /* ----------------------------------------------------------------------- */
3483 if (player_is_moving)
3485 /* handle the field the player is leaving ... */
3486 if (IS_ACCESSIBLE_INSIDE(last_element))
3487 DrawLevelField(last_jx, last_jy);
3488 else if (IS_ACCESSIBLE_UNDER(last_element))
3489 DrawLevelFieldThruMask(last_jx, last_jy);
3492 /* do not redraw accessible elements if the player is just pushing them */
3493 if (!player_is_moving || !player->is_pushing)
3495 /* ... and the field the player is entering */
3496 if (IS_ACCESSIBLE_INSIDE(element))
3497 DrawLevelField(jx, jy);
3498 else if (IS_ACCESSIBLE_UNDER(element))
3499 DrawLevelFieldThruMask(jx, jy);
3502 MarkTileDirty(sx, sy);
3505 /* ------------------------------------------------------------------------- */
3507 void WaitForEventToContinue()
3509 boolean still_wait = TRUE;
3511 /* simulate releasing mouse button over last gadget, if still pressed */
3513 HandleGadgets(-1, -1, 0);
3515 button_status = MB_RELEASED;
3529 case EVENT_BUTTONPRESS:
3530 case EVENT_KEYPRESS:
3534 case EVENT_KEYRELEASE:
3535 ClearPlayerAction();
3539 HandleOtherEvents(&event);
3543 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3552 #define MAX_REQUEST_LINES 13
3553 #define MAX_REQUEST_LINE_FONT1_LEN 7
3554 #define MAX_REQUEST_LINE_FONT2_LEN 10
3556 static int RequestHandleEvents(unsigned int req_state)
3558 boolean level_solved = (game_status == GAME_MODE_PLAYING &&
3559 local_player->LevelSolved_GameEnd);
3560 int width = request.width;
3561 int height = request.height;
3565 setRequestPosition(&sx, &sy, FALSE);
3567 button_status = MB_RELEASED;
3569 request_gadget_id = -1;
3576 SetDrawtoField(DRAW_TO_FIELDBUFFER);
3578 HandleGameActions();
3580 SetDrawtoField(DRAW_TO_BACKBUFFER);
3582 if (global.use_envelope_request)
3584 /* copy current state of request area to middle of playfield area */
3585 BlitBitmap(bitmap_db_store_2, drawto, sx, sy, width, height, sx, sy);
3593 while (NextValidEvent(&event))
3597 case EVENT_BUTTONPRESS:
3598 case EVENT_BUTTONRELEASE:
3599 case EVENT_MOTIONNOTIFY:
3603 if (event.type == EVENT_MOTIONNOTIFY)
3608 motion_status = TRUE;
3609 mx = ((MotionEvent *) &event)->x;
3610 my = ((MotionEvent *) &event)->y;
3614 motion_status = FALSE;
3615 mx = ((ButtonEvent *) &event)->x;
3616 my = ((ButtonEvent *) &event)->y;
3617 if (event.type == EVENT_BUTTONPRESS)
3618 button_status = ((ButtonEvent *) &event)->button;
3620 button_status = MB_RELEASED;
3623 /* this sets 'request_gadget_id' */
3624 HandleGadgets(mx, my, button_status);
3626 switch (request_gadget_id)
3628 case TOOL_CTRL_ID_YES:
3631 case TOOL_CTRL_ID_NO:
3634 case TOOL_CTRL_ID_CONFIRM:
3635 result = TRUE | FALSE;
3638 case TOOL_CTRL_ID_PLAYER_1:
3641 case TOOL_CTRL_ID_PLAYER_2:
3644 case TOOL_CTRL_ID_PLAYER_3:
3647 case TOOL_CTRL_ID_PLAYER_4:
3658 case EVENT_KEYPRESS:
3659 switch (GetEventKey((KeyEvent *)&event, TRUE))
3662 if (req_state & REQ_CONFIRM)
3667 #if defined(TARGET_SDL2)
3674 #if defined(TARGET_SDL2)
3684 if (req_state & REQ_PLAYER)
3688 case EVENT_KEYRELEASE:
3689 ClearPlayerAction();
3693 HandleOtherEvents(&event);
3698 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3700 int joy = AnyJoystick();
3702 if (joy & JOY_BUTTON_1)
3704 else if (joy & JOY_BUTTON_2)
3710 if (global.use_envelope_request)
3712 /* copy back current state of pressed buttons inside request area */
3713 BlitBitmap(drawto, bitmap_db_store_2, sx, sy, width, height, sx, sy);
3723 static boolean RequestDoor(char *text, unsigned int req_state)
3725 unsigned int old_door_state;
3726 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
3727 int font_nr = FONT_TEXT_2;
3732 if (maxWordLengthInString(text) > MAX_REQUEST_LINE_FONT1_LEN)
3734 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
3735 font_nr = FONT_TEXT_1;
3738 if (game_status == GAME_MODE_PLAYING)
3739 BlitScreenToBitmap(backbuffer);
3741 /* disable deactivated drawing when quick-loading level tape recording */
3742 if (tape.playing && tape.deactivate_display)
3743 TapeDeactivateDisplayOff(TRUE);
3745 SetMouseCursor(CURSOR_DEFAULT);
3747 #if defined(NETWORK_AVALIABLE)
3748 /* pause network game while waiting for request to answer */
3749 if (options.network &&
3750 game_status == GAME_MODE_PLAYING &&
3751 req_state & REQUEST_WAIT_FOR_INPUT)
3752 SendToServer_PausePlaying();
3755 old_door_state = GetDoorState();
3757 /* simulate releasing mouse button over last gadget, if still pressed */
3759 HandleGadgets(-1, -1, 0);
3763 /* draw released gadget before proceeding */
3766 if (old_door_state & DOOR_OPEN_1)
3768 CloseDoor(DOOR_CLOSE_1);
3770 /* save old door content */
3771 BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
3772 0 * DXSIZE, 0, DXSIZE, DYSIZE, 1 * DXSIZE, 0);
3775 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
3776 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3778 /* clear door drawing field */
3779 DrawBackground(DX, DY, DXSIZE, DYSIZE);
3781 /* force DOOR font inside door area */
3782 SetFontStatus(GAME_MODE_PSEUDO_DOOR);
3784 /* write text for request */
3785 for (text_ptr = text, ty = 0; ty < MAX_REQUEST_LINES; ty++)
3787 char text_line[max_request_line_len + 1];
3793 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
3795 tc = *(text_ptr + tx);
3796 // if (!tc || tc == ' ')
3797 if (!tc || tc == ' ' || tc == '?' || tc == '!')
3801 if ((tc == '?' || tc == '!') && tl == 0)
3811 strncpy(text_line, text_ptr, tl);
3814 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
3815 DY + 8 + ty * (getFontHeight(font_nr) + 2),
3816 text_line, font_nr);
3818 text_ptr += tl + (tc == ' ' ? 1 : 0);
3819 // text_ptr += tl + (tc == ' ' || tc == '?' || tc == '!' ? 1 : 0);
3824 if (req_state & REQ_ASK)
3826 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
3827 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
3829 else if (req_state & REQ_CONFIRM)
3831 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
3833 else if (req_state & REQ_PLAYER)
3835 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
3836 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
3837 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
3838 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
3841 /* copy request gadgets to door backbuffer */
3842 BlitBitmap(drawto, bitmap_db_door_1, DX, DY, DXSIZE, DYSIZE, 0, 0);
3844 OpenDoor(DOOR_OPEN_1);
3846 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
3848 if (game_status == GAME_MODE_PLAYING)
3850 SetPanelBackground();
3851 SetDrawBackgroundMask(REDRAW_DOOR_1);
3855 SetDrawBackgroundMask(REDRAW_FIELD);
3861 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3863 // ---------- handle request buttons ----------
3864 result = RequestHandleEvents(req_state);
3868 if (!(req_state & REQ_STAY_OPEN))
3870 CloseDoor(DOOR_CLOSE_1);
3872 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
3873 (req_state & REQ_REOPEN))
3874 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
3879 if (game_status == GAME_MODE_PLAYING)
3881 SetPanelBackground();
3882 SetDrawBackgroundMask(REDRAW_DOOR_1);
3886 SetDrawBackgroundMask(REDRAW_FIELD);
3889 #if defined(NETWORK_AVALIABLE)
3890 /* continue network game after request */
3891 if (options.network &&
3892 game_status == GAME_MODE_PLAYING &&
3893 req_state & REQUEST_WAIT_FOR_INPUT)
3894 SendToServer_ContinuePlaying();
3897 /* restore deactivated drawing when quick-loading level tape recording */
3898 if (tape.playing && tape.deactivate_display)
3899 TapeDeactivateDisplayOn();
3904 static boolean RequestEnvelope(char *text, unsigned int req_state)
3908 if (game_status == GAME_MODE_PLAYING)
3909 BlitScreenToBitmap(backbuffer);
3911 /* disable deactivated drawing when quick-loading level tape recording */
3912 if (tape.playing && tape.deactivate_display)
3913 TapeDeactivateDisplayOff(TRUE);
3915 SetMouseCursor(CURSOR_DEFAULT);
3917 #if defined(NETWORK_AVALIABLE)
3918 /* pause network game while waiting for request to answer */
3919 if (options.network &&
3920 game_status == GAME_MODE_PLAYING &&
3921 req_state & REQUEST_WAIT_FOR_INPUT)
3922 SendToServer_PausePlaying();
3925 /* simulate releasing mouse button over last gadget, if still pressed */
3927 HandleGadgets(-1, -1, 0);
3931 // (replace with setting corresponding request background)
3932 // SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
3933 // SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3935 /* clear door drawing field */
3936 // DrawBackground(DX, DY, DXSIZE, DYSIZE);
3938 ShowEnvelopeRequest(text, req_state, ACTION_OPENING);
3940 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
3942 if (game_status == GAME_MODE_PLAYING)
3944 SetPanelBackground();
3945 SetDrawBackgroundMask(REDRAW_DOOR_1);
3949 SetDrawBackgroundMask(REDRAW_FIELD);
3955 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3957 // ---------- handle request buttons ----------
3958 result = RequestHandleEvents(req_state);
3962 ShowEnvelopeRequest(text, req_state, ACTION_CLOSING);
3966 if (game_status == GAME_MODE_PLAYING)
3968 SetPanelBackground();
3969 SetDrawBackgroundMask(REDRAW_DOOR_1);
3973 SetDrawBackgroundMask(REDRAW_FIELD);
3976 #if defined(NETWORK_AVALIABLE)
3977 /* continue network game after request */
3978 if (options.network &&
3979 game_status == GAME_MODE_PLAYING &&
3980 req_state & REQUEST_WAIT_FOR_INPUT)
3981 SendToServer_ContinuePlaying();
3984 /* restore deactivated drawing when quick-loading level tape recording */
3985 if (tape.playing && tape.deactivate_display)
3986 TapeDeactivateDisplayOn();
3991 boolean Request(char *text, unsigned int req_state)
3993 if (global.use_envelope_request)
3994 return RequestEnvelope(text, req_state);
3996 return RequestDoor(text, req_state);
3999 static int compareDoorPartOrderInfo(const void *object1, const void *object2)
4001 const struct DoorPartOrderInfo *dpo1 = (struct DoorPartOrderInfo *)object1;
4002 const struct DoorPartOrderInfo *dpo2 = (struct DoorPartOrderInfo *)object2;
4005 if (dpo1->sort_priority != dpo2->sort_priority)
4006 compare_result = dpo1->sort_priority - dpo2->sort_priority;
4008 compare_result = dpo1->nr - dpo2->nr;
4010 return compare_result;
4013 void InitGraphicCompatibilityInfo_Doors()
4019 struct DoorInfo *door;
4023 { DOOR_1, IMG_GFX_DOOR_1_PART_1, IMG_GFX_DOOR_1_PART_8, &door_1 },
4024 { DOOR_2, IMG_GFX_DOOR_2_PART_1, IMG_GFX_DOOR_2_PART_8, &door_2 },
4026 { -1, -1, -1, NULL }
4028 struct Rect door_rect_list[] =
4030 { DX, DY, DXSIZE, DYSIZE },
4031 { VX, VY, VXSIZE, VYSIZE }
4035 for (i = 0; doors[i].door_token != -1; i++)
4037 int door_token = doors[i].door_token;
4038 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
4039 int part_1 = doors[i].part_1;
4040 int part_8 = doors[i].part_8;
4041 int part_2 = part_1 + 1;
4042 int part_3 = part_1 + 2;
4043 struct DoorInfo *door = doors[i].door;
4044 struct Rect *door_rect = &door_rect_list[door_index];
4045 boolean door_gfx_redefined = FALSE;
4047 /* check if any door part graphic definitions have been redefined */
4049 for (j = 0; door_part_controls[j].door_token != -1; j++)
4051 struct DoorPartControlInfo *dpc = &door_part_controls[j];
4052 struct FileInfo *fi = getImageListEntryFromImageID(dpc->graphic);
4054 if (dpc->door_token == door_token && fi->redefined)
4055 door_gfx_redefined = TRUE;
4058 /* check for old-style door graphic/animation modifications */
4060 if (!door_gfx_redefined)
4062 if (door->anim_mode & ANIM_STATIC_PANEL)
4064 door->panel.step_xoffset = 0;
4065 door->panel.step_yoffset = 0;
4068 if (door->anim_mode & (ANIM_HORIZONTAL | ANIM_VERTICAL))
4070 struct GraphicInfo *g_part_1 = &graphic_info[part_1];
4071 struct GraphicInfo *g_part_2 = &graphic_info[part_2];
4072 int num_door_steps, num_panel_steps;
4074 /* remove door part graphics other than the two default wings */
4076 for (j = 0; door_part_controls[j].door_token != -1; j++)
4078 struct DoorPartControlInfo *dpc = &door_part_controls[j];
4079 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4081 if (dpc->graphic >= part_3 &&
4082 dpc->graphic <= part_8)
4086 /* set graphics and screen positions of the default wings */
4088 g_part_1->width = door_rect->width;
4089 g_part_1->height = door_rect->height;
4090 g_part_2->width = door_rect->width;
4091 g_part_2->height = door_rect->height;
4092 g_part_2->src_x = door_rect->width;
4093 g_part_2->src_y = g_part_1->src_y;
4095 door->part_2.x = door->part_1.x;
4096 door->part_2.y = door->part_1.y;
4098 if (door->width != -1)
4100 g_part_1->width = door->width;
4101 g_part_2->width = door->width;
4103 // special treatment for graphics and screen position of right wing
4104 g_part_2->src_x += door_rect->width - door->width;
4105 door->part_2.x += door_rect->width - door->width;
4108 if (door->height != -1)
4110 g_part_1->height = door->height;
4111 g_part_2->height = door->height;
4113 // special treatment for graphics and screen position of bottom wing
4114 g_part_2->src_y += door_rect->height - door->height;
4115 door->part_2.y += door_rect->height - door->height;
4118 /* set animation delays for the default wings and panels */
4120 door->part_1.step_delay = door->step_delay;
4121 door->part_2.step_delay = door->step_delay;
4122 door->panel.step_delay = door->step_delay;
4124 /* set animation draw order for the default wings */
4126 door->part_1.sort_priority = 2; /* draw left wing over ... */
4127 door->part_2.sort_priority = 1; /* ... right wing */
4129 /* set animation draw offset for the default wings */
4131 if (door->anim_mode & ANIM_HORIZONTAL)
4133 door->part_1.step_xoffset = door->step_offset;
4134 door->part_1.step_yoffset = 0;
4135 door->part_2.step_xoffset = door->step_offset * -1;
4136 door->part_2.step_yoffset = 0;
4138 num_door_steps = g_part_1->width / door->step_offset;
4140 else // ANIM_VERTICAL
4142 door->part_1.step_xoffset = 0;
4143 door->part_1.step_yoffset = door->step_offset;
4144 door->part_2.step_xoffset = 0;
4145 door->part_2.step_yoffset = door->step_offset * -1;
4147 num_door_steps = g_part_1->height / door->step_offset;
4150 /* set animation draw offset for the default panels */
4152 if (door->step_offset > 1)
4154 num_panel_steps = 2 * door_rect->height / door->step_offset;
4155 door->panel.start_step = num_panel_steps - num_door_steps;
4156 door->panel.start_step_closing = door->panel.start_step;
4160 num_panel_steps = door_rect->height / door->step_offset;
4161 door->panel.start_step = num_panel_steps - num_door_steps / 2;
4162 door->panel.start_step_closing = door->panel.start_step;
4163 door->panel.step_delay *= 2;
4174 for (i = 0; door_part_controls[i].door_token != -1; i++)
4176 struct DoorPartControlInfo *dpc = &door_part_controls[i];
4177 struct DoorPartOrderInfo *dpo = &door_part_order[i];
4179 /* initialize "start_step_opening" and "start_step_closing", if needed */
4180 if (dpc->pos->start_step_opening == 0 &&
4181 dpc->pos->start_step_closing == 0)
4183 // dpc->pos->start_step_opening = dpc->pos->start_step;
4184 dpc->pos->start_step_closing = dpc->pos->start_step;
4187 /* fill structure for door part draw order (sorted below) */
4189 dpo->sort_priority = dpc->pos->sort_priority;
4192 /* sort door part controls according to sort_priority and graphic number */
4193 qsort(door_part_order, MAX_DOOR_PARTS,
4194 sizeof(struct DoorPartOrderInfo), compareDoorPartOrderInfo);
4197 unsigned int OpenDoor(unsigned int door_state)
4199 if (door_state & DOOR_COPY_BACK)
4201 if (door_state & DOOR_OPEN_1)
4202 BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
4203 1 * DXSIZE, 0, DXSIZE, DYSIZE, 0 * DXSIZE, 0);
4205 if (door_state & DOOR_OPEN_2)
4206 BlitBitmap(bitmap_db_door_2, bitmap_db_door_2,
4207 1 * VXSIZE, 0, VXSIZE, VYSIZE, 0 * VXSIZE, 0);
4209 door_state &= ~DOOR_COPY_BACK;
4212 return MoveDoor(door_state);
4215 unsigned int CloseDoor(unsigned int door_state)
4217 unsigned int old_door_state = GetDoorState();
4219 if (!(door_state & DOOR_NO_COPY_BACK))
4221 if (old_door_state & DOOR_OPEN_1)
4222 BlitBitmap(backbuffer, bitmap_db_door_1,
4223 DX, DY, DXSIZE, DYSIZE, 0, 0);
4225 if (old_door_state & DOOR_OPEN_2)
4226 BlitBitmap(backbuffer, bitmap_db_door_2,
4227 VX, VY, VXSIZE, VYSIZE, 0, 0);
4229 door_state &= ~DOOR_NO_COPY_BACK;
4232 return MoveDoor(door_state);
4235 unsigned int GetDoorState()
4237 return MoveDoor(DOOR_GET_STATE);
4240 unsigned int SetDoorState(unsigned int door_state)
4242 return MoveDoor(door_state | DOOR_SET_STATE);
4245 int euclid(int a, int b)
4247 return (b ? euclid(b, a % b) : a);
4250 unsigned int MoveDoor(unsigned int door_state)
4252 struct Rect door_rect_list[] =
4254 { DX, DY, DXSIZE, DYSIZE },
4255 { VX, VY, VXSIZE, VYSIZE }
4257 static int door1 = DOOR_CLOSE_1;
4258 static int door2 = DOOR_CLOSE_2;
4259 unsigned int door_delay = 0;
4260 unsigned int door_delay_value;
4263 if (door_state == DOOR_GET_STATE)
4264 return (door1 | door2);
4266 if (door_state & DOOR_SET_STATE)
4268 if (door_state & DOOR_ACTION_1)
4269 door1 = door_state & DOOR_ACTION_1;
4270 if (door_state & DOOR_ACTION_2)
4271 door2 = door_state & DOOR_ACTION_2;
4273 return (door1 | door2);
4276 if (!(door_state & DOOR_FORCE_REDRAW))
4278 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
4279 door_state &= ~DOOR_OPEN_1;
4280 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
4281 door_state &= ~DOOR_CLOSE_1;
4282 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
4283 door_state &= ~DOOR_OPEN_2;
4284 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
4285 door_state &= ~DOOR_CLOSE_2;
4288 if (global.autoplay_leveldir)
4290 door_state |= DOOR_NO_DELAY;
4291 door_state &= ~DOOR_CLOSE_ALL;
4294 if (game_status == GAME_MODE_EDITOR)
4295 door_state |= DOOR_NO_DELAY;
4297 if (door_state & DOOR_ACTION)
4299 boolean door_panel_drawn[NUM_DOORS];
4300 boolean panel_has_doors[NUM_DOORS];
4301 boolean door_part_skip[MAX_DOOR_PARTS];
4302 boolean door_part_done[MAX_DOOR_PARTS];
4303 boolean door_part_done_all;
4304 int num_steps[MAX_DOOR_PARTS];
4305 int max_move_delay = 0; // delay for complete animations of all doors
4306 int max_step_delay = 0; // delay (ms) between two animation frames
4307 int num_move_steps = 0; // number of animation steps for all doors
4308 int max_move_delay_doors_only = 0; // delay for doors only (no panel)
4309 int num_move_steps_doors_only = 0; // steps for doors only (no panel)
4310 int current_move_delay = 0;
4314 for (i = 0; i < NUM_DOORS; i++)
4315 panel_has_doors[i] = FALSE;
4317 for (i = 0; i < MAX_DOOR_PARTS; i++)
4319 struct DoorPartControlInfo *dpc = &door_part_controls[i];
4320 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4321 int door_token = dpc->door_token;
4323 door_part_done[i] = FALSE;
4324 door_part_skip[i] = (!(door_state & door_token) ||
4328 for (i = 0; i < MAX_DOOR_PARTS; i++)
4330 int nr = door_part_order[i].nr;
4331 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
4332 struct DoorPartPosInfo *pos = dpc->pos;
4333 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4334 int door_token = dpc->door_token;
4335 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
4336 boolean is_panel = DOOR_PART_IS_PANEL(nr);
4337 int step_xoffset = ABS(pos->step_xoffset);
4338 int step_yoffset = ABS(pos->step_yoffset);
4339 int step_delay = pos->step_delay;
4340 int current_door_state = door_state & door_token;
4341 boolean door_opening = ((current_door_state & DOOR_OPEN) != 0);
4342 boolean door_closing = ((current_door_state & DOOR_CLOSE) != 0);
4343 boolean part_opening = (is_panel ? door_closing : door_opening);
4344 int start_step = (part_opening ? pos->start_step_opening :
4345 pos->start_step_closing);
4346 float move_xsize = (step_xoffset ? g->width : 0);
4347 float move_ysize = (step_yoffset ? g->height : 0);
4348 int move_xsteps = (step_xoffset ? ceil(move_xsize / step_xoffset) : 0);
4349 int move_ysteps = (step_yoffset ? ceil(move_ysize / step_yoffset) : 0);
4350 int move_steps = (move_xsteps && move_ysteps ?
4351 MIN(move_xsteps, move_ysteps) :
4352 move_xsteps ? move_xsteps : move_ysteps) - start_step;
4353 int move_delay = move_steps * step_delay;
4355 if (door_part_skip[nr])
4358 max_move_delay = MAX(max_move_delay, move_delay);
4359 max_step_delay = (max_step_delay == 0 ? step_delay :
4360 euclid(max_step_delay, step_delay));
4361 num_steps[nr] = move_steps;
4365 max_move_delay_doors_only = MAX(max_move_delay_doors_only, move_delay);
4367 panel_has_doors[door_index] = TRUE;
4371 max_step_delay = MAX(1, max_step_delay); // prevent division by zero
4373 num_move_steps = max_move_delay / max_step_delay;
4374 num_move_steps_doors_only = max_move_delay_doors_only / max_step_delay;
4376 door_delay_value = max_step_delay;
4378 if ((door_state & DOOR_NO_DELAY) || setup.quick_doors)
4380 start = num_move_steps - 1;
4384 /* opening door sound has priority over simultaneously closing door */
4385 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
4386 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
4387 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
4388 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
4391 for (k = start; k < num_move_steps; k++)
4393 int last_frame = num_move_steps - 1; // last frame of this "for" loop
4395 door_part_done_all = TRUE;
4397 for (i = 0; i < NUM_DOORS; i++)
4398 door_panel_drawn[i] = FALSE;
4400 for (i = 0; i < MAX_DOOR_PARTS; i++)
4402 int nr = door_part_order[i].nr;
4403 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
4404 struct DoorPartPosInfo *pos = dpc->pos;
4405 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4406 int door_token = dpc->door_token;
4407 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
4408 boolean is_panel = DOOR_PART_IS_PANEL(nr);
4409 boolean is_panel_and_door_has_closed = FALSE;
4410 struct Rect *door_rect = &door_rect_list[door_index];
4411 Bitmap *bitmap_db_door = (door_token == DOOR_1 ? bitmap_db_door_1 :
4413 Bitmap *bitmap = (is_panel ? bitmap_db_door : g->bitmap);
4414 int current_door_state = door_state & door_token;
4415 boolean door_opening = ((current_door_state & DOOR_OPEN) != 0);
4416 boolean door_closing = !door_opening;
4417 boolean part_opening = (is_panel ? door_closing : door_opening);
4418 boolean part_closing = !part_opening;
4419 int start_step = (part_opening ? pos->start_step_opening :
4420 pos->start_step_closing);
4421 int step_delay = pos->step_delay;
4422 int step_factor = step_delay / max_step_delay;
4423 int k1 = (step_factor ? k / step_factor + 1 : k);
4424 int k2 = (part_opening ? k1 + start_step : num_steps[nr] - k1);
4425 int kk = MAX(0, k2);
4428 int src_x, src_y, src_xx, src_yy;
4429 int dst_x, dst_y, dst_xx, dst_yy;
4432 if (door_part_skip[nr])
4435 if (!(door_state & door_token))
4443 int k2_door = (door_opening ? k : num_move_steps_doors_only - k - 1);
4444 int kk_door = MAX(0, k2_door);
4445 int sync_frame = kk_door * door_delay_value;
4446 int frame = getGraphicAnimationFrame(dpc->graphic, sync_frame);
4448 getGraphicSource(dpc->graphic, frame, &bitmap, &g_src_x, &g_src_y);
4453 if (!door_panel_drawn[door_index])
4455 ClearRectangle(drawto, door_rect->x, door_rect->y,
4456 door_rect->width, door_rect->height);
4458 door_panel_drawn[door_index] = TRUE;
4461 // draw opening or closing door parts
4463 if (pos->step_xoffset < 0) // door part on right side
4466 dst_xx = pos->x + ABS(kk * pos->step_xoffset);
4469 if (dst_xx + width > door_rect->width)
4470 width = door_rect->width - dst_xx;
4472 else // door part on left side
4475 dst_xx = pos->x - kk * pos->step_xoffset;
4479 src_xx = ABS(dst_xx);
4483 width = g->width - src_xx;
4485 if (width > door_rect->width)
4486 width = door_rect->width;
4488 // printf("::: k == %d [%d] \n", k, start_step);
4491 if (pos->step_yoffset < 0) // door part on bottom side
4494 dst_yy = pos->y + ABS(kk * pos->step_yoffset);
4497 if (dst_yy + height > door_rect->height)
4498 height = door_rect->height - dst_yy;
4500 else // door part on top side
4503 dst_yy = pos->y - kk * pos->step_yoffset;
4507 src_yy = ABS(dst_yy);
4511 height = g->height - src_yy;
4514 src_x = g_src_x + src_xx;
4515 src_y = g_src_y + src_yy;
4517 dst_x = door_rect->x + dst_xx;
4518 dst_y = door_rect->y + dst_yy;
4520 is_panel_and_door_has_closed =
4523 panel_has_doors[door_index] &&
4524 k >= num_move_steps_doors_only - 1);
4526 if (width >= 0 && width <= g->width &&
4527 height >= 0 && height <= g->height &&
4528 !is_panel_and_door_has_closed)
4530 if (is_panel || !pos->draw_masked)
4531 BlitBitmap(bitmap, drawto, src_x, src_y, width, height,
4534 BlitBitmapMasked(bitmap, drawto, src_x, src_y, width, height,
4538 redraw_mask |= REDRAW_DOOR_FROM_TOKEN(door_token);
4540 if ((part_opening && (width < 0 || height < 0)) ||
4541 (part_closing && (width >= g->width && height >= g->height)))
4542 door_part_done[nr] = TRUE;
4544 // continue door part animations, but not panel after door has closed
4545 if (!door_part_done[nr] && !is_panel_and_door_has_closed)
4546 door_part_done_all = FALSE;
4549 if (!(door_state & DOOR_NO_DELAY))
4553 SkipUntilDelayReached(&door_delay, door_delay_value, &k, last_frame);
4555 current_move_delay += max_step_delay;
4558 if (door_part_done_all)
4563 if (door_state & DOOR_ACTION_1)
4564 door1 = door_state & DOOR_ACTION_1;
4565 if (door_state & DOOR_ACTION_2)
4566 door2 = door_state & DOOR_ACTION_2;
4568 // draw masked border over door area
4569 DrawMaskedBorder(REDRAW_DOOR_1);
4570 DrawMaskedBorder(REDRAW_DOOR_2);
4572 return (door1 | door2);
4575 static boolean useSpecialEditorDoor()
4577 int graphic = IMG_GLOBAL_BORDER_EDITOR;
4578 boolean redefined = getImageListEntryFromImageID(graphic)->redefined;
4580 // do not draw special editor door if editor border defined or redefined
4581 if (graphic_info[graphic].bitmap != NULL || redefined)
4584 // do not draw special editor door if global border defined to be empty
4585 if (graphic_info[IMG_GLOBAL_BORDER].bitmap == NULL)
4588 // do not draw special editor door if viewport definitions do not match
4592 EY + EYSIZE != VY + VYSIZE)
4598 void DrawSpecialEditorDoor()
4600 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
4601 int top_border_width = gfx1->width;
4602 int top_border_height = gfx1->height;
4603 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
4604 int ex = EX - outer_border;
4605 int ey = EY - outer_border;
4606 int vy = VY - outer_border;
4607 int exsize = EXSIZE + 2 * outer_border;
4609 if (!useSpecialEditorDoor())
4612 /* draw bigger level editor toolbox window */
4613 BlitBitmap(gfx1->bitmap, drawto, gfx1->src_x, gfx1->src_y,
4614 top_border_width, top_border_height, ex, ey - top_border_height);
4615 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto, ex, vy,
4616 exsize, EYSIZE - VYSIZE + outer_border, ex, ey);
4618 redraw_mask |= REDRAW_ALL;
4621 void UndrawSpecialEditorDoor()
4623 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
4624 int top_border_width = gfx1->width;
4625 int top_border_height = gfx1->height;
4626 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
4627 int ex = EX - outer_border;
4628 int ey = EY - outer_border;
4629 int ey_top = ey - top_border_height;
4630 int exsize = EXSIZE + 2 * outer_border;
4631 int eysize = EYSIZE + 2 * outer_border;
4633 if (!useSpecialEditorDoor())
4636 /* draw normal tape recorder window */
4637 if (graphic_info[IMG_GLOBAL_BORDER].bitmap)
4639 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
4640 ex, ey_top, top_border_width, top_border_height,
4642 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
4643 ex, ey, exsize, eysize, ex, ey);
4647 // if screen background is set to "[NONE]", clear editor toolbox window
4648 ClearRectangle(drawto, ex, ey_top, top_border_width, top_border_height);
4649 ClearRectangle(drawto, ex, ey, exsize, eysize);
4652 redraw_mask |= REDRAW_ALL;
4656 /* ---------- new tool button stuff ---------------------------------------- */
4661 struct TextPosInfo *pos;
4664 } toolbutton_info[NUM_TOOL_BUTTONS] =
4667 IMG_GFX_REQUEST_BUTTON_YES, &request.button.yes,
4668 TOOL_CTRL_ID_YES, "yes"
4671 IMG_GFX_REQUEST_BUTTON_NO, &request.button.no,
4672 TOOL_CTRL_ID_NO, "no"
4675 IMG_GFX_REQUEST_BUTTON_CONFIRM, &request.button.confirm,
4676 TOOL_CTRL_ID_CONFIRM, "confirm"
4679 IMG_GFX_REQUEST_BUTTON_PLAYER_1, &request.button.player_1,
4680 TOOL_CTRL_ID_PLAYER_1, "player 1"
4683 IMG_GFX_REQUEST_BUTTON_PLAYER_2, &request.button.player_2,
4684 TOOL_CTRL_ID_PLAYER_2, "player 2"
4687 IMG_GFX_REQUEST_BUTTON_PLAYER_3, &request.button.player_3,
4688 TOOL_CTRL_ID_PLAYER_3, "player 3"
4691 IMG_GFX_REQUEST_BUTTON_PLAYER_4, &request.button.player_4,
4692 TOOL_CTRL_ID_PLAYER_4, "player 4"
4696 void CreateToolButtons()
4700 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4702 struct GraphicInfo *gfx = &graphic_info[toolbutton_info[i].graphic];
4703 struct TextPosInfo *pos = toolbutton_info[i].pos;
4704 struct GadgetInfo *gi;
4705 Bitmap *deco_bitmap = None;
4706 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
4707 unsigned int event_mask = GD_EVENT_RELEASED;
4710 int gd_x = gfx->src_x;
4711 int gd_y = gfx->src_y;
4712 int gd_xp = gfx->src_x + gfx->pressed_xoffset;
4713 int gd_yp = gfx->src_y + gfx->pressed_yoffset;
4716 if (global.use_envelope_request)
4717 setRequestPosition(&dx, &dy, TRUE);
4719 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
4721 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
4723 getSizedGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr), 0,
4724 pos->size, &deco_bitmap, &deco_x, &deco_y);
4725 deco_xpos = (gfx->width - pos->size) / 2;
4726 deco_ypos = (gfx->height - pos->size) / 2;
4729 gi = CreateGadget(GDI_CUSTOM_ID, id,
4730 GDI_INFO_TEXT, toolbutton_info[i].infotext,
4731 GDI_X, dx + GDI_ACTIVE_POS(pos->x),
4732 GDI_Y, dy + GDI_ACTIVE_POS(pos->y),
4733 GDI_WIDTH, gfx->width,
4734 GDI_HEIGHT, gfx->height,
4735 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
4736 GDI_STATE, GD_BUTTON_UNPRESSED,
4737 GDI_DESIGN_UNPRESSED, gfx->bitmap, gd_x, gd_y,
4738 GDI_DESIGN_PRESSED, gfx->bitmap, gd_xp, gd_yp,
4739 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
4740 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
4741 GDI_DECORATION_SIZE, pos->size, pos->size,
4742 GDI_DECORATION_SHIFTING, 1, 1,
4743 GDI_DIRECT_DRAW, FALSE,
4744 GDI_EVENT_MASK, event_mask,
4745 GDI_CALLBACK_ACTION, HandleToolButtons,
4749 Error(ERR_EXIT, "cannot create gadget");
4751 tool_gadget[id] = gi;
4755 void FreeToolButtons()
4759 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4760 FreeGadget(tool_gadget[i]);
4763 static void UnmapToolButtons()
4767 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4768 UnmapGadget(tool_gadget[i]);
4771 static void HandleToolButtons(struct GadgetInfo *gi)
4773 request_gadget_id = gi->custom_id;
4776 static struct Mapping_EM_to_RND_object
4779 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
4780 boolean is_backside; /* backside of moving element */
4786 em_object_mapping_list[] =
4789 Xblank, TRUE, FALSE,
4793 Yacid_splash_eB, FALSE, FALSE,
4794 EL_ACID_SPLASH_RIGHT, -1, -1
4797 Yacid_splash_wB, FALSE, FALSE,
4798 EL_ACID_SPLASH_LEFT, -1, -1
4801 #ifdef EM_ENGINE_BAD_ROLL
4803 Xstone_force_e, FALSE, FALSE,
4804 EL_ROCK, -1, MV_BIT_RIGHT
4807 Xstone_force_w, FALSE, FALSE,
4808 EL_ROCK, -1, MV_BIT_LEFT
4811 Xnut_force_e, FALSE, FALSE,
4812 EL_NUT, -1, MV_BIT_RIGHT
4815 Xnut_force_w, FALSE, FALSE,
4816 EL_NUT, -1, MV_BIT_LEFT
4819 Xspring_force_e, FALSE, FALSE,
4820 EL_SPRING, -1, MV_BIT_RIGHT
4823 Xspring_force_w, FALSE, FALSE,
4824 EL_SPRING, -1, MV_BIT_LEFT
4827 Xemerald_force_e, FALSE, FALSE,
4828 EL_EMERALD, -1, MV_BIT_RIGHT
4831 Xemerald_force_w, FALSE, FALSE,
4832 EL_EMERALD, -1, MV_BIT_LEFT
4835 Xdiamond_force_e, FALSE, FALSE,
4836 EL_DIAMOND, -1, MV_BIT_RIGHT
4839 Xdiamond_force_w, FALSE, FALSE,
4840 EL_DIAMOND, -1, MV_BIT_LEFT
4843 Xbomb_force_e, FALSE, FALSE,
4844 EL_BOMB, -1, MV_BIT_RIGHT
4847 Xbomb_force_w, FALSE, FALSE,
4848 EL_BOMB, -1, MV_BIT_LEFT
4850 #endif /* EM_ENGINE_BAD_ROLL */
4853 Xstone, TRUE, FALSE,
4857 Xstone_pause, FALSE, FALSE,
4861 Xstone_fall, FALSE, FALSE,
4865 Ystone_s, FALSE, FALSE,
4866 EL_ROCK, ACTION_FALLING, -1
4869 Ystone_sB, FALSE, TRUE,
4870 EL_ROCK, ACTION_FALLING, -1
4873 Ystone_e, FALSE, FALSE,
4874 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
4877 Ystone_eB, FALSE, TRUE,
4878 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
4881 Ystone_w, FALSE, FALSE,
4882 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
4885 Ystone_wB, FALSE, TRUE,
4886 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
4893 Xnut_pause, FALSE, FALSE,
4897 Xnut_fall, FALSE, FALSE,
4901 Ynut_s, FALSE, FALSE,
4902 EL_NUT, ACTION_FALLING, -1
4905 Ynut_sB, FALSE, TRUE,
4906 EL_NUT, ACTION_FALLING, -1
4909 Ynut_e, FALSE, FALSE,
4910 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
4913 Ynut_eB, FALSE, TRUE,
4914 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
4917 Ynut_w, FALSE, FALSE,
4918 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
4921 Ynut_wB, FALSE, TRUE,
4922 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
4925 Xbug_n, TRUE, FALSE,
4929 Xbug_e, TRUE, FALSE,
4930 EL_BUG_RIGHT, -1, -1
4933 Xbug_s, TRUE, FALSE,
4937 Xbug_w, TRUE, FALSE,
4941 Xbug_gon, FALSE, FALSE,
4945 Xbug_goe, FALSE, FALSE,
4946 EL_BUG_RIGHT, -1, -1
4949 Xbug_gos, FALSE, FALSE,
4953 Xbug_gow, FALSE, FALSE,
4957 Ybug_n, FALSE, FALSE,
4958 EL_BUG, ACTION_MOVING, MV_BIT_UP
4961 Ybug_nB, FALSE, TRUE,
4962 EL_BUG, ACTION_MOVING, MV_BIT_UP
4965 Ybug_e, FALSE, FALSE,
4966 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
4969 Ybug_eB, FALSE, TRUE,
4970 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
4973 Ybug_s, FALSE, FALSE,
4974 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
4977 Ybug_sB, FALSE, TRUE,
4978 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
4981 Ybug_w, FALSE, FALSE,
4982 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
4985 Ybug_wB, FALSE, TRUE,
4986 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
4989 Ybug_w_n, FALSE, FALSE,
4990 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
4993 Ybug_n_e, FALSE, FALSE,
4994 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
4997 Ybug_e_s, FALSE, FALSE,
4998 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
5001 Ybug_s_w, FALSE, FALSE,
5002 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
5005 Ybug_e_n, FALSE, FALSE,
5006 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
5009 Ybug_s_e, FALSE, FALSE,
5010 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
5013 Ybug_w_s, FALSE, FALSE,
5014 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
5017 Ybug_n_w, FALSE, FALSE,
5018 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
5021 Ybug_stone, FALSE, FALSE,
5022 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
5025 Ybug_spring, FALSE, FALSE,
5026 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
5029 Xtank_n, TRUE, FALSE,
5030 EL_SPACESHIP_UP, -1, -1
5033 Xtank_e, TRUE, FALSE,
5034 EL_SPACESHIP_RIGHT, -1, -1
5037 Xtank_s, TRUE, FALSE,
5038 EL_SPACESHIP_DOWN, -1, -1
5041 Xtank_w, TRUE, FALSE,
5042 EL_SPACESHIP_LEFT, -1, -1
5045 Xtank_gon, FALSE, FALSE,
5046 EL_SPACESHIP_UP, -1, -1
5049 Xtank_goe, FALSE, FALSE,
5050 EL_SPACESHIP_RIGHT, -1, -1
5053 Xtank_gos, FALSE, FALSE,
5054 EL_SPACESHIP_DOWN, -1, -1
5057 Xtank_gow, FALSE, FALSE,
5058 EL_SPACESHIP_LEFT, -1, -1
5061 Ytank_n, FALSE, FALSE,
5062 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
5065 Ytank_nB, FALSE, TRUE,
5066 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
5069 Ytank_e, FALSE, FALSE,
5070 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
5073 Ytank_eB, FALSE, TRUE,
5074 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
5077 Ytank_s, FALSE, FALSE,
5078 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
5081 Ytank_sB, FALSE, TRUE,
5082 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
5085 Ytank_w, FALSE, FALSE,
5086 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
5089 Ytank_wB, FALSE, TRUE,
5090 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
5093 Ytank_w_n, FALSE, FALSE,
5094 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
5097 Ytank_n_e, FALSE, FALSE,
5098 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
5101 Ytank_e_s, FALSE, FALSE,
5102 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
5105 Ytank_s_w, FALSE, FALSE,
5106 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
5109 Ytank_e_n, FALSE, FALSE,
5110 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
5113 Ytank_s_e, FALSE, FALSE,
5114 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
5117 Ytank_w_s, FALSE, FALSE,
5118 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
5121 Ytank_n_w, FALSE, FALSE,
5122 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
5125 Ytank_stone, FALSE, FALSE,
5126 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
5129 Ytank_spring, FALSE, FALSE,
5130 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
5133 Xandroid, TRUE, FALSE,
5134 EL_EMC_ANDROID, ACTION_ACTIVE, -1
5137 Xandroid_1_n, FALSE, FALSE,
5138 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
5141 Xandroid_2_n, FALSE, FALSE,
5142 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
5145 Xandroid_1_e, FALSE, FALSE,
5146 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
5149 Xandroid_2_e, FALSE, FALSE,
5150 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
5153 Xandroid_1_w, FALSE, FALSE,
5154 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
5157 Xandroid_2_w, FALSE, FALSE,
5158 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
5161 Xandroid_1_s, FALSE, FALSE,
5162 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
5165 Xandroid_2_s, FALSE, FALSE,
5166 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
5169 Yandroid_n, FALSE, FALSE,
5170 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
5173 Yandroid_nB, FALSE, TRUE,
5174 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
5177 Yandroid_ne, FALSE, FALSE,
5178 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
5181 Yandroid_neB, FALSE, TRUE,
5182 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
5185 Yandroid_e, FALSE, FALSE,
5186 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
5189 Yandroid_eB, FALSE, TRUE,
5190 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
5193 Yandroid_se, FALSE, FALSE,
5194 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
5197 Yandroid_seB, FALSE, TRUE,
5198 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
5201 Yandroid_s, FALSE, FALSE,
5202 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
5205 Yandroid_sB, FALSE, TRUE,
5206 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
5209 Yandroid_sw, FALSE, FALSE,
5210 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
5213 Yandroid_swB, FALSE, TRUE,
5214 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
5217 Yandroid_w, FALSE, FALSE,
5218 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
5221 Yandroid_wB, FALSE, TRUE,
5222 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
5225 Yandroid_nw, FALSE, FALSE,
5226 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
5229 Yandroid_nwB, FALSE, TRUE,
5230 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
5233 Xspring, TRUE, FALSE,
5237 Xspring_pause, FALSE, FALSE,
5241 Xspring_e, FALSE, FALSE,
5245 Xspring_w, FALSE, FALSE,
5249 Xspring_fall, FALSE, FALSE,
5253 Yspring_s, FALSE, FALSE,
5254 EL_SPRING, ACTION_FALLING, -1
5257 Yspring_sB, FALSE, TRUE,
5258 EL_SPRING, ACTION_FALLING, -1
5261 Yspring_e, FALSE, FALSE,
5262 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
5265 Yspring_eB, FALSE, TRUE,
5266 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
5269 Yspring_w, FALSE, FALSE,
5270 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
5273 Yspring_wB, FALSE, TRUE,
5274 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
5277 Yspring_kill_e, FALSE, FALSE,
5278 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
5281 Yspring_kill_eB, FALSE, TRUE,
5282 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
5285 Yspring_kill_w, FALSE, FALSE,
5286 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
5289 Yspring_kill_wB, FALSE, TRUE,
5290 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
5293 Xeater_n, TRUE, FALSE,
5294 EL_YAMYAM_UP, -1, -1
5297 Xeater_e, TRUE, FALSE,
5298 EL_YAMYAM_RIGHT, -1, -1
5301 Xeater_w, TRUE, FALSE,
5302 EL_YAMYAM_LEFT, -1, -1
5305 Xeater_s, TRUE, FALSE,
5306 EL_YAMYAM_DOWN, -1, -1
5309 Yeater_n, FALSE, FALSE,
5310 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
5313 Yeater_nB, FALSE, TRUE,
5314 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
5317 Yeater_e, FALSE, FALSE,
5318 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
5321 Yeater_eB, FALSE, TRUE,
5322 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
5325 Yeater_s, FALSE, FALSE,
5326 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
5329 Yeater_sB, FALSE, TRUE,
5330 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
5333 Yeater_w, FALSE, FALSE,
5334 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
5337 Yeater_wB, FALSE, TRUE,
5338 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
5341 Yeater_stone, FALSE, FALSE,
5342 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
5345 Yeater_spring, FALSE, FALSE,
5346 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
5349 Xalien, TRUE, FALSE,
5353 Xalien_pause, FALSE, FALSE,
5357 Yalien_n, FALSE, FALSE,
5358 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
5361 Yalien_nB, FALSE, TRUE,
5362 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
5365 Yalien_e, FALSE, FALSE,
5366 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
5369 Yalien_eB, FALSE, TRUE,
5370 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
5373 Yalien_s, FALSE, FALSE,
5374 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
5377 Yalien_sB, FALSE, TRUE,
5378 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
5381 Yalien_w, FALSE, FALSE,
5382 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
5385 Yalien_wB, FALSE, TRUE,
5386 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
5389 Yalien_stone, FALSE, FALSE,
5390 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
5393 Yalien_spring, FALSE, FALSE,
5394 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
5397 Xemerald, TRUE, FALSE,
5401 Xemerald_pause, FALSE, FALSE,
5405 Xemerald_fall, FALSE, FALSE,
5409 Xemerald_shine, FALSE, FALSE,
5410 EL_EMERALD, ACTION_TWINKLING, -1
5413 Yemerald_s, FALSE, FALSE,
5414 EL_EMERALD, ACTION_FALLING, -1
5417 Yemerald_sB, FALSE, TRUE,
5418 EL_EMERALD, ACTION_FALLING, -1
5421 Yemerald_e, FALSE, FALSE,
5422 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
5425 Yemerald_eB, FALSE, TRUE,
5426 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
5429 Yemerald_w, FALSE, FALSE,
5430 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
5433 Yemerald_wB, FALSE, TRUE,
5434 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
5437 Yemerald_eat, FALSE, FALSE,
5438 EL_EMERALD, ACTION_COLLECTING, -1
5441 Yemerald_stone, FALSE, FALSE,
5442 EL_NUT, ACTION_BREAKING, -1
5445 Xdiamond, TRUE, FALSE,
5449 Xdiamond_pause, FALSE, FALSE,
5453 Xdiamond_fall, FALSE, FALSE,
5457 Xdiamond_shine, FALSE, FALSE,
5458 EL_DIAMOND, ACTION_TWINKLING, -1
5461 Ydiamond_s, FALSE, FALSE,
5462 EL_DIAMOND, ACTION_FALLING, -1
5465 Ydiamond_sB, FALSE, TRUE,
5466 EL_DIAMOND, ACTION_FALLING, -1
5469 Ydiamond_e, FALSE, FALSE,
5470 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
5473 Ydiamond_eB, FALSE, TRUE,
5474 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
5477 Ydiamond_w, FALSE, FALSE,
5478 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
5481 Ydiamond_wB, FALSE, TRUE,
5482 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
5485 Ydiamond_eat, FALSE, FALSE,
5486 EL_DIAMOND, ACTION_COLLECTING, -1
5489 Ydiamond_stone, FALSE, FALSE,
5490 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
5493 Xdrip_fall, TRUE, FALSE,
5494 EL_AMOEBA_DROP, -1, -1
5497 Xdrip_stretch, FALSE, FALSE,
5498 EL_AMOEBA_DROP, ACTION_FALLING, -1
5501 Xdrip_stretchB, FALSE, TRUE,
5502 EL_AMOEBA_DROP, ACTION_FALLING, -1
5505 Xdrip_eat, FALSE, FALSE,
5506 EL_AMOEBA_DROP, ACTION_GROWING, -1
5509 Ydrip_s1, FALSE, FALSE,
5510 EL_AMOEBA_DROP, ACTION_FALLING, -1
5513 Ydrip_s1B, FALSE, TRUE,
5514 EL_AMOEBA_DROP, ACTION_FALLING, -1
5517 Ydrip_s2, FALSE, FALSE,
5518 EL_AMOEBA_DROP, ACTION_FALLING, -1
5521 Ydrip_s2B, FALSE, TRUE,
5522 EL_AMOEBA_DROP, ACTION_FALLING, -1
5529 Xbomb_pause, FALSE, FALSE,
5533 Xbomb_fall, FALSE, FALSE,
5537 Ybomb_s, FALSE, FALSE,
5538 EL_BOMB, ACTION_FALLING, -1
5541 Ybomb_sB, FALSE, TRUE,
5542 EL_BOMB, ACTION_FALLING, -1
5545 Ybomb_e, FALSE, FALSE,
5546 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
5549 Ybomb_eB, FALSE, TRUE,
5550 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
5553 Ybomb_w, FALSE, FALSE,
5554 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
5557 Ybomb_wB, FALSE, TRUE,
5558 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
5561 Ybomb_eat, FALSE, FALSE,
5562 EL_BOMB, ACTION_ACTIVATING, -1
5565 Xballoon, TRUE, FALSE,
5569 Yballoon_n, FALSE, FALSE,
5570 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
5573 Yballoon_nB, FALSE, TRUE,
5574 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
5577 Yballoon_e, FALSE, FALSE,
5578 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
5581 Yballoon_eB, FALSE, TRUE,
5582 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
5585 Yballoon_s, FALSE, FALSE,
5586 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
5589 Yballoon_sB, FALSE, TRUE,
5590 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
5593 Yballoon_w, FALSE, FALSE,
5594 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
5597 Yballoon_wB, FALSE, TRUE,
5598 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
5601 Xgrass, TRUE, FALSE,
5602 EL_EMC_GRASS, -1, -1
5605 Ygrass_nB, FALSE, FALSE,
5606 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
5609 Ygrass_eB, FALSE, FALSE,
5610 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
5613 Ygrass_sB, FALSE, FALSE,
5614 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
5617 Ygrass_wB, FALSE, FALSE,
5618 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
5625 Ydirt_nB, FALSE, FALSE,
5626 EL_SAND, ACTION_DIGGING, MV_BIT_UP
5629 Ydirt_eB, FALSE, FALSE,
5630 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
5633 Ydirt_sB, FALSE, FALSE,
5634 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
5637 Ydirt_wB, FALSE, FALSE,
5638 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
5641 Xacid_ne, TRUE, FALSE,
5642 EL_ACID_POOL_TOPRIGHT, -1, -1
5645 Xacid_se, TRUE, FALSE,
5646 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
5649 Xacid_s, TRUE, FALSE,
5650 EL_ACID_POOL_BOTTOM, -1, -1
5653 Xacid_sw, TRUE, FALSE,
5654 EL_ACID_POOL_BOTTOMLEFT, -1, -1
5657 Xacid_nw, TRUE, FALSE,
5658 EL_ACID_POOL_TOPLEFT, -1, -1
5661 Xacid_1, TRUE, FALSE,
5665 Xacid_2, FALSE, FALSE,
5669 Xacid_3, FALSE, FALSE,
5673 Xacid_4, FALSE, FALSE,
5677 Xacid_5, FALSE, FALSE,
5681 Xacid_6, FALSE, FALSE,
5685 Xacid_7, FALSE, FALSE,
5689 Xacid_8, FALSE, FALSE,
5693 Xball_1, TRUE, FALSE,
5694 EL_EMC_MAGIC_BALL, -1, -1
5697 Xball_1B, FALSE, FALSE,
5698 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5701 Xball_2, FALSE, FALSE,
5702 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5705 Xball_2B, FALSE, FALSE,
5706 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5709 Yball_eat, FALSE, FALSE,
5710 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
5713 Ykey_1_eat, FALSE, FALSE,
5714 EL_EM_KEY_1, ACTION_COLLECTING, -1
5717 Ykey_2_eat, FALSE, FALSE,
5718 EL_EM_KEY_2, ACTION_COLLECTING, -1
5721 Ykey_3_eat, FALSE, FALSE,
5722 EL_EM_KEY_3, ACTION_COLLECTING, -1
5725 Ykey_4_eat, FALSE, FALSE,
5726 EL_EM_KEY_4, ACTION_COLLECTING, -1
5729 Ykey_5_eat, FALSE, FALSE,
5730 EL_EMC_KEY_5, ACTION_COLLECTING, -1
5733 Ykey_6_eat, FALSE, FALSE,
5734 EL_EMC_KEY_6, ACTION_COLLECTING, -1
5737 Ykey_7_eat, FALSE, FALSE,
5738 EL_EMC_KEY_7, ACTION_COLLECTING, -1
5741 Ykey_8_eat, FALSE, FALSE,
5742 EL_EMC_KEY_8, ACTION_COLLECTING, -1
5745 Ylenses_eat, FALSE, FALSE,
5746 EL_EMC_LENSES, ACTION_COLLECTING, -1
5749 Ymagnify_eat, FALSE, FALSE,
5750 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
5753 Ygrass_eat, FALSE, FALSE,
5754 EL_EMC_GRASS, ACTION_SNAPPING, -1
5757 Ydirt_eat, FALSE, FALSE,
5758 EL_SAND, ACTION_SNAPPING, -1
5761 Xgrow_ns, TRUE, FALSE,
5762 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
5765 Ygrow_ns_eat, FALSE, FALSE,
5766 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
5769 Xgrow_ew, TRUE, FALSE,
5770 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
5773 Ygrow_ew_eat, FALSE, FALSE,
5774 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
5777 Xwonderwall, TRUE, FALSE,
5778 EL_MAGIC_WALL, -1, -1
5781 XwonderwallB, FALSE, FALSE,
5782 EL_MAGIC_WALL, ACTION_ACTIVE, -1
5785 Xamoeba_1, TRUE, FALSE,
5786 EL_AMOEBA_DRY, ACTION_OTHER, -1
5789 Xamoeba_2, FALSE, FALSE,
5790 EL_AMOEBA_DRY, ACTION_OTHER, -1
5793 Xamoeba_3, FALSE, FALSE,
5794 EL_AMOEBA_DRY, ACTION_OTHER, -1
5797 Xamoeba_4, FALSE, FALSE,
5798 EL_AMOEBA_DRY, ACTION_OTHER, -1
5801 Xamoeba_5, TRUE, FALSE,
5802 EL_AMOEBA_WET, ACTION_OTHER, -1
5805 Xamoeba_6, FALSE, FALSE,
5806 EL_AMOEBA_WET, ACTION_OTHER, -1
5809 Xamoeba_7, FALSE, FALSE,
5810 EL_AMOEBA_WET, ACTION_OTHER, -1
5813 Xamoeba_8, FALSE, FALSE,
5814 EL_AMOEBA_WET, ACTION_OTHER, -1
5817 Xdoor_1, TRUE, FALSE,
5818 EL_EM_GATE_1, -1, -1
5821 Xdoor_2, TRUE, FALSE,
5822 EL_EM_GATE_2, -1, -1
5825 Xdoor_3, TRUE, FALSE,
5826 EL_EM_GATE_3, -1, -1
5829 Xdoor_4, TRUE, FALSE,
5830 EL_EM_GATE_4, -1, -1
5833 Xdoor_5, TRUE, FALSE,
5834 EL_EMC_GATE_5, -1, -1
5837 Xdoor_6, TRUE, FALSE,
5838 EL_EMC_GATE_6, -1, -1
5841 Xdoor_7, TRUE, FALSE,
5842 EL_EMC_GATE_7, -1, -1
5845 Xdoor_8, TRUE, FALSE,
5846 EL_EMC_GATE_8, -1, -1
5849 Xkey_1, TRUE, FALSE,
5853 Xkey_2, TRUE, FALSE,
5857 Xkey_3, TRUE, FALSE,
5861 Xkey_4, TRUE, FALSE,
5865 Xkey_5, TRUE, FALSE,
5866 EL_EMC_KEY_5, -1, -1
5869 Xkey_6, TRUE, FALSE,
5870 EL_EMC_KEY_6, -1, -1
5873 Xkey_7, TRUE, FALSE,
5874 EL_EMC_KEY_7, -1, -1
5877 Xkey_8, TRUE, FALSE,
5878 EL_EMC_KEY_8, -1, -1
5881 Xwind_n, TRUE, FALSE,
5882 EL_BALLOON_SWITCH_UP, -1, -1
5885 Xwind_e, TRUE, FALSE,
5886 EL_BALLOON_SWITCH_RIGHT, -1, -1
5889 Xwind_s, TRUE, FALSE,
5890 EL_BALLOON_SWITCH_DOWN, -1, -1
5893 Xwind_w, TRUE, FALSE,
5894 EL_BALLOON_SWITCH_LEFT, -1, -1
5897 Xwind_nesw, TRUE, FALSE,
5898 EL_BALLOON_SWITCH_ANY, -1, -1
5901 Xwind_stop, TRUE, FALSE,
5902 EL_BALLOON_SWITCH_NONE, -1, -1
5906 EL_EM_EXIT_CLOSED, -1, -1
5909 Xexit_1, TRUE, FALSE,
5910 EL_EM_EXIT_OPEN, -1, -1
5913 Xexit_2, FALSE, FALSE,
5914 EL_EM_EXIT_OPEN, -1, -1
5917 Xexit_3, FALSE, FALSE,
5918 EL_EM_EXIT_OPEN, -1, -1
5921 Xdynamite, TRUE, FALSE,
5922 EL_EM_DYNAMITE, -1, -1
5925 Ydynamite_eat, FALSE, FALSE,
5926 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
5929 Xdynamite_1, TRUE, FALSE,
5930 EL_EM_DYNAMITE_ACTIVE, -1, -1
5933 Xdynamite_2, FALSE, FALSE,
5934 EL_EM_DYNAMITE_ACTIVE, -1, -1
5937 Xdynamite_3, FALSE, FALSE,
5938 EL_EM_DYNAMITE_ACTIVE, -1, -1
5941 Xdynamite_4, FALSE, FALSE,
5942 EL_EM_DYNAMITE_ACTIVE, -1, -1
5945 Xbumper, TRUE, FALSE,
5946 EL_EMC_SPRING_BUMPER, -1, -1
5949 XbumperB, FALSE, FALSE,
5950 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
5953 Xwheel, TRUE, FALSE,
5954 EL_ROBOT_WHEEL, -1, -1
5957 XwheelB, FALSE, FALSE,
5958 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
5961 Xswitch, TRUE, FALSE,
5962 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
5965 XswitchB, FALSE, FALSE,
5966 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
5970 EL_QUICKSAND_EMPTY, -1, -1
5973 Xsand_stone, TRUE, FALSE,
5974 EL_QUICKSAND_FULL, -1, -1
5977 Xsand_stonein_1, FALSE, TRUE,
5978 EL_ROCK, ACTION_FILLING, -1
5981 Xsand_stonein_2, FALSE, TRUE,
5982 EL_ROCK, ACTION_FILLING, -1
5985 Xsand_stonein_3, FALSE, TRUE,
5986 EL_ROCK, ACTION_FILLING, -1
5989 Xsand_stonein_4, FALSE, TRUE,
5990 EL_ROCK, ACTION_FILLING, -1
5993 Xsand_stonesand_1, FALSE, FALSE,
5994 EL_QUICKSAND_EMPTYING, -1, -1
5997 Xsand_stonesand_2, FALSE, FALSE,
5998 EL_QUICKSAND_EMPTYING, -1, -1
6001 Xsand_stonesand_3, FALSE, FALSE,
6002 EL_QUICKSAND_EMPTYING, -1, -1
6005 Xsand_stonesand_4, FALSE, FALSE,
6006 EL_QUICKSAND_EMPTYING, -1, -1
6009 Xsand_stonesand_quickout_1, FALSE, FALSE,
6010 EL_QUICKSAND_EMPTYING, -1, -1
6013 Xsand_stonesand_quickout_2, FALSE, FALSE,
6014 EL_QUICKSAND_EMPTYING, -1, -1
6017 Xsand_stoneout_1, FALSE, FALSE,
6018 EL_ROCK, ACTION_EMPTYING, -1
6021 Xsand_stoneout_2, FALSE, FALSE,
6022 EL_ROCK, ACTION_EMPTYING, -1
6025 Xsand_sandstone_1, FALSE, FALSE,
6026 EL_QUICKSAND_FILLING, -1, -1
6029 Xsand_sandstone_2, FALSE, FALSE,
6030 EL_QUICKSAND_FILLING, -1, -1
6033 Xsand_sandstone_3, FALSE, FALSE,
6034 EL_QUICKSAND_FILLING, -1, -1
6037 Xsand_sandstone_4, FALSE, FALSE,
6038 EL_QUICKSAND_FILLING, -1, -1
6041 Xplant, TRUE, FALSE,
6042 EL_EMC_PLANT, -1, -1
6045 Yplant, FALSE, FALSE,
6046 EL_EMC_PLANT, -1, -1
6049 Xlenses, TRUE, FALSE,
6050 EL_EMC_LENSES, -1, -1
6053 Xmagnify, TRUE, FALSE,
6054 EL_EMC_MAGNIFIER, -1, -1
6057 Xdripper, TRUE, FALSE,
6058 EL_EMC_DRIPPER, -1, -1
6061 XdripperB, FALSE, FALSE,
6062 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
6065 Xfake_blank, TRUE, FALSE,
6066 EL_INVISIBLE_WALL, -1, -1
6069 Xfake_blankB, FALSE, FALSE,
6070 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
6073 Xfake_grass, TRUE, FALSE,
6074 EL_EMC_FAKE_GRASS, -1, -1
6077 Xfake_grassB, FALSE, FALSE,
6078 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
6081 Xfake_door_1, TRUE, FALSE,
6082 EL_EM_GATE_1_GRAY, -1, -1
6085 Xfake_door_2, TRUE, FALSE,
6086 EL_EM_GATE_2_GRAY, -1, -1
6089 Xfake_door_3, TRUE, FALSE,
6090 EL_EM_GATE_3_GRAY, -1, -1
6093 Xfake_door_4, TRUE, FALSE,
6094 EL_EM_GATE_4_GRAY, -1, -1
6097 Xfake_door_5, TRUE, FALSE,
6098 EL_EMC_GATE_5_GRAY, -1, -1
6101 Xfake_door_6, TRUE, FALSE,
6102 EL_EMC_GATE_6_GRAY, -1, -1
6105 Xfake_door_7, TRUE, FALSE,
6106 EL_EMC_GATE_7_GRAY, -1, -1
6109 Xfake_door_8, TRUE, FALSE,
6110 EL_EMC_GATE_8_GRAY, -1, -1
6113 Xfake_acid_1, TRUE, FALSE,
6114 EL_EMC_FAKE_ACID, -1, -1
6117 Xfake_acid_2, FALSE, FALSE,
6118 EL_EMC_FAKE_ACID, -1, -1
6121 Xfake_acid_3, FALSE, FALSE,
6122 EL_EMC_FAKE_ACID, -1, -1
6125 Xfake_acid_4, FALSE, FALSE,
6126 EL_EMC_FAKE_ACID, -1, -1
6129 Xfake_acid_5, FALSE, FALSE,
6130 EL_EMC_FAKE_ACID, -1, -1
6133 Xfake_acid_6, FALSE, FALSE,
6134 EL_EMC_FAKE_ACID, -1, -1
6137 Xfake_acid_7, FALSE, FALSE,
6138 EL_EMC_FAKE_ACID, -1, -1
6141 Xfake_acid_8, FALSE, FALSE,
6142 EL_EMC_FAKE_ACID, -1, -1
6145 Xsteel_1, TRUE, FALSE,
6146 EL_STEELWALL, -1, -1
6149 Xsteel_2, TRUE, FALSE,
6150 EL_EMC_STEELWALL_2, -1, -1
6153 Xsteel_3, TRUE, FALSE,
6154 EL_EMC_STEELWALL_3, -1, -1
6157 Xsteel_4, TRUE, FALSE,
6158 EL_EMC_STEELWALL_4, -1, -1
6161 Xwall_1, TRUE, FALSE,
6165 Xwall_2, TRUE, FALSE,
6166 EL_EMC_WALL_14, -1, -1
6169 Xwall_3, TRUE, FALSE,
6170 EL_EMC_WALL_15, -1, -1
6173 Xwall_4, TRUE, FALSE,
6174 EL_EMC_WALL_16, -1, -1
6177 Xround_wall_1, TRUE, FALSE,
6178 EL_WALL_SLIPPERY, -1, -1
6181 Xround_wall_2, TRUE, FALSE,
6182 EL_EMC_WALL_SLIPPERY_2, -1, -1
6185 Xround_wall_3, TRUE, FALSE,
6186 EL_EMC_WALL_SLIPPERY_3, -1, -1
6189 Xround_wall_4, TRUE, FALSE,
6190 EL_EMC_WALL_SLIPPERY_4, -1, -1
6193 Xdecor_1, TRUE, FALSE,
6194 EL_EMC_WALL_8, -1, -1
6197 Xdecor_2, TRUE, FALSE,
6198 EL_EMC_WALL_6, -1, -1
6201 Xdecor_3, TRUE, FALSE,
6202 EL_EMC_WALL_4, -1, -1
6205 Xdecor_4, TRUE, FALSE,
6206 EL_EMC_WALL_7, -1, -1
6209 Xdecor_5, TRUE, FALSE,
6210 EL_EMC_WALL_5, -1, -1
6213 Xdecor_6, TRUE, FALSE,
6214 EL_EMC_WALL_9, -1, -1
6217 Xdecor_7, TRUE, FALSE,
6218 EL_EMC_WALL_10, -1, -1
6221 Xdecor_8, TRUE, FALSE,
6222 EL_EMC_WALL_1, -1, -1
6225 Xdecor_9, TRUE, FALSE,
6226 EL_EMC_WALL_2, -1, -1
6229 Xdecor_10, TRUE, FALSE,
6230 EL_EMC_WALL_3, -1, -1
6233 Xdecor_11, TRUE, FALSE,
6234 EL_EMC_WALL_11, -1, -1
6237 Xdecor_12, TRUE, FALSE,
6238 EL_EMC_WALL_12, -1, -1
6241 Xalpha_0, TRUE, FALSE,
6242 EL_CHAR('0'), -1, -1
6245 Xalpha_1, TRUE, FALSE,
6246 EL_CHAR('1'), -1, -1
6249 Xalpha_2, TRUE, FALSE,
6250 EL_CHAR('2'), -1, -1
6253 Xalpha_3, TRUE, FALSE,
6254 EL_CHAR('3'), -1, -1
6257 Xalpha_4, TRUE, FALSE,
6258 EL_CHAR('4'), -1, -1
6261 Xalpha_5, TRUE, FALSE,
6262 EL_CHAR('5'), -1, -1
6265 Xalpha_6, TRUE, FALSE,
6266 EL_CHAR('6'), -1, -1
6269 Xalpha_7, TRUE, FALSE,
6270 EL_CHAR('7'), -1, -1
6273 Xalpha_8, TRUE, FALSE,
6274 EL_CHAR('8'), -1, -1
6277 Xalpha_9, TRUE, FALSE,
6278 EL_CHAR('9'), -1, -1
6281 Xalpha_excla, TRUE, FALSE,
6282 EL_CHAR('!'), -1, -1
6285 Xalpha_quote, TRUE, FALSE,
6286 EL_CHAR('"'), -1, -1
6289 Xalpha_comma, TRUE, FALSE,
6290 EL_CHAR(','), -1, -1
6293 Xalpha_minus, TRUE, FALSE,
6294 EL_CHAR('-'), -1, -1
6297 Xalpha_perio, TRUE, FALSE,
6298 EL_CHAR('.'), -1, -1
6301 Xalpha_colon, TRUE, FALSE,
6302 EL_CHAR(':'), -1, -1
6305 Xalpha_quest, TRUE, FALSE,
6306 EL_CHAR('?'), -1, -1
6309 Xalpha_a, TRUE, FALSE,
6310 EL_CHAR('A'), -1, -1
6313 Xalpha_b, TRUE, FALSE,
6314 EL_CHAR('B'), -1, -1
6317 Xalpha_c, TRUE, FALSE,
6318 EL_CHAR('C'), -1, -1
6321 Xalpha_d, TRUE, FALSE,
6322 EL_CHAR('D'), -1, -1
6325 Xalpha_e, TRUE, FALSE,
6326 EL_CHAR('E'), -1, -1
6329 Xalpha_f, TRUE, FALSE,
6330 EL_CHAR('F'), -1, -1
6333 Xalpha_g, TRUE, FALSE,
6334 EL_CHAR('G'), -1, -1
6337 Xalpha_h, TRUE, FALSE,
6338 EL_CHAR('H'), -1, -1
6341 Xalpha_i, TRUE, FALSE,
6342 EL_CHAR('I'), -1, -1
6345 Xalpha_j, TRUE, FALSE,
6346 EL_CHAR('J'), -1, -1
6349 Xalpha_k, TRUE, FALSE,
6350 EL_CHAR('K'), -1, -1
6353 Xalpha_l, TRUE, FALSE,
6354 EL_CHAR('L'), -1, -1
6357 Xalpha_m, TRUE, FALSE,
6358 EL_CHAR('M'), -1, -1
6361 Xalpha_n, TRUE, FALSE,
6362 EL_CHAR('N'), -1, -1
6365 Xalpha_o, TRUE, FALSE,
6366 EL_CHAR('O'), -1, -1
6369 Xalpha_p, TRUE, FALSE,
6370 EL_CHAR('P'), -1, -1
6373 Xalpha_q, TRUE, FALSE,
6374 EL_CHAR('Q'), -1, -1
6377 Xalpha_r, TRUE, FALSE,
6378 EL_CHAR('R'), -1, -1
6381 Xalpha_s, TRUE, FALSE,
6382 EL_CHAR('S'), -1, -1
6385 Xalpha_t, TRUE, FALSE,
6386 EL_CHAR('T'), -1, -1
6389 Xalpha_u, TRUE, FALSE,
6390 EL_CHAR('U'), -1, -1
6393 Xalpha_v, TRUE, FALSE,
6394 EL_CHAR('V'), -1, -1
6397 Xalpha_w, TRUE, FALSE,
6398 EL_CHAR('W'), -1, -1
6401 Xalpha_x, TRUE, FALSE,
6402 EL_CHAR('X'), -1, -1
6405 Xalpha_y, TRUE, FALSE,
6406 EL_CHAR('Y'), -1, -1
6409 Xalpha_z, TRUE, FALSE,
6410 EL_CHAR('Z'), -1, -1
6413 Xalpha_arrow_e, TRUE, FALSE,
6414 EL_CHAR('>'), -1, -1
6417 Xalpha_arrow_w, TRUE, FALSE,
6418 EL_CHAR('<'), -1, -1
6421 Xalpha_copyr, TRUE, FALSE,
6422 EL_CHAR(CHAR_BYTE_COPYRIGHT), -1, -1
6426 Xboom_bug, FALSE, FALSE,
6427 EL_BUG, ACTION_EXPLODING, -1
6430 Xboom_bomb, FALSE, FALSE,
6431 EL_BOMB, ACTION_EXPLODING, -1
6434 Xboom_android, FALSE, FALSE,
6435 EL_EMC_ANDROID, ACTION_OTHER, -1
6438 Xboom_1, FALSE, FALSE,
6439 EL_DEFAULT, ACTION_EXPLODING, -1
6442 Xboom_2, FALSE, FALSE,
6443 EL_DEFAULT, ACTION_EXPLODING, -1
6446 Znormal, FALSE, FALSE,
6450 Zdynamite, FALSE, FALSE,
6454 Zplayer, FALSE, FALSE,
6458 ZBORDER, FALSE, FALSE,
6468 static struct Mapping_EM_to_RND_player
6477 em_player_mapping_list[] =
6481 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
6485 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
6489 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
6493 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
6497 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
6501 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
6505 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
6509 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
6513 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
6517 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
6521 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
6525 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
6529 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
6533 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
6537 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
6541 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
6545 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
6549 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
6553 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
6557 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
6561 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
6565 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
6569 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
6573 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
6577 EL_PLAYER_1, ACTION_DEFAULT, -1,
6581 EL_PLAYER_2, ACTION_DEFAULT, -1,
6585 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
6589 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
6593 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
6597 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
6601 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
6605 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
6609 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
6613 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
6617 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
6621 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
6625 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
6629 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
6633 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
6637 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
6641 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
6645 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
6649 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
6653 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
6657 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
6661 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
6665 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
6669 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
6673 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
6677 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
6681 EL_PLAYER_3, ACTION_DEFAULT, -1,
6685 EL_PLAYER_4, ACTION_DEFAULT, -1,
6694 int map_element_RND_to_EM(int element_rnd)
6696 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
6697 static boolean mapping_initialized = FALSE;
6699 if (!mapping_initialized)
6703 /* return "Xalpha_quest" for all undefined elements in mapping array */
6704 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
6705 mapping_RND_to_EM[i] = Xalpha_quest;
6707 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6708 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
6709 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
6710 em_object_mapping_list[i].element_em;
6712 mapping_initialized = TRUE;
6715 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
6716 return mapping_RND_to_EM[element_rnd];
6718 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
6723 int map_element_EM_to_RND(int element_em)
6725 static unsigned short mapping_EM_to_RND[TILE_MAX];
6726 static boolean mapping_initialized = FALSE;
6728 if (!mapping_initialized)
6732 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
6733 for (i = 0; i < TILE_MAX; i++)
6734 mapping_EM_to_RND[i] = EL_UNKNOWN;
6736 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6737 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
6738 em_object_mapping_list[i].element_rnd;
6740 mapping_initialized = TRUE;
6743 if (element_em >= 0 && element_em < TILE_MAX)
6744 return mapping_EM_to_RND[element_em];
6746 Error(ERR_WARN, "invalid EM level element %d", element_em);
6751 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
6753 struct LevelInfo_EM *level_em = level->native_em_level;
6754 struct LEVEL *lev = level_em->lev;
6757 for (i = 0; i < TILE_MAX; i++)
6758 lev->android_array[i] = Xblank;
6760 for (i = 0; i < level->num_android_clone_elements; i++)
6762 int element_rnd = level->android_clone_element[i];
6763 int element_em = map_element_RND_to_EM(element_rnd);
6765 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
6766 if (em_object_mapping_list[j].element_rnd == element_rnd)
6767 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
6771 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
6773 struct LevelInfo_EM *level_em = level->native_em_level;
6774 struct LEVEL *lev = level_em->lev;
6777 level->num_android_clone_elements = 0;
6779 for (i = 0; i < TILE_MAX; i++)
6781 int element_em = lev->android_array[i];
6783 boolean element_found = FALSE;
6785 if (element_em == Xblank)
6788 element_rnd = map_element_EM_to_RND(element_em);
6790 for (j = 0; j < level->num_android_clone_elements; j++)
6791 if (level->android_clone_element[j] == element_rnd)
6792 element_found = TRUE;
6796 level->android_clone_element[level->num_android_clone_elements++] =
6799 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
6804 if (level->num_android_clone_elements == 0)
6806 level->num_android_clone_elements = 1;
6807 level->android_clone_element[0] = EL_EMPTY;
6811 int map_direction_RND_to_EM(int direction)
6813 return (direction == MV_UP ? 0 :
6814 direction == MV_RIGHT ? 1 :
6815 direction == MV_DOWN ? 2 :
6816 direction == MV_LEFT ? 3 :
6820 int map_direction_EM_to_RND(int direction)
6822 return (direction == 0 ? MV_UP :
6823 direction == 1 ? MV_RIGHT :
6824 direction == 2 ? MV_DOWN :
6825 direction == 3 ? MV_LEFT :
6829 int map_element_RND_to_SP(int element_rnd)
6831 int element_sp = 0x20; /* map unknown elements to yellow "hardware" */
6833 if (element_rnd >= EL_SP_START &&
6834 element_rnd <= EL_SP_END)
6835 element_sp = element_rnd - EL_SP_START;
6836 else if (element_rnd == EL_EMPTY_SPACE)
6838 else if (element_rnd == EL_INVISIBLE_WALL)
6844 int map_element_SP_to_RND(int element_sp)
6846 int element_rnd = EL_UNKNOWN;
6848 if (element_sp >= 0x00 &&
6850 element_rnd = EL_SP_START + element_sp;
6851 else if (element_sp == 0x28)
6852 element_rnd = EL_INVISIBLE_WALL;
6857 int map_action_SP_to_RND(int action_sp)
6861 case actActive: return ACTION_ACTIVE;
6862 case actImpact: return ACTION_IMPACT;
6863 case actExploding: return ACTION_EXPLODING;
6864 case actDigging: return ACTION_DIGGING;
6865 case actSnapping: return ACTION_SNAPPING;
6866 case actCollecting: return ACTION_COLLECTING;
6867 case actPassing: return ACTION_PASSING;
6868 case actPushing: return ACTION_PUSHING;
6869 case actDropping: return ACTION_DROPPING;
6871 default: return ACTION_DEFAULT;
6875 int get_next_element(int element)
6879 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
6880 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
6881 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
6882 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
6883 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
6884 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
6885 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
6886 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
6887 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
6888 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
6889 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
6891 default: return element;
6895 int el_act_dir2img(int element, int action, int direction)
6897 element = GFX_ELEMENT(element);
6898 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
6900 /* direction_graphic[][] == graphic[] for undefined direction graphics */
6901 return element_info[element].direction_graphic[action][direction];
6904 static int el_act_dir2crm(int element, int action, int direction)
6906 element = GFX_ELEMENT(element);
6907 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
6909 /* direction_graphic[][] == graphic[] for undefined direction graphics */
6910 return element_info[element].direction_crumbled[action][direction];
6913 int el_act2img(int element, int action)
6915 element = GFX_ELEMENT(element);
6917 return element_info[element].graphic[action];
6920 int el_act2crm(int element, int action)
6922 element = GFX_ELEMENT(element);
6924 return element_info[element].crumbled[action];
6927 int el_dir2img(int element, int direction)
6929 element = GFX_ELEMENT(element);
6931 return el_act_dir2img(element, ACTION_DEFAULT, direction);
6934 int el2baseimg(int element)
6936 return element_info[element].graphic[ACTION_DEFAULT];
6939 int el2img(int element)
6941 element = GFX_ELEMENT(element);
6943 return element_info[element].graphic[ACTION_DEFAULT];
6946 int el2edimg(int element)
6948 element = GFX_ELEMENT(element);
6950 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
6953 int el2preimg(int element)
6955 element = GFX_ELEMENT(element);
6957 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
6960 int el2panelimg(int element)
6962 element = GFX_ELEMENT(element);
6964 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL];
6967 int font2baseimg(int font_nr)
6969 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
6972 int getBeltNrFromBeltElement(int element)
6974 return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
6975 element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
6976 element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
6979 int getBeltNrFromBeltActiveElement(int element)
6981 return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
6982 element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
6983 element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
6986 int getBeltNrFromBeltSwitchElement(int element)
6988 return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
6989 element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
6990 element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
6993 int getBeltDirNrFromBeltElement(int element)
6995 static int belt_base_element[4] =
6997 EL_CONVEYOR_BELT_1_LEFT,
6998 EL_CONVEYOR_BELT_2_LEFT,
6999 EL_CONVEYOR_BELT_3_LEFT,
7000 EL_CONVEYOR_BELT_4_LEFT
7003 int belt_nr = getBeltNrFromBeltElement(element);
7004 int belt_dir_nr = element - belt_base_element[belt_nr];
7006 return (belt_dir_nr % 3);
7009 int getBeltDirNrFromBeltSwitchElement(int element)
7011 static int belt_base_element[4] =
7013 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
7014 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
7015 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
7016 EL_CONVEYOR_BELT_4_SWITCH_LEFT
7019 int belt_nr = getBeltNrFromBeltSwitchElement(element);
7020 int belt_dir_nr = element - belt_base_element[belt_nr];
7022 return (belt_dir_nr % 3);
7025 int getBeltDirFromBeltElement(int element)
7027 static int belt_move_dir[3] =
7034 int belt_dir_nr = getBeltDirNrFromBeltElement(element);
7036 return belt_move_dir[belt_dir_nr];
7039 int getBeltDirFromBeltSwitchElement(int element)
7041 static int belt_move_dir[3] =
7048 int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
7050 return belt_move_dir[belt_dir_nr];
7053 int getBeltElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
7055 static int belt_base_element[4] =
7057 EL_CONVEYOR_BELT_1_LEFT,
7058 EL_CONVEYOR_BELT_2_LEFT,
7059 EL_CONVEYOR_BELT_3_LEFT,
7060 EL_CONVEYOR_BELT_4_LEFT
7063 return belt_base_element[belt_nr] + belt_dir_nr;
7066 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
7068 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
7070 return getBeltElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
7073 int getBeltSwitchElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
7075 static int belt_base_element[4] =
7077 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
7078 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
7079 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
7080 EL_CONVEYOR_BELT_4_SWITCH_LEFT
7083 return belt_base_element[belt_nr] + belt_dir_nr;
7086 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
7088 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
7090 return getBeltSwitchElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
7093 boolean getTeamMode_EM()
7095 return game.team_mode;
7098 int getGameFrameDelay_EM(int native_em_game_frame_delay)
7100 int game_frame_delay_value;
7102 game_frame_delay_value =
7103 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
7104 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
7107 if (tape.playing && tape.warp_forward && !tape.pausing)
7108 game_frame_delay_value = 0;
7110 return game_frame_delay_value;
7113 unsigned int InitRND(int seed)
7115 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
7116 return InitEngineRandom_EM(seed);
7117 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
7118 return InitEngineRandom_SP(seed);
7120 return InitEngineRandom_RND(seed);
7123 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
7124 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
7126 inline static int get_effective_element_EM(int tile, int frame_em)
7128 int element = object_mapping[tile].element_rnd;
7129 int action = object_mapping[tile].action;
7130 boolean is_backside = object_mapping[tile].is_backside;
7131 boolean action_removing = (action == ACTION_DIGGING ||
7132 action == ACTION_SNAPPING ||
7133 action == ACTION_COLLECTING);
7139 case Yacid_splash_eB:
7140 case Yacid_splash_wB:
7141 return (frame_em > 5 ? EL_EMPTY : element);
7147 else /* frame_em == 7 */
7151 case Yacid_splash_eB:
7152 case Yacid_splash_wB:
7155 case Yemerald_stone:
7158 case Ydiamond_stone:
7162 case Xdrip_stretchB:
7181 case Xsand_stonein_1:
7182 case Xsand_stonein_2:
7183 case Xsand_stonein_3:
7184 case Xsand_stonein_4:
7188 return (is_backside || action_removing ? EL_EMPTY : element);
7193 inline static boolean check_linear_animation_EM(int tile)
7197 case Xsand_stonesand_1:
7198 case Xsand_stonesand_quickout_1:
7199 case Xsand_sandstone_1:
7200 case Xsand_stonein_1:
7201 case Xsand_stoneout_1:
7220 case Yacid_splash_eB:
7221 case Yacid_splash_wB:
7222 case Yemerald_stone:
7229 inline static void set_crumbled_graphics_EM(struct GraphicInfo_EM *g_em,
7230 boolean has_crumbled_graphics,
7231 int crumbled, int sync_frame)
7233 /* if element can be crumbled, but certain action graphics are just empty
7234 space (like instantly snapping sand to empty space in 1 frame), do not
7235 treat these empty space graphics as crumbled graphics in EMC engine */
7236 if (crumbled == IMG_EMPTY_SPACE)
7237 has_crumbled_graphics = FALSE;
7239 if (has_crumbled_graphics)
7241 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
7242 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
7243 g_crumbled->anim_delay,
7244 g_crumbled->anim_mode,
7245 g_crumbled->anim_start_frame,
7248 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
7249 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
7251 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
7253 g_em->has_crumbled_graphics = TRUE;
7257 g_em->crumbled_bitmap = NULL;
7258 g_em->crumbled_src_x = 0;
7259 g_em->crumbled_src_y = 0;
7260 g_em->crumbled_border_size = 0;
7262 g_em->has_crumbled_graphics = FALSE;
7266 void ResetGfxAnimation_EM(int x, int y, int tile)
7271 void SetGfxAnimation_EM(struct GraphicInfo_EM *g_em,
7272 int tile, int frame_em, int x, int y)
7274 int action = object_mapping[tile].action;
7275 int direction = object_mapping[tile].direction;
7276 int effective_element = get_effective_element_EM(tile, frame_em);
7277 int graphic = (direction == MV_NONE ?
7278 el_act2img(effective_element, action) :
7279 el_act_dir2img(effective_element, action, direction));
7280 struct GraphicInfo *g = &graphic_info[graphic];
7282 boolean action_removing = (action == ACTION_DIGGING ||
7283 action == ACTION_SNAPPING ||
7284 action == ACTION_COLLECTING);
7285 boolean action_moving = (action == ACTION_FALLING ||
7286 action == ACTION_MOVING ||
7287 action == ACTION_PUSHING ||
7288 action == ACTION_EATING ||
7289 action == ACTION_FILLING ||
7290 action == ACTION_EMPTYING);
7291 boolean action_falling = (action == ACTION_FALLING ||
7292 action == ACTION_FILLING ||
7293 action == ACTION_EMPTYING);
7295 /* special case: graphic uses "2nd movement tile" and has defined
7296 7 frames for movement animation (or less) => use default graphic
7297 for last (8th) frame which ends the movement animation */
7298 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
7300 action = ACTION_DEFAULT; /* (keep action_* unchanged for now) */
7301 graphic = (direction == MV_NONE ?
7302 el_act2img(effective_element, action) :
7303 el_act_dir2img(effective_element, action, direction));
7305 g = &graphic_info[graphic];
7308 if ((action_removing || check_linear_animation_EM(tile)) && frame_em == 0)
7312 else if (action_moving)
7314 boolean is_backside = object_mapping[tile].is_backside;
7318 int direction = object_mapping[tile].direction;
7319 int move_dir = (action_falling ? MV_DOWN : direction);
7324 /* !!! TEST !!! NEW !!! DOES NOT WORK RIGHT YET !!! */
7325 if (g->double_movement && frame_em == 0)
7329 if (move_dir == MV_LEFT)
7330 GfxFrame[x - 1][y] = GfxFrame[x][y];
7331 else if (move_dir == MV_RIGHT)
7332 GfxFrame[x + 1][y] = GfxFrame[x][y];
7333 else if (move_dir == MV_UP)
7334 GfxFrame[x][y - 1] = GfxFrame[x][y];
7335 else if (move_dir == MV_DOWN)
7336 GfxFrame[x][y + 1] = GfxFrame[x][y];
7343 /* special case: animation for Xsand_stonesand_quickout_1/2 twice as fast */
7344 if (tile == Xsand_stonesand_quickout_1 ||
7345 tile == Xsand_stonesand_quickout_2)
7349 if (graphic_info[graphic].anim_global_sync)
7350 sync_frame = FrameCounter;
7351 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
7352 sync_frame = GfxFrame[x][y];
7354 sync_frame = 0; /* playfield border (pseudo steel) */
7356 SetRandomAnimationValue(x, y);
7358 int frame = getAnimationFrame(g->anim_frames,
7361 g->anim_start_frame,
7364 g_em->unique_identifier =
7365 (graphic << 16) | ((frame % 8) << 12) | (g_em->width << 6) | g_em->height;
7368 void getGraphicSourceObjectExt_EM(struct GraphicInfo_EM *g_em,
7369 int tile, int frame_em, int x, int y)
7371 int action = object_mapping[tile].action;
7372 int direction = object_mapping[tile].direction;
7373 boolean is_backside = object_mapping[tile].is_backside;
7374 int effective_element = get_effective_element_EM(tile, frame_em);
7375 int effective_action = action;
7376 int graphic = (direction == MV_NONE ?
7377 el_act2img(effective_element, effective_action) :
7378 el_act_dir2img(effective_element, effective_action,
7380 int crumbled = (direction == MV_NONE ?
7381 el_act2crm(effective_element, effective_action) :
7382 el_act_dir2crm(effective_element, effective_action,
7384 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7385 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7386 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7387 struct GraphicInfo *g = &graphic_info[graphic];
7390 /* special case: graphic uses "2nd movement tile" and has defined
7391 7 frames for movement animation (or less) => use default graphic
7392 for last (8th) frame which ends the movement animation */
7393 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
7395 effective_action = ACTION_DEFAULT;
7396 graphic = (direction == MV_NONE ?
7397 el_act2img(effective_element, effective_action) :
7398 el_act_dir2img(effective_element, effective_action,
7400 crumbled = (direction == MV_NONE ?
7401 el_act2crm(effective_element, effective_action) :
7402 el_act_dir2crm(effective_element, effective_action,
7405 g = &graphic_info[graphic];
7408 if (graphic_info[graphic].anim_global_sync)
7409 sync_frame = FrameCounter;
7410 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
7411 sync_frame = GfxFrame[x][y];
7413 sync_frame = 0; /* playfield border (pseudo steel) */
7415 SetRandomAnimationValue(x, y);
7417 int frame = getAnimationFrame(g->anim_frames,
7420 g->anim_start_frame,
7423 getGraphicSourceExt(graphic, frame, &g_em->bitmap, &g_em->src_x, &g_em->src_y,
7424 g->double_movement && is_backside);
7426 /* (updating the "crumbled" graphic definitions is probably not really needed,
7427 as animations for crumbled graphics can't be longer than one EMC cycle) */
7428 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
7432 void getGraphicSourcePlayerExt_EM(struct GraphicInfo_EM *g_em,
7433 int player_nr, int anim, int frame_em)
7435 int element = player_mapping[player_nr][anim].element_rnd;
7436 int action = player_mapping[player_nr][anim].action;
7437 int direction = player_mapping[player_nr][anim].direction;
7438 int graphic = (direction == MV_NONE ?
7439 el_act2img(element, action) :
7440 el_act_dir2img(element, action, direction));
7441 struct GraphicInfo *g = &graphic_info[graphic];
7444 InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
7446 stored_player[player_nr].StepFrame = frame_em;
7448 sync_frame = stored_player[player_nr].Frame;
7450 int frame = getAnimationFrame(g->anim_frames,
7453 g->anim_start_frame,
7456 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
7457 &g_em->src_x, &g_em->src_y, FALSE);
7460 void InitGraphicInfo_EM(void)
7465 int num_em_gfx_errors = 0;
7467 if (graphic_info_em_object[0][0].bitmap == NULL)
7469 /* EM graphics not yet initialized in em_open_all() */
7474 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
7477 /* always start with reliable default values */
7478 for (i = 0; i < TILE_MAX; i++)
7480 object_mapping[i].element_rnd = EL_UNKNOWN;
7481 object_mapping[i].is_backside = FALSE;
7482 object_mapping[i].action = ACTION_DEFAULT;
7483 object_mapping[i].direction = MV_NONE;
7486 /* always start with reliable default values */
7487 for (p = 0; p < MAX_PLAYERS; p++)
7489 for (i = 0; i < SPR_MAX; i++)
7491 player_mapping[p][i].element_rnd = EL_UNKNOWN;
7492 player_mapping[p][i].action = ACTION_DEFAULT;
7493 player_mapping[p][i].direction = MV_NONE;
7497 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
7499 int e = em_object_mapping_list[i].element_em;
7501 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
7502 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
7504 if (em_object_mapping_list[i].action != -1)
7505 object_mapping[e].action = em_object_mapping_list[i].action;
7507 if (em_object_mapping_list[i].direction != -1)
7508 object_mapping[e].direction =
7509 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
7512 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
7514 int a = em_player_mapping_list[i].action_em;
7515 int p = em_player_mapping_list[i].player_nr;
7517 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
7519 if (em_player_mapping_list[i].action != -1)
7520 player_mapping[p][a].action = em_player_mapping_list[i].action;
7522 if (em_player_mapping_list[i].direction != -1)
7523 player_mapping[p][a].direction =
7524 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
7527 for (i = 0; i < TILE_MAX; i++)
7529 int element = object_mapping[i].element_rnd;
7530 int action = object_mapping[i].action;
7531 int direction = object_mapping[i].direction;
7532 boolean is_backside = object_mapping[i].is_backside;
7533 boolean action_exploding = ((action == ACTION_EXPLODING ||
7534 action == ACTION_SMASHED_BY_ROCK ||
7535 action == ACTION_SMASHED_BY_SPRING) &&
7536 element != EL_DIAMOND);
7537 boolean action_active = (action == ACTION_ACTIVE);
7538 boolean action_other = (action == ACTION_OTHER);
7540 for (j = 0; j < 8; j++)
7542 int effective_element = get_effective_element_EM(i, j);
7543 int effective_action = (j < 7 ? action :
7544 i == Xdrip_stretch ? action :
7545 i == Xdrip_stretchB ? action :
7546 i == Ydrip_s1 ? action :
7547 i == Ydrip_s1B ? action :
7548 i == Xball_1B ? action :
7549 i == Xball_2 ? action :
7550 i == Xball_2B ? action :
7551 i == Yball_eat ? action :
7552 i == Ykey_1_eat ? action :
7553 i == Ykey_2_eat ? action :
7554 i == Ykey_3_eat ? action :
7555 i == Ykey_4_eat ? action :
7556 i == Ykey_5_eat ? action :
7557 i == Ykey_6_eat ? action :
7558 i == Ykey_7_eat ? action :
7559 i == Ykey_8_eat ? action :
7560 i == Ylenses_eat ? action :
7561 i == Ymagnify_eat ? action :
7562 i == Ygrass_eat ? action :
7563 i == Ydirt_eat ? action :
7564 i == Xsand_stonein_1 ? action :
7565 i == Xsand_stonein_2 ? action :
7566 i == Xsand_stonein_3 ? action :
7567 i == Xsand_stonein_4 ? action :
7568 i == Xsand_stoneout_1 ? action :
7569 i == Xsand_stoneout_2 ? action :
7570 i == Xboom_android ? ACTION_EXPLODING :
7571 action_exploding ? ACTION_EXPLODING :
7572 action_active ? action :
7573 action_other ? action :
7575 int graphic = (el_act_dir2img(effective_element, effective_action,
7577 int crumbled = (el_act_dir2crm(effective_element, effective_action,
7579 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7580 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7581 boolean has_action_graphics = (graphic != base_graphic);
7582 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7583 struct GraphicInfo *g = &graphic_info[graphic];
7584 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7587 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
7588 boolean special_animation = (action != ACTION_DEFAULT &&
7589 g->anim_frames == 3 &&
7590 g->anim_delay == 2 &&
7591 g->anim_mode & ANIM_LINEAR);
7592 int sync_frame = (i == Xdrip_stretch ? 7 :
7593 i == Xdrip_stretchB ? 7 :
7594 i == Ydrip_s2 ? j + 8 :
7595 i == Ydrip_s2B ? j + 8 :
7604 i == Xfake_acid_1 ? 0 :
7605 i == Xfake_acid_2 ? 10 :
7606 i == Xfake_acid_3 ? 20 :
7607 i == Xfake_acid_4 ? 30 :
7608 i == Xfake_acid_5 ? 40 :
7609 i == Xfake_acid_6 ? 50 :
7610 i == Xfake_acid_7 ? 60 :
7611 i == Xfake_acid_8 ? 70 :
7613 i == Xball_2B ? j + 8 :
7614 i == Yball_eat ? j + 1 :
7615 i == Ykey_1_eat ? j + 1 :
7616 i == Ykey_2_eat ? j + 1 :
7617 i == Ykey_3_eat ? j + 1 :
7618 i == Ykey_4_eat ? j + 1 :
7619 i == Ykey_5_eat ? j + 1 :
7620 i == Ykey_6_eat ? j + 1 :
7621 i == Ykey_7_eat ? j + 1 :
7622 i == Ykey_8_eat ? j + 1 :
7623 i == Ylenses_eat ? j + 1 :
7624 i == Ymagnify_eat ? j + 1 :
7625 i == Ygrass_eat ? j + 1 :
7626 i == Ydirt_eat ? j + 1 :
7627 i == Xamoeba_1 ? 0 :
7628 i == Xamoeba_2 ? 1 :
7629 i == Xamoeba_3 ? 2 :
7630 i == Xamoeba_4 ? 3 :
7631 i == Xamoeba_5 ? 0 :
7632 i == Xamoeba_6 ? 1 :
7633 i == Xamoeba_7 ? 2 :
7634 i == Xamoeba_8 ? 3 :
7635 i == Xexit_2 ? j + 8 :
7636 i == Xexit_3 ? j + 16 :
7637 i == Xdynamite_1 ? 0 :
7638 i == Xdynamite_2 ? 8 :
7639 i == Xdynamite_3 ? 16 :
7640 i == Xdynamite_4 ? 24 :
7641 i == Xsand_stonein_1 ? j + 1 :
7642 i == Xsand_stonein_2 ? j + 9 :
7643 i == Xsand_stonein_3 ? j + 17 :
7644 i == Xsand_stonein_4 ? j + 25 :
7645 i == Xsand_stoneout_1 && j == 0 ? 0 :
7646 i == Xsand_stoneout_1 && j == 1 ? 0 :
7647 i == Xsand_stoneout_1 && j == 2 ? 1 :
7648 i == Xsand_stoneout_1 && j == 3 ? 2 :
7649 i == Xsand_stoneout_1 && j == 4 ? 2 :
7650 i == Xsand_stoneout_1 && j == 5 ? 3 :
7651 i == Xsand_stoneout_1 && j == 6 ? 4 :
7652 i == Xsand_stoneout_1 && j == 7 ? 4 :
7653 i == Xsand_stoneout_2 && j == 0 ? 5 :
7654 i == Xsand_stoneout_2 && j == 1 ? 6 :
7655 i == Xsand_stoneout_2 && j == 2 ? 7 :
7656 i == Xsand_stoneout_2 && j == 3 ? 8 :
7657 i == Xsand_stoneout_2 && j == 4 ? 9 :
7658 i == Xsand_stoneout_2 && j == 5 ? 11 :
7659 i == Xsand_stoneout_2 && j == 6 ? 13 :
7660 i == Xsand_stoneout_2 && j == 7 ? 15 :
7661 i == Xboom_bug && j == 1 ? 2 :
7662 i == Xboom_bug && j == 2 ? 2 :
7663 i == Xboom_bug && j == 3 ? 4 :
7664 i == Xboom_bug && j == 4 ? 4 :
7665 i == Xboom_bug && j == 5 ? 2 :
7666 i == Xboom_bug && j == 6 ? 2 :
7667 i == Xboom_bug && j == 7 ? 0 :
7668 i == Xboom_bomb && j == 1 ? 2 :
7669 i == Xboom_bomb && j == 2 ? 2 :
7670 i == Xboom_bomb && j == 3 ? 4 :
7671 i == Xboom_bomb && j == 4 ? 4 :
7672 i == Xboom_bomb && j == 5 ? 2 :
7673 i == Xboom_bomb && j == 6 ? 2 :
7674 i == Xboom_bomb && j == 7 ? 0 :
7675 i == Xboom_android && j == 7 ? 6 :
7676 i == Xboom_1 && j == 1 ? 2 :
7677 i == Xboom_1 && j == 2 ? 2 :
7678 i == Xboom_1 && j == 3 ? 4 :
7679 i == Xboom_1 && j == 4 ? 4 :
7680 i == Xboom_1 && j == 5 ? 6 :
7681 i == Xboom_1 && j == 6 ? 6 :
7682 i == Xboom_1 && j == 7 ? 8 :
7683 i == Xboom_2 && j == 0 ? 8 :
7684 i == Xboom_2 && j == 1 ? 8 :
7685 i == Xboom_2 && j == 2 ? 10 :
7686 i == Xboom_2 && j == 3 ? 10 :
7687 i == Xboom_2 && j == 4 ? 10 :
7688 i == Xboom_2 && j == 5 ? 12 :
7689 i == Xboom_2 && j == 6 ? 12 :
7690 i == Xboom_2 && j == 7 ? 12 :
7691 special_animation && j == 4 ? 3 :
7692 effective_action != action ? 0 :
7696 Bitmap *debug_bitmap = g_em->bitmap;
7697 int debug_src_x = g_em->src_x;
7698 int debug_src_y = g_em->src_y;
7701 int frame = getAnimationFrame(g->anim_frames,
7704 g->anim_start_frame,
7707 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
7708 g->double_movement && is_backside);
7710 g_em->bitmap = src_bitmap;
7711 g_em->src_x = src_x;
7712 g_em->src_y = src_y;
7713 g_em->src_offset_x = 0;
7714 g_em->src_offset_y = 0;
7715 g_em->dst_offset_x = 0;
7716 g_em->dst_offset_y = 0;
7717 g_em->width = TILEX;
7718 g_em->height = TILEY;
7720 g_em->preserve_background = FALSE;
7722 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
7725 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
7726 effective_action == ACTION_MOVING ||
7727 effective_action == ACTION_PUSHING ||
7728 effective_action == ACTION_EATING)) ||
7729 (!has_action_graphics && (effective_action == ACTION_FILLING ||
7730 effective_action == ACTION_EMPTYING)))
7733 (effective_action == ACTION_FALLING ||
7734 effective_action == ACTION_FILLING ||
7735 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
7736 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
7737 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
7738 int num_steps = (i == Ydrip_s1 ? 16 :
7739 i == Ydrip_s1B ? 16 :
7740 i == Ydrip_s2 ? 16 :
7741 i == Ydrip_s2B ? 16 :
7742 i == Xsand_stonein_1 ? 32 :
7743 i == Xsand_stonein_2 ? 32 :
7744 i == Xsand_stonein_3 ? 32 :
7745 i == Xsand_stonein_4 ? 32 :
7746 i == Xsand_stoneout_1 ? 16 :
7747 i == Xsand_stoneout_2 ? 16 : 8);
7748 int cx = ABS(dx) * (TILEX / num_steps);
7749 int cy = ABS(dy) * (TILEY / num_steps);
7750 int step_frame = (i == Ydrip_s2 ? j + 8 :
7751 i == Ydrip_s2B ? j + 8 :
7752 i == Xsand_stonein_2 ? j + 8 :
7753 i == Xsand_stonein_3 ? j + 16 :
7754 i == Xsand_stonein_4 ? j + 24 :
7755 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
7756 int step = (is_backside ? step_frame : num_steps - step_frame);
7758 if (is_backside) /* tile where movement starts */
7760 if (dx < 0 || dy < 0)
7762 g_em->src_offset_x = cx * step;
7763 g_em->src_offset_y = cy * step;
7767 g_em->dst_offset_x = cx * step;
7768 g_em->dst_offset_y = cy * step;
7771 else /* tile where movement ends */
7773 if (dx < 0 || dy < 0)
7775 g_em->dst_offset_x = cx * step;
7776 g_em->dst_offset_y = cy * step;
7780 g_em->src_offset_x = cx * step;
7781 g_em->src_offset_y = cy * step;
7785 g_em->width = TILEX - cx * step;
7786 g_em->height = TILEY - cy * step;
7789 /* create unique graphic identifier to decide if tile must be redrawn */
7790 /* bit 31 - 16 (16 bit): EM style graphic
7791 bit 15 - 12 ( 4 bit): EM style frame
7792 bit 11 - 6 ( 6 bit): graphic width
7793 bit 5 - 0 ( 6 bit): graphic height */
7794 g_em->unique_identifier =
7795 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
7799 /* skip check for EMC elements not contained in original EMC artwork */
7800 if (element == EL_EMC_FAKE_ACID)
7803 if (g_em->bitmap != debug_bitmap ||
7804 g_em->src_x != debug_src_x ||
7805 g_em->src_y != debug_src_y ||
7806 g_em->src_offset_x != 0 ||
7807 g_em->src_offset_y != 0 ||
7808 g_em->dst_offset_x != 0 ||
7809 g_em->dst_offset_y != 0 ||
7810 g_em->width != TILEX ||
7811 g_em->height != TILEY)
7813 static int last_i = -1;
7821 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
7822 i, element, element_info[element].token_name,
7823 element_action_info[effective_action].suffix, direction);
7825 if (element != effective_element)
7826 printf(" [%d ('%s')]",
7828 element_info[effective_element].token_name);
7832 if (g_em->bitmap != debug_bitmap)
7833 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
7834 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
7836 if (g_em->src_x != debug_src_x ||
7837 g_em->src_y != debug_src_y)
7838 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
7839 j, (is_backside ? 'B' : 'F'),
7840 g_em->src_x, g_em->src_y,
7841 g_em->src_x / 32, g_em->src_y / 32,
7842 debug_src_x, debug_src_y,
7843 debug_src_x / 32, debug_src_y / 32);
7845 if (g_em->src_offset_x != 0 ||
7846 g_em->src_offset_y != 0 ||
7847 g_em->dst_offset_x != 0 ||
7848 g_em->dst_offset_y != 0)
7849 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
7851 g_em->src_offset_x, g_em->src_offset_y,
7852 g_em->dst_offset_x, g_em->dst_offset_y);
7854 if (g_em->width != TILEX ||
7855 g_em->height != TILEY)
7856 printf(" %d (%d): size %d,%d should be %d,%d\n",
7858 g_em->width, g_em->height, TILEX, TILEY);
7860 num_em_gfx_errors++;
7867 for (i = 0; i < TILE_MAX; i++)
7869 for (j = 0; j < 8; j++)
7871 int element = object_mapping[i].element_rnd;
7872 int action = object_mapping[i].action;
7873 int direction = object_mapping[i].direction;
7874 boolean is_backside = object_mapping[i].is_backside;
7875 int graphic_action = el_act_dir2img(element, action, direction);
7876 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
7878 if ((action == ACTION_SMASHED_BY_ROCK ||
7879 action == ACTION_SMASHED_BY_SPRING ||
7880 action == ACTION_EATING) &&
7881 graphic_action == graphic_default)
7883 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
7884 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
7885 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
7886 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
7889 /* no separate animation for "smashed by rock" -- use rock instead */
7890 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7891 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
7893 g_em->bitmap = g_xx->bitmap;
7894 g_em->src_x = g_xx->src_x;
7895 g_em->src_y = g_xx->src_y;
7896 g_em->src_offset_x = g_xx->src_offset_x;
7897 g_em->src_offset_y = g_xx->src_offset_y;
7898 g_em->dst_offset_x = g_xx->dst_offset_x;
7899 g_em->dst_offset_y = g_xx->dst_offset_y;
7900 g_em->width = g_xx->width;
7901 g_em->height = g_xx->height;
7902 g_em->unique_identifier = g_xx->unique_identifier;
7905 g_em->preserve_background = TRUE;
7910 for (p = 0; p < MAX_PLAYERS; p++)
7912 for (i = 0; i < SPR_MAX; i++)
7914 int element = player_mapping[p][i].element_rnd;
7915 int action = player_mapping[p][i].action;
7916 int direction = player_mapping[p][i].direction;
7918 for (j = 0; j < 8; j++)
7920 int effective_element = element;
7921 int effective_action = action;
7922 int graphic = (direction == MV_NONE ?
7923 el_act2img(effective_element, effective_action) :
7924 el_act_dir2img(effective_element, effective_action,
7926 struct GraphicInfo *g = &graphic_info[graphic];
7927 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
7933 Bitmap *debug_bitmap = g_em->bitmap;
7934 int debug_src_x = g_em->src_x;
7935 int debug_src_y = g_em->src_y;
7938 int frame = getAnimationFrame(g->anim_frames,
7941 g->anim_start_frame,
7944 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
7946 g_em->bitmap = src_bitmap;
7947 g_em->src_x = src_x;
7948 g_em->src_y = src_y;
7949 g_em->src_offset_x = 0;
7950 g_em->src_offset_y = 0;
7951 g_em->dst_offset_x = 0;
7952 g_em->dst_offset_y = 0;
7953 g_em->width = TILEX;
7954 g_em->height = TILEY;
7958 /* skip check for EMC elements not contained in original EMC artwork */
7959 if (element == EL_PLAYER_3 ||
7960 element == EL_PLAYER_4)
7963 if (g_em->bitmap != debug_bitmap ||
7964 g_em->src_x != debug_src_x ||
7965 g_em->src_y != debug_src_y)
7967 static int last_i = -1;
7975 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
7976 p, i, element, element_info[element].token_name,
7977 element_action_info[effective_action].suffix, direction);
7979 if (element != effective_element)
7980 printf(" [%d ('%s')]",
7982 element_info[effective_element].token_name);
7986 if (g_em->bitmap != debug_bitmap)
7987 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
7988 j, (int)(g_em->bitmap), (int)(debug_bitmap));
7990 if (g_em->src_x != debug_src_x ||
7991 g_em->src_y != debug_src_y)
7992 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
7994 g_em->src_x, g_em->src_y,
7995 g_em->src_x / 32, g_em->src_y / 32,
7996 debug_src_x, debug_src_y,
7997 debug_src_x / 32, debug_src_y / 32);
7999 num_em_gfx_errors++;
8009 printf("::: [%d errors found]\n", num_em_gfx_errors);
8015 void CheckSaveEngineSnapshot_EM(byte action[MAX_PLAYERS], int frame,
8016 boolean any_player_moving,
8017 boolean any_player_snapping,
8018 boolean any_player_dropping)
8020 static boolean player_was_waiting = TRUE;
8022 if (frame == 0 && !any_player_dropping)
8024 if (!player_was_waiting)
8026 if (!SaveEngineSnapshotToList())
8029 player_was_waiting = TRUE;
8032 else if (any_player_moving || any_player_snapping || any_player_dropping)
8034 player_was_waiting = FALSE;
8038 void CheckSaveEngineSnapshot_SP(boolean murphy_is_waiting,
8039 boolean murphy_is_dropping)
8041 static boolean player_was_waiting = TRUE;
8043 if (murphy_is_waiting)
8045 if (!player_was_waiting)
8047 if (!SaveEngineSnapshotToList())
8050 player_was_waiting = TRUE;
8055 player_was_waiting = FALSE;
8059 void CheckSingleStepMode_EM(byte action[MAX_PLAYERS], int frame,
8060 boolean any_player_moving,
8061 boolean any_player_snapping,
8062 boolean any_player_dropping)
8064 if (tape.single_step && tape.recording && !tape.pausing)
8065 if (frame == 0 && !any_player_dropping)
8066 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
8068 CheckSaveEngineSnapshot_EM(action, frame, any_player_moving,
8069 any_player_snapping, any_player_dropping);
8072 void CheckSingleStepMode_SP(boolean murphy_is_waiting,
8073 boolean murphy_is_dropping)
8075 if (tape.single_step && tape.recording && !tape.pausing)
8076 if (murphy_is_waiting)
8077 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
8079 CheckSaveEngineSnapshot_SP(murphy_is_waiting, murphy_is_dropping);
8082 void getGraphicSource_SP(struct GraphicInfo_SP *g_sp,
8083 int graphic, int sync_frame, int x, int y)
8085 int frame = getGraphicAnimationFrame(graphic, sync_frame);
8087 getGraphicSource(graphic, frame, &g_sp->bitmap, &g_sp->src_x, &g_sp->src_y);
8090 boolean isNextAnimationFrame_SP(int graphic, int sync_frame)
8092 return (IS_NEXT_FRAME(sync_frame, graphic));
8095 int getGraphicInfo_Delay(int graphic)
8097 return graphic_info[graphic].anim_delay;
8100 void PlayMenuSoundExt(int sound)
8102 if (sound == SND_UNDEFINED)
8105 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8106 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8109 if (IS_LOOP_SOUND(sound))
8110 PlaySoundLoop(sound);
8115 void PlayMenuSound()
8117 PlayMenuSoundExt(menu.sound[game_status]);
8120 void PlayMenuSoundStereo(int sound, int stereo_position)
8122 if (sound == SND_UNDEFINED)
8125 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8126 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8129 if (IS_LOOP_SOUND(sound))
8130 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
8132 PlaySoundStereo(sound, stereo_position);
8135 void PlayMenuSoundIfLoopExt(int sound)
8137 if (sound == SND_UNDEFINED)
8140 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8141 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8144 if (IS_LOOP_SOUND(sound))
8145 PlaySoundLoop(sound);
8148 void PlayMenuSoundIfLoop()
8150 PlayMenuSoundIfLoopExt(menu.sound[game_status]);
8153 void PlayMenuMusicExt(int music)
8155 if (music == MUS_UNDEFINED)
8158 if (!setup.sound_music)
8164 void PlayMenuMusic()
8166 PlayMenuMusicExt(menu.music[game_status]);
8169 void PlaySoundActivating()
8172 PlaySound(SND_MENU_ITEM_ACTIVATING);
8176 void PlaySoundSelecting()
8179 PlaySound(SND_MENU_ITEM_SELECTING);
8183 void ToggleFullscreenOrChangeWindowScalingIfNeeded()
8185 boolean change_fullscreen = (setup.fullscreen !=
8186 video.fullscreen_enabled);
8187 boolean change_window_scaling_percent = (!video.fullscreen_enabled &&
8188 setup.window_scaling_percent !=
8189 video.window_scaling_percent);
8191 if (change_window_scaling_percent && video.fullscreen_enabled)
8194 if (!change_window_scaling_percent && !video.fullscreen_available)
8197 #if defined(TARGET_SDL2)
8198 if (change_window_scaling_percent)
8200 SDLSetWindowScaling(setup.window_scaling_percent);
8204 else if (change_fullscreen)
8206 SDLSetWindowFullscreen(setup.fullscreen);
8208 /* set setup value according to successfully changed fullscreen mode */
8209 setup.fullscreen = video.fullscreen_enabled;
8215 if (change_fullscreen ||
8216 change_window_scaling_percent)
8218 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
8220 /* save backbuffer content which gets lost when toggling fullscreen mode */
8221 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8223 if (change_window_scaling_percent)
8225 /* keep window mode, but change window scaling */
8226 video.fullscreen_enabled = TRUE; /* force new window scaling */
8229 /* toggle fullscreen */
8230 ChangeVideoModeIfNeeded(setup.fullscreen);
8232 /* set setup value according to successfully changed fullscreen mode */
8233 setup.fullscreen = video.fullscreen_enabled;
8235 /* restore backbuffer content from temporary backbuffer backup bitmap */
8236 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8238 FreeBitmap(tmp_backbuffer);
8240 /* update visible window/screen */
8241 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8245 void JoinRectangles(int *x, int *y, int *width, int *height,
8246 int x2, int y2, int width2, int height2)
8248 // do not join with "off-screen" rectangle
8249 if (x2 == -1 || y2 == -1)
8254 *width = MAX(*width, width2);
8255 *height = MAX(*height, height2);
8258 void SetAnimStatus(int anim_status_new)
8260 if (anim_status_new == GAME_MODE_MAIN)
8261 anim_status_new = GAME_MODE_PSEUDO_MAINONLY;
8263 global.anim_status_next = anim_status_new;
8265 // directly set screen modes that are entered without fading
8266 if ((global.anim_status == GAME_MODE_PSEUDO_MAINONLY &&
8267 global.anim_status_next == GAME_MODE_PSEUDO_TYPENAME) ||
8268 (global.anim_status == GAME_MODE_PSEUDO_TYPENAME &&
8269 global.anim_status_next == GAME_MODE_PSEUDO_MAINONLY))
8270 global.anim_status = global.anim_status_next;
8273 void SetGameStatus(int game_status_new)
8275 game_status = game_status_new;
8277 SetAnimStatus(game_status_new);
8280 void SetFontStatus(int game_status_new)
8282 static int last_game_status = -1;
8284 if (game_status_new != -1)
8286 // set game status for font use after storing last game status
8287 last_game_status = game_status;
8288 game_status = game_status_new;
8292 // reset game status after font use from last stored game status
8293 game_status = last_game_status;
8297 void ResetFontStatus()
8302 void ChangeViewportPropertiesIfNeeded()
8304 int gfx_game_mode = game_status;
8305 int gfx_game_mode2 = (game_status == GAME_MODE_EDITOR ? GAME_MODE_DEFAULT :
8307 struct RectWithBorder *vp_window = &viewport.window[gfx_game_mode];
8308 struct RectWithBorder *vp_playfield = &viewport.playfield[gfx_game_mode];
8309 struct RectWithBorder *vp_door_1 = &viewport.door_1[gfx_game_mode];
8310 struct RectWithBorder *vp_door_2 = &viewport.door_2[gfx_game_mode2];
8311 struct RectWithBorder *vp_door_3 = &viewport.door_2[GAME_MODE_EDITOR];
8312 int new_win_xsize = vp_window->width;
8313 int new_win_ysize = vp_window->height;
8314 int border_size = vp_playfield->border_size;
8315 int new_sx = vp_playfield->x + border_size;
8316 int new_sy = vp_playfield->y + border_size;
8317 int new_sxsize = vp_playfield->width - 2 * border_size;
8318 int new_sysize = vp_playfield->height - 2 * border_size;
8319 int new_real_sx = vp_playfield->x;
8320 int new_real_sy = vp_playfield->y;
8321 int new_full_sxsize = vp_playfield->width;
8322 int new_full_sysize = vp_playfield->height;
8323 int new_dx = vp_door_1->x;
8324 int new_dy = vp_door_1->y;
8325 int new_dxsize = vp_door_1->width;
8326 int new_dysize = vp_door_1->height;
8327 int new_vx = vp_door_2->x;
8328 int new_vy = vp_door_2->y;
8329 int new_vxsize = vp_door_2->width;
8330 int new_vysize = vp_door_2->height;
8331 int new_ex = vp_door_3->x;
8332 int new_ey = vp_door_3->y;
8333 int new_exsize = vp_door_3->width;
8334 int new_eysize = vp_door_3->height;
8335 int new_tilesize_var =
8336 (setup.small_game_graphics ? MINI_TILESIZE : game.tile_size);
8338 int tilesize = (gfx_game_mode == GAME_MODE_PLAYING ? new_tilesize_var :
8339 gfx_game_mode == GAME_MODE_EDITOR ? MINI_TILESIZE : TILESIZE);
8340 int new_scr_fieldx = new_sxsize / tilesize;
8341 int new_scr_fieldy = new_sysize / tilesize;
8342 int new_scr_fieldx_buffers = new_sxsize / new_tilesize_var;
8343 int new_scr_fieldy_buffers = new_sysize / new_tilesize_var;
8344 boolean init_gfx_buffers = FALSE;
8345 boolean init_video_buffer = FALSE;
8346 boolean init_gadgets_and_anims = FALSE;
8347 boolean init_em_graphics = FALSE;
8349 if (new_win_xsize != WIN_XSIZE ||
8350 new_win_ysize != WIN_YSIZE)
8352 WIN_XSIZE = new_win_xsize;
8353 WIN_YSIZE = new_win_ysize;
8355 init_video_buffer = TRUE;
8356 init_gfx_buffers = TRUE;
8357 init_gadgets_and_anims = TRUE;
8359 // printf("::: video: init_video_buffer, init_gfx_buffers\n");
8362 if (new_scr_fieldx != SCR_FIELDX ||
8363 new_scr_fieldy != SCR_FIELDY)
8365 /* this always toggles between MAIN and GAME when using small tile size */
8367 SCR_FIELDX = new_scr_fieldx;
8368 SCR_FIELDY = new_scr_fieldy;
8370 // printf("::: new_scr_fieldx != SCR_FIELDX ...\n");
8381 new_sxsize != SXSIZE ||
8382 new_sysize != SYSIZE ||
8383 new_dxsize != DXSIZE ||
8384 new_dysize != DYSIZE ||
8385 new_vxsize != VXSIZE ||
8386 new_vysize != VYSIZE ||
8387 new_exsize != EXSIZE ||
8388 new_eysize != EYSIZE ||
8389 new_real_sx != REAL_SX ||
8390 new_real_sy != REAL_SY ||
8391 new_full_sxsize != FULL_SXSIZE ||
8392 new_full_sysize != FULL_SYSIZE ||
8393 new_tilesize_var != TILESIZE_VAR
8396 // ------------------------------------------------------------------------
8397 // determine next fading area for changed viewport definitions
8398 // ------------------------------------------------------------------------
8400 // start with current playfield area (default fading area)
8403 FADE_SXSIZE = FULL_SXSIZE;
8404 FADE_SYSIZE = FULL_SYSIZE;
8406 // add new playfield area if position or size has changed
8407 if (new_real_sx != REAL_SX || new_real_sy != REAL_SY ||
8408 new_full_sxsize != FULL_SXSIZE || new_full_sysize != FULL_SYSIZE)
8410 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
8411 new_real_sx, new_real_sy, new_full_sxsize,new_full_sysize);
8414 // add current and new door 1 area if position or size has changed
8415 if (new_dx != DX || new_dy != DY ||
8416 new_dxsize != DXSIZE || new_dysize != DYSIZE)
8418 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
8419 DX, DY, DXSIZE, DYSIZE);
8420 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
8421 new_dx, new_dy, new_dxsize, new_dysize);
8424 // add current and new door 2 area if position or size has changed
8425 if (new_dx != VX || new_dy != VY ||
8426 new_dxsize != VXSIZE || new_dysize != VYSIZE)
8428 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
8429 VX, VY, VXSIZE, VYSIZE);
8430 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
8431 new_vx, new_vy, new_vxsize, new_vysize);
8434 // ------------------------------------------------------------------------
8435 // handle changed tile size
8436 // ------------------------------------------------------------------------
8438 if (new_tilesize_var != TILESIZE_VAR)
8440 // printf("::: new_tilesize_var != TILESIZE_VAR\n");
8442 // changing tile size invalidates scroll values of engine snapshots
8443 FreeEngineSnapshotSingle();
8445 // changing tile size requires update of graphic mapping for EM engine
8446 init_em_graphics = TRUE;
8457 SXSIZE = new_sxsize;
8458 SYSIZE = new_sysize;
8459 DXSIZE = new_dxsize;
8460 DYSIZE = new_dysize;
8461 VXSIZE = new_vxsize;
8462 VYSIZE = new_vysize;
8463 EXSIZE = new_exsize;
8464 EYSIZE = new_eysize;
8465 REAL_SX = new_real_sx;
8466 REAL_SY = new_real_sy;
8467 FULL_SXSIZE = new_full_sxsize;
8468 FULL_SYSIZE = new_full_sysize;
8469 TILESIZE_VAR = new_tilesize_var;
8471 init_gfx_buffers = TRUE;
8472 init_gadgets_and_anims = TRUE;
8474 // printf("::: viewports: init_gfx_buffers\n");
8475 // printf("::: viewports: init_gadgets_and_anims\n");
8478 if (init_gfx_buffers)
8480 // printf("::: init_gfx_buffers\n");
8482 SCR_FIELDX = new_scr_fieldx_buffers;
8483 SCR_FIELDY = new_scr_fieldy_buffers;
8487 SCR_FIELDX = new_scr_fieldx;
8488 SCR_FIELDY = new_scr_fieldy;
8490 SetDrawDeactivationMask(REDRAW_NONE);
8491 SetDrawBackgroundMask(REDRAW_FIELD);
8494 if (init_video_buffer)
8496 // printf("::: init_video_buffer\n");
8498 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
8499 InitImageTextures();
8502 if (init_gadgets_and_anims)
8504 // printf("::: init_gadgets_and_anims\n");
8507 InitGlobalAnimations();
8510 if (init_em_graphics)
8512 InitGraphicInfo_EM();