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_FIELDBUFFER)
243 BX2 = SCR_FIELDX + 1;
244 BY2 = SCR_FIELDY + 1;
246 drawto_field = fieldbuffer;
248 else /* DRAW_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_BORDER_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_BORDER_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_BORDER_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_BORDER_TO_BACKBUFFER);
377 void DrawMaskedBorder(int redraw_mask)
379 DrawMaskedBorderExt(redraw_mask, DRAW_BORDER_TO_BACKBUFFER);
382 void DrawMaskedBorderToTarget(int draw_target)
384 if (draw_target == DRAW_BORDER_TO_BACKBUFFER ||
385 draw_target == DRAW_BORDER_TO_SCREEN)
387 DrawMaskedBorderExt(REDRAW_ALL, draw_target);
391 int last_border_status = global.border_status;
393 if (draw_target == DRAW_BORDER_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_BORDER_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()
722 static void SetScreenStates_AfterFadingIn()
724 // store new source screen (to use correct masked border for fading)
725 gfx.fade_border_source_status = global.border_status;
727 global.anim_status = global.anim_status_next;
729 // force update of global animation status in case of rapid screen changes
730 redraw_mask = REDRAW_ALL;
734 static void SetScreenStates_BeforeFadingOut()
736 // store new target screen (to use correct masked border for fading)
737 gfx.fade_border_target_status = game_status;
739 global.anim_status = GAME_MODE_PSEUDO_FADING;
742 static void SetScreenStates_AfterFadingOut()
744 global.border_status = game_status;
747 void FadeIn(int fade_mask)
749 SetScreenStates_BeforeFadingIn();
752 DrawMaskedBorder(REDRAW_ALL);
755 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
756 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_IN);
758 FadeExt(fade_mask, FADE_MODE_FADE_IN, FADE_TYPE_FADE_IN);
762 FADE_SXSIZE = FULL_SXSIZE;
763 FADE_SYSIZE = FULL_SYSIZE;
765 SetScreenStates_AfterFadingIn();
768 void FadeOut(int fade_mask)
770 SetScreenStates_BeforeFadingOut();
773 DrawMaskedBorder(REDRAW_ALL);
776 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
777 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_OUT);
779 FadeExt(fade_mask, FADE_MODE_FADE_OUT, FADE_TYPE_FADE_OUT);
781 SetScreenStates_AfterFadingOut();
784 static void FadeSetLeaveNext(struct TitleFadingInfo fading_leave, boolean set)
786 static struct TitleFadingInfo fading_leave_stored;
789 fading_leave_stored = fading_leave;
791 fading = fading_leave_stored;
794 void FadeSetEnterMenu()
796 fading = menu.enter_menu;
798 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
801 void FadeSetLeaveMenu()
803 fading = menu.leave_menu;
805 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
808 void FadeSetEnterScreen()
810 fading = menu.enter_screen[game_status];
812 FadeSetLeaveNext(menu.leave_screen[game_status], TRUE); /* store */
815 void FadeSetNextScreen()
817 fading = menu.next_screen[game_status];
819 // (do not overwrite fade mode set by FadeSetEnterScreen)
820 // FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
823 void FadeSetLeaveScreen()
825 FadeSetLeaveNext(menu.leave_screen[game_status], FALSE); /* recall */
828 void FadeSetFromType(int type)
830 if (type & TYPE_ENTER_SCREEN)
831 FadeSetEnterScreen();
832 else if (type & TYPE_ENTER)
834 else if (type & TYPE_LEAVE)
838 void FadeSetDisabled()
840 static struct TitleFadingInfo fading_none = { FADE_MODE_NONE, -1, -1, -1 };
842 fading = fading_none;
845 void FadeSkipNextFadeIn()
847 FadeExt(0, FADE_MODE_SKIP_FADE_IN, FADE_TYPE_SKIP);
850 void FadeSkipNextFadeOut()
852 FadeExt(0, FADE_MODE_SKIP_FADE_OUT, FADE_TYPE_SKIP);
855 Bitmap *getBitmapFromGraphicOrDefault(int graphic, int default_graphic)
857 boolean redefined = getImageListEntryFromImageID(graphic)->redefined;
859 return (graphic == IMG_UNDEFINED ? NULL :
860 graphic_info[graphic].bitmap != NULL || redefined ?
861 graphic_info[graphic].bitmap :
862 graphic_info[default_graphic].bitmap);
865 Bitmap *getBackgroundBitmap(int graphic)
867 return getBitmapFromGraphicOrDefault(graphic, IMG_BACKGROUND);
870 Bitmap *getGlobalBorderBitmap(int graphic)
872 return getBitmapFromGraphicOrDefault(graphic, IMG_GLOBAL_BORDER);
875 Bitmap *getGlobalBorderBitmapFromStatus(int status)
878 (status == GAME_MODE_MAIN ||
879 status == GAME_MODE_PSEUDO_TYPENAME ? IMG_GLOBAL_BORDER_MAIN :
880 status == GAME_MODE_SCORES ? IMG_GLOBAL_BORDER_SCORES :
881 status == GAME_MODE_EDITOR ? IMG_GLOBAL_BORDER_EDITOR :
882 status == GAME_MODE_PLAYING ? IMG_GLOBAL_BORDER_PLAYING :
885 return getGlobalBorderBitmap(graphic);
888 void SetWindowBackgroundImageIfDefined(int graphic)
890 if (graphic_info[graphic].bitmap)
891 SetWindowBackgroundBitmap(graphic_info[graphic].bitmap);
894 void SetMainBackgroundImageIfDefined(int graphic)
896 if (graphic_info[graphic].bitmap)
897 SetMainBackgroundBitmap(graphic_info[graphic].bitmap);
900 void SetDoorBackgroundImageIfDefined(int graphic)
902 if (graphic_info[graphic].bitmap)
903 SetDoorBackgroundBitmap(graphic_info[graphic].bitmap);
906 void SetWindowBackgroundImage(int graphic)
908 SetWindowBackgroundBitmap(getBackgroundBitmap(graphic));
911 void SetMainBackgroundImage(int graphic)
913 SetMainBackgroundBitmap(getBackgroundBitmap(graphic));
916 void SetDoorBackgroundImage(int graphic)
918 SetDoorBackgroundBitmap(getBackgroundBitmap(graphic));
921 void SetPanelBackground()
923 struct GraphicInfo *gfx = &graphic_info[IMG_BACKGROUND_PANEL];
925 BlitBitmapTiled(gfx->bitmap, bitmap_db_panel, gfx->src_x, gfx->src_y,
926 gfx->width, gfx->height, 0, 0, DXSIZE, DYSIZE);
928 SetDoorBackgroundBitmap(bitmap_db_panel);
931 void DrawBackground(int x, int y, int width, int height)
933 /* "drawto" might still point to playfield buffer here (hall of fame) */
934 ClearRectangleOnBackground(backbuffer, x, y, width, height);
936 if (IN_GFX_FIELD_FULL(x, y))
937 redraw_mask |= REDRAW_FIELD;
938 else if (IN_GFX_DOOR_1(x, y))
939 redraw_mask |= REDRAW_DOOR_1;
940 else if (IN_GFX_DOOR_2(x, y))
941 redraw_mask |= REDRAW_DOOR_2;
942 else if (IN_GFX_DOOR_3(x, y))
943 redraw_mask |= REDRAW_DOOR_3;
946 void DrawBackgroundForFont(int x, int y, int width, int height, int font_nr)
948 struct FontBitmapInfo *font = getFontBitmapInfo(font_nr);
950 if (font->bitmap == NULL)
953 DrawBackground(x, y, width, height);
956 void DrawBackgroundForGraphic(int x, int y, int width, int height, int graphic)
958 struct GraphicInfo *g = &graphic_info[graphic];
960 if (g->bitmap == NULL)
963 DrawBackground(x, y, width, height);
966 static int game_status_last = -1;
967 static Bitmap *global_border_bitmap_last = NULL;
968 static Bitmap *global_border_bitmap = NULL;
969 static int real_sx_last = -1, real_sy_last = -1;
970 static int full_sxsize_last = -1, full_sysize_last = -1;
971 static int dx_last = -1, dy_last = -1;
972 static int dxsize_last = -1, dysize_last = -1;
973 static int vx_last = -1, vy_last = -1;
974 static int vxsize_last = -1, vysize_last = -1;
976 boolean CheckIfGlobalBorderHasChanged()
978 // if game status has not changed, global border has not changed either
979 if (game_status == game_status_last)
982 // determine and store new global border bitmap for current game status
983 global_border_bitmap = getGlobalBorderBitmapFromStatus(game_status);
985 return (global_border_bitmap_last != global_border_bitmap);
988 boolean CheckIfGlobalBorderRedrawIsNeeded()
990 // if game status has not changed, nothing has to be redrawn
991 if (game_status == game_status_last)
994 // redraw if last screen was title screen
995 if (game_status_last == GAME_MODE_TITLE)
998 // redraw if global screen border has changed
999 if (CheckIfGlobalBorderHasChanged())
1002 // redraw if position or size of playfield area has changed
1003 if (real_sx_last != REAL_SX || real_sy_last != REAL_SY ||
1004 full_sxsize_last != FULL_SXSIZE || full_sysize_last != FULL_SYSIZE)
1007 // redraw if position or size of door area has changed
1008 if (dx_last != DX || dy_last != DY ||
1009 dxsize_last != DXSIZE || dysize_last != DYSIZE)
1012 // redraw if position or size of tape area has changed
1013 if (vx_last != VX || vy_last != VY ||
1014 vxsize_last != VXSIZE || vysize_last != VYSIZE)
1020 void RedrawGlobalBorderFromBitmap(Bitmap *bitmap)
1023 BlitBitmap(bitmap, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
1025 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
1028 void RedrawGlobalBorder()
1030 Bitmap *bitmap = getGlobalBorderBitmapFromStatus(game_status);
1032 RedrawGlobalBorderFromBitmap(bitmap);
1034 redraw_mask = REDRAW_ALL;
1037 static void RedrawGlobalBorderIfNeeded()
1039 if (game_status == game_status_last)
1042 // copy current draw buffer to later copy back areas that have not changed
1043 if (game_status_last != GAME_MODE_TITLE)
1044 BlitBitmap(backbuffer, bitmap_db_store, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
1046 if (CheckIfGlobalBorderRedrawIsNeeded())
1048 // redraw global screen border (or clear, if defined to be empty)
1049 RedrawGlobalBorderFromBitmap(global_border_bitmap);
1051 // copy previous playfield and door areas, if they are defined on both
1052 // previous and current screen and if they still have the same size
1054 if (real_sx_last != -1 && real_sy_last != -1 &&
1055 REAL_SX != -1 && REAL_SY != -1 &&
1056 full_sxsize_last == FULL_SXSIZE && full_sysize_last == FULL_SYSIZE)
1057 BlitBitmap(bitmap_db_store, backbuffer,
1058 real_sx_last, real_sy_last, FULL_SXSIZE, FULL_SYSIZE,
1061 if (dx_last != -1 && dy_last != -1 &&
1062 DX != -1 && DY != -1 &&
1063 dxsize_last == DXSIZE && dysize_last == DYSIZE)
1064 BlitBitmap(bitmap_db_store, backbuffer,
1065 dx_last, dy_last, DXSIZE, DYSIZE, DX, DY);
1067 if (vx_last != -1 && vy_last != -1 &&
1068 VX != -1 && VY != -1 &&
1069 vxsize_last == VXSIZE && vysize_last == VYSIZE)
1070 BlitBitmap(bitmap_db_store, backbuffer,
1071 vx_last, vy_last, VXSIZE, VYSIZE, VX, VY);
1073 redraw_mask = REDRAW_ALL;
1076 game_status_last = game_status;
1078 global_border_bitmap_last = global_border_bitmap;
1080 real_sx_last = REAL_SX;
1081 real_sy_last = REAL_SY;
1082 full_sxsize_last = FULL_SXSIZE;
1083 full_sysize_last = FULL_SYSIZE;
1086 dxsize_last = DXSIZE;
1087 dysize_last = DYSIZE;
1090 vxsize_last = VXSIZE;
1091 vysize_last = VYSIZE;
1096 RedrawGlobalBorderIfNeeded();
1098 /* !!! "drawto" might still point to playfield buffer here (see above) !!! */
1099 /* (when entering hall of fame after playing) */
1100 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
1102 /* !!! maybe this should be done before clearing the background !!! */
1103 if (game_status == GAME_MODE_PLAYING)
1105 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
1106 SetDrawtoField(DRAW_FIELDBUFFER);
1110 SetDrawtoField(DRAW_BACKBUFFER);
1114 void MarkTileDirty(int x, int y)
1116 redraw_mask |= REDRAW_FIELD;
1119 void SetBorderElement()
1123 BorderElement = EL_EMPTY;
1125 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
1127 for (x = 0; x < lev_fieldx; x++)
1129 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
1130 BorderElement = EL_STEELWALL;
1132 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
1138 void FloodFillLevel(int from_x, int from_y, int fill_element,
1139 short field[MAX_LEV_FIELDX][MAX_LEV_FIELDY],
1140 int max_fieldx, int max_fieldy)
1144 static int check[4][2] = { { -1, 0 }, { 0, -1 }, { 1, 0 }, { 0, 1 } };
1145 static int safety = 0;
1147 /* check if starting field still has the desired content */
1148 if (field[from_x][from_y] == fill_element)
1153 if (safety > max_fieldx * max_fieldy)
1154 Error(ERR_EXIT, "Something went wrong in 'FloodFill()'. Please debug.");
1156 old_element = field[from_x][from_y];
1157 field[from_x][from_y] = fill_element;
1159 for (i = 0; i < 4; i++)
1161 x = from_x + check[i][0];
1162 y = from_y + check[i][1];
1164 if (IN_FIELD(x, y, max_fieldx, max_fieldy) && field[x][y] == old_element)
1165 FloodFillLevel(x, y, fill_element, field, max_fieldx, max_fieldy);
1171 void SetRandomAnimationValue(int x, int y)
1173 gfx.anim_random_frame = GfxRandom[x][y];
1176 int getGraphicAnimationFrame(int graphic, int sync_frame)
1178 /* animation synchronized with global frame counter, not move position */
1179 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
1180 sync_frame = FrameCounter;
1182 return getAnimationFrame(graphic_info[graphic].anim_frames,
1183 graphic_info[graphic].anim_delay,
1184 graphic_info[graphic].anim_mode,
1185 graphic_info[graphic].anim_start_frame,
1189 void getSizedGraphicSourceExt(int graphic, int frame, int tilesize,
1190 Bitmap **bitmap, int *x, int *y,
1191 boolean get_backside)
1193 struct GraphicInfo *g = &graphic_info[graphic];
1194 Bitmap *src_bitmap = g->bitmap;
1195 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
1196 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
1197 int tilesize_capped = MIN(MAX(1, tilesize), TILESIZE);
1199 // if no in-game graphics defined, always use standard graphic size
1200 if (g->bitmaps[IMG_BITMAP_GAME] == NULL)
1201 tilesize = TILESIZE;
1203 if (tilesize == gfx.standard_tile_size)
1204 src_bitmap = g->bitmaps[IMG_BITMAP_STANDARD];
1205 else if (tilesize == game.tile_size)
1206 src_bitmap = g->bitmaps[IMG_BITMAP_GAME];
1208 src_bitmap = g->bitmaps[IMG_BITMAP_1x1 - log_2(tilesize_capped)];
1210 if (g->offset_y == 0) /* frames are ordered horizontally */
1212 int max_width = g->anim_frames_per_line * g->width;
1213 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
1215 src_x = pos % max_width;
1216 src_y = src_y % g->height + pos / max_width * g->height;
1218 else if (g->offset_x == 0) /* frames are ordered vertically */
1220 int max_height = g->anim_frames_per_line * g->height;
1221 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
1223 src_x = src_x % g->width + pos / max_height * g->width;
1224 src_y = pos % max_height;
1226 else /* frames are ordered diagonally */
1228 src_x = src_x + frame * g->offset_x;
1229 src_y = src_y + frame * g->offset_y;
1232 *bitmap = src_bitmap;
1233 *x = src_x * tilesize / g->tile_size;
1234 *y = src_y * tilesize / g->tile_size;
1237 void getFixedGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1238 int *x, int *y, boolean get_backside)
1240 getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y,
1244 void getSizedGraphicSource(int graphic, int frame, int tilesize,
1245 Bitmap **bitmap, int *x, int *y)
1247 getSizedGraphicSourceExt(graphic, frame, tilesize, bitmap, x, y, FALSE);
1250 void getFixedGraphicSource(int graphic, int frame,
1251 Bitmap **bitmap, int *x, int *y)
1253 getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y, FALSE);
1256 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1258 getSizedGraphicSource(graphic, 0, MINI_TILESIZE, bitmap, x, y);
1261 inline static void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1262 int *x, int *y, boolean get_backside)
1264 struct GraphicInfo *g = &graphic_info[graphic];
1265 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
1266 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
1268 if (TILESIZE_VAR != TILESIZE)
1269 return getSizedGraphicSourceExt(graphic, frame, TILESIZE_VAR, bitmap, x, y,
1272 *bitmap = g->bitmap;
1274 if (g->offset_y == 0) /* frames are ordered horizontally */
1276 int max_width = g->anim_frames_per_line * g->width;
1277 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
1279 *x = pos % max_width;
1280 *y = src_y % g->height + pos / max_width * g->height;
1282 else if (g->offset_x == 0) /* frames are ordered vertically */
1284 int max_height = g->anim_frames_per_line * g->height;
1285 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
1287 *x = src_x % g->width + pos / max_height * g->width;
1288 *y = pos % max_height;
1290 else /* frames are ordered diagonally */
1292 *x = src_x + frame * g->offset_x;
1293 *y = src_y + frame * g->offset_y;
1296 *x = *x * TILESIZE_VAR / g->tile_size;
1297 *y = *y * TILESIZE_VAR / g->tile_size;
1300 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
1302 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
1305 void DrawGraphic(int x, int y, int graphic, int frame)
1308 if (!IN_SCR_FIELD(x, y))
1310 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1311 printf("DrawGraphic(): This should never happen!\n");
1316 DrawGraphicExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR, graphic,
1319 MarkTileDirty(x, y);
1322 void DrawFixedGraphic(int x, int y, int graphic, int frame)
1325 if (!IN_SCR_FIELD(x, y))
1327 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1328 printf("DrawGraphic(): This should never happen!\n");
1333 DrawFixedGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic,
1335 MarkTileDirty(x, y);
1338 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1344 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1346 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX_VAR, TILEY_VAR, x, y);
1349 void DrawFixedGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1355 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1356 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
1359 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
1362 if (!IN_SCR_FIELD(x, y))
1364 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1365 printf("DrawGraphicThruMask(): This should never happen!\n");
1370 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
1373 MarkTileDirty(x, y);
1376 void DrawFixedGraphicThruMask(int x, int y, int graphic, int frame)
1379 if (!IN_SCR_FIELD(x, y))
1381 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1382 printf("DrawGraphicThruMask(): This should never happen!\n");
1387 DrawFixedGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
1389 MarkTileDirty(x, y);
1392 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
1398 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1400 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX_VAR, TILEY_VAR,
1404 void DrawFixedGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y,
1405 int graphic, int frame)
1410 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1412 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY,
1416 void DrawSizedGraphic(int x, int y, int graphic, int frame, int tilesize)
1418 DrawSizedGraphicExt(drawto, SX + x * tilesize, SY + y * tilesize, graphic,
1420 MarkTileDirty(x / tilesize, y / tilesize);
1423 void DrawSizedGraphicExt(DrawBuffer *d, int x, int y, int graphic, int frame,
1429 getSizedGraphicSource(graphic, frame, tilesize, &src_bitmap, &src_x, &src_y);
1430 BlitBitmap(src_bitmap, d, src_x, src_y, tilesize, tilesize, x, y);
1433 void DrawMiniGraphic(int x, int y, int graphic)
1435 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
1436 MarkTileDirty(x / 2, y / 2);
1439 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
1444 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1445 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
1448 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
1449 int graphic, int frame,
1450 int cut_mode, int mask_mode)
1455 int width = TILEX, height = TILEY;
1458 if (dx || dy) /* shifted graphic */
1460 if (x < BX1) /* object enters playfield from the left */
1467 else if (x > BX2) /* object enters playfield from the right */
1473 else if (x == BX1 && dx < 0) /* object leaves playfield to the left */
1479 else if (x == BX2 && dx > 0) /* object leaves playfield to the right */
1481 else if (dx) /* general horizontal movement */
1482 MarkTileDirty(x + SIGN(dx), y);
1484 if (y < BY1) /* object enters playfield from the top */
1486 if (cut_mode == CUT_BELOW) /* object completely above top border */
1494 else if (y > BY2) /* object enters playfield from the bottom */
1500 else if (y == BY1 && dy < 0) /* object leaves playfield to the top */
1506 else if (dy > 0 && cut_mode == CUT_ABOVE)
1508 if (y == BY2) /* object completely above bottom border */
1514 MarkTileDirty(x, y + 1);
1515 } /* object leaves playfield to the bottom */
1516 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1518 else if (dy) /* general vertical movement */
1519 MarkTileDirty(x, y + SIGN(dy));
1523 if (!IN_SCR_FIELD(x, y))
1525 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1526 printf("DrawGraphicShifted(): This should never happen!\n");
1531 width = width * TILESIZE_VAR / TILESIZE;
1532 height = height * TILESIZE_VAR / TILESIZE;
1533 cx = cx * TILESIZE_VAR / TILESIZE;
1534 cy = cy * TILESIZE_VAR / TILESIZE;
1535 dx = dx * TILESIZE_VAR / TILESIZE;
1536 dy = dy * TILESIZE_VAR / TILESIZE;
1538 if (width > 0 && height > 0)
1540 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1545 dst_x = FX + x * TILEX_VAR + dx;
1546 dst_y = FY + y * TILEY_VAR + dy;
1548 if (mask_mode == USE_MASKING)
1549 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1552 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1555 MarkTileDirty(x, y);
1559 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
1560 int graphic, int frame,
1561 int cut_mode, int mask_mode)
1566 int width = TILEX_VAR, height = TILEY_VAR;
1569 int x2 = x + SIGN(dx);
1570 int y2 = y + SIGN(dy);
1572 /* movement with two-tile animations must be sync'ed with movement position,
1573 not with current GfxFrame (which can be higher when using slow movement) */
1574 int anim_pos = (dx ? ABS(dx) : ABS(dy));
1575 int anim_frames = graphic_info[graphic].anim_frames;
1577 /* (we also need anim_delay here for movement animations with less frames) */
1578 int anim_delay = graphic_info[graphic].anim_delay;
1579 int sync_frame = anim_pos * anim_frames * anim_delay / TILESIZE;
1581 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
1582 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
1584 /* re-calculate animation frame for two-tile movement animation */
1585 frame = getGraphicAnimationFrame(graphic, sync_frame);
1587 /* check if movement start graphic inside screen area and should be drawn */
1588 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
1590 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
1592 dst_x = FX + x1 * TILEX_VAR;
1593 dst_y = FY + y1 * TILEY_VAR;
1595 if (mask_mode == USE_MASKING)
1596 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1599 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1602 MarkTileDirty(x1, y1);
1605 /* check if movement end graphic inside screen area and should be drawn */
1606 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
1608 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
1610 dst_x = FX + x2 * TILEX_VAR;
1611 dst_y = FY + y2 * TILEY_VAR;
1613 if (mask_mode == USE_MASKING)
1614 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1617 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1620 MarkTileDirty(x2, y2);
1624 static void DrawGraphicShifted(int x, int y, int dx, int dy,
1625 int graphic, int frame,
1626 int cut_mode, int mask_mode)
1630 DrawGraphic(x, y, graphic, frame);
1635 if (graphic_info[graphic].double_movement) /* EM style movement images */
1636 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1638 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1641 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1642 int frame, int cut_mode)
1644 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
1647 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1648 int cut_mode, int mask_mode)
1650 int lx = LEVELX(x), ly = LEVELY(y);
1654 if (IN_LEV_FIELD(lx, ly))
1656 SetRandomAnimationValue(lx, ly);
1658 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
1659 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1661 /* do not use double (EM style) movement graphic when not moving */
1662 if (graphic_info[graphic].double_movement && !dx && !dy)
1664 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
1665 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1668 else /* border element */
1670 graphic = el2img(element);
1671 frame = getGraphicAnimationFrame(graphic, -1);
1674 if (element == EL_EXPANDABLE_WALL)
1676 boolean left_stopped = FALSE, right_stopped = FALSE;
1678 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1679 left_stopped = TRUE;
1680 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1681 right_stopped = TRUE;
1683 if (left_stopped && right_stopped)
1685 else if (left_stopped)
1687 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1688 frame = graphic_info[graphic].anim_frames - 1;
1690 else if (right_stopped)
1692 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1693 frame = graphic_info[graphic].anim_frames - 1;
1698 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1699 else if (mask_mode == USE_MASKING)
1700 DrawGraphicThruMask(x, y, graphic, frame);
1702 DrawGraphic(x, y, graphic, frame);
1705 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1706 int cut_mode, int mask_mode)
1708 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1709 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1710 cut_mode, mask_mode);
1713 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1716 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1719 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1722 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1725 void DrawLevelElementThruMask(int x, int y, int element)
1727 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1730 void DrawLevelFieldThruMask(int x, int y)
1732 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1735 /* !!! implementation of quicksand is totally broken !!! */
1736 #define IS_CRUMBLED_TILE(x, y, e) \
1737 (GFX_CRUMBLED(e) && (!IN_LEV_FIELD(x, y) || \
1738 !IS_MOVING(x, y) || \
1739 (e) == EL_QUICKSAND_EMPTYING || \
1740 (e) == EL_QUICKSAND_FAST_EMPTYING))
1742 static void DrawLevelFieldCrumbledInnerCorners(int x, int y, int dx, int dy,
1747 int width, height, cx, cy;
1748 int sx = SCREENX(x), sy = SCREENY(y);
1749 int crumbled_border_size = graphic_info[graphic].border_size;
1752 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1754 for (i = 1; i < 4; i++)
1756 int dxx = (i & 1 ? dx : 0);
1757 int dyy = (i & 2 ? dy : 0);
1760 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1763 /* check if neighbour field is of same crumble type */
1764 boolean same = (IS_CRUMBLED_TILE(xx, yy, element) &&
1765 graphic_info[graphic].class ==
1766 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class);
1768 /* return if check prevents inner corner */
1769 if (same == (dxx == dx && dyy == dy))
1773 /* if we reach this point, we have an inner corner */
1775 getGraphicSource(graphic, 1, &src_bitmap, &src_x, &src_y);
1777 width = crumbled_border_size * TILESIZE_VAR / TILESIZE;
1778 height = crumbled_border_size * TILESIZE_VAR / TILESIZE;
1779 cx = (dx > 0 ? TILESIZE_VAR - width : 0);
1780 cy = (dy > 0 ? TILESIZE_VAR - height : 0);
1782 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1783 width, height, FX + sx * TILEX_VAR + cx, FY + sy * TILEY_VAR + cy);
1786 static void DrawLevelFieldCrumbledBorders(int x, int y, int graphic, int frame,
1791 int width, height, bx, by, cx, cy;
1792 int sx = SCREENX(x), sy = SCREENY(y);
1793 int crumbled_border_size = graphic_info[graphic].border_size;
1794 int crumbled_border_size_var = crumbled_border_size * TILESIZE_VAR / TILESIZE;
1795 int crumbled_border_pos_var = TILESIZE_VAR - crumbled_border_size_var;
1798 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1800 /* draw simple, sloppy, non-corner-accurate crumbled border */
1802 width = (dir == 1 || dir == 2 ? crumbled_border_size_var : TILESIZE_VAR);
1803 height = (dir == 0 || dir == 3 ? crumbled_border_size_var : TILESIZE_VAR);
1804 cx = (dir == 2 ? crumbled_border_pos_var : 0);
1805 cy = (dir == 3 ? crumbled_border_pos_var : 0);
1807 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy, width, height,
1808 FX + sx * TILEX_VAR + cx,
1809 FY + sy * TILEY_VAR + cy);
1811 /* (remaining middle border part must be at least as big as corner part) */
1812 if (!(graphic_info[graphic].style & STYLE_ACCURATE_BORDERS) ||
1813 crumbled_border_size >= TILESIZE / 3)
1816 /* correct corners of crumbled border, if needed */
1818 for (i = -1; i <= 1; i += 2)
1820 int xx = x + (dir == 0 || dir == 3 ? i : 0);
1821 int yy = y + (dir == 1 || dir == 2 ? i : 0);
1822 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1825 /* check if neighbour field is of same crumble type */
1826 if (IS_CRUMBLED_TILE(xx, yy, element) &&
1827 graphic_info[graphic].class ==
1828 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1830 /* no crumbled corner, but continued crumbled border */
1832 int c1 = (dir == 2 || dir == 3 ? crumbled_border_pos_var : 0);
1833 int c2 = (i == 1 ? crumbled_border_pos_var : 0);
1834 int b1 = (i == 1 ? crumbled_border_size_var :
1835 TILESIZE_VAR - 2 * crumbled_border_size_var);
1837 width = crumbled_border_size_var;
1838 height = crumbled_border_size_var;
1840 if (dir == 1 || dir == 2)
1855 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
1857 FX + sx * TILEX_VAR + cx,
1858 FY + sy * TILEY_VAR + cy);
1863 static void DrawLevelFieldCrumbledExt(int x, int y, int graphic, int frame)
1865 int sx = SCREENX(x), sy = SCREENY(y);
1868 static int xy[4][2] =
1876 if (!IN_LEV_FIELD(x, y))
1879 element = TILE_GFX_ELEMENT(x, y);
1881 /* crumble field itself */
1882 if (IS_CRUMBLED_TILE(x, y, element))
1884 if (!IN_SCR_FIELD(sx, sy))
1887 for (i = 0; i < 4; i++)
1889 int xx = x + xy[i][0];
1890 int yy = y + xy[i][1];
1892 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1895 /* check if neighbour field is of same crumble type */
1896 if (IS_CRUMBLED_TILE(xx, yy, element) &&
1897 graphic_info[graphic].class ==
1898 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1901 DrawLevelFieldCrumbledBorders(x, y, graphic, frame, i);
1904 if ((graphic_info[graphic].style & STYLE_INNER_CORNERS) &&
1905 graphic_info[graphic].anim_frames == 2)
1907 for (i = 0; i < 4; i++)
1909 int dx = (i & 1 ? +1 : -1);
1910 int dy = (i & 2 ? +1 : -1);
1912 DrawLevelFieldCrumbledInnerCorners(x, y, dx, dy, graphic);
1916 MarkTileDirty(sx, sy);
1918 else /* center field not crumbled -- crumble neighbour fields */
1920 for (i = 0; i < 4; i++)
1922 int xx = x + xy[i][0];
1923 int yy = y + xy[i][1];
1924 int sxx = sx + xy[i][0];
1925 int syy = sy + xy[i][1];
1927 if (!IN_LEV_FIELD(xx, yy) ||
1928 !IN_SCR_FIELD(sxx, syy))
1931 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
1934 element = TILE_GFX_ELEMENT(xx, yy);
1936 if (!IS_CRUMBLED_TILE(xx, yy, element))
1939 graphic = el_act2crm(element, ACTION_DEFAULT);
1941 DrawLevelFieldCrumbledBorders(xx, yy, graphic, 0, 3 - i);
1943 MarkTileDirty(sxx, syy);
1948 void DrawLevelFieldCrumbled(int x, int y)
1952 if (!IN_LEV_FIELD(x, y))
1955 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1956 GfxElement[x][y] != EL_UNDEFINED &&
1957 GFX_CRUMBLED(GfxElement[x][y]))
1959 DrawLevelFieldCrumbledDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
1964 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
1966 DrawLevelFieldCrumbledExt(x, y, graphic, 0);
1969 void DrawLevelFieldCrumbledDigging(int x, int y, int direction,
1972 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1973 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1974 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1975 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1976 int sx = SCREENX(x), sy = SCREENY(y);
1978 DrawGraphic(sx, sy, graphic1, frame1);
1979 DrawLevelFieldCrumbledExt(x, y, graphic2, frame2);
1982 void DrawLevelFieldCrumbledNeighbours(int x, int y)
1984 int sx = SCREENX(x), sy = SCREENY(y);
1985 static int xy[4][2] =
1994 for (i = 0; i < 4; i++)
1996 int xx = x + xy[i][0];
1997 int yy = y + xy[i][1];
1998 int sxx = sx + xy[i][0];
1999 int syy = sy + xy[i][1];
2001 if (!IN_LEV_FIELD(xx, yy) ||
2002 !IN_SCR_FIELD(sxx, syy) ||
2003 !GFX_CRUMBLED(Feld[xx][yy]) ||
2007 DrawLevelField(xx, yy);
2011 static int getBorderElement(int x, int y)
2015 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
2016 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
2017 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
2018 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
2019 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
2020 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
2021 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
2023 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
2024 int steel_position = (x == -1 && y == -1 ? 0 :
2025 x == lev_fieldx && y == -1 ? 1 :
2026 x == -1 && y == lev_fieldy ? 2 :
2027 x == lev_fieldx && y == lev_fieldy ? 3 :
2028 x == -1 || x == lev_fieldx ? 4 :
2029 y == -1 || y == lev_fieldy ? 5 : 6);
2031 return border[steel_position][steel_type];
2034 void DrawScreenElement(int x, int y, int element)
2036 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
2037 DrawLevelFieldCrumbled(LEVELX(x), LEVELY(y));
2040 void DrawLevelElement(int x, int y, int element)
2042 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2043 DrawScreenElement(SCREENX(x), SCREENY(y), element);
2046 void DrawScreenField(int x, int y)
2048 int lx = LEVELX(x), ly = LEVELY(y);
2049 int element, content;
2051 if (!IN_LEV_FIELD(lx, ly))
2053 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
2056 element = getBorderElement(lx, ly);
2058 DrawScreenElement(x, y, element);
2063 element = Feld[lx][ly];
2064 content = Store[lx][ly];
2066 if (IS_MOVING(lx, ly))
2068 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
2069 boolean cut_mode = NO_CUTTING;
2071 if (element == EL_QUICKSAND_EMPTYING ||
2072 element == EL_QUICKSAND_FAST_EMPTYING ||
2073 element == EL_MAGIC_WALL_EMPTYING ||
2074 element == EL_BD_MAGIC_WALL_EMPTYING ||
2075 element == EL_DC_MAGIC_WALL_EMPTYING ||
2076 element == EL_AMOEBA_DROPPING)
2077 cut_mode = CUT_ABOVE;
2078 else if (element == EL_QUICKSAND_FILLING ||
2079 element == EL_QUICKSAND_FAST_FILLING ||
2080 element == EL_MAGIC_WALL_FILLING ||
2081 element == EL_BD_MAGIC_WALL_FILLING ||
2082 element == EL_DC_MAGIC_WALL_FILLING)
2083 cut_mode = CUT_BELOW;
2085 if (cut_mode == CUT_ABOVE)
2086 DrawScreenElement(x, y, element);
2088 DrawScreenElement(x, y, EL_EMPTY);
2091 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
2092 else if (cut_mode == NO_CUTTING)
2093 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
2096 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
2098 if (cut_mode == CUT_BELOW &&
2099 IN_LEV_FIELD(lx, ly + 1) && IN_SCR_FIELD(x, y + 1))
2100 DrawLevelElement(lx, ly + 1, element);
2103 if (content == EL_ACID)
2105 int dir = MovDir[lx][ly];
2106 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
2107 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
2109 DrawLevelElementThruMask(newlx, newly, EL_ACID);
2112 else if (IS_BLOCKED(lx, ly))
2117 boolean cut_mode = NO_CUTTING;
2118 int element_old, content_old;
2120 Blocked2Moving(lx, ly, &oldx, &oldy);
2123 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
2124 MovDir[oldx][oldy] == MV_RIGHT);
2126 element_old = Feld[oldx][oldy];
2127 content_old = Store[oldx][oldy];
2129 if (element_old == EL_QUICKSAND_EMPTYING ||
2130 element_old == EL_QUICKSAND_FAST_EMPTYING ||
2131 element_old == EL_MAGIC_WALL_EMPTYING ||
2132 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
2133 element_old == EL_DC_MAGIC_WALL_EMPTYING ||
2134 element_old == EL_AMOEBA_DROPPING)
2135 cut_mode = CUT_ABOVE;
2137 DrawScreenElement(x, y, EL_EMPTY);
2140 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
2142 else if (cut_mode == NO_CUTTING)
2143 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
2146 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
2149 else if (IS_DRAWABLE(element))
2150 DrawScreenElement(x, y, element);
2152 DrawScreenElement(x, y, EL_EMPTY);
2155 void DrawLevelField(int x, int y)
2157 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2158 DrawScreenField(SCREENX(x), SCREENY(y));
2159 else if (IS_MOVING(x, y))
2163 Moving2Blocked(x, y, &newx, &newy);
2164 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
2165 DrawScreenField(SCREENX(newx), SCREENY(newy));
2167 else if (IS_BLOCKED(x, y))
2171 Blocked2Moving(x, y, &oldx, &oldy);
2172 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
2173 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
2177 void DrawSizedElement(int x, int y, int element, int tilesize)
2181 graphic = el2edimg(element);
2182 DrawSizedGraphic(x, y, graphic, 0, tilesize);
2185 void DrawMiniElement(int x, int y, int element)
2189 graphic = el2edimg(element);
2190 DrawMiniGraphic(x, y, graphic);
2193 void DrawSizedElementOrWall(int sx, int sy, int scroll_x, int scroll_y,
2196 int x = sx + scroll_x, y = sy + scroll_y;
2198 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
2199 DrawSizedElement(sx, sy, EL_EMPTY, tilesize);
2200 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
2201 DrawSizedElement(sx, sy, Feld[x][y], tilesize);
2203 DrawSizedGraphic(sx, sy, el2edimg(getBorderElement(x, y)), 0, tilesize);
2206 void DrawMiniElementOrWall(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 DrawMiniElement(sx, sy, EL_EMPTY);
2212 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
2213 DrawMiniElement(sx, sy, Feld[x][y]);
2215 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
2218 void DrawEnvelopeBackgroundTiles(int graphic, int startx, int starty,
2219 int x, int y, int xsize, int ysize,
2220 int tile_width, int tile_height)
2224 int dst_x = startx + x * tile_width;
2225 int dst_y = starty + y * tile_height;
2226 int width = graphic_info[graphic].width;
2227 int height = graphic_info[graphic].height;
2228 int inner_width_raw = MAX(width - 2 * tile_width, tile_width);
2229 int inner_height_raw = MAX(height - 2 * tile_height, tile_height);
2230 int inner_width = inner_width_raw - (inner_width_raw % tile_width);
2231 int inner_height = inner_height_raw - (inner_height_raw % tile_height);
2232 int inner_sx = (width >= 3 * tile_width ? tile_width : 0);
2233 int inner_sy = (height >= 3 * tile_height ? tile_height : 0);
2234 boolean draw_masked = graphic_info[graphic].draw_masked;
2236 getFixedGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
2238 if (src_bitmap == NULL || width < tile_width || height < tile_height)
2240 ClearRectangle(drawto, dst_x, dst_y, tile_width, tile_height);
2244 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - tile_width :
2245 inner_sx + (x - 1) * tile_width % inner_width);
2246 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - tile_height :
2247 inner_sy + (y - 1) * tile_height % inner_height);
2250 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
2253 BlitBitmap(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
2257 void DrawEnvelopeBackground(int graphic, int startx, int starty,
2258 int x, int y, int xsize, int ysize, int font_nr)
2260 int font_width = getFontWidth(font_nr);
2261 int font_height = getFontHeight(font_nr);
2263 DrawEnvelopeBackgroundTiles(graphic, startx, starty, x, y, xsize, ysize,
2264 font_width, font_height);
2267 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
2269 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2270 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2271 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2272 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2273 boolean no_delay = (tape.warp_forward);
2274 unsigned int anim_delay = 0;
2275 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
2276 int anim_delay_value = (no_delay ? 0 : frame_delay_value) / 2;
2277 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
2278 int font_width = getFontWidth(font_nr);
2279 int font_height = getFontHeight(font_nr);
2280 int max_xsize = level.envelope[envelope_nr].xsize;
2281 int max_ysize = level.envelope[envelope_nr].ysize;
2282 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
2283 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
2284 int xend = max_xsize;
2285 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
2286 int xstep = (xstart < xend ? 1 : 0);
2287 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2289 int end = MAX(xend - xstart, yend - ystart);
2292 for (i = start; i <= end; i++)
2294 int last_frame = end; // last frame of this "for" loop
2295 int x = xstart + i * xstep;
2296 int y = ystart + i * ystep;
2297 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2298 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2299 int sx = SX + (SXSIZE - xsize * font_width) / 2;
2300 int sy = SY + (SYSIZE - ysize * font_height) / 2;
2303 SetDrawtoField(DRAW_FIELDBUFFER);
2305 BlitScreenToBitmap(backbuffer);
2307 SetDrawtoField(DRAW_BACKBUFFER);
2309 for (yy = 0; yy < ysize; yy++)
2310 for (xx = 0; xx < xsize; xx++)
2311 DrawEnvelopeBackground(graphic, sx, sy, xx, yy, xsize, ysize, font_nr);
2313 DrawTextBuffer(sx + font_width, sy + font_height,
2314 level.envelope[envelope_nr].text, font_nr, max_xsize,
2315 xsize - 2, ysize - 2, 0, mask_mode,
2316 level.envelope[envelope_nr].autowrap,
2317 level.envelope[envelope_nr].centered, FALSE);
2319 redraw_mask |= REDRAW_FIELD;
2322 SkipUntilDelayReached(&anim_delay, anim_delay_value, &i, last_frame);
2326 void ShowEnvelope(int envelope_nr)
2328 int element = EL_ENVELOPE_1 + envelope_nr;
2329 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2330 int sound_opening = element_info[element].sound[ACTION_OPENING];
2331 int sound_closing = element_info[element].sound[ACTION_CLOSING];
2332 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2333 boolean no_delay = (tape.warp_forward);
2334 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
2335 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
2336 int anim_mode = graphic_info[graphic].anim_mode;
2337 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2338 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2340 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
2342 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2344 if (anim_mode == ANIM_DEFAULT)
2345 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
2347 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
2350 Delay(wait_delay_value);
2352 WaitForEventToContinue();
2354 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2356 if (anim_mode != ANIM_NONE)
2357 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
2359 if (anim_mode == ANIM_DEFAULT)
2360 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
2362 game.envelope_active = FALSE;
2364 SetDrawtoField(DRAW_FIELDBUFFER);
2366 redraw_mask |= REDRAW_FIELD;
2370 static void setRequestBasePosition(int *x, int *y)
2372 int sx_base, sy_base;
2374 if (request.x != -1)
2375 sx_base = request.x;
2376 else if (request.align == ALIGN_LEFT)
2378 else if (request.align == ALIGN_RIGHT)
2379 sx_base = SX + SXSIZE;
2381 sx_base = SX + SXSIZE / 2;
2383 if (request.y != -1)
2384 sy_base = request.y;
2385 else if (request.valign == VALIGN_TOP)
2387 else if (request.valign == VALIGN_BOTTOM)
2388 sy_base = SY + SYSIZE;
2390 sy_base = SY + SYSIZE / 2;
2396 static void setRequestPositionExt(int *x, int *y, int width, int height,
2397 boolean add_border_size)
2399 int border_size = request.border_size;
2400 int sx_base, sy_base;
2403 setRequestBasePosition(&sx_base, &sy_base);
2405 if (request.align == ALIGN_LEFT)
2407 else if (request.align == ALIGN_RIGHT)
2408 sx = sx_base - width;
2410 sx = sx_base - width / 2;
2412 if (request.valign == VALIGN_TOP)
2414 else if (request.valign == VALIGN_BOTTOM)
2415 sy = sy_base - height;
2417 sy = sy_base - height / 2;
2419 sx = MAX(0, MIN(sx, WIN_XSIZE - width));
2420 sy = MAX(0, MIN(sy, WIN_YSIZE - height));
2422 if (add_border_size)
2432 static void setRequestPosition(int *x, int *y, boolean add_border_size)
2434 setRequestPositionExt(x, y, request.width, request.height, add_border_size);
2437 void DrawEnvelopeRequest(char *text)
2439 char *text_final = text;
2440 char *text_door_style = NULL;
2441 int graphic = IMG_BACKGROUND_REQUEST;
2442 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2443 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2444 int font_nr = FONT_REQUEST;
2445 int font_width = getFontWidth(font_nr);
2446 int font_height = getFontHeight(font_nr);
2447 int border_size = request.border_size;
2448 int line_spacing = request.line_spacing;
2449 int line_height = font_height + line_spacing;
2450 int max_text_width = request.width - 2 * border_size;
2451 int max_text_height = request.height - 2 * border_size;
2452 int line_length = max_text_width / font_width;
2453 int max_lines = max_text_height / line_height;
2454 int text_width = line_length * font_width;
2455 int width = request.width;
2456 int height = request.height;
2457 int tile_size = MAX(request.step_offset, 1);
2458 int x_steps = width / tile_size;
2459 int y_steps = height / tile_size;
2460 int sx_offset = border_size;
2461 int sy_offset = border_size;
2465 if (request.centered)
2466 sx_offset = (request.width - text_width) / 2;
2468 if (request.wrap_single_words && !request.autowrap)
2470 char *src_text_ptr, *dst_text_ptr;
2472 text_door_style = checked_malloc(2 * strlen(text) + 1);
2474 src_text_ptr = text;
2475 dst_text_ptr = text_door_style;
2477 while (*src_text_ptr)
2479 if (*src_text_ptr == ' ' ||
2480 *src_text_ptr == '?' ||
2481 *src_text_ptr == '!')
2482 *dst_text_ptr++ = '\n';
2484 if (*src_text_ptr != ' ')
2485 *dst_text_ptr++ = *src_text_ptr;
2490 *dst_text_ptr = '\0';
2492 text_final = text_door_style;
2495 setRequestPosition(&sx, &sy, FALSE);
2497 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
2499 for (y = 0; y < y_steps; y++)
2500 for (x = 0; x < x_steps; x++)
2501 DrawEnvelopeBackgroundTiles(graphic, sx, sy,
2502 x, y, x_steps, y_steps,
2503 tile_size, tile_size);
2505 /* force DOOR font inside door area */
2506 SetFontStatus(GAME_MODE_PSEUDO_DOOR);
2508 DrawTextBuffer(sx + sx_offset, sy + sy_offset, text_final, font_nr,
2509 line_length, -1, max_lines, line_spacing, mask_mode,
2510 request.autowrap, request.centered, FALSE);
2514 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2515 RedrawGadget(tool_gadget[i]);
2517 // store readily prepared envelope request for later use when animating
2518 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2520 if (text_door_style)
2521 free(text_door_style);
2524 void AnimateEnvelopeRequest(int anim_mode, int action)
2526 int graphic = IMG_BACKGROUND_REQUEST;
2527 boolean draw_masked = graphic_info[graphic].draw_masked;
2528 int delay_value_normal = request.step_delay;
2529 int delay_value_fast = delay_value_normal / 2;
2530 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2531 boolean no_delay = (tape.warp_forward);
2532 int delay_value = (ffwd_delay ? delay_value_fast : delay_value_normal);
2533 int anim_delay_value = (no_delay ? 0 : delay_value + 500 * 0) / 2;
2534 unsigned int anim_delay = 0;
2536 int tile_size = MAX(request.step_offset, 1);
2537 int max_xsize = request.width / tile_size;
2538 int max_ysize = request.height / tile_size;
2539 int max_xsize_inner = max_xsize - 2;
2540 int max_ysize_inner = max_ysize - 2;
2542 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize_inner : 0);
2543 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize_inner : 0);
2544 int xend = max_xsize_inner;
2545 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize_inner : 0);
2546 int xstep = (xstart < xend ? 1 : 0);
2547 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2549 int end = MAX(xend - xstart, yend - ystart);
2552 if (setup.quick_doors)
2559 for (i = start; i <= end; i++)
2561 int last_frame = end; // last frame of this "for" loop
2562 int x = xstart + i * xstep;
2563 int y = ystart + i * ystep;
2564 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2565 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2566 int xsize_size_left = (xsize - 1) * tile_size;
2567 int ysize_size_top = (ysize - 1) * tile_size;
2568 int max_xsize_pos = (max_xsize - 1) * tile_size;
2569 int max_ysize_pos = (max_ysize - 1) * tile_size;
2570 int width = xsize * tile_size;
2571 int height = ysize * tile_size;
2576 setRequestPosition(&src_x, &src_y, FALSE);
2577 setRequestPositionExt(&dst_x, &dst_y, width, height, FALSE);
2579 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2581 for (yy = 0; yy < 2; yy++)
2583 for (xx = 0; xx < 2; xx++)
2585 int src_xx = src_x + xx * max_xsize_pos;
2586 int src_yy = src_y + yy * max_ysize_pos;
2587 int dst_xx = dst_x + xx * xsize_size_left;
2588 int dst_yy = dst_y + yy * ysize_size_top;
2589 int xx_size = (xx ? tile_size : xsize_size_left);
2590 int yy_size = (yy ? tile_size : ysize_size_top);
2593 BlitBitmapMasked(bitmap_db_cross, backbuffer,
2594 src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
2596 BlitBitmap(bitmap_db_cross, backbuffer,
2597 src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
2601 redraw_mask |= REDRAW_FIELD;
2606 SkipUntilDelayReached(&anim_delay, anim_delay_value, &i, last_frame);
2610 void ShowEnvelopeRequest(char *text, unsigned int req_state, int action)
2612 int graphic = IMG_BACKGROUND_REQUEST;
2613 int sound_opening = SND_REQUEST_OPENING;
2614 int sound_closing = SND_REQUEST_CLOSING;
2615 int anim_mode_1 = request.anim_mode; /* (higher priority) */
2616 int anim_mode_2 = graphic_info[graphic].anim_mode; /* (lower priority) */
2617 int anim_mode = (anim_mode_1 != ANIM_DEFAULT ? anim_mode_1 : anim_mode_2);
2618 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2619 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2621 if (game_status == GAME_MODE_PLAYING)
2622 BlitScreenToBitmap(backbuffer);
2624 SetDrawtoField(DRAW_BACKBUFFER);
2626 // SetDrawBackgroundMask(REDRAW_NONE);
2628 if (action == ACTION_OPENING)
2630 BlitBitmap(backbuffer, bitmap_db_store, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2632 if (req_state & REQ_ASK)
2634 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2635 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2637 else if (req_state & REQ_CONFIRM)
2639 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2641 else if (req_state & REQ_PLAYER)
2643 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2644 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2645 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2646 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2649 DrawEnvelopeRequest(text);
2651 if (game_status != GAME_MODE_MAIN)
2655 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
2657 if (action == ACTION_OPENING)
2659 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2661 if (anim_mode == ANIM_DEFAULT)
2662 AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_OPENING);
2664 AnimateEnvelopeRequest(main_anim_mode, ACTION_OPENING);
2668 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2670 if (anim_mode != ANIM_NONE)
2671 AnimateEnvelopeRequest(main_anim_mode, ACTION_CLOSING);
2673 if (anim_mode == ANIM_DEFAULT)
2674 AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_CLOSING);
2677 game.envelope_active = FALSE;
2679 if (action == ACTION_CLOSING)
2681 if (game_status != GAME_MODE_MAIN)
2684 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2687 // SetDrawBackgroundMask(last_draw_background_mask);
2689 redraw_mask |= REDRAW_FIELD;
2691 if (game_status == GAME_MODE_MAIN)
2696 if (action == ACTION_CLOSING &&
2697 game_status == GAME_MODE_PLAYING &&
2698 level.game_engine_type == GAME_ENGINE_TYPE_RND)
2699 SetDrawtoField(DRAW_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)
3562 #define MAX_REQUEST_LINES 13
3563 #define MAX_REQUEST_LINE_FONT1_LEN 7
3564 #define MAX_REQUEST_LINE_FONT2_LEN 10
3566 static int RequestHandleEvents(unsigned int req_state)
3568 boolean level_solved = (game_status == GAME_MODE_PLAYING &&
3569 local_player->LevelSolved_GameEnd);
3570 int width = request.width;
3571 int height = request.height;
3575 setRequestPosition(&sx, &sy, FALSE);
3577 button_status = MB_RELEASED;
3579 request_gadget_id = -1;
3586 SetDrawtoField(DRAW_FIELDBUFFER);
3588 HandleGameActions();
3590 SetDrawtoField(DRAW_BACKBUFFER);
3592 if (global.use_envelope_request)
3594 /* copy current state of request area to middle of playfield area */
3595 BlitBitmap(bitmap_db_cross, drawto, sx, sy, width, height, sx, sy);
3603 while (NextValidEvent(&event))
3607 case EVENT_BUTTONPRESS:
3608 case EVENT_BUTTONRELEASE:
3609 case EVENT_MOTIONNOTIFY:
3613 if (event.type == EVENT_MOTIONNOTIFY)
3618 motion_status = TRUE;
3619 mx = ((MotionEvent *) &event)->x;
3620 my = ((MotionEvent *) &event)->y;
3624 motion_status = FALSE;
3625 mx = ((ButtonEvent *) &event)->x;
3626 my = ((ButtonEvent *) &event)->y;
3627 if (event.type == EVENT_BUTTONPRESS)
3628 button_status = ((ButtonEvent *) &event)->button;
3630 button_status = MB_RELEASED;
3633 /* this sets 'request_gadget_id' */
3634 HandleGadgets(mx, my, button_status);
3636 switch (request_gadget_id)
3638 case TOOL_CTRL_ID_YES:
3641 case TOOL_CTRL_ID_NO:
3644 case TOOL_CTRL_ID_CONFIRM:
3645 result = TRUE | FALSE;
3648 case TOOL_CTRL_ID_PLAYER_1:
3651 case TOOL_CTRL_ID_PLAYER_2:
3654 case TOOL_CTRL_ID_PLAYER_3:
3657 case TOOL_CTRL_ID_PLAYER_4:
3668 case EVENT_KEYPRESS:
3669 switch (GetEventKey((KeyEvent *)&event, TRUE))
3672 if (req_state & REQ_CONFIRM)
3677 #if defined(TARGET_SDL2)
3684 #if defined(TARGET_SDL2)
3694 if (req_state & REQ_PLAYER)
3698 case EVENT_KEYRELEASE:
3699 ClearPlayerAction();
3703 HandleOtherEvents(&event);
3708 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3710 int joy = AnyJoystick();
3712 if (joy & JOY_BUTTON_1)
3714 else if (joy & JOY_BUTTON_2)
3720 if (global.use_envelope_request)
3722 /* copy back current state of pressed buttons inside request area */
3723 BlitBitmap(drawto, bitmap_db_cross, sx, sy, width, height, sx, sy);
3737 static boolean RequestDoor(char *text, unsigned int req_state)
3739 unsigned int old_door_state;
3740 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
3741 int font_nr = FONT_TEXT_2;
3746 if (maxWordLengthInString(text) > MAX_REQUEST_LINE_FONT1_LEN)
3748 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
3749 font_nr = FONT_TEXT_1;
3752 if (game_status == GAME_MODE_PLAYING)
3753 BlitScreenToBitmap(backbuffer);
3755 /* disable deactivated drawing when quick-loading level tape recording */
3756 if (tape.playing && tape.deactivate_display)
3757 TapeDeactivateDisplayOff(TRUE);
3759 SetMouseCursor(CURSOR_DEFAULT);
3761 #if defined(NETWORK_AVALIABLE)
3762 /* pause network game while waiting for request to answer */
3763 if (options.network &&
3764 game_status == GAME_MODE_PLAYING &&
3765 req_state & REQUEST_WAIT_FOR_INPUT)
3766 SendToServer_PausePlaying();
3769 old_door_state = GetDoorState();
3771 /* simulate releasing mouse button over last gadget, if still pressed */
3773 HandleGadgets(-1, -1, 0);
3777 /* draw released gadget before proceeding */
3780 if (old_door_state & DOOR_OPEN_1)
3782 CloseDoor(DOOR_CLOSE_1);
3784 /* save old door content */
3785 BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
3786 0 * DXSIZE, 0, DXSIZE, DYSIZE, 1 * DXSIZE, 0);
3789 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
3790 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3792 /* clear door drawing field */
3793 DrawBackground(DX, DY, DXSIZE, DYSIZE);
3795 /* force DOOR font inside door area */
3796 SetFontStatus(GAME_MODE_PSEUDO_DOOR);
3798 /* write text for request */
3799 for (text_ptr = text, ty = 0; ty < MAX_REQUEST_LINES; ty++)
3801 char text_line[max_request_line_len + 1];
3807 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
3809 tc = *(text_ptr + tx);
3810 // if (!tc || tc == ' ')
3811 if (!tc || tc == ' ' || tc == '?' || tc == '!')
3815 if ((tc == '?' || tc == '!') && tl == 0)
3825 strncpy(text_line, text_ptr, tl);
3828 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
3829 DY + 8 + ty * (getFontHeight(font_nr) + 2),
3830 text_line, font_nr);
3832 text_ptr += tl + (tc == ' ' ? 1 : 0);
3833 // text_ptr += tl + (tc == ' ' || tc == '?' || tc == '!' ? 1 : 0);
3838 if (req_state & REQ_ASK)
3840 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
3841 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
3843 else if (req_state & REQ_CONFIRM)
3845 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
3847 else if (req_state & REQ_PLAYER)
3849 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
3850 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
3851 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
3852 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
3855 /* copy request gadgets to door backbuffer */
3856 BlitBitmap(drawto, bitmap_db_door_1, DX, DY, DXSIZE, DYSIZE, 0, 0);
3858 OpenDoor(DOOR_OPEN_1);
3860 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
3862 if (game_status == GAME_MODE_PLAYING)
3864 SetPanelBackground();
3865 SetDrawBackgroundMask(REDRAW_DOOR_1);
3869 SetDrawBackgroundMask(REDRAW_FIELD);
3875 if (game_status != GAME_MODE_MAIN)
3878 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3880 // ---------- handle request buttons ----------
3881 result = RequestHandleEvents(req_state);
3883 if (game_status != GAME_MODE_MAIN)
3888 if (!(req_state & REQ_STAY_OPEN))
3890 CloseDoor(DOOR_CLOSE_1);
3892 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
3893 (req_state & REQ_REOPEN))
3894 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
3899 if (game_status == GAME_MODE_PLAYING)
3901 SetPanelBackground();
3902 SetDrawBackgroundMask(REDRAW_DOOR_1);
3906 SetDrawBackgroundMask(REDRAW_FIELD);
3909 #if defined(NETWORK_AVALIABLE)
3910 /* continue network game after request */
3911 if (options.network &&
3912 game_status == GAME_MODE_PLAYING &&
3913 req_state & REQUEST_WAIT_FOR_INPUT)
3914 SendToServer_ContinuePlaying();
3917 /* restore deactivated drawing when quick-loading level tape recording */
3918 if (tape.playing && tape.deactivate_display)
3919 TapeDeactivateDisplayOn();
3924 static boolean RequestEnvelope(char *text, unsigned int req_state)
3928 if (game_status == GAME_MODE_PLAYING)
3929 BlitScreenToBitmap(backbuffer);
3931 /* disable deactivated drawing when quick-loading level tape recording */
3932 if (tape.playing && tape.deactivate_display)
3933 TapeDeactivateDisplayOff(TRUE);
3935 SetMouseCursor(CURSOR_DEFAULT);
3937 #if defined(NETWORK_AVALIABLE)
3938 /* pause network game while waiting for request to answer */
3939 if (options.network &&
3940 game_status == GAME_MODE_PLAYING &&
3941 req_state & REQUEST_WAIT_FOR_INPUT)
3942 SendToServer_PausePlaying();
3945 /* simulate releasing mouse button over last gadget, if still pressed */
3947 HandleGadgets(-1, -1, 0);
3951 // (replace with setting corresponding request background)
3952 // SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
3953 // SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3955 /* clear door drawing field */
3956 // DrawBackground(DX, DY, DXSIZE, DYSIZE);
3958 ShowEnvelopeRequest(text, req_state, ACTION_OPENING);
3960 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
3962 if (game_status == GAME_MODE_PLAYING)
3964 SetPanelBackground();
3965 SetDrawBackgroundMask(REDRAW_DOOR_1);
3969 SetDrawBackgroundMask(REDRAW_FIELD);
3975 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3977 // ---------- handle request buttons ----------
3978 result = RequestHandleEvents(req_state);
3980 if (game_status != GAME_MODE_MAIN)
3985 ShowEnvelopeRequest(text, req_state, ACTION_CLOSING);
3989 if (game_status == GAME_MODE_PLAYING)
3991 SetPanelBackground();
3992 SetDrawBackgroundMask(REDRAW_DOOR_1);
3996 SetDrawBackgroundMask(REDRAW_FIELD);
3999 #if defined(NETWORK_AVALIABLE)
4000 /* continue network game after request */
4001 if (options.network &&
4002 game_status == GAME_MODE_PLAYING &&
4003 req_state & REQUEST_WAIT_FOR_INPUT)
4004 SendToServer_ContinuePlaying();
4007 /* restore deactivated drawing when quick-loading level tape recording */
4008 if (tape.playing && tape.deactivate_display)
4009 TapeDeactivateDisplayOn();
4014 boolean Request(char *text, unsigned int req_state)
4016 if (global.use_envelope_request)
4017 return RequestEnvelope(text, req_state);
4019 return RequestDoor(text, req_state);
4022 static int compareDoorPartOrderInfo(const void *object1, const void *object2)
4024 const struct DoorPartOrderInfo *dpo1 = (struct DoorPartOrderInfo *)object1;
4025 const struct DoorPartOrderInfo *dpo2 = (struct DoorPartOrderInfo *)object2;
4028 if (dpo1->sort_priority != dpo2->sort_priority)
4029 compare_result = dpo1->sort_priority - dpo2->sort_priority;
4031 compare_result = dpo1->nr - dpo2->nr;
4033 return compare_result;
4036 void InitGraphicCompatibilityInfo_Doors()
4042 struct DoorInfo *door;
4046 { DOOR_1, IMG_GFX_DOOR_1_PART_1, IMG_GFX_DOOR_1_PART_8, &door_1 },
4047 { DOOR_2, IMG_GFX_DOOR_2_PART_1, IMG_GFX_DOOR_2_PART_8, &door_2 },
4049 { -1, -1, -1, NULL }
4051 struct Rect door_rect_list[] =
4053 { DX, DY, DXSIZE, DYSIZE },
4054 { VX, VY, VXSIZE, VYSIZE }
4058 for (i = 0; doors[i].door_token != -1; i++)
4060 int door_token = doors[i].door_token;
4061 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
4062 int part_1 = doors[i].part_1;
4063 int part_8 = doors[i].part_8;
4064 int part_2 = part_1 + 1;
4065 int part_3 = part_1 + 2;
4066 struct DoorInfo *door = doors[i].door;
4067 struct Rect *door_rect = &door_rect_list[door_index];
4068 boolean door_gfx_redefined = FALSE;
4070 /* check if any door part graphic definitions have been redefined */
4072 for (j = 0; door_part_controls[j].door_token != -1; j++)
4074 struct DoorPartControlInfo *dpc = &door_part_controls[j];
4075 struct FileInfo *fi = getImageListEntryFromImageID(dpc->graphic);
4077 if (dpc->door_token == door_token && fi->redefined)
4078 door_gfx_redefined = TRUE;
4081 /* check for old-style door graphic/animation modifications */
4083 if (!door_gfx_redefined)
4085 if (door->anim_mode & ANIM_STATIC_PANEL)
4087 door->panel.step_xoffset = 0;
4088 door->panel.step_yoffset = 0;
4091 if (door->anim_mode & (ANIM_HORIZONTAL | ANIM_VERTICAL))
4093 struct GraphicInfo *g_part_1 = &graphic_info[part_1];
4094 struct GraphicInfo *g_part_2 = &graphic_info[part_2];
4095 int num_door_steps, num_panel_steps;
4097 /* remove door part graphics other than the two default wings */
4099 for (j = 0; door_part_controls[j].door_token != -1; j++)
4101 struct DoorPartControlInfo *dpc = &door_part_controls[j];
4102 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4104 if (dpc->graphic >= part_3 &&
4105 dpc->graphic <= part_8)
4109 /* set graphics and screen positions of the default wings */
4111 g_part_1->width = door_rect->width;
4112 g_part_1->height = door_rect->height;
4113 g_part_2->width = door_rect->width;
4114 g_part_2->height = door_rect->height;
4115 g_part_2->src_x = door_rect->width;
4116 g_part_2->src_y = g_part_1->src_y;
4118 door->part_2.x = door->part_1.x;
4119 door->part_2.y = door->part_1.y;
4121 if (door->width != -1)
4123 g_part_1->width = door->width;
4124 g_part_2->width = door->width;
4126 // special treatment for graphics and screen position of right wing
4127 g_part_2->src_x += door_rect->width - door->width;
4128 door->part_2.x += door_rect->width - door->width;
4131 if (door->height != -1)
4133 g_part_1->height = door->height;
4134 g_part_2->height = door->height;
4136 // special treatment for graphics and screen position of bottom wing
4137 g_part_2->src_y += door_rect->height - door->height;
4138 door->part_2.y += door_rect->height - door->height;
4141 /* set animation delays for the default wings and panels */
4143 door->part_1.step_delay = door->step_delay;
4144 door->part_2.step_delay = door->step_delay;
4145 door->panel.step_delay = door->step_delay;
4147 /* set animation draw order for the default wings */
4149 door->part_1.sort_priority = 2; /* draw left wing over ... */
4150 door->part_2.sort_priority = 1; /* ... right wing */
4152 /* set animation draw offset for the default wings */
4154 if (door->anim_mode & ANIM_HORIZONTAL)
4156 door->part_1.step_xoffset = door->step_offset;
4157 door->part_1.step_yoffset = 0;
4158 door->part_2.step_xoffset = door->step_offset * -1;
4159 door->part_2.step_yoffset = 0;
4161 num_door_steps = g_part_1->width / door->step_offset;
4163 else // ANIM_VERTICAL
4165 door->part_1.step_xoffset = 0;
4166 door->part_1.step_yoffset = door->step_offset;
4167 door->part_2.step_xoffset = 0;
4168 door->part_2.step_yoffset = door->step_offset * -1;
4170 num_door_steps = g_part_1->height / door->step_offset;
4173 /* set animation draw offset for the default panels */
4175 if (door->step_offset > 1)
4177 num_panel_steps = 2 * door_rect->height / door->step_offset;
4178 door->panel.start_step = num_panel_steps - num_door_steps;
4179 door->panel.start_step_closing = door->panel.start_step;
4183 num_panel_steps = door_rect->height / door->step_offset;
4184 door->panel.start_step = num_panel_steps - num_door_steps / 2;
4185 door->panel.start_step_closing = door->panel.start_step;
4186 door->panel.step_delay *= 2;
4197 for (i = 0; door_part_controls[i].door_token != -1; i++)
4199 struct DoorPartControlInfo *dpc = &door_part_controls[i];
4200 struct DoorPartOrderInfo *dpo = &door_part_order[i];
4202 /* initialize "start_step_opening" and "start_step_closing", if needed */
4203 if (dpc->pos->start_step_opening == 0 &&
4204 dpc->pos->start_step_closing == 0)
4206 // dpc->pos->start_step_opening = dpc->pos->start_step;
4207 dpc->pos->start_step_closing = dpc->pos->start_step;
4210 /* fill structure for door part draw order (sorted below) */
4212 dpo->sort_priority = dpc->pos->sort_priority;
4215 /* sort door part controls according to sort_priority and graphic number */
4216 qsort(door_part_order, MAX_DOOR_PARTS,
4217 sizeof(struct DoorPartOrderInfo), compareDoorPartOrderInfo);
4220 unsigned int OpenDoor(unsigned int door_state)
4222 if (door_state & DOOR_COPY_BACK)
4224 if (door_state & DOOR_OPEN_1)
4225 BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
4226 1 * DXSIZE, 0, DXSIZE, DYSIZE, 0 * DXSIZE, 0);
4228 if (door_state & DOOR_OPEN_2)
4229 BlitBitmap(bitmap_db_door_2, bitmap_db_door_2,
4230 1 * VXSIZE, 0, VXSIZE, VYSIZE, 0 * VXSIZE, 0);
4232 door_state &= ~DOOR_COPY_BACK;
4235 return MoveDoor(door_state);
4238 unsigned int CloseDoor(unsigned int door_state)
4240 unsigned int old_door_state = GetDoorState();
4242 if (!(door_state & DOOR_NO_COPY_BACK))
4244 if (old_door_state & DOOR_OPEN_1)
4245 BlitBitmap(backbuffer, bitmap_db_door_1,
4246 DX, DY, DXSIZE, DYSIZE, 0, 0);
4248 if (old_door_state & DOOR_OPEN_2)
4249 BlitBitmap(backbuffer, bitmap_db_door_2,
4250 VX, VY, VXSIZE, VYSIZE, 0, 0);
4252 door_state &= ~DOOR_NO_COPY_BACK;
4255 return MoveDoor(door_state);
4258 unsigned int GetDoorState()
4260 return MoveDoor(DOOR_GET_STATE);
4263 unsigned int SetDoorState(unsigned int door_state)
4265 return MoveDoor(door_state | DOOR_SET_STATE);
4268 int euclid(int a, int b)
4270 return (b ? euclid(b, a % b) : a);
4273 unsigned int MoveDoor(unsigned int door_state)
4275 struct Rect door_rect_list[] =
4277 { DX, DY, DXSIZE, DYSIZE },
4278 { VX, VY, VXSIZE, VYSIZE }
4280 static int door1 = DOOR_CLOSE_1;
4281 static int door2 = DOOR_CLOSE_2;
4282 unsigned int door_delay = 0;
4283 unsigned int door_delay_value;
4286 if (door_state == DOOR_GET_STATE)
4287 return (door1 | door2);
4289 if (door_state & DOOR_SET_STATE)
4291 if (door_state & DOOR_ACTION_1)
4292 door1 = door_state & DOOR_ACTION_1;
4293 if (door_state & DOOR_ACTION_2)
4294 door2 = door_state & DOOR_ACTION_2;
4296 return (door1 | door2);
4299 if (!(door_state & DOOR_FORCE_REDRAW))
4301 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
4302 door_state &= ~DOOR_OPEN_1;
4303 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
4304 door_state &= ~DOOR_CLOSE_1;
4305 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
4306 door_state &= ~DOOR_OPEN_2;
4307 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
4308 door_state &= ~DOOR_CLOSE_2;
4311 if (global.autoplay_leveldir)
4313 door_state |= DOOR_NO_DELAY;
4314 door_state &= ~DOOR_CLOSE_ALL;
4317 if (game_status == GAME_MODE_EDITOR)
4318 door_state |= DOOR_NO_DELAY;
4320 if (door_state & DOOR_ACTION)
4322 boolean door_panel_drawn[NUM_DOORS];
4323 boolean panel_has_doors[NUM_DOORS];
4324 boolean door_part_skip[MAX_DOOR_PARTS];
4325 boolean door_part_done[MAX_DOOR_PARTS];
4326 boolean door_part_done_all;
4327 int num_steps[MAX_DOOR_PARTS];
4328 int max_move_delay = 0; // delay for complete animations of all doors
4329 int max_step_delay = 0; // delay (ms) between two animation frames
4330 int num_move_steps = 0; // number of animation steps for all doors
4331 int max_move_delay_doors_only = 0; // delay for doors only (no panel)
4332 int num_move_steps_doors_only = 0; // steps for doors only (no panel)
4333 int current_move_delay = 0;
4337 for (i = 0; i < NUM_DOORS; i++)
4338 panel_has_doors[i] = FALSE;
4340 for (i = 0; i < MAX_DOOR_PARTS; i++)
4342 struct DoorPartControlInfo *dpc = &door_part_controls[i];
4343 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4344 int door_token = dpc->door_token;
4346 door_part_done[i] = FALSE;
4347 door_part_skip[i] = (!(door_state & door_token) ||
4351 for (i = 0; i < MAX_DOOR_PARTS; i++)
4353 int nr = door_part_order[i].nr;
4354 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
4355 struct DoorPartPosInfo *pos = dpc->pos;
4356 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4357 int door_token = dpc->door_token;
4358 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
4359 boolean is_panel = DOOR_PART_IS_PANEL(nr);
4360 int step_xoffset = ABS(pos->step_xoffset);
4361 int step_yoffset = ABS(pos->step_yoffset);
4362 int step_delay = pos->step_delay;
4363 int current_door_state = door_state & door_token;
4364 boolean door_opening = ((current_door_state & DOOR_OPEN) != 0);
4365 boolean door_closing = ((current_door_state & DOOR_CLOSE) != 0);
4366 boolean part_opening = (is_panel ? door_closing : door_opening);
4367 int start_step = (part_opening ? pos->start_step_opening :
4368 pos->start_step_closing);
4369 float move_xsize = (step_xoffset ? g->width : 0);
4370 float move_ysize = (step_yoffset ? g->height : 0);
4371 int move_xsteps = (step_xoffset ? ceil(move_xsize / step_xoffset) : 0);
4372 int move_ysteps = (step_yoffset ? ceil(move_ysize / step_yoffset) : 0);
4373 int move_steps = (move_xsteps && move_ysteps ?
4374 MIN(move_xsteps, move_ysteps) :
4375 move_xsteps ? move_xsteps : move_ysteps) - start_step;
4376 int move_delay = move_steps * step_delay;
4378 if (door_part_skip[nr])
4381 max_move_delay = MAX(max_move_delay, move_delay);
4382 max_step_delay = (max_step_delay == 0 ? step_delay :
4383 euclid(max_step_delay, step_delay));
4384 num_steps[nr] = move_steps;
4388 max_move_delay_doors_only = MAX(max_move_delay_doors_only, move_delay);
4390 panel_has_doors[door_index] = TRUE;
4394 max_step_delay = MAX(1, max_step_delay); // prevent division by zero
4396 num_move_steps = max_move_delay / max_step_delay;
4397 num_move_steps_doors_only = max_move_delay_doors_only / max_step_delay;
4399 door_delay_value = max_step_delay;
4401 if ((door_state & DOOR_NO_DELAY) || setup.quick_doors)
4403 start = num_move_steps - 1;
4407 /* opening door sound has priority over simultaneously closing door */
4408 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
4409 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
4410 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
4411 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
4414 for (k = start; k < num_move_steps; k++)
4416 int last_frame = num_move_steps - 1; // last frame of this "for" loop
4418 door_part_done_all = TRUE;
4420 for (i = 0; i < NUM_DOORS; i++)
4421 door_panel_drawn[i] = FALSE;
4423 for (i = 0; i < MAX_DOOR_PARTS; i++)
4425 int nr = door_part_order[i].nr;
4426 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
4427 struct DoorPartPosInfo *pos = dpc->pos;
4428 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4429 int door_token = dpc->door_token;
4430 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
4431 boolean is_panel = DOOR_PART_IS_PANEL(nr);
4432 boolean is_panel_and_door_has_closed = FALSE;
4433 struct Rect *door_rect = &door_rect_list[door_index];
4434 Bitmap *bitmap_db_door = (door_token == DOOR_1 ? bitmap_db_door_1 :
4436 Bitmap *bitmap = (is_panel ? bitmap_db_door : g->bitmap);
4437 int current_door_state = door_state & door_token;
4438 boolean door_opening = ((current_door_state & DOOR_OPEN) != 0);
4439 boolean door_closing = !door_opening;
4440 boolean part_opening = (is_panel ? door_closing : door_opening);
4441 boolean part_closing = !part_opening;
4442 int start_step = (part_opening ? pos->start_step_opening :
4443 pos->start_step_closing);
4444 int step_delay = pos->step_delay;
4445 int step_factor = step_delay / max_step_delay;
4446 int k1 = (step_factor ? k / step_factor + 1 : k);
4447 int k2 = (part_opening ? k1 + start_step : num_steps[nr] - k1);
4448 int kk = MAX(0, k2);
4451 int src_x, src_y, src_xx, src_yy;
4452 int dst_x, dst_y, dst_xx, dst_yy;
4455 if (door_part_skip[nr])
4458 if (!(door_state & door_token))
4466 int k2_door = (door_opening ? k : num_move_steps_doors_only - k - 1);
4467 int kk_door = MAX(0, k2_door);
4468 int sync_frame = kk_door * door_delay_value;
4469 int frame = getGraphicAnimationFrame(dpc->graphic, sync_frame);
4471 getGraphicSource(dpc->graphic, frame, &bitmap, &g_src_x, &g_src_y);
4476 if (!door_panel_drawn[door_index])
4478 ClearRectangle(drawto, door_rect->x, door_rect->y,
4479 door_rect->width, door_rect->height);
4481 door_panel_drawn[door_index] = TRUE;
4484 // draw opening or closing door parts
4486 if (pos->step_xoffset < 0) // door part on right side
4489 dst_xx = pos->x + ABS(kk * pos->step_xoffset);
4492 if (dst_xx + width > door_rect->width)
4493 width = door_rect->width - dst_xx;
4495 else // door part on left side
4498 dst_xx = pos->x - kk * pos->step_xoffset;
4502 src_xx = ABS(dst_xx);
4506 width = g->width - src_xx;
4508 if (width > door_rect->width)
4509 width = door_rect->width;
4511 // printf("::: k == %d [%d] \n", k, start_step);
4514 if (pos->step_yoffset < 0) // door part on bottom side
4517 dst_yy = pos->y + ABS(kk * pos->step_yoffset);
4520 if (dst_yy + height > door_rect->height)
4521 height = door_rect->height - dst_yy;
4523 else // door part on top side
4526 dst_yy = pos->y - kk * pos->step_yoffset;
4530 src_yy = ABS(dst_yy);
4534 height = g->height - src_yy;
4537 src_x = g_src_x + src_xx;
4538 src_y = g_src_y + src_yy;
4540 dst_x = door_rect->x + dst_xx;
4541 dst_y = door_rect->y + dst_yy;
4543 is_panel_and_door_has_closed =
4546 panel_has_doors[door_index] &&
4547 k >= num_move_steps_doors_only - 1);
4549 if (width >= 0 && width <= g->width &&
4550 height >= 0 && height <= g->height &&
4551 !is_panel_and_door_has_closed)
4553 if (is_panel || !pos->draw_masked)
4554 BlitBitmap(bitmap, drawto, src_x, src_y, width, height,
4557 BlitBitmapMasked(bitmap, drawto, src_x, src_y, width, height,
4561 redraw_mask |= REDRAW_DOOR_FROM_TOKEN(door_token);
4563 if ((part_opening && (width < 0 || height < 0)) ||
4564 (part_closing && (width >= g->width && height >= g->height)))
4565 door_part_done[nr] = TRUE;
4567 // continue door part animations, but not panel after door has closed
4568 if (!door_part_done[nr] && !is_panel_and_door_has_closed)
4569 door_part_done_all = FALSE;
4572 if (!(door_state & DOOR_NO_DELAY))
4576 if (game_status == GAME_MODE_MAIN)
4579 SkipUntilDelayReached(&door_delay, door_delay_value, &k, last_frame);
4581 current_move_delay += max_step_delay;
4584 if (door_part_done_all)
4589 if (door_state & DOOR_ACTION_1)
4590 door1 = door_state & DOOR_ACTION_1;
4591 if (door_state & DOOR_ACTION_2)
4592 door2 = door_state & DOOR_ACTION_2;
4594 // draw masked border over door area
4595 DrawMaskedBorder(REDRAW_DOOR_1);
4596 DrawMaskedBorder(REDRAW_DOOR_2);
4598 return (door1 | door2);
4601 static boolean useSpecialEditorDoor()
4603 int graphic = IMG_GLOBAL_BORDER_EDITOR;
4604 boolean redefined = getImageListEntryFromImageID(graphic)->redefined;
4606 // do not draw special editor door if editor border defined or redefined
4607 if (graphic_info[graphic].bitmap != NULL || redefined)
4610 // do not draw special editor door if global border defined to be empty
4611 if (graphic_info[IMG_GLOBAL_BORDER].bitmap == NULL)
4614 // do not draw special editor door if viewport definitions do not match
4618 EY + EYSIZE != VY + VYSIZE)
4624 void DrawSpecialEditorDoor()
4626 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
4627 int top_border_width = gfx1->width;
4628 int top_border_height = gfx1->height;
4629 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
4630 int ex = EX - outer_border;
4631 int ey = EY - outer_border;
4632 int vy = VY - outer_border;
4633 int exsize = EXSIZE + 2 * outer_border;
4635 if (!useSpecialEditorDoor())
4638 /* draw bigger level editor toolbox window */
4639 BlitBitmap(gfx1->bitmap, drawto, gfx1->src_x, gfx1->src_y,
4640 top_border_width, top_border_height, ex, ey - top_border_height);
4641 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto, ex, vy,
4642 exsize, EYSIZE - VYSIZE + outer_border, ex, ey);
4644 redraw_mask |= REDRAW_ALL;
4647 void UndrawSpecialEditorDoor()
4649 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
4650 int top_border_width = gfx1->width;
4651 int top_border_height = gfx1->height;
4652 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
4653 int ex = EX - outer_border;
4654 int ey = EY - outer_border;
4655 int ey_top = ey - top_border_height;
4656 int exsize = EXSIZE + 2 * outer_border;
4657 int eysize = EYSIZE + 2 * outer_border;
4659 if (!useSpecialEditorDoor())
4662 /* draw normal tape recorder window */
4663 if (graphic_info[IMG_GLOBAL_BORDER].bitmap)
4665 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
4666 ex, ey_top, top_border_width, top_border_height,
4668 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
4669 ex, ey, exsize, eysize, ex, ey);
4673 // if screen background is set to "[NONE]", clear editor toolbox window
4674 ClearRectangle(drawto, ex, ey_top, top_border_width, top_border_height);
4675 ClearRectangle(drawto, ex, ey, exsize, eysize);
4678 redraw_mask |= REDRAW_ALL;
4682 /* ---------- new tool button stuff ---------------------------------------- */
4687 struct TextPosInfo *pos;
4690 } toolbutton_info[NUM_TOOL_BUTTONS] =
4693 IMG_GFX_REQUEST_BUTTON_YES, &request.button.yes,
4694 TOOL_CTRL_ID_YES, "yes"
4697 IMG_GFX_REQUEST_BUTTON_NO, &request.button.no,
4698 TOOL_CTRL_ID_NO, "no"
4701 IMG_GFX_REQUEST_BUTTON_CONFIRM, &request.button.confirm,
4702 TOOL_CTRL_ID_CONFIRM, "confirm"
4705 IMG_GFX_REQUEST_BUTTON_PLAYER_1, &request.button.player_1,
4706 TOOL_CTRL_ID_PLAYER_1, "player 1"
4709 IMG_GFX_REQUEST_BUTTON_PLAYER_2, &request.button.player_2,
4710 TOOL_CTRL_ID_PLAYER_2, "player 2"
4713 IMG_GFX_REQUEST_BUTTON_PLAYER_3, &request.button.player_3,
4714 TOOL_CTRL_ID_PLAYER_3, "player 3"
4717 IMG_GFX_REQUEST_BUTTON_PLAYER_4, &request.button.player_4,
4718 TOOL_CTRL_ID_PLAYER_4, "player 4"
4722 void CreateToolButtons()
4726 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4728 struct GraphicInfo *gfx = &graphic_info[toolbutton_info[i].graphic];
4729 struct TextPosInfo *pos = toolbutton_info[i].pos;
4730 struct GadgetInfo *gi;
4731 Bitmap *deco_bitmap = None;
4732 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
4733 unsigned int event_mask = GD_EVENT_RELEASED;
4736 int gd_x = gfx->src_x;
4737 int gd_y = gfx->src_y;
4738 int gd_xp = gfx->src_x + gfx->pressed_xoffset;
4739 int gd_yp = gfx->src_y + gfx->pressed_yoffset;
4742 if (global.use_envelope_request)
4743 setRequestPosition(&dx, &dy, TRUE);
4745 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
4747 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
4749 getSizedGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr), 0,
4750 pos->size, &deco_bitmap, &deco_x, &deco_y);
4751 deco_xpos = (gfx->width - pos->size) / 2;
4752 deco_ypos = (gfx->height - pos->size) / 2;
4755 gi = CreateGadget(GDI_CUSTOM_ID, id,
4756 GDI_INFO_TEXT, toolbutton_info[i].infotext,
4757 GDI_X, dx + GDI_ACTIVE_POS(pos->x),
4758 GDI_Y, dy + GDI_ACTIVE_POS(pos->y),
4759 GDI_WIDTH, gfx->width,
4760 GDI_HEIGHT, gfx->height,
4761 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
4762 GDI_STATE, GD_BUTTON_UNPRESSED,
4763 GDI_DESIGN_UNPRESSED, gfx->bitmap, gd_x, gd_y,
4764 GDI_DESIGN_PRESSED, gfx->bitmap, gd_xp, gd_yp,
4765 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
4766 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
4767 GDI_DECORATION_SIZE, pos->size, pos->size,
4768 GDI_DECORATION_SHIFTING, 1, 1,
4769 GDI_DIRECT_DRAW, FALSE,
4770 GDI_EVENT_MASK, event_mask,
4771 GDI_CALLBACK_ACTION, HandleToolButtons,
4775 Error(ERR_EXIT, "cannot create gadget");
4777 tool_gadget[id] = gi;
4781 void FreeToolButtons()
4785 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4786 FreeGadget(tool_gadget[i]);
4789 static void UnmapToolButtons()
4793 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4794 UnmapGadget(tool_gadget[i]);
4797 static void HandleToolButtons(struct GadgetInfo *gi)
4799 request_gadget_id = gi->custom_id;
4802 static struct Mapping_EM_to_RND_object
4805 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
4806 boolean is_backside; /* backside of moving element */
4812 em_object_mapping_list[] =
4815 Xblank, TRUE, FALSE,
4819 Yacid_splash_eB, FALSE, FALSE,
4820 EL_ACID_SPLASH_RIGHT, -1, -1
4823 Yacid_splash_wB, FALSE, FALSE,
4824 EL_ACID_SPLASH_LEFT, -1, -1
4827 #ifdef EM_ENGINE_BAD_ROLL
4829 Xstone_force_e, FALSE, FALSE,
4830 EL_ROCK, -1, MV_BIT_RIGHT
4833 Xstone_force_w, FALSE, FALSE,
4834 EL_ROCK, -1, MV_BIT_LEFT
4837 Xnut_force_e, FALSE, FALSE,
4838 EL_NUT, -1, MV_BIT_RIGHT
4841 Xnut_force_w, FALSE, FALSE,
4842 EL_NUT, -1, MV_BIT_LEFT
4845 Xspring_force_e, FALSE, FALSE,
4846 EL_SPRING, -1, MV_BIT_RIGHT
4849 Xspring_force_w, FALSE, FALSE,
4850 EL_SPRING, -1, MV_BIT_LEFT
4853 Xemerald_force_e, FALSE, FALSE,
4854 EL_EMERALD, -1, MV_BIT_RIGHT
4857 Xemerald_force_w, FALSE, FALSE,
4858 EL_EMERALD, -1, MV_BIT_LEFT
4861 Xdiamond_force_e, FALSE, FALSE,
4862 EL_DIAMOND, -1, MV_BIT_RIGHT
4865 Xdiamond_force_w, FALSE, FALSE,
4866 EL_DIAMOND, -1, MV_BIT_LEFT
4869 Xbomb_force_e, FALSE, FALSE,
4870 EL_BOMB, -1, MV_BIT_RIGHT
4873 Xbomb_force_w, FALSE, FALSE,
4874 EL_BOMB, -1, MV_BIT_LEFT
4876 #endif /* EM_ENGINE_BAD_ROLL */
4879 Xstone, TRUE, FALSE,
4883 Xstone_pause, FALSE, FALSE,
4887 Xstone_fall, FALSE, FALSE,
4891 Ystone_s, FALSE, FALSE,
4892 EL_ROCK, ACTION_FALLING, -1
4895 Ystone_sB, FALSE, TRUE,
4896 EL_ROCK, ACTION_FALLING, -1
4899 Ystone_e, FALSE, FALSE,
4900 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
4903 Ystone_eB, FALSE, TRUE,
4904 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
4907 Ystone_w, FALSE, FALSE,
4908 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
4911 Ystone_wB, FALSE, TRUE,
4912 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
4919 Xnut_pause, FALSE, FALSE,
4923 Xnut_fall, FALSE, FALSE,
4927 Ynut_s, FALSE, FALSE,
4928 EL_NUT, ACTION_FALLING, -1
4931 Ynut_sB, FALSE, TRUE,
4932 EL_NUT, ACTION_FALLING, -1
4935 Ynut_e, FALSE, FALSE,
4936 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
4939 Ynut_eB, FALSE, TRUE,
4940 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
4943 Ynut_w, FALSE, FALSE,
4944 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
4947 Ynut_wB, FALSE, TRUE,
4948 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
4951 Xbug_n, TRUE, FALSE,
4955 Xbug_e, TRUE, FALSE,
4956 EL_BUG_RIGHT, -1, -1
4959 Xbug_s, TRUE, FALSE,
4963 Xbug_w, TRUE, FALSE,
4967 Xbug_gon, FALSE, FALSE,
4971 Xbug_goe, FALSE, FALSE,
4972 EL_BUG_RIGHT, -1, -1
4975 Xbug_gos, FALSE, FALSE,
4979 Xbug_gow, FALSE, FALSE,
4983 Ybug_n, FALSE, FALSE,
4984 EL_BUG, ACTION_MOVING, MV_BIT_UP
4987 Ybug_nB, FALSE, TRUE,
4988 EL_BUG, ACTION_MOVING, MV_BIT_UP
4991 Ybug_e, FALSE, FALSE,
4992 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
4995 Ybug_eB, FALSE, TRUE,
4996 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
4999 Ybug_s, FALSE, FALSE,
5000 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
5003 Ybug_sB, FALSE, TRUE,
5004 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
5007 Ybug_w, FALSE, FALSE,
5008 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
5011 Ybug_wB, FALSE, TRUE,
5012 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
5015 Ybug_w_n, FALSE, FALSE,
5016 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
5019 Ybug_n_e, FALSE, FALSE,
5020 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
5023 Ybug_e_s, FALSE, FALSE,
5024 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
5027 Ybug_s_w, FALSE, FALSE,
5028 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
5031 Ybug_e_n, FALSE, FALSE,
5032 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
5035 Ybug_s_e, FALSE, FALSE,
5036 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
5039 Ybug_w_s, FALSE, FALSE,
5040 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
5043 Ybug_n_w, FALSE, FALSE,
5044 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
5047 Ybug_stone, FALSE, FALSE,
5048 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
5051 Ybug_spring, FALSE, FALSE,
5052 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
5055 Xtank_n, TRUE, FALSE,
5056 EL_SPACESHIP_UP, -1, -1
5059 Xtank_e, TRUE, FALSE,
5060 EL_SPACESHIP_RIGHT, -1, -1
5063 Xtank_s, TRUE, FALSE,
5064 EL_SPACESHIP_DOWN, -1, -1
5067 Xtank_w, TRUE, FALSE,
5068 EL_SPACESHIP_LEFT, -1, -1
5071 Xtank_gon, FALSE, FALSE,
5072 EL_SPACESHIP_UP, -1, -1
5075 Xtank_goe, FALSE, FALSE,
5076 EL_SPACESHIP_RIGHT, -1, -1
5079 Xtank_gos, FALSE, FALSE,
5080 EL_SPACESHIP_DOWN, -1, -1
5083 Xtank_gow, FALSE, FALSE,
5084 EL_SPACESHIP_LEFT, -1, -1
5087 Ytank_n, FALSE, FALSE,
5088 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
5091 Ytank_nB, FALSE, TRUE,
5092 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
5095 Ytank_e, FALSE, FALSE,
5096 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
5099 Ytank_eB, FALSE, TRUE,
5100 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
5103 Ytank_s, FALSE, FALSE,
5104 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
5107 Ytank_sB, FALSE, TRUE,
5108 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
5111 Ytank_w, FALSE, FALSE,
5112 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
5115 Ytank_wB, FALSE, TRUE,
5116 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
5119 Ytank_w_n, FALSE, FALSE,
5120 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
5123 Ytank_n_e, FALSE, FALSE,
5124 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
5127 Ytank_e_s, FALSE, FALSE,
5128 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
5131 Ytank_s_w, FALSE, FALSE,
5132 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
5135 Ytank_e_n, FALSE, FALSE,
5136 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
5139 Ytank_s_e, FALSE, FALSE,
5140 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
5143 Ytank_w_s, FALSE, FALSE,
5144 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
5147 Ytank_n_w, FALSE, FALSE,
5148 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
5151 Ytank_stone, FALSE, FALSE,
5152 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
5155 Ytank_spring, FALSE, FALSE,
5156 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
5159 Xandroid, TRUE, FALSE,
5160 EL_EMC_ANDROID, ACTION_ACTIVE, -1
5163 Xandroid_1_n, FALSE, FALSE,
5164 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
5167 Xandroid_2_n, FALSE, FALSE,
5168 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
5171 Xandroid_1_e, FALSE, FALSE,
5172 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
5175 Xandroid_2_e, FALSE, FALSE,
5176 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
5179 Xandroid_1_w, FALSE, FALSE,
5180 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
5183 Xandroid_2_w, FALSE, FALSE,
5184 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
5187 Xandroid_1_s, FALSE, FALSE,
5188 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
5191 Xandroid_2_s, FALSE, FALSE,
5192 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
5195 Yandroid_n, FALSE, FALSE,
5196 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
5199 Yandroid_nB, FALSE, TRUE,
5200 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
5203 Yandroid_ne, FALSE, FALSE,
5204 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
5207 Yandroid_neB, FALSE, TRUE,
5208 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
5211 Yandroid_e, FALSE, FALSE,
5212 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
5215 Yandroid_eB, FALSE, TRUE,
5216 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
5219 Yandroid_se, FALSE, FALSE,
5220 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
5223 Yandroid_seB, FALSE, TRUE,
5224 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
5227 Yandroid_s, FALSE, FALSE,
5228 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
5231 Yandroid_sB, FALSE, TRUE,
5232 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
5235 Yandroid_sw, FALSE, FALSE,
5236 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
5239 Yandroid_swB, FALSE, TRUE,
5240 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
5243 Yandroid_w, FALSE, FALSE,
5244 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
5247 Yandroid_wB, FALSE, TRUE,
5248 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
5251 Yandroid_nw, FALSE, FALSE,
5252 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
5255 Yandroid_nwB, FALSE, TRUE,
5256 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
5259 Xspring, TRUE, FALSE,
5263 Xspring_pause, FALSE, FALSE,
5267 Xspring_e, FALSE, FALSE,
5271 Xspring_w, FALSE, FALSE,
5275 Xspring_fall, FALSE, FALSE,
5279 Yspring_s, FALSE, FALSE,
5280 EL_SPRING, ACTION_FALLING, -1
5283 Yspring_sB, FALSE, TRUE,
5284 EL_SPRING, ACTION_FALLING, -1
5287 Yspring_e, FALSE, FALSE,
5288 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
5291 Yspring_eB, FALSE, TRUE,
5292 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
5295 Yspring_w, FALSE, FALSE,
5296 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
5299 Yspring_wB, FALSE, TRUE,
5300 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
5303 Yspring_kill_e, FALSE, FALSE,
5304 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
5307 Yspring_kill_eB, FALSE, TRUE,
5308 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
5311 Yspring_kill_w, FALSE, FALSE,
5312 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
5315 Yspring_kill_wB, FALSE, TRUE,
5316 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
5319 Xeater_n, TRUE, FALSE,
5320 EL_YAMYAM_UP, -1, -1
5323 Xeater_e, TRUE, FALSE,
5324 EL_YAMYAM_RIGHT, -1, -1
5327 Xeater_w, TRUE, FALSE,
5328 EL_YAMYAM_LEFT, -1, -1
5331 Xeater_s, TRUE, FALSE,
5332 EL_YAMYAM_DOWN, -1, -1
5335 Yeater_n, FALSE, FALSE,
5336 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
5339 Yeater_nB, FALSE, TRUE,
5340 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
5343 Yeater_e, FALSE, FALSE,
5344 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
5347 Yeater_eB, FALSE, TRUE,
5348 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
5351 Yeater_s, FALSE, FALSE,
5352 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
5355 Yeater_sB, FALSE, TRUE,
5356 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
5359 Yeater_w, FALSE, FALSE,
5360 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
5363 Yeater_wB, FALSE, TRUE,
5364 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
5367 Yeater_stone, FALSE, FALSE,
5368 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
5371 Yeater_spring, FALSE, FALSE,
5372 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
5375 Xalien, TRUE, FALSE,
5379 Xalien_pause, FALSE, FALSE,
5383 Yalien_n, FALSE, FALSE,
5384 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
5387 Yalien_nB, FALSE, TRUE,
5388 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
5391 Yalien_e, FALSE, FALSE,
5392 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
5395 Yalien_eB, FALSE, TRUE,
5396 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
5399 Yalien_s, FALSE, FALSE,
5400 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
5403 Yalien_sB, FALSE, TRUE,
5404 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
5407 Yalien_w, FALSE, FALSE,
5408 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
5411 Yalien_wB, FALSE, TRUE,
5412 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
5415 Yalien_stone, FALSE, FALSE,
5416 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
5419 Yalien_spring, FALSE, FALSE,
5420 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
5423 Xemerald, TRUE, FALSE,
5427 Xemerald_pause, FALSE, FALSE,
5431 Xemerald_fall, FALSE, FALSE,
5435 Xemerald_shine, FALSE, FALSE,
5436 EL_EMERALD, ACTION_TWINKLING, -1
5439 Yemerald_s, FALSE, FALSE,
5440 EL_EMERALD, ACTION_FALLING, -1
5443 Yemerald_sB, FALSE, TRUE,
5444 EL_EMERALD, ACTION_FALLING, -1
5447 Yemerald_e, FALSE, FALSE,
5448 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
5451 Yemerald_eB, FALSE, TRUE,
5452 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
5455 Yemerald_w, FALSE, FALSE,
5456 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
5459 Yemerald_wB, FALSE, TRUE,
5460 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
5463 Yemerald_eat, FALSE, FALSE,
5464 EL_EMERALD, ACTION_COLLECTING, -1
5467 Yemerald_stone, FALSE, FALSE,
5468 EL_NUT, ACTION_BREAKING, -1
5471 Xdiamond, TRUE, FALSE,
5475 Xdiamond_pause, FALSE, FALSE,
5479 Xdiamond_fall, FALSE, FALSE,
5483 Xdiamond_shine, FALSE, FALSE,
5484 EL_DIAMOND, ACTION_TWINKLING, -1
5487 Ydiamond_s, FALSE, FALSE,
5488 EL_DIAMOND, ACTION_FALLING, -1
5491 Ydiamond_sB, FALSE, TRUE,
5492 EL_DIAMOND, ACTION_FALLING, -1
5495 Ydiamond_e, FALSE, FALSE,
5496 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
5499 Ydiamond_eB, FALSE, TRUE,
5500 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
5503 Ydiamond_w, FALSE, FALSE,
5504 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
5507 Ydiamond_wB, FALSE, TRUE,
5508 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
5511 Ydiamond_eat, FALSE, FALSE,
5512 EL_DIAMOND, ACTION_COLLECTING, -1
5515 Ydiamond_stone, FALSE, FALSE,
5516 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
5519 Xdrip_fall, TRUE, FALSE,
5520 EL_AMOEBA_DROP, -1, -1
5523 Xdrip_stretch, FALSE, FALSE,
5524 EL_AMOEBA_DROP, ACTION_FALLING, -1
5527 Xdrip_stretchB, FALSE, TRUE,
5528 EL_AMOEBA_DROP, ACTION_FALLING, -1
5531 Xdrip_eat, FALSE, FALSE,
5532 EL_AMOEBA_DROP, ACTION_GROWING, -1
5535 Ydrip_s1, FALSE, FALSE,
5536 EL_AMOEBA_DROP, ACTION_FALLING, -1
5539 Ydrip_s1B, FALSE, TRUE,
5540 EL_AMOEBA_DROP, ACTION_FALLING, -1
5543 Ydrip_s2, FALSE, FALSE,
5544 EL_AMOEBA_DROP, ACTION_FALLING, -1
5547 Ydrip_s2B, FALSE, TRUE,
5548 EL_AMOEBA_DROP, ACTION_FALLING, -1
5555 Xbomb_pause, FALSE, FALSE,
5559 Xbomb_fall, FALSE, FALSE,
5563 Ybomb_s, FALSE, FALSE,
5564 EL_BOMB, ACTION_FALLING, -1
5567 Ybomb_sB, FALSE, TRUE,
5568 EL_BOMB, ACTION_FALLING, -1
5571 Ybomb_e, FALSE, FALSE,
5572 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
5575 Ybomb_eB, FALSE, TRUE,
5576 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
5579 Ybomb_w, FALSE, FALSE,
5580 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
5583 Ybomb_wB, FALSE, TRUE,
5584 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
5587 Ybomb_eat, FALSE, FALSE,
5588 EL_BOMB, ACTION_ACTIVATING, -1
5591 Xballoon, TRUE, FALSE,
5595 Yballoon_n, FALSE, FALSE,
5596 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
5599 Yballoon_nB, FALSE, TRUE,
5600 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
5603 Yballoon_e, FALSE, FALSE,
5604 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
5607 Yballoon_eB, FALSE, TRUE,
5608 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
5611 Yballoon_s, FALSE, FALSE,
5612 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
5615 Yballoon_sB, FALSE, TRUE,
5616 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
5619 Yballoon_w, FALSE, FALSE,
5620 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
5623 Yballoon_wB, FALSE, TRUE,
5624 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
5627 Xgrass, TRUE, FALSE,
5628 EL_EMC_GRASS, -1, -1
5631 Ygrass_nB, FALSE, FALSE,
5632 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
5635 Ygrass_eB, FALSE, FALSE,
5636 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
5639 Ygrass_sB, FALSE, FALSE,
5640 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
5643 Ygrass_wB, FALSE, FALSE,
5644 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
5651 Ydirt_nB, FALSE, FALSE,
5652 EL_SAND, ACTION_DIGGING, MV_BIT_UP
5655 Ydirt_eB, FALSE, FALSE,
5656 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
5659 Ydirt_sB, FALSE, FALSE,
5660 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
5663 Ydirt_wB, FALSE, FALSE,
5664 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
5667 Xacid_ne, TRUE, FALSE,
5668 EL_ACID_POOL_TOPRIGHT, -1, -1
5671 Xacid_se, TRUE, FALSE,
5672 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
5675 Xacid_s, TRUE, FALSE,
5676 EL_ACID_POOL_BOTTOM, -1, -1
5679 Xacid_sw, TRUE, FALSE,
5680 EL_ACID_POOL_BOTTOMLEFT, -1, -1
5683 Xacid_nw, TRUE, FALSE,
5684 EL_ACID_POOL_TOPLEFT, -1, -1
5687 Xacid_1, TRUE, FALSE,
5691 Xacid_2, FALSE, FALSE,
5695 Xacid_3, FALSE, FALSE,
5699 Xacid_4, FALSE, FALSE,
5703 Xacid_5, FALSE, FALSE,
5707 Xacid_6, FALSE, FALSE,
5711 Xacid_7, FALSE, FALSE,
5715 Xacid_8, FALSE, FALSE,
5719 Xball_1, TRUE, FALSE,
5720 EL_EMC_MAGIC_BALL, -1, -1
5723 Xball_1B, FALSE, FALSE,
5724 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5727 Xball_2, FALSE, FALSE,
5728 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5731 Xball_2B, FALSE, FALSE,
5732 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5735 Yball_eat, FALSE, FALSE,
5736 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
5739 Ykey_1_eat, FALSE, FALSE,
5740 EL_EM_KEY_1, ACTION_COLLECTING, -1
5743 Ykey_2_eat, FALSE, FALSE,
5744 EL_EM_KEY_2, ACTION_COLLECTING, -1
5747 Ykey_3_eat, FALSE, FALSE,
5748 EL_EM_KEY_3, ACTION_COLLECTING, -1
5751 Ykey_4_eat, FALSE, FALSE,
5752 EL_EM_KEY_4, ACTION_COLLECTING, -1
5755 Ykey_5_eat, FALSE, FALSE,
5756 EL_EMC_KEY_5, ACTION_COLLECTING, -1
5759 Ykey_6_eat, FALSE, FALSE,
5760 EL_EMC_KEY_6, ACTION_COLLECTING, -1
5763 Ykey_7_eat, FALSE, FALSE,
5764 EL_EMC_KEY_7, ACTION_COLLECTING, -1
5767 Ykey_8_eat, FALSE, FALSE,
5768 EL_EMC_KEY_8, ACTION_COLLECTING, -1
5771 Ylenses_eat, FALSE, FALSE,
5772 EL_EMC_LENSES, ACTION_COLLECTING, -1
5775 Ymagnify_eat, FALSE, FALSE,
5776 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
5779 Ygrass_eat, FALSE, FALSE,
5780 EL_EMC_GRASS, ACTION_SNAPPING, -1
5783 Ydirt_eat, FALSE, FALSE,
5784 EL_SAND, ACTION_SNAPPING, -1
5787 Xgrow_ns, TRUE, FALSE,
5788 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
5791 Ygrow_ns_eat, FALSE, FALSE,
5792 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
5795 Xgrow_ew, TRUE, FALSE,
5796 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
5799 Ygrow_ew_eat, FALSE, FALSE,
5800 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
5803 Xwonderwall, TRUE, FALSE,
5804 EL_MAGIC_WALL, -1, -1
5807 XwonderwallB, FALSE, FALSE,
5808 EL_MAGIC_WALL, ACTION_ACTIVE, -1
5811 Xamoeba_1, TRUE, FALSE,
5812 EL_AMOEBA_DRY, ACTION_OTHER, -1
5815 Xamoeba_2, FALSE, FALSE,
5816 EL_AMOEBA_DRY, ACTION_OTHER, -1
5819 Xamoeba_3, FALSE, FALSE,
5820 EL_AMOEBA_DRY, ACTION_OTHER, -1
5823 Xamoeba_4, FALSE, FALSE,
5824 EL_AMOEBA_DRY, ACTION_OTHER, -1
5827 Xamoeba_5, TRUE, FALSE,
5828 EL_AMOEBA_WET, ACTION_OTHER, -1
5831 Xamoeba_6, FALSE, FALSE,
5832 EL_AMOEBA_WET, ACTION_OTHER, -1
5835 Xamoeba_7, FALSE, FALSE,
5836 EL_AMOEBA_WET, ACTION_OTHER, -1
5839 Xamoeba_8, FALSE, FALSE,
5840 EL_AMOEBA_WET, ACTION_OTHER, -1
5843 Xdoor_1, TRUE, FALSE,
5844 EL_EM_GATE_1, -1, -1
5847 Xdoor_2, TRUE, FALSE,
5848 EL_EM_GATE_2, -1, -1
5851 Xdoor_3, TRUE, FALSE,
5852 EL_EM_GATE_3, -1, -1
5855 Xdoor_4, TRUE, FALSE,
5856 EL_EM_GATE_4, -1, -1
5859 Xdoor_5, TRUE, FALSE,
5860 EL_EMC_GATE_5, -1, -1
5863 Xdoor_6, TRUE, FALSE,
5864 EL_EMC_GATE_6, -1, -1
5867 Xdoor_7, TRUE, FALSE,
5868 EL_EMC_GATE_7, -1, -1
5871 Xdoor_8, TRUE, FALSE,
5872 EL_EMC_GATE_8, -1, -1
5875 Xkey_1, TRUE, FALSE,
5879 Xkey_2, TRUE, FALSE,
5883 Xkey_3, TRUE, FALSE,
5887 Xkey_4, TRUE, FALSE,
5891 Xkey_5, TRUE, FALSE,
5892 EL_EMC_KEY_5, -1, -1
5895 Xkey_6, TRUE, FALSE,
5896 EL_EMC_KEY_6, -1, -1
5899 Xkey_7, TRUE, FALSE,
5900 EL_EMC_KEY_7, -1, -1
5903 Xkey_8, TRUE, FALSE,
5904 EL_EMC_KEY_8, -1, -1
5907 Xwind_n, TRUE, FALSE,
5908 EL_BALLOON_SWITCH_UP, -1, -1
5911 Xwind_e, TRUE, FALSE,
5912 EL_BALLOON_SWITCH_RIGHT, -1, -1
5915 Xwind_s, TRUE, FALSE,
5916 EL_BALLOON_SWITCH_DOWN, -1, -1
5919 Xwind_w, TRUE, FALSE,
5920 EL_BALLOON_SWITCH_LEFT, -1, -1
5923 Xwind_nesw, TRUE, FALSE,
5924 EL_BALLOON_SWITCH_ANY, -1, -1
5927 Xwind_stop, TRUE, FALSE,
5928 EL_BALLOON_SWITCH_NONE, -1, -1
5932 EL_EM_EXIT_CLOSED, -1, -1
5935 Xexit_1, TRUE, FALSE,
5936 EL_EM_EXIT_OPEN, -1, -1
5939 Xexit_2, FALSE, FALSE,
5940 EL_EM_EXIT_OPEN, -1, -1
5943 Xexit_3, FALSE, FALSE,
5944 EL_EM_EXIT_OPEN, -1, -1
5947 Xdynamite, TRUE, FALSE,
5948 EL_EM_DYNAMITE, -1, -1
5951 Ydynamite_eat, FALSE, FALSE,
5952 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
5955 Xdynamite_1, TRUE, FALSE,
5956 EL_EM_DYNAMITE_ACTIVE, -1, -1
5959 Xdynamite_2, FALSE, FALSE,
5960 EL_EM_DYNAMITE_ACTIVE, -1, -1
5963 Xdynamite_3, FALSE, FALSE,
5964 EL_EM_DYNAMITE_ACTIVE, -1, -1
5967 Xdynamite_4, FALSE, FALSE,
5968 EL_EM_DYNAMITE_ACTIVE, -1, -1
5971 Xbumper, TRUE, FALSE,
5972 EL_EMC_SPRING_BUMPER, -1, -1
5975 XbumperB, FALSE, FALSE,
5976 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
5979 Xwheel, TRUE, FALSE,
5980 EL_ROBOT_WHEEL, -1, -1
5983 XwheelB, FALSE, FALSE,
5984 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
5987 Xswitch, TRUE, FALSE,
5988 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
5991 XswitchB, FALSE, FALSE,
5992 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
5996 EL_QUICKSAND_EMPTY, -1, -1
5999 Xsand_stone, TRUE, FALSE,
6000 EL_QUICKSAND_FULL, -1, -1
6003 Xsand_stonein_1, FALSE, TRUE,
6004 EL_ROCK, ACTION_FILLING, -1
6007 Xsand_stonein_2, FALSE, TRUE,
6008 EL_ROCK, ACTION_FILLING, -1
6011 Xsand_stonein_3, FALSE, TRUE,
6012 EL_ROCK, ACTION_FILLING, -1
6015 Xsand_stonein_4, FALSE, TRUE,
6016 EL_ROCK, ACTION_FILLING, -1
6019 Xsand_stonesand_1, FALSE, FALSE,
6020 EL_QUICKSAND_EMPTYING, -1, -1
6023 Xsand_stonesand_2, FALSE, FALSE,
6024 EL_QUICKSAND_EMPTYING, -1, -1
6027 Xsand_stonesand_3, FALSE, FALSE,
6028 EL_QUICKSAND_EMPTYING, -1, -1
6031 Xsand_stonesand_4, FALSE, FALSE,
6032 EL_QUICKSAND_EMPTYING, -1, -1
6035 Xsand_stonesand_quickout_1, FALSE, FALSE,
6036 EL_QUICKSAND_EMPTYING, -1, -1
6039 Xsand_stonesand_quickout_2, FALSE, FALSE,
6040 EL_QUICKSAND_EMPTYING, -1, -1
6043 Xsand_stoneout_1, FALSE, FALSE,
6044 EL_ROCK, ACTION_EMPTYING, -1
6047 Xsand_stoneout_2, FALSE, FALSE,
6048 EL_ROCK, ACTION_EMPTYING, -1
6051 Xsand_sandstone_1, FALSE, FALSE,
6052 EL_QUICKSAND_FILLING, -1, -1
6055 Xsand_sandstone_2, FALSE, FALSE,
6056 EL_QUICKSAND_FILLING, -1, -1
6059 Xsand_sandstone_3, FALSE, FALSE,
6060 EL_QUICKSAND_FILLING, -1, -1
6063 Xsand_sandstone_4, FALSE, FALSE,
6064 EL_QUICKSAND_FILLING, -1, -1
6067 Xplant, TRUE, FALSE,
6068 EL_EMC_PLANT, -1, -1
6071 Yplant, FALSE, FALSE,
6072 EL_EMC_PLANT, -1, -1
6075 Xlenses, TRUE, FALSE,
6076 EL_EMC_LENSES, -1, -1
6079 Xmagnify, TRUE, FALSE,
6080 EL_EMC_MAGNIFIER, -1, -1
6083 Xdripper, TRUE, FALSE,
6084 EL_EMC_DRIPPER, -1, -1
6087 XdripperB, FALSE, FALSE,
6088 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
6091 Xfake_blank, TRUE, FALSE,
6092 EL_INVISIBLE_WALL, -1, -1
6095 Xfake_blankB, FALSE, FALSE,
6096 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
6099 Xfake_grass, TRUE, FALSE,
6100 EL_EMC_FAKE_GRASS, -1, -1
6103 Xfake_grassB, FALSE, FALSE,
6104 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
6107 Xfake_door_1, TRUE, FALSE,
6108 EL_EM_GATE_1_GRAY, -1, -1
6111 Xfake_door_2, TRUE, FALSE,
6112 EL_EM_GATE_2_GRAY, -1, -1
6115 Xfake_door_3, TRUE, FALSE,
6116 EL_EM_GATE_3_GRAY, -1, -1
6119 Xfake_door_4, TRUE, FALSE,
6120 EL_EM_GATE_4_GRAY, -1, -1
6123 Xfake_door_5, TRUE, FALSE,
6124 EL_EMC_GATE_5_GRAY, -1, -1
6127 Xfake_door_6, TRUE, FALSE,
6128 EL_EMC_GATE_6_GRAY, -1, -1
6131 Xfake_door_7, TRUE, FALSE,
6132 EL_EMC_GATE_7_GRAY, -1, -1
6135 Xfake_door_8, TRUE, FALSE,
6136 EL_EMC_GATE_8_GRAY, -1, -1
6139 Xfake_acid_1, TRUE, FALSE,
6140 EL_EMC_FAKE_ACID, -1, -1
6143 Xfake_acid_2, FALSE, FALSE,
6144 EL_EMC_FAKE_ACID, -1, -1
6147 Xfake_acid_3, FALSE, FALSE,
6148 EL_EMC_FAKE_ACID, -1, -1
6151 Xfake_acid_4, FALSE, FALSE,
6152 EL_EMC_FAKE_ACID, -1, -1
6155 Xfake_acid_5, FALSE, FALSE,
6156 EL_EMC_FAKE_ACID, -1, -1
6159 Xfake_acid_6, FALSE, FALSE,
6160 EL_EMC_FAKE_ACID, -1, -1
6163 Xfake_acid_7, FALSE, FALSE,
6164 EL_EMC_FAKE_ACID, -1, -1
6167 Xfake_acid_8, FALSE, FALSE,
6168 EL_EMC_FAKE_ACID, -1, -1
6171 Xsteel_1, TRUE, FALSE,
6172 EL_STEELWALL, -1, -1
6175 Xsteel_2, TRUE, FALSE,
6176 EL_EMC_STEELWALL_2, -1, -1
6179 Xsteel_3, TRUE, FALSE,
6180 EL_EMC_STEELWALL_3, -1, -1
6183 Xsteel_4, TRUE, FALSE,
6184 EL_EMC_STEELWALL_4, -1, -1
6187 Xwall_1, TRUE, FALSE,
6191 Xwall_2, TRUE, FALSE,
6192 EL_EMC_WALL_14, -1, -1
6195 Xwall_3, TRUE, FALSE,
6196 EL_EMC_WALL_15, -1, -1
6199 Xwall_4, TRUE, FALSE,
6200 EL_EMC_WALL_16, -1, -1
6203 Xround_wall_1, TRUE, FALSE,
6204 EL_WALL_SLIPPERY, -1, -1
6207 Xround_wall_2, TRUE, FALSE,
6208 EL_EMC_WALL_SLIPPERY_2, -1, -1
6211 Xround_wall_3, TRUE, FALSE,
6212 EL_EMC_WALL_SLIPPERY_3, -1, -1
6215 Xround_wall_4, TRUE, FALSE,
6216 EL_EMC_WALL_SLIPPERY_4, -1, -1
6219 Xdecor_1, TRUE, FALSE,
6220 EL_EMC_WALL_8, -1, -1
6223 Xdecor_2, TRUE, FALSE,
6224 EL_EMC_WALL_6, -1, -1
6227 Xdecor_3, TRUE, FALSE,
6228 EL_EMC_WALL_4, -1, -1
6231 Xdecor_4, TRUE, FALSE,
6232 EL_EMC_WALL_7, -1, -1
6235 Xdecor_5, TRUE, FALSE,
6236 EL_EMC_WALL_5, -1, -1
6239 Xdecor_6, TRUE, FALSE,
6240 EL_EMC_WALL_9, -1, -1
6243 Xdecor_7, TRUE, FALSE,
6244 EL_EMC_WALL_10, -1, -1
6247 Xdecor_8, TRUE, FALSE,
6248 EL_EMC_WALL_1, -1, -1
6251 Xdecor_9, TRUE, FALSE,
6252 EL_EMC_WALL_2, -1, -1
6255 Xdecor_10, TRUE, FALSE,
6256 EL_EMC_WALL_3, -1, -1
6259 Xdecor_11, TRUE, FALSE,
6260 EL_EMC_WALL_11, -1, -1
6263 Xdecor_12, TRUE, FALSE,
6264 EL_EMC_WALL_12, -1, -1
6267 Xalpha_0, TRUE, FALSE,
6268 EL_CHAR('0'), -1, -1
6271 Xalpha_1, TRUE, FALSE,
6272 EL_CHAR('1'), -1, -1
6275 Xalpha_2, TRUE, FALSE,
6276 EL_CHAR('2'), -1, -1
6279 Xalpha_3, TRUE, FALSE,
6280 EL_CHAR('3'), -1, -1
6283 Xalpha_4, TRUE, FALSE,
6284 EL_CHAR('4'), -1, -1
6287 Xalpha_5, TRUE, FALSE,
6288 EL_CHAR('5'), -1, -1
6291 Xalpha_6, TRUE, FALSE,
6292 EL_CHAR('6'), -1, -1
6295 Xalpha_7, TRUE, FALSE,
6296 EL_CHAR('7'), -1, -1
6299 Xalpha_8, TRUE, FALSE,
6300 EL_CHAR('8'), -1, -1
6303 Xalpha_9, TRUE, FALSE,
6304 EL_CHAR('9'), -1, -1
6307 Xalpha_excla, TRUE, FALSE,
6308 EL_CHAR('!'), -1, -1
6311 Xalpha_quote, TRUE, FALSE,
6312 EL_CHAR('"'), -1, -1
6315 Xalpha_comma, TRUE, FALSE,
6316 EL_CHAR(','), -1, -1
6319 Xalpha_minus, TRUE, FALSE,
6320 EL_CHAR('-'), -1, -1
6323 Xalpha_perio, TRUE, FALSE,
6324 EL_CHAR('.'), -1, -1
6327 Xalpha_colon, TRUE, FALSE,
6328 EL_CHAR(':'), -1, -1
6331 Xalpha_quest, TRUE, FALSE,
6332 EL_CHAR('?'), -1, -1
6335 Xalpha_a, TRUE, FALSE,
6336 EL_CHAR('A'), -1, -1
6339 Xalpha_b, TRUE, FALSE,
6340 EL_CHAR('B'), -1, -1
6343 Xalpha_c, TRUE, FALSE,
6344 EL_CHAR('C'), -1, -1
6347 Xalpha_d, TRUE, FALSE,
6348 EL_CHAR('D'), -1, -1
6351 Xalpha_e, TRUE, FALSE,
6352 EL_CHAR('E'), -1, -1
6355 Xalpha_f, TRUE, FALSE,
6356 EL_CHAR('F'), -1, -1
6359 Xalpha_g, TRUE, FALSE,
6360 EL_CHAR('G'), -1, -1
6363 Xalpha_h, TRUE, FALSE,
6364 EL_CHAR('H'), -1, -1
6367 Xalpha_i, TRUE, FALSE,
6368 EL_CHAR('I'), -1, -1
6371 Xalpha_j, TRUE, FALSE,
6372 EL_CHAR('J'), -1, -1
6375 Xalpha_k, TRUE, FALSE,
6376 EL_CHAR('K'), -1, -1
6379 Xalpha_l, TRUE, FALSE,
6380 EL_CHAR('L'), -1, -1
6383 Xalpha_m, TRUE, FALSE,
6384 EL_CHAR('M'), -1, -1
6387 Xalpha_n, TRUE, FALSE,
6388 EL_CHAR('N'), -1, -1
6391 Xalpha_o, TRUE, FALSE,
6392 EL_CHAR('O'), -1, -1
6395 Xalpha_p, TRUE, FALSE,
6396 EL_CHAR('P'), -1, -1
6399 Xalpha_q, TRUE, FALSE,
6400 EL_CHAR('Q'), -1, -1
6403 Xalpha_r, TRUE, FALSE,
6404 EL_CHAR('R'), -1, -1
6407 Xalpha_s, TRUE, FALSE,
6408 EL_CHAR('S'), -1, -1
6411 Xalpha_t, TRUE, FALSE,
6412 EL_CHAR('T'), -1, -1
6415 Xalpha_u, TRUE, FALSE,
6416 EL_CHAR('U'), -1, -1
6419 Xalpha_v, TRUE, FALSE,
6420 EL_CHAR('V'), -1, -1
6423 Xalpha_w, TRUE, FALSE,
6424 EL_CHAR('W'), -1, -1
6427 Xalpha_x, TRUE, FALSE,
6428 EL_CHAR('X'), -1, -1
6431 Xalpha_y, TRUE, FALSE,
6432 EL_CHAR('Y'), -1, -1
6435 Xalpha_z, TRUE, FALSE,
6436 EL_CHAR('Z'), -1, -1
6439 Xalpha_arrow_e, TRUE, FALSE,
6440 EL_CHAR('>'), -1, -1
6443 Xalpha_arrow_w, TRUE, FALSE,
6444 EL_CHAR('<'), -1, -1
6447 Xalpha_copyr, TRUE, FALSE,
6448 EL_CHAR(CHAR_BYTE_COPYRIGHT), -1, -1
6452 Xboom_bug, FALSE, FALSE,
6453 EL_BUG, ACTION_EXPLODING, -1
6456 Xboom_bomb, FALSE, FALSE,
6457 EL_BOMB, ACTION_EXPLODING, -1
6460 Xboom_android, FALSE, FALSE,
6461 EL_EMC_ANDROID, ACTION_OTHER, -1
6464 Xboom_1, FALSE, FALSE,
6465 EL_DEFAULT, ACTION_EXPLODING, -1
6468 Xboom_2, FALSE, FALSE,
6469 EL_DEFAULT, ACTION_EXPLODING, -1
6472 Znormal, FALSE, FALSE,
6476 Zdynamite, FALSE, FALSE,
6480 Zplayer, FALSE, FALSE,
6484 ZBORDER, FALSE, FALSE,
6494 static struct Mapping_EM_to_RND_player
6503 em_player_mapping_list[] =
6507 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
6511 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
6515 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
6519 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
6523 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
6527 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
6531 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
6535 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
6539 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
6543 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
6547 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
6551 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
6555 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
6559 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
6563 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
6567 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
6571 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
6575 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
6579 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
6583 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
6587 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
6591 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
6595 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
6599 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
6603 EL_PLAYER_1, ACTION_DEFAULT, -1,
6607 EL_PLAYER_2, ACTION_DEFAULT, -1,
6611 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
6615 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
6619 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
6623 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
6627 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
6631 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
6635 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
6639 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
6643 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
6647 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
6651 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
6655 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
6659 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
6663 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
6667 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
6671 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
6675 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
6679 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
6683 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
6687 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
6691 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
6695 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
6699 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
6703 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
6707 EL_PLAYER_3, ACTION_DEFAULT, -1,
6711 EL_PLAYER_4, ACTION_DEFAULT, -1,
6720 int map_element_RND_to_EM(int element_rnd)
6722 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
6723 static boolean mapping_initialized = FALSE;
6725 if (!mapping_initialized)
6729 /* return "Xalpha_quest" for all undefined elements in mapping array */
6730 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
6731 mapping_RND_to_EM[i] = Xalpha_quest;
6733 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6734 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
6735 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
6736 em_object_mapping_list[i].element_em;
6738 mapping_initialized = TRUE;
6741 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
6742 return mapping_RND_to_EM[element_rnd];
6744 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
6749 int map_element_EM_to_RND(int element_em)
6751 static unsigned short mapping_EM_to_RND[TILE_MAX];
6752 static boolean mapping_initialized = FALSE;
6754 if (!mapping_initialized)
6758 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
6759 for (i = 0; i < TILE_MAX; i++)
6760 mapping_EM_to_RND[i] = EL_UNKNOWN;
6762 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6763 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
6764 em_object_mapping_list[i].element_rnd;
6766 mapping_initialized = TRUE;
6769 if (element_em >= 0 && element_em < TILE_MAX)
6770 return mapping_EM_to_RND[element_em];
6772 Error(ERR_WARN, "invalid EM level element %d", element_em);
6777 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
6779 struct LevelInfo_EM *level_em = level->native_em_level;
6780 struct LEVEL *lev = level_em->lev;
6783 for (i = 0; i < TILE_MAX; i++)
6784 lev->android_array[i] = Xblank;
6786 for (i = 0; i < level->num_android_clone_elements; i++)
6788 int element_rnd = level->android_clone_element[i];
6789 int element_em = map_element_RND_to_EM(element_rnd);
6791 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
6792 if (em_object_mapping_list[j].element_rnd == element_rnd)
6793 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
6797 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
6799 struct LevelInfo_EM *level_em = level->native_em_level;
6800 struct LEVEL *lev = level_em->lev;
6803 level->num_android_clone_elements = 0;
6805 for (i = 0; i < TILE_MAX; i++)
6807 int element_em = lev->android_array[i];
6809 boolean element_found = FALSE;
6811 if (element_em == Xblank)
6814 element_rnd = map_element_EM_to_RND(element_em);
6816 for (j = 0; j < level->num_android_clone_elements; j++)
6817 if (level->android_clone_element[j] == element_rnd)
6818 element_found = TRUE;
6822 level->android_clone_element[level->num_android_clone_elements++] =
6825 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
6830 if (level->num_android_clone_elements == 0)
6832 level->num_android_clone_elements = 1;
6833 level->android_clone_element[0] = EL_EMPTY;
6837 int map_direction_RND_to_EM(int direction)
6839 return (direction == MV_UP ? 0 :
6840 direction == MV_RIGHT ? 1 :
6841 direction == MV_DOWN ? 2 :
6842 direction == MV_LEFT ? 3 :
6846 int map_direction_EM_to_RND(int direction)
6848 return (direction == 0 ? MV_UP :
6849 direction == 1 ? MV_RIGHT :
6850 direction == 2 ? MV_DOWN :
6851 direction == 3 ? MV_LEFT :
6855 int map_element_RND_to_SP(int element_rnd)
6857 int element_sp = 0x20; /* map unknown elements to yellow "hardware" */
6859 if (element_rnd >= EL_SP_START &&
6860 element_rnd <= EL_SP_END)
6861 element_sp = element_rnd - EL_SP_START;
6862 else if (element_rnd == EL_EMPTY_SPACE)
6864 else if (element_rnd == EL_INVISIBLE_WALL)
6870 int map_element_SP_to_RND(int element_sp)
6872 int element_rnd = EL_UNKNOWN;
6874 if (element_sp >= 0x00 &&
6876 element_rnd = EL_SP_START + element_sp;
6877 else if (element_sp == 0x28)
6878 element_rnd = EL_INVISIBLE_WALL;
6883 int map_action_SP_to_RND(int action_sp)
6887 case actActive: return ACTION_ACTIVE;
6888 case actImpact: return ACTION_IMPACT;
6889 case actExploding: return ACTION_EXPLODING;
6890 case actDigging: return ACTION_DIGGING;
6891 case actSnapping: return ACTION_SNAPPING;
6892 case actCollecting: return ACTION_COLLECTING;
6893 case actPassing: return ACTION_PASSING;
6894 case actPushing: return ACTION_PUSHING;
6895 case actDropping: return ACTION_DROPPING;
6897 default: return ACTION_DEFAULT;
6901 int get_next_element(int element)
6905 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
6906 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
6907 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
6908 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
6909 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
6910 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
6911 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
6912 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
6913 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
6914 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
6915 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
6917 default: return element;
6921 int el_act_dir2img(int element, int action, int direction)
6923 element = GFX_ELEMENT(element);
6924 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
6926 /* direction_graphic[][] == graphic[] for undefined direction graphics */
6927 return element_info[element].direction_graphic[action][direction];
6930 static int el_act_dir2crm(int element, int action, int direction)
6932 element = GFX_ELEMENT(element);
6933 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
6935 /* direction_graphic[][] == graphic[] for undefined direction graphics */
6936 return element_info[element].direction_crumbled[action][direction];
6939 int el_act2img(int element, int action)
6941 element = GFX_ELEMENT(element);
6943 return element_info[element].graphic[action];
6946 int el_act2crm(int element, int action)
6948 element = GFX_ELEMENT(element);
6950 return element_info[element].crumbled[action];
6953 int el_dir2img(int element, int direction)
6955 element = GFX_ELEMENT(element);
6957 return el_act_dir2img(element, ACTION_DEFAULT, direction);
6960 int el2baseimg(int element)
6962 return element_info[element].graphic[ACTION_DEFAULT];
6965 int el2img(int element)
6967 element = GFX_ELEMENT(element);
6969 return element_info[element].graphic[ACTION_DEFAULT];
6972 int el2edimg(int element)
6974 element = GFX_ELEMENT(element);
6976 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
6979 int el2preimg(int element)
6981 element = GFX_ELEMENT(element);
6983 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
6986 int el2panelimg(int element)
6988 element = GFX_ELEMENT(element);
6990 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL];
6993 int font2baseimg(int font_nr)
6995 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
6998 int getBeltNrFromBeltElement(int element)
7000 return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
7001 element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
7002 element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
7005 int getBeltNrFromBeltActiveElement(int element)
7007 return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
7008 element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
7009 element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
7012 int getBeltNrFromBeltSwitchElement(int element)
7014 return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
7015 element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
7016 element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
7019 int getBeltDirNrFromBeltElement(int element)
7021 static int belt_base_element[4] =
7023 EL_CONVEYOR_BELT_1_LEFT,
7024 EL_CONVEYOR_BELT_2_LEFT,
7025 EL_CONVEYOR_BELT_3_LEFT,
7026 EL_CONVEYOR_BELT_4_LEFT
7029 int belt_nr = getBeltNrFromBeltElement(element);
7030 int belt_dir_nr = element - belt_base_element[belt_nr];
7032 return (belt_dir_nr % 3);
7035 int getBeltDirNrFromBeltSwitchElement(int element)
7037 static int belt_base_element[4] =
7039 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
7040 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
7041 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
7042 EL_CONVEYOR_BELT_4_SWITCH_LEFT
7045 int belt_nr = getBeltNrFromBeltSwitchElement(element);
7046 int belt_dir_nr = element - belt_base_element[belt_nr];
7048 return (belt_dir_nr % 3);
7051 int getBeltDirFromBeltElement(int element)
7053 static int belt_move_dir[3] =
7060 int belt_dir_nr = getBeltDirNrFromBeltElement(element);
7062 return belt_move_dir[belt_dir_nr];
7065 int getBeltDirFromBeltSwitchElement(int element)
7067 static int belt_move_dir[3] =
7074 int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
7076 return belt_move_dir[belt_dir_nr];
7079 int getBeltElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
7081 static int belt_base_element[4] =
7083 EL_CONVEYOR_BELT_1_LEFT,
7084 EL_CONVEYOR_BELT_2_LEFT,
7085 EL_CONVEYOR_BELT_3_LEFT,
7086 EL_CONVEYOR_BELT_4_LEFT
7089 return belt_base_element[belt_nr] + belt_dir_nr;
7092 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
7094 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
7096 return getBeltElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
7099 int getBeltSwitchElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
7101 static int belt_base_element[4] =
7103 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
7104 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
7105 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
7106 EL_CONVEYOR_BELT_4_SWITCH_LEFT
7109 return belt_base_element[belt_nr] + belt_dir_nr;
7112 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
7114 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
7116 return getBeltSwitchElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
7119 boolean getTeamMode_EM()
7121 return game.team_mode;
7124 int getGameFrameDelay_EM(int native_em_game_frame_delay)
7126 int game_frame_delay_value;
7128 game_frame_delay_value =
7129 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
7130 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
7133 if (tape.playing && tape.warp_forward && !tape.pausing)
7134 game_frame_delay_value = 0;
7136 return game_frame_delay_value;
7139 unsigned int InitRND(int seed)
7141 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
7142 return InitEngineRandom_EM(seed);
7143 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
7144 return InitEngineRandom_SP(seed);
7146 return InitEngineRandom_RND(seed);
7149 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
7150 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
7152 inline static int get_effective_element_EM(int tile, int frame_em)
7154 int element = object_mapping[tile].element_rnd;
7155 int action = object_mapping[tile].action;
7156 boolean is_backside = object_mapping[tile].is_backside;
7157 boolean action_removing = (action == ACTION_DIGGING ||
7158 action == ACTION_SNAPPING ||
7159 action == ACTION_COLLECTING);
7165 case Yacid_splash_eB:
7166 case Yacid_splash_wB:
7167 return (frame_em > 5 ? EL_EMPTY : element);
7173 else /* frame_em == 7 */
7177 case Yacid_splash_eB:
7178 case Yacid_splash_wB:
7181 case Yemerald_stone:
7184 case Ydiamond_stone:
7188 case Xdrip_stretchB:
7207 case Xsand_stonein_1:
7208 case Xsand_stonein_2:
7209 case Xsand_stonein_3:
7210 case Xsand_stonein_4:
7214 return (is_backside || action_removing ? EL_EMPTY : element);
7219 inline static boolean check_linear_animation_EM(int tile)
7223 case Xsand_stonesand_1:
7224 case Xsand_stonesand_quickout_1:
7225 case Xsand_sandstone_1:
7226 case Xsand_stonein_1:
7227 case Xsand_stoneout_1:
7246 case Yacid_splash_eB:
7247 case Yacid_splash_wB:
7248 case Yemerald_stone:
7255 inline static void set_crumbled_graphics_EM(struct GraphicInfo_EM *g_em,
7256 boolean has_crumbled_graphics,
7257 int crumbled, int sync_frame)
7259 /* if element can be crumbled, but certain action graphics are just empty
7260 space (like instantly snapping sand to empty space in 1 frame), do not
7261 treat these empty space graphics as crumbled graphics in EMC engine */
7262 if (crumbled == IMG_EMPTY_SPACE)
7263 has_crumbled_graphics = FALSE;
7265 if (has_crumbled_graphics)
7267 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
7268 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
7269 g_crumbled->anim_delay,
7270 g_crumbled->anim_mode,
7271 g_crumbled->anim_start_frame,
7274 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
7275 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
7277 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
7279 g_em->has_crumbled_graphics = TRUE;
7283 g_em->crumbled_bitmap = NULL;
7284 g_em->crumbled_src_x = 0;
7285 g_em->crumbled_src_y = 0;
7286 g_em->crumbled_border_size = 0;
7288 g_em->has_crumbled_graphics = FALSE;
7292 void ResetGfxAnimation_EM(int x, int y, int tile)
7297 void SetGfxAnimation_EM(struct GraphicInfo_EM *g_em,
7298 int tile, int frame_em, int x, int y)
7300 int action = object_mapping[tile].action;
7301 int direction = object_mapping[tile].direction;
7302 int effective_element = get_effective_element_EM(tile, frame_em);
7303 int graphic = (direction == MV_NONE ?
7304 el_act2img(effective_element, action) :
7305 el_act_dir2img(effective_element, action, direction));
7306 struct GraphicInfo *g = &graphic_info[graphic];
7308 boolean action_removing = (action == ACTION_DIGGING ||
7309 action == ACTION_SNAPPING ||
7310 action == ACTION_COLLECTING);
7311 boolean action_moving = (action == ACTION_FALLING ||
7312 action == ACTION_MOVING ||
7313 action == ACTION_PUSHING ||
7314 action == ACTION_EATING ||
7315 action == ACTION_FILLING ||
7316 action == ACTION_EMPTYING);
7317 boolean action_falling = (action == ACTION_FALLING ||
7318 action == ACTION_FILLING ||
7319 action == ACTION_EMPTYING);
7321 /* special case: graphic uses "2nd movement tile" and has defined
7322 7 frames for movement animation (or less) => use default graphic
7323 for last (8th) frame which ends the movement animation */
7324 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
7326 action = ACTION_DEFAULT; /* (keep action_* unchanged for now) */
7327 graphic = (direction == MV_NONE ?
7328 el_act2img(effective_element, action) :
7329 el_act_dir2img(effective_element, action, direction));
7331 g = &graphic_info[graphic];
7334 if ((action_removing || check_linear_animation_EM(tile)) && frame_em == 0)
7338 else if (action_moving)
7340 boolean is_backside = object_mapping[tile].is_backside;
7344 int direction = object_mapping[tile].direction;
7345 int move_dir = (action_falling ? MV_DOWN : direction);
7350 /* !!! TEST !!! NEW !!! DOES NOT WORK RIGHT YET !!! */
7351 if (g->double_movement && frame_em == 0)
7355 if (move_dir == MV_LEFT)
7356 GfxFrame[x - 1][y] = GfxFrame[x][y];
7357 else if (move_dir == MV_RIGHT)
7358 GfxFrame[x + 1][y] = GfxFrame[x][y];
7359 else if (move_dir == MV_UP)
7360 GfxFrame[x][y - 1] = GfxFrame[x][y];
7361 else if (move_dir == MV_DOWN)
7362 GfxFrame[x][y + 1] = GfxFrame[x][y];
7369 /* special case: animation for Xsand_stonesand_quickout_1/2 twice as fast */
7370 if (tile == Xsand_stonesand_quickout_1 ||
7371 tile == Xsand_stonesand_quickout_2)
7375 if (graphic_info[graphic].anim_global_sync)
7376 sync_frame = FrameCounter;
7377 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
7378 sync_frame = GfxFrame[x][y];
7380 sync_frame = 0; /* playfield border (pseudo steel) */
7382 SetRandomAnimationValue(x, y);
7384 int frame = getAnimationFrame(g->anim_frames,
7387 g->anim_start_frame,
7390 g_em->unique_identifier =
7391 (graphic << 16) | ((frame % 8) << 12) | (g_em->width << 6) | g_em->height;
7394 void getGraphicSourceObjectExt_EM(struct GraphicInfo_EM *g_em,
7395 int tile, int frame_em, int x, int y)
7397 int action = object_mapping[tile].action;
7398 int direction = object_mapping[tile].direction;
7399 boolean is_backside = object_mapping[tile].is_backside;
7400 int effective_element = get_effective_element_EM(tile, frame_em);
7401 int effective_action = action;
7402 int graphic = (direction == MV_NONE ?
7403 el_act2img(effective_element, effective_action) :
7404 el_act_dir2img(effective_element, effective_action,
7406 int crumbled = (direction == MV_NONE ?
7407 el_act2crm(effective_element, effective_action) :
7408 el_act_dir2crm(effective_element, effective_action,
7410 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7411 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7412 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7413 struct GraphicInfo *g = &graphic_info[graphic];
7416 /* special case: graphic uses "2nd movement tile" and has defined
7417 7 frames for movement animation (or less) => use default graphic
7418 for last (8th) frame which ends the movement animation */
7419 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
7421 effective_action = ACTION_DEFAULT;
7422 graphic = (direction == MV_NONE ?
7423 el_act2img(effective_element, effective_action) :
7424 el_act_dir2img(effective_element, effective_action,
7426 crumbled = (direction == MV_NONE ?
7427 el_act2crm(effective_element, effective_action) :
7428 el_act_dir2crm(effective_element, effective_action,
7431 g = &graphic_info[graphic];
7434 if (graphic_info[graphic].anim_global_sync)
7435 sync_frame = FrameCounter;
7436 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
7437 sync_frame = GfxFrame[x][y];
7439 sync_frame = 0; /* playfield border (pseudo steel) */
7441 SetRandomAnimationValue(x, y);
7443 int frame = getAnimationFrame(g->anim_frames,
7446 g->anim_start_frame,
7449 getGraphicSourceExt(graphic, frame, &g_em->bitmap, &g_em->src_x, &g_em->src_y,
7450 g->double_movement && is_backside);
7452 /* (updating the "crumbled" graphic definitions is probably not really needed,
7453 as animations for crumbled graphics can't be longer than one EMC cycle) */
7454 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
7458 void getGraphicSourcePlayerExt_EM(struct GraphicInfo_EM *g_em,
7459 int player_nr, int anim, int frame_em)
7461 int element = player_mapping[player_nr][anim].element_rnd;
7462 int action = player_mapping[player_nr][anim].action;
7463 int direction = player_mapping[player_nr][anim].direction;
7464 int graphic = (direction == MV_NONE ?
7465 el_act2img(element, action) :
7466 el_act_dir2img(element, action, direction));
7467 struct GraphicInfo *g = &graphic_info[graphic];
7470 InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
7472 stored_player[player_nr].StepFrame = frame_em;
7474 sync_frame = stored_player[player_nr].Frame;
7476 int frame = getAnimationFrame(g->anim_frames,
7479 g->anim_start_frame,
7482 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
7483 &g_em->src_x, &g_em->src_y, FALSE);
7486 void InitGraphicInfo_EM(void)
7491 int num_em_gfx_errors = 0;
7493 if (graphic_info_em_object[0][0].bitmap == NULL)
7495 /* EM graphics not yet initialized in em_open_all() */
7500 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
7503 /* always start with reliable default values */
7504 for (i = 0; i < TILE_MAX; i++)
7506 object_mapping[i].element_rnd = EL_UNKNOWN;
7507 object_mapping[i].is_backside = FALSE;
7508 object_mapping[i].action = ACTION_DEFAULT;
7509 object_mapping[i].direction = MV_NONE;
7512 /* always start with reliable default values */
7513 for (p = 0; p < MAX_PLAYERS; p++)
7515 for (i = 0; i < SPR_MAX; i++)
7517 player_mapping[p][i].element_rnd = EL_UNKNOWN;
7518 player_mapping[p][i].action = ACTION_DEFAULT;
7519 player_mapping[p][i].direction = MV_NONE;
7523 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
7525 int e = em_object_mapping_list[i].element_em;
7527 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
7528 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
7530 if (em_object_mapping_list[i].action != -1)
7531 object_mapping[e].action = em_object_mapping_list[i].action;
7533 if (em_object_mapping_list[i].direction != -1)
7534 object_mapping[e].direction =
7535 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
7538 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
7540 int a = em_player_mapping_list[i].action_em;
7541 int p = em_player_mapping_list[i].player_nr;
7543 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
7545 if (em_player_mapping_list[i].action != -1)
7546 player_mapping[p][a].action = em_player_mapping_list[i].action;
7548 if (em_player_mapping_list[i].direction != -1)
7549 player_mapping[p][a].direction =
7550 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
7553 for (i = 0; i < TILE_MAX; i++)
7555 int element = object_mapping[i].element_rnd;
7556 int action = object_mapping[i].action;
7557 int direction = object_mapping[i].direction;
7558 boolean is_backside = object_mapping[i].is_backside;
7559 boolean action_exploding = ((action == ACTION_EXPLODING ||
7560 action == ACTION_SMASHED_BY_ROCK ||
7561 action == ACTION_SMASHED_BY_SPRING) &&
7562 element != EL_DIAMOND);
7563 boolean action_active = (action == ACTION_ACTIVE);
7564 boolean action_other = (action == ACTION_OTHER);
7566 for (j = 0; j < 8; j++)
7568 int effective_element = get_effective_element_EM(i, j);
7569 int effective_action = (j < 7 ? action :
7570 i == Xdrip_stretch ? action :
7571 i == Xdrip_stretchB ? action :
7572 i == Ydrip_s1 ? action :
7573 i == Ydrip_s1B ? action :
7574 i == Xball_1B ? action :
7575 i == Xball_2 ? action :
7576 i == Xball_2B ? action :
7577 i == Yball_eat ? action :
7578 i == Ykey_1_eat ? action :
7579 i == Ykey_2_eat ? action :
7580 i == Ykey_3_eat ? action :
7581 i == Ykey_4_eat ? action :
7582 i == Ykey_5_eat ? action :
7583 i == Ykey_6_eat ? action :
7584 i == Ykey_7_eat ? action :
7585 i == Ykey_8_eat ? action :
7586 i == Ylenses_eat ? action :
7587 i == Ymagnify_eat ? action :
7588 i == Ygrass_eat ? action :
7589 i == Ydirt_eat ? action :
7590 i == Xsand_stonein_1 ? action :
7591 i == Xsand_stonein_2 ? action :
7592 i == Xsand_stonein_3 ? action :
7593 i == Xsand_stonein_4 ? action :
7594 i == Xsand_stoneout_1 ? action :
7595 i == Xsand_stoneout_2 ? action :
7596 i == Xboom_android ? ACTION_EXPLODING :
7597 action_exploding ? ACTION_EXPLODING :
7598 action_active ? action :
7599 action_other ? action :
7601 int graphic = (el_act_dir2img(effective_element, effective_action,
7603 int crumbled = (el_act_dir2crm(effective_element, effective_action,
7605 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7606 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7607 boolean has_action_graphics = (graphic != base_graphic);
7608 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7609 struct GraphicInfo *g = &graphic_info[graphic];
7610 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7613 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
7614 boolean special_animation = (action != ACTION_DEFAULT &&
7615 g->anim_frames == 3 &&
7616 g->anim_delay == 2 &&
7617 g->anim_mode & ANIM_LINEAR);
7618 int sync_frame = (i == Xdrip_stretch ? 7 :
7619 i == Xdrip_stretchB ? 7 :
7620 i == Ydrip_s2 ? j + 8 :
7621 i == Ydrip_s2B ? j + 8 :
7630 i == Xfake_acid_1 ? 0 :
7631 i == Xfake_acid_2 ? 10 :
7632 i == Xfake_acid_3 ? 20 :
7633 i == Xfake_acid_4 ? 30 :
7634 i == Xfake_acid_5 ? 40 :
7635 i == Xfake_acid_6 ? 50 :
7636 i == Xfake_acid_7 ? 60 :
7637 i == Xfake_acid_8 ? 70 :
7639 i == Xball_2B ? j + 8 :
7640 i == Yball_eat ? j + 1 :
7641 i == Ykey_1_eat ? j + 1 :
7642 i == Ykey_2_eat ? j + 1 :
7643 i == Ykey_3_eat ? j + 1 :
7644 i == Ykey_4_eat ? j + 1 :
7645 i == Ykey_5_eat ? j + 1 :
7646 i == Ykey_6_eat ? j + 1 :
7647 i == Ykey_7_eat ? j + 1 :
7648 i == Ykey_8_eat ? j + 1 :
7649 i == Ylenses_eat ? j + 1 :
7650 i == Ymagnify_eat ? j + 1 :
7651 i == Ygrass_eat ? j + 1 :
7652 i == Ydirt_eat ? j + 1 :
7653 i == Xamoeba_1 ? 0 :
7654 i == Xamoeba_2 ? 1 :
7655 i == Xamoeba_3 ? 2 :
7656 i == Xamoeba_4 ? 3 :
7657 i == Xamoeba_5 ? 0 :
7658 i == Xamoeba_6 ? 1 :
7659 i == Xamoeba_7 ? 2 :
7660 i == Xamoeba_8 ? 3 :
7661 i == Xexit_2 ? j + 8 :
7662 i == Xexit_3 ? j + 16 :
7663 i == Xdynamite_1 ? 0 :
7664 i == Xdynamite_2 ? 8 :
7665 i == Xdynamite_3 ? 16 :
7666 i == Xdynamite_4 ? 24 :
7667 i == Xsand_stonein_1 ? j + 1 :
7668 i == Xsand_stonein_2 ? j + 9 :
7669 i == Xsand_stonein_3 ? j + 17 :
7670 i == Xsand_stonein_4 ? j + 25 :
7671 i == Xsand_stoneout_1 && j == 0 ? 0 :
7672 i == Xsand_stoneout_1 && j == 1 ? 0 :
7673 i == Xsand_stoneout_1 && j == 2 ? 1 :
7674 i == Xsand_stoneout_1 && j == 3 ? 2 :
7675 i == Xsand_stoneout_1 && j == 4 ? 2 :
7676 i == Xsand_stoneout_1 && j == 5 ? 3 :
7677 i == Xsand_stoneout_1 && j == 6 ? 4 :
7678 i == Xsand_stoneout_1 && j == 7 ? 4 :
7679 i == Xsand_stoneout_2 && j == 0 ? 5 :
7680 i == Xsand_stoneout_2 && j == 1 ? 6 :
7681 i == Xsand_stoneout_2 && j == 2 ? 7 :
7682 i == Xsand_stoneout_2 && j == 3 ? 8 :
7683 i == Xsand_stoneout_2 && j == 4 ? 9 :
7684 i == Xsand_stoneout_2 && j == 5 ? 11 :
7685 i == Xsand_stoneout_2 && j == 6 ? 13 :
7686 i == Xsand_stoneout_2 && j == 7 ? 15 :
7687 i == Xboom_bug && j == 1 ? 2 :
7688 i == Xboom_bug && j == 2 ? 2 :
7689 i == Xboom_bug && j == 3 ? 4 :
7690 i == Xboom_bug && j == 4 ? 4 :
7691 i == Xboom_bug && j == 5 ? 2 :
7692 i == Xboom_bug && j == 6 ? 2 :
7693 i == Xboom_bug && j == 7 ? 0 :
7694 i == Xboom_bomb && j == 1 ? 2 :
7695 i == Xboom_bomb && j == 2 ? 2 :
7696 i == Xboom_bomb && j == 3 ? 4 :
7697 i == Xboom_bomb && j == 4 ? 4 :
7698 i == Xboom_bomb && j == 5 ? 2 :
7699 i == Xboom_bomb && j == 6 ? 2 :
7700 i == Xboom_bomb && j == 7 ? 0 :
7701 i == Xboom_android && j == 7 ? 6 :
7702 i == Xboom_1 && j == 1 ? 2 :
7703 i == Xboom_1 && j == 2 ? 2 :
7704 i == Xboom_1 && j == 3 ? 4 :
7705 i == Xboom_1 && j == 4 ? 4 :
7706 i == Xboom_1 && j == 5 ? 6 :
7707 i == Xboom_1 && j == 6 ? 6 :
7708 i == Xboom_1 && j == 7 ? 8 :
7709 i == Xboom_2 && j == 0 ? 8 :
7710 i == Xboom_2 && j == 1 ? 8 :
7711 i == Xboom_2 && j == 2 ? 10 :
7712 i == Xboom_2 && j == 3 ? 10 :
7713 i == Xboom_2 && j == 4 ? 10 :
7714 i == Xboom_2 && j == 5 ? 12 :
7715 i == Xboom_2 && j == 6 ? 12 :
7716 i == Xboom_2 && j == 7 ? 12 :
7717 special_animation && j == 4 ? 3 :
7718 effective_action != action ? 0 :
7722 Bitmap *debug_bitmap = g_em->bitmap;
7723 int debug_src_x = g_em->src_x;
7724 int debug_src_y = g_em->src_y;
7727 int frame = getAnimationFrame(g->anim_frames,
7730 g->anim_start_frame,
7733 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
7734 g->double_movement && is_backside);
7736 g_em->bitmap = src_bitmap;
7737 g_em->src_x = src_x;
7738 g_em->src_y = src_y;
7739 g_em->src_offset_x = 0;
7740 g_em->src_offset_y = 0;
7741 g_em->dst_offset_x = 0;
7742 g_em->dst_offset_y = 0;
7743 g_em->width = TILEX;
7744 g_em->height = TILEY;
7746 g_em->preserve_background = FALSE;
7748 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
7751 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
7752 effective_action == ACTION_MOVING ||
7753 effective_action == ACTION_PUSHING ||
7754 effective_action == ACTION_EATING)) ||
7755 (!has_action_graphics && (effective_action == ACTION_FILLING ||
7756 effective_action == ACTION_EMPTYING)))
7759 (effective_action == ACTION_FALLING ||
7760 effective_action == ACTION_FILLING ||
7761 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
7762 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
7763 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
7764 int num_steps = (i == Ydrip_s1 ? 16 :
7765 i == Ydrip_s1B ? 16 :
7766 i == Ydrip_s2 ? 16 :
7767 i == Ydrip_s2B ? 16 :
7768 i == Xsand_stonein_1 ? 32 :
7769 i == Xsand_stonein_2 ? 32 :
7770 i == Xsand_stonein_3 ? 32 :
7771 i == Xsand_stonein_4 ? 32 :
7772 i == Xsand_stoneout_1 ? 16 :
7773 i == Xsand_stoneout_2 ? 16 : 8);
7774 int cx = ABS(dx) * (TILEX / num_steps);
7775 int cy = ABS(dy) * (TILEY / num_steps);
7776 int step_frame = (i == Ydrip_s2 ? j + 8 :
7777 i == Ydrip_s2B ? j + 8 :
7778 i == Xsand_stonein_2 ? j + 8 :
7779 i == Xsand_stonein_3 ? j + 16 :
7780 i == Xsand_stonein_4 ? j + 24 :
7781 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
7782 int step = (is_backside ? step_frame : num_steps - step_frame);
7784 if (is_backside) /* tile where movement starts */
7786 if (dx < 0 || dy < 0)
7788 g_em->src_offset_x = cx * step;
7789 g_em->src_offset_y = cy * step;
7793 g_em->dst_offset_x = cx * step;
7794 g_em->dst_offset_y = cy * step;
7797 else /* tile where movement ends */
7799 if (dx < 0 || dy < 0)
7801 g_em->dst_offset_x = cx * step;
7802 g_em->dst_offset_y = cy * step;
7806 g_em->src_offset_x = cx * step;
7807 g_em->src_offset_y = cy * step;
7811 g_em->width = TILEX - cx * step;
7812 g_em->height = TILEY - cy * step;
7815 /* create unique graphic identifier to decide if tile must be redrawn */
7816 /* bit 31 - 16 (16 bit): EM style graphic
7817 bit 15 - 12 ( 4 bit): EM style frame
7818 bit 11 - 6 ( 6 bit): graphic width
7819 bit 5 - 0 ( 6 bit): graphic height */
7820 g_em->unique_identifier =
7821 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
7825 /* skip check for EMC elements not contained in original EMC artwork */
7826 if (element == EL_EMC_FAKE_ACID)
7829 if (g_em->bitmap != debug_bitmap ||
7830 g_em->src_x != debug_src_x ||
7831 g_em->src_y != debug_src_y ||
7832 g_em->src_offset_x != 0 ||
7833 g_em->src_offset_y != 0 ||
7834 g_em->dst_offset_x != 0 ||
7835 g_em->dst_offset_y != 0 ||
7836 g_em->width != TILEX ||
7837 g_em->height != TILEY)
7839 static int last_i = -1;
7847 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
7848 i, element, element_info[element].token_name,
7849 element_action_info[effective_action].suffix, direction);
7851 if (element != effective_element)
7852 printf(" [%d ('%s')]",
7854 element_info[effective_element].token_name);
7858 if (g_em->bitmap != debug_bitmap)
7859 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
7860 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
7862 if (g_em->src_x != debug_src_x ||
7863 g_em->src_y != debug_src_y)
7864 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
7865 j, (is_backside ? 'B' : 'F'),
7866 g_em->src_x, g_em->src_y,
7867 g_em->src_x / 32, g_em->src_y / 32,
7868 debug_src_x, debug_src_y,
7869 debug_src_x / 32, debug_src_y / 32);
7871 if (g_em->src_offset_x != 0 ||
7872 g_em->src_offset_y != 0 ||
7873 g_em->dst_offset_x != 0 ||
7874 g_em->dst_offset_y != 0)
7875 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
7877 g_em->src_offset_x, g_em->src_offset_y,
7878 g_em->dst_offset_x, g_em->dst_offset_y);
7880 if (g_em->width != TILEX ||
7881 g_em->height != TILEY)
7882 printf(" %d (%d): size %d,%d should be %d,%d\n",
7884 g_em->width, g_em->height, TILEX, TILEY);
7886 num_em_gfx_errors++;
7893 for (i = 0; i < TILE_MAX; i++)
7895 for (j = 0; j < 8; j++)
7897 int element = object_mapping[i].element_rnd;
7898 int action = object_mapping[i].action;
7899 int direction = object_mapping[i].direction;
7900 boolean is_backside = object_mapping[i].is_backside;
7901 int graphic_action = el_act_dir2img(element, action, direction);
7902 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
7904 if ((action == ACTION_SMASHED_BY_ROCK ||
7905 action == ACTION_SMASHED_BY_SPRING ||
7906 action == ACTION_EATING) &&
7907 graphic_action == graphic_default)
7909 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
7910 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
7911 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
7912 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
7915 /* no separate animation for "smashed by rock" -- use rock instead */
7916 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7917 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
7919 g_em->bitmap = g_xx->bitmap;
7920 g_em->src_x = g_xx->src_x;
7921 g_em->src_y = g_xx->src_y;
7922 g_em->src_offset_x = g_xx->src_offset_x;
7923 g_em->src_offset_y = g_xx->src_offset_y;
7924 g_em->dst_offset_x = g_xx->dst_offset_x;
7925 g_em->dst_offset_y = g_xx->dst_offset_y;
7926 g_em->width = g_xx->width;
7927 g_em->height = g_xx->height;
7928 g_em->unique_identifier = g_xx->unique_identifier;
7931 g_em->preserve_background = TRUE;
7936 for (p = 0; p < MAX_PLAYERS; p++)
7938 for (i = 0; i < SPR_MAX; i++)
7940 int element = player_mapping[p][i].element_rnd;
7941 int action = player_mapping[p][i].action;
7942 int direction = player_mapping[p][i].direction;
7944 for (j = 0; j < 8; j++)
7946 int effective_element = element;
7947 int effective_action = action;
7948 int graphic = (direction == MV_NONE ?
7949 el_act2img(effective_element, effective_action) :
7950 el_act_dir2img(effective_element, effective_action,
7952 struct GraphicInfo *g = &graphic_info[graphic];
7953 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
7959 Bitmap *debug_bitmap = g_em->bitmap;
7960 int debug_src_x = g_em->src_x;
7961 int debug_src_y = g_em->src_y;
7964 int frame = getAnimationFrame(g->anim_frames,
7967 g->anim_start_frame,
7970 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
7972 g_em->bitmap = src_bitmap;
7973 g_em->src_x = src_x;
7974 g_em->src_y = src_y;
7975 g_em->src_offset_x = 0;
7976 g_em->src_offset_y = 0;
7977 g_em->dst_offset_x = 0;
7978 g_em->dst_offset_y = 0;
7979 g_em->width = TILEX;
7980 g_em->height = TILEY;
7984 /* skip check for EMC elements not contained in original EMC artwork */
7985 if (element == EL_PLAYER_3 ||
7986 element == EL_PLAYER_4)
7989 if (g_em->bitmap != debug_bitmap ||
7990 g_em->src_x != debug_src_x ||
7991 g_em->src_y != debug_src_y)
7993 static int last_i = -1;
8001 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
8002 p, i, element, element_info[element].token_name,
8003 element_action_info[effective_action].suffix, direction);
8005 if (element != effective_element)
8006 printf(" [%d ('%s')]",
8008 element_info[effective_element].token_name);
8012 if (g_em->bitmap != debug_bitmap)
8013 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
8014 j, (int)(g_em->bitmap), (int)(debug_bitmap));
8016 if (g_em->src_x != debug_src_x ||
8017 g_em->src_y != debug_src_y)
8018 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
8020 g_em->src_x, g_em->src_y,
8021 g_em->src_x / 32, g_em->src_y / 32,
8022 debug_src_x, debug_src_y,
8023 debug_src_x / 32, debug_src_y / 32);
8025 num_em_gfx_errors++;
8035 printf("::: [%d errors found]\n", num_em_gfx_errors);
8041 void CheckSaveEngineSnapshot_EM(byte action[MAX_PLAYERS], int frame,
8042 boolean any_player_moving,
8043 boolean any_player_snapping,
8044 boolean any_player_dropping)
8046 static boolean player_was_waiting = TRUE;
8048 if (frame == 0 && !any_player_dropping)
8050 if (!player_was_waiting)
8052 if (!SaveEngineSnapshotToList())
8055 player_was_waiting = TRUE;
8058 else if (any_player_moving || any_player_snapping || any_player_dropping)
8060 player_was_waiting = FALSE;
8064 void CheckSaveEngineSnapshot_SP(boolean murphy_is_waiting,
8065 boolean murphy_is_dropping)
8067 static boolean player_was_waiting = TRUE;
8069 if (murphy_is_waiting)
8071 if (!player_was_waiting)
8073 if (!SaveEngineSnapshotToList())
8076 player_was_waiting = TRUE;
8081 player_was_waiting = FALSE;
8085 void CheckSingleStepMode_EM(byte action[MAX_PLAYERS], int frame,
8086 boolean any_player_moving,
8087 boolean any_player_snapping,
8088 boolean any_player_dropping)
8090 if (tape.single_step && tape.recording && !tape.pausing)
8091 if (frame == 0 && !any_player_dropping)
8092 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
8094 CheckSaveEngineSnapshot_EM(action, frame, any_player_moving,
8095 any_player_snapping, any_player_dropping);
8098 void CheckSingleStepMode_SP(boolean murphy_is_waiting,
8099 boolean murphy_is_dropping)
8101 if (tape.single_step && tape.recording && !tape.pausing)
8102 if (murphy_is_waiting)
8103 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
8105 CheckSaveEngineSnapshot_SP(murphy_is_waiting, murphy_is_dropping);
8108 void getGraphicSource_SP(struct GraphicInfo_SP *g_sp,
8109 int graphic, int sync_frame, int x, int y)
8111 int frame = getGraphicAnimationFrame(graphic, sync_frame);
8113 getGraphicSource(graphic, frame, &g_sp->bitmap, &g_sp->src_x, &g_sp->src_y);
8116 boolean isNextAnimationFrame_SP(int graphic, int sync_frame)
8118 return (IS_NEXT_FRAME(sync_frame, graphic));
8121 int getGraphicInfo_Delay(int graphic)
8123 return graphic_info[graphic].anim_delay;
8126 void PlayMenuSoundExt(int sound)
8128 if (sound == SND_UNDEFINED)
8131 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8132 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8135 if (IS_LOOP_SOUND(sound))
8136 PlaySoundLoop(sound);
8141 void PlayMenuSound()
8143 PlayMenuSoundExt(menu.sound[game_status]);
8146 void PlayMenuSoundStereo(int sound, int stereo_position)
8148 if (sound == SND_UNDEFINED)
8151 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8152 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8155 if (IS_LOOP_SOUND(sound))
8156 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
8158 PlaySoundStereo(sound, stereo_position);
8161 void PlayMenuSoundIfLoopExt(int sound)
8163 if (sound == SND_UNDEFINED)
8166 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8167 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8170 if (IS_LOOP_SOUND(sound))
8171 PlaySoundLoop(sound);
8174 void PlayMenuSoundIfLoop()
8176 PlayMenuSoundIfLoopExt(menu.sound[game_status]);
8179 void PlayMenuMusicExt(int music)
8181 if (music == MUS_UNDEFINED)
8184 if (!setup.sound_music)
8190 void PlayMenuMusic()
8192 PlayMenuMusicExt(menu.music[game_status]);
8195 void PlaySoundActivating()
8198 PlaySound(SND_MENU_ITEM_ACTIVATING);
8202 void PlaySoundSelecting()
8205 PlaySound(SND_MENU_ITEM_SELECTING);
8209 void ToggleFullscreenOrChangeWindowScalingIfNeeded()
8211 boolean change_fullscreen = (setup.fullscreen !=
8212 video.fullscreen_enabled);
8213 boolean change_window_scaling_percent = (!video.fullscreen_enabled &&
8214 setup.window_scaling_percent !=
8215 video.window_scaling_percent);
8217 if (change_window_scaling_percent && video.fullscreen_enabled)
8220 if (!change_window_scaling_percent && !video.fullscreen_available)
8223 #if defined(TARGET_SDL2)
8224 if (change_window_scaling_percent)
8226 SDLSetWindowScaling(setup.window_scaling_percent);
8230 else if (change_fullscreen)
8232 SDLSetWindowFullscreen(setup.fullscreen);
8234 /* set setup value according to successfully changed fullscreen mode */
8235 setup.fullscreen = video.fullscreen_enabled;
8241 if (change_fullscreen ||
8242 change_window_scaling_percent)
8244 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
8246 /* save backbuffer content which gets lost when toggling fullscreen mode */
8247 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8249 if (change_window_scaling_percent)
8251 /* keep window mode, but change window scaling */
8252 video.fullscreen_enabled = TRUE; /* force new window scaling */
8255 /* toggle fullscreen */
8256 ChangeVideoModeIfNeeded(setup.fullscreen);
8258 /* set setup value according to successfully changed fullscreen mode */
8259 setup.fullscreen = video.fullscreen_enabled;
8261 /* restore backbuffer content from temporary backbuffer backup bitmap */
8262 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8264 FreeBitmap(tmp_backbuffer);
8266 /* update visible window/screen */
8267 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8271 void JoinRectangles(int *x, int *y, int *width, int *height,
8272 int x2, int y2, int width2, int height2)
8274 // do not join with "off-screen" rectangle
8275 if (x2 == -1 || y2 == -1)
8280 *width = MAX(*width, width2);
8281 *height = MAX(*height, height2);
8284 void SetAnimStatus(int anim_status_new)
8286 if (anim_status_new == GAME_MODE_MAIN)
8287 anim_status_new = GAME_MODE_PSEUDO_MAINONLY;
8289 global.anim_status_next = anim_status_new;
8291 // directly set screen modes that are entered without fading
8292 if ((global.anim_status == GAME_MODE_PSEUDO_MAINONLY &&
8293 global.anim_status_next == GAME_MODE_PSEUDO_TYPENAME) ||
8294 (global.anim_status == GAME_MODE_PSEUDO_TYPENAME &&
8295 global.anim_status_next == GAME_MODE_PSEUDO_MAINONLY))
8296 global.anim_status = global.anim_status_next;
8299 void SetGameStatus(int game_status_new)
8301 game_status = game_status_new;
8303 SetAnimStatus(game_status_new);
8306 void SetFontStatus(int game_status_new)
8308 static int last_game_status = -1;
8310 if (game_status_new != -1)
8312 // set game status for font use after storing last game status
8313 last_game_status = game_status;
8314 game_status = game_status_new;
8318 // reset game status after font use from last stored game status
8319 game_status = last_game_status;
8323 void ResetFontStatus()
8328 void ChangeViewportPropertiesIfNeeded()
8330 int gfx_game_mode = game_status;
8331 int gfx_game_mode2 = (game_status == GAME_MODE_EDITOR ? GAME_MODE_DEFAULT :
8333 struct RectWithBorder *vp_window = &viewport.window[gfx_game_mode];
8334 struct RectWithBorder *vp_playfield = &viewport.playfield[gfx_game_mode];
8335 struct RectWithBorder *vp_door_1 = &viewport.door_1[gfx_game_mode];
8336 struct RectWithBorder *vp_door_2 = &viewport.door_2[gfx_game_mode2];
8337 struct RectWithBorder *vp_door_3 = &viewport.door_2[GAME_MODE_EDITOR];
8338 int new_win_xsize = vp_window->width;
8339 int new_win_ysize = vp_window->height;
8340 int border_size = vp_playfield->border_size;
8341 int new_sx = vp_playfield->x + border_size;
8342 int new_sy = vp_playfield->y + border_size;
8343 int new_sxsize = vp_playfield->width - 2 * border_size;
8344 int new_sysize = vp_playfield->height - 2 * border_size;
8345 int new_real_sx = vp_playfield->x;
8346 int new_real_sy = vp_playfield->y;
8347 int new_full_sxsize = vp_playfield->width;
8348 int new_full_sysize = vp_playfield->height;
8349 int new_dx = vp_door_1->x;
8350 int new_dy = vp_door_1->y;
8351 int new_dxsize = vp_door_1->width;
8352 int new_dysize = vp_door_1->height;
8353 int new_vx = vp_door_2->x;
8354 int new_vy = vp_door_2->y;
8355 int new_vxsize = vp_door_2->width;
8356 int new_vysize = vp_door_2->height;
8357 int new_ex = vp_door_3->x;
8358 int new_ey = vp_door_3->y;
8359 int new_exsize = vp_door_3->width;
8360 int new_eysize = vp_door_3->height;
8361 int new_tilesize_var =
8362 (setup.small_game_graphics ? MINI_TILESIZE : game.tile_size);
8364 int tilesize = (gfx_game_mode == GAME_MODE_PLAYING ? new_tilesize_var :
8365 gfx_game_mode == GAME_MODE_EDITOR ? MINI_TILESIZE : TILESIZE);
8366 int new_scr_fieldx = new_sxsize / tilesize;
8367 int new_scr_fieldy = new_sysize / tilesize;
8368 int new_scr_fieldx_buffers = new_sxsize / new_tilesize_var;
8369 int new_scr_fieldy_buffers = new_sysize / new_tilesize_var;
8370 boolean init_gfx_buffers = FALSE;
8371 boolean init_video_buffer = FALSE;
8372 boolean init_gadgets_and_toons = FALSE;
8373 boolean init_em_graphics = FALSE;
8375 if (new_win_xsize != WIN_XSIZE ||
8376 new_win_ysize != WIN_YSIZE)
8378 WIN_XSIZE = new_win_xsize;
8379 WIN_YSIZE = new_win_ysize;
8381 init_video_buffer = TRUE;
8382 init_gfx_buffers = TRUE;
8383 init_gadgets_and_toons = TRUE;
8385 // printf("::: video: init_video_buffer, init_gfx_buffers\n");
8388 if (new_scr_fieldx != SCR_FIELDX ||
8389 new_scr_fieldy != SCR_FIELDY)
8391 /* this always toggles between MAIN and GAME when using small tile size */
8393 SCR_FIELDX = new_scr_fieldx;
8394 SCR_FIELDY = new_scr_fieldy;
8396 // printf("::: new_scr_fieldx != SCR_FIELDX ...\n");
8407 new_sxsize != SXSIZE ||
8408 new_sysize != SYSIZE ||
8409 new_dxsize != DXSIZE ||
8410 new_dysize != DYSIZE ||
8411 new_vxsize != VXSIZE ||
8412 new_vysize != VYSIZE ||
8413 new_exsize != EXSIZE ||
8414 new_eysize != EYSIZE ||
8415 new_real_sx != REAL_SX ||
8416 new_real_sy != REAL_SY ||
8417 new_full_sxsize != FULL_SXSIZE ||
8418 new_full_sysize != FULL_SYSIZE ||
8419 new_tilesize_var != TILESIZE_VAR
8422 // ------------------------------------------------------------------------
8423 // determine next fading area for changed viewport definitions
8424 // ------------------------------------------------------------------------
8426 // start with current playfield area (default fading area)
8429 FADE_SXSIZE = FULL_SXSIZE;
8430 FADE_SYSIZE = FULL_SYSIZE;
8432 // add new playfield area if position or size has changed
8433 if (new_real_sx != REAL_SX || new_real_sy != REAL_SY ||
8434 new_full_sxsize != FULL_SXSIZE || new_full_sysize != FULL_SYSIZE)
8436 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
8437 new_real_sx, new_real_sy, new_full_sxsize,new_full_sysize);
8440 // add current and new door 1 area if position or size has changed
8441 if (new_dx != DX || new_dy != DY ||
8442 new_dxsize != DXSIZE || new_dysize != DYSIZE)
8444 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
8445 DX, DY, DXSIZE, DYSIZE);
8446 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
8447 new_dx, new_dy, new_dxsize, new_dysize);
8450 // add current and new door 2 area if position or size has changed
8451 if (new_dx != VX || new_dy != VY ||
8452 new_dxsize != VXSIZE || new_dysize != VYSIZE)
8454 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
8455 VX, VY, VXSIZE, VYSIZE);
8456 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
8457 new_vx, new_vy, new_vxsize, new_vysize);
8460 // ------------------------------------------------------------------------
8461 // handle changed tile size
8462 // ------------------------------------------------------------------------
8464 if (new_tilesize_var != TILESIZE_VAR)
8466 // printf("::: new_tilesize_var != TILESIZE_VAR\n");
8468 // changing tile size invalidates scroll values of engine snapshots
8469 FreeEngineSnapshotSingle();
8471 // changing tile size requires update of graphic mapping for EM engine
8472 init_em_graphics = TRUE;
8483 SXSIZE = new_sxsize;
8484 SYSIZE = new_sysize;
8485 DXSIZE = new_dxsize;
8486 DYSIZE = new_dysize;
8487 VXSIZE = new_vxsize;
8488 VYSIZE = new_vysize;
8489 EXSIZE = new_exsize;
8490 EYSIZE = new_eysize;
8491 REAL_SX = new_real_sx;
8492 REAL_SY = new_real_sy;
8493 FULL_SXSIZE = new_full_sxsize;
8494 FULL_SYSIZE = new_full_sysize;
8495 TILESIZE_VAR = new_tilesize_var;
8497 init_gfx_buffers = TRUE;
8498 init_gadgets_and_toons = TRUE;
8500 // printf("::: viewports: init_gfx_buffers\n");
8501 // printf("::: viewports: init_gadgets_and_toons\n");
8504 if (init_gfx_buffers)
8506 // printf("::: init_gfx_buffers\n");
8508 SCR_FIELDX = new_scr_fieldx_buffers;
8509 SCR_FIELDY = new_scr_fieldy_buffers;
8513 SCR_FIELDX = new_scr_fieldx;
8514 SCR_FIELDY = new_scr_fieldy;
8516 SetDrawDeactivationMask(REDRAW_NONE);
8517 SetDrawBackgroundMask(REDRAW_FIELD);
8520 if (init_video_buffer)
8522 // printf("::: init_video_buffer\n");
8524 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
8525 InitImageTextures();
8528 if (init_gadgets_and_toons)
8530 // printf("::: init_gadgets_and_toons\n");
8534 InitGlobalAnimations();
8537 if (init_em_graphics)
8539 InitGraphicInfo_EM();