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 0
29 /* tool button identifiers */
30 #define TOOL_CTRL_ID_YES 0
31 #define TOOL_CTRL_ID_NO 1
32 #define TOOL_CTRL_ID_CONFIRM 2
33 #define TOOL_CTRL_ID_PLAYER_1 3
34 #define TOOL_CTRL_ID_PLAYER_2 4
35 #define TOOL_CTRL_ID_PLAYER_3 5
36 #define TOOL_CTRL_ID_PLAYER_4 6
38 #define NUM_TOOL_BUTTONS 7
40 /* constants for number of doors and door parts */
42 #define NUM_PANELS NUM_DOORS
43 // #define NUM_PANELS 0
44 #define MAX_PARTS_PER_DOOR 8
45 #define MAX_DOOR_PARTS (NUM_DOORS * MAX_PARTS_PER_DOOR + NUM_PANELS)
46 #define DOOR_PART_IS_PANEL(i) ((i) >= NUM_DOORS * MAX_PARTS_PER_DOOR)
49 struct DoorPartOrderInfo
55 static struct DoorPartOrderInfo door_part_order[MAX_DOOR_PARTS];
57 struct DoorPartControlInfo
61 struct DoorPartPosInfo *pos;
64 static struct DoorPartControlInfo door_part_controls[] =
68 IMG_DOOR_1_GFX_PART_1,
73 IMG_DOOR_1_GFX_PART_2,
78 IMG_DOOR_1_GFX_PART_3,
83 IMG_DOOR_1_GFX_PART_4,
88 IMG_DOOR_1_GFX_PART_5,
93 IMG_DOOR_1_GFX_PART_6,
98 IMG_DOOR_1_GFX_PART_7,
103 IMG_DOOR_1_GFX_PART_8,
109 IMG_DOOR_2_GFX_PART_1,
114 IMG_DOOR_2_GFX_PART_2,
119 IMG_DOOR_2_GFX_PART_3,
124 IMG_DOOR_2_GFX_PART_4,
129 IMG_DOOR_2_GFX_PART_5,
134 IMG_DOOR_2_GFX_PART_6,
139 IMG_DOOR_2_GFX_PART_7,
144 IMG_DOOR_2_GFX_PART_8,
150 IMG_BACKGROUND_PANEL,
167 /* forward declaration for internal use */
168 static void UnmapToolButtons();
169 static void HandleToolButtons(struct GadgetInfo *);
170 static int el_act_dir2crm(int, int, int);
171 static int el_act2crm(int, int);
173 static struct GadgetInfo *tool_gadget[NUM_TOOL_BUTTONS];
174 static int request_gadget_id = -1;
176 static char *print_if_not_empty(int element)
178 static char *s = NULL;
179 char *token_name = element_info[element].token_name;
184 s = checked_malloc(strlen(token_name) + 10 + 1);
186 if (element != EL_EMPTY)
187 sprintf(s, "%d\t['%s']", element, token_name);
189 sprintf(s, "%d", element);
194 void DumpTile(int x, int y)
199 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
205 printf_line("-", 79);
206 printf("Field Info: SCREEN(%d, %d), LEVEL(%d, %d)\n", sx, sy, x, y);
207 printf_line("-", 79);
209 if (!IN_LEV_FIELD(x, y))
211 printf("(not in level field)\n");
217 printf(" Feld: %d\t['%s']\n", Feld[x][y],
218 element_info[Feld[x][y]].token_name);
219 printf(" Back: %s\n", print_if_not_empty(Back[x][y]));
220 printf(" Store: %s\n", print_if_not_empty(Store[x][y]));
221 printf(" Store2: %s\n", print_if_not_empty(Store2[x][y]));
222 printf(" StorePlayer: %s\n", print_if_not_empty(StorePlayer[x][y]));
223 printf(" MovPos: %d\n", MovPos[x][y]);
224 printf(" MovDir: %d\n", MovDir[x][y]);
225 printf(" MovDelay: %d\n", MovDelay[x][y]);
226 printf(" ChangeDelay: %d\n", ChangeDelay[x][y]);
227 printf(" CustomValue: %d\n", CustomValue[x][y]);
228 printf(" GfxElement: %d\n", GfxElement[x][y]);
229 printf(" GfxAction: %d\n", GfxAction[x][y]);
230 printf(" GfxFrame: %d\n", GfxFrame[x][y]);
234 void SetDrawtoField(int mode)
236 if (mode == DRAW_FIELDBUFFER)
242 BX2 = SCR_FIELDX + 1;
243 BY2 = SCR_FIELDY + 1;
245 drawto_field = fieldbuffer;
247 else /* DRAW_BACKBUFFER */
253 BX2 = SCR_FIELDX - 1;
254 BY2 = SCR_FIELDY - 1;
256 drawto_field = backbuffer;
260 static void RedrawPlayfield_RND()
262 if (game.envelope_active)
265 DrawLevel(REDRAW_ALL);
269 void RedrawPlayfield()
271 if (game_status != GAME_MODE_PLAYING)
274 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
275 RedrawPlayfield_EM(TRUE);
276 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
277 RedrawPlayfield_SP(TRUE);
278 else if (level.game_engine_type == GAME_ENGINE_TYPE_RND)
279 RedrawPlayfield_RND();
281 BlitScreenToBitmap(backbuffer);
283 BlitBitmap(drawto, window, gfx.sx, gfx.sy, gfx.sxsize, gfx.sysize,
287 void DrawMaskedBorder_Rect(int x, int y, int width, int height)
289 Bitmap *bitmap = graphic_info[IMG_GLOBAL_BORDER].bitmap;
291 BlitBitmapMasked(bitmap, backbuffer, x, y, width, height, x, y);
294 void DrawMaskedBorder_FIELD()
296 if (global.border_status >= GAME_MODE_TITLE &&
297 global.border_status <= GAME_MODE_PLAYING &&
298 border.draw_masked[global.border_status])
299 DrawMaskedBorder_Rect(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
302 void DrawMaskedBorder_DOOR_1()
304 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
305 (global.border_status != GAME_MODE_EDITOR ||
306 border.draw_masked[GFX_SPECIAL_ARG_EDITOR]))
307 DrawMaskedBorder_Rect(DX, DY, DXSIZE, DYSIZE);
310 void DrawMaskedBorder_DOOR_2()
312 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
313 global.border_status != GAME_MODE_EDITOR)
314 DrawMaskedBorder_Rect(VX, VY, VXSIZE, VYSIZE);
317 void DrawMaskedBorder_DOOR_3()
319 /* currently not available */
322 void DrawMaskedBorder_ALL()
324 DrawMaskedBorder_FIELD();
325 DrawMaskedBorder_DOOR_1();
326 DrawMaskedBorder_DOOR_2();
327 DrawMaskedBorder_DOOR_3();
330 void DrawMaskedBorder(int redraw_mask)
332 /* never draw masked screen borders on borderless screens */
333 if (effectiveGameStatus() == GAME_MODE_LOADING ||
334 effectiveGameStatus() == GAME_MODE_TITLE)
337 if (redraw_mask & REDRAW_ALL)
338 DrawMaskedBorder_ALL();
341 if (redraw_mask & REDRAW_FIELD)
342 DrawMaskedBorder_FIELD();
343 if (redraw_mask & REDRAW_DOOR_1)
344 DrawMaskedBorder_DOOR_1();
345 if (redraw_mask & REDRAW_DOOR_2)
346 DrawMaskedBorder_DOOR_2();
347 if (redraw_mask & REDRAW_DOOR_3)
348 DrawMaskedBorder_DOOR_3();
352 void BlitScreenToBitmap_RND(Bitmap *target_bitmap)
354 int fx = FX, fy = FY;
355 int full_lev_fieldx = lev_fieldx + (BorderElement != EL_EMPTY ? 2 : 0);
356 int full_lev_fieldy = lev_fieldy + (BorderElement != EL_EMPTY ? 2 : 0);
358 int dx = (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
359 int dy = (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
360 int dx_var = dx * TILESIZE_VAR / TILESIZE;
361 int dy_var = dy * TILESIZE_VAR / TILESIZE;
364 ffx = (scroll_x - SBX_Left) * TILEX_VAR + dx_var;
365 ffy = (scroll_y - SBY_Upper) * TILEY_VAR + dy_var;
367 if (EVEN(SCR_FIELDX))
369 if (ffx < SBX_Right * TILEX_VAR + TILEX_VAR / 2 + TILEX_VAR)
370 fx += dx_var - MIN(ffx, TILEX_VAR / 2) + TILEX_VAR;
372 fx += (dx_var > 0 ? TILEX_VAR : 0);
379 if (EVEN(SCR_FIELDY))
381 if (ffy < SBY_Lower * TILEY_VAR + TILEY_VAR / 2 + TILEY_VAR)
382 fy += dy_var - MIN(ffy, TILEY_VAR / 2) + TILEY_VAR;
384 fy += (dy_var > 0 ? TILEY_VAR : 0);
391 if (full_lev_fieldx <= SCR_FIELDX)
393 if (EVEN(SCR_FIELDX))
394 fx = 2 * TILEX_VAR - (ODD(lev_fieldx) ? TILEX_VAR / 2 : 0);
396 fx = 2 * TILEX_VAR - (EVEN(lev_fieldx) ? TILEX_VAR / 2 : 0);
399 if (full_lev_fieldy <= SCR_FIELDY)
401 if (EVEN(SCR_FIELDY))
402 fy = 2 * TILEY_VAR - (ODD(lev_fieldy) ? TILEY_VAR / 2 : 0);
404 fy = 2 * TILEY_VAR - (EVEN(lev_fieldy) ? TILEY_VAR / 2 : 0);
407 BlitBitmap(drawto_field, target_bitmap, fx, fy, SXSIZE, SYSIZE, SX, SY);
410 void BlitScreenToBitmap(Bitmap *target_bitmap)
412 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
413 BlitScreenToBitmap_EM(target_bitmap);
414 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
415 BlitScreenToBitmap_SP(target_bitmap);
416 else if (level.game_engine_type == GAME_ENGINE_TYPE_RND)
417 BlitScreenToBitmap_RND(target_bitmap);
419 redraw_mask |= REDRAW_FIELD;
422 void DrawFramesPerSecond()
425 int font_nr = FONT_TEXT_2;
426 int font_width = getFontWidth(font_nr);
428 sprintf(text, "%04.1f fps", global.frames_per_second);
430 DrawTextExt(backbuffer, WIN_XSIZE - font_width * strlen(text), 0, text,
431 font_nr, BLIT_OPAQUE);
436 if (redraw_mask == REDRAW_NONE)
439 // draw masked border to all viewports, if defined
440 DrawMaskedBorder(redraw_mask);
442 // draw frames per second (only if debug mode is enabled)
443 if (redraw_mask & REDRAW_FPS)
444 DrawFramesPerSecond();
446 // redraw complete window if both playfield and (some) doors need redraw
447 if (redraw_mask & REDRAW_FIELD && redraw_mask & REDRAW_DOORS)
448 redraw_mask = REDRAW_ALL;
450 /* although redrawing the whole window would be fine for normal gameplay,
451 being able to only redraw the playfield is required for deactivating
452 certain drawing areas (mainly playfield) to work, which is needed for
453 warp-forward to be fast enough (by skipping redraw of most frames) */
455 if (redraw_mask & REDRAW_ALL)
457 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
459 else if (redraw_mask & REDRAW_FIELD)
461 BlitBitmap(backbuffer, window,
462 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
464 else if (redraw_mask & REDRAW_DOORS)
466 if (redraw_mask & REDRAW_DOOR_1)
467 BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
469 if (redraw_mask & REDRAW_DOOR_2)
470 BlitBitmap(backbuffer, window, VX, VY, VXSIZE, VYSIZE, VX, VY);
472 if (redraw_mask & REDRAW_DOOR_3)
473 BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
476 redraw_mask = REDRAW_NONE;
479 static void FadeCrossSaveBackbuffer()
481 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
484 static void FadeExt(int fade_mask, int fade_mode, int fade_type)
486 static int fade_type_skip = FADE_TYPE_NONE;
487 void (*draw_border_function)(void) = NULL;
488 Bitmap *bitmap = (fade_mode & FADE_TYPE_TRANSFORM ? bitmap_db_cross : NULL);
489 int x, y, width, height;
490 int fade_delay, post_delay;
492 if (fade_type == FADE_TYPE_FADE_OUT)
494 if (fade_type_skip != FADE_TYPE_NONE)
496 /* skip all fade operations until specified fade operation */
497 if (fade_type & fade_type_skip)
498 fade_type_skip = FADE_TYPE_NONE;
503 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
505 FadeCrossSaveBackbuffer();
511 redraw_mask |= fade_mask;
513 if (fade_type == FADE_TYPE_SKIP)
515 fade_type_skip = fade_mode;
520 fade_delay = fading.fade_delay;
521 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
523 if (fade_type_skip != FADE_TYPE_NONE)
525 /* skip all fade operations until specified fade operation */
526 if (fade_type & fade_type_skip)
527 fade_type_skip = FADE_TYPE_NONE;
532 if (global.autoplay_leveldir)
537 if (fade_mask == REDRAW_FIELD)
542 height = FULL_SYSIZE;
544 if (border.draw_masked_when_fading)
545 draw_border_function = DrawMaskedBorder_FIELD; /* update when fading */
547 DrawMaskedBorder_FIELD(); /* draw once */
549 else /* REDRAW_ALL */
557 if (!setup.fade_screens ||
559 fading.fade_mode == FADE_MODE_NONE)
561 if (fade_mode == FADE_MODE_FADE_OUT)
564 BlitBitmap(backbuffer, window, x, y, width, height, x, y);
566 redraw_mask &= ~fade_mask;
571 FadeRectangle(bitmap, x, y, width, height, fade_mode, fade_delay, post_delay,
572 draw_border_function);
574 redraw_mask &= ~fade_mask;
577 void FadeIn(int fade_mask)
579 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
580 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_IN);
582 FadeExt(fade_mask, FADE_MODE_FADE_IN, FADE_TYPE_FADE_IN);
585 void FadeOut(int fade_mask)
587 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
588 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_OUT);
590 FadeExt(fade_mask, FADE_MODE_FADE_OUT, FADE_TYPE_FADE_OUT);
592 global.border_status = game_status;
595 static void FadeSetLeaveNext(struct TitleFadingInfo fading_leave, boolean set)
597 static struct TitleFadingInfo fading_leave_stored;
600 fading_leave_stored = fading_leave;
602 fading = fading_leave_stored;
605 void FadeSetEnterMenu()
607 fading = menu.enter_menu;
609 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
612 void FadeSetLeaveMenu()
614 fading = menu.leave_menu;
616 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
619 void FadeSetEnterScreen()
621 fading = menu.enter_screen[game_status];
623 FadeSetLeaveNext(menu.leave_screen[game_status], TRUE); /* store */
626 void FadeSetNextScreen()
628 fading = menu.next_screen;
630 // (do not overwrite fade mode set by FadeSetEnterScreen)
631 // FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
634 void FadeSetLeaveScreen()
636 FadeSetLeaveNext(menu.leave_screen[game_status], FALSE); /* recall */
639 void FadeSetFromType(int type)
641 if (type & TYPE_ENTER_SCREEN)
642 FadeSetEnterScreen();
643 else if (type & TYPE_ENTER)
645 else if (type & TYPE_LEAVE)
649 void FadeSetDisabled()
651 static struct TitleFadingInfo fading_none = { FADE_MODE_NONE, -1, -1, -1 };
653 fading = fading_none;
656 void FadeSkipNextFadeIn()
658 FadeExt(0, FADE_MODE_SKIP_FADE_IN, FADE_TYPE_SKIP);
661 void FadeSkipNextFadeOut()
663 FadeExt(0, FADE_MODE_SKIP_FADE_OUT, FADE_TYPE_SKIP);
666 void SetWindowBackgroundImageIfDefined(int graphic)
668 if (graphic_info[graphic].bitmap)
669 SetWindowBackgroundBitmap(graphic_info[graphic].bitmap);
672 void SetMainBackgroundImageIfDefined(int graphic)
674 if (graphic_info[graphic].bitmap)
675 SetMainBackgroundBitmap(graphic_info[graphic].bitmap);
678 void SetDoorBackgroundImageIfDefined(int graphic)
680 if (graphic_info[graphic].bitmap)
681 SetDoorBackgroundBitmap(graphic_info[graphic].bitmap);
684 void SetWindowBackgroundImage(int graphic)
686 SetWindowBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
687 graphic_info[graphic].bitmap ?
688 graphic_info[graphic].bitmap :
689 graphic_info[IMG_BACKGROUND].bitmap);
692 void SetMainBackgroundImage(int graphic)
694 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
695 graphic_info[graphic].bitmap ?
696 graphic_info[graphic].bitmap :
697 graphic_info[IMG_BACKGROUND].bitmap);
700 void SetDoorBackgroundImage(int graphic)
702 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
703 graphic_info[graphic].bitmap ?
704 graphic_info[graphic].bitmap :
705 graphic_info[IMG_BACKGROUND].bitmap);
708 void SetPanelBackground()
710 struct GraphicInfo *gfx = &graphic_info[IMG_BACKGROUND_PANEL];
712 BlitBitmapTiled(gfx->bitmap, bitmap_db_panel, gfx->src_x, gfx->src_y,
713 gfx->width, gfx->height, 0, 0, DXSIZE, DYSIZE);
715 SetDoorBackgroundBitmap(bitmap_db_panel);
718 void DrawBackground(int x, int y, int width, int height)
720 /* "drawto" might still point to playfield buffer here (hall of fame) */
721 ClearRectangleOnBackground(backbuffer, x, y, width, height);
723 if (IN_GFX_FIELD_FULL(x, y))
724 redraw_mask |= REDRAW_FIELD;
725 else if (IN_GFX_DOOR_1(x, y))
726 redraw_mask |= REDRAW_DOOR_1;
727 else if (IN_GFX_DOOR_2(x, y))
728 redraw_mask |= REDRAW_DOOR_2;
729 else if (IN_GFX_DOOR_3(x, y))
730 redraw_mask |= REDRAW_DOOR_3;
733 void DrawBackgroundForFont(int x, int y, int width, int height, int font_nr)
735 struct FontBitmapInfo *font = getFontBitmapInfo(font_nr);
737 if (font->bitmap == NULL)
740 DrawBackground(x, y, width, height);
743 void DrawBackgroundForGraphic(int x, int y, int width, int height, int graphic)
745 struct GraphicInfo *g = &graphic_info[graphic];
747 if (g->bitmap == NULL)
750 DrawBackground(x, y, width, height);
755 /* !!! "drawto" might still point to playfield buffer here (see above) !!! */
756 /* (when entering hall of fame after playing) */
757 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
759 /* !!! maybe this should be done before clearing the background !!! */
760 if (game_status == GAME_MODE_PLAYING)
762 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
763 SetDrawtoField(DRAW_FIELDBUFFER);
767 SetDrawtoField(DRAW_BACKBUFFER);
771 void MarkTileDirty(int x, int y)
773 redraw_mask |= REDRAW_FIELD;
776 void SetBorderElement()
780 BorderElement = EL_EMPTY;
782 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
784 for (x = 0; x < lev_fieldx; x++)
786 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
787 BorderElement = EL_STEELWALL;
789 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
795 void FloodFillLevel(int from_x, int from_y, int fill_element,
796 short field[MAX_LEV_FIELDX][MAX_LEV_FIELDY],
797 int max_fieldx, int max_fieldy)
801 static int check[4][2] = { { -1, 0 }, { 0, -1 }, { 1, 0 }, { 0, 1 } };
802 static int safety = 0;
804 /* check if starting field still has the desired content */
805 if (field[from_x][from_y] == fill_element)
810 if (safety > max_fieldx * max_fieldy)
811 Error(ERR_EXIT, "Something went wrong in 'FloodFill()'. Please debug.");
813 old_element = field[from_x][from_y];
814 field[from_x][from_y] = fill_element;
816 for (i = 0; i < 4; i++)
818 x = from_x + check[i][0];
819 y = from_y + check[i][1];
821 if (IN_FIELD(x, y, max_fieldx, max_fieldy) && field[x][y] == old_element)
822 FloodFillLevel(x, y, fill_element, field, max_fieldx, max_fieldy);
828 void SetRandomAnimationValue(int x, int y)
830 gfx.anim_random_frame = GfxRandom[x][y];
833 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
835 /* animation synchronized with global frame counter, not move position */
836 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
837 sync_frame = FrameCounter;
839 return getAnimationFrame(graphic_info[graphic].anim_frames,
840 graphic_info[graphic].anim_delay,
841 graphic_info[graphic].anim_mode,
842 graphic_info[graphic].anim_start_frame,
846 void getSizedGraphicSourceExt(int graphic, int frame, int tilesize,
847 Bitmap **bitmap, int *x, int *y,
848 boolean get_backside)
850 struct GraphicInfo *g = &graphic_info[graphic];
851 Bitmap *src_bitmap = g->bitmap;
852 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
853 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
854 int tilesize_capped = MIN(MAX(1, tilesize), TILESIZE);
856 // if no in-game graphics defined, always use standard graphic size
857 if (g->bitmaps[IMG_BITMAP_GAME] == NULL)
860 if (tilesize == gfx.standard_tile_size)
861 src_bitmap = g->bitmaps[IMG_BITMAP_STANDARD];
862 else if (tilesize == game.tile_size)
863 src_bitmap = g->bitmaps[IMG_BITMAP_GAME];
865 src_bitmap = g->bitmaps[IMG_BITMAP_1x1 - log_2(tilesize_capped)];
867 if (g->offset_y == 0) /* frames are ordered horizontally */
869 int max_width = g->anim_frames_per_line * g->width;
870 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
872 src_x = pos % max_width;
873 src_y = src_y % g->height + pos / max_width * g->height;
875 else if (g->offset_x == 0) /* frames are ordered vertically */
877 int max_height = g->anim_frames_per_line * g->height;
878 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
880 src_x = src_x % g->width + pos / max_height * g->width;
881 src_y = pos % max_height;
883 else /* frames are ordered diagonally */
885 src_x = src_x + frame * g->offset_x;
886 src_y = src_y + frame * g->offset_y;
889 *bitmap = src_bitmap;
890 *x = src_x * tilesize / TILESIZE;
891 *y = src_y * tilesize / TILESIZE;
894 void getFixedGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
895 int *x, int *y, boolean get_backside)
897 getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y,
901 void getSizedGraphicSource(int graphic, int frame, int tilesize,
902 Bitmap **bitmap, int *x, int *y)
904 getSizedGraphicSourceExt(graphic, frame, tilesize, bitmap, x, y, FALSE);
907 void getFixedGraphicSource(int graphic, int frame,
908 Bitmap **bitmap, int *x, int *y)
910 getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y, FALSE);
913 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
915 getSizedGraphicSource(graphic, 0, MINI_TILESIZE, bitmap, x, y);
918 inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
919 int *x, int *y, boolean get_backside)
921 struct GraphicInfo *g = &graphic_info[graphic];
922 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
923 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
925 if (TILESIZE_VAR != TILESIZE)
926 return getSizedGraphicSourceExt(graphic, frame, TILESIZE_VAR, bitmap, x, y,
931 if (g->offset_y == 0) /* frames are ordered horizontally */
933 int max_width = g->anim_frames_per_line * g->width;
934 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
936 *x = pos % max_width;
937 *y = src_y % g->height + pos / max_width * g->height;
939 else if (g->offset_x == 0) /* frames are ordered vertically */
941 int max_height = g->anim_frames_per_line * g->height;
942 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
944 *x = src_x % g->width + pos / max_height * g->width;
945 *y = pos % max_height;
947 else /* frames are ordered diagonally */
949 *x = src_x + frame * g->offset_x;
950 *y = src_y + frame * g->offset_y;
954 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
956 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
959 void DrawGraphic(int x, int y, int graphic, int frame)
962 if (!IN_SCR_FIELD(x, y))
964 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
965 printf("DrawGraphic(): This should never happen!\n");
970 DrawGraphicExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR, graphic,
976 void DrawFixedGraphic(int x, int y, int graphic, int frame)
979 if (!IN_SCR_FIELD(x, y))
981 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
982 printf("DrawGraphic(): This should never happen!\n");
987 DrawFixedGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic,
992 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
998 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1000 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX_VAR, TILEY_VAR, x, y);
1003 void DrawFixedGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1009 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1010 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
1013 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
1016 if (!IN_SCR_FIELD(x, y))
1018 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1019 printf("DrawGraphicThruMask(): This should never happen!\n");
1024 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
1027 MarkTileDirty(x, y);
1030 void DrawFixedGraphicThruMask(int x, int y, int graphic, int frame)
1033 if (!IN_SCR_FIELD(x, y))
1035 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1036 printf("DrawGraphicThruMask(): This should never happen!\n");
1041 DrawFixedGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
1043 MarkTileDirty(x, y);
1046 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
1052 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1054 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX_VAR, TILEY_VAR,
1058 void DrawFixedGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y,
1059 int graphic, int frame)
1061 struct GraphicInfo *g = &graphic_info[graphic];
1065 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1067 BlitBitmapMasked(src_bitmap, d, src_x, src_y, g->width, g->height,
1071 void DrawSizedGraphic(int x, int y, int graphic, int frame, int tilesize)
1073 DrawSizedGraphicExt(drawto, SX + x * tilesize, SY + y * tilesize, graphic,
1075 MarkTileDirty(x / tilesize, y / tilesize);
1078 void DrawSizedGraphicExt(DrawBuffer *d, int x, int y, int graphic, int frame,
1084 getSizedGraphicSource(graphic, frame, tilesize, &src_bitmap, &src_x, &src_y);
1085 BlitBitmap(src_bitmap, d, src_x, src_y, tilesize, tilesize, x, y);
1088 void DrawMiniGraphic(int x, int y, int graphic)
1090 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
1091 MarkTileDirty(x / 2, y / 2);
1094 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
1099 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1100 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
1103 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
1104 int graphic, int frame,
1105 int cut_mode, int mask_mode)
1110 int width = TILEX, height = TILEY;
1113 if (dx || dy) /* shifted graphic */
1115 if (x < BX1) /* object enters playfield from the left */
1122 else if (x > BX2) /* object enters playfield from the right */
1128 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
1134 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
1136 else if (dx) /* general horizontal movement */
1137 MarkTileDirty(x + SIGN(dx), y);
1139 if (y < BY1) /* object enters playfield from the top */
1141 if (cut_mode==CUT_BELOW) /* object completely above top border */
1149 else if (y > BY2) /* object enters playfield from the bottom */
1155 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
1161 else if (dy > 0 && cut_mode == CUT_ABOVE)
1163 if (y == BY2) /* object completely above bottom border */
1169 MarkTileDirty(x, y + 1);
1170 } /* object leaves playfield to the bottom */
1171 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1173 else if (dy) /* general vertical movement */
1174 MarkTileDirty(x, y + SIGN(dy));
1178 if (!IN_SCR_FIELD(x, y))
1180 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1181 printf("DrawGraphicShifted(): This should never happen!\n");
1186 width = width * TILESIZE_VAR / TILESIZE;
1187 height = height * TILESIZE_VAR / TILESIZE;
1188 cx = cx * TILESIZE_VAR / TILESIZE;
1189 cy = cy * TILESIZE_VAR / TILESIZE;
1190 dx = dx * TILESIZE_VAR / TILESIZE;
1191 dy = dy * TILESIZE_VAR / TILESIZE;
1193 if (width > 0 && height > 0)
1195 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1200 dst_x = FX + x * TILEX_VAR + dx;
1201 dst_y = FY + y * TILEY_VAR + dy;
1203 if (mask_mode == USE_MASKING)
1204 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1207 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1210 MarkTileDirty(x, y);
1214 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
1215 int graphic, int frame,
1216 int cut_mode, int mask_mode)
1221 int width = TILEX_VAR, height = TILEY_VAR;
1224 int x2 = x + SIGN(dx);
1225 int y2 = y + SIGN(dy);
1227 /* movement with two-tile animations must be sync'ed with movement position,
1228 not with current GfxFrame (which can be higher when using slow movement) */
1229 int anim_pos = (dx ? ABS(dx) : ABS(dy));
1230 int anim_frames = graphic_info[graphic].anim_frames;
1232 /* (we also need anim_delay here for movement animations with less frames) */
1233 int anim_delay = graphic_info[graphic].anim_delay;
1234 int sync_frame = anim_pos * anim_frames * anim_delay / TILESIZE;
1236 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
1237 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
1239 /* re-calculate animation frame for two-tile movement animation */
1240 frame = getGraphicAnimationFrame(graphic, sync_frame);
1242 /* check if movement start graphic inside screen area and should be drawn */
1243 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
1245 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
1247 dst_x = FX + x1 * TILEX_VAR;
1248 dst_y = FY + y1 * TILEY_VAR;
1250 if (mask_mode == USE_MASKING)
1251 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1254 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1257 MarkTileDirty(x1, y1);
1260 /* check if movement end graphic inside screen area and should be drawn */
1261 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
1263 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
1265 dst_x = FX + x2 * TILEX_VAR;
1266 dst_y = FY + y2 * TILEY_VAR;
1268 if (mask_mode == USE_MASKING)
1269 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1272 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1275 MarkTileDirty(x2, y2);
1279 static void DrawGraphicShifted(int x, int y, int dx, int dy,
1280 int graphic, int frame,
1281 int cut_mode, int mask_mode)
1285 DrawGraphic(x, y, graphic, frame);
1290 if (graphic_info[graphic].double_movement) /* EM style movement images */
1291 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1293 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1296 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1297 int frame, int cut_mode)
1299 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
1302 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1303 int cut_mode, int mask_mode)
1305 int lx = LEVELX(x), ly = LEVELY(y);
1309 if (IN_LEV_FIELD(lx, ly))
1311 SetRandomAnimationValue(lx, ly);
1313 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
1314 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1316 /* do not use double (EM style) movement graphic when not moving */
1317 if (graphic_info[graphic].double_movement && !dx && !dy)
1319 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
1320 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1323 else /* border element */
1325 graphic = el2img(element);
1326 frame = getGraphicAnimationFrame(graphic, -1);
1329 if (element == EL_EXPANDABLE_WALL)
1331 boolean left_stopped = FALSE, right_stopped = FALSE;
1333 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1334 left_stopped = TRUE;
1335 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1336 right_stopped = TRUE;
1338 if (left_stopped && right_stopped)
1340 else if (left_stopped)
1342 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1343 frame = graphic_info[graphic].anim_frames - 1;
1345 else if (right_stopped)
1347 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1348 frame = graphic_info[graphic].anim_frames - 1;
1353 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1354 else if (mask_mode == USE_MASKING)
1355 DrawGraphicThruMask(x, y, graphic, frame);
1357 DrawGraphic(x, y, graphic, frame);
1360 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1361 int cut_mode, int mask_mode)
1363 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1364 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1365 cut_mode, mask_mode);
1368 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1371 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1374 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1377 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1380 void DrawLevelElementThruMask(int x, int y, int element)
1382 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1385 void DrawLevelFieldThruMask(int x, int y)
1387 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1390 /* !!! implementation of quicksand is totally broken !!! */
1391 #define IS_CRUMBLED_TILE(x, y, e) \
1392 (GFX_CRUMBLED(e) && (!IN_LEV_FIELD(x, y) || \
1393 !IS_MOVING(x, y) || \
1394 (e) == EL_QUICKSAND_EMPTYING || \
1395 (e) == EL_QUICKSAND_FAST_EMPTYING))
1397 static void DrawLevelFieldCrumbledInnerCorners(int x, int y, int dx, int dy,
1402 int width, height, cx, cy;
1403 int sx = SCREENX(x), sy = SCREENY(y);
1404 int crumbled_border_size = graphic_info[graphic].border_size;
1407 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1409 for (i = 1; i < 4; i++)
1411 int dxx = (i & 1 ? dx : 0);
1412 int dyy = (i & 2 ? dy : 0);
1415 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1418 /* check if neighbour field is of same crumble type */
1419 boolean same = (IS_CRUMBLED_TILE(xx, yy, element) &&
1420 graphic_info[graphic].class ==
1421 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class);
1423 /* return if check prevents inner corner */
1424 if (same == (dxx == dx && dyy == dy))
1428 /* if we reach this point, we have an inner corner */
1430 getGraphicSource(graphic, 1, &src_bitmap, &src_x, &src_y);
1432 width = crumbled_border_size * TILESIZE_VAR / TILESIZE;
1433 height = crumbled_border_size * TILESIZE_VAR / TILESIZE;
1434 cx = (dx > 0 ? TILESIZE_VAR - width : 0);
1435 cy = (dy > 0 ? TILESIZE_VAR - height : 0);
1437 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1438 width, height, FX + sx * TILEX_VAR + cx, FY + sy * TILEY_VAR + cy);
1441 static void DrawLevelFieldCrumbledBorders(int x, int y, int graphic, int frame,
1446 int width, height, bx, by, cx, cy;
1447 int sx = SCREENX(x), sy = SCREENY(y);
1448 int crumbled_border_size = graphic_info[graphic].border_size;
1449 int crumbled_border_size_var = crumbled_border_size * TILESIZE_VAR / TILESIZE;
1450 int crumbled_border_pos_var = TILESIZE_VAR - crumbled_border_size_var;
1453 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1455 /* draw simple, sloppy, non-corner-accurate crumbled border */
1457 width = (dir == 1 || dir == 2 ? crumbled_border_size_var : TILESIZE_VAR);
1458 height = (dir == 0 || dir == 3 ? crumbled_border_size_var : TILESIZE_VAR);
1459 cx = (dir == 2 ? crumbled_border_pos_var : 0);
1460 cy = (dir == 3 ? crumbled_border_pos_var : 0);
1462 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy, width, height,
1463 FX + sx * TILEX_VAR + cx,
1464 FY + sy * TILEY_VAR + cy);
1466 /* (remaining middle border part must be at least as big as corner part) */
1467 if (!(graphic_info[graphic].style & STYLE_ACCURATE_BORDERS) ||
1468 crumbled_border_size >= TILESIZE / 3)
1471 /* correct corners of crumbled border, if needed */
1473 for (i = -1; i <= 1; i += 2)
1475 int xx = x + (dir == 0 || dir == 3 ? i : 0);
1476 int yy = y + (dir == 1 || dir == 2 ? i : 0);
1477 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1480 /* check if neighbour field is of same crumble type */
1481 if (IS_CRUMBLED_TILE(xx, yy, element) &&
1482 graphic_info[graphic].class ==
1483 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1485 /* no crumbled corner, but continued crumbled border */
1487 int c1 = (dir == 2 || dir == 3 ? crumbled_border_pos_var : 0);
1488 int c2 = (i == 1 ? crumbled_border_pos_var : 0);
1489 int b1 = (i == 1 ? crumbled_border_size_var :
1490 TILESIZE_VAR - 2 * crumbled_border_size_var);
1492 width = crumbled_border_size_var;
1493 height = crumbled_border_size_var;
1495 if (dir == 1 || dir == 2)
1510 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
1512 FX + sx * TILEX_VAR + cx,
1513 FY + sy * TILEY_VAR + cy);
1518 static void DrawLevelFieldCrumbledExt(int x, int y, int graphic, int frame)
1520 int sx = SCREENX(x), sy = SCREENY(y);
1523 static int xy[4][2] =
1531 if (!IN_LEV_FIELD(x, y))
1534 element = TILE_GFX_ELEMENT(x, y);
1536 /* crumble field itself */
1537 if (IS_CRUMBLED_TILE(x, y, element))
1539 if (!IN_SCR_FIELD(sx, sy))
1542 for (i = 0; i < 4; i++)
1544 int xx = x + xy[i][0];
1545 int yy = y + xy[i][1];
1547 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1550 /* check if neighbour field is of same crumble type */
1551 if (IS_CRUMBLED_TILE(xx, yy, element) &&
1552 graphic_info[graphic].class ==
1553 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1556 DrawLevelFieldCrumbledBorders(x, y, graphic, frame, i);
1559 if ((graphic_info[graphic].style & STYLE_INNER_CORNERS) &&
1560 graphic_info[graphic].anim_frames == 2)
1562 for (i = 0; i < 4; i++)
1564 int dx = (i & 1 ? +1 : -1);
1565 int dy = (i & 2 ? +1 : -1);
1567 DrawLevelFieldCrumbledInnerCorners(x, y, dx, dy, graphic);
1571 MarkTileDirty(sx, sy);
1573 else /* center field not crumbled -- crumble neighbour fields */
1575 for (i = 0; i < 4; i++)
1577 int xx = x + xy[i][0];
1578 int yy = y + xy[i][1];
1579 int sxx = sx + xy[i][0];
1580 int syy = sy + xy[i][1];
1582 if (!IN_LEV_FIELD(xx, yy) ||
1583 !IN_SCR_FIELD(sxx, syy))
1586 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
1589 element = TILE_GFX_ELEMENT(xx, yy);
1591 if (!IS_CRUMBLED_TILE(xx, yy, element))
1594 graphic = el_act2crm(element, ACTION_DEFAULT);
1596 DrawLevelFieldCrumbledBorders(xx, yy, graphic, 0, 3 - i);
1598 MarkTileDirty(sxx, syy);
1603 void DrawLevelFieldCrumbled(int x, int y)
1607 if (!IN_LEV_FIELD(x, y))
1610 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1611 GfxElement[x][y] != EL_UNDEFINED &&
1612 GFX_CRUMBLED(GfxElement[x][y]))
1614 DrawLevelFieldCrumbledDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
1619 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
1621 DrawLevelFieldCrumbledExt(x, y, graphic, 0);
1624 void DrawLevelFieldCrumbledDigging(int x, int y, int direction,
1627 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1628 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1629 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1630 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1631 int sx = SCREENX(x), sy = SCREENY(y);
1633 DrawGraphic(sx, sy, graphic1, frame1);
1634 DrawLevelFieldCrumbledExt(x, y, graphic2, frame2);
1637 void DrawLevelFieldCrumbledNeighbours(int x, int y)
1639 int sx = SCREENX(x), sy = SCREENY(y);
1640 static int xy[4][2] =
1649 for (i = 0; i < 4; i++)
1651 int xx = x + xy[i][0];
1652 int yy = y + xy[i][1];
1653 int sxx = sx + xy[i][0];
1654 int syy = sy + xy[i][1];
1656 if (!IN_LEV_FIELD(xx, yy) ||
1657 !IN_SCR_FIELD(sxx, syy) ||
1658 !GFX_CRUMBLED(Feld[xx][yy]) ||
1662 DrawLevelField(xx, yy);
1666 static int getBorderElement(int x, int y)
1670 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1671 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1672 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1673 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1674 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1675 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1676 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1678 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1679 int steel_position = (x == -1 && y == -1 ? 0 :
1680 x == lev_fieldx && y == -1 ? 1 :
1681 x == -1 && y == lev_fieldy ? 2 :
1682 x == lev_fieldx && y == lev_fieldy ? 3 :
1683 x == -1 || x == lev_fieldx ? 4 :
1684 y == -1 || y == lev_fieldy ? 5 : 6);
1686 return border[steel_position][steel_type];
1689 void DrawScreenElement(int x, int y, int element)
1691 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1692 DrawLevelFieldCrumbled(LEVELX(x), LEVELY(y));
1695 void DrawLevelElement(int x, int y, int element)
1697 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1698 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1701 void DrawScreenField(int x, int y)
1703 int lx = LEVELX(x), ly = LEVELY(y);
1704 int element, content;
1706 if (!IN_LEV_FIELD(lx, ly))
1708 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1711 element = getBorderElement(lx, ly);
1713 DrawScreenElement(x, y, element);
1718 element = Feld[lx][ly];
1719 content = Store[lx][ly];
1721 if (IS_MOVING(lx, ly))
1723 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1724 boolean cut_mode = NO_CUTTING;
1726 if (element == EL_QUICKSAND_EMPTYING ||
1727 element == EL_QUICKSAND_FAST_EMPTYING ||
1728 element == EL_MAGIC_WALL_EMPTYING ||
1729 element == EL_BD_MAGIC_WALL_EMPTYING ||
1730 element == EL_DC_MAGIC_WALL_EMPTYING ||
1731 element == EL_AMOEBA_DROPPING)
1732 cut_mode = CUT_ABOVE;
1733 else if (element == EL_QUICKSAND_FILLING ||
1734 element == EL_QUICKSAND_FAST_FILLING ||
1735 element == EL_MAGIC_WALL_FILLING ||
1736 element == EL_BD_MAGIC_WALL_FILLING ||
1737 element == EL_DC_MAGIC_WALL_FILLING)
1738 cut_mode = CUT_BELOW;
1740 if (cut_mode == CUT_ABOVE)
1741 DrawScreenElement(x, y, element);
1743 DrawScreenElement(x, y, EL_EMPTY);
1746 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1747 else if (cut_mode == NO_CUTTING)
1748 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1751 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1753 if (cut_mode == CUT_BELOW &&
1754 IN_LEV_FIELD(lx, ly + 1) && IN_SCR_FIELD(x, y + 1))
1755 DrawLevelElement(lx, ly + 1, element);
1758 if (content == EL_ACID)
1760 int dir = MovDir[lx][ly];
1761 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
1762 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
1764 DrawLevelElementThruMask(newlx, newly, EL_ACID);
1767 else if (IS_BLOCKED(lx, ly))
1772 boolean cut_mode = NO_CUTTING;
1773 int element_old, content_old;
1775 Blocked2Moving(lx, ly, &oldx, &oldy);
1778 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1779 MovDir[oldx][oldy] == MV_RIGHT);
1781 element_old = Feld[oldx][oldy];
1782 content_old = Store[oldx][oldy];
1784 if (element_old == EL_QUICKSAND_EMPTYING ||
1785 element_old == EL_QUICKSAND_FAST_EMPTYING ||
1786 element_old == EL_MAGIC_WALL_EMPTYING ||
1787 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1788 element_old == EL_DC_MAGIC_WALL_EMPTYING ||
1789 element_old == EL_AMOEBA_DROPPING)
1790 cut_mode = CUT_ABOVE;
1792 DrawScreenElement(x, y, EL_EMPTY);
1795 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1797 else if (cut_mode == NO_CUTTING)
1798 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1801 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1804 else if (IS_DRAWABLE(element))
1805 DrawScreenElement(x, y, element);
1807 DrawScreenElement(x, y, EL_EMPTY);
1810 void DrawLevelField(int x, int y)
1812 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1813 DrawScreenField(SCREENX(x), SCREENY(y));
1814 else if (IS_MOVING(x, y))
1818 Moving2Blocked(x, y, &newx, &newy);
1819 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1820 DrawScreenField(SCREENX(newx), SCREENY(newy));
1822 else if (IS_BLOCKED(x, y))
1826 Blocked2Moving(x, y, &oldx, &oldy);
1827 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1828 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1832 void DrawSizedElement(int x, int y, int element, int tilesize)
1836 graphic = el2edimg(element);
1837 DrawSizedGraphic(x, y, graphic, 0, tilesize);
1840 void DrawMiniElement(int x, int y, int element)
1844 graphic = el2edimg(element);
1845 DrawMiniGraphic(x, y, graphic);
1848 void DrawSizedElementOrWall(int sx, int sy, int scroll_x, int scroll_y,
1851 int x = sx + scroll_x, y = sy + scroll_y;
1853 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1854 DrawSizedElement(sx, sy, EL_EMPTY, tilesize);
1855 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1856 DrawSizedElement(sx, sy, Feld[x][y], tilesize);
1858 DrawSizedGraphic(sx, sy, el2edimg(getBorderElement(x, y)), 0, tilesize);
1861 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1863 int x = sx + scroll_x, y = sy + scroll_y;
1865 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1866 DrawMiniElement(sx, sy, EL_EMPTY);
1867 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1868 DrawMiniElement(sx, sy, Feld[x][y]);
1870 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1873 void DrawEnvelopeBackgroundTiles(int graphic, int startx, int starty,
1874 int x, int y, int xsize, int ysize,
1875 int tile_width, int tile_height)
1879 int dst_x = startx + x * tile_width;
1880 int dst_y = starty + y * tile_height;
1881 int width = graphic_info[graphic].width;
1882 int height = graphic_info[graphic].height;
1883 int inner_width_raw = MAX(width - 2 * tile_width, tile_width);
1884 int inner_height_raw = MAX(height - 2 * tile_height, tile_height);
1885 int inner_width = inner_width_raw - (inner_width_raw % tile_width);
1886 int inner_height = inner_height_raw - (inner_height_raw % tile_height);
1887 int inner_sx = (width >= 3 * tile_width ? tile_width : 0);
1888 int inner_sy = (height >= 3 * tile_height ? tile_height : 0);
1889 boolean draw_masked = graphic_info[graphic].draw_masked;
1891 getFixedGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1893 if (src_bitmap == NULL || width < tile_width || height < tile_height)
1895 ClearRectangle(drawto, dst_x, dst_y, tile_width, tile_height);
1899 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - tile_width :
1900 inner_sx + (x - 1) * tile_width % inner_width);
1901 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - tile_height :
1902 inner_sy + (y - 1) * tile_height % inner_height);
1905 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
1908 BlitBitmap(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
1912 void DrawEnvelopeBackground(int graphic, int startx, int starty,
1913 int x, int y, int xsize, int ysize, int font_nr)
1915 int font_width = getFontWidth(font_nr);
1916 int font_height = getFontHeight(font_nr);
1918 DrawEnvelopeBackgroundTiles(graphic, startx, starty, x, y, xsize, ysize,
1919 font_width, font_height);
1922 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
1924 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1925 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1926 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
1927 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1928 boolean no_delay = (tape.warp_forward);
1929 unsigned int anim_delay = 0;
1930 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
1931 int anim_delay_value = (no_delay ? 0 : frame_delay_value) / 2;
1932 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
1933 int font_width = getFontWidth(font_nr);
1934 int font_height = getFontHeight(font_nr);
1935 int max_xsize = level.envelope[envelope_nr].xsize;
1936 int max_ysize = level.envelope[envelope_nr].ysize;
1937 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
1938 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
1939 int xend = max_xsize;
1940 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
1941 int xstep = (xstart < xend ? 1 : 0);
1942 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
1944 int end = MAX(xend - xstart, yend - ystart);
1947 for (i = start; i <= end; i++)
1949 int last_frame = end; // last frame of this "for" loop
1950 int x = xstart + i * xstep;
1951 int y = ystart + i * ystep;
1952 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
1953 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
1954 int sx = SX + (SXSIZE - xsize * font_width) / 2;
1955 int sy = SY + (SYSIZE - ysize * font_height) / 2;
1958 SetDrawtoField(DRAW_FIELDBUFFER);
1960 BlitScreenToBitmap(backbuffer);
1962 SetDrawtoField(DRAW_BACKBUFFER);
1964 for (yy = 0; yy < ysize; yy++)
1965 for (xx = 0; xx < xsize; xx++)
1966 DrawEnvelopeBackground(graphic, sx, sy, xx, yy, xsize, ysize, font_nr);
1968 DrawTextBuffer(sx + font_width, sy + font_height,
1969 level.envelope[envelope_nr].text, font_nr, max_xsize,
1970 xsize - 2, ysize - 2, 0, mask_mode,
1971 level.envelope[envelope_nr].autowrap,
1972 level.envelope[envelope_nr].centered, FALSE);
1974 redraw_mask |= REDRAW_FIELD;
1977 SkipUntilDelayReached(&anim_delay, anim_delay_value, &i, last_frame);
1981 void ShowEnvelope(int envelope_nr)
1983 int element = EL_ENVELOPE_1 + envelope_nr;
1984 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1985 int sound_opening = element_info[element].sound[ACTION_OPENING];
1986 int sound_closing = element_info[element].sound[ACTION_CLOSING];
1987 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1988 boolean no_delay = (tape.warp_forward);
1989 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
1990 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
1991 int anim_mode = graphic_info[graphic].anim_mode;
1992 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
1993 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
1995 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
1997 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
1999 if (anim_mode == ANIM_DEFAULT)
2000 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
2002 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
2005 Delay(wait_delay_value);
2007 WaitForEventToContinue();
2009 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2011 if (anim_mode != ANIM_NONE)
2012 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
2014 if (anim_mode == ANIM_DEFAULT)
2015 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
2017 game.envelope_active = FALSE;
2019 SetDrawtoField(DRAW_FIELDBUFFER);
2021 redraw_mask |= REDRAW_FIELD;
2025 static void setRequestBasePosition(int *x, int *y)
2027 int sx_base, sy_base;
2029 if (request.x != -1)
2030 sx_base = request.x;
2031 else if (request.align == ALIGN_LEFT)
2033 else if (request.align == ALIGN_RIGHT)
2034 sx_base = SX + SXSIZE;
2036 sx_base = SX + SXSIZE / 2;
2038 if (request.y != -1)
2039 sy_base = request.y;
2040 else if (request.valign == VALIGN_TOP)
2042 else if (request.valign == VALIGN_BOTTOM)
2043 sy_base = SY + SYSIZE;
2045 sy_base = SY + SYSIZE / 2;
2051 static void setRequestPositionExt(int *x, int *y, int width, int height,
2052 boolean add_border_size)
2054 int border_size = request.border_size;
2055 int sx_base, sy_base;
2058 setRequestBasePosition(&sx_base, &sy_base);
2060 if (request.align == ALIGN_LEFT)
2062 else if (request.align == ALIGN_RIGHT)
2063 sx = sx_base - width;
2065 sx = sx_base - width / 2;
2067 if (request.valign == VALIGN_TOP)
2069 else if (request.valign == VALIGN_BOTTOM)
2070 sy = sy_base - height;
2072 sy = sy_base - height / 2;
2074 sx = MAX(0, MIN(sx, WIN_XSIZE - width));
2075 sy = MAX(0, MIN(sy, WIN_YSIZE - height));
2077 if (add_border_size)
2087 static void setRequestPosition(int *x, int *y, boolean add_border_size)
2089 setRequestPositionExt(x, y, request.width, request.height, add_border_size);
2092 void DrawEnvelopeRequest(char *text)
2094 char *text_final = text;
2095 char *text_door_style = NULL;
2096 int graphic = IMG_BACKGROUND_REQUEST;
2097 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2098 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2099 int font_nr = FONT_REQUEST;
2100 int font_width = getFontWidth(font_nr);
2101 int font_height = getFontHeight(font_nr);
2102 int border_size = request.border_size;
2103 int line_spacing = request.line_spacing;
2104 int line_height = font_height + line_spacing;
2105 int text_width = request.width - 2 * border_size;
2106 int text_height = request.height - 2 * border_size;
2107 int line_length = text_width / font_width;
2108 int max_lines = text_height / line_height;
2109 int width = request.width;
2110 int height = request.height;
2111 int tile_size = request.step_offset;
2112 int x_steps = width / tile_size;
2113 int y_steps = height / tile_size;
2117 if (request.wrap_single_words)
2119 char *src_text_ptr, *dst_text_ptr;
2121 text_door_style = checked_malloc(2 * strlen(text) + 1);
2123 src_text_ptr = text;
2124 dst_text_ptr = text_door_style;
2126 while (*src_text_ptr)
2128 if (*src_text_ptr == ' ' ||
2129 *src_text_ptr == '?' ||
2130 *src_text_ptr == '!')
2131 *dst_text_ptr++ = '\n';
2133 if (*src_text_ptr != ' ')
2134 *dst_text_ptr++ = *src_text_ptr;
2139 *dst_text_ptr = '\0';
2141 text_final = text_door_style;
2144 setRequestPosition(&sx, &sy, FALSE);
2146 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
2148 for (y = 0; y < y_steps; y++)
2149 for (x = 0; x < x_steps; x++)
2150 DrawEnvelopeBackgroundTiles(graphic, sx, sy,
2151 x, y, x_steps, y_steps,
2152 tile_size, tile_size);
2154 DrawTextBuffer(sx + border_size, sy + border_size, text_final, font_nr,
2155 line_length, -1, max_lines, line_spacing, mask_mode,
2156 request.autowrap, request.centered, FALSE);
2158 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2159 RedrawGadget(tool_gadget[i]);
2161 // store readily prepared envelope request for later use when animating
2162 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2164 if (text_door_style)
2165 free(text_door_style);
2168 void AnimateEnvelopeRequest(int anim_mode, int action)
2170 int graphic = IMG_BACKGROUND_REQUEST;
2171 boolean draw_masked = graphic_info[graphic].draw_masked;
2172 int delay_value_normal = request.step_delay;
2173 int delay_value_fast = delay_value_normal / 2;
2174 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2175 boolean no_delay = (tape.warp_forward);
2176 int delay_value = (ffwd_delay ? delay_value_fast : delay_value_normal);
2177 int anim_delay_value = (no_delay ? 0 : delay_value + 500 * 0) / 2;
2178 unsigned int anim_delay = 0;
2180 int tile_size = request.step_offset;
2181 int max_xsize = request.width / tile_size;
2182 int max_ysize = request.height / tile_size;
2183 int max_xsize_inner = max_xsize - 2;
2184 int max_ysize_inner = max_ysize - 2;
2186 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize_inner : 0);
2187 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize_inner : 0);
2188 int xend = max_xsize_inner;
2189 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize_inner : 0);
2190 int xstep = (xstart < xend ? 1 : 0);
2191 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2193 int end = MAX(xend - xstart, yend - ystart);
2196 if (setup.quick_doors)
2204 if (action == ACTION_OPENING)
2205 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2206 else if (action == ACTION_CLOSING)
2207 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2210 for (i = start; i <= end; i++)
2212 int last_frame = end; // last frame of this "for" loop
2213 int x = xstart + i * xstep;
2214 int y = ystart + i * ystep;
2215 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2216 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2217 int xsize_size_left = (xsize - 1) * tile_size;
2218 int ysize_size_top = (ysize - 1) * tile_size;
2219 int max_xsize_pos = (max_xsize - 1) * tile_size;
2220 int max_ysize_pos = (max_ysize - 1) * tile_size;
2221 int width = xsize * tile_size;
2222 int height = ysize * tile_size;
2227 setRequestPosition(&src_x, &src_y, FALSE);
2228 setRequestPositionExt(&dst_x, &dst_y, width, height, FALSE);
2230 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2232 for (yy = 0; yy < 2; yy++)
2234 for (xx = 0; xx < 2; xx++)
2236 int src_xx = src_x + xx * max_xsize_pos;
2237 int src_yy = src_y + yy * max_ysize_pos;
2238 int dst_xx = dst_x + xx * xsize_size_left;
2239 int dst_yy = dst_y + yy * ysize_size_top;
2240 int xx_size = (xx ? tile_size : xsize_size_left);
2241 int yy_size = (yy ? tile_size : ysize_size_top);
2244 BlitBitmapMasked(bitmap_db_cross, backbuffer,
2245 src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
2247 BlitBitmap(bitmap_db_cross, backbuffer,
2248 src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
2252 redraw_mask |= REDRAW_FIELD;
2257 SkipUntilDelayReached(&anim_delay, anim_delay_value, &i, last_frame);
2261 void ShowEnvelopeRequest(char *text, unsigned int req_state, int action)
2263 int last_game_status = game_status; /* save current game status */
2264 int graphic = IMG_BACKGROUND_REQUEST;
2265 int sound_opening = SND_REQUEST_OPENING;
2266 int sound_closing = SND_REQUEST_CLOSING;
2267 int anim_mode_1 = request.anim_mode; /* (higher priority) */
2268 int anim_mode_2 = graphic_info[graphic].anim_mode; /* (lower priority) */
2269 int anim_mode = (anim_mode_1 != ANIM_DEFAULT ? anim_mode_1 : anim_mode_2);
2270 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2271 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2273 if (game_status == GAME_MODE_PLAYING)
2274 BlitScreenToBitmap(backbuffer);
2276 SetDrawtoField(DRAW_BACKBUFFER);
2278 // SetDrawBackgroundMask(REDRAW_NONE);
2280 if (action == ACTION_OPENING)
2282 BlitBitmap(backbuffer, bitmap_db_store, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2284 if (req_state & REQ_ASK)
2286 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2287 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2289 else if (req_state & REQ_CONFIRM)
2291 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2293 else if (req_state & REQ_PLAYER)
2295 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2296 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2297 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2298 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2301 DrawEnvelopeRequest(text);
2303 if (game_status != GAME_MODE_MAIN)
2307 /* force DOOR font inside door area */
2308 game_status = GAME_MODE_PSEUDO_DOOR;
2310 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
2312 if (action == ACTION_OPENING)
2314 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2316 if (anim_mode == ANIM_DEFAULT)
2317 AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_OPENING);
2319 AnimateEnvelopeRequest(main_anim_mode, ACTION_OPENING);
2323 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2325 if (anim_mode != ANIM_NONE)
2326 AnimateEnvelopeRequest(main_anim_mode, ACTION_CLOSING);
2328 if (anim_mode == ANIM_DEFAULT)
2329 AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_CLOSING);
2332 game.envelope_active = FALSE;
2334 game_status = last_game_status; /* restore current game status */
2336 if (action == ACTION_CLOSING)
2338 if (game_status != GAME_MODE_MAIN)
2341 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2344 // SetDrawBackgroundMask(last_draw_background_mask);
2346 redraw_mask |= REDRAW_FIELD;
2348 if (game_status == GAME_MODE_MAIN)
2353 if (action == ACTION_CLOSING &&
2354 game_status == GAME_MODE_PLAYING &&
2355 level.game_engine_type == GAME_ENGINE_TYPE_RND)
2356 SetDrawtoField(DRAW_FIELDBUFFER);
2359 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
2363 int graphic = el2preimg(element);
2365 getSizedGraphicSource(graphic, 0, tilesize, &src_bitmap, &src_x, &src_y);
2366 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
2369 void DrawLevel(int draw_background_mask)
2373 SetMainBackgroundImage(IMG_BACKGROUND_PLAYING);
2374 SetDrawBackgroundMask(draw_background_mask);
2378 for (x = BX1; x <= BX2; x++)
2379 for (y = BY1; y <= BY2; y++)
2380 DrawScreenField(x, y);
2382 redraw_mask |= REDRAW_FIELD;
2385 void DrawSizedLevel(int size_x, int size_y, int scroll_x, int scroll_y,
2390 for (x = 0; x < size_x; x++)
2391 for (y = 0; y < size_y; y++)
2392 DrawSizedElementOrWall(x, y, scroll_x, scroll_y, tilesize);
2394 redraw_mask |= REDRAW_FIELD;
2397 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
2401 for (x = 0; x < size_x; x++)
2402 for (y = 0; y < size_y; y++)
2403 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
2405 redraw_mask |= REDRAW_FIELD;
2408 static void DrawPreviewLevelPlayfieldExt(int from_x, int from_y)
2410 boolean show_level_border = (BorderElement != EL_EMPTY);
2411 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2412 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2413 int tile_size = preview.tile_size;
2414 int preview_width = preview.xsize * tile_size;
2415 int preview_height = preview.ysize * tile_size;
2416 int real_preview_xsize = MIN(level_xsize, preview.xsize);
2417 int real_preview_ysize = MIN(level_ysize, preview.ysize);
2418 int real_preview_width = real_preview_xsize * tile_size;
2419 int real_preview_height = real_preview_ysize * tile_size;
2420 int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
2421 int dst_y = SY + ALIGNED_YPOS(preview.y, preview_height, preview.valign);
2424 if (!IN_GFX_FIELD_FULL(dst_x, dst_y + preview_height - 1))
2427 DrawBackground(dst_x, dst_y, preview_width, preview_height);
2429 dst_x += (preview_width - real_preview_width) / 2;
2430 dst_y += (preview_height - real_preview_height) / 2;
2432 for (x = 0; x < real_preview_xsize; x++)
2434 for (y = 0; y < real_preview_ysize; y++)
2436 int lx = from_x + x + (show_level_border ? -1 : 0);
2437 int ly = from_y + y + (show_level_border ? -1 : 0);
2438 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
2439 getBorderElement(lx, ly));
2441 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
2442 element, tile_size);
2446 redraw_mask |= REDRAW_FIELD;
2449 #define MICROLABEL_EMPTY 0
2450 #define MICROLABEL_LEVEL_NAME 1
2451 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
2452 #define MICROLABEL_LEVEL_AUTHOR 3
2453 #define MICROLABEL_IMPORTED_FROM_HEAD 4
2454 #define MICROLABEL_IMPORTED_FROM 5
2455 #define MICROLABEL_IMPORTED_BY_HEAD 6
2456 #define MICROLABEL_IMPORTED_BY 7
2458 static int getMaxTextLength(struct TextPosInfo *pos, int font_nr)
2460 int max_text_width = SXSIZE;
2461 int font_width = getFontWidth(font_nr);
2463 if (pos->align == ALIGN_CENTER)
2464 max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
2465 else if (pos->align == ALIGN_RIGHT)
2466 max_text_width = pos->x;
2468 max_text_width = SXSIZE - pos->x;
2470 return max_text_width / font_width;
2473 static void DrawPreviewLevelLabelExt(int mode)
2475 struct TextPosInfo *pos = &menu.main.text.level_info_2;
2476 char label_text[MAX_OUTPUT_LINESIZE + 1];
2477 int max_len_label_text;
2478 int font_nr = pos->font;
2481 if (!IN_GFX_FIELD_FULL(pos->x, pos->y + getFontHeight(pos->font)))
2484 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
2485 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
2486 mode == MICROLABEL_IMPORTED_BY_HEAD)
2487 font_nr = pos->font_alt;
2489 max_len_label_text = getMaxTextLength(pos, font_nr);
2491 if (pos->size != -1)
2492 max_len_label_text = pos->size;
2494 for (i = 0; i < max_len_label_text; i++)
2495 label_text[i] = ' ';
2496 label_text[max_len_label_text] = '\0';
2498 if (strlen(label_text) > 0)
2499 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2502 (mode == MICROLABEL_LEVEL_NAME ? level.name :
2503 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
2504 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
2505 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
2506 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
2507 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
2508 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
2509 max_len_label_text);
2510 label_text[max_len_label_text] = '\0';
2512 if (strlen(label_text) > 0)
2513 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2515 redraw_mask |= REDRAW_FIELD;
2518 static void DrawPreviewLevelExt(boolean restart)
2520 static unsigned int scroll_delay = 0;
2521 static unsigned int label_delay = 0;
2522 static int from_x, from_y, scroll_direction;
2523 static int label_state, label_counter;
2524 unsigned int scroll_delay_value = preview.step_delay;
2525 boolean show_level_border = (BorderElement != EL_EMPTY);
2526 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2527 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2528 int last_game_status = game_status; /* save current game status */
2535 if (preview.anim_mode == ANIM_CENTERED)
2537 if (level_xsize > preview.xsize)
2538 from_x = (level_xsize - preview.xsize) / 2;
2539 if (level_ysize > preview.ysize)
2540 from_y = (level_ysize - preview.ysize) / 2;
2543 from_x += preview.xoffset;
2544 from_y += preview.yoffset;
2546 scroll_direction = MV_RIGHT;
2550 DrawPreviewLevelPlayfieldExt(from_x, from_y);
2551 DrawPreviewLevelLabelExt(label_state);
2553 /* initialize delay counters */
2554 DelayReached(&scroll_delay, 0);
2555 DelayReached(&label_delay, 0);
2557 if (leveldir_current->name)
2559 struct TextPosInfo *pos = &menu.main.text.level_info_1;
2560 char label_text[MAX_OUTPUT_LINESIZE + 1];
2561 int font_nr = pos->font;
2562 int max_len_label_text = getMaxTextLength(pos, font_nr);
2564 if (pos->size != -1)
2565 max_len_label_text = pos->size;
2567 strncpy(label_text, leveldir_current->name, max_len_label_text);
2568 label_text[max_len_label_text] = '\0';
2570 if (IN_GFX_FIELD_FULL(pos->x, pos->y + getFontHeight(pos->font)))
2571 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2574 game_status = last_game_status; /* restore current game status */
2579 /* scroll preview level, if needed */
2580 if (preview.anim_mode != ANIM_NONE &&
2581 (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
2582 DelayReached(&scroll_delay, scroll_delay_value))
2584 switch (scroll_direction)
2589 from_x -= preview.step_offset;
2590 from_x = (from_x < 0 ? 0 : from_x);
2593 scroll_direction = MV_UP;
2597 if (from_x < level_xsize - preview.xsize)
2599 from_x += preview.step_offset;
2600 from_x = (from_x > level_xsize - preview.xsize ?
2601 level_xsize - preview.xsize : from_x);
2604 scroll_direction = MV_DOWN;
2610 from_y -= preview.step_offset;
2611 from_y = (from_y < 0 ? 0 : from_y);
2614 scroll_direction = MV_RIGHT;
2618 if (from_y < level_ysize - preview.ysize)
2620 from_y += preview.step_offset;
2621 from_y = (from_y > level_ysize - preview.ysize ?
2622 level_ysize - preview.ysize : from_y);
2625 scroll_direction = MV_LEFT;
2632 DrawPreviewLevelPlayfieldExt(from_x, from_y);
2635 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
2636 /* redraw micro level label, if needed */
2637 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
2638 !strEqual(level.author, ANONYMOUS_NAME) &&
2639 !strEqual(level.author, leveldir_current->name) &&
2640 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
2642 int max_label_counter = 23;
2644 if (leveldir_current->imported_from != NULL &&
2645 strlen(leveldir_current->imported_from) > 0)
2646 max_label_counter += 14;
2647 if (leveldir_current->imported_by != NULL &&
2648 strlen(leveldir_current->imported_by) > 0)
2649 max_label_counter += 14;
2651 label_counter = (label_counter + 1) % max_label_counter;
2652 label_state = (label_counter >= 0 && label_counter <= 7 ?
2653 MICROLABEL_LEVEL_NAME :
2654 label_counter >= 9 && label_counter <= 12 ?
2655 MICROLABEL_LEVEL_AUTHOR_HEAD :
2656 label_counter >= 14 && label_counter <= 21 ?
2657 MICROLABEL_LEVEL_AUTHOR :
2658 label_counter >= 23 && label_counter <= 26 ?
2659 MICROLABEL_IMPORTED_FROM_HEAD :
2660 label_counter >= 28 && label_counter <= 35 ?
2661 MICROLABEL_IMPORTED_FROM :
2662 label_counter >= 37 && label_counter <= 40 ?
2663 MICROLABEL_IMPORTED_BY_HEAD :
2664 label_counter >= 42 && label_counter <= 49 ?
2665 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
2667 if (leveldir_current->imported_from == NULL &&
2668 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
2669 label_state == MICROLABEL_IMPORTED_FROM))
2670 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
2671 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
2673 DrawPreviewLevelLabelExt(label_state);
2676 game_status = last_game_status; /* restore current game status */
2679 void DrawPreviewLevelInitial()
2681 DrawPreviewLevelExt(TRUE);
2684 void DrawPreviewLevelAnimation()
2686 DrawPreviewLevelExt(FALSE);
2689 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
2690 int graphic, int sync_frame, int mask_mode)
2692 int frame = getGraphicAnimationFrame(graphic, sync_frame);
2694 if (mask_mode == USE_MASKING)
2695 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
2697 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
2700 inline void DrawFixedGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
2701 int graphic, int sync_frame,
2704 int frame = getGraphicAnimationFrame(graphic, sync_frame);
2706 if (mask_mode == USE_MASKING)
2707 DrawFixedGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
2709 DrawFixedGraphicExt(dst_bitmap, x, y, graphic, frame);
2712 inline void DrawGraphicAnimation(int x, int y, int graphic)
2714 int lx = LEVELX(x), ly = LEVELY(y);
2716 if (!IN_SCR_FIELD(x, y))
2719 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
2720 graphic, GfxFrame[lx][ly], NO_MASKING);
2722 MarkTileDirty(x, y);
2725 inline void DrawFixedGraphicAnimation(int x, int y, int graphic)
2727 int lx = LEVELX(x), ly = LEVELY(y);
2729 if (!IN_SCR_FIELD(x, y))
2732 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
2733 graphic, GfxFrame[lx][ly], NO_MASKING);
2734 MarkTileDirty(x, y);
2737 void DrawLevelGraphicAnimation(int x, int y, int graphic)
2739 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2742 void DrawLevelElementAnimation(int x, int y, int element)
2744 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2746 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2749 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
2751 int sx = SCREENX(x), sy = SCREENY(y);
2753 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2756 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2759 DrawGraphicAnimation(sx, sy, graphic);
2762 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
2763 DrawLevelFieldCrumbled(x, y);
2765 if (GFX_CRUMBLED(Feld[x][y]))
2766 DrawLevelFieldCrumbled(x, y);
2770 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
2772 int sx = SCREENX(x), sy = SCREENY(y);
2775 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2778 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2780 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2783 DrawGraphicAnimation(sx, sy, graphic);
2785 if (GFX_CRUMBLED(element))
2786 DrawLevelFieldCrumbled(x, y);
2789 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
2791 if (player->use_murphy)
2793 /* this works only because currently only one player can be "murphy" ... */
2794 static int last_horizontal_dir = MV_LEFT;
2795 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
2797 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2798 last_horizontal_dir = move_dir;
2800 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
2802 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
2804 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
2810 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
2813 static boolean equalGraphics(int graphic1, int graphic2)
2815 struct GraphicInfo *g1 = &graphic_info[graphic1];
2816 struct GraphicInfo *g2 = &graphic_info[graphic2];
2818 return (g1->bitmap == g2->bitmap &&
2819 g1->src_x == g2->src_x &&
2820 g1->src_y == g2->src_y &&
2821 g1->anim_frames == g2->anim_frames &&
2822 g1->anim_delay == g2->anim_delay &&
2823 g1->anim_mode == g2->anim_mode);
2826 void DrawAllPlayers()
2830 for (i = 0; i < MAX_PLAYERS; i++)
2831 if (stored_player[i].active)
2832 DrawPlayer(&stored_player[i]);
2835 void DrawPlayerField(int x, int y)
2837 if (!IS_PLAYER(x, y))
2840 DrawPlayer(PLAYERINFO(x, y));
2843 #define DRAW_PLAYER_OVER_PUSHED_ELEMENT 1
2845 void DrawPlayer(struct PlayerInfo *player)
2847 int jx = player->jx;
2848 int jy = player->jy;
2849 int move_dir = player->MovDir;
2850 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
2851 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
2852 int last_jx = (player->is_moving ? jx - dx : jx);
2853 int last_jy = (player->is_moving ? jy - dy : jy);
2854 int next_jx = jx + dx;
2855 int next_jy = jy + dy;
2856 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
2857 boolean player_is_opaque = FALSE;
2858 int sx = SCREENX(jx), sy = SCREENY(jy);
2859 int sxx = 0, syy = 0;
2860 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
2862 int action = ACTION_DEFAULT;
2863 int last_player_graphic = getPlayerGraphic(player, move_dir);
2864 int last_player_frame = player->Frame;
2867 /* GfxElement[][] is set to the element the player is digging or collecting;
2868 remove also for off-screen player if the player is not moving anymore */
2869 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
2870 GfxElement[jx][jy] = EL_UNDEFINED;
2872 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
2876 if (!IN_LEV_FIELD(jx, jy))
2878 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
2879 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
2880 printf("DrawPlayerField(): This should never happen!\n");
2885 if (element == EL_EXPLOSION)
2888 action = (player->is_pushing ? ACTION_PUSHING :
2889 player->is_digging ? ACTION_DIGGING :
2890 player->is_collecting ? ACTION_COLLECTING :
2891 player->is_moving ? ACTION_MOVING :
2892 player->is_snapping ? ACTION_SNAPPING :
2893 player->is_dropping ? ACTION_DROPPING :
2894 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
2896 if (player->is_waiting)
2897 move_dir = player->dir_waiting;
2899 InitPlayerGfxAnimation(player, action, move_dir);
2901 /* ----------------------------------------------------------------------- */
2902 /* draw things in the field the player is leaving, if needed */
2903 /* ----------------------------------------------------------------------- */
2905 if (player->is_moving)
2907 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
2909 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
2911 if (last_element == EL_DYNAMITE_ACTIVE ||
2912 last_element == EL_EM_DYNAMITE_ACTIVE ||
2913 last_element == EL_SP_DISK_RED_ACTIVE)
2914 DrawDynamite(last_jx, last_jy);
2916 DrawLevelFieldThruMask(last_jx, last_jy);
2918 else if (last_element == EL_DYNAMITE_ACTIVE ||
2919 last_element == EL_EM_DYNAMITE_ACTIVE ||
2920 last_element == EL_SP_DISK_RED_ACTIVE)
2921 DrawDynamite(last_jx, last_jy);
2923 /* !!! this is not enough to prevent flickering of players which are
2924 moving next to each others without a free tile between them -- this
2925 can only be solved by drawing all players layer by layer (first the
2926 background, then the foreground etc.) !!! => TODO */
2927 else if (!IS_PLAYER(last_jx, last_jy))
2928 DrawLevelField(last_jx, last_jy);
2931 DrawLevelField(last_jx, last_jy);
2934 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
2935 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
2938 if (!IN_SCR_FIELD(sx, sy))
2941 /* ----------------------------------------------------------------------- */
2942 /* draw things behind the player, if needed */
2943 /* ----------------------------------------------------------------------- */
2946 DrawLevelElement(jx, jy, Back[jx][jy]);
2947 else if (IS_ACTIVE_BOMB(element))
2948 DrawLevelElement(jx, jy, EL_EMPTY);
2951 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
2953 int old_element = GfxElement[jx][jy];
2954 int old_graphic = el_act_dir2img(old_element, action, move_dir);
2955 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
2957 if (GFX_CRUMBLED(old_element))
2958 DrawLevelFieldCrumbledDigging(jx, jy, move_dir, player->StepFrame);
2960 DrawGraphic(sx, sy, old_graphic, frame);
2962 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
2963 player_is_opaque = TRUE;
2967 GfxElement[jx][jy] = EL_UNDEFINED;
2969 /* make sure that pushed elements are drawn with correct frame rate */
2970 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2972 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
2973 GfxFrame[jx][jy] = player->StepFrame;
2975 DrawLevelField(jx, jy);
2979 #if !DRAW_PLAYER_OVER_PUSHED_ELEMENT
2980 /* ----------------------------------------------------------------------- */
2981 /* draw player himself */
2982 /* ----------------------------------------------------------------------- */
2984 graphic = getPlayerGraphic(player, move_dir);
2986 /* in the case of changed player action or direction, prevent the current
2987 animation frame from being restarted for identical animations */
2988 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
2989 player->Frame = last_player_frame;
2991 frame = getGraphicAnimationFrame(graphic, player->Frame);
2995 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2996 sxx = player->GfxPos;
2998 syy = player->GfxPos;
3001 if (player_is_opaque)
3002 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
3004 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3006 if (SHIELD_ON(player))
3008 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
3009 IMG_SHIELD_NORMAL_ACTIVE);
3010 int frame = getGraphicAnimationFrame(graphic, -1);
3012 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3016 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
3019 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3020 sxx = player->GfxPos;
3022 syy = player->GfxPos;
3026 /* ----------------------------------------------------------------------- */
3027 /* draw things the player is pushing, if needed */
3028 /* ----------------------------------------------------------------------- */
3030 if (player->is_pushing && player->is_moving)
3032 int px = SCREENX(jx), py = SCREENY(jy);
3033 int pxx = (TILEX - ABS(sxx)) * dx;
3034 int pyy = (TILEY - ABS(syy)) * dy;
3035 int gfx_frame = GfxFrame[jx][jy];
3041 if (!IS_MOVING(jx, jy)) /* push movement already finished */
3043 element = Feld[next_jx][next_jy];
3044 gfx_frame = GfxFrame[next_jx][next_jy];
3047 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
3049 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
3050 frame = getGraphicAnimationFrame(graphic, sync_frame);
3052 /* draw background element under pushed element (like the Sokoban field) */
3053 if (game.use_masked_pushing && IS_MOVING(jx, jy))
3055 /* this allows transparent pushing animation over non-black background */
3058 DrawLevelElement(jx, jy, Back[jx][jy]);
3060 DrawLevelElement(jx, jy, EL_EMPTY);
3062 if (Back[next_jx][next_jy])
3063 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3065 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
3067 else if (Back[next_jx][next_jy])
3068 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3071 /* do not draw (EM style) pushing animation when pushing is finished */
3072 /* (two-tile animations usually do not contain start and end frame) */
3073 if (graphic_info[graphic].double_movement && !IS_MOVING(jx, jy))
3074 DrawLevelElement(next_jx, next_jy, Feld[next_jx][next_jy]);
3076 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3078 /* masked drawing is needed for EMC style (double) movement graphics */
3079 /* !!! (ONLY WHEN DRAWING PUSHED ELEMENT OVER THE PLAYER) !!! */
3080 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3084 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
3085 /* ----------------------------------------------------------------------- */
3086 /* draw player himself */
3087 /* ----------------------------------------------------------------------- */
3089 graphic = getPlayerGraphic(player, move_dir);
3091 /* in the case of changed player action or direction, prevent the current
3092 animation frame from being restarted for identical animations */
3093 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
3094 player->Frame = last_player_frame;
3096 frame = getGraphicAnimationFrame(graphic, player->Frame);
3100 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3101 sxx = player->GfxPos;
3103 syy = player->GfxPos;
3106 if (player_is_opaque)
3107 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
3109 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3111 if (SHIELD_ON(player))
3113 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
3114 IMG_SHIELD_NORMAL_ACTIVE);
3115 int frame = getGraphicAnimationFrame(graphic, -1);
3117 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3121 /* ----------------------------------------------------------------------- */
3122 /* draw things in front of player (active dynamite or dynabombs) */
3123 /* ----------------------------------------------------------------------- */
3125 if (IS_ACTIVE_BOMB(element))
3127 graphic = el2img(element);
3128 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
3130 if (game.emulation == EMU_SUPAPLEX)
3131 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
3133 DrawGraphicThruMask(sx, sy, graphic, frame);
3136 if (player_is_moving && last_element == EL_EXPLOSION)
3138 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
3139 GfxElement[last_jx][last_jy] : EL_EMPTY);
3140 int graphic = el_act2img(element, ACTION_EXPLODING);
3141 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
3142 int phase = ExplodePhase[last_jx][last_jy] - 1;
3143 int frame = getGraphicAnimationFrame(graphic, phase - delay);
3146 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
3149 /* ----------------------------------------------------------------------- */
3150 /* draw elements the player is just walking/passing through/under */
3151 /* ----------------------------------------------------------------------- */
3153 if (player_is_moving)
3155 /* handle the field the player is leaving ... */
3156 if (IS_ACCESSIBLE_INSIDE(last_element))
3157 DrawLevelField(last_jx, last_jy);
3158 else if (IS_ACCESSIBLE_UNDER(last_element))
3159 DrawLevelFieldThruMask(last_jx, last_jy);
3162 /* do not redraw accessible elements if the player is just pushing them */
3163 if (!player_is_moving || !player->is_pushing)
3165 /* ... and the field the player is entering */
3166 if (IS_ACCESSIBLE_INSIDE(element))
3167 DrawLevelField(jx, jy);
3168 else if (IS_ACCESSIBLE_UNDER(element))
3169 DrawLevelFieldThruMask(jx, jy);
3172 MarkTileDirty(sx, sy);
3175 /* ------------------------------------------------------------------------- */
3177 void WaitForEventToContinue()
3179 boolean still_wait = TRUE;
3181 /* simulate releasing mouse button over last gadget, if still pressed */
3183 HandleGadgets(-1, -1, 0);
3185 button_status = MB_RELEASED;
3199 case EVENT_BUTTONPRESS:
3200 case EVENT_KEYPRESS:
3204 case EVENT_KEYRELEASE:
3205 ClearPlayerAction();
3209 HandleOtherEvents(&event);
3213 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3220 /* don't eat all CPU time */
3225 #define MAX_REQUEST_LINES 13
3226 #define MAX_REQUEST_LINE_FONT1_LEN 7
3227 #define MAX_REQUEST_LINE_FONT2_LEN 10
3229 static int RequestHandleEvents(unsigned int req_state)
3231 boolean level_solved = (game_status == GAME_MODE_PLAYING &&
3232 local_player->LevelSolved_GameEnd);
3233 int last_game_status = game_status; /* save current game status */
3234 int width = request.width;
3235 int height = request.height;
3239 setRequestPosition(&sx, &sy, FALSE);
3241 button_status = MB_RELEASED;
3243 request_gadget_id = -1;
3250 SetDrawtoField(DRAW_FIELDBUFFER);
3252 HandleGameActions();
3254 SetDrawtoField(DRAW_BACKBUFFER);
3256 if (global.use_envelope_request)
3258 /* copy current state of request area to middle of playfield area */
3259 BlitBitmap(bitmap_db_cross, drawto, sx, sy, width, height, sx, sy);
3267 while (NextValidEvent(&event))
3271 case EVENT_BUTTONPRESS:
3272 case EVENT_BUTTONRELEASE:
3273 case EVENT_MOTIONNOTIFY:
3277 if (event.type == EVENT_MOTIONNOTIFY)
3282 motion_status = TRUE;
3283 mx = ((MotionEvent *) &event)->x;
3284 my = ((MotionEvent *) &event)->y;
3288 motion_status = FALSE;
3289 mx = ((ButtonEvent *) &event)->x;
3290 my = ((ButtonEvent *) &event)->y;
3291 if (event.type == EVENT_BUTTONPRESS)
3292 button_status = ((ButtonEvent *) &event)->button;
3294 button_status = MB_RELEASED;
3297 /* this sets 'request_gadget_id' */
3298 HandleGadgets(mx, my, button_status);
3300 switch (request_gadget_id)
3302 case TOOL_CTRL_ID_YES:
3305 case TOOL_CTRL_ID_NO:
3308 case TOOL_CTRL_ID_CONFIRM:
3309 result = TRUE | FALSE;
3312 case TOOL_CTRL_ID_PLAYER_1:
3315 case TOOL_CTRL_ID_PLAYER_2:
3318 case TOOL_CTRL_ID_PLAYER_3:
3321 case TOOL_CTRL_ID_PLAYER_4:
3332 case EVENT_KEYPRESS:
3333 switch (GetEventKey((KeyEvent *)&event, TRUE))
3336 if (req_state & REQ_CONFIRM)
3341 #if defined(TARGET_SDL2)
3348 #if defined(TARGET_SDL2)
3358 if (req_state & REQ_PLAYER)
3362 case EVENT_KEYRELEASE:
3363 ClearPlayerAction();
3367 HandleOtherEvents(&event);
3372 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3374 int joy = AnyJoystick();
3376 if (joy & JOY_BUTTON_1)
3378 else if (joy & JOY_BUTTON_2)
3384 if (global.use_envelope_request)
3386 /* copy back current state of pressed buttons inside request area */
3387 BlitBitmap(drawto, bitmap_db_cross, sx, sy, width, height, sx, sy);
3394 if (!PendingEvent()) /* delay only if no pending events */
3398 game_status = GAME_MODE_PSEUDO_DOOR;
3402 game_status = last_game_status; /* restore current game status */
3408 static boolean RequestDoor(char *text, unsigned int req_state)
3410 unsigned int old_door_state;
3411 int last_game_status = game_status; /* save current game status */
3412 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
3413 int font_nr = FONT_TEXT_2;
3418 if (maxWordLengthInString(text) > MAX_REQUEST_LINE_FONT1_LEN)
3420 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
3421 font_nr = FONT_TEXT_1;
3424 if (game_status == GAME_MODE_PLAYING)
3425 BlitScreenToBitmap(backbuffer);
3427 /* disable deactivated drawing when quick-loading level tape recording */
3428 if (tape.playing && tape.deactivate_display)
3429 TapeDeactivateDisplayOff(TRUE);
3431 SetMouseCursor(CURSOR_DEFAULT);
3433 #if defined(NETWORK_AVALIABLE)
3434 /* pause network game while waiting for request to answer */
3435 if (options.network &&
3436 game_status == GAME_MODE_PLAYING &&
3437 req_state & REQUEST_WAIT_FOR_INPUT)
3438 SendToServer_PausePlaying();
3441 old_door_state = GetDoorState();
3443 /* simulate releasing mouse button over last gadget, if still pressed */
3445 HandleGadgets(-1, -1, 0);
3449 /* draw released gadget before proceeding */
3452 if (old_door_state & DOOR_OPEN_1)
3454 CloseDoor(DOOR_CLOSE_1);
3456 /* save old door content */
3457 BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
3458 0 * DXSIZE, 0, DXSIZE, DYSIZE, 1 * DXSIZE, 0);
3461 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
3462 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3464 /* clear door drawing field */
3465 DrawBackground(DX, DY, DXSIZE, DYSIZE);
3467 /* force DOOR font inside door area */
3468 game_status = GAME_MODE_PSEUDO_DOOR;
3470 /* write text for request */
3471 for (text_ptr = text, ty = 0; ty < MAX_REQUEST_LINES; ty++)
3473 char text_line[max_request_line_len + 1];
3479 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
3481 tc = *(text_ptr + tx);
3482 // if (!tc || tc == ' ')
3483 if (!tc || tc == ' ' || tc == '?' || tc == '!')
3487 if ((tc == '?' || tc == '!') && tl == 0)
3497 strncpy(text_line, text_ptr, tl);
3500 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
3501 DY + 8 + ty * (getFontHeight(font_nr) + 2),
3502 text_line, font_nr);
3504 text_ptr += tl + (tc == ' ' ? 1 : 0);
3505 // text_ptr += tl + (tc == ' ' || tc == '?' || tc == '!' ? 1 : 0);
3508 game_status = last_game_status; /* restore current game status */
3510 if (req_state & REQ_ASK)
3512 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
3513 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
3515 else if (req_state & REQ_CONFIRM)
3517 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
3519 else if (req_state & REQ_PLAYER)
3521 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
3522 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
3523 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
3524 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
3527 /* copy request gadgets to door backbuffer */
3528 BlitBitmap(drawto, bitmap_db_door_1, DX, DY, DXSIZE, DYSIZE, 0, 0);
3530 OpenDoor(DOOR_OPEN_1);
3532 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
3534 if (game_status == GAME_MODE_PLAYING)
3536 SetPanelBackground();
3537 SetDrawBackgroundMask(REDRAW_DOOR_1);
3541 SetDrawBackgroundMask(REDRAW_FIELD);
3547 if (game_status != GAME_MODE_MAIN)
3550 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3552 // ---------- handle request buttons ----------
3553 result = RequestHandleEvents(req_state);
3555 if (game_status != GAME_MODE_MAIN)
3560 if (!(req_state & REQ_STAY_OPEN))
3562 CloseDoor(DOOR_CLOSE_1);
3564 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
3565 (req_state & REQ_REOPEN))
3566 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
3571 if (game_status == GAME_MODE_PLAYING)
3573 SetPanelBackground();
3574 SetDrawBackgroundMask(REDRAW_DOOR_1);
3578 SetDrawBackgroundMask(REDRAW_FIELD);
3581 #if defined(NETWORK_AVALIABLE)
3582 /* continue network game after request */
3583 if (options.network &&
3584 game_status == GAME_MODE_PLAYING &&
3585 req_state & REQUEST_WAIT_FOR_INPUT)
3586 SendToServer_ContinuePlaying();
3589 /* restore deactivated drawing when quick-loading level tape recording */
3590 if (tape.playing && tape.deactivate_display)
3591 TapeDeactivateDisplayOn();
3596 static boolean RequestEnvelope(char *text, unsigned int req_state)
3600 if (game_status == GAME_MODE_PLAYING)
3601 BlitScreenToBitmap(backbuffer);
3603 /* disable deactivated drawing when quick-loading level tape recording */
3604 if (tape.playing && tape.deactivate_display)
3605 TapeDeactivateDisplayOff(TRUE);
3607 SetMouseCursor(CURSOR_DEFAULT);
3609 #if defined(NETWORK_AVALIABLE)
3610 /* pause network game while waiting for request to answer */
3611 if (options.network &&
3612 game_status == GAME_MODE_PLAYING &&
3613 req_state & REQUEST_WAIT_FOR_INPUT)
3614 SendToServer_PausePlaying();
3617 /* simulate releasing mouse button over last gadget, if still pressed */
3619 HandleGadgets(-1, -1, 0);
3623 // (replace with setting corresponding request background)
3624 // SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
3625 // SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3627 /* clear door drawing field */
3628 // DrawBackground(DX, DY, DXSIZE, DYSIZE);
3630 ShowEnvelopeRequest(text, req_state, ACTION_OPENING);
3632 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
3634 if (game_status == GAME_MODE_PLAYING)
3636 SetPanelBackground();
3637 SetDrawBackgroundMask(REDRAW_DOOR_1);
3641 SetDrawBackgroundMask(REDRAW_FIELD);
3647 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3649 // ---------- handle request buttons ----------
3650 result = RequestHandleEvents(req_state);
3652 if (game_status != GAME_MODE_MAIN)
3657 ShowEnvelopeRequest(text, req_state, ACTION_CLOSING);
3661 if (game_status == GAME_MODE_PLAYING)
3663 SetPanelBackground();
3664 SetDrawBackgroundMask(REDRAW_DOOR_1);
3668 SetDrawBackgroundMask(REDRAW_FIELD);
3671 #if defined(NETWORK_AVALIABLE)
3672 /* continue network game after request */
3673 if (options.network &&
3674 game_status == GAME_MODE_PLAYING &&
3675 req_state & REQUEST_WAIT_FOR_INPUT)
3676 SendToServer_ContinuePlaying();
3679 /* restore deactivated drawing when quick-loading level tape recording */
3680 if (tape.playing && tape.deactivate_display)
3681 TapeDeactivateDisplayOn();
3686 boolean Request(char *text, unsigned int req_state)
3688 if (global.use_envelope_request)
3689 return RequestEnvelope(text, req_state);
3691 return RequestDoor(text, req_state);
3694 static int compareDoorPartOrderInfo(const void *object1, const void *object2)
3696 const struct DoorPartOrderInfo *dpo1 = (struct DoorPartOrderInfo *)object1;
3697 const struct DoorPartOrderInfo *dpo2 = (struct DoorPartOrderInfo *)object2;
3700 if (dpo1->sort_priority != dpo2->sort_priority)
3701 compare_result = dpo1->sort_priority - dpo2->sort_priority;
3703 compare_result = dpo1->nr - dpo2->nr;
3705 return compare_result;
3708 void InitGraphicCompatibilityInfo_Doors()
3714 struct DoorInfo *door;
3718 { DOOR_1, IMG_DOOR_1_GFX_PART_1, IMG_DOOR_1_GFX_PART_8, &door_1 },
3719 { DOOR_2, IMG_DOOR_2_GFX_PART_1, IMG_DOOR_2_GFX_PART_8, &door_2 },
3721 { -1, -1, -1, NULL }
3723 struct Rect door_rect_list[] =
3725 { DX, DY, DXSIZE, DYSIZE },
3726 { VX, VY, VXSIZE, VYSIZE }
3730 for (i = 0; doors[i].door_token != -1; i++)
3732 int door_token = doors[i].door_token;
3733 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
3734 int part_1 = doors[i].part_1;
3735 int part_8 = doors[i].part_8;
3736 int part_2 = part_1 + 1;
3737 int part_3 = part_1 + 2;
3738 struct DoorInfo *door = doors[i].door;
3739 struct Rect *door_rect = &door_rect_list[door_index];
3740 boolean door_gfx_redefined = FALSE;
3742 /* check if any door part graphic definitions have been redefined */
3744 for (j = 0; door_part_controls[j].door_token != -1; j++)
3746 struct DoorPartControlInfo *dpc = &door_part_controls[j];
3747 struct FileInfo *fi = getImageListEntryFromImageID(dpc->graphic);
3749 if (dpc->door_token == door_token && fi->redefined)
3750 door_gfx_redefined = TRUE;
3753 /* check for old-style door graphic/animation modifications */
3755 if (!door_gfx_redefined)
3757 if (door->anim_mode & ANIM_STATIC_PANEL)
3759 door->panel.step_xoffset = 0;
3760 door->panel.step_yoffset = 0;
3763 if (door->anim_mode & (ANIM_HORIZONTAL | ANIM_VERTICAL))
3765 struct GraphicInfo *g_part_1 = &graphic_info[part_1];
3766 struct GraphicInfo *g_part_2 = &graphic_info[part_2];
3767 int num_door_steps, num_panel_steps;
3769 /* remove door part graphics other than the two default wings */
3771 for (j = 0; door_part_controls[j].door_token != -1; j++)
3773 struct DoorPartControlInfo *dpc = &door_part_controls[j];
3774 struct GraphicInfo *g = &graphic_info[dpc->graphic];
3776 if (dpc->graphic >= part_3 &&
3777 dpc->graphic <= part_8)
3781 /* set graphics and screen positions of the default wings */
3783 g_part_1->width = door_rect->width;
3784 g_part_1->height = door_rect->height;
3785 g_part_2->width = door_rect->width;
3786 g_part_2->height = door_rect->height;
3787 g_part_2->src_x = door_rect->width;
3788 g_part_2->src_y = g_part_1->src_y;
3790 door->part_2.x = door->part_1.x;
3791 door->part_2.y = door->part_1.y;
3793 if (door->width != -1)
3795 g_part_1->width = door->width;
3796 g_part_2->width = door->width;
3798 // special treatment for graphics and screen position of right wing
3799 g_part_2->src_x += door_rect->width - door->width;
3800 door->part_2.x += door_rect->width - door->width;
3803 if (door->height != -1)
3805 g_part_1->height = door->height;
3806 g_part_2->height = door->height;
3808 // special treatment for graphics and screen position of bottom wing
3809 g_part_2->src_y += door_rect->height - door->height;
3810 door->part_2.y += door_rect->height - door->height;
3813 /* set animation delays for the default wings and panels */
3815 door->part_1.step_delay = door->step_delay;
3816 door->part_2.step_delay = door->step_delay;
3817 door->panel.step_delay = door->step_delay;
3819 /* set animation draw order for the default wings */
3821 door->part_1.sort_priority = 2; /* draw left wing over ... */
3822 door->part_2.sort_priority = 1; /* ... right wing */
3824 /* set animation draw offset for the default wings */
3826 if (door->anim_mode & ANIM_HORIZONTAL)
3828 door->part_1.step_xoffset = door->step_offset;
3829 door->part_1.step_yoffset = 0;
3830 door->part_2.step_xoffset = door->step_offset * -1;
3831 door->part_2.step_yoffset = 0;
3833 num_door_steps = g_part_1->width / door->step_offset;
3835 else // ANIM_VERTICAL
3837 door->part_1.step_xoffset = 0;
3838 door->part_1.step_yoffset = door->step_offset;
3839 door->part_2.step_xoffset = 0;
3840 door->part_2.step_yoffset = door->step_offset * -1;
3842 num_door_steps = g_part_1->height / door->step_offset;
3845 /* set animation draw offset for the default panels */
3847 if (door->step_offset > 1)
3849 num_panel_steps = 2 * door_rect->height / door->step_offset;
3850 door->panel.start_step = num_panel_steps - num_door_steps;
3851 door->panel.start_step_closing = door->panel.start_step;
3855 num_panel_steps = door_rect->height / door->step_offset;
3856 door->panel.start_step = num_panel_steps - num_door_steps / 2;
3857 door->panel.start_step_closing = door->panel.start_step;
3858 door->panel.step_delay *= 2;
3869 for (i = 0; door_part_controls[i].door_token != -1; i++)
3871 struct DoorPartControlInfo *dpc = &door_part_controls[i];
3872 struct DoorPartOrderInfo *dpo = &door_part_order[i];
3874 /* initialize "start_step_opening" and "start_step_closing", if needed */
3875 if (dpc->pos->start_step_opening == 0 &&
3876 dpc->pos->start_step_closing == 0)
3878 // dpc->pos->start_step_opening = dpc->pos->start_step;
3879 dpc->pos->start_step_closing = dpc->pos->start_step;
3882 /* fill structure for door part draw order (sorted below) */
3884 dpo->sort_priority = dpc->pos->sort_priority;
3887 /* sort door part controls according to sort_priority and graphic number */
3888 qsort(door_part_order, MAX_DOOR_PARTS,
3889 sizeof(struct DoorPartOrderInfo), compareDoorPartOrderInfo);
3892 unsigned int OpenDoor(unsigned int door_state)
3894 if (door_state & DOOR_COPY_BACK)
3896 if (door_state & DOOR_OPEN_1)
3897 BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
3898 1 * DXSIZE, 0, DXSIZE, DYSIZE, 0 * DXSIZE, 0);
3900 if (door_state & DOOR_OPEN_2)
3901 BlitBitmap(bitmap_db_door_2, bitmap_db_door_2,
3902 1 * VXSIZE, 0, VXSIZE, VYSIZE, 0 * VXSIZE, 0);
3904 door_state &= ~DOOR_COPY_BACK;
3907 return MoveDoor(door_state);
3910 unsigned int CloseDoor(unsigned int door_state)
3912 unsigned int old_door_state = GetDoorState();
3914 if (!(door_state & DOOR_NO_COPY_BACK))
3916 if (old_door_state & DOOR_OPEN_1)
3917 BlitBitmap(backbuffer, bitmap_db_door_1,
3918 DX, DY, DXSIZE, DYSIZE, 0, 0);
3920 if (old_door_state & DOOR_OPEN_2)
3921 BlitBitmap(backbuffer, bitmap_db_door_2,
3922 VX, VY, VXSIZE, VYSIZE, 0, 0);
3924 door_state &= ~DOOR_NO_COPY_BACK;
3927 return MoveDoor(door_state);
3930 unsigned int GetDoorState()
3932 return MoveDoor(DOOR_GET_STATE);
3935 unsigned int SetDoorState(unsigned int door_state)
3937 return MoveDoor(door_state | DOOR_SET_STATE);
3940 int euclid(int a, int b)
3942 return (b ? euclid(b, a % b) : a);
3945 unsigned int MoveDoor(unsigned int door_state)
3947 struct Rect door_rect_list[] =
3949 { DX, DY, DXSIZE, DYSIZE },
3950 { VX, VY, VXSIZE, VYSIZE }
3952 static int door1 = DOOR_OPEN_1;
3953 static int door2 = DOOR_CLOSE_2;
3954 unsigned int door_delay = 0;
3955 unsigned int door_delay_value;
3958 if (door_state == DOOR_GET_STATE)
3959 return (door1 | door2);
3961 if (door_state & DOOR_SET_STATE)
3963 if (door_state & DOOR_ACTION_1)
3964 door1 = door_state & DOOR_ACTION_1;
3965 if (door_state & DOOR_ACTION_2)
3966 door2 = door_state & DOOR_ACTION_2;
3968 return (door1 | door2);
3971 if (!(door_state & DOOR_FORCE_REDRAW))
3973 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
3974 door_state &= ~DOOR_OPEN_1;
3975 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
3976 door_state &= ~DOOR_CLOSE_1;
3977 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
3978 door_state &= ~DOOR_OPEN_2;
3979 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
3980 door_state &= ~DOOR_CLOSE_2;
3983 if (global.autoplay_leveldir)
3985 door_state |= DOOR_NO_DELAY;
3986 door_state &= ~DOOR_CLOSE_ALL;
3989 if (game_status == GAME_MODE_EDITOR)
3990 door_state |= DOOR_NO_DELAY;
3992 if (door_state & DOOR_ACTION)
3994 boolean door_panel_drawn[NUM_DOORS];
3995 boolean panel_has_doors[NUM_DOORS];
3996 boolean door_part_skip[MAX_DOOR_PARTS];
3997 boolean door_part_done[MAX_DOOR_PARTS];
3998 boolean door_part_done_all;
3999 int num_steps[MAX_DOOR_PARTS];
4000 int max_move_delay = 0; // delay for complete animations of all doors
4001 int max_step_delay = 0; // delay (ms) between two animation frames
4002 int num_move_steps = 0; // number of animation steps for all doors
4003 int max_move_delay_doors_only = 0; // delay for doors only (no panel)
4004 int num_move_steps_doors_only = 0; // steps for doors only (no panel)
4005 int current_move_delay = 0;
4009 for (i = 0; i < NUM_DOORS; i++)
4010 panel_has_doors[i] = FALSE;
4012 for (i = 0; i < MAX_DOOR_PARTS; i++)
4014 struct DoorPartControlInfo *dpc = &door_part_controls[i];
4015 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4016 int door_token = dpc->door_token;
4018 door_part_done[i] = FALSE;
4019 door_part_skip[i] = (!(door_state & door_token) ||
4023 for (i = 0; i < MAX_DOOR_PARTS; i++)
4025 int nr = door_part_order[i].nr;
4026 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
4027 struct DoorPartPosInfo *pos = dpc->pos;
4028 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4029 int door_token = dpc->door_token;
4030 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
4031 boolean is_panel = DOOR_PART_IS_PANEL(nr);
4032 int step_xoffset = ABS(pos->step_xoffset);
4033 int step_yoffset = ABS(pos->step_yoffset);
4034 int step_delay = pos->step_delay;
4035 int current_door_state = door_state & door_token;
4036 boolean door_opening = ((current_door_state & DOOR_OPEN) != 0);
4037 boolean door_closing = ((current_door_state & DOOR_CLOSE) != 0);
4038 boolean part_opening = (is_panel ? door_closing : door_opening);
4039 int start_step = (part_opening ? pos->start_step_opening :
4040 pos->start_step_closing);
4041 float move_xsize = (step_xoffset ? g->width : 0);
4042 float move_ysize = (step_yoffset ? g->height : 0);
4043 int move_xsteps = (step_xoffset ? ceil(move_xsize / step_xoffset) : 0);
4044 int move_ysteps = (step_yoffset ? ceil(move_ysize / step_yoffset) : 0);
4045 int move_steps = (move_xsteps && move_ysteps ?
4046 MIN(move_xsteps, move_ysteps) :
4047 move_xsteps ? move_xsteps : move_ysteps) - start_step;
4048 int move_delay = move_steps * step_delay;
4050 if (door_part_skip[nr])
4053 max_move_delay = MAX(max_move_delay, move_delay);
4054 max_step_delay = (max_step_delay == 0 ? step_delay :
4055 euclid(max_step_delay, step_delay));
4056 num_steps[nr] = move_steps;
4060 max_move_delay_doors_only = MAX(max_move_delay_doors_only, move_delay);
4062 panel_has_doors[door_index] = TRUE;
4066 max_step_delay = MAX(1, max_step_delay); // prevent division by zero
4068 num_move_steps = max_move_delay / max_step_delay;
4069 num_move_steps_doors_only = max_move_delay_doors_only / max_step_delay;
4071 door_delay_value = max_step_delay;
4073 if ((door_state & DOOR_NO_DELAY) || setup.quick_doors)
4075 start = num_move_steps - 1;
4079 /* opening door sound has priority over simultaneously closing door */
4080 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
4081 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
4082 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
4083 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
4086 for (k = start; k < num_move_steps; k++)
4088 int last_frame = num_move_steps - 1; // last frame of this "for" loop
4090 door_part_done_all = TRUE;
4092 for (i = 0; i < NUM_DOORS; i++)
4093 door_panel_drawn[i] = FALSE;
4095 for (i = 0; i < MAX_DOOR_PARTS; i++)
4097 int nr = door_part_order[i].nr;
4098 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
4099 struct DoorPartPosInfo *pos = dpc->pos;
4100 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4101 int door_token = dpc->door_token;
4102 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
4103 boolean is_panel = DOOR_PART_IS_PANEL(nr);
4104 boolean is_panel_and_door_has_closed = FALSE;
4105 struct Rect *door_rect = &door_rect_list[door_index];
4106 Bitmap *bitmap_db_door = (door_token == DOOR_1 ? bitmap_db_door_1 :
4108 Bitmap *bitmap = (is_panel ? bitmap_db_door : g->bitmap);
4109 int current_door_state = door_state & door_token;
4110 boolean door_opening = ((current_door_state & DOOR_OPEN) != 0);
4111 boolean door_closing = !door_opening;
4112 boolean part_opening = (is_panel ? door_closing : door_opening);
4113 boolean part_closing = !part_opening;
4114 int start_step = (part_opening ? pos->start_step_opening :
4115 pos->start_step_closing);
4116 int step_delay = pos->step_delay;
4117 int step_factor = step_delay / max_step_delay;
4118 int k1 = (step_factor ? k / step_factor + 1 : k);
4119 int k2 = (part_opening ? k1 + start_step : num_steps[nr] - k1);
4120 int kk = MAX(0, k2);
4123 int src_x, src_y, src_xx, src_yy;
4124 int dst_x, dst_y, dst_xx, dst_yy;
4127 if (door_part_skip[nr])
4130 if (!(door_state & door_token))
4138 int k2_door = (door_opening ? k : num_move_steps_doors_only - k - 1);
4139 int kk_door = MAX(0, k2_door);
4140 int sync_frame = kk_door * door_delay_value;
4141 int frame = getGraphicAnimationFrame(dpc->graphic, sync_frame);
4143 getGraphicSource(dpc->graphic, frame, &bitmap, &g_src_x, &g_src_y);
4148 if (!door_panel_drawn[door_index])
4150 ClearRectangle(drawto, door_rect->x, door_rect->y,
4151 door_rect->width, door_rect->height);
4153 door_panel_drawn[door_index] = TRUE;
4156 // draw opening or closing door parts
4158 if (pos->step_xoffset < 0) // door part on right side
4161 dst_xx = pos->x + ABS(kk * pos->step_xoffset);
4164 if (dst_xx + width > door_rect->width)
4165 width = door_rect->width - dst_xx;
4167 else // door part on left side
4170 dst_xx = pos->x - kk * pos->step_xoffset;
4174 src_xx = ABS(dst_xx);
4178 width = g->width - src_xx;
4180 // printf("::: k == %d [%d] \n", k, start_step);
4183 if (pos->step_yoffset < 0) // door part on bottom side
4186 dst_yy = pos->y + ABS(kk * pos->step_yoffset);
4189 if (dst_yy + height > door_rect->height)
4190 height = door_rect->height - dst_yy;
4192 else // door part on top side
4195 dst_yy = pos->y - kk * pos->step_yoffset;
4199 src_yy = ABS(dst_yy);
4203 height = g->height - src_yy;
4206 src_x = g_src_x + src_xx;
4207 src_y = g_src_y + src_yy;
4209 dst_x = door_rect->x + dst_xx;
4210 dst_y = door_rect->y + dst_yy;
4212 is_panel_and_door_has_closed =
4215 panel_has_doors[door_index] &&
4216 k >= num_move_steps_doors_only - 1);
4218 if (width >= 0 && width <= g->width &&
4219 height >= 0 && height <= g->height &&
4220 !is_panel_and_door_has_closed)
4222 if (is_panel || !pos->draw_masked)
4223 BlitBitmap(bitmap, drawto, src_x, src_y, width, height,
4226 BlitBitmapMasked(bitmap, drawto, src_x, src_y, width, height,
4230 redraw_mask |= REDRAW_DOOR_FROM_TOKEN(door_token);
4232 if ((part_opening && (width < 0 || height < 0)) ||
4233 (part_closing && (width >= g->width && height >= g->height)))
4234 door_part_done[nr] = TRUE;
4236 // continue door part animations, but not panel after door has closed
4237 if (!door_part_done[nr] && !is_panel_and_door_has_closed)
4238 door_part_done_all = FALSE;
4241 if (!(door_state & DOOR_NO_DELAY))
4245 if (game_status == GAME_MODE_MAIN)
4248 SkipUntilDelayReached(&door_delay, door_delay_value, &k, last_frame);
4250 current_move_delay += max_step_delay;
4253 if (door_part_done_all)
4258 if (door_state & DOOR_ACTION_1)
4259 door1 = door_state & DOOR_ACTION_1;
4260 if (door_state & DOOR_ACTION_2)
4261 door2 = door_state & DOOR_ACTION_2;
4263 return (door1 | door2);
4266 void DrawSpecialEditorDoor()
4268 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
4269 int top_border_width = gfx1->width;
4270 int top_border_height = gfx1->height;
4271 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
4272 int ex = EX - outer_border;
4273 int ey = EY - outer_border;
4274 int vy = VY - outer_border;
4275 int exsize = EXSIZE + 2 * outer_border;
4277 /* draw bigger level editor toolbox window */
4278 BlitBitmap(gfx1->bitmap, drawto, gfx1->src_x, gfx1->src_y,
4279 top_border_width, top_border_height, ex, ey - top_border_height);
4280 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto, ex, vy,
4281 exsize, EYSIZE - VYSIZE + outer_border, ex, ey);
4283 redraw_mask |= REDRAW_ALL;
4286 void UndrawSpecialEditorDoor()
4288 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
4289 int top_border_width = gfx1->width;
4290 int top_border_height = gfx1->height;
4291 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
4292 int ex = EX - outer_border;
4293 int ey = EY - outer_border;
4294 int ey_top = ey - top_border_height;
4295 int exsize = EXSIZE + 2 * outer_border;
4296 int eysize = EYSIZE + 2 * outer_border;
4298 /* draw normal tape recorder window */
4299 if (graphic_info[IMG_GLOBAL_BORDER].bitmap)
4301 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
4302 ex, ey_top, top_border_width, top_border_height,
4304 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
4305 ex, ey, exsize, eysize, ex, ey);
4309 // if screen background is set to "[NONE]", clear editor toolbox window
4310 ClearRectangle(drawto, ex, ey_top, top_border_width, top_border_height);
4311 ClearRectangle(drawto, ex, ey, exsize, eysize);
4314 redraw_mask |= REDRAW_ALL;
4318 /* ---------- new tool button stuff ---------------------------------------- */
4323 struct TextPosInfo *pos;
4326 } toolbutton_info[NUM_TOOL_BUTTONS] =
4329 IMG_REQUEST_BUTTON_GFX_YES, &request.button.yes,
4330 TOOL_CTRL_ID_YES, "yes"
4333 IMG_REQUEST_BUTTON_GFX_NO, &request.button.no,
4334 TOOL_CTRL_ID_NO, "no"
4337 IMG_REQUEST_BUTTON_GFX_CONFIRM, &request.button.confirm,
4338 TOOL_CTRL_ID_CONFIRM, "confirm"
4341 IMG_REQUEST_BUTTON_GFX_PLAYER_1, &request.button.player_1,
4342 TOOL_CTRL_ID_PLAYER_1, "player 1"
4345 IMG_REQUEST_BUTTON_GFX_PLAYER_2, &request.button.player_2,
4346 TOOL_CTRL_ID_PLAYER_2, "player 2"
4349 IMG_REQUEST_BUTTON_GFX_PLAYER_3, &request.button.player_3,
4350 TOOL_CTRL_ID_PLAYER_3, "player 3"
4353 IMG_REQUEST_BUTTON_GFX_PLAYER_4, &request.button.player_4,
4354 TOOL_CTRL_ID_PLAYER_4, "player 4"
4358 void CreateToolButtons()
4362 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4364 struct GraphicInfo *gfx = &graphic_info[toolbutton_info[i].graphic];
4365 struct TextPosInfo *pos = toolbutton_info[i].pos;
4366 struct GadgetInfo *gi;
4367 Bitmap *deco_bitmap = None;
4368 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
4369 unsigned int event_mask = GD_EVENT_RELEASED;
4372 int gd_x = gfx->src_x;
4373 int gd_y = gfx->src_y;
4374 int gd_xp = gfx->src_x + gfx->pressed_xoffset;
4375 int gd_yp = gfx->src_y + gfx->pressed_yoffset;
4378 if (global.use_envelope_request)
4379 setRequestPosition(&dx, &dy, TRUE);
4381 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
4383 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
4385 getSizedGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr), 0,
4386 pos->size, &deco_bitmap, &deco_x, &deco_y);
4387 deco_xpos = (gfx->width - pos->size) / 2;
4388 deco_ypos = (gfx->height - pos->size) / 2;
4391 gi = CreateGadget(GDI_CUSTOM_ID, id,
4392 GDI_INFO_TEXT, toolbutton_info[i].infotext,
4393 GDI_X, dx + GDI_ACTIVE_POS(pos->x),
4394 GDI_Y, dy + GDI_ACTIVE_POS(pos->y),
4395 GDI_WIDTH, gfx->width,
4396 GDI_HEIGHT, gfx->height,
4397 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
4398 GDI_STATE, GD_BUTTON_UNPRESSED,
4399 GDI_DESIGN_UNPRESSED, gfx->bitmap, gd_x, gd_y,
4400 GDI_DESIGN_PRESSED, gfx->bitmap, gd_xp, gd_yp,
4401 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
4402 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
4403 GDI_DECORATION_SIZE, pos->size, pos->size,
4404 GDI_DECORATION_SHIFTING, 1, 1,
4405 GDI_DIRECT_DRAW, FALSE,
4406 GDI_EVENT_MASK, event_mask,
4407 GDI_CALLBACK_ACTION, HandleToolButtons,
4411 Error(ERR_EXIT, "cannot create gadget");
4413 tool_gadget[id] = gi;
4417 void FreeToolButtons()
4421 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4422 FreeGadget(tool_gadget[i]);
4425 static void UnmapToolButtons()
4429 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4430 UnmapGadget(tool_gadget[i]);
4433 static void HandleToolButtons(struct GadgetInfo *gi)
4435 request_gadget_id = gi->custom_id;
4438 static struct Mapping_EM_to_RND_object
4441 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
4442 boolean is_backside; /* backside of moving element */
4448 em_object_mapping_list[] =
4451 Xblank, TRUE, FALSE,
4455 Yacid_splash_eB, FALSE, FALSE,
4456 EL_ACID_SPLASH_RIGHT, -1, -1
4459 Yacid_splash_wB, FALSE, FALSE,
4460 EL_ACID_SPLASH_LEFT, -1, -1
4463 #ifdef EM_ENGINE_BAD_ROLL
4465 Xstone_force_e, FALSE, FALSE,
4466 EL_ROCK, -1, MV_BIT_RIGHT
4469 Xstone_force_w, FALSE, FALSE,
4470 EL_ROCK, -1, MV_BIT_LEFT
4473 Xnut_force_e, FALSE, FALSE,
4474 EL_NUT, -1, MV_BIT_RIGHT
4477 Xnut_force_w, FALSE, FALSE,
4478 EL_NUT, -1, MV_BIT_LEFT
4481 Xspring_force_e, FALSE, FALSE,
4482 EL_SPRING, -1, MV_BIT_RIGHT
4485 Xspring_force_w, FALSE, FALSE,
4486 EL_SPRING, -1, MV_BIT_LEFT
4489 Xemerald_force_e, FALSE, FALSE,
4490 EL_EMERALD, -1, MV_BIT_RIGHT
4493 Xemerald_force_w, FALSE, FALSE,
4494 EL_EMERALD, -1, MV_BIT_LEFT
4497 Xdiamond_force_e, FALSE, FALSE,
4498 EL_DIAMOND, -1, MV_BIT_RIGHT
4501 Xdiamond_force_w, FALSE, FALSE,
4502 EL_DIAMOND, -1, MV_BIT_LEFT
4505 Xbomb_force_e, FALSE, FALSE,
4506 EL_BOMB, -1, MV_BIT_RIGHT
4509 Xbomb_force_w, FALSE, FALSE,
4510 EL_BOMB, -1, MV_BIT_LEFT
4512 #endif /* EM_ENGINE_BAD_ROLL */
4515 Xstone, TRUE, FALSE,
4519 Xstone_pause, FALSE, FALSE,
4523 Xstone_fall, FALSE, FALSE,
4527 Ystone_s, FALSE, FALSE,
4528 EL_ROCK, ACTION_FALLING, -1
4531 Ystone_sB, FALSE, TRUE,
4532 EL_ROCK, ACTION_FALLING, -1
4535 Ystone_e, FALSE, FALSE,
4536 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
4539 Ystone_eB, FALSE, TRUE,
4540 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
4543 Ystone_w, FALSE, FALSE,
4544 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
4547 Ystone_wB, FALSE, TRUE,
4548 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
4555 Xnut_pause, FALSE, FALSE,
4559 Xnut_fall, FALSE, FALSE,
4563 Ynut_s, FALSE, FALSE,
4564 EL_NUT, ACTION_FALLING, -1
4567 Ynut_sB, FALSE, TRUE,
4568 EL_NUT, ACTION_FALLING, -1
4571 Ynut_e, FALSE, FALSE,
4572 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
4575 Ynut_eB, FALSE, TRUE,
4576 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
4579 Ynut_w, FALSE, FALSE,
4580 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
4583 Ynut_wB, FALSE, TRUE,
4584 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
4587 Xbug_n, TRUE, FALSE,
4591 Xbug_e, TRUE, FALSE,
4592 EL_BUG_RIGHT, -1, -1
4595 Xbug_s, TRUE, FALSE,
4599 Xbug_w, TRUE, FALSE,
4603 Xbug_gon, FALSE, FALSE,
4607 Xbug_goe, FALSE, FALSE,
4608 EL_BUG_RIGHT, -1, -1
4611 Xbug_gos, FALSE, FALSE,
4615 Xbug_gow, FALSE, FALSE,
4619 Ybug_n, FALSE, FALSE,
4620 EL_BUG, ACTION_MOVING, MV_BIT_UP
4623 Ybug_nB, FALSE, TRUE,
4624 EL_BUG, ACTION_MOVING, MV_BIT_UP
4627 Ybug_e, FALSE, FALSE,
4628 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
4631 Ybug_eB, FALSE, TRUE,
4632 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
4635 Ybug_s, FALSE, FALSE,
4636 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
4639 Ybug_sB, FALSE, TRUE,
4640 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
4643 Ybug_w, FALSE, FALSE,
4644 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
4647 Ybug_wB, FALSE, TRUE,
4648 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
4651 Ybug_w_n, FALSE, FALSE,
4652 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
4655 Ybug_n_e, FALSE, FALSE,
4656 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
4659 Ybug_e_s, FALSE, FALSE,
4660 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
4663 Ybug_s_w, FALSE, FALSE,
4664 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
4667 Ybug_e_n, FALSE, FALSE,
4668 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
4671 Ybug_s_e, FALSE, FALSE,
4672 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
4675 Ybug_w_s, FALSE, FALSE,
4676 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
4679 Ybug_n_w, FALSE, FALSE,
4680 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
4683 Ybug_stone, FALSE, FALSE,
4684 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
4687 Ybug_spring, FALSE, FALSE,
4688 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
4691 Xtank_n, TRUE, FALSE,
4692 EL_SPACESHIP_UP, -1, -1
4695 Xtank_e, TRUE, FALSE,
4696 EL_SPACESHIP_RIGHT, -1, -1
4699 Xtank_s, TRUE, FALSE,
4700 EL_SPACESHIP_DOWN, -1, -1
4703 Xtank_w, TRUE, FALSE,
4704 EL_SPACESHIP_LEFT, -1, -1
4707 Xtank_gon, FALSE, FALSE,
4708 EL_SPACESHIP_UP, -1, -1
4711 Xtank_goe, FALSE, FALSE,
4712 EL_SPACESHIP_RIGHT, -1, -1
4715 Xtank_gos, FALSE, FALSE,
4716 EL_SPACESHIP_DOWN, -1, -1
4719 Xtank_gow, FALSE, FALSE,
4720 EL_SPACESHIP_LEFT, -1, -1
4723 Ytank_n, FALSE, FALSE,
4724 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
4727 Ytank_nB, FALSE, TRUE,
4728 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
4731 Ytank_e, FALSE, FALSE,
4732 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
4735 Ytank_eB, FALSE, TRUE,
4736 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
4739 Ytank_s, FALSE, FALSE,
4740 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
4743 Ytank_sB, FALSE, TRUE,
4744 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
4747 Ytank_w, FALSE, FALSE,
4748 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
4751 Ytank_wB, FALSE, TRUE,
4752 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
4755 Ytank_w_n, FALSE, FALSE,
4756 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
4759 Ytank_n_e, FALSE, FALSE,
4760 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
4763 Ytank_e_s, FALSE, FALSE,
4764 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
4767 Ytank_s_w, FALSE, FALSE,
4768 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
4771 Ytank_e_n, FALSE, FALSE,
4772 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
4775 Ytank_s_e, FALSE, FALSE,
4776 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
4779 Ytank_w_s, FALSE, FALSE,
4780 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
4783 Ytank_n_w, FALSE, FALSE,
4784 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
4787 Ytank_stone, FALSE, FALSE,
4788 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
4791 Ytank_spring, FALSE, FALSE,
4792 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
4795 Xandroid, TRUE, FALSE,
4796 EL_EMC_ANDROID, ACTION_ACTIVE, -1
4799 Xandroid_1_n, FALSE, FALSE,
4800 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
4803 Xandroid_2_n, FALSE, FALSE,
4804 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
4807 Xandroid_1_e, FALSE, FALSE,
4808 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
4811 Xandroid_2_e, FALSE, FALSE,
4812 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
4815 Xandroid_1_w, FALSE, FALSE,
4816 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
4819 Xandroid_2_w, FALSE, FALSE,
4820 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
4823 Xandroid_1_s, FALSE, FALSE,
4824 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
4827 Xandroid_2_s, FALSE, FALSE,
4828 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
4831 Yandroid_n, FALSE, FALSE,
4832 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
4835 Yandroid_nB, FALSE, TRUE,
4836 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
4839 Yandroid_ne, FALSE, FALSE,
4840 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
4843 Yandroid_neB, FALSE, TRUE,
4844 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
4847 Yandroid_e, FALSE, FALSE,
4848 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
4851 Yandroid_eB, FALSE, TRUE,
4852 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
4855 Yandroid_se, FALSE, FALSE,
4856 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
4859 Yandroid_seB, FALSE, TRUE,
4860 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
4863 Yandroid_s, FALSE, FALSE,
4864 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
4867 Yandroid_sB, FALSE, TRUE,
4868 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
4871 Yandroid_sw, FALSE, FALSE,
4872 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
4875 Yandroid_swB, FALSE, TRUE,
4876 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
4879 Yandroid_w, FALSE, FALSE,
4880 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
4883 Yandroid_wB, FALSE, TRUE,
4884 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
4887 Yandroid_nw, FALSE, FALSE,
4888 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
4891 Yandroid_nwB, FALSE, TRUE,
4892 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
4895 Xspring, TRUE, FALSE,
4899 Xspring_pause, FALSE, FALSE,
4903 Xspring_e, FALSE, FALSE,
4907 Xspring_w, FALSE, FALSE,
4911 Xspring_fall, FALSE, FALSE,
4915 Yspring_s, FALSE, FALSE,
4916 EL_SPRING, ACTION_FALLING, -1
4919 Yspring_sB, FALSE, TRUE,
4920 EL_SPRING, ACTION_FALLING, -1
4923 Yspring_e, FALSE, FALSE,
4924 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
4927 Yspring_eB, FALSE, TRUE,
4928 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
4931 Yspring_w, FALSE, FALSE,
4932 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
4935 Yspring_wB, FALSE, TRUE,
4936 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
4939 Yspring_kill_e, FALSE, FALSE,
4940 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
4943 Yspring_kill_eB, FALSE, TRUE,
4944 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
4947 Yspring_kill_w, FALSE, FALSE,
4948 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
4951 Yspring_kill_wB, FALSE, TRUE,
4952 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
4955 Xeater_n, TRUE, FALSE,
4956 EL_YAMYAM_UP, -1, -1
4959 Xeater_e, TRUE, FALSE,
4960 EL_YAMYAM_RIGHT, -1, -1
4963 Xeater_w, TRUE, FALSE,
4964 EL_YAMYAM_LEFT, -1, -1
4967 Xeater_s, TRUE, FALSE,
4968 EL_YAMYAM_DOWN, -1, -1
4971 Yeater_n, FALSE, FALSE,
4972 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
4975 Yeater_nB, FALSE, TRUE,
4976 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
4979 Yeater_e, FALSE, FALSE,
4980 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
4983 Yeater_eB, FALSE, TRUE,
4984 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
4987 Yeater_s, FALSE, FALSE,
4988 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
4991 Yeater_sB, FALSE, TRUE,
4992 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
4995 Yeater_w, FALSE, FALSE,
4996 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
4999 Yeater_wB, FALSE, TRUE,
5000 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
5003 Yeater_stone, FALSE, FALSE,
5004 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
5007 Yeater_spring, FALSE, FALSE,
5008 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
5011 Xalien, TRUE, FALSE,
5015 Xalien_pause, FALSE, FALSE,
5019 Yalien_n, FALSE, FALSE,
5020 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
5023 Yalien_nB, FALSE, TRUE,
5024 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
5027 Yalien_e, FALSE, FALSE,
5028 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
5031 Yalien_eB, FALSE, TRUE,
5032 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
5035 Yalien_s, FALSE, FALSE,
5036 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
5039 Yalien_sB, FALSE, TRUE,
5040 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
5043 Yalien_w, FALSE, FALSE,
5044 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
5047 Yalien_wB, FALSE, TRUE,
5048 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
5051 Yalien_stone, FALSE, FALSE,
5052 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
5055 Yalien_spring, FALSE, FALSE,
5056 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
5059 Xemerald, TRUE, FALSE,
5063 Xemerald_pause, FALSE, FALSE,
5067 Xemerald_fall, FALSE, FALSE,
5071 Xemerald_shine, FALSE, FALSE,
5072 EL_EMERALD, ACTION_TWINKLING, -1
5075 Yemerald_s, FALSE, FALSE,
5076 EL_EMERALD, ACTION_FALLING, -1
5079 Yemerald_sB, FALSE, TRUE,
5080 EL_EMERALD, ACTION_FALLING, -1
5083 Yemerald_e, FALSE, FALSE,
5084 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
5087 Yemerald_eB, FALSE, TRUE,
5088 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
5091 Yemerald_w, FALSE, FALSE,
5092 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
5095 Yemerald_wB, FALSE, TRUE,
5096 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
5099 Yemerald_eat, FALSE, FALSE,
5100 EL_EMERALD, ACTION_COLLECTING, -1
5103 Yemerald_stone, FALSE, FALSE,
5104 EL_NUT, ACTION_BREAKING, -1
5107 Xdiamond, TRUE, FALSE,
5111 Xdiamond_pause, FALSE, FALSE,
5115 Xdiamond_fall, FALSE, FALSE,
5119 Xdiamond_shine, FALSE, FALSE,
5120 EL_DIAMOND, ACTION_TWINKLING, -1
5123 Ydiamond_s, FALSE, FALSE,
5124 EL_DIAMOND, ACTION_FALLING, -1
5127 Ydiamond_sB, FALSE, TRUE,
5128 EL_DIAMOND, ACTION_FALLING, -1
5131 Ydiamond_e, FALSE, FALSE,
5132 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
5135 Ydiamond_eB, FALSE, TRUE,
5136 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
5139 Ydiamond_w, FALSE, FALSE,
5140 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
5143 Ydiamond_wB, FALSE, TRUE,
5144 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
5147 Ydiamond_eat, FALSE, FALSE,
5148 EL_DIAMOND, ACTION_COLLECTING, -1
5151 Ydiamond_stone, FALSE, FALSE,
5152 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
5155 Xdrip_fall, TRUE, FALSE,
5156 EL_AMOEBA_DROP, -1, -1
5159 Xdrip_stretch, FALSE, FALSE,
5160 EL_AMOEBA_DROP, ACTION_FALLING, -1
5163 Xdrip_stretchB, FALSE, TRUE,
5164 EL_AMOEBA_DROP, ACTION_FALLING, -1
5167 Xdrip_eat, FALSE, FALSE,
5168 EL_AMOEBA_DROP, ACTION_GROWING, -1
5171 Ydrip_s1, FALSE, FALSE,
5172 EL_AMOEBA_DROP, ACTION_FALLING, -1
5175 Ydrip_s1B, FALSE, TRUE,
5176 EL_AMOEBA_DROP, ACTION_FALLING, -1
5179 Ydrip_s2, FALSE, FALSE,
5180 EL_AMOEBA_DROP, ACTION_FALLING, -1
5183 Ydrip_s2B, FALSE, TRUE,
5184 EL_AMOEBA_DROP, ACTION_FALLING, -1
5191 Xbomb_pause, FALSE, FALSE,
5195 Xbomb_fall, FALSE, FALSE,
5199 Ybomb_s, FALSE, FALSE,
5200 EL_BOMB, ACTION_FALLING, -1
5203 Ybomb_sB, FALSE, TRUE,
5204 EL_BOMB, ACTION_FALLING, -1
5207 Ybomb_e, FALSE, FALSE,
5208 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
5211 Ybomb_eB, FALSE, TRUE,
5212 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
5215 Ybomb_w, FALSE, FALSE,
5216 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
5219 Ybomb_wB, FALSE, TRUE,
5220 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
5223 Ybomb_eat, FALSE, FALSE,
5224 EL_BOMB, ACTION_ACTIVATING, -1
5227 Xballoon, TRUE, FALSE,
5231 Yballoon_n, FALSE, FALSE,
5232 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
5235 Yballoon_nB, FALSE, TRUE,
5236 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
5239 Yballoon_e, FALSE, FALSE,
5240 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
5243 Yballoon_eB, FALSE, TRUE,
5244 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
5247 Yballoon_s, FALSE, FALSE,
5248 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
5251 Yballoon_sB, FALSE, TRUE,
5252 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
5255 Yballoon_w, FALSE, FALSE,
5256 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
5259 Yballoon_wB, FALSE, TRUE,
5260 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
5263 Xgrass, TRUE, FALSE,
5264 EL_EMC_GRASS, -1, -1
5267 Ygrass_nB, FALSE, FALSE,
5268 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
5271 Ygrass_eB, FALSE, FALSE,
5272 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
5275 Ygrass_sB, FALSE, FALSE,
5276 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
5279 Ygrass_wB, FALSE, FALSE,
5280 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
5287 Ydirt_nB, FALSE, FALSE,
5288 EL_SAND, ACTION_DIGGING, MV_BIT_UP
5291 Ydirt_eB, FALSE, FALSE,
5292 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
5295 Ydirt_sB, FALSE, FALSE,
5296 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
5299 Ydirt_wB, FALSE, FALSE,
5300 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
5303 Xacid_ne, TRUE, FALSE,
5304 EL_ACID_POOL_TOPRIGHT, -1, -1
5307 Xacid_se, TRUE, FALSE,
5308 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
5311 Xacid_s, TRUE, FALSE,
5312 EL_ACID_POOL_BOTTOM, -1, -1
5315 Xacid_sw, TRUE, FALSE,
5316 EL_ACID_POOL_BOTTOMLEFT, -1, -1
5319 Xacid_nw, TRUE, FALSE,
5320 EL_ACID_POOL_TOPLEFT, -1, -1
5323 Xacid_1, TRUE, FALSE,
5327 Xacid_2, FALSE, FALSE,
5331 Xacid_3, FALSE, FALSE,
5335 Xacid_4, FALSE, FALSE,
5339 Xacid_5, FALSE, FALSE,
5343 Xacid_6, FALSE, FALSE,
5347 Xacid_7, FALSE, FALSE,
5351 Xacid_8, FALSE, FALSE,
5355 Xball_1, TRUE, FALSE,
5356 EL_EMC_MAGIC_BALL, -1, -1
5359 Xball_1B, FALSE, FALSE,
5360 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5363 Xball_2, FALSE, FALSE,
5364 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5367 Xball_2B, FALSE, FALSE,
5368 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5371 Yball_eat, FALSE, FALSE,
5372 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
5375 Ykey_1_eat, FALSE, FALSE,
5376 EL_EM_KEY_1, ACTION_COLLECTING, -1
5379 Ykey_2_eat, FALSE, FALSE,
5380 EL_EM_KEY_2, ACTION_COLLECTING, -1
5383 Ykey_3_eat, FALSE, FALSE,
5384 EL_EM_KEY_3, ACTION_COLLECTING, -1
5387 Ykey_4_eat, FALSE, FALSE,
5388 EL_EM_KEY_4, ACTION_COLLECTING, -1
5391 Ykey_5_eat, FALSE, FALSE,
5392 EL_EMC_KEY_5, ACTION_COLLECTING, -1
5395 Ykey_6_eat, FALSE, FALSE,
5396 EL_EMC_KEY_6, ACTION_COLLECTING, -1
5399 Ykey_7_eat, FALSE, FALSE,
5400 EL_EMC_KEY_7, ACTION_COLLECTING, -1
5403 Ykey_8_eat, FALSE, FALSE,
5404 EL_EMC_KEY_8, ACTION_COLLECTING, -1
5407 Ylenses_eat, FALSE, FALSE,
5408 EL_EMC_LENSES, ACTION_COLLECTING, -1
5411 Ymagnify_eat, FALSE, FALSE,
5412 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
5415 Ygrass_eat, FALSE, FALSE,
5416 EL_EMC_GRASS, ACTION_SNAPPING, -1
5419 Ydirt_eat, FALSE, FALSE,
5420 EL_SAND, ACTION_SNAPPING, -1
5423 Xgrow_ns, TRUE, FALSE,
5424 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
5427 Ygrow_ns_eat, FALSE, FALSE,
5428 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
5431 Xgrow_ew, TRUE, FALSE,
5432 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
5435 Ygrow_ew_eat, FALSE, FALSE,
5436 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
5439 Xwonderwall, TRUE, FALSE,
5440 EL_MAGIC_WALL, -1, -1
5443 XwonderwallB, FALSE, FALSE,
5444 EL_MAGIC_WALL, ACTION_ACTIVE, -1
5447 Xamoeba_1, TRUE, FALSE,
5448 EL_AMOEBA_DRY, ACTION_OTHER, -1
5451 Xamoeba_2, FALSE, FALSE,
5452 EL_AMOEBA_DRY, ACTION_OTHER, -1
5455 Xamoeba_3, FALSE, FALSE,
5456 EL_AMOEBA_DRY, ACTION_OTHER, -1
5459 Xamoeba_4, FALSE, FALSE,
5460 EL_AMOEBA_DRY, ACTION_OTHER, -1
5463 Xamoeba_5, TRUE, FALSE,
5464 EL_AMOEBA_WET, ACTION_OTHER, -1
5467 Xamoeba_6, FALSE, FALSE,
5468 EL_AMOEBA_WET, ACTION_OTHER, -1
5471 Xamoeba_7, FALSE, FALSE,
5472 EL_AMOEBA_WET, ACTION_OTHER, -1
5475 Xamoeba_8, FALSE, FALSE,
5476 EL_AMOEBA_WET, ACTION_OTHER, -1
5479 Xdoor_1, TRUE, FALSE,
5480 EL_EM_GATE_1, -1, -1
5483 Xdoor_2, TRUE, FALSE,
5484 EL_EM_GATE_2, -1, -1
5487 Xdoor_3, TRUE, FALSE,
5488 EL_EM_GATE_3, -1, -1
5491 Xdoor_4, TRUE, FALSE,
5492 EL_EM_GATE_4, -1, -1
5495 Xdoor_5, TRUE, FALSE,
5496 EL_EMC_GATE_5, -1, -1
5499 Xdoor_6, TRUE, FALSE,
5500 EL_EMC_GATE_6, -1, -1
5503 Xdoor_7, TRUE, FALSE,
5504 EL_EMC_GATE_7, -1, -1
5507 Xdoor_8, TRUE, FALSE,
5508 EL_EMC_GATE_8, -1, -1
5511 Xkey_1, TRUE, FALSE,
5515 Xkey_2, TRUE, FALSE,
5519 Xkey_3, TRUE, FALSE,
5523 Xkey_4, TRUE, FALSE,
5527 Xkey_5, TRUE, FALSE,
5528 EL_EMC_KEY_5, -1, -1
5531 Xkey_6, TRUE, FALSE,
5532 EL_EMC_KEY_6, -1, -1
5535 Xkey_7, TRUE, FALSE,
5536 EL_EMC_KEY_7, -1, -1
5539 Xkey_8, TRUE, FALSE,
5540 EL_EMC_KEY_8, -1, -1
5543 Xwind_n, TRUE, FALSE,
5544 EL_BALLOON_SWITCH_UP, -1, -1
5547 Xwind_e, TRUE, FALSE,
5548 EL_BALLOON_SWITCH_RIGHT, -1, -1
5551 Xwind_s, TRUE, FALSE,
5552 EL_BALLOON_SWITCH_DOWN, -1, -1
5555 Xwind_w, TRUE, FALSE,
5556 EL_BALLOON_SWITCH_LEFT, -1, -1
5559 Xwind_nesw, TRUE, FALSE,
5560 EL_BALLOON_SWITCH_ANY, -1, -1
5563 Xwind_stop, TRUE, FALSE,
5564 EL_BALLOON_SWITCH_NONE, -1, -1
5568 EL_EM_EXIT_CLOSED, -1, -1
5571 Xexit_1, TRUE, FALSE,
5572 EL_EM_EXIT_OPEN, -1, -1
5575 Xexit_2, FALSE, FALSE,
5576 EL_EM_EXIT_OPEN, -1, -1
5579 Xexit_3, FALSE, FALSE,
5580 EL_EM_EXIT_OPEN, -1, -1
5583 Xdynamite, TRUE, FALSE,
5584 EL_EM_DYNAMITE, -1, -1
5587 Ydynamite_eat, FALSE, FALSE,
5588 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
5591 Xdynamite_1, TRUE, FALSE,
5592 EL_EM_DYNAMITE_ACTIVE, -1, -1
5595 Xdynamite_2, FALSE, FALSE,
5596 EL_EM_DYNAMITE_ACTIVE, -1, -1
5599 Xdynamite_3, FALSE, FALSE,
5600 EL_EM_DYNAMITE_ACTIVE, -1, -1
5603 Xdynamite_4, FALSE, FALSE,
5604 EL_EM_DYNAMITE_ACTIVE, -1, -1
5607 Xbumper, TRUE, FALSE,
5608 EL_EMC_SPRING_BUMPER, -1, -1
5611 XbumperB, FALSE, FALSE,
5612 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
5615 Xwheel, TRUE, FALSE,
5616 EL_ROBOT_WHEEL, -1, -1
5619 XwheelB, FALSE, FALSE,
5620 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
5623 Xswitch, TRUE, FALSE,
5624 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
5627 XswitchB, FALSE, FALSE,
5628 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
5632 EL_QUICKSAND_EMPTY, -1, -1
5635 Xsand_stone, TRUE, FALSE,
5636 EL_QUICKSAND_FULL, -1, -1
5639 Xsand_stonein_1, FALSE, TRUE,
5640 EL_ROCK, ACTION_FILLING, -1
5643 Xsand_stonein_2, FALSE, TRUE,
5644 EL_ROCK, ACTION_FILLING, -1
5647 Xsand_stonein_3, FALSE, TRUE,
5648 EL_ROCK, ACTION_FILLING, -1
5651 Xsand_stonein_4, FALSE, TRUE,
5652 EL_ROCK, ACTION_FILLING, -1
5655 Xsand_stonesand_1, FALSE, FALSE,
5656 EL_QUICKSAND_EMPTYING, -1, -1
5659 Xsand_stonesand_2, FALSE, FALSE,
5660 EL_QUICKSAND_EMPTYING, -1, -1
5663 Xsand_stonesand_3, FALSE, FALSE,
5664 EL_QUICKSAND_EMPTYING, -1, -1
5667 Xsand_stonesand_4, FALSE, FALSE,
5668 EL_QUICKSAND_EMPTYING, -1, -1
5671 Xsand_stonesand_quickout_1, FALSE, FALSE,
5672 EL_QUICKSAND_EMPTYING, -1, -1
5675 Xsand_stonesand_quickout_2, FALSE, FALSE,
5676 EL_QUICKSAND_EMPTYING, -1, -1
5679 Xsand_stoneout_1, FALSE, FALSE,
5680 EL_ROCK, ACTION_EMPTYING, -1
5683 Xsand_stoneout_2, FALSE, FALSE,
5684 EL_ROCK, ACTION_EMPTYING, -1
5687 Xsand_sandstone_1, FALSE, FALSE,
5688 EL_QUICKSAND_FILLING, -1, -1
5691 Xsand_sandstone_2, FALSE, FALSE,
5692 EL_QUICKSAND_FILLING, -1, -1
5695 Xsand_sandstone_3, FALSE, FALSE,
5696 EL_QUICKSAND_FILLING, -1, -1
5699 Xsand_sandstone_4, FALSE, FALSE,
5700 EL_QUICKSAND_FILLING, -1, -1
5703 Xplant, TRUE, FALSE,
5704 EL_EMC_PLANT, -1, -1
5707 Yplant, FALSE, FALSE,
5708 EL_EMC_PLANT, -1, -1
5711 Xlenses, TRUE, FALSE,
5712 EL_EMC_LENSES, -1, -1
5715 Xmagnify, TRUE, FALSE,
5716 EL_EMC_MAGNIFIER, -1, -1
5719 Xdripper, TRUE, FALSE,
5720 EL_EMC_DRIPPER, -1, -1
5723 XdripperB, FALSE, FALSE,
5724 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
5727 Xfake_blank, TRUE, FALSE,
5728 EL_INVISIBLE_WALL, -1, -1
5731 Xfake_blankB, FALSE, FALSE,
5732 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
5735 Xfake_grass, TRUE, FALSE,
5736 EL_EMC_FAKE_GRASS, -1, -1
5739 Xfake_grassB, FALSE, FALSE,
5740 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
5743 Xfake_door_1, TRUE, FALSE,
5744 EL_EM_GATE_1_GRAY, -1, -1
5747 Xfake_door_2, TRUE, FALSE,
5748 EL_EM_GATE_2_GRAY, -1, -1
5751 Xfake_door_3, TRUE, FALSE,
5752 EL_EM_GATE_3_GRAY, -1, -1
5755 Xfake_door_4, TRUE, FALSE,
5756 EL_EM_GATE_4_GRAY, -1, -1
5759 Xfake_door_5, TRUE, FALSE,
5760 EL_EMC_GATE_5_GRAY, -1, -1
5763 Xfake_door_6, TRUE, FALSE,
5764 EL_EMC_GATE_6_GRAY, -1, -1
5767 Xfake_door_7, TRUE, FALSE,
5768 EL_EMC_GATE_7_GRAY, -1, -1
5771 Xfake_door_8, TRUE, FALSE,
5772 EL_EMC_GATE_8_GRAY, -1, -1
5775 Xfake_acid_1, TRUE, FALSE,
5776 EL_EMC_FAKE_ACID, -1, -1
5779 Xfake_acid_2, FALSE, FALSE,
5780 EL_EMC_FAKE_ACID, -1, -1
5783 Xfake_acid_3, FALSE, FALSE,
5784 EL_EMC_FAKE_ACID, -1, -1
5787 Xfake_acid_4, FALSE, FALSE,
5788 EL_EMC_FAKE_ACID, -1, -1
5791 Xfake_acid_5, FALSE, FALSE,
5792 EL_EMC_FAKE_ACID, -1, -1
5795 Xfake_acid_6, FALSE, FALSE,
5796 EL_EMC_FAKE_ACID, -1, -1
5799 Xfake_acid_7, FALSE, FALSE,
5800 EL_EMC_FAKE_ACID, -1, -1
5803 Xfake_acid_8, FALSE, FALSE,
5804 EL_EMC_FAKE_ACID, -1, -1
5807 Xsteel_1, TRUE, FALSE,
5808 EL_STEELWALL, -1, -1
5811 Xsteel_2, TRUE, FALSE,
5812 EL_EMC_STEELWALL_2, -1, -1
5815 Xsteel_3, TRUE, FALSE,
5816 EL_EMC_STEELWALL_3, -1, -1
5819 Xsteel_4, TRUE, FALSE,
5820 EL_EMC_STEELWALL_4, -1, -1
5823 Xwall_1, TRUE, FALSE,
5827 Xwall_2, TRUE, FALSE,
5828 EL_EMC_WALL_14, -1, -1
5831 Xwall_3, TRUE, FALSE,
5832 EL_EMC_WALL_15, -1, -1
5835 Xwall_4, TRUE, FALSE,
5836 EL_EMC_WALL_16, -1, -1
5839 Xround_wall_1, TRUE, FALSE,
5840 EL_WALL_SLIPPERY, -1, -1
5843 Xround_wall_2, TRUE, FALSE,
5844 EL_EMC_WALL_SLIPPERY_2, -1, -1
5847 Xround_wall_3, TRUE, FALSE,
5848 EL_EMC_WALL_SLIPPERY_3, -1, -1
5851 Xround_wall_4, TRUE, FALSE,
5852 EL_EMC_WALL_SLIPPERY_4, -1, -1
5855 Xdecor_1, TRUE, FALSE,
5856 EL_EMC_WALL_8, -1, -1
5859 Xdecor_2, TRUE, FALSE,
5860 EL_EMC_WALL_6, -1, -1
5863 Xdecor_3, TRUE, FALSE,
5864 EL_EMC_WALL_4, -1, -1
5867 Xdecor_4, TRUE, FALSE,
5868 EL_EMC_WALL_7, -1, -1
5871 Xdecor_5, TRUE, FALSE,
5872 EL_EMC_WALL_5, -1, -1
5875 Xdecor_6, TRUE, FALSE,
5876 EL_EMC_WALL_9, -1, -1
5879 Xdecor_7, TRUE, FALSE,
5880 EL_EMC_WALL_10, -1, -1
5883 Xdecor_8, TRUE, FALSE,
5884 EL_EMC_WALL_1, -1, -1
5887 Xdecor_9, TRUE, FALSE,
5888 EL_EMC_WALL_2, -1, -1
5891 Xdecor_10, TRUE, FALSE,
5892 EL_EMC_WALL_3, -1, -1
5895 Xdecor_11, TRUE, FALSE,
5896 EL_EMC_WALL_11, -1, -1
5899 Xdecor_12, TRUE, FALSE,
5900 EL_EMC_WALL_12, -1, -1
5903 Xalpha_0, TRUE, FALSE,
5904 EL_CHAR('0'), -1, -1
5907 Xalpha_1, TRUE, FALSE,
5908 EL_CHAR('1'), -1, -1
5911 Xalpha_2, TRUE, FALSE,
5912 EL_CHAR('2'), -1, -1
5915 Xalpha_3, TRUE, FALSE,
5916 EL_CHAR('3'), -1, -1
5919 Xalpha_4, TRUE, FALSE,
5920 EL_CHAR('4'), -1, -1
5923 Xalpha_5, TRUE, FALSE,
5924 EL_CHAR('5'), -1, -1
5927 Xalpha_6, TRUE, FALSE,
5928 EL_CHAR('6'), -1, -1
5931 Xalpha_7, TRUE, FALSE,
5932 EL_CHAR('7'), -1, -1
5935 Xalpha_8, TRUE, FALSE,
5936 EL_CHAR('8'), -1, -1
5939 Xalpha_9, TRUE, FALSE,
5940 EL_CHAR('9'), -1, -1
5943 Xalpha_excla, TRUE, FALSE,
5944 EL_CHAR('!'), -1, -1
5947 Xalpha_quote, TRUE, FALSE,
5948 EL_CHAR('"'), -1, -1
5951 Xalpha_comma, TRUE, FALSE,
5952 EL_CHAR(','), -1, -1
5955 Xalpha_minus, TRUE, FALSE,
5956 EL_CHAR('-'), -1, -1
5959 Xalpha_perio, TRUE, FALSE,
5960 EL_CHAR('.'), -1, -1
5963 Xalpha_colon, TRUE, FALSE,
5964 EL_CHAR(':'), -1, -1
5967 Xalpha_quest, TRUE, FALSE,
5968 EL_CHAR('?'), -1, -1
5971 Xalpha_a, TRUE, FALSE,
5972 EL_CHAR('A'), -1, -1
5975 Xalpha_b, TRUE, FALSE,
5976 EL_CHAR('B'), -1, -1
5979 Xalpha_c, TRUE, FALSE,
5980 EL_CHAR('C'), -1, -1
5983 Xalpha_d, TRUE, FALSE,
5984 EL_CHAR('D'), -1, -1
5987 Xalpha_e, TRUE, FALSE,
5988 EL_CHAR('E'), -1, -1
5991 Xalpha_f, TRUE, FALSE,
5992 EL_CHAR('F'), -1, -1
5995 Xalpha_g, TRUE, FALSE,
5996 EL_CHAR('G'), -1, -1
5999 Xalpha_h, TRUE, FALSE,
6000 EL_CHAR('H'), -1, -1
6003 Xalpha_i, TRUE, FALSE,
6004 EL_CHAR('I'), -1, -1
6007 Xalpha_j, TRUE, FALSE,
6008 EL_CHAR('J'), -1, -1
6011 Xalpha_k, TRUE, FALSE,
6012 EL_CHAR('K'), -1, -1
6015 Xalpha_l, TRUE, FALSE,
6016 EL_CHAR('L'), -1, -1
6019 Xalpha_m, TRUE, FALSE,
6020 EL_CHAR('M'), -1, -1
6023 Xalpha_n, TRUE, FALSE,
6024 EL_CHAR('N'), -1, -1
6027 Xalpha_o, TRUE, FALSE,
6028 EL_CHAR('O'), -1, -1
6031 Xalpha_p, TRUE, FALSE,
6032 EL_CHAR('P'), -1, -1
6035 Xalpha_q, TRUE, FALSE,
6036 EL_CHAR('Q'), -1, -1
6039 Xalpha_r, TRUE, FALSE,
6040 EL_CHAR('R'), -1, -1
6043 Xalpha_s, TRUE, FALSE,
6044 EL_CHAR('S'), -1, -1
6047 Xalpha_t, TRUE, FALSE,
6048 EL_CHAR('T'), -1, -1
6051 Xalpha_u, TRUE, FALSE,
6052 EL_CHAR('U'), -1, -1
6055 Xalpha_v, TRUE, FALSE,
6056 EL_CHAR('V'), -1, -1
6059 Xalpha_w, TRUE, FALSE,
6060 EL_CHAR('W'), -1, -1
6063 Xalpha_x, TRUE, FALSE,
6064 EL_CHAR('X'), -1, -1
6067 Xalpha_y, TRUE, FALSE,
6068 EL_CHAR('Y'), -1, -1
6071 Xalpha_z, TRUE, FALSE,
6072 EL_CHAR('Z'), -1, -1
6075 Xalpha_arrow_e, TRUE, FALSE,
6076 EL_CHAR('>'), -1, -1
6079 Xalpha_arrow_w, TRUE, FALSE,
6080 EL_CHAR('<'), -1, -1
6083 Xalpha_copyr, TRUE, FALSE,
6084 EL_CHAR(CHAR_BYTE_COPYRIGHT), -1, -1
6088 Xboom_bug, FALSE, FALSE,
6089 EL_BUG, ACTION_EXPLODING, -1
6092 Xboom_bomb, FALSE, FALSE,
6093 EL_BOMB, ACTION_EXPLODING, -1
6096 Xboom_android, FALSE, FALSE,
6097 EL_EMC_ANDROID, ACTION_OTHER, -1
6100 Xboom_1, FALSE, FALSE,
6101 EL_DEFAULT, ACTION_EXPLODING, -1
6104 Xboom_2, FALSE, FALSE,
6105 EL_DEFAULT, ACTION_EXPLODING, -1
6108 Znormal, FALSE, FALSE,
6112 Zdynamite, FALSE, FALSE,
6116 Zplayer, FALSE, FALSE,
6120 ZBORDER, FALSE, FALSE,
6130 static struct Mapping_EM_to_RND_player
6139 em_player_mapping_list[] =
6143 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
6147 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
6151 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
6155 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
6159 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
6163 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
6167 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
6171 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
6175 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
6179 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
6183 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
6187 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
6191 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
6195 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
6199 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
6203 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
6207 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
6211 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
6215 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
6219 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
6223 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
6227 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
6231 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
6235 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
6239 EL_PLAYER_1, ACTION_DEFAULT, -1,
6243 EL_PLAYER_2, ACTION_DEFAULT, -1,
6247 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
6251 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
6255 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
6259 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
6263 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
6267 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
6271 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
6275 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
6279 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
6283 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
6287 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
6291 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
6295 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
6299 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
6303 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
6307 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
6311 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
6315 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
6319 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
6323 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
6327 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
6331 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
6335 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
6339 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
6343 EL_PLAYER_3, ACTION_DEFAULT, -1,
6347 EL_PLAYER_4, ACTION_DEFAULT, -1,
6356 int map_element_RND_to_EM(int element_rnd)
6358 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
6359 static boolean mapping_initialized = FALSE;
6361 if (!mapping_initialized)
6365 /* return "Xalpha_quest" for all undefined elements in mapping array */
6366 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
6367 mapping_RND_to_EM[i] = Xalpha_quest;
6369 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6370 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
6371 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
6372 em_object_mapping_list[i].element_em;
6374 mapping_initialized = TRUE;
6377 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
6378 return mapping_RND_to_EM[element_rnd];
6380 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
6385 int map_element_EM_to_RND(int element_em)
6387 static unsigned short mapping_EM_to_RND[TILE_MAX];
6388 static boolean mapping_initialized = FALSE;
6390 if (!mapping_initialized)
6394 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
6395 for (i = 0; i < TILE_MAX; i++)
6396 mapping_EM_to_RND[i] = EL_UNKNOWN;
6398 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6399 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
6400 em_object_mapping_list[i].element_rnd;
6402 mapping_initialized = TRUE;
6405 if (element_em >= 0 && element_em < TILE_MAX)
6406 return mapping_EM_to_RND[element_em];
6408 Error(ERR_WARN, "invalid EM level element %d", element_em);
6413 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
6415 struct LevelInfo_EM *level_em = level->native_em_level;
6416 struct LEVEL *lev = level_em->lev;
6419 for (i = 0; i < TILE_MAX; i++)
6420 lev->android_array[i] = Xblank;
6422 for (i = 0; i < level->num_android_clone_elements; i++)
6424 int element_rnd = level->android_clone_element[i];
6425 int element_em = map_element_RND_to_EM(element_rnd);
6427 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
6428 if (em_object_mapping_list[j].element_rnd == element_rnd)
6429 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
6433 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
6435 struct LevelInfo_EM *level_em = level->native_em_level;
6436 struct LEVEL *lev = level_em->lev;
6439 level->num_android_clone_elements = 0;
6441 for (i = 0; i < TILE_MAX; i++)
6443 int element_em = lev->android_array[i];
6445 boolean element_found = FALSE;
6447 if (element_em == Xblank)
6450 element_rnd = map_element_EM_to_RND(element_em);
6452 for (j = 0; j < level->num_android_clone_elements; j++)
6453 if (level->android_clone_element[j] == element_rnd)
6454 element_found = TRUE;
6458 level->android_clone_element[level->num_android_clone_elements++] =
6461 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
6466 if (level->num_android_clone_elements == 0)
6468 level->num_android_clone_elements = 1;
6469 level->android_clone_element[0] = EL_EMPTY;
6473 int map_direction_RND_to_EM(int direction)
6475 return (direction == MV_UP ? 0 :
6476 direction == MV_RIGHT ? 1 :
6477 direction == MV_DOWN ? 2 :
6478 direction == MV_LEFT ? 3 :
6482 int map_direction_EM_to_RND(int direction)
6484 return (direction == 0 ? MV_UP :
6485 direction == 1 ? MV_RIGHT :
6486 direction == 2 ? MV_DOWN :
6487 direction == 3 ? MV_LEFT :
6491 int map_element_RND_to_SP(int element_rnd)
6493 int element_sp = 0x20; /* map unknown elements to yellow "hardware" */
6495 if (element_rnd >= EL_SP_START &&
6496 element_rnd <= EL_SP_END)
6497 element_sp = element_rnd - EL_SP_START;
6498 else if (element_rnd == EL_EMPTY_SPACE)
6500 else if (element_rnd == EL_INVISIBLE_WALL)
6506 int map_element_SP_to_RND(int element_sp)
6508 int element_rnd = EL_UNKNOWN;
6510 if (element_sp >= 0x00 &&
6512 element_rnd = EL_SP_START + element_sp;
6513 else if (element_sp == 0x28)
6514 element_rnd = EL_INVISIBLE_WALL;
6519 int map_action_SP_to_RND(int action_sp)
6523 case actActive: return ACTION_ACTIVE;
6524 case actImpact: return ACTION_IMPACT;
6525 case actExploding: return ACTION_EXPLODING;
6526 case actDigging: return ACTION_DIGGING;
6527 case actSnapping: return ACTION_SNAPPING;
6528 case actCollecting: return ACTION_COLLECTING;
6529 case actPassing: return ACTION_PASSING;
6530 case actPushing: return ACTION_PUSHING;
6531 case actDropping: return ACTION_DROPPING;
6533 default: return ACTION_DEFAULT;
6537 int get_next_element(int element)
6541 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
6542 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
6543 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
6544 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
6545 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
6546 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
6547 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
6548 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
6549 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
6550 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
6551 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
6553 default: return element;
6557 int el_act_dir2img(int element, int action, int direction)
6559 element = GFX_ELEMENT(element);
6560 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
6562 /* direction_graphic[][] == graphic[] for undefined direction graphics */
6563 return element_info[element].direction_graphic[action][direction];
6566 static int el_act_dir2crm(int element, int action, int direction)
6568 element = GFX_ELEMENT(element);
6569 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
6571 /* direction_graphic[][] == graphic[] for undefined direction graphics */
6572 return element_info[element].direction_crumbled[action][direction];
6575 int el_act2img(int element, int action)
6577 element = GFX_ELEMENT(element);
6579 return element_info[element].graphic[action];
6582 int el_act2crm(int element, int action)
6584 element = GFX_ELEMENT(element);
6586 return element_info[element].crumbled[action];
6589 int el_dir2img(int element, int direction)
6591 element = GFX_ELEMENT(element);
6593 return el_act_dir2img(element, ACTION_DEFAULT, direction);
6596 int el2baseimg(int element)
6598 return element_info[element].graphic[ACTION_DEFAULT];
6601 int el2img(int element)
6603 element = GFX_ELEMENT(element);
6605 return element_info[element].graphic[ACTION_DEFAULT];
6608 int el2edimg(int element)
6610 element = GFX_ELEMENT(element);
6612 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
6615 int el2preimg(int element)
6617 element = GFX_ELEMENT(element);
6619 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
6622 int el2panelimg(int element)
6624 element = GFX_ELEMENT(element);
6626 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL];
6629 int font2baseimg(int font_nr)
6631 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
6634 int getBeltNrFromBeltElement(int element)
6636 return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
6637 element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
6638 element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
6641 int getBeltNrFromBeltActiveElement(int element)
6643 return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
6644 element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
6645 element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
6648 int getBeltNrFromBeltSwitchElement(int element)
6650 return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
6651 element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
6652 element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
6655 int getBeltDirNrFromBeltElement(int element)
6657 static int belt_base_element[4] =
6659 EL_CONVEYOR_BELT_1_LEFT,
6660 EL_CONVEYOR_BELT_2_LEFT,
6661 EL_CONVEYOR_BELT_3_LEFT,
6662 EL_CONVEYOR_BELT_4_LEFT
6665 int belt_nr = getBeltNrFromBeltElement(element);
6666 int belt_dir_nr = element - belt_base_element[belt_nr];
6668 return (belt_dir_nr % 3);
6671 int getBeltDirNrFromBeltSwitchElement(int element)
6673 static int belt_base_element[4] =
6675 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
6676 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
6677 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
6678 EL_CONVEYOR_BELT_4_SWITCH_LEFT
6681 int belt_nr = getBeltNrFromBeltSwitchElement(element);
6682 int belt_dir_nr = element - belt_base_element[belt_nr];
6684 return (belt_dir_nr % 3);
6687 int getBeltDirFromBeltElement(int element)
6689 static int belt_move_dir[3] =
6696 int belt_dir_nr = getBeltDirNrFromBeltElement(element);
6698 return belt_move_dir[belt_dir_nr];
6701 int getBeltDirFromBeltSwitchElement(int element)
6703 static int belt_move_dir[3] =
6710 int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
6712 return belt_move_dir[belt_dir_nr];
6715 int getBeltElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
6717 static int belt_base_element[4] =
6719 EL_CONVEYOR_BELT_1_LEFT,
6720 EL_CONVEYOR_BELT_2_LEFT,
6721 EL_CONVEYOR_BELT_3_LEFT,
6722 EL_CONVEYOR_BELT_4_LEFT
6725 return belt_base_element[belt_nr] + belt_dir_nr;
6728 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
6730 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
6732 return getBeltElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
6735 int getBeltSwitchElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
6737 static int belt_base_element[4] =
6739 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
6740 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
6741 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
6742 EL_CONVEYOR_BELT_4_SWITCH_LEFT
6745 return belt_base_element[belt_nr] + belt_dir_nr;
6748 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
6750 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
6752 return getBeltSwitchElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
6755 boolean getTeamMode_EM()
6757 return game.team_mode;
6760 int getGameFrameDelay_EM(int native_em_game_frame_delay)
6762 int game_frame_delay_value;
6764 game_frame_delay_value =
6765 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
6766 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
6769 if (tape.playing && tape.warp_forward && !tape.pausing)
6770 game_frame_delay_value = 0;
6772 return game_frame_delay_value;
6775 unsigned int InitRND(int seed)
6777 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
6778 return InitEngineRandom_EM(seed);
6779 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
6780 return InitEngineRandom_SP(seed);
6782 return InitEngineRandom_RND(seed);
6785 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
6786 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
6788 inline static int get_effective_element_EM(int tile, int frame_em)
6790 int element = object_mapping[tile].element_rnd;
6791 int action = object_mapping[tile].action;
6792 boolean is_backside = object_mapping[tile].is_backside;
6793 boolean action_removing = (action == ACTION_DIGGING ||
6794 action == ACTION_SNAPPING ||
6795 action == ACTION_COLLECTING);
6801 case Yacid_splash_eB:
6802 case Yacid_splash_wB:
6803 return (frame_em > 5 ? EL_EMPTY : element);
6809 else /* frame_em == 7 */
6813 case Yacid_splash_eB:
6814 case Yacid_splash_wB:
6817 case Yemerald_stone:
6820 case Ydiamond_stone:
6824 case Xdrip_stretchB:
6843 case Xsand_stonein_1:
6844 case Xsand_stonein_2:
6845 case Xsand_stonein_3:
6846 case Xsand_stonein_4:
6850 return (is_backside || action_removing ? EL_EMPTY : element);
6855 inline static boolean check_linear_animation_EM(int tile)
6859 case Xsand_stonesand_1:
6860 case Xsand_stonesand_quickout_1:
6861 case Xsand_sandstone_1:
6862 case Xsand_stonein_1:
6863 case Xsand_stoneout_1:
6882 case Yacid_splash_eB:
6883 case Yacid_splash_wB:
6884 case Yemerald_stone:
6891 inline static void set_crumbled_graphics_EM(struct GraphicInfo_EM *g_em,
6892 boolean has_crumbled_graphics,
6893 int crumbled, int sync_frame)
6895 /* if element can be crumbled, but certain action graphics are just empty
6896 space (like instantly snapping sand to empty space in 1 frame), do not
6897 treat these empty space graphics as crumbled graphics in EMC engine */
6898 if (crumbled == IMG_EMPTY_SPACE)
6899 has_crumbled_graphics = FALSE;
6901 if (has_crumbled_graphics)
6903 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
6904 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
6905 g_crumbled->anim_delay,
6906 g_crumbled->anim_mode,
6907 g_crumbled->anim_start_frame,
6910 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
6911 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
6913 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
6915 g_em->has_crumbled_graphics = TRUE;
6919 g_em->crumbled_bitmap = NULL;
6920 g_em->crumbled_src_x = 0;
6921 g_em->crumbled_src_y = 0;
6922 g_em->crumbled_border_size = 0;
6924 g_em->has_crumbled_graphics = FALSE;
6928 void ResetGfxAnimation_EM(int x, int y, int tile)
6933 void SetGfxAnimation_EM(struct GraphicInfo_EM *g_em,
6934 int tile, int frame_em, int x, int y)
6936 int action = object_mapping[tile].action;
6937 int direction = object_mapping[tile].direction;
6938 int effective_element = get_effective_element_EM(tile, frame_em);
6939 int graphic = (direction == MV_NONE ?
6940 el_act2img(effective_element, action) :
6941 el_act_dir2img(effective_element, action, direction));
6942 struct GraphicInfo *g = &graphic_info[graphic];
6944 boolean action_removing = (action == ACTION_DIGGING ||
6945 action == ACTION_SNAPPING ||
6946 action == ACTION_COLLECTING);
6947 boolean action_moving = (action == ACTION_FALLING ||
6948 action == ACTION_MOVING ||
6949 action == ACTION_PUSHING ||
6950 action == ACTION_EATING ||
6951 action == ACTION_FILLING ||
6952 action == ACTION_EMPTYING);
6953 boolean action_falling = (action == ACTION_FALLING ||
6954 action == ACTION_FILLING ||
6955 action == ACTION_EMPTYING);
6957 /* special case: graphic uses "2nd movement tile" and has defined
6958 7 frames for movement animation (or less) => use default graphic
6959 for last (8th) frame which ends the movement animation */
6960 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
6962 action = ACTION_DEFAULT; /* (keep action_* unchanged for now) */
6963 graphic = (direction == MV_NONE ?
6964 el_act2img(effective_element, action) :
6965 el_act_dir2img(effective_element, action, direction));
6967 g = &graphic_info[graphic];
6970 if ((action_removing || check_linear_animation_EM(tile)) && frame_em == 0)
6974 else if (action_moving)
6976 boolean is_backside = object_mapping[tile].is_backside;
6980 int direction = object_mapping[tile].direction;
6981 int move_dir = (action_falling ? MV_DOWN : direction);
6986 /* !!! TEST !!! NEW !!! DOES NOT WORK RIGHT YET !!! */
6987 if (g->double_movement && frame_em == 0)
6991 if (move_dir == MV_LEFT)
6992 GfxFrame[x - 1][y] = GfxFrame[x][y];
6993 else if (move_dir == MV_RIGHT)
6994 GfxFrame[x + 1][y] = GfxFrame[x][y];
6995 else if (move_dir == MV_UP)
6996 GfxFrame[x][y - 1] = GfxFrame[x][y];
6997 else if (move_dir == MV_DOWN)
6998 GfxFrame[x][y + 1] = GfxFrame[x][y];
7005 /* special case: animation for Xsand_stonesand_quickout_1/2 twice as fast */
7006 if (tile == Xsand_stonesand_quickout_1 ||
7007 tile == Xsand_stonesand_quickout_2)
7011 if (graphic_info[graphic].anim_global_sync)
7012 sync_frame = FrameCounter;
7013 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
7014 sync_frame = GfxFrame[x][y];
7016 sync_frame = 0; /* playfield border (pseudo steel) */
7018 SetRandomAnimationValue(x, y);
7020 int frame = getAnimationFrame(g->anim_frames,
7023 g->anim_start_frame,
7026 g_em->unique_identifier =
7027 (graphic << 16) | ((frame % 8) << 12) | (g_em->width << 6) | g_em->height;
7030 void getGraphicSourceObjectExt_EM(struct GraphicInfo_EM *g_em,
7031 int tile, int frame_em, int x, int y)
7033 int action = object_mapping[tile].action;
7034 int direction = object_mapping[tile].direction;
7035 boolean is_backside = object_mapping[tile].is_backside;
7036 int effective_element = get_effective_element_EM(tile, frame_em);
7037 int effective_action = action;
7038 int graphic = (direction == MV_NONE ?
7039 el_act2img(effective_element, effective_action) :
7040 el_act_dir2img(effective_element, effective_action,
7042 int crumbled = (direction == MV_NONE ?
7043 el_act2crm(effective_element, effective_action) :
7044 el_act_dir2crm(effective_element, effective_action,
7046 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7047 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7048 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7049 struct GraphicInfo *g = &graphic_info[graphic];
7052 /* special case: graphic uses "2nd movement tile" and has defined
7053 7 frames for movement animation (or less) => use default graphic
7054 for last (8th) frame which ends the movement animation */
7055 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
7057 effective_action = ACTION_DEFAULT;
7058 graphic = (direction == MV_NONE ?
7059 el_act2img(effective_element, effective_action) :
7060 el_act_dir2img(effective_element, effective_action,
7062 crumbled = (direction == MV_NONE ?
7063 el_act2crm(effective_element, effective_action) :
7064 el_act_dir2crm(effective_element, effective_action,
7067 g = &graphic_info[graphic];
7070 if (graphic_info[graphic].anim_global_sync)
7071 sync_frame = FrameCounter;
7072 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
7073 sync_frame = GfxFrame[x][y];
7075 sync_frame = 0; /* playfield border (pseudo steel) */
7077 SetRandomAnimationValue(x, y);
7079 int frame = getAnimationFrame(g->anim_frames,
7082 g->anim_start_frame,
7085 getGraphicSourceExt(graphic, frame, &g_em->bitmap, &g_em->src_x, &g_em->src_y,
7086 g->double_movement && is_backside);
7088 /* (updating the "crumbled" graphic definitions is probably not really needed,
7089 as animations for crumbled graphics can't be longer than one EMC cycle) */
7090 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
7094 void getGraphicSourcePlayerExt_EM(struct GraphicInfo_EM *g_em,
7095 int player_nr, int anim, int frame_em)
7097 int element = player_mapping[player_nr][anim].element_rnd;
7098 int action = player_mapping[player_nr][anim].action;
7099 int direction = player_mapping[player_nr][anim].direction;
7100 int graphic = (direction == MV_NONE ?
7101 el_act2img(element, action) :
7102 el_act_dir2img(element, action, direction));
7103 struct GraphicInfo *g = &graphic_info[graphic];
7106 InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
7108 stored_player[player_nr].StepFrame = frame_em;
7110 sync_frame = stored_player[player_nr].Frame;
7112 int frame = getAnimationFrame(g->anim_frames,
7115 g->anim_start_frame,
7118 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
7119 &g_em->src_x, &g_em->src_y, FALSE);
7122 void InitGraphicInfo_EM(void)
7127 int num_em_gfx_errors = 0;
7129 if (graphic_info_em_object[0][0].bitmap == NULL)
7131 /* EM graphics not yet initialized in em_open_all() */
7136 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
7139 /* always start with reliable default values */
7140 for (i = 0; i < TILE_MAX; i++)
7142 object_mapping[i].element_rnd = EL_UNKNOWN;
7143 object_mapping[i].is_backside = FALSE;
7144 object_mapping[i].action = ACTION_DEFAULT;
7145 object_mapping[i].direction = MV_NONE;
7148 /* always start with reliable default values */
7149 for (p = 0; p < MAX_PLAYERS; p++)
7151 for (i = 0; i < SPR_MAX; i++)
7153 player_mapping[p][i].element_rnd = EL_UNKNOWN;
7154 player_mapping[p][i].action = ACTION_DEFAULT;
7155 player_mapping[p][i].direction = MV_NONE;
7159 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
7161 int e = em_object_mapping_list[i].element_em;
7163 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
7164 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
7166 if (em_object_mapping_list[i].action != -1)
7167 object_mapping[e].action = em_object_mapping_list[i].action;
7169 if (em_object_mapping_list[i].direction != -1)
7170 object_mapping[e].direction =
7171 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
7174 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
7176 int a = em_player_mapping_list[i].action_em;
7177 int p = em_player_mapping_list[i].player_nr;
7179 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
7181 if (em_player_mapping_list[i].action != -1)
7182 player_mapping[p][a].action = em_player_mapping_list[i].action;
7184 if (em_player_mapping_list[i].direction != -1)
7185 player_mapping[p][a].direction =
7186 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
7189 for (i = 0; i < TILE_MAX; i++)
7191 int element = object_mapping[i].element_rnd;
7192 int action = object_mapping[i].action;
7193 int direction = object_mapping[i].direction;
7194 boolean is_backside = object_mapping[i].is_backside;
7195 boolean action_exploding = ((action == ACTION_EXPLODING ||
7196 action == ACTION_SMASHED_BY_ROCK ||
7197 action == ACTION_SMASHED_BY_SPRING) &&
7198 element != EL_DIAMOND);
7199 boolean action_active = (action == ACTION_ACTIVE);
7200 boolean action_other = (action == ACTION_OTHER);
7202 for (j = 0; j < 8; j++)
7204 int effective_element = get_effective_element_EM(i, j);
7205 int effective_action = (j < 7 ? action :
7206 i == Xdrip_stretch ? action :
7207 i == Xdrip_stretchB ? action :
7208 i == Ydrip_s1 ? action :
7209 i == Ydrip_s1B ? action :
7210 i == Xball_1B ? action :
7211 i == Xball_2 ? action :
7212 i == Xball_2B ? action :
7213 i == Yball_eat ? action :
7214 i == Ykey_1_eat ? action :
7215 i == Ykey_2_eat ? action :
7216 i == Ykey_3_eat ? action :
7217 i == Ykey_4_eat ? action :
7218 i == Ykey_5_eat ? action :
7219 i == Ykey_6_eat ? action :
7220 i == Ykey_7_eat ? action :
7221 i == Ykey_8_eat ? action :
7222 i == Ylenses_eat ? action :
7223 i == Ymagnify_eat ? action :
7224 i == Ygrass_eat ? action :
7225 i == Ydirt_eat ? action :
7226 i == Xsand_stonein_1 ? action :
7227 i == Xsand_stonein_2 ? action :
7228 i == Xsand_stonein_3 ? action :
7229 i == Xsand_stonein_4 ? action :
7230 i == Xsand_stoneout_1 ? action :
7231 i == Xsand_stoneout_2 ? action :
7232 i == Xboom_android ? ACTION_EXPLODING :
7233 action_exploding ? ACTION_EXPLODING :
7234 action_active ? action :
7235 action_other ? action :
7237 int graphic = (el_act_dir2img(effective_element, effective_action,
7239 int crumbled = (el_act_dir2crm(effective_element, effective_action,
7241 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7242 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7243 boolean has_action_graphics = (graphic != base_graphic);
7244 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7245 struct GraphicInfo *g = &graphic_info[graphic];
7246 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7249 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
7250 boolean special_animation = (action != ACTION_DEFAULT &&
7251 g->anim_frames == 3 &&
7252 g->anim_delay == 2 &&
7253 g->anim_mode & ANIM_LINEAR);
7254 int sync_frame = (i == Xdrip_stretch ? 7 :
7255 i == Xdrip_stretchB ? 7 :
7256 i == Ydrip_s2 ? j + 8 :
7257 i == Ydrip_s2B ? j + 8 :
7266 i == Xfake_acid_1 ? 0 :
7267 i == Xfake_acid_2 ? 10 :
7268 i == Xfake_acid_3 ? 20 :
7269 i == Xfake_acid_4 ? 30 :
7270 i == Xfake_acid_5 ? 40 :
7271 i == Xfake_acid_6 ? 50 :
7272 i == Xfake_acid_7 ? 60 :
7273 i == Xfake_acid_8 ? 70 :
7275 i == Xball_2B ? j + 8 :
7276 i == Yball_eat ? j + 1 :
7277 i == Ykey_1_eat ? j + 1 :
7278 i == Ykey_2_eat ? j + 1 :
7279 i == Ykey_3_eat ? j + 1 :
7280 i == Ykey_4_eat ? j + 1 :
7281 i == Ykey_5_eat ? j + 1 :
7282 i == Ykey_6_eat ? j + 1 :
7283 i == Ykey_7_eat ? j + 1 :
7284 i == Ykey_8_eat ? j + 1 :
7285 i == Ylenses_eat ? j + 1 :
7286 i == Ymagnify_eat ? j + 1 :
7287 i == Ygrass_eat ? j + 1 :
7288 i == Ydirt_eat ? j + 1 :
7289 i == Xamoeba_1 ? 0 :
7290 i == Xamoeba_2 ? 1 :
7291 i == Xamoeba_3 ? 2 :
7292 i == Xamoeba_4 ? 3 :
7293 i == Xamoeba_5 ? 0 :
7294 i == Xamoeba_6 ? 1 :
7295 i == Xamoeba_7 ? 2 :
7296 i == Xamoeba_8 ? 3 :
7297 i == Xexit_2 ? j + 8 :
7298 i == Xexit_3 ? j + 16 :
7299 i == Xdynamite_1 ? 0 :
7300 i == Xdynamite_2 ? 8 :
7301 i == Xdynamite_3 ? 16 :
7302 i == Xdynamite_4 ? 24 :
7303 i == Xsand_stonein_1 ? j + 1 :
7304 i == Xsand_stonein_2 ? j + 9 :
7305 i == Xsand_stonein_3 ? j + 17 :
7306 i == Xsand_stonein_4 ? j + 25 :
7307 i == Xsand_stoneout_1 && j == 0 ? 0 :
7308 i == Xsand_stoneout_1 && j == 1 ? 0 :
7309 i == Xsand_stoneout_1 && j == 2 ? 1 :
7310 i == Xsand_stoneout_1 && j == 3 ? 2 :
7311 i == Xsand_stoneout_1 && j == 4 ? 2 :
7312 i == Xsand_stoneout_1 && j == 5 ? 3 :
7313 i == Xsand_stoneout_1 && j == 6 ? 4 :
7314 i == Xsand_stoneout_1 && j == 7 ? 4 :
7315 i == Xsand_stoneout_2 && j == 0 ? 5 :
7316 i == Xsand_stoneout_2 && j == 1 ? 6 :
7317 i == Xsand_stoneout_2 && j == 2 ? 7 :
7318 i == Xsand_stoneout_2 && j == 3 ? 8 :
7319 i == Xsand_stoneout_2 && j == 4 ? 9 :
7320 i == Xsand_stoneout_2 && j == 5 ? 11 :
7321 i == Xsand_stoneout_2 && j == 6 ? 13 :
7322 i == Xsand_stoneout_2 && j == 7 ? 15 :
7323 i == Xboom_bug && j == 1 ? 2 :
7324 i == Xboom_bug && j == 2 ? 2 :
7325 i == Xboom_bug && j == 3 ? 4 :
7326 i == Xboom_bug && j == 4 ? 4 :
7327 i == Xboom_bug && j == 5 ? 2 :
7328 i == Xboom_bug && j == 6 ? 2 :
7329 i == Xboom_bug && j == 7 ? 0 :
7330 i == Xboom_bomb && j == 1 ? 2 :
7331 i == Xboom_bomb && j == 2 ? 2 :
7332 i == Xboom_bomb && j == 3 ? 4 :
7333 i == Xboom_bomb && j == 4 ? 4 :
7334 i == Xboom_bomb && j == 5 ? 2 :
7335 i == Xboom_bomb && j == 6 ? 2 :
7336 i == Xboom_bomb && j == 7 ? 0 :
7337 i == Xboom_android && j == 7 ? 6 :
7338 i == Xboom_1 && j == 1 ? 2 :
7339 i == Xboom_1 && j == 2 ? 2 :
7340 i == Xboom_1 && j == 3 ? 4 :
7341 i == Xboom_1 && j == 4 ? 4 :
7342 i == Xboom_1 && j == 5 ? 6 :
7343 i == Xboom_1 && j == 6 ? 6 :
7344 i == Xboom_1 && j == 7 ? 8 :
7345 i == Xboom_2 && j == 0 ? 8 :
7346 i == Xboom_2 && j == 1 ? 8 :
7347 i == Xboom_2 && j == 2 ? 10 :
7348 i == Xboom_2 && j == 3 ? 10 :
7349 i == Xboom_2 && j == 4 ? 10 :
7350 i == Xboom_2 && j == 5 ? 12 :
7351 i == Xboom_2 && j == 6 ? 12 :
7352 i == Xboom_2 && j == 7 ? 12 :
7353 special_animation && j == 4 ? 3 :
7354 effective_action != action ? 0 :
7358 Bitmap *debug_bitmap = g_em->bitmap;
7359 int debug_src_x = g_em->src_x;
7360 int debug_src_y = g_em->src_y;
7363 int frame = getAnimationFrame(g->anim_frames,
7366 g->anim_start_frame,
7369 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
7370 g->double_movement && is_backside);
7372 g_em->bitmap = src_bitmap;
7373 g_em->src_x = src_x;
7374 g_em->src_y = src_y;
7375 g_em->src_offset_x = 0;
7376 g_em->src_offset_y = 0;
7377 g_em->dst_offset_x = 0;
7378 g_em->dst_offset_y = 0;
7379 g_em->width = TILEX;
7380 g_em->height = TILEY;
7382 g_em->preserve_background = FALSE;
7384 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
7387 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
7388 effective_action == ACTION_MOVING ||
7389 effective_action == ACTION_PUSHING ||
7390 effective_action == ACTION_EATING)) ||
7391 (!has_action_graphics && (effective_action == ACTION_FILLING ||
7392 effective_action == ACTION_EMPTYING)))
7395 (effective_action == ACTION_FALLING ||
7396 effective_action == ACTION_FILLING ||
7397 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
7398 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
7399 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
7400 int num_steps = (i == Ydrip_s1 ? 16 :
7401 i == Ydrip_s1B ? 16 :
7402 i == Ydrip_s2 ? 16 :
7403 i == Ydrip_s2B ? 16 :
7404 i == Xsand_stonein_1 ? 32 :
7405 i == Xsand_stonein_2 ? 32 :
7406 i == Xsand_stonein_3 ? 32 :
7407 i == Xsand_stonein_4 ? 32 :
7408 i == Xsand_stoneout_1 ? 16 :
7409 i == Xsand_stoneout_2 ? 16 : 8);
7410 int cx = ABS(dx) * (TILEX / num_steps);
7411 int cy = ABS(dy) * (TILEY / num_steps);
7412 int step_frame = (i == Ydrip_s2 ? j + 8 :
7413 i == Ydrip_s2B ? j + 8 :
7414 i == Xsand_stonein_2 ? j + 8 :
7415 i == Xsand_stonein_3 ? j + 16 :
7416 i == Xsand_stonein_4 ? j + 24 :
7417 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
7418 int step = (is_backside ? step_frame : num_steps - step_frame);
7420 if (is_backside) /* tile where movement starts */
7422 if (dx < 0 || dy < 0)
7424 g_em->src_offset_x = cx * step;
7425 g_em->src_offset_y = cy * step;
7429 g_em->dst_offset_x = cx * step;
7430 g_em->dst_offset_y = cy * step;
7433 else /* tile where movement ends */
7435 if (dx < 0 || dy < 0)
7437 g_em->dst_offset_x = cx * step;
7438 g_em->dst_offset_y = cy * step;
7442 g_em->src_offset_x = cx * step;
7443 g_em->src_offset_y = cy * step;
7447 g_em->width = TILEX - cx * step;
7448 g_em->height = TILEY - cy * step;
7451 /* create unique graphic identifier to decide if tile must be redrawn */
7452 /* bit 31 - 16 (16 bit): EM style graphic
7453 bit 15 - 12 ( 4 bit): EM style frame
7454 bit 11 - 6 ( 6 bit): graphic width
7455 bit 5 - 0 ( 6 bit): graphic height */
7456 g_em->unique_identifier =
7457 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
7461 /* skip check for EMC elements not contained in original EMC artwork */
7462 if (element == EL_EMC_FAKE_ACID)
7465 if (g_em->bitmap != debug_bitmap ||
7466 g_em->src_x != debug_src_x ||
7467 g_em->src_y != debug_src_y ||
7468 g_em->src_offset_x != 0 ||
7469 g_em->src_offset_y != 0 ||
7470 g_em->dst_offset_x != 0 ||
7471 g_em->dst_offset_y != 0 ||
7472 g_em->width != TILEX ||
7473 g_em->height != TILEY)
7475 static int last_i = -1;
7483 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
7484 i, element, element_info[element].token_name,
7485 element_action_info[effective_action].suffix, direction);
7487 if (element != effective_element)
7488 printf(" [%d ('%s')]",
7490 element_info[effective_element].token_name);
7494 if (g_em->bitmap != debug_bitmap)
7495 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
7496 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
7498 if (g_em->src_x != debug_src_x ||
7499 g_em->src_y != debug_src_y)
7500 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
7501 j, (is_backside ? 'B' : 'F'),
7502 g_em->src_x, g_em->src_y,
7503 g_em->src_x / 32, g_em->src_y / 32,
7504 debug_src_x, debug_src_y,
7505 debug_src_x / 32, debug_src_y / 32);
7507 if (g_em->src_offset_x != 0 ||
7508 g_em->src_offset_y != 0 ||
7509 g_em->dst_offset_x != 0 ||
7510 g_em->dst_offset_y != 0)
7511 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
7513 g_em->src_offset_x, g_em->src_offset_y,
7514 g_em->dst_offset_x, g_em->dst_offset_y);
7516 if (g_em->width != TILEX ||
7517 g_em->height != TILEY)
7518 printf(" %d (%d): size %d,%d should be %d,%d\n",
7520 g_em->width, g_em->height, TILEX, TILEY);
7522 num_em_gfx_errors++;
7529 for (i = 0; i < TILE_MAX; i++)
7531 for (j = 0; j < 8; j++)
7533 int element = object_mapping[i].element_rnd;
7534 int action = object_mapping[i].action;
7535 int direction = object_mapping[i].direction;
7536 boolean is_backside = object_mapping[i].is_backside;
7537 int graphic_action = el_act_dir2img(element, action, direction);
7538 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
7540 if ((action == ACTION_SMASHED_BY_ROCK ||
7541 action == ACTION_SMASHED_BY_SPRING ||
7542 action == ACTION_EATING) &&
7543 graphic_action == graphic_default)
7545 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
7546 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
7547 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
7548 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
7551 /* no separate animation for "smashed by rock" -- use rock instead */
7552 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7553 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
7555 g_em->bitmap = g_xx->bitmap;
7556 g_em->src_x = g_xx->src_x;
7557 g_em->src_y = g_xx->src_y;
7558 g_em->src_offset_x = g_xx->src_offset_x;
7559 g_em->src_offset_y = g_xx->src_offset_y;
7560 g_em->dst_offset_x = g_xx->dst_offset_x;
7561 g_em->dst_offset_y = g_xx->dst_offset_y;
7562 g_em->width = g_xx->width;
7563 g_em->height = g_xx->height;
7564 g_em->unique_identifier = g_xx->unique_identifier;
7567 g_em->preserve_background = TRUE;
7572 for (p = 0; p < MAX_PLAYERS; p++)
7574 for (i = 0; i < SPR_MAX; i++)
7576 int element = player_mapping[p][i].element_rnd;
7577 int action = player_mapping[p][i].action;
7578 int direction = player_mapping[p][i].direction;
7580 for (j = 0; j < 8; j++)
7582 int effective_element = element;
7583 int effective_action = action;
7584 int graphic = (direction == MV_NONE ?
7585 el_act2img(effective_element, effective_action) :
7586 el_act_dir2img(effective_element, effective_action,
7588 struct GraphicInfo *g = &graphic_info[graphic];
7589 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
7595 Bitmap *debug_bitmap = g_em->bitmap;
7596 int debug_src_x = g_em->src_x;
7597 int debug_src_y = g_em->src_y;
7600 int frame = getAnimationFrame(g->anim_frames,
7603 g->anim_start_frame,
7606 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
7608 g_em->bitmap = src_bitmap;
7609 g_em->src_x = src_x;
7610 g_em->src_y = src_y;
7611 g_em->src_offset_x = 0;
7612 g_em->src_offset_y = 0;
7613 g_em->dst_offset_x = 0;
7614 g_em->dst_offset_y = 0;
7615 g_em->width = TILEX;
7616 g_em->height = TILEY;
7620 /* skip check for EMC elements not contained in original EMC artwork */
7621 if (element == EL_PLAYER_3 ||
7622 element == EL_PLAYER_4)
7625 if (g_em->bitmap != debug_bitmap ||
7626 g_em->src_x != debug_src_x ||
7627 g_em->src_y != debug_src_y)
7629 static int last_i = -1;
7637 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
7638 p, i, element, element_info[element].token_name,
7639 element_action_info[effective_action].suffix, direction);
7641 if (element != effective_element)
7642 printf(" [%d ('%s')]",
7644 element_info[effective_element].token_name);
7648 if (g_em->bitmap != debug_bitmap)
7649 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
7650 j, (int)(g_em->bitmap), (int)(debug_bitmap));
7652 if (g_em->src_x != debug_src_x ||
7653 g_em->src_y != debug_src_y)
7654 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
7656 g_em->src_x, g_em->src_y,
7657 g_em->src_x / 32, g_em->src_y / 32,
7658 debug_src_x, debug_src_y,
7659 debug_src_x / 32, debug_src_y / 32);
7661 num_em_gfx_errors++;
7671 printf("::: [%d errors found]\n", num_em_gfx_errors);
7677 void CheckSaveEngineSnapshot_EM(byte action[MAX_PLAYERS], int frame,
7678 boolean any_player_moving,
7679 boolean any_player_snapping,
7680 boolean any_player_dropping)
7682 static boolean player_was_waiting = TRUE;
7684 if (frame == 0 && !any_player_dropping)
7686 if (!player_was_waiting)
7688 if (!SaveEngineSnapshotToList())
7691 player_was_waiting = TRUE;
7694 else if (any_player_moving || any_player_snapping || any_player_dropping)
7696 player_was_waiting = FALSE;
7700 void CheckSaveEngineSnapshot_SP(boolean murphy_is_waiting,
7701 boolean murphy_is_dropping)
7703 static boolean player_was_waiting = TRUE;
7705 if (murphy_is_waiting)
7707 if (!player_was_waiting)
7709 if (!SaveEngineSnapshotToList())
7712 player_was_waiting = TRUE;
7717 player_was_waiting = FALSE;
7721 void CheckSingleStepMode_EM(byte action[MAX_PLAYERS], int frame,
7722 boolean any_player_moving,
7723 boolean any_player_snapping,
7724 boolean any_player_dropping)
7726 if (tape.single_step && tape.recording && !tape.pausing)
7727 if (frame == 0 && !any_player_dropping)
7728 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
7730 CheckSaveEngineSnapshot_EM(action, frame, any_player_moving,
7731 any_player_snapping, any_player_dropping);
7734 void CheckSingleStepMode_SP(boolean murphy_is_waiting,
7735 boolean murphy_is_dropping)
7737 if (tape.single_step && tape.recording && !tape.pausing)
7738 if (murphy_is_waiting)
7739 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
7741 CheckSaveEngineSnapshot_SP(murphy_is_waiting, murphy_is_dropping);
7744 void getGraphicSource_SP(struct GraphicInfo_SP *g_sp,
7745 int graphic, int sync_frame, int x, int y)
7747 int frame = getGraphicAnimationFrame(graphic, sync_frame);
7749 getGraphicSource(graphic, frame, &g_sp->bitmap, &g_sp->src_x, &g_sp->src_y);
7752 boolean isNextAnimationFrame_SP(int graphic, int sync_frame)
7754 return (IS_NEXT_FRAME(sync_frame, graphic));
7757 int getGraphicInfo_Delay(int graphic)
7759 return graphic_info[graphic].anim_delay;
7762 void PlayMenuSoundExt(int sound)
7764 if (sound == SND_UNDEFINED)
7767 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
7768 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
7771 if (IS_LOOP_SOUND(sound))
7772 PlaySoundLoop(sound);
7777 void PlayMenuSound()
7779 PlayMenuSoundExt(menu.sound[game_status]);
7782 void PlayMenuSoundStereo(int sound, int stereo_position)
7784 if (sound == SND_UNDEFINED)
7787 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
7788 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
7791 if (IS_LOOP_SOUND(sound))
7792 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
7794 PlaySoundStereo(sound, stereo_position);
7797 void PlayMenuSoundIfLoopExt(int sound)
7799 if (sound == SND_UNDEFINED)
7802 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
7803 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
7806 if (IS_LOOP_SOUND(sound))
7807 PlaySoundLoop(sound);
7810 void PlayMenuSoundIfLoop()
7812 PlayMenuSoundIfLoopExt(menu.sound[game_status]);
7815 void PlayMenuMusicExt(int music)
7817 if (music == MUS_UNDEFINED)
7820 if (!setup.sound_music)
7826 void PlayMenuMusic()
7828 PlayMenuMusicExt(menu.music[game_status]);
7831 void PlaySoundActivating()
7834 PlaySound(SND_MENU_ITEM_ACTIVATING);
7838 void PlaySoundSelecting()
7841 PlaySound(SND_MENU_ITEM_SELECTING);
7845 void ToggleFullscreenOrChangeWindowScalingIfNeeded()
7847 boolean change_fullscreen = (setup.fullscreen !=
7848 video.fullscreen_enabled);
7849 boolean change_fullscreen_mode = (video.fullscreen_enabled &&
7850 !strEqual(setup.fullscreen_mode,
7851 video.fullscreen_mode_current));
7852 boolean change_window_scaling_percent = (!video.fullscreen_enabled &&
7853 setup.window_scaling_percent !=
7854 video.window_scaling_percent);
7856 if (change_window_scaling_percent && video.fullscreen_enabled)
7859 if (!change_window_scaling_percent && !video.fullscreen_available)
7862 #if defined(TARGET_SDL2)
7863 if (change_window_scaling_percent)
7865 SDLSetWindowScaling(setup.window_scaling_percent);
7869 else if (change_fullscreen)
7871 SDLSetWindowFullscreen(setup.fullscreen);
7873 /* set setup value according to successfully changed fullscreen mode */
7874 setup.fullscreen = video.fullscreen_enabled;
7880 if (change_fullscreen ||
7881 change_fullscreen_mode ||
7882 change_window_scaling_percent)
7884 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
7886 /* save backbuffer content which gets lost when toggling fullscreen mode */
7887 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
7889 if (change_fullscreen_mode)
7891 /* keep fullscreen, but change fullscreen mode (screen resolution) */
7892 video.fullscreen_enabled = FALSE; /* force new fullscreen mode */
7895 if (change_window_scaling_percent)
7897 /* keep window mode, but change window scaling */
7898 video.fullscreen_enabled = TRUE; /* force new window scaling */
7901 /* toggle fullscreen */
7902 ChangeVideoModeIfNeeded(setup.fullscreen);
7904 /* set setup value according to successfully changed fullscreen mode */
7905 setup.fullscreen = video.fullscreen_enabled;
7907 /* restore backbuffer content from temporary backbuffer backup bitmap */
7908 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
7910 FreeBitmap(tmp_backbuffer);
7912 /* update visible window/screen */
7913 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
7917 void ChangeViewportPropertiesIfNeeded()
7919 int gfx_game_mode = game_status;
7920 int gfx_game_mode2 = (game_status == GAME_MODE_EDITOR ? GAME_MODE_DEFAULT :
7922 struct RectWithBorder *vp_playfield = &viewport.playfield[gfx_game_mode];
7923 struct RectWithBorder *vp_door_1 = &viewport.door_1[gfx_game_mode];
7924 struct RectWithBorder *vp_door_2 = &viewport.door_2[gfx_game_mode2];
7925 struct RectWithBorder *vp_door_3 = &viewport.door_2[GAME_MODE_EDITOR];
7926 int border_size = vp_playfield->border_size;
7927 int new_sx = vp_playfield->x + border_size;
7928 int new_sy = vp_playfield->y + border_size;
7929 int new_sxsize = vp_playfield->width - 2 * border_size;
7930 int new_sysize = vp_playfield->height - 2 * border_size;
7931 int new_real_sx = vp_playfield->x;
7932 int new_real_sy = vp_playfield->y;
7933 int new_full_sxsize = vp_playfield->width;
7934 int new_full_sysize = vp_playfield->height;
7935 int new_dx = vp_door_1->x;
7936 int new_dy = vp_door_1->y;
7937 int new_dxsize = vp_door_1->width;
7938 int new_dysize = vp_door_1->height;
7939 int new_vx = vp_door_2->x;
7940 int new_vy = vp_door_2->y;
7941 int new_vxsize = vp_door_2->width;
7942 int new_vysize = vp_door_2->height;
7943 int new_ex = vp_door_3->x;
7944 int new_ey = vp_door_3->y;
7945 int new_exsize = vp_door_3->width;
7946 int new_eysize = vp_door_3->height;
7947 int new_tilesize_var =
7948 (setup.small_game_graphics ? MINI_TILESIZE : game.tile_size);
7950 int tilesize = (gfx_game_mode == GAME_MODE_PLAYING ? new_tilesize_var :
7951 gfx_game_mode == GAME_MODE_EDITOR ? MINI_TILESIZE : TILESIZE);
7952 int new_scr_fieldx = new_sxsize / tilesize;
7953 int new_scr_fieldy = new_sysize / tilesize;
7954 int new_scr_fieldx_buffers = new_sxsize / new_tilesize_var;
7955 int new_scr_fieldy_buffers = new_sysize / new_tilesize_var;
7956 boolean init_gfx_buffers = FALSE;
7957 boolean init_video_buffer = FALSE;
7958 boolean init_gadgets_and_toons = FALSE;
7959 boolean init_em_graphics = FALSE;
7960 boolean drawing_area_changed = FALSE;
7962 if (viewport.window.width != WIN_XSIZE ||
7963 viewport.window.height != WIN_YSIZE)
7965 WIN_XSIZE = viewport.window.width;
7966 WIN_YSIZE = viewport.window.height;
7968 init_video_buffer = TRUE;
7969 init_gfx_buffers = TRUE;
7971 // printf("::: video: init_video_buffer, init_gfx_buffers\n");
7974 if (new_scr_fieldx != SCR_FIELDX ||
7975 new_scr_fieldy != SCR_FIELDY)
7977 /* this always toggles between MAIN and GAME when using small tile size */
7979 SCR_FIELDX = new_scr_fieldx;
7980 SCR_FIELDY = new_scr_fieldy;
7982 // printf("::: new_scr_fieldx != SCR_FIELDX ...\n");
7993 new_sxsize != SXSIZE ||
7994 new_sysize != SYSIZE ||
7995 new_dxsize != DXSIZE ||
7996 new_dysize != DYSIZE ||
7997 new_vxsize != VXSIZE ||
7998 new_vysize != VYSIZE ||
7999 new_exsize != EXSIZE ||
8000 new_eysize != EYSIZE ||
8001 new_real_sx != REAL_SX ||
8002 new_real_sy != REAL_SY ||
8003 new_full_sxsize != FULL_SXSIZE ||
8004 new_full_sysize != FULL_SYSIZE ||
8005 new_tilesize_var != TILESIZE_VAR
8008 if (new_tilesize_var != TILESIZE_VAR)
8010 // printf("::: new_tilesize_var != TILESIZE_VAR\n");
8012 // changing tile size invalidates scroll values of engine snapshots
8013 FreeEngineSnapshotSingle();
8015 // changing tile size requires update of graphic mapping for EM engine
8016 init_em_graphics = TRUE;
8021 new_sxsize != SXSIZE ||
8022 new_sysize != SYSIZE ||
8023 new_real_sx != REAL_SX ||
8024 new_real_sy != REAL_SY ||
8025 new_full_sxsize != FULL_SXSIZE ||
8026 new_full_sysize != FULL_SYSIZE)
8028 if (!init_video_buffer)
8029 drawing_area_changed = TRUE;
8040 SXSIZE = new_sxsize;
8041 SYSIZE = new_sysize;
8042 DXSIZE = new_dxsize;
8043 DYSIZE = new_dysize;
8044 VXSIZE = new_vxsize;
8045 VYSIZE = new_vysize;
8046 EXSIZE = new_exsize;
8047 EYSIZE = new_eysize;
8048 REAL_SX = new_real_sx;
8049 REAL_SY = new_real_sy;
8050 FULL_SXSIZE = new_full_sxsize;
8051 FULL_SYSIZE = new_full_sysize;
8052 TILESIZE_VAR = new_tilesize_var;
8054 init_gfx_buffers = TRUE;
8055 init_gadgets_and_toons = TRUE;
8057 // printf("::: viewports: init_gfx_buffers\n");
8058 // printf("::: viewports: init_gadgets_and_toons\n");
8061 if (init_gfx_buffers)
8063 // printf("::: init_gfx_buffers\n");
8065 SCR_FIELDX = new_scr_fieldx_buffers;
8066 SCR_FIELDY = new_scr_fieldy_buffers;
8070 SCR_FIELDX = new_scr_fieldx;
8071 SCR_FIELDY = new_scr_fieldy;
8073 gfx.drawing_area_changed = drawing_area_changed;
8075 SetDrawDeactivationMask(REDRAW_NONE);
8076 SetDrawBackgroundMask(REDRAW_FIELD);
8079 if (init_video_buffer)
8081 // printf("::: init_video_buffer\n");
8083 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
8086 if (init_gadgets_and_toons)
8088 // printf("::: init_gadgets_and_toons\n");
8094 if (init_em_graphics)
8096 InitGraphicInfo_EM();