1 // ============================================================================
2 // Rocks'n'Diamonds - McDuffin Strikes Back!
3 // ----------------------------------------------------------------------------
4 // (c) 1995-2014 by Artsoft Entertainment
7 // http://www.artsoft.org/
8 // ----------------------------------------------------------------------------
10 // ============================================================================
14 #include "libgame/libgame.h"
26 /* select level set with EMC X11 graphics before activating EM GFX debugging */
27 #define DEBUG_EM_GFX FALSE
28 #define DEBUG_FRAME_TIME FALSE
30 /* tool button identifiers */
31 #define TOOL_CTRL_ID_YES 0
32 #define TOOL_CTRL_ID_NO 1
33 #define TOOL_CTRL_ID_CONFIRM 2
34 #define TOOL_CTRL_ID_PLAYER_1 3
35 #define TOOL_CTRL_ID_PLAYER_2 4
36 #define TOOL_CTRL_ID_PLAYER_3 5
37 #define TOOL_CTRL_ID_PLAYER_4 6
39 #define NUM_TOOL_BUTTONS 7
41 /* constants for number of doors and door parts */
43 #define NUM_PANELS NUM_DOORS
44 // #define NUM_PANELS 0
45 #define MAX_PARTS_PER_DOOR 8
46 #define MAX_DOOR_PARTS (NUM_DOORS * MAX_PARTS_PER_DOOR + NUM_PANELS)
47 #define DOOR_PART_IS_PANEL(i) ((i) >= NUM_DOORS * MAX_PARTS_PER_DOOR)
50 struct DoorPartOrderInfo
56 static struct DoorPartOrderInfo door_part_order[MAX_DOOR_PARTS];
58 struct DoorPartControlInfo
62 struct DoorPartPosInfo *pos;
65 static struct DoorPartControlInfo door_part_controls[] =
69 IMG_GFX_DOOR_1_PART_1,
74 IMG_GFX_DOOR_1_PART_2,
79 IMG_GFX_DOOR_1_PART_3,
84 IMG_GFX_DOOR_1_PART_4,
89 IMG_GFX_DOOR_1_PART_5,
94 IMG_GFX_DOOR_1_PART_6,
99 IMG_GFX_DOOR_1_PART_7,
104 IMG_GFX_DOOR_1_PART_8,
110 IMG_GFX_DOOR_2_PART_1,
115 IMG_GFX_DOOR_2_PART_2,
120 IMG_GFX_DOOR_2_PART_3,
125 IMG_GFX_DOOR_2_PART_4,
130 IMG_GFX_DOOR_2_PART_5,
135 IMG_GFX_DOOR_2_PART_6,
140 IMG_GFX_DOOR_2_PART_7,
145 IMG_GFX_DOOR_2_PART_8,
151 IMG_BACKGROUND_PANEL,
168 /* forward declaration for internal use */
169 static void UnmapToolButtons();
170 static void HandleToolButtons(struct GadgetInfo *);
171 static int el_act_dir2crm(int, int, int);
172 static int el_act2crm(int, int);
174 static struct GadgetInfo *tool_gadget[NUM_TOOL_BUTTONS];
175 static int request_gadget_id = -1;
177 static char *print_if_not_empty(int element)
179 static char *s = NULL;
180 char *token_name = element_info[element].token_name;
185 s = checked_malloc(strlen(token_name) + 10 + 1);
187 if (element != EL_EMPTY)
188 sprintf(s, "%d\t['%s']", element, token_name);
190 sprintf(s, "%d", element);
195 void DumpTile(int x, int y)
200 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
206 printf_line("-", 79);
207 printf("Field Info: SCREEN(%d, %d), LEVEL(%d, %d)\n", sx, sy, x, y);
208 printf_line("-", 79);
210 if (!IN_LEV_FIELD(x, y))
212 printf("(not in level field)\n");
218 printf(" Feld: %d\t['%s']\n", Feld[x][y],
219 element_info[Feld[x][y]].token_name);
220 printf(" Back: %s\n", print_if_not_empty(Back[x][y]));
221 printf(" Store: %s\n", print_if_not_empty(Store[x][y]));
222 printf(" Store2: %s\n", print_if_not_empty(Store2[x][y]));
223 printf(" StorePlayer: %s\n", print_if_not_empty(StorePlayer[x][y]));
224 printf(" MovPos: %d\n", MovPos[x][y]);
225 printf(" MovDir: %d\n", MovDir[x][y]);
226 printf(" MovDelay: %d\n", MovDelay[x][y]);
227 printf(" ChangeDelay: %d\n", ChangeDelay[x][y]);
228 printf(" CustomValue: %d\n", CustomValue[x][y]);
229 printf(" GfxElement: %d\n", GfxElement[x][y]);
230 printf(" GfxAction: %d\n", GfxAction[x][y]);
231 printf(" GfxFrame: %d [%d]\n", GfxFrame[x][y], FrameCounter);
235 void SetDrawtoField(int mode)
237 if (mode == DRAW_TO_FIELDBUFFER)
243 BX2 = SCR_FIELDX + 1;
244 BY2 = SCR_FIELDY + 1;
246 drawto_field = fieldbuffer;
248 else /* DRAW_TO_BACKBUFFER */
254 BX2 = SCR_FIELDX - 1;
255 BY2 = SCR_FIELDY - 1;
257 drawto_field = backbuffer;
261 static void RedrawPlayfield_RND()
263 if (game.envelope_active)
266 DrawLevel(REDRAW_ALL);
270 void RedrawPlayfield()
272 if (game_status != GAME_MODE_PLAYING)
275 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
276 RedrawPlayfield_EM(TRUE);
277 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
278 RedrawPlayfield_SP(TRUE);
279 else if (level.game_engine_type == GAME_ENGINE_TYPE_RND)
280 RedrawPlayfield_RND();
282 BlitScreenToBitmap(backbuffer);
284 BlitBitmap(drawto, window, gfx.sx, gfx.sy, gfx.sxsize, gfx.sysize,
288 static void DrawMaskedBorderExt_Rect(int x, int y, int width, int height,
291 Bitmap *src_bitmap = getGlobalBorderBitmapFromStatus(global.border_status);
292 Bitmap *dst_bitmap = gfx.masked_border_bitmap_ptr;
294 if (x == -1 && y == -1)
297 if (draw_target == DRAW_TO_SCREEN)
298 BlitToScreenMasked(src_bitmap, x, y, width, height, x, y);
300 BlitBitmapMasked(src_bitmap, dst_bitmap, x, y, width, height, x, y);
303 static void DrawMaskedBorderExt_FIELD(int draw_target)
305 if (global.border_status >= GAME_MODE_MAIN &&
306 global.border_status <= GAME_MODE_PLAYING &&
307 border.draw_masked[global.border_status])
308 DrawMaskedBorderExt_Rect(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
312 static void DrawMaskedBorderExt_DOOR_1(int draw_target)
314 // when drawing to backbuffer, never draw border over open doors
315 if (draw_target == DRAW_TO_BACKBUFFER &&
316 (GetDoorState() & DOOR_OPEN_1))
319 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
320 (global.border_status != GAME_MODE_EDITOR ||
321 border.draw_masked[GFX_SPECIAL_ARG_EDITOR]))
322 DrawMaskedBorderExt_Rect(DX, DY, DXSIZE, DYSIZE, draw_target);
325 static void DrawMaskedBorderExt_DOOR_2(int draw_target)
327 // when drawing to backbuffer, never draw border over open doors
328 if (draw_target == DRAW_TO_BACKBUFFER &&
329 (GetDoorState() & DOOR_OPEN_2))
332 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
333 global.border_status != GAME_MODE_EDITOR)
334 DrawMaskedBorderExt_Rect(VX, VY, VXSIZE, VYSIZE, draw_target);
337 static void DrawMaskedBorderExt_DOOR_3(int draw_target)
339 /* currently not available */
342 static void DrawMaskedBorderExt_ALL(int draw_target)
344 DrawMaskedBorderExt_FIELD(draw_target);
345 DrawMaskedBorderExt_DOOR_1(draw_target);
346 DrawMaskedBorderExt_DOOR_2(draw_target);
347 DrawMaskedBorderExt_DOOR_3(draw_target);
350 static void DrawMaskedBorderExt(int redraw_mask, int draw_target)
352 /* never draw masked screen borders on borderless screens */
353 if (global.border_status == GAME_MODE_LOADING ||
354 global.border_status == GAME_MODE_TITLE)
357 if (redraw_mask & REDRAW_ALL)
358 DrawMaskedBorderExt_ALL(draw_target);
361 if (redraw_mask & REDRAW_FIELD)
362 DrawMaskedBorderExt_FIELD(draw_target);
363 if (redraw_mask & REDRAW_DOOR_1)
364 DrawMaskedBorderExt_DOOR_1(draw_target);
365 if (redraw_mask & REDRAW_DOOR_2)
366 DrawMaskedBorderExt_DOOR_2(draw_target);
367 if (redraw_mask & REDRAW_DOOR_3)
368 DrawMaskedBorderExt_DOOR_3(draw_target);
372 void DrawMaskedBorder_FIELD()
374 DrawMaskedBorderExt_FIELD(DRAW_TO_BACKBUFFER);
377 void DrawMaskedBorder(int redraw_mask)
379 DrawMaskedBorderExt(redraw_mask, DRAW_TO_BACKBUFFER);
382 void DrawMaskedBorderToTarget(int draw_target)
384 if (draw_target == DRAW_TO_BACKBUFFER ||
385 draw_target == DRAW_TO_SCREEN)
387 DrawMaskedBorderExt(REDRAW_ALL, draw_target);
391 int last_border_status = global.border_status;
393 if (draw_target == DRAW_TO_FADE_SOURCE)
395 global.border_status = gfx.fade_border_source_status;
396 gfx.masked_border_bitmap_ptr = gfx.fade_bitmap_source;
398 else if (draw_target == DRAW_TO_FADE_TARGET)
400 global.border_status = gfx.fade_border_target_status;
401 gfx.masked_border_bitmap_ptr = gfx.fade_bitmap_target;
404 DrawMaskedBorderExt(REDRAW_ALL, draw_target);
406 global.border_status = last_border_status;
407 gfx.masked_border_bitmap_ptr = backbuffer;
411 void BlitScreenToBitmap_RND(Bitmap *target_bitmap)
413 int fx = FX, fy = FY;
414 int full_lev_fieldx = lev_fieldx + (BorderElement != EL_EMPTY ? 2 : 0);
415 int full_lev_fieldy = lev_fieldy + (BorderElement != EL_EMPTY ? 2 : 0);
417 int dx = (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
418 int dy = (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
419 int dx_var = dx * TILESIZE_VAR / TILESIZE;
420 int dy_var = dy * TILESIZE_VAR / TILESIZE;
423 ffx = (scroll_x - SBX_Left) * TILEX_VAR + dx_var;
424 ffy = (scroll_y - SBY_Upper) * TILEY_VAR + dy_var;
426 if (EVEN(SCR_FIELDX))
428 if (ffx < SBX_Right * TILEX_VAR + TILEX_VAR / 2 + TILEX_VAR)
429 fx += dx_var - MIN(ffx, TILEX_VAR / 2) + TILEX_VAR;
431 fx += (dx_var > 0 ? TILEX_VAR : 0);
438 if (EVEN(SCR_FIELDY))
440 if (ffy < SBY_Lower * TILEY_VAR + TILEY_VAR / 2 + TILEY_VAR)
441 fy += dy_var - MIN(ffy, TILEY_VAR / 2) + TILEY_VAR;
443 fy += (dy_var > 0 ? TILEY_VAR : 0);
450 if (full_lev_fieldx <= SCR_FIELDX)
452 if (EVEN(SCR_FIELDX))
453 fx = 2 * TILEX_VAR - (ODD(lev_fieldx) ? TILEX_VAR / 2 : 0);
455 fx = 2 * TILEX_VAR - (EVEN(lev_fieldx) ? TILEX_VAR / 2 : 0);
458 if (full_lev_fieldy <= SCR_FIELDY)
460 if (EVEN(SCR_FIELDY))
461 fy = 2 * TILEY_VAR - (ODD(lev_fieldy) ? TILEY_VAR / 2 : 0);
463 fy = 2 * TILEY_VAR - (EVEN(lev_fieldy) ? TILEY_VAR / 2 : 0);
466 BlitBitmap(drawto_field, target_bitmap, fx, fy, SXSIZE, SYSIZE, SX, SY);
469 void BlitScreenToBitmap(Bitmap *target_bitmap)
471 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
472 BlitScreenToBitmap_EM(target_bitmap);
473 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
474 BlitScreenToBitmap_SP(target_bitmap);
475 else if (level.game_engine_type == GAME_ENGINE_TYPE_RND)
476 BlitScreenToBitmap_RND(target_bitmap);
478 redraw_mask |= REDRAW_FIELD;
481 void DrawFramesPerSecond()
484 int font_nr = FONT_TEXT_2;
485 int font_width = getFontWidth(font_nr);
487 sprintf(text, "%04.1f fps", global.frames_per_second);
489 DrawTextExt(backbuffer, WIN_XSIZE - font_width * strlen(text), 0, text,
490 font_nr, BLIT_OPAQUE);
494 static void PrintFrameTimeDebugging()
496 static unsigned int last_counter = 0;
497 unsigned int counter = Counter();
498 int diff_1 = counter - last_counter;
499 int diff_2 = diff_1 - GAME_FRAME_DELAY;
501 int diff_2_cut = MIN(ABS(diff_2), diff_2_max);
502 char diff_bar[2 * diff_2_max + 5];
506 diff_bar[pos++] = (diff_2 < -diff_2_max ? '<' : ' ');
508 for (i = 0; i < diff_2_max; i++)
509 diff_bar[pos++] = (diff_2 >= 0 ? ' ' :
510 i >= diff_2_max - diff_2_cut ? '-' : ' ');
512 diff_bar[pos++] = '|';
514 for (i = 0; i < diff_2_max; i++)
515 diff_bar[pos++] = (diff_2 <= 0 ? ' ' : i < diff_2_cut ? '+' : ' ');
517 diff_bar[pos++] = (diff_2 > diff_2_max ? '>' : ' ');
519 diff_bar[pos++] = '\0';
521 Error(ERR_INFO, "%06d [%02d] [%c%02d] %s",
524 (diff_2 < 0 ? '-' : diff_2 > 0 ? '+' : ' '), ABS(diff_2),
527 last_counter = counter;
533 static int last_redraw_mask = REDRAW_NONE;
535 // force screen redraw in every frame to continue drawing global animations
536 // (but always use the last redraw mask to prevent unwanted side effects)
537 if (redraw_mask == REDRAW_NONE)
538 redraw_mask = last_redraw_mask;
540 last_redraw_mask = redraw_mask;
543 // masked border now drawn immediately when blitting backbuffer to window
545 // draw masked border to all viewports, if defined
546 DrawMaskedBorder(redraw_mask);
549 // draw frames per second (only if debug mode is enabled)
550 if (redraw_mask & REDRAW_FPS)
551 DrawFramesPerSecond();
553 // redraw complete window if both playfield and (some) doors need redraw
554 if (redraw_mask & REDRAW_FIELD && redraw_mask & REDRAW_DOORS)
555 redraw_mask = REDRAW_ALL;
557 /* although redrawing the whole window would be fine for normal gameplay,
558 being able to only redraw the playfield is required for deactivating
559 certain drawing areas (mainly playfield) to work, which is needed for
560 warp-forward to be fast enough (by skipping redraw of most frames) */
562 if (redraw_mask & REDRAW_ALL)
564 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
566 else if (redraw_mask & REDRAW_FIELD)
568 BlitBitmap(backbuffer, window,
569 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
571 else if (redraw_mask & REDRAW_DOORS)
573 if (redraw_mask & REDRAW_DOOR_1)
574 BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
576 if (redraw_mask & REDRAW_DOOR_2)
577 BlitBitmap(backbuffer, window, VX, VY, VXSIZE, VYSIZE, VX, VY);
579 if (redraw_mask & REDRAW_DOOR_3)
580 BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
583 redraw_mask = REDRAW_NONE;
586 PrintFrameTimeDebugging();
590 void BackToFront_WithFrameDelay(unsigned int frame_delay_value)
592 unsigned int frame_delay_value_old = GetVideoFrameDelay();
594 SetVideoFrameDelay(frame_delay_value);
598 SetVideoFrameDelay(frame_delay_value_old);
601 static void FadeCrossSaveBackbuffer()
603 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
606 static void FadeCrossRestoreBackbuffer()
608 int redraw_mask_last = redraw_mask;
610 BlitBitmap(bitmap_db_cross, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
612 // do not change redraw mask when restoring backbuffer after cross-fading
613 redraw_mask = redraw_mask_last;
616 static void FadeExt(int fade_mask, int fade_mode, int fade_type)
618 static int fade_type_skip = FADE_TYPE_NONE;
619 void (*draw_border_function)(void) = NULL;
620 Bitmap *bitmap = (fade_mode & FADE_TYPE_TRANSFORM ? bitmap_db_cross : NULL);
621 int x, y, width, height;
622 int fade_delay, post_delay;
624 if (fade_type == FADE_TYPE_FADE_OUT)
626 if (fade_type_skip != FADE_TYPE_NONE)
628 /* skip all fade operations until specified fade operation */
629 if (fade_type & fade_type_skip)
630 fade_type_skip = FADE_TYPE_NONE;
636 FadeCrossSaveBackbuffer();
639 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
642 FadeCrossSaveBackbuffer();
649 redraw_mask |= fade_mask;
651 if (fade_type == FADE_TYPE_SKIP)
653 fade_type_skip = fade_mode;
658 fade_delay = fading.fade_delay;
659 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
661 if (fade_type_skip != FADE_TYPE_NONE)
663 /* skip all fade operations until specified fade operation */
664 if (fade_type & fade_type_skip)
665 fade_type_skip = FADE_TYPE_NONE;
670 if (global.autoplay_leveldir)
675 if (fade_mask == REDRAW_FIELD)
680 height = FADE_SYSIZE;
682 if (border.draw_masked_when_fading)
683 draw_border_function = DrawMaskedBorder_FIELD; /* update when fading */
685 DrawMaskedBorder_FIELD(); /* draw once */
687 else /* REDRAW_ALL */
695 if (!setup.fade_screens ||
697 fading.fade_mode == FADE_MODE_NONE)
699 if (fade_mode == FADE_MODE_FADE_OUT)
702 BlitBitmap(backbuffer, window, x, y, width, height, x, y);
704 redraw_mask &= ~fade_mask;
709 FadeRectangle(bitmap, x, y, width, height, fade_mode, fade_delay, post_delay,
710 draw_border_function);
712 if (fade_type == FADE_TYPE_FADE_OUT)
713 FadeCrossRestoreBackbuffer();
715 redraw_mask &= ~fade_mask;
718 static void SetScreenStates_BeforeFadingIn()
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_TO_FIELDBUFFER);
1110 SetDrawtoField(DRAW_TO_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_TO_FIELDBUFFER);
2305 BlitScreenToBitmap(backbuffer);
2307 SetDrawtoField(DRAW_TO_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_TO_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;
2605 SkipUntilDelayReached(&anim_delay, anim_delay_value, &i, last_frame);
2609 void ShowEnvelopeRequest(char *text, unsigned int req_state, int action)
2611 int graphic = IMG_BACKGROUND_REQUEST;
2612 int sound_opening = SND_REQUEST_OPENING;
2613 int sound_closing = SND_REQUEST_CLOSING;
2614 int anim_mode_1 = request.anim_mode; /* (higher priority) */
2615 int anim_mode_2 = graphic_info[graphic].anim_mode; /* (lower priority) */
2616 int anim_mode = (anim_mode_1 != ANIM_DEFAULT ? anim_mode_1 : anim_mode_2);
2617 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2618 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2620 if (game_status == GAME_MODE_PLAYING)
2621 BlitScreenToBitmap(backbuffer);
2623 SetDrawtoField(DRAW_TO_BACKBUFFER);
2625 // SetDrawBackgroundMask(REDRAW_NONE);
2627 if (action == ACTION_OPENING)
2629 BlitBitmap(backbuffer, bitmap_db_store, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2631 if (req_state & REQ_ASK)
2633 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2634 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2636 else if (req_state & REQ_CONFIRM)
2638 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2640 else if (req_state & REQ_PLAYER)
2642 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2643 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2644 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2645 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2648 DrawEnvelopeRequest(text);
2651 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
2653 if (action == ACTION_OPENING)
2655 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2657 if (anim_mode == ANIM_DEFAULT)
2658 AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_OPENING);
2660 AnimateEnvelopeRequest(main_anim_mode, ACTION_OPENING);
2664 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2666 if (anim_mode != ANIM_NONE)
2667 AnimateEnvelopeRequest(main_anim_mode, ACTION_CLOSING);
2669 if (anim_mode == ANIM_DEFAULT)
2670 AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_CLOSING);
2673 game.envelope_active = FALSE;
2675 if (action == ACTION_CLOSING)
2676 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2678 // SetDrawBackgroundMask(last_draw_background_mask);
2680 redraw_mask |= REDRAW_FIELD;
2684 if (action == ACTION_CLOSING &&
2685 game_status == GAME_MODE_PLAYING &&
2686 level.game_engine_type == GAME_ENGINE_TYPE_RND)
2687 SetDrawtoField(DRAW_TO_FIELDBUFFER);
2690 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
2694 int graphic = el2preimg(element);
2696 getSizedGraphicSource(graphic, 0, tilesize, &src_bitmap, &src_x, &src_y);
2697 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
2700 void DrawLevel(int draw_background_mask)
2704 SetMainBackgroundImage(IMG_BACKGROUND_PLAYING);
2705 SetDrawBackgroundMask(draw_background_mask);
2709 for (x = BX1; x <= BX2; x++)
2710 for (y = BY1; y <= BY2; y++)
2711 DrawScreenField(x, y);
2713 redraw_mask |= REDRAW_FIELD;
2716 void DrawSizedLevel(int size_x, int size_y, int scroll_x, int scroll_y,
2721 for (x = 0; x < size_x; x++)
2722 for (y = 0; y < size_y; y++)
2723 DrawSizedElementOrWall(x, y, scroll_x, scroll_y, tilesize);
2725 redraw_mask |= REDRAW_FIELD;
2728 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
2732 for (x = 0; x < size_x; x++)
2733 for (y = 0; y < size_y; y++)
2734 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
2736 redraw_mask |= REDRAW_FIELD;
2739 static void DrawPreviewLevelPlayfieldExt(int from_x, int from_y)
2741 boolean show_level_border = (BorderElement != EL_EMPTY);
2742 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2743 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2744 int tile_size = preview.tile_size;
2745 int preview_width = preview.xsize * tile_size;
2746 int preview_height = preview.ysize * tile_size;
2747 int real_preview_xsize = MIN(level_xsize, preview.xsize);
2748 int real_preview_ysize = MIN(level_ysize, preview.ysize);
2749 int real_preview_width = real_preview_xsize * tile_size;
2750 int real_preview_height = real_preview_ysize * tile_size;
2751 int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
2752 int dst_y = SY + ALIGNED_YPOS(preview.y, preview_height, preview.valign);
2755 if (!IN_GFX_FIELD_FULL(dst_x, dst_y + preview_height - 1))
2758 DrawBackground(dst_x, dst_y, preview_width, preview_height);
2760 dst_x += (preview_width - real_preview_width) / 2;
2761 dst_y += (preview_height - real_preview_height) / 2;
2763 for (x = 0; x < real_preview_xsize; x++)
2765 for (y = 0; y < real_preview_ysize; y++)
2767 int lx = from_x + x + (show_level_border ? -1 : 0);
2768 int ly = from_y + y + (show_level_border ? -1 : 0);
2769 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
2770 getBorderElement(lx, ly));
2772 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
2773 element, tile_size);
2777 redraw_mask |= REDRAW_FIELD;
2780 #define MICROLABEL_EMPTY 0
2781 #define MICROLABEL_LEVEL_NAME 1
2782 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
2783 #define MICROLABEL_LEVEL_AUTHOR 3
2784 #define MICROLABEL_IMPORTED_FROM_HEAD 4
2785 #define MICROLABEL_IMPORTED_FROM 5
2786 #define MICROLABEL_IMPORTED_BY_HEAD 6
2787 #define MICROLABEL_IMPORTED_BY 7
2789 static int getMaxTextLength(struct TextPosInfo *pos, int font_nr)
2791 int max_text_width = SXSIZE;
2792 int font_width = getFontWidth(font_nr);
2794 if (pos->align == ALIGN_CENTER)
2795 max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
2796 else if (pos->align == ALIGN_RIGHT)
2797 max_text_width = pos->x;
2799 max_text_width = SXSIZE - pos->x;
2801 return max_text_width / font_width;
2804 static void DrawPreviewLevelLabelExt(int mode)
2806 struct TextPosInfo *pos = &menu.main.text.level_info_2;
2807 char label_text[MAX_OUTPUT_LINESIZE + 1];
2808 int max_len_label_text;
2809 int font_nr = pos->font;
2812 if (!IN_GFX_FIELD_FULL(pos->x, pos->y + getFontHeight(pos->font)))
2815 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
2816 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
2817 mode == MICROLABEL_IMPORTED_BY_HEAD)
2818 font_nr = pos->font_alt;
2820 max_len_label_text = getMaxTextLength(pos, font_nr);
2822 if (pos->size != -1)
2823 max_len_label_text = pos->size;
2825 for (i = 0; i < max_len_label_text; i++)
2826 label_text[i] = ' ';
2827 label_text[max_len_label_text] = '\0';
2829 if (strlen(label_text) > 0)
2830 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2833 (mode == MICROLABEL_LEVEL_NAME ? level.name :
2834 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
2835 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
2836 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
2837 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
2838 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
2839 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
2840 max_len_label_text);
2841 label_text[max_len_label_text] = '\0';
2843 if (strlen(label_text) > 0)
2844 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2846 redraw_mask |= REDRAW_FIELD;
2849 static void DrawPreviewLevelExt(boolean restart)
2851 static unsigned int scroll_delay = 0;
2852 static unsigned int label_delay = 0;
2853 static int from_x, from_y, scroll_direction;
2854 static int label_state, label_counter;
2855 unsigned int scroll_delay_value = preview.step_delay;
2856 boolean show_level_border = (BorderElement != EL_EMPTY);
2857 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2858 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2865 if (preview.anim_mode == ANIM_CENTERED)
2867 if (level_xsize > preview.xsize)
2868 from_x = (level_xsize - preview.xsize) / 2;
2869 if (level_ysize > preview.ysize)
2870 from_y = (level_ysize - preview.ysize) / 2;
2873 from_x += preview.xoffset;
2874 from_y += preview.yoffset;
2876 scroll_direction = MV_RIGHT;
2880 DrawPreviewLevelPlayfieldExt(from_x, from_y);
2881 DrawPreviewLevelLabelExt(label_state);
2883 /* initialize delay counters */
2884 DelayReached(&scroll_delay, 0);
2885 DelayReached(&label_delay, 0);
2887 if (leveldir_current->name)
2889 struct TextPosInfo *pos = &menu.main.text.level_info_1;
2890 char label_text[MAX_OUTPUT_LINESIZE + 1];
2891 int font_nr = pos->font;
2892 int max_len_label_text = getMaxTextLength(pos, font_nr);
2894 if (pos->size != -1)
2895 max_len_label_text = pos->size;
2897 strncpy(label_text, leveldir_current->name, max_len_label_text);
2898 label_text[max_len_label_text] = '\0';
2900 if (IN_GFX_FIELD_FULL(pos->x, pos->y + getFontHeight(pos->font)))
2901 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2907 /* scroll preview level, if needed */
2908 if (preview.anim_mode != ANIM_NONE &&
2909 (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
2910 DelayReached(&scroll_delay, scroll_delay_value))
2912 switch (scroll_direction)
2917 from_x -= preview.step_offset;
2918 from_x = (from_x < 0 ? 0 : from_x);
2921 scroll_direction = MV_UP;
2925 if (from_x < level_xsize - preview.xsize)
2927 from_x += preview.step_offset;
2928 from_x = (from_x > level_xsize - preview.xsize ?
2929 level_xsize - preview.xsize : from_x);
2932 scroll_direction = MV_DOWN;
2938 from_y -= preview.step_offset;
2939 from_y = (from_y < 0 ? 0 : from_y);
2942 scroll_direction = MV_RIGHT;
2946 if (from_y < level_ysize - preview.ysize)
2948 from_y += preview.step_offset;
2949 from_y = (from_y > level_ysize - preview.ysize ?
2950 level_ysize - preview.ysize : from_y);
2953 scroll_direction = MV_LEFT;
2960 DrawPreviewLevelPlayfieldExt(from_x, from_y);
2963 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
2964 /* redraw micro level label, if needed */
2965 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
2966 !strEqual(level.author, ANONYMOUS_NAME) &&
2967 !strEqual(level.author, leveldir_current->name) &&
2968 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
2970 int max_label_counter = 23;
2972 if (leveldir_current->imported_from != NULL &&
2973 strlen(leveldir_current->imported_from) > 0)
2974 max_label_counter += 14;
2975 if (leveldir_current->imported_by != NULL &&
2976 strlen(leveldir_current->imported_by) > 0)
2977 max_label_counter += 14;
2979 label_counter = (label_counter + 1) % max_label_counter;
2980 label_state = (label_counter >= 0 && label_counter <= 7 ?
2981 MICROLABEL_LEVEL_NAME :
2982 label_counter >= 9 && label_counter <= 12 ?
2983 MICROLABEL_LEVEL_AUTHOR_HEAD :
2984 label_counter >= 14 && label_counter <= 21 ?
2985 MICROLABEL_LEVEL_AUTHOR :
2986 label_counter >= 23 && label_counter <= 26 ?
2987 MICROLABEL_IMPORTED_FROM_HEAD :
2988 label_counter >= 28 && label_counter <= 35 ?
2989 MICROLABEL_IMPORTED_FROM :
2990 label_counter >= 37 && label_counter <= 40 ?
2991 MICROLABEL_IMPORTED_BY_HEAD :
2992 label_counter >= 42 && label_counter <= 49 ?
2993 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
2995 if (leveldir_current->imported_from == NULL &&
2996 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
2997 label_state == MICROLABEL_IMPORTED_FROM))
2998 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
2999 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
3001 DrawPreviewLevelLabelExt(label_state);
3005 void DrawPreviewLevelInitial()
3007 DrawPreviewLevelExt(TRUE);
3010 void DrawPreviewLevelAnimation()
3012 DrawPreviewLevelExt(FALSE);
3015 inline static void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
3016 int graphic, int sync_frame,
3019 int frame = getGraphicAnimationFrame(graphic, sync_frame);
3021 if (mask_mode == USE_MASKING)
3022 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
3024 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
3027 void DrawFixedGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
3028 int graphic, int sync_frame, int mask_mode)
3030 int frame = getGraphicAnimationFrame(graphic, sync_frame);
3032 if (mask_mode == USE_MASKING)
3033 DrawFixedGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
3035 DrawFixedGraphicExt(dst_bitmap, x, y, graphic, frame);
3038 inline static void DrawGraphicAnimation(int x, int y, int graphic)
3040 int lx = LEVELX(x), ly = LEVELY(y);
3042 if (!IN_SCR_FIELD(x, y))
3045 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
3046 graphic, GfxFrame[lx][ly], NO_MASKING);
3048 MarkTileDirty(x, y);
3051 void DrawFixedGraphicAnimation(int x, int y, int graphic)
3053 int lx = LEVELX(x), ly = LEVELY(y);
3055 if (!IN_SCR_FIELD(x, y))
3058 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
3059 graphic, GfxFrame[lx][ly], NO_MASKING);
3060 MarkTileDirty(x, y);
3063 void DrawLevelGraphicAnimation(int x, int y, int graphic)
3065 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
3068 void DrawLevelElementAnimation(int x, int y, int element)
3070 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
3072 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
3075 void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
3077 int sx = SCREENX(x), sy = SCREENY(y);
3079 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
3082 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
3085 DrawGraphicAnimation(sx, sy, graphic);
3088 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
3089 DrawLevelFieldCrumbled(x, y);
3091 if (GFX_CRUMBLED(Feld[x][y]))
3092 DrawLevelFieldCrumbled(x, y);
3096 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
3098 int sx = SCREENX(x), sy = SCREENY(y);
3101 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
3104 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
3106 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
3109 DrawGraphicAnimation(sx, sy, graphic);
3111 if (GFX_CRUMBLED(element))
3112 DrawLevelFieldCrumbled(x, y);
3115 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
3117 if (player->use_murphy)
3119 /* this works only because currently only one player can be "murphy" ... */
3120 static int last_horizontal_dir = MV_LEFT;
3121 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
3123 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3124 last_horizontal_dir = move_dir;
3126 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
3128 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
3130 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
3136 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
3139 static boolean equalGraphics(int graphic1, int graphic2)
3141 struct GraphicInfo *g1 = &graphic_info[graphic1];
3142 struct GraphicInfo *g2 = &graphic_info[graphic2];
3144 return (g1->bitmap == g2->bitmap &&
3145 g1->src_x == g2->src_x &&
3146 g1->src_y == g2->src_y &&
3147 g1->anim_frames == g2->anim_frames &&
3148 g1->anim_delay == g2->anim_delay &&
3149 g1->anim_mode == g2->anim_mode);
3152 void DrawAllPlayers()
3156 for (i = 0; i < MAX_PLAYERS; i++)
3157 if (stored_player[i].active)
3158 DrawPlayer(&stored_player[i]);
3161 void DrawPlayerField(int x, int y)
3163 if (!IS_PLAYER(x, y))
3166 DrawPlayer(PLAYERINFO(x, y));
3169 #define DRAW_PLAYER_OVER_PUSHED_ELEMENT 1
3171 void DrawPlayer(struct PlayerInfo *player)
3173 int jx = player->jx;
3174 int jy = player->jy;
3175 int move_dir = player->MovDir;
3176 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
3177 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
3178 int last_jx = (player->is_moving ? jx - dx : jx);
3179 int last_jy = (player->is_moving ? jy - dy : jy);
3180 int next_jx = jx + dx;
3181 int next_jy = jy + dy;
3182 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
3183 boolean player_is_opaque = FALSE;
3184 int sx = SCREENX(jx), sy = SCREENY(jy);
3185 int sxx = 0, syy = 0;
3186 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
3188 int action = ACTION_DEFAULT;
3189 int last_player_graphic = getPlayerGraphic(player, move_dir);
3190 int last_player_frame = player->Frame;
3193 /* GfxElement[][] is set to the element the player is digging or collecting;
3194 remove also for off-screen player if the player is not moving anymore */
3195 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
3196 GfxElement[jx][jy] = EL_UNDEFINED;
3198 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
3202 if (!IN_LEV_FIELD(jx, jy))
3204 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
3205 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
3206 printf("DrawPlayerField(): This should never happen!\n");
3211 if (element == EL_EXPLOSION)
3214 action = (player->is_pushing ? ACTION_PUSHING :
3215 player->is_digging ? ACTION_DIGGING :
3216 player->is_collecting ? ACTION_COLLECTING :
3217 player->is_moving ? ACTION_MOVING :
3218 player->is_snapping ? ACTION_SNAPPING :
3219 player->is_dropping ? ACTION_DROPPING :
3220 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
3222 if (player->is_waiting)
3223 move_dir = player->dir_waiting;
3225 InitPlayerGfxAnimation(player, action, move_dir);
3227 /* ----------------------------------------------------------------------- */
3228 /* draw things in the field the player is leaving, if needed */
3229 /* ----------------------------------------------------------------------- */
3231 if (player->is_moving)
3233 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
3235 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
3237 if (last_element == EL_DYNAMITE_ACTIVE ||
3238 last_element == EL_EM_DYNAMITE_ACTIVE ||
3239 last_element == EL_SP_DISK_RED_ACTIVE)
3240 DrawDynamite(last_jx, last_jy);
3242 DrawLevelFieldThruMask(last_jx, last_jy);
3244 else if (last_element == EL_DYNAMITE_ACTIVE ||
3245 last_element == EL_EM_DYNAMITE_ACTIVE ||
3246 last_element == EL_SP_DISK_RED_ACTIVE)
3247 DrawDynamite(last_jx, last_jy);
3249 /* !!! this is not enough to prevent flickering of players which are
3250 moving next to each others without a free tile between them -- this
3251 can only be solved by drawing all players layer by layer (first the
3252 background, then the foreground etc.) !!! => TODO */
3253 else if (!IS_PLAYER(last_jx, last_jy))
3254 DrawLevelField(last_jx, last_jy);
3257 DrawLevelField(last_jx, last_jy);
3260 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
3261 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
3264 if (!IN_SCR_FIELD(sx, sy))
3267 /* ----------------------------------------------------------------------- */
3268 /* draw things behind the player, if needed */
3269 /* ----------------------------------------------------------------------- */
3272 DrawLevelElement(jx, jy, Back[jx][jy]);
3273 else if (IS_ACTIVE_BOMB(element))
3274 DrawLevelElement(jx, jy, EL_EMPTY);
3277 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
3279 int old_element = GfxElement[jx][jy];
3280 int old_graphic = el_act_dir2img(old_element, action, move_dir);
3281 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
3283 if (GFX_CRUMBLED(old_element))
3284 DrawLevelFieldCrumbledDigging(jx, jy, move_dir, player->StepFrame);
3286 DrawGraphic(sx, sy, old_graphic, frame);
3288 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
3289 player_is_opaque = TRUE;
3293 GfxElement[jx][jy] = EL_UNDEFINED;
3295 /* make sure that pushed elements are drawn with correct frame rate */
3296 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
3298 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
3299 GfxFrame[jx][jy] = player->StepFrame;
3301 DrawLevelField(jx, jy);
3305 #if !DRAW_PLAYER_OVER_PUSHED_ELEMENT
3306 /* ----------------------------------------------------------------------- */
3307 /* draw player himself */
3308 /* ----------------------------------------------------------------------- */
3310 graphic = getPlayerGraphic(player, move_dir);
3312 /* in the case of changed player action or direction, prevent the current
3313 animation frame from being restarted for identical animations */
3314 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
3315 player->Frame = last_player_frame;
3317 frame = getGraphicAnimationFrame(graphic, player->Frame);
3321 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3322 sxx = player->GfxPos;
3324 syy = player->GfxPos;
3327 if (player_is_opaque)
3328 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
3330 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3332 if (SHIELD_ON(player))
3334 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
3335 IMG_SHIELD_NORMAL_ACTIVE);
3336 int frame = getGraphicAnimationFrame(graphic, -1);
3338 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3342 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
3345 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3346 sxx = player->GfxPos;
3348 syy = player->GfxPos;
3352 /* ----------------------------------------------------------------------- */
3353 /* draw things the player is pushing, if needed */
3354 /* ----------------------------------------------------------------------- */
3356 if (player->is_pushing && player->is_moving)
3358 int px = SCREENX(jx), py = SCREENY(jy);
3359 int pxx = (TILEX - ABS(sxx)) * dx;
3360 int pyy = (TILEY - ABS(syy)) * dy;
3361 int gfx_frame = GfxFrame[jx][jy];
3367 if (!IS_MOVING(jx, jy)) /* push movement already finished */
3369 element = Feld[next_jx][next_jy];
3370 gfx_frame = GfxFrame[next_jx][next_jy];
3373 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
3375 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
3376 frame = getGraphicAnimationFrame(graphic, sync_frame);
3378 /* draw background element under pushed element (like the Sokoban field) */
3379 if (game.use_masked_pushing && IS_MOVING(jx, jy))
3381 /* this allows transparent pushing animation over non-black background */
3384 DrawLevelElement(jx, jy, Back[jx][jy]);
3386 DrawLevelElement(jx, jy, EL_EMPTY);
3388 if (Back[next_jx][next_jy])
3389 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3391 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
3393 else if (Back[next_jx][next_jy])
3394 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3397 /* do not draw (EM style) pushing animation when pushing is finished */
3398 /* (two-tile animations usually do not contain start and end frame) */
3399 if (graphic_info[graphic].double_movement && !IS_MOVING(jx, jy))
3400 DrawLevelElement(next_jx, next_jy, Feld[next_jx][next_jy]);
3402 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3404 /* masked drawing is needed for EMC style (double) movement graphics */
3405 /* !!! (ONLY WHEN DRAWING PUSHED ELEMENT OVER THE PLAYER) !!! */
3406 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3410 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
3411 /* ----------------------------------------------------------------------- */
3412 /* draw player himself */
3413 /* ----------------------------------------------------------------------- */
3415 graphic = getPlayerGraphic(player, move_dir);
3417 /* in the case of changed player action or direction, prevent the current
3418 animation frame from being restarted for identical animations */
3419 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
3420 player->Frame = last_player_frame;
3422 frame = getGraphicAnimationFrame(graphic, player->Frame);
3426 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3427 sxx = player->GfxPos;
3429 syy = player->GfxPos;
3432 if (player_is_opaque)
3433 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
3435 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3437 if (SHIELD_ON(player))
3439 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
3440 IMG_SHIELD_NORMAL_ACTIVE);
3441 int frame = getGraphicAnimationFrame(graphic, -1);
3443 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3447 /* ----------------------------------------------------------------------- */
3448 /* draw things in front of player (active dynamite or dynabombs) */
3449 /* ----------------------------------------------------------------------- */
3451 if (IS_ACTIVE_BOMB(element))
3453 graphic = el2img(element);
3454 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
3456 if (game.emulation == EMU_SUPAPLEX)
3457 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
3459 DrawGraphicThruMask(sx, sy, graphic, frame);
3462 if (player_is_moving && last_element == EL_EXPLOSION)
3464 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
3465 GfxElement[last_jx][last_jy] : EL_EMPTY);
3466 int graphic = el_act2img(element, ACTION_EXPLODING);
3467 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
3468 int phase = ExplodePhase[last_jx][last_jy] - 1;
3469 int frame = getGraphicAnimationFrame(graphic, phase - delay);
3472 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
3475 /* ----------------------------------------------------------------------- */
3476 /* draw elements the player is just walking/passing through/under */
3477 /* ----------------------------------------------------------------------- */
3479 if (player_is_moving)
3481 /* handle the field the player is leaving ... */
3482 if (IS_ACCESSIBLE_INSIDE(last_element))
3483 DrawLevelField(last_jx, last_jy);
3484 else if (IS_ACCESSIBLE_UNDER(last_element))
3485 DrawLevelFieldThruMask(last_jx, last_jy);
3488 /* do not redraw accessible elements if the player is just pushing them */
3489 if (!player_is_moving || !player->is_pushing)
3491 /* ... and the field the player is entering */
3492 if (IS_ACCESSIBLE_INSIDE(element))
3493 DrawLevelField(jx, jy);
3494 else if (IS_ACCESSIBLE_UNDER(element))
3495 DrawLevelFieldThruMask(jx, jy);
3498 MarkTileDirty(sx, sy);
3501 /* ------------------------------------------------------------------------- */
3503 void WaitForEventToContinue()
3505 boolean still_wait = TRUE;
3507 /* simulate releasing mouse button over last gadget, if still pressed */
3509 HandleGadgets(-1, -1, 0);
3511 button_status = MB_RELEASED;
3525 case EVENT_BUTTONPRESS:
3526 case EVENT_KEYPRESS:
3530 case EVENT_KEYRELEASE:
3531 ClearPlayerAction();
3535 HandleOtherEvents(&event);
3539 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3548 #define MAX_REQUEST_LINES 13
3549 #define MAX_REQUEST_LINE_FONT1_LEN 7
3550 #define MAX_REQUEST_LINE_FONT2_LEN 10
3552 static int RequestHandleEvents(unsigned int req_state)
3554 boolean level_solved = (game_status == GAME_MODE_PLAYING &&
3555 local_player->LevelSolved_GameEnd);
3556 int width = request.width;
3557 int height = request.height;
3561 setRequestPosition(&sx, &sy, FALSE);
3563 button_status = MB_RELEASED;
3565 request_gadget_id = -1;
3572 SetDrawtoField(DRAW_TO_FIELDBUFFER);
3574 HandleGameActions();
3576 SetDrawtoField(DRAW_TO_BACKBUFFER);
3578 if (global.use_envelope_request)
3580 /* copy current state of request area to middle of playfield area */
3581 BlitBitmap(bitmap_db_cross, drawto, sx, sy, width, height, sx, sy);
3589 while (NextValidEvent(&event))
3593 case EVENT_BUTTONPRESS:
3594 case EVENT_BUTTONRELEASE:
3595 case EVENT_MOTIONNOTIFY:
3599 if (event.type == EVENT_MOTIONNOTIFY)
3604 motion_status = TRUE;
3605 mx = ((MotionEvent *) &event)->x;
3606 my = ((MotionEvent *) &event)->y;
3610 motion_status = FALSE;
3611 mx = ((ButtonEvent *) &event)->x;
3612 my = ((ButtonEvent *) &event)->y;
3613 if (event.type == EVENT_BUTTONPRESS)
3614 button_status = ((ButtonEvent *) &event)->button;
3616 button_status = MB_RELEASED;
3619 /* this sets 'request_gadget_id' */
3620 HandleGadgets(mx, my, button_status);
3622 switch (request_gadget_id)
3624 case TOOL_CTRL_ID_YES:
3627 case TOOL_CTRL_ID_NO:
3630 case TOOL_CTRL_ID_CONFIRM:
3631 result = TRUE | FALSE;
3634 case TOOL_CTRL_ID_PLAYER_1:
3637 case TOOL_CTRL_ID_PLAYER_2:
3640 case TOOL_CTRL_ID_PLAYER_3:
3643 case TOOL_CTRL_ID_PLAYER_4:
3654 case EVENT_KEYPRESS:
3655 switch (GetEventKey((KeyEvent *)&event, TRUE))
3658 if (req_state & REQ_CONFIRM)
3663 #if defined(TARGET_SDL2)
3670 #if defined(TARGET_SDL2)
3680 if (req_state & REQ_PLAYER)
3684 case EVENT_KEYRELEASE:
3685 ClearPlayerAction();
3689 HandleOtherEvents(&event);
3694 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3696 int joy = AnyJoystick();
3698 if (joy & JOY_BUTTON_1)
3700 else if (joy & JOY_BUTTON_2)
3706 if (global.use_envelope_request)
3708 /* copy back current state of pressed buttons inside request area */
3709 BlitBitmap(drawto, bitmap_db_cross, sx, sy, width, height, sx, sy);
3719 static boolean RequestDoor(char *text, unsigned int req_state)
3721 unsigned int old_door_state;
3722 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
3723 int font_nr = FONT_TEXT_2;
3728 if (maxWordLengthInString(text) > MAX_REQUEST_LINE_FONT1_LEN)
3730 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
3731 font_nr = FONT_TEXT_1;
3734 if (game_status == GAME_MODE_PLAYING)
3735 BlitScreenToBitmap(backbuffer);
3737 /* disable deactivated drawing when quick-loading level tape recording */
3738 if (tape.playing && tape.deactivate_display)
3739 TapeDeactivateDisplayOff(TRUE);
3741 SetMouseCursor(CURSOR_DEFAULT);
3743 #if defined(NETWORK_AVALIABLE)
3744 /* pause network game while waiting for request to answer */
3745 if (options.network &&
3746 game_status == GAME_MODE_PLAYING &&
3747 req_state & REQUEST_WAIT_FOR_INPUT)
3748 SendToServer_PausePlaying();
3751 old_door_state = GetDoorState();
3753 /* simulate releasing mouse button over last gadget, if still pressed */
3755 HandleGadgets(-1, -1, 0);
3759 /* draw released gadget before proceeding */
3762 if (old_door_state & DOOR_OPEN_1)
3764 CloseDoor(DOOR_CLOSE_1);
3766 /* save old door content */
3767 BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
3768 0 * DXSIZE, 0, DXSIZE, DYSIZE, 1 * DXSIZE, 0);
3771 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
3772 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3774 /* clear door drawing field */
3775 DrawBackground(DX, DY, DXSIZE, DYSIZE);
3777 /* force DOOR font inside door area */
3778 SetFontStatus(GAME_MODE_PSEUDO_DOOR);
3780 /* write text for request */
3781 for (text_ptr = text, ty = 0; ty < MAX_REQUEST_LINES; ty++)
3783 char text_line[max_request_line_len + 1];
3789 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
3791 tc = *(text_ptr + tx);
3792 // if (!tc || tc == ' ')
3793 if (!tc || tc == ' ' || tc == '?' || tc == '!')
3797 if ((tc == '?' || tc == '!') && tl == 0)
3807 strncpy(text_line, text_ptr, tl);
3810 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
3811 DY + 8 + ty * (getFontHeight(font_nr) + 2),
3812 text_line, font_nr);
3814 text_ptr += tl + (tc == ' ' ? 1 : 0);
3815 // text_ptr += tl + (tc == ' ' || tc == '?' || tc == '!' ? 1 : 0);
3820 if (req_state & REQ_ASK)
3822 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
3823 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
3825 else if (req_state & REQ_CONFIRM)
3827 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
3829 else if (req_state & REQ_PLAYER)
3831 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
3832 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
3833 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
3834 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
3837 /* copy request gadgets to door backbuffer */
3838 BlitBitmap(drawto, bitmap_db_door_1, DX, DY, DXSIZE, DYSIZE, 0, 0);
3840 OpenDoor(DOOR_OPEN_1);
3842 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
3844 if (game_status == GAME_MODE_PLAYING)
3846 SetPanelBackground();
3847 SetDrawBackgroundMask(REDRAW_DOOR_1);
3851 SetDrawBackgroundMask(REDRAW_FIELD);
3857 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3859 // ---------- handle request buttons ----------
3860 result = RequestHandleEvents(req_state);
3864 if (!(req_state & REQ_STAY_OPEN))
3866 CloseDoor(DOOR_CLOSE_1);
3868 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
3869 (req_state & REQ_REOPEN))
3870 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
3875 if (game_status == GAME_MODE_PLAYING)
3877 SetPanelBackground();
3878 SetDrawBackgroundMask(REDRAW_DOOR_1);
3882 SetDrawBackgroundMask(REDRAW_FIELD);
3885 #if defined(NETWORK_AVALIABLE)
3886 /* continue network game after request */
3887 if (options.network &&
3888 game_status == GAME_MODE_PLAYING &&
3889 req_state & REQUEST_WAIT_FOR_INPUT)
3890 SendToServer_ContinuePlaying();
3893 /* restore deactivated drawing when quick-loading level tape recording */
3894 if (tape.playing && tape.deactivate_display)
3895 TapeDeactivateDisplayOn();
3900 static boolean RequestEnvelope(char *text, unsigned int req_state)
3904 if (game_status == GAME_MODE_PLAYING)
3905 BlitScreenToBitmap(backbuffer);
3907 /* disable deactivated drawing when quick-loading level tape recording */
3908 if (tape.playing && tape.deactivate_display)
3909 TapeDeactivateDisplayOff(TRUE);
3911 SetMouseCursor(CURSOR_DEFAULT);
3913 #if defined(NETWORK_AVALIABLE)
3914 /* pause network game while waiting for request to answer */
3915 if (options.network &&
3916 game_status == GAME_MODE_PLAYING &&
3917 req_state & REQUEST_WAIT_FOR_INPUT)
3918 SendToServer_PausePlaying();
3921 /* simulate releasing mouse button over last gadget, if still pressed */
3923 HandleGadgets(-1, -1, 0);
3927 // (replace with setting corresponding request background)
3928 // SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
3929 // SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3931 /* clear door drawing field */
3932 // DrawBackground(DX, DY, DXSIZE, DYSIZE);
3934 ShowEnvelopeRequest(text, req_state, ACTION_OPENING);
3936 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
3938 if (game_status == GAME_MODE_PLAYING)
3940 SetPanelBackground();
3941 SetDrawBackgroundMask(REDRAW_DOOR_1);
3945 SetDrawBackgroundMask(REDRAW_FIELD);
3951 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3953 // ---------- handle request buttons ----------
3954 result = RequestHandleEvents(req_state);
3958 ShowEnvelopeRequest(text, req_state, ACTION_CLOSING);
3962 if (game_status == GAME_MODE_PLAYING)
3964 SetPanelBackground();
3965 SetDrawBackgroundMask(REDRAW_DOOR_1);
3969 SetDrawBackgroundMask(REDRAW_FIELD);
3972 #if defined(NETWORK_AVALIABLE)
3973 /* continue network game after request */
3974 if (options.network &&
3975 game_status == GAME_MODE_PLAYING &&
3976 req_state & REQUEST_WAIT_FOR_INPUT)
3977 SendToServer_ContinuePlaying();
3980 /* restore deactivated drawing when quick-loading level tape recording */
3981 if (tape.playing && tape.deactivate_display)
3982 TapeDeactivateDisplayOn();
3987 boolean Request(char *text, unsigned int req_state)
3989 if (global.use_envelope_request)
3990 return RequestEnvelope(text, req_state);
3992 return RequestDoor(text, req_state);
3995 static int compareDoorPartOrderInfo(const void *object1, const void *object2)
3997 const struct DoorPartOrderInfo *dpo1 = (struct DoorPartOrderInfo *)object1;
3998 const struct DoorPartOrderInfo *dpo2 = (struct DoorPartOrderInfo *)object2;
4001 if (dpo1->sort_priority != dpo2->sort_priority)
4002 compare_result = dpo1->sort_priority - dpo2->sort_priority;
4004 compare_result = dpo1->nr - dpo2->nr;
4006 return compare_result;
4009 void InitGraphicCompatibilityInfo_Doors()
4015 struct DoorInfo *door;
4019 { DOOR_1, IMG_GFX_DOOR_1_PART_1, IMG_GFX_DOOR_1_PART_8, &door_1 },
4020 { DOOR_2, IMG_GFX_DOOR_2_PART_1, IMG_GFX_DOOR_2_PART_8, &door_2 },
4022 { -1, -1, -1, NULL }
4024 struct Rect door_rect_list[] =
4026 { DX, DY, DXSIZE, DYSIZE },
4027 { VX, VY, VXSIZE, VYSIZE }
4031 for (i = 0; doors[i].door_token != -1; i++)
4033 int door_token = doors[i].door_token;
4034 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
4035 int part_1 = doors[i].part_1;
4036 int part_8 = doors[i].part_8;
4037 int part_2 = part_1 + 1;
4038 int part_3 = part_1 + 2;
4039 struct DoorInfo *door = doors[i].door;
4040 struct Rect *door_rect = &door_rect_list[door_index];
4041 boolean door_gfx_redefined = FALSE;
4043 /* check if any door part graphic definitions have been redefined */
4045 for (j = 0; door_part_controls[j].door_token != -1; j++)
4047 struct DoorPartControlInfo *dpc = &door_part_controls[j];
4048 struct FileInfo *fi = getImageListEntryFromImageID(dpc->graphic);
4050 if (dpc->door_token == door_token && fi->redefined)
4051 door_gfx_redefined = TRUE;
4054 /* check for old-style door graphic/animation modifications */
4056 if (!door_gfx_redefined)
4058 if (door->anim_mode & ANIM_STATIC_PANEL)
4060 door->panel.step_xoffset = 0;
4061 door->panel.step_yoffset = 0;
4064 if (door->anim_mode & (ANIM_HORIZONTAL | ANIM_VERTICAL))
4066 struct GraphicInfo *g_part_1 = &graphic_info[part_1];
4067 struct GraphicInfo *g_part_2 = &graphic_info[part_2];
4068 int num_door_steps, num_panel_steps;
4070 /* remove door part graphics other than the two default wings */
4072 for (j = 0; door_part_controls[j].door_token != -1; j++)
4074 struct DoorPartControlInfo *dpc = &door_part_controls[j];
4075 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4077 if (dpc->graphic >= part_3 &&
4078 dpc->graphic <= part_8)
4082 /* set graphics and screen positions of the default wings */
4084 g_part_1->width = door_rect->width;
4085 g_part_1->height = door_rect->height;
4086 g_part_2->width = door_rect->width;
4087 g_part_2->height = door_rect->height;
4088 g_part_2->src_x = door_rect->width;
4089 g_part_2->src_y = g_part_1->src_y;
4091 door->part_2.x = door->part_1.x;
4092 door->part_2.y = door->part_1.y;
4094 if (door->width != -1)
4096 g_part_1->width = door->width;
4097 g_part_2->width = door->width;
4099 // special treatment for graphics and screen position of right wing
4100 g_part_2->src_x += door_rect->width - door->width;
4101 door->part_2.x += door_rect->width - door->width;
4104 if (door->height != -1)
4106 g_part_1->height = door->height;
4107 g_part_2->height = door->height;
4109 // special treatment for graphics and screen position of bottom wing
4110 g_part_2->src_y += door_rect->height - door->height;
4111 door->part_2.y += door_rect->height - door->height;
4114 /* set animation delays for the default wings and panels */
4116 door->part_1.step_delay = door->step_delay;
4117 door->part_2.step_delay = door->step_delay;
4118 door->panel.step_delay = door->step_delay;
4120 /* set animation draw order for the default wings */
4122 door->part_1.sort_priority = 2; /* draw left wing over ... */
4123 door->part_2.sort_priority = 1; /* ... right wing */
4125 /* set animation draw offset for the default wings */
4127 if (door->anim_mode & ANIM_HORIZONTAL)
4129 door->part_1.step_xoffset = door->step_offset;
4130 door->part_1.step_yoffset = 0;
4131 door->part_2.step_xoffset = door->step_offset * -1;
4132 door->part_2.step_yoffset = 0;
4134 num_door_steps = g_part_1->width / door->step_offset;
4136 else // ANIM_VERTICAL
4138 door->part_1.step_xoffset = 0;
4139 door->part_1.step_yoffset = door->step_offset;
4140 door->part_2.step_xoffset = 0;
4141 door->part_2.step_yoffset = door->step_offset * -1;
4143 num_door_steps = g_part_1->height / door->step_offset;
4146 /* set animation draw offset for the default panels */
4148 if (door->step_offset > 1)
4150 num_panel_steps = 2 * door_rect->height / door->step_offset;
4151 door->panel.start_step = num_panel_steps - num_door_steps;
4152 door->panel.start_step_closing = door->panel.start_step;
4156 num_panel_steps = door_rect->height / door->step_offset;
4157 door->panel.start_step = num_panel_steps - num_door_steps / 2;
4158 door->panel.start_step_closing = door->panel.start_step;
4159 door->panel.step_delay *= 2;
4170 for (i = 0; door_part_controls[i].door_token != -1; i++)
4172 struct DoorPartControlInfo *dpc = &door_part_controls[i];
4173 struct DoorPartOrderInfo *dpo = &door_part_order[i];
4175 /* initialize "start_step_opening" and "start_step_closing", if needed */
4176 if (dpc->pos->start_step_opening == 0 &&
4177 dpc->pos->start_step_closing == 0)
4179 // dpc->pos->start_step_opening = dpc->pos->start_step;
4180 dpc->pos->start_step_closing = dpc->pos->start_step;
4183 /* fill structure for door part draw order (sorted below) */
4185 dpo->sort_priority = dpc->pos->sort_priority;
4188 /* sort door part controls according to sort_priority and graphic number */
4189 qsort(door_part_order, MAX_DOOR_PARTS,
4190 sizeof(struct DoorPartOrderInfo), compareDoorPartOrderInfo);
4193 unsigned int OpenDoor(unsigned int door_state)
4195 if (door_state & DOOR_COPY_BACK)
4197 if (door_state & DOOR_OPEN_1)
4198 BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
4199 1 * DXSIZE, 0, DXSIZE, DYSIZE, 0 * DXSIZE, 0);
4201 if (door_state & DOOR_OPEN_2)
4202 BlitBitmap(bitmap_db_door_2, bitmap_db_door_2,
4203 1 * VXSIZE, 0, VXSIZE, VYSIZE, 0 * VXSIZE, 0);
4205 door_state &= ~DOOR_COPY_BACK;
4208 return MoveDoor(door_state);
4211 unsigned int CloseDoor(unsigned int door_state)
4213 unsigned int old_door_state = GetDoorState();
4215 if (!(door_state & DOOR_NO_COPY_BACK))
4217 if (old_door_state & DOOR_OPEN_1)
4218 BlitBitmap(backbuffer, bitmap_db_door_1,
4219 DX, DY, DXSIZE, DYSIZE, 0, 0);
4221 if (old_door_state & DOOR_OPEN_2)
4222 BlitBitmap(backbuffer, bitmap_db_door_2,
4223 VX, VY, VXSIZE, VYSIZE, 0, 0);
4225 door_state &= ~DOOR_NO_COPY_BACK;
4228 return MoveDoor(door_state);
4231 unsigned int GetDoorState()
4233 return MoveDoor(DOOR_GET_STATE);
4236 unsigned int SetDoorState(unsigned int door_state)
4238 return MoveDoor(door_state | DOOR_SET_STATE);
4241 int euclid(int a, int b)
4243 return (b ? euclid(b, a % b) : a);
4246 unsigned int MoveDoor(unsigned int door_state)
4248 struct Rect door_rect_list[] =
4250 { DX, DY, DXSIZE, DYSIZE },
4251 { VX, VY, VXSIZE, VYSIZE }
4253 static int door1 = DOOR_CLOSE_1;
4254 static int door2 = DOOR_CLOSE_2;
4255 unsigned int door_delay = 0;
4256 unsigned int door_delay_value;
4259 if (door_state == DOOR_GET_STATE)
4260 return (door1 | door2);
4262 if (door_state & DOOR_SET_STATE)
4264 if (door_state & DOOR_ACTION_1)
4265 door1 = door_state & DOOR_ACTION_1;
4266 if (door_state & DOOR_ACTION_2)
4267 door2 = door_state & DOOR_ACTION_2;
4269 return (door1 | door2);
4272 if (!(door_state & DOOR_FORCE_REDRAW))
4274 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
4275 door_state &= ~DOOR_OPEN_1;
4276 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
4277 door_state &= ~DOOR_CLOSE_1;
4278 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
4279 door_state &= ~DOOR_OPEN_2;
4280 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
4281 door_state &= ~DOOR_CLOSE_2;
4284 if (global.autoplay_leveldir)
4286 door_state |= DOOR_NO_DELAY;
4287 door_state &= ~DOOR_CLOSE_ALL;
4290 if (game_status == GAME_MODE_EDITOR)
4291 door_state |= DOOR_NO_DELAY;
4293 if (door_state & DOOR_ACTION)
4295 boolean door_panel_drawn[NUM_DOORS];
4296 boolean panel_has_doors[NUM_DOORS];
4297 boolean door_part_skip[MAX_DOOR_PARTS];
4298 boolean door_part_done[MAX_DOOR_PARTS];
4299 boolean door_part_done_all;
4300 int num_steps[MAX_DOOR_PARTS];
4301 int max_move_delay = 0; // delay for complete animations of all doors
4302 int max_step_delay = 0; // delay (ms) between two animation frames
4303 int num_move_steps = 0; // number of animation steps for all doors
4304 int max_move_delay_doors_only = 0; // delay for doors only (no panel)
4305 int num_move_steps_doors_only = 0; // steps for doors only (no panel)
4306 int current_move_delay = 0;
4310 for (i = 0; i < NUM_DOORS; i++)
4311 panel_has_doors[i] = FALSE;
4313 for (i = 0; i < MAX_DOOR_PARTS; i++)
4315 struct DoorPartControlInfo *dpc = &door_part_controls[i];
4316 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4317 int door_token = dpc->door_token;
4319 door_part_done[i] = FALSE;
4320 door_part_skip[i] = (!(door_state & door_token) ||
4324 for (i = 0; i < MAX_DOOR_PARTS; i++)
4326 int nr = door_part_order[i].nr;
4327 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
4328 struct DoorPartPosInfo *pos = dpc->pos;
4329 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4330 int door_token = dpc->door_token;
4331 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
4332 boolean is_panel = DOOR_PART_IS_PANEL(nr);
4333 int step_xoffset = ABS(pos->step_xoffset);
4334 int step_yoffset = ABS(pos->step_yoffset);
4335 int step_delay = pos->step_delay;
4336 int current_door_state = door_state & door_token;
4337 boolean door_opening = ((current_door_state & DOOR_OPEN) != 0);
4338 boolean door_closing = ((current_door_state & DOOR_CLOSE) != 0);
4339 boolean part_opening = (is_panel ? door_closing : door_opening);
4340 int start_step = (part_opening ? pos->start_step_opening :
4341 pos->start_step_closing);
4342 float move_xsize = (step_xoffset ? g->width : 0);
4343 float move_ysize = (step_yoffset ? g->height : 0);
4344 int move_xsteps = (step_xoffset ? ceil(move_xsize / step_xoffset) : 0);
4345 int move_ysteps = (step_yoffset ? ceil(move_ysize / step_yoffset) : 0);
4346 int move_steps = (move_xsteps && move_ysteps ?
4347 MIN(move_xsteps, move_ysteps) :
4348 move_xsteps ? move_xsteps : move_ysteps) - start_step;
4349 int move_delay = move_steps * step_delay;
4351 if (door_part_skip[nr])
4354 max_move_delay = MAX(max_move_delay, move_delay);
4355 max_step_delay = (max_step_delay == 0 ? step_delay :
4356 euclid(max_step_delay, step_delay));
4357 num_steps[nr] = move_steps;
4361 max_move_delay_doors_only = MAX(max_move_delay_doors_only, move_delay);
4363 panel_has_doors[door_index] = TRUE;
4367 max_step_delay = MAX(1, max_step_delay); // prevent division by zero
4369 num_move_steps = max_move_delay / max_step_delay;
4370 num_move_steps_doors_only = max_move_delay_doors_only / max_step_delay;
4372 door_delay_value = max_step_delay;
4374 if ((door_state & DOOR_NO_DELAY) || setup.quick_doors)
4376 start = num_move_steps - 1;
4380 /* opening door sound has priority over simultaneously closing door */
4381 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
4382 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
4383 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
4384 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
4387 for (k = start; k < num_move_steps; k++)
4389 int last_frame = num_move_steps - 1; // last frame of this "for" loop
4391 door_part_done_all = TRUE;
4393 for (i = 0; i < NUM_DOORS; i++)
4394 door_panel_drawn[i] = FALSE;
4396 for (i = 0; i < MAX_DOOR_PARTS; i++)
4398 int nr = door_part_order[i].nr;
4399 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
4400 struct DoorPartPosInfo *pos = dpc->pos;
4401 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4402 int door_token = dpc->door_token;
4403 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
4404 boolean is_panel = DOOR_PART_IS_PANEL(nr);
4405 boolean is_panel_and_door_has_closed = FALSE;
4406 struct Rect *door_rect = &door_rect_list[door_index];
4407 Bitmap *bitmap_db_door = (door_token == DOOR_1 ? bitmap_db_door_1 :
4409 Bitmap *bitmap = (is_panel ? bitmap_db_door : g->bitmap);
4410 int current_door_state = door_state & door_token;
4411 boolean door_opening = ((current_door_state & DOOR_OPEN) != 0);
4412 boolean door_closing = !door_opening;
4413 boolean part_opening = (is_panel ? door_closing : door_opening);
4414 boolean part_closing = !part_opening;
4415 int start_step = (part_opening ? pos->start_step_opening :
4416 pos->start_step_closing);
4417 int step_delay = pos->step_delay;
4418 int step_factor = step_delay / max_step_delay;
4419 int k1 = (step_factor ? k / step_factor + 1 : k);
4420 int k2 = (part_opening ? k1 + start_step : num_steps[nr] - k1);
4421 int kk = MAX(0, k2);
4424 int src_x, src_y, src_xx, src_yy;
4425 int dst_x, dst_y, dst_xx, dst_yy;
4428 if (door_part_skip[nr])
4431 if (!(door_state & door_token))
4439 int k2_door = (door_opening ? k : num_move_steps_doors_only - k - 1);
4440 int kk_door = MAX(0, k2_door);
4441 int sync_frame = kk_door * door_delay_value;
4442 int frame = getGraphicAnimationFrame(dpc->graphic, sync_frame);
4444 getGraphicSource(dpc->graphic, frame, &bitmap, &g_src_x, &g_src_y);
4449 if (!door_panel_drawn[door_index])
4451 ClearRectangle(drawto, door_rect->x, door_rect->y,
4452 door_rect->width, door_rect->height);
4454 door_panel_drawn[door_index] = TRUE;
4457 // draw opening or closing door parts
4459 if (pos->step_xoffset < 0) // door part on right side
4462 dst_xx = pos->x + ABS(kk * pos->step_xoffset);
4465 if (dst_xx + width > door_rect->width)
4466 width = door_rect->width - dst_xx;
4468 else // door part on left side
4471 dst_xx = pos->x - kk * pos->step_xoffset;
4475 src_xx = ABS(dst_xx);
4479 width = g->width - src_xx;
4481 if (width > door_rect->width)
4482 width = door_rect->width;
4484 // printf("::: k == %d [%d] \n", k, start_step);
4487 if (pos->step_yoffset < 0) // door part on bottom side
4490 dst_yy = pos->y + ABS(kk * pos->step_yoffset);
4493 if (dst_yy + height > door_rect->height)
4494 height = door_rect->height - dst_yy;
4496 else // door part on top side
4499 dst_yy = pos->y - kk * pos->step_yoffset;
4503 src_yy = ABS(dst_yy);
4507 height = g->height - src_yy;
4510 src_x = g_src_x + src_xx;
4511 src_y = g_src_y + src_yy;
4513 dst_x = door_rect->x + dst_xx;
4514 dst_y = door_rect->y + dst_yy;
4516 is_panel_and_door_has_closed =
4519 panel_has_doors[door_index] &&
4520 k >= num_move_steps_doors_only - 1);
4522 if (width >= 0 && width <= g->width &&
4523 height >= 0 && height <= g->height &&
4524 !is_panel_and_door_has_closed)
4526 if (is_panel || !pos->draw_masked)
4527 BlitBitmap(bitmap, drawto, src_x, src_y, width, height,
4530 BlitBitmapMasked(bitmap, drawto, src_x, src_y, width, height,
4534 redraw_mask |= REDRAW_DOOR_FROM_TOKEN(door_token);
4536 if ((part_opening && (width < 0 || height < 0)) ||
4537 (part_closing && (width >= g->width && height >= g->height)))
4538 door_part_done[nr] = TRUE;
4540 // continue door part animations, but not panel after door has closed
4541 if (!door_part_done[nr] && !is_panel_and_door_has_closed)
4542 door_part_done_all = FALSE;
4545 if (!(door_state & DOOR_NO_DELAY))
4549 SkipUntilDelayReached(&door_delay, door_delay_value, &k, last_frame);
4551 current_move_delay += max_step_delay;
4554 if (door_part_done_all)
4559 if (door_state & DOOR_ACTION_1)
4560 door1 = door_state & DOOR_ACTION_1;
4561 if (door_state & DOOR_ACTION_2)
4562 door2 = door_state & DOOR_ACTION_2;
4564 // draw masked border over door area
4565 DrawMaskedBorder(REDRAW_DOOR_1);
4566 DrawMaskedBorder(REDRAW_DOOR_2);
4568 return (door1 | door2);
4571 static boolean useSpecialEditorDoor()
4573 int graphic = IMG_GLOBAL_BORDER_EDITOR;
4574 boolean redefined = getImageListEntryFromImageID(graphic)->redefined;
4576 // do not draw special editor door if editor border defined or redefined
4577 if (graphic_info[graphic].bitmap != NULL || redefined)
4580 // do not draw special editor door if global border defined to be empty
4581 if (graphic_info[IMG_GLOBAL_BORDER].bitmap == NULL)
4584 // do not draw special editor door if viewport definitions do not match
4588 EY + EYSIZE != VY + VYSIZE)
4594 void DrawSpecialEditorDoor()
4596 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
4597 int top_border_width = gfx1->width;
4598 int top_border_height = gfx1->height;
4599 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
4600 int ex = EX - outer_border;
4601 int ey = EY - outer_border;
4602 int vy = VY - outer_border;
4603 int exsize = EXSIZE + 2 * outer_border;
4605 if (!useSpecialEditorDoor())
4608 /* draw bigger level editor toolbox window */
4609 BlitBitmap(gfx1->bitmap, drawto, gfx1->src_x, gfx1->src_y,
4610 top_border_width, top_border_height, ex, ey - top_border_height);
4611 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto, ex, vy,
4612 exsize, EYSIZE - VYSIZE + outer_border, ex, ey);
4614 redraw_mask |= REDRAW_ALL;
4617 void UndrawSpecialEditorDoor()
4619 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
4620 int top_border_width = gfx1->width;
4621 int top_border_height = gfx1->height;
4622 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
4623 int ex = EX - outer_border;
4624 int ey = EY - outer_border;
4625 int ey_top = ey - top_border_height;
4626 int exsize = EXSIZE + 2 * outer_border;
4627 int eysize = EYSIZE + 2 * outer_border;
4629 if (!useSpecialEditorDoor())
4632 /* draw normal tape recorder window */
4633 if (graphic_info[IMG_GLOBAL_BORDER].bitmap)
4635 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
4636 ex, ey_top, top_border_width, top_border_height,
4638 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
4639 ex, ey, exsize, eysize, ex, ey);
4643 // if screen background is set to "[NONE]", clear editor toolbox window
4644 ClearRectangle(drawto, ex, ey_top, top_border_width, top_border_height);
4645 ClearRectangle(drawto, ex, ey, exsize, eysize);
4648 redraw_mask |= REDRAW_ALL;
4652 /* ---------- new tool button stuff ---------------------------------------- */
4657 struct TextPosInfo *pos;
4660 } toolbutton_info[NUM_TOOL_BUTTONS] =
4663 IMG_GFX_REQUEST_BUTTON_YES, &request.button.yes,
4664 TOOL_CTRL_ID_YES, "yes"
4667 IMG_GFX_REQUEST_BUTTON_NO, &request.button.no,
4668 TOOL_CTRL_ID_NO, "no"
4671 IMG_GFX_REQUEST_BUTTON_CONFIRM, &request.button.confirm,
4672 TOOL_CTRL_ID_CONFIRM, "confirm"
4675 IMG_GFX_REQUEST_BUTTON_PLAYER_1, &request.button.player_1,
4676 TOOL_CTRL_ID_PLAYER_1, "player 1"
4679 IMG_GFX_REQUEST_BUTTON_PLAYER_2, &request.button.player_2,
4680 TOOL_CTRL_ID_PLAYER_2, "player 2"
4683 IMG_GFX_REQUEST_BUTTON_PLAYER_3, &request.button.player_3,
4684 TOOL_CTRL_ID_PLAYER_3, "player 3"
4687 IMG_GFX_REQUEST_BUTTON_PLAYER_4, &request.button.player_4,
4688 TOOL_CTRL_ID_PLAYER_4, "player 4"
4692 void CreateToolButtons()
4696 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4698 struct GraphicInfo *gfx = &graphic_info[toolbutton_info[i].graphic];
4699 struct TextPosInfo *pos = toolbutton_info[i].pos;
4700 struct GadgetInfo *gi;
4701 Bitmap *deco_bitmap = None;
4702 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
4703 unsigned int event_mask = GD_EVENT_RELEASED;
4706 int gd_x = gfx->src_x;
4707 int gd_y = gfx->src_y;
4708 int gd_xp = gfx->src_x + gfx->pressed_xoffset;
4709 int gd_yp = gfx->src_y + gfx->pressed_yoffset;
4712 if (global.use_envelope_request)
4713 setRequestPosition(&dx, &dy, TRUE);
4715 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
4717 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
4719 getSizedGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr), 0,
4720 pos->size, &deco_bitmap, &deco_x, &deco_y);
4721 deco_xpos = (gfx->width - pos->size) / 2;
4722 deco_ypos = (gfx->height - pos->size) / 2;
4725 gi = CreateGadget(GDI_CUSTOM_ID, id,
4726 GDI_INFO_TEXT, toolbutton_info[i].infotext,
4727 GDI_X, dx + GDI_ACTIVE_POS(pos->x),
4728 GDI_Y, dy + GDI_ACTIVE_POS(pos->y),
4729 GDI_WIDTH, gfx->width,
4730 GDI_HEIGHT, gfx->height,
4731 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
4732 GDI_STATE, GD_BUTTON_UNPRESSED,
4733 GDI_DESIGN_UNPRESSED, gfx->bitmap, gd_x, gd_y,
4734 GDI_DESIGN_PRESSED, gfx->bitmap, gd_xp, gd_yp,
4735 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
4736 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
4737 GDI_DECORATION_SIZE, pos->size, pos->size,
4738 GDI_DECORATION_SHIFTING, 1, 1,
4739 GDI_DIRECT_DRAW, FALSE,
4740 GDI_EVENT_MASK, event_mask,
4741 GDI_CALLBACK_ACTION, HandleToolButtons,
4745 Error(ERR_EXIT, "cannot create gadget");
4747 tool_gadget[id] = gi;
4751 void FreeToolButtons()
4755 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4756 FreeGadget(tool_gadget[i]);
4759 static void UnmapToolButtons()
4763 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4764 UnmapGadget(tool_gadget[i]);
4767 static void HandleToolButtons(struct GadgetInfo *gi)
4769 request_gadget_id = gi->custom_id;
4772 static struct Mapping_EM_to_RND_object
4775 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
4776 boolean is_backside; /* backside of moving element */
4782 em_object_mapping_list[] =
4785 Xblank, TRUE, FALSE,
4789 Yacid_splash_eB, FALSE, FALSE,
4790 EL_ACID_SPLASH_RIGHT, -1, -1
4793 Yacid_splash_wB, FALSE, FALSE,
4794 EL_ACID_SPLASH_LEFT, -1, -1
4797 #ifdef EM_ENGINE_BAD_ROLL
4799 Xstone_force_e, FALSE, FALSE,
4800 EL_ROCK, -1, MV_BIT_RIGHT
4803 Xstone_force_w, FALSE, FALSE,
4804 EL_ROCK, -1, MV_BIT_LEFT
4807 Xnut_force_e, FALSE, FALSE,
4808 EL_NUT, -1, MV_BIT_RIGHT
4811 Xnut_force_w, FALSE, FALSE,
4812 EL_NUT, -1, MV_BIT_LEFT
4815 Xspring_force_e, FALSE, FALSE,
4816 EL_SPRING, -1, MV_BIT_RIGHT
4819 Xspring_force_w, FALSE, FALSE,
4820 EL_SPRING, -1, MV_BIT_LEFT
4823 Xemerald_force_e, FALSE, FALSE,
4824 EL_EMERALD, -1, MV_BIT_RIGHT
4827 Xemerald_force_w, FALSE, FALSE,
4828 EL_EMERALD, -1, MV_BIT_LEFT
4831 Xdiamond_force_e, FALSE, FALSE,
4832 EL_DIAMOND, -1, MV_BIT_RIGHT
4835 Xdiamond_force_w, FALSE, FALSE,
4836 EL_DIAMOND, -1, MV_BIT_LEFT
4839 Xbomb_force_e, FALSE, FALSE,
4840 EL_BOMB, -1, MV_BIT_RIGHT
4843 Xbomb_force_w, FALSE, FALSE,
4844 EL_BOMB, -1, MV_BIT_LEFT
4846 #endif /* EM_ENGINE_BAD_ROLL */
4849 Xstone, TRUE, FALSE,
4853 Xstone_pause, FALSE, FALSE,
4857 Xstone_fall, FALSE, FALSE,
4861 Ystone_s, FALSE, FALSE,
4862 EL_ROCK, ACTION_FALLING, -1
4865 Ystone_sB, FALSE, TRUE,
4866 EL_ROCK, ACTION_FALLING, -1
4869 Ystone_e, FALSE, FALSE,
4870 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
4873 Ystone_eB, FALSE, TRUE,
4874 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
4877 Ystone_w, FALSE, FALSE,
4878 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
4881 Ystone_wB, FALSE, TRUE,
4882 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
4889 Xnut_pause, FALSE, FALSE,
4893 Xnut_fall, FALSE, FALSE,
4897 Ynut_s, FALSE, FALSE,
4898 EL_NUT, ACTION_FALLING, -1
4901 Ynut_sB, FALSE, TRUE,
4902 EL_NUT, ACTION_FALLING, -1
4905 Ynut_e, FALSE, FALSE,
4906 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
4909 Ynut_eB, FALSE, TRUE,
4910 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
4913 Ynut_w, FALSE, FALSE,
4914 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
4917 Ynut_wB, FALSE, TRUE,
4918 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
4921 Xbug_n, TRUE, FALSE,
4925 Xbug_e, TRUE, FALSE,
4926 EL_BUG_RIGHT, -1, -1
4929 Xbug_s, TRUE, FALSE,
4933 Xbug_w, TRUE, FALSE,
4937 Xbug_gon, FALSE, FALSE,
4941 Xbug_goe, FALSE, FALSE,
4942 EL_BUG_RIGHT, -1, -1
4945 Xbug_gos, FALSE, FALSE,
4949 Xbug_gow, FALSE, FALSE,
4953 Ybug_n, FALSE, FALSE,
4954 EL_BUG, ACTION_MOVING, MV_BIT_UP
4957 Ybug_nB, FALSE, TRUE,
4958 EL_BUG, ACTION_MOVING, MV_BIT_UP
4961 Ybug_e, FALSE, FALSE,
4962 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
4965 Ybug_eB, FALSE, TRUE,
4966 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
4969 Ybug_s, FALSE, FALSE,
4970 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
4973 Ybug_sB, FALSE, TRUE,
4974 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
4977 Ybug_w, FALSE, FALSE,
4978 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
4981 Ybug_wB, FALSE, TRUE,
4982 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
4985 Ybug_w_n, FALSE, FALSE,
4986 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
4989 Ybug_n_e, FALSE, FALSE,
4990 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
4993 Ybug_e_s, FALSE, FALSE,
4994 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
4997 Ybug_s_w, FALSE, FALSE,
4998 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
5001 Ybug_e_n, FALSE, FALSE,
5002 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
5005 Ybug_s_e, FALSE, FALSE,
5006 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
5009 Ybug_w_s, FALSE, FALSE,
5010 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
5013 Ybug_n_w, FALSE, FALSE,
5014 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
5017 Ybug_stone, FALSE, FALSE,
5018 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
5021 Ybug_spring, FALSE, FALSE,
5022 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
5025 Xtank_n, TRUE, FALSE,
5026 EL_SPACESHIP_UP, -1, -1
5029 Xtank_e, TRUE, FALSE,
5030 EL_SPACESHIP_RIGHT, -1, -1
5033 Xtank_s, TRUE, FALSE,
5034 EL_SPACESHIP_DOWN, -1, -1
5037 Xtank_w, TRUE, FALSE,
5038 EL_SPACESHIP_LEFT, -1, -1
5041 Xtank_gon, FALSE, FALSE,
5042 EL_SPACESHIP_UP, -1, -1
5045 Xtank_goe, FALSE, FALSE,
5046 EL_SPACESHIP_RIGHT, -1, -1
5049 Xtank_gos, FALSE, FALSE,
5050 EL_SPACESHIP_DOWN, -1, -1
5053 Xtank_gow, FALSE, FALSE,
5054 EL_SPACESHIP_LEFT, -1, -1
5057 Ytank_n, FALSE, FALSE,
5058 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
5061 Ytank_nB, FALSE, TRUE,
5062 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
5065 Ytank_e, FALSE, FALSE,
5066 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
5069 Ytank_eB, FALSE, TRUE,
5070 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
5073 Ytank_s, FALSE, FALSE,
5074 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
5077 Ytank_sB, FALSE, TRUE,
5078 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
5081 Ytank_w, FALSE, FALSE,
5082 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
5085 Ytank_wB, FALSE, TRUE,
5086 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
5089 Ytank_w_n, FALSE, FALSE,
5090 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
5093 Ytank_n_e, FALSE, FALSE,
5094 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
5097 Ytank_e_s, FALSE, FALSE,
5098 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
5101 Ytank_s_w, FALSE, FALSE,
5102 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
5105 Ytank_e_n, FALSE, FALSE,
5106 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
5109 Ytank_s_e, FALSE, FALSE,
5110 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
5113 Ytank_w_s, FALSE, FALSE,
5114 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
5117 Ytank_n_w, FALSE, FALSE,
5118 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
5121 Ytank_stone, FALSE, FALSE,
5122 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
5125 Ytank_spring, FALSE, FALSE,
5126 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
5129 Xandroid, TRUE, FALSE,
5130 EL_EMC_ANDROID, ACTION_ACTIVE, -1
5133 Xandroid_1_n, FALSE, FALSE,
5134 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
5137 Xandroid_2_n, FALSE, FALSE,
5138 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
5141 Xandroid_1_e, FALSE, FALSE,
5142 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
5145 Xandroid_2_e, FALSE, FALSE,
5146 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
5149 Xandroid_1_w, FALSE, FALSE,
5150 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
5153 Xandroid_2_w, FALSE, FALSE,
5154 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
5157 Xandroid_1_s, FALSE, FALSE,
5158 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
5161 Xandroid_2_s, FALSE, FALSE,
5162 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
5165 Yandroid_n, FALSE, FALSE,
5166 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
5169 Yandroid_nB, FALSE, TRUE,
5170 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
5173 Yandroid_ne, FALSE, FALSE,
5174 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
5177 Yandroid_neB, FALSE, TRUE,
5178 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
5181 Yandroid_e, FALSE, FALSE,
5182 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
5185 Yandroid_eB, FALSE, TRUE,
5186 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
5189 Yandroid_se, FALSE, FALSE,
5190 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
5193 Yandroid_seB, FALSE, TRUE,
5194 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
5197 Yandroid_s, FALSE, FALSE,
5198 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
5201 Yandroid_sB, FALSE, TRUE,
5202 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
5205 Yandroid_sw, FALSE, FALSE,
5206 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
5209 Yandroid_swB, FALSE, TRUE,
5210 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
5213 Yandroid_w, FALSE, FALSE,
5214 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
5217 Yandroid_wB, FALSE, TRUE,
5218 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
5221 Yandroid_nw, FALSE, FALSE,
5222 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
5225 Yandroid_nwB, FALSE, TRUE,
5226 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
5229 Xspring, TRUE, FALSE,
5233 Xspring_pause, FALSE, FALSE,
5237 Xspring_e, FALSE, FALSE,
5241 Xspring_w, FALSE, FALSE,
5245 Xspring_fall, FALSE, FALSE,
5249 Yspring_s, FALSE, FALSE,
5250 EL_SPRING, ACTION_FALLING, -1
5253 Yspring_sB, FALSE, TRUE,
5254 EL_SPRING, ACTION_FALLING, -1
5257 Yspring_e, FALSE, FALSE,
5258 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
5261 Yspring_eB, FALSE, TRUE,
5262 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
5265 Yspring_w, FALSE, FALSE,
5266 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
5269 Yspring_wB, FALSE, TRUE,
5270 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
5273 Yspring_kill_e, FALSE, FALSE,
5274 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
5277 Yspring_kill_eB, FALSE, TRUE,
5278 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
5281 Yspring_kill_w, FALSE, FALSE,
5282 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
5285 Yspring_kill_wB, FALSE, TRUE,
5286 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
5289 Xeater_n, TRUE, FALSE,
5290 EL_YAMYAM_UP, -1, -1
5293 Xeater_e, TRUE, FALSE,
5294 EL_YAMYAM_RIGHT, -1, -1
5297 Xeater_w, TRUE, FALSE,
5298 EL_YAMYAM_LEFT, -1, -1
5301 Xeater_s, TRUE, FALSE,
5302 EL_YAMYAM_DOWN, -1, -1
5305 Yeater_n, FALSE, FALSE,
5306 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
5309 Yeater_nB, FALSE, TRUE,
5310 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
5313 Yeater_e, FALSE, FALSE,
5314 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
5317 Yeater_eB, FALSE, TRUE,
5318 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
5321 Yeater_s, FALSE, FALSE,
5322 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
5325 Yeater_sB, FALSE, TRUE,
5326 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
5329 Yeater_w, FALSE, FALSE,
5330 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
5333 Yeater_wB, FALSE, TRUE,
5334 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
5337 Yeater_stone, FALSE, FALSE,
5338 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
5341 Yeater_spring, FALSE, FALSE,
5342 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
5345 Xalien, TRUE, FALSE,
5349 Xalien_pause, FALSE, FALSE,
5353 Yalien_n, FALSE, FALSE,
5354 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
5357 Yalien_nB, FALSE, TRUE,
5358 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
5361 Yalien_e, FALSE, FALSE,
5362 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
5365 Yalien_eB, FALSE, TRUE,
5366 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
5369 Yalien_s, FALSE, FALSE,
5370 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
5373 Yalien_sB, FALSE, TRUE,
5374 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
5377 Yalien_w, FALSE, FALSE,
5378 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
5381 Yalien_wB, FALSE, TRUE,
5382 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
5385 Yalien_stone, FALSE, FALSE,
5386 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
5389 Yalien_spring, FALSE, FALSE,
5390 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
5393 Xemerald, TRUE, FALSE,
5397 Xemerald_pause, FALSE, FALSE,
5401 Xemerald_fall, FALSE, FALSE,
5405 Xemerald_shine, FALSE, FALSE,
5406 EL_EMERALD, ACTION_TWINKLING, -1
5409 Yemerald_s, FALSE, FALSE,
5410 EL_EMERALD, ACTION_FALLING, -1
5413 Yemerald_sB, FALSE, TRUE,
5414 EL_EMERALD, ACTION_FALLING, -1
5417 Yemerald_e, FALSE, FALSE,
5418 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
5421 Yemerald_eB, FALSE, TRUE,
5422 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
5425 Yemerald_w, FALSE, FALSE,
5426 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
5429 Yemerald_wB, FALSE, TRUE,
5430 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
5433 Yemerald_eat, FALSE, FALSE,
5434 EL_EMERALD, ACTION_COLLECTING, -1
5437 Yemerald_stone, FALSE, FALSE,
5438 EL_NUT, ACTION_BREAKING, -1
5441 Xdiamond, TRUE, FALSE,
5445 Xdiamond_pause, FALSE, FALSE,
5449 Xdiamond_fall, FALSE, FALSE,
5453 Xdiamond_shine, FALSE, FALSE,
5454 EL_DIAMOND, ACTION_TWINKLING, -1
5457 Ydiamond_s, FALSE, FALSE,
5458 EL_DIAMOND, ACTION_FALLING, -1
5461 Ydiamond_sB, FALSE, TRUE,
5462 EL_DIAMOND, ACTION_FALLING, -1
5465 Ydiamond_e, FALSE, FALSE,
5466 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
5469 Ydiamond_eB, FALSE, TRUE,
5470 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
5473 Ydiamond_w, FALSE, FALSE,
5474 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
5477 Ydiamond_wB, FALSE, TRUE,
5478 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
5481 Ydiamond_eat, FALSE, FALSE,
5482 EL_DIAMOND, ACTION_COLLECTING, -1
5485 Ydiamond_stone, FALSE, FALSE,
5486 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
5489 Xdrip_fall, TRUE, FALSE,
5490 EL_AMOEBA_DROP, -1, -1
5493 Xdrip_stretch, FALSE, FALSE,
5494 EL_AMOEBA_DROP, ACTION_FALLING, -1
5497 Xdrip_stretchB, FALSE, TRUE,
5498 EL_AMOEBA_DROP, ACTION_FALLING, -1
5501 Xdrip_eat, FALSE, FALSE,
5502 EL_AMOEBA_DROP, ACTION_GROWING, -1
5505 Ydrip_s1, FALSE, FALSE,
5506 EL_AMOEBA_DROP, ACTION_FALLING, -1
5509 Ydrip_s1B, FALSE, TRUE,
5510 EL_AMOEBA_DROP, ACTION_FALLING, -1
5513 Ydrip_s2, FALSE, FALSE,
5514 EL_AMOEBA_DROP, ACTION_FALLING, -1
5517 Ydrip_s2B, FALSE, TRUE,
5518 EL_AMOEBA_DROP, ACTION_FALLING, -1
5525 Xbomb_pause, FALSE, FALSE,
5529 Xbomb_fall, FALSE, FALSE,
5533 Ybomb_s, FALSE, FALSE,
5534 EL_BOMB, ACTION_FALLING, -1
5537 Ybomb_sB, FALSE, TRUE,
5538 EL_BOMB, ACTION_FALLING, -1
5541 Ybomb_e, FALSE, FALSE,
5542 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
5545 Ybomb_eB, FALSE, TRUE,
5546 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
5549 Ybomb_w, FALSE, FALSE,
5550 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
5553 Ybomb_wB, FALSE, TRUE,
5554 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
5557 Ybomb_eat, FALSE, FALSE,
5558 EL_BOMB, ACTION_ACTIVATING, -1
5561 Xballoon, TRUE, FALSE,
5565 Yballoon_n, FALSE, FALSE,
5566 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
5569 Yballoon_nB, FALSE, TRUE,
5570 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
5573 Yballoon_e, FALSE, FALSE,
5574 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
5577 Yballoon_eB, FALSE, TRUE,
5578 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
5581 Yballoon_s, FALSE, FALSE,
5582 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
5585 Yballoon_sB, FALSE, TRUE,
5586 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
5589 Yballoon_w, FALSE, FALSE,
5590 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
5593 Yballoon_wB, FALSE, TRUE,
5594 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
5597 Xgrass, TRUE, FALSE,
5598 EL_EMC_GRASS, -1, -1
5601 Ygrass_nB, FALSE, FALSE,
5602 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
5605 Ygrass_eB, FALSE, FALSE,
5606 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
5609 Ygrass_sB, FALSE, FALSE,
5610 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
5613 Ygrass_wB, FALSE, FALSE,
5614 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
5621 Ydirt_nB, FALSE, FALSE,
5622 EL_SAND, ACTION_DIGGING, MV_BIT_UP
5625 Ydirt_eB, FALSE, FALSE,
5626 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
5629 Ydirt_sB, FALSE, FALSE,
5630 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
5633 Ydirt_wB, FALSE, FALSE,
5634 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
5637 Xacid_ne, TRUE, FALSE,
5638 EL_ACID_POOL_TOPRIGHT, -1, -1
5641 Xacid_se, TRUE, FALSE,
5642 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
5645 Xacid_s, TRUE, FALSE,
5646 EL_ACID_POOL_BOTTOM, -1, -1
5649 Xacid_sw, TRUE, FALSE,
5650 EL_ACID_POOL_BOTTOMLEFT, -1, -1
5653 Xacid_nw, TRUE, FALSE,
5654 EL_ACID_POOL_TOPLEFT, -1, -1
5657 Xacid_1, TRUE, FALSE,
5661 Xacid_2, FALSE, FALSE,
5665 Xacid_3, FALSE, FALSE,
5669 Xacid_4, FALSE, FALSE,
5673 Xacid_5, FALSE, FALSE,
5677 Xacid_6, FALSE, FALSE,
5681 Xacid_7, FALSE, FALSE,
5685 Xacid_8, FALSE, FALSE,
5689 Xball_1, TRUE, FALSE,
5690 EL_EMC_MAGIC_BALL, -1, -1
5693 Xball_1B, FALSE, FALSE,
5694 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5697 Xball_2, FALSE, FALSE,
5698 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5701 Xball_2B, FALSE, FALSE,
5702 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5705 Yball_eat, FALSE, FALSE,
5706 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
5709 Ykey_1_eat, FALSE, FALSE,
5710 EL_EM_KEY_1, ACTION_COLLECTING, -1
5713 Ykey_2_eat, FALSE, FALSE,
5714 EL_EM_KEY_2, ACTION_COLLECTING, -1
5717 Ykey_3_eat, FALSE, FALSE,
5718 EL_EM_KEY_3, ACTION_COLLECTING, -1
5721 Ykey_4_eat, FALSE, FALSE,
5722 EL_EM_KEY_4, ACTION_COLLECTING, -1
5725 Ykey_5_eat, FALSE, FALSE,
5726 EL_EMC_KEY_5, ACTION_COLLECTING, -1
5729 Ykey_6_eat, FALSE, FALSE,
5730 EL_EMC_KEY_6, ACTION_COLLECTING, -1
5733 Ykey_7_eat, FALSE, FALSE,
5734 EL_EMC_KEY_7, ACTION_COLLECTING, -1
5737 Ykey_8_eat, FALSE, FALSE,
5738 EL_EMC_KEY_8, ACTION_COLLECTING, -1
5741 Ylenses_eat, FALSE, FALSE,
5742 EL_EMC_LENSES, ACTION_COLLECTING, -1
5745 Ymagnify_eat, FALSE, FALSE,
5746 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
5749 Ygrass_eat, FALSE, FALSE,
5750 EL_EMC_GRASS, ACTION_SNAPPING, -1
5753 Ydirt_eat, FALSE, FALSE,
5754 EL_SAND, ACTION_SNAPPING, -1
5757 Xgrow_ns, TRUE, FALSE,
5758 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
5761 Ygrow_ns_eat, FALSE, FALSE,
5762 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
5765 Xgrow_ew, TRUE, FALSE,
5766 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
5769 Ygrow_ew_eat, FALSE, FALSE,
5770 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
5773 Xwonderwall, TRUE, FALSE,
5774 EL_MAGIC_WALL, -1, -1
5777 XwonderwallB, FALSE, FALSE,
5778 EL_MAGIC_WALL, ACTION_ACTIVE, -1
5781 Xamoeba_1, TRUE, FALSE,
5782 EL_AMOEBA_DRY, ACTION_OTHER, -1
5785 Xamoeba_2, FALSE, FALSE,
5786 EL_AMOEBA_DRY, ACTION_OTHER, -1
5789 Xamoeba_3, FALSE, FALSE,
5790 EL_AMOEBA_DRY, ACTION_OTHER, -1
5793 Xamoeba_4, FALSE, FALSE,
5794 EL_AMOEBA_DRY, ACTION_OTHER, -1
5797 Xamoeba_5, TRUE, FALSE,
5798 EL_AMOEBA_WET, ACTION_OTHER, -1
5801 Xamoeba_6, FALSE, FALSE,
5802 EL_AMOEBA_WET, ACTION_OTHER, -1
5805 Xamoeba_7, FALSE, FALSE,
5806 EL_AMOEBA_WET, ACTION_OTHER, -1
5809 Xamoeba_8, FALSE, FALSE,
5810 EL_AMOEBA_WET, ACTION_OTHER, -1
5813 Xdoor_1, TRUE, FALSE,
5814 EL_EM_GATE_1, -1, -1
5817 Xdoor_2, TRUE, FALSE,
5818 EL_EM_GATE_2, -1, -1
5821 Xdoor_3, TRUE, FALSE,
5822 EL_EM_GATE_3, -1, -1
5825 Xdoor_4, TRUE, FALSE,
5826 EL_EM_GATE_4, -1, -1
5829 Xdoor_5, TRUE, FALSE,
5830 EL_EMC_GATE_5, -1, -1
5833 Xdoor_6, TRUE, FALSE,
5834 EL_EMC_GATE_6, -1, -1
5837 Xdoor_7, TRUE, FALSE,
5838 EL_EMC_GATE_7, -1, -1
5841 Xdoor_8, TRUE, FALSE,
5842 EL_EMC_GATE_8, -1, -1
5845 Xkey_1, TRUE, FALSE,
5849 Xkey_2, TRUE, FALSE,
5853 Xkey_3, TRUE, FALSE,
5857 Xkey_4, TRUE, FALSE,
5861 Xkey_5, TRUE, FALSE,
5862 EL_EMC_KEY_5, -1, -1
5865 Xkey_6, TRUE, FALSE,
5866 EL_EMC_KEY_6, -1, -1
5869 Xkey_7, TRUE, FALSE,
5870 EL_EMC_KEY_7, -1, -1
5873 Xkey_8, TRUE, FALSE,
5874 EL_EMC_KEY_8, -1, -1
5877 Xwind_n, TRUE, FALSE,
5878 EL_BALLOON_SWITCH_UP, -1, -1
5881 Xwind_e, TRUE, FALSE,
5882 EL_BALLOON_SWITCH_RIGHT, -1, -1
5885 Xwind_s, TRUE, FALSE,
5886 EL_BALLOON_SWITCH_DOWN, -1, -1
5889 Xwind_w, TRUE, FALSE,
5890 EL_BALLOON_SWITCH_LEFT, -1, -1
5893 Xwind_nesw, TRUE, FALSE,
5894 EL_BALLOON_SWITCH_ANY, -1, -1
5897 Xwind_stop, TRUE, FALSE,
5898 EL_BALLOON_SWITCH_NONE, -1, -1
5902 EL_EM_EXIT_CLOSED, -1, -1
5905 Xexit_1, TRUE, FALSE,
5906 EL_EM_EXIT_OPEN, -1, -1
5909 Xexit_2, FALSE, FALSE,
5910 EL_EM_EXIT_OPEN, -1, -1
5913 Xexit_3, FALSE, FALSE,
5914 EL_EM_EXIT_OPEN, -1, -1
5917 Xdynamite, TRUE, FALSE,
5918 EL_EM_DYNAMITE, -1, -1
5921 Ydynamite_eat, FALSE, FALSE,
5922 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
5925 Xdynamite_1, TRUE, FALSE,
5926 EL_EM_DYNAMITE_ACTIVE, -1, -1
5929 Xdynamite_2, FALSE, FALSE,
5930 EL_EM_DYNAMITE_ACTIVE, -1, -1
5933 Xdynamite_3, FALSE, FALSE,
5934 EL_EM_DYNAMITE_ACTIVE, -1, -1
5937 Xdynamite_4, FALSE, FALSE,
5938 EL_EM_DYNAMITE_ACTIVE, -1, -1
5941 Xbumper, TRUE, FALSE,
5942 EL_EMC_SPRING_BUMPER, -1, -1
5945 XbumperB, FALSE, FALSE,
5946 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
5949 Xwheel, TRUE, FALSE,
5950 EL_ROBOT_WHEEL, -1, -1
5953 XwheelB, FALSE, FALSE,
5954 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
5957 Xswitch, TRUE, FALSE,
5958 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
5961 XswitchB, FALSE, FALSE,
5962 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
5966 EL_QUICKSAND_EMPTY, -1, -1
5969 Xsand_stone, TRUE, FALSE,
5970 EL_QUICKSAND_FULL, -1, -1
5973 Xsand_stonein_1, FALSE, TRUE,
5974 EL_ROCK, ACTION_FILLING, -1
5977 Xsand_stonein_2, FALSE, TRUE,
5978 EL_ROCK, ACTION_FILLING, -1
5981 Xsand_stonein_3, FALSE, TRUE,
5982 EL_ROCK, ACTION_FILLING, -1
5985 Xsand_stonein_4, FALSE, TRUE,
5986 EL_ROCK, ACTION_FILLING, -1
5989 Xsand_stonesand_1, FALSE, FALSE,
5990 EL_QUICKSAND_EMPTYING, -1, -1
5993 Xsand_stonesand_2, FALSE, FALSE,
5994 EL_QUICKSAND_EMPTYING, -1, -1
5997 Xsand_stonesand_3, FALSE, FALSE,
5998 EL_QUICKSAND_EMPTYING, -1, -1
6001 Xsand_stonesand_4, FALSE, FALSE,
6002 EL_QUICKSAND_EMPTYING, -1, -1
6005 Xsand_stonesand_quickout_1, FALSE, FALSE,
6006 EL_QUICKSAND_EMPTYING, -1, -1
6009 Xsand_stonesand_quickout_2, FALSE, FALSE,
6010 EL_QUICKSAND_EMPTYING, -1, -1
6013 Xsand_stoneout_1, FALSE, FALSE,
6014 EL_ROCK, ACTION_EMPTYING, -1
6017 Xsand_stoneout_2, FALSE, FALSE,
6018 EL_ROCK, ACTION_EMPTYING, -1
6021 Xsand_sandstone_1, FALSE, FALSE,
6022 EL_QUICKSAND_FILLING, -1, -1
6025 Xsand_sandstone_2, FALSE, FALSE,
6026 EL_QUICKSAND_FILLING, -1, -1
6029 Xsand_sandstone_3, FALSE, FALSE,
6030 EL_QUICKSAND_FILLING, -1, -1
6033 Xsand_sandstone_4, FALSE, FALSE,
6034 EL_QUICKSAND_FILLING, -1, -1
6037 Xplant, TRUE, FALSE,
6038 EL_EMC_PLANT, -1, -1
6041 Yplant, FALSE, FALSE,
6042 EL_EMC_PLANT, -1, -1
6045 Xlenses, TRUE, FALSE,
6046 EL_EMC_LENSES, -1, -1
6049 Xmagnify, TRUE, FALSE,
6050 EL_EMC_MAGNIFIER, -1, -1
6053 Xdripper, TRUE, FALSE,
6054 EL_EMC_DRIPPER, -1, -1
6057 XdripperB, FALSE, FALSE,
6058 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
6061 Xfake_blank, TRUE, FALSE,
6062 EL_INVISIBLE_WALL, -1, -1
6065 Xfake_blankB, FALSE, FALSE,
6066 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
6069 Xfake_grass, TRUE, FALSE,
6070 EL_EMC_FAKE_GRASS, -1, -1
6073 Xfake_grassB, FALSE, FALSE,
6074 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
6077 Xfake_door_1, TRUE, FALSE,
6078 EL_EM_GATE_1_GRAY, -1, -1
6081 Xfake_door_2, TRUE, FALSE,
6082 EL_EM_GATE_2_GRAY, -1, -1
6085 Xfake_door_3, TRUE, FALSE,
6086 EL_EM_GATE_3_GRAY, -1, -1
6089 Xfake_door_4, TRUE, FALSE,
6090 EL_EM_GATE_4_GRAY, -1, -1
6093 Xfake_door_5, TRUE, FALSE,
6094 EL_EMC_GATE_5_GRAY, -1, -1
6097 Xfake_door_6, TRUE, FALSE,
6098 EL_EMC_GATE_6_GRAY, -1, -1
6101 Xfake_door_7, TRUE, FALSE,
6102 EL_EMC_GATE_7_GRAY, -1, -1
6105 Xfake_door_8, TRUE, FALSE,
6106 EL_EMC_GATE_8_GRAY, -1, -1
6109 Xfake_acid_1, TRUE, FALSE,
6110 EL_EMC_FAKE_ACID, -1, -1
6113 Xfake_acid_2, FALSE, FALSE,
6114 EL_EMC_FAKE_ACID, -1, -1
6117 Xfake_acid_3, FALSE, FALSE,
6118 EL_EMC_FAKE_ACID, -1, -1
6121 Xfake_acid_4, FALSE, FALSE,
6122 EL_EMC_FAKE_ACID, -1, -1
6125 Xfake_acid_5, FALSE, FALSE,
6126 EL_EMC_FAKE_ACID, -1, -1
6129 Xfake_acid_6, FALSE, FALSE,
6130 EL_EMC_FAKE_ACID, -1, -1
6133 Xfake_acid_7, FALSE, FALSE,
6134 EL_EMC_FAKE_ACID, -1, -1
6137 Xfake_acid_8, FALSE, FALSE,
6138 EL_EMC_FAKE_ACID, -1, -1
6141 Xsteel_1, TRUE, FALSE,
6142 EL_STEELWALL, -1, -1
6145 Xsteel_2, TRUE, FALSE,
6146 EL_EMC_STEELWALL_2, -1, -1
6149 Xsteel_3, TRUE, FALSE,
6150 EL_EMC_STEELWALL_3, -1, -1
6153 Xsteel_4, TRUE, FALSE,
6154 EL_EMC_STEELWALL_4, -1, -1
6157 Xwall_1, TRUE, FALSE,
6161 Xwall_2, TRUE, FALSE,
6162 EL_EMC_WALL_14, -1, -1
6165 Xwall_3, TRUE, FALSE,
6166 EL_EMC_WALL_15, -1, -1
6169 Xwall_4, TRUE, FALSE,
6170 EL_EMC_WALL_16, -1, -1
6173 Xround_wall_1, TRUE, FALSE,
6174 EL_WALL_SLIPPERY, -1, -1
6177 Xround_wall_2, TRUE, FALSE,
6178 EL_EMC_WALL_SLIPPERY_2, -1, -1
6181 Xround_wall_3, TRUE, FALSE,
6182 EL_EMC_WALL_SLIPPERY_3, -1, -1
6185 Xround_wall_4, TRUE, FALSE,
6186 EL_EMC_WALL_SLIPPERY_4, -1, -1
6189 Xdecor_1, TRUE, FALSE,
6190 EL_EMC_WALL_8, -1, -1
6193 Xdecor_2, TRUE, FALSE,
6194 EL_EMC_WALL_6, -1, -1
6197 Xdecor_3, TRUE, FALSE,
6198 EL_EMC_WALL_4, -1, -1
6201 Xdecor_4, TRUE, FALSE,
6202 EL_EMC_WALL_7, -1, -1
6205 Xdecor_5, TRUE, FALSE,
6206 EL_EMC_WALL_5, -1, -1
6209 Xdecor_6, TRUE, FALSE,
6210 EL_EMC_WALL_9, -1, -1
6213 Xdecor_7, TRUE, FALSE,
6214 EL_EMC_WALL_10, -1, -1
6217 Xdecor_8, TRUE, FALSE,
6218 EL_EMC_WALL_1, -1, -1
6221 Xdecor_9, TRUE, FALSE,
6222 EL_EMC_WALL_2, -1, -1
6225 Xdecor_10, TRUE, FALSE,
6226 EL_EMC_WALL_3, -1, -1
6229 Xdecor_11, TRUE, FALSE,
6230 EL_EMC_WALL_11, -1, -1
6233 Xdecor_12, TRUE, FALSE,
6234 EL_EMC_WALL_12, -1, -1
6237 Xalpha_0, TRUE, FALSE,
6238 EL_CHAR('0'), -1, -1
6241 Xalpha_1, TRUE, FALSE,
6242 EL_CHAR('1'), -1, -1
6245 Xalpha_2, TRUE, FALSE,
6246 EL_CHAR('2'), -1, -1
6249 Xalpha_3, TRUE, FALSE,
6250 EL_CHAR('3'), -1, -1
6253 Xalpha_4, TRUE, FALSE,
6254 EL_CHAR('4'), -1, -1
6257 Xalpha_5, TRUE, FALSE,
6258 EL_CHAR('5'), -1, -1
6261 Xalpha_6, TRUE, FALSE,
6262 EL_CHAR('6'), -1, -1
6265 Xalpha_7, TRUE, FALSE,
6266 EL_CHAR('7'), -1, -1
6269 Xalpha_8, TRUE, FALSE,
6270 EL_CHAR('8'), -1, -1
6273 Xalpha_9, TRUE, FALSE,
6274 EL_CHAR('9'), -1, -1
6277 Xalpha_excla, TRUE, FALSE,
6278 EL_CHAR('!'), -1, -1
6281 Xalpha_quote, TRUE, FALSE,
6282 EL_CHAR('"'), -1, -1
6285 Xalpha_comma, TRUE, FALSE,
6286 EL_CHAR(','), -1, -1
6289 Xalpha_minus, TRUE, FALSE,
6290 EL_CHAR('-'), -1, -1
6293 Xalpha_perio, TRUE, FALSE,
6294 EL_CHAR('.'), -1, -1
6297 Xalpha_colon, TRUE, FALSE,
6298 EL_CHAR(':'), -1, -1
6301 Xalpha_quest, TRUE, FALSE,
6302 EL_CHAR('?'), -1, -1
6305 Xalpha_a, TRUE, FALSE,
6306 EL_CHAR('A'), -1, -1
6309 Xalpha_b, TRUE, FALSE,
6310 EL_CHAR('B'), -1, -1
6313 Xalpha_c, TRUE, FALSE,
6314 EL_CHAR('C'), -1, -1
6317 Xalpha_d, TRUE, FALSE,
6318 EL_CHAR('D'), -1, -1
6321 Xalpha_e, TRUE, FALSE,
6322 EL_CHAR('E'), -1, -1
6325 Xalpha_f, TRUE, FALSE,
6326 EL_CHAR('F'), -1, -1
6329 Xalpha_g, TRUE, FALSE,
6330 EL_CHAR('G'), -1, -1
6333 Xalpha_h, TRUE, FALSE,
6334 EL_CHAR('H'), -1, -1
6337 Xalpha_i, TRUE, FALSE,
6338 EL_CHAR('I'), -1, -1
6341 Xalpha_j, TRUE, FALSE,
6342 EL_CHAR('J'), -1, -1
6345 Xalpha_k, TRUE, FALSE,
6346 EL_CHAR('K'), -1, -1
6349 Xalpha_l, TRUE, FALSE,
6350 EL_CHAR('L'), -1, -1
6353 Xalpha_m, TRUE, FALSE,
6354 EL_CHAR('M'), -1, -1
6357 Xalpha_n, TRUE, FALSE,
6358 EL_CHAR('N'), -1, -1
6361 Xalpha_o, TRUE, FALSE,
6362 EL_CHAR('O'), -1, -1
6365 Xalpha_p, TRUE, FALSE,
6366 EL_CHAR('P'), -1, -1
6369 Xalpha_q, TRUE, FALSE,
6370 EL_CHAR('Q'), -1, -1
6373 Xalpha_r, TRUE, FALSE,
6374 EL_CHAR('R'), -1, -1
6377 Xalpha_s, TRUE, FALSE,
6378 EL_CHAR('S'), -1, -1
6381 Xalpha_t, TRUE, FALSE,
6382 EL_CHAR('T'), -1, -1
6385 Xalpha_u, TRUE, FALSE,
6386 EL_CHAR('U'), -1, -1
6389 Xalpha_v, TRUE, FALSE,
6390 EL_CHAR('V'), -1, -1
6393 Xalpha_w, TRUE, FALSE,
6394 EL_CHAR('W'), -1, -1
6397 Xalpha_x, TRUE, FALSE,
6398 EL_CHAR('X'), -1, -1
6401 Xalpha_y, TRUE, FALSE,
6402 EL_CHAR('Y'), -1, -1
6405 Xalpha_z, TRUE, FALSE,
6406 EL_CHAR('Z'), -1, -1
6409 Xalpha_arrow_e, TRUE, FALSE,
6410 EL_CHAR('>'), -1, -1
6413 Xalpha_arrow_w, TRUE, FALSE,
6414 EL_CHAR('<'), -1, -1
6417 Xalpha_copyr, TRUE, FALSE,
6418 EL_CHAR(CHAR_BYTE_COPYRIGHT), -1, -1
6422 Xboom_bug, FALSE, FALSE,
6423 EL_BUG, ACTION_EXPLODING, -1
6426 Xboom_bomb, FALSE, FALSE,
6427 EL_BOMB, ACTION_EXPLODING, -1
6430 Xboom_android, FALSE, FALSE,
6431 EL_EMC_ANDROID, ACTION_OTHER, -1
6434 Xboom_1, FALSE, FALSE,
6435 EL_DEFAULT, ACTION_EXPLODING, -1
6438 Xboom_2, FALSE, FALSE,
6439 EL_DEFAULT, ACTION_EXPLODING, -1
6442 Znormal, FALSE, FALSE,
6446 Zdynamite, FALSE, FALSE,
6450 Zplayer, FALSE, FALSE,
6454 ZBORDER, FALSE, FALSE,
6464 static struct Mapping_EM_to_RND_player
6473 em_player_mapping_list[] =
6477 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
6481 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
6485 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
6489 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
6493 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
6497 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
6501 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
6505 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
6509 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
6513 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
6517 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
6521 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
6525 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
6529 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
6533 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
6537 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
6541 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
6545 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
6549 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
6553 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
6557 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
6561 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
6565 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
6569 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
6573 EL_PLAYER_1, ACTION_DEFAULT, -1,
6577 EL_PLAYER_2, ACTION_DEFAULT, -1,
6581 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
6585 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
6589 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
6593 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
6597 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
6601 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
6605 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
6609 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
6613 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
6617 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
6621 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
6625 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
6629 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
6633 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
6637 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
6641 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
6645 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
6649 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
6653 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
6657 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
6661 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
6665 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
6669 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
6673 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
6677 EL_PLAYER_3, ACTION_DEFAULT, -1,
6681 EL_PLAYER_4, ACTION_DEFAULT, -1,
6690 int map_element_RND_to_EM(int element_rnd)
6692 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
6693 static boolean mapping_initialized = FALSE;
6695 if (!mapping_initialized)
6699 /* return "Xalpha_quest" for all undefined elements in mapping array */
6700 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
6701 mapping_RND_to_EM[i] = Xalpha_quest;
6703 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6704 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
6705 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
6706 em_object_mapping_list[i].element_em;
6708 mapping_initialized = TRUE;
6711 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
6712 return mapping_RND_to_EM[element_rnd];
6714 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
6719 int map_element_EM_to_RND(int element_em)
6721 static unsigned short mapping_EM_to_RND[TILE_MAX];
6722 static boolean mapping_initialized = FALSE;
6724 if (!mapping_initialized)
6728 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
6729 for (i = 0; i < TILE_MAX; i++)
6730 mapping_EM_to_RND[i] = EL_UNKNOWN;
6732 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6733 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
6734 em_object_mapping_list[i].element_rnd;
6736 mapping_initialized = TRUE;
6739 if (element_em >= 0 && element_em < TILE_MAX)
6740 return mapping_EM_to_RND[element_em];
6742 Error(ERR_WARN, "invalid EM level element %d", element_em);
6747 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
6749 struct LevelInfo_EM *level_em = level->native_em_level;
6750 struct LEVEL *lev = level_em->lev;
6753 for (i = 0; i < TILE_MAX; i++)
6754 lev->android_array[i] = Xblank;
6756 for (i = 0; i < level->num_android_clone_elements; i++)
6758 int element_rnd = level->android_clone_element[i];
6759 int element_em = map_element_RND_to_EM(element_rnd);
6761 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
6762 if (em_object_mapping_list[j].element_rnd == element_rnd)
6763 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
6767 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
6769 struct LevelInfo_EM *level_em = level->native_em_level;
6770 struct LEVEL *lev = level_em->lev;
6773 level->num_android_clone_elements = 0;
6775 for (i = 0; i < TILE_MAX; i++)
6777 int element_em = lev->android_array[i];
6779 boolean element_found = FALSE;
6781 if (element_em == Xblank)
6784 element_rnd = map_element_EM_to_RND(element_em);
6786 for (j = 0; j < level->num_android_clone_elements; j++)
6787 if (level->android_clone_element[j] == element_rnd)
6788 element_found = TRUE;
6792 level->android_clone_element[level->num_android_clone_elements++] =
6795 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
6800 if (level->num_android_clone_elements == 0)
6802 level->num_android_clone_elements = 1;
6803 level->android_clone_element[0] = EL_EMPTY;
6807 int map_direction_RND_to_EM(int direction)
6809 return (direction == MV_UP ? 0 :
6810 direction == MV_RIGHT ? 1 :
6811 direction == MV_DOWN ? 2 :
6812 direction == MV_LEFT ? 3 :
6816 int map_direction_EM_to_RND(int direction)
6818 return (direction == 0 ? MV_UP :
6819 direction == 1 ? MV_RIGHT :
6820 direction == 2 ? MV_DOWN :
6821 direction == 3 ? MV_LEFT :
6825 int map_element_RND_to_SP(int element_rnd)
6827 int element_sp = 0x20; /* map unknown elements to yellow "hardware" */
6829 if (element_rnd >= EL_SP_START &&
6830 element_rnd <= EL_SP_END)
6831 element_sp = element_rnd - EL_SP_START;
6832 else if (element_rnd == EL_EMPTY_SPACE)
6834 else if (element_rnd == EL_INVISIBLE_WALL)
6840 int map_element_SP_to_RND(int element_sp)
6842 int element_rnd = EL_UNKNOWN;
6844 if (element_sp >= 0x00 &&
6846 element_rnd = EL_SP_START + element_sp;
6847 else if (element_sp == 0x28)
6848 element_rnd = EL_INVISIBLE_WALL;
6853 int map_action_SP_to_RND(int action_sp)
6857 case actActive: return ACTION_ACTIVE;
6858 case actImpact: return ACTION_IMPACT;
6859 case actExploding: return ACTION_EXPLODING;
6860 case actDigging: return ACTION_DIGGING;
6861 case actSnapping: return ACTION_SNAPPING;
6862 case actCollecting: return ACTION_COLLECTING;
6863 case actPassing: return ACTION_PASSING;
6864 case actPushing: return ACTION_PUSHING;
6865 case actDropping: return ACTION_DROPPING;
6867 default: return ACTION_DEFAULT;
6871 int get_next_element(int element)
6875 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
6876 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
6877 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
6878 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
6879 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
6880 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
6881 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
6882 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
6883 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
6884 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
6885 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
6887 default: return element;
6891 int el_act_dir2img(int element, int action, int direction)
6893 element = GFX_ELEMENT(element);
6894 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
6896 /* direction_graphic[][] == graphic[] for undefined direction graphics */
6897 return element_info[element].direction_graphic[action][direction];
6900 static int el_act_dir2crm(int element, int action, int direction)
6902 element = GFX_ELEMENT(element);
6903 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
6905 /* direction_graphic[][] == graphic[] for undefined direction graphics */
6906 return element_info[element].direction_crumbled[action][direction];
6909 int el_act2img(int element, int action)
6911 element = GFX_ELEMENT(element);
6913 return element_info[element].graphic[action];
6916 int el_act2crm(int element, int action)
6918 element = GFX_ELEMENT(element);
6920 return element_info[element].crumbled[action];
6923 int el_dir2img(int element, int direction)
6925 element = GFX_ELEMENT(element);
6927 return el_act_dir2img(element, ACTION_DEFAULT, direction);
6930 int el2baseimg(int element)
6932 return element_info[element].graphic[ACTION_DEFAULT];
6935 int el2img(int element)
6937 element = GFX_ELEMENT(element);
6939 return element_info[element].graphic[ACTION_DEFAULT];
6942 int el2edimg(int element)
6944 element = GFX_ELEMENT(element);
6946 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
6949 int el2preimg(int element)
6951 element = GFX_ELEMENT(element);
6953 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
6956 int el2panelimg(int element)
6958 element = GFX_ELEMENT(element);
6960 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL];
6963 int font2baseimg(int font_nr)
6965 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
6968 int getBeltNrFromBeltElement(int element)
6970 return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
6971 element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
6972 element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
6975 int getBeltNrFromBeltActiveElement(int element)
6977 return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
6978 element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
6979 element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
6982 int getBeltNrFromBeltSwitchElement(int element)
6984 return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
6985 element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
6986 element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
6989 int getBeltDirNrFromBeltElement(int element)
6991 static int belt_base_element[4] =
6993 EL_CONVEYOR_BELT_1_LEFT,
6994 EL_CONVEYOR_BELT_2_LEFT,
6995 EL_CONVEYOR_BELT_3_LEFT,
6996 EL_CONVEYOR_BELT_4_LEFT
6999 int belt_nr = getBeltNrFromBeltElement(element);
7000 int belt_dir_nr = element - belt_base_element[belt_nr];
7002 return (belt_dir_nr % 3);
7005 int getBeltDirNrFromBeltSwitchElement(int element)
7007 static int belt_base_element[4] =
7009 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
7010 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
7011 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
7012 EL_CONVEYOR_BELT_4_SWITCH_LEFT
7015 int belt_nr = getBeltNrFromBeltSwitchElement(element);
7016 int belt_dir_nr = element - belt_base_element[belt_nr];
7018 return (belt_dir_nr % 3);
7021 int getBeltDirFromBeltElement(int element)
7023 static int belt_move_dir[3] =
7030 int belt_dir_nr = getBeltDirNrFromBeltElement(element);
7032 return belt_move_dir[belt_dir_nr];
7035 int getBeltDirFromBeltSwitchElement(int element)
7037 static int belt_move_dir[3] =
7044 int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
7046 return belt_move_dir[belt_dir_nr];
7049 int getBeltElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
7051 static int belt_base_element[4] =
7053 EL_CONVEYOR_BELT_1_LEFT,
7054 EL_CONVEYOR_BELT_2_LEFT,
7055 EL_CONVEYOR_BELT_3_LEFT,
7056 EL_CONVEYOR_BELT_4_LEFT
7059 return belt_base_element[belt_nr] + belt_dir_nr;
7062 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
7064 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
7066 return getBeltElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
7069 int getBeltSwitchElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
7071 static int belt_base_element[4] =
7073 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
7074 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
7075 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
7076 EL_CONVEYOR_BELT_4_SWITCH_LEFT
7079 return belt_base_element[belt_nr] + belt_dir_nr;
7082 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
7084 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
7086 return getBeltSwitchElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
7089 boolean getTeamMode_EM()
7091 return game.team_mode;
7094 int getGameFrameDelay_EM(int native_em_game_frame_delay)
7096 int game_frame_delay_value;
7098 game_frame_delay_value =
7099 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
7100 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
7103 if (tape.playing && tape.warp_forward && !tape.pausing)
7104 game_frame_delay_value = 0;
7106 return game_frame_delay_value;
7109 unsigned int InitRND(int seed)
7111 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
7112 return InitEngineRandom_EM(seed);
7113 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
7114 return InitEngineRandom_SP(seed);
7116 return InitEngineRandom_RND(seed);
7119 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
7120 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
7122 inline static int get_effective_element_EM(int tile, int frame_em)
7124 int element = object_mapping[tile].element_rnd;
7125 int action = object_mapping[tile].action;
7126 boolean is_backside = object_mapping[tile].is_backside;
7127 boolean action_removing = (action == ACTION_DIGGING ||
7128 action == ACTION_SNAPPING ||
7129 action == ACTION_COLLECTING);
7135 case Yacid_splash_eB:
7136 case Yacid_splash_wB:
7137 return (frame_em > 5 ? EL_EMPTY : element);
7143 else /* frame_em == 7 */
7147 case Yacid_splash_eB:
7148 case Yacid_splash_wB:
7151 case Yemerald_stone:
7154 case Ydiamond_stone:
7158 case Xdrip_stretchB:
7177 case Xsand_stonein_1:
7178 case Xsand_stonein_2:
7179 case Xsand_stonein_3:
7180 case Xsand_stonein_4:
7184 return (is_backside || action_removing ? EL_EMPTY : element);
7189 inline static boolean check_linear_animation_EM(int tile)
7193 case Xsand_stonesand_1:
7194 case Xsand_stonesand_quickout_1:
7195 case Xsand_sandstone_1:
7196 case Xsand_stonein_1:
7197 case Xsand_stoneout_1:
7216 case Yacid_splash_eB:
7217 case Yacid_splash_wB:
7218 case Yemerald_stone:
7225 inline static void set_crumbled_graphics_EM(struct GraphicInfo_EM *g_em,
7226 boolean has_crumbled_graphics,
7227 int crumbled, int sync_frame)
7229 /* if element can be crumbled, but certain action graphics are just empty
7230 space (like instantly snapping sand to empty space in 1 frame), do not
7231 treat these empty space graphics as crumbled graphics in EMC engine */
7232 if (crumbled == IMG_EMPTY_SPACE)
7233 has_crumbled_graphics = FALSE;
7235 if (has_crumbled_graphics)
7237 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
7238 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
7239 g_crumbled->anim_delay,
7240 g_crumbled->anim_mode,
7241 g_crumbled->anim_start_frame,
7244 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
7245 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
7247 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
7249 g_em->has_crumbled_graphics = TRUE;
7253 g_em->crumbled_bitmap = NULL;
7254 g_em->crumbled_src_x = 0;
7255 g_em->crumbled_src_y = 0;
7256 g_em->crumbled_border_size = 0;
7258 g_em->has_crumbled_graphics = FALSE;
7262 void ResetGfxAnimation_EM(int x, int y, int tile)
7267 void SetGfxAnimation_EM(struct GraphicInfo_EM *g_em,
7268 int tile, int frame_em, int x, int y)
7270 int action = object_mapping[tile].action;
7271 int direction = object_mapping[tile].direction;
7272 int effective_element = get_effective_element_EM(tile, frame_em);
7273 int graphic = (direction == MV_NONE ?
7274 el_act2img(effective_element, action) :
7275 el_act_dir2img(effective_element, action, direction));
7276 struct GraphicInfo *g = &graphic_info[graphic];
7278 boolean action_removing = (action == ACTION_DIGGING ||
7279 action == ACTION_SNAPPING ||
7280 action == ACTION_COLLECTING);
7281 boolean action_moving = (action == ACTION_FALLING ||
7282 action == ACTION_MOVING ||
7283 action == ACTION_PUSHING ||
7284 action == ACTION_EATING ||
7285 action == ACTION_FILLING ||
7286 action == ACTION_EMPTYING);
7287 boolean action_falling = (action == ACTION_FALLING ||
7288 action == ACTION_FILLING ||
7289 action == ACTION_EMPTYING);
7291 /* special case: graphic uses "2nd movement tile" and has defined
7292 7 frames for movement animation (or less) => use default graphic
7293 for last (8th) frame which ends the movement animation */
7294 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
7296 action = ACTION_DEFAULT; /* (keep action_* unchanged for now) */
7297 graphic = (direction == MV_NONE ?
7298 el_act2img(effective_element, action) :
7299 el_act_dir2img(effective_element, action, direction));
7301 g = &graphic_info[graphic];
7304 if ((action_removing || check_linear_animation_EM(tile)) && frame_em == 0)
7308 else if (action_moving)
7310 boolean is_backside = object_mapping[tile].is_backside;
7314 int direction = object_mapping[tile].direction;
7315 int move_dir = (action_falling ? MV_DOWN : direction);
7320 /* !!! TEST !!! NEW !!! DOES NOT WORK RIGHT YET !!! */
7321 if (g->double_movement && frame_em == 0)
7325 if (move_dir == MV_LEFT)
7326 GfxFrame[x - 1][y] = GfxFrame[x][y];
7327 else if (move_dir == MV_RIGHT)
7328 GfxFrame[x + 1][y] = GfxFrame[x][y];
7329 else if (move_dir == MV_UP)
7330 GfxFrame[x][y - 1] = GfxFrame[x][y];
7331 else if (move_dir == MV_DOWN)
7332 GfxFrame[x][y + 1] = GfxFrame[x][y];
7339 /* special case: animation for Xsand_stonesand_quickout_1/2 twice as fast */
7340 if (tile == Xsand_stonesand_quickout_1 ||
7341 tile == Xsand_stonesand_quickout_2)
7345 if (graphic_info[graphic].anim_global_sync)
7346 sync_frame = FrameCounter;
7347 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
7348 sync_frame = GfxFrame[x][y];
7350 sync_frame = 0; /* playfield border (pseudo steel) */
7352 SetRandomAnimationValue(x, y);
7354 int frame = getAnimationFrame(g->anim_frames,
7357 g->anim_start_frame,
7360 g_em->unique_identifier =
7361 (graphic << 16) | ((frame % 8) << 12) | (g_em->width << 6) | g_em->height;
7364 void getGraphicSourceObjectExt_EM(struct GraphicInfo_EM *g_em,
7365 int tile, int frame_em, int x, int y)
7367 int action = object_mapping[tile].action;
7368 int direction = object_mapping[tile].direction;
7369 boolean is_backside = object_mapping[tile].is_backside;
7370 int effective_element = get_effective_element_EM(tile, frame_em);
7371 int effective_action = action;
7372 int graphic = (direction == MV_NONE ?
7373 el_act2img(effective_element, effective_action) :
7374 el_act_dir2img(effective_element, effective_action,
7376 int crumbled = (direction == MV_NONE ?
7377 el_act2crm(effective_element, effective_action) :
7378 el_act_dir2crm(effective_element, effective_action,
7380 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7381 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7382 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7383 struct GraphicInfo *g = &graphic_info[graphic];
7386 /* special case: graphic uses "2nd movement tile" and has defined
7387 7 frames for movement animation (or less) => use default graphic
7388 for last (8th) frame which ends the movement animation */
7389 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
7391 effective_action = ACTION_DEFAULT;
7392 graphic = (direction == MV_NONE ?
7393 el_act2img(effective_element, effective_action) :
7394 el_act_dir2img(effective_element, effective_action,
7396 crumbled = (direction == MV_NONE ?
7397 el_act2crm(effective_element, effective_action) :
7398 el_act_dir2crm(effective_element, effective_action,
7401 g = &graphic_info[graphic];
7404 if (graphic_info[graphic].anim_global_sync)
7405 sync_frame = FrameCounter;
7406 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
7407 sync_frame = GfxFrame[x][y];
7409 sync_frame = 0; /* playfield border (pseudo steel) */
7411 SetRandomAnimationValue(x, y);
7413 int frame = getAnimationFrame(g->anim_frames,
7416 g->anim_start_frame,
7419 getGraphicSourceExt(graphic, frame, &g_em->bitmap, &g_em->src_x, &g_em->src_y,
7420 g->double_movement && is_backside);
7422 /* (updating the "crumbled" graphic definitions is probably not really needed,
7423 as animations for crumbled graphics can't be longer than one EMC cycle) */
7424 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
7428 void getGraphicSourcePlayerExt_EM(struct GraphicInfo_EM *g_em,
7429 int player_nr, int anim, int frame_em)
7431 int element = player_mapping[player_nr][anim].element_rnd;
7432 int action = player_mapping[player_nr][anim].action;
7433 int direction = player_mapping[player_nr][anim].direction;
7434 int graphic = (direction == MV_NONE ?
7435 el_act2img(element, action) :
7436 el_act_dir2img(element, action, direction));
7437 struct GraphicInfo *g = &graphic_info[graphic];
7440 InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
7442 stored_player[player_nr].StepFrame = frame_em;
7444 sync_frame = stored_player[player_nr].Frame;
7446 int frame = getAnimationFrame(g->anim_frames,
7449 g->anim_start_frame,
7452 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
7453 &g_em->src_x, &g_em->src_y, FALSE);
7456 void InitGraphicInfo_EM(void)
7461 int num_em_gfx_errors = 0;
7463 if (graphic_info_em_object[0][0].bitmap == NULL)
7465 /* EM graphics not yet initialized in em_open_all() */
7470 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
7473 /* always start with reliable default values */
7474 for (i = 0; i < TILE_MAX; i++)
7476 object_mapping[i].element_rnd = EL_UNKNOWN;
7477 object_mapping[i].is_backside = FALSE;
7478 object_mapping[i].action = ACTION_DEFAULT;
7479 object_mapping[i].direction = MV_NONE;
7482 /* always start with reliable default values */
7483 for (p = 0; p < MAX_PLAYERS; p++)
7485 for (i = 0; i < SPR_MAX; i++)
7487 player_mapping[p][i].element_rnd = EL_UNKNOWN;
7488 player_mapping[p][i].action = ACTION_DEFAULT;
7489 player_mapping[p][i].direction = MV_NONE;
7493 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
7495 int e = em_object_mapping_list[i].element_em;
7497 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
7498 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
7500 if (em_object_mapping_list[i].action != -1)
7501 object_mapping[e].action = em_object_mapping_list[i].action;
7503 if (em_object_mapping_list[i].direction != -1)
7504 object_mapping[e].direction =
7505 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
7508 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
7510 int a = em_player_mapping_list[i].action_em;
7511 int p = em_player_mapping_list[i].player_nr;
7513 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
7515 if (em_player_mapping_list[i].action != -1)
7516 player_mapping[p][a].action = em_player_mapping_list[i].action;
7518 if (em_player_mapping_list[i].direction != -1)
7519 player_mapping[p][a].direction =
7520 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
7523 for (i = 0; i < TILE_MAX; i++)
7525 int element = object_mapping[i].element_rnd;
7526 int action = object_mapping[i].action;
7527 int direction = object_mapping[i].direction;
7528 boolean is_backside = object_mapping[i].is_backside;
7529 boolean action_exploding = ((action == ACTION_EXPLODING ||
7530 action == ACTION_SMASHED_BY_ROCK ||
7531 action == ACTION_SMASHED_BY_SPRING) &&
7532 element != EL_DIAMOND);
7533 boolean action_active = (action == ACTION_ACTIVE);
7534 boolean action_other = (action == ACTION_OTHER);
7536 for (j = 0; j < 8; j++)
7538 int effective_element = get_effective_element_EM(i, j);
7539 int effective_action = (j < 7 ? action :
7540 i == Xdrip_stretch ? action :
7541 i == Xdrip_stretchB ? action :
7542 i == Ydrip_s1 ? action :
7543 i == Ydrip_s1B ? action :
7544 i == Xball_1B ? action :
7545 i == Xball_2 ? action :
7546 i == Xball_2B ? action :
7547 i == Yball_eat ? action :
7548 i == Ykey_1_eat ? action :
7549 i == Ykey_2_eat ? action :
7550 i == Ykey_3_eat ? action :
7551 i == Ykey_4_eat ? action :
7552 i == Ykey_5_eat ? action :
7553 i == Ykey_6_eat ? action :
7554 i == Ykey_7_eat ? action :
7555 i == Ykey_8_eat ? action :
7556 i == Ylenses_eat ? action :
7557 i == Ymagnify_eat ? action :
7558 i == Ygrass_eat ? action :
7559 i == Ydirt_eat ? action :
7560 i == Xsand_stonein_1 ? action :
7561 i == Xsand_stonein_2 ? action :
7562 i == Xsand_stonein_3 ? action :
7563 i == Xsand_stonein_4 ? action :
7564 i == Xsand_stoneout_1 ? action :
7565 i == Xsand_stoneout_2 ? action :
7566 i == Xboom_android ? ACTION_EXPLODING :
7567 action_exploding ? ACTION_EXPLODING :
7568 action_active ? action :
7569 action_other ? action :
7571 int graphic = (el_act_dir2img(effective_element, effective_action,
7573 int crumbled = (el_act_dir2crm(effective_element, effective_action,
7575 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7576 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7577 boolean has_action_graphics = (graphic != base_graphic);
7578 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7579 struct GraphicInfo *g = &graphic_info[graphic];
7580 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7583 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
7584 boolean special_animation = (action != ACTION_DEFAULT &&
7585 g->anim_frames == 3 &&
7586 g->anim_delay == 2 &&
7587 g->anim_mode & ANIM_LINEAR);
7588 int sync_frame = (i == Xdrip_stretch ? 7 :
7589 i == Xdrip_stretchB ? 7 :
7590 i == Ydrip_s2 ? j + 8 :
7591 i == Ydrip_s2B ? j + 8 :
7600 i == Xfake_acid_1 ? 0 :
7601 i == Xfake_acid_2 ? 10 :
7602 i == Xfake_acid_3 ? 20 :
7603 i == Xfake_acid_4 ? 30 :
7604 i == Xfake_acid_5 ? 40 :
7605 i == Xfake_acid_6 ? 50 :
7606 i == Xfake_acid_7 ? 60 :
7607 i == Xfake_acid_8 ? 70 :
7609 i == Xball_2B ? j + 8 :
7610 i == Yball_eat ? j + 1 :
7611 i == Ykey_1_eat ? j + 1 :
7612 i == Ykey_2_eat ? j + 1 :
7613 i == Ykey_3_eat ? j + 1 :
7614 i == Ykey_4_eat ? j + 1 :
7615 i == Ykey_5_eat ? j + 1 :
7616 i == Ykey_6_eat ? j + 1 :
7617 i == Ykey_7_eat ? j + 1 :
7618 i == Ykey_8_eat ? j + 1 :
7619 i == Ylenses_eat ? j + 1 :
7620 i == Ymagnify_eat ? j + 1 :
7621 i == Ygrass_eat ? j + 1 :
7622 i == Ydirt_eat ? j + 1 :
7623 i == Xamoeba_1 ? 0 :
7624 i == Xamoeba_2 ? 1 :
7625 i == Xamoeba_3 ? 2 :
7626 i == Xamoeba_4 ? 3 :
7627 i == Xamoeba_5 ? 0 :
7628 i == Xamoeba_6 ? 1 :
7629 i == Xamoeba_7 ? 2 :
7630 i == Xamoeba_8 ? 3 :
7631 i == Xexit_2 ? j + 8 :
7632 i == Xexit_3 ? j + 16 :
7633 i == Xdynamite_1 ? 0 :
7634 i == Xdynamite_2 ? 8 :
7635 i == Xdynamite_3 ? 16 :
7636 i == Xdynamite_4 ? 24 :
7637 i == Xsand_stonein_1 ? j + 1 :
7638 i == Xsand_stonein_2 ? j + 9 :
7639 i == Xsand_stonein_3 ? j + 17 :
7640 i == Xsand_stonein_4 ? j + 25 :
7641 i == Xsand_stoneout_1 && j == 0 ? 0 :
7642 i == Xsand_stoneout_1 && j == 1 ? 0 :
7643 i == Xsand_stoneout_1 && j == 2 ? 1 :
7644 i == Xsand_stoneout_1 && j == 3 ? 2 :
7645 i == Xsand_stoneout_1 && j == 4 ? 2 :
7646 i == Xsand_stoneout_1 && j == 5 ? 3 :
7647 i == Xsand_stoneout_1 && j == 6 ? 4 :
7648 i == Xsand_stoneout_1 && j == 7 ? 4 :
7649 i == Xsand_stoneout_2 && j == 0 ? 5 :
7650 i == Xsand_stoneout_2 && j == 1 ? 6 :
7651 i == Xsand_stoneout_2 && j == 2 ? 7 :
7652 i == Xsand_stoneout_2 && j == 3 ? 8 :
7653 i == Xsand_stoneout_2 && j == 4 ? 9 :
7654 i == Xsand_stoneout_2 && j == 5 ? 11 :
7655 i == Xsand_stoneout_2 && j == 6 ? 13 :
7656 i == Xsand_stoneout_2 && j == 7 ? 15 :
7657 i == Xboom_bug && j == 1 ? 2 :
7658 i == Xboom_bug && j == 2 ? 2 :
7659 i == Xboom_bug && j == 3 ? 4 :
7660 i == Xboom_bug && j == 4 ? 4 :
7661 i == Xboom_bug && j == 5 ? 2 :
7662 i == Xboom_bug && j == 6 ? 2 :
7663 i == Xboom_bug && j == 7 ? 0 :
7664 i == Xboom_bomb && j == 1 ? 2 :
7665 i == Xboom_bomb && j == 2 ? 2 :
7666 i == Xboom_bomb && j == 3 ? 4 :
7667 i == Xboom_bomb && j == 4 ? 4 :
7668 i == Xboom_bomb && j == 5 ? 2 :
7669 i == Xboom_bomb && j == 6 ? 2 :
7670 i == Xboom_bomb && j == 7 ? 0 :
7671 i == Xboom_android && j == 7 ? 6 :
7672 i == Xboom_1 && j == 1 ? 2 :
7673 i == Xboom_1 && j == 2 ? 2 :
7674 i == Xboom_1 && j == 3 ? 4 :
7675 i == Xboom_1 && j == 4 ? 4 :
7676 i == Xboom_1 && j == 5 ? 6 :
7677 i == Xboom_1 && j == 6 ? 6 :
7678 i == Xboom_1 && j == 7 ? 8 :
7679 i == Xboom_2 && j == 0 ? 8 :
7680 i == Xboom_2 && j == 1 ? 8 :
7681 i == Xboom_2 && j == 2 ? 10 :
7682 i == Xboom_2 && j == 3 ? 10 :
7683 i == Xboom_2 && j == 4 ? 10 :
7684 i == Xboom_2 && j == 5 ? 12 :
7685 i == Xboom_2 && j == 6 ? 12 :
7686 i == Xboom_2 && j == 7 ? 12 :
7687 special_animation && j == 4 ? 3 :
7688 effective_action != action ? 0 :
7692 Bitmap *debug_bitmap = g_em->bitmap;
7693 int debug_src_x = g_em->src_x;
7694 int debug_src_y = g_em->src_y;
7697 int frame = getAnimationFrame(g->anim_frames,
7700 g->anim_start_frame,
7703 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
7704 g->double_movement && is_backside);
7706 g_em->bitmap = src_bitmap;
7707 g_em->src_x = src_x;
7708 g_em->src_y = src_y;
7709 g_em->src_offset_x = 0;
7710 g_em->src_offset_y = 0;
7711 g_em->dst_offset_x = 0;
7712 g_em->dst_offset_y = 0;
7713 g_em->width = TILEX;
7714 g_em->height = TILEY;
7716 g_em->preserve_background = FALSE;
7718 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
7721 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
7722 effective_action == ACTION_MOVING ||
7723 effective_action == ACTION_PUSHING ||
7724 effective_action == ACTION_EATING)) ||
7725 (!has_action_graphics && (effective_action == ACTION_FILLING ||
7726 effective_action == ACTION_EMPTYING)))
7729 (effective_action == ACTION_FALLING ||
7730 effective_action == ACTION_FILLING ||
7731 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
7732 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
7733 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
7734 int num_steps = (i == Ydrip_s1 ? 16 :
7735 i == Ydrip_s1B ? 16 :
7736 i == Ydrip_s2 ? 16 :
7737 i == Ydrip_s2B ? 16 :
7738 i == Xsand_stonein_1 ? 32 :
7739 i == Xsand_stonein_2 ? 32 :
7740 i == Xsand_stonein_3 ? 32 :
7741 i == Xsand_stonein_4 ? 32 :
7742 i == Xsand_stoneout_1 ? 16 :
7743 i == Xsand_stoneout_2 ? 16 : 8);
7744 int cx = ABS(dx) * (TILEX / num_steps);
7745 int cy = ABS(dy) * (TILEY / num_steps);
7746 int step_frame = (i == Ydrip_s2 ? j + 8 :
7747 i == Ydrip_s2B ? j + 8 :
7748 i == Xsand_stonein_2 ? j + 8 :
7749 i == Xsand_stonein_3 ? j + 16 :
7750 i == Xsand_stonein_4 ? j + 24 :
7751 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
7752 int step = (is_backside ? step_frame : num_steps - step_frame);
7754 if (is_backside) /* tile where movement starts */
7756 if (dx < 0 || dy < 0)
7758 g_em->src_offset_x = cx * step;
7759 g_em->src_offset_y = cy * step;
7763 g_em->dst_offset_x = cx * step;
7764 g_em->dst_offset_y = cy * step;
7767 else /* tile where movement ends */
7769 if (dx < 0 || dy < 0)
7771 g_em->dst_offset_x = cx * step;
7772 g_em->dst_offset_y = cy * step;
7776 g_em->src_offset_x = cx * step;
7777 g_em->src_offset_y = cy * step;
7781 g_em->width = TILEX - cx * step;
7782 g_em->height = TILEY - cy * step;
7785 /* create unique graphic identifier to decide if tile must be redrawn */
7786 /* bit 31 - 16 (16 bit): EM style graphic
7787 bit 15 - 12 ( 4 bit): EM style frame
7788 bit 11 - 6 ( 6 bit): graphic width
7789 bit 5 - 0 ( 6 bit): graphic height */
7790 g_em->unique_identifier =
7791 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
7795 /* skip check for EMC elements not contained in original EMC artwork */
7796 if (element == EL_EMC_FAKE_ACID)
7799 if (g_em->bitmap != debug_bitmap ||
7800 g_em->src_x != debug_src_x ||
7801 g_em->src_y != debug_src_y ||
7802 g_em->src_offset_x != 0 ||
7803 g_em->src_offset_y != 0 ||
7804 g_em->dst_offset_x != 0 ||
7805 g_em->dst_offset_y != 0 ||
7806 g_em->width != TILEX ||
7807 g_em->height != TILEY)
7809 static int last_i = -1;
7817 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
7818 i, element, element_info[element].token_name,
7819 element_action_info[effective_action].suffix, direction);
7821 if (element != effective_element)
7822 printf(" [%d ('%s')]",
7824 element_info[effective_element].token_name);
7828 if (g_em->bitmap != debug_bitmap)
7829 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
7830 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
7832 if (g_em->src_x != debug_src_x ||
7833 g_em->src_y != debug_src_y)
7834 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
7835 j, (is_backside ? 'B' : 'F'),
7836 g_em->src_x, g_em->src_y,
7837 g_em->src_x / 32, g_em->src_y / 32,
7838 debug_src_x, debug_src_y,
7839 debug_src_x / 32, debug_src_y / 32);
7841 if (g_em->src_offset_x != 0 ||
7842 g_em->src_offset_y != 0 ||
7843 g_em->dst_offset_x != 0 ||
7844 g_em->dst_offset_y != 0)
7845 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
7847 g_em->src_offset_x, g_em->src_offset_y,
7848 g_em->dst_offset_x, g_em->dst_offset_y);
7850 if (g_em->width != TILEX ||
7851 g_em->height != TILEY)
7852 printf(" %d (%d): size %d,%d should be %d,%d\n",
7854 g_em->width, g_em->height, TILEX, TILEY);
7856 num_em_gfx_errors++;
7863 for (i = 0; i < TILE_MAX; i++)
7865 for (j = 0; j < 8; j++)
7867 int element = object_mapping[i].element_rnd;
7868 int action = object_mapping[i].action;
7869 int direction = object_mapping[i].direction;
7870 boolean is_backside = object_mapping[i].is_backside;
7871 int graphic_action = el_act_dir2img(element, action, direction);
7872 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
7874 if ((action == ACTION_SMASHED_BY_ROCK ||
7875 action == ACTION_SMASHED_BY_SPRING ||
7876 action == ACTION_EATING) &&
7877 graphic_action == graphic_default)
7879 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
7880 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
7881 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
7882 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
7885 /* no separate animation for "smashed by rock" -- use rock instead */
7886 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7887 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
7889 g_em->bitmap = g_xx->bitmap;
7890 g_em->src_x = g_xx->src_x;
7891 g_em->src_y = g_xx->src_y;
7892 g_em->src_offset_x = g_xx->src_offset_x;
7893 g_em->src_offset_y = g_xx->src_offset_y;
7894 g_em->dst_offset_x = g_xx->dst_offset_x;
7895 g_em->dst_offset_y = g_xx->dst_offset_y;
7896 g_em->width = g_xx->width;
7897 g_em->height = g_xx->height;
7898 g_em->unique_identifier = g_xx->unique_identifier;
7901 g_em->preserve_background = TRUE;
7906 for (p = 0; p < MAX_PLAYERS; p++)
7908 for (i = 0; i < SPR_MAX; i++)
7910 int element = player_mapping[p][i].element_rnd;
7911 int action = player_mapping[p][i].action;
7912 int direction = player_mapping[p][i].direction;
7914 for (j = 0; j < 8; j++)
7916 int effective_element = element;
7917 int effective_action = action;
7918 int graphic = (direction == MV_NONE ?
7919 el_act2img(effective_element, effective_action) :
7920 el_act_dir2img(effective_element, effective_action,
7922 struct GraphicInfo *g = &graphic_info[graphic];
7923 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
7929 Bitmap *debug_bitmap = g_em->bitmap;
7930 int debug_src_x = g_em->src_x;
7931 int debug_src_y = g_em->src_y;
7934 int frame = getAnimationFrame(g->anim_frames,
7937 g->anim_start_frame,
7940 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
7942 g_em->bitmap = src_bitmap;
7943 g_em->src_x = src_x;
7944 g_em->src_y = src_y;
7945 g_em->src_offset_x = 0;
7946 g_em->src_offset_y = 0;
7947 g_em->dst_offset_x = 0;
7948 g_em->dst_offset_y = 0;
7949 g_em->width = TILEX;
7950 g_em->height = TILEY;
7954 /* skip check for EMC elements not contained in original EMC artwork */
7955 if (element == EL_PLAYER_3 ||
7956 element == EL_PLAYER_4)
7959 if (g_em->bitmap != debug_bitmap ||
7960 g_em->src_x != debug_src_x ||
7961 g_em->src_y != debug_src_y)
7963 static int last_i = -1;
7971 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
7972 p, i, element, element_info[element].token_name,
7973 element_action_info[effective_action].suffix, direction);
7975 if (element != effective_element)
7976 printf(" [%d ('%s')]",
7978 element_info[effective_element].token_name);
7982 if (g_em->bitmap != debug_bitmap)
7983 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
7984 j, (int)(g_em->bitmap), (int)(debug_bitmap));
7986 if (g_em->src_x != debug_src_x ||
7987 g_em->src_y != debug_src_y)
7988 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
7990 g_em->src_x, g_em->src_y,
7991 g_em->src_x / 32, g_em->src_y / 32,
7992 debug_src_x, debug_src_y,
7993 debug_src_x / 32, debug_src_y / 32);
7995 num_em_gfx_errors++;
8005 printf("::: [%d errors found]\n", num_em_gfx_errors);
8011 void CheckSaveEngineSnapshot_EM(byte action[MAX_PLAYERS], int frame,
8012 boolean any_player_moving,
8013 boolean any_player_snapping,
8014 boolean any_player_dropping)
8016 static boolean player_was_waiting = TRUE;
8018 if (frame == 0 && !any_player_dropping)
8020 if (!player_was_waiting)
8022 if (!SaveEngineSnapshotToList())
8025 player_was_waiting = TRUE;
8028 else if (any_player_moving || any_player_snapping || any_player_dropping)
8030 player_was_waiting = FALSE;
8034 void CheckSaveEngineSnapshot_SP(boolean murphy_is_waiting,
8035 boolean murphy_is_dropping)
8037 static boolean player_was_waiting = TRUE;
8039 if (murphy_is_waiting)
8041 if (!player_was_waiting)
8043 if (!SaveEngineSnapshotToList())
8046 player_was_waiting = TRUE;
8051 player_was_waiting = FALSE;
8055 void CheckSingleStepMode_EM(byte action[MAX_PLAYERS], int frame,
8056 boolean any_player_moving,
8057 boolean any_player_snapping,
8058 boolean any_player_dropping)
8060 if (tape.single_step && tape.recording && !tape.pausing)
8061 if (frame == 0 && !any_player_dropping)
8062 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
8064 CheckSaveEngineSnapshot_EM(action, frame, any_player_moving,
8065 any_player_snapping, any_player_dropping);
8068 void CheckSingleStepMode_SP(boolean murphy_is_waiting,
8069 boolean murphy_is_dropping)
8071 if (tape.single_step && tape.recording && !tape.pausing)
8072 if (murphy_is_waiting)
8073 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
8075 CheckSaveEngineSnapshot_SP(murphy_is_waiting, murphy_is_dropping);
8078 void getGraphicSource_SP(struct GraphicInfo_SP *g_sp,
8079 int graphic, int sync_frame, int x, int y)
8081 int frame = getGraphicAnimationFrame(graphic, sync_frame);
8083 getGraphicSource(graphic, frame, &g_sp->bitmap, &g_sp->src_x, &g_sp->src_y);
8086 boolean isNextAnimationFrame_SP(int graphic, int sync_frame)
8088 return (IS_NEXT_FRAME(sync_frame, graphic));
8091 int getGraphicInfo_Delay(int graphic)
8093 return graphic_info[graphic].anim_delay;
8096 void PlayMenuSoundExt(int sound)
8098 if (sound == SND_UNDEFINED)
8101 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8102 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8105 if (IS_LOOP_SOUND(sound))
8106 PlaySoundLoop(sound);
8111 void PlayMenuSound()
8113 PlayMenuSoundExt(menu.sound[game_status]);
8116 void PlayMenuSoundStereo(int sound, int stereo_position)
8118 if (sound == SND_UNDEFINED)
8121 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8122 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8125 if (IS_LOOP_SOUND(sound))
8126 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
8128 PlaySoundStereo(sound, stereo_position);
8131 void PlayMenuSoundIfLoopExt(int sound)
8133 if (sound == SND_UNDEFINED)
8136 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8137 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8140 if (IS_LOOP_SOUND(sound))
8141 PlaySoundLoop(sound);
8144 void PlayMenuSoundIfLoop()
8146 PlayMenuSoundIfLoopExt(menu.sound[game_status]);
8149 void PlayMenuMusicExt(int music)
8151 if (music == MUS_UNDEFINED)
8154 if (!setup.sound_music)
8160 void PlayMenuMusic()
8162 PlayMenuMusicExt(menu.music[game_status]);
8165 void PlaySoundActivating()
8168 PlaySound(SND_MENU_ITEM_ACTIVATING);
8172 void PlaySoundSelecting()
8175 PlaySound(SND_MENU_ITEM_SELECTING);
8179 void ToggleFullscreenOrChangeWindowScalingIfNeeded()
8181 boolean change_fullscreen = (setup.fullscreen !=
8182 video.fullscreen_enabled);
8183 boolean change_window_scaling_percent = (!video.fullscreen_enabled &&
8184 setup.window_scaling_percent !=
8185 video.window_scaling_percent);
8187 if (change_window_scaling_percent && video.fullscreen_enabled)
8190 if (!change_window_scaling_percent && !video.fullscreen_available)
8193 #if defined(TARGET_SDL2)
8194 if (change_window_scaling_percent)
8196 SDLSetWindowScaling(setup.window_scaling_percent);
8200 else if (change_fullscreen)
8202 SDLSetWindowFullscreen(setup.fullscreen);
8204 /* set setup value according to successfully changed fullscreen mode */
8205 setup.fullscreen = video.fullscreen_enabled;
8211 if (change_fullscreen ||
8212 change_window_scaling_percent)
8214 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
8216 /* save backbuffer content which gets lost when toggling fullscreen mode */
8217 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8219 if (change_window_scaling_percent)
8221 /* keep window mode, but change window scaling */
8222 video.fullscreen_enabled = TRUE; /* force new window scaling */
8225 /* toggle fullscreen */
8226 ChangeVideoModeIfNeeded(setup.fullscreen);
8228 /* set setup value according to successfully changed fullscreen mode */
8229 setup.fullscreen = video.fullscreen_enabled;
8231 /* restore backbuffer content from temporary backbuffer backup bitmap */
8232 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8234 FreeBitmap(tmp_backbuffer);
8236 /* update visible window/screen */
8237 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8241 void JoinRectangles(int *x, int *y, int *width, int *height,
8242 int x2, int y2, int width2, int height2)
8244 // do not join with "off-screen" rectangle
8245 if (x2 == -1 || y2 == -1)
8250 *width = MAX(*width, width2);
8251 *height = MAX(*height, height2);
8254 void SetAnimStatus(int anim_status_new)
8256 if (anim_status_new == GAME_MODE_MAIN)
8257 anim_status_new = GAME_MODE_PSEUDO_MAINONLY;
8259 global.anim_status_next = anim_status_new;
8261 // directly set screen modes that are entered without fading
8262 if ((global.anim_status == GAME_MODE_PSEUDO_MAINONLY &&
8263 global.anim_status_next == GAME_MODE_PSEUDO_TYPENAME) ||
8264 (global.anim_status == GAME_MODE_PSEUDO_TYPENAME &&
8265 global.anim_status_next == GAME_MODE_PSEUDO_MAINONLY))
8266 global.anim_status = global.anim_status_next;
8269 void SetGameStatus(int game_status_new)
8271 game_status = game_status_new;
8273 SetAnimStatus(game_status_new);
8276 void SetFontStatus(int game_status_new)
8278 static int last_game_status = -1;
8280 if (game_status_new != -1)
8282 // set game status for font use after storing last game status
8283 last_game_status = game_status;
8284 game_status = game_status_new;
8288 // reset game status after font use from last stored game status
8289 game_status = last_game_status;
8293 void ResetFontStatus()
8298 void ChangeViewportPropertiesIfNeeded()
8300 int gfx_game_mode = game_status;
8301 int gfx_game_mode2 = (game_status == GAME_MODE_EDITOR ? GAME_MODE_DEFAULT :
8303 struct RectWithBorder *vp_window = &viewport.window[gfx_game_mode];
8304 struct RectWithBorder *vp_playfield = &viewport.playfield[gfx_game_mode];
8305 struct RectWithBorder *vp_door_1 = &viewport.door_1[gfx_game_mode];
8306 struct RectWithBorder *vp_door_2 = &viewport.door_2[gfx_game_mode2];
8307 struct RectWithBorder *vp_door_3 = &viewport.door_2[GAME_MODE_EDITOR];
8308 int new_win_xsize = vp_window->width;
8309 int new_win_ysize = vp_window->height;
8310 int border_size = vp_playfield->border_size;
8311 int new_sx = vp_playfield->x + border_size;
8312 int new_sy = vp_playfield->y + border_size;
8313 int new_sxsize = vp_playfield->width - 2 * border_size;
8314 int new_sysize = vp_playfield->height - 2 * border_size;
8315 int new_real_sx = vp_playfield->x;
8316 int new_real_sy = vp_playfield->y;
8317 int new_full_sxsize = vp_playfield->width;
8318 int new_full_sysize = vp_playfield->height;
8319 int new_dx = vp_door_1->x;
8320 int new_dy = vp_door_1->y;
8321 int new_dxsize = vp_door_1->width;
8322 int new_dysize = vp_door_1->height;
8323 int new_vx = vp_door_2->x;
8324 int new_vy = vp_door_2->y;
8325 int new_vxsize = vp_door_2->width;
8326 int new_vysize = vp_door_2->height;
8327 int new_ex = vp_door_3->x;
8328 int new_ey = vp_door_3->y;
8329 int new_exsize = vp_door_3->width;
8330 int new_eysize = vp_door_3->height;
8331 int new_tilesize_var =
8332 (setup.small_game_graphics ? MINI_TILESIZE : game.tile_size);
8334 int tilesize = (gfx_game_mode == GAME_MODE_PLAYING ? new_tilesize_var :
8335 gfx_game_mode == GAME_MODE_EDITOR ? MINI_TILESIZE : TILESIZE);
8336 int new_scr_fieldx = new_sxsize / tilesize;
8337 int new_scr_fieldy = new_sysize / tilesize;
8338 int new_scr_fieldx_buffers = new_sxsize / new_tilesize_var;
8339 int new_scr_fieldy_buffers = new_sysize / new_tilesize_var;
8340 boolean init_gfx_buffers = FALSE;
8341 boolean init_video_buffer = FALSE;
8342 boolean init_gadgets_and_anims = FALSE;
8343 boolean init_em_graphics = FALSE;
8345 if (new_win_xsize != WIN_XSIZE ||
8346 new_win_ysize != WIN_YSIZE)
8348 WIN_XSIZE = new_win_xsize;
8349 WIN_YSIZE = new_win_ysize;
8351 init_video_buffer = TRUE;
8352 init_gfx_buffers = TRUE;
8353 init_gadgets_and_anims = TRUE;
8355 // printf("::: video: init_video_buffer, init_gfx_buffers\n");
8358 if (new_scr_fieldx != SCR_FIELDX ||
8359 new_scr_fieldy != SCR_FIELDY)
8361 /* this always toggles between MAIN and GAME when using small tile size */
8363 SCR_FIELDX = new_scr_fieldx;
8364 SCR_FIELDY = new_scr_fieldy;
8366 // printf("::: new_scr_fieldx != SCR_FIELDX ...\n");
8377 new_sxsize != SXSIZE ||
8378 new_sysize != SYSIZE ||
8379 new_dxsize != DXSIZE ||
8380 new_dysize != DYSIZE ||
8381 new_vxsize != VXSIZE ||
8382 new_vysize != VYSIZE ||
8383 new_exsize != EXSIZE ||
8384 new_eysize != EYSIZE ||
8385 new_real_sx != REAL_SX ||
8386 new_real_sy != REAL_SY ||
8387 new_full_sxsize != FULL_SXSIZE ||
8388 new_full_sysize != FULL_SYSIZE ||
8389 new_tilesize_var != TILESIZE_VAR
8392 // ------------------------------------------------------------------------
8393 // determine next fading area for changed viewport definitions
8394 // ------------------------------------------------------------------------
8396 // start with current playfield area (default fading area)
8399 FADE_SXSIZE = FULL_SXSIZE;
8400 FADE_SYSIZE = FULL_SYSIZE;
8402 // add new playfield area if position or size has changed
8403 if (new_real_sx != REAL_SX || new_real_sy != REAL_SY ||
8404 new_full_sxsize != FULL_SXSIZE || new_full_sysize != FULL_SYSIZE)
8406 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
8407 new_real_sx, new_real_sy, new_full_sxsize,new_full_sysize);
8410 // add current and new door 1 area if position or size has changed
8411 if (new_dx != DX || new_dy != DY ||
8412 new_dxsize != DXSIZE || new_dysize != DYSIZE)
8414 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
8415 DX, DY, DXSIZE, DYSIZE);
8416 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
8417 new_dx, new_dy, new_dxsize, new_dysize);
8420 // add current and new door 2 area if position or size has changed
8421 if (new_dx != VX || new_dy != VY ||
8422 new_dxsize != VXSIZE || new_dysize != VYSIZE)
8424 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
8425 VX, VY, VXSIZE, VYSIZE);
8426 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
8427 new_vx, new_vy, new_vxsize, new_vysize);
8430 // ------------------------------------------------------------------------
8431 // handle changed tile size
8432 // ------------------------------------------------------------------------
8434 if (new_tilesize_var != TILESIZE_VAR)
8436 // printf("::: new_tilesize_var != TILESIZE_VAR\n");
8438 // changing tile size invalidates scroll values of engine snapshots
8439 FreeEngineSnapshotSingle();
8441 // changing tile size requires update of graphic mapping for EM engine
8442 init_em_graphics = TRUE;
8453 SXSIZE = new_sxsize;
8454 SYSIZE = new_sysize;
8455 DXSIZE = new_dxsize;
8456 DYSIZE = new_dysize;
8457 VXSIZE = new_vxsize;
8458 VYSIZE = new_vysize;
8459 EXSIZE = new_exsize;
8460 EYSIZE = new_eysize;
8461 REAL_SX = new_real_sx;
8462 REAL_SY = new_real_sy;
8463 FULL_SXSIZE = new_full_sxsize;
8464 FULL_SYSIZE = new_full_sysize;
8465 TILESIZE_VAR = new_tilesize_var;
8467 init_gfx_buffers = TRUE;
8468 init_gadgets_and_anims = TRUE;
8470 // printf("::: viewports: init_gfx_buffers\n");
8471 // printf("::: viewports: init_gadgets_and_anims\n");
8474 if (init_gfx_buffers)
8476 // printf("::: init_gfx_buffers\n");
8478 SCR_FIELDX = new_scr_fieldx_buffers;
8479 SCR_FIELDY = new_scr_fieldy_buffers;
8483 SCR_FIELDX = new_scr_fieldx;
8484 SCR_FIELDY = new_scr_fieldy;
8486 SetDrawDeactivationMask(REDRAW_NONE);
8487 SetDrawBackgroundMask(REDRAW_FIELD);
8490 if (init_video_buffer)
8492 // printf("::: init_video_buffer\n");
8494 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
8495 InitImageTextures();
8498 if (init_gadgets_and_anims)
8500 // printf("::: init_gadgets_and_anims\n");
8503 InitGlobalAnimations();
8506 if (init_em_graphics)
8508 InitGraphicInfo_EM();