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 if (redraw_mask & REDRAW_DOOR_1)
574 BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
576 if (redraw_mask & REDRAW_DOOR_2)
577 BlitBitmap(backbuffer, window, VX, VY, VXSIZE, VYSIZE, VX, VY);
579 if (redraw_mask & REDRAW_DOOR_3)
580 BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
583 redraw_mask = REDRAW_NONE;
586 PrintFrameTimeDebugging();
590 void BackToFront_WithFrameDelay(unsigned int frame_delay_value)
592 unsigned int frame_delay_value_old = GetVideoFrameDelay();
594 SetVideoFrameDelay(frame_delay_value);
598 SetVideoFrameDelay(frame_delay_value_old);
601 static void FadeCrossSaveBackbuffer()
603 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
606 static void FadeCrossRestoreBackbuffer()
608 int redraw_mask_last = redraw_mask;
610 BlitBitmap(bitmap_db_cross, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
612 // do not change redraw mask when restoring backbuffer after cross-fading
613 redraw_mask = redraw_mask_last;
616 static void FadeExt(int fade_mask, int fade_mode, int fade_type)
618 static int fade_type_skip = FADE_TYPE_NONE;
619 void (*draw_border_function)(void) = NULL;
620 Bitmap *bitmap = (fade_mode & FADE_TYPE_TRANSFORM ? bitmap_db_cross : NULL);
621 int x, y, width, height;
622 int fade_delay, post_delay;
624 if (fade_type == FADE_TYPE_FADE_OUT)
626 if (fade_type_skip != FADE_TYPE_NONE)
628 /* skip all fade operations until specified fade operation */
629 if (fade_type & fade_type_skip)
630 fade_type_skip = FADE_TYPE_NONE;
636 FadeCrossSaveBackbuffer();
639 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
642 FadeCrossSaveBackbuffer();
649 redraw_mask |= fade_mask;
651 if (fade_type == FADE_TYPE_SKIP)
653 fade_type_skip = fade_mode;
658 fade_delay = fading.fade_delay;
659 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
661 if (fade_type_skip != FADE_TYPE_NONE)
663 /* skip all fade operations until specified fade operation */
664 if (fade_type & fade_type_skip)
665 fade_type_skip = FADE_TYPE_NONE;
670 if (global.autoplay_leveldir)
675 if (fade_mask == REDRAW_FIELD)
680 height = FADE_SYSIZE;
682 if (border.draw_masked_when_fading)
683 draw_border_function = DrawMaskedBorder_FIELD; /* update when fading */
685 DrawMaskedBorder_FIELD(); /* draw once */
687 else /* REDRAW_ALL */
695 if (!setup.fade_screens ||
697 fading.fade_mode == FADE_MODE_NONE)
699 if (fade_mode == FADE_MODE_FADE_OUT)
702 BlitBitmap(backbuffer, window, x, y, width, height, x, y);
704 redraw_mask &= ~fade_mask;
709 FadeRectangle(bitmap, x, y, width, height, fade_mode, fade_delay, post_delay,
710 draw_border_function);
712 if (fade_type == FADE_TYPE_FADE_OUT)
713 FadeCrossRestoreBackbuffer();
715 redraw_mask &= ~fade_mask;
718 static void SetScreenStates_BeforeFadingIn()
720 // temporarily set screen mode for animations to screen after fading in
721 global.anim_status = global.anim_status_next;
723 // store backbuffer with all animations that will be started after fading in
724 PrepareFadeBitmap(DRAW_TO_FADE_TARGET);
726 // set screen mode for animations back to fading
727 global.anim_status = GAME_MODE_PSEUDO_FADING;
730 static void SetScreenStates_AfterFadingIn()
732 // store new source screen (to use correct masked border for fading)
733 gfx.fade_border_source_status = global.border_status;
735 global.anim_status = global.anim_status_next;
737 // force update of global animation status in case of rapid screen changes
738 redraw_mask = REDRAW_ALL;
742 static void SetScreenStates_BeforeFadingOut()
744 // store new target screen (to use correct masked border for fading)
745 gfx.fade_border_target_status = game_status;
747 // set screen mode for animations to fading
748 global.anim_status = GAME_MODE_PSEUDO_FADING;
750 // store backbuffer with all animations that will be stopped for fading out
751 PrepareFadeBitmap(DRAW_TO_FADE_SOURCE);
754 static void SetScreenStates_AfterFadingOut()
756 global.border_status = game_status;
759 void FadeIn(int fade_mask)
761 SetScreenStates_BeforeFadingIn();
764 DrawMaskedBorder(REDRAW_ALL);
767 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
768 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_IN);
770 FadeExt(fade_mask, FADE_MODE_FADE_IN, FADE_TYPE_FADE_IN);
774 FADE_SXSIZE = FULL_SXSIZE;
775 FADE_SYSIZE = FULL_SYSIZE;
777 SetScreenStates_AfterFadingIn();
780 void FadeOut(int fade_mask)
782 SetScreenStates_BeforeFadingOut();
785 DrawMaskedBorder(REDRAW_ALL);
788 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
789 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_OUT);
791 FadeExt(fade_mask, FADE_MODE_FADE_OUT, FADE_TYPE_FADE_OUT);
793 SetScreenStates_AfterFadingOut();
796 static void FadeSetLeaveNext(struct TitleFadingInfo fading_leave, boolean set)
798 static struct TitleFadingInfo fading_leave_stored;
801 fading_leave_stored = fading_leave;
803 fading = fading_leave_stored;
806 void FadeSetEnterMenu()
808 fading = menu.enter_menu;
810 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
813 void FadeSetLeaveMenu()
815 fading = menu.leave_menu;
817 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
820 void FadeSetEnterScreen()
822 fading = menu.enter_screen[game_status];
824 FadeSetLeaveNext(menu.leave_screen[game_status], TRUE); /* store */
827 void FadeSetNextScreen()
829 fading = menu.next_screen[game_status];
831 // (do not overwrite fade mode set by FadeSetEnterScreen)
832 // FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
835 void FadeSetLeaveScreen()
837 FadeSetLeaveNext(menu.leave_screen[game_status], FALSE); /* recall */
840 void FadeSetFromType(int type)
842 if (type & TYPE_ENTER_SCREEN)
843 FadeSetEnterScreen();
844 else if (type & TYPE_ENTER)
846 else if (type & TYPE_LEAVE)
850 void FadeSetDisabled()
852 static struct TitleFadingInfo fading_none = { FADE_MODE_NONE, -1, -1, -1 };
854 fading = fading_none;
857 void FadeSkipNextFadeIn()
859 FadeExt(0, FADE_MODE_SKIP_FADE_IN, FADE_TYPE_SKIP);
862 void FadeSkipNextFadeOut()
864 FadeExt(0, FADE_MODE_SKIP_FADE_OUT, FADE_TYPE_SKIP);
867 Bitmap *getBitmapFromGraphicOrDefault(int graphic, int default_graphic)
869 boolean redefined = getImageListEntryFromImageID(graphic)->redefined;
871 return (graphic == IMG_UNDEFINED ? NULL :
872 graphic_info[graphic].bitmap != NULL || redefined ?
873 graphic_info[graphic].bitmap :
874 graphic_info[default_graphic].bitmap);
877 Bitmap *getBackgroundBitmap(int graphic)
879 return getBitmapFromGraphicOrDefault(graphic, IMG_BACKGROUND);
882 Bitmap *getGlobalBorderBitmap(int graphic)
884 return getBitmapFromGraphicOrDefault(graphic, IMG_GLOBAL_BORDER);
887 Bitmap *getGlobalBorderBitmapFromStatus(int status)
890 (status == GAME_MODE_MAIN ||
891 status == GAME_MODE_PSEUDO_TYPENAME ? IMG_GLOBAL_BORDER_MAIN :
892 status == GAME_MODE_SCORES ? IMG_GLOBAL_BORDER_SCORES :
893 status == GAME_MODE_EDITOR ? IMG_GLOBAL_BORDER_EDITOR :
894 status == GAME_MODE_PLAYING ? IMG_GLOBAL_BORDER_PLAYING :
897 return getGlobalBorderBitmap(graphic);
900 void SetWindowBackgroundImageIfDefined(int graphic)
902 if (graphic_info[graphic].bitmap)
903 SetWindowBackgroundBitmap(graphic_info[graphic].bitmap);
906 void SetMainBackgroundImageIfDefined(int graphic)
908 if (graphic_info[graphic].bitmap)
909 SetMainBackgroundBitmap(graphic_info[graphic].bitmap);
912 void SetDoorBackgroundImageIfDefined(int graphic)
914 if (graphic_info[graphic].bitmap)
915 SetDoorBackgroundBitmap(graphic_info[graphic].bitmap);
918 void SetWindowBackgroundImage(int graphic)
920 SetWindowBackgroundBitmap(getBackgroundBitmap(graphic));
923 void SetMainBackgroundImage(int graphic)
925 SetMainBackgroundBitmap(getBackgroundBitmap(graphic));
928 void SetDoorBackgroundImage(int graphic)
930 SetDoorBackgroundBitmap(getBackgroundBitmap(graphic));
933 void SetPanelBackground()
935 struct GraphicInfo *gfx = &graphic_info[IMG_BACKGROUND_PANEL];
937 BlitBitmapTiled(gfx->bitmap, bitmap_db_panel, gfx->src_x, gfx->src_y,
938 gfx->width, gfx->height, 0, 0, DXSIZE, DYSIZE);
940 SetDoorBackgroundBitmap(bitmap_db_panel);
943 void DrawBackground(int x, int y, int width, int height)
945 /* "drawto" might still point to playfield buffer here (hall of fame) */
946 ClearRectangleOnBackground(backbuffer, x, y, width, height);
948 if (IN_GFX_FIELD_FULL(x, y))
949 redraw_mask |= REDRAW_FIELD;
950 else if (IN_GFX_DOOR_1(x, y))
951 redraw_mask |= REDRAW_DOOR_1;
952 else if (IN_GFX_DOOR_2(x, y))
953 redraw_mask |= REDRAW_DOOR_2;
954 else if (IN_GFX_DOOR_3(x, y))
955 redraw_mask |= REDRAW_DOOR_3;
958 void DrawBackgroundForFont(int x, int y, int width, int height, int font_nr)
960 struct FontBitmapInfo *font = getFontBitmapInfo(font_nr);
962 if (font->bitmap == NULL)
965 DrawBackground(x, y, width, height);
968 void DrawBackgroundForGraphic(int x, int y, int width, int height, int graphic)
970 struct GraphicInfo *g = &graphic_info[graphic];
972 if (g->bitmap == NULL)
975 DrawBackground(x, y, width, height);
978 static int game_status_last = -1;
979 static Bitmap *global_border_bitmap_last = NULL;
980 static Bitmap *global_border_bitmap = NULL;
981 static int real_sx_last = -1, real_sy_last = -1;
982 static int full_sxsize_last = -1, full_sysize_last = -1;
983 static int dx_last = -1, dy_last = -1;
984 static int dxsize_last = -1, dysize_last = -1;
985 static int vx_last = -1, vy_last = -1;
986 static int vxsize_last = -1, vysize_last = -1;
988 boolean CheckIfGlobalBorderHasChanged()
990 // if game status has not changed, global border has not changed either
991 if (game_status == game_status_last)
994 // determine and store new global border bitmap for current game status
995 global_border_bitmap = getGlobalBorderBitmapFromStatus(game_status);
997 return (global_border_bitmap_last != global_border_bitmap);
1000 boolean CheckIfGlobalBorderRedrawIsNeeded()
1002 // if game status has not changed, nothing has to be redrawn
1003 if (game_status == game_status_last)
1006 // redraw if last screen was title screen
1007 if (game_status_last == GAME_MODE_TITLE)
1010 // redraw if global screen border has changed
1011 if (CheckIfGlobalBorderHasChanged())
1014 // redraw if position or size of playfield area has changed
1015 if (real_sx_last != REAL_SX || real_sy_last != REAL_SY ||
1016 full_sxsize_last != FULL_SXSIZE || full_sysize_last != FULL_SYSIZE)
1019 // redraw if position or size of door area has changed
1020 if (dx_last != DX || dy_last != DY ||
1021 dxsize_last != DXSIZE || dysize_last != DYSIZE)
1024 // redraw if position or size of tape area has changed
1025 if (vx_last != VX || vy_last != VY ||
1026 vxsize_last != VXSIZE || vysize_last != VYSIZE)
1032 void RedrawGlobalBorderFromBitmap(Bitmap *bitmap)
1035 BlitBitmap(bitmap, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
1037 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
1040 void RedrawGlobalBorder()
1042 Bitmap *bitmap = getGlobalBorderBitmapFromStatus(game_status);
1044 RedrawGlobalBorderFromBitmap(bitmap);
1046 redraw_mask = REDRAW_ALL;
1049 static void RedrawGlobalBorderIfNeeded()
1051 if (game_status == game_status_last)
1054 // copy current draw buffer to later copy back areas that have not changed
1055 if (game_status_last != GAME_MODE_TITLE)
1056 BlitBitmap(backbuffer, bitmap_db_store, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
1058 if (CheckIfGlobalBorderRedrawIsNeeded())
1060 // redraw global screen border (or clear, if defined to be empty)
1061 RedrawGlobalBorderFromBitmap(global_border_bitmap);
1063 // copy previous playfield and door areas, if they are defined on both
1064 // previous and current screen and if they still have the same size
1066 if (real_sx_last != -1 && real_sy_last != -1 &&
1067 REAL_SX != -1 && REAL_SY != -1 &&
1068 full_sxsize_last == FULL_SXSIZE && full_sysize_last == FULL_SYSIZE)
1069 BlitBitmap(bitmap_db_store, backbuffer,
1070 real_sx_last, real_sy_last, FULL_SXSIZE, FULL_SYSIZE,
1073 if (dx_last != -1 && dy_last != -1 &&
1074 DX != -1 && DY != -1 &&
1075 dxsize_last == DXSIZE && dysize_last == DYSIZE)
1076 BlitBitmap(bitmap_db_store, backbuffer,
1077 dx_last, dy_last, DXSIZE, DYSIZE, DX, DY);
1079 if (vx_last != -1 && vy_last != -1 &&
1080 VX != -1 && VY != -1 &&
1081 vxsize_last == VXSIZE && vysize_last == VYSIZE)
1082 BlitBitmap(bitmap_db_store, backbuffer,
1083 vx_last, vy_last, VXSIZE, VYSIZE, VX, VY);
1085 redraw_mask = REDRAW_ALL;
1088 game_status_last = game_status;
1090 global_border_bitmap_last = global_border_bitmap;
1092 real_sx_last = REAL_SX;
1093 real_sy_last = REAL_SY;
1094 full_sxsize_last = FULL_SXSIZE;
1095 full_sysize_last = FULL_SYSIZE;
1098 dxsize_last = DXSIZE;
1099 dysize_last = DYSIZE;
1102 vxsize_last = VXSIZE;
1103 vysize_last = VYSIZE;
1108 RedrawGlobalBorderIfNeeded();
1110 /* !!! "drawto" might still point to playfield buffer here (see above) !!! */
1111 /* (when entering hall of fame after playing) */
1112 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
1114 /* !!! maybe this should be done before clearing the background !!! */
1115 if (game_status == GAME_MODE_PLAYING)
1117 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
1118 SetDrawtoField(DRAW_TO_FIELDBUFFER);
1122 SetDrawtoField(DRAW_TO_BACKBUFFER);
1126 void MarkTileDirty(int x, int y)
1128 redraw_mask |= REDRAW_FIELD;
1131 void SetBorderElement()
1135 BorderElement = EL_EMPTY;
1137 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
1139 for (x = 0; x < lev_fieldx; x++)
1141 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
1142 BorderElement = EL_STEELWALL;
1144 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
1150 void FloodFillLevel(int from_x, int from_y, int fill_element,
1151 short field[MAX_LEV_FIELDX][MAX_LEV_FIELDY],
1152 int max_fieldx, int max_fieldy)
1156 static int check[4][2] = { { -1, 0 }, { 0, -1 }, { 1, 0 }, { 0, 1 } };
1157 static int safety = 0;
1159 /* check if starting field still has the desired content */
1160 if (field[from_x][from_y] == fill_element)
1165 if (safety > max_fieldx * max_fieldy)
1166 Error(ERR_EXIT, "Something went wrong in 'FloodFill()'. Please debug.");
1168 old_element = field[from_x][from_y];
1169 field[from_x][from_y] = fill_element;
1171 for (i = 0; i < 4; i++)
1173 x = from_x + check[i][0];
1174 y = from_y + check[i][1];
1176 if (IN_FIELD(x, y, max_fieldx, max_fieldy) && field[x][y] == old_element)
1177 FloodFillLevel(x, y, fill_element, field, max_fieldx, max_fieldy);
1183 void SetRandomAnimationValue(int x, int y)
1185 gfx.anim_random_frame = GfxRandom[x][y];
1188 int getGraphicAnimationFrame(int graphic, int sync_frame)
1190 /* animation synchronized with global frame counter, not move position */
1191 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
1192 sync_frame = FrameCounter;
1194 return getAnimationFrame(graphic_info[graphic].anim_frames,
1195 graphic_info[graphic].anim_delay,
1196 graphic_info[graphic].anim_mode,
1197 graphic_info[graphic].anim_start_frame,
1201 void getSizedGraphicSourceExt(int graphic, int frame, int tilesize,
1202 Bitmap **bitmap, int *x, int *y,
1203 boolean get_backside)
1205 struct GraphicInfo *g = &graphic_info[graphic];
1206 Bitmap *src_bitmap = g->bitmap;
1207 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
1208 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
1209 int tilesize_capped = MIN(MAX(1, tilesize), TILESIZE);
1211 // if no in-game graphics defined, always use standard graphic size
1212 if (g->bitmaps[IMG_BITMAP_GAME] == NULL)
1213 tilesize = TILESIZE;
1215 if (tilesize == gfx.standard_tile_size)
1216 src_bitmap = g->bitmaps[IMG_BITMAP_STANDARD];
1217 else if (tilesize == game.tile_size)
1218 src_bitmap = g->bitmaps[IMG_BITMAP_GAME];
1220 src_bitmap = g->bitmaps[IMG_BITMAP_1x1 - log_2(tilesize_capped)];
1222 if (g->offset_y == 0) /* frames are ordered horizontally */
1224 int max_width = g->anim_frames_per_line * g->width;
1225 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
1227 src_x = pos % max_width;
1228 src_y = src_y % g->height + pos / max_width * g->height;
1230 else if (g->offset_x == 0) /* frames are ordered vertically */
1232 int max_height = g->anim_frames_per_line * g->height;
1233 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
1235 src_x = src_x % g->width + pos / max_height * g->width;
1236 src_y = pos % max_height;
1238 else /* frames are ordered diagonally */
1240 src_x = src_x + frame * g->offset_x;
1241 src_y = src_y + frame * g->offset_y;
1244 *bitmap = src_bitmap;
1245 *x = src_x * tilesize / g->tile_size;
1246 *y = src_y * tilesize / g->tile_size;
1249 void getFixedGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1250 int *x, int *y, boolean get_backside)
1252 getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y,
1256 void getSizedGraphicSource(int graphic, int frame, int tilesize,
1257 Bitmap **bitmap, int *x, int *y)
1259 getSizedGraphicSourceExt(graphic, frame, tilesize, bitmap, x, y, FALSE);
1262 void getFixedGraphicSource(int graphic, int frame,
1263 Bitmap **bitmap, int *x, int *y)
1265 getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y, FALSE);
1268 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1270 getSizedGraphicSource(graphic, 0, MINI_TILESIZE, bitmap, x, y);
1273 inline static void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1274 int *x, int *y, boolean get_backside)
1276 struct GraphicInfo *g = &graphic_info[graphic];
1277 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
1278 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
1280 if (TILESIZE_VAR != TILESIZE)
1281 return getSizedGraphicSourceExt(graphic, frame, TILESIZE_VAR, bitmap, x, y,
1284 *bitmap = g->bitmap;
1286 if (g->offset_y == 0) /* frames are ordered horizontally */
1288 int max_width = g->anim_frames_per_line * g->width;
1289 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
1291 *x = pos % max_width;
1292 *y = src_y % g->height + pos / max_width * g->height;
1294 else if (g->offset_x == 0) /* frames are ordered vertically */
1296 int max_height = g->anim_frames_per_line * g->height;
1297 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
1299 *x = src_x % g->width + pos / max_height * g->width;
1300 *y = pos % max_height;
1302 else /* frames are ordered diagonally */
1304 *x = src_x + frame * g->offset_x;
1305 *y = src_y + frame * g->offset_y;
1308 *x = *x * TILESIZE_VAR / g->tile_size;
1309 *y = *y * TILESIZE_VAR / g->tile_size;
1312 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
1314 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
1317 void DrawGraphic(int x, int y, int graphic, int frame)
1320 if (!IN_SCR_FIELD(x, y))
1322 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1323 printf("DrawGraphic(): This should never happen!\n");
1328 DrawGraphicExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR, graphic,
1331 MarkTileDirty(x, y);
1334 void DrawFixedGraphic(int x, int y, int graphic, int frame)
1337 if (!IN_SCR_FIELD(x, y))
1339 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1340 printf("DrawGraphic(): This should never happen!\n");
1345 DrawFixedGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic,
1347 MarkTileDirty(x, y);
1350 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1356 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1358 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX_VAR, TILEY_VAR, x, y);
1361 void DrawFixedGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1367 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1368 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
1371 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
1374 if (!IN_SCR_FIELD(x, y))
1376 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1377 printf("DrawGraphicThruMask(): This should never happen!\n");
1382 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
1385 MarkTileDirty(x, y);
1388 void DrawFixedGraphicThruMask(int x, int y, int graphic, int frame)
1391 if (!IN_SCR_FIELD(x, y))
1393 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1394 printf("DrawGraphicThruMask(): This should never happen!\n");
1399 DrawFixedGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
1401 MarkTileDirty(x, y);
1404 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
1410 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1412 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX_VAR, TILEY_VAR,
1416 void DrawFixedGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y,
1417 int graphic, int frame)
1422 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1424 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY,
1428 void DrawSizedGraphic(int x, int y, int graphic, int frame, int tilesize)
1430 DrawSizedGraphicExt(drawto, SX + x * tilesize, SY + y * tilesize, graphic,
1432 MarkTileDirty(x / tilesize, y / tilesize);
1435 void DrawSizedGraphicExt(DrawBuffer *d, int x, int y, int graphic, int frame,
1441 getSizedGraphicSource(graphic, frame, tilesize, &src_bitmap, &src_x, &src_y);
1442 BlitBitmap(src_bitmap, d, src_x, src_y, tilesize, tilesize, x, y);
1445 void DrawMiniGraphic(int x, int y, int graphic)
1447 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
1448 MarkTileDirty(x / 2, y / 2);
1451 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
1456 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1457 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
1460 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
1461 int graphic, int frame,
1462 int cut_mode, int mask_mode)
1467 int width = TILEX, height = TILEY;
1470 if (dx || dy) /* shifted graphic */
1472 if (x < BX1) /* object enters playfield from the left */
1479 else if (x > BX2) /* object enters playfield from the right */
1485 else if (x == BX1 && dx < 0) /* object leaves playfield to the left */
1491 else if (x == BX2 && dx > 0) /* object leaves playfield to the right */
1493 else if (dx) /* general horizontal movement */
1494 MarkTileDirty(x + SIGN(dx), y);
1496 if (y < BY1) /* object enters playfield from the top */
1498 if (cut_mode == CUT_BELOW) /* object completely above top border */
1506 else if (y > BY2) /* object enters playfield from the bottom */
1512 else if (y == BY1 && dy < 0) /* object leaves playfield to the top */
1518 else if (dy > 0 && cut_mode == CUT_ABOVE)
1520 if (y == BY2) /* object completely above bottom border */
1526 MarkTileDirty(x, y + 1);
1527 } /* object leaves playfield to the bottom */
1528 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1530 else if (dy) /* general vertical movement */
1531 MarkTileDirty(x, y + SIGN(dy));
1535 if (!IN_SCR_FIELD(x, y))
1537 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1538 printf("DrawGraphicShifted(): This should never happen!\n");
1543 width = width * TILESIZE_VAR / TILESIZE;
1544 height = height * TILESIZE_VAR / TILESIZE;
1545 cx = cx * TILESIZE_VAR / TILESIZE;
1546 cy = cy * TILESIZE_VAR / TILESIZE;
1547 dx = dx * TILESIZE_VAR / TILESIZE;
1548 dy = dy * TILESIZE_VAR / TILESIZE;
1550 if (width > 0 && height > 0)
1552 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1557 dst_x = FX + x * TILEX_VAR + dx;
1558 dst_y = FY + y * TILEY_VAR + dy;
1560 if (mask_mode == USE_MASKING)
1561 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1564 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1567 MarkTileDirty(x, y);
1571 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
1572 int graphic, int frame,
1573 int cut_mode, int mask_mode)
1578 int width = TILEX_VAR, height = TILEY_VAR;
1581 int x2 = x + SIGN(dx);
1582 int y2 = y + SIGN(dy);
1584 /* movement with two-tile animations must be sync'ed with movement position,
1585 not with current GfxFrame (which can be higher when using slow movement) */
1586 int anim_pos = (dx ? ABS(dx) : ABS(dy));
1587 int anim_frames = graphic_info[graphic].anim_frames;
1589 /* (we also need anim_delay here for movement animations with less frames) */
1590 int anim_delay = graphic_info[graphic].anim_delay;
1591 int sync_frame = anim_pos * anim_frames * anim_delay / TILESIZE;
1593 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
1594 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
1596 /* re-calculate animation frame for two-tile movement animation */
1597 frame = getGraphicAnimationFrame(graphic, sync_frame);
1599 /* check if movement start graphic inside screen area and should be drawn */
1600 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
1602 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
1604 dst_x = FX + x1 * TILEX_VAR;
1605 dst_y = FY + y1 * TILEY_VAR;
1607 if (mask_mode == USE_MASKING)
1608 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1611 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1614 MarkTileDirty(x1, y1);
1617 /* check if movement end graphic inside screen area and should be drawn */
1618 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
1620 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
1622 dst_x = FX + x2 * TILEX_VAR;
1623 dst_y = FY + y2 * TILEY_VAR;
1625 if (mask_mode == USE_MASKING)
1626 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1629 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1632 MarkTileDirty(x2, y2);
1636 static void DrawGraphicShifted(int x, int y, int dx, int dy,
1637 int graphic, int frame,
1638 int cut_mode, int mask_mode)
1642 DrawGraphic(x, y, graphic, frame);
1647 if (graphic_info[graphic].double_movement) /* EM style movement images */
1648 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1650 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1653 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1654 int frame, int cut_mode)
1656 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
1659 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1660 int cut_mode, int mask_mode)
1662 int lx = LEVELX(x), ly = LEVELY(y);
1666 if (IN_LEV_FIELD(lx, ly))
1668 SetRandomAnimationValue(lx, ly);
1670 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
1671 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1673 /* do not use double (EM style) movement graphic when not moving */
1674 if (graphic_info[graphic].double_movement && !dx && !dy)
1676 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
1677 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1680 else /* border element */
1682 graphic = el2img(element);
1683 frame = getGraphicAnimationFrame(graphic, -1);
1686 if (element == EL_EXPANDABLE_WALL)
1688 boolean left_stopped = FALSE, right_stopped = FALSE;
1690 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1691 left_stopped = TRUE;
1692 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1693 right_stopped = TRUE;
1695 if (left_stopped && right_stopped)
1697 else if (left_stopped)
1699 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1700 frame = graphic_info[graphic].anim_frames - 1;
1702 else if (right_stopped)
1704 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1705 frame = graphic_info[graphic].anim_frames - 1;
1710 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1711 else if (mask_mode == USE_MASKING)
1712 DrawGraphicThruMask(x, y, graphic, frame);
1714 DrawGraphic(x, y, graphic, frame);
1717 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1718 int cut_mode, int mask_mode)
1720 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1721 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1722 cut_mode, mask_mode);
1725 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1728 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1731 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1734 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1737 void DrawLevelElementThruMask(int x, int y, int element)
1739 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1742 void DrawLevelFieldThruMask(int x, int y)
1744 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1747 /* !!! implementation of quicksand is totally broken !!! */
1748 #define IS_CRUMBLED_TILE(x, y, e) \
1749 (GFX_CRUMBLED(e) && (!IN_LEV_FIELD(x, y) || \
1750 !IS_MOVING(x, y) || \
1751 (e) == EL_QUICKSAND_EMPTYING || \
1752 (e) == EL_QUICKSAND_FAST_EMPTYING))
1754 static void DrawLevelFieldCrumbledInnerCorners(int x, int y, int dx, int dy,
1759 int width, height, cx, cy;
1760 int sx = SCREENX(x), sy = SCREENY(y);
1761 int crumbled_border_size = graphic_info[graphic].border_size;
1764 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1766 for (i = 1; i < 4; i++)
1768 int dxx = (i & 1 ? dx : 0);
1769 int dyy = (i & 2 ? dy : 0);
1772 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1775 /* check if neighbour field is of same crumble type */
1776 boolean same = (IS_CRUMBLED_TILE(xx, yy, element) &&
1777 graphic_info[graphic].class ==
1778 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class);
1780 /* return if check prevents inner corner */
1781 if (same == (dxx == dx && dyy == dy))
1785 /* if we reach this point, we have an inner corner */
1787 getGraphicSource(graphic, 1, &src_bitmap, &src_x, &src_y);
1789 width = crumbled_border_size * TILESIZE_VAR / TILESIZE;
1790 height = crumbled_border_size * TILESIZE_VAR / TILESIZE;
1791 cx = (dx > 0 ? TILESIZE_VAR - width : 0);
1792 cy = (dy > 0 ? TILESIZE_VAR - height : 0);
1794 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1795 width, height, FX + sx * TILEX_VAR + cx, FY + sy * TILEY_VAR + cy);
1798 static void DrawLevelFieldCrumbledBorders(int x, int y, int graphic, int frame,
1803 int width, height, bx, by, cx, cy;
1804 int sx = SCREENX(x), sy = SCREENY(y);
1805 int crumbled_border_size = graphic_info[graphic].border_size;
1806 int crumbled_border_size_var = crumbled_border_size * TILESIZE_VAR / TILESIZE;
1807 int crumbled_border_pos_var = TILESIZE_VAR - crumbled_border_size_var;
1810 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1812 /* draw simple, sloppy, non-corner-accurate crumbled border */
1814 width = (dir == 1 || dir == 2 ? crumbled_border_size_var : TILESIZE_VAR);
1815 height = (dir == 0 || dir == 3 ? crumbled_border_size_var : TILESIZE_VAR);
1816 cx = (dir == 2 ? crumbled_border_pos_var : 0);
1817 cy = (dir == 3 ? crumbled_border_pos_var : 0);
1819 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy, width, height,
1820 FX + sx * TILEX_VAR + cx,
1821 FY + sy * TILEY_VAR + cy);
1823 /* (remaining middle border part must be at least as big as corner part) */
1824 if (!(graphic_info[graphic].style & STYLE_ACCURATE_BORDERS) ||
1825 crumbled_border_size >= TILESIZE / 3)
1828 /* correct corners of crumbled border, if needed */
1830 for (i = -1; i <= 1; i += 2)
1832 int xx = x + (dir == 0 || dir == 3 ? i : 0);
1833 int yy = y + (dir == 1 || dir == 2 ? i : 0);
1834 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1837 /* check if neighbour field is of same crumble type */
1838 if (IS_CRUMBLED_TILE(xx, yy, element) &&
1839 graphic_info[graphic].class ==
1840 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1842 /* no crumbled corner, but continued crumbled border */
1844 int c1 = (dir == 2 || dir == 3 ? crumbled_border_pos_var : 0);
1845 int c2 = (i == 1 ? crumbled_border_pos_var : 0);
1846 int b1 = (i == 1 ? crumbled_border_size_var :
1847 TILESIZE_VAR - 2 * crumbled_border_size_var);
1849 width = crumbled_border_size_var;
1850 height = crumbled_border_size_var;
1852 if (dir == 1 || dir == 2)
1867 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
1869 FX + sx * TILEX_VAR + cx,
1870 FY + sy * TILEY_VAR + cy);
1875 static void DrawLevelFieldCrumbledExt(int x, int y, int graphic, int frame)
1877 int sx = SCREENX(x), sy = SCREENY(y);
1880 static int xy[4][2] =
1888 if (!IN_LEV_FIELD(x, y))
1891 element = TILE_GFX_ELEMENT(x, y);
1893 /* crumble field itself */
1894 if (IS_CRUMBLED_TILE(x, y, element))
1896 if (!IN_SCR_FIELD(sx, sy))
1899 for (i = 0; i < 4; i++)
1901 int xx = x + xy[i][0];
1902 int yy = y + xy[i][1];
1904 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1907 /* check if neighbour field is of same crumble type */
1908 if (IS_CRUMBLED_TILE(xx, yy, element) &&
1909 graphic_info[graphic].class ==
1910 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1913 DrawLevelFieldCrumbledBorders(x, y, graphic, frame, i);
1916 if ((graphic_info[graphic].style & STYLE_INNER_CORNERS) &&
1917 graphic_info[graphic].anim_frames == 2)
1919 for (i = 0; i < 4; i++)
1921 int dx = (i & 1 ? +1 : -1);
1922 int dy = (i & 2 ? +1 : -1);
1924 DrawLevelFieldCrumbledInnerCorners(x, y, dx, dy, graphic);
1928 MarkTileDirty(sx, sy);
1930 else /* center field not crumbled -- crumble neighbour fields */
1932 for (i = 0; i < 4; i++)
1934 int xx = x + xy[i][0];
1935 int yy = y + xy[i][1];
1936 int sxx = sx + xy[i][0];
1937 int syy = sy + xy[i][1];
1939 if (!IN_LEV_FIELD(xx, yy) ||
1940 !IN_SCR_FIELD(sxx, syy))
1943 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
1946 element = TILE_GFX_ELEMENT(xx, yy);
1948 if (!IS_CRUMBLED_TILE(xx, yy, element))
1951 graphic = el_act2crm(element, ACTION_DEFAULT);
1953 DrawLevelFieldCrumbledBorders(xx, yy, graphic, 0, 3 - i);
1955 MarkTileDirty(sxx, syy);
1960 void DrawLevelFieldCrumbled(int x, int y)
1964 if (!IN_LEV_FIELD(x, y))
1967 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1968 GfxElement[x][y] != EL_UNDEFINED &&
1969 GFX_CRUMBLED(GfxElement[x][y]))
1971 DrawLevelFieldCrumbledDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
1976 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
1978 DrawLevelFieldCrumbledExt(x, y, graphic, 0);
1981 void DrawLevelFieldCrumbledDigging(int x, int y, int direction,
1984 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1985 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1986 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1987 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1988 int sx = SCREENX(x), sy = SCREENY(y);
1990 DrawGraphic(sx, sy, graphic1, frame1);
1991 DrawLevelFieldCrumbledExt(x, y, graphic2, frame2);
1994 void DrawLevelFieldCrumbledNeighbours(int x, int y)
1996 int sx = SCREENX(x), sy = SCREENY(y);
1997 static int xy[4][2] =
2006 for (i = 0; i < 4; i++)
2008 int xx = x + xy[i][0];
2009 int yy = y + xy[i][1];
2010 int sxx = sx + xy[i][0];
2011 int syy = sy + xy[i][1];
2013 if (!IN_LEV_FIELD(xx, yy) ||
2014 !IN_SCR_FIELD(sxx, syy) ||
2015 !GFX_CRUMBLED(Feld[xx][yy]) ||
2019 DrawLevelField(xx, yy);
2023 static int getBorderElement(int x, int y)
2027 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
2028 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
2029 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
2030 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
2031 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
2032 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
2033 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
2035 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
2036 int steel_position = (x == -1 && y == -1 ? 0 :
2037 x == lev_fieldx && y == -1 ? 1 :
2038 x == -1 && y == lev_fieldy ? 2 :
2039 x == lev_fieldx && y == lev_fieldy ? 3 :
2040 x == -1 || x == lev_fieldx ? 4 :
2041 y == -1 || y == lev_fieldy ? 5 : 6);
2043 return border[steel_position][steel_type];
2046 void DrawScreenElement(int x, int y, int element)
2048 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
2049 DrawLevelFieldCrumbled(LEVELX(x), LEVELY(y));
2052 void DrawLevelElement(int x, int y, int element)
2054 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2055 DrawScreenElement(SCREENX(x), SCREENY(y), element);
2058 void DrawScreenField(int x, int y)
2060 int lx = LEVELX(x), ly = LEVELY(y);
2061 int element, content;
2063 if (!IN_LEV_FIELD(lx, ly))
2065 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
2068 element = getBorderElement(lx, ly);
2070 DrawScreenElement(x, y, element);
2075 element = Feld[lx][ly];
2076 content = Store[lx][ly];
2078 if (IS_MOVING(lx, ly))
2080 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
2081 boolean cut_mode = NO_CUTTING;
2083 if (element == EL_QUICKSAND_EMPTYING ||
2084 element == EL_QUICKSAND_FAST_EMPTYING ||
2085 element == EL_MAGIC_WALL_EMPTYING ||
2086 element == EL_BD_MAGIC_WALL_EMPTYING ||
2087 element == EL_DC_MAGIC_WALL_EMPTYING ||
2088 element == EL_AMOEBA_DROPPING)
2089 cut_mode = CUT_ABOVE;
2090 else if (element == EL_QUICKSAND_FILLING ||
2091 element == EL_QUICKSAND_FAST_FILLING ||
2092 element == EL_MAGIC_WALL_FILLING ||
2093 element == EL_BD_MAGIC_WALL_FILLING ||
2094 element == EL_DC_MAGIC_WALL_FILLING)
2095 cut_mode = CUT_BELOW;
2097 if (cut_mode == CUT_ABOVE)
2098 DrawScreenElement(x, y, element);
2100 DrawScreenElement(x, y, EL_EMPTY);
2103 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
2104 else if (cut_mode == NO_CUTTING)
2105 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
2108 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
2110 if (cut_mode == CUT_BELOW &&
2111 IN_LEV_FIELD(lx, ly + 1) && IN_SCR_FIELD(x, y + 1))
2112 DrawLevelElement(lx, ly + 1, element);
2115 if (content == EL_ACID)
2117 int dir = MovDir[lx][ly];
2118 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
2119 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
2121 DrawLevelElementThruMask(newlx, newly, EL_ACID);
2124 else if (IS_BLOCKED(lx, ly))
2129 boolean cut_mode = NO_CUTTING;
2130 int element_old, content_old;
2132 Blocked2Moving(lx, ly, &oldx, &oldy);
2135 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
2136 MovDir[oldx][oldy] == MV_RIGHT);
2138 element_old = Feld[oldx][oldy];
2139 content_old = Store[oldx][oldy];
2141 if (element_old == EL_QUICKSAND_EMPTYING ||
2142 element_old == EL_QUICKSAND_FAST_EMPTYING ||
2143 element_old == EL_MAGIC_WALL_EMPTYING ||
2144 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
2145 element_old == EL_DC_MAGIC_WALL_EMPTYING ||
2146 element_old == EL_AMOEBA_DROPPING)
2147 cut_mode = CUT_ABOVE;
2149 DrawScreenElement(x, y, EL_EMPTY);
2152 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
2154 else if (cut_mode == NO_CUTTING)
2155 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
2158 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
2161 else if (IS_DRAWABLE(element))
2162 DrawScreenElement(x, y, element);
2164 DrawScreenElement(x, y, EL_EMPTY);
2167 void DrawLevelField(int x, int y)
2169 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2170 DrawScreenField(SCREENX(x), SCREENY(y));
2171 else if (IS_MOVING(x, y))
2175 Moving2Blocked(x, y, &newx, &newy);
2176 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
2177 DrawScreenField(SCREENX(newx), SCREENY(newy));
2179 else if (IS_BLOCKED(x, y))
2183 Blocked2Moving(x, y, &oldx, &oldy);
2184 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
2185 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
2189 void DrawSizedElement(int x, int y, int element, int tilesize)
2193 graphic = el2edimg(element);
2194 DrawSizedGraphic(x, y, graphic, 0, tilesize);
2197 void DrawMiniElement(int x, int y, int element)
2201 graphic = el2edimg(element);
2202 DrawMiniGraphic(x, y, graphic);
2205 void DrawSizedElementOrWall(int sx, int sy, int scroll_x, int scroll_y,
2208 int x = sx + scroll_x, y = sy + scroll_y;
2210 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
2211 DrawSizedElement(sx, sy, EL_EMPTY, tilesize);
2212 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
2213 DrawSizedElement(sx, sy, Feld[x][y], tilesize);
2215 DrawSizedGraphic(sx, sy, el2edimg(getBorderElement(x, y)), 0, tilesize);
2218 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
2220 int x = sx + scroll_x, y = sy + scroll_y;
2222 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
2223 DrawMiniElement(sx, sy, EL_EMPTY);
2224 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
2225 DrawMiniElement(sx, sy, Feld[x][y]);
2227 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
2230 void DrawEnvelopeBackgroundTiles(int graphic, int startx, int starty,
2231 int x, int y, int xsize, int ysize,
2232 int tile_width, int tile_height)
2236 int dst_x = startx + x * tile_width;
2237 int dst_y = starty + y * tile_height;
2238 int width = graphic_info[graphic].width;
2239 int height = graphic_info[graphic].height;
2240 int inner_width_raw = MAX(width - 2 * tile_width, tile_width);
2241 int inner_height_raw = MAX(height - 2 * tile_height, tile_height);
2242 int inner_width = inner_width_raw - (inner_width_raw % tile_width);
2243 int inner_height = inner_height_raw - (inner_height_raw % tile_height);
2244 int inner_sx = (width >= 3 * tile_width ? tile_width : 0);
2245 int inner_sy = (height >= 3 * tile_height ? tile_height : 0);
2246 boolean draw_masked = graphic_info[graphic].draw_masked;
2248 getFixedGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
2250 if (src_bitmap == NULL || width < tile_width || height < tile_height)
2252 ClearRectangle(drawto, dst_x, dst_y, tile_width, tile_height);
2256 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - tile_width :
2257 inner_sx + (x - 1) * tile_width % inner_width);
2258 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - tile_height :
2259 inner_sy + (y - 1) * tile_height % inner_height);
2262 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
2265 BlitBitmap(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
2269 void DrawEnvelopeBackground(int graphic, int startx, int starty,
2270 int x, int y, int xsize, int ysize, int font_nr)
2272 int font_width = getFontWidth(font_nr);
2273 int font_height = getFontHeight(font_nr);
2275 DrawEnvelopeBackgroundTiles(graphic, startx, starty, x, y, xsize, ysize,
2276 font_width, font_height);
2279 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
2281 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2282 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2283 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2284 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2285 boolean no_delay = (tape.warp_forward);
2286 unsigned int anim_delay = 0;
2287 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
2288 int anim_delay_value = (no_delay ? 0 : frame_delay_value) / 2;
2289 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
2290 int font_width = getFontWidth(font_nr);
2291 int font_height = getFontHeight(font_nr);
2292 int max_xsize = level.envelope[envelope_nr].xsize;
2293 int max_ysize = level.envelope[envelope_nr].ysize;
2294 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
2295 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
2296 int xend = max_xsize;
2297 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
2298 int xstep = (xstart < xend ? 1 : 0);
2299 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2301 int end = MAX(xend - xstart, yend - ystart);
2304 for (i = start; i <= end; i++)
2306 int last_frame = end; // last frame of this "for" loop
2307 int x = xstart + i * xstep;
2308 int y = ystart + i * ystep;
2309 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2310 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2311 int sx = SX + (SXSIZE - xsize * font_width) / 2;
2312 int sy = SY + (SYSIZE - ysize * font_height) / 2;
2315 SetDrawtoField(DRAW_TO_FIELDBUFFER);
2317 BlitScreenToBitmap(backbuffer);
2319 SetDrawtoField(DRAW_TO_BACKBUFFER);
2321 for (yy = 0; yy < ysize; yy++)
2322 for (xx = 0; xx < xsize; xx++)
2323 DrawEnvelopeBackground(graphic, sx, sy, xx, yy, xsize, ysize, font_nr);
2325 DrawTextBuffer(sx + font_width, sy + font_height,
2326 level.envelope[envelope_nr].text, font_nr, max_xsize,
2327 xsize - 2, ysize - 2, 0, mask_mode,
2328 level.envelope[envelope_nr].autowrap,
2329 level.envelope[envelope_nr].centered, FALSE);
2331 redraw_mask |= REDRAW_FIELD;
2334 SkipUntilDelayReached(&anim_delay, anim_delay_value, &i, last_frame);
2338 void ShowEnvelope(int envelope_nr)
2340 int element = EL_ENVELOPE_1 + envelope_nr;
2341 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2342 int sound_opening = element_info[element].sound[ACTION_OPENING];
2343 int sound_closing = element_info[element].sound[ACTION_CLOSING];
2344 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2345 boolean no_delay = (tape.warp_forward);
2346 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
2347 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
2348 int anim_mode = graphic_info[graphic].anim_mode;
2349 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2350 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2352 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
2354 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2356 if (anim_mode == ANIM_DEFAULT)
2357 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
2359 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
2362 Delay(wait_delay_value);
2364 WaitForEventToContinue();
2366 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2368 if (anim_mode != ANIM_NONE)
2369 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
2371 if (anim_mode == ANIM_DEFAULT)
2372 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
2374 game.envelope_active = FALSE;
2376 SetDrawtoField(DRAW_TO_FIELDBUFFER);
2378 redraw_mask |= REDRAW_FIELD;
2382 static void setRequestBasePosition(int *x, int *y)
2384 int sx_base, sy_base;
2386 if (request.x != -1)
2387 sx_base = request.x;
2388 else if (request.align == ALIGN_LEFT)
2390 else if (request.align == ALIGN_RIGHT)
2391 sx_base = SX + SXSIZE;
2393 sx_base = SX + SXSIZE / 2;
2395 if (request.y != -1)
2396 sy_base = request.y;
2397 else if (request.valign == VALIGN_TOP)
2399 else if (request.valign == VALIGN_BOTTOM)
2400 sy_base = SY + SYSIZE;
2402 sy_base = SY + SYSIZE / 2;
2408 static void setRequestPositionExt(int *x, int *y, int width, int height,
2409 boolean add_border_size)
2411 int border_size = request.border_size;
2412 int sx_base, sy_base;
2415 setRequestBasePosition(&sx_base, &sy_base);
2417 if (request.align == ALIGN_LEFT)
2419 else if (request.align == ALIGN_RIGHT)
2420 sx = sx_base - width;
2422 sx = sx_base - width / 2;
2424 if (request.valign == VALIGN_TOP)
2426 else if (request.valign == VALIGN_BOTTOM)
2427 sy = sy_base - height;
2429 sy = sy_base - height / 2;
2431 sx = MAX(0, MIN(sx, WIN_XSIZE - width));
2432 sy = MAX(0, MIN(sy, WIN_YSIZE - height));
2434 if (add_border_size)
2444 static void setRequestPosition(int *x, int *y, boolean add_border_size)
2446 setRequestPositionExt(x, y, request.width, request.height, add_border_size);
2449 void DrawEnvelopeRequest(char *text)
2451 char *text_final = text;
2452 char *text_door_style = NULL;
2453 int graphic = IMG_BACKGROUND_REQUEST;
2454 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2455 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2456 int font_nr = FONT_REQUEST;
2457 int font_width = getFontWidth(font_nr);
2458 int font_height = getFontHeight(font_nr);
2459 int border_size = request.border_size;
2460 int line_spacing = request.line_spacing;
2461 int line_height = font_height + line_spacing;
2462 int max_text_width = request.width - 2 * border_size;
2463 int max_text_height = request.height - 2 * border_size;
2464 int line_length = max_text_width / font_width;
2465 int max_lines = max_text_height / line_height;
2466 int text_width = line_length * font_width;
2467 int width = request.width;
2468 int height = request.height;
2469 int tile_size = MAX(request.step_offset, 1);
2470 int x_steps = width / tile_size;
2471 int y_steps = height / tile_size;
2472 int sx_offset = border_size;
2473 int sy_offset = border_size;
2477 if (request.centered)
2478 sx_offset = (request.width - text_width) / 2;
2480 if (request.wrap_single_words && !request.autowrap)
2482 char *src_text_ptr, *dst_text_ptr;
2484 text_door_style = checked_malloc(2 * strlen(text) + 1);
2486 src_text_ptr = text;
2487 dst_text_ptr = text_door_style;
2489 while (*src_text_ptr)
2491 if (*src_text_ptr == ' ' ||
2492 *src_text_ptr == '?' ||
2493 *src_text_ptr == '!')
2494 *dst_text_ptr++ = '\n';
2496 if (*src_text_ptr != ' ')
2497 *dst_text_ptr++ = *src_text_ptr;
2502 *dst_text_ptr = '\0';
2504 text_final = text_door_style;
2507 setRequestPosition(&sx, &sy, FALSE);
2509 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
2511 for (y = 0; y < y_steps; y++)
2512 for (x = 0; x < x_steps; x++)
2513 DrawEnvelopeBackgroundTiles(graphic, sx, sy,
2514 x, y, x_steps, y_steps,
2515 tile_size, tile_size);
2517 /* force DOOR font inside door area */
2518 SetFontStatus(GAME_MODE_PSEUDO_DOOR);
2520 DrawTextBuffer(sx + sx_offset, sy + sy_offset, text_final, font_nr,
2521 line_length, -1, max_lines, line_spacing, mask_mode,
2522 request.autowrap, request.centered, FALSE);
2526 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2527 RedrawGadget(tool_gadget[i]);
2529 // store readily prepared envelope request for later use when animating
2530 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2532 if (text_door_style)
2533 free(text_door_style);
2536 void AnimateEnvelopeRequest(int anim_mode, int action)
2538 int graphic = IMG_BACKGROUND_REQUEST;
2539 boolean draw_masked = graphic_info[graphic].draw_masked;
2540 int delay_value_normal = request.step_delay;
2541 int delay_value_fast = delay_value_normal / 2;
2542 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2543 boolean no_delay = (tape.warp_forward);
2544 int delay_value = (ffwd_delay ? delay_value_fast : delay_value_normal);
2545 int anim_delay_value = (no_delay ? 0 : delay_value + 500 * 0) / 2;
2546 unsigned int anim_delay = 0;
2548 int tile_size = MAX(request.step_offset, 1);
2549 int max_xsize = request.width / tile_size;
2550 int max_ysize = request.height / tile_size;
2551 int max_xsize_inner = max_xsize - 2;
2552 int max_ysize_inner = max_ysize - 2;
2554 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize_inner : 0);
2555 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize_inner : 0);
2556 int xend = max_xsize_inner;
2557 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize_inner : 0);
2558 int xstep = (xstart < xend ? 1 : 0);
2559 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2561 int end = MAX(xend - xstart, yend - ystart);
2564 if (setup.quick_doors)
2571 for (i = start; i <= end; i++)
2573 int last_frame = end; // last frame of this "for" loop
2574 int x = xstart + i * xstep;
2575 int y = ystart + i * ystep;
2576 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2577 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2578 int xsize_size_left = (xsize - 1) * tile_size;
2579 int ysize_size_top = (ysize - 1) * tile_size;
2580 int max_xsize_pos = (max_xsize - 1) * tile_size;
2581 int max_ysize_pos = (max_ysize - 1) * tile_size;
2582 int width = xsize * tile_size;
2583 int height = ysize * tile_size;
2588 setRequestPosition(&src_x, &src_y, FALSE);
2589 setRequestPositionExt(&dst_x, &dst_y, width, height, FALSE);
2591 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2593 for (yy = 0; yy < 2; yy++)
2595 for (xx = 0; xx < 2; xx++)
2597 int src_xx = src_x + xx * max_xsize_pos;
2598 int src_yy = src_y + yy * max_ysize_pos;
2599 int dst_xx = dst_x + xx * xsize_size_left;
2600 int dst_yy = dst_y + yy * ysize_size_top;
2601 int xx_size = (xx ? tile_size : xsize_size_left);
2602 int yy_size = (yy ? tile_size : ysize_size_top);
2605 BlitBitmapMasked(bitmap_db_cross, backbuffer,
2606 src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
2608 BlitBitmap(bitmap_db_cross, backbuffer,
2609 src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
2613 redraw_mask |= REDRAW_FIELD;
2617 SkipUntilDelayReached(&anim_delay, anim_delay_value, &i, last_frame);
2621 void ShowEnvelopeRequest(char *text, unsigned int req_state, int action)
2623 int graphic = IMG_BACKGROUND_REQUEST;
2624 int sound_opening = SND_REQUEST_OPENING;
2625 int sound_closing = SND_REQUEST_CLOSING;
2626 int anim_mode_1 = request.anim_mode; /* (higher priority) */
2627 int anim_mode_2 = graphic_info[graphic].anim_mode; /* (lower priority) */
2628 int anim_mode = (anim_mode_1 != ANIM_DEFAULT ? anim_mode_1 : anim_mode_2);
2629 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2630 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2632 if (game_status == GAME_MODE_PLAYING)
2633 BlitScreenToBitmap(backbuffer);
2635 SetDrawtoField(DRAW_TO_BACKBUFFER);
2637 // SetDrawBackgroundMask(REDRAW_NONE);
2639 if (action == ACTION_OPENING)
2641 BlitBitmap(backbuffer, bitmap_db_store, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2643 if (req_state & REQ_ASK)
2645 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2646 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2648 else if (req_state & REQ_CONFIRM)
2650 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2652 else if (req_state & REQ_PLAYER)
2654 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2655 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2656 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2657 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2660 DrawEnvelopeRequest(text);
2663 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
2665 if (action == ACTION_OPENING)
2667 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2669 if (anim_mode == ANIM_DEFAULT)
2670 AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_OPENING);
2672 AnimateEnvelopeRequest(main_anim_mode, ACTION_OPENING);
2676 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2678 if (anim_mode != ANIM_NONE)
2679 AnimateEnvelopeRequest(main_anim_mode, ACTION_CLOSING);
2681 if (anim_mode == ANIM_DEFAULT)
2682 AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_CLOSING);
2685 game.envelope_active = FALSE;
2687 if (action == ACTION_CLOSING)
2688 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2690 // SetDrawBackgroundMask(last_draw_background_mask);
2692 redraw_mask |= REDRAW_FIELD;
2696 if (action == ACTION_CLOSING &&
2697 game_status == GAME_MODE_PLAYING &&
2698 level.game_engine_type == GAME_ENGINE_TYPE_RND)
2699 SetDrawtoField(DRAW_TO_FIELDBUFFER);
2702 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
2706 int graphic = el2preimg(element);
2708 getSizedGraphicSource(graphic, 0, tilesize, &src_bitmap, &src_x, &src_y);
2709 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
2712 void DrawLevel(int draw_background_mask)
2716 SetMainBackgroundImage(IMG_BACKGROUND_PLAYING);
2717 SetDrawBackgroundMask(draw_background_mask);
2721 for (x = BX1; x <= BX2; x++)
2722 for (y = BY1; y <= BY2; y++)
2723 DrawScreenField(x, y);
2725 redraw_mask |= REDRAW_FIELD;
2728 void DrawSizedLevel(int size_x, int size_y, int scroll_x, int scroll_y,
2733 for (x = 0; x < size_x; x++)
2734 for (y = 0; y < size_y; y++)
2735 DrawSizedElementOrWall(x, y, scroll_x, scroll_y, tilesize);
2737 redraw_mask |= REDRAW_FIELD;
2740 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
2744 for (x = 0; x < size_x; x++)
2745 for (y = 0; y < size_y; y++)
2746 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
2748 redraw_mask |= REDRAW_FIELD;
2751 static void DrawPreviewLevelPlayfieldExt(int from_x, int from_y)
2753 boolean show_level_border = (BorderElement != EL_EMPTY);
2754 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2755 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2756 int tile_size = preview.tile_size;
2757 int preview_width = preview.xsize * tile_size;
2758 int preview_height = preview.ysize * tile_size;
2759 int real_preview_xsize = MIN(level_xsize, preview.xsize);
2760 int real_preview_ysize = MIN(level_ysize, preview.ysize);
2761 int real_preview_width = real_preview_xsize * tile_size;
2762 int real_preview_height = real_preview_ysize * tile_size;
2763 int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
2764 int dst_y = SY + ALIGNED_YPOS(preview.y, preview_height, preview.valign);
2767 if (!IN_GFX_FIELD_FULL(dst_x, dst_y + preview_height - 1))
2770 DrawBackground(dst_x, dst_y, preview_width, preview_height);
2772 dst_x += (preview_width - real_preview_width) / 2;
2773 dst_y += (preview_height - real_preview_height) / 2;
2775 for (x = 0; x < real_preview_xsize; x++)
2777 for (y = 0; y < real_preview_ysize; y++)
2779 int lx = from_x + x + (show_level_border ? -1 : 0);
2780 int ly = from_y + y + (show_level_border ? -1 : 0);
2781 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
2782 getBorderElement(lx, ly));
2784 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
2785 element, tile_size);
2789 redraw_mask |= REDRAW_FIELD;
2792 #define MICROLABEL_EMPTY 0
2793 #define MICROLABEL_LEVEL_NAME 1
2794 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
2795 #define MICROLABEL_LEVEL_AUTHOR 3
2796 #define MICROLABEL_IMPORTED_FROM_HEAD 4
2797 #define MICROLABEL_IMPORTED_FROM 5
2798 #define MICROLABEL_IMPORTED_BY_HEAD 6
2799 #define MICROLABEL_IMPORTED_BY 7
2801 static int getMaxTextLength(struct TextPosInfo *pos, int font_nr)
2803 int max_text_width = SXSIZE;
2804 int font_width = getFontWidth(font_nr);
2806 if (pos->align == ALIGN_CENTER)
2807 max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
2808 else if (pos->align == ALIGN_RIGHT)
2809 max_text_width = pos->x;
2811 max_text_width = SXSIZE - pos->x;
2813 return max_text_width / font_width;
2816 static void DrawPreviewLevelLabelExt(int mode)
2818 struct TextPosInfo *pos = &menu.main.text.level_info_2;
2819 char label_text[MAX_OUTPUT_LINESIZE + 1];
2820 int max_len_label_text;
2821 int font_nr = pos->font;
2824 if (!IN_GFX_FIELD_FULL(pos->x, pos->y + getFontHeight(pos->font)))
2827 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
2828 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
2829 mode == MICROLABEL_IMPORTED_BY_HEAD)
2830 font_nr = pos->font_alt;
2832 max_len_label_text = getMaxTextLength(pos, font_nr);
2834 if (pos->size != -1)
2835 max_len_label_text = pos->size;
2837 for (i = 0; i < max_len_label_text; i++)
2838 label_text[i] = ' ';
2839 label_text[max_len_label_text] = '\0';
2841 if (strlen(label_text) > 0)
2842 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2845 (mode == MICROLABEL_LEVEL_NAME ? level.name :
2846 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
2847 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
2848 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
2849 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
2850 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
2851 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
2852 max_len_label_text);
2853 label_text[max_len_label_text] = '\0';
2855 if (strlen(label_text) > 0)
2856 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2858 redraw_mask |= REDRAW_FIELD;
2861 static void DrawPreviewLevelExt(boolean restart)
2863 static unsigned int scroll_delay = 0;
2864 static unsigned int label_delay = 0;
2865 static int from_x, from_y, scroll_direction;
2866 static int label_state, label_counter;
2867 unsigned int scroll_delay_value = preview.step_delay;
2868 boolean show_level_border = (BorderElement != EL_EMPTY);
2869 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2870 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2877 if (preview.anim_mode == ANIM_CENTERED)
2879 if (level_xsize > preview.xsize)
2880 from_x = (level_xsize - preview.xsize) / 2;
2881 if (level_ysize > preview.ysize)
2882 from_y = (level_ysize - preview.ysize) / 2;
2885 from_x += preview.xoffset;
2886 from_y += preview.yoffset;
2888 scroll_direction = MV_RIGHT;
2892 DrawPreviewLevelPlayfieldExt(from_x, from_y);
2893 DrawPreviewLevelLabelExt(label_state);
2895 /* initialize delay counters */
2896 DelayReached(&scroll_delay, 0);
2897 DelayReached(&label_delay, 0);
2899 if (leveldir_current->name)
2901 struct TextPosInfo *pos = &menu.main.text.level_info_1;
2902 char label_text[MAX_OUTPUT_LINESIZE + 1];
2903 int font_nr = pos->font;
2904 int max_len_label_text = getMaxTextLength(pos, font_nr);
2906 if (pos->size != -1)
2907 max_len_label_text = pos->size;
2909 strncpy(label_text, leveldir_current->name, max_len_label_text);
2910 label_text[max_len_label_text] = '\0';
2912 if (IN_GFX_FIELD_FULL(pos->x, pos->y + getFontHeight(pos->font)))
2913 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2919 /* scroll preview level, if needed */
2920 if (preview.anim_mode != ANIM_NONE &&
2921 (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
2922 DelayReached(&scroll_delay, scroll_delay_value))
2924 switch (scroll_direction)
2929 from_x -= preview.step_offset;
2930 from_x = (from_x < 0 ? 0 : from_x);
2933 scroll_direction = MV_UP;
2937 if (from_x < level_xsize - preview.xsize)
2939 from_x += preview.step_offset;
2940 from_x = (from_x > level_xsize - preview.xsize ?
2941 level_xsize - preview.xsize : from_x);
2944 scroll_direction = MV_DOWN;
2950 from_y -= preview.step_offset;
2951 from_y = (from_y < 0 ? 0 : from_y);
2954 scroll_direction = MV_RIGHT;
2958 if (from_y < level_ysize - preview.ysize)
2960 from_y += preview.step_offset;
2961 from_y = (from_y > level_ysize - preview.ysize ?
2962 level_ysize - preview.ysize : from_y);
2965 scroll_direction = MV_LEFT;
2972 DrawPreviewLevelPlayfieldExt(from_x, from_y);
2975 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
2976 /* redraw micro level label, if needed */
2977 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
2978 !strEqual(level.author, ANONYMOUS_NAME) &&
2979 !strEqual(level.author, leveldir_current->name) &&
2980 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
2982 int max_label_counter = 23;
2984 if (leveldir_current->imported_from != NULL &&
2985 strlen(leveldir_current->imported_from) > 0)
2986 max_label_counter += 14;
2987 if (leveldir_current->imported_by != NULL &&
2988 strlen(leveldir_current->imported_by) > 0)
2989 max_label_counter += 14;
2991 label_counter = (label_counter + 1) % max_label_counter;
2992 label_state = (label_counter >= 0 && label_counter <= 7 ?
2993 MICROLABEL_LEVEL_NAME :
2994 label_counter >= 9 && label_counter <= 12 ?
2995 MICROLABEL_LEVEL_AUTHOR_HEAD :
2996 label_counter >= 14 && label_counter <= 21 ?
2997 MICROLABEL_LEVEL_AUTHOR :
2998 label_counter >= 23 && label_counter <= 26 ?
2999 MICROLABEL_IMPORTED_FROM_HEAD :
3000 label_counter >= 28 && label_counter <= 35 ?
3001 MICROLABEL_IMPORTED_FROM :
3002 label_counter >= 37 && label_counter <= 40 ?
3003 MICROLABEL_IMPORTED_BY_HEAD :
3004 label_counter >= 42 && label_counter <= 49 ?
3005 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
3007 if (leveldir_current->imported_from == NULL &&
3008 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
3009 label_state == MICROLABEL_IMPORTED_FROM))
3010 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
3011 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
3013 DrawPreviewLevelLabelExt(label_state);
3017 void DrawPreviewLevelInitial()
3019 DrawPreviewLevelExt(TRUE);
3022 void DrawPreviewLevelAnimation()
3024 DrawPreviewLevelExt(FALSE);
3027 inline static void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
3028 int graphic, int sync_frame,
3031 int frame = getGraphicAnimationFrame(graphic, sync_frame);
3033 if (mask_mode == USE_MASKING)
3034 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
3036 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
3039 void DrawFixedGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
3040 int graphic, int sync_frame, int mask_mode)
3042 int frame = getGraphicAnimationFrame(graphic, sync_frame);
3044 if (mask_mode == USE_MASKING)
3045 DrawFixedGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
3047 DrawFixedGraphicExt(dst_bitmap, x, y, graphic, frame);
3050 inline static void DrawGraphicAnimation(int x, int y, int graphic)
3052 int lx = LEVELX(x), ly = LEVELY(y);
3054 if (!IN_SCR_FIELD(x, y))
3057 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
3058 graphic, GfxFrame[lx][ly], NO_MASKING);
3060 MarkTileDirty(x, y);
3063 void DrawFixedGraphicAnimation(int x, int y, int graphic)
3065 int lx = LEVELX(x), ly = LEVELY(y);
3067 if (!IN_SCR_FIELD(x, y))
3070 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
3071 graphic, GfxFrame[lx][ly], NO_MASKING);
3072 MarkTileDirty(x, y);
3075 void DrawLevelGraphicAnimation(int x, int y, int graphic)
3077 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
3080 void DrawLevelElementAnimation(int x, int y, int element)
3082 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
3084 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
3087 void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
3089 int sx = SCREENX(x), sy = SCREENY(y);
3091 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
3094 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
3097 DrawGraphicAnimation(sx, sy, graphic);
3100 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
3101 DrawLevelFieldCrumbled(x, y);
3103 if (GFX_CRUMBLED(Feld[x][y]))
3104 DrawLevelFieldCrumbled(x, y);
3108 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
3110 int sx = SCREENX(x), sy = SCREENY(y);
3113 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
3116 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
3118 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
3121 DrawGraphicAnimation(sx, sy, graphic);
3123 if (GFX_CRUMBLED(element))
3124 DrawLevelFieldCrumbled(x, y);
3127 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
3129 if (player->use_murphy)
3131 /* this works only because currently only one player can be "murphy" ... */
3132 static int last_horizontal_dir = MV_LEFT;
3133 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
3135 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3136 last_horizontal_dir = move_dir;
3138 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
3140 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
3142 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
3148 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
3151 static boolean equalGraphics(int graphic1, int graphic2)
3153 struct GraphicInfo *g1 = &graphic_info[graphic1];
3154 struct GraphicInfo *g2 = &graphic_info[graphic2];
3156 return (g1->bitmap == g2->bitmap &&
3157 g1->src_x == g2->src_x &&
3158 g1->src_y == g2->src_y &&
3159 g1->anim_frames == g2->anim_frames &&
3160 g1->anim_delay == g2->anim_delay &&
3161 g1->anim_mode == g2->anim_mode);
3164 void DrawAllPlayers()
3168 for (i = 0; i < MAX_PLAYERS; i++)
3169 if (stored_player[i].active)
3170 DrawPlayer(&stored_player[i]);
3173 void DrawPlayerField(int x, int y)
3175 if (!IS_PLAYER(x, y))
3178 DrawPlayer(PLAYERINFO(x, y));
3181 #define DRAW_PLAYER_OVER_PUSHED_ELEMENT 1
3183 void DrawPlayer(struct PlayerInfo *player)
3185 int jx = player->jx;
3186 int jy = player->jy;
3187 int move_dir = player->MovDir;
3188 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
3189 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
3190 int last_jx = (player->is_moving ? jx - dx : jx);
3191 int last_jy = (player->is_moving ? jy - dy : jy);
3192 int next_jx = jx + dx;
3193 int next_jy = jy + dy;
3194 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
3195 boolean player_is_opaque = FALSE;
3196 int sx = SCREENX(jx), sy = SCREENY(jy);
3197 int sxx = 0, syy = 0;
3198 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
3200 int action = ACTION_DEFAULT;
3201 int last_player_graphic = getPlayerGraphic(player, move_dir);
3202 int last_player_frame = player->Frame;
3205 /* GfxElement[][] is set to the element the player is digging or collecting;
3206 remove also for off-screen player if the player is not moving anymore */
3207 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
3208 GfxElement[jx][jy] = EL_UNDEFINED;
3210 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
3214 if (!IN_LEV_FIELD(jx, jy))
3216 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
3217 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
3218 printf("DrawPlayerField(): This should never happen!\n");
3223 if (element == EL_EXPLOSION)
3226 action = (player->is_pushing ? ACTION_PUSHING :
3227 player->is_digging ? ACTION_DIGGING :
3228 player->is_collecting ? ACTION_COLLECTING :
3229 player->is_moving ? ACTION_MOVING :
3230 player->is_snapping ? ACTION_SNAPPING :
3231 player->is_dropping ? ACTION_DROPPING :
3232 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
3234 if (player->is_waiting)
3235 move_dir = player->dir_waiting;
3237 InitPlayerGfxAnimation(player, action, move_dir);
3239 /* ----------------------------------------------------------------------- */
3240 /* draw things in the field the player is leaving, if needed */
3241 /* ----------------------------------------------------------------------- */
3243 if (player->is_moving)
3245 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
3247 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
3249 if (last_element == EL_DYNAMITE_ACTIVE ||
3250 last_element == EL_EM_DYNAMITE_ACTIVE ||
3251 last_element == EL_SP_DISK_RED_ACTIVE)
3252 DrawDynamite(last_jx, last_jy);
3254 DrawLevelFieldThruMask(last_jx, last_jy);
3256 else if (last_element == EL_DYNAMITE_ACTIVE ||
3257 last_element == EL_EM_DYNAMITE_ACTIVE ||
3258 last_element == EL_SP_DISK_RED_ACTIVE)
3259 DrawDynamite(last_jx, last_jy);
3261 /* !!! this is not enough to prevent flickering of players which are
3262 moving next to each others without a free tile between them -- this
3263 can only be solved by drawing all players layer by layer (first the
3264 background, then the foreground etc.) !!! => TODO */
3265 else if (!IS_PLAYER(last_jx, last_jy))
3266 DrawLevelField(last_jx, last_jy);
3269 DrawLevelField(last_jx, last_jy);
3272 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
3273 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
3276 if (!IN_SCR_FIELD(sx, sy))
3279 /* ----------------------------------------------------------------------- */
3280 /* draw things behind the player, if needed */
3281 /* ----------------------------------------------------------------------- */
3284 DrawLevelElement(jx, jy, Back[jx][jy]);
3285 else if (IS_ACTIVE_BOMB(element))
3286 DrawLevelElement(jx, jy, EL_EMPTY);
3289 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
3291 int old_element = GfxElement[jx][jy];
3292 int old_graphic = el_act_dir2img(old_element, action, move_dir);
3293 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
3295 if (GFX_CRUMBLED(old_element))
3296 DrawLevelFieldCrumbledDigging(jx, jy, move_dir, player->StepFrame);
3298 DrawGraphic(sx, sy, old_graphic, frame);
3300 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
3301 player_is_opaque = TRUE;
3305 GfxElement[jx][jy] = EL_UNDEFINED;
3307 /* make sure that pushed elements are drawn with correct frame rate */
3308 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
3310 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
3311 GfxFrame[jx][jy] = player->StepFrame;
3313 DrawLevelField(jx, jy);
3317 #if !DRAW_PLAYER_OVER_PUSHED_ELEMENT
3318 /* ----------------------------------------------------------------------- */
3319 /* draw player himself */
3320 /* ----------------------------------------------------------------------- */
3322 graphic = getPlayerGraphic(player, move_dir);
3324 /* in the case of changed player action or direction, prevent the current
3325 animation frame from being restarted for identical animations */
3326 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
3327 player->Frame = last_player_frame;
3329 frame = getGraphicAnimationFrame(graphic, player->Frame);
3333 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3334 sxx = player->GfxPos;
3336 syy = player->GfxPos;
3339 if (player_is_opaque)
3340 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
3342 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3344 if (SHIELD_ON(player))
3346 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
3347 IMG_SHIELD_NORMAL_ACTIVE);
3348 int frame = getGraphicAnimationFrame(graphic, -1);
3350 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3354 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
3357 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3358 sxx = player->GfxPos;
3360 syy = player->GfxPos;
3364 /* ----------------------------------------------------------------------- */
3365 /* draw things the player is pushing, if needed */
3366 /* ----------------------------------------------------------------------- */
3368 if (player->is_pushing && player->is_moving)
3370 int px = SCREENX(jx), py = SCREENY(jy);
3371 int pxx = (TILEX - ABS(sxx)) * dx;
3372 int pyy = (TILEY - ABS(syy)) * dy;
3373 int gfx_frame = GfxFrame[jx][jy];
3379 if (!IS_MOVING(jx, jy)) /* push movement already finished */
3381 element = Feld[next_jx][next_jy];
3382 gfx_frame = GfxFrame[next_jx][next_jy];
3385 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
3387 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
3388 frame = getGraphicAnimationFrame(graphic, sync_frame);
3390 /* draw background element under pushed element (like the Sokoban field) */
3391 if (game.use_masked_pushing && IS_MOVING(jx, jy))
3393 /* this allows transparent pushing animation over non-black background */
3396 DrawLevelElement(jx, jy, Back[jx][jy]);
3398 DrawLevelElement(jx, jy, EL_EMPTY);
3400 if (Back[next_jx][next_jy])
3401 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3403 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
3405 else if (Back[next_jx][next_jy])
3406 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3409 /* do not draw (EM style) pushing animation when pushing is finished */
3410 /* (two-tile animations usually do not contain start and end frame) */
3411 if (graphic_info[graphic].double_movement && !IS_MOVING(jx, jy))
3412 DrawLevelElement(next_jx, next_jy, Feld[next_jx][next_jy]);
3414 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3416 /* masked drawing is needed for EMC style (double) movement graphics */
3417 /* !!! (ONLY WHEN DRAWING PUSHED ELEMENT OVER THE PLAYER) !!! */
3418 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3422 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
3423 /* ----------------------------------------------------------------------- */
3424 /* draw player himself */
3425 /* ----------------------------------------------------------------------- */
3427 graphic = getPlayerGraphic(player, move_dir);
3429 /* in the case of changed player action or direction, prevent the current
3430 animation frame from being restarted for identical animations */
3431 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
3432 player->Frame = last_player_frame;
3434 frame = getGraphicAnimationFrame(graphic, player->Frame);
3438 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3439 sxx = player->GfxPos;
3441 syy = player->GfxPos;
3444 if (player_is_opaque)
3445 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
3447 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3449 if (SHIELD_ON(player))
3451 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
3452 IMG_SHIELD_NORMAL_ACTIVE);
3453 int frame = getGraphicAnimationFrame(graphic, -1);
3455 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3459 /* ----------------------------------------------------------------------- */
3460 /* draw things in front of player (active dynamite or dynabombs) */
3461 /* ----------------------------------------------------------------------- */
3463 if (IS_ACTIVE_BOMB(element))
3465 graphic = el2img(element);
3466 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
3468 if (game.emulation == EMU_SUPAPLEX)
3469 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
3471 DrawGraphicThruMask(sx, sy, graphic, frame);
3474 if (player_is_moving && last_element == EL_EXPLOSION)
3476 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
3477 GfxElement[last_jx][last_jy] : EL_EMPTY);
3478 int graphic = el_act2img(element, ACTION_EXPLODING);
3479 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
3480 int phase = ExplodePhase[last_jx][last_jy] - 1;
3481 int frame = getGraphicAnimationFrame(graphic, phase - delay);
3484 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
3487 /* ----------------------------------------------------------------------- */
3488 /* draw elements the player is just walking/passing through/under */
3489 /* ----------------------------------------------------------------------- */
3491 if (player_is_moving)
3493 /* handle the field the player is leaving ... */
3494 if (IS_ACCESSIBLE_INSIDE(last_element))
3495 DrawLevelField(last_jx, last_jy);
3496 else if (IS_ACCESSIBLE_UNDER(last_element))
3497 DrawLevelFieldThruMask(last_jx, last_jy);
3500 /* do not redraw accessible elements if the player is just pushing them */
3501 if (!player_is_moving || !player->is_pushing)
3503 /* ... and the field the player is entering */
3504 if (IS_ACCESSIBLE_INSIDE(element))
3505 DrawLevelField(jx, jy);
3506 else if (IS_ACCESSIBLE_UNDER(element))
3507 DrawLevelFieldThruMask(jx, jy);
3510 MarkTileDirty(sx, sy);
3513 /* ------------------------------------------------------------------------- */
3515 void WaitForEventToContinue()
3517 boolean still_wait = TRUE;
3519 /* simulate releasing mouse button over last gadget, if still pressed */
3521 HandleGadgets(-1, -1, 0);
3523 button_status = MB_RELEASED;
3537 case EVENT_BUTTONPRESS:
3538 case EVENT_KEYPRESS:
3542 case EVENT_KEYRELEASE:
3543 ClearPlayerAction();
3547 HandleOtherEvents(&event);
3551 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3560 #define MAX_REQUEST_LINES 13
3561 #define MAX_REQUEST_LINE_FONT1_LEN 7
3562 #define MAX_REQUEST_LINE_FONT2_LEN 10
3564 static int RequestHandleEvents(unsigned int req_state)
3566 boolean level_solved = (game_status == GAME_MODE_PLAYING &&
3567 local_player->LevelSolved_GameEnd);
3568 int width = request.width;
3569 int height = request.height;
3573 setRequestPosition(&sx, &sy, FALSE);
3575 button_status = MB_RELEASED;
3577 request_gadget_id = -1;
3584 SetDrawtoField(DRAW_TO_FIELDBUFFER);
3586 HandleGameActions();
3588 SetDrawtoField(DRAW_TO_BACKBUFFER);
3590 if (global.use_envelope_request)
3592 /* copy current state of request area to middle of playfield area */
3593 BlitBitmap(bitmap_db_cross, drawto, sx, sy, width, height, sx, sy);
3601 while (NextValidEvent(&event))
3605 case EVENT_BUTTONPRESS:
3606 case EVENT_BUTTONRELEASE:
3607 case EVENT_MOTIONNOTIFY:
3611 if (event.type == EVENT_MOTIONNOTIFY)
3616 motion_status = TRUE;
3617 mx = ((MotionEvent *) &event)->x;
3618 my = ((MotionEvent *) &event)->y;
3622 motion_status = FALSE;
3623 mx = ((ButtonEvent *) &event)->x;
3624 my = ((ButtonEvent *) &event)->y;
3625 if (event.type == EVENT_BUTTONPRESS)
3626 button_status = ((ButtonEvent *) &event)->button;
3628 button_status = MB_RELEASED;
3631 /* this sets 'request_gadget_id' */
3632 HandleGadgets(mx, my, button_status);
3634 switch (request_gadget_id)
3636 case TOOL_CTRL_ID_YES:
3639 case TOOL_CTRL_ID_NO:
3642 case TOOL_CTRL_ID_CONFIRM:
3643 result = TRUE | FALSE;
3646 case TOOL_CTRL_ID_PLAYER_1:
3649 case TOOL_CTRL_ID_PLAYER_2:
3652 case TOOL_CTRL_ID_PLAYER_3:
3655 case TOOL_CTRL_ID_PLAYER_4:
3666 case EVENT_KEYPRESS:
3667 switch (GetEventKey((KeyEvent *)&event, TRUE))
3670 if (req_state & REQ_CONFIRM)
3675 #if defined(TARGET_SDL2)
3682 #if defined(TARGET_SDL2)
3692 if (req_state & REQ_PLAYER)
3696 case EVENT_KEYRELEASE:
3697 ClearPlayerAction();
3701 HandleOtherEvents(&event);
3706 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3708 int joy = AnyJoystick();
3710 if (joy & JOY_BUTTON_1)
3712 else if (joy & JOY_BUTTON_2)
3718 if (global.use_envelope_request)
3720 /* copy back current state of pressed buttons inside request area */
3721 BlitBitmap(drawto, bitmap_db_cross, sx, sy, width, height, sx, sy);
3731 static boolean RequestDoor(char *text, unsigned int req_state)
3733 unsigned int old_door_state;
3734 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
3735 int font_nr = FONT_TEXT_2;
3740 if (maxWordLengthInString(text) > MAX_REQUEST_LINE_FONT1_LEN)
3742 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
3743 font_nr = FONT_TEXT_1;
3746 if (game_status == GAME_MODE_PLAYING)
3747 BlitScreenToBitmap(backbuffer);
3749 /* disable deactivated drawing when quick-loading level tape recording */
3750 if (tape.playing && tape.deactivate_display)
3751 TapeDeactivateDisplayOff(TRUE);
3753 SetMouseCursor(CURSOR_DEFAULT);
3755 #if defined(NETWORK_AVALIABLE)
3756 /* pause network game while waiting for request to answer */
3757 if (options.network &&
3758 game_status == GAME_MODE_PLAYING &&
3759 req_state & REQUEST_WAIT_FOR_INPUT)
3760 SendToServer_PausePlaying();
3763 old_door_state = GetDoorState();
3765 /* simulate releasing mouse button over last gadget, if still pressed */
3767 HandleGadgets(-1, -1, 0);
3771 /* draw released gadget before proceeding */
3774 if (old_door_state & DOOR_OPEN_1)
3776 CloseDoor(DOOR_CLOSE_1);
3778 /* save old door content */
3779 BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
3780 0 * DXSIZE, 0, DXSIZE, DYSIZE, 1 * DXSIZE, 0);
3783 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
3784 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3786 /* clear door drawing field */
3787 DrawBackground(DX, DY, DXSIZE, DYSIZE);
3789 /* force DOOR font inside door area */
3790 SetFontStatus(GAME_MODE_PSEUDO_DOOR);
3792 /* write text for request */
3793 for (text_ptr = text, ty = 0; ty < MAX_REQUEST_LINES; ty++)
3795 char text_line[max_request_line_len + 1];
3801 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
3803 tc = *(text_ptr + tx);
3804 // if (!tc || tc == ' ')
3805 if (!tc || tc == ' ' || tc == '?' || tc == '!')
3809 if ((tc == '?' || tc == '!') && tl == 0)
3819 strncpy(text_line, text_ptr, tl);
3822 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
3823 DY + 8 + ty * (getFontHeight(font_nr) + 2),
3824 text_line, font_nr);
3826 text_ptr += tl + (tc == ' ' ? 1 : 0);
3827 // text_ptr += tl + (tc == ' ' || tc == '?' || tc == '!' ? 1 : 0);
3832 if (req_state & REQ_ASK)
3834 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
3835 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
3837 else if (req_state & REQ_CONFIRM)
3839 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
3841 else if (req_state & REQ_PLAYER)
3843 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
3844 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
3845 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
3846 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
3849 /* copy request gadgets to door backbuffer */
3850 BlitBitmap(drawto, bitmap_db_door_1, DX, DY, DXSIZE, DYSIZE, 0, 0);
3852 OpenDoor(DOOR_OPEN_1);
3854 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
3856 if (game_status == GAME_MODE_PLAYING)
3858 SetPanelBackground();
3859 SetDrawBackgroundMask(REDRAW_DOOR_1);
3863 SetDrawBackgroundMask(REDRAW_FIELD);
3869 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3871 // ---------- handle request buttons ----------
3872 result = RequestHandleEvents(req_state);
3876 if (!(req_state & REQ_STAY_OPEN))
3878 CloseDoor(DOOR_CLOSE_1);
3880 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
3881 (req_state & REQ_REOPEN))
3882 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
3887 if (game_status == GAME_MODE_PLAYING)
3889 SetPanelBackground();
3890 SetDrawBackgroundMask(REDRAW_DOOR_1);
3894 SetDrawBackgroundMask(REDRAW_FIELD);
3897 #if defined(NETWORK_AVALIABLE)
3898 /* continue network game after request */
3899 if (options.network &&
3900 game_status == GAME_MODE_PLAYING &&
3901 req_state & REQUEST_WAIT_FOR_INPUT)
3902 SendToServer_ContinuePlaying();
3905 /* restore deactivated drawing when quick-loading level tape recording */
3906 if (tape.playing && tape.deactivate_display)
3907 TapeDeactivateDisplayOn();
3912 static boolean RequestEnvelope(char *text, unsigned int req_state)
3916 if (game_status == GAME_MODE_PLAYING)
3917 BlitScreenToBitmap(backbuffer);
3919 /* disable deactivated drawing when quick-loading level tape recording */
3920 if (tape.playing && tape.deactivate_display)
3921 TapeDeactivateDisplayOff(TRUE);
3923 SetMouseCursor(CURSOR_DEFAULT);
3925 #if defined(NETWORK_AVALIABLE)
3926 /* pause network game while waiting for request to answer */
3927 if (options.network &&
3928 game_status == GAME_MODE_PLAYING &&
3929 req_state & REQUEST_WAIT_FOR_INPUT)
3930 SendToServer_PausePlaying();
3933 /* simulate releasing mouse button over last gadget, if still pressed */
3935 HandleGadgets(-1, -1, 0);
3939 // (replace with setting corresponding request background)
3940 // SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
3941 // SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3943 /* clear door drawing field */
3944 // DrawBackground(DX, DY, DXSIZE, DYSIZE);
3946 ShowEnvelopeRequest(text, req_state, ACTION_OPENING);
3948 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
3950 if (game_status == GAME_MODE_PLAYING)
3952 SetPanelBackground();
3953 SetDrawBackgroundMask(REDRAW_DOOR_1);
3957 SetDrawBackgroundMask(REDRAW_FIELD);
3963 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3965 // ---------- handle request buttons ----------
3966 result = RequestHandleEvents(req_state);
3970 ShowEnvelopeRequest(text, req_state, ACTION_CLOSING);
3974 if (game_status == GAME_MODE_PLAYING)
3976 SetPanelBackground();
3977 SetDrawBackgroundMask(REDRAW_DOOR_1);
3981 SetDrawBackgroundMask(REDRAW_FIELD);
3984 #if defined(NETWORK_AVALIABLE)
3985 /* continue network game after request */
3986 if (options.network &&
3987 game_status == GAME_MODE_PLAYING &&
3988 req_state & REQUEST_WAIT_FOR_INPUT)
3989 SendToServer_ContinuePlaying();
3992 /* restore deactivated drawing when quick-loading level tape recording */
3993 if (tape.playing && tape.deactivate_display)
3994 TapeDeactivateDisplayOn();
3999 boolean Request(char *text, unsigned int req_state)
4001 if (global.use_envelope_request)
4002 return RequestEnvelope(text, req_state);
4004 return RequestDoor(text, req_state);
4007 static int compareDoorPartOrderInfo(const void *object1, const void *object2)
4009 const struct DoorPartOrderInfo *dpo1 = (struct DoorPartOrderInfo *)object1;
4010 const struct DoorPartOrderInfo *dpo2 = (struct DoorPartOrderInfo *)object2;
4013 if (dpo1->sort_priority != dpo2->sort_priority)
4014 compare_result = dpo1->sort_priority - dpo2->sort_priority;
4016 compare_result = dpo1->nr - dpo2->nr;
4018 return compare_result;
4021 void InitGraphicCompatibilityInfo_Doors()
4027 struct DoorInfo *door;
4031 { DOOR_1, IMG_GFX_DOOR_1_PART_1, IMG_GFX_DOOR_1_PART_8, &door_1 },
4032 { DOOR_2, IMG_GFX_DOOR_2_PART_1, IMG_GFX_DOOR_2_PART_8, &door_2 },
4034 { -1, -1, -1, NULL }
4036 struct Rect door_rect_list[] =
4038 { DX, DY, DXSIZE, DYSIZE },
4039 { VX, VY, VXSIZE, VYSIZE }
4043 for (i = 0; doors[i].door_token != -1; i++)
4045 int door_token = doors[i].door_token;
4046 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
4047 int part_1 = doors[i].part_1;
4048 int part_8 = doors[i].part_8;
4049 int part_2 = part_1 + 1;
4050 int part_3 = part_1 + 2;
4051 struct DoorInfo *door = doors[i].door;
4052 struct Rect *door_rect = &door_rect_list[door_index];
4053 boolean door_gfx_redefined = FALSE;
4055 /* check if any door part graphic definitions have been redefined */
4057 for (j = 0; door_part_controls[j].door_token != -1; j++)
4059 struct DoorPartControlInfo *dpc = &door_part_controls[j];
4060 struct FileInfo *fi = getImageListEntryFromImageID(dpc->graphic);
4062 if (dpc->door_token == door_token && fi->redefined)
4063 door_gfx_redefined = TRUE;
4066 /* check for old-style door graphic/animation modifications */
4068 if (!door_gfx_redefined)
4070 if (door->anim_mode & ANIM_STATIC_PANEL)
4072 door->panel.step_xoffset = 0;
4073 door->panel.step_yoffset = 0;
4076 if (door->anim_mode & (ANIM_HORIZONTAL | ANIM_VERTICAL))
4078 struct GraphicInfo *g_part_1 = &graphic_info[part_1];
4079 struct GraphicInfo *g_part_2 = &graphic_info[part_2];
4080 int num_door_steps, num_panel_steps;
4082 /* remove door part graphics other than the two default wings */
4084 for (j = 0; door_part_controls[j].door_token != -1; j++)
4086 struct DoorPartControlInfo *dpc = &door_part_controls[j];
4087 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4089 if (dpc->graphic >= part_3 &&
4090 dpc->graphic <= part_8)
4094 /* set graphics and screen positions of the default wings */
4096 g_part_1->width = door_rect->width;
4097 g_part_1->height = door_rect->height;
4098 g_part_2->width = door_rect->width;
4099 g_part_2->height = door_rect->height;
4100 g_part_2->src_x = door_rect->width;
4101 g_part_2->src_y = g_part_1->src_y;
4103 door->part_2.x = door->part_1.x;
4104 door->part_2.y = door->part_1.y;
4106 if (door->width != -1)
4108 g_part_1->width = door->width;
4109 g_part_2->width = door->width;
4111 // special treatment for graphics and screen position of right wing
4112 g_part_2->src_x += door_rect->width - door->width;
4113 door->part_2.x += door_rect->width - door->width;
4116 if (door->height != -1)
4118 g_part_1->height = door->height;
4119 g_part_2->height = door->height;
4121 // special treatment for graphics and screen position of bottom wing
4122 g_part_2->src_y += door_rect->height - door->height;
4123 door->part_2.y += door_rect->height - door->height;
4126 /* set animation delays for the default wings and panels */
4128 door->part_1.step_delay = door->step_delay;
4129 door->part_2.step_delay = door->step_delay;
4130 door->panel.step_delay = door->step_delay;
4132 /* set animation draw order for the default wings */
4134 door->part_1.sort_priority = 2; /* draw left wing over ... */
4135 door->part_2.sort_priority = 1; /* ... right wing */
4137 /* set animation draw offset for the default wings */
4139 if (door->anim_mode & ANIM_HORIZONTAL)
4141 door->part_1.step_xoffset = door->step_offset;
4142 door->part_1.step_yoffset = 0;
4143 door->part_2.step_xoffset = door->step_offset * -1;
4144 door->part_2.step_yoffset = 0;
4146 num_door_steps = g_part_1->width / door->step_offset;
4148 else // ANIM_VERTICAL
4150 door->part_1.step_xoffset = 0;
4151 door->part_1.step_yoffset = door->step_offset;
4152 door->part_2.step_xoffset = 0;
4153 door->part_2.step_yoffset = door->step_offset * -1;
4155 num_door_steps = g_part_1->height / door->step_offset;
4158 /* set animation draw offset for the default panels */
4160 if (door->step_offset > 1)
4162 num_panel_steps = 2 * door_rect->height / door->step_offset;
4163 door->panel.start_step = num_panel_steps - num_door_steps;
4164 door->panel.start_step_closing = door->panel.start_step;
4168 num_panel_steps = door_rect->height / door->step_offset;
4169 door->panel.start_step = num_panel_steps - num_door_steps / 2;
4170 door->panel.start_step_closing = door->panel.start_step;
4171 door->panel.step_delay *= 2;
4182 for (i = 0; door_part_controls[i].door_token != -1; i++)
4184 struct DoorPartControlInfo *dpc = &door_part_controls[i];
4185 struct DoorPartOrderInfo *dpo = &door_part_order[i];
4187 /* initialize "start_step_opening" and "start_step_closing", if needed */
4188 if (dpc->pos->start_step_opening == 0 &&
4189 dpc->pos->start_step_closing == 0)
4191 // dpc->pos->start_step_opening = dpc->pos->start_step;
4192 dpc->pos->start_step_closing = dpc->pos->start_step;
4195 /* fill structure for door part draw order (sorted below) */
4197 dpo->sort_priority = dpc->pos->sort_priority;
4200 /* sort door part controls according to sort_priority and graphic number */
4201 qsort(door_part_order, MAX_DOOR_PARTS,
4202 sizeof(struct DoorPartOrderInfo), compareDoorPartOrderInfo);
4205 unsigned int OpenDoor(unsigned int door_state)
4207 if (door_state & DOOR_COPY_BACK)
4209 if (door_state & DOOR_OPEN_1)
4210 BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
4211 1 * DXSIZE, 0, DXSIZE, DYSIZE, 0 * DXSIZE, 0);
4213 if (door_state & DOOR_OPEN_2)
4214 BlitBitmap(bitmap_db_door_2, bitmap_db_door_2,
4215 1 * VXSIZE, 0, VXSIZE, VYSIZE, 0 * VXSIZE, 0);
4217 door_state &= ~DOOR_COPY_BACK;
4220 return MoveDoor(door_state);
4223 unsigned int CloseDoor(unsigned int door_state)
4225 unsigned int old_door_state = GetDoorState();
4227 if (!(door_state & DOOR_NO_COPY_BACK))
4229 if (old_door_state & DOOR_OPEN_1)
4230 BlitBitmap(backbuffer, bitmap_db_door_1,
4231 DX, DY, DXSIZE, DYSIZE, 0, 0);
4233 if (old_door_state & DOOR_OPEN_2)
4234 BlitBitmap(backbuffer, bitmap_db_door_2,
4235 VX, VY, VXSIZE, VYSIZE, 0, 0);
4237 door_state &= ~DOOR_NO_COPY_BACK;
4240 return MoveDoor(door_state);
4243 unsigned int GetDoorState()
4245 return MoveDoor(DOOR_GET_STATE);
4248 unsigned int SetDoorState(unsigned int door_state)
4250 return MoveDoor(door_state | DOOR_SET_STATE);
4253 int euclid(int a, int b)
4255 return (b ? euclid(b, a % b) : a);
4258 unsigned int MoveDoor(unsigned int door_state)
4260 struct Rect door_rect_list[] =
4262 { DX, DY, DXSIZE, DYSIZE },
4263 { VX, VY, VXSIZE, VYSIZE }
4265 static int door1 = DOOR_CLOSE_1;
4266 static int door2 = DOOR_CLOSE_2;
4267 unsigned int door_delay = 0;
4268 unsigned int door_delay_value;
4271 if (door_state == DOOR_GET_STATE)
4272 return (door1 | door2);
4274 if (door_state & DOOR_SET_STATE)
4276 if (door_state & DOOR_ACTION_1)
4277 door1 = door_state & DOOR_ACTION_1;
4278 if (door_state & DOOR_ACTION_2)
4279 door2 = door_state & DOOR_ACTION_2;
4281 return (door1 | door2);
4284 if (!(door_state & DOOR_FORCE_REDRAW))
4286 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
4287 door_state &= ~DOOR_OPEN_1;
4288 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
4289 door_state &= ~DOOR_CLOSE_1;
4290 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
4291 door_state &= ~DOOR_OPEN_2;
4292 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
4293 door_state &= ~DOOR_CLOSE_2;
4296 if (global.autoplay_leveldir)
4298 door_state |= DOOR_NO_DELAY;
4299 door_state &= ~DOOR_CLOSE_ALL;
4302 if (game_status == GAME_MODE_EDITOR)
4303 door_state |= DOOR_NO_DELAY;
4305 if (door_state & DOOR_ACTION)
4307 boolean door_panel_drawn[NUM_DOORS];
4308 boolean panel_has_doors[NUM_DOORS];
4309 boolean door_part_skip[MAX_DOOR_PARTS];
4310 boolean door_part_done[MAX_DOOR_PARTS];
4311 boolean door_part_done_all;
4312 int num_steps[MAX_DOOR_PARTS];
4313 int max_move_delay = 0; // delay for complete animations of all doors
4314 int max_step_delay = 0; // delay (ms) between two animation frames
4315 int num_move_steps = 0; // number of animation steps for all doors
4316 int max_move_delay_doors_only = 0; // delay for doors only (no panel)
4317 int num_move_steps_doors_only = 0; // steps for doors only (no panel)
4318 int current_move_delay = 0;
4322 for (i = 0; i < NUM_DOORS; i++)
4323 panel_has_doors[i] = FALSE;
4325 for (i = 0; i < MAX_DOOR_PARTS; i++)
4327 struct DoorPartControlInfo *dpc = &door_part_controls[i];
4328 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4329 int door_token = dpc->door_token;
4331 door_part_done[i] = FALSE;
4332 door_part_skip[i] = (!(door_state & door_token) ||
4336 for (i = 0; i < MAX_DOOR_PARTS; i++)
4338 int nr = door_part_order[i].nr;
4339 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
4340 struct DoorPartPosInfo *pos = dpc->pos;
4341 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4342 int door_token = dpc->door_token;
4343 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
4344 boolean is_panel = DOOR_PART_IS_PANEL(nr);
4345 int step_xoffset = ABS(pos->step_xoffset);
4346 int step_yoffset = ABS(pos->step_yoffset);
4347 int step_delay = pos->step_delay;
4348 int current_door_state = door_state & door_token;
4349 boolean door_opening = ((current_door_state & DOOR_OPEN) != 0);
4350 boolean door_closing = ((current_door_state & DOOR_CLOSE) != 0);
4351 boolean part_opening = (is_panel ? door_closing : door_opening);
4352 int start_step = (part_opening ? pos->start_step_opening :
4353 pos->start_step_closing);
4354 float move_xsize = (step_xoffset ? g->width : 0);
4355 float move_ysize = (step_yoffset ? g->height : 0);
4356 int move_xsteps = (step_xoffset ? ceil(move_xsize / step_xoffset) : 0);
4357 int move_ysteps = (step_yoffset ? ceil(move_ysize / step_yoffset) : 0);
4358 int move_steps = (move_xsteps && move_ysteps ?
4359 MIN(move_xsteps, move_ysteps) :
4360 move_xsteps ? move_xsteps : move_ysteps) - start_step;
4361 int move_delay = move_steps * step_delay;
4363 if (door_part_skip[nr])
4366 max_move_delay = MAX(max_move_delay, move_delay);
4367 max_step_delay = (max_step_delay == 0 ? step_delay :
4368 euclid(max_step_delay, step_delay));
4369 num_steps[nr] = move_steps;
4373 max_move_delay_doors_only = MAX(max_move_delay_doors_only, move_delay);
4375 panel_has_doors[door_index] = TRUE;
4379 max_step_delay = MAX(1, max_step_delay); // prevent division by zero
4381 num_move_steps = max_move_delay / max_step_delay;
4382 num_move_steps_doors_only = max_move_delay_doors_only / max_step_delay;
4384 door_delay_value = max_step_delay;
4386 if ((door_state & DOOR_NO_DELAY) || setup.quick_doors)
4388 start = num_move_steps - 1;
4392 /* opening door sound has priority over simultaneously closing door */
4393 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
4394 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
4395 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
4396 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
4399 for (k = start; k < num_move_steps; k++)
4401 int last_frame = num_move_steps - 1; // last frame of this "for" loop
4403 door_part_done_all = TRUE;
4405 for (i = 0; i < NUM_DOORS; i++)
4406 door_panel_drawn[i] = FALSE;
4408 for (i = 0; i < MAX_DOOR_PARTS; i++)
4410 int nr = door_part_order[i].nr;
4411 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
4412 struct DoorPartPosInfo *pos = dpc->pos;
4413 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4414 int door_token = dpc->door_token;
4415 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
4416 boolean is_panel = DOOR_PART_IS_PANEL(nr);
4417 boolean is_panel_and_door_has_closed = FALSE;
4418 struct Rect *door_rect = &door_rect_list[door_index];
4419 Bitmap *bitmap_db_door = (door_token == DOOR_1 ? bitmap_db_door_1 :
4421 Bitmap *bitmap = (is_panel ? bitmap_db_door : g->bitmap);
4422 int current_door_state = door_state & door_token;
4423 boolean door_opening = ((current_door_state & DOOR_OPEN) != 0);
4424 boolean door_closing = !door_opening;
4425 boolean part_opening = (is_panel ? door_closing : door_opening);
4426 boolean part_closing = !part_opening;
4427 int start_step = (part_opening ? pos->start_step_opening :
4428 pos->start_step_closing);
4429 int step_delay = pos->step_delay;
4430 int step_factor = step_delay / max_step_delay;
4431 int k1 = (step_factor ? k / step_factor + 1 : k);
4432 int k2 = (part_opening ? k1 + start_step : num_steps[nr] - k1);
4433 int kk = MAX(0, k2);
4436 int src_x, src_y, src_xx, src_yy;
4437 int dst_x, dst_y, dst_xx, dst_yy;
4440 if (door_part_skip[nr])
4443 if (!(door_state & door_token))
4451 int k2_door = (door_opening ? k : num_move_steps_doors_only - k - 1);
4452 int kk_door = MAX(0, k2_door);
4453 int sync_frame = kk_door * door_delay_value;
4454 int frame = getGraphicAnimationFrame(dpc->graphic, sync_frame);
4456 getGraphicSource(dpc->graphic, frame, &bitmap, &g_src_x, &g_src_y);
4461 if (!door_panel_drawn[door_index])
4463 ClearRectangle(drawto, door_rect->x, door_rect->y,
4464 door_rect->width, door_rect->height);
4466 door_panel_drawn[door_index] = TRUE;
4469 // draw opening or closing door parts
4471 if (pos->step_xoffset < 0) // door part on right side
4474 dst_xx = pos->x + ABS(kk * pos->step_xoffset);
4477 if (dst_xx + width > door_rect->width)
4478 width = door_rect->width - dst_xx;
4480 else // door part on left side
4483 dst_xx = pos->x - kk * pos->step_xoffset;
4487 src_xx = ABS(dst_xx);
4491 width = g->width - src_xx;
4493 if (width > door_rect->width)
4494 width = door_rect->width;
4496 // printf("::: k == %d [%d] \n", k, start_step);
4499 if (pos->step_yoffset < 0) // door part on bottom side
4502 dst_yy = pos->y + ABS(kk * pos->step_yoffset);
4505 if (dst_yy + height > door_rect->height)
4506 height = door_rect->height - dst_yy;
4508 else // door part on top side
4511 dst_yy = pos->y - kk * pos->step_yoffset;
4515 src_yy = ABS(dst_yy);
4519 height = g->height - src_yy;
4522 src_x = g_src_x + src_xx;
4523 src_y = g_src_y + src_yy;
4525 dst_x = door_rect->x + dst_xx;
4526 dst_y = door_rect->y + dst_yy;
4528 is_panel_and_door_has_closed =
4531 panel_has_doors[door_index] &&
4532 k >= num_move_steps_doors_only - 1);
4534 if (width >= 0 && width <= g->width &&
4535 height >= 0 && height <= g->height &&
4536 !is_panel_and_door_has_closed)
4538 if (is_panel || !pos->draw_masked)
4539 BlitBitmap(bitmap, drawto, src_x, src_y, width, height,
4542 BlitBitmapMasked(bitmap, drawto, src_x, src_y, width, height,
4546 redraw_mask |= REDRAW_DOOR_FROM_TOKEN(door_token);
4548 if ((part_opening && (width < 0 || height < 0)) ||
4549 (part_closing && (width >= g->width && height >= g->height)))
4550 door_part_done[nr] = TRUE;
4552 // continue door part animations, but not panel after door has closed
4553 if (!door_part_done[nr] && !is_panel_and_door_has_closed)
4554 door_part_done_all = FALSE;
4557 if (!(door_state & DOOR_NO_DELAY))
4561 SkipUntilDelayReached(&door_delay, door_delay_value, &k, last_frame);
4563 current_move_delay += max_step_delay;
4566 if (door_part_done_all)
4571 if (door_state & DOOR_ACTION_1)
4572 door1 = door_state & DOOR_ACTION_1;
4573 if (door_state & DOOR_ACTION_2)
4574 door2 = door_state & DOOR_ACTION_2;
4576 // draw masked border over door area
4577 DrawMaskedBorder(REDRAW_DOOR_1);
4578 DrawMaskedBorder(REDRAW_DOOR_2);
4580 return (door1 | door2);
4583 static boolean useSpecialEditorDoor()
4585 int graphic = IMG_GLOBAL_BORDER_EDITOR;
4586 boolean redefined = getImageListEntryFromImageID(graphic)->redefined;
4588 // do not draw special editor door if editor border defined or redefined
4589 if (graphic_info[graphic].bitmap != NULL || redefined)
4592 // do not draw special editor door if global border defined to be empty
4593 if (graphic_info[IMG_GLOBAL_BORDER].bitmap == NULL)
4596 // do not draw special editor door if viewport definitions do not match
4600 EY + EYSIZE != VY + VYSIZE)
4606 void DrawSpecialEditorDoor()
4608 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
4609 int top_border_width = gfx1->width;
4610 int top_border_height = gfx1->height;
4611 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
4612 int ex = EX - outer_border;
4613 int ey = EY - outer_border;
4614 int vy = VY - outer_border;
4615 int exsize = EXSIZE + 2 * outer_border;
4617 if (!useSpecialEditorDoor())
4620 /* draw bigger level editor toolbox window */
4621 BlitBitmap(gfx1->bitmap, drawto, gfx1->src_x, gfx1->src_y,
4622 top_border_width, top_border_height, ex, ey - top_border_height);
4623 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto, ex, vy,
4624 exsize, EYSIZE - VYSIZE + outer_border, ex, ey);
4626 redraw_mask |= REDRAW_ALL;
4629 void UndrawSpecialEditorDoor()
4631 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
4632 int top_border_width = gfx1->width;
4633 int top_border_height = gfx1->height;
4634 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
4635 int ex = EX - outer_border;
4636 int ey = EY - outer_border;
4637 int ey_top = ey - top_border_height;
4638 int exsize = EXSIZE + 2 * outer_border;
4639 int eysize = EYSIZE + 2 * outer_border;
4641 if (!useSpecialEditorDoor())
4644 /* draw normal tape recorder window */
4645 if (graphic_info[IMG_GLOBAL_BORDER].bitmap)
4647 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
4648 ex, ey_top, top_border_width, top_border_height,
4650 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
4651 ex, ey, exsize, eysize, ex, ey);
4655 // if screen background is set to "[NONE]", clear editor toolbox window
4656 ClearRectangle(drawto, ex, ey_top, top_border_width, top_border_height);
4657 ClearRectangle(drawto, ex, ey, exsize, eysize);
4660 redraw_mask |= REDRAW_ALL;
4664 /* ---------- new tool button stuff ---------------------------------------- */
4669 struct TextPosInfo *pos;
4672 } toolbutton_info[NUM_TOOL_BUTTONS] =
4675 IMG_GFX_REQUEST_BUTTON_YES, &request.button.yes,
4676 TOOL_CTRL_ID_YES, "yes"
4679 IMG_GFX_REQUEST_BUTTON_NO, &request.button.no,
4680 TOOL_CTRL_ID_NO, "no"
4683 IMG_GFX_REQUEST_BUTTON_CONFIRM, &request.button.confirm,
4684 TOOL_CTRL_ID_CONFIRM, "confirm"
4687 IMG_GFX_REQUEST_BUTTON_PLAYER_1, &request.button.player_1,
4688 TOOL_CTRL_ID_PLAYER_1, "player 1"
4691 IMG_GFX_REQUEST_BUTTON_PLAYER_2, &request.button.player_2,
4692 TOOL_CTRL_ID_PLAYER_2, "player 2"
4695 IMG_GFX_REQUEST_BUTTON_PLAYER_3, &request.button.player_3,
4696 TOOL_CTRL_ID_PLAYER_3, "player 3"
4699 IMG_GFX_REQUEST_BUTTON_PLAYER_4, &request.button.player_4,
4700 TOOL_CTRL_ID_PLAYER_4, "player 4"
4704 void CreateToolButtons()
4708 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4710 struct GraphicInfo *gfx = &graphic_info[toolbutton_info[i].graphic];
4711 struct TextPosInfo *pos = toolbutton_info[i].pos;
4712 struct GadgetInfo *gi;
4713 Bitmap *deco_bitmap = None;
4714 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
4715 unsigned int event_mask = GD_EVENT_RELEASED;
4718 int gd_x = gfx->src_x;
4719 int gd_y = gfx->src_y;
4720 int gd_xp = gfx->src_x + gfx->pressed_xoffset;
4721 int gd_yp = gfx->src_y + gfx->pressed_yoffset;
4724 if (global.use_envelope_request)
4725 setRequestPosition(&dx, &dy, TRUE);
4727 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
4729 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
4731 getSizedGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr), 0,
4732 pos->size, &deco_bitmap, &deco_x, &deco_y);
4733 deco_xpos = (gfx->width - pos->size) / 2;
4734 deco_ypos = (gfx->height - pos->size) / 2;
4737 gi = CreateGadget(GDI_CUSTOM_ID, id,
4738 GDI_INFO_TEXT, toolbutton_info[i].infotext,
4739 GDI_X, dx + GDI_ACTIVE_POS(pos->x),
4740 GDI_Y, dy + GDI_ACTIVE_POS(pos->y),
4741 GDI_WIDTH, gfx->width,
4742 GDI_HEIGHT, gfx->height,
4743 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
4744 GDI_STATE, GD_BUTTON_UNPRESSED,
4745 GDI_DESIGN_UNPRESSED, gfx->bitmap, gd_x, gd_y,
4746 GDI_DESIGN_PRESSED, gfx->bitmap, gd_xp, gd_yp,
4747 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
4748 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
4749 GDI_DECORATION_SIZE, pos->size, pos->size,
4750 GDI_DECORATION_SHIFTING, 1, 1,
4751 GDI_DIRECT_DRAW, FALSE,
4752 GDI_EVENT_MASK, event_mask,
4753 GDI_CALLBACK_ACTION, HandleToolButtons,
4757 Error(ERR_EXIT, "cannot create gadget");
4759 tool_gadget[id] = gi;
4763 void FreeToolButtons()
4767 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4768 FreeGadget(tool_gadget[i]);
4771 static void UnmapToolButtons()
4775 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4776 UnmapGadget(tool_gadget[i]);
4779 static void HandleToolButtons(struct GadgetInfo *gi)
4781 request_gadget_id = gi->custom_id;
4784 static struct Mapping_EM_to_RND_object
4787 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
4788 boolean is_backside; /* backside of moving element */
4794 em_object_mapping_list[] =
4797 Xblank, TRUE, FALSE,
4801 Yacid_splash_eB, FALSE, FALSE,
4802 EL_ACID_SPLASH_RIGHT, -1, -1
4805 Yacid_splash_wB, FALSE, FALSE,
4806 EL_ACID_SPLASH_LEFT, -1, -1
4809 #ifdef EM_ENGINE_BAD_ROLL
4811 Xstone_force_e, FALSE, FALSE,
4812 EL_ROCK, -1, MV_BIT_RIGHT
4815 Xstone_force_w, FALSE, FALSE,
4816 EL_ROCK, -1, MV_BIT_LEFT
4819 Xnut_force_e, FALSE, FALSE,
4820 EL_NUT, -1, MV_BIT_RIGHT
4823 Xnut_force_w, FALSE, FALSE,
4824 EL_NUT, -1, MV_BIT_LEFT
4827 Xspring_force_e, FALSE, FALSE,
4828 EL_SPRING, -1, MV_BIT_RIGHT
4831 Xspring_force_w, FALSE, FALSE,
4832 EL_SPRING, -1, MV_BIT_LEFT
4835 Xemerald_force_e, FALSE, FALSE,
4836 EL_EMERALD, -1, MV_BIT_RIGHT
4839 Xemerald_force_w, FALSE, FALSE,
4840 EL_EMERALD, -1, MV_BIT_LEFT
4843 Xdiamond_force_e, FALSE, FALSE,
4844 EL_DIAMOND, -1, MV_BIT_RIGHT
4847 Xdiamond_force_w, FALSE, FALSE,
4848 EL_DIAMOND, -1, MV_BIT_LEFT
4851 Xbomb_force_e, FALSE, FALSE,
4852 EL_BOMB, -1, MV_BIT_RIGHT
4855 Xbomb_force_w, FALSE, FALSE,
4856 EL_BOMB, -1, MV_BIT_LEFT
4858 #endif /* EM_ENGINE_BAD_ROLL */
4861 Xstone, TRUE, FALSE,
4865 Xstone_pause, FALSE, FALSE,
4869 Xstone_fall, FALSE, FALSE,
4873 Ystone_s, FALSE, FALSE,
4874 EL_ROCK, ACTION_FALLING, -1
4877 Ystone_sB, FALSE, TRUE,
4878 EL_ROCK, ACTION_FALLING, -1
4881 Ystone_e, FALSE, FALSE,
4882 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
4885 Ystone_eB, FALSE, TRUE,
4886 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
4889 Ystone_w, FALSE, FALSE,
4890 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
4893 Ystone_wB, FALSE, TRUE,
4894 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
4901 Xnut_pause, FALSE, FALSE,
4905 Xnut_fall, FALSE, FALSE,
4909 Ynut_s, FALSE, FALSE,
4910 EL_NUT, ACTION_FALLING, -1
4913 Ynut_sB, FALSE, TRUE,
4914 EL_NUT, ACTION_FALLING, -1
4917 Ynut_e, FALSE, FALSE,
4918 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
4921 Ynut_eB, FALSE, TRUE,
4922 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
4925 Ynut_w, FALSE, FALSE,
4926 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
4929 Ynut_wB, FALSE, TRUE,
4930 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
4933 Xbug_n, TRUE, FALSE,
4937 Xbug_e, TRUE, FALSE,
4938 EL_BUG_RIGHT, -1, -1
4941 Xbug_s, TRUE, FALSE,
4945 Xbug_w, TRUE, FALSE,
4949 Xbug_gon, FALSE, FALSE,
4953 Xbug_goe, FALSE, FALSE,
4954 EL_BUG_RIGHT, -1, -1
4957 Xbug_gos, FALSE, FALSE,
4961 Xbug_gow, FALSE, FALSE,
4965 Ybug_n, FALSE, FALSE,
4966 EL_BUG, ACTION_MOVING, MV_BIT_UP
4969 Ybug_nB, FALSE, TRUE,
4970 EL_BUG, ACTION_MOVING, MV_BIT_UP
4973 Ybug_e, FALSE, FALSE,
4974 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
4977 Ybug_eB, FALSE, TRUE,
4978 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
4981 Ybug_s, FALSE, FALSE,
4982 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
4985 Ybug_sB, FALSE, TRUE,
4986 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
4989 Ybug_w, FALSE, FALSE,
4990 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
4993 Ybug_wB, FALSE, TRUE,
4994 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
4997 Ybug_w_n, FALSE, FALSE,
4998 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
5001 Ybug_n_e, FALSE, FALSE,
5002 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
5005 Ybug_e_s, FALSE, FALSE,
5006 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
5009 Ybug_s_w, FALSE, FALSE,
5010 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
5013 Ybug_e_n, FALSE, FALSE,
5014 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
5017 Ybug_s_e, FALSE, FALSE,
5018 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
5021 Ybug_w_s, FALSE, FALSE,
5022 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
5025 Ybug_n_w, FALSE, FALSE,
5026 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
5029 Ybug_stone, FALSE, FALSE,
5030 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
5033 Ybug_spring, FALSE, FALSE,
5034 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
5037 Xtank_n, TRUE, FALSE,
5038 EL_SPACESHIP_UP, -1, -1
5041 Xtank_e, TRUE, FALSE,
5042 EL_SPACESHIP_RIGHT, -1, -1
5045 Xtank_s, TRUE, FALSE,
5046 EL_SPACESHIP_DOWN, -1, -1
5049 Xtank_w, TRUE, FALSE,
5050 EL_SPACESHIP_LEFT, -1, -1
5053 Xtank_gon, FALSE, FALSE,
5054 EL_SPACESHIP_UP, -1, -1
5057 Xtank_goe, FALSE, FALSE,
5058 EL_SPACESHIP_RIGHT, -1, -1
5061 Xtank_gos, FALSE, FALSE,
5062 EL_SPACESHIP_DOWN, -1, -1
5065 Xtank_gow, FALSE, FALSE,
5066 EL_SPACESHIP_LEFT, -1, -1
5069 Ytank_n, FALSE, FALSE,
5070 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
5073 Ytank_nB, FALSE, TRUE,
5074 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
5077 Ytank_e, FALSE, FALSE,
5078 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
5081 Ytank_eB, FALSE, TRUE,
5082 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
5085 Ytank_s, FALSE, FALSE,
5086 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
5089 Ytank_sB, FALSE, TRUE,
5090 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
5093 Ytank_w, FALSE, FALSE,
5094 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
5097 Ytank_wB, FALSE, TRUE,
5098 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
5101 Ytank_w_n, FALSE, FALSE,
5102 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
5105 Ytank_n_e, FALSE, FALSE,
5106 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
5109 Ytank_e_s, FALSE, FALSE,
5110 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
5113 Ytank_s_w, FALSE, FALSE,
5114 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
5117 Ytank_e_n, FALSE, FALSE,
5118 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
5121 Ytank_s_e, FALSE, FALSE,
5122 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
5125 Ytank_w_s, FALSE, FALSE,
5126 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
5129 Ytank_n_w, FALSE, FALSE,
5130 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
5133 Ytank_stone, FALSE, FALSE,
5134 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
5137 Ytank_spring, FALSE, FALSE,
5138 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
5141 Xandroid, TRUE, FALSE,
5142 EL_EMC_ANDROID, ACTION_ACTIVE, -1
5145 Xandroid_1_n, FALSE, FALSE,
5146 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
5149 Xandroid_2_n, FALSE, FALSE,
5150 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
5153 Xandroid_1_e, FALSE, FALSE,
5154 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
5157 Xandroid_2_e, FALSE, FALSE,
5158 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
5161 Xandroid_1_w, FALSE, FALSE,
5162 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
5165 Xandroid_2_w, FALSE, FALSE,
5166 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
5169 Xandroid_1_s, FALSE, FALSE,
5170 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
5173 Xandroid_2_s, FALSE, FALSE,
5174 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
5177 Yandroid_n, FALSE, FALSE,
5178 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
5181 Yandroid_nB, FALSE, TRUE,
5182 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
5185 Yandroid_ne, FALSE, FALSE,
5186 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
5189 Yandroid_neB, FALSE, TRUE,
5190 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
5193 Yandroid_e, FALSE, FALSE,
5194 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
5197 Yandroid_eB, FALSE, TRUE,
5198 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
5201 Yandroid_se, FALSE, FALSE,
5202 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
5205 Yandroid_seB, FALSE, TRUE,
5206 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
5209 Yandroid_s, FALSE, FALSE,
5210 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
5213 Yandroid_sB, FALSE, TRUE,
5214 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
5217 Yandroid_sw, FALSE, FALSE,
5218 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
5221 Yandroid_swB, FALSE, TRUE,
5222 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
5225 Yandroid_w, FALSE, FALSE,
5226 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
5229 Yandroid_wB, FALSE, TRUE,
5230 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
5233 Yandroid_nw, FALSE, FALSE,
5234 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
5237 Yandroid_nwB, FALSE, TRUE,
5238 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
5241 Xspring, TRUE, FALSE,
5245 Xspring_pause, FALSE, FALSE,
5249 Xspring_e, FALSE, FALSE,
5253 Xspring_w, FALSE, FALSE,
5257 Xspring_fall, FALSE, FALSE,
5261 Yspring_s, FALSE, FALSE,
5262 EL_SPRING, ACTION_FALLING, -1
5265 Yspring_sB, FALSE, TRUE,
5266 EL_SPRING, ACTION_FALLING, -1
5269 Yspring_e, FALSE, FALSE,
5270 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
5273 Yspring_eB, FALSE, TRUE,
5274 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
5277 Yspring_w, FALSE, FALSE,
5278 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
5281 Yspring_wB, FALSE, TRUE,
5282 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
5285 Yspring_kill_e, FALSE, FALSE,
5286 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
5289 Yspring_kill_eB, FALSE, TRUE,
5290 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
5293 Yspring_kill_w, FALSE, FALSE,
5294 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
5297 Yspring_kill_wB, FALSE, TRUE,
5298 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
5301 Xeater_n, TRUE, FALSE,
5302 EL_YAMYAM_UP, -1, -1
5305 Xeater_e, TRUE, FALSE,
5306 EL_YAMYAM_RIGHT, -1, -1
5309 Xeater_w, TRUE, FALSE,
5310 EL_YAMYAM_LEFT, -1, -1
5313 Xeater_s, TRUE, FALSE,
5314 EL_YAMYAM_DOWN, -1, -1
5317 Yeater_n, FALSE, FALSE,
5318 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
5321 Yeater_nB, FALSE, TRUE,
5322 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
5325 Yeater_e, FALSE, FALSE,
5326 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
5329 Yeater_eB, FALSE, TRUE,
5330 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
5333 Yeater_s, FALSE, FALSE,
5334 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
5337 Yeater_sB, FALSE, TRUE,
5338 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
5341 Yeater_w, FALSE, FALSE,
5342 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
5345 Yeater_wB, FALSE, TRUE,
5346 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
5349 Yeater_stone, FALSE, FALSE,
5350 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
5353 Yeater_spring, FALSE, FALSE,
5354 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
5357 Xalien, TRUE, FALSE,
5361 Xalien_pause, FALSE, FALSE,
5365 Yalien_n, FALSE, FALSE,
5366 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
5369 Yalien_nB, FALSE, TRUE,
5370 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
5373 Yalien_e, FALSE, FALSE,
5374 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
5377 Yalien_eB, FALSE, TRUE,
5378 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
5381 Yalien_s, FALSE, FALSE,
5382 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
5385 Yalien_sB, FALSE, TRUE,
5386 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
5389 Yalien_w, FALSE, FALSE,
5390 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
5393 Yalien_wB, FALSE, TRUE,
5394 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
5397 Yalien_stone, FALSE, FALSE,
5398 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
5401 Yalien_spring, FALSE, FALSE,
5402 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
5405 Xemerald, TRUE, FALSE,
5409 Xemerald_pause, FALSE, FALSE,
5413 Xemerald_fall, FALSE, FALSE,
5417 Xemerald_shine, FALSE, FALSE,
5418 EL_EMERALD, ACTION_TWINKLING, -1
5421 Yemerald_s, FALSE, FALSE,
5422 EL_EMERALD, ACTION_FALLING, -1
5425 Yemerald_sB, FALSE, TRUE,
5426 EL_EMERALD, ACTION_FALLING, -1
5429 Yemerald_e, FALSE, FALSE,
5430 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
5433 Yemerald_eB, FALSE, TRUE,
5434 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
5437 Yemerald_w, FALSE, FALSE,
5438 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
5441 Yemerald_wB, FALSE, TRUE,
5442 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
5445 Yemerald_eat, FALSE, FALSE,
5446 EL_EMERALD, ACTION_COLLECTING, -1
5449 Yemerald_stone, FALSE, FALSE,
5450 EL_NUT, ACTION_BREAKING, -1
5453 Xdiamond, TRUE, FALSE,
5457 Xdiamond_pause, FALSE, FALSE,
5461 Xdiamond_fall, FALSE, FALSE,
5465 Xdiamond_shine, FALSE, FALSE,
5466 EL_DIAMOND, ACTION_TWINKLING, -1
5469 Ydiamond_s, FALSE, FALSE,
5470 EL_DIAMOND, ACTION_FALLING, -1
5473 Ydiamond_sB, FALSE, TRUE,
5474 EL_DIAMOND, ACTION_FALLING, -1
5477 Ydiamond_e, FALSE, FALSE,
5478 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
5481 Ydiamond_eB, FALSE, TRUE,
5482 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
5485 Ydiamond_w, FALSE, FALSE,
5486 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
5489 Ydiamond_wB, FALSE, TRUE,
5490 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
5493 Ydiamond_eat, FALSE, FALSE,
5494 EL_DIAMOND, ACTION_COLLECTING, -1
5497 Ydiamond_stone, FALSE, FALSE,
5498 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
5501 Xdrip_fall, TRUE, FALSE,
5502 EL_AMOEBA_DROP, -1, -1
5505 Xdrip_stretch, FALSE, FALSE,
5506 EL_AMOEBA_DROP, ACTION_FALLING, -1
5509 Xdrip_stretchB, FALSE, TRUE,
5510 EL_AMOEBA_DROP, ACTION_FALLING, -1
5513 Xdrip_eat, FALSE, FALSE,
5514 EL_AMOEBA_DROP, ACTION_GROWING, -1
5517 Ydrip_s1, FALSE, FALSE,
5518 EL_AMOEBA_DROP, ACTION_FALLING, -1
5521 Ydrip_s1B, FALSE, TRUE,
5522 EL_AMOEBA_DROP, ACTION_FALLING, -1
5525 Ydrip_s2, FALSE, FALSE,
5526 EL_AMOEBA_DROP, ACTION_FALLING, -1
5529 Ydrip_s2B, FALSE, TRUE,
5530 EL_AMOEBA_DROP, ACTION_FALLING, -1
5537 Xbomb_pause, FALSE, FALSE,
5541 Xbomb_fall, FALSE, FALSE,
5545 Ybomb_s, FALSE, FALSE,
5546 EL_BOMB, ACTION_FALLING, -1
5549 Ybomb_sB, FALSE, TRUE,
5550 EL_BOMB, ACTION_FALLING, -1
5553 Ybomb_e, FALSE, FALSE,
5554 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
5557 Ybomb_eB, FALSE, TRUE,
5558 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
5561 Ybomb_w, FALSE, FALSE,
5562 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
5565 Ybomb_wB, FALSE, TRUE,
5566 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
5569 Ybomb_eat, FALSE, FALSE,
5570 EL_BOMB, ACTION_ACTIVATING, -1
5573 Xballoon, TRUE, FALSE,
5577 Yballoon_n, FALSE, FALSE,
5578 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
5581 Yballoon_nB, FALSE, TRUE,
5582 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
5585 Yballoon_e, FALSE, FALSE,
5586 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
5589 Yballoon_eB, FALSE, TRUE,
5590 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
5593 Yballoon_s, FALSE, FALSE,
5594 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
5597 Yballoon_sB, FALSE, TRUE,
5598 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
5601 Yballoon_w, FALSE, FALSE,
5602 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
5605 Yballoon_wB, FALSE, TRUE,
5606 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
5609 Xgrass, TRUE, FALSE,
5610 EL_EMC_GRASS, -1, -1
5613 Ygrass_nB, FALSE, FALSE,
5614 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
5617 Ygrass_eB, FALSE, FALSE,
5618 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
5621 Ygrass_sB, FALSE, FALSE,
5622 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
5625 Ygrass_wB, FALSE, FALSE,
5626 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
5633 Ydirt_nB, FALSE, FALSE,
5634 EL_SAND, ACTION_DIGGING, MV_BIT_UP
5637 Ydirt_eB, FALSE, FALSE,
5638 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
5641 Ydirt_sB, FALSE, FALSE,
5642 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
5645 Ydirt_wB, FALSE, FALSE,
5646 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
5649 Xacid_ne, TRUE, FALSE,
5650 EL_ACID_POOL_TOPRIGHT, -1, -1
5653 Xacid_se, TRUE, FALSE,
5654 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
5657 Xacid_s, TRUE, FALSE,
5658 EL_ACID_POOL_BOTTOM, -1, -1
5661 Xacid_sw, TRUE, FALSE,
5662 EL_ACID_POOL_BOTTOMLEFT, -1, -1
5665 Xacid_nw, TRUE, FALSE,
5666 EL_ACID_POOL_TOPLEFT, -1, -1
5669 Xacid_1, TRUE, FALSE,
5673 Xacid_2, FALSE, FALSE,
5677 Xacid_3, FALSE, FALSE,
5681 Xacid_4, FALSE, FALSE,
5685 Xacid_5, FALSE, FALSE,
5689 Xacid_6, FALSE, FALSE,
5693 Xacid_7, FALSE, FALSE,
5697 Xacid_8, FALSE, FALSE,
5701 Xball_1, TRUE, FALSE,
5702 EL_EMC_MAGIC_BALL, -1, -1
5705 Xball_1B, FALSE, FALSE,
5706 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5709 Xball_2, FALSE, FALSE,
5710 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5713 Xball_2B, FALSE, FALSE,
5714 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5717 Yball_eat, FALSE, FALSE,
5718 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
5721 Ykey_1_eat, FALSE, FALSE,
5722 EL_EM_KEY_1, ACTION_COLLECTING, -1
5725 Ykey_2_eat, FALSE, FALSE,
5726 EL_EM_KEY_2, ACTION_COLLECTING, -1
5729 Ykey_3_eat, FALSE, FALSE,
5730 EL_EM_KEY_3, ACTION_COLLECTING, -1
5733 Ykey_4_eat, FALSE, FALSE,
5734 EL_EM_KEY_4, ACTION_COLLECTING, -1
5737 Ykey_5_eat, FALSE, FALSE,
5738 EL_EMC_KEY_5, ACTION_COLLECTING, -1
5741 Ykey_6_eat, FALSE, FALSE,
5742 EL_EMC_KEY_6, ACTION_COLLECTING, -1
5745 Ykey_7_eat, FALSE, FALSE,
5746 EL_EMC_KEY_7, ACTION_COLLECTING, -1
5749 Ykey_8_eat, FALSE, FALSE,
5750 EL_EMC_KEY_8, ACTION_COLLECTING, -1
5753 Ylenses_eat, FALSE, FALSE,
5754 EL_EMC_LENSES, ACTION_COLLECTING, -1
5757 Ymagnify_eat, FALSE, FALSE,
5758 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
5761 Ygrass_eat, FALSE, FALSE,
5762 EL_EMC_GRASS, ACTION_SNAPPING, -1
5765 Ydirt_eat, FALSE, FALSE,
5766 EL_SAND, ACTION_SNAPPING, -1
5769 Xgrow_ns, TRUE, FALSE,
5770 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
5773 Ygrow_ns_eat, FALSE, FALSE,
5774 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
5777 Xgrow_ew, TRUE, FALSE,
5778 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
5781 Ygrow_ew_eat, FALSE, FALSE,
5782 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
5785 Xwonderwall, TRUE, FALSE,
5786 EL_MAGIC_WALL, -1, -1
5789 XwonderwallB, FALSE, FALSE,
5790 EL_MAGIC_WALL, ACTION_ACTIVE, -1
5793 Xamoeba_1, TRUE, FALSE,
5794 EL_AMOEBA_DRY, ACTION_OTHER, -1
5797 Xamoeba_2, FALSE, FALSE,
5798 EL_AMOEBA_DRY, ACTION_OTHER, -1
5801 Xamoeba_3, FALSE, FALSE,
5802 EL_AMOEBA_DRY, ACTION_OTHER, -1
5805 Xamoeba_4, FALSE, FALSE,
5806 EL_AMOEBA_DRY, ACTION_OTHER, -1
5809 Xamoeba_5, TRUE, FALSE,
5810 EL_AMOEBA_WET, ACTION_OTHER, -1
5813 Xamoeba_6, FALSE, FALSE,
5814 EL_AMOEBA_WET, ACTION_OTHER, -1
5817 Xamoeba_7, FALSE, FALSE,
5818 EL_AMOEBA_WET, ACTION_OTHER, -1
5821 Xamoeba_8, FALSE, FALSE,
5822 EL_AMOEBA_WET, ACTION_OTHER, -1
5825 Xdoor_1, TRUE, FALSE,
5826 EL_EM_GATE_1, -1, -1
5829 Xdoor_2, TRUE, FALSE,
5830 EL_EM_GATE_2, -1, -1
5833 Xdoor_3, TRUE, FALSE,
5834 EL_EM_GATE_3, -1, -1
5837 Xdoor_4, TRUE, FALSE,
5838 EL_EM_GATE_4, -1, -1
5841 Xdoor_5, TRUE, FALSE,
5842 EL_EMC_GATE_5, -1, -1
5845 Xdoor_6, TRUE, FALSE,
5846 EL_EMC_GATE_6, -1, -1
5849 Xdoor_7, TRUE, FALSE,
5850 EL_EMC_GATE_7, -1, -1
5853 Xdoor_8, TRUE, FALSE,
5854 EL_EMC_GATE_8, -1, -1
5857 Xkey_1, TRUE, FALSE,
5861 Xkey_2, TRUE, FALSE,
5865 Xkey_3, TRUE, FALSE,
5869 Xkey_4, TRUE, FALSE,
5873 Xkey_5, TRUE, FALSE,
5874 EL_EMC_KEY_5, -1, -1
5877 Xkey_6, TRUE, FALSE,
5878 EL_EMC_KEY_6, -1, -1
5881 Xkey_7, TRUE, FALSE,
5882 EL_EMC_KEY_7, -1, -1
5885 Xkey_8, TRUE, FALSE,
5886 EL_EMC_KEY_8, -1, -1
5889 Xwind_n, TRUE, FALSE,
5890 EL_BALLOON_SWITCH_UP, -1, -1
5893 Xwind_e, TRUE, FALSE,
5894 EL_BALLOON_SWITCH_RIGHT, -1, -1
5897 Xwind_s, TRUE, FALSE,
5898 EL_BALLOON_SWITCH_DOWN, -1, -1
5901 Xwind_w, TRUE, FALSE,
5902 EL_BALLOON_SWITCH_LEFT, -1, -1
5905 Xwind_nesw, TRUE, FALSE,
5906 EL_BALLOON_SWITCH_ANY, -1, -1
5909 Xwind_stop, TRUE, FALSE,
5910 EL_BALLOON_SWITCH_NONE, -1, -1
5914 EL_EM_EXIT_CLOSED, -1, -1
5917 Xexit_1, TRUE, FALSE,
5918 EL_EM_EXIT_OPEN, -1, -1
5921 Xexit_2, FALSE, FALSE,
5922 EL_EM_EXIT_OPEN, -1, -1
5925 Xexit_3, FALSE, FALSE,
5926 EL_EM_EXIT_OPEN, -1, -1
5929 Xdynamite, TRUE, FALSE,
5930 EL_EM_DYNAMITE, -1, -1
5933 Ydynamite_eat, FALSE, FALSE,
5934 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
5937 Xdynamite_1, TRUE, FALSE,
5938 EL_EM_DYNAMITE_ACTIVE, -1, -1
5941 Xdynamite_2, FALSE, FALSE,
5942 EL_EM_DYNAMITE_ACTIVE, -1, -1
5945 Xdynamite_3, FALSE, FALSE,
5946 EL_EM_DYNAMITE_ACTIVE, -1, -1
5949 Xdynamite_4, FALSE, FALSE,
5950 EL_EM_DYNAMITE_ACTIVE, -1, -1
5953 Xbumper, TRUE, FALSE,
5954 EL_EMC_SPRING_BUMPER, -1, -1
5957 XbumperB, FALSE, FALSE,
5958 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
5961 Xwheel, TRUE, FALSE,
5962 EL_ROBOT_WHEEL, -1, -1
5965 XwheelB, FALSE, FALSE,
5966 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
5969 Xswitch, TRUE, FALSE,
5970 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
5973 XswitchB, FALSE, FALSE,
5974 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
5978 EL_QUICKSAND_EMPTY, -1, -1
5981 Xsand_stone, TRUE, FALSE,
5982 EL_QUICKSAND_FULL, -1, -1
5985 Xsand_stonein_1, FALSE, TRUE,
5986 EL_ROCK, ACTION_FILLING, -1
5989 Xsand_stonein_2, FALSE, TRUE,
5990 EL_ROCK, ACTION_FILLING, -1
5993 Xsand_stonein_3, FALSE, TRUE,
5994 EL_ROCK, ACTION_FILLING, -1
5997 Xsand_stonein_4, FALSE, TRUE,
5998 EL_ROCK, ACTION_FILLING, -1
6001 Xsand_stonesand_1, FALSE, FALSE,
6002 EL_QUICKSAND_EMPTYING, -1, -1
6005 Xsand_stonesand_2, FALSE, FALSE,
6006 EL_QUICKSAND_EMPTYING, -1, -1
6009 Xsand_stonesand_3, FALSE, FALSE,
6010 EL_QUICKSAND_EMPTYING, -1, -1
6013 Xsand_stonesand_4, FALSE, FALSE,
6014 EL_QUICKSAND_EMPTYING, -1, -1
6017 Xsand_stonesand_quickout_1, FALSE, FALSE,
6018 EL_QUICKSAND_EMPTYING, -1, -1
6021 Xsand_stonesand_quickout_2, FALSE, FALSE,
6022 EL_QUICKSAND_EMPTYING, -1, -1
6025 Xsand_stoneout_1, FALSE, FALSE,
6026 EL_ROCK, ACTION_EMPTYING, -1
6029 Xsand_stoneout_2, FALSE, FALSE,
6030 EL_ROCK, ACTION_EMPTYING, -1
6033 Xsand_sandstone_1, FALSE, FALSE,
6034 EL_QUICKSAND_FILLING, -1, -1
6037 Xsand_sandstone_2, FALSE, FALSE,
6038 EL_QUICKSAND_FILLING, -1, -1
6041 Xsand_sandstone_3, FALSE, FALSE,
6042 EL_QUICKSAND_FILLING, -1, -1
6045 Xsand_sandstone_4, FALSE, FALSE,
6046 EL_QUICKSAND_FILLING, -1, -1
6049 Xplant, TRUE, FALSE,
6050 EL_EMC_PLANT, -1, -1
6053 Yplant, FALSE, FALSE,
6054 EL_EMC_PLANT, -1, -1
6057 Xlenses, TRUE, FALSE,
6058 EL_EMC_LENSES, -1, -1
6061 Xmagnify, TRUE, FALSE,
6062 EL_EMC_MAGNIFIER, -1, -1
6065 Xdripper, TRUE, FALSE,
6066 EL_EMC_DRIPPER, -1, -1
6069 XdripperB, FALSE, FALSE,
6070 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
6073 Xfake_blank, TRUE, FALSE,
6074 EL_INVISIBLE_WALL, -1, -1
6077 Xfake_blankB, FALSE, FALSE,
6078 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
6081 Xfake_grass, TRUE, FALSE,
6082 EL_EMC_FAKE_GRASS, -1, -1
6085 Xfake_grassB, FALSE, FALSE,
6086 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
6089 Xfake_door_1, TRUE, FALSE,
6090 EL_EM_GATE_1_GRAY, -1, -1
6093 Xfake_door_2, TRUE, FALSE,
6094 EL_EM_GATE_2_GRAY, -1, -1
6097 Xfake_door_3, TRUE, FALSE,
6098 EL_EM_GATE_3_GRAY, -1, -1
6101 Xfake_door_4, TRUE, FALSE,
6102 EL_EM_GATE_4_GRAY, -1, -1
6105 Xfake_door_5, TRUE, FALSE,
6106 EL_EMC_GATE_5_GRAY, -1, -1
6109 Xfake_door_6, TRUE, FALSE,
6110 EL_EMC_GATE_6_GRAY, -1, -1
6113 Xfake_door_7, TRUE, FALSE,
6114 EL_EMC_GATE_7_GRAY, -1, -1
6117 Xfake_door_8, TRUE, FALSE,
6118 EL_EMC_GATE_8_GRAY, -1, -1
6121 Xfake_acid_1, TRUE, FALSE,
6122 EL_EMC_FAKE_ACID, -1, -1
6125 Xfake_acid_2, FALSE, FALSE,
6126 EL_EMC_FAKE_ACID, -1, -1
6129 Xfake_acid_3, FALSE, FALSE,
6130 EL_EMC_FAKE_ACID, -1, -1
6133 Xfake_acid_4, FALSE, FALSE,
6134 EL_EMC_FAKE_ACID, -1, -1
6137 Xfake_acid_5, FALSE, FALSE,
6138 EL_EMC_FAKE_ACID, -1, -1
6141 Xfake_acid_6, FALSE, FALSE,
6142 EL_EMC_FAKE_ACID, -1, -1
6145 Xfake_acid_7, FALSE, FALSE,
6146 EL_EMC_FAKE_ACID, -1, -1
6149 Xfake_acid_8, FALSE, FALSE,
6150 EL_EMC_FAKE_ACID, -1, -1
6153 Xsteel_1, TRUE, FALSE,
6154 EL_STEELWALL, -1, -1
6157 Xsteel_2, TRUE, FALSE,
6158 EL_EMC_STEELWALL_2, -1, -1
6161 Xsteel_3, TRUE, FALSE,
6162 EL_EMC_STEELWALL_3, -1, -1
6165 Xsteel_4, TRUE, FALSE,
6166 EL_EMC_STEELWALL_4, -1, -1
6169 Xwall_1, TRUE, FALSE,
6173 Xwall_2, TRUE, FALSE,
6174 EL_EMC_WALL_14, -1, -1
6177 Xwall_3, TRUE, FALSE,
6178 EL_EMC_WALL_15, -1, -1
6181 Xwall_4, TRUE, FALSE,
6182 EL_EMC_WALL_16, -1, -1
6185 Xround_wall_1, TRUE, FALSE,
6186 EL_WALL_SLIPPERY, -1, -1
6189 Xround_wall_2, TRUE, FALSE,
6190 EL_EMC_WALL_SLIPPERY_2, -1, -1
6193 Xround_wall_3, TRUE, FALSE,
6194 EL_EMC_WALL_SLIPPERY_3, -1, -1
6197 Xround_wall_4, TRUE, FALSE,
6198 EL_EMC_WALL_SLIPPERY_4, -1, -1
6201 Xdecor_1, TRUE, FALSE,
6202 EL_EMC_WALL_8, -1, -1
6205 Xdecor_2, TRUE, FALSE,
6206 EL_EMC_WALL_6, -1, -1
6209 Xdecor_3, TRUE, FALSE,
6210 EL_EMC_WALL_4, -1, -1
6213 Xdecor_4, TRUE, FALSE,
6214 EL_EMC_WALL_7, -1, -1
6217 Xdecor_5, TRUE, FALSE,
6218 EL_EMC_WALL_5, -1, -1
6221 Xdecor_6, TRUE, FALSE,
6222 EL_EMC_WALL_9, -1, -1
6225 Xdecor_7, TRUE, FALSE,
6226 EL_EMC_WALL_10, -1, -1
6229 Xdecor_8, TRUE, FALSE,
6230 EL_EMC_WALL_1, -1, -1
6233 Xdecor_9, TRUE, FALSE,
6234 EL_EMC_WALL_2, -1, -1
6237 Xdecor_10, TRUE, FALSE,
6238 EL_EMC_WALL_3, -1, -1
6241 Xdecor_11, TRUE, FALSE,
6242 EL_EMC_WALL_11, -1, -1
6245 Xdecor_12, TRUE, FALSE,
6246 EL_EMC_WALL_12, -1, -1
6249 Xalpha_0, TRUE, FALSE,
6250 EL_CHAR('0'), -1, -1
6253 Xalpha_1, TRUE, FALSE,
6254 EL_CHAR('1'), -1, -1
6257 Xalpha_2, TRUE, FALSE,
6258 EL_CHAR('2'), -1, -1
6261 Xalpha_3, TRUE, FALSE,
6262 EL_CHAR('3'), -1, -1
6265 Xalpha_4, TRUE, FALSE,
6266 EL_CHAR('4'), -1, -1
6269 Xalpha_5, TRUE, FALSE,
6270 EL_CHAR('5'), -1, -1
6273 Xalpha_6, TRUE, FALSE,
6274 EL_CHAR('6'), -1, -1
6277 Xalpha_7, TRUE, FALSE,
6278 EL_CHAR('7'), -1, -1
6281 Xalpha_8, TRUE, FALSE,
6282 EL_CHAR('8'), -1, -1
6285 Xalpha_9, TRUE, FALSE,
6286 EL_CHAR('9'), -1, -1
6289 Xalpha_excla, TRUE, FALSE,
6290 EL_CHAR('!'), -1, -1
6293 Xalpha_quote, TRUE, FALSE,
6294 EL_CHAR('"'), -1, -1
6297 Xalpha_comma, TRUE, FALSE,
6298 EL_CHAR(','), -1, -1
6301 Xalpha_minus, TRUE, FALSE,
6302 EL_CHAR('-'), -1, -1
6305 Xalpha_perio, TRUE, FALSE,
6306 EL_CHAR('.'), -1, -1
6309 Xalpha_colon, TRUE, FALSE,
6310 EL_CHAR(':'), -1, -1
6313 Xalpha_quest, TRUE, FALSE,
6314 EL_CHAR('?'), -1, -1
6317 Xalpha_a, TRUE, FALSE,
6318 EL_CHAR('A'), -1, -1
6321 Xalpha_b, TRUE, FALSE,
6322 EL_CHAR('B'), -1, -1
6325 Xalpha_c, TRUE, FALSE,
6326 EL_CHAR('C'), -1, -1
6329 Xalpha_d, TRUE, FALSE,
6330 EL_CHAR('D'), -1, -1
6333 Xalpha_e, TRUE, FALSE,
6334 EL_CHAR('E'), -1, -1
6337 Xalpha_f, TRUE, FALSE,
6338 EL_CHAR('F'), -1, -1
6341 Xalpha_g, TRUE, FALSE,
6342 EL_CHAR('G'), -1, -1
6345 Xalpha_h, TRUE, FALSE,
6346 EL_CHAR('H'), -1, -1
6349 Xalpha_i, TRUE, FALSE,
6350 EL_CHAR('I'), -1, -1
6353 Xalpha_j, TRUE, FALSE,
6354 EL_CHAR('J'), -1, -1
6357 Xalpha_k, TRUE, FALSE,
6358 EL_CHAR('K'), -1, -1
6361 Xalpha_l, TRUE, FALSE,
6362 EL_CHAR('L'), -1, -1
6365 Xalpha_m, TRUE, FALSE,
6366 EL_CHAR('M'), -1, -1
6369 Xalpha_n, TRUE, FALSE,
6370 EL_CHAR('N'), -1, -1
6373 Xalpha_o, TRUE, FALSE,
6374 EL_CHAR('O'), -1, -1
6377 Xalpha_p, TRUE, FALSE,
6378 EL_CHAR('P'), -1, -1
6381 Xalpha_q, TRUE, FALSE,
6382 EL_CHAR('Q'), -1, -1
6385 Xalpha_r, TRUE, FALSE,
6386 EL_CHAR('R'), -1, -1
6389 Xalpha_s, TRUE, FALSE,
6390 EL_CHAR('S'), -1, -1
6393 Xalpha_t, TRUE, FALSE,
6394 EL_CHAR('T'), -1, -1
6397 Xalpha_u, TRUE, FALSE,
6398 EL_CHAR('U'), -1, -1
6401 Xalpha_v, TRUE, FALSE,
6402 EL_CHAR('V'), -1, -1
6405 Xalpha_w, TRUE, FALSE,
6406 EL_CHAR('W'), -1, -1
6409 Xalpha_x, TRUE, FALSE,
6410 EL_CHAR('X'), -1, -1
6413 Xalpha_y, TRUE, FALSE,
6414 EL_CHAR('Y'), -1, -1
6417 Xalpha_z, TRUE, FALSE,
6418 EL_CHAR('Z'), -1, -1
6421 Xalpha_arrow_e, TRUE, FALSE,
6422 EL_CHAR('>'), -1, -1
6425 Xalpha_arrow_w, TRUE, FALSE,
6426 EL_CHAR('<'), -1, -1
6429 Xalpha_copyr, TRUE, FALSE,
6430 EL_CHAR(CHAR_BYTE_COPYRIGHT), -1, -1
6434 Xboom_bug, FALSE, FALSE,
6435 EL_BUG, ACTION_EXPLODING, -1
6438 Xboom_bomb, FALSE, FALSE,
6439 EL_BOMB, ACTION_EXPLODING, -1
6442 Xboom_android, FALSE, FALSE,
6443 EL_EMC_ANDROID, ACTION_OTHER, -1
6446 Xboom_1, FALSE, FALSE,
6447 EL_DEFAULT, ACTION_EXPLODING, -1
6450 Xboom_2, FALSE, FALSE,
6451 EL_DEFAULT, ACTION_EXPLODING, -1
6454 Znormal, FALSE, FALSE,
6458 Zdynamite, FALSE, FALSE,
6462 Zplayer, FALSE, FALSE,
6466 ZBORDER, FALSE, FALSE,
6476 static struct Mapping_EM_to_RND_player
6485 em_player_mapping_list[] =
6489 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
6493 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
6497 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
6501 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
6505 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
6509 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
6513 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
6517 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
6521 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
6525 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
6529 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
6533 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
6537 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
6541 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
6545 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
6549 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
6553 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
6557 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
6561 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
6565 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
6569 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
6573 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
6577 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
6581 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
6585 EL_PLAYER_1, ACTION_DEFAULT, -1,
6589 EL_PLAYER_2, ACTION_DEFAULT, -1,
6593 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
6597 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
6601 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
6605 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
6609 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
6613 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
6617 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
6621 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
6625 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
6629 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
6633 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
6637 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
6641 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
6645 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
6649 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
6653 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
6657 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
6661 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
6665 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
6669 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
6673 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
6677 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
6681 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
6685 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
6689 EL_PLAYER_3, ACTION_DEFAULT, -1,
6693 EL_PLAYER_4, ACTION_DEFAULT, -1,
6702 int map_element_RND_to_EM(int element_rnd)
6704 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
6705 static boolean mapping_initialized = FALSE;
6707 if (!mapping_initialized)
6711 /* return "Xalpha_quest" for all undefined elements in mapping array */
6712 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
6713 mapping_RND_to_EM[i] = Xalpha_quest;
6715 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6716 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
6717 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
6718 em_object_mapping_list[i].element_em;
6720 mapping_initialized = TRUE;
6723 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
6724 return mapping_RND_to_EM[element_rnd];
6726 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
6731 int map_element_EM_to_RND(int element_em)
6733 static unsigned short mapping_EM_to_RND[TILE_MAX];
6734 static boolean mapping_initialized = FALSE;
6736 if (!mapping_initialized)
6740 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
6741 for (i = 0; i < TILE_MAX; i++)
6742 mapping_EM_to_RND[i] = EL_UNKNOWN;
6744 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6745 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
6746 em_object_mapping_list[i].element_rnd;
6748 mapping_initialized = TRUE;
6751 if (element_em >= 0 && element_em < TILE_MAX)
6752 return mapping_EM_to_RND[element_em];
6754 Error(ERR_WARN, "invalid EM level element %d", element_em);
6759 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
6761 struct LevelInfo_EM *level_em = level->native_em_level;
6762 struct LEVEL *lev = level_em->lev;
6765 for (i = 0; i < TILE_MAX; i++)
6766 lev->android_array[i] = Xblank;
6768 for (i = 0; i < level->num_android_clone_elements; i++)
6770 int element_rnd = level->android_clone_element[i];
6771 int element_em = map_element_RND_to_EM(element_rnd);
6773 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
6774 if (em_object_mapping_list[j].element_rnd == element_rnd)
6775 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
6779 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
6781 struct LevelInfo_EM *level_em = level->native_em_level;
6782 struct LEVEL *lev = level_em->lev;
6785 level->num_android_clone_elements = 0;
6787 for (i = 0; i < TILE_MAX; i++)
6789 int element_em = lev->android_array[i];
6791 boolean element_found = FALSE;
6793 if (element_em == Xblank)
6796 element_rnd = map_element_EM_to_RND(element_em);
6798 for (j = 0; j < level->num_android_clone_elements; j++)
6799 if (level->android_clone_element[j] == element_rnd)
6800 element_found = TRUE;
6804 level->android_clone_element[level->num_android_clone_elements++] =
6807 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
6812 if (level->num_android_clone_elements == 0)
6814 level->num_android_clone_elements = 1;
6815 level->android_clone_element[0] = EL_EMPTY;
6819 int map_direction_RND_to_EM(int direction)
6821 return (direction == MV_UP ? 0 :
6822 direction == MV_RIGHT ? 1 :
6823 direction == MV_DOWN ? 2 :
6824 direction == MV_LEFT ? 3 :
6828 int map_direction_EM_to_RND(int direction)
6830 return (direction == 0 ? MV_UP :
6831 direction == 1 ? MV_RIGHT :
6832 direction == 2 ? MV_DOWN :
6833 direction == 3 ? MV_LEFT :
6837 int map_element_RND_to_SP(int element_rnd)
6839 int element_sp = 0x20; /* map unknown elements to yellow "hardware" */
6841 if (element_rnd >= EL_SP_START &&
6842 element_rnd <= EL_SP_END)
6843 element_sp = element_rnd - EL_SP_START;
6844 else if (element_rnd == EL_EMPTY_SPACE)
6846 else if (element_rnd == EL_INVISIBLE_WALL)
6852 int map_element_SP_to_RND(int element_sp)
6854 int element_rnd = EL_UNKNOWN;
6856 if (element_sp >= 0x00 &&
6858 element_rnd = EL_SP_START + element_sp;
6859 else if (element_sp == 0x28)
6860 element_rnd = EL_INVISIBLE_WALL;
6865 int map_action_SP_to_RND(int action_sp)
6869 case actActive: return ACTION_ACTIVE;
6870 case actImpact: return ACTION_IMPACT;
6871 case actExploding: return ACTION_EXPLODING;
6872 case actDigging: return ACTION_DIGGING;
6873 case actSnapping: return ACTION_SNAPPING;
6874 case actCollecting: return ACTION_COLLECTING;
6875 case actPassing: return ACTION_PASSING;
6876 case actPushing: return ACTION_PUSHING;
6877 case actDropping: return ACTION_DROPPING;
6879 default: return ACTION_DEFAULT;
6883 int get_next_element(int element)
6887 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
6888 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
6889 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
6890 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
6891 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
6892 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
6893 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
6894 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
6895 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
6896 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
6897 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
6899 default: return element;
6903 int el_act_dir2img(int element, int action, int direction)
6905 element = GFX_ELEMENT(element);
6906 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
6908 /* direction_graphic[][] == graphic[] for undefined direction graphics */
6909 return element_info[element].direction_graphic[action][direction];
6912 static int el_act_dir2crm(int element, int action, int direction)
6914 element = GFX_ELEMENT(element);
6915 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
6917 /* direction_graphic[][] == graphic[] for undefined direction graphics */
6918 return element_info[element].direction_crumbled[action][direction];
6921 int el_act2img(int element, int action)
6923 element = GFX_ELEMENT(element);
6925 return element_info[element].graphic[action];
6928 int el_act2crm(int element, int action)
6930 element = GFX_ELEMENT(element);
6932 return element_info[element].crumbled[action];
6935 int el_dir2img(int element, int direction)
6937 element = GFX_ELEMENT(element);
6939 return el_act_dir2img(element, ACTION_DEFAULT, direction);
6942 int el2baseimg(int element)
6944 return element_info[element].graphic[ACTION_DEFAULT];
6947 int el2img(int element)
6949 element = GFX_ELEMENT(element);
6951 return element_info[element].graphic[ACTION_DEFAULT];
6954 int el2edimg(int element)
6956 element = GFX_ELEMENT(element);
6958 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
6961 int el2preimg(int element)
6963 element = GFX_ELEMENT(element);
6965 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
6968 int el2panelimg(int element)
6970 element = GFX_ELEMENT(element);
6972 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL];
6975 int font2baseimg(int font_nr)
6977 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
6980 int getBeltNrFromBeltElement(int element)
6982 return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
6983 element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
6984 element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
6987 int getBeltNrFromBeltActiveElement(int element)
6989 return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
6990 element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
6991 element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
6994 int getBeltNrFromBeltSwitchElement(int element)
6996 return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
6997 element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
6998 element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
7001 int getBeltDirNrFromBeltElement(int element)
7003 static int belt_base_element[4] =
7005 EL_CONVEYOR_BELT_1_LEFT,
7006 EL_CONVEYOR_BELT_2_LEFT,
7007 EL_CONVEYOR_BELT_3_LEFT,
7008 EL_CONVEYOR_BELT_4_LEFT
7011 int belt_nr = getBeltNrFromBeltElement(element);
7012 int belt_dir_nr = element - belt_base_element[belt_nr];
7014 return (belt_dir_nr % 3);
7017 int getBeltDirNrFromBeltSwitchElement(int element)
7019 static int belt_base_element[4] =
7021 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
7022 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
7023 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
7024 EL_CONVEYOR_BELT_4_SWITCH_LEFT
7027 int belt_nr = getBeltNrFromBeltSwitchElement(element);
7028 int belt_dir_nr = element - belt_base_element[belt_nr];
7030 return (belt_dir_nr % 3);
7033 int getBeltDirFromBeltElement(int element)
7035 static int belt_move_dir[3] =
7042 int belt_dir_nr = getBeltDirNrFromBeltElement(element);
7044 return belt_move_dir[belt_dir_nr];
7047 int getBeltDirFromBeltSwitchElement(int element)
7049 static int belt_move_dir[3] =
7056 int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
7058 return belt_move_dir[belt_dir_nr];
7061 int getBeltElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
7063 static int belt_base_element[4] =
7065 EL_CONVEYOR_BELT_1_LEFT,
7066 EL_CONVEYOR_BELT_2_LEFT,
7067 EL_CONVEYOR_BELT_3_LEFT,
7068 EL_CONVEYOR_BELT_4_LEFT
7071 return belt_base_element[belt_nr] + belt_dir_nr;
7074 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
7076 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
7078 return getBeltElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
7081 int getBeltSwitchElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
7083 static int belt_base_element[4] =
7085 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
7086 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
7087 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
7088 EL_CONVEYOR_BELT_4_SWITCH_LEFT
7091 return belt_base_element[belt_nr] + belt_dir_nr;
7094 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
7096 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
7098 return getBeltSwitchElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
7101 boolean getTeamMode_EM()
7103 return game.team_mode;
7106 int getGameFrameDelay_EM(int native_em_game_frame_delay)
7108 int game_frame_delay_value;
7110 game_frame_delay_value =
7111 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
7112 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
7115 if (tape.playing && tape.warp_forward && !tape.pausing)
7116 game_frame_delay_value = 0;
7118 return game_frame_delay_value;
7121 unsigned int InitRND(int seed)
7123 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
7124 return InitEngineRandom_EM(seed);
7125 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
7126 return InitEngineRandom_SP(seed);
7128 return InitEngineRandom_RND(seed);
7131 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
7132 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
7134 inline static int get_effective_element_EM(int tile, int frame_em)
7136 int element = object_mapping[tile].element_rnd;
7137 int action = object_mapping[tile].action;
7138 boolean is_backside = object_mapping[tile].is_backside;
7139 boolean action_removing = (action == ACTION_DIGGING ||
7140 action == ACTION_SNAPPING ||
7141 action == ACTION_COLLECTING);
7147 case Yacid_splash_eB:
7148 case Yacid_splash_wB:
7149 return (frame_em > 5 ? EL_EMPTY : element);
7155 else /* frame_em == 7 */
7159 case Yacid_splash_eB:
7160 case Yacid_splash_wB:
7163 case Yemerald_stone:
7166 case Ydiamond_stone:
7170 case Xdrip_stretchB:
7189 case Xsand_stonein_1:
7190 case Xsand_stonein_2:
7191 case Xsand_stonein_3:
7192 case Xsand_stonein_4:
7196 return (is_backside || action_removing ? EL_EMPTY : element);
7201 inline static boolean check_linear_animation_EM(int tile)
7205 case Xsand_stonesand_1:
7206 case Xsand_stonesand_quickout_1:
7207 case Xsand_sandstone_1:
7208 case Xsand_stonein_1:
7209 case Xsand_stoneout_1:
7228 case Yacid_splash_eB:
7229 case Yacid_splash_wB:
7230 case Yemerald_stone:
7237 inline static void set_crumbled_graphics_EM(struct GraphicInfo_EM *g_em,
7238 boolean has_crumbled_graphics,
7239 int crumbled, int sync_frame)
7241 /* if element can be crumbled, but certain action graphics are just empty
7242 space (like instantly snapping sand to empty space in 1 frame), do not
7243 treat these empty space graphics as crumbled graphics in EMC engine */
7244 if (crumbled == IMG_EMPTY_SPACE)
7245 has_crumbled_graphics = FALSE;
7247 if (has_crumbled_graphics)
7249 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
7250 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
7251 g_crumbled->anim_delay,
7252 g_crumbled->anim_mode,
7253 g_crumbled->anim_start_frame,
7256 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
7257 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
7259 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
7261 g_em->has_crumbled_graphics = TRUE;
7265 g_em->crumbled_bitmap = NULL;
7266 g_em->crumbled_src_x = 0;
7267 g_em->crumbled_src_y = 0;
7268 g_em->crumbled_border_size = 0;
7270 g_em->has_crumbled_graphics = FALSE;
7274 void ResetGfxAnimation_EM(int x, int y, int tile)
7279 void SetGfxAnimation_EM(struct GraphicInfo_EM *g_em,
7280 int tile, int frame_em, int x, int y)
7282 int action = object_mapping[tile].action;
7283 int direction = object_mapping[tile].direction;
7284 int effective_element = get_effective_element_EM(tile, frame_em);
7285 int graphic = (direction == MV_NONE ?
7286 el_act2img(effective_element, action) :
7287 el_act_dir2img(effective_element, action, direction));
7288 struct GraphicInfo *g = &graphic_info[graphic];
7290 boolean action_removing = (action == ACTION_DIGGING ||
7291 action == ACTION_SNAPPING ||
7292 action == ACTION_COLLECTING);
7293 boolean action_moving = (action == ACTION_FALLING ||
7294 action == ACTION_MOVING ||
7295 action == ACTION_PUSHING ||
7296 action == ACTION_EATING ||
7297 action == ACTION_FILLING ||
7298 action == ACTION_EMPTYING);
7299 boolean action_falling = (action == ACTION_FALLING ||
7300 action == ACTION_FILLING ||
7301 action == ACTION_EMPTYING);
7303 /* special case: graphic uses "2nd movement tile" and has defined
7304 7 frames for movement animation (or less) => use default graphic
7305 for last (8th) frame which ends the movement animation */
7306 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
7308 action = ACTION_DEFAULT; /* (keep action_* unchanged for now) */
7309 graphic = (direction == MV_NONE ?
7310 el_act2img(effective_element, action) :
7311 el_act_dir2img(effective_element, action, direction));
7313 g = &graphic_info[graphic];
7316 if ((action_removing || check_linear_animation_EM(tile)) && frame_em == 0)
7320 else if (action_moving)
7322 boolean is_backside = object_mapping[tile].is_backside;
7326 int direction = object_mapping[tile].direction;
7327 int move_dir = (action_falling ? MV_DOWN : direction);
7332 /* !!! TEST !!! NEW !!! DOES NOT WORK RIGHT YET !!! */
7333 if (g->double_movement && frame_em == 0)
7337 if (move_dir == MV_LEFT)
7338 GfxFrame[x - 1][y] = GfxFrame[x][y];
7339 else if (move_dir == MV_RIGHT)
7340 GfxFrame[x + 1][y] = GfxFrame[x][y];
7341 else if (move_dir == MV_UP)
7342 GfxFrame[x][y - 1] = GfxFrame[x][y];
7343 else if (move_dir == MV_DOWN)
7344 GfxFrame[x][y + 1] = GfxFrame[x][y];
7351 /* special case: animation for Xsand_stonesand_quickout_1/2 twice as fast */
7352 if (tile == Xsand_stonesand_quickout_1 ||
7353 tile == Xsand_stonesand_quickout_2)
7357 if (graphic_info[graphic].anim_global_sync)
7358 sync_frame = FrameCounter;
7359 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
7360 sync_frame = GfxFrame[x][y];
7362 sync_frame = 0; /* playfield border (pseudo steel) */
7364 SetRandomAnimationValue(x, y);
7366 int frame = getAnimationFrame(g->anim_frames,
7369 g->anim_start_frame,
7372 g_em->unique_identifier =
7373 (graphic << 16) | ((frame % 8) << 12) | (g_em->width << 6) | g_em->height;
7376 void getGraphicSourceObjectExt_EM(struct GraphicInfo_EM *g_em,
7377 int tile, int frame_em, int x, int y)
7379 int action = object_mapping[tile].action;
7380 int direction = object_mapping[tile].direction;
7381 boolean is_backside = object_mapping[tile].is_backside;
7382 int effective_element = get_effective_element_EM(tile, frame_em);
7383 int effective_action = action;
7384 int graphic = (direction == MV_NONE ?
7385 el_act2img(effective_element, effective_action) :
7386 el_act_dir2img(effective_element, effective_action,
7388 int crumbled = (direction == MV_NONE ?
7389 el_act2crm(effective_element, effective_action) :
7390 el_act_dir2crm(effective_element, effective_action,
7392 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7393 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7394 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7395 struct GraphicInfo *g = &graphic_info[graphic];
7398 /* special case: graphic uses "2nd movement tile" and has defined
7399 7 frames for movement animation (or less) => use default graphic
7400 for last (8th) frame which ends the movement animation */
7401 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
7403 effective_action = ACTION_DEFAULT;
7404 graphic = (direction == MV_NONE ?
7405 el_act2img(effective_element, effective_action) :
7406 el_act_dir2img(effective_element, effective_action,
7408 crumbled = (direction == MV_NONE ?
7409 el_act2crm(effective_element, effective_action) :
7410 el_act_dir2crm(effective_element, effective_action,
7413 g = &graphic_info[graphic];
7416 if (graphic_info[graphic].anim_global_sync)
7417 sync_frame = FrameCounter;
7418 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
7419 sync_frame = GfxFrame[x][y];
7421 sync_frame = 0; /* playfield border (pseudo steel) */
7423 SetRandomAnimationValue(x, y);
7425 int frame = getAnimationFrame(g->anim_frames,
7428 g->anim_start_frame,
7431 getGraphicSourceExt(graphic, frame, &g_em->bitmap, &g_em->src_x, &g_em->src_y,
7432 g->double_movement && is_backside);
7434 /* (updating the "crumbled" graphic definitions is probably not really needed,
7435 as animations for crumbled graphics can't be longer than one EMC cycle) */
7436 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
7440 void getGraphicSourcePlayerExt_EM(struct GraphicInfo_EM *g_em,
7441 int player_nr, int anim, int frame_em)
7443 int element = player_mapping[player_nr][anim].element_rnd;
7444 int action = player_mapping[player_nr][anim].action;
7445 int direction = player_mapping[player_nr][anim].direction;
7446 int graphic = (direction == MV_NONE ?
7447 el_act2img(element, action) :
7448 el_act_dir2img(element, action, direction));
7449 struct GraphicInfo *g = &graphic_info[graphic];
7452 InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
7454 stored_player[player_nr].StepFrame = frame_em;
7456 sync_frame = stored_player[player_nr].Frame;
7458 int frame = getAnimationFrame(g->anim_frames,
7461 g->anim_start_frame,
7464 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
7465 &g_em->src_x, &g_em->src_y, FALSE);
7468 void InitGraphicInfo_EM(void)
7473 int num_em_gfx_errors = 0;
7475 if (graphic_info_em_object[0][0].bitmap == NULL)
7477 /* EM graphics not yet initialized in em_open_all() */
7482 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
7485 /* always start with reliable default values */
7486 for (i = 0; i < TILE_MAX; i++)
7488 object_mapping[i].element_rnd = EL_UNKNOWN;
7489 object_mapping[i].is_backside = FALSE;
7490 object_mapping[i].action = ACTION_DEFAULT;
7491 object_mapping[i].direction = MV_NONE;
7494 /* always start with reliable default values */
7495 for (p = 0; p < MAX_PLAYERS; p++)
7497 for (i = 0; i < SPR_MAX; i++)
7499 player_mapping[p][i].element_rnd = EL_UNKNOWN;
7500 player_mapping[p][i].action = ACTION_DEFAULT;
7501 player_mapping[p][i].direction = MV_NONE;
7505 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
7507 int e = em_object_mapping_list[i].element_em;
7509 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
7510 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
7512 if (em_object_mapping_list[i].action != -1)
7513 object_mapping[e].action = em_object_mapping_list[i].action;
7515 if (em_object_mapping_list[i].direction != -1)
7516 object_mapping[e].direction =
7517 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
7520 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
7522 int a = em_player_mapping_list[i].action_em;
7523 int p = em_player_mapping_list[i].player_nr;
7525 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
7527 if (em_player_mapping_list[i].action != -1)
7528 player_mapping[p][a].action = em_player_mapping_list[i].action;
7530 if (em_player_mapping_list[i].direction != -1)
7531 player_mapping[p][a].direction =
7532 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
7535 for (i = 0; i < TILE_MAX; i++)
7537 int element = object_mapping[i].element_rnd;
7538 int action = object_mapping[i].action;
7539 int direction = object_mapping[i].direction;
7540 boolean is_backside = object_mapping[i].is_backside;
7541 boolean action_exploding = ((action == ACTION_EXPLODING ||
7542 action == ACTION_SMASHED_BY_ROCK ||
7543 action == ACTION_SMASHED_BY_SPRING) &&
7544 element != EL_DIAMOND);
7545 boolean action_active = (action == ACTION_ACTIVE);
7546 boolean action_other = (action == ACTION_OTHER);
7548 for (j = 0; j < 8; j++)
7550 int effective_element = get_effective_element_EM(i, j);
7551 int effective_action = (j < 7 ? action :
7552 i == Xdrip_stretch ? action :
7553 i == Xdrip_stretchB ? action :
7554 i == Ydrip_s1 ? action :
7555 i == Ydrip_s1B ? action :
7556 i == Xball_1B ? action :
7557 i == Xball_2 ? action :
7558 i == Xball_2B ? action :
7559 i == Yball_eat ? action :
7560 i == Ykey_1_eat ? action :
7561 i == Ykey_2_eat ? action :
7562 i == Ykey_3_eat ? action :
7563 i == Ykey_4_eat ? action :
7564 i == Ykey_5_eat ? action :
7565 i == Ykey_6_eat ? action :
7566 i == Ykey_7_eat ? action :
7567 i == Ykey_8_eat ? action :
7568 i == Ylenses_eat ? action :
7569 i == Ymagnify_eat ? action :
7570 i == Ygrass_eat ? action :
7571 i == Ydirt_eat ? action :
7572 i == Xsand_stonein_1 ? action :
7573 i == Xsand_stonein_2 ? action :
7574 i == Xsand_stonein_3 ? action :
7575 i == Xsand_stonein_4 ? action :
7576 i == Xsand_stoneout_1 ? action :
7577 i == Xsand_stoneout_2 ? action :
7578 i == Xboom_android ? ACTION_EXPLODING :
7579 action_exploding ? ACTION_EXPLODING :
7580 action_active ? action :
7581 action_other ? action :
7583 int graphic = (el_act_dir2img(effective_element, effective_action,
7585 int crumbled = (el_act_dir2crm(effective_element, effective_action,
7587 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7588 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7589 boolean has_action_graphics = (graphic != base_graphic);
7590 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7591 struct GraphicInfo *g = &graphic_info[graphic];
7592 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7595 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
7596 boolean special_animation = (action != ACTION_DEFAULT &&
7597 g->anim_frames == 3 &&
7598 g->anim_delay == 2 &&
7599 g->anim_mode & ANIM_LINEAR);
7600 int sync_frame = (i == Xdrip_stretch ? 7 :
7601 i == Xdrip_stretchB ? 7 :
7602 i == Ydrip_s2 ? j + 8 :
7603 i == Ydrip_s2B ? j + 8 :
7612 i == Xfake_acid_1 ? 0 :
7613 i == Xfake_acid_2 ? 10 :
7614 i == Xfake_acid_3 ? 20 :
7615 i == Xfake_acid_4 ? 30 :
7616 i == Xfake_acid_5 ? 40 :
7617 i == Xfake_acid_6 ? 50 :
7618 i == Xfake_acid_7 ? 60 :
7619 i == Xfake_acid_8 ? 70 :
7621 i == Xball_2B ? j + 8 :
7622 i == Yball_eat ? j + 1 :
7623 i == Ykey_1_eat ? j + 1 :
7624 i == Ykey_2_eat ? j + 1 :
7625 i == Ykey_3_eat ? j + 1 :
7626 i == Ykey_4_eat ? j + 1 :
7627 i == Ykey_5_eat ? j + 1 :
7628 i == Ykey_6_eat ? j + 1 :
7629 i == Ykey_7_eat ? j + 1 :
7630 i == Ykey_8_eat ? j + 1 :
7631 i == Ylenses_eat ? j + 1 :
7632 i == Ymagnify_eat ? j + 1 :
7633 i == Ygrass_eat ? j + 1 :
7634 i == Ydirt_eat ? j + 1 :
7635 i == Xamoeba_1 ? 0 :
7636 i == Xamoeba_2 ? 1 :
7637 i == Xamoeba_3 ? 2 :
7638 i == Xamoeba_4 ? 3 :
7639 i == Xamoeba_5 ? 0 :
7640 i == Xamoeba_6 ? 1 :
7641 i == Xamoeba_7 ? 2 :
7642 i == Xamoeba_8 ? 3 :
7643 i == Xexit_2 ? j + 8 :
7644 i == Xexit_3 ? j + 16 :
7645 i == Xdynamite_1 ? 0 :
7646 i == Xdynamite_2 ? 8 :
7647 i == Xdynamite_3 ? 16 :
7648 i == Xdynamite_4 ? 24 :
7649 i == Xsand_stonein_1 ? j + 1 :
7650 i == Xsand_stonein_2 ? j + 9 :
7651 i == Xsand_stonein_3 ? j + 17 :
7652 i == Xsand_stonein_4 ? j + 25 :
7653 i == Xsand_stoneout_1 && j == 0 ? 0 :
7654 i == Xsand_stoneout_1 && j == 1 ? 0 :
7655 i == Xsand_stoneout_1 && j == 2 ? 1 :
7656 i == Xsand_stoneout_1 && j == 3 ? 2 :
7657 i == Xsand_stoneout_1 && j == 4 ? 2 :
7658 i == Xsand_stoneout_1 && j == 5 ? 3 :
7659 i == Xsand_stoneout_1 && j == 6 ? 4 :
7660 i == Xsand_stoneout_1 && j == 7 ? 4 :
7661 i == Xsand_stoneout_2 && j == 0 ? 5 :
7662 i == Xsand_stoneout_2 && j == 1 ? 6 :
7663 i == Xsand_stoneout_2 && j == 2 ? 7 :
7664 i == Xsand_stoneout_2 && j == 3 ? 8 :
7665 i == Xsand_stoneout_2 && j == 4 ? 9 :
7666 i == Xsand_stoneout_2 && j == 5 ? 11 :
7667 i == Xsand_stoneout_2 && j == 6 ? 13 :
7668 i == Xsand_stoneout_2 && j == 7 ? 15 :
7669 i == Xboom_bug && j == 1 ? 2 :
7670 i == Xboom_bug && j == 2 ? 2 :
7671 i == Xboom_bug && j == 3 ? 4 :
7672 i == Xboom_bug && j == 4 ? 4 :
7673 i == Xboom_bug && j == 5 ? 2 :
7674 i == Xboom_bug && j == 6 ? 2 :
7675 i == Xboom_bug && j == 7 ? 0 :
7676 i == Xboom_bomb && j == 1 ? 2 :
7677 i == Xboom_bomb && j == 2 ? 2 :
7678 i == Xboom_bomb && j == 3 ? 4 :
7679 i == Xboom_bomb && j == 4 ? 4 :
7680 i == Xboom_bomb && j == 5 ? 2 :
7681 i == Xboom_bomb && j == 6 ? 2 :
7682 i == Xboom_bomb && j == 7 ? 0 :
7683 i == Xboom_android && j == 7 ? 6 :
7684 i == Xboom_1 && j == 1 ? 2 :
7685 i == Xboom_1 && j == 2 ? 2 :
7686 i == Xboom_1 && j == 3 ? 4 :
7687 i == Xboom_1 && j == 4 ? 4 :
7688 i == Xboom_1 && j == 5 ? 6 :
7689 i == Xboom_1 && j == 6 ? 6 :
7690 i == Xboom_1 && j == 7 ? 8 :
7691 i == Xboom_2 && j == 0 ? 8 :
7692 i == Xboom_2 && j == 1 ? 8 :
7693 i == Xboom_2 && j == 2 ? 10 :
7694 i == Xboom_2 && j == 3 ? 10 :
7695 i == Xboom_2 && j == 4 ? 10 :
7696 i == Xboom_2 && j == 5 ? 12 :
7697 i == Xboom_2 && j == 6 ? 12 :
7698 i == Xboom_2 && j == 7 ? 12 :
7699 special_animation && j == 4 ? 3 :
7700 effective_action != action ? 0 :
7704 Bitmap *debug_bitmap = g_em->bitmap;
7705 int debug_src_x = g_em->src_x;
7706 int debug_src_y = g_em->src_y;
7709 int frame = getAnimationFrame(g->anim_frames,
7712 g->anim_start_frame,
7715 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
7716 g->double_movement && is_backside);
7718 g_em->bitmap = src_bitmap;
7719 g_em->src_x = src_x;
7720 g_em->src_y = src_y;
7721 g_em->src_offset_x = 0;
7722 g_em->src_offset_y = 0;
7723 g_em->dst_offset_x = 0;
7724 g_em->dst_offset_y = 0;
7725 g_em->width = TILEX;
7726 g_em->height = TILEY;
7728 g_em->preserve_background = FALSE;
7730 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
7733 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
7734 effective_action == ACTION_MOVING ||
7735 effective_action == ACTION_PUSHING ||
7736 effective_action == ACTION_EATING)) ||
7737 (!has_action_graphics && (effective_action == ACTION_FILLING ||
7738 effective_action == ACTION_EMPTYING)))
7741 (effective_action == ACTION_FALLING ||
7742 effective_action == ACTION_FILLING ||
7743 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
7744 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
7745 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
7746 int num_steps = (i == Ydrip_s1 ? 16 :
7747 i == Ydrip_s1B ? 16 :
7748 i == Ydrip_s2 ? 16 :
7749 i == Ydrip_s2B ? 16 :
7750 i == Xsand_stonein_1 ? 32 :
7751 i == Xsand_stonein_2 ? 32 :
7752 i == Xsand_stonein_3 ? 32 :
7753 i == Xsand_stonein_4 ? 32 :
7754 i == Xsand_stoneout_1 ? 16 :
7755 i == Xsand_stoneout_2 ? 16 : 8);
7756 int cx = ABS(dx) * (TILEX / num_steps);
7757 int cy = ABS(dy) * (TILEY / num_steps);
7758 int step_frame = (i == Ydrip_s2 ? j + 8 :
7759 i == Ydrip_s2B ? j + 8 :
7760 i == Xsand_stonein_2 ? j + 8 :
7761 i == Xsand_stonein_3 ? j + 16 :
7762 i == Xsand_stonein_4 ? j + 24 :
7763 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
7764 int step = (is_backside ? step_frame : num_steps - step_frame);
7766 if (is_backside) /* tile where movement starts */
7768 if (dx < 0 || dy < 0)
7770 g_em->src_offset_x = cx * step;
7771 g_em->src_offset_y = cy * step;
7775 g_em->dst_offset_x = cx * step;
7776 g_em->dst_offset_y = cy * step;
7779 else /* tile where movement ends */
7781 if (dx < 0 || dy < 0)
7783 g_em->dst_offset_x = cx * step;
7784 g_em->dst_offset_y = cy * step;
7788 g_em->src_offset_x = cx * step;
7789 g_em->src_offset_y = cy * step;
7793 g_em->width = TILEX - cx * step;
7794 g_em->height = TILEY - cy * step;
7797 /* create unique graphic identifier to decide if tile must be redrawn */
7798 /* bit 31 - 16 (16 bit): EM style graphic
7799 bit 15 - 12 ( 4 bit): EM style frame
7800 bit 11 - 6 ( 6 bit): graphic width
7801 bit 5 - 0 ( 6 bit): graphic height */
7802 g_em->unique_identifier =
7803 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
7807 /* skip check for EMC elements not contained in original EMC artwork */
7808 if (element == EL_EMC_FAKE_ACID)
7811 if (g_em->bitmap != debug_bitmap ||
7812 g_em->src_x != debug_src_x ||
7813 g_em->src_y != debug_src_y ||
7814 g_em->src_offset_x != 0 ||
7815 g_em->src_offset_y != 0 ||
7816 g_em->dst_offset_x != 0 ||
7817 g_em->dst_offset_y != 0 ||
7818 g_em->width != TILEX ||
7819 g_em->height != TILEY)
7821 static int last_i = -1;
7829 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
7830 i, element, element_info[element].token_name,
7831 element_action_info[effective_action].suffix, direction);
7833 if (element != effective_element)
7834 printf(" [%d ('%s')]",
7836 element_info[effective_element].token_name);
7840 if (g_em->bitmap != debug_bitmap)
7841 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
7842 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
7844 if (g_em->src_x != debug_src_x ||
7845 g_em->src_y != debug_src_y)
7846 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
7847 j, (is_backside ? 'B' : 'F'),
7848 g_em->src_x, g_em->src_y,
7849 g_em->src_x / 32, g_em->src_y / 32,
7850 debug_src_x, debug_src_y,
7851 debug_src_x / 32, debug_src_y / 32);
7853 if (g_em->src_offset_x != 0 ||
7854 g_em->src_offset_y != 0 ||
7855 g_em->dst_offset_x != 0 ||
7856 g_em->dst_offset_y != 0)
7857 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
7859 g_em->src_offset_x, g_em->src_offset_y,
7860 g_em->dst_offset_x, g_em->dst_offset_y);
7862 if (g_em->width != TILEX ||
7863 g_em->height != TILEY)
7864 printf(" %d (%d): size %d,%d should be %d,%d\n",
7866 g_em->width, g_em->height, TILEX, TILEY);
7868 num_em_gfx_errors++;
7875 for (i = 0; i < TILE_MAX; i++)
7877 for (j = 0; j < 8; j++)
7879 int element = object_mapping[i].element_rnd;
7880 int action = object_mapping[i].action;
7881 int direction = object_mapping[i].direction;
7882 boolean is_backside = object_mapping[i].is_backside;
7883 int graphic_action = el_act_dir2img(element, action, direction);
7884 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
7886 if ((action == ACTION_SMASHED_BY_ROCK ||
7887 action == ACTION_SMASHED_BY_SPRING ||
7888 action == ACTION_EATING) &&
7889 graphic_action == graphic_default)
7891 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
7892 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
7893 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
7894 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
7897 /* no separate animation for "smashed by rock" -- use rock instead */
7898 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7899 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
7901 g_em->bitmap = g_xx->bitmap;
7902 g_em->src_x = g_xx->src_x;
7903 g_em->src_y = g_xx->src_y;
7904 g_em->src_offset_x = g_xx->src_offset_x;
7905 g_em->src_offset_y = g_xx->src_offset_y;
7906 g_em->dst_offset_x = g_xx->dst_offset_x;
7907 g_em->dst_offset_y = g_xx->dst_offset_y;
7908 g_em->width = g_xx->width;
7909 g_em->height = g_xx->height;
7910 g_em->unique_identifier = g_xx->unique_identifier;
7913 g_em->preserve_background = TRUE;
7918 for (p = 0; p < MAX_PLAYERS; p++)
7920 for (i = 0; i < SPR_MAX; i++)
7922 int element = player_mapping[p][i].element_rnd;
7923 int action = player_mapping[p][i].action;
7924 int direction = player_mapping[p][i].direction;
7926 for (j = 0; j < 8; j++)
7928 int effective_element = element;
7929 int effective_action = action;
7930 int graphic = (direction == MV_NONE ?
7931 el_act2img(effective_element, effective_action) :
7932 el_act_dir2img(effective_element, effective_action,
7934 struct GraphicInfo *g = &graphic_info[graphic];
7935 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
7941 Bitmap *debug_bitmap = g_em->bitmap;
7942 int debug_src_x = g_em->src_x;
7943 int debug_src_y = g_em->src_y;
7946 int frame = getAnimationFrame(g->anim_frames,
7949 g->anim_start_frame,
7952 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
7954 g_em->bitmap = src_bitmap;
7955 g_em->src_x = src_x;
7956 g_em->src_y = src_y;
7957 g_em->src_offset_x = 0;
7958 g_em->src_offset_y = 0;
7959 g_em->dst_offset_x = 0;
7960 g_em->dst_offset_y = 0;
7961 g_em->width = TILEX;
7962 g_em->height = TILEY;
7966 /* skip check for EMC elements not contained in original EMC artwork */
7967 if (element == EL_PLAYER_3 ||
7968 element == EL_PLAYER_4)
7971 if (g_em->bitmap != debug_bitmap ||
7972 g_em->src_x != debug_src_x ||
7973 g_em->src_y != debug_src_y)
7975 static int last_i = -1;
7983 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
7984 p, i, element, element_info[element].token_name,
7985 element_action_info[effective_action].suffix, direction);
7987 if (element != effective_element)
7988 printf(" [%d ('%s')]",
7990 element_info[effective_element].token_name);
7994 if (g_em->bitmap != debug_bitmap)
7995 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
7996 j, (int)(g_em->bitmap), (int)(debug_bitmap));
7998 if (g_em->src_x != debug_src_x ||
7999 g_em->src_y != debug_src_y)
8000 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
8002 g_em->src_x, g_em->src_y,
8003 g_em->src_x / 32, g_em->src_y / 32,
8004 debug_src_x, debug_src_y,
8005 debug_src_x / 32, debug_src_y / 32);
8007 num_em_gfx_errors++;
8017 printf("::: [%d errors found]\n", num_em_gfx_errors);
8023 void CheckSaveEngineSnapshot_EM(byte action[MAX_PLAYERS], int frame,
8024 boolean any_player_moving,
8025 boolean any_player_snapping,
8026 boolean any_player_dropping)
8028 static boolean player_was_waiting = TRUE;
8030 if (frame == 0 && !any_player_dropping)
8032 if (!player_was_waiting)
8034 if (!SaveEngineSnapshotToList())
8037 player_was_waiting = TRUE;
8040 else if (any_player_moving || any_player_snapping || any_player_dropping)
8042 player_was_waiting = FALSE;
8046 void CheckSaveEngineSnapshot_SP(boolean murphy_is_waiting,
8047 boolean murphy_is_dropping)
8049 static boolean player_was_waiting = TRUE;
8051 if (murphy_is_waiting)
8053 if (!player_was_waiting)
8055 if (!SaveEngineSnapshotToList())
8058 player_was_waiting = TRUE;
8063 player_was_waiting = FALSE;
8067 void CheckSingleStepMode_EM(byte action[MAX_PLAYERS], int frame,
8068 boolean any_player_moving,
8069 boolean any_player_snapping,
8070 boolean any_player_dropping)
8072 if (tape.single_step && tape.recording && !tape.pausing)
8073 if (frame == 0 && !any_player_dropping)
8074 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
8076 CheckSaveEngineSnapshot_EM(action, frame, any_player_moving,
8077 any_player_snapping, any_player_dropping);
8080 void CheckSingleStepMode_SP(boolean murphy_is_waiting,
8081 boolean murphy_is_dropping)
8083 if (tape.single_step && tape.recording && !tape.pausing)
8084 if (murphy_is_waiting)
8085 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
8087 CheckSaveEngineSnapshot_SP(murphy_is_waiting, murphy_is_dropping);
8090 void getGraphicSource_SP(struct GraphicInfo_SP *g_sp,
8091 int graphic, int sync_frame, int x, int y)
8093 int frame = getGraphicAnimationFrame(graphic, sync_frame);
8095 getGraphicSource(graphic, frame, &g_sp->bitmap, &g_sp->src_x, &g_sp->src_y);
8098 boolean isNextAnimationFrame_SP(int graphic, int sync_frame)
8100 return (IS_NEXT_FRAME(sync_frame, graphic));
8103 int getGraphicInfo_Delay(int graphic)
8105 return graphic_info[graphic].anim_delay;
8108 void PlayMenuSoundExt(int sound)
8110 if (sound == SND_UNDEFINED)
8113 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8114 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8117 if (IS_LOOP_SOUND(sound))
8118 PlaySoundLoop(sound);
8123 void PlayMenuSound()
8125 PlayMenuSoundExt(menu.sound[game_status]);
8128 void PlayMenuSoundStereo(int sound, int stereo_position)
8130 if (sound == SND_UNDEFINED)
8133 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8134 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8137 if (IS_LOOP_SOUND(sound))
8138 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
8140 PlaySoundStereo(sound, stereo_position);
8143 void PlayMenuSoundIfLoopExt(int sound)
8145 if (sound == SND_UNDEFINED)
8148 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8149 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8152 if (IS_LOOP_SOUND(sound))
8153 PlaySoundLoop(sound);
8156 void PlayMenuSoundIfLoop()
8158 PlayMenuSoundIfLoopExt(menu.sound[game_status]);
8161 void PlayMenuMusicExt(int music)
8163 if (music == MUS_UNDEFINED)
8166 if (!setup.sound_music)
8172 void PlayMenuMusic()
8174 PlayMenuMusicExt(menu.music[game_status]);
8177 void PlaySoundActivating()
8180 PlaySound(SND_MENU_ITEM_ACTIVATING);
8184 void PlaySoundSelecting()
8187 PlaySound(SND_MENU_ITEM_SELECTING);
8191 void ToggleFullscreenOrChangeWindowScalingIfNeeded()
8193 boolean change_fullscreen = (setup.fullscreen !=
8194 video.fullscreen_enabled);
8195 boolean change_window_scaling_percent = (!video.fullscreen_enabled &&
8196 setup.window_scaling_percent !=
8197 video.window_scaling_percent);
8199 if (change_window_scaling_percent && video.fullscreen_enabled)
8202 if (!change_window_scaling_percent && !video.fullscreen_available)
8205 #if defined(TARGET_SDL2)
8206 if (change_window_scaling_percent)
8208 SDLSetWindowScaling(setup.window_scaling_percent);
8212 else if (change_fullscreen)
8214 SDLSetWindowFullscreen(setup.fullscreen);
8216 /* set setup value according to successfully changed fullscreen mode */
8217 setup.fullscreen = video.fullscreen_enabled;
8223 if (change_fullscreen ||
8224 change_window_scaling_percent)
8226 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
8228 /* save backbuffer content which gets lost when toggling fullscreen mode */
8229 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8231 if (change_window_scaling_percent)
8233 /* keep window mode, but change window scaling */
8234 video.fullscreen_enabled = TRUE; /* force new window scaling */
8237 /* toggle fullscreen */
8238 ChangeVideoModeIfNeeded(setup.fullscreen);
8240 /* set setup value according to successfully changed fullscreen mode */
8241 setup.fullscreen = video.fullscreen_enabled;
8243 /* restore backbuffer content from temporary backbuffer backup bitmap */
8244 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8246 FreeBitmap(tmp_backbuffer);
8248 /* update visible window/screen */
8249 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8253 void JoinRectangles(int *x, int *y, int *width, int *height,
8254 int x2, int y2, int width2, int height2)
8256 // do not join with "off-screen" rectangle
8257 if (x2 == -1 || y2 == -1)
8262 *width = MAX(*width, width2);
8263 *height = MAX(*height, height2);
8266 void SetAnimStatus(int anim_status_new)
8268 if (anim_status_new == GAME_MODE_MAIN)
8269 anim_status_new = GAME_MODE_PSEUDO_MAINONLY;
8271 global.anim_status_next = anim_status_new;
8273 // directly set screen modes that are entered without fading
8274 if ((global.anim_status == GAME_MODE_PSEUDO_MAINONLY &&
8275 global.anim_status_next == GAME_MODE_PSEUDO_TYPENAME) ||
8276 (global.anim_status == GAME_MODE_PSEUDO_TYPENAME &&
8277 global.anim_status_next == GAME_MODE_PSEUDO_MAINONLY))
8278 global.anim_status = global.anim_status_next;
8281 void SetGameStatus(int game_status_new)
8283 game_status = game_status_new;
8285 SetAnimStatus(game_status_new);
8288 void SetFontStatus(int game_status_new)
8290 static int last_game_status = -1;
8292 if (game_status_new != -1)
8294 // set game status for font use after storing last game status
8295 last_game_status = game_status;
8296 game_status = game_status_new;
8300 // reset game status after font use from last stored game status
8301 game_status = last_game_status;
8305 void ResetFontStatus()
8310 void ChangeViewportPropertiesIfNeeded()
8312 int gfx_game_mode = game_status;
8313 int gfx_game_mode2 = (game_status == GAME_MODE_EDITOR ? GAME_MODE_DEFAULT :
8315 struct RectWithBorder *vp_window = &viewport.window[gfx_game_mode];
8316 struct RectWithBorder *vp_playfield = &viewport.playfield[gfx_game_mode];
8317 struct RectWithBorder *vp_door_1 = &viewport.door_1[gfx_game_mode];
8318 struct RectWithBorder *vp_door_2 = &viewport.door_2[gfx_game_mode2];
8319 struct RectWithBorder *vp_door_3 = &viewport.door_2[GAME_MODE_EDITOR];
8320 int new_win_xsize = vp_window->width;
8321 int new_win_ysize = vp_window->height;
8322 int border_size = vp_playfield->border_size;
8323 int new_sx = vp_playfield->x + border_size;
8324 int new_sy = vp_playfield->y + border_size;
8325 int new_sxsize = vp_playfield->width - 2 * border_size;
8326 int new_sysize = vp_playfield->height - 2 * border_size;
8327 int new_real_sx = vp_playfield->x;
8328 int new_real_sy = vp_playfield->y;
8329 int new_full_sxsize = vp_playfield->width;
8330 int new_full_sysize = vp_playfield->height;
8331 int new_dx = vp_door_1->x;
8332 int new_dy = vp_door_1->y;
8333 int new_dxsize = vp_door_1->width;
8334 int new_dysize = vp_door_1->height;
8335 int new_vx = vp_door_2->x;
8336 int new_vy = vp_door_2->y;
8337 int new_vxsize = vp_door_2->width;
8338 int new_vysize = vp_door_2->height;
8339 int new_ex = vp_door_3->x;
8340 int new_ey = vp_door_3->y;
8341 int new_exsize = vp_door_3->width;
8342 int new_eysize = vp_door_3->height;
8343 int new_tilesize_var =
8344 (setup.small_game_graphics ? MINI_TILESIZE : game.tile_size);
8346 int tilesize = (gfx_game_mode == GAME_MODE_PLAYING ? new_tilesize_var :
8347 gfx_game_mode == GAME_MODE_EDITOR ? MINI_TILESIZE : TILESIZE);
8348 int new_scr_fieldx = new_sxsize / tilesize;
8349 int new_scr_fieldy = new_sysize / tilesize;
8350 int new_scr_fieldx_buffers = new_sxsize / new_tilesize_var;
8351 int new_scr_fieldy_buffers = new_sysize / new_tilesize_var;
8352 boolean init_gfx_buffers = FALSE;
8353 boolean init_video_buffer = FALSE;
8354 boolean init_gadgets_and_anims = FALSE;
8355 boolean init_em_graphics = FALSE;
8357 if (new_win_xsize != WIN_XSIZE ||
8358 new_win_ysize != WIN_YSIZE)
8360 WIN_XSIZE = new_win_xsize;
8361 WIN_YSIZE = new_win_ysize;
8363 init_video_buffer = TRUE;
8364 init_gfx_buffers = TRUE;
8365 init_gadgets_and_anims = TRUE;
8367 // printf("::: video: init_video_buffer, init_gfx_buffers\n");
8370 if (new_scr_fieldx != SCR_FIELDX ||
8371 new_scr_fieldy != SCR_FIELDY)
8373 /* this always toggles between MAIN and GAME when using small tile size */
8375 SCR_FIELDX = new_scr_fieldx;
8376 SCR_FIELDY = new_scr_fieldy;
8378 // printf("::: new_scr_fieldx != SCR_FIELDX ...\n");
8389 new_sxsize != SXSIZE ||
8390 new_sysize != SYSIZE ||
8391 new_dxsize != DXSIZE ||
8392 new_dysize != DYSIZE ||
8393 new_vxsize != VXSIZE ||
8394 new_vysize != VYSIZE ||
8395 new_exsize != EXSIZE ||
8396 new_eysize != EYSIZE ||
8397 new_real_sx != REAL_SX ||
8398 new_real_sy != REAL_SY ||
8399 new_full_sxsize != FULL_SXSIZE ||
8400 new_full_sysize != FULL_SYSIZE ||
8401 new_tilesize_var != TILESIZE_VAR
8404 // ------------------------------------------------------------------------
8405 // determine next fading area for changed viewport definitions
8406 // ------------------------------------------------------------------------
8408 // start with current playfield area (default fading area)
8411 FADE_SXSIZE = FULL_SXSIZE;
8412 FADE_SYSIZE = FULL_SYSIZE;
8414 // add new playfield area if position or size has changed
8415 if (new_real_sx != REAL_SX || new_real_sy != REAL_SY ||
8416 new_full_sxsize != FULL_SXSIZE || new_full_sysize != FULL_SYSIZE)
8418 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
8419 new_real_sx, new_real_sy, new_full_sxsize,new_full_sysize);
8422 // add current and new door 1 area if position or size has changed
8423 if (new_dx != DX || new_dy != DY ||
8424 new_dxsize != DXSIZE || new_dysize != DYSIZE)
8426 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
8427 DX, DY, DXSIZE, DYSIZE);
8428 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
8429 new_dx, new_dy, new_dxsize, new_dysize);
8432 // add current and new door 2 area if position or size has changed
8433 if (new_dx != VX || new_dy != VY ||
8434 new_dxsize != VXSIZE || new_dysize != VYSIZE)
8436 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
8437 VX, VY, VXSIZE, VYSIZE);
8438 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
8439 new_vx, new_vy, new_vxsize, new_vysize);
8442 // ------------------------------------------------------------------------
8443 // handle changed tile size
8444 // ------------------------------------------------------------------------
8446 if (new_tilesize_var != TILESIZE_VAR)
8448 // printf("::: new_tilesize_var != TILESIZE_VAR\n");
8450 // changing tile size invalidates scroll values of engine snapshots
8451 FreeEngineSnapshotSingle();
8453 // changing tile size requires update of graphic mapping for EM engine
8454 init_em_graphics = TRUE;
8465 SXSIZE = new_sxsize;
8466 SYSIZE = new_sysize;
8467 DXSIZE = new_dxsize;
8468 DYSIZE = new_dysize;
8469 VXSIZE = new_vxsize;
8470 VYSIZE = new_vysize;
8471 EXSIZE = new_exsize;
8472 EYSIZE = new_eysize;
8473 REAL_SX = new_real_sx;
8474 REAL_SY = new_real_sy;
8475 FULL_SXSIZE = new_full_sxsize;
8476 FULL_SYSIZE = new_full_sysize;
8477 TILESIZE_VAR = new_tilesize_var;
8479 init_gfx_buffers = TRUE;
8480 init_gadgets_and_anims = TRUE;
8482 // printf("::: viewports: init_gfx_buffers\n");
8483 // printf("::: viewports: init_gadgets_and_anims\n");
8486 if (init_gfx_buffers)
8488 // printf("::: init_gfx_buffers\n");
8490 SCR_FIELDX = new_scr_fieldx_buffers;
8491 SCR_FIELDY = new_scr_fieldy_buffers;
8495 SCR_FIELDX = new_scr_fieldx;
8496 SCR_FIELDY = new_scr_fieldy;
8498 SetDrawDeactivationMask(REDRAW_NONE);
8499 SetDrawBackgroundMask(REDRAW_FIELD);
8502 if (init_video_buffer)
8504 // printf("::: init_video_buffer\n");
8506 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
8507 InitImageTextures();
8510 if (init_gadgets_and_anims)
8512 // printf("::: init_gadgets_and_anims\n");
8515 InitGlobalAnimations();
8518 if (init_em_graphics)
8520 InitGraphicInfo_EM();