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_DOOR_1_GFX_PART_1,
74 IMG_DOOR_1_GFX_PART_2,
79 IMG_DOOR_1_GFX_PART_3,
84 IMG_DOOR_1_GFX_PART_4,
89 IMG_DOOR_1_GFX_PART_5,
94 IMG_DOOR_1_GFX_PART_6,
99 IMG_DOOR_1_GFX_PART_7,
104 IMG_DOOR_1_GFX_PART_8,
110 IMG_DOOR_2_GFX_PART_1,
115 IMG_DOOR_2_GFX_PART_2,
120 IMG_DOOR_2_GFX_PART_3,
125 IMG_DOOR_2_GFX_PART_4,
130 IMG_DOOR_2_GFX_PART_5,
135 IMG_DOOR_2_GFX_PART_6,
140 IMG_DOOR_2_GFX_PART_7,
145 IMG_DOOR_2_GFX_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 unsigned int sync_frame_delay = 0;
178 static unsigned int sync_frame_delay_value = GAME_FRAME_DELAY;
180 static char *print_if_not_empty(int element)
182 static char *s = NULL;
183 char *token_name = element_info[element].token_name;
188 s = checked_malloc(strlen(token_name) + 10 + 1);
190 if (element != EL_EMPTY)
191 sprintf(s, "%d\t['%s']", element, token_name);
193 sprintf(s, "%d", element);
198 void DumpTile(int x, int y)
203 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
209 printf_line("-", 79);
210 printf("Field Info: SCREEN(%d, %d), LEVEL(%d, %d)\n", sx, sy, x, y);
211 printf_line("-", 79);
213 if (!IN_LEV_FIELD(x, y))
215 printf("(not in level field)\n");
221 printf(" Feld: %d\t['%s']\n", Feld[x][y],
222 element_info[Feld[x][y]].token_name);
223 printf(" Back: %s\n", print_if_not_empty(Back[x][y]));
224 printf(" Store: %s\n", print_if_not_empty(Store[x][y]));
225 printf(" Store2: %s\n", print_if_not_empty(Store2[x][y]));
226 printf(" StorePlayer: %s\n", print_if_not_empty(StorePlayer[x][y]));
227 printf(" MovPos: %d\n", MovPos[x][y]);
228 printf(" MovDir: %d\n", MovDir[x][y]);
229 printf(" MovDelay: %d\n", MovDelay[x][y]);
230 printf(" ChangeDelay: %d\n", ChangeDelay[x][y]);
231 printf(" CustomValue: %d\n", CustomValue[x][y]);
232 printf(" GfxElement: %d\n", GfxElement[x][y]);
233 printf(" GfxAction: %d\n", GfxAction[x][y]);
234 printf(" GfxFrame: %d [%d]\n", GfxFrame[x][y], FrameCounter);
238 void SetDrawtoField(int mode)
240 if (mode == DRAW_FIELDBUFFER)
246 BX2 = SCR_FIELDX + 1;
247 BY2 = SCR_FIELDY + 1;
249 drawto_field = fieldbuffer;
251 else /* DRAW_BACKBUFFER */
257 BX2 = SCR_FIELDX - 1;
258 BY2 = SCR_FIELDY - 1;
260 drawto_field = backbuffer;
264 static void RedrawPlayfield_RND()
266 if (game.envelope_active)
269 DrawLevel(REDRAW_ALL);
273 void RedrawPlayfield()
275 if (game_status != GAME_MODE_PLAYING)
278 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
279 RedrawPlayfield_EM(TRUE);
280 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
281 RedrawPlayfield_SP(TRUE);
282 else if (level.game_engine_type == GAME_ENGINE_TYPE_RND)
283 RedrawPlayfield_RND();
285 BlitScreenToBitmap(backbuffer);
287 BlitBitmap(drawto, window, gfx.sx, gfx.sy, gfx.sxsize, gfx.sysize,
291 static void DrawMaskedBorderExt_Rect(int x, int y, int width, int height,
294 Bitmap *src_bitmap = getGlobalBorderBitmapFromStatus(global.border_status);
295 Bitmap *dst_bitmap = gfx.masked_border_bitmap_ptr;
297 if (x == -1 && y == -1)
300 if (draw_target == DRAW_BORDER_TO_SCREEN)
301 BlitToScreenMasked(src_bitmap, x, y, width, height, x, y);
303 BlitBitmapMasked(src_bitmap, dst_bitmap, x, y, width, height, x, y);
306 static void DrawMaskedBorderExt_FIELD(int draw_target)
308 if (global.border_status >= GAME_MODE_MAIN &&
309 global.border_status <= GAME_MODE_PLAYING &&
310 border.draw_masked[global.border_status])
311 DrawMaskedBorderExt_Rect(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
315 static void DrawMaskedBorderExt_DOOR_1(int draw_target)
317 // when drawing to backbuffer, never draw border over open doors
318 if (draw_target == DRAW_BORDER_TO_BACKBUFFER &&
319 (GetDoorState() & DOOR_OPEN_1))
322 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
323 (global.border_status != GAME_MODE_EDITOR ||
324 border.draw_masked[GFX_SPECIAL_ARG_EDITOR]))
325 DrawMaskedBorderExt_Rect(DX, DY, DXSIZE, DYSIZE, draw_target);
328 static void DrawMaskedBorderExt_DOOR_2(int draw_target)
330 // when drawing to backbuffer, never draw border over open doors
331 if (draw_target == DRAW_BORDER_TO_BACKBUFFER &&
332 (GetDoorState() & DOOR_OPEN_2))
335 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
336 global.border_status != GAME_MODE_EDITOR)
337 DrawMaskedBorderExt_Rect(VX, VY, VXSIZE, VYSIZE, draw_target);
340 static void DrawMaskedBorderExt_DOOR_3(int draw_target)
342 /* currently not available */
345 static void DrawMaskedBorderExt_ALL(int draw_target)
347 DrawMaskedBorderExt_FIELD(draw_target);
348 DrawMaskedBorderExt_DOOR_1(draw_target);
349 DrawMaskedBorderExt_DOOR_2(draw_target);
350 DrawMaskedBorderExt_DOOR_3(draw_target);
353 static void DrawMaskedBorderExt(int redraw_mask, int draw_target)
355 /* never draw masked screen borders on borderless screens */
356 if (global.border_status == GAME_MODE_LOADING ||
357 global.border_status == GAME_MODE_TITLE)
360 if (redraw_mask & REDRAW_ALL)
361 DrawMaskedBorderExt_ALL(draw_target);
364 if (redraw_mask & REDRAW_FIELD)
365 DrawMaskedBorderExt_FIELD(draw_target);
366 if (redraw_mask & REDRAW_DOOR_1)
367 DrawMaskedBorderExt_DOOR_1(draw_target);
368 if (redraw_mask & REDRAW_DOOR_2)
369 DrawMaskedBorderExt_DOOR_2(draw_target);
370 if (redraw_mask & REDRAW_DOOR_3)
371 DrawMaskedBorderExt_DOOR_3(draw_target);
375 void DrawMaskedBorder_FIELD()
377 DrawMaskedBorderExt_FIELD(DRAW_BORDER_TO_BACKBUFFER);
380 void DrawMaskedBorder(int redraw_mask)
382 DrawMaskedBorderExt(redraw_mask, DRAW_BORDER_TO_BACKBUFFER);
385 void DrawMaskedBorderToTarget(int draw_target)
387 if (draw_target == DRAW_BORDER_TO_SCREEN)
389 DrawMaskedBorderExt(REDRAW_ALL, draw_target);
393 int last_border_status = global.border_status;
395 if (draw_target == DRAW_BORDER_TO_FADE_SOURCE)
397 global.border_status = gfx.fade_border_source_status;
398 gfx.masked_border_bitmap_ptr = gfx.fade_bitmap_source;
402 global.border_status = gfx.fade_border_target_status;
403 gfx.masked_border_bitmap_ptr = gfx.fade_bitmap_target;
406 DrawMaskedBorderExt(REDRAW_ALL, draw_target);
408 global.border_status = last_border_status;
409 gfx.masked_border_bitmap_ptr = backbuffer;
413 void BlitScreenToBitmap_RND(Bitmap *target_bitmap)
415 int fx = FX, fy = FY;
416 int full_lev_fieldx = lev_fieldx + (BorderElement != EL_EMPTY ? 2 : 0);
417 int full_lev_fieldy = lev_fieldy + (BorderElement != EL_EMPTY ? 2 : 0);
419 int dx = (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
420 int dy = (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
421 int dx_var = dx * TILESIZE_VAR / TILESIZE;
422 int dy_var = dy * TILESIZE_VAR / TILESIZE;
425 ffx = (scroll_x - SBX_Left) * TILEX_VAR + dx_var;
426 ffy = (scroll_y - SBY_Upper) * TILEY_VAR + dy_var;
428 if (EVEN(SCR_FIELDX))
430 if (ffx < SBX_Right * TILEX_VAR + TILEX_VAR / 2 + TILEX_VAR)
431 fx += dx_var - MIN(ffx, TILEX_VAR / 2) + TILEX_VAR;
433 fx += (dx_var > 0 ? TILEX_VAR : 0);
440 if (EVEN(SCR_FIELDY))
442 if (ffy < SBY_Lower * TILEY_VAR + TILEY_VAR / 2 + TILEY_VAR)
443 fy += dy_var - MIN(ffy, TILEY_VAR / 2) + TILEY_VAR;
445 fy += (dy_var > 0 ? TILEY_VAR : 0);
452 if (full_lev_fieldx <= SCR_FIELDX)
454 if (EVEN(SCR_FIELDX))
455 fx = 2 * TILEX_VAR - (ODD(lev_fieldx) ? TILEX_VAR / 2 : 0);
457 fx = 2 * TILEX_VAR - (EVEN(lev_fieldx) ? TILEX_VAR / 2 : 0);
460 if (full_lev_fieldy <= SCR_FIELDY)
462 if (EVEN(SCR_FIELDY))
463 fy = 2 * TILEY_VAR - (ODD(lev_fieldy) ? TILEY_VAR / 2 : 0);
465 fy = 2 * TILEY_VAR - (EVEN(lev_fieldy) ? TILEY_VAR / 2 : 0);
468 BlitBitmap(drawto_field, target_bitmap, fx, fy, SXSIZE, SYSIZE, SX, SY);
471 void BlitScreenToBitmap(Bitmap *target_bitmap)
473 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
474 BlitScreenToBitmap_EM(target_bitmap);
475 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
476 BlitScreenToBitmap_SP(target_bitmap);
477 else if (level.game_engine_type == GAME_ENGINE_TYPE_RND)
478 BlitScreenToBitmap_RND(target_bitmap);
480 redraw_mask |= REDRAW_FIELD;
483 void DrawFramesPerSecond()
486 int font_nr = FONT_TEXT_2;
487 int font_width = getFontWidth(font_nr);
489 sprintf(text, "%04.1f fps", global.frames_per_second);
491 DrawTextExt(backbuffer, WIN_XSIZE - font_width * strlen(text), 0, text,
492 font_nr, BLIT_OPAQUE);
496 static void PrintFrameTimeDebugging()
498 static unsigned int last_counter = 0;
499 unsigned int counter = Counter();
500 int diff_1 = counter - last_counter;
501 int diff_2 = diff_1 - GAME_FRAME_DELAY;
503 int diff_2_cut = MIN(ABS(diff_2), diff_2_max);
504 char diff_bar[2 * diff_2_max + 5];
508 diff_bar[pos++] = (diff_2 < -diff_2_max ? '<' : ' ');
510 for (i = 0; i < diff_2_max; i++)
511 diff_bar[pos++] = (diff_2 >= 0 ? ' ' :
512 i >= diff_2_max - diff_2_cut ? '-' : ' ');
514 diff_bar[pos++] = '|';
516 for (i = 0; i < diff_2_max; i++)
517 diff_bar[pos++] = (diff_2 <= 0 ? ' ' : i < diff_2_cut ? '+' : ' ');
519 diff_bar[pos++] = (diff_2 > diff_2_max ? '>' : ' ');
521 diff_bar[pos++] = '\0';
523 Error(ERR_INFO, "%06d [%02d] [%c%02d] %s",
526 (diff_2 < 0 ? '-' : diff_2 > 0 ? '+' : ' '), ABS(diff_2),
529 last_counter = counter;
535 static int last_redraw_mask = REDRAW_NONE;
537 // force screen redraw in every frame to continue drawing global animations
538 // (but always use the last redraw mask to prevent unwanted side effects)
539 if (redraw_mask == REDRAW_NONE)
540 redraw_mask = last_redraw_mask;
542 last_redraw_mask = redraw_mask;
545 // masked border now drawn immediately when blitting backbuffer to window
547 // draw masked border to all viewports, if defined
548 DrawMaskedBorder(redraw_mask);
551 // draw frames per second (only if debug mode is enabled)
552 if (redraw_mask & REDRAW_FPS)
553 DrawFramesPerSecond();
555 // redraw complete window if both playfield and (some) doors need redraw
556 if (redraw_mask & REDRAW_FIELD && redraw_mask & REDRAW_DOORS)
557 redraw_mask = REDRAW_ALL;
559 /* although redrawing the whole window would be fine for normal gameplay,
560 being able to only redraw the playfield is required for deactivating
561 certain drawing areas (mainly playfield) to work, which is needed for
562 warp-forward to be fast enough (by skipping redraw of most frames) */
564 if (redraw_mask & REDRAW_ALL)
566 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
568 else if (redraw_mask & REDRAW_FIELD)
570 BlitBitmap(backbuffer, window,
571 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
573 else if (redraw_mask & REDRAW_DOORS)
575 if (redraw_mask & REDRAW_DOOR_1)
576 BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
578 if (redraw_mask & REDRAW_DOOR_2)
579 BlitBitmap(backbuffer, window, VX, VY, VXSIZE, VYSIZE, VX, VY);
581 if (redraw_mask & REDRAW_DOOR_3)
582 BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
585 redraw_mask = REDRAW_NONE;
588 PrintFrameTimeDebugging();
592 static void FadeCrossSaveBackbuffer()
594 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
597 static void FadeCrossRestoreBackbuffer()
599 int redraw_mask_last = redraw_mask;
601 BlitBitmap(bitmap_db_cross, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
603 // do not change redraw mask when restoring backbuffer after cross-fading
604 redraw_mask = redraw_mask_last;
607 static void FadeExt(int fade_mask, int fade_mode, int fade_type)
609 static int fade_type_skip = FADE_TYPE_NONE;
610 void (*draw_border_function)(void) = NULL;
611 Bitmap *bitmap = (fade_mode & FADE_TYPE_TRANSFORM ? bitmap_db_cross : NULL);
612 int x, y, width, height;
613 int fade_delay, post_delay;
615 if (fade_type == FADE_TYPE_FADE_OUT)
617 if (fade_type_skip != FADE_TYPE_NONE)
619 /* skip all fade operations until specified fade operation */
620 if (fade_type & fade_type_skip)
621 fade_type_skip = FADE_TYPE_NONE;
627 FadeCrossSaveBackbuffer();
630 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
633 FadeCrossSaveBackbuffer();
640 redraw_mask |= fade_mask;
642 if (fade_type == FADE_TYPE_SKIP)
644 fade_type_skip = fade_mode;
649 fade_delay = fading.fade_delay;
650 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
652 if (fade_type_skip != FADE_TYPE_NONE)
654 /* skip all fade operations until specified fade operation */
655 if (fade_type & fade_type_skip)
656 fade_type_skip = FADE_TYPE_NONE;
661 if (global.autoplay_leveldir)
666 if (fade_mask == REDRAW_FIELD)
671 height = FADE_SYSIZE;
673 if (border.draw_masked_when_fading)
674 draw_border_function = DrawMaskedBorder_FIELD; /* update when fading */
676 DrawMaskedBorder_FIELD(); /* draw once */
678 else /* REDRAW_ALL */
686 if (!setup.fade_screens ||
688 fading.fade_mode == FADE_MODE_NONE)
690 if (fade_mode == FADE_MODE_FADE_OUT)
693 BlitBitmap(backbuffer, window, x, y, width, height, x, y);
695 redraw_mask &= ~fade_mask;
700 FadeRectangle(bitmap, x, y, width, height, fade_mode, fade_delay, post_delay,
701 draw_border_function);
703 if (fade_type == FADE_TYPE_FADE_OUT)
704 FadeCrossRestoreBackbuffer();
706 redraw_mask &= ~fade_mask;
709 static void SetScreenStates_BeforeFadingIn()
713 static void SetScreenStates_AfterFadingIn()
715 // store new source screen (to use correct masked border for fading)
716 gfx.fade_border_source_status = global.border_status;
718 global.anim_status = global.anim_status_next;
720 // force update of global animation status in case of rapid screen changes
721 redraw_mask = REDRAW_ALL;
725 static void SetScreenStates_BeforeFadingOut()
727 // store new target screen (to use correct masked border for fading)
728 gfx.fade_border_target_status = game_status;
730 global.anim_status = GAME_MODE_PSEUDO_FADING;
733 static void SetScreenStates_AfterFadingOut()
735 global.border_status = game_status;
738 void FadeIn(int fade_mask)
740 SetScreenStates_BeforeFadingIn();
743 DrawMaskedBorder(REDRAW_ALL);
746 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
747 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_IN);
749 FadeExt(fade_mask, FADE_MODE_FADE_IN, FADE_TYPE_FADE_IN);
753 FADE_SXSIZE = FULL_SXSIZE;
754 FADE_SYSIZE = FULL_SYSIZE;
756 SetScreenStates_AfterFadingIn();
759 void FadeOut(int fade_mask)
761 SetScreenStates_BeforeFadingOut();
764 DrawMaskedBorder(REDRAW_ALL);
767 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
768 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_OUT);
770 FadeExt(fade_mask, FADE_MODE_FADE_OUT, FADE_TYPE_FADE_OUT);
772 SetScreenStates_AfterFadingOut();
775 static void FadeSetLeaveNext(struct TitleFadingInfo fading_leave, boolean set)
777 static struct TitleFadingInfo fading_leave_stored;
780 fading_leave_stored = fading_leave;
782 fading = fading_leave_stored;
785 void FadeSetEnterMenu()
787 fading = menu.enter_menu;
789 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
792 void FadeSetLeaveMenu()
794 fading = menu.leave_menu;
796 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
799 void FadeSetEnterScreen()
801 fading = menu.enter_screen[game_status];
803 FadeSetLeaveNext(menu.leave_screen[game_status], TRUE); /* store */
806 void FadeSetNextScreen()
808 fading = menu.next_screen[game_status];
810 // (do not overwrite fade mode set by FadeSetEnterScreen)
811 // FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
814 void FadeSetLeaveScreen()
816 FadeSetLeaveNext(menu.leave_screen[game_status], FALSE); /* recall */
819 void FadeSetFromType(int type)
821 if (type & TYPE_ENTER_SCREEN)
822 FadeSetEnterScreen();
823 else if (type & TYPE_ENTER)
825 else if (type & TYPE_LEAVE)
829 void FadeSetDisabled()
831 static struct TitleFadingInfo fading_none = { FADE_MODE_NONE, -1, -1, -1 };
833 fading = fading_none;
836 void FadeSkipNextFadeIn()
838 FadeExt(0, FADE_MODE_SKIP_FADE_IN, FADE_TYPE_SKIP);
841 void FadeSkipNextFadeOut()
843 FadeExt(0, FADE_MODE_SKIP_FADE_OUT, FADE_TYPE_SKIP);
846 Bitmap *getBitmapFromGraphicOrDefault(int graphic, int default_graphic)
848 boolean redefined = getImageListEntryFromImageID(graphic)->redefined;
850 return (graphic == IMG_UNDEFINED ? NULL :
851 graphic_info[graphic].bitmap != NULL || redefined ?
852 graphic_info[graphic].bitmap :
853 graphic_info[default_graphic].bitmap);
856 Bitmap *getBackgroundBitmap(int graphic)
858 return getBitmapFromGraphicOrDefault(graphic, IMG_BACKGROUND);
861 Bitmap *getGlobalBorderBitmap(int graphic)
863 return getBitmapFromGraphicOrDefault(graphic, IMG_GLOBAL_BORDER);
866 Bitmap *getGlobalBorderBitmapFromStatus(int status)
869 (status == GAME_MODE_MAIN ||
870 status == GAME_MODE_PSEUDO_TYPENAME ? IMG_GLOBAL_BORDER_MAIN :
871 status == GAME_MODE_SCORES ? IMG_GLOBAL_BORDER_SCORES :
872 status == GAME_MODE_EDITOR ? IMG_GLOBAL_BORDER_EDITOR :
873 status == GAME_MODE_PLAYING ? IMG_GLOBAL_BORDER_PLAYING :
876 return getGlobalBorderBitmap(graphic);
879 void SetWindowBackgroundImageIfDefined(int graphic)
881 if (graphic_info[graphic].bitmap)
882 SetWindowBackgroundBitmap(graphic_info[graphic].bitmap);
885 void SetMainBackgroundImageIfDefined(int graphic)
887 if (graphic_info[graphic].bitmap)
888 SetMainBackgroundBitmap(graphic_info[graphic].bitmap);
891 void SetDoorBackgroundImageIfDefined(int graphic)
893 if (graphic_info[graphic].bitmap)
894 SetDoorBackgroundBitmap(graphic_info[graphic].bitmap);
897 void SetWindowBackgroundImage(int graphic)
899 SetWindowBackgroundBitmap(getBackgroundBitmap(graphic));
902 void SetMainBackgroundImage(int graphic)
904 SetMainBackgroundBitmap(getBackgroundBitmap(graphic));
907 void SetDoorBackgroundImage(int graphic)
909 SetDoorBackgroundBitmap(getBackgroundBitmap(graphic));
912 void SetPanelBackground()
914 struct GraphicInfo *gfx = &graphic_info[IMG_BACKGROUND_PANEL];
916 BlitBitmapTiled(gfx->bitmap, bitmap_db_panel, gfx->src_x, gfx->src_y,
917 gfx->width, gfx->height, 0, 0, DXSIZE, DYSIZE);
919 SetDoorBackgroundBitmap(bitmap_db_panel);
922 void DrawBackground(int x, int y, int width, int height)
924 /* "drawto" might still point to playfield buffer here (hall of fame) */
925 ClearRectangleOnBackground(backbuffer, x, y, width, height);
927 if (IN_GFX_FIELD_FULL(x, y))
928 redraw_mask |= REDRAW_FIELD;
929 else if (IN_GFX_DOOR_1(x, y))
930 redraw_mask |= REDRAW_DOOR_1;
931 else if (IN_GFX_DOOR_2(x, y))
932 redraw_mask |= REDRAW_DOOR_2;
933 else if (IN_GFX_DOOR_3(x, y))
934 redraw_mask |= REDRAW_DOOR_3;
937 void DrawBackgroundForFont(int x, int y, int width, int height, int font_nr)
939 struct FontBitmapInfo *font = getFontBitmapInfo(font_nr);
941 if (font->bitmap == NULL)
944 DrawBackground(x, y, width, height);
947 void DrawBackgroundForGraphic(int x, int y, int width, int height, int graphic)
949 struct GraphicInfo *g = &graphic_info[graphic];
951 if (g->bitmap == NULL)
954 DrawBackground(x, y, width, height);
957 static int game_status_last = -1;
958 static Bitmap *global_border_bitmap_last = NULL;
959 static Bitmap *global_border_bitmap = NULL;
960 static int real_sx_last = -1, real_sy_last = -1;
961 static int full_sxsize_last = -1, full_sysize_last = -1;
962 static int dx_last = -1, dy_last = -1;
963 static int dxsize_last = -1, dysize_last = -1;
964 static int vx_last = -1, vy_last = -1;
965 static int vxsize_last = -1, vysize_last = -1;
967 boolean CheckIfGlobalBorderHasChanged()
969 // if game status has not changed, global border has not changed either
970 if (game_status == game_status_last)
973 // determine and store new global border bitmap for current game status
974 global_border_bitmap = getGlobalBorderBitmapFromStatus(game_status);
976 return (global_border_bitmap_last != global_border_bitmap);
979 boolean CheckIfGlobalBorderRedrawIsNeeded()
981 // if game status has not changed, nothing has to be redrawn
982 if (game_status == game_status_last)
985 // redraw if last screen was title screen
986 if (game_status_last == GAME_MODE_TITLE)
989 // redraw if global screen border has changed
990 if (CheckIfGlobalBorderHasChanged())
993 // redraw if position or size of playfield area has changed
994 if (real_sx_last != REAL_SX || real_sy_last != REAL_SY ||
995 full_sxsize_last != FULL_SXSIZE || full_sysize_last != FULL_SYSIZE)
998 // redraw if position or size of door area has changed
999 if (dx_last != DX || dy_last != DY ||
1000 dxsize_last != DXSIZE || dysize_last != DYSIZE)
1003 // redraw if position or size of tape area has changed
1004 if (vx_last != VX || vy_last != VY ||
1005 vxsize_last != VXSIZE || vysize_last != VYSIZE)
1011 void RedrawGlobalBorderFromBitmap(Bitmap *bitmap)
1014 BlitBitmap(bitmap, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
1016 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
1019 void RedrawGlobalBorder()
1021 Bitmap *bitmap = getGlobalBorderBitmapFromStatus(game_status);
1023 RedrawGlobalBorderFromBitmap(bitmap);
1025 redraw_mask = REDRAW_ALL;
1028 static void RedrawGlobalBorderIfNeeded()
1030 if (game_status == game_status_last)
1033 // copy current draw buffer to later copy back areas that have not changed
1034 if (game_status_last != GAME_MODE_TITLE)
1035 BlitBitmap(backbuffer, bitmap_db_store, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
1037 if (CheckIfGlobalBorderRedrawIsNeeded())
1039 // redraw global screen border (or clear, if defined to be empty)
1040 RedrawGlobalBorderFromBitmap(global_border_bitmap);
1042 // copy previous playfield and door areas, if they are defined on both
1043 // previous and current screen and if they still have the same size
1045 if (real_sx_last != -1 && real_sy_last != -1 &&
1046 REAL_SX != -1 && REAL_SY != -1 &&
1047 full_sxsize_last == FULL_SXSIZE && full_sysize_last == FULL_SYSIZE)
1048 BlitBitmap(bitmap_db_store, backbuffer,
1049 real_sx_last, real_sy_last, FULL_SXSIZE, FULL_SYSIZE,
1052 if (dx_last != -1 && dy_last != -1 &&
1053 DX != -1 && DY != -1 &&
1054 dxsize_last == DXSIZE && dysize_last == DYSIZE)
1055 BlitBitmap(bitmap_db_store, backbuffer,
1056 dx_last, dy_last, DXSIZE, DYSIZE, DX, DY);
1058 if (vx_last != -1 && vy_last != -1 &&
1059 VX != -1 && VY != -1 &&
1060 vxsize_last == VXSIZE && vysize_last == VYSIZE)
1061 BlitBitmap(bitmap_db_store, backbuffer,
1062 vx_last, vy_last, VXSIZE, VYSIZE, VX, VY);
1064 redraw_mask = REDRAW_ALL;
1067 game_status_last = game_status;
1069 global_border_bitmap_last = global_border_bitmap;
1071 real_sx_last = REAL_SX;
1072 real_sy_last = REAL_SY;
1073 full_sxsize_last = FULL_SXSIZE;
1074 full_sysize_last = FULL_SYSIZE;
1077 dxsize_last = DXSIZE;
1078 dysize_last = DYSIZE;
1081 vxsize_last = VXSIZE;
1082 vysize_last = VYSIZE;
1087 RedrawGlobalBorderIfNeeded();
1089 /* !!! "drawto" might still point to playfield buffer here (see above) !!! */
1090 /* (when entering hall of fame after playing) */
1091 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
1093 /* !!! maybe this should be done before clearing the background !!! */
1094 if (game_status == GAME_MODE_PLAYING)
1096 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
1097 SetDrawtoField(DRAW_FIELDBUFFER);
1101 SetDrawtoField(DRAW_BACKBUFFER);
1105 void MarkTileDirty(int x, int y)
1107 redraw_mask |= REDRAW_FIELD;
1110 void SetBorderElement()
1114 BorderElement = EL_EMPTY;
1116 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
1118 for (x = 0; x < lev_fieldx; x++)
1120 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
1121 BorderElement = EL_STEELWALL;
1123 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
1129 void FloodFillLevel(int from_x, int from_y, int fill_element,
1130 short field[MAX_LEV_FIELDX][MAX_LEV_FIELDY],
1131 int max_fieldx, int max_fieldy)
1135 static int check[4][2] = { { -1, 0 }, { 0, -1 }, { 1, 0 }, { 0, 1 } };
1136 static int safety = 0;
1138 /* check if starting field still has the desired content */
1139 if (field[from_x][from_y] == fill_element)
1144 if (safety > max_fieldx * max_fieldy)
1145 Error(ERR_EXIT, "Something went wrong in 'FloodFill()'. Please debug.");
1147 old_element = field[from_x][from_y];
1148 field[from_x][from_y] = fill_element;
1150 for (i = 0; i < 4; i++)
1152 x = from_x + check[i][0];
1153 y = from_y + check[i][1];
1155 if (IN_FIELD(x, y, max_fieldx, max_fieldy) && field[x][y] == old_element)
1156 FloodFillLevel(x, y, fill_element, field, max_fieldx, max_fieldy);
1162 void SetRandomAnimationValue(int x, int y)
1164 gfx.anim_random_frame = GfxRandom[x][y];
1167 int getGraphicAnimationFrame(int graphic, int sync_frame)
1169 /* animation synchronized with global frame counter, not move position */
1170 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
1171 sync_frame = FrameCounter;
1173 return getAnimationFrame(graphic_info[graphic].anim_frames,
1174 graphic_info[graphic].anim_delay,
1175 graphic_info[graphic].anim_mode,
1176 graphic_info[graphic].anim_start_frame,
1180 void getSizedGraphicSourceExt(int graphic, int frame, int tilesize,
1181 Bitmap **bitmap, int *x, int *y,
1182 boolean get_backside)
1184 struct GraphicInfo *g = &graphic_info[graphic];
1185 Bitmap *src_bitmap = g->bitmap;
1186 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
1187 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
1188 int tilesize_capped = MIN(MAX(1, tilesize), TILESIZE);
1190 // if no in-game graphics defined, always use standard graphic size
1191 if (g->bitmaps[IMG_BITMAP_GAME] == NULL)
1192 tilesize = TILESIZE;
1194 if (tilesize == gfx.standard_tile_size)
1195 src_bitmap = g->bitmaps[IMG_BITMAP_STANDARD];
1196 else if (tilesize == game.tile_size)
1197 src_bitmap = g->bitmaps[IMG_BITMAP_GAME];
1199 src_bitmap = g->bitmaps[IMG_BITMAP_1x1 - log_2(tilesize_capped)];
1201 if (g->offset_y == 0) /* frames are ordered horizontally */
1203 int max_width = g->anim_frames_per_line * g->width;
1204 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
1206 src_x = pos % max_width;
1207 src_y = src_y % g->height + pos / max_width * g->height;
1209 else if (g->offset_x == 0) /* frames are ordered vertically */
1211 int max_height = g->anim_frames_per_line * g->height;
1212 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
1214 src_x = src_x % g->width + pos / max_height * g->width;
1215 src_y = pos % max_height;
1217 else /* frames are ordered diagonally */
1219 src_x = src_x + frame * g->offset_x;
1220 src_y = src_y + frame * g->offset_y;
1223 *bitmap = src_bitmap;
1224 *x = src_x * tilesize / g->tile_size;
1225 *y = src_y * tilesize / g->tile_size;
1228 void getFixedGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1229 int *x, int *y, boolean get_backside)
1231 getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y,
1235 void getSizedGraphicSource(int graphic, int frame, int tilesize,
1236 Bitmap **bitmap, int *x, int *y)
1238 getSizedGraphicSourceExt(graphic, frame, tilesize, bitmap, x, y, FALSE);
1241 void getFixedGraphicSource(int graphic, int frame,
1242 Bitmap **bitmap, int *x, int *y)
1244 getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y, FALSE);
1247 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1249 getSizedGraphicSource(graphic, 0, MINI_TILESIZE, bitmap, x, y);
1252 inline static void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1253 int *x, int *y, boolean get_backside)
1255 struct GraphicInfo *g = &graphic_info[graphic];
1256 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
1257 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
1259 if (TILESIZE_VAR != TILESIZE)
1260 return getSizedGraphicSourceExt(graphic, frame, TILESIZE_VAR, bitmap, x, y,
1263 *bitmap = g->bitmap;
1265 if (g->offset_y == 0) /* frames are ordered horizontally */
1267 int max_width = g->anim_frames_per_line * g->width;
1268 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
1270 *x = pos % max_width;
1271 *y = src_y % g->height + pos / max_width * g->height;
1273 else if (g->offset_x == 0) /* frames are ordered vertically */
1275 int max_height = g->anim_frames_per_line * g->height;
1276 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
1278 *x = src_x % g->width + pos / max_height * g->width;
1279 *y = pos % max_height;
1281 else /* frames are ordered diagonally */
1283 *x = src_x + frame * g->offset_x;
1284 *y = src_y + frame * g->offset_y;
1287 *x = *x * TILESIZE_VAR / g->tile_size;
1288 *y = *y * TILESIZE_VAR / g->tile_size;
1291 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
1293 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
1296 void DrawGraphic(int x, int y, int graphic, int frame)
1299 if (!IN_SCR_FIELD(x, y))
1301 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1302 printf("DrawGraphic(): This should never happen!\n");
1307 DrawGraphicExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR, graphic,
1310 MarkTileDirty(x, y);
1313 void DrawFixedGraphic(int x, int y, int graphic, int frame)
1316 if (!IN_SCR_FIELD(x, y))
1318 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1319 printf("DrawGraphic(): This should never happen!\n");
1324 DrawFixedGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic,
1326 MarkTileDirty(x, y);
1329 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1335 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1337 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX_VAR, TILEY_VAR, x, y);
1340 void DrawFixedGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1346 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1347 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
1350 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
1353 if (!IN_SCR_FIELD(x, y))
1355 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1356 printf("DrawGraphicThruMask(): This should never happen!\n");
1361 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
1364 MarkTileDirty(x, y);
1367 void DrawFixedGraphicThruMask(int x, int y, int graphic, int frame)
1370 if (!IN_SCR_FIELD(x, y))
1372 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1373 printf("DrawGraphicThruMask(): This should never happen!\n");
1378 DrawFixedGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
1380 MarkTileDirty(x, y);
1383 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
1389 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1391 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX_VAR, TILEY_VAR,
1395 void DrawFixedGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y,
1396 int graphic, int frame)
1401 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1403 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY,
1407 void DrawSizedGraphic(int x, int y, int graphic, int frame, int tilesize)
1409 DrawSizedGraphicExt(drawto, SX + x * tilesize, SY + y * tilesize, graphic,
1411 MarkTileDirty(x / tilesize, y / tilesize);
1414 void DrawSizedGraphicExt(DrawBuffer *d, int x, int y, int graphic, int frame,
1420 getSizedGraphicSource(graphic, frame, tilesize, &src_bitmap, &src_x, &src_y);
1421 BlitBitmap(src_bitmap, d, src_x, src_y, tilesize, tilesize, x, y);
1424 void DrawMiniGraphic(int x, int y, int graphic)
1426 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
1427 MarkTileDirty(x / 2, y / 2);
1430 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
1435 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1436 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
1439 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
1440 int graphic, int frame,
1441 int cut_mode, int mask_mode)
1446 int width = TILEX, height = TILEY;
1449 if (dx || dy) /* shifted graphic */
1451 if (x < BX1) /* object enters playfield from the left */
1458 else if (x > BX2) /* object enters playfield from the right */
1464 else if (x == BX1 && dx < 0) /* object leaves playfield to the left */
1470 else if (x == BX2 && dx > 0) /* object leaves playfield to the right */
1472 else if (dx) /* general horizontal movement */
1473 MarkTileDirty(x + SIGN(dx), y);
1475 if (y < BY1) /* object enters playfield from the top */
1477 if (cut_mode == CUT_BELOW) /* object completely above top border */
1485 else if (y > BY2) /* object enters playfield from the bottom */
1491 else if (y == BY1 && dy < 0) /* object leaves playfield to the top */
1497 else if (dy > 0 && cut_mode == CUT_ABOVE)
1499 if (y == BY2) /* object completely above bottom border */
1505 MarkTileDirty(x, y + 1);
1506 } /* object leaves playfield to the bottom */
1507 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1509 else if (dy) /* general vertical movement */
1510 MarkTileDirty(x, y + SIGN(dy));
1514 if (!IN_SCR_FIELD(x, y))
1516 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1517 printf("DrawGraphicShifted(): This should never happen!\n");
1522 width = width * TILESIZE_VAR / TILESIZE;
1523 height = height * TILESIZE_VAR / TILESIZE;
1524 cx = cx * TILESIZE_VAR / TILESIZE;
1525 cy = cy * TILESIZE_VAR / TILESIZE;
1526 dx = dx * TILESIZE_VAR / TILESIZE;
1527 dy = dy * TILESIZE_VAR / TILESIZE;
1529 if (width > 0 && height > 0)
1531 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1536 dst_x = FX + x * TILEX_VAR + dx;
1537 dst_y = FY + y * TILEY_VAR + dy;
1539 if (mask_mode == USE_MASKING)
1540 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1543 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1546 MarkTileDirty(x, y);
1550 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
1551 int graphic, int frame,
1552 int cut_mode, int mask_mode)
1557 int width = TILEX_VAR, height = TILEY_VAR;
1560 int x2 = x + SIGN(dx);
1561 int y2 = y + SIGN(dy);
1563 /* movement with two-tile animations must be sync'ed with movement position,
1564 not with current GfxFrame (which can be higher when using slow movement) */
1565 int anim_pos = (dx ? ABS(dx) : ABS(dy));
1566 int anim_frames = graphic_info[graphic].anim_frames;
1568 /* (we also need anim_delay here for movement animations with less frames) */
1569 int anim_delay = graphic_info[graphic].anim_delay;
1570 int sync_frame = anim_pos * anim_frames * anim_delay / TILESIZE;
1572 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
1573 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
1575 /* re-calculate animation frame for two-tile movement animation */
1576 frame = getGraphicAnimationFrame(graphic, sync_frame);
1578 /* check if movement start graphic inside screen area and should be drawn */
1579 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
1581 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
1583 dst_x = FX + x1 * TILEX_VAR;
1584 dst_y = FY + y1 * TILEY_VAR;
1586 if (mask_mode == USE_MASKING)
1587 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1590 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1593 MarkTileDirty(x1, y1);
1596 /* check if movement end graphic inside screen area and should be drawn */
1597 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
1599 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
1601 dst_x = FX + x2 * TILEX_VAR;
1602 dst_y = FY + y2 * TILEY_VAR;
1604 if (mask_mode == USE_MASKING)
1605 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1608 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1611 MarkTileDirty(x2, y2);
1615 static void DrawGraphicShifted(int x, int y, int dx, int dy,
1616 int graphic, int frame,
1617 int cut_mode, int mask_mode)
1621 DrawGraphic(x, y, graphic, frame);
1626 if (graphic_info[graphic].double_movement) /* EM style movement images */
1627 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1629 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1632 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1633 int frame, int cut_mode)
1635 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
1638 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1639 int cut_mode, int mask_mode)
1641 int lx = LEVELX(x), ly = LEVELY(y);
1645 if (IN_LEV_FIELD(lx, ly))
1647 SetRandomAnimationValue(lx, ly);
1649 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
1650 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1652 /* do not use double (EM style) movement graphic when not moving */
1653 if (graphic_info[graphic].double_movement && !dx && !dy)
1655 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
1656 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1659 else /* border element */
1661 graphic = el2img(element);
1662 frame = getGraphicAnimationFrame(graphic, -1);
1665 if (element == EL_EXPANDABLE_WALL)
1667 boolean left_stopped = FALSE, right_stopped = FALSE;
1669 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1670 left_stopped = TRUE;
1671 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1672 right_stopped = TRUE;
1674 if (left_stopped && right_stopped)
1676 else if (left_stopped)
1678 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1679 frame = graphic_info[graphic].anim_frames - 1;
1681 else if (right_stopped)
1683 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1684 frame = graphic_info[graphic].anim_frames - 1;
1689 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1690 else if (mask_mode == USE_MASKING)
1691 DrawGraphicThruMask(x, y, graphic, frame);
1693 DrawGraphic(x, y, graphic, frame);
1696 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1697 int cut_mode, int mask_mode)
1699 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1700 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1701 cut_mode, mask_mode);
1704 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1707 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1710 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1713 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1716 void DrawLevelElementThruMask(int x, int y, int element)
1718 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1721 void DrawLevelFieldThruMask(int x, int y)
1723 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1726 /* !!! implementation of quicksand is totally broken !!! */
1727 #define IS_CRUMBLED_TILE(x, y, e) \
1728 (GFX_CRUMBLED(e) && (!IN_LEV_FIELD(x, y) || \
1729 !IS_MOVING(x, y) || \
1730 (e) == EL_QUICKSAND_EMPTYING || \
1731 (e) == EL_QUICKSAND_FAST_EMPTYING))
1733 static void DrawLevelFieldCrumbledInnerCorners(int x, int y, int dx, int dy,
1738 int width, height, cx, cy;
1739 int sx = SCREENX(x), sy = SCREENY(y);
1740 int crumbled_border_size = graphic_info[graphic].border_size;
1743 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1745 for (i = 1; i < 4; i++)
1747 int dxx = (i & 1 ? dx : 0);
1748 int dyy = (i & 2 ? dy : 0);
1751 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1754 /* check if neighbour field is of same crumble type */
1755 boolean same = (IS_CRUMBLED_TILE(xx, yy, element) &&
1756 graphic_info[graphic].class ==
1757 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class);
1759 /* return if check prevents inner corner */
1760 if (same == (dxx == dx && dyy == dy))
1764 /* if we reach this point, we have an inner corner */
1766 getGraphicSource(graphic, 1, &src_bitmap, &src_x, &src_y);
1768 width = crumbled_border_size * TILESIZE_VAR / TILESIZE;
1769 height = crumbled_border_size * TILESIZE_VAR / TILESIZE;
1770 cx = (dx > 0 ? TILESIZE_VAR - width : 0);
1771 cy = (dy > 0 ? TILESIZE_VAR - height : 0);
1773 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1774 width, height, FX + sx * TILEX_VAR + cx, FY + sy * TILEY_VAR + cy);
1777 static void DrawLevelFieldCrumbledBorders(int x, int y, int graphic, int frame,
1782 int width, height, bx, by, cx, cy;
1783 int sx = SCREENX(x), sy = SCREENY(y);
1784 int crumbled_border_size = graphic_info[graphic].border_size;
1785 int crumbled_border_size_var = crumbled_border_size * TILESIZE_VAR / TILESIZE;
1786 int crumbled_border_pos_var = TILESIZE_VAR - crumbled_border_size_var;
1789 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1791 /* draw simple, sloppy, non-corner-accurate crumbled border */
1793 width = (dir == 1 || dir == 2 ? crumbled_border_size_var : TILESIZE_VAR);
1794 height = (dir == 0 || dir == 3 ? crumbled_border_size_var : TILESIZE_VAR);
1795 cx = (dir == 2 ? crumbled_border_pos_var : 0);
1796 cy = (dir == 3 ? crumbled_border_pos_var : 0);
1798 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy, width, height,
1799 FX + sx * TILEX_VAR + cx,
1800 FY + sy * TILEY_VAR + cy);
1802 /* (remaining middle border part must be at least as big as corner part) */
1803 if (!(graphic_info[graphic].style & STYLE_ACCURATE_BORDERS) ||
1804 crumbled_border_size >= TILESIZE / 3)
1807 /* correct corners of crumbled border, if needed */
1809 for (i = -1; i <= 1; i += 2)
1811 int xx = x + (dir == 0 || dir == 3 ? i : 0);
1812 int yy = y + (dir == 1 || dir == 2 ? i : 0);
1813 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1816 /* check if neighbour field is of same crumble type */
1817 if (IS_CRUMBLED_TILE(xx, yy, element) &&
1818 graphic_info[graphic].class ==
1819 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1821 /* no crumbled corner, but continued crumbled border */
1823 int c1 = (dir == 2 || dir == 3 ? crumbled_border_pos_var : 0);
1824 int c2 = (i == 1 ? crumbled_border_pos_var : 0);
1825 int b1 = (i == 1 ? crumbled_border_size_var :
1826 TILESIZE_VAR - 2 * crumbled_border_size_var);
1828 width = crumbled_border_size_var;
1829 height = crumbled_border_size_var;
1831 if (dir == 1 || dir == 2)
1846 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
1848 FX + sx * TILEX_VAR + cx,
1849 FY + sy * TILEY_VAR + cy);
1854 static void DrawLevelFieldCrumbledExt(int x, int y, int graphic, int frame)
1856 int sx = SCREENX(x), sy = SCREENY(y);
1859 static int xy[4][2] =
1867 if (!IN_LEV_FIELD(x, y))
1870 element = TILE_GFX_ELEMENT(x, y);
1872 /* crumble field itself */
1873 if (IS_CRUMBLED_TILE(x, y, element))
1875 if (!IN_SCR_FIELD(sx, sy))
1878 for (i = 0; i < 4; i++)
1880 int xx = x + xy[i][0];
1881 int yy = y + xy[i][1];
1883 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1886 /* check if neighbour field is of same crumble type */
1887 if (IS_CRUMBLED_TILE(xx, yy, element) &&
1888 graphic_info[graphic].class ==
1889 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1892 DrawLevelFieldCrumbledBorders(x, y, graphic, frame, i);
1895 if ((graphic_info[graphic].style & STYLE_INNER_CORNERS) &&
1896 graphic_info[graphic].anim_frames == 2)
1898 for (i = 0; i < 4; i++)
1900 int dx = (i & 1 ? +1 : -1);
1901 int dy = (i & 2 ? +1 : -1);
1903 DrawLevelFieldCrumbledInnerCorners(x, y, dx, dy, graphic);
1907 MarkTileDirty(sx, sy);
1909 else /* center field not crumbled -- crumble neighbour fields */
1911 for (i = 0; i < 4; i++)
1913 int xx = x + xy[i][0];
1914 int yy = y + xy[i][1];
1915 int sxx = sx + xy[i][0];
1916 int syy = sy + xy[i][1];
1918 if (!IN_LEV_FIELD(xx, yy) ||
1919 !IN_SCR_FIELD(sxx, syy))
1922 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
1925 element = TILE_GFX_ELEMENT(xx, yy);
1927 if (!IS_CRUMBLED_TILE(xx, yy, element))
1930 graphic = el_act2crm(element, ACTION_DEFAULT);
1932 DrawLevelFieldCrumbledBorders(xx, yy, graphic, 0, 3 - i);
1934 MarkTileDirty(sxx, syy);
1939 void DrawLevelFieldCrumbled(int x, int y)
1943 if (!IN_LEV_FIELD(x, y))
1946 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1947 GfxElement[x][y] != EL_UNDEFINED &&
1948 GFX_CRUMBLED(GfxElement[x][y]))
1950 DrawLevelFieldCrumbledDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
1955 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
1957 DrawLevelFieldCrumbledExt(x, y, graphic, 0);
1960 void DrawLevelFieldCrumbledDigging(int x, int y, int direction,
1963 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1964 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1965 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1966 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1967 int sx = SCREENX(x), sy = SCREENY(y);
1969 DrawGraphic(sx, sy, graphic1, frame1);
1970 DrawLevelFieldCrumbledExt(x, y, graphic2, frame2);
1973 void DrawLevelFieldCrumbledNeighbours(int x, int y)
1975 int sx = SCREENX(x), sy = SCREENY(y);
1976 static int xy[4][2] =
1985 for (i = 0; i < 4; i++)
1987 int xx = x + xy[i][0];
1988 int yy = y + xy[i][1];
1989 int sxx = sx + xy[i][0];
1990 int syy = sy + xy[i][1];
1992 if (!IN_LEV_FIELD(xx, yy) ||
1993 !IN_SCR_FIELD(sxx, syy) ||
1994 !GFX_CRUMBLED(Feld[xx][yy]) ||
1998 DrawLevelField(xx, yy);
2002 static int getBorderElement(int x, int y)
2006 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
2007 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
2008 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
2009 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
2010 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
2011 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
2012 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
2014 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
2015 int steel_position = (x == -1 && y == -1 ? 0 :
2016 x == lev_fieldx && y == -1 ? 1 :
2017 x == -1 && y == lev_fieldy ? 2 :
2018 x == lev_fieldx && y == lev_fieldy ? 3 :
2019 x == -1 || x == lev_fieldx ? 4 :
2020 y == -1 || y == lev_fieldy ? 5 : 6);
2022 return border[steel_position][steel_type];
2025 void DrawScreenElement(int x, int y, int element)
2027 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
2028 DrawLevelFieldCrumbled(LEVELX(x), LEVELY(y));
2031 void DrawLevelElement(int x, int y, int element)
2033 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2034 DrawScreenElement(SCREENX(x), SCREENY(y), element);
2037 void DrawScreenField(int x, int y)
2039 int lx = LEVELX(x), ly = LEVELY(y);
2040 int element, content;
2042 if (!IN_LEV_FIELD(lx, ly))
2044 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
2047 element = getBorderElement(lx, ly);
2049 DrawScreenElement(x, y, element);
2054 element = Feld[lx][ly];
2055 content = Store[lx][ly];
2057 if (IS_MOVING(lx, ly))
2059 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
2060 boolean cut_mode = NO_CUTTING;
2062 if (element == EL_QUICKSAND_EMPTYING ||
2063 element == EL_QUICKSAND_FAST_EMPTYING ||
2064 element == EL_MAGIC_WALL_EMPTYING ||
2065 element == EL_BD_MAGIC_WALL_EMPTYING ||
2066 element == EL_DC_MAGIC_WALL_EMPTYING ||
2067 element == EL_AMOEBA_DROPPING)
2068 cut_mode = CUT_ABOVE;
2069 else if (element == EL_QUICKSAND_FILLING ||
2070 element == EL_QUICKSAND_FAST_FILLING ||
2071 element == EL_MAGIC_WALL_FILLING ||
2072 element == EL_BD_MAGIC_WALL_FILLING ||
2073 element == EL_DC_MAGIC_WALL_FILLING)
2074 cut_mode = CUT_BELOW;
2076 if (cut_mode == CUT_ABOVE)
2077 DrawScreenElement(x, y, element);
2079 DrawScreenElement(x, y, EL_EMPTY);
2082 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
2083 else if (cut_mode == NO_CUTTING)
2084 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
2087 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
2089 if (cut_mode == CUT_BELOW &&
2090 IN_LEV_FIELD(lx, ly + 1) && IN_SCR_FIELD(x, y + 1))
2091 DrawLevelElement(lx, ly + 1, element);
2094 if (content == EL_ACID)
2096 int dir = MovDir[lx][ly];
2097 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
2098 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
2100 DrawLevelElementThruMask(newlx, newly, EL_ACID);
2103 else if (IS_BLOCKED(lx, ly))
2108 boolean cut_mode = NO_CUTTING;
2109 int element_old, content_old;
2111 Blocked2Moving(lx, ly, &oldx, &oldy);
2114 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
2115 MovDir[oldx][oldy] == MV_RIGHT);
2117 element_old = Feld[oldx][oldy];
2118 content_old = Store[oldx][oldy];
2120 if (element_old == EL_QUICKSAND_EMPTYING ||
2121 element_old == EL_QUICKSAND_FAST_EMPTYING ||
2122 element_old == EL_MAGIC_WALL_EMPTYING ||
2123 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
2124 element_old == EL_DC_MAGIC_WALL_EMPTYING ||
2125 element_old == EL_AMOEBA_DROPPING)
2126 cut_mode = CUT_ABOVE;
2128 DrawScreenElement(x, y, EL_EMPTY);
2131 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
2133 else if (cut_mode == NO_CUTTING)
2134 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
2137 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
2140 else if (IS_DRAWABLE(element))
2141 DrawScreenElement(x, y, element);
2143 DrawScreenElement(x, y, EL_EMPTY);
2146 void DrawLevelField(int x, int y)
2148 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2149 DrawScreenField(SCREENX(x), SCREENY(y));
2150 else if (IS_MOVING(x, y))
2154 Moving2Blocked(x, y, &newx, &newy);
2155 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
2156 DrawScreenField(SCREENX(newx), SCREENY(newy));
2158 else if (IS_BLOCKED(x, y))
2162 Blocked2Moving(x, y, &oldx, &oldy);
2163 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
2164 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
2168 void DrawSizedElement(int x, int y, int element, int tilesize)
2172 graphic = el2edimg(element);
2173 DrawSizedGraphic(x, y, graphic, 0, tilesize);
2176 void DrawMiniElement(int x, int y, int element)
2180 graphic = el2edimg(element);
2181 DrawMiniGraphic(x, y, graphic);
2184 void DrawSizedElementOrWall(int sx, int sy, int scroll_x, int scroll_y,
2187 int x = sx + scroll_x, y = sy + scroll_y;
2189 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
2190 DrawSizedElement(sx, sy, EL_EMPTY, tilesize);
2191 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
2192 DrawSizedElement(sx, sy, Feld[x][y], tilesize);
2194 DrawSizedGraphic(sx, sy, el2edimg(getBorderElement(x, y)), 0, tilesize);
2197 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
2199 int x = sx + scroll_x, y = sy + scroll_y;
2201 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
2202 DrawMiniElement(sx, sy, EL_EMPTY);
2203 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
2204 DrawMiniElement(sx, sy, Feld[x][y]);
2206 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
2209 void DrawEnvelopeBackgroundTiles(int graphic, int startx, int starty,
2210 int x, int y, int xsize, int ysize,
2211 int tile_width, int tile_height)
2215 int dst_x = startx + x * tile_width;
2216 int dst_y = starty + y * tile_height;
2217 int width = graphic_info[graphic].width;
2218 int height = graphic_info[graphic].height;
2219 int inner_width_raw = MAX(width - 2 * tile_width, tile_width);
2220 int inner_height_raw = MAX(height - 2 * tile_height, tile_height);
2221 int inner_width = inner_width_raw - (inner_width_raw % tile_width);
2222 int inner_height = inner_height_raw - (inner_height_raw % tile_height);
2223 int inner_sx = (width >= 3 * tile_width ? tile_width : 0);
2224 int inner_sy = (height >= 3 * tile_height ? tile_height : 0);
2225 boolean draw_masked = graphic_info[graphic].draw_masked;
2227 getFixedGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
2229 if (src_bitmap == NULL || width < tile_width || height < tile_height)
2231 ClearRectangle(drawto, dst_x, dst_y, tile_width, tile_height);
2235 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - tile_width :
2236 inner_sx + (x - 1) * tile_width % inner_width);
2237 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - tile_height :
2238 inner_sy + (y - 1) * tile_height % inner_height);
2241 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
2244 BlitBitmap(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
2248 void DrawEnvelopeBackground(int graphic, int startx, int starty,
2249 int x, int y, int xsize, int ysize, int font_nr)
2251 int font_width = getFontWidth(font_nr);
2252 int font_height = getFontHeight(font_nr);
2254 DrawEnvelopeBackgroundTiles(graphic, startx, starty, x, y, xsize, ysize,
2255 font_width, font_height);
2258 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
2260 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2261 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2262 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2263 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2264 boolean no_delay = (tape.warp_forward);
2265 unsigned int anim_delay = 0;
2266 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
2267 int anim_delay_value = (no_delay ? 0 : frame_delay_value) / 2;
2268 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
2269 int font_width = getFontWidth(font_nr);
2270 int font_height = getFontHeight(font_nr);
2271 int max_xsize = level.envelope[envelope_nr].xsize;
2272 int max_ysize = level.envelope[envelope_nr].ysize;
2273 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
2274 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
2275 int xend = max_xsize;
2276 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
2277 int xstep = (xstart < xend ? 1 : 0);
2278 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2280 int end = MAX(xend - xstart, yend - ystart);
2283 for (i = start; i <= end; i++)
2285 int last_frame = end; // last frame of this "for" loop
2286 int x = xstart + i * xstep;
2287 int y = ystart + i * ystep;
2288 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2289 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2290 int sx = SX + (SXSIZE - xsize * font_width) / 2;
2291 int sy = SY + (SYSIZE - ysize * font_height) / 2;
2294 SetDrawtoField(DRAW_FIELDBUFFER);
2296 BlitScreenToBitmap(backbuffer);
2298 SetDrawtoField(DRAW_BACKBUFFER);
2300 for (yy = 0; yy < ysize; yy++)
2301 for (xx = 0; xx < xsize; xx++)
2302 DrawEnvelopeBackground(graphic, sx, sy, xx, yy, xsize, ysize, font_nr);
2304 DrawTextBuffer(sx + font_width, sy + font_height,
2305 level.envelope[envelope_nr].text, font_nr, max_xsize,
2306 xsize - 2, ysize - 2, 0, mask_mode,
2307 level.envelope[envelope_nr].autowrap,
2308 level.envelope[envelope_nr].centered, FALSE);
2310 redraw_mask |= REDRAW_FIELD;
2313 SkipUntilDelayReached(&anim_delay, anim_delay_value, &i, last_frame);
2317 void ShowEnvelope(int envelope_nr)
2319 int element = EL_ENVELOPE_1 + envelope_nr;
2320 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2321 int sound_opening = element_info[element].sound[ACTION_OPENING];
2322 int sound_closing = element_info[element].sound[ACTION_CLOSING];
2323 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2324 boolean no_delay = (tape.warp_forward);
2325 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
2326 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
2327 int anim_mode = graphic_info[graphic].anim_mode;
2328 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2329 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2331 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
2333 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2335 if (anim_mode == ANIM_DEFAULT)
2336 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
2338 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
2341 Delay(wait_delay_value);
2343 WaitForEventToContinue();
2345 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2347 if (anim_mode != ANIM_NONE)
2348 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
2350 if (anim_mode == ANIM_DEFAULT)
2351 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
2353 game.envelope_active = FALSE;
2355 SetDrawtoField(DRAW_FIELDBUFFER);
2357 redraw_mask |= REDRAW_FIELD;
2361 static void setRequestBasePosition(int *x, int *y)
2363 int sx_base, sy_base;
2365 if (request.x != -1)
2366 sx_base = request.x;
2367 else if (request.align == ALIGN_LEFT)
2369 else if (request.align == ALIGN_RIGHT)
2370 sx_base = SX + SXSIZE;
2372 sx_base = SX + SXSIZE / 2;
2374 if (request.y != -1)
2375 sy_base = request.y;
2376 else if (request.valign == VALIGN_TOP)
2378 else if (request.valign == VALIGN_BOTTOM)
2379 sy_base = SY + SYSIZE;
2381 sy_base = SY + SYSIZE / 2;
2387 static void setRequestPositionExt(int *x, int *y, int width, int height,
2388 boolean add_border_size)
2390 int border_size = request.border_size;
2391 int sx_base, sy_base;
2394 setRequestBasePosition(&sx_base, &sy_base);
2396 if (request.align == ALIGN_LEFT)
2398 else if (request.align == ALIGN_RIGHT)
2399 sx = sx_base - width;
2401 sx = sx_base - width / 2;
2403 if (request.valign == VALIGN_TOP)
2405 else if (request.valign == VALIGN_BOTTOM)
2406 sy = sy_base - height;
2408 sy = sy_base - height / 2;
2410 sx = MAX(0, MIN(sx, WIN_XSIZE - width));
2411 sy = MAX(0, MIN(sy, WIN_YSIZE - height));
2413 if (add_border_size)
2423 static void setRequestPosition(int *x, int *y, boolean add_border_size)
2425 setRequestPositionExt(x, y, request.width, request.height, add_border_size);
2428 void DrawEnvelopeRequest(char *text)
2430 int last_game_status = game_status; /* save current game status */
2431 char *text_final = text;
2432 char *text_door_style = NULL;
2433 int graphic = IMG_BACKGROUND_REQUEST;
2434 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2435 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2436 int font_nr = FONT_REQUEST;
2437 int font_width = getFontWidth(font_nr);
2438 int font_height = getFontHeight(font_nr);
2439 int border_size = request.border_size;
2440 int line_spacing = request.line_spacing;
2441 int line_height = font_height + line_spacing;
2442 int max_text_width = request.width - 2 * border_size;
2443 int max_text_height = request.height - 2 * border_size;
2444 int line_length = max_text_width / font_width;
2445 int max_lines = max_text_height / line_height;
2446 int text_width = line_length * font_width;
2447 int width = request.width;
2448 int height = request.height;
2449 int tile_size = MAX(request.step_offset, 1);
2450 int x_steps = width / tile_size;
2451 int y_steps = height / tile_size;
2452 int sx_offset = border_size;
2453 int sy_offset = border_size;
2457 if (request.centered)
2458 sx_offset = (request.width - text_width) / 2;
2460 if (request.wrap_single_words && !request.autowrap)
2462 char *src_text_ptr, *dst_text_ptr;
2464 text_door_style = checked_malloc(2 * strlen(text) + 1);
2466 src_text_ptr = text;
2467 dst_text_ptr = text_door_style;
2469 while (*src_text_ptr)
2471 if (*src_text_ptr == ' ' ||
2472 *src_text_ptr == '?' ||
2473 *src_text_ptr == '!')
2474 *dst_text_ptr++ = '\n';
2476 if (*src_text_ptr != ' ')
2477 *dst_text_ptr++ = *src_text_ptr;
2482 *dst_text_ptr = '\0';
2484 text_final = text_door_style;
2487 setRequestPosition(&sx, &sy, FALSE);
2489 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
2491 for (y = 0; y < y_steps; y++)
2492 for (x = 0; x < x_steps; x++)
2493 DrawEnvelopeBackgroundTiles(graphic, sx, sy,
2494 x, y, x_steps, y_steps,
2495 tile_size, tile_size);
2497 /* force DOOR font inside door area */
2498 SetGameStatus(GAME_MODE_PSEUDO_DOOR);
2500 DrawTextBuffer(sx + sx_offset, sy + sy_offset, text_final, font_nr,
2501 line_length, -1, max_lines, line_spacing, mask_mode,
2502 request.autowrap, request.centered, FALSE);
2504 SetGameStatus(last_game_status); /* restore current game status */
2506 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2507 RedrawGadget(tool_gadget[i]);
2509 // store readily prepared envelope request for later use when animating
2510 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2512 if (text_door_style)
2513 free(text_door_style);
2516 void AnimateEnvelopeRequest(int anim_mode, int action)
2518 int graphic = IMG_BACKGROUND_REQUEST;
2519 boolean draw_masked = graphic_info[graphic].draw_masked;
2520 int delay_value_normal = request.step_delay;
2521 int delay_value_fast = delay_value_normal / 2;
2522 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2523 boolean no_delay = (tape.warp_forward);
2524 int delay_value = (ffwd_delay ? delay_value_fast : delay_value_normal);
2525 int anim_delay_value = (no_delay ? 0 : delay_value + 500 * 0) / 2;
2526 unsigned int anim_delay = 0;
2528 int tile_size = MAX(request.step_offset, 1);
2529 int max_xsize = request.width / tile_size;
2530 int max_ysize = request.height / tile_size;
2531 int max_xsize_inner = max_xsize - 2;
2532 int max_ysize_inner = max_ysize - 2;
2534 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize_inner : 0);
2535 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize_inner : 0);
2536 int xend = max_xsize_inner;
2537 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize_inner : 0);
2538 int xstep = (xstart < xend ? 1 : 0);
2539 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2541 int end = MAX(xend - xstart, yend - ystart);
2544 if (setup.quick_doors)
2551 for (i = start; i <= end; i++)
2553 int last_frame = end; // last frame of this "for" loop
2554 int x = xstart + i * xstep;
2555 int y = ystart + i * ystep;
2556 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2557 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2558 int xsize_size_left = (xsize - 1) * tile_size;
2559 int ysize_size_top = (ysize - 1) * tile_size;
2560 int max_xsize_pos = (max_xsize - 1) * tile_size;
2561 int max_ysize_pos = (max_ysize - 1) * tile_size;
2562 int width = xsize * tile_size;
2563 int height = ysize * tile_size;
2568 setRequestPosition(&src_x, &src_y, FALSE);
2569 setRequestPositionExt(&dst_x, &dst_y, width, height, FALSE);
2571 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2573 for (yy = 0; yy < 2; yy++)
2575 for (xx = 0; xx < 2; xx++)
2577 int src_xx = src_x + xx * max_xsize_pos;
2578 int src_yy = src_y + yy * max_ysize_pos;
2579 int dst_xx = dst_x + xx * xsize_size_left;
2580 int dst_yy = dst_y + yy * ysize_size_top;
2581 int xx_size = (xx ? tile_size : xsize_size_left);
2582 int yy_size = (yy ? tile_size : ysize_size_top);
2585 BlitBitmapMasked(bitmap_db_cross, backbuffer,
2586 src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
2588 BlitBitmap(bitmap_db_cross, backbuffer,
2589 src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
2593 redraw_mask |= REDRAW_FIELD;
2598 SkipUntilDelayReached(&anim_delay, anim_delay_value, &i, last_frame);
2602 void ShowEnvelopeRequest(char *text, unsigned int req_state, int action)
2604 int graphic = IMG_BACKGROUND_REQUEST;
2605 int sound_opening = SND_REQUEST_OPENING;
2606 int sound_closing = SND_REQUEST_CLOSING;
2607 int anim_mode_1 = request.anim_mode; /* (higher priority) */
2608 int anim_mode_2 = graphic_info[graphic].anim_mode; /* (lower priority) */
2609 int anim_mode = (anim_mode_1 != ANIM_DEFAULT ? anim_mode_1 : anim_mode_2);
2610 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2611 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2613 if (game_status == GAME_MODE_PLAYING)
2614 BlitScreenToBitmap(backbuffer);
2616 SetDrawtoField(DRAW_BACKBUFFER);
2618 // SetDrawBackgroundMask(REDRAW_NONE);
2620 if (action == ACTION_OPENING)
2622 BlitBitmap(backbuffer, bitmap_db_store, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2624 if (req_state & REQ_ASK)
2626 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2627 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2629 else if (req_state & REQ_CONFIRM)
2631 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2633 else if (req_state & REQ_PLAYER)
2635 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2636 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2637 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2638 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2641 DrawEnvelopeRequest(text);
2643 if (game_status != GAME_MODE_MAIN)
2647 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
2649 if (action == ACTION_OPENING)
2651 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2653 if (anim_mode == ANIM_DEFAULT)
2654 AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_OPENING);
2656 AnimateEnvelopeRequest(main_anim_mode, ACTION_OPENING);
2660 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2662 if (anim_mode != ANIM_NONE)
2663 AnimateEnvelopeRequest(main_anim_mode, ACTION_CLOSING);
2665 if (anim_mode == ANIM_DEFAULT)
2666 AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_CLOSING);
2669 game.envelope_active = FALSE;
2671 if (action == ACTION_CLOSING)
2673 if (game_status != GAME_MODE_MAIN)
2676 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2679 // SetDrawBackgroundMask(last_draw_background_mask);
2681 redraw_mask |= REDRAW_FIELD;
2683 if (game_status == GAME_MODE_MAIN)
2688 if (action == ACTION_CLOSING &&
2689 game_status == GAME_MODE_PLAYING &&
2690 level.game_engine_type == GAME_ENGINE_TYPE_RND)
2691 SetDrawtoField(DRAW_FIELDBUFFER);
2694 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
2698 int graphic = el2preimg(element);
2700 getSizedGraphicSource(graphic, 0, tilesize, &src_bitmap, &src_x, &src_y);
2701 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
2704 void DrawLevel(int draw_background_mask)
2708 SetMainBackgroundImage(IMG_BACKGROUND_PLAYING);
2709 SetDrawBackgroundMask(draw_background_mask);
2713 for (x = BX1; x <= BX2; x++)
2714 for (y = BY1; y <= BY2; y++)
2715 DrawScreenField(x, y);
2717 redraw_mask |= REDRAW_FIELD;
2720 void DrawSizedLevel(int size_x, int size_y, int scroll_x, int scroll_y,
2725 for (x = 0; x < size_x; x++)
2726 for (y = 0; y < size_y; y++)
2727 DrawSizedElementOrWall(x, y, scroll_x, scroll_y, tilesize);
2729 redraw_mask |= REDRAW_FIELD;
2732 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
2736 for (x = 0; x < size_x; x++)
2737 for (y = 0; y < size_y; y++)
2738 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
2740 redraw_mask |= REDRAW_FIELD;
2743 static void DrawPreviewLevelPlayfieldExt(int from_x, int from_y)
2745 boolean show_level_border = (BorderElement != EL_EMPTY);
2746 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2747 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2748 int tile_size = preview.tile_size;
2749 int preview_width = preview.xsize * tile_size;
2750 int preview_height = preview.ysize * tile_size;
2751 int real_preview_xsize = MIN(level_xsize, preview.xsize);
2752 int real_preview_ysize = MIN(level_ysize, preview.ysize);
2753 int real_preview_width = real_preview_xsize * tile_size;
2754 int real_preview_height = real_preview_ysize * tile_size;
2755 int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
2756 int dst_y = SY + ALIGNED_YPOS(preview.y, preview_height, preview.valign);
2759 if (!IN_GFX_FIELD_FULL(dst_x, dst_y + preview_height - 1))
2762 DrawBackground(dst_x, dst_y, preview_width, preview_height);
2764 dst_x += (preview_width - real_preview_width) / 2;
2765 dst_y += (preview_height - real_preview_height) / 2;
2767 for (x = 0; x < real_preview_xsize; x++)
2769 for (y = 0; y < real_preview_ysize; y++)
2771 int lx = from_x + x + (show_level_border ? -1 : 0);
2772 int ly = from_y + y + (show_level_border ? -1 : 0);
2773 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
2774 getBorderElement(lx, ly));
2776 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
2777 element, tile_size);
2781 redraw_mask |= REDRAW_FIELD;
2784 #define MICROLABEL_EMPTY 0
2785 #define MICROLABEL_LEVEL_NAME 1
2786 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
2787 #define MICROLABEL_LEVEL_AUTHOR 3
2788 #define MICROLABEL_IMPORTED_FROM_HEAD 4
2789 #define MICROLABEL_IMPORTED_FROM 5
2790 #define MICROLABEL_IMPORTED_BY_HEAD 6
2791 #define MICROLABEL_IMPORTED_BY 7
2793 static int getMaxTextLength(struct TextPosInfo *pos, int font_nr)
2795 int max_text_width = SXSIZE;
2796 int font_width = getFontWidth(font_nr);
2798 if (pos->align == ALIGN_CENTER)
2799 max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
2800 else if (pos->align == ALIGN_RIGHT)
2801 max_text_width = pos->x;
2803 max_text_width = SXSIZE - pos->x;
2805 return max_text_width / font_width;
2808 static void DrawPreviewLevelLabelExt(int mode)
2810 struct TextPosInfo *pos = &menu.main.text.level_info_2;
2811 char label_text[MAX_OUTPUT_LINESIZE + 1];
2812 int max_len_label_text;
2813 int font_nr = pos->font;
2816 if (!IN_GFX_FIELD_FULL(pos->x, pos->y + getFontHeight(pos->font)))
2819 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
2820 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
2821 mode == MICROLABEL_IMPORTED_BY_HEAD)
2822 font_nr = pos->font_alt;
2824 max_len_label_text = getMaxTextLength(pos, font_nr);
2826 if (pos->size != -1)
2827 max_len_label_text = pos->size;
2829 for (i = 0; i < max_len_label_text; i++)
2830 label_text[i] = ' ';
2831 label_text[max_len_label_text] = '\0';
2833 if (strlen(label_text) > 0)
2834 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2837 (mode == MICROLABEL_LEVEL_NAME ? level.name :
2838 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
2839 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
2840 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
2841 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
2842 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
2843 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
2844 max_len_label_text);
2845 label_text[max_len_label_text] = '\0';
2847 if (strlen(label_text) > 0)
2848 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2850 redraw_mask |= REDRAW_FIELD;
2853 static void DrawPreviewLevelExt(boolean restart)
2855 static unsigned int scroll_delay = 0;
2856 static unsigned int label_delay = 0;
2857 static int from_x, from_y, scroll_direction;
2858 static int label_state, label_counter;
2859 unsigned int scroll_delay_value = preview.step_delay;
2860 boolean show_level_border = (BorderElement != EL_EMPTY);
2861 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2862 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2863 int last_game_status = game_status; /* save current game status */
2870 if (preview.anim_mode == ANIM_CENTERED)
2872 if (level_xsize > preview.xsize)
2873 from_x = (level_xsize - preview.xsize) / 2;
2874 if (level_ysize > preview.ysize)
2875 from_y = (level_ysize - preview.ysize) / 2;
2878 from_x += preview.xoffset;
2879 from_y += preview.yoffset;
2881 scroll_direction = MV_RIGHT;
2885 DrawPreviewLevelPlayfieldExt(from_x, from_y);
2886 DrawPreviewLevelLabelExt(label_state);
2888 /* initialize delay counters */
2889 DelayReached(&scroll_delay, 0);
2890 DelayReached(&label_delay, 0);
2892 if (leveldir_current->name)
2894 struct TextPosInfo *pos = &menu.main.text.level_info_1;
2895 char label_text[MAX_OUTPUT_LINESIZE + 1];
2896 int font_nr = pos->font;
2897 int max_len_label_text = getMaxTextLength(pos, font_nr);
2899 if (pos->size != -1)
2900 max_len_label_text = pos->size;
2902 strncpy(label_text, leveldir_current->name, max_len_label_text);
2903 label_text[max_len_label_text] = '\0';
2905 if (IN_GFX_FIELD_FULL(pos->x, pos->y + getFontHeight(pos->font)))
2906 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2909 SetGameStatus(last_game_status); /* restore current game status */
2914 /* scroll preview level, if needed */
2915 if (preview.anim_mode != ANIM_NONE &&
2916 (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
2917 DelayReached(&scroll_delay, scroll_delay_value))
2919 switch (scroll_direction)
2924 from_x -= preview.step_offset;
2925 from_x = (from_x < 0 ? 0 : from_x);
2928 scroll_direction = MV_UP;
2932 if (from_x < level_xsize - preview.xsize)
2934 from_x += preview.step_offset;
2935 from_x = (from_x > level_xsize - preview.xsize ?
2936 level_xsize - preview.xsize : from_x);
2939 scroll_direction = MV_DOWN;
2945 from_y -= preview.step_offset;
2946 from_y = (from_y < 0 ? 0 : from_y);
2949 scroll_direction = MV_RIGHT;
2953 if (from_y < level_ysize - preview.ysize)
2955 from_y += preview.step_offset;
2956 from_y = (from_y > level_ysize - preview.ysize ?
2957 level_ysize - preview.ysize : from_y);
2960 scroll_direction = MV_LEFT;
2967 DrawPreviewLevelPlayfieldExt(from_x, from_y);
2970 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
2971 /* redraw micro level label, if needed */
2972 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
2973 !strEqual(level.author, ANONYMOUS_NAME) &&
2974 !strEqual(level.author, leveldir_current->name) &&
2975 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
2977 int max_label_counter = 23;
2979 if (leveldir_current->imported_from != NULL &&
2980 strlen(leveldir_current->imported_from) > 0)
2981 max_label_counter += 14;
2982 if (leveldir_current->imported_by != NULL &&
2983 strlen(leveldir_current->imported_by) > 0)
2984 max_label_counter += 14;
2986 label_counter = (label_counter + 1) % max_label_counter;
2987 label_state = (label_counter >= 0 && label_counter <= 7 ?
2988 MICROLABEL_LEVEL_NAME :
2989 label_counter >= 9 && label_counter <= 12 ?
2990 MICROLABEL_LEVEL_AUTHOR_HEAD :
2991 label_counter >= 14 && label_counter <= 21 ?
2992 MICROLABEL_LEVEL_AUTHOR :
2993 label_counter >= 23 && label_counter <= 26 ?
2994 MICROLABEL_IMPORTED_FROM_HEAD :
2995 label_counter >= 28 && label_counter <= 35 ?
2996 MICROLABEL_IMPORTED_FROM :
2997 label_counter >= 37 && label_counter <= 40 ?
2998 MICROLABEL_IMPORTED_BY_HEAD :
2999 label_counter >= 42 && label_counter <= 49 ?
3000 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
3002 if (leveldir_current->imported_from == NULL &&
3003 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
3004 label_state == MICROLABEL_IMPORTED_FROM))
3005 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
3006 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
3008 DrawPreviewLevelLabelExt(label_state);
3011 SetGameStatus(last_game_status); /* restore current game status */
3014 void DrawPreviewLevelInitial()
3016 DrawPreviewLevelExt(TRUE);
3019 void DrawPreviewLevelAnimation()
3021 DrawPreviewLevelExt(FALSE);
3024 inline static void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
3025 int graphic, int sync_frame,
3028 int frame = getGraphicAnimationFrame(graphic, sync_frame);
3030 if (mask_mode == USE_MASKING)
3031 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
3033 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
3036 void DrawFixedGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
3037 int graphic, int sync_frame, int mask_mode)
3039 int frame = getGraphicAnimationFrame(graphic, sync_frame);
3041 if (mask_mode == USE_MASKING)
3042 DrawFixedGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
3044 DrawFixedGraphicExt(dst_bitmap, x, y, graphic, frame);
3047 inline static void DrawGraphicAnimation(int x, int y, int graphic)
3049 int lx = LEVELX(x), ly = LEVELY(y);
3051 if (!IN_SCR_FIELD(x, y))
3054 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
3055 graphic, GfxFrame[lx][ly], NO_MASKING);
3057 MarkTileDirty(x, y);
3060 void DrawFixedGraphicAnimation(int x, int y, int graphic)
3062 int lx = LEVELX(x), ly = LEVELY(y);
3064 if (!IN_SCR_FIELD(x, y))
3067 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
3068 graphic, GfxFrame[lx][ly], NO_MASKING);
3069 MarkTileDirty(x, y);
3072 void DrawLevelGraphicAnimation(int x, int y, int graphic)
3074 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
3077 void DrawLevelElementAnimation(int x, int y, int element)
3079 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
3081 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
3084 void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
3086 int sx = SCREENX(x), sy = SCREENY(y);
3088 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
3091 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
3094 DrawGraphicAnimation(sx, sy, graphic);
3097 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
3098 DrawLevelFieldCrumbled(x, y);
3100 if (GFX_CRUMBLED(Feld[x][y]))
3101 DrawLevelFieldCrumbled(x, y);
3105 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
3107 int sx = SCREENX(x), sy = SCREENY(y);
3110 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
3113 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
3115 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
3118 DrawGraphicAnimation(sx, sy, graphic);
3120 if (GFX_CRUMBLED(element))
3121 DrawLevelFieldCrumbled(x, y);
3124 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
3126 if (player->use_murphy)
3128 /* this works only because currently only one player can be "murphy" ... */
3129 static int last_horizontal_dir = MV_LEFT;
3130 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
3132 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3133 last_horizontal_dir = move_dir;
3135 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
3137 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
3139 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
3145 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
3148 static boolean equalGraphics(int graphic1, int graphic2)
3150 struct GraphicInfo *g1 = &graphic_info[graphic1];
3151 struct GraphicInfo *g2 = &graphic_info[graphic2];
3153 return (g1->bitmap == g2->bitmap &&
3154 g1->src_x == g2->src_x &&
3155 g1->src_y == g2->src_y &&
3156 g1->anim_frames == g2->anim_frames &&
3157 g1->anim_delay == g2->anim_delay &&
3158 g1->anim_mode == g2->anim_mode);
3161 void DrawAllPlayers()
3165 for (i = 0; i < MAX_PLAYERS; i++)
3166 if (stored_player[i].active)
3167 DrawPlayer(&stored_player[i]);
3170 void DrawPlayerField(int x, int y)
3172 if (!IS_PLAYER(x, y))
3175 DrawPlayer(PLAYERINFO(x, y));
3178 #define DRAW_PLAYER_OVER_PUSHED_ELEMENT 1
3180 void DrawPlayer(struct PlayerInfo *player)
3182 int jx = player->jx;
3183 int jy = player->jy;
3184 int move_dir = player->MovDir;
3185 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
3186 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
3187 int last_jx = (player->is_moving ? jx - dx : jx);
3188 int last_jy = (player->is_moving ? jy - dy : jy);
3189 int next_jx = jx + dx;
3190 int next_jy = jy + dy;
3191 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
3192 boolean player_is_opaque = FALSE;
3193 int sx = SCREENX(jx), sy = SCREENY(jy);
3194 int sxx = 0, syy = 0;
3195 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
3197 int action = ACTION_DEFAULT;
3198 int last_player_graphic = getPlayerGraphic(player, move_dir);
3199 int last_player_frame = player->Frame;
3202 /* GfxElement[][] is set to the element the player is digging or collecting;
3203 remove also for off-screen player if the player is not moving anymore */
3204 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
3205 GfxElement[jx][jy] = EL_UNDEFINED;
3207 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
3211 if (!IN_LEV_FIELD(jx, jy))
3213 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
3214 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
3215 printf("DrawPlayerField(): This should never happen!\n");
3220 if (element == EL_EXPLOSION)
3223 action = (player->is_pushing ? ACTION_PUSHING :
3224 player->is_digging ? ACTION_DIGGING :
3225 player->is_collecting ? ACTION_COLLECTING :
3226 player->is_moving ? ACTION_MOVING :
3227 player->is_snapping ? ACTION_SNAPPING :
3228 player->is_dropping ? ACTION_DROPPING :
3229 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
3231 if (player->is_waiting)
3232 move_dir = player->dir_waiting;
3234 InitPlayerGfxAnimation(player, action, move_dir);
3236 /* ----------------------------------------------------------------------- */
3237 /* draw things in the field the player is leaving, if needed */
3238 /* ----------------------------------------------------------------------- */
3240 if (player->is_moving)
3242 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
3244 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
3246 if (last_element == EL_DYNAMITE_ACTIVE ||
3247 last_element == EL_EM_DYNAMITE_ACTIVE ||
3248 last_element == EL_SP_DISK_RED_ACTIVE)
3249 DrawDynamite(last_jx, last_jy);
3251 DrawLevelFieldThruMask(last_jx, last_jy);
3253 else if (last_element == EL_DYNAMITE_ACTIVE ||
3254 last_element == EL_EM_DYNAMITE_ACTIVE ||
3255 last_element == EL_SP_DISK_RED_ACTIVE)
3256 DrawDynamite(last_jx, last_jy);
3258 /* !!! this is not enough to prevent flickering of players which are
3259 moving next to each others without a free tile between them -- this
3260 can only be solved by drawing all players layer by layer (first the
3261 background, then the foreground etc.) !!! => TODO */
3262 else if (!IS_PLAYER(last_jx, last_jy))
3263 DrawLevelField(last_jx, last_jy);
3266 DrawLevelField(last_jx, last_jy);
3269 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
3270 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
3273 if (!IN_SCR_FIELD(sx, sy))
3276 /* ----------------------------------------------------------------------- */
3277 /* draw things behind the player, if needed */
3278 /* ----------------------------------------------------------------------- */
3281 DrawLevelElement(jx, jy, Back[jx][jy]);
3282 else if (IS_ACTIVE_BOMB(element))
3283 DrawLevelElement(jx, jy, EL_EMPTY);
3286 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
3288 int old_element = GfxElement[jx][jy];
3289 int old_graphic = el_act_dir2img(old_element, action, move_dir);
3290 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
3292 if (GFX_CRUMBLED(old_element))
3293 DrawLevelFieldCrumbledDigging(jx, jy, move_dir, player->StepFrame);
3295 DrawGraphic(sx, sy, old_graphic, frame);
3297 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
3298 player_is_opaque = TRUE;
3302 GfxElement[jx][jy] = EL_UNDEFINED;
3304 /* make sure that pushed elements are drawn with correct frame rate */
3305 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
3307 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
3308 GfxFrame[jx][jy] = player->StepFrame;
3310 DrawLevelField(jx, jy);
3314 #if !DRAW_PLAYER_OVER_PUSHED_ELEMENT
3315 /* ----------------------------------------------------------------------- */
3316 /* draw player himself */
3317 /* ----------------------------------------------------------------------- */
3319 graphic = getPlayerGraphic(player, move_dir);
3321 /* in the case of changed player action or direction, prevent the current
3322 animation frame from being restarted for identical animations */
3323 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
3324 player->Frame = last_player_frame;
3326 frame = getGraphicAnimationFrame(graphic, player->Frame);
3330 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3331 sxx = player->GfxPos;
3333 syy = player->GfxPos;
3336 if (player_is_opaque)
3337 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
3339 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3341 if (SHIELD_ON(player))
3343 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
3344 IMG_SHIELD_NORMAL_ACTIVE);
3345 int frame = getGraphicAnimationFrame(graphic, -1);
3347 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3351 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
3354 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3355 sxx = player->GfxPos;
3357 syy = player->GfxPos;
3361 /* ----------------------------------------------------------------------- */
3362 /* draw things the player is pushing, if needed */
3363 /* ----------------------------------------------------------------------- */
3365 if (player->is_pushing && player->is_moving)
3367 int px = SCREENX(jx), py = SCREENY(jy);
3368 int pxx = (TILEX - ABS(sxx)) * dx;
3369 int pyy = (TILEY - ABS(syy)) * dy;
3370 int gfx_frame = GfxFrame[jx][jy];
3376 if (!IS_MOVING(jx, jy)) /* push movement already finished */
3378 element = Feld[next_jx][next_jy];
3379 gfx_frame = GfxFrame[next_jx][next_jy];
3382 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
3384 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
3385 frame = getGraphicAnimationFrame(graphic, sync_frame);
3387 /* draw background element under pushed element (like the Sokoban field) */
3388 if (game.use_masked_pushing && IS_MOVING(jx, jy))
3390 /* this allows transparent pushing animation over non-black background */
3393 DrawLevelElement(jx, jy, Back[jx][jy]);
3395 DrawLevelElement(jx, jy, EL_EMPTY);
3397 if (Back[next_jx][next_jy])
3398 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3400 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
3402 else if (Back[next_jx][next_jy])
3403 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3406 /* do not draw (EM style) pushing animation when pushing is finished */
3407 /* (two-tile animations usually do not contain start and end frame) */
3408 if (graphic_info[graphic].double_movement && !IS_MOVING(jx, jy))
3409 DrawLevelElement(next_jx, next_jy, Feld[next_jx][next_jy]);
3411 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3413 /* masked drawing is needed for EMC style (double) movement graphics */
3414 /* !!! (ONLY WHEN DRAWING PUSHED ELEMENT OVER THE PLAYER) !!! */
3415 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3419 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
3420 /* ----------------------------------------------------------------------- */
3421 /* draw player himself */
3422 /* ----------------------------------------------------------------------- */
3424 graphic = getPlayerGraphic(player, move_dir);
3426 /* in the case of changed player action or direction, prevent the current
3427 animation frame from being restarted for identical animations */
3428 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
3429 player->Frame = last_player_frame;
3431 frame = getGraphicAnimationFrame(graphic, player->Frame);
3435 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3436 sxx = player->GfxPos;
3438 syy = player->GfxPos;
3441 if (player_is_opaque)
3442 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
3444 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3446 if (SHIELD_ON(player))
3448 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
3449 IMG_SHIELD_NORMAL_ACTIVE);
3450 int frame = getGraphicAnimationFrame(graphic, -1);
3452 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3456 /* ----------------------------------------------------------------------- */
3457 /* draw things in front of player (active dynamite or dynabombs) */
3458 /* ----------------------------------------------------------------------- */
3460 if (IS_ACTIVE_BOMB(element))
3462 graphic = el2img(element);
3463 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
3465 if (game.emulation == EMU_SUPAPLEX)
3466 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
3468 DrawGraphicThruMask(sx, sy, graphic, frame);
3471 if (player_is_moving && last_element == EL_EXPLOSION)
3473 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
3474 GfxElement[last_jx][last_jy] : EL_EMPTY);
3475 int graphic = el_act2img(element, ACTION_EXPLODING);
3476 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
3477 int phase = ExplodePhase[last_jx][last_jy] - 1;
3478 int frame = getGraphicAnimationFrame(graphic, phase - delay);
3481 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
3484 /* ----------------------------------------------------------------------- */
3485 /* draw elements the player is just walking/passing through/under */
3486 /* ----------------------------------------------------------------------- */
3488 if (player_is_moving)
3490 /* handle the field the player is leaving ... */
3491 if (IS_ACCESSIBLE_INSIDE(last_element))
3492 DrawLevelField(last_jx, last_jy);
3493 else if (IS_ACCESSIBLE_UNDER(last_element))
3494 DrawLevelFieldThruMask(last_jx, last_jy);
3497 /* do not redraw accessible elements if the player is just pushing them */
3498 if (!player_is_moving || !player->is_pushing)
3500 /* ... and the field the player is entering */
3501 if (IS_ACCESSIBLE_INSIDE(element))
3502 DrawLevelField(jx, jy);
3503 else if (IS_ACCESSIBLE_UNDER(element))
3504 DrawLevelFieldThruMask(jx, jy);
3507 MarkTileDirty(sx, sy);
3510 /* ------------------------------------------------------------------------- */
3512 void WaitForEventToContinue()
3514 boolean still_wait = TRUE;
3516 /* simulate releasing mouse button over last gadget, if still pressed */
3518 HandleGadgets(-1, -1, 0);
3520 button_status = MB_RELEASED;
3534 case EVENT_BUTTONPRESS:
3535 case EVENT_KEYPRESS:
3539 case EVENT_KEYRELEASE:
3540 ClearPlayerAction();
3544 HandleOtherEvents(&event);
3548 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3555 WaitUntilDelayReached(&sync_frame_delay, sync_frame_delay_value);
3559 #define MAX_REQUEST_LINES 13
3560 #define MAX_REQUEST_LINE_FONT1_LEN 7
3561 #define MAX_REQUEST_LINE_FONT2_LEN 10
3563 static int RequestHandleEvents(unsigned int req_state)
3565 boolean level_solved = (game_status == GAME_MODE_PLAYING &&
3566 local_player->LevelSolved_GameEnd);
3567 int width = request.width;
3568 int height = request.height;
3572 setRequestPosition(&sx, &sy, FALSE);
3574 button_status = MB_RELEASED;
3576 request_gadget_id = -1;
3583 SetDrawtoField(DRAW_FIELDBUFFER);
3585 HandleGameActions();
3587 SetDrawtoField(DRAW_BACKBUFFER);
3589 if (global.use_envelope_request)
3591 /* copy current state of request area to middle of playfield area */
3592 BlitBitmap(bitmap_db_cross, drawto, sx, sy, width, height, sx, sy);
3600 while (NextValidEvent(&event))
3604 case EVENT_BUTTONPRESS:
3605 case EVENT_BUTTONRELEASE:
3606 case EVENT_MOTIONNOTIFY:
3610 if (event.type == EVENT_MOTIONNOTIFY)
3615 motion_status = TRUE;
3616 mx = ((MotionEvent *) &event)->x;
3617 my = ((MotionEvent *) &event)->y;
3621 motion_status = FALSE;
3622 mx = ((ButtonEvent *) &event)->x;
3623 my = ((ButtonEvent *) &event)->y;
3624 if (event.type == EVENT_BUTTONPRESS)
3625 button_status = ((ButtonEvent *) &event)->button;
3627 button_status = MB_RELEASED;
3630 /* this sets 'request_gadget_id' */
3631 HandleGadgets(mx, my, button_status);
3633 switch (request_gadget_id)
3635 case TOOL_CTRL_ID_YES:
3638 case TOOL_CTRL_ID_NO:
3641 case TOOL_CTRL_ID_CONFIRM:
3642 result = TRUE | FALSE;
3645 case TOOL_CTRL_ID_PLAYER_1:
3648 case TOOL_CTRL_ID_PLAYER_2:
3651 case TOOL_CTRL_ID_PLAYER_3:
3654 case TOOL_CTRL_ID_PLAYER_4:
3665 case EVENT_KEYPRESS:
3666 switch (GetEventKey((KeyEvent *)&event, TRUE))
3669 if (req_state & REQ_CONFIRM)
3674 #if defined(TARGET_SDL2)
3681 #if defined(TARGET_SDL2)
3691 if (req_state & REQ_PLAYER)
3695 case EVENT_KEYRELEASE:
3696 ClearPlayerAction();
3700 HandleOtherEvents(&event);
3705 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3707 int joy = AnyJoystick();
3709 if (joy & JOY_BUTTON_1)
3711 else if (joy & JOY_BUTTON_2)
3717 if (global.use_envelope_request)
3719 /* copy back current state of pressed buttons inside request area */
3720 BlitBitmap(drawto, bitmap_db_cross, sx, sy, width, height, sx, sy);
3730 WaitUntilDelayReached(&sync_frame_delay, sync_frame_delay_value);
3736 static boolean RequestDoor(char *text, unsigned int req_state)
3738 unsigned int old_door_state;
3739 int last_game_status = game_status; /* save current game status */
3740 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
3741 int font_nr = FONT_TEXT_2;
3746 if (maxWordLengthInString(text) > MAX_REQUEST_LINE_FONT1_LEN)
3748 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
3749 font_nr = FONT_TEXT_1;
3752 if (game_status == GAME_MODE_PLAYING)
3753 BlitScreenToBitmap(backbuffer);
3755 /* disable deactivated drawing when quick-loading level tape recording */
3756 if (tape.playing && tape.deactivate_display)
3757 TapeDeactivateDisplayOff(TRUE);
3759 SetMouseCursor(CURSOR_DEFAULT);
3761 #if defined(NETWORK_AVALIABLE)
3762 /* pause network game while waiting for request to answer */
3763 if (options.network &&
3764 game_status == GAME_MODE_PLAYING &&
3765 req_state & REQUEST_WAIT_FOR_INPUT)
3766 SendToServer_PausePlaying();
3769 old_door_state = GetDoorState();
3771 /* simulate releasing mouse button over last gadget, if still pressed */
3773 HandleGadgets(-1, -1, 0);
3777 /* draw released gadget before proceeding */
3780 if (old_door_state & DOOR_OPEN_1)
3782 CloseDoor(DOOR_CLOSE_1);
3784 /* save old door content */
3785 BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
3786 0 * DXSIZE, 0, DXSIZE, DYSIZE, 1 * DXSIZE, 0);
3789 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
3790 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3792 /* clear door drawing field */
3793 DrawBackground(DX, DY, DXSIZE, DYSIZE);
3795 /* force DOOR font inside door area */
3796 SetGameStatus(GAME_MODE_PSEUDO_DOOR);
3798 /* write text for request */
3799 for (text_ptr = text, ty = 0; ty < MAX_REQUEST_LINES; ty++)
3801 char text_line[max_request_line_len + 1];
3807 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
3809 tc = *(text_ptr + tx);
3810 // if (!tc || tc == ' ')
3811 if (!tc || tc == ' ' || tc == '?' || tc == '!')
3815 if ((tc == '?' || tc == '!') && tl == 0)
3825 strncpy(text_line, text_ptr, tl);
3828 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
3829 DY + 8 + ty * (getFontHeight(font_nr) + 2),
3830 text_line, font_nr);
3832 text_ptr += tl + (tc == ' ' ? 1 : 0);
3833 // text_ptr += tl + (tc == ' ' || tc == '?' || tc == '!' ? 1 : 0);
3836 SetGameStatus(last_game_status); /* restore current game status */
3838 if (req_state & REQ_ASK)
3840 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
3841 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
3843 else if (req_state & REQ_CONFIRM)
3845 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
3847 else if (req_state & REQ_PLAYER)
3849 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
3850 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
3851 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
3852 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
3855 /* copy request gadgets to door backbuffer */
3856 BlitBitmap(drawto, bitmap_db_door_1, DX, DY, DXSIZE, DYSIZE, 0, 0);
3858 OpenDoor(DOOR_OPEN_1);
3860 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
3862 if (game_status == GAME_MODE_PLAYING)
3864 SetPanelBackground();
3865 SetDrawBackgroundMask(REDRAW_DOOR_1);
3869 SetDrawBackgroundMask(REDRAW_FIELD);
3875 if (game_status != GAME_MODE_MAIN)
3878 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3880 // ---------- handle request buttons ----------
3881 result = RequestHandleEvents(req_state);
3883 if (game_status != GAME_MODE_MAIN)
3888 if (!(req_state & REQ_STAY_OPEN))
3890 CloseDoor(DOOR_CLOSE_1);
3892 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
3893 (req_state & REQ_REOPEN))
3894 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
3899 if (game_status == GAME_MODE_PLAYING)
3901 SetPanelBackground();
3902 SetDrawBackgroundMask(REDRAW_DOOR_1);
3906 SetDrawBackgroundMask(REDRAW_FIELD);
3909 #if defined(NETWORK_AVALIABLE)
3910 /* continue network game after request */
3911 if (options.network &&
3912 game_status == GAME_MODE_PLAYING &&
3913 req_state & REQUEST_WAIT_FOR_INPUT)
3914 SendToServer_ContinuePlaying();
3917 /* restore deactivated drawing when quick-loading level tape recording */
3918 if (tape.playing && tape.deactivate_display)
3919 TapeDeactivateDisplayOn();
3924 static boolean RequestEnvelope(char *text, unsigned int req_state)
3928 if (game_status == GAME_MODE_PLAYING)
3929 BlitScreenToBitmap(backbuffer);
3931 /* disable deactivated drawing when quick-loading level tape recording */
3932 if (tape.playing && tape.deactivate_display)
3933 TapeDeactivateDisplayOff(TRUE);
3935 SetMouseCursor(CURSOR_DEFAULT);
3937 #if defined(NETWORK_AVALIABLE)
3938 /* pause network game while waiting for request to answer */
3939 if (options.network &&
3940 game_status == GAME_MODE_PLAYING &&
3941 req_state & REQUEST_WAIT_FOR_INPUT)
3942 SendToServer_PausePlaying();
3945 /* simulate releasing mouse button over last gadget, if still pressed */
3947 HandleGadgets(-1, -1, 0);
3951 // (replace with setting corresponding request background)
3952 // SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
3953 // SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3955 /* clear door drawing field */
3956 // DrawBackground(DX, DY, DXSIZE, DYSIZE);
3958 ShowEnvelopeRequest(text, req_state, ACTION_OPENING);
3960 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
3962 if (game_status == GAME_MODE_PLAYING)
3964 SetPanelBackground();
3965 SetDrawBackgroundMask(REDRAW_DOOR_1);
3969 SetDrawBackgroundMask(REDRAW_FIELD);
3975 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3977 // ---------- handle request buttons ----------
3978 result = RequestHandleEvents(req_state);
3980 if (game_status != GAME_MODE_MAIN)
3985 ShowEnvelopeRequest(text, req_state, ACTION_CLOSING);
3989 if (game_status == GAME_MODE_PLAYING)
3991 SetPanelBackground();
3992 SetDrawBackgroundMask(REDRAW_DOOR_1);
3996 SetDrawBackgroundMask(REDRAW_FIELD);
3999 #if defined(NETWORK_AVALIABLE)
4000 /* continue network game after request */
4001 if (options.network &&
4002 game_status == GAME_MODE_PLAYING &&
4003 req_state & REQUEST_WAIT_FOR_INPUT)
4004 SendToServer_ContinuePlaying();
4007 /* restore deactivated drawing when quick-loading level tape recording */
4008 if (tape.playing && tape.deactivate_display)
4009 TapeDeactivateDisplayOn();
4014 boolean Request(char *text, unsigned int req_state)
4016 if (global.use_envelope_request)
4017 return RequestEnvelope(text, req_state);
4019 return RequestDoor(text, req_state);
4022 static int compareDoorPartOrderInfo(const void *object1, const void *object2)
4024 const struct DoorPartOrderInfo *dpo1 = (struct DoorPartOrderInfo *)object1;
4025 const struct DoorPartOrderInfo *dpo2 = (struct DoorPartOrderInfo *)object2;
4028 if (dpo1->sort_priority != dpo2->sort_priority)
4029 compare_result = dpo1->sort_priority - dpo2->sort_priority;
4031 compare_result = dpo1->nr - dpo2->nr;
4033 return compare_result;
4036 void InitGraphicCompatibilityInfo_Doors()
4042 struct DoorInfo *door;
4046 { DOOR_1, IMG_DOOR_1_GFX_PART_1, IMG_DOOR_1_GFX_PART_8, &door_1 },
4047 { DOOR_2, IMG_DOOR_2_GFX_PART_1, IMG_DOOR_2_GFX_PART_8, &door_2 },
4049 { -1, -1, -1, NULL }
4051 struct Rect door_rect_list[] =
4053 { DX, DY, DXSIZE, DYSIZE },
4054 { VX, VY, VXSIZE, VYSIZE }
4058 for (i = 0; doors[i].door_token != -1; i++)
4060 int door_token = doors[i].door_token;
4061 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
4062 int part_1 = doors[i].part_1;
4063 int part_8 = doors[i].part_8;
4064 int part_2 = part_1 + 1;
4065 int part_3 = part_1 + 2;
4066 struct DoorInfo *door = doors[i].door;
4067 struct Rect *door_rect = &door_rect_list[door_index];
4068 boolean door_gfx_redefined = FALSE;
4070 /* check if any door part graphic definitions have been redefined */
4072 for (j = 0; door_part_controls[j].door_token != -1; j++)
4074 struct DoorPartControlInfo *dpc = &door_part_controls[j];
4075 struct FileInfo *fi = getImageListEntryFromImageID(dpc->graphic);
4077 if (dpc->door_token == door_token && fi->redefined)
4078 door_gfx_redefined = TRUE;
4081 /* check for old-style door graphic/animation modifications */
4083 if (!door_gfx_redefined)
4085 if (door->anim_mode & ANIM_STATIC_PANEL)
4087 door->panel.step_xoffset = 0;
4088 door->panel.step_yoffset = 0;
4091 if (door->anim_mode & (ANIM_HORIZONTAL | ANIM_VERTICAL))
4093 struct GraphicInfo *g_part_1 = &graphic_info[part_1];
4094 struct GraphicInfo *g_part_2 = &graphic_info[part_2];
4095 int num_door_steps, num_panel_steps;
4097 /* remove door part graphics other than the two default wings */
4099 for (j = 0; door_part_controls[j].door_token != -1; j++)
4101 struct DoorPartControlInfo *dpc = &door_part_controls[j];
4102 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4104 if (dpc->graphic >= part_3 &&
4105 dpc->graphic <= part_8)
4109 /* set graphics and screen positions of the default wings */
4111 g_part_1->width = door_rect->width;
4112 g_part_1->height = door_rect->height;
4113 g_part_2->width = door_rect->width;
4114 g_part_2->height = door_rect->height;
4115 g_part_2->src_x = door_rect->width;
4116 g_part_2->src_y = g_part_1->src_y;
4118 door->part_2.x = door->part_1.x;
4119 door->part_2.y = door->part_1.y;
4121 if (door->width != -1)
4123 g_part_1->width = door->width;
4124 g_part_2->width = door->width;
4126 // special treatment for graphics and screen position of right wing
4127 g_part_2->src_x += door_rect->width - door->width;
4128 door->part_2.x += door_rect->width - door->width;
4131 if (door->height != -1)
4133 g_part_1->height = door->height;
4134 g_part_2->height = door->height;
4136 // special treatment for graphics and screen position of bottom wing
4137 g_part_2->src_y += door_rect->height - door->height;
4138 door->part_2.y += door_rect->height - door->height;
4141 /* set animation delays for the default wings and panels */
4143 door->part_1.step_delay = door->step_delay;
4144 door->part_2.step_delay = door->step_delay;
4145 door->panel.step_delay = door->step_delay;
4147 /* set animation draw order for the default wings */
4149 door->part_1.sort_priority = 2; /* draw left wing over ... */
4150 door->part_2.sort_priority = 1; /* ... right wing */
4152 /* set animation draw offset for the default wings */
4154 if (door->anim_mode & ANIM_HORIZONTAL)
4156 door->part_1.step_xoffset = door->step_offset;
4157 door->part_1.step_yoffset = 0;
4158 door->part_2.step_xoffset = door->step_offset * -1;
4159 door->part_2.step_yoffset = 0;
4161 num_door_steps = g_part_1->width / door->step_offset;
4163 else // ANIM_VERTICAL
4165 door->part_1.step_xoffset = 0;
4166 door->part_1.step_yoffset = door->step_offset;
4167 door->part_2.step_xoffset = 0;
4168 door->part_2.step_yoffset = door->step_offset * -1;
4170 num_door_steps = g_part_1->height / door->step_offset;
4173 /* set animation draw offset for the default panels */
4175 if (door->step_offset > 1)
4177 num_panel_steps = 2 * door_rect->height / door->step_offset;
4178 door->panel.start_step = num_panel_steps - num_door_steps;
4179 door->panel.start_step_closing = door->panel.start_step;
4183 num_panel_steps = door_rect->height / door->step_offset;
4184 door->panel.start_step = num_panel_steps - num_door_steps / 2;
4185 door->panel.start_step_closing = door->panel.start_step;
4186 door->panel.step_delay *= 2;
4197 for (i = 0; door_part_controls[i].door_token != -1; i++)
4199 struct DoorPartControlInfo *dpc = &door_part_controls[i];
4200 struct DoorPartOrderInfo *dpo = &door_part_order[i];
4202 /* initialize "start_step_opening" and "start_step_closing", if needed */
4203 if (dpc->pos->start_step_opening == 0 &&
4204 dpc->pos->start_step_closing == 0)
4206 // dpc->pos->start_step_opening = dpc->pos->start_step;
4207 dpc->pos->start_step_closing = dpc->pos->start_step;
4210 /* fill structure for door part draw order (sorted below) */
4212 dpo->sort_priority = dpc->pos->sort_priority;
4215 /* sort door part controls according to sort_priority and graphic number */
4216 qsort(door_part_order, MAX_DOOR_PARTS,
4217 sizeof(struct DoorPartOrderInfo), compareDoorPartOrderInfo);
4220 unsigned int OpenDoor(unsigned int door_state)
4222 if (door_state & DOOR_COPY_BACK)
4224 if (door_state & DOOR_OPEN_1)
4225 BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
4226 1 * DXSIZE, 0, DXSIZE, DYSIZE, 0 * DXSIZE, 0);
4228 if (door_state & DOOR_OPEN_2)
4229 BlitBitmap(bitmap_db_door_2, bitmap_db_door_2,
4230 1 * VXSIZE, 0, VXSIZE, VYSIZE, 0 * VXSIZE, 0);
4232 door_state &= ~DOOR_COPY_BACK;
4235 return MoveDoor(door_state);
4238 unsigned int CloseDoor(unsigned int door_state)
4240 unsigned int old_door_state = GetDoorState();
4242 if (!(door_state & DOOR_NO_COPY_BACK))
4244 if (old_door_state & DOOR_OPEN_1)
4245 BlitBitmap(backbuffer, bitmap_db_door_1,
4246 DX, DY, DXSIZE, DYSIZE, 0, 0);
4248 if (old_door_state & DOOR_OPEN_2)
4249 BlitBitmap(backbuffer, bitmap_db_door_2,
4250 VX, VY, VXSIZE, VYSIZE, 0, 0);
4252 door_state &= ~DOOR_NO_COPY_BACK;
4255 return MoveDoor(door_state);
4258 unsigned int GetDoorState()
4260 return MoveDoor(DOOR_GET_STATE);
4263 unsigned int SetDoorState(unsigned int door_state)
4265 return MoveDoor(door_state | DOOR_SET_STATE);
4268 int euclid(int a, int b)
4270 return (b ? euclid(b, a % b) : a);
4273 unsigned int MoveDoor(unsigned int door_state)
4275 struct Rect door_rect_list[] =
4277 { DX, DY, DXSIZE, DYSIZE },
4278 { VX, VY, VXSIZE, VYSIZE }
4280 static int door1 = DOOR_CLOSE_1;
4281 static int door2 = DOOR_CLOSE_2;
4282 unsigned int door_delay = 0;
4283 unsigned int door_delay_value;
4286 if (door_state == DOOR_GET_STATE)
4287 return (door1 | door2);
4289 if (door_state & DOOR_SET_STATE)
4291 if (door_state & DOOR_ACTION_1)
4292 door1 = door_state & DOOR_ACTION_1;
4293 if (door_state & DOOR_ACTION_2)
4294 door2 = door_state & DOOR_ACTION_2;
4296 return (door1 | door2);
4299 if (!(door_state & DOOR_FORCE_REDRAW))
4301 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
4302 door_state &= ~DOOR_OPEN_1;
4303 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
4304 door_state &= ~DOOR_CLOSE_1;
4305 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
4306 door_state &= ~DOOR_OPEN_2;
4307 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
4308 door_state &= ~DOOR_CLOSE_2;
4311 if (global.autoplay_leveldir)
4313 door_state |= DOOR_NO_DELAY;
4314 door_state &= ~DOOR_CLOSE_ALL;
4317 if (game_status == GAME_MODE_EDITOR)
4318 door_state |= DOOR_NO_DELAY;
4320 if (door_state & DOOR_ACTION)
4322 boolean door_panel_drawn[NUM_DOORS];
4323 boolean panel_has_doors[NUM_DOORS];
4324 boolean door_part_skip[MAX_DOOR_PARTS];
4325 boolean door_part_done[MAX_DOOR_PARTS];
4326 boolean door_part_done_all;
4327 int num_steps[MAX_DOOR_PARTS];
4328 int max_move_delay = 0; // delay for complete animations of all doors
4329 int max_step_delay = 0; // delay (ms) between two animation frames
4330 int num_move_steps = 0; // number of animation steps for all doors
4331 int max_move_delay_doors_only = 0; // delay for doors only (no panel)
4332 int num_move_steps_doors_only = 0; // steps for doors only (no panel)
4333 int current_move_delay = 0;
4337 for (i = 0; i < NUM_DOORS; i++)
4338 panel_has_doors[i] = FALSE;
4340 for (i = 0; i < MAX_DOOR_PARTS; i++)
4342 struct DoorPartControlInfo *dpc = &door_part_controls[i];
4343 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4344 int door_token = dpc->door_token;
4346 door_part_done[i] = FALSE;
4347 door_part_skip[i] = (!(door_state & door_token) ||
4351 for (i = 0; i < MAX_DOOR_PARTS; i++)
4353 int nr = door_part_order[i].nr;
4354 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
4355 struct DoorPartPosInfo *pos = dpc->pos;
4356 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4357 int door_token = dpc->door_token;
4358 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
4359 boolean is_panel = DOOR_PART_IS_PANEL(nr);
4360 int step_xoffset = ABS(pos->step_xoffset);
4361 int step_yoffset = ABS(pos->step_yoffset);
4362 int step_delay = pos->step_delay;
4363 int current_door_state = door_state & door_token;
4364 boolean door_opening = ((current_door_state & DOOR_OPEN) != 0);
4365 boolean door_closing = ((current_door_state & DOOR_CLOSE) != 0);
4366 boolean part_opening = (is_panel ? door_closing : door_opening);
4367 int start_step = (part_opening ? pos->start_step_opening :
4368 pos->start_step_closing);
4369 float move_xsize = (step_xoffset ? g->width : 0);
4370 float move_ysize = (step_yoffset ? g->height : 0);
4371 int move_xsteps = (step_xoffset ? ceil(move_xsize / step_xoffset) : 0);
4372 int move_ysteps = (step_yoffset ? ceil(move_ysize / step_yoffset) : 0);
4373 int move_steps = (move_xsteps && move_ysteps ?
4374 MIN(move_xsteps, move_ysteps) :
4375 move_xsteps ? move_xsteps : move_ysteps) - start_step;
4376 int move_delay = move_steps * step_delay;
4378 if (door_part_skip[nr])
4381 max_move_delay = MAX(max_move_delay, move_delay);
4382 max_step_delay = (max_step_delay == 0 ? step_delay :
4383 euclid(max_step_delay, step_delay));
4384 num_steps[nr] = move_steps;
4388 max_move_delay_doors_only = MAX(max_move_delay_doors_only, move_delay);
4390 panel_has_doors[door_index] = TRUE;
4394 max_step_delay = MAX(1, max_step_delay); // prevent division by zero
4396 num_move_steps = max_move_delay / max_step_delay;
4397 num_move_steps_doors_only = max_move_delay_doors_only / max_step_delay;
4399 door_delay_value = max_step_delay;
4401 if ((door_state & DOOR_NO_DELAY) || setup.quick_doors)
4403 start = num_move_steps - 1;
4407 /* opening door sound has priority over simultaneously closing door */
4408 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
4409 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
4410 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
4411 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
4414 for (k = start; k < num_move_steps; k++)
4416 int last_frame = num_move_steps - 1; // last frame of this "for" loop
4418 door_part_done_all = TRUE;
4420 for (i = 0; i < NUM_DOORS; i++)
4421 door_panel_drawn[i] = FALSE;
4423 for (i = 0; i < MAX_DOOR_PARTS; i++)
4425 int nr = door_part_order[i].nr;
4426 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
4427 struct DoorPartPosInfo *pos = dpc->pos;
4428 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4429 int door_token = dpc->door_token;
4430 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
4431 boolean is_panel = DOOR_PART_IS_PANEL(nr);
4432 boolean is_panel_and_door_has_closed = FALSE;
4433 struct Rect *door_rect = &door_rect_list[door_index];
4434 Bitmap *bitmap_db_door = (door_token == DOOR_1 ? bitmap_db_door_1 :
4436 Bitmap *bitmap = (is_panel ? bitmap_db_door : g->bitmap);
4437 int current_door_state = door_state & door_token;
4438 boolean door_opening = ((current_door_state & DOOR_OPEN) != 0);
4439 boolean door_closing = !door_opening;
4440 boolean part_opening = (is_panel ? door_closing : door_opening);
4441 boolean part_closing = !part_opening;
4442 int start_step = (part_opening ? pos->start_step_opening :
4443 pos->start_step_closing);
4444 int step_delay = pos->step_delay;
4445 int step_factor = step_delay / max_step_delay;
4446 int k1 = (step_factor ? k / step_factor + 1 : k);
4447 int k2 = (part_opening ? k1 + start_step : num_steps[nr] - k1);
4448 int kk = MAX(0, k2);
4451 int src_x, src_y, src_xx, src_yy;
4452 int dst_x, dst_y, dst_xx, dst_yy;
4455 if (door_part_skip[nr])
4458 if (!(door_state & door_token))
4466 int k2_door = (door_opening ? k : num_move_steps_doors_only - k - 1);
4467 int kk_door = MAX(0, k2_door);
4468 int sync_frame = kk_door * door_delay_value;
4469 int frame = getGraphicAnimationFrame(dpc->graphic, sync_frame);
4471 getGraphicSource(dpc->graphic, frame, &bitmap, &g_src_x, &g_src_y);
4476 if (!door_panel_drawn[door_index])
4478 ClearRectangle(drawto, door_rect->x, door_rect->y,
4479 door_rect->width, door_rect->height);
4481 door_panel_drawn[door_index] = TRUE;
4484 // draw opening or closing door parts
4486 if (pos->step_xoffset < 0) // door part on right side
4489 dst_xx = pos->x + ABS(kk * pos->step_xoffset);
4492 if (dst_xx + width > door_rect->width)
4493 width = door_rect->width - dst_xx;
4495 else // door part on left side
4498 dst_xx = pos->x - kk * pos->step_xoffset;
4502 src_xx = ABS(dst_xx);
4506 width = g->width - src_xx;
4508 if (width > door_rect->width)
4509 width = door_rect->width;
4511 // printf("::: k == %d [%d] \n", k, start_step);
4514 if (pos->step_yoffset < 0) // door part on bottom side
4517 dst_yy = pos->y + ABS(kk * pos->step_yoffset);
4520 if (dst_yy + height > door_rect->height)
4521 height = door_rect->height - dst_yy;
4523 else // door part on top side
4526 dst_yy = pos->y - kk * pos->step_yoffset;
4530 src_yy = ABS(dst_yy);
4534 height = g->height - src_yy;
4537 src_x = g_src_x + src_xx;
4538 src_y = g_src_y + src_yy;
4540 dst_x = door_rect->x + dst_xx;
4541 dst_y = door_rect->y + dst_yy;
4543 is_panel_and_door_has_closed =
4546 panel_has_doors[door_index] &&
4547 k >= num_move_steps_doors_only - 1);
4549 if (width >= 0 && width <= g->width &&
4550 height >= 0 && height <= g->height &&
4551 !is_panel_and_door_has_closed)
4553 if (is_panel || !pos->draw_masked)
4554 BlitBitmap(bitmap, drawto, src_x, src_y, width, height,
4557 BlitBitmapMasked(bitmap, drawto, src_x, src_y, width, height,
4561 redraw_mask |= REDRAW_DOOR_FROM_TOKEN(door_token);
4563 if ((part_opening && (width < 0 || height < 0)) ||
4564 (part_closing && (width >= g->width && height >= g->height)))
4565 door_part_done[nr] = TRUE;
4567 // continue door part animations, but not panel after door has closed
4568 if (!door_part_done[nr] && !is_panel_and_door_has_closed)
4569 door_part_done_all = FALSE;
4572 if (!(door_state & DOOR_NO_DELAY))
4576 if (game_status == GAME_MODE_MAIN)
4579 SkipUntilDelayReached(&door_delay, door_delay_value, &k, last_frame);
4581 current_move_delay += max_step_delay;
4584 if (door_part_done_all)
4589 if (door_state & DOOR_ACTION_1)
4590 door1 = door_state & DOOR_ACTION_1;
4591 if (door_state & DOOR_ACTION_2)
4592 door2 = door_state & DOOR_ACTION_2;
4594 // draw masked border over door area
4595 DrawMaskedBorder(REDRAW_DOOR_1);
4596 DrawMaskedBorder(REDRAW_DOOR_2);
4598 return (door1 | door2);
4601 static boolean useSpecialEditorDoor()
4603 int graphic = IMG_GLOBAL_BORDER_EDITOR;
4604 boolean redefined = getImageListEntryFromImageID(graphic)->redefined;
4606 // do not draw special editor door if editor border defined or redefined
4607 if (graphic_info[graphic].bitmap != NULL || redefined)
4610 // do not draw special editor door if global border defined to be empty
4611 if (graphic_info[IMG_GLOBAL_BORDER].bitmap == NULL)
4614 // do not draw special editor door if viewport definitions do not match
4618 EY + EYSIZE != VY + VYSIZE)
4624 void DrawSpecialEditorDoor()
4626 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
4627 int top_border_width = gfx1->width;
4628 int top_border_height = gfx1->height;
4629 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
4630 int ex = EX - outer_border;
4631 int ey = EY - outer_border;
4632 int vy = VY - outer_border;
4633 int exsize = EXSIZE + 2 * outer_border;
4635 if (!useSpecialEditorDoor())
4638 /* draw bigger level editor toolbox window */
4639 BlitBitmap(gfx1->bitmap, drawto, gfx1->src_x, gfx1->src_y,
4640 top_border_width, top_border_height, ex, ey - top_border_height);
4641 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto, ex, vy,
4642 exsize, EYSIZE - VYSIZE + outer_border, ex, ey);
4644 redraw_mask |= REDRAW_ALL;
4647 void UndrawSpecialEditorDoor()
4649 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
4650 int top_border_width = gfx1->width;
4651 int top_border_height = gfx1->height;
4652 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
4653 int ex = EX - outer_border;
4654 int ey = EY - outer_border;
4655 int ey_top = ey - top_border_height;
4656 int exsize = EXSIZE + 2 * outer_border;
4657 int eysize = EYSIZE + 2 * outer_border;
4659 if (!useSpecialEditorDoor())
4662 /* draw normal tape recorder window */
4663 if (graphic_info[IMG_GLOBAL_BORDER].bitmap)
4665 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
4666 ex, ey_top, top_border_width, top_border_height,
4668 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
4669 ex, ey, exsize, eysize, ex, ey);
4673 // if screen background is set to "[NONE]", clear editor toolbox window
4674 ClearRectangle(drawto, ex, ey_top, top_border_width, top_border_height);
4675 ClearRectangle(drawto, ex, ey, exsize, eysize);
4678 redraw_mask |= REDRAW_ALL;
4682 /* ---------- new tool button stuff ---------------------------------------- */
4687 struct TextPosInfo *pos;
4690 } toolbutton_info[NUM_TOOL_BUTTONS] =
4693 IMG_REQUEST_BUTTON_GFX_YES, &request.button.yes,
4694 TOOL_CTRL_ID_YES, "yes"
4697 IMG_REQUEST_BUTTON_GFX_NO, &request.button.no,
4698 TOOL_CTRL_ID_NO, "no"
4701 IMG_REQUEST_BUTTON_GFX_CONFIRM, &request.button.confirm,
4702 TOOL_CTRL_ID_CONFIRM, "confirm"
4705 IMG_REQUEST_BUTTON_GFX_PLAYER_1, &request.button.player_1,
4706 TOOL_CTRL_ID_PLAYER_1, "player 1"
4709 IMG_REQUEST_BUTTON_GFX_PLAYER_2, &request.button.player_2,
4710 TOOL_CTRL_ID_PLAYER_2, "player 2"
4713 IMG_REQUEST_BUTTON_GFX_PLAYER_3, &request.button.player_3,
4714 TOOL_CTRL_ID_PLAYER_3, "player 3"
4717 IMG_REQUEST_BUTTON_GFX_PLAYER_4, &request.button.player_4,
4718 TOOL_CTRL_ID_PLAYER_4, "player 4"
4722 void CreateToolButtons()
4726 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4728 struct GraphicInfo *gfx = &graphic_info[toolbutton_info[i].graphic];
4729 struct TextPosInfo *pos = toolbutton_info[i].pos;
4730 struct GadgetInfo *gi;
4731 Bitmap *deco_bitmap = None;
4732 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
4733 unsigned int event_mask = GD_EVENT_RELEASED;
4736 int gd_x = gfx->src_x;
4737 int gd_y = gfx->src_y;
4738 int gd_xp = gfx->src_x + gfx->pressed_xoffset;
4739 int gd_yp = gfx->src_y + gfx->pressed_yoffset;
4742 if (global.use_envelope_request)
4743 setRequestPosition(&dx, &dy, TRUE);
4745 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
4747 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
4749 getSizedGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr), 0,
4750 pos->size, &deco_bitmap, &deco_x, &deco_y);
4751 deco_xpos = (gfx->width - pos->size) / 2;
4752 deco_ypos = (gfx->height - pos->size) / 2;
4755 gi = CreateGadget(GDI_CUSTOM_ID, id,
4756 GDI_INFO_TEXT, toolbutton_info[i].infotext,
4757 GDI_X, dx + GDI_ACTIVE_POS(pos->x),
4758 GDI_Y, dy + GDI_ACTIVE_POS(pos->y),
4759 GDI_WIDTH, gfx->width,
4760 GDI_HEIGHT, gfx->height,
4761 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
4762 GDI_STATE, GD_BUTTON_UNPRESSED,
4763 GDI_DESIGN_UNPRESSED, gfx->bitmap, gd_x, gd_y,
4764 GDI_DESIGN_PRESSED, gfx->bitmap, gd_xp, gd_yp,
4765 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
4766 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
4767 GDI_DECORATION_SIZE, pos->size, pos->size,
4768 GDI_DECORATION_SHIFTING, 1, 1,
4769 GDI_DIRECT_DRAW, FALSE,
4770 GDI_EVENT_MASK, event_mask,
4771 GDI_CALLBACK_ACTION, HandleToolButtons,
4775 Error(ERR_EXIT, "cannot create gadget");
4777 tool_gadget[id] = gi;
4781 void FreeToolButtons()
4785 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4786 FreeGadget(tool_gadget[i]);
4789 static void UnmapToolButtons()
4793 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4794 UnmapGadget(tool_gadget[i]);
4797 static void HandleToolButtons(struct GadgetInfo *gi)
4799 request_gadget_id = gi->custom_id;
4802 static struct Mapping_EM_to_RND_object
4805 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
4806 boolean is_backside; /* backside of moving element */
4812 em_object_mapping_list[] =
4815 Xblank, TRUE, FALSE,
4819 Yacid_splash_eB, FALSE, FALSE,
4820 EL_ACID_SPLASH_RIGHT, -1, -1
4823 Yacid_splash_wB, FALSE, FALSE,
4824 EL_ACID_SPLASH_LEFT, -1, -1
4827 #ifdef EM_ENGINE_BAD_ROLL
4829 Xstone_force_e, FALSE, FALSE,
4830 EL_ROCK, -1, MV_BIT_RIGHT
4833 Xstone_force_w, FALSE, FALSE,
4834 EL_ROCK, -1, MV_BIT_LEFT
4837 Xnut_force_e, FALSE, FALSE,
4838 EL_NUT, -1, MV_BIT_RIGHT
4841 Xnut_force_w, FALSE, FALSE,
4842 EL_NUT, -1, MV_BIT_LEFT
4845 Xspring_force_e, FALSE, FALSE,
4846 EL_SPRING, -1, MV_BIT_RIGHT
4849 Xspring_force_w, FALSE, FALSE,
4850 EL_SPRING, -1, MV_BIT_LEFT
4853 Xemerald_force_e, FALSE, FALSE,
4854 EL_EMERALD, -1, MV_BIT_RIGHT
4857 Xemerald_force_w, FALSE, FALSE,
4858 EL_EMERALD, -1, MV_BIT_LEFT
4861 Xdiamond_force_e, FALSE, FALSE,
4862 EL_DIAMOND, -1, MV_BIT_RIGHT
4865 Xdiamond_force_w, FALSE, FALSE,
4866 EL_DIAMOND, -1, MV_BIT_LEFT
4869 Xbomb_force_e, FALSE, FALSE,
4870 EL_BOMB, -1, MV_BIT_RIGHT
4873 Xbomb_force_w, FALSE, FALSE,
4874 EL_BOMB, -1, MV_BIT_LEFT
4876 #endif /* EM_ENGINE_BAD_ROLL */
4879 Xstone, TRUE, FALSE,
4883 Xstone_pause, FALSE, FALSE,
4887 Xstone_fall, FALSE, FALSE,
4891 Ystone_s, FALSE, FALSE,
4892 EL_ROCK, ACTION_FALLING, -1
4895 Ystone_sB, FALSE, TRUE,
4896 EL_ROCK, ACTION_FALLING, -1
4899 Ystone_e, FALSE, FALSE,
4900 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
4903 Ystone_eB, FALSE, TRUE,
4904 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
4907 Ystone_w, FALSE, FALSE,
4908 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
4911 Ystone_wB, FALSE, TRUE,
4912 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
4919 Xnut_pause, FALSE, FALSE,
4923 Xnut_fall, FALSE, FALSE,
4927 Ynut_s, FALSE, FALSE,
4928 EL_NUT, ACTION_FALLING, -1
4931 Ynut_sB, FALSE, TRUE,
4932 EL_NUT, ACTION_FALLING, -1
4935 Ynut_e, FALSE, FALSE,
4936 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
4939 Ynut_eB, FALSE, TRUE,
4940 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
4943 Ynut_w, FALSE, FALSE,
4944 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
4947 Ynut_wB, FALSE, TRUE,
4948 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
4951 Xbug_n, TRUE, FALSE,
4955 Xbug_e, TRUE, FALSE,
4956 EL_BUG_RIGHT, -1, -1
4959 Xbug_s, TRUE, FALSE,
4963 Xbug_w, TRUE, FALSE,
4967 Xbug_gon, FALSE, FALSE,
4971 Xbug_goe, FALSE, FALSE,
4972 EL_BUG_RIGHT, -1, -1
4975 Xbug_gos, FALSE, FALSE,
4979 Xbug_gow, FALSE, FALSE,
4983 Ybug_n, FALSE, FALSE,
4984 EL_BUG, ACTION_MOVING, MV_BIT_UP
4987 Ybug_nB, FALSE, TRUE,
4988 EL_BUG, ACTION_MOVING, MV_BIT_UP
4991 Ybug_e, FALSE, FALSE,
4992 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
4995 Ybug_eB, FALSE, TRUE,
4996 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
4999 Ybug_s, FALSE, FALSE,
5000 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
5003 Ybug_sB, FALSE, TRUE,
5004 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
5007 Ybug_w, FALSE, FALSE,
5008 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
5011 Ybug_wB, FALSE, TRUE,
5012 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
5015 Ybug_w_n, FALSE, FALSE,
5016 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
5019 Ybug_n_e, FALSE, FALSE,
5020 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
5023 Ybug_e_s, FALSE, FALSE,
5024 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
5027 Ybug_s_w, FALSE, FALSE,
5028 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
5031 Ybug_e_n, FALSE, FALSE,
5032 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
5035 Ybug_s_e, FALSE, FALSE,
5036 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
5039 Ybug_w_s, FALSE, FALSE,
5040 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
5043 Ybug_n_w, FALSE, FALSE,
5044 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
5047 Ybug_stone, FALSE, FALSE,
5048 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
5051 Ybug_spring, FALSE, FALSE,
5052 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
5055 Xtank_n, TRUE, FALSE,
5056 EL_SPACESHIP_UP, -1, -1
5059 Xtank_e, TRUE, FALSE,
5060 EL_SPACESHIP_RIGHT, -1, -1
5063 Xtank_s, TRUE, FALSE,
5064 EL_SPACESHIP_DOWN, -1, -1
5067 Xtank_w, TRUE, FALSE,
5068 EL_SPACESHIP_LEFT, -1, -1
5071 Xtank_gon, FALSE, FALSE,
5072 EL_SPACESHIP_UP, -1, -1
5075 Xtank_goe, FALSE, FALSE,
5076 EL_SPACESHIP_RIGHT, -1, -1
5079 Xtank_gos, FALSE, FALSE,
5080 EL_SPACESHIP_DOWN, -1, -1
5083 Xtank_gow, FALSE, FALSE,
5084 EL_SPACESHIP_LEFT, -1, -1
5087 Ytank_n, FALSE, FALSE,
5088 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
5091 Ytank_nB, FALSE, TRUE,
5092 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
5095 Ytank_e, FALSE, FALSE,
5096 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
5099 Ytank_eB, FALSE, TRUE,
5100 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
5103 Ytank_s, FALSE, FALSE,
5104 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
5107 Ytank_sB, FALSE, TRUE,
5108 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
5111 Ytank_w, FALSE, FALSE,
5112 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
5115 Ytank_wB, FALSE, TRUE,
5116 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
5119 Ytank_w_n, FALSE, FALSE,
5120 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
5123 Ytank_n_e, FALSE, FALSE,
5124 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
5127 Ytank_e_s, FALSE, FALSE,
5128 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
5131 Ytank_s_w, FALSE, FALSE,
5132 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
5135 Ytank_e_n, FALSE, FALSE,
5136 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
5139 Ytank_s_e, FALSE, FALSE,
5140 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
5143 Ytank_w_s, FALSE, FALSE,
5144 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
5147 Ytank_n_w, FALSE, FALSE,
5148 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
5151 Ytank_stone, FALSE, FALSE,
5152 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
5155 Ytank_spring, FALSE, FALSE,
5156 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
5159 Xandroid, TRUE, FALSE,
5160 EL_EMC_ANDROID, ACTION_ACTIVE, -1
5163 Xandroid_1_n, FALSE, FALSE,
5164 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
5167 Xandroid_2_n, FALSE, FALSE,
5168 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
5171 Xandroid_1_e, FALSE, FALSE,
5172 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
5175 Xandroid_2_e, FALSE, FALSE,
5176 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
5179 Xandroid_1_w, FALSE, FALSE,
5180 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
5183 Xandroid_2_w, FALSE, FALSE,
5184 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
5187 Xandroid_1_s, FALSE, FALSE,
5188 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
5191 Xandroid_2_s, FALSE, FALSE,
5192 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
5195 Yandroid_n, FALSE, FALSE,
5196 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
5199 Yandroid_nB, FALSE, TRUE,
5200 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
5203 Yandroid_ne, FALSE, FALSE,
5204 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
5207 Yandroid_neB, FALSE, TRUE,
5208 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
5211 Yandroid_e, FALSE, FALSE,
5212 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
5215 Yandroid_eB, FALSE, TRUE,
5216 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
5219 Yandroid_se, FALSE, FALSE,
5220 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
5223 Yandroid_seB, FALSE, TRUE,
5224 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
5227 Yandroid_s, FALSE, FALSE,
5228 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
5231 Yandroid_sB, FALSE, TRUE,
5232 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
5235 Yandroid_sw, FALSE, FALSE,
5236 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
5239 Yandroid_swB, FALSE, TRUE,
5240 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
5243 Yandroid_w, FALSE, FALSE,
5244 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
5247 Yandroid_wB, FALSE, TRUE,
5248 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
5251 Yandroid_nw, FALSE, FALSE,
5252 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
5255 Yandroid_nwB, FALSE, TRUE,
5256 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
5259 Xspring, TRUE, FALSE,
5263 Xspring_pause, FALSE, FALSE,
5267 Xspring_e, FALSE, FALSE,
5271 Xspring_w, FALSE, FALSE,
5275 Xspring_fall, FALSE, FALSE,
5279 Yspring_s, FALSE, FALSE,
5280 EL_SPRING, ACTION_FALLING, -1
5283 Yspring_sB, FALSE, TRUE,
5284 EL_SPRING, ACTION_FALLING, -1
5287 Yspring_e, FALSE, FALSE,
5288 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
5291 Yspring_eB, FALSE, TRUE,
5292 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
5295 Yspring_w, FALSE, FALSE,
5296 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
5299 Yspring_wB, FALSE, TRUE,
5300 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
5303 Yspring_kill_e, FALSE, FALSE,
5304 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
5307 Yspring_kill_eB, FALSE, TRUE,
5308 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
5311 Yspring_kill_w, FALSE, FALSE,
5312 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
5315 Yspring_kill_wB, FALSE, TRUE,
5316 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
5319 Xeater_n, TRUE, FALSE,
5320 EL_YAMYAM_UP, -1, -1
5323 Xeater_e, TRUE, FALSE,
5324 EL_YAMYAM_RIGHT, -1, -1
5327 Xeater_w, TRUE, FALSE,
5328 EL_YAMYAM_LEFT, -1, -1
5331 Xeater_s, TRUE, FALSE,
5332 EL_YAMYAM_DOWN, -1, -1
5335 Yeater_n, FALSE, FALSE,
5336 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
5339 Yeater_nB, FALSE, TRUE,
5340 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
5343 Yeater_e, FALSE, FALSE,
5344 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
5347 Yeater_eB, FALSE, TRUE,
5348 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
5351 Yeater_s, FALSE, FALSE,
5352 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
5355 Yeater_sB, FALSE, TRUE,
5356 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
5359 Yeater_w, FALSE, FALSE,
5360 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
5363 Yeater_wB, FALSE, TRUE,
5364 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
5367 Yeater_stone, FALSE, FALSE,
5368 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
5371 Yeater_spring, FALSE, FALSE,
5372 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
5375 Xalien, TRUE, FALSE,
5379 Xalien_pause, FALSE, FALSE,
5383 Yalien_n, FALSE, FALSE,
5384 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
5387 Yalien_nB, FALSE, TRUE,
5388 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
5391 Yalien_e, FALSE, FALSE,
5392 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
5395 Yalien_eB, FALSE, TRUE,
5396 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
5399 Yalien_s, FALSE, FALSE,
5400 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
5403 Yalien_sB, FALSE, TRUE,
5404 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
5407 Yalien_w, FALSE, FALSE,
5408 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
5411 Yalien_wB, FALSE, TRUE,
5412 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
5415 Yalien_stone, FALSE, FALSE,
5416 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
5419 Yalien_spring, FALSE, FALSE,
5420 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
5423 Xemerald, TRUE, FALSE,
5427 Xemerald_pause, FALSE, FALSE,
5431 Xemerald_fall, FALSE, FALSE,
5435 Xemerald_shine, FALSE, FALSE,
5436 EL_EMERALD, ACTION_TWINKLING, -1
5439 Yemerald_s, FALSE, FALSE,
5440 EL_EMERALD, ACTION_FALLING, -1
5443 Yemerald_sB, FALSE, TRUE,
5444 EL_EMERALD, ACTION_FALLING, -1
5447 Yemerald_e, FALSE, FALSE,
5448 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
5451 Yemerald_eB, FALSE, TRUE,
5452 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
5455 Yemerald_w, FALSE, FALSE,
5456 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
5459 Yemerald_wB, FALSE, TRUE,
5460 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
5463 Yemerald_eat, FALSE, FALSE,
5464 EL_EMERALD, ACTION_COLLECTING, -1
5467 Yemerald_stone, FALSE, FALSE,
5468 EL_NUT, ACTION_BREAKING, -1
5471 Xdiamond, TRUE, FALSE,
5475 Xdiamond_pause, FALSE, FALSE,
5479 Xdiamond_fall, FALSE, FALSE,
5483 Xdiamond_shine, FALSE, FALSE,
5484 EL_DIAMOND, ACTION_TWINKLING, -1
5487 Ydiamond_s, FALSE, FALSE,
5488 EL_DIAMOND, ACTION_FALLING, -1
5491 Ydiamond_sB, FALSE, TRUE,
5492 EL_DIAMOND, ACTION_FALLING, -1
5495 Ydiamond_e, FALSE, FALSE,
5496 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
5499 Ydiamond_eB, FALSE, TRUE,
5500 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
5503 Ydiamond_w, FALSE, FALSE,
5504 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
5507 Ydiamond_wB, FALSE, TRUE,
5508 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
5511 Ydiamond_eat, FALSE, FALSE,
5512 EL_DIAMOND, ACTION_COLLECTING, -1
5515 Ydiamond_stone, FALSE, FALSE,
5516 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
5519 Xdrip_fall, TRUE, FALSE,
5520 EL_AMOEBA_DROP, -1, -1
5523 Xdrip_stretch, FALSE, FALSE,
5524 EL_AMOEBA_DROP, ACTION_FALLING, -1
5527 Xdrip_stretchB, FALSE, TRUE,
5528 EL_AMOEBA_DROP, ACTION_FALLING, -1
5531 Xdrip_eat, FALSE, FALSE,
5532 EL_AMOEBA_DROP, ACTION_GROWING, -1
5535 Ydrip_s1, FALSE, FALSE,
5536 EL_AMOEBA_DROP, ACTION_FALLING, -1
5539 Ydrip_s1B, FALSE, TRUE,
5540 EL_AMOEBA_DROP, ACTION_FALLING, -1
5543 Ydrip_s2, FALSE, FALSE,
5544 EL_AMOEBA_DROP, ACTION_FALLING, -1
5547 Ydrip_s2B, FALSE, TRUE,
5548 EL_AMOEBA_DROP, ACTION_FALLING, -1
5555 Xbomb_pause, FALSE, FALSE,
5559 Xbomb_fall, FALSE, FALSE,
5563 Ybomb_s, FALSE, FALSE,
5564 EL_BOMB, ACTION_FALLING, -1
5567 Ybomb_sB, FALSE, TRUE,
5568 EL_BOMB, ACTION_FALLING, -1
5571 Ybomb_e, FALSE, FALSE,
5572 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
5575 Ybomb_eB, FALSE, TRUE,
5576 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
5579 Ybomb_w, FALSE, FALSE,
5580 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
5583 Ybomb_wB, FALSE, TRUE,
5584 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
5587 Ybomb_eat, FALSE, FALSE,
5588 EL_BOMB, ACTION_ACTIVATING, -1
5591 Xballoon, TRUE, FALSE,
5595 Yballoon_n, FALSE, FALSE,
5596 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
5599 Yballoon_nB, FALSE, TRUE,
5600 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
5603 Yballoon_e, FALSE, FALSE,
5604 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
5607 Yballoon_eB, FALSE, TRUE,
5608 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
5611 Yballoon_s, FALSE, FALSE,
5612 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
5615 Yballoon_sB, FALSE, TRUE,
5616 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
5619 Yballoon_w, FALSE, FALSE,
5620 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
5623 Yballoon_wB, FALSE, TRUE,
5624 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
5627 Xgrass, TRUE, FALSE,
5628 EL_EMC_GRASS, -1, -1
5631 Ygrass_nB, FALSE, FALSE,
5632 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
5635 Ygrass_eB, FALSE, FALSE,
5636 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
5639 Ygrass_sB, FALSE, FALSE,
5640 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
5643 Ygrass_wB, FALSE, FALSE,
5644 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
5651 Ydirt_nB, FALSE, FALSE,
5652 EL_SAND, ACTION_DIGGING, MV_BIT_UP
5655 Ydirt_eB, FALSE, FALSE,
5656 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
5659 Ydirt_sB, FALSE, FALSE,
5660 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
5663 Ydirt_wB, FALSE, FALSE,
5664 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
5667 Xacid_ne, TRUE, FALSE,
5668 EL_ACID_POOL_TOPRIGHT, -1, -1
5671 Xacid_se, TRUE, FALSE,
5672 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
5675 Xacid_s, TRUE, FALSE,
5676 EL_ACID_POOL_BOTTOM, -1, -1
5679 Xacid_sw, TRUE, FALSE,
5680 EL_ACID_POOL_BOTTOMLEFT, -1, -1
5683 Xacid_nw, TRUE, FALSE,
5684 EL_ACID_POOL_TOPLEFT, -1, -1
5687 Xacid_1, TRUE, FALSE,
5691 Xacid_2, FALSE, FALSE,
5695 Xacid_3, FALSE, FALSE,
5699 Xacid_4, FALSE, FALSE,
5703 Xacid_5, FALSE, FALSE,
5707 Xacid_6, FALSE, FALSE,
5711 Xacid_7, FALSE, FALSE,
5715 Xacid_8, FALSE, FALSE,
5719 Xball_1, TRUE, FALSE,
5720 EL_EMC_MAGIC_BALL, -1, -1
5723 Xball_1B, FALSE, FALSE,
5724 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5727 Xball_2, FALSE, FALSE,
5728 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5731 Xball_2B, FALSE, FALSE,
5732 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5735 Yball_eat, FALSE, FALSE,
5736 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
5739 Ykey_1_eat, FALSE, FALSE,
5740 EL_EM_KEY_1, ACTION_COLLECTING, -1
5743 Ykey_2_eat, FALSE, FALSE,
5744 EL_EM_KEY_2, ACTION_COLLECTING, -1
5747 Ykey_3_eat, FALSE, FALSE,
5748 EL_EM_KEY_3, ACTION_COLLECTING, -1
5751 Ykey_4_eat, FALSE, FALSE,
5752 EL_EM_KEY_4, ACTION_COLLECTING, -1
5755 Ykey_5_eat, FALSE, FALSE,
5756 EL_EMC_KEY_5, ACTION_COLLECTING, -1
5759 Ykey_6_eat, FALSE, FALSE,
5760 EL_EMC_KEY_6, ACTION_COLLECTING, -1
5763 Ykey_7_eat, FALSE, FALSE,
5764 EL_EMC_KEY_7, ACTION_COLLECTING, -1
5767 Ykey_8_eat, FALSE, FALSE,
5768 EL_EMC_KEY_8, ACTION_COLLECTING, -1
5771 Ylenses_eat, FALSE, FALSE,
5772 EL_EMC_LENSES, ACTION_COLLECTING, -1
5775 Ymagnify_eat, FALSE, FALSE,
5776 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
5779 Ygrass_eat, FALSE, FALSE,
5780 EL_EMC_GRASS, ACTION_SNAPPING, -1
5783 Ydirt_eat, FALSE, FALSE,
5784 EL_SAND, ACTION_SNAPPING, -1
5787 Xgrow_ns, TRUE, FALSE,
5788 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
5791 Ygrow_ns_eat, FALSE, FALSE,
5792 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
5795 Xgrow_ew, TRUE, FALSE,
5796 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
5799 Ygrow_ew_eat, FALSE, FALSE,
5800 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
5803 Xwonderwall, TRUE, FALSE,
5804 EL_MAGIC_WALL, -1, -1
5807 XwonderwallB, FALSE, FALSE,
5808 EL_MAGIC_WALL, ACTION_ACTIVE, -1
5811 Xamoeba_1, TRUE, FALSE,
5812 EL_AMOEBA_DRY, ACTION_OTHER, -1
5815 Xamoeba_2, FALSE, FALSE,
5816 EL_AMOEBA_DRY, ACTION_OTHER, -1
5819 Xamoeba_3, FALSE, FALSE,
5820 EL_AMOEBA_DRY, ACTION_OTHER, -1
5823 Xamoeba_4, FALSE, FALSE,
5824 EL_AMOEBA_DRY, ACTION_OTHER, -1
5827 Xamoeba_5, TRUE, FALSE,
5828 EL_AMOEBA_WET, ACTION_OTHER, -1
5831 Xamoeba_6, FALSE, FALSE,
5832 EL_AMOEBA_WET, ACTION_OTHER, -1
5835 Xamoeba_7, FALSE, FALSE,
5836 EL_AMOEBA_WET, ACTION_OTHER, -1
5839 Xamoeba_8, FALSE, FALSE,
5840 EL_AMOEBA_WET, ACTION_OTHER, -1
5843 Xdoor_1, TRUE, FALSE,
5844 EL_EM_GATE_1, -1, -1
5847 Xdoor_2, TRUE, FALSE,
5848 EL_EM_GATE_2, -1, -1
5851 Xdoor_3, TRUE, FALSE,
5852 EL_EM_GATE_3, -1, -1
5855 Xdoor_4, TRUE, FALSE,
5856 EL_EM_GATE_4, -1, -1
5859 Xdoor_5, TRUE, FALSE,
5860 EL_EMC_GATE_5, -1, -1
5863 Xdoor_6, TRUE, FALSE,
5864 EL_EMC_GATE_6, -1, -1
5867 Xdoor_7, TRUE, FALSE,
5868 EL_EMC_GATE_7, -1, -1
5871 Xdoor_8, TRUE, FALSE,
5872 EL_EMC_GATE_8, -1, -1
5875 Xkey_1, TRUE, FALSE,
5879 Xkey_2, TRUE, FALSE,
5883 Xkey_3, TRUE, FALSE,
5887 Xkey_4, TRUE, FALSE,
5891 Xkey_5, TRUE, FALSE,
5892 EL_EMC_KEY_5, -1, -1
5895 Xkey_6, TRUE, FALSE,
5896 EL_EMC_KEY_6, -1, -1
5899 Xkey_7, TRUE, FALSE,
5900 EL_EMC_KEY_7, -1, -1
5903 Xkey_8, TRUE, FALSE,
5904 EL_EMC_KEY_8, -1, -1
5907 Xwind_n, TRUE, FALSE,
5908 EL_BALLOON_SWITCH_UP, -1, -1
5911 Xwind_e, TRUE, FALSE,
5912 EL_BALLOON_SWITCH_RIGHT, -1, -1
5915 Xwind_s, TRUE, FALSE,
5916 EL_BALLOON_SWITCH_DOWN, -1, -1
5919 Xwind_w, TRUE, FALSE,
5920 EL_BALLOON_SWITCH_LEFT, -1, -1
5923 Xwind_nesw, TRUE, FALSE,
5924 EL_BALLOON_SWITCH_ANY, -1, -1
5927 Xwind_stop, TRUE, FALSE,
5928 EL_BALLOON_SWITCH_NONE, -1, -1
5932 EL_EM_EXIT_CLOSED, -1, -1
5935 Xexit_1, TRUE, FALSE,
5936 EL_EM_EXIT_OPEN, -1, -1
5939 Xexit_2, FALSE, FALSE,
5940 EL_EM_EXIT_OPEN, -1, -1
5943 Xexit_3, FALSE, FALSE,
5944 EL_EM_EXIT_OPEN, -1, -1
5947 Xdynamite, TRUE, FALSE,
5948 EL_EM_DYNAMITE, -1, -1
5951 Ydynamite_eat, FALSE, FALSE,
5952 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
5955 Xdynamite_1, TRUE, FALSE,
5956 EL_EM_DYNAMITE_ACTIVE, -1, -1
5959 Xdynamite_2, FALSE, FALSE,
5960 EL_EM_DYNAMITE_ACTIVE, -1, -1
5963 Xdynamite_3, FALSE, FALSE,
5964 EL_EM_DYNAMITE_ACTIVE, -1, -1
5967 Xdynamite_4, FALSE, FALSE,
5968 EL_EM_DYNAMITE_ACTIVE, -1, -1
5971 Xbumper, TRUE, FALSE,
5972 EL_EMC_SPRING_BUMPER, -1, -1
5975 XbumperB, FALSE, FALSE,
5976 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
5979 Xwheel, TRUE, FALSE,
5980 EL_ROBOT_WHEEL, -1, -1
5983 XwheelB, FALSE, FALSE,
5984 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
5987 Xswitch, TRUE, FALSE,
5988 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
5991 XswitchB, FALSE, FALSE,
5992 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
5996 EL_QUICKSAND_EMPTY, -1, -1
5999 Xsand_stone, TRUE, FALSE,
6000 EL_QUICKSAND_FULL, -1, -1
6003 Xsand_stonein_1, FALSE, TRUE,
6004 EL_ROCK, ACTION_FILLING, -1
6007 Xsand_stonein_2, FALSE, TRUE,
6008 EL_ROCK, ACTION_FILLING, -1
6011 Xsand_stonein_3, FALSE, TRUE,
6012 EL_ROCK, ACTION_FILLING, -1
6015 Xsand_stonein_4, FALSE, TRUE,
6016 EL_ROCK, ACTION_FILLING, -1
6019 Xsand_stonesand_1, FALSE, FALSE,
6020 EL_QUICKSAND_EMPTYING, -1, -1
6023 Xsand_stonesand_2, FALSE, FALSE,
6024 EL_QUICKSAND_EMPTYING, -1, -1
6027 Xsand_stonesand_3, FALSE, FALSE,
6028 EL_QUICKSAND_EMPTYING, -1, -1
6031 Xsand_stonesand_4, FALSE, FALSE,
6032 EL_QUICKSAND_EMPTYING, -1, -1
6035 Xsand_stonesand_quickout_1, FALSE, FALSE,
6036 EL_QUICKSAND_EMPTYING, -1, -1
6039 Xsand_stonesand_quickout_2, FALSE, FALSE,
6040 EL_QUICKSAND_EMPTYING, -1, -1
6043 Xsand_stoneout_1, FALSE, FALSE,
6044 EL_ROCK, ACTION_EMPTYING, -1
6047 Xsand_stoneout_2, FALSE, FALSE,
6048 EL_ROCK, ACTION_EMPTYING, -1
6051 Xsand_sandstone_1, FALSE, FALSE,
6052 EL_QUICKSAND_FILLING, -1, -1
6055 Xsand_sandstone_2, FALSE, FALSE,
6056 EL_QUICKSAND_FILLING, -1, -1
6059 Xsand_sandstone_3, FALSE, FALSE,
6060 EL_QUICKSAND_FILLING, -1, -1
6063 Xsand_sandstone_4, FALSE, FALSE,
6064 EL_QUICKSAND_FILLING, -1, -1
6067 Xplant, TRUE, FALSE,
6068 EL_EMC_PLANT, -1, -1
6071 Yplant, FALSE, FALSE,
6072 EL_EMC_PLANT, -1, -1
6075 Xlenses, TRUE, FALSE,
6076 EL_EMC_LENSES, -1, -1
6079 Xmagnify, TRUE, FALSE,
6080 EL_EMC_MAGNIFIER, -1, -1
6083 Xdripper, TRUE, FALSE,
6084 EL_EMC_DRIPPER, -1, -1
6087 XdripperB, FALSE, FALSE,
6088 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
6091 Xfake_blank, TRUE, FALSE,
6092 EL_INVISIBLE_WALL, -1, -1
6095 Xfake_blankB, FALSE, FALSE,
6096 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
6099 Xfake_grass, TRUE, FALSE,
6100 EL_EMC_FAKE_GRASS, -1, -1
6103 Xfake_grassB, FALSE, FALSE,
6104 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
6107 Xfake_door_1, TRUE, FALSE,
6108 EL_EM_GATE_1_GRAY, -1, -1
6111 Xfake_door_2, TRUE, FALSE,
6112 EL_EM_GATE_2_GRAY, -1, -1
6115 Xfake_door_3, TRUE, FALSE,
6116 EL_EM_GATE_3_GRAY, -1, -1
6119 Xfake_door_4, TRUE, FALSE,
6120 EL_EM_GATE_4_GRAY, -1, -1
6123 Xfake_door_5, TRUE, FALSE,
6124 EL_EMC_GATE_5_GRAY, -1, -1
6127 Xfake_door_6, TRUE, FALSE,
6128 EL_EMC_GATE_6_GRAY, -1, -1
6131 Xfake_door_7, TRUE, FALSE,
6132 EL_EMC_GATE_7_GRAY, -1, -1
6135 Xfake_door_8, TRUE, FALSE,
6136 EL_EMC_GATE_8_GRAY, -1, -1
6139 Xfake_acid_1, TRUE, FALSE,
6140 EL_EMC_FAKE_ACID, -1, -1
6143 Xfake_acid_2, FALSE, FALSE,
6144 EL_EMC_FAKE_ACID, -1, -1
6147 Xfake_acid_3, FALSE, FALSE,
6148 EL_EMC_FAKE_ACID, -1, -1
6151 Xfake_acid_4, FALSE, FALSE,
6152 EL_EMC_FAKE_ACID, -1, -1
6155 Xfake_acid_5, FALSE, FALSE,
6156 EL_EMC_FAKE_ACID, -1, -1
6159 Xfake_acid_6, FALSE, FALSE,
6160 EL_EMC_FAKE_ACID, -1, -1
6163 Xfake_acid_7, FALSE, FALSE,
6164 EL_EMC_FAKE_ACID, -1, -1
6167 Xfake_acid_8, FALSE, FALSE,
6168 EL_EMC_FAKE_ACID, -1, -1
6171 Xsteel_1, TRUE, FALSE,
6172 EL_STEELWALL, -1, -1
6175 Xsteel_2, TRUE, FALSE,
6176 EL_EMC_STEELWALL_2, -1, -1
6179 Xsteel_3, TRUE, FALSE,
6180 EL_EMC_STEELWALL_3, -1, -1
6183 Xsteel_4, TRUE, FALSE,
6184 EL_EMC_STEELWALL_4, -1, -1
6187 Xwall_1, TRUE, FALSE,
6191 Xwall_2, TRUE, FALSE,
6192 EL_EMC_WALL_14, -1, -1
6195 Xwall_3, TRUE, FALSE,
6196 EL_EMC_WALL_15, -1, -1
6199 Xwall_4, TRUE, FALSE,
6200 EL_EMC_WALL_16, -1, -1
6203 Xround_wall_1, TRUE, FALSE,
6204 EL_WALL_SLIPPERY, -1, -1
6207 Xround_wall_2, TRUE, FALSE,
6208 EL_EMC_WALL_SLIPPERY_2, -1, -1
6211 Xround_wall_3, TRUE, FALSE,
6212 EL_EMC_WALL_SLIPPERY_3, -1, -1
6215 Xround_wall_4, TRUE, FALSE,
6216 EL_EMC_WALL_SLIPPERY_4, -1, -1
6219 Xdecor_1, TRUE, FALSE,
6220 EL_EMC_WALL_8, -1, -1
6223 Xdecor_2, TRUE, FALSE,
6224 EL_EMC_WALL_6, -1, -1
6227 Xdecor_3, TRUE, FALSE,
6228 EL_EMC_WALL_4, -1, -1
6231 Xdecor_4, TRUE, FALSE,
6232 EL_EMC_WALL_7, -1, -1
6235 Xdecor_5, TRUE, FALSE,
6236 EL_EMC_WALL_5, -1, -1
6239 Xdecor_6, TRUE, FALSE,
6240 EL_EMC_WALL_9, -1, -1
6243 Xdecor_7, TRUE, FALSE,
6244 EL_EMC_WALL_10, -1, -1
6247 Xdecor_8, TRUE, FALSE,
6248 EL_EMC_WALL_1, -1, -1
6251 Xdecor_9, TRUE, FALSE,
6252 EL_EMC_WALL_2, -1, -1
6255 Xdecor_10, TRUE, FALSE,
6256 EL_EMC_WALL_3, -1, -1
6259 Xdecor_11, TRUE, FALSE,
6260 EL_EMC_WALL_11, -1, -1
6263 Xdecor_12, TRUE, FALSE,
6264 EL_EMC_WALL_12, -1, -1
6267 Xalpha_0, TRUE, FALSE,
6268 EL_CHAR('0'), -1, -1
6271 Xalpha_1, TRUE, FALSE,
6272 EL_CHAR('1'), -1, -1
6275 Xalpha_2, TRUE, FALSE,
6276 EL_CHAR('2'), -1, -1
6279 Xalpha_3, TRUE, FALSE,
6280 EL_CHAR('3'), -1, -1
6283 Xalpha_4, TRUE, FALSE,
6284 EL_CHAR('4'), -1, -1
6287 Xalpha_5, TRUE, FALSE,
6288 EL_CHAR('5'), -1, -1
6291 Xalpha_6, TRUE, FALSE,
6292 EL_CHAR('6'), -1, -1
6295 Xalpha_7, TRUE, FALSE,
6296 EL_CHAR('7'), -1, -1
6299 Xalpha_8, TRUE, FALSE,
6300 EL_CHAR('8'), -1, -1
6303 Xalpha_9, TRUE, FALSE,
6304 EL_CHAR('9'), -1, -1
6307 Xalpha_excla, TRUE, FALSE,
6308 EL_CHAR('!'), -1, -1
6311 Xalpha_quote, TRUE, FALSE,
6312 EL_CHAR('"'), -1, -1
6315 Xalpha_comma, TRUE, FALSE,
6316 EL_CHAR(','), -1, -1
6319 Xalpha_minus, TRUE, FALSE,
6320 EL_CHAR('-'), -1, -1
6323 Xalpha_perio, TRUE, FALSE,
6324 EL_CHAR('.'), -1, -1
6327 Xalpha_colon, TRUE, FALSE,
6328 EL_CHAR(':'), -1, -1
6331 Xalpha_quest, TRUE, FALSE,
6332 EL_CHAR('?'), -1, -1
6335 Xalpha_a, TRUE, FALSE,
6336 EL_CHAR('A'), -1, -1
6339 Xalpha_b, TRUE, FALSE,
6340 EL_CHAR('B'), -1, -1
6343 Xalpha_c, TRUE, FALSE,
6344 EL_CHAR('C'), -1, -1
6347 Xalpha_d, TRUE, FALSE,
6348 EL_CHAR('D'), -1, -1
6351 Xalpha_e, TRUE, FALSE,
6352 EL_CHAR('E'), -1, -1
6355 Xalpha_f, TRUE, FALSE,
6356 EL_CHAR('F'), -1, -1
6359 Xalpha_g, TRUE, FALSE,
6360 EL_CHAR('G'), -1, -1
6363 Xalpha_h, TRUE, FALSE,
6364 EL_CHAR('H'), -1, -1
6367 Xalpha_i, TRUE, FALSE,
6368 EL_CHAR('I'), -1, -1
6371 Xalpha_j, TRUE, FALSE,
6372 EL_CHAR('J'), -1, -1
6375 Xalpha_k, TRUE, FALSE,
6376 EL_CHAR('K'), -1, -1
6379 Xalpha_l, TRUE, FALSE,
6380 EL_CHAR('L'), -1, -1
6383 Xalpha_m, TRUE, FALSE,
6384 EL_CHAR('M'), -1, -1
6387 Xalpha_n, TRUE, FALSE,
6388 EL_CHAR('N'), -1, -1
6391 Xalpha_o, TRUE, FALSE,
6392 EL_CHAR('O'), -1, -1
6395 Xalpha_p, TRUE, FALSE,
6396 EL_CHAR('P'), -1, -1
6399 Xalpha_q, TRUE, FALSE,
6400 EL_CHAR('Q'), -1, -1
6403 Xalpha_r, TRUE, FALSE,
6404 EL_CHAR('R'), -1, -1
6407 Xalpha_s, TRUE, FALSE,
6408 EL_CHAR('S'), -1, -1
6411 Xalpha_t, TRUE, FALSE,
6412 EL_CHAR('T'), -1, -1
6415 Xalpha_u, TRUE, FALSE,
6416 EL_CHAR('U'), -1, -1
6419 Xalpha_v, TRUE, FALSE,
6420 EL_CHAR('V'), -1, -1
6423 Xalpha_w, TRUE, FALSE,
6424 EL_CHAR('W'), -1, -1
6427 Xalpha_x, TRUE, FALSE,
6428 EL_CHAR('X'), -1, -1
6431 Xalpha_y, TRUE, FALSE,
6432 EL_CHAR('Y'), -1, -1
6435 Xalpha_z, TRUE, FALSE,
6436 EL_CHAR('Z'), -1, -1
6439 Xalpha_arrow_e, TRUE, FALSE,
6440 EL_CHAR('>'), -1, -1
6443 Xalpha_arrow_w, TRUE, FALSE,
6444 EL_CHAR('<'), -1, -1
6447 Xalpha_copyr, TRUE, FALSE,
6448 EL_CHAR(CHAR_BYTE_COPYRIGHT), -1, -1
6452 Xboom_bug, FALSE, FALSE,
6453 EL_BUG, ACTION_EXPLODING, -1
6456 Xboom_bomb, FALSE, FALSE,
6457 EL_BOMB, ACTION_EXPLODING, -1
6460 Xboom_android, FALSE, FALSE,
6461 EL_EMC_ANDROID, ACTION_OTHER, -1
6464 Xboom_1, FALSE, FALSE,
6465 EL_DEFAULT, ACTION_EXPLODING, -1
6468 Xboom_2, FALSE, FALSE,
6469 EL_DEFAULT, ACTION_EXPLODING, -1
6472 Znormal, FALSE, FALSE,
6476 Zdynamite, FALSE, FALSE,
6480 Zplayer, FALSE, FALSE,
6484 ZBORDER, FALSE, FALSE,
6494 static struct Mapping_EM_to_RND_player
6503 em_player_mapping_list[] =
6507 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
6511 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
6515 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
6519 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
6523 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
6527 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
6531 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
6535 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
6539 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
6543 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
6547 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
6551 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
6555 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
6559 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
6563 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
6567 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
6571 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
6575 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
6579 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
6583 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
6587 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
6591 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
6595 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
6599 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
6603 EL_PLAYER_1, ACTION_DEFAULT, -1,
6607 EL_PLAYER_2, ACTION_DEFAULT, -1,
6611 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
6615 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
6619 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
6623 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
6627 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
6631 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
6635 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
6639 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
6643 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
6647 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
6651 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
6655 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
6659 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
6663 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
6667 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
6671 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
6675 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
6679 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
6683 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
6687 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
6691 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
6695 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
6699 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
6703 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
6707 EL_PLAYER_3, ACTION_DEFAULT, -1,
6711 EL_PLAYER_4, ACTION_DEFAULT, -1,
6720 int map_element_RND_to_EM(int element_rnd)
6722 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
6723 static boolean mapping_initialized = FALSE;
6725 if (!mapping_initialized)
6729 /* return "Xalpha_quest" for all undefined elements in mapping array */
6730 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
6731 mapping_RND_to_EM[i] = Xalpha_quest;
6733 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6734 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
6735 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
6736 em_object_mapping_list[i].element_em;
6738 mapping_initialized = TRUE;
6741 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
6742 return mapping_RND_to_EM[element_rnd];
6744 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
6749 int map_element_EM_to_RND(int element_em)
6751 static unsigned short mapping_EM_to_RND[TILE_MAX];
6752 static boolean mapping_initialized = FALSE;
6754 if (!mapping_initialized)
6758 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
6759 for (i = 0; i < TILE_MAX; i++)
6760 mapping_EM_to_RND[i] = EL_UNKNOWN;
6762 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6763 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
6764 em_object_mapping_list[i].element_rnd;
6766 mapping_initialized = TRUE;
6769 if (element_em >= 0 && element_em < TILE_MAX)
6770 return mapping_EM_to_RND[element_em];
6772 Error(ERR_WARN, "invalid EM level element %d", element_em);
6777 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
6779 struct LevelInfo_EM *level_em = level->native_em_level;
6780 struct LEVEL *lev = level_em->lev;
6783 for (i = 0; i < TILE_MAX; i++)
6784 lev->android_array[i] = Xblank;
6786 for (i = 0; i < level->num_android_clone_elements; i++)
6788 int element_rnd = level->android_clone_element[i];
6789 int element_em = map_element_RND_to_EM(element_rnd);
6791 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
6792 if (em_object_mapping_list[j].element_rnd == element_rnd)
6793 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
6797 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
6799 struct LevelInfo_EM *level_em = level->native_em_level;
6800 struct LEVEL *lev = level_em->lev;
6803 level->num_android_clone_elements = 0;
6805 for (i = 0; i < TILE_MAX; i++)
6807 int element_em = lev->android_array[i];
6809 boolean element_found = FALSE;
6811 if (element_em == Xblank)
6814 element_rnd = map_element_EM_to_RND(element_em);
6816 for (j = 0; j < level->num_android_clone_elements; j++)
6817 if (level->android_clone_element[j] == element_rnd)
6818 element_found = TRUE;
6822 level->android_clone_element[level->num_android_clone_elements++] =
6825 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
6830 if (level->num_android_clone_elements == 0)
6832 level->num_android_clone_elements = 1;
6833 level->android_clone_element[0] = EL_EMPTY;
6837 int map_direction_RND_to_EM(int direction)
6839 return (direction == MV_UP ? 0 :
6840 direction == MV_RIGHT ? 1 :
6841 direction == MV_DOWN ? 2 :
6842 direction == MV_LEFT ? 3 :
6846 int map_direction_EM_to_RND(int direction)
6848 return (direction == 0 ? MV_UP :
6849 direction == 1 ? MV_RIGHT :
6850 direction == 2 ? MV_DOWN :
6851 direction == 3 ? MV_LEFT :
6855 int map_element_RND_to_SP(int element_rnd)
6857 int element_sp = 0x20; /* map unknown elements to yellow "hardware" */
6859 if (element_rnd >= EL_SP_START &&
6860 element_rnd <= EL_SP_END)
6861 element_sp = element_rnd - EL_SP_START;
6862 else if (element_rnd == EL_EMPTY_SPACE)
6864 else if (element_rnd == EL_INVISIBLE_WALL)
6870 int map_element_SP_to_RND(int element_sp)
6872 int element_rnd = EL_UNKNOWN;
6874 if (element_sp >= 0x00 &&
6876 element_rnd = EL_SP_START + element_sp;
6877 else if (element_sp == 0x28)
6878 element_rnd = EL_INVISIBLE_WALL;
6883 int map_action_SP_to_RND(int action_sp)
6887 case actActive: return ACTION_ACTIVE;
6888 case actImpact: return ACTION_IMPACT;
6889 case actExploding: return ACTION_EXPLODING;
6890 case actDigging: return ACTION_DIGGING;
6891 case actSnapping: return ACTION_SNAPPING;
6892 case actCollecting: return ACTION_COLLECTING;
6893 case actPassing: return ACTION_PASSING;
6894 case actPushing: return ACTION_PUSHING;
6895 case actDropping: return ACTION_DROPPING;
6897 default: return ACTION_DEFAULT;
6901 int get_next_element(int element)
6905 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
6906 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
6907 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
6908 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
6909 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
6910 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
6911 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
6912 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
6913 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
6914 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
6915 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
6917 default: return element;
6921 int el_act_dir2img(int element, int action, int direction)
6923 element = GFX_ELEMENT(element);
6924 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
6926 /* direction_graphic[][] == graphic[] for undefined direction graphics */
6927 return element_info[element].direction_graphic[action][direction];
6930 static int el_act_dir2crm(int element, int action, int direction)
6932 element = GFX_ELEMENT(element);
6933 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
6935 /* direction_graphic[][] == graphic[] for undefined direction graphics */
6936 return element_info[element].direction_crumbled[action][direction];
6939 int el_act2img(int element, int action)
6941 element = GFX_ELEMENT(element);
6943 return element_info[element].graphic[action];
6946 int el_act2crm(int element, int action)
6948 element = GFX_ELEMENT(element);
6950 return element_info[element].crumbled[action];
6953 int el_dir2img(int element, int direction)
6955 element = GFX_ELEMENT(element);
6957 return el_act_dir2img(element, ACTION_DEFAULT, direction);
6960 int el2baseimg(int element)
6962 return element_info[element].graphic[ACTION_DEFAULT];
6965 int el2img(int element)
6967 element = GFX_ELEMENT(element);
6969 return element_info[element].graphic[ACTION_DEFAULT];
6972 int el2edimg(int element)
6974 element = GFX_ELEMENT(element);
6976 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
6979 int el2preimg(int element)
6981 element = GFX_ELEMENT(element);
6983 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
6986 int el2panelimg(int element)
6988 element = GFX_ELEMENT(element);
6990 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL];
6993 int font2baseimg(int font_nr)
6995 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
6998 int getBeltNrFromBeltElement(int element)
7000 return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
7001 element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
7002 element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
7005 int getBeltNrFromBeltActiveElement(int element)
7007 return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
7008 element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
7009 element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
7012 int getBeltNrFromBeltSwitchElement(int element)
7014 return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
7015 element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
7016 element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
7019 int getBeltDirNrFromBeltElement(int element)
7021 static int belt_base_element[4] =
7023 EL_CONVEYOR_BELT_1_LEFT,
7024 EL_CONVEYOR_BELT_2_LEFT,
7025 EL_CONVEYOR_BELT_3_LEFT,
7026 EL_CONVEYOR_BELT_4_LEFT
7029 int belt_nr = getBeltNrFromBeltElement(element);
7030 int belt_dir_nr = element - belt_base_element[belt_nr];
7032 return (belt_dir_nr % 3);
7035 int getBeltDirNrFromBeltSwitchElement(int element)
7037 static int belt_base_element[4] =
7039 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
7040 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
7041 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
7042 EL_CONVEYOR_BELT_4_SWITCH_LEFT
7045 int belt_nr = getBeltNrFromBeltSwitchElement(element);
7046 int belt_dir_nr = element - belt_base_element[belt_nr];
7048 return (belt_dir_nr % 3);
7051 int getBeltDirFromBeltElement(int element)
7053 static int belt_move_dir[3] =
7060 int belt_dir_nr = getBeltDirNrFromBeltElement(element);
7062 return belt_move_dir[belt_dir_nr];
7065 int getBeltDirFromBeltSwitchElement(int element)
7067 static int belt_move_dir[3] =
7074 int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
7076 return belt_move_dir[belt_dir_nr];
7079 int getBeltElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
7081 static int belt_base_element[4] =
7083 EL_CONVEYOR_BELT_1_LEFT,
7084 EL_CONVEYOR_BELT_2_LEFT,
7085 EL_CONVEYOR_BELT_3_LEFT,
7086 EL_CONVEYOR_BELT_4_LEFT
7089 return belt_base_element[belt_nr] + belt_dir_nr;
7092 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
7094 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
7096 return getBeltElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
7099 int getBeltSwitchElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
7101 static int belt_base_element[4] =
7103 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
7104 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
7105 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
7106 EL_CONVEYOR_BELT_4_SWITCH_LEFT
7109 return belt_base_element[belt_nr] + belt_dir_nr;
7112 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
7114 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
7116 return getBeltSwitchElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
7119 boolean getTeamMode_EM()
7121 return game.team_mode;
7124 int getGameFrameDelay_EM(int native_em_game_frame_delay)
7126 int game_frame_delay_value;
7128 game_frame_delay_value =
7129 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
7130 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
7133 if (tape.playing && tape.warp_forward && !tape.pausing)
7134 game_frame_delay_value = 0;
7136 return game_frame_delay_value;
7139 unsigned int InitRND(int seed)
7141 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
7142 return InitEngineRandom_EM(seed);
7143 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
7144 return InitEngineRandom_SP(seed);
7146 return InitEngineRandom_RND(seed);
7149 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
7150 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
7152 inline static int get_effective_element_EM(int tile, int frame_em)
7154 int element = object_mapping[tile].element_rnd;
7155 int action = object_mapping[tile].action;
7156 boolean is_backside = object_mapping[tile].is_backside;
7157 boolean action_removing = (action == ACTION_DIGGING ||
7158 action == ACTION_SNAPPING ||
7159 action == ACTION_COLLECTING);
7165 case Yacid_splash_eB:
7166 case Yacid_splash_wB:
7167 return (frame_em > 5 ? EL_EMPTY : element);
7173 else /* frame_em == 7 */
7177 case Yacid_splash_eB:
7178 case Yacid_splash_wB:
7181 case Yemerald_stone:
7184 case Ydiamond_stone:
7188 case Xdrip_stretchB:
7207 case Xsand_stonein_1:
7208 case Xsand_stonein_2:
7209 case Xsand_stonein_3:
7210 case Xsand_stonein_4:
7214 return (is_backside || action_removing ? EL_EMPTY : element);
7219 inline static boolean check_linear_animation_EM(int tile)
7223 case Xsand_stonesand_1:
7224 case Xsand_stonesand_quickout_1:
7225 case Xsand_sandstone_1:
7226 case Xsand_stonein_1:
7227 case Xsand_stoneout_1:
7246 case Yacid_splash_eB:
7247 case Yacid_splash_wB:
7248 case Yemerald_stone:
7255 inline static void set_crumbled_graphics_EM(struct GraphicInfo_EM *g_em,
7256 boolean has_crumbled_graphics,
7257 int crumbled, int sync_frame)
7259 /* if element can be crumbled, but certain action graphics are just empty
7260 space (like instantly snapping sand to empty space in 1 frame), do not
7261 treat these empty space graphics as crumbled graphics in EMC engine */
7262 if (crumbled == IMG_EMPTY_SPACE)
7263 has_crumbled_graphics = FALSE;
7265 if (has_crumbled_graphics)
7267 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
7268 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
7269 g_crumbled->anim_delay,
7270 g_crumbled->anim_mode,
7271 g_crumbled->anim_start_frame,
7274 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
7275 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
7277 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
7279 g_em->has_crumbled_graphics = TRUE;
7283 g_em->crumbled_bitmap = NULL;
7284 g_em->crumbled_src_x = 0;
7285 g_em->crumbled_src_y = 0;
7286 g_em->crumbled_border_size = 0;
7288 g_em->has_crumbled_graphics = FALSE;
7292 void ResetGfxAnimation_EM(int x, int y, int tile)
7297 void SetGfxAnimation_EM(struct GraphicInfo_EM *g_em,
7298 int tile, int frame_em, int x, int y)
7300 int action = object_mapping[tile].action;
7301 int direction = object_mapping[tile].direction;
7302 int effective_element = get_effective_element_EM(tile, frame_em);
7303 int graphic = (direction == MV_NONE ?
7304 el_act2img(effective_element, action) :
7305 el_act_dir2img(effective_element, action, direction));
7306 struct GraphicInfo *g = &graphic_info[graphic];
7308 boolean action_removing = (action == ACTION_DIGGING ||
7309 action == ACTION_SNAPPING ||
7310 action == ACTION_COLLECTING);
7311 boolean action_moving = (action == ACTION_FALLING ||
7312 action == ACTION_MOVING ||
7313 action == ACTION_PUSHING ||
7314 action == ACTION_EATING ||
7315 action == ACTION_FILLING ||
7316 action == ACTION_EMPTYING);
7317 boolean action_falling = (action == ACTION_FALLING ||
7318 action == ACTION_FILLING ||
7319 action == ACTION_EMPTYING);
7321 /* special case: graphic uses "2nd movement tile" and has defined
7322 7 frames for movement animation (or less) => use default graphic
7323 for last (8th) frame which ends the movement animation */
7324 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
7326 action = ACTION_DEFAULT; /* (keep action_* unchanged for now) */
7327 graphic = (direction == MV_NONE ?
7328 el_act2img(effective_element, action) :
7329 el_act_dir2img(effective_element, action, direction));
7331 g = &graphic_info[graphic];
7334 if ((action_removing || check_linear_animation_EM(tile)) && frame_em == 0)
7338 else if (action_moving)
7340 boolean is_backside = object_mapping[tile].is_backside;
7344 int direction = object_mapping[tile].direction;
7345 int move_dir = (action_falling ? MV_DOWN : direction);
7350 /* !!! TEST !!! NEW !!! DOES NOT WORK RIGHT YET !!! */
7351 if (g->double_movement && frame_em == 0)
7355 if (move_dir == MV_LEFT)
7356 GfxFrame[x - 1][y] = GfxFrame[x][y];
7357 else if (move_dir == MV_RIGHT)
7358 GfxFrame[x + 1][y] = GfxFrame[x][y];
7359 else if (move_dir == MV_UP)
7360 GfxFrame[x][y - 1] = GfxFrame[x][y];
7361 else if (move_dir == MV_DOWN)
7362 GfxFrame[x][y + 1] = GfxFrame[x][y];
7369 /* special case: animation for Xsand_stonesand_quickout_1/2 twice as fast */
7370 if (tile == Xsand_stonesand_quickout_1 ||
7371 tile == Xsand_stonesand_quickout_2)
7375 if (graphic_info[graphic].anim_global_sync)
7376 sync_frame = FrameCounter;
7377 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
7378 sync_frame = GfxFrame[x][y];
7380 sync_frame = 0; /* playfield border (pseudo steel) */
7382 SetRandomAnimationValue(x, y);
7384 int frame = getAnimationFrame(g->anim_frames,
7387 g->anim_start_frame,
7390 g_em->unique_identifier =
7391 (graphic << 16) | ((frame % 8) << 12) | (g_em->width << 6) | g_em->height;
7394 void getGraphicSourceObjectExt_EM(struct GraphicInfo_EM *g_em,
7395 int tile, int frame_em, int x, int y)
7397 int action = object_mapping[tile].action;
7398 int direction = object_mapping[tile].direction;
7399 boolean is_backside = object_mapping[tile].is_backside;
7400 int effective_element = get_effective_element_EM(tile, frame_em);
7401 int effective_action = action;
7402 int graphic = (direction == MV_NONE ?
7403 el_act2img(effective_element, effective_action) :
7404 el_act_dir2img(effective_element, effective_action,
7406 int crumbled = (direction == MV_NONE ?
7407 el_act2crm(effective_element, effective_action) :
7408 el_act_dir2crm(effective_element, effective_action,
7410 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7411 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7412 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7413 struct GraphicInfo *g = &graphic_info[graphic];
7416 /* special case: graphic uses "2nd movement tile" and has defined
7417 7 frames for movement animation (or less) => use default graphic
7418 for last (8th) frame which ends the movement animation */
7419 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
7421 effective_action = ACTION_DEFAULT;
7422 graphic = (direction == MV_NONE ?
7423 el_act2img(effective_element, effective_action) :
7424 el_act_dir2img(effective_element, effective_action,
7426 crumbled = (direction == MV_NONE ?
7427 el_act2crm(effective_element, effective_action) :
7428 el_act_dir2crm(effective_element, effective_action,
7431 g = &graphic_info[graphic];
7434 if (graphic_info[graphic].anim_global_sync)
7435 sync_frame = FrameCounter;
7436 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
7437 sync_frame = GfxFrame[x][y];
7439 sync_frame = 0; /* playfield border (pseudo steel) */
7441 SetRandomAnimationValue(x, y);
7443 int frame = getAnimationFrame(g->anim_frames,
7446 g->anim_start_frame,
7449 getGraphicSourceExt(graphic, frame, &g_em->bitmap, &g_em->src_x, &g_em->src_y,
7450 g->double_movement && is_backside);
7452 /* (updating the "crumbled" graphic definitions is probably not really needed,
7453 as animations for crumbled graphics can't be longer than one EMC cycle) */
7454 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
7458 void getGraphicSourcePlayerExt_EM(struct GraphicInfo_EM *g_em,
7459 int player_nr, int anim, int frame_em)
7461 int element = player_mapping[player_nr][anim].element_rnd;
7462 int action = player_mapping[player_nr][anim].action;
7463 int direction = player_mapping[player_nr][anim].direction;
7464 int graphic = (direction == MV_NONE ?
7465 el_act2img(element, action) :
7466 el_act_dir2img(element, action, direction));
7467 struct GraphicInfo *g = &graphic_info[graphic];
7470 InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
7472 stored_player[player_nr].StepFrame = frame_em;
7474 sync_frame = stored_player[player_nr].Frame;
7476 int frame = getAnimationFrame(g->anim_frames,
7479 g->anim_start_frame,
7482 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
7483 &g_em->src_x, &g_em->src_y, FALSE);
7486 void InitGraphicInfo_EM(void)
7491 int num_em_gfx_errors = 0;
7493 if (graphic_info_em_object[0][0].bitmap == NULL)
7495 /* EM graphics not yet initialized in em_open_all() */
7500 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
7503 /* always start with reliable default values */
7504 for (i = 0; i < TILE_MAX; i++)
7506 object_mapping[i].element_rnd = EL_UNKNOWN;
7507 object_mapping[i].is_backside = FALSE;
7508 object_mapping[i].action = ACTION_DEFAULT;
7509 object_mapping[i].direction = MV_NONE;
7512 /* always start with reliable default values */
7513 for (p = 0; p < MAX_PLAYERS; p++)
7515 for (i = 0; i < SPR_MAX; i++)
7517 player_mapping[p][i].element_rnd = EL_UNKNOWN;
7518 player_mapping[p][i].action = ACTION_DEFAULT;
7519 player_mapping[p][i].direction = MV_NONE;
7523 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
7525 int e = em_object_mapping_list[i].element_em;
7527 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
7528 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
7530 if (em_object_mapping_list[i].action != -1)
7531 object_mapping[e].action = em_object_mapping_list[i].action;
7533 if (em_object_mapping_list[i].direction != -1)
7534 object_mapping[e].direction =
7535 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
7538 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
7540 int a = em_player_mapping_list[i].action_em;
7541 int p = em_player_mapping_list[i].player_nr;
7543 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
7545 if (em_player_mapping_list[i].action != -1)
7546 player_mapping[p][a].action = em_player_mapping_list[i].action;
7548 if (em_player_mapping_list[i].direction != -1)
7549 player_mapping[p][a].direction =
7550 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
7553 for (i = 0; i < TILE_MAX; i++)
7555 int element = object_mapping[i].element_rnd;
7556 int action = object_mapping[i].action;
7557 int direction = object_mapping[i].direction;
7558 boolean is_backside = object_mapping[i].is_backside;
7559 boolean action_exploding = ((action == ACTION_EXPLODING ||
7560 action == ACTION_SMASHED_BY_ROCK ||
7561 action == ACTION_SMASHED_BY_SPRING) &&
7562 element != EL_DIAMOND);
7563 boolean action_active = (action == ACTION_ACTIVE);
7564 boolean action_other = (action == ACTION_OTHER);
7566 for (j = 0; j < 8; j++)
7568 int effective_element = get_effective_element_EM(i, j);
7569 int effective_action = (j < 7 ? action :
7570 i == Xdrip_stretch ? action :
7571 i == Xdrip_stretchB ? action :
7572 i == Ydrip_s1 ? action :
7573 i == Ydrip_s1B ? action :
7574 i == Xball_1B ? action :
7575 i == Xball_2 ? action :
7576 i == Xball_2B ? action :
7577 i == Yball_eat ? action :
7578 i == Ykey_1_eat ? action :
7579 i == Ykey_2_eat ? action :
7580 i == Ykey_3_eat ? action :
7581 i == Ykey_4_eat ? action :
7582 i == Ykey_5_eat ? action :
7583 i == Ykey_6_eat ? action :
7584 i == Ykey_7_eat ? action :
7585 i == Ykey_8_eat ? action :
7586 i == Ylenses_eat ? action :
7587 i == Ymagnify_eat ? action :
7588 i == Ygrass_eat ? action :
7589 i == Ydirt_eat ? action :
7590 i == Xsand_stonein_1 ? action :
7591 i == Xsand_stonein_2 ? action :
7592 i == Xsand_stonein_3 ? action :
7593 i == Xsand_stonein_4 ? action :
7594 i == Xsand_stoneout_1 ? action :
7595 i == Xsand_stoneout_2 ? action :
7596 i == Xboom_android ? ACTION_EXPLODING :
7597 action_exploding ? ACTION_EXPLODING :
7598 action_active ? action :
7599 action_other ? action :
7601 int graphic = (el_act_dir2img(effective_element, effective_action,
7603 int crumbled = (el_act_dir2crm(effective_element, effective_action,
7605 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7606 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7607 boolean has_action_graphics = (graphic != base_graphic);
7608 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7609 struct GraphicInfo *g = &graphic_info[graphic];
7610 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7613 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
7614 boolean special_animation = (action != ACTION_DEFAULT &&
7615 g->anim_frames == 3 &&
7616 g->anim_delay == 2 &&
7617 g->anim_mode & ANIM_LINEAR);
7618 int sync_frame = (i == Xdrip_stretch ? 7 :
7619 i == Xdrip_stretchB ? 7 :
7620 i == Ydrip_s2 ? j + 8 :
7621 i == Ydrip_s2B ? j + 8 :
7630 i == Xfake_acid_1 ? 0 :
7631 i == Xfake_acid_2 ? 10 :
7632 i == Xfake_acid_3 ? 20 :
7633 i == Xfake_acid_4 ? 30 :
7634 i == Xfake_acid_5 ? 40 :
7635 i == Xfake_acid_6 ? 50 :
7636 i == Xfake_acid_7 ? 60 :
7637 i == Xfake_acid_8 ? 70 :
7639 i == Xball_2B ? j + 8 :
7640 i == Yball_eat ? j + 1 :
7641 i == Ykey_1_eat ? j + 1 :
7642 i == Ykey_2_eat ? j + 1 :
7643 i == Ykey_3_eat ? j + 1 :
7644 i == Ykey_4_eat ? j + 1 :
7645 i == Ykey_5_eat ? j + 1 :
7646 i == Ykey_6_eat ? j + 1 :
7647 i == Ykey_7_eat ? j + 1 :
7648 i == Ykey_8_eat ? j + 1 :
7649 i == Ylenses_eat ? j + 1 :
7650 i == Ymagnify_eat ? j + 1 :
7651 i == Ygrass_eat ? j + 1 :
7652 i == Ydirt_eat ? j + 1 :
7653 i == Xamoeba_1 ? 0 :
7654 i == Xamoeba_2 ? 1 :
7655 i == Xamoeba_3 ? 2 :
7656 i == Xamoeba_4 ? 3 :
7657 i == Xamoeba_5 ? 0 :
7658 i == Xamoeba_6 ? 1 :
7659 i == Xamoeba_7 ? 2 :
7660 i == Xamoeba_8 ? 3 :
7661 i == Xexit_2 ? j + 8 :
7662 i == Xexit_3 ? j + 16 :
7663 i == Xdynamite_1 ? 0 :
7664 i == Xdynamite_2 ? 8 :
7665 i == Xdynamite_3 ? 16 :
7666 i == Xdynamite_4 ? 24 :
7667 i == Xsand_stonein_1 ? j + 1 :
7668 i == Xsand_stonein_2 ? j + 9 :
7669 i == Xsand_stonein_3 ? j + 17 :
7670 i == Xsand_stonein_4 ? j + 25 :
7671 i == Xsand_stoneout_1 && j == 0 ? 0 :
7672 i == Xsand_stoneout_1 && j == 1 ? 0 :
7673 i == Xsand_stoneout_1 && j == 2 ? 1 :
7674 i == Xsand_stoneout_1 && j == 3 ? 2 :
7675 i == Xsand_stoneout_1 && j == 4 ? 2 :
7676 i == Xsand_stoneout_1 && j == 5 ? 3 :
7677 i == Xsand_stoneout_1 && j == 6 ? 4 :
7678 i == Xsand_stoneout_1 && j == 7 ? 4 :
7679 i == Xsand_stoneout_2 && j == 0 ? 5 :
7680 i == Xsand_stoneout_2 && j == 1 ? 6 :
7681 i == Xsand_stoneout_2 && j == 2 ? 7 :
7682 i == Xsand_stoneout_2 && j == 3 ? 8 :
7683 i == Xsand_stoneout_2 && j == 4 ? 9 :
7684 i == Xsand_stoneout_2 && j == 5 ? 11 :
7685 i == Xsand_stoneout_2 && j == 6 ? 13 :
7686 i == Xsand_stoneout_2 && j == 7 ? 15 :
7687 i == Xboom_bug && j == 1 ? 2 :
7688 i == Xboom_bug && j == 2 ? 2 :
7689 i == Xboom_bug && j == 3 ? 4 :
7690 i == Xboom_bug && j == 4 ? 4 :
7691 i == Xboom_bug && j == 5 ? 2 :
7692 i == Xboom_bug && j == 6 ? 2 :
7693 i == Xboom_bug && j == 7 ? 0 :
7694 i == Xboom_bomb && j == 1 ? 2 :
7695 i == Xboom_bomb && j == 2 ? 2 :
7696 i == Xboom_bomb && j == 3 ? 4 :
7697 i == Xboom_bomb && j == 4 ? 4 :
7698 i == Xboom_bomb && j == 5 ? 2 :
7699 i == Xboom_bomb && j == 6 ? 2 :
7700 i == Xboom_bomb && j == 7 ? 0 :
7701 i == Xboom_android && j == 7 ? 6 :
7702 i == Xboom_1 && j == 1 ? 2 :
7703 i == Xboom_1 && j == 2 ? 2 :
7704 i == Xboom_1 && j == 3 ? 4 :
7705 i == Xboom_1 && j == 4 ? 4 :
7706 i == Xboom_1 && j == 5 ? 6 :
7707 i == Xboom_1 && j == 6 ? 6 :
7708 i == Xboom_1 && j == 7 ? 8 :
7709 i == Xboom_2 && j == 0 ? 8 :
7710 i == Xboom_2 && j == 1 ? 8 :
7711 i == Xboom_2 && j == 2 ? 10 :
7712 i == Xboom_2 && j == 3 ? 10 :
7713 i == Xboom_2 && j == 4 ? 10 :
7714 i == Xboom_2 && j == 5 ? 12 :
7715 i == Xboom_2 && j == 6 ? 12 :
7716 i == Xboom_2 && j == 7 ? 12 :
7717 special_animation && j == 4 ? 3 :
7718 effective_action != action ? 0 :
7722 Bitmap *debug_bitmap = g_em->bitmap;
7723 int debug_src_x = g_em->src_x;
7724 int debug_src_y = g_em->src_y;
7727 int frame = getAnimationFrame(g->anim_frames,
7730 g->anim_start_frame,
7733 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
7734 g->double_movement && is_backside);
7736 g_em->bitmap = src_bitmap;
7737 g_em->src_x = src_x;
7738 g_em->src_y = src_y;
7739 g_em->src_offset_x = 0;
7740 g_em->src_offset_y = 0;
7741 g_em->dst_offset_x = 0;
7742 g_em->dst_offset_y = 0;
7743 g_em->width = TILEX;
7744 g_em->height = TILEY;
7746 g_em->preserve_background = FALSE;
7748 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
7751 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
7752 effective_action == ACTION_MOVING ||
7753 effective_action == ACTION_PUSHING ||
7754 effective_action == ACTION_EATING)) ||
7755 (!has_action_graphics && (effective_action == ACTION_FILLING ||
7756 effective_action == ACTION_EMPTYING)))
7759 (effective_action == ACTION_FALLING ||
7760 effective_action == ACTION_FILLING ||
7761 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
7762 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
7763 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
7764 int num_steps = (i == Ydrip_s1 ? 16 :
7765 i == Ydrip_s1B ? 16 :
7766 i == Ydrip_s2 ? 16 :
7767 i == Ydrip_s2B ? 16 :
7768 i == Xsand_stonein_1 ? 32 :
7769 i == Xsand_stonein_2 ? 32 :
7770 i == Xsand_stonein_3 ? 32 :
7771 i == Xsand_stonein_4 ? 32 :
7772 i == Xsand_stoneout_1 ? 16 :
7773 i == Xsand_stoneout_2 ? 16 : 8);
7774 int cx = ABS(dx) * (TILEX / num_steps);
7775 int cy = ABS(dy) * (TILEY / num_steps);
7776 int step_frame = (i == Ydrip_s2 ? j + 8 :
7777 i == Ydrip_s2B ? j + 8 :
7778 i == Xsand_stonein_2 ? j + 8 :
7779 i == Xsand_stonein_3 ? j + 16 :
7780 i == Xsand_stonein_4 ? j + 24 :
7781 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
7782 int step = (is_backside ? step_frame : num_steps - step_frame);
7784 if (is_backside) /* tile where movement starts */
7786 if (dx < 0 || dy < 0)
7788 g_em->src_offset_x = cx * step;
7789 g_em->src_offset_y = cy * step;
7793 g_em->dst_offset_x = cx * step;
7794 g_em->dst_offset_y = cy * step;
7797 else /* tile where movement ends */
7799 if (dx < 0 || dy < 0)
7801 g_em->dst_offset_x = cx * step;
7802 g_em->dst_offset_y = cy * step;
7806 g_em->src_offset_x = cx * step;
7807 g_em->src_offset_y = cy * step;
7811 g_em->width = TILEX - cx * step;
7812 g_em->height = TILEY - cy * step;
7815 /* create unique graphic identifier to decide if tile must be redrawn */
7816 /* bit 31 - 16 (16 bit): EM style graphic
7817 bit 15 - 12 ( 4 bit): EM style frame
7818 bit 11 - 6 ( 6 bit): graphic width
7819 bit 5 - 0 ( 6 bit): graphic height */
7820 g_em->unique_identifier =
7821 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
7825 /* skip check for EMC elements not contained in original EMC artwork */
7826 if (element == EL_EMC_FAKE_ACID)
7829 if (g_em->bitmap != debug_bitmap ||
7830 g_em->src_x != debug_src_x ||
7831 g_em->src_y != debug_src_y ||
7832 g_em->src_offset_x != 0 ||
7833 g_em->src_offset_y != 0 ||
7834 g_em->dst_offset_x != 0 ||
7835 g_em->dst_offset_y != 0 ||
7836 g_em->width != TILEX ||
7837 g_em->height != TILEY)
7839 static int last_i = -1;
7847 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
7848 i, element, element_info[element].token_name,
7849 element_action_info[effective_action].suffix, direction);
7851 if (element != effective_element)
7852 printf(" [%d ('%s')]",
7854 element_info[effective_element].token_name);
7858 if (g_em->bitmap != debug_bitmap)
7859 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
7860 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
7862 if (g_em->src_x != debug_src_x ||
7863 g_em->src_y != debug_src_y)
7864 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
7865 j, (is_backside ? 'B' : 'F'),
7866 g_em->src_x, g_em->src_y,
7867 g_em->src_x / 32, g_em->src_y / 32,
7868 debug_src_x, debug_src_y,
7869 debug_src_x / 32, debug_src_y / 32);
7871 if (g_em->src_offset_x != 0 ||
7872 g_em->src_offset_y != 0 ||
7873 g_em->dst_offset_x != 0 ||
7874 g_em->dst_offset_y != 0)
7875 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
7877 g_em->src_offset_x, g_em->src_offset_y,
7878 g_em->dst_offset_x, g_em->dst_offset_y);
7880 if (g_em->width != TILEX ||
7881 g_em->height != TILEY)
7882 printf(" %d (%d): size %d,%d should be %d,%d\n",
7884 g_em->width, g_em->height, TILEX, TILEY);
7886 num_em_gfx_errors++;
7893 for (i = 0; i < TILE_MAX; i++)
7895 for (j = 0; j < 8; j++)
7897 int element = object_mapping[i].element_rnd;
7898 int action = object_mapping[i].action;
7899 int direction = object_mapping[i].direction;
7900 boolean is_backside = object_mapping[i].is_backside;
7901 int graphic_action = el_act_dir2img(element, action, direction);
7902 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
7904 if ((action == ACTION_SMASHED_BY_ROCK ||
7905 action == ACTION_SMASHED_BY_SPRING ||
7906 action == ACTION_EATING) &&
7907 graphic_action == graphic_default)
7909 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
7910 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
7911 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
7912 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
7915 /* no separate animation for "smashed by rock" -- use rock instead */
7916 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7917 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
7919 g_em->bitmap = g_xx->bitmap;
7920 g_em->src_x = g_xx->src_x;
7921 g_em->src_y = g_xx->src_y;
7922 g_em->src_offset_x = g_xx->src_offset_x;
7923 g_em->src_offset_y = g_xx->src_offset_y;
7924 g_em->dst_offset_x = g_xx->dst_offset_x;
7925 g_em->dst_offset_y = g_xx->dst_offset_y;
7926 g_em->width = g_xx->width;
7927 g_em->height = g_xx->height;
7928 g_em->unique_identifier = g_xx->unique_identifier;
7931 g_em->preserve_background = TRUE;
7936 for (p = 0; p < MAX_PLAYERS; p++)
7938 for (i = 0; i < SPR_MAX; i++)
7940 int element = player_mapping[p][i].element_rnd;
7941 int action = player_mapping[p][i].action;
7942 int direction = player_mapping[p][i].direction;
7944 for (j = 0; j < 8; j++)
7946 int effective_element = element;
7947 int effective_action = action;
7948 int graphic = (direction == MV_NONE ?
7949 el_act2img(effective_element, effective_action) :
7950 el_act_dir2img(effective_element, effective_action,
7952 struct GraphicInfo *g = &graphic_info[graphic];
7953 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
7959 Bitmap *debug_bitmap = g_em->bitmap;
7960 int debug_src_x = g_em->src_x;
7961 int debug_src_y = g_em->src_y;
7964 int frame = getAnimationFrame(g->anim_frames,
7967 g->anim_start_frame,
7970 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
7972 g_em->bitmap = src_bitmap;
7973 g_em->src_x = src_x;
7974 g_em->src_y = src_y;
7975 g_em->src_offset_x = 0;
7976 g_em->src_offset_y = 0;
7977 g_em->dst_offset_x = 0;
7978 g_em->dst_offset_y = 0;
7979 g_em->width = TILEX;
7980 g_em->height = TILEY;
7984 /* skip check for EMC elements not contained in original EMC artwork */
7985 if (element == EL_PLAYER_3 ||
7986 element == EL_PLAYER_4)
7989 if (g_em->bitmap != debug_bitmap ||
7990 g_em->src_x != debug_src_x ||
7991 g_em->src_y != debug_src_y)
7993 static int last_i = -1;
8001 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
8002 p, i, element, element_info[element].token_name,
8003 element_action_info[effective_action].suffix, direction);
8005 if (element != effective_element)
8006 printf(" [%d ('%s')]",
8008 element_info[effective_element].token_name);
8012 if (g_em->bitmap != debug_bitmap)
8013 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
8014 j, (int)(g_em->bitmap), (int)(debug_bitmap));
8016 if (g_em->src_x != debug_src_x ||
8017 g_em->src_y != debug_src_y)
8018 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
8020 g_em->src_x, g_em->src_y,
8021 g_em->src_x / 32, g_em->src_y / 32,
8022 debug_src_x, debug_src_y,
8023 debug_src_x / 32, debug_src_y / 32);
8025 num_em_gfx_errors++;
8035 printf("::: [%d errors found]\n", num_em_gfx_errors);
8041 void CheckSaveEngineSnapshot_EM(byte action[MAX_PLAYERS], int frame,
8042 boolean any_player_moving,
8043 boolean any_player_snapping,
8044 boolean any_player_dropping)
8046 static boolean player_was_waiting = TRUE;
8048 if (frame == 0 && !any_player_dropping)
8050 if (!player_was_waiting)
8052 if (!SaveEngineSnapshotToList())
8055 player_was_waiting = TRUE;
8058 else if (any_player_moving || any_player_snapping || any_player_dropping)
8060 player_was_waiting = FALSE;
8064 void CheckSaveEngineSnapshot_SP(boolean murphy_is_waiting,
8065 boolean murphy_is_dropping)
8067 static boolean player_was_waiting = TRUE;
8069 if (murphy_is_waiting)
8071 if (!player_was_waiting)
8073 if (!SaveEngineSnapshotToList())
8076 player_was_waiting = TRUE;
8081 player_was_waiting = FALSE;
8085 void CheckSingleStepMode_EM(byte action[MAX_PLAYERS], int frame,
8086 boolean any_player_moving,
8087 boolean any_player_snapping,
8088 boolean any_player_dropping)
8090 if (tape.single_step && tape.recording && !tape.pausing)
8091 if (frame == 0 && !any_player_dropping)
8092 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
8094 CheckSaveEngineSnapshot_EM(action, frame, any_player_moving,
8095 any_player_snapping, any_player_dropping);
8098 void CheckSingleStepMode_SP(boolean murphy_is_waiting,
8099 boolean murphy_is_dropping)
8101 if (tape.single_step && tape.recording && !tape.pausing)
8102 if (murphy_is_waiting)
8103 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
8105 CheckSaveEngineSnapshot_SP(murphy_is_waiting, murphy_is_dropping);
8108 void getGraphicSource_SP(struct GraphicInfo_SP *g_sp,
8109 int graphic, int sync_frame, int x, int y)
8111 int frame = getGraphicAnimationFrame(graphic, sync_frame);
8113 getGraphicSource(graphic, frame, &g_sp->bitmap, &g_sp->src_x, &g_sp->src_y);
8116 boolean isNextAnimationFrame_SP(int graphic, int sync_frame)
8118 return (IS_NEXT_FRAME(sync_frame, graphic));
8121 int getGraphicInfo_Delay(int graphic)
8123 return graphic_info[graphic].anim_delay;
8126 void PlayMenuSoundExt(int sound)
8128 if (sound == SND_UNDEFINED)
8131 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8132 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8135 if (IS_LOOP_SOUND(sound))
8136 PlaySoundLoop(sound);
8141 void PlayMenuSound()
8143 PlayMenuSoundExt(menu.sound[game_status]);
8146 void PlayMenuSoundStereo(int sound, int stereo_position)
8148 if (sound == SND_UNDEFINED)
8151 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8152 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8155 if (IS_LOOP_SOUND(sound))
8156 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
8158 PlaySoundStereo(sound, stereo_position);
8161 void PlayMenuSoundIfLoopExt(int sound)
8163 if (sound == SND_UNDEFINED)
8166 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8167 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8170 if (IS_LOOP_SOUND(sound))
8171 PlaySoundLoop(sound);
8174 void PlayMenuSoundIfLoop()
8176 PlayMenuSoundIfLoopExt(menu.sound[game_status]);
8179 void PlayMenuMusicExt(int music)
8181 if (music == MUS_UNDEFINED)
8184 if (!setup.sound_music)
8190 void PlayMenuMusic()
8192 PlayMenuMusicExt(menu.music[game_status]);
8195 void PlaySoundActivating()
8198 PlaySound(SND_MENU_ITEM_ACTIVATING);
8202 void PlaySoundSelecting()
8205 PlaySound(SND_MENU_ITEM_SELECTING);
8209 void ToggleFullscreenOrChangeWindowScalingIfNeeded()
8211 boolean change_fullscreen = (setup.fullscreen !=
8212 video.fullscreen_enabled);
8213 boolean change_fullscreen_mode = (video.fullscreen_enabled &&
8214 !strEqual(setup.fullscreen_mode,
8215 video.fullscreen_mode_current));
8216 boolean change_window_scaling_percent = (!video.fullscreen_enabled &&
8217 setup.window_scaling_percent !=
8218 video.window_scaling_percent);
8220 if (change_window_scaling_percent && video.fullscreen_enabled)
8223 if (!change_window_scaling_percent && !video.fullscreen_available)
8226 #if defined(TARGET_SDL2)
8227 if (change_window_scaling_percent)
8229 SDLSetWindowScaling(setup.window_scaling_percent);
8233 else if (change_fullscreen)
8235 SDLSetWindowFullscreen(setup.fullscreen);
8237 /* set setup value according to successfully changed fullscreen mode */
8238 setup.fullscreen = video.fullscreen_enabled;
8244 if (change_fullscreen ||
8245 change_fullscreen_mode ||
8246 change_window_scaling_percent)
8248 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
8250 /* save backbuffer content which gets lost when toggling fullscreen mode */
8251 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8253 if (change_fullscreen_mode)
8255 /* keep fullscreen, but change fullscreen mode (screen resolution) */
8256 video.fullscreen_enabled = FALSE; /* force new fullscreen mode */
8259 if (change_window_scaling_percent)
8261 /* keep window mode, but change window scaling */
8262 video.fullscreen_enabled = TRUE; /* force new window scaling */
8265 /* toggle fullscreen */
8266 ChangeVideoModeIfNeeded(setup.fullscreen);
8268 /* set setup value according to successfully changed fullscreen mode */
8269 setup.fullscreen = video.fullscreen_enabled;
8271 /* restore backbuffer content from temporary backbuffer backup bitmap */
8272 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8274 FreeBitmap(tmp_backbuffer);
8276 /* update visible window/screen */
8277 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8281 void JoinRectangles(int *x, int *y, int *width, int *height,
8282 int x2, int y2, int width2, int height2)
8284 // do not join with "off-screen" rectangle
8285 if (x2 == -1 || y2 == -1)
8290 *width = MAX(*width, width2);
8291 *height = MAX(*height, height2);
8294 void SetGameStatus(int game_status_new)
8296 game_status = game_status_new;
8298 global.anim_status_next = game_status;
8301 void ChangeViewportPropertiesIfNeeded()
8303 int gfx_game_mode = game_status;
8304 int gfx_game_mode2 = (game_status == GAME_MODE_EDITOR ? GAME_MODE_DEFAULT :
8306 struct RectWithBorder *vp_window = &viewport.window[gfx_game_mode];
8307 struct RectWithBorder *vp_playfield = &viewport.playfield[gfx_game_mode];
8308 struct RectWithBorder *vp_door_1 = &viewport.door_1[gfx_game_mode];
8309 struct RectWithBorder *vp_door_2 = &viewport.door_2[gfx_game_mode2];
8310 struct RectWithBorder *vp_door_3 = &viewport.door_2[GAME_MODE_EDITOR];
8311 int new_win_xsize = vp_window->width;
8312 int new_win_ysize = vp_window->height;
8313 int border_size = vp_playfield->border_size;
8314 int new_sx = vp_playfield->x + border_size;
8315 int new_sy = vp_playfield->y + border_size;
8316 int new_sxsize = vp_playfield->width - 2 * border_size;
8317 int new_sysize = vp_playfield->height - 2 * border_size;
8318 int new_real_sx = vp_playfield->x;
8319 int new_real_sy = vp_playfield->y;
8320 int new_full_sxsize = vp_playfield->width;
8321 int new_full_sysize = vp_playfield->height;
8322 int new_dx = vp_door_1->x;
8323 int new_dy = vp_door_1->y;
8324 int new_dxsize = vp_door_1->width;
8325 int new_dysize = vp_door_1->height;
8326 int new_vx = vp_door_2->x;
8327 int new_vy = vp_door_2->y;
8328 int new_vxsize = vp_door_2->width;
8329 int new_vysize = vp_door_2->height;
8330 int new_ex = vp_door_3->x;
8331 int new_ey = vp_door_3->y;
8332 int new_exsize = vp_door_3->width;
8333 int new_eysize = vp_door_3->height;
8334 int new_tilesize_var =
8335 (setup.small_game_graphics ? MINI_TILESIZE : game.tile_size);
8337 int tilesize = (gfx_game_mode == GAME_MODE_PLAYING ? new_tilesize_var :
8338 gfx_game_mode == GAME_MODE_EDITOR ? MINI_TILESIZE : TILESIZE);
8339 int new_scr_fieldx = new_sxsize / tilesize;
8340 int new_scr_fieldy = new_sysize / tilesize;
8341 int new_scr_fieldx_buffers = new_sxsize / new_tilesize_var;
8342 int new_scr_fieldy_buffers = new_sysize / new_tilesize_var;
8343 boolean init_gfx_buffers = FALSE;
8344 boolean init_video_buffer = FALSE;
8345 boolean init_gadgets_and_toons = FALSE;
8346 boolean init_em_graphics = FALSE;
8348 if (new_win_xsize != WIN_XSIZE ||
8349 new_win_ysize != WIN_YSIZE)
8351 WIN_XSIZE = new_win_xsize;
8352 WIN_YSIZE = new_win_ysize;
8354 init_video_buffer = TRUE;
8355 init_gfx_buffers = TRUE;
8356 init_gadgets_and_toons = TRUE;
8358 // printf("::: video: init_video_buffer, init_gfx_buffers\n");
8361 if (new_scr_fieldx != SCR_FIELDX ||
8362 new_scr_fieldy != SCR_FIELDY)
8364 /* this always toggles between MAIN and GAME when using small tile size */
8366 SCR_FIELDX = new_scr_fieldx;
8367 SCR_FIELDY = new_scr_fieldy;
8369 // printf("::: new_scr_fieldx != SCR_FIELDX ...\n");
8380 new_sxsize != SXSIZE ||
8381 new_sysize != SYSIZE ||
8382 new_dxsize != DXSIZE ||
8383 new_dysize != DYSIZE ||
8384 new_vxsize != VXSIZE ||
8385 new_vysize != VYSIZE ||
8386 new_exsize != EXSIZE ||
8387 new_eysize != EYSIZE ||
8388 new_real_sx != REAL_SX ||
8389 new_real_sy != REAL_SY ||
8390 new_full_sxsize != FULL_SXSIZE ||
8391 new_full_sysize != FULL_SYSIZE ||
8392 new_tilesize_var != TILESIZE_VAR
8395 // ------------------------------------------------------------------------
8396 // determine next fading area for changed viewport definitions
8397 // ------------------------------------------------------------------------
8399 // start with current playfield area (default fading area)
8402 FADE_SXSIZE = FULL_SXSIZE;
8403 FADE_SYSIZE = FULL_SYSIZE;
8405 // add new playfield area if position or size has changed
8406 if (new_real_sx != REAL_SX || new_real_sy != REAL_SY ||
8407 new_full_sxsize != FULL_SXSIZE || new_full_sysize != FULL_SYSIZE)
8409 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
8410 new_real_sx, new_real_sy, new_full_sxsize,new_full_sysize);
8413 // add current and new door 1 area if position or size has changed
8414 if (new_dx != DX || new_dy != DY ||
8415 new_dxsize != DXSIZE || new_dysize != DYSIZE)
8417 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
8418 DX, DY, DXSIZE, DYSIZE);
8419 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
8420 new_dx, new_dy, new_dxsize, new_dysize);
8423 // add current and new door 2 area if position or size has changed
8424 if (new_dx != VX || new_dy != VY ||
8425 new_dxsize != VXSIZE || new_dysize != VYSIZE)
8427 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
8428 VX, VY, VXSIZE, VYSIZE);
8429 JoinRectangles(&FADE_SX, &FADE_SY, &FADE_SXSIZE, &FADE_SYSIZE,
8430 new_vx, new_vy, new_vxsize, new_vysize);
8433 // ------------------------------------------------------------------------
8434 // handle changed tile size
8435 // ------------------------------------------------------------------------
8437 if (new_tilesize_var != TILESIZE_VAR)
8439 // printf("::: new_tilesize_var != TILESIZE_VAR\n");
8441 // changing tile size invalidates scroll values of engine snapshots
8442 FreeEngineSnapshotSingle();
8444 // changing tile size requires update of graphic mapping for EM engine
8445 init_em_graphics = TRUE;
8456 SXSIZE = new_sxsize;
8457 SYSIZE = new_sysize;
8458 DXSIZE = new_dxsize;
8459 DYSIZE = new_dysize;
8460 VXSIZE = new_vxsize;
8461 VYSIZE = new_vysize;
8462 EXSIZE = new_exsize;
8463 EYSIZE = new_eysize;
8464 REAL_SX = new_real_sx;
8465 REAL_SY = new_real_sy;
8466 FULL_SXSIZE = new_full_sxsize;
8467 FULL_SYSIZE = new_full_sysize;
8468 TILESIZE_VAR = new_tilesize_var;
8470 init_gfx_buffers = TRUE;
8471 init_gadgets_and_toons = TRUE;
8473 // printf("::: viewports: init_gfx_buffers\n");
8474 // printf("::: viewports: init_gadgets_and_toons\n");
8477 if (init_gfx_buffers)
8479 // printf("::: init_gfx_buffers\n");
8481 SCR_FIELDX = new_scr_fieldx_buffers;
8482 SCR_FIELDY = new_scr_fieldy_buffers;
8486 SCR_FIELDX = new_scr_fieldx;
8487 SCR_FIELDY = new_scr_fieldy;
8489 SetDrawDeactivationMask(REDRAW_NONE);
8490 SetDrawBackgroundMask(REDRAW_FIELD);
8493 if (init_video_buffer)
8495 // printf("::: init_video_buffer\n");
8497 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
8498 InitImageTextures();
8501 if (init_gadgets_and_toons)
8503 // printf("::: init_gadgets_and_toons\n");
8507 InitGlobalAnimations();
8510 if (init_em_graphics)
8512 InitGraphicInfo_EM();