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;
424 if (redraw_mask == REDRAW_NONE)
427 // redraw playfield if anything inside main playfield area needs redraw
428 if (redraw_mask & REDRAW_MAIN)
429 redraw_mask |= REDRAW_FIELD;
431 // draw masked border to all viewports, if defined
432 DrawMaskedBorder(redraw_mask);
434 // redraw complete window if both playfield and (some) doors need redraw
435 if (redraw_mask & REDRAW_FIELD && redraw_mask & REDRAW_DOORS)
436 redraw_mask = REDRAW_ALL;
438 /* although redrawing the whole window would be fine for normal gameplay,
439 being able to only redraw the playfield is required for deactivating
440 certain drawing areas (mainly playfield) to work, which is needed for
441 warp-forward to be fast enough (by skipping redraw of most frames) */
443 if (redraw_mask & REDRAW_ALL)
445 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
447 else if (redraw_mask & REDRAW_FIELD)
449 BlitBitmap(backbuffer, window,
450 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
452 else if (redraw_mask & REDRAW_DOORS)
454 if (redraw_mask & REDRAW_DOOR_1)
455 BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
457 if (redraw_mask & REDRAW_DOOR_2)
458 BlitBitmap(backbuffer, window, VX, VY, VXSIZE, VYSIZE, VX, VY);
460 if (redraw_mask & REDRAW_DOOR_3)
461 BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
464 redraw_mask = REDRAW_NONE;
467 static void FadeCrossSaveBackbuffer()
469 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
472 static void FadeExt(int fade_mask, int fade_mode, int fade_type)
474 static int fade_type_skip = FADE_TYPE_NONE;
475 void (*draw_border_function)(void) = NULL;
476 Bitmap *bitmap = (fade_mode & FADE_TYPE_TRANSFORM ? bitmap_db_cross : NULL);
477 int x, y, width, height;
478 int fade_delay, post_delay;
480 if (fade_type == FADE_TYPE_FADE_OUT)
482 if (fade_type_skip != FADE_TYPE_NONE)
484 /* skip all fade operations until specified fade operation */
485 if (fade_type & fade_type_skip)
486 fade_type_skip = FADE_TYPE_NONE;
491 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
493 FadeCrossSaveBackbuffer();
499 redraw_mask |= fade_mask;
501 if (fade_type == FADE_TYPE_SKIP)
503 fade_type_skip = fade_mode;
508 fade_delay = fading.fade_delay;
509 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
511 if (fade_type_skip != FADE_TYPE_NONE)
513 /* skip all fade operations until specified fade operation */
514 if (fade_type & fade_type_skip)
515 fade_type_skip = FADE_TYPE_NONE;
520 if (global.autoplay_leveldir)
525 if (fade_mask == REDRAW_FIELD)
530 height = FULL_SYSIZE;
532 if (border.draw_masked_when_fading)
533 draw_border_function = DrawMaskedBorder_FIELD; /* update when fading */
535 DrawMaskedBorder_FIELD(); /* draw once */
537 else /* REDRAW_ALL */
545 if (!setup.fade_screens ||
547 fading.fade_mode == FADE_MODE_NONE)
549 if (fade_mode == FADE_MODE_FADE_OUT)
552 BlitBitmap(backbuffer, window, x, y, width, height, x, y);
554 redraw_mask &= ~fade_mask;
559 FadeRectangle(bitmap, x, y, width, height, fade_mode, fade_delay, post_delay,
560 draw_border_function);
562 redraw_mask &= ~fade_mask;
565 void FadeIn(int fade_mask)
567 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
568 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_IN);
570 FadeExt(fade_mask, FADE_MODE_FADE_IN, FADE_TYPE_FADE_IN);
573 void FadeOut(int fade_mask)
575 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
576 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_OUT);
578 FadeExt(fade_mask, FADE_MODE_FADE_OUT, FADE_TYPE_FADE_OUT);
580 global.border_status = game_status;
583 static void FadeSetLeaveNext(struct TitleFadingInfo fading_leave, boolean set)
585 static struct TitleFadingInfo fading_leave_stored;
588 fading_leave_stored = fading_leave;
590 fading = fading_leave_stored;
593 void FadeSetEnterMenu()
595 fading = menu.enter_menu;
597 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
600 void FadeSetLeaveMenu()
602 fading = menu.leave_menu;
604 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
607 void FadeSetEnterScreen()
609 fading = menu.enter_screen[game_status];
611 FadeSetLeaveNext(menu.leave_screen[game_status], TRUE); /* store */
614 void FadeSetNextScreen()
616 fading = menu.next_screen;
618 // (do not overwrite fade mode set by FadeSetEnterScreen)
619 // FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
622 void FadeSetLeaveScreen()
624 FadeSetLeaveNext(menu.leave_screen[game_status], FALSE); /* recall */
627 void FadeSetFromType(int type)
629 if (type & TYPE_ENTER_SCREEN)
630 FadeSetEnterScreen();
631 else if (type & TYPE_ENTER)
633 else if (type & TYPE_LEAVE)
637 void FadeSetDisabled()
639 static struct TitleFadingInfo fading_none = { FADE_MODE_NONE, -1, -1, -1 };
641 fading = fading_none;
644 void FadeSkipNextFadeIn()
646 FadeExt(0, FADE_MODE_SKIP_FADE_IN, FADE_TYPE_SKIP);
649 void FadeSkipNextFadeOut()
651 FadeExt(0, FADE_MODE_SKIP_FADE_OUT, FADE_TYPE_SKIP);
654 void SetWindowBackgroundImageIfDefined(int graphic)
656 if (graphic_info[graphic].bitmap)
657 SetWindowBackgroundBitmap(graphic_info[graphic].bitmap);
660 void SetMainBackgroundImageIfDefined(int graphic)
662 if (graphic_info[graphic].bitmap)
663 SetMainBackgroundBitmap(graphic_info[graphic].bitmap);
666 void SetDoorBackgroundImageIfDefined(int graphic)
668 if (graphic_info[graphic].bitmap)
669 SetDoorBackgroundBitmap(graphic_info[graphic].bitmap);
672 void SetWindowBackgroundImage(int graphic)
674 SetWindowBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
675 graphic_info[graphic].bitmap ?
676 graphic_info[graphic].bitmap :
677 graphic_info[IMG_BACKGROUND].bitmap);
680 void SetMainBackgroundImage(int graphic)
682 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
683 graphic_info[graphic].bitmap ?
684 graphic_info[graphic].bitmap :
685 graphic_info[IMG_BACKGROUND].bitmap);
688 void SetDoorBackgroundImage(int graphic)
690 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
691 graphic_info[graphic].bitmap ?
692 graphic_info[graphic].bitmap :
693 graphic_info[IMG_BACKGROUND].bitmap);
696 void SetPanelBackground()
698 struct GraphicInfo *gfx = &graphic_info[IMG_BACKGROUND_PANEL];
700 BlitBitmapTiled(gfx->bitmap, bitmap_db_panel, gfx->src_x, gfx->src_y,
701 gfx->width, gfx->height, 0, 0, DXSIZE, DYSIZE);
703 SetDoorBackgroundBitmap(bitmap_db_panel);
706 void DrawBackground(int x, int y, int width, int height)
708 /* "drawto" might still point to playfield buffer here (hall of fame) */
709 ClearRectangleOnBackground(backbuffer, x, y, width, height);
711 if (IN_GFX_FIELD_FULL(x, y))
712 redraw_mask |= REDRAW_FIELD;
713 else if (IN_GFX_DOOR_1(x, y))
714 redraw_mask |= REDRAW_DOOR_1;
715 else if (IN_GFX_DOOR_2(x, y))
716 redraw_mask |= REDRAW_DOOR_2;
717 else if (IN_GFX_DOOR_3(x, y))
718 redraw_mask |= REDRAW_DOOR_3;
721 void DrawBackgroundForFont(int x, int y, int width, int height, int font_nr)
723 struct FontBitmapInfo *font = getFontBitmapInfo(font_nr);
725 if (font->bitmap == NULL)
728 DrawBackground(x, y, width, height);
731 void DrawBackgroundForGraphic(int x, int y, int width, int height, int graphic)
733 struct GraphicInfo *g = &graphic_info[graphic];
735 if (g->bitmap == NULL)
738 DrawBackground(x, y, width, height);
743 /* !!! "drawto" might still point to playfield buffer here (see above) !!! */
744 /* (when entering hall of fame after playing) */
745 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
747 /* !!! maybe this should be done before clearing the background !!! */
748 if (game_status == GAME_MODE_PLAYING)
750 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
751 SetDrawtoField(DRAW_FIELDBUFFER);
755 SetDrawtoField(DRAW_BACKBUFFER);
759 void MarkTileDirty(int x, int y)
761 redraw_mask |= REDRAW_FIELD;
764 void SetBorderElement()
768 BorderElement = EL_EMPTY;
770 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
772 for (x = 0; x < lev_fieldx; x++)
774 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
775 BorderElement = EL_STEELWALL;
777 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
783 void FloodFillLevel(int from_x, int from_y, int fill_element,
784 short field[MAX_LEV_FIELDX][MAX_LEV_FIELDY],
785 int max_fieldx, int max_fieldy)
789 static int check[4][2] = { { -1, 0 }, { 0, -1 }, { 1, 0 }, { 0, 1 } };
790 static int safety = 0;
792 /* check if starting field still has the desired content */
793 if (field[from_x][from_y] == fill_element)
798 if (safety > max_fieldx * max_fieldy)
799 Error(ERR_EXIT, "Something went wrong in 'FloodFill()'. Please debug.");
801 old_element = field[from_x][from_y];
802 field[from_x][from_y] = fill_element;
804 for (i = 0; i < 4; i++)
806 x = from_x + check[i][0];
807 y = from_y + check[i][1];
809 if (IN_FIELD(x, y, max_fieldx, max_fieldy) && field[x][y] == old_element)
810 FloodFillLevel(x, y, fill_element, field, max_fieldx, max_fieldy);
816 void SetRandomAnimationValue(int x, int y)
818 gfx.anim_random_frame = GfxRandom[x][y];
821 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
823 /* animation synchronized with global frame counter, not move position */
824 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
825 sync_frame = FrameCounter;
827 return getAnimationFrame(graphic_info[graphic].anim_frames,
828 graphic_info[graphic].anim_delay,
829 graphic_info[graphic].anim_mode,
830 graphic_info[graphic].anim_start_frame,
834 void getSizedGraphicSourceExt(int graphic, int frame, int tilesize,
835 Bitmap **bitmap, int *x, int *y,
836 boolean get_backside)
838 struct GraphicInfo *g = &graphic_info[graphic];
839 Bitmap *src_bitmap = g->bitmap;
840 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
841 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
842 int tilesize_capped = MIN(MAX(1, tilesize), TILESIZE);
844 // if no in-game graphics defined, always use standard graphic size
845 if (g->bitmaps[IMG_BITMAP_GAME] == NULL)
848 if (tilesize == gfx.standard_tile_size)
849 src_bitmap = g->bitmaps[IMG_BITMAP_STANDARD];
850 else if (tilesize == game.tile_size)
851 src_bitmap = g->bitmaps[IMG_BITMAP_GAME];
853 src_bitmap = g->bitmaps[IMG_BITMAP_1x1 - log_2(tilesize_capped)];
855 if (g->offset_y == 0) /* frames are ordered horizontally */
857 int max_width = g->anim_frames_per_line * g->width;
858 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
860 src_x = pos % max_width;
861 src_y = src_y % g->height + pos / max_width * g->height;
863 else if (g->offset_x == 0) /* frames are ordered vertically */
865 int max_height = g->anim_frames_per_line * g->height;
866 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
868 src_x = src_x % g->width + pos / max_height * g->width;
869 src_y = pos % max_height;
871 else /* frames are ordered diagonally */
873 src_x = src_x + frame * g->offset_x;
874 src_y = src_y + frame * g->offset_y;
877 *bitmap = src_bitmap;
878 *x = src_x * tilesize / TILESIZE;
879 *y = src_y * tilesize / TILESIZE;
882 void getFixedGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
883 int *x, int *y, boolean get_backside)
885 getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y,
889 void getSizedGraphicSource(int graphic, int frame, int tilesize,
890 Bitmap **bitmap, int *x, int *y)
892 getSizedGraphicSourceExt(graphic, frame, tilesize, bitmap, x, y, FALSE);
895 void getFixedGraphicSource(int graphic, int frame,
896 Bitmap **bitmap, int *x, int *y)
898 getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y, FALSE);
901 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
903 getSizedGraphicSource(graphic, 0, MINI_TILESIZE, bitmap, x, y);
906 inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
907 int *x, int *y, boolean get_backside)
909 struct GraphicInfo *g = &graphic_info[graphic];
910 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
911 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
913 if (TILESIZE_VAR != TILESIZE)
914 return getSizedGraphicSourceExt(graphic, frame, TILESIZE_VAR, bitmap, x, y,
919 if (g->offset_y == 0) /* frames are ordered horizontally */
921 int max_width = g->anim_frames_per_line * g->width;
922 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
924 *x = pos % max_width;
925 *y = src_y % g->height + pos / max_width * g->height;
927 else if (g->offset_x == 0) /* frames are ordered vertically */
929 int max_height = g->anim_frames_per_line * g->height;
930 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
932 *x = src_x % g->width + pos / max_height * g->width;
933 *y = pos % max_height;
935 else /* frames are ordered diagonally */
937 *x = src_x + frame * g->offset_x;
938 *y = src_y + frame * g->offset_y;
942 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
944 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
947 void DrawGraphic(int x, int y, int graphic, int frame)
950 if (!IN_SCR_FIELD(x, y))
952 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
953 printf("DrawGraphic(): This should never happen!\n");
958 DrawGraphicExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR, graphic,
964 void DrawFixedGraphic(int x, int y, int graphic, int frame)
967 if (!IN_SCR_FIELD(x, y))
969 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
970 printf("DrawGraphic(): This should never happen!\n");
975 DrawFixedGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic,
980 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
986 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
988 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX_VAR, TILEY_VAR, x, y);
991 void DrawFixedGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
997 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
998 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
1001 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
1004 if (!IN_SCR_FIELD(x, y))
1006 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1007 printf("DrawGraphicThruMask(): This should never happen!\n");
1012 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
1015 MarkTileDirty(x, y);
1018 void DrawFixedGraphicThruMask(int x, int y, int graphic, int frame)
1021 if (!IN_SCR_FIELD(x, y))
1023 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1024 printf("DrawGraphicThruMask(): This should never happen!\n");
1029 DrawFixedGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
1031 MarkTileDirty(x, y);
1034 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
1040 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1042 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX_VAR, TILEY_VAR,
1046 void DrawFixedGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y,
1047 int graphic, int frame)
1049 struct GraphicInfo *g = &graphic_info[graphic];
1053 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1055 BlitBitmapMasked(src_bitmap, d, src_x, src_y, g->width, g->height,
1059 void DrawSizedGraphic(int x, int y, int graphic, int frame, int tilesize)
1061 DrawSizedGraphicExt(drawto, SX + x * tilesize, SY + y * tilesize, graphic,
1063 MarkTileDirty(x / tilesize, y / tilesize);
1066 void DrawSizedGraphicExt(DrawBuffer *d, int x, int y, int graphic, int frame,
1072 getSizedGraphicSource(graphic, frame, tilesize, &src_bitmap, &src_x, &src_y);
1073 BlitBitmap(src_bitmap, d, src_x, src_y, tilesize, tilesize, x, y);
1076 void DrawMiniGraphic(int x, int y, int graphic)
1078 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
1079 MarkTileDirty(x / 2, y / 2);
1082 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
1087 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1088 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
1091 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
1092 int graphic, int frame,
1093 int cut_mode, int mask_mode)
1098 int width = TILEX, height = TILEY;
1101 if (dx || dy) /* shifted graphic */
1103 if (x < BX1) /* object enters playfield from the left */
1110 else if (x > BX2) /* object enters playfield from the right */
1116 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
1122 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
1124 else if (dx) /* general horizontal movement */
1125 MarkTileDirty(x + SIGN(dx), y);
1127 if (y < BY1) /* object enters playfield from the top */
1129 if (cut_mode==CUT_BELOW) /* object completely above top border */
1137 else if (y > BY2) /* object enters playfield from the bottom */
1143 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
1149 else if (dy > 0 && cut_mode == CUT_ABOVE)
1151 if (y == BY2) /* object completely above bottom border */
1157 MarkTileDirty(x, y + 1);
1158 } /* object leaves playfield to the bottom */
1159 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1161 else if (dy) /* general vertical movement */
1162 MarkTileDirty(x, y + SIGN(dy));
1166 if (!IN_SCR_FIELD(x, y))
1168 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1169 printf("DrawGraphicShifted(): This should never happen!\n");
1174 width = width * TILESIZE_VAR / TILESIZE;
1175 height = height * TILESIZE_VAR / TILESIZE;
1176 cx = cx * TILESIZE_VAR / TILESIZE;
1177 cy = cy * TILESIZE_VAR / TILESIZE;
1178 dx = dx * TILESIZE_VAR / TILESIZE;
1179 dy = dy * TILESIZE_VAR / TILESIZE;
1181 if (width > 0 && height > 0)
1183 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1188 dst_x = FX + x * TILEX_VAR + dx;
1189 dst_y = FY + y * TILEY_VAR + dy;
1191 if (mask_mode == USE_MASKING)
1192 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1195 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1198 MarkTileDirty(x, y);
1202 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
1203 int graphic, int frame,
1204 int cut_mode, int mask_mode)
1209 int width = TILEX_VAR, height = TILEY_VAR;
1212 int x2 = x + SIGN(dx);
1213 int y2 = y + SIGN(dy);
1215 /* movement with two-tile animations must be sync'ed with movement position,
1216 not with current GfxFrame (which can be higher when using slow movement) */
1217 int anim_pos = (dx ? ABS(dx) : ABS(dy));
1218 int anim_frames = graphic_info[graphic].anim_frames;
1220 /* (we also need anim_delay here for movement animations with less frames) */
1221 int anim_delay = graphic_info[graphic].anim_delay;
1222 int sync_frame = anim_pos * anim_frames * anim_delay / TILESIZE;
1224 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
1225 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
1227 /* re-calculate animation frame for two-tile movement animation */
1228 frame = getGraphicAnimationFrame(graphic, sync_frame);
1230 /* check if movement start graphic inside screen area and should be drawn */
1231 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
1233 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
1235 dst_x = FX + x1 * TILEX_VAR;
1236 dst_y = FY + y1 * TILEY_VAR;
1238 if (mask_mode == USE_MASKING)
1239 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1242 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1245 MarkTileDirty(x1, y1);
1248 /* check if movement end graphic inside screen area and should be drawn */
1249 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
1251 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
1253 dst_x = FX + x2 * TILEX_VAR;
1254 dst_y = FY + y2 * TILEY_VAR;
1256 if (mask_mode == USE_MASKING)
1257 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1260 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1263 MarkTileDirty(x2, y2);
1267 static void DrawGraphicShifted(int x, int y, int dx, int dy,
1268 int graphic, int frame,
1269 int cut_mode, int mask_mode)
1273 DrawGraphic(x, y, graphic, frame);
1278 if (graphic_info[graphic].double_movement) /* EM style movement images */
1279 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1281 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1284 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1285 int frame, int cut_mode)
1287 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
1290 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1291 int cut_mode, int mask_mode)
1293 int lx = LEVELX(x), ly = LEVELY(y);
1297 if (IN_LEV_FIELD(lx, ly))
1299 SetRandomAnimationValue(lx, ly);
1301 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
1302 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1304 /* do not use double (EM style) movement graphic when not moving */
1305 if (graphic_info[graphic].double_movement && !dx && !dy)
1307 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
1308 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1311 else /* border element */
1313 graphic = el2img(element);
1314 frame = getGraphicAnimationFrame(graphic, -1);
1317 if (element == EL_EXPANDABLE_WALL)
1319 boolean left_stopped = FALSE, right_stopped = FALSE;
1321 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1322 left_stopped = TRUE;
1323 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1324 right_stopped = TRUE;
1326 if (left_stopped && right_stopped)
1328 else if (left_stopped)
1330 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1331 frame = graphic_info[graphic].anim_frames - 1;
1333 else if (right_stopped)
1335 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1336 frame = graphic_info[graphic].anim_frames - 1;
1341 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1342 else if (mask_mode == USE_MASKING)
1343 DrawGraphicThruMask(x, y, graphic, frame);
1345 DrawGraphic(x, y, graphic, frame);
1348 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1349 int cut_mode, int mask_mode)
1351 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1352 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1353 cut_mode, mask_mode);
1356 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1359 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1362 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1365 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1368 void DrawLevelElementThruMask(int x, int y, int element)
1370 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1373 void DrawLevelFieldThruMask(int x, int y)
1375 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1378 /* !!! implementation of quicksand is totally broken !!! */
1379 #define IS_CRUMBLED_TILE(x, y, e) \
1380 (GFX_CRUMBLED(e) && (!IN_LEV_FIELD(x, y) || \
1381 !IS_MOVING(x, y) || \
1382 (e) == EL_QUICKSAND_EMPTYING || \
1383 (e) == EL_QUICKSAND_FAST_EMPTYING))
1385 static void DrawLevelFieldCrumbledInnerCorners(int x, int y, int dx, int dy,
1390 int width, height, cx, cy;
1391 int sx = SCREENX(x), sy = SCREENY(y);
1392 int crumbled_border_size = graphic_info[graphic].border_size;
1395 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1397 for (i = 1; i < 4; i++)
1399 int dxx = (i & 1 ? dx : 0);
1400 int dyy = (i & 2 ? dy : 0);
1403 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1406 /* check if neighbour field is of same crumble type */
1407 boolean same = (IS_CRUMBLED_TILE(xx, yy, element) &&
1408 graphic_info[graphic].class ==
1409 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class);
1411 /* return if check prevents inner corner */
1412 if (same == (dxx == dx && dyy == dy))
1416 /* if we reach this point, we have an inner corner */
1418 getGraphicSource(graphic, 1, &src_bitmap, &src_x, &src_y);
1420 width = crumbled_border_size * TILESIZE_VAR / TILESIZE;
1421 height = crumbled_border_size * TILESIZE_VAR / TILESIZE;
1422 cx = (dx > 0 ? TILESIZE_VAR - width : 0);
1423 cy = (dy > 0 ? TILESIZE_VAR - height : 0);
1425 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1426 width, height, FX + sx * TILEX_VAR + cx, FY + sy * TILEY_VAR + cy);
1429 static void DrawLevelFieldCrumbledBorders(int x, int y, int graphic, int frame,
1434 int width, height, bx, by, cx, cy;
1435 int sx = SCREENX(x), sy = SCREENY(y);
1436 int crumbled_border_size = graphic_info[graphic].border_size;
1437 int crumbled_border_size_var = crumbled_border_size * TILESIZE_VAR / TILESIZE;
1438 int crumbled_border_pos_var = TILESIZE_VAR - crumbled_border_size_var;
1441 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1443 /* draw simple, sloppy, non-corner-accurate crumbled border */
1445 width = (dir == 1 || dir == 2 ? crumbled_border_size_var : TILESIZE_VAR);
1446 height = (dir == 0 || dir == 3 ? crumbled_border_size_var : TILESIZE_VAR);
1447 cx = (dir == 2 ? crumbled_border_pos_var : 0);
1448 cy = (dir == 3 ? crumbled_border_pos_var : 0);
1450 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy, width, height,
1451 FX + sx * TILEX_VAR + cx,
1452 FY + sy * TILEY_VAR + cy);
1454 /* (remaining middle border part must be at least as big as corner part) */
1455 if (!(graphic_info[graphic].style & STYLE_ACCURATE_BORDERS) ||
1456 crumbled_border_size >= TILESIZE / 3)
1459 /* correct corners of crumbled border, if needed */
1461 for (i = -1; i <= 1; i += 2)
1463 int xx = x + (dir == 0 || dir == 3 ? i : 0);
1464 int yy = y + (dir == 1 || dir == 2 ? i : 0);
1465 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1468 /* check if neighbour field is of same crumble type */
1469 if (IS_CRUMBLED_TILE(xx, yy, element) &&
1470 graphic_info[graphic].class ==
1471 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1473 /* no crumbled corner, but continued crumbled border */
1475 int c1 = (dir == 2 || dir == 3 ? crumbled_border_pos_var : 0);
1476 int c2 = (i == 1 ? crumbled_border_pos_var : 0);
1477 int b1 = (i == 1 ? crumbled_border_size_var :
1478 TILESIZE_VAR - 2 * crumbled_border_size_var);
1480 width = crumbled_border_size_var;
1481 height = crumbled_border_size_var;
1483 if (dir == 1 || dir == 2)
1498 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
1500 FX + sx * TILEX_VAR + cx,
1501 FY + sy * TILEY_VAR + cy);
1506 static void DrawLevelFieldCrumbledExt(int x, int y, int graphic, int frame)
1508 int sx = SCREENX(x), sy = SCREENY(y);
1511 static int xy[4][2] =
1519 if (!IN_LEV_FIELD(x, y))
1522 element = TILE_GFX_ELEMENT(x, y);
1524 /* crumble field itself */
1525 if (IS_CRUMBLED_TILE(x, y, element))
1527 if (!IN_SCR_FIELD(sx, sy))
1530 for (i = 0; i < 4; i++)
1532 int xx = x + xy[i][0];
1533 int yy = y + xy[i][1];
1535 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1538 /* check if neighbour field is of same crumble type */
1539 if (IS_CRUMBLED_TILE(xx, yy, element) &&
1540 graphic_info[graphic].class ==
1541 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1544 DrawLevelFieldCrumbledBorders(x, y, graphic, frame, i);
1547 if ((graphic_info[graphic].style & STYLE_INNER_CORNERS) &&
1548 graphic_info[graphic].anim_frames == 2)
1550 for (i = 0; i < 4; i++)
1552 int dx = (i & 1 ? +1 : -1);
1553 int dy = (i & 2 ? +1 : -1);
1555 DrawLevelFieldCrumbledInnerCorners(x, y, dx, dy, graphic);
1559 MarkTileDirty(sx, sy);
1561 else /* center field not crumbled -- crumble neighbour fields */
1563 for (i = 0; i < 4; i++)
1565 int xx = x + xy[i][0];
1566 int yy = y + xy[i][1];
1567 int sxx = sx + xy[i][0];
1568 int syy = sy + xy[i][1];
1570 if (!IN_LEV_FIELD(xx, yy) ||
1571 !IN_SCR_FIELD(sxx, syy))
1574 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
1577 element = TILE_GFX_ELEMENT(xx, yy);
1579 if (!IS_CRUMBLED_TILE(xx, yy, element))
1582 graphic = el_act2crm(element, ACTION_DEFAULT);
1584 DrawLevelFieldCrumbledBorders(xx, yy, graphic, 0, 3 - i);
1586 MarkTileDirty(sxx, syy);
1591 void DrawLevelFieldCrumbled(int x, int y)
1595 if (!IN_LEV_FIELD(x, y))
1598 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1599 GfxElement[x][y] != EL_UNDEFINED &&
1600 GFX_CRUMBLED(GfxElement[x][y]))
1602 DrawLevelFieldCrumbledDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
1607 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
1609 DrawLevelFieldCrumbledExt(x, y, graphic, 0);
1612 void DrawLevelFieldCrumbledDigging(int x, int y, int direction,
1615 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1616 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1617 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1618 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1619 int sx = SCREENX(x), sy = SCREENY(y);
1621 DrawGraphic(sx, sy, graphic1, frame1);
1622 DrawLevelFieldCrumbledExt(x, y, graphic2, frame2);
1625 void DrawLevelFieldCrumbledNeighbours(int x, int y)
1627 int sx = SCREENX(x), sy = SCREENY(y);
1628 static int xy[4][2] =
1637 for (i = 0; i < 4; i++)
1639 int xx = x + xy[i][0];
1640 int yy = y + xy[i][1];
1641 int sxx = sx + xy[i][0];
1642 int syy = sy + xy[i][1];
1644 if (!IN_LEV_FIELD(xx, yy) ||
1645 !IN_SCR_FIELD(sxx, syy) ||
1646 !GFX_CRUMBLED(Feld[xx][yy]) ||
1650 DrawLevelField(xx, yy);
1654 static int getBorderElement(int x, int y)
1658 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1659 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1660 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1661 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1662 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1663 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1664 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1666 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1667 int steel_position = (x == -1 && y == -1 ? 0 :
1668 x == lev_fieldx && y == -1 ? 1 :
1669 x == -1 && y == lev_fieldy ? 2 :
1670 x == lev_fieldx && y == lev_fieldy ? 3 :
1671 x == -1 || x == lev_fieldx ? 4 :
1672 y == -1 || y == lev_fieldy ? 5 : 6);
1674 return border[steel_position][steel_type];
1677 void DrawScreenElement(int x, int y, int element)
1679 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1680 DrawLevelFieldCrumbled(LEVELX(x), LEVELY(y));
1683 void DrawLevelElement(int x, int y, int element)
1685 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1686 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1689 void DrawScreenField(int x, int y)
1691 int lx = LEVELX(x), ly = LEVELY(y);
1692 int element, content;
1694 if (!IN_LEV_FIELD(lx, ly))
1696 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1699 element = getBorderElement(lx, ly);
1701 DrawScreenElement(x, y, element);
1706 element = Feld[lx][ly];
1707 content = Store[lx][ly];
1709 if (IS_MOVING(lx, ly))
1711 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1712 boolean cut_mode = NO_CUTTING;
1714 if (element == EL_QUICKSAND_EMPTYING ||
1715 element == EL_QUICKSAND_FAST_EMPTYING ||
1716 element == EL_MAGIC_WALL_EMPTYING ||
1717 element == EL_BD_MAGIC_WALL_EMPTYING ||
1718 element == EL_DC_MAGIC_WALL_EMPTYING ||
1719 element == EL_AMOEBA_DROPPING)
1720 cut_mode = CUT_ABOVE;
1721 else if (element == EL_QUICKSAND_FILLING ||
1722 element == EL_QUICKSAND_FAST_FILLING ||
1723 element == EL_MAGIC_WALL_FILLING ||
1724 element == EL_BD_MAGIC_WALL_FILLING ||
1725 element == EL_DC_MAGIC_WALL_FILLING)
1726 cut_mode = CUT_BELOW;
1728 if (cut_mode == CUT_ABOVE)
1729 DrawScreenElement(x, y, element);
1731 DrawScreenElement(x, y, EL_EMPTY);
1734 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1735 else if (cut_mode == NO_CUTTING)
1736 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1739 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1741 if (cut_mode == CUT_BELOW &&
1742 IN_LEV_FIELD(lx, ly + 1) && IN_SCR_FIELD(x, y + 1))
1743 DrawLevelElement(lx, ly + 1, element);
1746 if (content == EL_ACID)
1748 int dir = MovDir[lx][ly];
1749 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
1750 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
1752 DrawLevelElementThruMask(newlx, newly, EL_ACID);
1755 else if (IS_BLOCKED(lx, ly))
1760 boolean cut_mode = NO_CUTTING;
1761 int element_old, content_old;
1763 Blocked2Moving(lx, ly, &oldx, &oldy);
1766 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1767 MovDir[oldx][oldy] == MV_RIGHT);
1769 element_old = Feld[oldx][oldy];
1770 content_old = Store[oldx][oldy];
1772 if (element_old == EL_QUICKSAND_EMPTYING ||
1773 element_old == EL_QUICKSAND_FAST_EMPTYING ||
1774 element_old == EL_MAGIC_WALL_EMPTYING ||
1775 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1776 element_old == EL_DC_MAGIC_WALL_EMPTYING ||
1777 element_old == EL_AMOEBA_DROPPING)
1778 cut_mode = CUT_ABOVE;
1780 DrawScreenElement(x, y, EL_EMPTY);
1783 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1785 else if (cut_mode == NO_CUTTING)
1786 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1789 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1792 else if (IS_DRAWABLE(element))
1793 DrawScreenElement(x, y, element);
1795 DrawScreenElement(x, y, EL_EMPTY);
1798 void DrawLevelField(int x, int y)
1800 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1801 DrawScreenField(SCREENX(x), SCREENY(y));
1802 else if (IS_MOVING(x, y))
1806 Moving2Blocked(x, y, &newx, &newy);
1807 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1808 DrawScreenField(SCREENX(newx), SCREENY(newy));
1810 else if (IS_BLOCKED(x, y))
1814 Blocked2Moving(x, y, &oldx, &oldy);
1815 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1816 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1820 void DrawSizedElement(int x, int y, int element, int tilesize)
1824 graphic = el2edimg(element);
1825 DrawSizedGraphic(x, y, graphic, 0, tilesize);
1828 void DrawMiniElement(int x, int y, int element)
1832 graphic = el2edimg(element);
1833 DrawMiniGraphic(x, y, graphic);
1836 void DrawSizedElementOrWall(int sx, int sy, int scroll_x, int scroll_y,
1839 int x = sx + scroll_x, y = sy + scroll_y;
1841 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1842 DrawSizedElement(sx, sy, EL_EMPTY, tilesize);
1843 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1844 DrawSizedElement(sx, sy, Feld[x][y], tilesize);
1846 DrawSizedGraphic(sx, sy, el2edimg(getBorderElement(x, y)), 0, tilesize);
1849 void DrawMiniElementOrWall(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 DrawMiniElement(sx, sy, EL_EMPTY);
1855 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1856 DrawMiniElement(sx, sy, Feld[x][y]);
1858 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1861 void DrawEnvelopeBackgroundTiles(int graphic, int startx, int starty,
1862 int x, int y, int xsize, int ysize,
1863 int tile_width, int tile_height)
1867 int dst_x = startx + x * tile_width;
1868 int dst_y = starty + y * tile_height;
1869 int width = graphic_info[graphic].width;
1870 int height = graphic_info[graphic].height;
1871 int inner_width_raw = MAX(width - 2 * tile_width, tile_width);
1872 int inner_height_raw = MAX(height - 2 * tile_height, tile_height);
1873 int inner_width = inner_width_raw - (inner_width_raw % tile_width);
1874 int inner_height = inner_height_raw - (inner_height_raw % tile_height);
1875 int inner_sx = (width >= 3 * tile_width ? tile_width : 0);
1876 int inner_sy = (height >= 3 * tile_height ? tile_height : 0);
1877 boolean draw_masked = graphic_info[graphic].draw_masked;
1879 getFixedGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1881 if (src_bitmap == NULL || width < tile_width || height < tile_height)
1883 ClearRectangle(drawto, dst_x, dst_y, tile_width, tile_height);
1887 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - tile_width :
1888 inner_sx + (x - 1) * tile_width % inner_width);
1889 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - tile_height :
1890 inner_sy + (y - 1) * tile_height % inner_height);
1893 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
1896 BlitBitmap(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
1900 void DrawEnvelopeBackground(int graphic, int startx, int starty,
1901 int x, int y, int xsize, int ysize, int font_nr)
1903 int font_width = getFontWidth(font_nr);
1904 int font_height = getFontHeight(font_nr);
1906 DrawEnvelopeBackgroundTiles(graphic, startx, starty, x, y, xsize, ysize,
1907 font_width, font_height);
1910 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
1912 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1913 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1914 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
1915 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1916 boolean no_delay = (tape.warp_forward);
1917 unsigned int anim_delay = 0;
1918 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
1919 int anim_delay_value = (no_delay ? 0 : frame_delay_value) / 2;
1920 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
1921 int font_width = getFontWidth(font_nr);
1922 int font_height = getFontHeight(font_nr);
1923 int max_xsize = level.envelope[envelope_nr].xsize;
1924 int max_ysize = level.envelope[envelope_nr].ysize;
1925 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
1926 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
1927 int xend = max_xsize;
1928 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
1929 int xstep = (xstart < xend ? 1 : 0);
1930 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
1932 int end = MAX(xend - xstart, yend - ystart);
1935 for (i = start; i <= end; i++)
1937 int last_frame = end; // last frame of this "for" loop
1938 int x = xstart + i * xstep;
1939 int y = ystart + i * ystep;
1940 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
1941 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
1942 int sx = SX + (SXSIZE - xsize * font_width) / 2;
1943 int sy = SY + (SYSIZE - ysize * font_height) / 2;
1946 SetDrawtoField(DRAW_FIELDBUFFER);
1948 BlitScreenToBitmap(backbuffer);
1950 SetDrawtoField(DRAW_BACKBUFFER);
1952 for (yy = 0; yy < ysize; yy++)
1953 for (xx = 0; xx < xsize; xx++)
1954 DrawEnvelopeBackground(graphic, sx, sy, xx, yy, xsize, ysize, font_nr);
1956 DrawTextBuffer(sx + font_width, sy + font_height,
1957 level.envelope[envelope_nr].text, font_nr, max_xsize,
1958 xsize - 2, ysize - 2, 0, mask_mode,
1959 level.envelope[envelope_nr].autowrap,
1960 level.envelope[envelope_nr].centered, FALSE);
1962 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
1965 SkipUntilDelayReached(&anim_delay, anim_delay_value, &i, last_frame);
1969 void ShowEnvelope(int envelope_nr)
1971 int element = EL_ENVELOPE_1 + envelope_nr;
1972 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1973 int sound_opening = element_info[element].sound[ACTION_OPENING];
1974 int sound_closing = element_info[element].sound[ACTION_CLOSING];
1975 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1976 boolean no_delay = (tape.warp_forward);
1977 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
1978 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
1979 int anim_mode = graphic_info[graphic].anim_mode;
1980 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
1981 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
1983 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
1985 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
1987 if (anim_mode == ANIM_DEFAULT)
1988 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
1990 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
1993 Delay(wait_delay_value);
1995 WaitForEventToContinue();
1997 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
1999 if (anim_mode != ANIM_NONE)
2000 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
2002 if (anim_mode == ANIM_DEFAULT)
2003 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
2005 game.envelope_active = FALSE;
2007 SetDrawtoField(DRAW_FIELDBUFFER);
2009 redraw_mask |= REDRAW_FIELD;
2013 static void setRequestCenterPosition(int *x, int *y)
2015 int sx_center = (request.x != -1 ? request.x : SX + SXSIZE / 2);
2016 int sy_center = (request.y != -1 ? request.y : SY + SYSIZE / 2);
2022 static void setRequestPosition(int *x, int *y, boolean add_border_size)
2024 int border_size = request.border_size;
2025 int sx_center, sy_center;
2028 setRequestCenterPosition(&sx_center, &sy_center);
2030 sx = sx_center - request.width / 2;
2031 sy = sy_center - request.height / 2;
2033 if (add_border_size)
2043 void DrawEnvelopeRequest(char *text)
2045 char *text_final = text;
2046 char *text_door_style = NULL;
2047 int graphic = IMG_BACKGROUND_REQUEST;
2048 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2049 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2050 int font_nr = FONT_REQUEST;
2051 int font_width = getFontWidth(font_nr);
2052 int font_height = getFontHeight(font_nr);
2053 int border_size = request.border_size;
2054 int line_spacing = request.line_spacing;
2055 int line_height = font_height + line_spacing;
2056 int text_width = request.width - 2 * border_size;
2057 int text_height = request.height - 2 * border_size;
2058 int line_length = text_width / font_width;
2059 int max_lines = text_height / line_height;
2060 int width = request.width;
2061 int height = request.height;
2062 int tile_size = request.step_offset;
2063 int x_steps = width / tile_size;
2064 int y_steps = height / tile_size;
2068 if (request.wrap_single_words)
2070 char *src_text_ptr, *dst_text_ptr;
2072 text_door_style = checked_malloc(2 * strlen(text) + 1);
2074 src_text_ptr = text;
2075 dst_text_ptr = text_door_style;
2077 while (*src_text_ptr)
2079 if (*src_text_ptr == ' ' ||
2080 *src_text_ptr == '?' ||
2081 *src_text_ptr == '!')
2082 *dst_text_ptr++ = '\n';
2084 if (*src_text_ptr != ' ')
2085 *dst_text_ptr++ = *src_text_ptr;
2090 *dst_text_ptr = '\0';
2092 text_final = text_door_style;
2095 setRequestPosition(&sx, &sy, FALSE);
2097 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
2099 for (y = 0; y < y_steps; y++)
2100 for (x = 0; x < x_steps; x++)
2101 DrawEnvelopeBackgroundTiles(graphic, sx, sy,
2102 x, y, x_steps, y_steps,
2103 tile_size, tile_size);
2105 DrawTextBuffer(sx + border_size, sy + border_size, text_final, font_nr,
2106 line_length, -1, max_lines, line_spacing, mask_mode,
2107 request.autowrap, request.centered, FALSE);
2109 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2110 RedrawGadget(tool_gadget[i]);
2112 // store readily prepared envelope request for later use when animating
2113 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2115 if (text_door_style)
2116 free(text_door_style);
2119 void AnimateEnvelopeRequest(int anim_mode, int action)
2121 int graphic = IMG_BACKGROUND_REQUEST;
2122 boolean draw_masked = graphic_info[graphic].draw_masked;
2123 int delay_value_normal = request.step_delay;
2124 int delay_value_fast = delay_value_normal / 2;
2125 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2126 boolean no_delay = (tape.warp_forward);
2127 int delay_value = (ffwd_delay ? delay_value_fast : delay_value_normal);
2128 int anim_delay_value = (no_delay ? 0 : delay_value + 500 * 0) / 2;
2129 unsigned int anim_delay = 0;
2131 int width = request.width;
2132 int height = request.height;
2133 int tile_size = request.step_offset;
2134 int max_xsize = width / tile_size;
2135 int max_ysize = height / tile_size;
2136 int max_xsize_inner = max_xsize - 2;
2137 int max_ysize_inner = max_ysize - 2;
2139 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize_inner : 0);
2140 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize_inner : 0);
2141 int xend = max_xsize_inner;
2142 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize_inner : 0);
2143 int xstep = (xstart < xend ? 1 : 0);
2144 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2146 int end = MAX(xend - xstart, yend - ystart);
2149 if (setup.quick_doors)
2157 if (action == ACTION_OPENING)
2158 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2159 else if (action == ACTION_CLOSING)
2160 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2163 for (i = start; i <= end; i++)
2165 int last_frame = end; // last frame of this "for" loop
2166 int x = xstart + i * xstep;
2167 int y = ystart + i * ystep;
2168 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2169 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2170 int xsize_size_left = (xsize - 1) * tile_size;
2171 int ysize_size_top = (ysize - 1) * tile_size;
2172 int max_xsize_pos = (max_xsize - 1) * tile_size;
2173 int max_ysize_pos = (max_ysize - 1) * tile_size;
2174 int sx_center, sy_center;
2179 setRequestCenterPosition(&sx_center, &sy_center);
2181 src_x = sx_center - width / 2;
2182 src_y = sy_center - height / 2;
2183 dst_x = sx_center - xsize * tile_size / 2;
2184 dst_y = sy_center - ysize * tile_size / 2;
2186 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2188 for (yy = 0; yy < 2; yy++)
2190 for (xx = 0; xx < 2; xx++)
2192 int src_xx = src_x + xx * max_xsize_pos;
2193 int src_yy = src_y + yy * max_ysize_pos;
2194 int dst_xx = dst_x + xx * xsize_size_left;
2195 int dst_yy = dst_y + yy * ysize_size_top;
2196 int xx_size = (xx ? tile_size : xsize_size_left);
2197 int yy_size = (yy ? tile_size : ysize_size_top);
2200 BlitBitmapMasked(bitmap_db_cross, backbuffer,
2201 src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
2203 BlitBitmap(bitmap_db_cross, backbuffer,
2204 src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
2208 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2213 SkipUntilDelayReached(&anim_delay, anim_delay_value, &i, last_frame);
2217 void ShowEnvelopeRequest(char *text, unsigned int req_state, int action)
2219 int last_game_status = game_status; /* save current game status */
2220 int graphic = IMG_BACKGROUND_REQUEST;
2221 int sound_opening = SND_REQUEST_OPENING;
2222 int sound_closing = SND_REQUEST_CLOSING;
2223 int anim_mode = graphic_info[graphic].anim_mode;
2224 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2225 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2227 if (game_status == GAME_MODE_PLAYING)
2228 BlitScreenToBitmap(backbuffer);
2230 SetDrawtoField(DRAW_BACKBUFFER);
2232 // SetDrawBackgroundMask(REDRAW_NONE);
2234 if (action == ACTION_OPENING)
2236 BlitBitmap(backbuffer, bitmap_db_store, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2238 if (req_state & REQ_ASK)
2240 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2241 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2243 else if (req_state & REQ_CONFIRM)
2245 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2247 else if (req_state & REQ_PLAYER)
2249 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2250 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2251 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2252 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2255 DrawEnvelopeRequest(text);
2257 if (game_status != GAME_MODE_MAIN)
2261 /* force DOOR font inside door area */
2262 game_status = GAME_MODE_PSEUDO_DOOR;
2264 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
2266 if (action == ACTION_OPENING)
2268 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2270 if (anim_mode == ANIM_DEFAULT)
2271 AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_OPENING);
2273 AnimateEnvelopeRequest(main_anim_mode, ACTION_OPENING);
2277 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2279 if (anim_mode != ANIM_NONE)
2280 AnimateEnvelopeRequest(main_anim_mode, ACTION_CLOSING);
2282 if (anim_mode == ANIM_DEFAULT)
2283 AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_CLOSING);
2286 game.envelope_active = FALSE;
2288 game_status = last_game_status; /* restore current game status */
2290 if (action == ACTION_CLOSING)
2292 if (game_status != GAME_MODE_MAIN)
2295 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2298 // SetDrawBackgroundMask(last_draw_background_mask);
2300 redraw_mask |= REDRAW_FIELD;
2302 if (game_status == GAME_MODE_MAIN)
2307 if (action == ACTION_CLOSING &&
2308 game_status == GAME_MODE_PLAYING &&
2309 level.game_engine_type == GAME_ENGINE_TYPE_RND)
2310 SetDrawtoField(DRAW_FIELDBUFFER);
2313 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
2317 int graphic = el2preimg(element);
2319 getSizedGraphicSource(graphic, 0, tilesize, &src_bitmap, &src_x, &src_y);
2320 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
2323 void DrawLevel(int draw_background_mask)
2327 SetMainBackgroundImage(IMG_BACKGROUND_PLAYING);
2328 SetDrawBackgroundMask(draw_background_mask);
2332 for (x = BX1; x <= BX2; x++)
2333 for (y = BY1; y <= BY2; y++)
2334 DrawScreenField(x, y);
2336 redraw_mask |= REDRAW_FIELD;
2339 void DrawSizedLevel(int size_x, int size_y, int scroll_x, int scroll_y,
2344 for (x = 0; x < size_x; x++)
2345 for (y = 0; y < size_y; y++)
2346 DrawSizedElementOrWall(x, y, scroll_x, scroll_y, tilesize);
2348 redraw_mask |= REDRAW_FIELD;
2351 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
2355 for (x = 0; x < size_x; x++)
2356 for (y = 0; y < size_y; y++)
2357 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
2359 redraw_mask |= REDRAW_FIELD;
2362 static void DrawPreviewLevelPlayfieldExt(int from_x, int from_y)
2364 boolean show_level_border = (BorderElement != EL_EMPTY);
2365 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2366 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2367 int tile_size = preview.tile_size;
2368 int preview_width = preview.xsize * tile_size;
2369 int preview_height = preview.ysize * tile_size;
2370 int real_preview_xsize = MIN(level_xsize, preview.xsize);
2371 int real_preview_ysize = MIN(level_ysize, preview.ysize);
2372 int real_preview_width = real_preview_xsize * tile_size;
2373 int real_preview_height = real_preview_ysize * tile_size;
2374 int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
2375 int dst_y = SY + ALIGNED_YPOS(preview.y, preview_height, preview.valign);
2378 if (!IN_GFX_FIELD_FULL(dst_x, dst_y + preview_height - 1))
2381 DrawBackground(dst_x, dst_y, preview_width, preview_height);
2383 dst_x += (preview_width - real_preview_width) / 2;
2384 dst_y += (preview_height - real_preview_height) / 2;
2386 for (x = 0; x < real_preview_xsize; x++)
2388 for (y = 0; y < real_preview_ysize; y++)
2390 int lx = from_x + x + (show_level_border ? -1 : 0);
2391 int ly = from_y + y + (show_level_border ? -1 : 0);
2392 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
2393 getBorderElement(lx, ly));
2395 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
2396 element, tile_size);
2400 redraw_mask |= REDRAW_MICROLEVEL;
2403 #define MICROLABEL_EMPTY 0
2404 #define MICROLABEL_LEVEL_NAME 1
2405 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
2406 #define MICROLABEL_LEVEL_AUTHOR 3
2407 #define MICROLABEL_IMPORTED_FROM_HEAD 4
2408 #define MICROLABEL_IMPORTED_FROM 5
2409 #define MICROLABEL_IMPORTED_BY_HEAD 6
2410 #define MICROLABEL_IMPORTED_BY 7
2412 static int getMaxTextLength(struct TextPosInfo *pos, int font_nr)
2414 int max_text_width = SXSIZE;
2415 int font_width = getFontWidth(font_nr);
2417 if (pos->align == ALIGN_CENTER)
2418 max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
2419 else if (pos->align == ALIGN_RIGHT)
2420 max_text_width = pos->x;
2422 max_text_width = SXSIZE - pos->x;
2424 return max_text_width / font_width;
2427 static void DrawPreviewLevelLabelExt(int mode)
2429 struct TextPosInfo *pos = &menu.main.text.level_info_2;
2430 char label_text[MAX_OUTPUT_LINESIZE + 1];
2431 int max_len_label_text;
2432 int font_nr = pos->font;
2435 if (!IN_GFX_FIELD_FULL(pos->x, pos->y + getFontHeight(pos->font)))
2438 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
2439 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
2440 mode == MICROLABEL_IMPORTED_BY_HEAD)
2441 font_nr = pos->font_alt;
2443 max_len_label_text = getMaxTextLength(pos, font_nr);
2445 if (pos->size != -1)
2446 max_len_label_text = pos->size;
2448 for (i = 0; i < max_len_label_text; i++)
2449 label_text[i] = ' ';
2450 label_text[max_len_label_text] = '\0';
2452 if (strlen(label_text) > 0)
2453 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2456 (mode == MICROLABEL_LEVEL_NAME ? level.name :
2457 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
2458 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
2459 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
2460 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
2461 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
2462 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
2463 max_len_label_text);
2464 label_text[max_len_label_text] = '\0';
2466 if (strlen(label_text) > 0)
2467 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2469 redraw_mask |= REDRAW_MICROLEVEL;
2472 static void DrawPreviewLevelExt(boolean restart)
2474 static unsigned int scroll_delay = 0;
2475 static unsigned int label_delay = 0;
2476 static int from_x, from_y, scroll_direction;
2477 static int label_state, label_counter;
2478 unsigned int scroll_delay_value = preview.step_delay;
2479 boolean show_level_border = (BorderElement != EL_EMPTY);
2480 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2481 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2482 int last_game_status = game_status; /* save current game status */
2489 if (preview.anim_mode == ANIM_CENTERED)
2491 if (level_xsize > preview.xsize)
2492 from_x = (level_xsize - preview.xsize) / 2;
2493 if (level_ysize > preview.ysize)
2494 from_y = (level_ysize - preview.ysize) / 2;
2497 from_x += preview.xoffset;
2498 from_y += preview.yoffset;
2500 scroll_direction = MV_RIGHT;
2504 DrawPreviewLevelPlayfieldExt(from_x, from_y);
2505 DrawPreviewLevelLabelExt(label_state);
2507 /* initialize delay counters */
2508 DelayReached(&scroll_delay, 0);
2509 DelayReached(&label_delay, 0);
2511 if (leveldir_current->name)
2513 struct TextPosInfo *pos = &menu.main.text.level_info_1;
2514 char label_text[MAX_OUTPUT_LINESIZE + 1];
2515 int font_nr = pos->font;
2516 int max_len_label_text = getMaxTextLength(pos, font_nr);
2518 if (pos->size != -1)
2519 max_len_label_text = pos->size;
2521 strncpy(label_text, leveldir_current->name, max_len_label_text);
2522 label_text[max_len_label_text] = '\0';
2524 if (IN_GFX_FIELD_FULL(pos->x, pos->y + getFontHeight(pos->font)))
2525 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2528 game_status = last_game_status; /* restore current game status */
2533 /* scroll preview level, if needed */
2534 if (preview.anim_mode != ANIM_NONE &&
2535 (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
2536 DelayReached(&scroll_delay, scroll_delay_value))
2538 switch (scroll_direction)
2543 from_x -= preview.step_offset;
2544 from_x = (from_x < 0 ? 0 : from_x);
2547 scroll_direction = MV_UP;
2551 if (from_x < level_xsize - preview.xsize)
2553 from_x += preview.step_offset;
2554 from_x = (from_x > level_xsize - preview.xsize ?
2555 level_xsize - preview.xsize : from_x);
2558 scroll_direction = MV_DOWN;
2564 from_y -= preview.step_offset;
2565 from_y = (from_y < 0 ? 0 : from_y);
2568 scroll_direction = MV_RIGHT;
2572 if (from_y < level_ysize - preview.ysize)
2574 from_y += preview.step_offset;
2575 from_y = (from_y > level_ysize - preview.ysize ?
2576 level_ysize - preview.ysize : from_y);
2579 scroll_direction = MV_LEFT;
2586 DrawPreviewLevelPlayfieldExt(from_x, from_y);
2589 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
2590 /* redraw micro level label, if needed */
2591 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
2592 !strEqual(level.author, ANONYMOUS_NAME) &&
2593 !strEqual(level.author, leveldir_current->name) &&
2594 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
2596 int max_label_counter = 23;
2598 if (leveldir_current->imported_from != NULL &&
2599 strlen(leveldir_current->imported_from) > 0)
2600 max_label_counter += 14;
2601 if (leveldir_current->imported_by != NULL &&
2602 strlen(leveldir_current->imported_by) > 0)
2603 max_label_counter += 14;
2605 label_counter = (label_counter + 1) % max_label_counter;
2606 label_state = (label_counter >= 0 && label_counter <= 7 ?
2607 MICROLABEL_LEVEL_NAME :
2608 label_counter >= 9 && label_counter <= 12 ?
2609 MICROLABEL_LEVEL_AUTHOR_HEAD :
2610 label_counter >= 14 && label_counter <= 21 ?
2611 MICROLABEL_LEVEL_AUTHOR :
2612 label_counter >= 23 && label_counter <= 26 ?
2613 MICROLABEL_IMPORTED_FROM_HEAD :
2614 label_counter >= 28 && label_counter <= 35 ?
2615 MICROLABEL_IMPORTED_FROM :
2616 label_counter >= 37 && label_counter <= 40 ?
2617 MICROLABEL_IMPORTED_BY_HEAD :
2618 label_counter >= 42 && label_counter <= 49 ?
2619 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
2621 if (leveldir_current->imported_from == NULL &&
2622 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
2623 label_state == MICROLABEL_IMPORTED_FROM))
2624 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
2625 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
2627 DrawPreviewLevelLabelExt(label_state);
2630 game_status = last_game_status; /* restore current game status */
2633 void DrawPreviewLevelInitial()
2635 DrawPreviewLevelExt(TRUE);
2638 void DrawPreviewLevelAnimation()
2640 DrawPreviewLevelExt(FALSE);
2643 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
2644 int graphic, int sync_frame, int mask_mode)
2646 int frame = getGraphicAnimationFrame(graphic, sync_frame);
2648 if (mask_mode == USE_MASKING)
2649 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
2651 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
2654 inline void DrawFixedGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
2655 int graphic, int sync_frame,
2658 int frame = getGraphicAnimationFrame(graphic, sync_frame);
2660 if (mask_mode == USE_MASKING)
2661 DrawFixedGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
2663 DrawFixedGraphicExt(dst_bitmap, x, y, graphic, frame);
2666 inline void DrawGraphicAnimation(int x, int y, int graphic)
2668 int lx = LEVELX(x), ly = LEVELY(y);
2670 if (!IN_SCR_FIELD(x, y))
2673 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
2674 graphic, GfxFrame[lx][ly], NO_MASKING);
2676 MarkTileDirty(x, y);
2679 inline void DrawFixedGraphicAnimation(int x, int y, int graphic)
2681 int lx = LEVELX(x), ly = LEVELY(y);
2683 if (!IN_SCR_FIELD(x, y))
2686 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
2687 graphic, GfxFrame[lx][ly], NO_MASKING);
2688 MarkTileDirty(x, y);
2691 void DrawLevelGraphicAnimation(int x, int y, int graphic)
2693 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2696 void DrawLevelElementAnimation(int x, int y, int element)
2698 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2700 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2703 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
2705 int sx = SCREENX(x), sy = SCREENY(y);
2707 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2710 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2713 DrawGraphicAnimation(sx, sy, graphic);
2716 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
2717 DrawLevelFieldCrumbled(x, y);
2719 if (GFX_CRUMBLED(Feld[x][y]))
2720 DrawLevelFieldCrumbled(x, y);
2724 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
2726 int sx = SCREENX(x), sy = SCREENY(y);
2729 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2732 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2734 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2737 DrawGraphicAnimation(sx, sy, graphic);
2739 if (GFX_CRUMBLED(element))
2740 DrawLevelFieldCrumbled(x, y);
2743 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
2745 if (player->use_murphy)
2747 /* this works only because currently only one player can be "murphy" ... */
2748 static int last_horizontal_dir = MV_LEFT;
2749 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
2751 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2752 last_horizontal_dir = move_dir;
2754 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
2756 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
2758 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
2764 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
2767 static boolean equalGraphics(int graphic1, int graphic2)
2769 struct GraphicInfo *g1 = &graphic_info[graphic1];
2770 struct GraphicInfo *g2 = &graphic_info[graphic2];
2772 return (g1->bitmap == g2->bitmap &&
2773 g1->src_x == g2->src_x &&
2774 g1->src_y == g2->src_y &&
2775 g1->anim_frames == g2->anim_frames &&
2776 g1->anim_delay == g2->anim_delay &&
2777 g1->anim_mode == g2->anim_mode);
2780 void DrawAllPlayers()
2784 for (i = 0; i < MAX_PLAYERS; i++)
2785 if (stored_player[i].active)
2786 DrawPlayer(&stored_player[i]);
2789 void DrawPlayerField(int x, int y)
2791 if (!IS_PLAYER(x, y))
2794 DrawPlayer(PLAYERINFO(x, y));
2797 #define DRAW_PLAYER_OVER_PUSHED_ELEMENT 1
2799 void DrawPlayer(struct PlayerInfo *player)
2801 int jx = player->jx;
2802 int jy = player->jy;
2803 int move_dir = player->MovDir;
2804 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
2805 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
2806 int last_jx = (player->is_moving ? jx - dx : jx);
2807 int last_jy = (player->is_moving ? jy - dy : jy);
2808 int next_jx = jx + dx;
2809 int next_jy = jy + dy;
2810 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
2811 boolean player_is_opaque = FALSE;
2812 int sx = SCREENX(jx), sy = SCREENY(jy);
2813 int sxx = 0, syy = 0;
2814 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
2816 int action = ACTION_DEFAULT;
2817 int last_player_graphic = getPlayerGraphic(player, move_dir);
2818 int last_player_frame = player->Frame;
2821 /* GfxElement[][] is set to the element the player is digging or collecting;
2822 remove also for off-screen player if the player is not moving anymore */
2823 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
2824 GfxElement[jx][jy] = EL_UNDEFINED;
2826 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
2830 if (!IN_LEV_FIELD(jx, jy))
2832 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
2833 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
2834 printf("DrawPlayerField(): This should never happen!\n");
2839 if (element == EL_EXPLOSION)
2842 action = (player->is_pushing ? ACTION_PUSHING :
2843 player->is_digging ? ACTION_DIGGING :
2844 player->is_collecting ? ACTION_COLLECTING :
2845 player->is_moving ? ACTION_MOVING :
2846 player->is_snapping ? ACTION_SNAPPING :
2847 player->is_dropping ? ACTION_DROPPING :
2848 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
2850 if (player->is_waiting)
2851 move_dir = player->dir_waiting;
2853 InitPlayerGfxAnimation(player, action, move_dir);
2855 /* ----------------------------------------------------------------------- */
2856 /* draw things in the field the player is leaving, if needed */
2857 /* ----------------------------------------------------------------------- */
2859 if (player->is_moving)
2861 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
2863 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
2865 if (last_element == EL_DYNAMITE_ACTIVE ||
2866 last_element == EL_EM_DYNAMITE_ACTIVE ||
2867 last_element == EL_SP_DISK_RED_ACTIVE)
2868 DrawDynamite(last_jx, last_jy);
2870 DrawLevelFieldThruMask(last_jx, last_jy);
2872 else if (last_element == EL_DYNAMITE_ACTIVE ||
2873 last_element == EL_EM_DYNAMITE_ACTIVE ||
2874 last_element == EL_SP_DISK_RED_ACTIVE)
2875 DrawDynamite(last_jx, last_jy);
2877 /* !!! this is not enough to prevent flickering of players which are
2878 moving next to each others without a free tile between them -- this
2879 can only be solved by drawing all players layer by layer (first the
2880 background, then the foreground etc.) !!! => TODO */
2881 else if (!IS_PLAYER(last_jx, last_jy))
2882 DrawLevelField(last_jx, last_jy);
2885 DrawLevelField(last_jx, last_jy);
2888 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
2889 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
2892 if (!IN_SCR_FIELD(sx, sy))
2895 /* ----------------------------------------------------------------------- */
2896 /* draw things behind the player, if needed */
2897 /* ----------------------------------------------------------------------- */
2900 DrawLevelElement(jx, jy, Back[jx][jy]);
2901 else if (IS_ACTIVE_BOMB(element))
2902 DrawLevelElement(jx, jy, EL_EMPTY);
2905 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
2907 int old_element = GfxElement[jx][jy];
2908 int old_graphic = el_act_dir2img(old_element, action, move_dir);
2909 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
2911 if (GFX_CRUMBLED(old_element))
2912 DrawLevelFieldCrumbledDigging(jx, jy, move_dir, player->StepFrame);
2914 DrawGraphic(sx, sy, old_graphic, frame);
2916 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
2917 player_is_opaque = TRUE;
2921 GfxElement[jx][jy] = EL_UNDEFINED;
2923 /* make sure that pushed elements are drawn with correct frame rate */
2924 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2926 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
2927 GfxFrame[jx][jy] = player->StepFrame;
2929 DrawLevelField(jx, jy);
2933 #if !DRAW_PLAYER_OVER_PUSHED_ELEMENT
2934 /* ----------------------------------------------------------------------- */
2935 /* draw player himself */
2936 /* ----------------------------------------------------------------------- */
2938 graphic = getPlayerGraphic(player, move_dir);
2940 /* in the case of changed player action or direction, prevent the current
2941 animation frame from being restarted for identical animations */
2942 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
2943 player->Frame = last_player_frame;
2945 frame = getGraphicAnimationFrame(graphic, player->Frame);
2949 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2950 sxx = player->GfxPos;
2952 syy = player->GfxPos;
2955 if (player_is_opaque)
2956 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
2958 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2960 if (SHIELD_ON(player))
2962 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
2963 IMG_SHIELD_NORMAL_ACTIVE);
2964 int frame = getGraphicAnimationFrame(graphic, -1);
2966 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2970 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
2973 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2974 sxx = player->GfxPos;
2976 syy = player->GfxPos;
2980 /* ----------------------------------------------------------------------- */
2981 /* draw things the player is pushing, if needed */
2982 /* ----------------------------------------------------------------------- */
2984 if (player->is_pushing && player->is_moving)
2986 int px = SCREENX(jx), py = SCREENY(jy);
2987 int pxx = (TILEX - ABS(sxx)) * dx;
2988 int pyy = (TILEY - ABS(syy)) * dy;
2989 int gfx_frame = GfxFrame[jx][jy];
2995 if (!IS_MOVING(jx, jy)) /* push movement already finished */
2997 element = Feld[next_jx][next_jy];
2998 gfx_frame = GfxFrame[next_jx][next_jy];
3001 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
3003 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
3004 frame = getGraphicAnimationFrame(graphic, sync_frame);
3006 /* draw background element under pushed element (like the Sokoban field) */
3007 if (game.use_masked_pushing && IS_MOVING(jx, jy))
3009 /* this allows transparent pushing animation over non-black background */
3012 DrawLevelElement(jx, jy, Back[jx][jy]);
3014 DrawLevelElement(jx, jy, EL_EMPTY);
3016 if (Back[next_jx][next_jy])
3017 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3019 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
3021 else if (Back[next_jx][next_jy])
3022 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3025 /* do not draw (EM style) pushing animation when pushing is finished */
3026 /* (two-tile animations usually do not contain start and end frame) */
3027 if (graphic_info[graphic].double_movement && !IS_MOVING(jx, jy))
3028 DrawLevelElement(next_jx, next_jy, Feld[next_jx][next_jy]);
3030 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3032 /* masked drawing is needed for EMC style (double) movement graphics */
3033 /* !!! (ONLY WHEN DRAWING PUSHED ELEMENT OVER THE PLAYER) !!! */
3034 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3038 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
3039 /* ----------------------------------------------------------------------- */
3040 /* draw player himself */
3041 /* ----------------------------------------------------------------------- */
3043 graphic = getPlayerGraphic(player, move_dir);
3045 /* in the case of changed player action or direction, prevent the current
3046 animation frame from being restarted for identical animations */
3047 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
3048 player->Frame = last_player_frame;
3050 frame = getGraphicAnimationFrame(graphic, player->Frame);
3054 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3055 sxx = player->GfxPos;
3057 syy = player->GfxPos;
3060 if (player_is_opaque)
3061 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
3063 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3065 if (SHIELD_ON(player))
3067 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
3068 IMG_SHIELD_NORMAL_ACTIVE);
3069 int frame = getGraphicAnimationFrame(graphic, -1);
3071 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3075 /* ----------------------------------------------------------------------- */
3076 /* draw things in front of player (active dynamite or dynabombs) */
3077 /* ----------------------------------------------------------------------- */
3079 if (IS_ACTIVE_BOMB(element))
3081 graphic = el2img(element);
3082 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
3084 if (game.emulation == EMU_SUPAPLEX)
3085 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
3087 DrawGraphicThruMask(sx, sy, graphic, frame);
3090 if (player_is_moving && last_element == EL_EXPLOSION)
3092 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
3093 GfxElement[last_jx][last_jy] : EL_EMPTY);
3094 int graphic = el_act2img(element, ACTION_EXPLODING);
3095 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
3096 int phase = ExplodePhase[last_jx][last_jy] - 1;
3097 int frame = getGraphicAnimationFrame(graphic, phase - delay);
3100 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
3103 /* ----------------------------------------------------------------------- */
3104 /* draw elements the player is just walking/passing through/under */
3105 /* ----------------------------------------------------------------------- */
3107 if (player_is_moving)
3109 /* handle the field the player is leaving ... */
3110 if (IS_ACCESSIBLE_INSIDE(last_element))
3111 DrawLevelField(last_jx, last_jy);
3112 else if (IS_ACCESSIBLE_UNDER(last_element))
3113 DrawLevelFieldThruMask(last_jx, last_jy);
3116 /* do not redraw accessible elements if the player is just pushing them */
3117 if (!player_is_moving || !player->is_pushing)
3119 /* ... and the field the player is entering */
3120 if (IS_ACCESSIBLE_INSIDE(element))
3121 DrawLevelField(jx, jy);
3122 else if (IS_ACCESSIBLE_UNDER(element))
3123 DrawLevelFieldThruMask(jx, jy);
3126 MarkTileDirty(sx, sy);
3129 /* ------------------------------------------------------------------------- */
3131 void WaitForEventToContinue()
3133 boolean still_wait = TRUE;
3135 /* simulate releasing mouse button over last gadget, if still pressed */
3137 HandleGadgets(-1, -1, 0);
3139 button_status = MB_RELEASED;
3153 case EVENT_BUTTONPRESS:
3154 case EVENT_KEYPRESS:
3158 case EVENT_KEYRELEASE:
3159 ClearPlayerAction();
3163 HandleOtherEvents(&event);
3167 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3174 /* don't eat all CPU time */
3179 #define MAX_REQUEST_LINES 13
3180 #define MAX_REQUEST_LINE_FONT1_LEN 7
3181 #define MAX_REQUEST_LINE_FONT2_LEN 10
3183 static int RequestHandleEvents(unsigned int req_state)
3185 boolean level_solved = (game_status == GAME_MODE_PLAYING &&
3186 local_player->LevelSolved_GameEnd);
3187 int last_game_status = game_status; /* save current game status */
3188 int width = request.width;
3189 int height = request.height;
3193 setRequestPosition(&sx, &sy, FALSE);
3195 button_status = MB_RELEASED;
3197 request_gadget_id = -1;
3204 SetDrawtoField(DRAW_FIELDBUFFER);
3206 HandleGameActions();
3208 SetDrawtoField(DRAW_BACKBUFFER);
3210 if (global.use_envelope_request)
3212 /* copy current state of request area to middle of playfield area */
3213 BlitBitmap(bitmap_db_cross, drawto, sx, sy, width, height, sx, sy);
3221 while (NextValidEvent(&event))
3225 case EVENT_BUTTONPRESS:
3226 case EVENT_BUTTONRELEASE:
3227 case EVENT_MOTIONNOTIFY:
3231 if (event.type == EVENT_MOTIONNOTIFY)
3236 motion_status = TRUE;
3237 mx = ((MotionEvent *) &event)->x;
3238 my = ((MotionEvent *) &event)->y;
3242 motion_status = FALSE;
3243 mx = ((ButtonEvent *) &event)->x;
3244 my = ((ButtonEvent *) &event)->y;
3245 if (event.type == EVENT_BUTTONPRESS)
3246 button_status = ((ButtonEvent *) &event)->button;
3248 button_status = MB_RELEASED;
3251 /* this sets 'request_gadget_id' */
3252 HandleGadgets(mx, my, button_status);
3254 switch (request_gadget_id)
3256 case TOOL_CTRL_ID_YES:
3259 case TOOL_CTRL_ID_NO:
3262 case TOOL_CTRL_ID_CONFIRM:
3263 result = TRUE | FALSE;
3266 case TOOL_CTRL_ID_PLAYER_1:
3269 case TOOL_CTRL_ID_PLAYER_2:
3272 case TOOL_CTRL_ID_PLAYER_3:
3275 case TOOL_CTRL_ID_PLAYER_4:
3286 case EVENT_KEYPRESS:
3287 switch (GetEventKey((KeyEvent *)&event, TRUE))
3290 if (req_state & REQ_CONFIRM)
3295 #if defined(TARGET_SDL2)
3302 #if defined(TARGET_SDL2)
3312 if (req_state & REQ_PLAYER)
3316 case EVENT_KEYRELEASE:
3317 ClearPlayerAction();
3321 HandleOtherEvents(&event);
3326 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3328 int joy = AnyJoystick();
3330 if (joy & JOY_BUTTON_1)
3332 else if (joy & JOY_BUTTON_2)
3338 if (global.use_envelope_request)
3340 /* copy back current state of pressed buttons inside request area */
3341 BlitBitmap(drawto, bitmap_db_cross, sx, sy, width, height, sx, sy);
3348 if (!PendingEvent()) /* delay only if no pending events */
3352 game_status = GAME_MODE_PSEUDO_DOOR;
3356 game_status = last_game_status; /* restore current game status */
3362 static boolean RequestDoor(char *text, unsigned int req_state)
3364 unsigned int old_door_state;
3365 int last_game_status = game_status; /* save current game status */
3366 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
3367 int font_nr = FONT_TEXT_2;
3372 if (maxWordLengthInString(text) > MAX_REQUEST_LINE_FONT1_LEN)
3374 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
3375 font_nr = FONT_TEXT_1;
3378 if (game_status == GAME_MODE_PLAYING)
3379 BlitScreenToBitmap(backbuffer);
3381 /* disable deactivated drawing when quick-loading level tape recording */
3382 if (tape.playing && tape.deactivate_display)
3383 TapeDeactivateDisplayOff(TRUE);
3385 SetMouseCursor(CURSOR_DEFAULT);
3387 #if defined(NETWORK_AVALIABLE)
3388 /* pause network game while waiting for request to answer */
3389 if (options.network &&
3390 game_status == GAME_MODE_PLAYING &&
3391 req_state & REQUEST_WAIT_FOR_INPUT)
3392 SendToServer_PausePlaying();
3395 old_door_state = GetDoorState();
3397 /* simulate releasing mouse button over last gadget, if still pressed */
3399 HandleGadgets(-1, -1, 0);
3403 /* draw released gadget before proceeding */
3406 if (old_door_state & DOOR_OPEN_1)
3408 CloseDoor(DOOR_CLOSE_1);
3410 /* save old door content */
3411 BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
3412 0 * DXSIZE, 0, DXSIZE, DYSIZE, 1 * DXSIZE, 0);
3415 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
3416 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3418 /* clear door drawing field */
3419 DrawBackground(DX, DY, DXSIZE, DYSIZE);
3421 /* force DOOR font inside door area */
3422 game_status = GAME_MODE_PSEUDO_DOOR;
3424 /* write text for request */
3425 for (text_ptr = text, ty = 0; ty < MAX_REQUEST_LINES; ty++)
3427 char text_line[max_request_line_len + 1];
3433 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
3435 tc = *(text_ptr + tx);
3436 // if (!tc || tc == ' ')
3437 if (!tc || tc == ' ' || tc == '?' || tc == '!')
3441 if ((tc == '?' || tc == '!') && tl == 0)
3451 strncpy(text_line, text_ptr, tl);
3454 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
3455 DY + 8 + ty * (getFontHeight(font_nr) + 2),
3456 text_line, font_nr);
3458 text_ptr += tl + (tc == ' ' ? 1 : 0);
3459 // text_ptr += tl + (tc == ' ' || tc == '?' || tc == '!' ? 1 : 0);
3462 game_status = last_game_status; /* restore current game status */
3464 if (req_state & REQ_ASK)
3466 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
3467 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
3469 else if (req_state & REQ_CONFIRM)
3471 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
3473 else if (req_state & REQ_PLAYER)
3475 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
3476 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
3477 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
3478 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
3481 /* copy request gadgets to door backbuffer */
3482 BlitBitmap(drawto, bitmap_db_door_1, DX, DY, DXSIZE, DYSIZE, 0, 0);
3484 OpenDoor(DOOR_OPEN_1);
3486 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
3488 if (game_status == GAME_MODE_PLAYING)
3490 SetPanelBackground();
3491 SetDrawBackgroundMask(REDRAW_DOOR_1);
3495 SetDrawBackgroundMask(REDRAW_FIELD);
3501 if (game_status != GAME_MODE_MAIN)
3504 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3506 // ---------- handle request buttons ----------
3507 result = RequestHandleEvents(req_state);
3509 if (game_status != GAME_MODE_MAIN)
3514 if (!(req_state & REQ_STAY_OPEN))
3516 CloseDoor(DOOR_CLOSE_1);
3518 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
3519 (req_state & REQ_REOPEN))
3520 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
3525 if (game_status == GAME_MODE_PLAYING)
3527 SetPanelBackground();
3528 SetDrawBackgroundMask(REDRAW_DOOR_1);
3532 SetDrawBackgroundMask(REDRAW_FIELD);
3535 #if defined(NETWORK_AVALIABLE)
3536 /* continue network game after request */
3537 if (options.network &&
3538 game_status == GAME_MODE_PLAYING &&
3539 req_state & REQUEST_WAIT_FOR_INPUT)
3540 SendToServer_ContinuePlaying();
3543 /* restore deactivated drawing when quick-loading level tape recording */
3544 if (tape.playing && tape.deactivate_display)
3545 TapeDeactivateDisplayOn();
3550 static boolean RequestEnvelope(char *text, unsigned int req_state)
3554 if (game_status == GAME_MODE_PLAYING)
3555 BlitScreenToBitmap(backbuffer);
3557 /* disable deactivated drawing when quick-loading level tape recording */
3558 if (tape.playing && tape.deactivate_display)
3559 TapeDeactivateDisplayOff(TRUE);
3561 SetMouseCursor(CURSOR_DEFAULT);
3563 #if defined(NETWORK_AVALIABLE)
3564 /* pause network game while waiting for request to answer */
3565 if (options.network &&
3566 game_status == GAME_MODE_PLAYING &&
3567 req_state & REQUEST_WAIT_FOR_INPUT)
3568 SendToServer_PausePlaying();
3571 /* simulate releasing mouse button over last gadget, if still pressed */
3573 HandleGadgets(-1, -1, 0);
3577 // (replace with setting corresponding request background)
3578 // SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
3579 // SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3581 /* clear door drawing field */
3582 // DrawBackground(DX, DY, DXSIZE, DYSIZE);
3584 ShowEnvelopeRequest(text, req_state, ACTION_OPENING);
3586 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
3588 if (game_status == GAME_MODE_PLAYING)
3590 SetPanelBackground();
3591 SetDrawBackgroundMask(REDRAW_DOOR_1);
3595 SetDrawBackgroundMask(REDRAW_FIELD);
3601 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3603 // ---------- handle request buttons ----------
3604 result = RequestHandleEvents(req_state);
3606 if (game_status != GAME_MODE_MAIN)
3611 ShowEnvelopeRequest(text, req_state, ACTION_CLOSING);
3615 if (game_status == GAME_MODE_PLAYING)
3617 SetPanelBackground();
3618 SetDrawBackgroundMask(REDRAW_DOOR_1);
3622 SetDrawBackgroundMask(REDRAW_FIELD);
3625 #if defined(NETWORK_AVALIABLE)
3626 /* continue network game after request */
3627 if (options.network &&
3628 game_status == GAME_MODE_PLAYING &&
3629 req_state & REQUEST_WAIT_FOR_INPUT)
3630 SendToServer_ContinuePlaying();
3633 /* restore deactivated drawing when quick-loading level tape recording */
3634 if (tape.playing && tape.deactivate_display)
3635 TapeDeactivateDisplayOn();
3640 boolean Request(char *text, unsigned int req_state)
3642 if (global.use_envelope_request)
3643 return RequestEnvelope(text, req_state);
3645 return RequestDoor(text, req_state);
3648 static int compareDoorPartOrderInfo(const void *object1, const void *object2)
3650 const struct DoorPartOrderInfo *dpo1 = (struct DoorPartOrderInfo *)object1;
3651 const struct DoorPartOrderInfo *dpo2 = (struct DoorPartOrderInfo *)object2;
3654 if (dpo1->sort_priority != dpo2->sort_priority)
3655 compare_result = dpo1->sort_priority - dpo2->sort_priority;
3657 compare_result = dpo1->nr - dpo2->nr;
3659 return compare_result;
3662 void InitGraphicCompatibilityInfo_Doors()
3668 struct DoorInfo *door;
3672 { DOOR_1, IMG_DOOR_1_GFX_PART_1, IMG_DOOR_1_GFX_PART_8, &door_1 },
3673 { DOOR_2, IMG_DOOR_2_GFX_PART_1, IMG_DOOR_2_GFX_PART_8, &door_2 },
3675 { -1, -1, -1, NULL }
3677 struct Rect door_rect_list[] =
3679 { DX, DY, DXSIZE, DYSIZE },
3680 { VX, VY, VXSIZE, VYSIZE }
3684 for (i = 0; doors[i].door_token != -1; i++)
3686 int door_token = doors[i].door_token;
3687 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
3688 int part_1 = doors[i].part_1;
3689 int part_8 = doors[i].part_8;
3690 int part_2 = part_1 + 1;
3691 int part_3 = part_1 + 2;
3692 struct DoorInfo *door = doors[i].door;
3693 struct Rect *door_rect = &door_rect_list[door_index];
3694 boolean door_gfx_redefined = FALSE;
3696 /* check if any door part graphic definitions have been redefined */
3698 for (j = 0; door_part_controls[j].door_token != -1; j++)
3700 struct DoorPartControlInfo *dpc = &door_part_controls[j];
3701 struct FileInfo *fi = getImageListEntryFromImageID(dpc->graphic);
3703 if (dpc->door_token == door_token && fi->redefined)
3704 door_gfx_redefined = TRUE;
3707 /* check for old-style door graphic/animation modifications */
3709 if (!door_gfx_redefined)
3711 if (door->anim_mode & ANIM_STATIC_PANEL)
3713 door->panel.step_xoffset = 0;
3714 door->panel.step_yoffset = 0;
3717 if (door->anim_mode & (ANIM_HORIZONTAL | ANIM_VERTICAL))
3719 struct GraphicInfo *g_part_1 = &graphic_info[part_1];
3720 struct GraphicInfo *g_part_2 = &graphic_info[part_2];
3721 int num_door_steps, num_panel_steps;
3723 /* remove door part graphics other than the two default wings */
3725 for (j = 0; door_part_controls[j].door_token != -1; j++)
3727 struct DoorPartControlInfo *dpc = &door_part_controls[j];
3728 struct GraphicInfo *g = &graphic_info[dpc->graphic];
3730 if (dpc->graphic >= part_3 &&
3731 dpc->graphic <= part_8)
3735 /* set graphics and screen positions of the default wings */
3737 g_part_1->width = door_rect->width;
3738 g_part_1->height = door_rect->height;
3739 g_part_2->width = door_rect->width;
3740 g_part_2->height = door_rect->height;
3741 g_part_2->src_x = door_rect->width;
3742 g_part_2->src_y = g_part_1->src_y;
3744 door->part_2.x = door->part_1.x;
3745 door->part_2.y = door->part_1.y;
3747 if (door->width != -1)
3749 g_part_1->width = door->width;
3750 g_part_2->width = door->width;
3752 // special treatment for graphics and screen position of right wing
3753 g_part_2->src_x += door_rect->width - door->width;
3754 door->part_2.x += door_rect->width - door->width;
3757 if (door->height != -1)
3759 g_part_1->height = door->height;
3760 g_part_2->height = door->height;
3762 // special treatment for graphics and screen position of bottom wing
3763 g_part_2->src_y += door_rect->height - door->height;
3764 door->part_2.y += door_rect->height - door->height;
3767 /* set animation delays for the default wings and panels */
3769 door->part_1.step_delay = door->step_delay;
3770 door->part_2.step_delay = door->step_delay;
3771 door->panel.step_delay = door->step_delay;
3773 /* set animation draw order for the default wings */
3775 door->part_1.sort_priority = 2; /* draw left wing over ... */
3776 door->part_2.sort_priority = 1; /* ... right wing */
3778 /* set animation draw offset for the default wings */
3780 if (door->anim_mode & ANIM_HORIZONTAL)
3782 door->part_1.step_xoffset = door->step_offset;
3783 door->part_1.step_yoffset = 0;
3784 door->part_2.step_xoffset = door->step_offset * -1;
3785 door->part_2.step_yoffset = 0;
3787 num_door_steps = g_part_1->width / door->step_offset;
3789 else // ANIM_VERTICAL
3791 door->part_1.step_xoffset = 0;
3792 door->part_1.step_yoffset = door->step_offset;
3793 door->part_2.step_xoffset = 0;
3794 door->part_2.step_yoffset = door->step_offset * -1;
3796 num_door_steps = g_part_1->height / door->step_offset;
3799 /* set animation draw offset for the default panels */
3801 if (door->step_offset > 1)
3803 num_panel_steps = 2 * door_rect->height / door->step_offset;
3804 door->panel.start_step = num_panel_steps - num_door_steps;
3805 door->panel.start_step_closing = door->panel.start_step;
3809 num_panel_steps = door_rect->height / door->step_offset;
3810 door->panel.start_step = num_panel_steps - num_door_steps / 2;
3811 door->panel.start_step_closing = door->panel.start_step;
3812 door->panel.step_delay *= 2;
3823 for (i = 0; door_part_controls[i].door_token != -1; i++)
3825 struct DoorPartControlInfo *dpc = &door_part_controls[i];
3826 struct DoorPartOrderInfo *dpo = &door_part_order[i];
3828 /* initialize "start_step_opening" and "start_step_closing", if needed */
3829 if (dpc->pos->start_step_opening == 0 &&
3830 dpc->pos->start_step_closing == 0)
3832 // dpc->pos->start_step_opening = dpc->pos->start_step;
3833 dpc->pos->start_step_closing = dpc->pos->start_step;
3836 /* fill structure for door part draw order (sorted below) */
3838 dpo->sort_priority = dpc->pos->sort_priority;
3841 /* sort door part controls according to sort_priority and graphic number */
3842 qsort(door_part_order, MAX_DOOR_PARTS,
3843 sizeof(struct DoorPartOrderInfo), compareDoorPartOrderInfo);
3846 unsigned int OpenDoor(unsigned int door_state)
3848 if (door_state & DOOR_COPY_BACK)
3850 if (door_state & DOOR_OPEN_1)
3851 BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
3852 1 * DXSIZE, 0, DXSIZE, DYSIZE, 0 * DXSIZE, 0);
3854 if (door_state & DOOR_OPEN_2)
3855 BlitBitmap(bitmap_db_door_2, bitmap_db_door_2,
3856 1 * VXSIZE, 0, VXSIZE, VYSIZE, 0 * VXSIZE, 0);
3858 door_state &= ~DOOR_COPY_BACK;
3861 return MoveDoor(door_state);
3864 unsigned int CloseDoor(unsigned int door_state)
3866 unsigned int old_door_state = GetDoorState();
3868 if (!(door_state & DOOR_NO_COPY_BACK))
3870 if (old_door_state & DOOR_OPEN_1)
3871 BlitBitmap(backbuffer, bitmap_db_door_1,
3872 DX, DY, DXSIZE, DYSIZE, 0, 0);
3874 if (old_door_state & DOOR_OPEN_2)
3875 BlitBitmap(backbuffer, bitmap_db_door_2,
3876 VX, VY, VXSIZE, VYSIZE, 0, 0);
3878 door_state &= ~DOOR_NO_COPY_BACK;
3881 return MoveDoor(door_state);
3884 unsigned int GetDoorState()
3886 return MoveDoor(DOOR_GET_STATE);
3889 unsigned int SetDoorState(unsigned int door_state)
3891 return MoveDoor(door_state | DOOR_SET_STATE);
3894 int euclid(int a, int b)
3896 return (b ? euclid(b, a % b) : a);
3899 unsigned int MoveDoor(unsigned int door_state)
3901 struct Rect door_rect_list[] =
3903 { DX, DY, DXSIZE, DYSIZE },
3904 { VX, VY, VXSIZE, VYSIZE }
3906 static int door1 = DOOR_OPEN_1;
3907 static int door2 = DOOR_CLOSE_2;
3908 unsigned int door_delay = 0;
3909 unsigned int door_delay_value;
3912 if (door_state == DOOR_GET_STATE)
3913 return (door1 | door2);
3915 if (door_state & DOOR_SET_STATE)
3917 if (door_state & DOOR_ACTION_1)
3918 door1 = door_state & DOOR_ACTION_1;
3919 if (door_state & DOOR_ACTION_2)
3920 door2 = door_state & DOOR_ACTION_2;
3922 return (door1 | door2);
3925 if (!(door_state & DOOR_FORCE_REDRAW))
3927 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
3928 door_state &= ~DOOR_OPEN_1;
3929 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
3930 door_state &= ~DOOR_CLOSE_1;
3931 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
3932 door_state &= ~DOOR_OPEN_2;
3933 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
3934 door_state &= ~DOOR_CLOSE_2;
3937 if (global.autoplay_leveldir)
3939 door_state |= DOOR_NO_DELAY;
3940 door_state &= ~DOOR_CLOSE_ALL;
3943 if (game_status == GAME_MODE_EDITOR)
3944 door_state |= DOOR_NO_DELAY;
3946 if (door_state & DOOR_ACTION)
3948 boolean door_panel_drawn[NUM_DOORS];
3949 boolean panel_has_doors[NUM_DOORS];
3950 boolean door_part_skip[MAX_DOOR_PARTS];
3951 boolean door_part_done[MAX_DOOR_PARTS];
3952 boolean door_part_done_all;
3953 int num_steps[MAX_DOOR_PARTS];
3954 int max_move_delay = 0; // delay for complete animations of all doors
3955 int max_step_delay = 0; // delay (ms) between two animation frames
3956 int num_move_steps = 0; // number of animation steps for all doors
3957 int max_move_delay_doors_only = 0; // delay for doors only (no panel)
3958 int num_move_steps_doors_only = 0; // steps for doors only (no panel)
3959 int current_move_delay = 0;
3963 for (i = 0; i < NUM_DOORS; i++)
3964 panel_has_doors[i] = FALSE;
3966 for (i = 0; i < MAX_DOOR_PARTS; i++)
3968 struct DoorPartControlInfo *dpc = &door_part_controls[i];
3969 struct GraphicInfo *g = &graphic_info[dpc->graphic];
3970 int door_token = dpc->door_token;
3972 door_part_done[i] = FALSE;
3973 door_part_skip[i] = (!(door_state & door_token) ||
3977 for (i = 0; i < MAX_DOOR_PARTS; i++)
3979 int nr = door_part_order[i].nr;
3980 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
3981 struct DoorPartPosInfo *pos = dpc->pos;
3982 struct GraphicInfo *g = &graphic_info[dpc->graphic];
3983 int door_token = dpc->door_token;
3984 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
3985 boolean is_panel = DOOR_PART_IS_PANEL(nr);
3986 int step_xoffset = ABS(pos->step_xoffset);
3987 int step_yoffset = ABS(pos->step_yoffset);
3988 int step_delay = pos->step_delay;
3989 int current_door_state = door_state & door_token;
3990 boolean door_opening = ((current_door_state & DOOR_OPEN) != 0);
3991 boolean door_closing = ((current_door_state & DOOR_CLOSE) != 0);
3992 boolean part_opening = (is_panel ? door_closing : door_opening);
3993 int start_step = (part_opening ? pos->start_step_opening :
3994 pos->start_step_closing);
3995 float move_xsize = (step_xoffset ? g->width : 0);
3996 float move_ysize = (step_yoffset ? g->height : 0);
3997 int move_xsteps = (step_xoffset ? ceil(move_xsize / step_xoffset) : 0);
3998 int move_ysteps = (step_yoffset ? ceil(move_ysize / step_yoffset) : 0);
3999 int move_steps = (move_xsteps && move_ysteps ?
4000 MIN(move_xsteps, move_ysteps) :
4001 move_xsteps ? move_xsteps : move_ysteps) - start_step;
4002 int move_delay = move_steps * step_delay;
4004 if (door_part_skip[nr])
4007 max_move_delay = MAX(max_move_delay, move_delay);
4008 max_step_delay = (max_step_delay == 0 ? step_delay :
4009 euclid(max_step_delay, step_delay));
4010 num_steps[nr] = move_steps;
4014 max_move_delay_doors_only = MAX(max_move_delay_doors_only, move_delay);
4016 panel_has_doors[door_index] = TRUE;
4020 max_step_delay = MAX(1, max_step_delay); // prevent division by zero
4022 num_move_steps = max_move_delay / max_step_delay;
4023 num_move_steps_doors_only = max_move_delay_doors_only / max_step_delay;
4025 door_delay_value = max_step_delay;
4027 if ((door_state & DOOR_NO_DELAY) || setup.quick_doors)
4029 start = num_move_steps - 1;
4033 /* opening door sound has priority over simultaneously closing door */
4034 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
4035 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
4036 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
4037 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
4040 for (k = start; k < num_move_steps; k++)
4042 int last_frame = num_move_steps - 1; // last frame of this "for" loop
4044 door_part_done_all = TRUE;
4046 for (i = 0; i < NUM_DOORS; i++)
4047 door_panel_drawn[i] = FALSE;
4049 for (i = 0; i < MAX_DOOR_PARTS; i++)
4051 int nr = door_part_order[i].nr;
4052 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
4053 struct DoorPartPosInfo *pos = dpc->pos;
4054 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4055 int door_token = dpc->door_token;
4056 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
4057 boolean is_panel = DOOR_PART_IS_PANEL(nr);
4058 boolean is_panel_and_door_has_closed = FALSE;
4059 struct Rect *door_rect = &door_rect_list[door_index];
4060 Bitmap *bitmap_db_door = (door_token == DOOR_1 ? bitmap_db_door_1 :
4062 Bitmap *bitmap = (is_panel ? bitmap_db_door : g->bitmap);
4063 int current_door_state = door_state & door_token;
4064 boolean door_opening = ((current_door_state & DOOR_OPEN) != 0);
4065 boolean door_closing = !door_opening;
4066 boolean part_opening = (is_panel ? door_closing : door_opening);
4067 boolean part_closing = !part_opening;
4068 int start_step = (part_opening ? pos->start_step_opening :
4069 pos->start_step_closing);
4070 int step_delay = pos->step_delay;
4071 int step_factor = step_delay / max_step_delay;
4072 int k1 = (step_factor ? k / step_factor + 1 : k);
4073 int k2 = (part_opening ? k1 + start_step : num_steps[nr] - k1);
4074 int kk = MAX(0, k2);
4077 int src_x, src_y, src_xx, src_yy;
4078 int dst_x, dst_y, dst_xx, dst_yy;
4081 if (door_part_skip[nr])
4084 if (!(door_state & door_token))
4092 int k2_door = (door_opening ? k : num_move_steps_doors_only - k - 1);
4093 int kk_door = MAX(0, k2_door);
4094 int sync_frame = kk_door * door_delay_value;
4095 int frame = getGraphicAnimationFrame(dpc->graphic, sync_frame);
4097 getGraphicSource(dpc->graphic, frame, &bitmap, &g_src_x, &g_src_y);
4102 if (!door_panel_drawn[door_index])
4104 ClearRectangle(drawto, door_rect->x, door_rect->y,
4105 door_rect->width, door_rect->height);
4107 door_panel_drawn[door_index] = TRUE;
4110 // draw opening or closing door parts
4112 if (pos->step_xoffset < 0) // door part on right side
4115 dst_xx = pos->x + ABS(kk * pos->step_xoffset);
4118 if (dst_xx + width > door_rect->width)
4119 width = door_rect->width - dst_xx;
4121 else // door part on left side
4124 dst_xx = pos->x - kk * pos->step_xoffset;
4128 src_xx = ABS(dst_xx);
4132 width = g->width - src_xx;
4134 // printf("::: k == %d [%d] \n", k, start_step);
4137 if (pos->step_yoffset < 0) // door part on bottom side
4140 dst_yy = pos->y + ABS(kk * pos->step_yoffset);
4143 if (dst_yy + height > door_rect->height)
4144 height = door_rect->height - dst_yy;
4146 else // door part on top side
4149 dst_yy = pos->y - kk * pos->step_yoffset;
4153 src_yy = ABS(dst_yy);
4157 height = g->height - src_yy;
4160 src_x = g_src_x + src_xx;
4161 src_y = g_src_y + src_yy;
4163 dst_x = door_rect->x + dst_xx;
4164 dst_y = door_rect->y + dst_yy;
4166 is_panel_and_door_has_closed =
4169 panel_has_doors[door_index] &&
4170 k >= num_move_steps_doors_only - 1);
4172 if (width >= 0 && width <= g->width &&
4173 height >= 0 && height <= g->height &&
4174 !is_panel_and_door_has_closed)
4176 if (is_panel || !pos->draw_masked)
4177 BlitBitmap(bitmap, drawto, src_x, src_y, width, height,
4180 BlitBitmapMasked(bitmap, drawto, src_x, src_y, width, height,
4184 redraw_mask |= REDRAW_DOOR_FROM_TOKEN(door_token);
4186 if ((part_opening && (width < 0 || height < 0)) ||
4187 (part_closing && (width >= g->width && height >= g->height)))
4188 door_part_done[nr] = TRUE;
4190 // continue door part animations, but not panel after door has closed
4191 if (!door_part_done[nr] && !is_panel_and_door_has_closed)
4192 door_part_done_all = FALSE;
4195 if (!(door_state & DOOR_NO_DELAY))
4199 if (game_status == GAME_MODE_MAIN)
4202 SkipUntilDelayReached(&door_delay, door_delay_value, &k, last_frame);
4204 current_move_delay += max_step_delay;
4207 if (door_part_done_all)
4212 if (door_state & DOOR_ACTION_1)
4213 door1 = door_state & DOOR_ACTION_1;
4214 if (door_state & DOOR_ACTION_2)
4215 door2 = door_state & DOOR_ACTION_2;
4217 return (door1 | door2);
4220 void DrawSpecialEditorDoor()
4222 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
4223 int top_border_width = gfx1->width;
4224 int top_border_height = gfx1->height;
4225 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
4226 int ex = EX - outer_border;
4227 int ey = EY - outer_border;
4228 int vy = VY - outer_border;
4229 int exsize = EXSIZE + 2 * outer_border;
4231 /* draw bigger level editor toolbox window */
4232 BlitBitmap(gfx1->bitmap, drawto, gfx1->src_x, gfx1->src_y,
4233 top_border_width, top_border_height, ex, ey - top_border_height);
4234 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto, ex, vy,
4235 exsize, EYSIZE - VYSIZE + outer_border, ex, ey);
4237 redraw_mask |= REDRAW_ALL;
4240 void UndrawSpecialEditorDoor()
4242 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
4243 int top_border_width = gfx1->width;
4244 int top_border_height = gfx1->height;
4245 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
4246 int ex = EX - outer_border;
4247 int ey = EY - outer_border;
4248 int ey_top = ey - top_border_height;
4249 int exsize = EXSIZE + 2 * outer_border;
4250 int eysize = EYSIZE + 2 * outer_border;
4252 /* draw normal tape recorder window */
4253 if (graphic_info[IMG_GLOBAL_BORDER].bitmap)
4255 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
4256 ex, ey_top, top_border_width, top_border_height,
4258 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
4259 ex, ey, exsize, eysize, ex, ey);
4263 // if screen background is set to "[NONE]", clear editor toolbox window
4264 ClearRectangle(drawto, ex, ey_top, top_border_width, top_border_height);
4265 ClearRectangle(drawto, ex, ey, exsize, eysize);
4268 redraw_mask |= REDRAW_ALL;
4272 /* ---------- new tool button stuff ---------------------------------------- */
4277 struct TextPosInfo *pos;
4280 } toolbutton_info[NUM_TOOL_BUTTONS] =
4283 IMG_REQUEST_BUTTON_GFX_YES, &request.button.yes,
4284 TOOL_CTRL_ID_YES, "yes"
4287 IMG_REQUEST_BUTTON_GFX_NO, &request.button.no,
4288 TOOL_CTRL_ID_NO, "no"
4291 IMG_REQUEST_BUTTON_GFX_CONFIRM, &request.button.confirm,
4292 TOOL_CTRL_ID_CONFIRM, "confirm"
4295 IMG_REQUEST_BUTTON_GFX_PLAYER_1, &request.button.player_1,
4296 TOOL_CTRL_ID_PLAYER_1, "player 1"
4299 IMG_REQUEST_BUTTON_GFX_PLAYER_2, &request.button.player_2,
4300 TOOL_CTRL_ID_PLAYER_2, "player 2"
4303 IMG_REQUEST_BUTTON_GFX_PLAYER_3, &request.button.player_3,
4304 TOOL_CTRL_ID_PLAYER_3, "player 3"
4307 IMG_REQUEST_BUTTON_GFX_PLAYER_4, &request.button.player_4,
4308 TOOL_CTRL_ID_PLAYER_4, "player 4"
4312 void CreateToolButtons()
4316 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4318 struct GraphicInfo *gfx = &graphic_info[toolbutton_info[i].graphic];
4319 struct TextPosInfo *pos = toolbutton_info[i].pos;
4320 struct GadgetInfo *gi;
4321 Bitmap *deco_bitmap = None;
4322 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
4323 unsigned int event_mask = GD_EVENT_RELEASED;
4326 int gd_x = gfx->src_x;
4327 int gd_y = gfx->src_y;
4328 int gd_xp = gfx->src_x + gfx->pressed_xoffset;
4329 int gd_yp = gfx->src_y + gfx->pressed_yoffset;
4332 if (global.use_envelope_request)
4333 setRequestPosition(&dx, &dy, TRUE);
4335 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
4337 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
4339 getSizedGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr), 0,
4340 pos->size, &deco_bitmap, &deco_x, &deco_y);
4341 deco_xpos = (gfx->width - pos->size) / 2;
4342 deco_ypos = (gfx->height - pos->size) / 2;
4345 gi = CreateGadget(GDI_CUSTOM_ID, id,
4346 GDI_INFO_TEXT, toolbutton_info[i].infotext,
4347 GDI_X, dx + GDI_ACTIVE_POS(pos->x),
4348 GDI_Y, dy + GDI_ACTIVE_POS(pos->y),
4349 GDI_WIDTH, gfx->width,
4350 GDI_HEIGHT, gfx->height,
4351 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
4352 GDI_STATE, GD_BUTTON_UNPRESSED,
4353 GDI_DESIGN_UNPRESSED, gfx->bitmap, gd_x, gd_y,
4354 GDI_DESIGN_PRESSED, gfx->bitmap, gd_xp, gd_yp,
4355 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
4356 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
4357 GDI_DECORATION_SIZE, pos->size, pos->size,
4358 GDI_DECORATION_SHIFTING, 1, 1,
4359 GDI_DIRECT_DRAW, FALSE,
4360 GDI_EVENT_MASK, event_mask,
4361 GDI_CALLBACK_ACTION, HandleToolButtons,
4365 Error(ERR_EXIT, "cannot create gadget");
4367 tool_gadget[id] = gi;
4371 void FreeToolButtons()
4375 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4376 FreeGadget(tool_gadget[i]);
4379 static void UnmapToolButtons()
4383 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4384 UnmapGadget(tool_gadget[i]);
4387 static void HandleToolButtons(struct GadgetInfo *gi)
4389 request_gadget_id = gi->custom_id;
4392 static struct Mapping_EM_to_RND_object
4395 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
4396 boolean is_backside; /* backside of moving element */
4402 em_object_mapping_list[] =
4405 Xblank, TRUE, FALSE,
4409 Yacid_splash_eB, FALSE, FALSE,
4410 EL_ACID_SPLASH_RIGHT, -1, -1
4413 Yacid_splash_wB, FALSE, FALSE,
4414 EL_ACID_SPLASH_LEFT, -1, -1
4417 #ifdef EM_ENGINE_BAD_ROLL
4419 Xstone_force_e, FALSE, FALSE,
4420 EL_ROCK, -1, MV_BIT_RIGHT
4423 Xstone_force_w, FALSE, FALSE,
4424 EL_ROCK, -1, MV_BIT_LEFT
4427 Xnut_force_e, FALSE, FALSE,
4428 EL_NUT, -1, MV_BIT_RIGHT
4431 Xnut_force_w, FALSE, FALSE,
4432 EL_NUT, -1, MV_BIT_LEFT
4435 Xspring_force_e, FALSE, FALSE,
4436 EL_SPRING, -1, MV_BIT_RIGHT
4439 Xspring_force_w, FALSE, FALSE,
4440 EL_SPRING, -1, MV_BIT_LEFT
4443 Xemerald_force_e, FALSE, FALSE,
4444 EL_EMERALD, -1, MV_BIT_RIGHT
4447 Xemerald_force_w, FALSE, FALSE,
4448 EL_EMERALD, -1, MV_BIT_LEFT
4451 Xdiamond_force_e, FALSE, FALSE,
4452 EL_DIAMOND, -1, MV_BIT_RIGHT
4455 Xdiamond_force_w, FALSE, FALSE,
4456 EL_DIAMOND, -1, MV_BIT_LEFT
4459 Xbomb_force_e, FALSE, FALSE,
4460 EL_BOMB, -1, MV_BIT_RIGHT
4463 Xbomb_force_w, FALSE, FALSE,
4464 EL_BOMB, -1, MV_BIT_LEFT
4466 #endif /* EM_ENGINE_BAD_ROLL */
4469 Xstone, TRUE, FALSE,
4473 Xstone_pause, FALSE, FALSE,
4477 Xstone_fall, FALSE, FALSE,
4481 Ystone_s, FALSE, FALSE,
4482 EL_ROCK, ACTION_FALLING, -1
4485 Ystone_sB, FALSE, TRUE,
4486 EL_ROCK, ACTION_FALLING, -1
4489 Ystone_e, FALSE, FALSE,
4490 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
4493 Ystone_eB, FALSE, TRUE,
4494 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
4497 Ystone_w, FALSE, FALSE,
4498 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
4501 Ystone_wB, FALSE, TRUE,
4502 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
4509 Xnut_pause, FALSE, FALSE,
4513 Xnut_fall, FALSE, FALSE,
4517 Ynut_s, FALSE, FALSE,
4518 EL_NUT, ACTION_FALLING, -1
4521 Ynut_sB, FALSE, TRUE,
4522 EL_NUT, ACTION_FALLING, -1
4525 Ynut_e, FALSE, FALSE,
4526 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
4529 Ynut_eB, FALSE, TRUE,
4530 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
4533 Ynut_w, FALSE, FALSE,
4534 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
4537 Ynut_wB, FALSE, TRUE,
4538 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
4541 Xbug_n, TRUE, FALSE,
4545 Xbug_e, TRUE, FALSE,
4546 EL_BUG_RIGHT, -1, -1
4549 Xbug_s, TRUE, FALSE,
4553 Xbug_w, TRUE, FALSE,
4557 Xbug_gon, FALSE, FALSE,
4561 Xbug_goe, FALSE, FALSE,
4562 EL_BUG_RIGHT, -1, -1
4565 Xbug_gos, FALSE, FALSE,
4569 Xbug_gow, FALSE, FALSE,
4573 Ybug_n, FALSE, FALSE,
4574 EL_BUG, ACTION_MOVING, MV_BIT_UP
4577 Ybug_nB, FALSE, TRUE,
4578 EL_BUG, ACTION_MOVING, MV_BIT_UP
4581 Ybug_e, FALSE, FALSE,
4582 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
4585 Ybug_eB, FALSE, TRUE,
4586 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
4589 Ybug_s, FALSE, FALSE,
4590 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
4593 Ybug_sB, FALSE, TRUE,
4594 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
4597 Ybug_w, FALSE, FALSE,
4598 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
4601 Ybug_wB, FALSE, TRUE,
4602 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
4605 Ybug_w_n, FALSE, FALSE,
4606 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
4609 Ybug_n_e, FALSE, FALSE,
4610 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
4613 Ybug_e_s, FALSE, FALSE,
4614 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
4617 Ybug_s_w, FALSE, FALSE,
4618 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
4621 Ybug_e_n, FALSE, FALSE,
4622 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
4625 Ybug_s_e, FALSE, FALSE,
4626 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
4629 Ybug_w_s, FALSE, FALSE,
4630 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
4633 Ybug_n_w, FALSE, FALSE,
4634 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
4637 Ybug_stone, FALSE, FALSE,
4638 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
4641 Ybug_spring, FALSE, FALSE,
4642 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
4645 Xtank_n, TRUE, FALSE,
4646 EL_SPACESHIP_UP, -1, -1
4649 Xtank_e, TRUE, FALSE,
4650 EL_SPACESHIP_RIGHT, -1, -1
4653 Xtank_s, TRUE, FALSE,
4654 EL_SPACESHIP_DOWN, -1, -1
4657 Xtank_w, TRUE, FALSE,
4658 EL_SPACESHIP_LEFT, -1, -1
4661 Xtank_gon, FALSE, FALSE,
4662 EL_SPACESHIP_UP, -1, -1
4665 Xtank_goe, FALSE, FALSE,
4666 EL_SPACESHIP_RIGHT, -1, -1
4669 Xtank_gos, FALSE, FALSE,
4670 EL_SPACESHIP_DOWN, -1, -1
4673 Xtank_gow, FALSE, FALSE,
4674 EL_SPACESHIP_LEFT, -1, -1
4677 Ytank_n, FALSE, FALSE,
4678 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
4681 Ytank_nB, FALSE, TRUE,
4682 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
4685 Ytank_e, FALSE, FALSE,
4686 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
4689 Ytank_eB, FALSE, TRUE,
4690 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
4693 Ytank_s, FALSE, FALSE,
4694 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
4697 Ytank_sB, FALSE, TRUE,
4698 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
4701 Ytank_w, FALSE, FALSE,
4702 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
4705 Ytank_wB, FALSE, TRUE,
4706 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
4709 Ytank_w_n, FALSE, FALSE,
4710 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
4713 Ytank_n_e, FALSE, FALSE,
4714 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
4717 Ytank_e_s, FALSE, FALSE,
4718 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
4721 Ytank_s_w, FALSE, FALSE,
4722 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
4725 Ytank_e_n, FALSE, FALSE,
4726 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
4729 Ytank_s_e, FALSE, FALSE,
4730 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
4733 Ytank_w_s, FALSE, FALSE,
4734 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
4737 Ytank_n_w, FALSE, FALSE,
4738 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
4741 Ytank_stone, FALSE, FALSE,
4742 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
4745 Ytank_spring, FALSE, FALSE,
4746 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
4749 Xandroid, TRUE, FALSE,
4750 EL_EMC_ANDROID, ACTION_ACTIVE, -1
4753 Xandroid_1_n, FALSE, FALSE,
4754 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
4757 Xandroid_2_n, FALSE, FALSE,
4758 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
4761 Xandroid_1_e, FALSE, FALSE,
4762 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
4765 Xandroid_2_e, FALSE, FALSE,
4766 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
4769 Xandroid_1_w, FALSE, FALSE,
4770 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
4773 Xandroid_2_w, FALSE, FALSE,
4774 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
4777 Xandroid_1_s, FALSE, FALSE,
4778 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
4781 Xandroid_2_s, FALSE, FALSE,
4782 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
4785 Yandroid_n, FALSE, FALSE,
4786 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
4789 Yandroid_nB, FALSE, TRUE,
4790 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
4793 Yandroid_ne, FALSE, FALSE,
4794 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
4797 Yandroid_neB, FALSE, TRUE,
4798 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
4801 Yandroid_e, FALSE, FALSE,
4802 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
4805 Yandroid_eB, FALSE, TRUE,
4806 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
4809 Yandroid_se, FALSE, FALSE,
4810 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
4813 Yandroid_seB, FALSE, TRUE,
4814 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
4817 Yandroid_s, FALSE, FALSE,
4818 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
4821 Yandroid_sB, FALSE, TRUE,
4822 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
4825 Yandroid_sw, FALSE, FALSE,
4826 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
4829 Yandroid_swB, FALSE, TRUE,
4830 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
4833 Yandroid_w, FALSE, FALSE,
4834 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
4837 Yandroid_wB, FALSE, TRUE,
4838 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
4841 Yandroid_nw, FALSE, FALSE,
4842 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
4845 Yandroid_nwB, FALSE, TRUE,
4846 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
4849 Xspring, TRUE, FALSE,
4853 Xspring_pause, FALSE, FALSE,
4857 Xspring_e, FALSE, FALSE,
4861 Xspring_w, FALSE, FALSE,
4865 Xspring_fall, FALSE, FALSE,
4869 Yspring_s, FALSE, FALSE,
4870 EL_SPRING, ACTION_FALLING, -1
4873 Yspring_sB, FALSE, TRUE,
4874 EL_SPRING, ACTION_FALLING, -1
4877 Yspring_e, FALSE, FALSE,
4878 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
4881 Yspring_eB, FALSE, TRUE,
4882 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
4885 Yspring_w, FALSE, FALSE,
4886 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
4889 Yspring_wB, FALSE, TRUE,
4890 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
4893 Yspring_kill_e, FALSE, FALSE,
4894 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
4897 Yspring_kill_eB, FALSE, TRUE,
4898 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
4901 Yspring_kill_w, FALSE, FALSE,
4902 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
4905 Yspring_kill_wB, FALSE, TRUE,
4906 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
4909 Xeater_n, TRUE, FALSE,
4910 EL_YAMYAM_UP, -1, -1
4913 Xeater_e, TRUE, FALSE,
4914 EL_YAMYAM_RIGHT, -1, -1
4917 Xeater_w, TRUE, FALSE,
4918 EL_YAMYAM_LEFT, -1, -1
4921 Xeater_s, TRUE, FALSE,
4922 EL_YAMYAM_DOWN, -1, -1
4925 Yeater_n, FALSE, FALSE,
4926 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
4929 Yeater_nB, FALSE, TRUE,
4930 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
4933 Yeater_e, FALSE, FALSE,
4934 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
4937 Yeater_eB, FALSE, TRUE,
4938 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
4941 Yeater_s, FALSE, FALSE,
4942 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
4945 Yeater_sB, FALSE, TRUE,
4946 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
4949 Yeater_w, FALSE, FALSE,
4950 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
4953 Yeater_wB, FALSE, TRUE,
4954 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
4957 Yeater_stone, FALSE, FALSE,
4958 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
4961 Yeater_spring, FALSE, FALSE,
4962 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
4965 Xalien, TRUE, FALSE,
4969 Xalien_pause, FALSE, FALSE,
4973 Yalien_n, FALSE, FALSE,
4974 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
4977 Yalien_nB, FALSE, TRUE,
4978 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
4981 Yalien_e, FALSE, FALSE,
4982 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
4985 Yalien_eB, FALSE, TRUE,
4986 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
4989 Yalien_s, FALSE, FALSE,
4990 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
4993 Yalien_sB, FALSE, TRUE,
4994 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
4997 Yalien_w, FALSE, FALSE,
4998 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
5001 Yalien_wB, FALSE, TRUE,
5002 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
5005 Yalien_stone, FALSE, FALSE,
5006 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
5009 Yalien_spring, FALSE, FALSE,
5010 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
5013 Xemerald, TRUE, FALSE,
5017 Xemerald_pause, FALSE, FALSE,
5021 Xemerald_fall, FALSE, FALSE,
5025 Xemerald_shine, FALSE, FALSE,
5026 EL_EMERALD, ACTION_TWINKLING, -1
5029 Yemerald_s, FALSE, FALSE,
5030 EL_EMERALD, ACTION_FALLING, -1
5033 Yemerald_sB, FALSE, TRUE,
5034 EL_EMERALD, ACTION_FALLING, -1
5037 Yemerald_e, FALSE, FALSE,
5038 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
5041 Yemerald_eB, FALSE, TRUE,
5042 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
5045 Yemerald_w, FALSE, FALSE,
5046 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
5049 Yemerald_wB, FALSE, TRUE,
5050 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
5053 Yemerald_eat, FALSE, FALSE,
5054 EL_EMERALD, ACTION_COLLECTING, -1
5057 Yemerald_stone, FALSE, FALSE,
5058 EL_NUT, ACTION_BREAKING, -1
5061 Xdiamond, TRUE, FALSE,
5065 Xdiamond_pause, FALSE, FALSE,
5069 Xdiamond_fall, FALSE, FALSE,
5073 Xdiamond_shine, FALSE, FALSE,
5074 EL_DIAMOND, ACTION_TWINKLING, -1
5077 Ydiamond_s, FALSE, FALSE,
5078 EL_DIAMOND, ACTION_FALLING, -1
5081 Ydiamond_sB, FALSE, TRUE,
5082 EL_DIAMOND, ACTION_FALLING, -1
5085 Ydiamond_e, FALSE, FALSE,
5086 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
5089 Ydiamond_eB, FALSE, TRUE,
5090 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
5093 Ydiamond_w, FALSE, FALSE,
5094 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
5097 Ydiamond_wB, FALSE, TRUE,
5098 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
5101 Ydiamond_eat, FALSE, FALSE,
5102 EL_DIAMOND, ACTION_COLLECTING, -1
5105 Ydiamond_stone, FALSE, FALSE,
5106 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
5109 Xdrip_fall, TRUE, FALSE,
5110 EL_AMOEBA_DROP, -1, -1
5113 Xdrip_stretch, FALSE, FALSE,
5114 EL_AMOEBA_DROP, ACTION_FALLING, -1
5117 Xdrip_stretchB, FALSE, TRUE,
5118 EL_AMOEBA_DROP, ACTION_FALLING, -1
5121 Xdrip_eat, FALSE, FALSE,
5122 EL_AMOEBA_DROP, ACTION_GROWING, -1
5125 Ydrip_s1, FALSE, FALSE,
5126 EL_AMOEBA_DROP, ACTION_FALLING, -1
5129 Ydrip_s1B, FALSE, TRUE,
5130 EL_AMOEBA_DROP, ACTION_FALLING, -1
5133 Ydrip_s2, FALSE, FALSE,
5134 EL_AMOEBA_DROP, ACTION_FALLING, -1
5137 Ydrip_s2B, FALSE, TRUE,
5138 EL_AMOEBA_DROP, ACTION_FALLING, -1
5145 Xbomb_pause, FALSE, FALSE,
5149 Xbomb_fall, FALSE, FALSE,
5153 Ybomb_s, FALSE, FALSE,
5154 EL_BOMB, ACTION_FALLING, -1
5157 Ybomb_sB, FALSE, TRUE,
5158 EL_BOMB, ACTION_FALLING, -1
5161 Ybomb_e, FALSE, FALSE,
5162 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
5165 Ybomb_eB, FALSE, TRUE,
5166 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
5169 Ybomb_w, FALSE, FALSE,
5170 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
5173 Ybomb_wB, FALSE, TRUE,
5174 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
5177 Ybomb_eat, FALSE, FALSE,
5178 EL_BOMB, ACTION_ACTIVATING, -1
5181 Xballoon, TRUE, FALSE,
5185 Yballoon_n, FALSE, FALSE,
5186 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
5189 Yballoon_nB, FALSE, TRUE,
5190 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
5193 Yballoon_e, FALSE, FALSE,
5194 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
5197 Yballoon_eB, FALSE, TRUE,
5198 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
5201 Yballoon_s, FALSE, FALSE,
5202 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
5205 Yballoon_sB, FALSE, TRUE,
5206 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
5209 Yballoon_w, FALSE, FALSE,
5210 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
5213 Yballoon_wB, FALSE, TRUE,
5214 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
5217 Xgrass, TRUE, FALSE,
5218 EL_EMC_GRASS, -1, -1
5221 Ygrass_nB, FALSE, FALSE,
5222 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
5225 Ygrass_eB, FALSE, FALSE,
5226 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
5229 Ygrass_sB, FALSE, FALSE,
5230 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
5233 Ygrass_wB, FALSE, FALSE,
5234 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
5241 Ydirt_nB, FALSE, FALSE,
5242 EL_SAND, ACTION_DIGGING, MV_BIT_UP
5245 Ydirt_eB, FALSE, FALSE,
5246 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
5249 Ydirt_sB, FALSE, FALSE,
5250 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
5253 Ydirt_wB, FALSE, FALSE,
5254 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
5257 Xacid_ne, TRUE, FALSE,
5258 EL_ACID_POOL_TOPRIGHT, -1, -1
5261 Xacid_se, TRUE, FALSE,
5262 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
5265 Xacid_s, TRUE, FALSE,
5266 EL_ACID_POOL_BOTTOM, -1, -1
5269 Xacid_sw, TRUE, FALSE,
5270 EL_ACID_POOL_BOTTOMLEFT, -1, -1
5273 Xacid_nw, TRUE, FALSE,
5274 EL_ACID_POOL_TOPLEFT, -1, -1
5277 Xacid_1, TRUE, FALSE,
5281 Xacid_2, FALSE, FALSE,
5285 Xacid_3, FALSE, FALSE,
5289 Xacid_4, FALSE, FALSE,
5293 Xacid_5, FALSE, FALSE,
5297 Xacid_6, FALSE, FALSE,
5301 Xacid_7, FALSE, FALSE,
5305 Xacid_8, FALSE, FALSE,
5309 Xball_1, TRUE, FALSE,
5310 EL_EMC_MAGIC_BALL, -1, -1
5313 Xball_1B, FALSE, FALSE,
5314 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5317 Xball_2, FALSE, FALSE,
5318 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5321 Xball_2B, FALSE, FALSE,
5322 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5325 Yball_eat, FALSE, FALSE,
5326 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
5329 Ykey_1_eat, FALSE, FALSE,
5330 EL_EM_KEY_1, ACTION_COLLECTING, -1
5333 Ykey_2_eat, FALSE, FALSE,
5334 EL_EM_KEY_2, ACTION_COLLECTING, -1
5337 Ykey_3_eat, FALSE, FALSE,
5338 EL_EM_KEY_3, ACTION_COLLECTING, -1
5341 Ykey_4_eat, FALSE, FALSE,
5342 EL_EM_KEY_4, ACTION_COLLECTING, -1
5345 Ykey_5_eat, FALSE, FALSE,
5346 EL_EMC_KEY_5, ACTION_COLLECTING, -1
5349 Ykey_6_eat, FALSE, FALSE,
5350 EL_EMC_KEY_6, ACTION_COLLECTING, -1
5353 Ykey_7_eat, FALSE, FALSE,
5354 EL_EMC_KEY_7, ACTION_COLLECTING, -1
5357 Ykey_8_eat, FALSE, FALSE,
5358 EL_EMC_KEY_8, ACTION_COLLECTING, -1
5361 Ylenses_eat, FALSE, FALSE,
5362 EL_EMC_LENSES, ACTION_COLLECTING, -1
5365 Ymagnify_eat, FALSE, FALSE,
5366 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
5369 Ygrass_eat, FALSE, FALSE,
5370 EL_EMC_GRASS, ACTION_SNAPPING, -1
5373 Ydirt_eat, FALSE, FALSE,
5374 EL_SAND, ACTION_SNAPPING, -1
5377 Xgrow_ns, TRUE, FALSE,
5378 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
5381 Ygrow_ns_eat, FALSE, FALSE,
5382 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
5385 Xgrow_ew, TRUE, FALSE,
5386 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
5389 Ygrow_ew_eat, FALSE, FALSE,
5390 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
5393 Xwonderwall, TRUE, FALSE,
5394 EL_MAGIC_WALL, -1, -1
5397 XwonderwallB, FALSE, FALSE,
5398 EL_MAGIC_WALL, ACTION_ACTIVE, -1
5401 Xamoeba_1, TRUE, FALSE,
5402 EL_AMOEBA_DRY, ACTION_OTHER, -1
5405 Xamoeba_2, FALSE, FALSE,
5406 EL_AMOEBA_DRY, ACTION_OTHER, -1
5409 Xamoeba_3, FALSE, FALSE,
5410 EL_AMOEBA_DRY, ACTION_OTHER, -1
5413 Xamoeba_4, FALSE, FALSE,
5414 EL_AMOEBA_DRY, ACTION_OTHER, -1
5417 Xamoeba_5, TRUE, FALSE,
5418 EL_AMOEBA_WET, ACTION_OTHER, -1
5421 Xamoeba_6, FALSE, FALSE,
5422 EL_AMOEBA_WET, ACTION_OTHER, -1
5425 Xamoeba_7, FALSE, FALSE,
5426 EL_AMOEBA_WET, ACTION_OTHER, -1
5429 Xamoeba_8, FALSE, FALSE,
5430 EL_AMOEBA_WET, ACTION_OTHER, -1
5433 Xdoor_1, TRUE, FALSE,
5434 EL_EM_GATE_1, -1, -1
5437 Xdoor_2, TRUE, FALSE,
5438 EL_EM_GATE_2, -1, -1
5441 Xdoor_3, TRUE, FALSE,
5442 EL_EM_GATE_3, -1, -1
5445 Xdoor_4, TRUE, FALSE,
5446 EL_EM_GATE_4, -1, -1
5449 Xdoor_5, TRUE, FALSE,
5450 EL_EMC_GATE_5, -1, -1
5453 Xdoor_6, TRUE, FALSE,
5454 EL_EMC_GATE_6, -1, -1
5457 Xdoor_7, TRUE, FALSE,
5458 EL_EMC_GATE_7, -1, -1
5461 Xdoor_8, TRUE, FALSE,
5462 EL_EMC_GATE_8, -1, -1
5465 Xkey_1, TRUE, FALSE,
5469 Xkey_2, TRUE, FALSE,
5473 Xkey_3, TRUE, FALSE,
5477 Xkey_4, TRUE, FALSE,
5481 Xkey_5, TRUE, FALSE,
5482 EL_EMC_KEY_5, -1, -1
5485 Xkey_6, TRUE, FALSE,
5486 EL_EMC_KEY_6, -1, -1
5489 Xkey_7, TRUE, FALSE,
5490 EL_EMC_KEY_7, -1, -1
5493 Xkey_8, TRUE, FALSE,
5494 EL_EMC_KEY_8, -1, -1
5497 Xwind_n, TRUE, FALSE,
5498 EL_BALLOON_SWITCH_UP, -1, -1
5501 Xwind_e, TRUE, FALSE,
5502 EL_BALLOON_SWITCH_RIGHT, -1, -1
5505 Xwind_s, TRUE, FALSE,
5506 EL_BALLOON_SWITCH_DOWN, -1, -1
5509 Xwind_w, TRUE, FALSE,
5510 EL_BALLOON_SWITCH_LEFT, -1, -1
5513 Xwind_nesw, TRUE, FALSE,
5514 EL_BALLOON_SWITCH_ANY, -1, -1
5517 Xwind_stop, TRUE, FALSE,
5518 EL_BALLOON_SWITCH_NONE, -1, -1
5522 EL_EM_EXIT_CLOSED, -1, -1
5525 Xexit_1, TRUE, FALSE,
5526 EL_EM_EXIT_OPEN, -1, -1
5529 Xexit_2, FALSE, FALSE,
5530 EL_EM_EXIT_OPEN, -1, -1
5533 Xexit_3, FALSE, FALSE,
5534 EL_EM_EXIT_OPEN, -1, -1
5537 Xdynamite, TRUE, FALSE,
5538 EL_EM_DYNAMITE, -1, -1
5541 Ydynamite_eat, FALSE, FALSE,
5542 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
5545 Xdynamite_1, TRUE, FALSE,
5546 EL_EM_DYNAMITE_ACTIVE, -1, -1
5549 Xdynamite_2, FALSE, FALSE,
5550 EL_EM_DYNAMITE_ACTIVE, -1, -1
5553 Xdynamite_3, FALSE, FALSE,
5554 EL_EM_DYNAMITE_ACTIVE, -1, -1
5557 Xdynamite_4, FALSE, FALSE,
5558 EL_EM_DYNAMITE_ACTIVE, -1, -1
5561 Xbumper, TRUE, FALSE,
5562 EL_EMC_SPRING_BUMPER, -1, -1
5565 XbumperB, FALSE, FALSE,
5566 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
5569 Xwheel, TRUE, FALSE,
5570 EL_ROBOT_WHEEL, -1, -1
5573 XwheelB, FALSE, FALSE,
5574 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
5577 Xswitch, TRUE, FALSE,
5578 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
5581 XswitchB, FALSE, FALSE,
5582 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
5586 EL_QUICKSAND_EMPTY, -1, -1
5589 Xsand_stone, TRUE, FALSE,
5590 EL_QUICKSAND_FULL, -1, -1
5593 Xsand_stonein_1, FALSE, TRUE,
5594 EL_ROCK, ACTION_FILLING, -1
5597 Xsand_stonein_2, FALSE, TRUE,
5598 EL_ROCK, ACTION_FILLING, -1
5601 Xsand_stonein_3, FALSE, TRUE,
5602 EL_ROCK, ACTION_FILLING, -1
5605 Xsand_stonein_4, FALSE, TRUE,
5606 EL_ROCK, ACTION_FILLING, -1
5609 Xsand_stonesand_1, FALSE, FALSE,
5610 EL_QUICKSAND_EMPTYING, -1, -1
5613 Xsand_stonesand_2, FALSE, FALSE,
5614 EL_QUICKSAND_EMPTYING, -1, -1
5617 Xsand_stonesand_3, FALSE, FALSE,
5618 EL_QUICKSAND_EMPTYING, -1, -1
5621 Xsand_stonesand_4, FALSE, FALSE,
5622 EL_QUICKSAND_EMPTYING, -1, -1
5625 Xsand_stonesand_quickout_1, FALSE, FALSE,
5626 EL_QUICKSAND_EMPTYING, -1, -1
5629 Xsand_stonesand_quickout_2, FALSE, FALSE,
5630 EL_QUICKSAND_EMPTYING, -1, -1
5633 Xsand_stoneout_1, FALSE, FALSE,
5634 EL_ROCK, ACTION_EMPTYING, -1
5637 Xsand_stoneout_2, FALSE, FALSE,
5638 EL_ROCK, ACTION_EMPTYING, -1
5641 Xsand_sandstone_1, FALSE, FALSE,
5642 EL_QUICKSAND_FILLING, -1, -1
5645 Xsand_sandstone_2, FALSE, FALSE,
5646 EL_QUICKSAND_FILLING, -1, -1
5649 Xsand_sandstone_3, FALSE, FALSE,
5650 EL_QUICKSAND_FILLING, -1, -1
5653 Xsand_sandstone_4, FALSE, FALSE,
5654 EL_QUICKSAND_FILLING, -1, -1
5657 Xplant, TRUE, FALSE,
5658 EL_EMC_PLANT, -1, -1
5661 Yplant, FALSE, FALSE,
5662 EL_EMC_PLANT, -1, -1
5665 Xlenses, TRUE, FALSE,
5666 EL_EMC_LENSES, -1, -1
5669 Xmagnify, TRUE, FALSE,
5670 EL_EMC_MAGNIFIER, -1, -1
5673 Xdripper, TRUE, FALSE,
5674 EL_EMC_DRIPPER, -1, -1
5677 XdripperB, FALSE, FALSE,
5678 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
5681 Xfake_blank, TRUE, FALSE,
5682 EL_INVISIBLE_WALL, -1, -1
5685 Xfake_blankB, FALSE, FALSE,
5686 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
5689 Xfake_grass, TRUE, FALSE,
5690 EL_EMC_FAKE_GRASS, -1, -1
5693 Xfake_grassB, FALSE, FALSE,
5694 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
5697 Xfake_door_1, TRUE, FALSE,
5698 EL_EM_GATE_1_GRAY, -1, -1
5701 Xfake_door_2, TRUE, FALSE,
5702 EL_EM_GATE_2_GRAY, -1, -1
5705 Xfake_door_3, TRUE, FALSE,
5706 EL_EM_GATE_3_GRAY, -1, -1
5709 Xfake_door_4, TRUE, FALSE,
5710 EL_EM_GATE_4_GRAY, -1, -1
5713 Xfake_door_5, TRUE, FALSE,
5714 EL_EMC_GATE_5_GRAY, -1, -1
5717 Xfake_door_6, TRUE, FALSE,
5718 EL_EMC_GATE_6_GRAY, -1, -1
5721 Xfake_door_7, TRUE, FALSE,
5722 EL_EMC_GATE_7_GRAY, -1, -1
5725 Xfake_door_8, TRUE, FALSE,
5726 EL_EMC_GATE_8_GRAY, -1, -1
5729 Xfake_acid_1, TRUE, FALSE,
5730 EL_EMC_FAKE_ACID, -1, -1
5733 Xfake_acid_2, FALSE, FALSE,
5734 EL_EMC_FAKE_ACID, -1, -1
5737 Xfake_acid_3, FALSE, FALSE,
5738 EL_EMC_FAKE_ACID, -1, -1
5741 Xfake_acid_4, FALSE, FALSE,
5742 EL_EMC_FAKE_ACID, -1, -1
5745 Xfake_acid_5, FALSE, FALSE,
5746 EL_EMC_FAKE_ACID, -1, -1
5749 Xfake_acid_6, FALSE, FALSE,
5750 EL_EMC_FAKE_ACID, -1, -1
5753 Xfake_acid_7, FALSE, FALSE,
5754 EL_EMC_FAKE_ACID, -1, -1
5757 Xfake_acid_8, FALSE, FALSE,
5758 EL_EMC_FAKE_ACID, -1, -1
5761 Xsteel_1, TRUE, FALSE,
5762 EL_STEELWALL, -1, -1
5765 Xsteel_2, TRUE, FALSE,
5766 EL_EMC_STEELWALL_2, -1, -1
5769 Xsteel_3, TRUE, FALSE,
5770 EL_EMC_STEELWALL_3, -1, -1
5773 Xsteel_4, TRUE, FALSE,
5774 EL_EMC_STEELWALL_4, -1, -1
5777 Xwall_1, TRUE, FALSE,
5781 Xwall_2, TRUE, FALSE,
5782 EL_EMC_WALL_14, -1, -1
5785 Xwall_3, TRUE, FALSE,
5786 EL_EMC_WALL_15, -1, -1
5789 Xwall_4, TRUE, FALSE,
5790 EL_EMC_WALL_16, -1, -1
5793 Xround_wall_1, TRUE, FALSE,
5794 EL_WALL_SLIPPERY, -1, -1
5797 Xround_wall_2, TRUE, FALSE,
5798 EL_EMC_WALL_SLIPPERY_2, -1, -1
5801 Xround_wall_3, TRUE, FALSE,
5802 EL_EMC_WALL_SLIPPERY_3, -1, -1
5805 Xround_wall_4, TRUE, FALSE,
5806 EL_EMC_WALL_SLIPPERY_4, -1, -1
5809 Xdecor_1, TRUE, FALSE,
5810 EL_EMC_WALL_8, -1, -1
5813 Xdecor_2, TRUE, FALSE,
5814 EL_EMC_WALL_6, -1, -1
5817 Xdecor_3, TRUE, FALSE,
5818 EL_EMC_WALL_4, -1, -1
5821 Xdecor_4, TRUE, FALSE,
5822 EL_EMC_WALL_7, -1, -1
5825 Xdecor_5, TRUE, FALSE,
5826 EL_EMC_WALL_5, -1, -1
5829 Xdecor_6, TRUE, FALSE,
5830 EL_EMC_WALL_9, -1, -1
5833 Xdecor_7, TRUE, FALSE,
5834 EL_EMC_WALL_10, -1, -1
5837 Xdecor_8, TRUE, FALSE,
5838 EL_EMC_WALL_1, -1, -1
5841 Xdecor_9, TRUE, FALSE,
5842 EL_EMC_WALL_2, -1, -1
5845 Xdecor_10, TRUE, FALSE,
5846 EL_EMC_WALL_3, -1, -1
5849 Xdecor_11, TRUE, FALSE,
5850 EL_EMC_WALL_11, -1, -1
5853 Xdecor_12, TRUE, FALSE,
5854 EL_EMC_WALL_12, -1, -1
5857 Xalpha_0, TRUE, FALSE,
5858 EL_CHAR('0'), -1, -1
5861 Xalpha_1, TRUE, FALSE,
5862 EL_CHAR('1'), -1, -1
5865 Xalpha_2, TRUE, FALSE,
5866 EL_CHAR('2'), -1, -1
5869 Xalpha_3, TRUE, FALSE,
5870 EL_CHAR('3'), -1, -1
5873 Xalpha_4, TRUE, FALSE,
5874 EL_CHAR('4'), -1, -1
5877 Xalpha_5, TRUE, FALSE,
5878 EL_CHAR('5'), -1, -1
5881 Xalpha_6, TRUE, FALSE,
5882 EL_CHAR('6'), -1, -1
5885 Xalpha_7, TRUE, FALSE,
5886 EL_CHAR('7'), -1, -1
5889 Xalpha_8, TRUE, FALSE,
5890 EL_CHAR('8'), -1, -1
5893 Xalpha_9, TRUE, FALSE,
5894 EL_CHAR('9'), -1, -1
5897 Xalpha_excla, TRUE, FALSE,
5898 EL_CHAR('!'), -1, -1
5901 Xalpha_quote, TRUE, FALSE,
5902 EL_CHAR('"'), -1, -1
5905 Xalpha_comma, TRUE, FALSE,
5906 EL_CHAR(','), -1, -1
5909 Xalpha_minus, TRUE, FALSE,
5910 EL_CHAR('-'), -1, -1
5913 Xalpha_perio, TRUE, FALSE,
5914 EL_CHAR('.'), -1, -1
5917 Xalpha_colon, TRUE, FALSE,
5918 EL_CHAR(':'), -1, -1
5921 Xalpha_quest, TRUE, FALSE,
5922 EL_CHAR('?'), -1, -1
5925 Xalpha_a, TRUE, FALSE,
5926 EL_CHAR('A'), -1, -1
5929 Xalpha_b, TRUE, FALSE,
5930 EL_CHAR('B'), -1, -1
5933 Xalpha_c, TRUE, FALSE,
5934 EL_CHAR('C'), -1, -1
5937 Xalpha_d, TRUE, FALSE,
5938 EL_CHAR('D'), -1, -1
5941 Xalpha_e, TRUE, FALSE,
5942 EL_CHAR('E'), -1, -1
5945 Xalpha_f, TRUE, FALSE,
5946 EL_CHAR('F'), -1, -1
5949 Xalpha_g, TRUE, FALSE,
5950 EL_CHAR('G'), -1, -1
5953 Xalpha_h, TRUE, FALSE,
5954 EL_CHAR('H'), -1, -1
5957 Xalpha_i, TRUE, FALSE,
5958 EL_CHAR('I'), -1, -1
5961 Xalpha_j, TRUE, FALSE,
5962 EL_CHAR('J'), -1, -1
5965 Xalpha_k, TRUE, FALSE,
5966 EL_CHAR('K'), -1, -1
5969 Xalpha_l, TRUE, FALSE,
5970 EL_CHAR('L'), -1, -1
5973 Xalpha_m, TRUE, FALSE,
5974 EL_CHAR('M'), -1, -1
5977 Xalpha_n, TRUE, FALSE,
5978 EL_CHAR('N'), -1, -1
5981 Xalpha_o, TRUE, FALSE,
5982 EL_CHAR('O'), -1, -1
5985 Xalpha_p, TRUE, FALSE,
5986 EL_CHAR('P'), -1, -1
5989 Xalpha_q, TRUE, FALSE,
5990 EL_CHAR('Q'), -1, -1
5993 Xalpha_r, TRUE, FALSE,
5994 EL_CHAR('R'), -1, -1
5997 Xalpha_s, TRUE, FALSE,
5998 EL_CHAR('S'), -1, -1
6001 Xalpha_t, TRUE, FALSE,
6002 EL_CHAR('T'), -1, -1
6005 Xalpha_u, TRUE, FALSE,
6006 EL_CHAR('U'), -1, -1
6009 Xalpha_v, TRUE, FALSE,
6010 EL_CHAR('V'), -1, -1
6013 Xalpha_w, TRUE, FALSE,
6014 EL_CHAR('W'), -1, -1
6017 Xalpha_x, TRUE, FALSE,
6018 EL_CHAR('X'), -1, -1
6021 Xalpha_y, TRUE, FALSE,
6022 EL_CHAR('Y'), -1, -1
6025 Xalpha_z, TRUE, FALSE,
6026 EL_CHAR('Z'), -1, -1
6029 Xalpha_arrow_e, TRUE, FALSE,
6030 EL_CHAR('>'), -1, -1
6033 Xalpha_arrow_w, TRUE, FALSE,
6034 EL_CHAR('<'), -1, -1
6037 Xalpha_copyr, TRUE, FALSE,
6038 EL_CHAR(CHAR_BYTE_COPYRIGHT), -1, -1
6042 Xboom_bug, FALSE, FALSE,
6043 EL_BUG, ACTION_EXPLODING, -1
6046 Xboom_bomb, FALSE, FALSE,
6047 EL_BOMB, ACTION_EXPLODING, -1
6050 Xboom_android, FALSE, FALSE,
6051 EL_EMC_ANDROID, ACTION_OTHER, -1
6054 Xboom_1, FALSE, FALSE,
6055 EL_DEFAULT, ACTION_EXPLODING, -1
6058 Xboom_2, FALSE, FALSE,
6059 EL_DEFAULT, ACTION_EXPLODING, -1
6062 Znormal, FALSE, FALSE,
6066 Zdynamite, FALSE, FALSE,
6070 Zplayer, FALSE, FALSE,
6074 ZBORDER, FALSE, FALSE,
6084 static struct Mapping_EM_to_RND_player
6093 em_player_mapping_list[] =
6097 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
6101 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
6105 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
6109 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
6113 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
6117 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
6121 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
6125 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
6129 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
6133 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
6137 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
6141 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
6145 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
6149 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
6153 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
6157 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
6161 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
6165 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
6169 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
6173 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
6177 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
6181 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
6185 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
6189 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
6193 EL_PLAYER_1, ACTION_DEFAULT, -1,
6197 EL_PLAYER_2, ACTION_DEFAULT, -1,
6201 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
6205 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
6209 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
6213 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
6217 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
6221 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
6225 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
6229 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
6233 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
6237 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
6241 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
6245 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
6249 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
6253 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
6257 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
6261 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
6265 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
6269 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
6273 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
6277 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
6281 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
6285 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
6289 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
6293 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
6297 EL_PLAYER_3, ACTION_DEFAULT, -1,
6301 EL_PLAYER_4, ACTION_DEFAULT, -1,
6310 int map_element_RND_to_EM(int element_rnd)
6312 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
6313 static boolean mapping_initialized = FALSE;
6315 if (!mapping_initialized)
6319 /* return "Xalpha_quest" for all undefined elements in mapping array */
6320 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
6321 mapping_RND_to_EM[i] = Xalpha_quest;
6323 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6324 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
6325 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
6326 em_object_mapping_list[i].element_em;
6328 mapping_initialized = TRUE;
6331 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
6332 return mapping_RND_to_EM[element_rnd];
6334 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
6339 int map_element_EM_to_RND(int element_em)
6341 static unsigned short mapping_EM_to_RND[TILE_MAX];
6342 static boolean mapping_initialized = FALSE;
6344 if (!mapping_initialized)
6348 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
6349 for (i = 0; i < TILE_MAX; i++)
6350 mapping_EM_to_RND[i] = EL_UNKNOWN;
6352 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6353 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
6354 em_object_mapping_list[i].element_rnd;
6356 mapping_initialized = TRUE;
6359 if (element_em >= 0 && element_em < TILE_MAX)
6360 return mapping_EM_to_RND[element_em];
6362 Error(ERR_WARN, "invalid EM level element %d", element_em);
6367 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
6369 struct LevelInfo_EM *level_em = level->native_em_level;
6370 struct LEVEL *lev = level_em->lev;
6373 for (i = 0; i < TILE_MAX; i++)
6374 lev->android_array[i] = Xblank;
6376 for (i = 0; i < level->num_android_clone_elements; i++)
6378 int element_rnd = level->android_clone_element[i];
6379 int element_em = map_element_RND_to_EM(element_rnd);
6381 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
6382 if (em_object_mapping_list[j].element_rnd == element_rnd)
6383 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
6387 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
6389 struct LevelInfo_EM *level_em = level->native_em_level;
6390 struct LEVEL *lev = level_em->lev;
6393 level->num_android_clone_elements = 0;
6395 for (i = 0; i < TILE_MAX; i++)
6397 int element_em = lev->android_array[i];
6399 boolean element_found = FALSE;
6401 if (element_em == Xblank)
6404 element_rnd = map_element_EM_to_RND(element_em);
6406 for (j = 0; j < level->num_android_clone_elements; j++)
6407 if (level->android_clone_element[j] == element_rnd)
6408 element_found = TRUE;
6412 level->android_clone_element[level->num_android_clone_elements++] =
6415 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
6420 if (level->num_android_clone_elements == 0)
6422 level->num_android_clone_elements = 1;
6423 level->android_clone_element[0] = EL_EMPTY;
6427 int map_direction_RND_to_EM(int direction)
6429 return (direction == MV_UP ? 0 :
6430 direction == MV_RIGHT ? 1 :
6431 direction == MV_DOWN ? 2 :
6432 direction == MV_LEFT ? 3 :
6436 int map_direction_EM_to_RND(int direction)
6438 return (direction == 0 ? MV_UP :
6439 direction == 1 ? MV_RIGHT :
6440 direction == 2 ? MV_DOWN :
6441 direction == 3 ? MV_LEFT :
6445 int map_element_RND_to_SP(int element_rnd)
6447 int element_sp = 0x20; /* map unknown elements to yellow "hardware" */
6449 if (element_rnd >= EL_SP_START &&
6450 element_rnd <= EL_SP_END)
6451 element_sp = element_rnd - EL_SP_START;
6452 else if (element_rnd == EL_EMPTY_SPACE)
6454 else if (element_rnd == EL_INVISIBLE_WALL)
6460 int map_element_SP_to_RND(int element_sp)
6462 int element_rnd = EL_UNKNOWN;
6464 if (element_sp >= 0x00 &&
6466 element_rnd = EL_SP_START + element_sp;
6467 else if (element_sp == 0x28)
6468 element_rnd = EL_INVISIBLE_WALL;
6473 int map_action_SP_to_RND(int action_sp)
6477 case actActive: return ACTION_ACTIVE;
6478 case actImpact: return ACTION_IMPACT;
6479 case actExploding: return ACTION_EXPLODING;
6480 case actDigging: return ACTION_DIGGING;
6481 case actSnapping: return ACTION_SNAPPING;
6482 case actCollecting: return ACTION_COLLECTING;
6483 case actPassing: return ACTION_PASSING;
6484 case actPushing: return ACTION_PUSHING;
6485 case actDropping: return ACTION_DROPPING;
6487 default: return ACTION_DEFAULT;
6491 int get_next_element(int element)
6495 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
6496 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
6497 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
6498 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
6499 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
6500 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
6501 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
6502 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
6503 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
6504 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
6505 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
6507 default: return element;
6511 int el_act_dir2img(int element, int action, int direction)
6513 element = GFX_ELEMENT(element);
6514 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
6516 /* direction_graphic[][] == graphic[] for undefined direction graphics */
6517 return element_info[element].direction_graphic[action][direction];
6520 static int el_act_dir2crm(int element, int action, int direction)
6522 element = GFX_ELEMENT(element);
6523 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
6525 /* direction_graphic[][] == graphic[] for undefined direction graphics */
6526 return element_info[element].direction_crumbled[action][direction];
6529 int el_act2img(int element, int action)
6531 element = GFX_ELEMENT(element);
6533 return element_info[element].graphic[action];
6536 int el_act2crm(int element, int action)
6538 element = GFX_ELEMENT(element);
6540 return element_info[element].crumbled[action];
6543 int el_dir2img(int element, int direction)
6545 element = GFX_ELEMENT(element);
6547 return el_act_dir2img(element, ACTION_DEFAULT, direction);
6550 int el2baseimg(int element)
6552 return element_info[element].graphic[ACTION_DEFAULT];
6555 int el2img(int element)
6557 element = GFX_ELEMENT(element);
6559 return element_info[element].graphic[ACTION_DEFAULT];
6562 int el2edimg(int element)
6564 element = GFX_ELEMENT(element);
6566 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
6569 int el2preimg(int element)
6571 element = GFX_ELEMENT(element);
6573 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
6576 int el2panelimg(int element)
6578 element = GFX_ELEMENT(element);
6580 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL];
6583 int font2baseimg(int font_nr)
6585 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
6588 int getBeltNrFromBeltElement(int element)
6590 return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
6591 element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
6592 element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
6595 int getBeltNrFromBeltActiveElement(int element)
6597 return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
6598 element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
6599 element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
6602 int getBeltNrFromBeltSwitchElement(int element)
6604 return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
6605 element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
6606 element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
6609 int getBeltDirNrFromBeltElement(int element)
6611 static int belt_base_element[4] =
6613 EL_CONVEYOR_BELT_1_LEFT,
6614 EL_CONVEYOR_BELT_2_LEFT,
6615 EL_CONVEYOR_BELT_3_LEFT,
6616 EL_CONVEYOR_BELT_4_LEFT
6619 int belt_nr = getBeltNrFromBeltElement(element);
6620 int belt_dir_nr = element - belt_base_element[belt_nr];
6622 return (belt_dir_nr % 3);
6625 int getBeltDirNrFromBeltSwitchElement(int element)
6627 static int belt_base_element[4] =
6629 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
6630 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
6631 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
6632 EL_CONVEYOR_BELT_4_SWITCH_LEFT
6635 int belt_nr = getBeltNrFromBeltSwitchElement(element);
6636 int belt_dir_nr = element - belt_base_element[belt_nr];
6638 return (belt_dir_nr % 3);
6641 int getBeltDirFromBeltElement(int element)
6643 static int belt_move_dir[3] =
6650 int belt_dir_nr = getBeltDirNrFromBeltElement(element);
6652 return belt_move_dir[belt_dir_nr];
6655 int getBeltDirFromBeltSwitchElement(int element)
6657 static int belt_move_dir[3] =
6664 int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
6666 return belt_move_dir[belt_dir_nr];
6669 int getBeltElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
6671 static int belt_base_element[4] =
6673 EL_CONVEYOR_BELT_1_LEFT,
6674 EL_CONVEYOR_BELT_2_LEFT,
6675 EL_CONVEYOR_BELT_3_LEFT,
6676 EL_CONVEYOR_BELT_4_LEFT
6679 return belt_base_element[belt_nr] + belt_dir_nr;
6682 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
6684 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
6686 return getBeltElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
6689 int getBeltSwitchElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
6691 static int belt_base_element[4] =
6693 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
6694 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
6695 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
6696 EL_CONVEYOR_BELT_4_SWITCH_LEFT
6699 return belt_base_element[belt_nr] + belt_dir_nr;
6702 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
6704 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
6706 return getBeltSwitchElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
6709 boolean getTeamMode_EM()
6711 return game.team_mode;
6714 int getGameFrameDelay_EM(int native_em_game_frame_delay)
6716 int game_frame_delay_value;
6718 game_frame_delay_value =
6719 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
6720 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
6723 if (tape.playing && tape.warp_forward && !tape.pausing)
6724 game_frame_delay_value = 0;
6726 return game_frame_delay_value;
6729 unsigned int InitRND(int seed)
6731 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
6732 return InitEngineRandom_EM(seed);
6733 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
6734 return InitEngineRandom_SP(seed);
6736 return InitEngineRandom_RND(seed);
6739 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
6740 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
6742 inline static int get_effective_element_EM(int tile, int frame_em)
6744 int element = object_mapping[tile].element_rnd;
6745 int action = object_mapping[tile].action;
6746 boolean is_backside = object_mapping[tile].is_backside;
6747 boolean action_removing = (action == ACTION_DIGGING ||
6748 action == ACTION_SNAPPING ||
6749 action == ACTION_COLLECTING);
6755 case Yacid_splash_eB:
6756 case Yacid_splash_wB:
6757 return (frame_em > 5 ? EL_EMPTY : element);
6763 else /* frame_em == 7 */
6767 case Yacid_splash_eB:
6768 case Yacid_splash_wB:
6771 case Yemerald_stone:
6774 case Ydiamond_stone:
6778 case Xdrip_stretchB:
6797 case Xsand_stonein_1:
6798 case Xsand_stonein_2:
6799 case Xsand_stonein_3:
6800 case Xsand_stonein_4:
6804 return (is_backside || action_removing ? EL_EMPTY : element);
6809 inline static boolean check_linear_animation_EM(int tile)
6813 case Xsand_stonesand_1:
6814 case Xsand_stonesand_quickout_1:
6815 case Xsand_sandstone_1:
6816 case Xsand_stonein_1:
6817 case Xsand_stoneout_1:
6836 case Yacid_splash_eB:
6837 case Yacid_splash_wB:
6838 case Yemerald_stone:
6845 inline static void set_crumbled_graphics_EM(struct GraphicInfo_EM *g_em,
6846 boolean has_crumbled_graphics,
6847 int crumbled, int sync_frame)
6849 /* if element can be crumbled, but certain action graphics are just empty
6850 space (like instantly snapping sand to empty space in 1 frame), do not
6851 treat these empty space graphics as crumbled graphics in EMC engine */
6852 if (crumbled == IMG_EMPTY_SPACE)
6853 has_crumbled_graphics = FALSE;
6855 if (has_crumbled_graphics)
6857 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
6858 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
6859 g_crumbled->anim_delay,
6860 g_crumbled->anim_mode,
6861 g_crumbled->anim_start_frame,
6864 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
6865 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
6867 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
6869 g_em->has_crumbled_graphics = TRUE;
6873 g_em->crumbled_bitmap = NULL;
6874 g_em->crumbled_src_x = 0;
6875 g_em->crumbled_src_y = 0;
6876 g_em->crumbled_border_size = 0;
6878 g_em->has_crumbled_graphics = FALSE;
6882 void ResetGfxAnimation_EM(int x, int y, int tile)
6887 void SetGfxAnimation_EM(struct GraphicInfo_EM *g_em,
6888 int tile, int frame_em, int x, int y)
6890 int action = object_mapping[tile].action;
6891 int direction = object_mapping[tile].direction;
6892 int effective_element = get_effective_element_EM(tile, frame_em);
6893 int graphic = (direction == MV_NONE ?
6894 el_act2img(effective_element, action) :
6895 el_act_dir2img(effective_element, action, direction));
6896 struct GraphicInfo *g = &graphic_info[graphic];
6898 boolean action_removing = (action == ACTION_DIGGING ||
6899 action == ACTION_SNAPPING ||
6900 action == ACTION_COLLECTING);
6901 boolean action_moving = (action == ACTION_FALLING ||
6902 action == ACTION_MOVING ||
6903 action == ACTION_PUSHING ||
6904 action == ACTION_EATING ||
6905 action == ACTION_FILLING ||
6906 action == ACTION_EMPTYING);
6907 boolean action_falling = (action == ACTION_FALLING ||
6908 action == ACTION_FILLING ||
6909 action == ACTION_EMPTYING);
6911 /* special case: graphic uses "2nd movement tile" and has defined
6912 7 frames for movement animation (or less) => use default graphic
6913 for last (8th) frame which ends the movement animation */
6914 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
6916 action = ACTION_DEFAULT; /* (keep action_* unchanged for now) */
6917 graphic = (direction == MV_NONE ?
6918 el_act2img(effective_element, action) :
6919 el_act_dir2img(effective_element, action, direction));
6921 g = &graphic_info[graphic];
6924 if ((action_removing || check_linear_animation_EM(tile)) && frame_em == 0)
6928 else if (action_moving)
6930 boolean is_backside = object_mapping[tile].is_backside;
6934 int direction = object_mapping[tile].direction;
6935 int move_dir = (action_falling ? MV_DOWN : direction);
6940 /* !!! TEST !!! NEW !!! DOES NOT WORK RIGHT YET !!! */
6941 if (g->double_movement && frame_em == 0)
6945 if (move_dir == MV_LEFT)
6946 GfxFrame[x - 1][y] = GfxFrame[x][y];
6947 else if (move_dir == MV_RIGHT)
6948 GfxFrame[x + 1][y] = GfxFrame[x][y];
6949 else if (move_dir == MV_UP)
6950 GfxFrame[x][y - 1] = GfxFrame[x][y];
6951 else if (move_dir == MV_DOWN)
6952 GfxFrame[x][y + 1] = GfxFrame[x][y];
6959 /* special case: animation for Xsand_stonesand_quickout_1/2 twice as fast */
6960 if (tile == Xsand_stonesand_quickout_1 ||
6961 tile == Xsand_stonesand_quickout_2)
6965 if (graphic_info[graphic].anim_global_sync)
6966 sync_frame = FrameCounter;
6967 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
6968 sync_frame = GfxFrame[x][y];
6970 sync_frame = 0; /* playfield border (pseudo steel) */
6972 SetRandomAnimationValue(x, y);
6974 int frame = getAnimationFrame(g->anim_frames,
6977 g->anim_start_frame,
6980 g_em->unique_identifier =
6981 (graphic << 16) | ((frame % 8) << 12) | (g_em->width << 6) | g_em->height;
6984 void getGraphicSourceObjectExt_EM(struct GraphicInfo_EM *g_em,
6985 int tile, int frame_em, int x, int y)
6987 int action = object_mapping[tile].action;
6988 int direction = object_mapping[tile].direction;
6989 boolean is_backside = object_mapping[tile].is_backside;
6990 int effective_element = get_effective_element_EM(tile, frame_em);
6991 int effective_action = action;
6992 int graphic = (direction == MV_NONE ?
6993 el_act2img(effective_element, effective_action) :
6994 el_act_dir2img(effective_element, effective_action,
6996 int crumbled = (direction == MV_NONE ?
6997 el_act2crm(effective_element, effective_action) :
6998 el_act_dir2crm(effective_element, effective_action,
7000 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7001 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7002 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7003 struct GraphicInfo *g = &graphic_info[graphic];
7006 /* special case: graphic uses "2nd movement tile" and has defined
7007 7 frames for movement animation (or less) => use default graphic
7008 for last (8th) frame which ends the movement animation */
7009 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
7011 effective_action = ACTION_DEFAULT;
7012 graphic = (direction == MV_NONE ?
7013 el_act2img(effective_element, effective_action) :
7014 el_act_dir2img(effective_element, effective_action,
7016 crumbled = (direction == MV_NONE ?
7017 el_act2crm(effective_element, effective_action) :
7018 el_act_dir2crm(effective_element, effective_action,
7021 g = &graphic_info[graphic];
7024 if (graphic_info[graphic].anim_global_sync)
7025 sync_frame = FrameCounter;
7026 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
7027 sync_frame = GfxFrame[x][y];
7029 sync_frame = 0; /* playfield border (pseudo steel) */
7031 SetRandomAnimationValue(x, y);
7033 int frame = getAnimationFrame(g->anim_frames,
7036 g->anim_start_frame,
7039 getGraphicSourceExt(graphic, frame, &g_em->bitmap, &g_em->src_x, &g_em->src_y,
7040 g->double_movement && is_backside);
7042 /* (updating the "crumbled" graphic definitions is probably not really needed,
7043 as animations for crumbled graphics can't be longer than one EMC cycle) */
7044 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
7048 void getGraphicSourcePlayerExt_EM(struct GraphicInfo_EM *g_em,
7049 int player_nr, int anim, int frame_em)
7051 int element = player_mapping[player_nr][anim].element_rnd;
7052 int action = player_mapping[player_nr][anim].action;
7053 int direction = player_mapping[player_nr][anim].direction;
7054 int graphic = (direction == MV_NONE ?
7055 el_act2img(element, action) :
7056 el_act_dir2img(element, action, direction));
7057 struct GraphicInfo *g = &graphic_info[graphic];
7060 InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
7062 stored_player[player_nr].StepFrame = frame_em;
7064 sync_frame = stored_player[player_nr].Frame;
7066 int frame = getAnimationFrame(g->anim_frames,
7069 g->anim_start_frame,
7072 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
7073 &g_em->src_x, &g_em->src_y, FALSE);
7076 void InitGraphicInfo_EM(void)
7081 int num_em_gfx_errors = 0;
7083 if (graphic_info_em_object[0][0].bitmap == NULL)
7085 /* EM graphics not yet initialized in em_open_all() */
7090 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
7093 /* always start with reliable default values */
7094 for (i = 0; i < TILE_MAX; i++)
7096 object_mapping[i].element_rnd = EL_UNKNOWN;
7097 object_mapping[i].is_backside = FALSE;
7098 object_mapping[i].action = ACTION_DEFAULT;
7099 object_mapping[i].direction = MV_NONE;
7102 /* always start with reliable default values */
7103 for (p = 0; p < MAX_PLAYERS; p++)
7105 for (i = 0; i < SPR_MAX; i++)
7107 player_mapping[p][i].element_rnd = EL_UNKNOWN;
7108 player_mapping[p][i].action = ACTION_DEFAULT;
7109 player_mapping[p][i].direction = MV_NONE;
7113 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
7115 int e = em_object_mapping_list[i].element_em;
7117 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
7118 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
7120 if (em_object_mapping_list[i].action != -1)
7121 object_mapping[e].action = em_object_mapping_list[i].action;
7123 if (em_object_mapping_list[i].direction != -1)
7124 object_mapping[e].direction =
7125 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
7128 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
7130 int a = em_player_mapping_list[i].action_em;
7131 int p = em_player_mapping_list[i].player_nr;
7133 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
7135 if (em_player_mapping_list[i].action != -1)
7136 player_mapping[p][a].action = em_player_mapping_list[i].action;
7138 if (em_player_mapping_list[i].direction != -1)
7139 player_mapping[p][a].direction =
7140 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
7143 for (i = 0; i < TILE_MAX; i++)
7145 int element = object_mapping[i].element_rnd;
7146 int action = object_mapping[i].action;
7147 int direction = object_mapping[i].direction;
7148 boolean is_backside = object_mapping[i].is_backside;
7149 boolean action_exploding = ((action == ACTION_EXPLODING ||
7150 action == ACTION_SMASHED_BY_ROCK ||
7151 action == ACTION_SMASHED_BY_SPRING) &&
7152 element != EL_DIAMOND);
7153 boolean action_active = (action == ACTION_ACTIVE);
7154 boolean action_other = (action == ACTION_OTHER);
7156 for (j = 0; j < 8; j++)
7158 int effective_element = get_effective_element_EM(i, j);
7159 int effective_action = (j < 7 ? action :
7160 i == Xdrip_stretch ? action :
7161 i == Xdrip_stretchB ? action :
7162 i == Ydrip_s1 ? action :
7163 i == Ydrip_s1B ? action :
7164 i == Xball_1B ? action :
7165 i == Xball_2 ? action :
7166 i == Xball_2B ? action :
7167 i == Yball_eat ? action :
7168 i == Ykey_1_eat ? action :
7169 i == Ykey_2_eat ? action :
7170 i == Ykey_3_eat ? action :
7171 i == Ykey_4_eat ? action :
7172 i == Ykey_5_eat ? action :
7173 i == Ykey_6_eat ? action :
7174 i == Ykey_7_eat ? action :
7175 i == Ykey_8_eat ? action :
7176 i == Ylenses_eat ? action :
7177 i == Ymagnify_eat ? action :
7178 i == Ygrass_eat ? action :
7179 i == Ydirt_eat ? action :
7180 i == Xsand_stonein_1 ? action :
7181 i == Xsand_stonein_2 ? action :
7182 i == Xsand_stonein_3 ? action :
7183 i == Xsand_stonein_4 ? action :
7184 i == Xsand_stoneout_1 ? action :
7185 i == Xsand_stoneout_2 ? action :
7186 i == Xboom_android ? ACTION_EXPLODING :
7187 action_exploding ? ACTION_EXPLODING :
7188 action_active ? action :
7189 action_other ? action :
7191 int graphic = (el_act_dir2img(effective_element, effective_action,
7193 int crumbled = (el_act_dir2crm(effective_element, effective_action,
7195 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7196 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7197 boolean has_action_graphics = (graphic != base_graphic);
7198 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7199 struct GraphicInfo *g = &graphic_info[graphic];
7200 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7203 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
7204 boolean special_animation = (action != ACTION_DEFAULT &&
7205 g->anim_frames == 3 &&
7206 g->anim_delay == 2 &&
7207 g->anim_mode & ANIM_LINEAR);
7208 int sync_frame = (i == Xdrip_stretch ? 7 :
7209 i == Xdrip_stretchB ? 7 :
7210 i == Ydrip_s2 ? j + 8 :
7211 i == Ydrip_s2B ? j + 8 :
7220 i == Xfake_acid_1 ? 0 :
7221 i == Xfake_acid_2 ? 10 :
7222 i == Xfake_acid_3 ? 20 :
7223 i == Xfake_acid_4 ? 30 :
7224 i == Xfake_acid_5 ? 40 :
7225 i == Xfake_acid_6 ? 50 :
7226 i == Xfake_acid_7 ? 60 :
7227 i == Xfake_acid_8 ? 70 :
7229 i == Xball_2B ? j + 8 :
7230 i == Yball_eat ? j + 1 :
7231 i == Ykey_1_eat ? j + 1 :
7232 i == Ykey_2_eat ? j + 1 :
7233 i == Ykey_3_eat ? j + 1 :
7234 i == Ykey_4_eat ? j + 1 :
7235 i == Ykey_5_eat ? j + 1 :
7236 i == Ykey_6_eat ? j + 1 :
7237 i == Ykey_7_eat ? j + 1 :
7238 i == Ykey_8_eat ? j + 1 :
7239 i == Ylenses_eat ? j + 1 :
7240 i == Ymagnify_eat ? j + 1 :
7241 i == Ygrass_eat ? j + 1 :
7242 i == Ydirt_eat ? j + 1 :
7243 i == Xamoeba_1 ? 0 :
7244 i == Xamoeba_2 ? 1 :
7245 i == Xamoeba_3 ? 2 :
7246 i == Xamoeba_4 ? 3 :
7247 i == Xamoeba_5 ? 0 :
7248 i == Xamoeba_6 ? 1 :
7249 i == Xamoeba_7 ? 2 :
7250 i == Xamoeba_8 ? 3 :
7251 i == Xexit_2 ? j + 8 :
7252 i == Xexit_3 ? j + 16 :
7253 i == Xdynamite_1 ? 0 :
7254 i == Xdynamite_2 ? 8 :
7255 i == Xdynamite_3 ? 16 :
7256 i == Xdynamite_4 ? 24 :
7257 i == Xsand_stonein_1 ? j + 1 :
7258 i == Xsand_stonein_2 ? j + 9 :
7259 i == Xsand_stonein_3 ? j + 17 :
7260 i == Xsand_stonein_4 ? j + 25 :
7261 i == Xsand_stoneout_1 && j == 0 ? 0 :
7262 i == Xsand_stoneout_1 && j == 1 ? 0 :
7263 i == Xsand_stoneout_1 && j == 2 ? 1 :
7264 i == Xsand_stoneout_1 && j == 3 ? 2 :
7265 i == Xsand_stoneout_1 && j == 4 ? 2 :
7266 i == Xsand_stoneout_1 && j == 5 ? 3 :
7267 i == Xsand_stoneout_1 && j == 6 ? 4 :
7268 i == Xsand_stoneout_1 && j == 7 ? 4 :
7269 i == Xsand_stoneout_2 && j == 0 ? 5 :
7270 i == Xsand_stoneout_2 && j == 1 ? 6 :
7271 i == Xsand_stoneout_2 && j == 2 ? 7 :
7272 i == Xsand_stoneout_2 && j == 3 ? 8 :
7273 i == Xsand_stoneout_2 && j == 4 ? 9 :
7274 i == Xsand_stoneout_2 && j == 5 ? 11 :
7275 i == Xsand_stoneout_2 && j == 6 ? 13 :
7276 i == Xsand_stoneout_2 && j == 7 ? 15 :
7277 i == Xboom_bug && j == 1 ? 2 :
7278 i == Xboom_bug && j == 2 ? 2 :
7279 i == Xboom_bug && j == 3 ? 4 :
7280 i == Xboom_bug && j == 4 ? 4 :
7281 i == Xboom_bug && j == 5 ? 2 :
7282 i == Xboom_bug && j == 6 ? 2 :
7283 i == Xboom_bug && j == 7 ? 0 :
7284 i == Xboom_bomb && j == 1 ? 2 :
7285 i == Xboom_bomb && j == 2 ? 2 :
7286 i == Xboom_bomb && j == 3 ? 4 :
7287 i == Xboom_bomb && j == 4 ? 4 :
7288 i == Xboom_bomb && j == 5 ? 2 :
7289 i == Xboom_bomb && j == 6 ? 2 :
7290 i == Xboom_bomb && j == 7 ? 0 :
7291 i == Xboom_android && j == 7 ? 6 :
7292 i == Xboom_1 && j == 1 ? 2 :
7293 i == Xboom_1 && j == 2 ? 2 :
7294 i == Xboom_1 && j == 3 ? 4 :
7295 i == Xboom_1 && j == 4 ? 4 :
7296 i == Xboom_1 && j == 5 ? 6 :
7297 i == Xboom_1 && j == 6 ? 6 :
7298 i == Xboom_1 && j == 7 ? 8 :
7299 i == Xboom_2 && j == 0 ? 8 :
7300 i == Xboom_2 && j == 1 ? 8 :
7301 i == Xboom_2 && j == 2 ? 10 :
7302 i == Xboom_2 && j == 3 ? 10 :
7303 i == Xboom_2 && j == 4 ? 10 :
7304 i == Xboom_2 && j == 5 ? 12 :
7305 i == Xboom_2 && j == 6 ? 12 :
7306 i == Xboom_2 && j == 7 ? 12 :
7307 special_animation && j == 4 ? 3 :
7308 effective_action != action ? 0 :
7312 Bitmap *debug_bitmap = g_em->bitmap;
7313 int debug_src_x = g_em->src_x;
7314 int debug_src_y = g_em->src_y;
7317 int frame = getAnimationFrame(g->anim_frames,
7320 g->anim_start_frame,
7323 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
7324 g->double_movement && is_backside);
7326 g_em->bitmap = src_bitmap;
7327 g_em->src_x = src_x;
7328 g_em->src_y = src_y;
7329 g_em->src_offset_x = 0;
7330 g_em->src_offset_y = 0;
7331 g_em->dst_offset_x = 0;
7332 g_em->dst_offset_y = 0;
7333 g_em->width = TILEX;
7334 g_em->height = TILEY;
7336 g_em->preserve_background = FALSE;
7338 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
7341 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
7342 effective_action == ACTION_MOVING ||
7343 effective_action == ACTION_PUSHING ||
7344 effective_action == ACTION_EATING)) ||
7345 (!has_action_graphics && (effective_action == ACTION_FILLING ||
7346 effective_action == ACTION_EMPTYING)))
7349 (effective_action == ACTION_FALLING ||
7350 effective_action == ACTION_FILLING ||
7351 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
7352 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
7353 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
7354 int num_steps = (i == Ydrip_s1 ? 16 :
7355 i == Ydrip_s1B ? 16 :
7356 i == Ydrip_s2 ? 16 :
7357 i == Ydrip_s2B ? 16 :
7358 i == Xsand_stonein_1 ? 32 :
7359 i == Xsand_stonein_2 ? 32 :
7360 i == Xsand_stonein_3 ? 32 :
7361 i == Xsand_stonein_4 ? 32 :
7362 i == Xsand_stoneout_1 ? 16 :
7363 i == Xsand_stoneout_2 ? 16 : 8);
7364 int cx = ABS(dx) * (TILEX / num_steps);
7365 int cy = ABS(dy) * (TILEY / num_steps);
7366 int step_frame = (i == Ydrip_s2 ? j + 8 :
7367 i == Ydrip_s2B ? j + 8 :
7368 i == Xsand_stonein_2 ? j + 8 :
7369 i == Xsand_stonein_3 ? j + 16 :
7370 i == Xsand_stonein_4 ? j + 24 :
7371 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
7372 int step = (is_backside ? step_frame : num_steps - step_frame);
7374 if (is_backside) /* tile where movement starts */
7376 if (dx < 0 || dy < 0)
7378 g_em->src_offset_x = cx * step;
7379 g_em->src_offset_y = cy * step;
7383 g_em->dst_offset_x = cx * step;
7384 g_em->dst_offset_y = cy * step;
7387 else /* tile where movement ends */
7389 if (dx < 0 || dy < 0)
7391 g_em->dst_offset_x = cx * step;
7392 g_em->dst_offset_y = cy * step;
7396 g_em->src_offset_x = cx * step;
7397 g_em->src_offset_y = cy * step;
7401 g_em->width = TILEX - cx * step;
7402 g_em->height = TILEY - cy * step;
7405 /* create unique graphic identifier to decide if tile must be redrawn */
7406 /* bit 31 - 16 (16 bit): EM style graphic
7407 bit 15 - 12 ( 4 bit): EM style frame
7408 bit 11 - 6 ( 6 bit): graphic width
7409 bit 5 - 0 ( 6 bit): graphic height */
7410 g_em->unique_identifier =
7411 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
7415 /* skip check for EMC elements not contained in original EMC artwork */
7416 if (element == EL_EMC_FAKE_ACID)
7419 if (g_em->bitmap != debug_bitmap ||
7420 g_em->src_x != debug_src_x ||
7421 g_em->src_y != debug_src_y ||
7422 g_em->src_offset_x != 0 ||
7423 g_em->src_offset_y != 0 ||
7424 g_em->dst_offset_x != 0 ||
7425 g_em->dst_offset_y != 0 ||
7426 g_em->width != TILEX ||
7427 g_em->height != TILEY)
7429 static int last_i = -1;
7437 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
7438 i, element, element_info[element].token_name,
7439 element_action_info[effective_action].suffix, direction);
7441 if (element != effective_element)
7442 printf(" [%d ('%s')]",
7444 element_info[effective_element].token_name);
7448 if (g_em->bitmap != debug_bitmap)
7449 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
7450 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
7452 if (g_em->src_x != debug_src_x ||
7453 g_em->src_y != debug_src_y)
7454 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
7455 j, (is_backside ? 'B' : 'F'),
7456 g_em->src_x, g_em->src_y,
7457 g_em->src_x / 32, g_em->src_y / 32,
7458 debug_src_x, debug_src_y,
7459 debug_src_x / 32, debug_src_y / 32);
7461 if (g_em->src_offset_x != 0 ||
7462 g_em->src_offset_y != 0 ||
7463 g_em->dst_offset_x != 0 ||
7464 g_em->dst_offset_y != 0)
7465 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
7467 g_em->src_offset_x, g_em->src_offset_y,
7468 g_em->dst_offset_x, g_em->dst_offset_y);
7470 if (g_em->width != TILEX ||
7471 g_em->height != TILEY)
7472 printf(" %d (%d): size %d,%d should be %d,%d\n",
7474 g_em->width, g_em->height, TILEX, TILEY);
7476 num_em_gfx_errors++;
7483 for (i = 0; i < TILE_MAX; i++)
7485 for (j = 0; j < 8; j++)
7487 int element = object_mapping[i].element_rnd;
7488 int action = object_mapping[i].action;
7489 int direction = object_mapping[i].direction;
7490 boolean is_backside = object_mapping[i].is_backside;
7491 int graphic_action = el_act_dir2img(element, action, direction);
7492 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
7494 if ((action == ACTION_SMASHED_BY_ROCK ||
7495 action == ACTION_SMASHED_BY_SPRING ||
7496 action == ACTION_EATING) &&
7497 graphic_action == graphic_default)
7499 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
7500 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
7501 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
7502 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
7505 /* no separate animation for "smashed by rock" -- use rock instead */
7506 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7507 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
7509 g_em->bitmap = g_xx->bitmap;
7510 g_em->src_x = g_xx->src_x;
7511 g_em->src_y = g_xx->src_y;
7512 g_em->src_offset_x = g_xx->src_offset_x;
7513 g_em->src_offset_y = g_xx->src_offset_y;
7514 g_em->dst_offset_x = g_xx->dst_offset_x;
7515 g_em->dst_offset_y = g_xx->dst_offset_y;
7516 g_em->width = g_xx->width;
7517 g_em->height = g_xx->height;
7518 g_em->unique_identifier = g_xx->unique_identifier;
7521 g_em->preserve_background = TRUE;
7526 for (p = 0; p < MAX_PLAYERS; p++)
7528 for (i = 0; i < SPR_MAX; i++)
7530 int element = player_mapping[p][i].element_rnd;
7531 int action = player_mapping[p][i].action;
7532 int direction = player_mapping[p][i].direction;
7534 for (j = 0; j < 8; j++)
7536 int effective_element = element;
7537 int effective_action = action;
7538 int graphic = (direction == MV_NONE ?
7539 el_act2img(effective_element, effective_action) :
7540 el_act_dir2img(effective_element, effective_action,
7542 struct GraphicInfo *g = &graphic_info[graphic];
7543 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
7549 Bitmap *debug_bitmap = g_em->bitmap;
7550 int debug_src_x = g_em->src_x;
7551 int debug_src_y = g_em->src_y;
7554 int frame = getAnimationFrame(g->anim_frames,
7557 g->anim_start_frame,
7560 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
7562 g_em->bitmap = src_bitmap;
7563 g_em->src_x = src_x;
7564 g_em->src_y = src_y;
7565 g_em->src_offset_x = 0;
7566 g_em->src_offset_y = 0;
7567 g_em->dst_offset_x = 0;
7568 g_em->dst_offset_y = 0;
7569 g_em->width = TILEX;
7570 g_em->height = TILEY;
7574 /* skip check for EMC elements not contained in original EMC artwork */
7575 if (element == EL_PLAYER_3 ||
7576 element == EL_PLAYER_4)
7579 if (g_em->bitmap != debug_bitmap ||
7580 g_em->src_x != debug_src_x ||
7581 g_em->src_y != debug_src_y)
7583 static int last_i = -1;
7591 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
7592 p, i, element, element_info[element].token_name,
7593 element_action_info[effective_action].suffix, direction);
7595 if (element != effective_element)
7596 printf(" [%d ('%s')]",
7598 element_info[effective_element].token_name);
7602 if (g_em->bitmap != debug_bitmap)
7603 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
7604 j, (int)(g_em->bitmap), (int)(debug_bitmap));
7606 if (g_em->src_x != debug_src_x ||
7607 g_em->src_y != debug_src_y)
7608 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
7610 g_em->src_x, g_em->src_y,
7611 g_em->src_x / 32, g_em->src_y / 32,
7612 debug_src_x, debug_src_y,
7613 debug_src_x / 32, debug_src_y / 32);
7615 num_em_gfx_errors++;
7625 printf("::: [%d errors found]\n", num_em_gfx_errors);
7631 void CheckSaveEngineSnapshot_EM(byte action[MAX_PLAYERS], int frame,
7632 boolean any_player_moving,
7633 boolean any_player_snapping,
7634 boolean any_player_dropping)
7636 static boolean player_was_waiting = TRUE;
7638 if (frame == 0 && !any_player_dropping)
7640 if (!player_was_waiting)
7642 if (!SaveEngineSnapshotToList())
7645 player_was_waiting = TRUE;
7648 else if (any_player_moving || any_player_snapping || any_player_dropping)
7650 player_was_waiting = FALSE;
7654 void CheckSaveEngineSnapshot_SP(boolean murphy_is_waiting,
7655 boolean murphy_is_dropping)
7657 static boolean player_was_waiting = TRUE;
7659 if (murphy_is_waiting)
7661 if (!player_was_waiting)
7663 if (!SaveEngineSnapshotToList())
7666 player_was_waiting = TRUE;
7671 player_was_waiting = FALSE;
7675 void CheckSingleStepMode_EM(byte action[MAX_PLAYERS], int frame,
7676 boolean any_player_moving,
7677 boolean any_player_snapping,
7678 boolean any_player_dropping)
7680 if (tape.single_step && tape.recording && !tape.pausing)
7681 if (frame == 0 && !any_player_dropping)
7682 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
7684 CheckSaveEngineSnapshot_EM(action, frame, any_player_moving,
7685 any_player_snapping, any_player_dropping);
7688 void CheckSingleStepMode_SP(boolean murphy_is_waiting,
7689 boolean murphy_is_dropping)
7691 if (tape.single_step && tape.recording && !tape.pausing)
7692 if (murphy_is_waiting)
7693 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
7695 CheckSaveEngineSnapshot_SP(murphy_is_waiting, murphy_is_dropping);
7698 void getGraphicSource_SP(struct GraphicInfo_SP *g_sp,
7699 int graphic, int sync_frame, int x, int y)
7701 int frame = getGraphicAnimationFrame(graphic, sync_frame);
7703 getGraphicSource(graphic, frame, &g_sp->bitmap, &g_sp->src_x, &g_sp->src_y);
7706 boolean isNextAnimationFrame_SP(int graphic, int sync_frame)
7708 return (IS_NEXT_FRAME(sync_frame, graphic));
7711 int getGraphicInfo_Delay(int graphic)
7713 return graphic_info[graphic].anim_delay;
7716 void PlayMenuSoundExt(int sound)
7718 if (sound == SND_UNDEFINED)
7721 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
7722 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
7725 if (IS_LOOP_SOUND(sound))
7726 PlaySoundLoop(sound);
7731 void PlayMenuSound()
7733 PlayMenuSoundExt(menu.sound[game_status]);
7736 void PlayMenuSoundStereo(int sound, int stereo_position)
7738 if (sound == SND_UNDEFINED)
7741 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
7742 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
7745 if (IS_LOOP_SOUND(sound))
7746 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
7748 PlaySoundStereo(sound, stereo_position);
7751 void PlayMenuSoundIfLoopExt(int sound)
7753 if (sound == SND_UNDEFINED)
7756 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
7757 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
7760 if (IS_LOOP_SOUND(sound))
7761 PlaySoundLoop(sound);
7764 void PlayMenuSoundIfLoop()
7766 PlayMenuSoundIfLoopExt(menu.sound[game_status]);
7769 void PlayMenuMusicExt(int music)
7771 if (music == MUS_UNDEFINED)
7774 if (!setup.sound_music)
7780 void PlayMenuMusic()
7782 PlayMenuMusicExt(menu.music[game_status]);
7785 void PlaySoundActivating()
7788 PlaySound(SND_MENU_ITEM_ACTIVATING);
7792 void PlaySoundSelecting()
7795 PlaySound(SND_MENU_ITEM_SELECTING);
7799 void ToggleFullscreenOrChangeWindowScalingIfNeeded()
7801 boolean change_fullscreen = (setup.fullscreen !=
7802 video.fullscreen_enabled);
7803 boolean change_fullscreen_mode = (video.fullscreen_enabled &&
7804 !strEqual(setup.fullscreen_mode,
7805 video.fullscreen_mode_current));
7806 boolean change_window_scaling_percent = (!video.fullscreen_enabled &&
7807 setup.window_scaling_percent !=
7808 video.window_scaling_percent);
7810 if (change_window_scaling_percent && video.fullscreen_enabled)
7813 if (!change_window_scaling_percent && !video.fullscreen_available)
7816 #if defined(TARGET_SDL2)
7817 if (change_window_scaling_percent)
7819 SDLSetWindowScaling(setup.window_scaling_percent);
7823 else if (change_fullscreen)
7825 SDLSetWindowFullscreen(setup.fullscreen);
7827 /* set setup value according to successfully changed fullscreen mode */
7828 setup.fullscreen = video.fullscreen_enabled;
7834 if (change_fullscreen ||
7835 change_fullscreen_mode ||
7836 change_window_scaling_percent)
7838 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
7840 /* save backbuffer content which gets lost when toggling fullscreen mode */
7841 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
7843 if (change_fullscreen_mode)
7845 /* keep fullscreen, but change fullscreen mode (screen resolution) */
7846 video.fullscreen_enabled = FALSE; /* force new fullscreen mode */
7849 if (change_window_scaling_percent)
7851 /* keep window mode, but change window scaling */
7852 video.fullscreen_enabled = TRUE; /* force new window scaling */
7855 /* toggle fullscreen */
7856 ChangeVideoModeIfNeeded(setup.fullscreen);
7858 /* set setup value according to successfully changed fullscreen mode */
7859 setup.fullscreen = video.fullscreen_enabled;
7861 /* restore backbuffer content from temporary backbuffer backup bitmap */
7862 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
7864 FreeBitmap(tmp_backbuffer);
7866 /* update visible window/screen */
7867 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
7871 void ChangeViewportPropertiesIfNeeded()
7873 int gfx_game_mode = game_status;
7874 int gfx_game_mode2 = (game_status == GAME_MODE_EDITOR ? GAME_MODE_DEFAULT :
7876 struct RectWithBorder *vp_playfield = &viewport.playfield[gfx_game_mode];
7877 struct RectWithBorder *vp_door_1 = &viewport.door_1[gfx_game_mode];
7878 struct RectWithBorder *vp_door_2 = &viewport.door_2[gfx_game_mode2];
7879 struct RectWithBorder *vp_door_3 = &viewport.door_2[GAME_MODE_EDITOR];
7880 int border_size = vp_playfield->border_size;
7881 int new_sx = vp_playfield->x + border_size;
7882 int new_sy = vp_playfield->y + border_size;
7883 int new_sxsize = vp_playfield->width - 2 * border_size;
7884 int new_sysize = vp_playfield->height - 2 * border_size;
7885 int new_real_sx = vp_playfield->x;
7886 int new_real_sy = vp_playfield->y;
7887 int new_full_sxsize = vp_playfield->width;
7888 int new_full_sysize = vp_playfield->height;
7889 int new_dx = vp_door_1->x;
7890 int new_dy = vp_door_1->y;
7891 int new_dxsize = vp_door_1->width;
7892 int new_dysize = vp_door_1->height;
7893 int new_vx = vp_door_2->x;
7894 int new_vy = vp_door_2->y;
7895 int new_vxsize = vp_door_2->width;
7896 int new_vysize = vp_door_2->height;
7897 int new_ex = vp_door_3->x;
7898 int new_ey = vp_door_3->y;
7899 int new_exsize = vp_door_3->width;
7900 int new_eysize = vp_door_3->height;
7901 int new_tilesize_var =
7902 (setup.small_game_graphics ? MINI_TILESIZE : game.tile_size);
7904 int tilesize = (gfx_game_mode == GAME_MODE_PLAYING ? new_tilesize_var :
7905 gfx_game_mode == GAME_MODE_EDITOR ? MINI_TILESIZE : TILESIZE);
7906 int new_scr_fieldx = new_sxsize / tilesize;
7907 int new_scr_fieldy = new_sysize / tilesize;
7908 int new_scr_fieldx_buffers = new_sxsize / new_tilesize_var;
7909 int new_scr_fieldy_buffers = new_sysize / new_tilesize_var;
7910 boolean init_gfx_buffers = FALSE;
7911 boolean init_video_buffer = FALSE;
7912 boolean init_gadgets_and_toons = FALSE;
7913 boolean init_em_graphics = FALSE;
7914 boolean drawing_area_changed = FALSE;
7916 if (viewport.window.width != WIN_XSIZE ||
7917 viewport.window.height != WIN_YSIZE)
7919 WIN_XSIZE = viewport.window.width;
7920 WIN_YSIZE = viewport.window.height;
7922 init_video_buffer = TRUE;
7923 init_gfx_buffers = TRUE;
7925 // printf("::: video: init_video_buffer, init_gfx_buffers\n");
7928 if (new_scr_fieldx != SCR_FIELDX ||
7929 new_scr_fieldy != SCR_FIELDY)
7931 /* this always toggles between MAIN and GAME when using small tile size */
7933 SCR_FIELDX = new_scr_fieldx;
7934 SCR_FIELDY = new_scr_fieldy;
7936 // printf("::: new_scr_fieldx != SCR_FIELDX ...\n");
7947 new_sxsize != SXSIZE ||
7948 new_sysize != SYSIZE ||
7949 new_dxsize != DXSIZE ||
7950 new_dysize != DYSIZE ||
7951 new_vxsize != VXSIZE ||
7952 new_vysize != VYSIZE ||
7953 new_exsize != EXSIZE ||
7954 new_eysize != EYSIZE ||
7955 new_real_sx != REAL_SX ||
7956 new_real_sy != REAL_SY ||
7957 new_full_sxsize != FULL_SXSIZE ||
7958 new_full_sysize != FULL_SYSIZE ||
7959 new_tilesize_var != TILESIZE_VAR
7962 if (new_tilesize_var != TILESIZE_VAR)
7964 // printf("::: new_tilesize_var != TILESIZE_VAR\n");
7966 // changing tile size invalidates scroll values of engine snapshots
7967 FreeEngineSnapshotSingle();
7969 // changing tile size requires update of graphic mapping for EM engine
7970 init_em_graphics = TRUE;
7975 new_sxsize != SXSIZE ||
7976 new_sysize != SYSIZE ||
7977 new_real_sx != REAL_SX ||
7978 new_real_sy != REAL_SY ||
7979 new_full_sxsize != FULL_SXSIZE ||
7980 new_full_sysize != FULL_SYSIZE)
7982 if (!init_video_buffer)
7983 drawing_area_changed = TRUE;
7994 SXSIZE = new_sxsize;
7995 SYSIZE = new_sysize;
7996 DXSIZE = new_dxsize;
7997 DYSIZE = new_dysize;
7998 VXSIZE = new_vxsize;
7999 VYSIZE = new_vysize;
8000 EXSIZE = new_exsize;
8001 EYSIZE = new_eysize;
8002 REAL_SX = new_real_sx;
8003 REAL_SY = new_real_sy;
8004 FULL_SXSIZE = new_full_sxsize;
8005 FULL_SYSIZE = new_full_sysize;
8006 TILESIZE_VAR = new_tilesize_var;
8008 init_gfx_buffers = TRUE;
8009 init_gadgets_and_toons = TRUE;
8011 // printf("::: viewports: init_gfx_buffers\n");
8012 // printf("::: viewports: init_gadgets_and_toons\n");
8015 if (init_gfx_buffers)
8017 // printf("::: init_gfx_buffers\n");
8019 SCR_FIELDX = new_scr_fieldx_buffers;
8020 SCR_FIELDY = new_scr_fieldy_buffers;
8024 SCR_FIELDX = new_scr_fieldx;
8025 SCR_FIELDY = new_scr_fieldy;
8027 gfx.drawing_area_changed = drawing_area_changed;
8029 SetDrawDeactivationMask(REDRAW_NONE);
8030 SetDrawBackgroundMask(REDRAW_FIELD);
8033 if (init_video_buffer)
8035 // printf("::: init_video_buffer\n");
8037 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
8040 if (init_gadgets_and_toons)
8042 // printf("::: init_gadgets_and_toons\n");
8048 if (init_em_graphics)
8050 InitGraphicInfo_EM();