1 // ============================================================================
2 // Rocks'n'Diamonds - McDuffin Strikes Back!
3 // ----------------------------------------------------------------------------
4 // (c) 1995-2014 by Artsoft Entertainment
7 // http://www.artsoft.org/
8 // ----------------------------------------------------------------------------
10 // ============================================================================
14 #include "libgame/libgame.h"
26 /* select level set with EMC X11 graphics before activating EM GFX debugging */
27 #define DEBUG_EM_GFX 0
29 /* tool button identifiers */
30 #define TOOL_CTRL_ID_YES 0
31 #define TOOL_CTRL_ID_NO 1
32 #define TOOL_CTRL_ID_CONFIRM 2
33 #define TOOL_CTRL_ID_PLAYER_1 3
34 #define TOOL_CTRL_ID_PLAYER_2 4
35 #define TOOL_CTRL_ID_PLAYER_3 5
36 #define TOOL_CTRL_ID_PLAYER_4 6
38 #define NUM_TOOL_BUTTONS 7
40 /* constants for number of doors and door parts */
42 #define NUM_PANELS NUM_DOORS
43 // #define NUM_PANELS 0
44 #define MAX_PARTS_PER_DOOR 8
45 #define MAX_DOOR_PARTS (NUM_DOORS * MAX_PARTS_PER_DOOR + NUM_PANELS)
46 #define DOOR_PART_IS_PANEL(i) ((i) >= NUM_DOORS * MAX_PARTS_PER_DOOR)
49 struct DoorPartOrderInfo
55 static struct DoorPartOrderInfo door_part_order[MAX_DOOR_PARTS];
57 struct DoorPartControlInfo
61 struct DoorPartPosInfo *pos;
64 static struct DoorPartControlInfo door_part_controls[] =
68 IMG_DOOR_1_GFX_PART_1,
73 IMG_DOOR_1_GFX_PART_2,
78 IMG_DOOR_1_GFX_PART_3,
83 IMG_DOOR_1_GFX_PART_4,
88 IMG_DOOR_1_GFX_PART_5,
93 IMG_DOOR_1_GFX_PART_6,
98 IMG_DOOR_1_GFX_PART_7,
103 IMG_DOOR_1_GFX_PART_8,
109 IMG_DOOR_2_GFX_PART_1,
114 IMG_DOOR_2_GFX_PART_2,
119 IMG_DOOR_2_GFX_PART_3,
124 IMG_DOOR_2_GFX_PART_4,
129 IMG_DOOR_2_GFX_PART_5,
134 IMG_DOOR_2_GFX_PART_6,
139 IMG_DOOR_2_GFX_PART_7,
144 IMG_DOOR_2_GFX_PART_8,
150 IMG_BACKGROUND_PANEL,
167 /* forward declaration for internal use */
168 static void UnmapToolButtons();
169 static void HandleToolButtons(struct GadgetInfo *);
170 static int el_act_dir2crm(int, int, int);
171 static int el_act2crm(int, int);
173 static struct GadgetInfo *tool_gadget[NUM_TOOL_BUTTONS];
174 static int request_gadget_id = -1;
176 static char *print_if_not_empty(int element)
178 static char *s = NULL;
179 char *token_name = element_info[element].token_name;
184 s = checked_malloc(strlen(token_name) + 10 + 1);
186 if (element != EL_EMPTY)
187 sprintf(s, "%d\t['%s']", element, token_name);
189 sprintf(s, "%d", element);
194 void DumpTile(int x, int y)
199 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
205 printf_line("-", 79);
206 printf("Field Info: SCREEN(%d, %d), LEVEL(%d, %d)\n", sx, sy, x, y);
207 printf_line("-", 79);
209 if (!IN_LEV_FIELD(x, y))
211 printf("(not in level field)\n");
217 printf(" Feld: %d\t['%s']\n", Feld[x][y],
218 element_info[Feld[x][y]].token_name);
219 printf(" Back: %s\n", print_if_not_empty(Back[x][y]));
220 printf(" Store: %s\n", print_if_not_empty(Store[x][y]));
221 printf(" Store2: %s\n", print_if_not_empty(Store2[x][y]));
222 printf(" StorePlayer: %s\n", print_if_not_empty(StorePlayer[x][y]));
223 printf(" MovPos: %d\n", MovPos[x][y]);
224 printf(" MovDir: %d\n", MovDir[x][y]);
225 printf(" MovDelay: %d\n", MovDelay[x][y]);
226 printf(" ChangeDelay: %d\n", ChangeDelay[x][y]);
227 printf(" CustomValue: %d\n", CustomValue[x][y]);
228 printf(" GfxElement: %d\n", GfxElement[x][y]);
229 printf(" GfxAction: %d\n", GfxAction[x][y]);
230 printf(" GfxFrame: %d\n", GfxFrame[x][y]);
234 void SetDrawtoField(int mode)
236 if (mode == DRAW_FIELDBUFFER)
242 BX2 = SCR_FIELDX + 1;
243 BY2 = SCR_FIELDY + 1;
245 drawto_field = fieldbuffer;
247 else /* DRAW_BACKBUFFER */
253 BX2 = SCR_FIELDX - 1;
254 BY2 = SCR_FIELDY - 1;
256 drawto_field = backbuffer;
260 static void RedrawPlayfield_RND()
262 if (game.envelope_active)
265 DrawLevel(REDRAW_ALL);
269 void RedrawPlayfield()
271 if (game_status != GAME_MODE_PLAYING)
274 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
275 RedrawPlayfield_EM(TRUE);
276 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
277 RedrawPlayfield_SP(TRUE);
278 else if (level.game_engine_type == GAME_ENGINE_TYPE_RND)
279 RedrawPlayfield_RND();
281 BlitScreenToBitmap(backbuffer);
283 BlitBitmap(drawto, window, gfx.sx, gfx.sy, gfx.sxsize, gfx.sysize,
287 void DrawMaskedBorder_Rect(int x, int y, int width, int height)
289 Bitmap *bitmap = graphic_info[IMG_GLOBAL_BORDER].bitmap;
291 BlitBitmapMasked(bitmap, backbuffer, x, y, width, height, x, y);
294 void DrawMaskedBorder_FIELD()
296 if (global.border_status >= GAME_MODE_TITLE &&
297 global.border_status <= GAME_MODE_PLAYING &&
298 border.draw_masked[global.border_status])
299 DrawMaskedBorder_Rect(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
302 void DrawMaskedBorder_DOOR_1()
304 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
305 (global.border_status != GAME_MODE_EDITOR ||
306 border.draw_masked[GFX_SPECIAL_ARG_EDITOR]))
307 DrawMaskedBorder_Rect(DX, DY, DXSIZE, DYSIZE);
310 void DrawMaskedBorder_DOOR_2()
312 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
313 global.border_status != GAME_MODE_EDITOR)
314 DrawMaskedBorder_Rect(VX, VY, VXSIZE, VYSIZE);
317 void DrawMaskedBorder_DOOR_3()
319 /* currently not available */
322 void DrawMaskedBorder_ALL()
324 DrawMaskedBorder_FIELD();
325 DrawMaskedBorder_DOOR_1();
326 DrawMaskedBorder_DOOR_2();
327 DrawMaskedBorder_DOOR_3();
330 void DrawMaskedBorder(int redraw_mask)
332 /* never draw masked screen borders on borderless screens */
333 if (effectiveGameStatus() == GAME_MODE_LOADING ||
334 effectiveGameStatus() == GAME_MODE_TITLE)
337 if (redraw_mask & REDRAW_ALL)
338 DrawMaskedBorder_ALL();
341 if (redraw_mask & REDRAW_FIELD)
342 DrawMaskedBorder_FIELD();
343 if (redraw_mask & REDRAW_DOOR_1)
344 DrawMaskedBorder_DOOR_1();
345 if (redraw_mask & REDRAW_DOOR_2)
346 DrawMaskedBorder_DOOR_2();
347 if (redraw_mask & REDRAW_DOOR_3)
348 DrawMaskedBorder_DOOR_3();
352 void BlitScreenToBitmap_RND(Bitmap *target_bitmap)
354 int fx = FX, fy = FY;
355 int full_lev_fieldx = lev_fieldx + (BorderElement != EL_EMPTY ? 2 : 0);
356 int full_lev_fieldy = lev_fieldy + (BorderElement != EL_EMPTY ? 2 : 0);
358 int dx = (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
359 int dy = (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
360 int dx_var = dx * TILESIZE_VAR / TILESIZE;
361 int dy_var = dy * TILESIZE_VAR / TILESIZE;
364 ffx = (scroll_x - SBX_Left) * TILEX_VAR + dx_var;
365 ffy = (scroll_y - SBY_Upper) * TILEY_VAR + dy_var;
367 if (EVEN(SCR_FIELDX))
369 if (ffx < SBX_Right * TILEX_VAR + TILEX_VAR / 2 + TILEX_VAR)
370 fx += dx_var - MIN(ffx, TILEX_VAR / 2) + TILEX_VAR;
372 fx += (dx_var > 0 ? TILEX_VAR : 0);
379 if (EVEN(SCR_FIELDY))
381 if (ffy < SBY_Lower * TILEY_VAR + TILEY_VAR / 2 + TILEY_VAR)
382 fy += dy_var - MIN(ffy, TILEY_VAR / 2) + TILEY_VAR;
384 fy += (dy_var > 0 ? TILEY_VAR : 0);
391 if (full_lev_fieldx <= SCR_FIELDX)
393 if (EVEN(SCR_FIELDX))
394 fx = 2 * TILEX_VAR - (ODD(lev_fieldx) ? TILEX_VAR / 2 : 0);
396 fx = 2 * TILEX_VAR - (EVEN(lev_fieldx) ? TILEX_VAR / 2 : 0);
399 if (full_lev_fieldy <= SCR_FIELDY)
401 if (EVEN(SCR_FIELDY))
402 fy = 2 * TILEY_VAR - (ODD(lev_fieldy) ? TILEY_VAR / 2 : 0);
404 fy = 2 * TILEY_VAR - (EVEN(lev_fieldy) ? TILEY_VAR / 2 : 0);
407 BlitBitmap(drawto_field, target_bitmap, fx, fy, SXSIZE, SYSIZE, SX, SY);
410 void BlitScreenToBitmap(Bitmap *target_bitmap)
412 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
413 BlitScreenToBitmap_EM(target_bitmap);
414 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
415 BlitScreenToBitmap_SP(target_bitmap);
416 else if (level.game_engine_type == GAME_ENGINE_TYPE_RND)
417 BlitScreenToBitmap_RND(target_bitmap);
419 redraw_mask |= REDRAW_FIELD;
422 void DrawFramesPerSecond()
425 int font_nr = FONT_TEXT_2;
426 int font_width = getFontWidth(font_nr);
428 sprintf(text, "%04.1f fps", global.frames_per_second);
430 DrawTextExt(backbuffer, WIN_XSIZE - font_width * strlen(text), 0, text,
431 font_nr, BLIT_OPAQUE);
436 if (redraw_mask == REDRAW_NONE)
439 // draw masked border to all viewports, if defined
440 DrawMaskedBorder(redraw_mask);
442 // draw frames per second (only if debug mode is enabled)
443 if (redraw_mask & REDRAW_FPS)
444 DrawFramesPerSecond();
446 // redraw complete window if both playfield and (some) doors need redraw
447 if (redraw_mask & REDRAW_FIELD && redraw_mask & REDRAW_DOORS)
448 redraw_mask = REDRAW_ALL;
450 /* although redrawing the whole window would be fine for normal gameplay,
451 being able to only redraw the playfield is required for deactivating
452 certain drawing areas (mainly playfield) to work, which is needed for
453 warp-forward to be fast enough (by skipping redraw of most frames) */
455 if (redraw_mask & REDRAW_ALL)
457 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
459 else if (redraw_mask & REDRAW_FIELD)
461 BlitBitmap(backbuffer, window,
462 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
464 else if (redraw_mask & REDRAW_DOORS)
466 if (redraw_mask & REDRAW_DOOR_1)
467 BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
469 if (redraw_mask & REDRAW_DOOR_2)
470 BlitBitmap(backbuffer, window, VX, VY, VXSIZE, VYSIZE, VX, VY);
472 if (redraw_mask & REDRAW_DOOR_3)
473 BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
476 redraw_mask = REDRAW_NONE;
479 static void FadeCrossSaveBackbuffer()
481 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
484 static void FadeExt(int fade_mask, int fade_mode, int fade_type)
486 static int fade_type_skip = FADE_TYPE_NONE;
487 void (*draw_border_function)(void) = NULL;
488 Bitmap *bitmap = (fade_mode & FADE_TYPE_TRANSFORM ? bitmap_db_cross : NULL);
489 int x, y, width, height;
490 int fade_delay, post_delay;
492 if (fade_type == FADE_TYPE_FADE_OUT)
494 if (fade_type_skip != FADE_TYPE_NONE)
496 /* skip all fade operations until specified fade operation */
497 if (fade_type & fade_type_skip)
498 fade_type_skip = FADE_TYPE_NONE;
503 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
505 FadeCrossSaveBackbuffer();
511 redraw_mask |= fade_mask;
513 if (fade_type == FADE_TYPE_SKIP)
515 fade_type_skip = fade_mode;
520 fade_delay = fading.fade_delay;
521 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
523 if (fade_type_skip != FADE_TYPE_NONE)
525 /* skip all fade operations until specified fade operation */
526 if (fade_type & fade_type_skip)
527 fade_type_skip = FADE_TYPE_NONE;
532 if (global.autoplay_leveldir)
537 if (fade_mask == REDRAW_FIELD)
542 height = FULL_SYSIZE;
544 if (border.draw_masked_when_fading)
545 draw_border_function = DrawMaskedBorder_FIELD; /* update when fading */
547 DrawMaskedBorder_FIELD(); /* draw once */
549 else /* REDRAW_ALL */
557 if (!setup.fade_screens ||
559 fading.fade_mode == FADE_MODE_NONE)
561 if (fade_mode == FADE_MODE_FADE_OUT)
564 BlitBitmap(backbuffer, window, x, y, width, height, x, y);
566 redraw_mask &= ~fade_mask;
571 FadeRectangle(bitmap, x, y, width, height, fade_mode, fade_delay, post_delay,
572 draw_border_function);
574 redraw_mask &= ~fade_mask;
577 void FadeIn(int fade_mask)
579 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
580 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_IN);
582 FadeExt(fade_mask, FADE_MODE_FADE_IN, FADE_TYPE_FADE_IN);
585 void FadeOut(int fade_mask)
587 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
588 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_OUT);
590 FadeExt(fade_mask, FADE_MODE_FADE_OUT, FADE_TYPE_FADE_OUT);
592 global.border_status = game_status;
595 static void FadeSetLeaveNext(struct TitleFadingInfo fading_leave, boolean set)
597 static struct TitleFadingInfo fading_leave_stored;
600 fading_leave_stored = fading_leave;
602 fading = fading_leave_stored;
605 void FadeSetEnterMenu()
607 fading = menu.enter_menu;
609 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
612 void FadeSetLeaveMenu()
614 fading = menu.leave_menu;
616 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
619 void FadeSetEnterScreen()
621 fading = menu.enter_screen[game_status];
623 FadeSetLeaveNext(menu.leave_screen[game_status], TRUE); /* store */
626 void FadeSetNextScreen()
628 fading = menu.next_screen;
630 // (do not overwrite fade mode set by FadeSetEnterScreen)
631 // FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
634 void FadeSetLeaveScreen()
636 FadeSetLeaveNext(menu.leave_screen[game_status], FALSE); /* recall */
639 void FadeSetFromType(int type)
641 if (type & TYPE_ENTER_SCREEN)
642 FadeSetEnterScreen();
643 else if (type & TYPE_ENTER)
645 else if (type & TYPE_LEAVE)
649 void FadeSetDisabled()
651 static struct TitleFadingInfo fading_none = { FADE_MODE_NONE, -1, -1, -1 };
653 fading = fading_none;
656 void FadeSkipNextFadeIn()
658 FadeExt(0, FADE_MODE_SKIP_FADE_IN, FADE_TYPE_SKIP);
661 void FadeSkipNextFadeOut()
663 FadeExt(0, FADE_MODE_SKIP_FADE_OUT, FADE_TYPE_SKIP);
666 void SetWindowBackgroundImageIfDefined(int graphic)
668 if (graphic_info[graphic].bitmap)
669 SetWindowBackgroundBitmap(graphic_info[graphic].bitmap);
672 void SetMainBackgroundImageIfDefined(int graphic)
674 if (graphic_info[graphic].bitmap)
675 SetMainBackgroundBitmap(graphic_info[graphic].bitmap);
678 void SetDoorBackgroundImageIfDefined(int graphic)
680 if (graphic_info[graphic].bitmap)
681 SetDoorBackgroundBitmap(graphic_info[graphic].bitmap);
684 void SetWindowBackgroundImage(int graphic)
686 SetWindowBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
687 graphic_info[graphic].bitmap ?
688 graphic_info[graphic].bitmap :
689 graphic_info[IMG_BACKGROUND].bitmap);
692 void SetMainBackgroundImage(int graphic)
694 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
695 graphic_info[graphic].bitmap ?
696 graphic_info[graphic].bitmap :
697 graphic_info[IMG_BACKGROUND].bitmap);
700 void SetDoorBackgroundImage(int graphic)
702 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
703 graphic_info[graphic].bitmap ?
704 graphic_info[graphic].bitmap :
705 graphic_info[IMG_BACKGROUND].bitmap);
708 void SetPanelBackground()
710 struct GraphicInfo *gfx = &graphic_info[IMG_BACKGROUND_PANEL];
712 BlitBitmapTiled(gfx->bitmap, bitmap_db_panel, gfx->src_x, gfx->src_y,
713 gfx->width, gfx->height, 0, 0, DXSIZE, DYSIZE);
715 SetDoorBackgroundBitmap(bitmap_db_panel);
718 void DrawBackground(int x, int y, int width, int height)
720 /* "drawto" might still point to playfield buffer here (hall of fame) */
721 ClearRectangleOnBackground(backbuffer, x, y, width, height);
723 if (IN_GFX_FIELD_FULL(x, y))
724 redraw_mask |= REDRAW_FIELD;
725 else if (IN_GFX_DOOR_1(x, y))
726 redraw_mask |= REDRAW_DOOR_1;
727 else if (IN_GFX_DOOR_2(x, y))
728 redraw_mask |= REDRAW_DOOR_2;
729 else if (IN_GFX_DOOR_3(x, y))
730 redraw_mask |= REDRAW_DOOR_3;
733 void DrawBackgroundForFont(int x, int y, int width, int height, int font_nr)
735 struct FontBitmapInfo *font = getFontBitmapInfo(font_nr);
737 if (font->bitmap == NULL)
740 DrawBackground(x, y, width, height);
743 void DrawBackgroundForGraphic(int x, int y, int width, int height, int graphic)
745 struct GraphicInfo *g = &graphic_info[graphic];
747 if (g->bitmap == NULL)
750 DrawBackground(x, y, width, height);
755 /* !!! "drawto" might still point to playfield buffer here (see above) !!! */
756 /* (when entering hall of fame after playing) */
757 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
759 /* !!! maybe this should be done before clearing the background !!! */
760 if (game_status == GAME_MODE_PLAYING)
762 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
763 SetDrawtoField(DRAW_FIELDBUFFER);
767 SetDrawtoField(DRAW_BACKBUFFER);
771 void MarkTileDirty(int x, int y)
773 redraw_mask |= REDRAW_FIELD;
776 void SetBorderElement()
780 BorderElement = EL_EMPTY;
782 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
784 for (x = 0; x < lev_fieldx; x++)
786 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
787 BorderElement = EL_STEELWALL;
789 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
795 void FloodFillLevel(int from_x, int from_y, int fill_element,
796 short field[MAX_LEV_FIELDX][MAX_LEV_FIELDY],
797 int max_fieldx, int max_fieldy)
801 static int check[4][2] = { { -1, 0 }, { 0, -1 }, { 1, 0 }, { 0, 1 } };
802 static int safety = 0;
804 /* check if starting field still has the desired content */
805 if (field[from_x][from_y] == fill_element)
810 if (safety > max_fieldx * max_fieldy)
811 Error(ERR_EXIT, "Something went wrong in 'FloodFill()'. Please debug.");
813 old_element = field[from_x][from_y];
814 field[from_x][from_y] = fill_element;
816 for (i = 0; i < 4; i++)
818 x = from_x + check[i][0];
819 y = from_y + check[i][1];
821 if (IN_FIELD(x, y, max_fieldx, max_fieldy) && field[x][y] == old_element)
822 FloodFillLevel(x, y, fill_element, field, max_fieldx, max_fieldy);
828 void SetRandomAnimationValue(int x, int y)
830 gfx.anim_random_frame = GfxRandom[x][y];
833 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
835 /* animation synchronized with global frame counter, not move position */
836 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
837 sync_frame = FrameCounter;
839 return getAnimationFrame(graphic_info[graphic].anim_frames,
840 graphic_info[graphic].anim_delay,
841 graphic_info[graphic].anim_mode,
842 graphic_info[graphic].anim_start_frame,
846 void getSizedGraphicSourceExt(int graphic, int frame, int tilesize,
847 Bitmap **bitmap, int *x, int *y,
848 boolean get_backside)
850 struct GraphicInfo *g = &graphic_info[graphic];
851 Bitmap *src_bitmap = g->bitmap;
852 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
853 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
854 int tilesize_capped = MIN(MAX(1, tilesize), TILESIZE);
856 // if no in-game graphics defined, always use standard graphic size
857 if (g->bitmaps[IMG_BITMAP_GAME] == NULL)
860 if (tilesize == gfx.standard_tile_size)
861 src_bitmap = g->bitmaps[IMG_BITMAP_STANDARD];
862 else if (tilesize == game.tile_size)
863 src_bitmap = g->bitmaps[IMG_BITMAP_GAME];
865 src_bitmap = g->bitmaps[IMG_BITMAP_1x1 - log_2(tilesize_capped)];
867 if (g->offset_y == 0) /* frames are ordered horizontally */
869 int max_width = g->anim_frames_per_line * g->width;
870 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
872 src_x = pos % max_width;
873 src_y = src_y % g->height + pos / max_width * g->height;
875 else if (g->offset_x == 0) /* frames are ordered vertically */
877 int max_height = g->anim_frames_per_line * g->height;
878 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
880 src_x = src_x % g->width + pos / max_height * g->width;
881 src_y = pos % max_height;
883 else /* frames are ordered diagonally */
885 src_x = src_x + frame * g->offset_x;
886 src_y = src_y + frame * g->offset_y;
889 *bitmap = src_bitmap;
890 *x = src_x * tilesize / TILESIZE;
891 *y = src_y * tilesize / TILESIZE;
894 void getFixedGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
895 int *x, int *y, boolean get_backside)
897 getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y,
901 void getSizedGraphicSource(int graphic, int frame, int tilesize,
902 Bitmap **bitmap, int *x, int *y)
904 getSizedGraphicSourceExt(graphic, frame, tilesize, bitmap, x, y, FALSE);
907 void getFixedGraphicSource(int graphic, int frame,
908 Bitmap **bitmap, int *x, int *y)
910 getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y, FALSE);
913 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
915 getSizedGraphicSource(graphic, 0, MINI_TILESIZE, bitmap, x, y);
918 inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
919 int *x, int *y, boolean get_backside)
921 struct GraphicInfo *g = &graphic_info[graphic];
922 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
923 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
925 if (TILESIZE_VAR != TILESIZE)
926 return getSizedGraphicSourceExt(graphic, frame, TILESIZE_VAR, bitmap, x, y,
931 if (g->offset_y == 0) /* frames are ordered horizontally */
933 int max_width = g->anim_frames_per_line * g->width;
934 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
936 *x = pos % max_width;
937 *y = src_y % g->height + pos / max_width * g->height;
939 else if (g->offset_x == 0) /* frames are ordered vertically */
941 int max_height = g->anim_frames_per_line * g->height;
942 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
944 *x = src_x % g->width + pos / max_height * g->width;
945 *y = pos % max_height;
947 else /* frames are ordered diagonally */
949 *x = src_x + frame * g->offset_x;
950 *y = src_y + frame * g->offset_y;
954 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
956 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
959 void DrawGraphic(int x, int y, int graphic, int frame)
962 if (!IN_SCR_FIELD(x, y))
964 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
965 printf("DrawGraphic(): This should never happen!\n");
970 DrawGraphicExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR, graphic,
976 void DrawFixedGraphic(int x, int y, int graphic, int frame)
979 if (!IN_SCR_FIELD(x, y))
981 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
982 printf("DrawGraphic(): This should never happen!\n");
987 DrawFixedGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic,
992 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
998 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1000 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX_VAR, TILEY_VAR, x, y);
1003 void DrawFixedGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1009 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1010 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
1013 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
1016 if (!IN_SCR_FIELD(x, y))
1018 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1019 printf("DrawGraphicThruMask(): This should never happen!\n");
1024 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
1027 MarkTileDirty(x, y);
1030 void DrawFixedGraphicThruMask(int x, int y, int graphic, int frame)
1033 if (!IN_SCR_FIELD(x, y))
1035 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1036 printf("DrawGraphicThruMask(): This should never happen!\n");
1041 DrawFixedGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
1043 MarkTileDirty(x, y);
1046 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
1052 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1054 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX_VAR, TILEY_VAR,
1058 void DrawFixedGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y,
1059 int graphic, int frame)
1061 struct GraphicInfo *g = &graphic_info[graphic];
1065 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1067 BlitBitmapMasked(src_bitmap, d, src_x, src_y, g->width, g->height,
1071 void DrawSizedGraphic(int x, int y, int graphic, int frame, int tilesize)
1073 DrawSizedGraphicExt(drawto, SX + x * tilesize, SY + y * tilesize, graphic,
1075 MarkTileDirty(x / tilesize, y / tilesize);
1078 void DrawSizedGraphicExt(DrawBuffer *d, int x, int y, int graphic, int frame,
1084 getSizedGraphicSource(graphic, frame, tilesize, &src_bitmap, &src_x, &src_y);
1085 BlitBitmap(src_bitmap, d, src_x, src_y, tilesize, tilesize, x, y);
1088 void DrawMiniGraphic(int x, int y, int graphic)
1090 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
1091 MarkTileDirty(x / 2, y / 2);
1094 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
1099 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1100 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
1103 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
1104 int graphic, int frame,
1105 int cut_mode, int mask_mode)
1110 int width = TILEX, height = TILEY;
1113 if (dx || dy) /* shifted graphic */
1115 if (x < BX1) /* object enters playfield from the left */
1122 else if (x > BX2) /* object enters playfield from the right */
1128 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
1134 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
1136 else if (dx) /* general horizontal movement */
1137 MarkTileDirty(x + SIGN(dx), y);
1139 if (y < BY1) /* object enters playfield from the top */
1141 if (cut_mode==CUT_BELOW) /* object completely above top border */
1149 else if (y > BY2) /* object enters playfield from the bottom */
1155 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
1161 else if (dy > 0 && cut_mode == CUT_ABOVE)
1163 if (y == BY2) /* object completely above bottom border */
1169 MarkTileDirty(x, y + 1);
1170 } /* object leaves playfield to the bottom */
1171 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1173 else if (dy) /* general vertical movement */
1174 MarkTileDirty(x, y + SIGN(dy));
1178 if (!IN_SCR_FIELD(x, y))
1180 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1181 printf("DrawGraphicShifted(): This should never happen!\n");
1186 width = width * TILESIZE_VAR / TILESIZE;
1187 height = height * TILESIZE_VAR / TILESIZE;
1188 cx = cx * TILESIZE_VAR / TILESIZE;
1189 cy = cy * TILESIZE_VAR / TILESIZE;
1190 dx = dx * TILESIZE_VAR / TILESIZE;
1191 dy = dy * TILESIZE_VAR / TILESIZE;
1193 if (width > 0 && height > 0)
1195 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1200 dst_x = FX + x * TILEX_VAR + dx;
1201 dst_y = FY + y * TILEY_VAR + dy;
1203 if (mask_mode == USE_MASKING)
1204 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1207 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1210 MarkTileDirty(x, y);
1214 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
1215 int graphic, int frame,
1216 int cut_mode, int mask_mode)
1221 int width = TILEX_VAR, height = TILEY_VAR;
1224 int x2 = x + SIGN(dx);
1225 int y2 = y + SIGN(dy);
1227 /* movement with two-tile animations must be sync'ed with movement position,
1228 not with current GfxFrame (which can be higher when using slow movement) */
1229 int anim_pos = (dx ? ABS(dx) : ABS(dy));
1230 int anim_frames = graphic_info[graphic].anim_frames;
1232 /* (we also need anim_delay here for movement animations with less frames) */
1233 int anim_delay = graphic_info[graphic].anim_delay;
1234 int sync_frame = anim_pos * anim_frames * anim_delay / TILESIZE;
1236 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
1237 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
1239 /* re-calculate animation frame for two-tile movement animation */
1240 frame = getGraphicAnimationFrame(graphic, sync_frame);
1242 /* check if movement start graphic inside screen area and should be drawn */
1243 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
1245 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
1247 dst_x = FX + x1 * TILEX_VAR;
1248 dst_y = FY + y1 * TILEY_VAR;
1250 if (mask_mode == USE_MASKING)
1251 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1254 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1257 MarkTileDirty(x1, y1);
1260 /* check if movement end graphic inside screen area and should be drawn */
1261 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
1263 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
1265 dst_x = FX + x2 * TILEX_VAR;
1266 dst_y = FY + y2 * TILEY_VAR;
1268 if (mask_mode == USE_MASKING)
1269 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1272 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1275 MarkTileDirty(x2, y2);
1279 static void DrawGraphicShifted(int x, int y, int dx, int dy,
1280 int graphic, int frame,
1281 int cut_mode, int mask_mode)
1285 DrawGraphic(x, y, graphic, frame);
1290 if (graphic_info[graphic].double_movement) /* EM style movement images */
1291 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1293 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1296 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1297 int frame, int cut_mode)
1299 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
1302 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1303 int cut_mode, int mask_mode)
1305 int lx = LEVELX(x), ly = LEVELY(y);
1309 if (IN_LEV_FIELD(lx, ly))
1311 SetRandomAnimationValue(lx, ly);
1313 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
1314 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1316 /* do not use double (EM style) movement graphic when not moving */
1317 if (graphic_info[graphic].double_movement && !dx && !dy)
1319 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
1320 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1323 else /* border element */
1325 graphic = el2img(element);
1326 frame = getGraphicAnimationFrame(graphic, -1);
1329 if (element == EL_EXPANDABLE_WALL)
1331 boolean left_stopped = FALSE, right_stopped = FALSE;
1333 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1334 left_stopped = TRUE;
1335 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1336 right_stopped = TRUE;
1338 if (left_stopped && right_stopped)
1340 else if (left_stopped)
1342 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1343 frame = graphic_info[graphic].anim_frames - 1;
1345 else if (right_stopped)
1347 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1348 frame = graphic_info[graphic].anim_frames - 1;
1353 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1354 else if (mask_mode == USE_MASKING)
1355 DrawGraphicThruMask(x, y, graphic, frame);
1357 DrawGraphic(x, y, graphic, frame);
1360 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1361 int cut_mode, int mask_mode)
1363 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1364 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1365 cut_mode, mask_mode);
1368 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1371 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1374 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1377 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1380 void DrawLevelElementThruMask(int x, int y, int element)
1382 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1385 void DrawLevelFieldThruMask(int x, int y)
1387 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1390 /* !!! implementation of quicksand is totally broken !!! */
1391 #define IS_CRUMBLED_TILE(x, y, e) \
1392 (GFX_CRUMBLED(e) && (!IN_LEV_FIELD(x, y) || \
1393 !IS_MOVING(x, y) || \
1394 (e) == EL_QUICKSAND_EMPTYING || \
1395 (e) == EL_QUICKSAND_FAST_EMPTYING))
1397 static void DrawLevelFieldCrumbledInnerCorners(int x, int y, int dx, int dy,
1402 int width, height, cx, cy;
1403 int sx = SCREENX(x), sy = SCREENY(y);
1404 int crumbled_border_size = graphic_info[graphic].border_size;
1407 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1409 for (i = 1; i < 4; i++)
1411 int dxx = (i & 1 ? dx : 0);
1412 int dyy = (i & 2 ? dy : 0);
1415 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1418 /* check if neighbour field is of same crumble type */
1419 boolean same = (IS_CRUMBLED_TILE(xx, yy, element) &&
1420 graphic_info[graphic].class ==
1421 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class);
1423 /* return if check prevents inner corner */
1424 if (same == (dxx == dx && dyy == dy))
1428 /* if we reach this point, we have an inner corner */
1430 getGraphicSource(graphic, 1, &src_bitmap, &src_x, &src_y);
1432 width = crumbled_border_size * TILESIZE_VAR / TILESIZE;
1433 height = crumbled_border_size * TILESIZE_VAR / TILESIZE;
1434 cx = (dx > 0 ? TILESIZE_VAR - width : 0);
1435 cy = (dy > 0 ? TILESIZE_VAR - height : 0);
1437 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1438 width, height, FX + sx * TILEX_VAR + cx, FY + sy * TILEY_VAR + cy);
1441 static void DrawLevelFieldCrumbledBorders(int x, int y, int graphic, int frame,
1446 int width, height, bx, by, cx, cy;
1447 int sx = SCREENX(x), sy = SCREENY(y);
1448 int crumbled_border_size = graphic_info[graphic].border_size;
1449 int crumbled_border_size_var = crumbled_border_size * TILESIZE_VAR / TILESIZE;
1450 int crumbled_border_pos_var = TILESIZE_VAR - crumbled_border_size_var;
1453 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1455 /* draw simple, sloppy, non-corner-accurate crumbled border */
1457 width = (dir == 1 || dir == 2 ? crumbled_border_size_var : TILESIZE_VAR);
1458 height = (dir == 0 || dir == 3 ? crumbled_border_size_var : TILESIZE_VAR);
1459 cx = (dir == 2 ? crumbled_border_pos_var : 0);
1460 cy = (dir == 3 ? crumbled_border_pos_var : 0);
1462 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy, width, height,
1463 FX + sx * TILEX_VAR + cx,
1464 FY + sy * TILEY_VAR + cy);
1466 /* (remaining middle border part must be at least as big as corner part) */
1467 if (!(graphic_info[graphic].style & STYLE_ACCURATE_BORDERS) ||
1468 crumbled_border_size >= TILESIZE / 3)
1471 /* correct corners of crumbled border, if needed */
1473 for (i = -1; i <= 1; i += 2)
1475 int xx = x + (dir == 0 || dir == 3 ? i : 0);
1476 int yy = y + (dir == 1 || dir == 2 ? i : 0);
1477 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1480 /* check if neighbour field is of same crumble type */
1481 if (IS_CRUMBLED_TILE(xx, yy, element) &&
1482 graphic_info[graphic].class ==
1483 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1485 /* no crumbled corner, but continued crumbled border */
1487 int c1 = (dir == 2 || dir == 3 ? crumbled_border_pos_var : 0);
1488 int c2 = (i == 1 ? crumbled_border_pos_var : 0);
1489 int b1 = (i == 1 ? crumbled_border_size_var :
1490 TILESIZE_VAR - 2 * crumbled_border_size_var);
1492 width = crumbled_border_size_var;
1493 height = crumbled_border_size_var;
1495 if (dir == 1 || dir == 2)
1510 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
1512 FX + sx * TILEX_VAR + cx,
1513 FY + sy * TILEY_VAR + cy);
1518 static void DrawLevelFieldCrumbledExt(int x, int y, int graphic, int frame)
1520 int sx = SCREENX(x), sy = SCREENY(y);
1523 static int xy[4][2] =
1531 if (!IN_LEV_FIELD(x, y))
1534 element = TILE_GFX_ELEMENT(x, y);
1536 /* crumble field itself */
1537 if (IS_CRUMBLED_TILE(x, y, element))
1539 if (!IN_SCR_FIELD(sx, sy))
1542 for (i = 0; i < 4; i++)
1544 int xx = x + xy[i][0];
1545 int yy = y + xy[i][1];
1547 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1550 /* check if neighbour field is of same crumble type */
1551 if (IS_CRUMBLED_TILE(xx, yy, element) &&
1552 graphic_info[graphic].class ==
1553 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1556 DrawLevelFieldCrumbledBorders(x, y, graphic, frame, i);
1559 if ((graphic_info[graphic].style & STYLE_INNER_CORNERS) &&
1560 graphic_info[graphic].anim_frames == 2)
1562 for (i = 0; i < 4; i++)
1564 int dx = (i & 1 ? +1 : -1);
1565 int dy = (i & 2 ? +1 : -1);
1567 DrawLevelFieldCrumbledInnerCorners(x, y, dx, dy, graphic);
1571 MarkTileDirty(sx, sy);
1573 else /* center field not crumbled -- crumble neighbour fields */
1575 for (i = 0; i < 4; i++)
1577 int xx = x + xy[i][0];
1578 int yy = y + xy[i][1];
1579 int sxx = sx + xy[i][0];
1580 int syy = sy + xy[i][1];
1582 if (!IN_LEV_FIELD(xx, yy) ||
1583 !IN_SCR_FIELD(sxx, syy))
1586 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
1589 element = TILE_GFX_ELEMENT(xx, yy);
1591 if (!IS_CRUMBLED_TILE(xx, yy, element))
1594 graphic = el_act2crm(element, ACTION_DEFAULT);
1596 DrawLevelFieldCrumbledBorders(xx, yy, graphic, 0, 3 - i);
1598 MarkTileDirty(sxx, syy);
1603 void DrawLevelFieldCrumbled(int x, int y)
1607 if (!IN_LEV_FIELD(x, y))
1610 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1611 GfxElement[x][y] != EL_UNDEFINED &&
1612 GFX_CRUMBLED(GfxElement[x][y]))
1614 DrawLevelFieldCrumbledDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
1619 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
1621 DrawLevelFieldCrumbledExt(x, y, graphic, 0);
1624 void DrawLevelFieldCrumbledDigging(int x, int y, int direction,
1627 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1628 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1629 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1630 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1631 int sx = SCREENX(x), sy = SCREENY(y);
1633 DrawGraphic(sx, sy, graphic1, frame1);
1634 DrawLevelFieldCrumbledExt(x, y, graphic2, frame2);
1637 void DrawLevelFieldCrumbledNeighbours(int x, int y)
1639 int sx = SCREENX(x), sy = SCREENY(y);
1640 static int xy[4][2] =
1649 for (i = 0; i < 4; i++)
1651 int xx = x + xy[i][0];
1652 int yy = y + xy[i][1];
1653 int sxx = sx + xy[i][0];
1654 int syy = sy + xy[i][1];
1656 if (!IN_LEV_FIELD(xx, yy) ||
1657 !IN_SCR_FIELD(sxx, syy) ||
1658 !GFX_CRUMBLED(Feld[xx][yy]) ||
1662 DrawLevelField(xx, yy);
1666 static int getBorderElement(int x, int y)
1670 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1671 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1672 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1673 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1674 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1675 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1676 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1678 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1679 int steel_position = (x == -1 && y == -1 ? 0 :
1680 x == lev_fieldx && y == -1 ? 1 :
1681 x == -1 && y == lev_fieldy ? 2 :
1682 x == lev_fieldx && y == lev_fieldy ? 3 :
1683 x == -1 || x == lev_fieldx ? 4 :
1684 y == -1 || y == lev_fieldy ? 5 : 6);
1686 return border[steel_position][steel_type];
1689 void DrawScreenElement(int x, int y, int element)
1691 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1692 DrawLevelFieldCrumbled(LEVELX(x), LEVELY(y));
1695 void DrawLevelElement(int x, int y, int element)
1697 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1698 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1701 void DrawScreenField(int x, int y)
1703 int lx = LEVELX(x), ly = LEVELY(y);
1704 int element, content;
1706 if (!IN_LEV_FIELD(lx, ly))
1708 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1711 element = getBorderElement(lx, ly);
1713 DrawScreenElement(x, y, element);
1718 element = Feld[lx][ly];
1719 content = Store[lx][ly];
1721 if (IS_MOVING(lx, ly))
1723 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1724 boolean cut_mode = NO_CUTTING;
1726 if (element == EL_QUICKSAND_EMPTYING ||
1727 element == EL_QUICKSAND_FAST_EMPTYING ||
1728 element == EL_MAGIC_WALL_EMPTYING ||
1729 element == EL_BD_MAGIC_WALL_EMPTYING ||
1730 element == EL_DC_MAGIC_WALL_EMPTYING ||
1731 element == EL_AMOEBA_DROPPING)
1732 cut_mode = CUT_ABOVE;
1733 else if (element == EL_QUICKSAND_FILLING ||
1734 element == EL_QUICKSAND_FAST_FILLING ||
1735 element == EL_MAGIC_WALL_FILLING ||
1736 element == EL_BD_MAGIC_WALL_FILLING ||
1737 element == EL_DC_MAGIC_WALL_FILLING)
1738 cut_mode = CUT_BELOW;
1740 if (cut_mode == CUT_ABOVE)
1741 DrawScreenElement(x, y, element);
1743 DrawScreenElement(x, y, EL_EMPTY);
1746 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1747 else if (cut_mode == NO_CUTTING)
1748 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1751 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1753 if (cut_mode == CUT_BELOW &&
1754 IN_LEV_FIELD(lx, ly + 1) && IN_SCR_FIELD(x, y + 1))
1755 DrawLevelElement(lx, ly + 1, element);
1758 if (content == EL_ACID)
1760 int dir = MovDir[lx][ly];
1761 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
1762 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
1764 DrawLevelElementThruMask(newlx, newly, EL_ACID);
1767 else if (IS_BLOCKED(lx, ly))
1772 boolean cut_mode = NO_CUTTING;
1773 int element_old, content_old;
1775 Blocked2Moving(lx, ly, &oldx, &oldy);
1778 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1779 MovDir[oldx][oldy] == MV_RIGHT);
1781 element_old = Feld[oldx][oldy];
1782 content_old = Store[oldx][oldy];
1784 if (element_old == EL_QUICKSAND_EMPTYING ||
1785 element_old == EL_QUICKSAND_FAST_EMPTYING ||
1786 element_old == EL_MAGIC_WALL_EMPTYING ||
1787 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1788 element_old == EL_DC_MAGIC_WALL_EMPTYING ||
1789 element_old == EL_AMOEBA_DROPPING)
1790 cut_mode = CUT_ABOVE;
1792 DrawScreenElement(x, y, EL_EMPTY);
1795 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1797 else if (cut_mode == NO_CUTTING)
1798 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1801 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1804 else if (IS_DRAWABLE(element))
1805 DrawScreenElement(x, y, element);
1807 DrawScreenElement(x, y, EL_EMPTY);
1810 void DrawLevelField(int x, int y)
1812 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1813 DrawScreenField(SCREENX(x), SCREENY(y));
1814 else if (IS_MOVING(x, y))
1818 Moving2Blocked(x, y, &newx, &newy);
1819 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1820 DrawScreenField(SCREENX(newx), SCREENY(newy));
1822 else if (IS_BLOCKED(x, y))
1826 Blocked2Moving(x, y, &oldx, &oldy);
1827 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1828 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1832 void DrawSizedElement(int x, int y, int element, int tilesize)
1836 graphic = el2edimg(element);
1837 DrawSizedGraphic(x, y, graphic, 0, tilesize);
1840 void DrawMiniElement(int x, int y, int element)
1844 graphic = el2edimg(element);
1845 DrawMiniGraphic(x, y, graphic);
1848 void DrawSizedElementOrWall(int sx, int sy, int scroll_x, int scroll_y,
1851 int x = sx + scroll_x, y = sy + scroll_y;
1853 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1854 DrawSizedElement(sx, sy, EL_EMPTY, tilesize);
1855 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1856 DrawSizedElement(sx, sy, Feld[x][y], tilesize);
1858 DrawSizedGraphic(sx, sy, el2edimg(getBorderElement(x, y)), 0, tilesize);
1861 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1863 int x = sx + scroll_x, y = sy + scroll_y;
1865 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1866 DrawMiniElement(sx, sy, EL_EMPTY);
1867 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1868 DrawMiniElement(sx, sy, Feld[x][y]);
1870 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1873 void DrawEnvelopeBackgroundTiles(int graphic, int startx, int starty,
1874 int x, int y, int xsize, int ysize,
1875 int tile_width, int tile_height)
1879 int dst_x = startx + x * tile_width;
1880 int dst_y = starty + y * tile_height;
1881 int width = graphic_info[graphic].width;
1882 int height = graphic_info[graphic].height;
1883 int inner_width_raw = MAX(width - 2 * tile_width, tile_width);
1884 int inner_height_raw = MAX(height - 2 * tile_height, tile_height);
1885 int inner_width = inner_width_raw - (inner_width_raw % tile_width);
1886 int inner_height = inner_height_raw - (inner_height_raw % tile_height);
1887 int inner_sx = (width >= 3 * tile_width ? tile_width : 0);
1888 int inner_sy = (height >= 3 * tile_height ? tile_height : 0);
1889 boolean draw_masked = graphic_info[graphic].draw_masked;
1891 getFixedGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1893 if (src_bitmap == NULL || width < tile_width || height < tile_height)
1895 ClearRectangle(drawto, dst_x, dst_y, tile_width, tile_height);
1899 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - tile_width :
1900 inner_sx + (x - 1) * tile_width % inner_width);
1901 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - tile_height :
1902 inner_sy + (y - 1) * tile_height % inner_height);
1905 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
1908 BlitBitmap(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
1912 void DrawEnvelopeBackground(int graphic, int startx, int starty,
1913 int x, int y, int xsize, int ysize, int font_nr)
1915 int font_width = getFontWidth(font_nr);
1916 int font_height = getFontHeight(font_nr);
1918 DrawEnvelopeBackgroundTiles(graphic, startx, starty, x, y, xsize, ysize,
1919 font_width, font_height);
1922 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
1924 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1925 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1926 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
1927 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1928 boolean no_delay = (tape.warp_forward);
1929 unsigned int anim_delay = 0;
1930 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
1931 int anim_delay_value = (no_delay ? 0 : frame_delay_value) / 2;
1932 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
1933 int font_width = getFontWidth(font_nr);
1934 int font_height = getFontHeight(font_nr);
1935 int max_xsize = level.envelope[envelope_nr].xsize;
1936 int max_ysize = level.envelope[envelope_nr].ysize;
1937 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
1938 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
1939 int xend = max_xsize;
1940 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
1941 int xstep = (xstart < xend ? 1 : 0);
1942 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
1944 int end = MAX(xend - xstart, yend - ystart);
1947 for (i = start; i <= end; i++)
1949 int last_frame = end; // last frame of this "for" loop
1950 int x = xstart + i * xstep;
1951 int y = ystart + i * ystep;
1952 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
1953 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
1954 int sx = SX + (SXSIZE - xsize * font_width) / 2;
1955 int sy = SY + (SYSIZE - ysize * font_height) / 2;
1958 SetDrawtoField(DRAW_FIELDBUFFER);
1960 BlitScreenToBitmap(backbuffer);
1962 SetDrawtoField(DRAW_BACKBUFFER);
1964 for (yy = 0; yy < ysize; yy++)
1965 for (xx = 0; xx < xsize; xx++)
1966 DrawEnvelopeBackground(graphic, sx, sy, xx, yy, xsize, ysize, font_nr);
1968 DrawTextBuffer(sx + font_width, sy + font_height,
1969 level.envelope[envelope_nr].text, font_nr, max_xsize,
1970 xsize - 2, ysize - 2, 0, mask_mode,
1971 level.envelope[envelope_nr].autowrap,
1972 level.envelope[envelope_nr].centered, FALSE);
1974 redraw_mask |= REDRAW_FIELD;
1977 SkipUntilDelayReached(&anim_delay, anim_delay_value, &i, last_frame);
1981 void ShowEnvelope(int envelope_nr)
1983 int element = EL_ENVELOPE_1 + envelope_nr;
1984 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1985 int sound_opening = element_info[element].sound[ACTION_OPENING];
1986 int sound_closing = element_info[element].sound[ACTION_CLOSING];
1987 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1988 boolean no_delay = (tape.warp_forward);
1989 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
1990 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
1991 int anim_mode = graphic_info[graphic].anim_mode;
1992 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
1993 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
1995 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
1997 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
1999 if (anim_mode == ANIM_DEFAULT)
2000 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
2002 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
2005 Delay(wait_delay_value);
2007 WaitForEventToContinue();
2009 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2011 if (anim_mode != ANIM_NONE)
2012 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
2014 if (anim_mode == ANIM_DEFAULT)
2015 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
2017 game.envelope_active = FALSE;
2019 SetDrawtoField(DRAW_FIELDBUFFER);
2021 redraw_mask |= REDRAW_FIELD;
2025 static void setRequestCenterPosition(int *x, int *y)
2027 int sx_center = (request.x != -1 ? request.x : SX + SXSIZE / 2);
2028 int sy_center = (request.y != -1 ? request.y : SY + SYSIZE / 2);
2034 static void setRequestPosition(int *x, int *y, boolean add_border_size)
2036 int border_size = request.border_size;
2037 int sx_center, sy_center;
2040 setRequestCenterPosition(&sx_center, &sy_center);
2042 sx = sx_center - request.width / 2;
2043 sy = sy_center - request.height / 2;
2045 if (add_border_size)
2055 void DrawEnvelopeRequest(char *text)
2057 char *text_final = text;
2058 char *text_door_style = NULL;
2059 int graphic = IMG_BACKGROUND_REQUEST;
2060 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2061 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2062 int font_nr = FONT_REQUEST;
2063 int font_width = getFontWidth(font_nr);
2064 int font_height = getFontHeight(font_nr);
2065 int border_size = request.border_size;
2066 int line_spacing = request.line_spacing;
2067 int line_height = font_height + line_spacing;
2068 int text_width = request.width - 2 * border_size;
2069 int text_height = request.height - 2 * border_size;
2070 int line_length = text_width / font_width;
2071 int max_lines = text_height / line_height;
2072 int width = request.width;
2073 int height = request.height;
2074 int tile_size = request.step_offset;
2075 int x_steps = width / tile_size;
2076 int y_steps = height / tile_size;
2080 if (request.wrap_single_words)
2082 char *src_text_ptr, *dst_text_ptr;
2084 text_door_style = checked_malloc(2 * strlen(text) + 1);
2086 src_text_ptr = text;
2087 dst_text_ptr = text_door_style;
2089 while (*src_text_ptr)
2091 if (*src_text_ptr == ' ' ||
2092 *src_text_ptr == '?' ||
2093 *src_text_ptr == '!')
2094 *dst_text_ptr++ = '\n';
2096 if (*src_text_ptr != ' ')
2097 *dst_text_ptr++ = *src_text_ptr;
2102 *dst_text_ptr = '\0';
2104 text_final = text_door_style;
2107 setRequestPosition(&sx, &sy, FALSE);
2109 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
2111 for (y = 0; y < y_steps; y++)
2112 for (x = 0; x < x_steps; x++)
2113 DrawEnvelopeBackgroundTiles(graphic, sx, sy,
2114 x, y, x_steps, y_steps,
2115 tile_size, tile_size);
2117 DrawTextBuffer(sx + border_size, sy + border_size, text_final, font_nr,
2118 line_length, -1, max_lines, line_spacing, mask_mode,
2119 request.autowrap, request.centered, FALSE);
2121 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2122 RedrawGadget(tool_gadget[i]);
2124 // store readily prepared envelope request for later use when animating
2125 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2127 if (text_door_style)
2128 free(text_door_style);
2131 void AnimateEnvelopeRequest(int anim_mode, int action)
2133 int graphic = IMG_BACKGROUND_REQUEST;
2134 boolean draw_masked = graphic_info[graphic].draw_masked;
2135 int delay_value_normal = request.step_delay;
2136 int delay_value_fast = delay_value_normal / 2;
2137 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2138 boolean no_delay = (tape.warp_forward);
2139 int delay_value = (ffwd_delay ? delay_value_fast : delay_value_normal);
2140 int anim_delay_value = (no_delay ? 0 : delay_value + 500 * 0) / 2;
2141 unsigned int anim_delay = 0;
2143 int width = request.width;
2144 int height = request.height;
2145 int tile_size = request.step_offset;
2146 int max_xsize = width / tile_size;
2147 int max_ysize = height / tile_size;
2148 int max_xsize_inner = max_xsize - 2;
2149 int max_ysize_inner = max_ysize - 2;
2151 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize_inner : 0);
2152 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize_inner : 0);
2153 int xend = max_xsize_inner;
2154 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize_inner : 0);
2155 int xstep = (xstart < xend ? 1 : 0);
2156 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2158 int end = MAX(xend - xstart, yend - ystart);
2161 if (setup.quick_doors)
2169 if (action == ACTION_OPENING)
2170 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2171 else if (action == ACTION_CLOSING)
2172 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2175 for (i = start; i <= end; i++)
2177 int last_frame = end; // last frame of this "for" loop
2178 int x = xstart + i * xstep;
2179 int y = ystart + i * ystep;
2180 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2181 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2182 int xsize_size_left = (xsize - 1) * tile_size;
2183 int ysize_size_top = (ysize - 1) * tile_size;
2184 int max_xsize_pos = (max_xsize - 1) * tile_size;
2185 int max_ysize_pos = (max_ysize - 1) * tile_size;
2186 int sx_center, sy_center;
2191 setRequestCenterPosition(&sx_center, &sy_center);
2193 src_x = sx_center - width / 2;
2194 src_y = sy_center - height / 2;
2195 dst_x = sx_center - xsize * tile_size / 2;
2196 dst_y = sy_center - ysize * tile_size / 2;
2198 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2200 for (yy = 0; yy < 2; yy++)
2202 for (xx = 0; xx < 2; xx++)
2204 int src_xx = src_x + xx * max_xsize_pos;
2205 int src_yy = src_y + yy * max_ysize_pos;
2206 int dst_xx = dst_x + xx * xsize_size_left;
2207 int dst_yy = dst_y + yy * ysize_size_top;
2208 int xx_size = (xx ? tile_size : xsize_size_left);
2209 int yy_size = (yy ? tile_size : ysize_size_top);
2212 BlitBitmapMasked(bitmap_db_cross, backbuffer,
2213 src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
2215 BlitBitmap(bitmap_db_cross, backbuffer,
2216 src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
2220 redraw_mask |= REDRAW_FIELD;
2225 SkipUntilDelayReached(&anim_delay, anim_delay_value, &i, last_frame);
2229 void ShowEnvelopeRequest(char *text, unsigned int req_state, int action)
2231 int last_game_status = game_status; /* save current game status */
2232 int graphic = IMG_BACKGROUND_REQUEST;
2233 int sound_opening = SND_REQUEST_OPENING;
2234 int sound_closing = SND_REQUEST_CLOSING;
2235 int anim_mode = graphic_info[graphic].anim_mode;
2236 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2237 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2239 if (game_status == GAME_MODE_PLAYING)
2240 BlitScreenToBitmap(backbuffer);
2242 SetDrawtoField(DRAW_BACKBUFFER);
2244 // SetDrawBackgroundMask(REDRAW_NONE);
2246 if (action == ACTION_OPENING)
2248 BlitBitmap(backbuffer, bitmap_db_store, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2250 if (req_state & REQ_ASK)
2252 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2253 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2255 else if (req_state & REQ_CONFIRM)
2257 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2259 else if (req_state & REQ_PLAYER)
2261 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2262 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2263 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2264 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2267 DrawEnvelopeRequest(text);
2269 if (game_status != GAME_MODE_MAIN)
2273 /* force DOOR font inside door area */
2274 game_status = GAME_MODE_PSEUDO_DOOR;
2276 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
2278 if (action == ACTION_OPENING)
2280 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2282 if (anim_mode == ANIM_DEFAULT)
2283 AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_OPENING);
2285 AnimateEnvelopeRequest(main_anim_mode, ACTION_OPENING);
2289 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2291 if (anim_mode != ANIM_NONE)
2292 AnimateEnvelopeRequest(main_anim_mode, ACTION_CLOSING);
2294 if (anim_mode == ANIM_DEFAULT)
2295 AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_CLOSING);
2298 game.envelope_active = FALSE;
2300 game_status = last_game_status; /* restore current game status */
2302 if (action == ACTION_CLOSING)
2304 if (game_status != GAME_MODE_MAIN)
2307 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2310 // SetDrawBackgroundMask(last_draw_background_mask);
2312 redraw_mask |= REDRAW_FIELD;
2314 if (game_status == GAME_MODE_MAIN)
2319 if (action == ACTION_CLOSING &&
2320 game_status == GAME_MODE_PLAYING &&
2321 level.game_engine_type == GAME_ENGINE_TYPE_RND)
2322 SetDrawtoField(DRAW_FIELDBUFFER);
2325 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
2329 int graphic = el2preimg(element);
2331 getSizedGraphicSource(graphic, 0, tilesize, &src_bitmap, &src_x, &src_y);
2332 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
2335 void DrawLevel(int draw_background_mask)
2339 SetMainBackgroundImage(IMG_BACKGROUND_PLAYING);
2340 SetDrawBackgroundMask(draw_background_mask);
2344 for (x = BX1; x <= BX2; x++)
2345 for (y = BY1; y <= BY2; y++)
2346 DrawScreenField(x, y);
2348 redraw_mask |= REDRAW_FIELD;
2351 void DrawSizedLevel(int size_x, int size_y, int scroll_x, int scroll_y,
2356 for (x = 0; x < size_x; x++)
2357 for (y = 0; y < size_y; y++)
2358 DrawSizedElementOrWall(x, y, scroll_x, scroll_y, tilesize);
2360 redraw_mask |= REDRAW_FIELD;
2363 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
2367 for (x = 0; x < size_x; x++)
2368 for (y = 0; y < size_y; y++)
2369 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
2371 redraw_mask |= REDRAW_FIELD;
2374 static void DrawPreviewLevelPlayfieldExt(int from_x, int from_y)
2376 boolean show_level_border = (BorderElement != EL_EMPTY);
2377 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2378 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2379 int tile_size = preview.tile_size;
2380 int preview_width = preview.xsize * tile_size;
2381 int preview_height = preview.ysize * tile_size;
2382 int real_preview_xsize = MIN(level_xsize, preview.xsize);
2383 int real_preview_ysize = MIN(level_ysize, preview.ysize);
2384 int real_preview_width = real_preview_xsize * tile_size;
2385 int real_preview_height = real_preview_ysize * tile_size;
2386 int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
2387 int dst_y = SY + ALIGNED_YPOS(preview.y, preview_height, preview.valign);
2390 if (!IN_GFX_FIELD_FULL(dst_x, dst_y + preview_height - 1))
2393 DrawBackground(dst_x, dst_y, preview_width, preview_height);
2395 dst_x += (preview_width - real_preview_width) / 2;
2396 dst_y += (preview_height - real_preview_height) / 2;
2398 for (x = 0; x < real_preview_xsize; x++)
2400 for (y = 0; y < real_preview_ysize; y++)
2402 int lx = from_x + x + (show_level_border ? -1 : 0);
2403 int ly = from_y + y + (show_level_border ? -1 : 0);
2404 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
2405 getBorderElement(lx, ly));
2407 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
2408 element, tile_size);
2412 redraw_mask |= REDRAW_FIELD;
2415 #define MICROLABEL_EMPTY 0
2416 #define MICROLABEL_LEVEL_NAME 1
2417 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
2418 #define MICROLABEL_LEVEL_AUTHOR 3
2419 #define MICROLABEL_IMPORTED_FROM_HEAD 4
2420 #define MICROLABEL_IMPORTED_FROM 5
2421 #define MICROLABEL_IMPORTED_BY_HEAD 6
2422 #define MICROLABEL_IMPORTED_BY 7
2424 static int getMaxTextLength(struct TextPosInfo *pos, int font_nr)
2426 int max_text_width = SXSIZE;
2427 int font_width = getFontWidth(font_nr);
2429 if (pos->align == ALIGN_CENTER)
2430 max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
2431 else if (pos->align == ALIGN_RIGHT)
2432 max_text_width = pos->x;
2434 max_text_width = SXSIZE - pos->x;
2436 return max_text_width / font_width;
2439 static void DrawPreviewLevelLabelExt(int mode)
2441 struct TextPosInfo *pos = &menu.main.text.level_info_2;
2442 char label_text[MAX_OUTPUT_LINESIZE + 1];
2443 int max_len_label_text;
2444 int font_nr = pos->font;
2447 if (!IN_GFX_FIELD_FULL(pos->x, pos->y + getFontHeight(pos->font)))
2450 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
2451 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
2452 mode == MICROLABEL_IMPORTED_BY_HEAD)
2453 font_nr = pos->font_alt;
2455 max_len_label_text = getMaxTextLength(pos, font_nr);
2457 if (pos->size != -1)
2458 max_len_label_text = pos->size;
2460 for (i = 0; i < max_len_label_text; i++)
2461 label_text[i] = ' ';
2462 label_text[max_len_label_text] = '\0';
2464 if (strlen(label_text) > 0)
2465 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2468 (mode == MICROLABEL_LEVEL_NAME ? level.name :
2469 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
2470 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
2471 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
2472 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
2473 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
2474 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
2475 max_len_label_text);
2476 label_text[max_len_label_text] = '\0';
2478 if (strlen(label_text) > 0)
2479 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2481 redraw_mask |= REDRAW_FIELD;
2484 static void DrawPreviewLevelExt(boolean restart)
2486 static unsigned int scroll_delay = 0;
2487 static unsigned int label_delay = 0;
2488 static int from_x, from_y, scroll_direction;
2489 static int label_state, label_counter;
2490 unsigned int scroll_delay_value = preview.step_delay;
2491 boolean show_level_border = (BorderElement != EL_EMPTY);
2492 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2493 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2494 int last_game_status = game_status; /* save current game status */
2501 if (preview.anim_mode == ANIM_CENTERED)
2503 if (level_xsize > preview.xsize)
2504 from_x = (level_xsize - preview.xsize) / 2;
2505 if (level_ysize > preview.ysize)
2506 from_y = (level_ysize - preview.ysize) / 2;
2509 from_x += preview.xoffset;
2510 from_y += preview.yoffset;
2512 scroll_direction = MV_RIGHT;
2516 DrawPreviewLevelPlayfieldExt(from_x, from_y);
2517 DrawPreviewLevelLabelExt(label_state);
2519 /* initialize delay counters */
2520 DelayReached(&scroll_delay, 0);
2521 DelayReached(&label_delay, 0);
2523 if (leveldir_current->name)
2525 struct TextPosInfo *pos = &menu.main.text.level_info_1;
2526 char label_text[MAX_OUTPUT_LINESIZE + 1];
2527 int font_nr = pos->font;
2528 int max_len_label_text = getMaxTextLength(pos, font_nr);
2530 if (pos->size != -1)
2531 max_len_label_text = pos->size;
2533 strncpy(label_text, leveldir_current->name, max_len_label_text);
2534 label_text[max_len_label_text] = '\0';
2536 if (IN_GFX_FIELD_FULL(pos->x, pos->y + getFontHeight(pos->font)))
2537 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2540 game_status = last_game_status; /* restore current game status */
2545 /* scroll preview level, if needed */
2546 if (preview.anim_mode != ANIM_NONE &&
2547 (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
2548 DelayReached(&scroll_delay, scroll_delay_value))
2550 switch (scroll_direction)
2555 from_x -= preview.step_offset;
2556 from_x = (from_x < 0 ? 0 : from_x);
2559 scroll_direction = MV_UP;
2563 if (from_x < level_xsize - preview.xsize)
2565 from_x += preview.step_offset;
2566 from_x = (from_x > level_xsize - preview.xsize ?
2567 level_xsize - preview.xsize : from_x);
2570 scroll_direction = MV_DOWN;
2576 from_y -= preview.step_offset;
2577 from_y = (from_y < 0 ? 0 : from_y);
2580 scroll_direction = MV_RIGHT;
2584 if (from_y < level_ysize - preview.ysize)
2586 from_y += preview.step_offset;
2587 from_y = (from_y > level_ysize - preview.ysize ?
2588 level_ysize - preview.ysize : from_y);
2591 scroll_direction = MV_LEFT;
2598 DrawPreviewLevelPlayfieldExt(from_x, from_y);
2601 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
2602 /* redraw micro level label, if needed */
2603 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
2604 !strEqual(level.author, ANONYMOUS_NAME) &&
2605 !strEqual(level.author, leveldir_current->name) &&
2606 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
2608 int max_label_counter = 23;
2610 if (leveldir_current->imported_from != NULL &&
2611 strlen(leveldir_current->imported_from) > 0)
2612 max_label_counter += 14;
2613 if (leveldir_current->imported_by != NULL &&
2614 strlen(leveldir_current->imported_by) > 0)
2615 max_label_counter += 14;
2617 label_counter = (label_counter + 1) % max_label_counter;
2618 label_state = (label_counter >= 0 && label_counter <= 7 ?
2619 MICROLABEL_LEVEL_NAME :
2620 label_counter >= 9 && label_counter <= 12 ?
2621 MICROLABEL_LEVEL_AUTHOR_HEAD :
2622 label_counter >= 14 && label_counter <= 21 ?
2623 MICROLABEL_LEVEL_AUTHOR :
2624 label_counter >= 23 && label_counter <= 26 ?
2625 MICROLABEL_IMPORTED_FROM_HEAD :
2626 label_counter >= 28 && label_counter <= 35 ?
2627 MICROLABEL_IMPORTED_FROM :
2628 label_counter >= 37 && label_counter <= 40 ?
2629 MICROLABEL_IMPORTED_BY_HEAD :
2630 label_counter >= 42 && label_counter <= 49 ?
2631 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
2633 if (leveldir_current->imported_from == NULL &&
2634 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
2635 label_state == MICROLABEL_IMPORTED_FROM))
2636 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
2637 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
2639 DrawPreviewLevelLabelExt(label_state);
2642 game_status = last_game_status; /* restore current game status */
2645 void DrawPreviewLevelInitial()
2647 DrawPreviewLevelExt(TRUE);
2650 void DrawPreviewLevelAnimation()
2652 DrawPreviewLevelExt(FALSE);
2655 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
2656 int graphic, int sync_frame, int mask_mode)
2658 int frame = getGraphicAnimationFrame(graphic, sync_frame);
2660 if (mask_mode == USE_MASKING)
2661 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
2663 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
2666 inline void DrawFixedGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
2667 int graphic, int sync_frame,
2670 int frame = getGraphicAnimationFrame(graphic, sync_frame);
2672 if (mask_mode == USE_MASKING)
2673 DrawFixedGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
2675 DrawFixedGraphicExt(dst_bitmap, x, y, graphic, frame);
2678 inline void DrawGraphicAnimation(int x, int y, int graphic)
2680 int lx = LEVELX(x), ly = LEVELY(y);
2682 if (!IN_SCR_FIELD(x, y))
2685 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
2686 graphic, GfxFrame[lx][ly], NO_MASKING);
2688 MarkTileDirty(x, y);
2691 inline void DrawFixedGraphicAnimation(int x, int y, int graphic)
2693 int lx = LEVELX(x), ly = LEVELY(y);
2695 if (!IN_SCR_FIELD(x, y))
2698 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
2699 graphic, GfxFrame[lx][ly], NO_MASKING);
2700 MarkTileDirty(x, y);
2703 void DrawLevelGraphicAnimation(int x, int y, int graphic)
2705 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2708 void DrawLevelElementAnimation(int x, int y, int element)
2710 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2712 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2715 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
2717 int sx = SCREENX(x), sy = SCREENY(y);
2719 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2722 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2725 DrawGraphicAnimation(sx, sy, graphic);
2728 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
2729 DrawLevelFieldCrumbled(x, y);
2731 if (GFX_CRUMBLED(Feld[x][y]))
2732 DrawLevelFieldCrumbled(x, y);
2736 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
2738 int sx = SCREENX(x), sy = SCREENY(y);
2741 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2744 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2746 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2749 DrawGraphicAnimation(sx, sy, graphic);
2751 if (GFX_CRUMBLED(element))
2752 DrawLevelFieldCrumbled(x, y);
2755 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
2757 if (player->use_murphy)
2759 /* this works only because currently only one player can be "murphy" ... */
2760 static int last_horizontal_dir = MV_LEFT;
2761 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
2763 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2764 last_horizontal_dir = move_dir;
2766 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
2768 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
2770 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
2776 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
2779 static boolean equalGraphics(int graphic1, int graphic2)
2781 struct GraphicInfo *g1 = &graphic_info[graphic1];
2782 struct GraphicInfo *g2 = &graphic_info[graphic2];
2784 return (g1->bitmap == g2->bitmap &&
2785 g1->src_x == g2->src_x &&
2786 g1->src_y == g2->src_y &&
2787 g1->anim_frames == g2->anim_frames &&
2788 g1->anim_delay == g2->anim_delay &&
2789 g1->anim_mode == g2->anim_mode);
2792 void DrawAllPlayers()
2796 for (i = 0; i < MAX_PLAYERS; i++)
2797 if (stored_player[i].active)
2798 DrawPlayer(&stored_player[i]);
2801 void DrawPlayerField(int x, int y)
2803 if (!IS_PLAYER(x, y))
2806 DrawPlayer(PLAYERINFO(x, y));
2809 #define DRAW_PLAYER_OVER_PUSHED_ELEMENT 1
2811 void DrawPlayer(struct PlayerInfo *player)
2813 int jx = player->jx;
2814 int jy = player->jy;
2815 int move_dir = player->MovDir;
2816 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
2817 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
2818 int last_jx = (player->is_moving ? jx - dx : jx);
2819 int last_jy = (player->is_moving ? jy - dy : jy);
2820 int next_jx = jx + dx;
2821 int next_jy = jy + dy;
2822 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
2823 boolean player_is_opaque = FALSE;
2824 int sx = SCREENX(jx), sy = SCREENY(jy);
2825 int sxx = 0, syy = 0;
2826 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
2828 int action = ACTION_DEFAULT;
2829 int last_player_graphic = getPlayerGraphic(player, move_dir);
2830 int last_player_frame = player->Frame;
2833 /* GfxElement[][] is set to the element the player is digging or collecting;
2834 remove also for off-screen player if the player is not moving anymore */
2835 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
2836 GfxElement[jx][jy] = EL_UNDEFINED;
2838 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
2842 if (!IN_LEV_FIELD(jx, jy))
2844 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
2845 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
2846 printf("DrawPlayerField(): This should never happen!\n");
2851 if (element == EL_EXPLOSION)
2854 action = (player->is_pushing ? ACTION_PUSHING :
2855 player->is_digging ? ACTION_DIGGING :
2856 player->is_collecting ? ACTION_COLLECTING :
2857 player->is_moving ? ACTION_MOVING :
2858 player->is_snapping ? ACTION_SNAPPING :
2859 player->is_dropping ? ACTION_DROPPING :
2860 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
2862 if (player->is_waiting)
2863 move_dir = player->dir_waiting;
2865 InitPlayerGfxAnimation(player, action, move_dir);
2867 /* ----------------------------------------------------------------------- */
2868 /* draw things in the field the player is leaving, if needed */
2869 /* ----------------------------------------------------------------------- */
2871 if (player->is_moving)
2873 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
2875 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
2877 if (last_element == EL_DYNAMITE_ACTIVE ||
2878 last_element == EL_EM_DYNAMITE_ACTIVE ||
2879 last_element == EL_SP_DISK_RED_ACTIVE)
2880 DrawDynamite(last_jx, last_jy);
2882 DrawLevelFieldThruMask(last_jx, last_jy);
2884 else if (last_element == EL_DYNAMITE_ACTIVE ||
2885 last_element == EL_EM_DYNAMITE_ACTIVE ||
2886 last_element == EL_SP_DISK_RED_ACTIVE)
2887 DrawDynamite(last_jx, last_jy);
2889 /* !!! this is not enough to prevent flickering of players which are
2890 moving next to each others without a free tile between them -- this
2891 can only be solved by drawing all players layer by layer (first the
2892 background, then the foreground etc.) !!! => TODO */
2893 else if (!IS_PLAYER(last_jx, last_jy))
2894 DrawLevelField(last_jx, last_jy);
2897 DrawLevelField(last_jx, last_jy);
2900 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
2901 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
2904 if (!IN_SCR_FIELD(sx, sy))
2907 /* ----------------------------------------------------------------------- */
2908 /* draw things behind the player, if needed */
2909 /* ----------------------------------------------------------------------- */
2912 DrawLevelElement(jx, jy, Back[jx][jy]);
2913 else if (IS_ACTIVE_BOMB(element))
2914 DrawLevelElement(jx, jy, EL_EMPTY);
2917 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
2919 int old_element = GfxElement[jx][jy];
2920 int old_graphic = el_act_dir2img(old_element, action, move_dir);
2921 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
2923 if (GFX_CRUMBLED(old_element))
2924 DrawLevelFieldCrumbledDigging(jx, jy, move_dir, player->StepFrame);
2926 DrawGraphic(sx, sy, old_graphic, frame);
2928 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
2929 player_is_opaque = TRUE;
2933 GfxElement[jx][jy] = EL_UNDEFINED;
2935 /* make sure that pushed elements are drawn with correct frame rate */
2936 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2938 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
2939 GfxFrame[jx][jy] = player->StepFrame;
2941 DrawLevelField(jx, jy);
2945 #if !DRAW_PLAYER_OVER_PUSHED_ELEMENT
2946 /* ----------------------------------------------------------------------- */
2947 /* draw player himself */
2948 /* ----------------------------------------------------------------------- */
2950 graphic = getPlayerGraphic(player, move_dir);
2952 /* in the case of changed player action or direction, prevent the current
2953 animation frame from being restarted for identical animations */
2954 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
2955 player->Frame = last_player_frame;
2957 frame = getGraphicAnimationFrame(graphic, player->Frame);
2961 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2962 sxx = player->GfxPos;
2964 syy = player->GfxPos;
2967 if (player_is_opaque)
2968 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
2970 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2972 if (SHIELD_ON(player))
2974 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
2975 IMG_SHIELD_NORMAL_ACTIVE);
2976 int frame = getGraphicAnimationFrame(graphic, -1);
2978 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2982 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
2985 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2986 sxx = player->GfxPos;
2988 syy = player->GfxPos;
2992 /* ----------------------------------------------------------------------- */
2993 /* draw things the player is pushing, if needed */
2994 /* ----------------------------------------------------------------------- */
2996 if (player->is_pushing && player->is_moving)
2998 int px = SCREENX(jx), py = SCREENY(jy);
2999 int pxx = (TILEX - ABS(sxx)) * dx;
3000 int pyy = (TILEY - ABS(syy)) * dy;
3001 int gfx_frame = GfxFrame[jx][jy];
3007 if (!IS_MOVING(jx, jy)) /* push movement already finished */
3009 element = Feld[next_jx][next_jy];
3010 gfx_frame = GfxFrame[next_jx][next_jy];
3013 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
3015 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
3016 frame = getGraphicAnimationFrame(graphic, sync_frame);
3018 /* draw background element under pushed element (like the Sokoban field) */
3019 if (game.use_masked_pushing && IS_MOVING(jx, jy))
3021 /* this allows transparent pushing animation over non-black background */
3024 DrawLevelElement(jx, jy, Back[jx][jy]);
3026 DrawLevelElement(jx, jy, EL_EMPTY);
3028 if (Back[next_jx][next_jy])
3029 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3031 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
3033 else if (Back[next_jx][next_jy])
3034 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3037 /* do not draw (EM style) pushing animation when pushing is finished */
3038 /* (two-tile animations usually do not contain start and end frame) */
3039 if (graphic_info[graphic].double_movement && !IS_MOVING(jx, jy))
3040 DrawLevelElement(next_jx, next_jy, Feld[next_jx][next_jy]);
3042 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3044 /* masked drawing is needed for EMC style (double) movement graphics */
3045 /* !!! (ONLY WHEN DRAWING PUSHED ELEMENT OVER THE PLAYER) !!! */
3046 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3050 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
3051 /* ----------------------------------------------------------------------- */
3052 /* draw player himself */
3053 /* ----------------------------------------------------------------------- */
3055 graphic = getPlayerGraphic(player, move_dir);
3057 /* in the case of changed player action or direction, prevent the current
3058 animation frame from being restarted for identical animations */
3059 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
3060 player->Frame = last_player_frame;
3062 frame = getGraphicAnimationFrame(graphic, player->Frame);
3066 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3067 sxx = player->GfxPos;
3069 syy = player->GfxPos;
3072 if (player_is_opaque)
3073 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
3075 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3077 if (SHIELD_ON(player))
3079 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
3080 IMG_SHIELD_NORMAL_ACTIVE);
3081 int frame = getGraphicAnimationFrame(graphic, -1);
3083 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3087 /* ----------------------------------------------------------------------- */
3088 /* draw things in front of player (active dynamite or dynabombs) */
3089 /* ----------------------------------------------------------------------- */
3091 if (IS_ACTIVE_BOMB(element))
3093 graphic = el2img(element);
3094 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
3096 if (game.emulation == EMU_SUPAPLEX)
3097 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
3099 DrawGraphicThruMask(sx, sy, graphic, frame);
3102 if (player_is_moving && last_element == EL_EXPLOSION)
3104 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
3105 GfxElement[last_jx][last_jy] : EL_EMPTY);
3106 int graphic = el_act2img(element, ACTION_EXPLODING);
3107 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
3108 int phase = ExplodePhase[last_jx][last_jy] - 1;
3109 int frame = getGraphicAnimationFrame(graphic, phase - delay);
3112 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
3115 /* ----------------------------------------------------------------------- */
3116 /* draw elements the player is just walking/passing through/under */
3117 /* ----------------------------------------------------------------------- */
3119 if (player_is_moving)
3121 /* handle the field the player is leaving ... */
3122 if (IS_ACCESSIBLE_INSIDE(last_element))
3123 DrawLevelField(last_jx, last_jy);
3124 else if (IS_ACCESSIBLE_UNDER(last_element))
3125 DrawLevelFieldThruMask(last_jx, last_jy);
3128 /* do not redraw accessible elements if the player is just pushing them */
3129 if (!player_is_moving || !player->is_pushing)
3131 /* ... and the field the player is entering */
3132 if (IS_ACCESSIBLE_INSIDE(element))
3133 DrawLevelField(jx, jy);
3134 else if (IS_ACCESSIBLE_UNDER(element))
3135 DrawLevelFieldThruMask(jx, jy);
3138 MarkTileDirty(sx, sy);
3141 /* ------------------------------------------------------------------------- */
3143 void WaitForEventToContinue()
3145 boolean still_wait = TRUE;
3147 /* simulate releasing mouse button over last gadget, if still pressed */
3149 HandleGadgets(-1, -1, 0);
3151 button_status = MB_RELEASED;
3165 case EVENT_BUTTONPRESS:
3166 case EVENT_KEYPRESS:
3170 case EVENT_KEYRELEASE:
3171 ClearPlayerAction();
3175 HandleOtherEvents(&event);
3179 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3186 /* don't eat all CPU time */
3191 #define MAX_REQUEST_LINES 13
3192 #define MAX_REQUEST_LINE_FONT1_LEN 7
3193 #define MAX_REQUEST_LINE_FONT2_LEN 10
3195 static int RequestHandleEvents(unsigned int req_state)
3197 boolean level_solved = (game_status == GAME_MODE_PLAYING &&
3198 local_player->LevelSolved_GameEnd);
3199 int last_game_status = game_status; /* save current game status */
3200 int width = request.width;
3201 int height = request.height;
3205 setRequestPosition(&sx, &sy, FALSE);
3207 button_status = MB_RELEASED;
3209 request_gadget_id = -1;
3216 SetDrawtoField(DRAW_FIELDBUFFER);
3218 HandleGameActions();
3220 SetDrawtoField(DRAW_BACKBUFFER);
3222 if (global.use_envelope_request)
3224 /* copy current state of request area to middle of playfield area */
3225 BlitBitmap(bitmap_db_cross, drawto, sx, sy, width, height, sx, sy);
3233 while (NextValidEvent(&event))
3237 case EVENT_BUTTONPRESS:
3238 case EVENT_BUTTONRELEASE:
3239 case EVENT_MOTIONNOTIFY:
3243 if (event.type == EVENT_MOTIONNOTIFY)
3248 motion_status = TRUE;
3249 mx = ((MotionEvent *) &event)->x;
3250 my = ((MotionEvent *) &event)->y;
3254 motion_status = FALSE;
3255 mx = ((ButtonEvent *) &event)->x;
3256 my = ((ButtonEvent *) &event)->y;
3257 if (event.type == EVENT_BUTTONPRESS)
3258 button_status = ((ButtonEvent *) &event)->button;
3260 button_status = MB_RELEASED;
3263 /* this sets 'request_gadget_id' */
3264 HandleGadgets(mx, my, button_status);
3266 switch (request_gadget_id)
3268 case TOOL_CTRL_ID_YES:
3271 case TOOL_CTRL_ID_NO:
3274 case TOOL_CTRL_ID_CONFIRM:
3275 result = TRUE | FALSE;
3278 case TOOL_CTRL_ID_PLAYER_1:
3281 case TOOL_CTRL_ID_PLAYER_2:
3284 case TOOL_CTRL_ID_PLAYER_3:
3287 case TOOL_CTRL_ID_PLAYER_4:
3298 case EVENT_KEYPRESS:
3299 switch (GetEventKey((KeyEvent *)&event, TRUE))
3302 if (req_state & REQ_CONFIRM)
3307 #if defined(TARGET_SDL2)
3314 #if defined(TARGET_SDL2)
3324 if (req_state & REQ_PLAYER)
3328 case EVENT_KEYRELEASE:
3329 ClearPlayerAction();
3333 HandleOtherEvents(&event);
3338 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3340 int joy = AnyJoystick();
3342 if (joy & JOY_BUTTON_1)
3344 else if (joy & JOY_BUTTON_2)
3350 if (global.use_envelope_request)
3352 /* copy back current state of pressed buttons inside request area */
3353 BlitBitmap(drawto, bitmap_db_cross, sx, sy, width, height, sx, sy);
3360 if (!PendingEvent()) /* delay only if no pending events */
3364 game_status = GAME_MODE_PSEUDO_DOOR;
3368 game_status = last_game_status; /* restore current game status */
3374 static boolean RequestDoor(char *text, unsigned int req_state)
3376 unsigned int old_door_state;
3377 int last_game_status = game_status; /* save current game status */
3378 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
3379 int font_nr = FONT_TEXT_2;
3384 if (maxWordLengthInString(text) > MAX_REQUEST_LINE_FONT1_LEN)
3386 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
3387 font_nr = FONT_TEXT_1;
3390 if (game_status == GAME_MODE_PLAYING)
3391 BlitScreenToBitmap(backbuffer);
3393 /* disable deactivated drawing when quick-loading level tape recording */
3394 if (tape.playing && tape.deactivate_display)
3395 TapeDeactivateDisplayOff(TRUE);
3397 SetMouseCursor(CURSOR_DEFAULT);
3399 #if defined(NETWORK_AVALIABLE)
3400 /* pause network game while waiting for request to answer */
3401 if (options.network &&
3402 game_status == GAME_MODE_PLAYING &&
3403 req_state & REQUEST_WAIT_FOR_INPUT)
3404 SendToServer_PausePlaying();
3407 old_door_state = GetDoorState();
3409 /* simulate releasing mouse button over last gadget, if still pressed */
3411 HandleGadgets(-1, -1, 0);
3415 /* draw released gadget before proceeding */
3418 if (old_door_state & DOOR_OPEN_1)
3420 CloseDoor(DOOR_CLOSE_1);
3422 /* save old door content */
3423 BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
3424 0 * DXSIZE, 0, DXSIZE, DYSIZE, 1 * DXSIZE, 0);
3427 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
3428 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3430 /* clear door drawing field */
3431 DrawBackground(DX, DY, DXSIZE, DYSIZE);
3433 /* force DOOR font inside door area */
3434 game_status = GAME_MODE_PSEUDO_DOOR;
3436 /* write text for request */
3437 for (text_ptr = text, ty = 0; ty < MAX_REQUEST_LINES; ty++)
3439 char text_line[max_request_line_len + 1];
3445 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
3447 tc = *(text_ptr + tx);
3448 // if (!tc || tc == ' ')
3449 if (!tc || tc == ' ' || tc == '?' || tc == '!')
3453 if ((tc == '?' || tc == '!') && tl == 0)
3463 strncpy(text_line, text_ptr, tl);
3466 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
3467 DY + 8 + ty * (getFontHeight(font_nr) + 2),
3468 text_line, font_nr);
3470 text_ptr += tl + (tc == ' ' ? 1 : 0);
3471 // text_ptr += tl + (tc == ' ' || tc == '?' || tc == '!' ? 1 : 0);
3474 game_status = last_game_status; /* restore current game status */
3476 if (req_state & REQ_ASK)
3478 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
3479 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
3481 else if (req_state & REQ_CONFIRM)
3483 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
3485 else if (req_state & REQ_PLAYER)
3487 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
3488 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
3489 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
3490 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
3493 /* copy request gadgets to door backbuffer */
3494 BlitBitmap(drawto, bitmap_db_door_1, DX, DY, DXSIZE, DYSIZE, 0, 0);
3496 OpenDoor(DOOR_OPEN_1);
3498 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
3500 if (game_status == GAME_MODE_PLAYING)
3502 SetPanelBackground();
3503 SetDrawBackgroundMask(REDRAW_DOOR_1);
3507 SetDrawBackgroundMask(REDRAW_FIELD);
3513 if (game_status != GAME_MODE_MAIN)
3516 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3518 // ---------- handle request buttons ----------
3519 result = RequestHandleEvents(req_state);
3521 if (game_status != GAME_MODE_MAIN)
3526 if (!(req_state & REQ_STAY_OPEN))
3528 CloseDoor(DOOR_CLOSE_1);
3530 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
3531 (req_state & REQ_REOPEN))
3532 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
3537 if (game_status == GAME_MODE_PLAYING)
3539 SetPanelBackground();
3540 SetDrawBackgroundMask(REDRAW_DOOR_1);
3544 SetDrawBackgroundMask(REDRAW_FIELD);
3547 #if defined(NETWORK_AVALIABLE)
3548 /* continue network game after request */
3549 if (options.network &&
3550 game_status == GAME_MODE_PLAYING &&
3551 req_state & REQUEST_WAIT_FOR_INPUT)
3552 SendToServer_ContinuePlaying();
3555 /* restore deactivated drawing when quick-loading level tape recording */
3556 if (tape.playing && tape.deactivate_display)
3557 TapeDeactivateDisplayOn();
3562 static boolean RequestEnvelope(char *text, unsigned int req_state)
3566 if (game_status == GAME_MODE_PLAYING)
3567 BlitScreenToBitmap(backbuffer);
3569 /* disable deactivated drawing when quick-loading level tape recording */
3570 if (tape.playing && tape.deactivate_display)
3571 TapeDeactivateDisplayOff(TRUE);
3573 SetMouseCursor(CURSOR_DEFAULT);
3575 #if defined(NETWORK_AVALIABLE)
3576 /* pause network game while waiting for request to answer */
3577 if (options.network &&
3578 game_status == GAME_MODE_PLAYING &&
3579 req_state & REQUEST_WAIT_FOR_INPUT)
3580 SendToServer_PausePlaying();
3583 /* simulate releasing mouse button over last gadget, if still pressed */
3585 HandleGadgets(-1, -1, 0);
3589 // (replace with setting corresponding request background)
3590 // SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
3591 // SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3593 /* clear door drawing field */
3594 // DrawBackground(DX, DY, DXSIZE, DYSIZE);
3596 ShowEnvelopeRequest(text, req_state, ACTION_OPENING);
3598 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
3600 if (game_status == GAME_MODE_PLAYING)
3602 SetPanelBackground();
3603 SetDrawBackgroundMask(REDRAW_DOOR_1);
3607 SetDrawBackgroundMask(REDRAW_FIELD);
3613 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3615 // ---------- handle request buttons ----------
3616 result = RequestHandleEvents(req_state);
3618 if (game_status != GAME_MODE_MAIN)
3623 ShowEnvelopeRequest(text, req_state, ACTION_CLOSING);
3627 if (game_status == GAME_MODE_PLAYING)
3629 SetPanelBackground();
3630 SetDrawBackgroundMask(REDRAW_DOOR_1);
3634 SetDrawBackgroundMask(REDRAW_FIELD);
3637 #if defined(NETWORK_AVALIABLE)
3638 /* continue network game after request */
3639 if (options.network &&
3640 game_status == GAME_MODE_PLAYING &&
3641 req_state & REQUEST_WAIT_FOR_INPUT)
3642 SendToServer_ContinuePlaying();
3645 /* restore deactivated drawing when quick-loading level tape recording */
3646 if (tape.playing && tape.deactivate_display)
3647 TapeDeactivateDisplayOn();
3652 boolean Request(char *text, unsigned int req_state)
3654 if (global.use_envelope_request)
3655 return RequestEnvelope(text, req_state);
3657 return RequestDoor(text, req_state);
3660 static int compareDoorPartOrderInfo(const void *object1, const void *object2)
3662 const struct DoorPartOrderInfo *dpo1 = (struct DoorPartOrderInfo *)object1;
3663 const struct DoorPartOrderInfo *dpo2 = (struct DoorPartOrderInfo *)object2;
3666 if (dpo1->sort_priority != dpo2->sort_priority)
3667 compare_result = dpo1->sort_priority - dpo2->sort_priority;
3669 compare_result = dpo1->nr - dpo2->nr;
3671 return compare_result;
3674 void InitGraphicCompatibilityInfo_Doors()
3680 struct DoorInfo *door;
3684 { DOOR_1, IMG_DOOR_1_GFX_PART_1, IMG_DOOR_1_GFX_PART_8, &door_1 },
3685 { DOOR_2, IMG_DOOR_2_GFX_PART_1, IMG_DOOR_2_GFX_PART_8, &door_2 },
3687 { -1, -1, -1, NULL }
3689 struct Rect door_rect_list[] =
3691 { DX, DY, DXSIZE, DYSIZE },
3692 { VX, VY, VXSIZE, VYSIZE }
3696 for (i = 0; doors[i].door_token != -1; i++)
3698 int door_token = doors[i].door_token;
3699 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
3700 int part_1 = doors[i].part_1;
3701 int part_8 = doors[i].part_8;
3702 int part_2 = part_1 + 1;
3703 int part_3 = part_1 + 2;
3704 struct DoorInfo *door = doors[i].door;
3705 struct Rect *door_rect = &door_rect_list[door_index];
3706 boolean door_gfx_redefined = FALSE;
3708 /* check if any door part graphic definitions have been redefined */
3710 for (j = 0; door_part_controls[j].door_token != -1; j++)
3712 struct DoorPartControlInfo *dpc = &door_part_controls[j];
3713 struct FileInfo *fi = getImageListEntryFromImageID(dpc->graphic);
3715 if (dpc->door_token == door_token && fi->redefined)
3716 door_gfx_redefined = TRUE;
3719 /* check for old-style door graphic/animation modifications */
3721 if (!door_gfx_redefined)
3723 if (door->anim_mode & ANIM_STATIC_PANEL)
3725 door->panel.step_xoffset = 0;
3726 door->panel.step_yoffset = 0;
3729 if (door->anim_mode & (ANIM_HORIZONTAL | ANIM_VERTICAL))
3731 struct GraphicInfo *g_part_1 = &graphic_info[part_1];
3732 struct GraphicInfo *g_part_2 = &graphic_info[part_2];
3733 int num_door_steps, num_panel_steps;
3735 /* remove door part graphics other than the two default wings */
3737 for (j = 0; door_part_controls[j].door_token != -1; j++)
3739 struct DoorPartControlInfo *dpc = &door_part_controls[j];
3740 struct GraphicInfo *g = &graphic_info[dpc->graphic];
3742 if (dpc->graphic >= part_3 &&
3743 dpc->graphic <= part_8)
3747 /* set graphics and screen positions of the default wings */
3749 g_part_1->width = door_rect->width;
3750 g_part_1->height = door_rect->height;
3751 g_part_2->width = door_rect->width;
3752 g_part_2->height = door_rect->height;
3753 g_part_2->src_x = door_rect->width;
3754 g_part_2->src_y = g_part_1->src_y;
3756 door->part_2.x = door->part_1.x;
3757 door->part_2.y = door->part_1.y;
3759 if (door->width != -1)
3761 g_part_1->width = door->width;
3762 g_part_2->width = door->width;
3764 // special treatment for graphics and screen position of right wing
3765 g_part_2->src_x += door_rect->width - door->width;
3766 door->part_2.x += door_rect->width - door->width;
3769 if (door->height != -1)
3771 g_part_1->height = door->height;
3772 g_part_2->height = door->height;
3774 // special treatment for graphics and screen position of bottom wing
3775 g_part_2->src_y += door_rect->height - door->height;
3776 door->part_2.y += door_rect->height - door->height;
3779 /* set animation delays for the default wings and panels */
3781 door->part_1.step_delay = door->step_delay;
3782 door->part_2.step_delay = door->step_delay;
3783 door->panel.step_delay = door->step_delay;
3785 /* set animation draw order for the default wings */
3787 door->part_1.sort_priority = 2; /* draw left wing over ... */
3788 door->part_2.sort_priority = 1; /* ... right wing */
3790 /* set animation draw offset for the default wings */
3792 if (door->anim_mode & ANIM_HORIZONTAL)
3794 door->part_1.step_xoffset = door->step_offset;
3795 door->part_1.step_yoffset = 0;
3796 door->part_2.step_xoffset = door->step_offset * -1;
3797 door->part_2.step_yoffset = 0;
3799 num_door_steps = g_part_1->width / door->step_offset;
3801 else // ANIM_VERTICAL
3803 door->part_1.step_xoffset = 0;
3804 door->part_1.step_yoffset = door->step_offset;
3805 door->part_2.step_xoffset = 0;
3806 door->part_2.step_yoffset = door->step_offset * -1;
3808 num_door_steps = g_part_1->height / door->step_offset;
3811 /* set animation draw offset for the default panels */
3813 if (door->step_offset > 1)
3815 num_panel_steps = 2 * door_rect->height / door->step_offset;
3816 door->panel.start_step = num_panel_steps - num_door_steps;
3817 door->panel.start_step_closing = door->panel.start_step;
3821 num_panel_steps = door_rect->height / door->step_offset;
3822 door->panel.start_step = num_panel_steps - num_door_steps / 2;
3823 door->panel.start_step_closing = door->panel.start_step;
3824 door->panel.step_delay *= 2;
3835 for (i = 0; door_part_controls[i].door_token != -1; i++)
3837 struct DoorPartControlInfo *dpc = &door_part_controls[i];
3838 struct DoorPartOrderInfo *dpo = &door_part_order[i];
3840 /* initialize "start_step_opening" and "start_step_closing", if needed */
3841 if (dpc->pos->start_step_opening == 0 &&
3842 dpc->pos->start_step_closing == 0)
3844 // dpc->pos->start_step_opening = dpc->pos->start_step;
3845 dpc->pos->start_step_closing = dpc->pos->start_step;
3848 /* fill structure for door part draw order (sorted below) */
3850 dpo->sort_priority = dpc->pos->sort_priority;
3853 /* sort door part controls according to sort_priority and graphic number */
3854 qsort(door_part_order, MAX_DOOR_PARTS,
3855 sizeof(struct DoorPartOrderInfo), compareDoorPartOrderInfo);
3858 unsigned int OpenDoor(unsigned int door_state)
3860 if (door_state & DOOR_COPY_BACK)
3862 if (door_state & DOOR_OPEN_1)
3863 BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
3864 1 * DXSIZE, 0, DXSIZE, DYSIZE, 0 * DXSIZE, 0);
3866 if (door_state & DOOR_OPEN_2)
3867 BlitBitmap(bitmap_db_door_2, bitmap_db_door_2,
3868 1 * VXSIZE, 0, VXSIZE, VYSIZE, 0 * VXSIZE, 0);
3870 door_state &= ~DOOR_COPY_BACK;
3873 return MoveDoor(door_state);
3876 unsigned int CloseDoor(unsigned int door_state)
3878 unsigned int old_door_state = GetDoorState();
3880 if (!(door_state & DOOR_NO_COPY_BACK))
3882 if (old_door_state & DOOR_OPEN_1)
3883 BlitBitmap(backbuffer, bitmap_db_door_1,
3884 DX, DY, DXSIZE, DYSIZE, 0, 0);
3886 if (old_door_state & DOOR_OPEN_2)
3887 BlitBitmap(backbuffer, bitmap_db_door_2,
3888 VX, VY, VXSIZE, VYSIZE, 0, 0);
3890 door_state &= ~DOOR_NO_COPY_BACK;
3893 return MoveDoor(door_state);
3896 unsigned int GetDoorState()
3898 return MoveDoor(DOOR_GET_STATE);
3901 unsigned int SetDoorState(unsigned int door_state)
3903 return MoveDoor(door_state | DOOR_SET_STATE);
3906 int euclid(int a, int b)
3908 return (b ? euclid(b, a % b) : a);
3911 unsigned int MoveDoor(unsigned int door_state)
3913 struct Rect door_rect_list[] =
3915 { DX, DY, DXSIZE, DYSIZE },
3916 { VX, VY, VXSIZE, VYSIZE }
3918 static int door1 = DOOR_OPEN_1;
3919 static int door2 = DOOR_CLOSE_2;
3920 unsigned int door_delay = 0;
3921 unsigned int door_delay_value;
3924 if (door_state == DOOR_GET_STATE)
3925 return (door1 | door2);
3927 if (door_state & DOOR_SET_STATE)
3929 if (door_state & DOOR_ACTION_1)
3930 door1 = door_state & DOOR_ACTION_1;
3931 if (door_state & DOOR_ACTION_2)
3932 door2 = door_state & DOOR_ACTION_2;
3934 return (door1 | door2);
3937 if (!(door_state & DOOR_FORCE_REDRAW))
3939 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
3940 door_state &= ~DOOR_OPEN_1;
3941 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
3942 door_state &= ~DOOR_CLOSE_1;
3943 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
3944 door_state &= ~DOOR_OPEN_2;
3945 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
3946 door_state &= ~DOOR_CLOSE_2;
3949 if (global.autoplay_leveldir)
3951 door_state |= DOOR_NO_DELAY;
3952 door_state &= ~DOOR_CLOSE_ALL;
3955 if (game_status == GAME_MODE_EDITOR)
3956 door_state |= DOOR_NO_DELAY;
3958 if (door_state & DOOR_ACTION)
3960 boolean door_panel_drawn[NUM_DOORS];
3961 boolean panel_has_doors[NUM_DOORS];
3962 boolean door_part_skip[MAX_DOOR_PARTS];
3963 boolean door_part_done[MAX_DOOR_PARTS];
3964 boolean door_part_done_all;
3965 int num_steps[MAX_DOOR_PARTS];
3966 int max_move_delay = 0; // delay for complete animations of all doors
3967 int max_step_delay = 0; // delay (ms) between two animation frames
3968 int num_move_steps = 0; // number of animation steps for all doors
3969 int max_move_delay_doors_only = 0; // delay for doors only (no panel)
3970 int num_move_steps_doors_only = 0; // steps for doors only (no panel)
3971 int current_move_delay = 0;
3975 for (i = 0; i < NUM_DOORS; i++)
3976 panel_has_doors[i] = FALSE;
3978 for (i = 0; i < MAX_DOOR_PARTS; i++)
3980 struct DoorPartControlInfo *dpc = &door_part_controls[i];
3981 struct GraphicInfo *g = &graphic_info[dpc->graphic];
3982 int door_token = dpc->door_token;
3984 door_part_done[i] = FALSE;
3985 door_part_skip[i] = (!(door_state & door_token) ||
3989 for (i = 0; i < MAX_DOOR_PARTS; i++)
3991 int nr = door_part_order[i].nr;
3992 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
3993 struct DoorPartPosInfo *pos = dpc->pos;
3994 struct GraphicInfo *g = &graphic_info[dpc->graphic];
3995 int door_token = dpc->door_token;
3996 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
3997 boolean is_panel = DOOR_PART_IS_PANEL(nr);
3998 int step_xoffset = ABS(pos->step_xoffset);
3999 int step_yoffset = ABS(pos->step_yoffset);
4000 int step_delay = pos->step_delay;
4001 int current_door_state = door_state & door_token;
4002 boolean door_opening = ((current_door_state & DOOR_OPEN) != 0);
4003 boolean door_closing = ((current_door_state & DOOR_CLOSE) != 0);
4004 boolean part_opening = (is_panel ? door_closing : door_opening);
4005 int start_step = (part_opening ? pos->start_step_opening :
4006 pos->start_step_closing);
4007 float move_xsize = (step_xoffset ? g->width : 0);
4008 float move_ysize = (step_yoffset ? g->height : 0);
4009 int move_xsteps = (step_xoffset ? ceil(move_xsize / step_xoffset) : 0);
4010 int move_ysteps = (step_yoffset ? ceil(move_ysize / step_yoffset) : 0);
4011 int move_steps = (move_xsteps && move_ysteps ?
4012 MIN(move_xsteps, move_ysteps) :
4013 move_xsteps ? move_xsteps : move_ysteps) - start_step;
4014 int move_delay = move_steps * step_delay;
4016 if (door_part_skip[nr])
4019 max_move_delay = MAX(max_move_delay, move_delay);
4020 max_step_delay = (max_step_delay == 0 ? step_delay :
4021 euclid(max_step_delay, step_delay));
4022 num_steps[nr] = move_steps;
4026 max_move_delay_doors_only = MAX(max_move_delay_doors_only, move_delay);
4028 panel_has_doors[door_index] = TRUE;
4032 max_step_delay = MAX(1, max_step_delay); // prevent division by zero
4034 num_move_steps = max_move_delay / max_step_delay;
4035 num_move_steps_doors_only = max_move_delay_doors_only / max_step_delay;
4037 door_delay_value = max_step_delay;
4039 if ((door_state & DOOR_NO_DELAY) || setup.quick_doors)
4041 start = num_move_steps - 1;
4045 /* opening door sound has priority over simultaneously closing door */
4046 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
4047 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
4048 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
4049 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
4052 for (k = start; k < num_move_steps; k++)
4054 int last_frame = num_move_steps - 1; // last frame of this "for" loop
4056 door_part_done_all = TRUE;
4058 for (i = 0; i < NUM_DOORS; i++)
4059 door_panel_drawn[i] = FALSE;
4061 for (i = 0; i < MAX_DOOR_PARTS; i++)
4063 int nr = door_part_order[i].nr;
4064 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
4065 struct DoorPartPosInfo *pos = dpc->pos;
4066 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4067 int door_token = dpc->door_token;
4068 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
4069 boolean is_panel = DOOR_PART_IS_PANEL(nr);
4070 boolean is_panel_and_door_has_closed = FALSE;
4071 struct Rect *door_rect = &door_rect_list[door_index];
4072 Bitmap *bitmap_db_door = (door_token == DOOR_1 ? bitmap_db_door_1 :
4074 Bitmap *bitmap = (is_panel ? bitmap_db_door : g->bitmap);
4075 int current_door_state = door_state & door_token;
4076 boolean door_opening = ((current_door_state & DOOR_OPEN) != 0);
4077 boolean door_closing = !door_opening;
4078 boolean part_opening = (is_panel ? door_closing : door_opening);
4079 boolean part_closing = !part_opening;
4080 int start_step = (part_opening ? pos->start_step_opening :
4081 pos->start_step_closing);
4082 int step_delay = pos->step_delay;
4083 int step_factor = step_delay / max_step_delay;
4084 int k1 = (step_factor ? k / step_factor + 1 : k);
4085 int k2 = (part_opening ? k1 + start_step : num_steps[nr] - k1);
4086 int kk = MAX(0, k2);
4089 int src_x, src_y, src_xx, src_yy;
4090 int dst_x, dst_y, dst_xx, dst_yy;
4093 if (door_part_skip[nr])
4096 if (!(door_state & door_token))
4104 int k2_door = (door_opening ? k : num_move_steps_doors_only - k - 1);
4105 int kk_door = MAX(0, k2_door);
4106 int sync_frame = kk_door * door_delay_value;
4107 int frame = getGraphicAnimationFrame(dpc->graphic, sync_frame);
4109 getGraphicSource(dpc->graphic, frame, &bitmap, &g_src_x, &g_src_y);
4114 if (!door_panel_drawn[door_index])
4116 ClearRectangle(drawto, door_rect->x, door_rect->y,
4117 door_rect->width, door_rect->height);
4119 door_panel_drawn[door_index] = TRUE;
4122 // draw opening or closing door parts
4124 if (pos->step_xoffset < 0) // door part on right side
4127 dst_xx = pos->x + ABS(kk * pos->step_xoffset);
4130 if (dst_xx + width > door_rect->width)
4131 width = door_rect->width - dst_xx;
4133 else // door part on left side
4136 dst_xx = pos->x - kk * pos->step_xoffset;
4140 src_xx = ABS(dst_xx);
4144 width = g->width - src_xx;
4146 // printf("::: k == %d [%d] \n", k, start_step);
4149 if (pos->step_yoffset < 0) // door part on bottom side
4152 dst_yy = pos->y + ABS(kk * pos->step_yoffset);
4155 if (dst_yy + height > door_rect->height)
4156 height = door_rect->height - dst_yy;
4158 else // door part on top side
4161 dst_yy = pos->y - kk * pos->step_yoffset;
4165 src_yy = ABS(dst_yy);
4169 height = g->height - src_yy;
4172 src_x = g_src_x + src_xx;
4173 src_y = g_src_y + src_yy;
4175 dst_x = door_rect->x + dst_xx;
4176 dst_y = door_rect->y + dst_yy;
4178 is_panel_and_door_has_closed =
4181 panel_has_doors[door_index] &&
4182 k >= num_move_steps_doors_only - 1);
4184 if (width >= 0 && width <= g->width &&
4185 height >= 0 && height <= g->height &&
4186 !is_panel_and_door_has_closed)
4188 if (is_panel || !pos->draw_masked)
4189 BlitBitmap(bitmap, drawto, src_x, src_y, width, height,
4192 BlitBitmapMasked(bitmap, drawto, src_x, src_y, width, height,
4196 redraw_mask |= REDRAW_DOOR_FROM_TOKEN(door_token);
4198 if ((part_opening && (width < 0 || height < 0)) ||
4199 (part_closing && (width >= g->width && height >= g->height)))
4200 door_part_done[nr] = TRUE;
4202 // continue door part animations, but not panel after door has closed
4203 if (!door_part_done[nr] && !is_panel_and_door_has_closed)
4204 door_part_done_all = FALSE;
4207 if (!(door_state & DOOR_NO_DELAY))
4211 if (game_status == GAME_MODE_MAIN)
4214 SkipUntilDelayReached(&door_delay, door_delay_value, &k, last_frame);
4216 current_move_delay += max_step_delay;
4219 if (door_part_done_all)
4224 if (door_state & DOOR_ACTION_1)
4225 door1 = door_state & DOOR_ACTION_1;
4226 if (door_state & DOOR_ACTION_2)
4227 door2 = door_state & DOOR_ACTION_2;
4229 return (door1 | door2);
4232 void DrawSpecialEditorDoor()
4234 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
4235 int top_border_width = gfx1->width;
4236 int top_border_height = gfx1->height;
4237 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
4238 int ex = EX - outer_border;
4239 int ey = EY - outer_border;
4240 int vy = VY - outer_border;
4241 int exsize = EXSIZE + 2 * outer_border;
4243 /* draw bigger level editor toolbox window */
4244 BlitBitmap(gfx1->bitmap, drawto, gfx1->src_x, gfx1->src_y,
4245 top_border_width, top_border_height, ex, ey - top_border_height);
4246 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto, ex, vy,
4247 exsize, EYSIZE - VYSIZE + outer_border, ex, ey);
4249 redraw_mask |= REDRAW_ALL;
4252 void UndrawSpecialEditorDoor()
4254 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
4255 int top_border_width = gfx1->width;
4256 int top_border_height = gfx1->height;
4257 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
4258 int ex = EX - outer_border;
4259 int ey = EY - outer_border;
4260 int ey_top = ey - top_border_height;
4261 int exsize = EXSIZE + 2 * outer_border;
4262 int eysize = EYSIZE + 2 * outer_border;
4264 /* draw normal tape recorder window */
4265 if (graphic_info[IMG_GLOBAL_BORDER].bitmap)
4267 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
4268 ex, ey_top, top_border_width, top_border_height,
4270 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
4271 ex, ey, exsize, eysize, ex, ey);
4275 // if screen background is set to "[NONE]", clear editor toolbox window
4276 ClearRectangle(drawto, ex, ey_top, top_border_width, top_border_height);
4277 ClearRectangle(drawto, ex, ey, exsize, eysize);
4280 redraw_mask |= REDRAW_ALL;
4284 /* ---------- new tool button stuff ---------------------------------------- */
4289 struct TextPosInfo *pos;
4292 } toolbutton_info[NUM_TOOL_BUTTONS] =
4295 IMG_REQUEST_BUTTON_GFX_YES, &request.button.yes,
4296 TOOL_CTRL_ID_YES, "yes"
4299 IMG_REQUEST_BUTTON_GFX_NO, &request.button.no,
4300 TOOL_CTRL_ID_NO, "no"
4303 IMG_REQUEST_BUTTON_GFX_CONFIRM, &request.button.confirm,
4304 TOOL_CTRL_ID_CONFIRM, "confirm"
4307 IMG_REQUEST_BUTTON_GFX_PLAYER_1, &request.button.player_1,
4308 TOOL_CTRL_ID_PLAYER_1, "player 1"
4311 IMG_REQUEST_BUTTON_GFX_PLAYER_2, &request.button.player_2,
4312 TOOL_CTRL_ID_PLAYER_2, "player 2"
4315 IMG_REQUEST_BUTTON_GFX_PLAYER_3, &request.button.player_3,
4316 TOOL_CTRL_ID_PLAYER_3, "player 3"
4319 IMG_REQUEST_BUTTON_GFX_PLAYER_4, &request.button.player_4,
4320 TOOL_CTRL_ID_PLAYER_4, "player 4"
4324 void CreateToolButtons()
4328 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4330 struct GraphicInfo *gfx = &graphic_info[toolbutton_info[i].graphic];
4331 struct TextPosInfo *pos = toolbutton_info[i].pos;
4332 struct GadgetInfo *gi;
4333 Bitmap *deco_bitmap = None;
4334 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
4335 unsigned int event_mask = GD_EVENT_RELEASED;
4338 int gd_x = gfx->src_x;
4339 int gd_y = gfx->src_y;
4340 int gd_xp = gfx->src_x + gfx->pressed_xoffset;
4341 int gd_yp = gfx->src_y + gfx->pressed_yoffset;
4344 if (global.use_envelope_request)
4345 setRequestPosition(&dx, &dy, TRUE);
4347 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
4349 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
4351 getSizedGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr), 0,
4352 pos->size, &deco_bitmap, &deco_x, &deco_y);
4353 deco_xpos = (gfx->width - pos->size) / 2;
4354 deco_ypos = (gfx->height - pos->size) / 2;
4357 gi = CreateGadget(GDI_CUSTOM_ID, id,
4358 GDI_INFO_TEXT, toolbutton_info[i].infotext,
4359 GDI_X, dx + GDI_ACTIVE_POS(pos->x),
4360 GDI_Y, dy + GDI_ACTIVE_POS(pos->y),
4361 GDI_WIDTH, gfx->width,
4362 GDI_HEIGHT, gfx->height,
4363 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
4364 GDI_STATE, GD_BUTTON_UNPRESSED,
4365 GDI_DESIGN_UNPRESSED, gfx->bitmap, gd_x, gd_y,
4366 GDI_DESIGN_PRESSED, gfx->bitmap, gd_xp, gd_yp,
4367 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
4368 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
4369 GDI_DECORATION_SIZE, pos->size, pos->size,
4370 GDI_DECORATION_SHIFTING, 1, 1,
4371 GDI_DIRECT_DRAW, FALSE,
4372 GDI_EVENT_MASK, event_mask,
4373 GDI_CALLBACK_ACTION, HandleToolButtons,
4377 Error(ERR_EXIT, "cannot create gadget");
4379 tool_gadget[id] = gi;
4383 void FreeToolButtons()
4387 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4388 FreeGadget(tool_gadget[i]);
4391 static void UnmapToolButtons()
4395 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4396 UnmapGadget(tool_gadget[i]);
4399 static void HandleToolButtons(struct GadgetInfo *gi)
4401 request_gadget_id = gi->custom_id;
4404 static struct Mapping_EM_to_RND_object
4407 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
4408 boolean is_backside; /* backside of moving element */
4414 em_object_mapping_list[] =
4417 Xblank, TRUE, FALSE,
4421 Yacid_splash_eB, FALSE, FALSE,
4422 EL_ACID_SPLASH_RIGHT, -1, -1
4425 Yacid_splash_wB, FALSE, FALSE,
4426 EL_ACID_SPLASH_LEFT, -1, -1
4429 #ifdef EM_ENGINE_BAD_ROLL
4431 Xstone_force_e, FALSE, FALSE,
4432 EL_ROCK, -1, MV_BIT_RIGHT
4435 Xstone_force_w, FALSE, FALSE,
4436 EL_ROCK, -1, MV_BIT_LEFT
4439 Xnut_force_e, FALSE, FALSE,
4440 EL_NUT, -1, MV_BIT_RIGHT
4443 Xnut_force_w, FALSE, FALSE,
4444 EL_NUT, -1, MV_BIT_LEFT
4447 Xspring_force_e, FALSE, FALSE,
4448 EL_SPRING, -1, MV_BIT_RIGHT
4451 Xspring_force_w, FALSE, FALSE,
4452 EL_SPRING, -1, MV_BIT_LEFT
4455 Xemerald_force_e, FALSE, FALSE,
4456 EL_EMERALD, -1, MV_BIT_RIGHT
4459 Xemerald_force_w, FALSE, FALSE,
4460 EL_EMERALD, -1, MV_BIT_LEFT
4463 Xdiamond_force_e, FALSE, FALSE,
4464 EL_DIAMOND, -1, MV_BIT_RIGHT
4467 Xdiamond_force_w, FALSE, FALSE,
4468 EL_DIAMOND, -1, MV_BIT_LEFT
4471 Xbomb_force_e, FALSE, FALSE,
4472 EL_BOMB, -1, MV_BIT_RIGHT
4475 Xbomb_force_w, FALSE, FALSE,
4476 EL_BOMB, -1, MV_BIT_LEFT
4478 #endif /* EM_ENGINE_BAD_ROLL */
4481 Xstone, TRUE, FALSE,
4485 Xstone_pause, FALSE, FALSE,
4489 Xstone_fall, FALSE, FALSE,
4493 Ystone_s, FALSE, FALSE,
4494 EL_ROCK, ACTION_FALLING, -1
4497 Ystone_sB, FALSE, TRUE,
4498 EL_ROCK, ACTION_FALLING, -1
4501 Ystone_e, FALSE, FALSE,
4502 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
4505 Ystone_eB, FALSE, TRUE,
4506 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
4509 Ystone_w, FALSE, FALSE,
4510 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
4513 Ystone_wB, FALSE, TRUE,
4514 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
4521 Xnut_pause, FALSE, FALSE,
4525 Xnut_fall, FALSE, FALSE,
4529 Ynut_s, FALSE, FALSE,
4530 EL_NUT, ACTION_FALLING, -1
4533 Ynut_sB, FALSE, TRUE,
4534 EL_NUT, ACTION_FALLING, -1
4537 Ynut_e, FALSE, FALSE,
4538 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
4541 Ynut_eB, FALSE, TRUE,
4542 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
4545 Ynut_w, FALSE, FALSE,
4546 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
4549 Ynut_wB, FALSE, TRUE,
4550 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
4553 Xbug_n, TRUE, FALSE,
4557 Xbug_e, TRUE, FALSE,
4558 EL_BUG_RIGHT, -1, -1
4561 Xbug_s, TRUE, FALSE,
4565 Xbug_w, TRUE, FALSE,
4569 Xbug_gon, FALSE, FALSE,
4573 Xbug_goe, FALSE, FALSE,
4574 EL_BUG_RIGHT, -1, -1
4577 Xbug_gos, FALSE, FALSE,
4581 Xbug_gow, FALSE, FALSE,
4585 Ybug_n, FALSE, FALSE,
4586 EL_BUG, ACTION_MOVING, MV_BIT_UP
4589 Ybug_nB, FALSE, TRUE,
4590 EL_BUG, ACTION_MOVING, MV_BIT_UP
4593 Ybug_e, FALSE, FALSE,
4594 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
4597 Ybug_eB, FALSE, TRUE,
4598 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
4601 Ybug_s, FALSE, FALSE,
4602 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
4605 Ybug_sB, FALSE, TRUE,
4606 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
4609 Ybug_w, FALSE, FALSE,
4610 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
4613 Ybug_wB, FALSE, TRUE,
4614 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
4617 Ybug_w_n, FALSE, FALSE,
4618 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
4621 Ybug_n_e, FALSE, FALSE,
4622 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
4625 Ybug_e_s, FALSE, FALSE,
4626 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
4629 Ybug_s_w, FALSE, FALSE,
4630 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
4633 Ybug_e_n, FALSE, FALSE,
4634 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
4637 Ybug_s_e, FALSE, FALSE,
4638 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
4641 Ybug_w_s, FALSE, FALSE,
4642 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
4645 Ybug_n_w, FALSE, FALSE,
4646 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
4649 Ybug_stone, FALSE, FALSE,
4650 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
4653 Ybug_spring, FALSE, FALSE,
4654 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
4657 Xtank_n, TRUE, FALSE,
4658 EL_SPACESHIP_UP, -1, -1
4661 Xtank_e, TRUE, FALSE,
4662 EL_SPACESHIP_RIGHT, -1, -1
4665 Xtank_s, TRUE, FALSE,
4666 EL_SPACESHIP_DOWN, -1, -1
4669 Xtank_w, TRUE, FALSE,
4670 EL_SPACESHIP_LEFT, -1, -1
4673 Xtank_gon, FALSE, FALSE,
4674 EL_SPACESHIP_UP, -1, -1
4677 Xtank_goe, FALSE, FALSE,
4678 EL_SPACESHIP_RIGHT, -1, -1
4681 Xtank_gos, FALSE, FALSE,
4682 EL_SPACESHIP_DOWN, -1, -1
4685 Xtank_gow, FALSE, FALSE,
4686 EL_SPACESHIP_LEFT, -1, -1
4689 Ytank_n, FALSE, FALSE,
4690 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
4693 Ytank_nB, FALSE, TRUE,
4694 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
4697 Ytank_e, FALSE, FALSE,
4698 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
4701 Ytank_eB, FALSE, TRUE,
4702 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
4705 Ytank_s, FALSE, FALSE,
4706 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
4709 Ytank_sB, FALSE, TRUE,
4710 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
4713 Ytank_w, FALSE, FALSE,
4714 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
4717 Ytank_wB, FALSE, TRUE,
4718 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
4721 Ytank_w_n, FALSE, FALSE,
4722 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
4725 Ytank_n_e, FALSE, FALSE,
4726 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
4729 Ytank_e_s, FALSE, FALSE,
4730 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
4733 Ytank_s_w, FALSE, FALSE,
4734 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
4737 Ytank_e_n, FALSE, FALSE,
4738 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
4741 Ytank_s_e, FALSE, FALSE,
4742 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
4745 Ytank_w_s, FALSE, FALSE,
4746 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
4749 Ytank_n_w, FALSE, FALSE,
4750 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
4753 Ytank_stone, FALSE, FALSE,
4754 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
4757 Ytank_spring, FALSE, FALSE,
4758 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
4761 Xandroid, TRUE, FALSE,
4762 EL_EMC_ANDROID, ACTION_ACTIVE, -1
4765 Xandroid_1_n, FALSE, FALSE,
4766 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
4769 Xandroid_2_n, FALSE, FALSE,
4770 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
4773 Xandroid_1_e, FALSE, FALSE,
4774 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
4777 Xandroid_2_e, FALSE, FALSE,
4778 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
4781 Xandroid_1_w, FALSE, FALSE,
4782 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
4785 Xandroid_2_w, FALSE, FALSE,
4786 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
4789 Xandroid_1_s, FALSE, FALSE,
4790 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
4793 Xandroid_2_s, FALSE, FALSE,
4794 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
4797 Yandroid_n, FALSE, FALSE,
4798 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
4801 Yandroid_nB, FALSE, TRUE,
4802 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
4805 Yandroid_ne, FALSE, FALSE,
4806 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
4809 Yandroid_neB, FALSE, TRUE,
4810 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
4813 Yandroid_e, FALSE, FALSE,
4814 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
4817 Yandroid_eB, FALSE, TRUE,
4818 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
4821 Yandroid_se, FALSE, FALSE,
4822 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
4825 Yandroid_seB, FALSE, TRUE,
4826 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
4829 Yandroid_s, FALSE, FALSE,
4830 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
4833 Yandroid_sB, FALSE, TRUE,
4834 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
4837 Yandroid_sw, FALSE, FALSE,
4838 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
4841 Yandroid_swB, FALSE, TRUE,
4842 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
4845 Yandroid_w, FALSE, FALSE,
4846 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
4849 Yandroid_wB, FALSE, TRUE,
4850 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
4853 Yandroid_nw, FALSE, FALSE,
4854 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
4857 Yandroid_nwB, FALSE, TRUE,
4858 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
4861 Xspring, TRUE, FALSE,
4865 Xspring_pause, FALSE, FALSE,
4869 Xspring_e, FALSE, FALSE,
4873 Xspring_w, FALSE, FALSE,
4877 Xspring_fall, FALSE, FALSE,
4881 Yspring_s, FALSE, FALSE,
4882 EL_SPRING, ACTION_FALLING, -1
4885 Yspring_sB, FALSE, TRUE,
4886 EL_SPRING, ACTION_FALLING, -1
4889 Yspring_e, FALSE, FALSE,
4890 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
4893 Yspring_eB, FALSE, TRUE,
4894 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
4897 Yspring_w, FALSE, FALSE,
4898 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
4901 Yspring_wB, FALSE, TRUE,
4902 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
4905 Yspring_kill_e, FALSE, FALSE,
4906 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
4909 Yspring_kill_eB, FALSE, TRUE,
4910 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
4913 Yspring_kill_w, FALSE, FALSE,
4914 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
4917 Yspring_kill_wB, FALSE, TRUE,
4918 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
4921 Xeater_n, TRUE, FALSE,
4922 EL_YAMYAM_UP, -1, -1
4925 Xeater_e, TRUE, FALSE,
4926 EL_YAMYAM_RIGHT, -1, -1
4929 Xeater_w, TRUE, FALSE,
4930 EL_YAMYAM_LEFT, -1, -1
4933 Xeater_s, TRUE, FALSE,
4934 EL_YAMYAM_DOWN, -1, -1
4937 Yeater_n, FALSE, FALSE,
4938 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
4941 Yeater_nB, FALSE, TRUE,
4942 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
4945 Yeater_e, FALSE, FALSE,
4946 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
4949 Yeater_eB, FALSE, TRUE,
4950 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
4953 Yeater_s, FALSE, FALSE,
4954 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
4957 Yeater_sB, FALSE, TRUE,
4958 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
4961 Yeater_w, FALSE, FALSE,
4962 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
4965 Yeater_wB, FALSE, TRUE,
4966 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
4969 Yeater_stone, FALSE, FALSE,
4970 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
4973 Yeater_spring, FALSE, FALSE,
4974 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
4977 Xalien, TRUE, FALSE,
4981 Xalien_pause, FALSE, FALSE,
4985 Yalien_n, FALSE, FALSE,
4986 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
4989 Yalien_nB, FALSE, TRUE,
4990 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
4993 Yalien_e, FALSE, FALSE,
4994 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
4997 Yalien_eB, FALSE, TRUE,
4998 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
5001 Yalien_s, FALSE, FALSE,
5002 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
5005 Yalien_sB, FALSE, TRUE,
5006 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
5009 Yalien_w, FALSE, FALSE,
5010 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
5013 Yalien_wB, FALSE, TRUE,
5014 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
5017 Yalien_stone, FALSE, FALSE,
5018 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
5021 Yalien_spring, FALSE, FALSE,
5022 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
5025 Xemerald, TRUE, FALSE,
5029 Xemerald_pause, FALSE, FALSE,
5033 Xemerald_fall, FALSE, FALSE,
5037 Xemerald_shine, FALSE, FALSE,
5038 EL_EMERALD, ACTION_TWINKLING, -1
5041 Yemerald_s, FALSE, FALSE,
5042 EL_EMERALD, ACTION_FALLING, -1
5045 Yemerald_sB, FALSE, TRUE,
5046 EL_EMERALD, ACTION_FALLING, -1
5049 Yemerald_e, FALSE, FALSE,
5050 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
5053 Yemerald_eB, FALSE, TRUE,
5054 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
5057 Yemerald_w, FALSE, FALSE,
5058 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
5061 Yemerald_wB, FALSE, TRUE,
5062 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
5065 Yemerald_eat, FALSE, FALSE,
5066 EL_EMERALD, ACTION_COLLECTING, -1
5069 Yemerald_stone, FALSE, FALSE,
5070 EL_NUT, ACTION_BREAKING, -1
5073 Xdiamond, TRUE, FALSE,
5077 Xdiamond_pause, FALSE, FALSE,
5081 Xdiamond_fall, FALSE, FALSE,
5085 Xdiamond_shine, FALSE, FALSE,
5086 EL_DIAMOND, ACTION_TWINKLING, -1
5089 Ydiamond_s, FALSE, FALSE,
5090 EL_DIAMOND, ACTION_FALLING, -1
5093 Ydiamond_sB, FALSE, TRUE,
5094 EL_DIAMOND, ACTION_FALLING, -1
5097 Ydiamond_e, FALSE, FALSE,
5098 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
5101 Ydiamond_eB, FALSE, TRUE,
5102 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
5105 Ydiamond_w, FALSE, FALSE,
5106 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
5109 Ydiamond_wB, FALSE, TRUE,
5110 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
5113 Ydiamond_eat, FALSE, FALSE,
5114 EL_DIAMOND, ACTION_COLLECTING, -1
5117 Ydiamond_stone, FALSE, FALSE,
5118 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
5121 Xdrip_fall, TRUE, FALSE,
5122 EL_AMOEBA_DROP, -1, -1
5125 Xdrip_stretch, FALSE, FALSE,
5126 EL_AMOEBA_DROP, ACTION_FALLING, -1
5129 Xdrip_stretchB, FALSE, TRUE,
5130 EL_AMOEBA_DROP, ACTION_FALLING, -1
5133 Xdrip_eat, FALSE, FALSE,
5134 EL_AMOEBA_DROP, ACTION_GROWING, -1
5137 Ydrip_s1, FALSE, FALSE,
5138 EL_AMOEBA_DROP, ACTION_FALLING, -1
5141 Ydrip_s1B, FALSE, TRUE,
5142 EL_AMOEBA_DROP, ACTION_FALLING, -1
5145 Ydrip_s2, FALSE, FALSE,
5146 EL_AMOEBA_DROP, ACTION_FALLING, -1
5149 Ydrip_s2B, FALSE, TRUE,
5150 EL_AMOEBA_DROP, ACTION_FALLING, -1
5157 Xbomb_pause, FALSE, FALSE,
5161 Xbomb_fall, FALSE, FALSE,
5165 Ybomb_s, FALSE, FALSE,
5166 EL_BOMB, ACTION_FALLING, -1
5169 Ybomb_sB, FALSE, TRUE,
5170 EL_BOMB, ACTION_FALLING, -1
5173 Ybomb_e, FALSE, FALSE,
5174 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
5177 Ybomb_eB, FALSE, TRUE,
5178 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
5181 Ybomb_w, FALSE, FALSE,
5182 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
5185 Ybomb_wB, FALSE, TRUE,
5186 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
5189 Ybomb_eat, FALSE, FALSE,
5190 EL_BOMB, ACTION_ACTIVATING, -1
5193 Xballoon, TRUE, FALSE,
5197 Yballoon_n, FALSE, FALSE,
5198 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
5201 Yballoon_nB, FALSE, TRUE,
5202 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
5205 Yballoon_e, FALSE, FALSE,
5206 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
5209 Yballoon_eB, FALSE, TRUE,
5210 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
5213 Yballoon_s, FALSE, FALSE,
5214 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
5217 Yballoon_sB, FALSE, TRUE,
5218 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
5221 Yballoon_w, FALSE, FALSE,
5222 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
5225 Yballoon_wB, FALSE, TRUE,
5226 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
5229 Xgrass, TRUE, FALSE,
5230 EL_EMC_GRASS, -1, -1
5233 Ygrass_nB, FALSE, FALSE,
5234 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
5237 Ygrass_eB, FALSE, FALSE,
5238 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
5241 Ygrass_sB, FALSE, FALSE,
5242 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
5245 Ygrass_wB, FALSE, FALSE,
5246 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
5253 Ydirt_nB, FALSE, FALSE,
5254 EL_SAND, ACTION_DIGGING, MV_BIT_UP
5257 Ydirt_eB, FALSE, FALSE,
5258 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
5261 Ydirt_sB, FALSE, FALSE,
5262 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
5265 Ydirt_wB, FALSE, FALSE,
5266 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
5269 Xacid_ne, TRUE, FALSE,
5270 EL_ACID_POOL_TOPRIGHT, -1, -1
5273 Xacid_se, TRUE, FALSE,
5274 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
5277 Xacid_s, TRUE, FALSE,
5278 EL_ACID_POOL_BOTTOM, -1, -1
5281 Xacid_sw, TRUE, FALSE,
5282 EL_ACID_POOL_BOTTOMLEFT, -1, -1
5285 Xacid_nw, TRUE, FALSE,
5286 EL_ACID_POOL_TOPLEFT, -1, -1
5289 Xacid_1, TRUE, FALSE,
5293 Xacid_2, FALSE, FALSE,
5297 Xacid_3, FALSE, FALSE,
5301 Xacid_4, FALSE, FALSE,
5305 Xacid_5, FALSE, FALSE,
5309 Xacid_6, FALSE, FALSE,
5313 Xacid_7, FALSE, FALSE,
5317 Xacid_8, FALSE, FALSE,
5321 Xball_1, TRUE, FALSE,
5322 EL_EMC_MAGIC_BALL, -1, -1
5325 Xball_1B, FALSE, FALSE,
5326 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5329 Xball_2, FALSE, FALSE,
5330 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5333 Xball_2B, FALSE, FALSE,
5334 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5337 Yball_eat, FALSE, FALSE,
5338 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
5341 Ykey_1_eat, FALSE, FALSE,
5342 EL_EM_KEY_1, ACTION_COLLECTING, -1
5345 Ykey_2_eat, FALSE, FALSE,
5346 EL_EM_KEY_2, ACTION_COLLECTING, -1
5349 Ykey_3_eat, FALSE, FALSE,
5350 EL_EM_KEY_3, ACTION_COLLECTING, -1
5353 Ykey_4_eat, FALSE, FALSE,
5354 EL_EM_KEY_4, ACTION_COLLECTING, -1
5357 Ykey_5_eat, FALSE, FALSE,
5358 EL_EMC_KEY_5, ACTION_COLLECTING, -1
5361 Ykey_6_eat, FALSE, FALSE,
5362 EL_EMC_KEY_6, ACTION_COLLECTING, -1
5365 Ykey_7_eat, FALSE, FALSE,
5366 EL_EMC_KEY_7, ACTION_COLLECTING, -1
5369 Ykey_8_eat, FALSE, FALSE,
5370 EL_EMC_KEY_8, ACTION_COLLECTING, -1
5373 Ylenses_eat, FALSE, FALSE,
5374 EL_EMC_LENSES, ACTION_COLLECTING, -1
5377 Ymagnify_eat, FALSE, FALSE,
5378 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
5381 Ygrass_eat, FALSE, FALSE,
5382 EL_EMC_GRASS, ACTION_SNAPPING, -1
5385 Ydirt_eat, FALSE, FALSE,
5386 EL_SAND, ACTION_SNAPPING, -1
5389 Xgrow_ns, TRUE, FALSE,
5390 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
5393 Ygrow_ns_eat, FALSE, FALSE,
5394 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
5397 Xgrow_ew, TRUE, FALSE,
5398 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
5401 Ygrow_ew_eat, FALSE, FALSE,
5402 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
5405 Xwonderwall, TRUE, FALSE,
5406 EL_MAGIC_WALL, -1, -1
5409 XwonderwallB, FALSE, FALSE,
5410 EL_MAGIC_WALL, ACTION_ACTIVE, -1
5413 Xamoeba_1, TRUE, FALSE,
5414 EL_AMOEBA_DRY, ACTION_OTHER, -1
5417 Xamoeba_2, FALSE, FALSE,
5418 EL_AMOEBA_DRY, ACTION_OTHER, -1
5421 Xamoeba_3, FALSE, FALSE,
5422 EL_AMOEBA_DRY, ACTION_OTHER, -1
5425 Xamoeba_4, FALSE, FALSE,
5426 EL_AMOEBA_DRY, ACTION_OTHER, -1
5429 Xamoeba_5, TRUE, FALSE,
5430 EL_AMOEBA_WET, ACTION_OTHER, -1
5433 Xamoeba_6, FALSE, FALSE,
5434 EL_AMOEBA_WET, ACTION_OTHER, -1
5437 Xamoeba_7, FALSE, FALSE,
5438 EL_AMOEBA_WET, ACTION_OTHER, -1
5441 Xamoeba_8, FALSE, FALSE,
5442 EL_AMOEBA_WET, ACTION_OTHER, -1
5445 Xdoor_1, TRUE, FALSE,
5446 EL_EM_GATE_1, -1, -1
5449 Xdoor_2, TRUE, FALSE,
5450 EL_EM_GATE_2, -1, -1
5453 Xdoor_3, TRUE, FALSE,
5454 EL_EM_GATE_3, -1, -1
5457 Xdoor_4, TRUE, FALSE,
5458 EL_EM_GATE_4, -1, -1
5461 Xdoor_5, TRUE, FALSE,
5462 EL_EMC_GATE_5, -1, -1
5465 Xdoor_6, TRUE, FALSE,
5466 EL_EMC_GATE_6, -1, -1
5469 Xdoor_7, TRUE, FALSE,
5470 EL_EMC_GATE_7, -1, -1
5473 Xdoor_8, TRUE, FALSE,
5474 EL_EMC_GATE_8, -1, -1
5477 Xkey_1, TRUE, FALSE,
5481 Xkey_2, TRUE, FALSE,
5485 Xkey_3, TRUE, FALSE,
5489 Xkey_4, TRUE, FALSE,
5493 Xkey_5, TRUE, FALSE,
5494 EL_EMC_KEY_5, -1, -1
5497 Xkey_6, TRUE, FALSE,
5498 EL_EMC_KEY_6, -1, -1
5501 Xkey_7, TRUE, FALSE,
5502 EL_EMC_KEY_7, -1, -1
5505 Xkey_8, TRUE, FALSE,
5506 EL_EMC_KEY_8, -1, -1
5509 Xwind_n, TRUE, FALSE,
5510 EL_BALLOON_SWITCH_UP, -1, -1
5513 Xwind_e, TRUE, FALSE,
5514 EL_BALLOON_SWITCH_RIGHT, -1, -1
5517 Xwind_s, TRUE, FALSE,
5518 EL_BALLOON_SWITCH_DOWN, -1, -1
5521 Xwind_w, TRUE, FALSE,
5522 EL_BALLOON_SWITCH_LEFT, -1, -1
5525 Xwind_nesw, TRUE, FALSE,
5526 EL_BALLOON_SWITCH_ANY, -1, -1
5529 Xwind_stop, TRUE, FALSE,
5530 EL_BALLOON_SWITCH_NONE, -1, -1
5534 EL_EM_EXIT_CLOSED, -1, -1
5537 Xexit_1, TRUE, FALSE,
5538 EL_EM_EXIT_OPEN, -1, -1
5541 Xexit_2, FALSE, FALSE,
5542 EL_EM_EXIT_OPEN, -1, -1
5545 Xexit_3, FALSE, FALSE,
5546 EL_EM_EXIT_OPEN, -1, -1
5549 Xdynamite, TRUE, FALSE,
5550 EL_EM_DYNAMITE, -1, -1
5553 Ydynamite_eat, FALSE, FALSE,
5554 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
5557 Xdynamite_1, TRUE, FALSE,
5558 EL_EM_DYNAMITE_ACTIVE, -1, -1
5561 Xdynamite_2, FALSE, FALSE,
5562 EL_EM_DYNAMITE_ACTIVE, -1, -1
5565 Xdynamite_3, FALSE, FALSE,
5566 EL_EM_DYNAMITE_ACTIVE, -1, -1
5569 Xdynamite_4, FALSE, FALSE,
5570 EL_EM_DYNAMITE_ACTIVE, -1, -1
5573 Xbumper, TRUE, FALSE,
5574 EL_EMC_SPRING_BUMPER, -1, -1
5577 XbumperB, FALSE, FALSE,
5578 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
5581 Xwheel, TRUE, FALSE,
5582 EL_ROBOT_WHEEL, -1, -1
5585 XwheelB, FALSE, FALSE,
5586 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
5589 Xswitch, TRUE, FALSE,
5590 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
5593 XswitchB, FALSE, FALSE,
5594 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
5598 EL_QUICKSAND_EMPTY, -1, -1
5601 Xsand_stone, TRUE, FALSE,
5602 EL_QUICKSAND_FULL, -1, -1
5605 Xsand_stonein_1, FALSE, TRUE,
5606 EL_ROCK, ACTION_FILLING, -1
5609 Xsand_stonein_2, FALSE, TRUE,
5610 EL_ROCK, ACTION_FILLING, -1
5613 Xsand_stonein_3, FALSE, TRUE,
5614 EL_ROCK, ACTION_FILLING, -1
5617 Xsand_stonein_4, FALSE, TRUE,
5618 EL_ROCK, ACTION_FILLING, -1
5621 Xsand_stonesand_1, FALSE, FALSE,
5622 EL_QUICKSAND_EMPTYING, -1, -1
5625 Xsand_stonesand_2, FALSE, FALSE,
5626 EL_QUICKSAND_EMPTYING, -1, -1
5629 Xsand_stonesand_3, FALSE, FALSE,
5630 EL_QUICKSAND_EMPTYING, -1, -1
5633 Xsand_stonesand_4, FALSE, FALSE,
5634 EL_QUICKSAND_EMPTYING, -1, -1
5637 Xsand_stonesand_quickout_1, FALSE, FALSE,
5638 EL_QUICKSAND_EMPTYING, -1, -1
5641 Xsand_stonesand_quickout_2, FALSE, FALSE,
5642 EL_QUICKSAND_EMPTYING, -1, -1
5645 Xsand_stoneout_1, FALSE, FALSE,
5646 EL_ROCK, ACTION_EMPTYING, -1
5649 Xsand_stoneout_2, FALSE, FALSE,
5650 EL_ROCK, ACTION_EMPTYING, -1
5653 Xsand_sandstone_1, FALSE, FALSE,
5654 EL_QUICKSAND_FILLING, -1, -1
5657 Xsand_sandstone_2, FALSE, FALSE,
5658 EL_QUICKSAND_FILLING, -1, -1
5661 Xsand_sandstone_3, FALSE, FALSE,
5662 EL_QUICKSAND_FILLING, -1, -1
5665 Xsand_sandstone_4, FALSE, FALSE,
5666 EL_QUICKSAND_FILLING, -1, -1
5669 Xplant, TRUE, FALSE,
5670 EL_EMC_PLANT, -1, -1
5673 Yplant, FALSE, FALSE,
5674 EL_EMC_PLANT, -1, -1
5677 Xlenses, TRUE, FALSE,
5678 EL_EMC_LENSES, -1, -1
5681 Xmagnify, TRUE, FALSE,
5682 EL_EMC_MAGNIFIER, -1, -1
5685 Xdripper, TRUE, FALSE,
5686 EL_EMC_DRIPPER, -1, -1
5689 XdripperB, FALSE, FALSE,
5690 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
5693 Xfake_blank, TRUE, FALSE,
5694 EL_INVISIBLE_WALL, -1, -1
5697 Xfake_blankB, FALSE, FALSE,
5698 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
5701 Xfake_grass, TRUE, FALSE,
5702 EL_EMC_FAKE_GRASS, -1, -1
5705 Xfake_grassB, FALSE, FALSE,
5706 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
5709 Xfake_door_1, TRUE, FALSE,
5710 EL_EM_GATE_1_GRAY, -1, -1
5713 Xfake_door_2, TRUE, FALSE,
5714 EL_EM_GATE_2_GRAY, -1, -1
5717 Xfake_door_3, TRUE, FALSE,
5718 EL_EM_GATE_3_GRAY, -1, -1
5721 Xfake_door_4, TRUE, FALSE,
5722 EL_EM_GATE_4_GRAY, -1, -1
5725 Xfake_door_5, TRUE, FALSE,
5726 EL_EMC_GATE_5_GRAY, -1, -1
5729 Xfake_door_6, TRUE, FALSE,
5730 EL_EMC_GATE_6_GRAY, -1, -1
5733 Xfake_door_7, TRUE, FALSE,
5734 EL_EMC_GATE_7_GRAY, -1, -1
5737 Xfake_door_8, TRUE, FALSE,
5738 EL_EMC_GATE_8_GRAY, -1, -1
5741 Xfake_acid_1, TRUE, FALSE,
5742 EL_EMC_FAKE_ACID, -1, -1
5745 Xfake_acid_2, FALSE, FALSE,
5746 EL_EMC_FAKE_ACID, -1, -1
5749 Xfake_acid_3, FALSE, FALSE,
5750 EL_EMC_FAKE_ACID, -1, -1
5753 Xfake_acid_4, FALSE, FALSE,
5754 EL_EMC_FAKE_ACID, -1, -1
5757 Xfake_acid_5, FALSE, FALSE,
5758 EL_EMC_FAKE_ACID, -1, -1
5761 Xfake_acid_6, FALSE, FALSE,
5762 EL_EMC_FAKE_ACID, -1, -1
5765 Xfake_acid_7, FALSE, FALSE,
5766 EL_EMC_FAKE_ACID, -1, -1
5769 Xfake_acid_8, FALSE, FALSE,
5770 EL_EMC_FAKE_ACID, -1, -1
5773 Xsteel_1, TRUE, FALSE,
5774 EL_STEELWALL, -1, -1
5777 Xsteel_2, TRUE, FALSE,
5778 EL_EMC_STEELWALL_2, -1, -1
5781 Xsteel_3, TRUE, FALSE,
5782 EL_EMC_STEELWALL_3, -1, -1
5785 Xsteel_4, TRUE, FALSE,
5786 EL_EMC_STEELWALL_4, -1, -1
5789 Xwall_1, TRUE, FALSE,
5793 Xwall_2, TRUE, FALSE,
5794 EL_EMC_WALL_14, -1, -1
5797 Xwall_3, TRUE, FALSE,
5798 EL_EMC_WALL_15, -1, -1
5801 Xwall_4, TRUE, FALSE,
5802 EL_EMC_WALL_16, -1, -1
5805 Xround_wall_1, TRUE, FALSE,
5806 EL_WALL_SLIPPERY, -1, -1
5809 Xround_wall_2, TRUE, FALSE,
5810 EL_EMC_WALL_SLIPPERY_2, -1, -1
5813 Xround_wall_3, TRUE, FALSE,
5814 EL_EMC_WALL_SLIPPERY_3, -1, -1
5817 Xround_wall_4, TRUE, FALSE,
5818 EL_EMC_WALL_SLIPPERY_4, -1, -1
5821 Xdecor_1, TRUE, FALSE,
5822 EL_EMC_WALL_8, -1, -1
5825 Xdecor_2, TRUE, FALSE,
5826 EL_EMC_WALL_6, -1, -1
5829 Xdecor_3, TRUE, FALSE,
5830 EL_EMC_WALL_4, -1, -1
5833 Xdecor_4, TRUE, FALSE,
5834 EL_EMC_WALL_7, -1, -1
5837 Xdecor_5, TRUE, FALSE,
5838 EL_EMC_WALL_5, -1, -1
5841 Xdecor_6, TRUE, FALSE,
5842 EL_EMC_WALL_9, -1, -1
5845 Xdecor_7, TRUE, FALSE,
5846 EL_EMC_WALL_10, -1, -1
5849 Xdecor_8, TRUE, FALSE,
5850 EL_EMC_WALL_1, -1, -1
5853 Xdecor_9, TRUE, FALSE,
5854 EL_EMC_WALL_2, -1, -1
5857 Xdecor_10, TRUE, FALSE,
5858 EL_EMC_WALL_3, -1, -1
5861 Xdecor_11, TRUE, FALSE,
5862 EL_EMC_WALL_11, -1, -1
5865 Xdecor_12, TRUE, FALSE,
5866 EL_EMC_WALL_12, -1, -1
5869 Xalpha_0, TRUE, FALSE,
5870 EL_CHAR('0'), -1, -1
5873 Xalpha_1, TRUE, FALSE,
5874 EL_CHAR('1'), -1, -1
5877 Xalpha_2, TRUE, FALSE,
5878 EL_CHAR('2'), -1, -1
5881 Xalpha_3, TRUE, FALSE,
5882 EL_CHAR('3'), -1, -1
5885 Xalpha_4, TRUE, FALSE,
5886 EL_CHAR('4'), -1, -1
5889 Xalpha_5, TRUE, FALSE,
5890 EL_CHAR('5'), -1, -1
5893 Xalpha_6, TRUE, FALSE,
5894 EL_CHAR('6'), -1, -1
5897 Xalpha_7, TRUE, FALSE,
5898 EL_CHAR('7'), -1, -1
5901 Xalpha_8, TRUE, FALSE,
5902 EL_CHAR('8'), -1, -1
5905 Xalpha_9, TRUE, FALSE,
5906 EL_CHAR('9'), -1, -1
5909 Xalpha_excla, TRUE, FALSE,
5910 EL_CHAR('!'), -1, -1
5913 Xalpha_quote, TRUE, FALSE,
5914 EL_CHAR('"'), -1, -1
5917 Xalpha_comma, TRUE, FALSE,
5918 EL_CHAR(','), -1, -1
5921 Xalpha_minus, TRUE, FALSE,
5922 EL_CHAR('-'), -1, -1
5925 Xalpha_perio, TRUE, FALSE,
5926 EL_CHAR('.'), -1, -1
5929 Xalpha_colon, TRUE, FALSE,
5930 EL_CHAR(':'), -1, -1
5933 Xalpha_quest, TRUE, FALSE,
5934 EL_CHAR('?'), -1, -1
5937 Xalpha_a, TRUE, FALSE,
5938 EL_CHAR('A'), -1, -1
5941 Xalpha_b, TRUE, FALSE,
5942 EL_CHAR('B'), -1, -1
5945 Xalpha_c, TRUE, FALSE,
5946 EL_CHAR('C'), -1, -1
5949 Xalpha_d, TRUE, FALSE,
5950 EL_CHAR('D'), -1, -1
5953 Xalpha_e, TRUE, FALSE,
5954 EL_CHAR('E'), -1, -1
5957 Xalpha_f, TRUE, FALSE,
5958 EL_CHAR('F'), -1, -1
5961 Xalpha_g, TRUE, FALSE,
5962 EL_CHAR('G'), -1, -1
5965 Xalpha_h, TRUE, FALSE,
5966 EL_CHAR('H'), -1, -1
5969 Xalpha_i, TRUE, FALSE,
5970 EL_CHAR('I'), -1, -1
5973 Xalpha_j, TRUE, FALSE,
5974 EL_CHAR('J'), -1, -1
5977 Xalpha_k, TRUE, FALSE,
5978 EL_CHAR('K'), -1, -1
5981 Xalpha_l, TRUE, FALSE,
5982 EL_CHAR('L'), -1, -1
5985 Xalpha_m, TRUE, FALSE,
5986 EL_CHAR('M'), -1, -1
5989 Xalpha_n, TRUE, FALSE,
5990 EL_CHAR('N'), -1, -1
5993 Xalpha_o, TRUE, FALSE,
5994 EL_CHAR('O'), -1, -1
5997 Xalpha_p, TRUE, FALSE,
5998 EL_CHAR('P'), -1, -1
6001 Xalpha_q, TRUE, FALSE,
6002 EL_CHAR('Q'), -1, -1
6005 Xalpha_r, TRUE, FALSE,
6006 EL_CHAR('R'), -1, -1
6009 Xalpha_s, TRUE, FALSE,
6010 EL_CHAR('S'), -1, -1
6013 Xalpha_t, TRUE, FALSE,
6014 EL_CHAR('T'), -1, -1
6017 Xalpha_u, TRUE, FALSE,
6018 EL_CHAR('U'), -1, -1
6021 Xalpha_v, TRUE, FALSE,
6022 EL_CHAR('V'), -1, -1
6025 Xalpha_w, TRUE, FALSE,
6026 EL_CHAR('W'), -1, -1
6029 Xalpha_x, TRUE, FALSE,
6030 EL_CHAR('X'), -1, -1
6033 Xalpha_y, TRUE, FALSE,
6034 EL_CHAR('Y'), -1, -1
6037 Xalpha_z, TRUE, FALSE,
6038 EL_CHAR('Z'), -1, -1
6041 Xalpha_arrow_e, TRUE, FALSE,
6042 EL_CHAR('>'), -1, -1
6045 Xalpha_arrow_w, TRUE, FALSE,
6046 EL_CHAR('<'), -1, -1
6049 Xalpha_copyr, TRUE, FALSE,
6050 EL_CHAR(CHAR_BYTE_COPYRIGHT), -1, -1
6054 Xboom_bug, FALSE, FALSE,
6055 EL_BUG, ACTION_EXPLODING, -1
6058 Xboom_bomb, FALSE, FALSE,
6059 EL_BOMB, ACTION_EXPLODING, -1
6062 Xboom_android, FALSE, FALSE,
6063 EL_EMC_ANDROID, ACTION_OTHER, -1
6066 Xboom_1, FALSE, FALSE,
6067 EL_DEFAULT, ACTION_EXPLODING, -1
6070 Xboom_2, FALSE, FALSE,
6071 EL_DEFAULT, ACTION_EXPLODING, -1
6074 Znormal, FALSE, FALSE,
6078 Zdynamite, FALSE, FALSE,
6082 Zplayer, FALSE, FALSE,
6086 ZBORDER, FALSE, FALSE,
6096 static struct Mapping_EM_to_RND_player
6105 em_player_mapping_list[] =
6109 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
6113 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
6117 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
6121 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
6125 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
6129 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
6133 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
6137 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
6141 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
6145 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
6149 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
6153 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
6157 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
6161 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
6165 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
6169 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
6173 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
6177 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
6181 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
6185 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
6189 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
6193 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
6197 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
6201 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
6205 EL_PLAYER_1, ACTION_DEFAULT, -1,
6209 EL_PLAYER_2, ACTION_DEFAULT, -1,
6213 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
6217 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
6221 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
6225 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
6229 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
6233 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
6237 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
6241 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
6245 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
6249 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
6253 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
6257 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
6261 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
6265 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
6269 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
6273 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
6277 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
6281 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
6285 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
6289 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
6293 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
6297 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
6301 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
6305 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
6309 EL_PLAYER_3, ACTION_DEFAULT, -1,
6313 EL_PLAYER_4, ACTION_DEFAULT, -1,
6322 int map_element_RND_to_EM(int element_rnd)
6324 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
6325 static boolean mapping_initialized = FALSE;
6327 if (!mapping_initialized)
6331 /* return "Xalpha_quest" for all undefined elements in mapping array */
6332 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
6333 mapping_RND_to_EM[i] = Xalpha_quest;
6335 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6336 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
6337 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
6338 em_object_mapping_list[i].element_em;
6340 mapping_initialized = TRUE;
6343 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
6344 return mapping_RND_to_EM[element_rnd];
6346 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
6351 int map_element_EM_to_RND(int element_em)
6353 static unsigned short mapping_EM_to_RND[TILE_MAX];
6354 static boolean mapping_initialized = FALSE;
6356 if (!mapping_initialized)
6360 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
6361 for (i = 0; i < TILE_MAX; i++)
6362 mapping_EM_to_RND[i] = EL_UNKNOWN;
6364 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6365 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
6366 em_object_mapping_list[i].element_rnd;
6368 mapping_initialized = TRUE;
6371 if (element_em >= 0 && element_em < TILE_MAX)
6372 return mapping_EM_to_RND[element_em];
6374 Error(ERR_WARN, "invalid EM level element %d", element_em);
6379 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
6381 struct LevelInfo_EM *level_em = level->native_em_level;
6382 struct LEVEL *lev = level_em->lev;
6385 for (i = 0; i < TILE_MAX; i++)
6386 lev->android_array[i] = Xblank;
6388 for (i = 0; i < level->num_android_clone_elements; i++)
6390 int element_rnd = level->android_clone_element[i];
6391 int element_em = map_element_RND_to_EM(element_rnd);
6393 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
6394 if (em_object_mapping_list[j].element_rnd == element_rnd)
6395 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
6399 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
6401 struct LevelInfo_EM *level_em = level->native_em_level;
6402 struct LEVEL *lev = level_em->lev;
6405 level->num_android_clone_elements = 0;
6407 for (i = 0; i < TILE_MAX; i++)
6409 int element_em = lev->android_array[i];
6411 boolean element_found = FALSE;
6413 if (element_em == Xblank)
6416 element_rnd = map_element_EM_to_RND(element_em);
6418 for (j = 0; j < level->num_android_clone_elements; j++)
6419 if (level->android_clone_element[j] == element_rnd)
6420 element_found = TRUE;
6424 level->android_clone_element[level->num_android_clone_elements++] =
6427 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
6432 if (level->num_android_clone_elements == 0)
6434 level->num_android_clone_elements = 1;
6435 level->android_clone_element[0] = EL_EMPTY;
6439 int map_direction_RND_to_EM(int direction)
6441 return (direction == MV_UP ? 0 :
6442 direction == MV_RIGHT ? 1 :
6443 direction == MV_DOWN ? 2 :
6444 direction == MV_LEFT ? 3 :
6448 int map_direction_EM_to_RND(int direction)
6450 return (direction == 0 ? MV_UP :
6451 direction == 1 ? MV_RIGHT :
6452 direction == 2 ? MV_DOWN :
6453 direction == 3 ? MV_LEFT :
6457 int map_element_RND_to_SP(int element_rnd)
6459 int element_sp = 0x20; /* map unknown elements to yellow "hardware" */
6461 if (element_rnd >= EL_SP_START &&
6462 element_rnd <= EL_SP_END)
6463 element_sp = element_rnd - EL_SP_START;
6464 else if (element_rnd == EL_EMPTY_SPACE)
6466 else if (element_rnd == EL_INVISIBLE_WALL)
6472 int map_element_SP_to_RND(int element_sp)
6474 int element_rnd = EL_UNKNOWN;
6476 if (element_sp >= 0x00 &&
6478 element_rnd = EL_SP_START + element_sp;
6479 else if (element_sp == 0x28)
6480 element_rnd = EL_INVISIBLE_WALL;
6485 int map_action_SP_to_RND(int action_sp)
6489 case actActive: return ACTION_ACTIVE;
6490 case actImpact: return ACTION_IMPACT;
6491 case actExploding: return ACTION_EXPLODING;
6492 case actDigging: return ACTION_DIGGING;
6493 case actSnapping: return ACTION_SNAPPING;
6494 case actCollecting: return ACTION_COLLECTING;
6495 case actPassing: return ACTION_PASSING;
6496 case actPushing: return ACTION_PUSHING;
6497 case actDropping: return ACTION_DROPPING;
6499 default: return ACTION_DEFAULT;
6503 int get_next_element(int element)
6507 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
6508 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
6509 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
6510 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
6511 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
6512 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
6513 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
6514 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
6515 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
6516 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
6517 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
6519 default: return element;
6523 int el_act_dir2img(int element, int action, int direction)
6525 element = GFX_ELEMENT(element);
6526 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
6528 /* direction_graphic[][] == graphic[] for undefined direction graphics */
6529 return element_info[element].direction_graphic[action][direction];
6532 static int el_act_dir2crm(int element, int action, int direction)
6534 element = GFX_ELEMENT(element);
6535 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
6537 /* direction_graphic[][] == graphic[] for undefined direction graphics */
6538 return element_info[element].direction_crumbled[action][direction];
6541 int el_act2img(int element, int action)
6543 element = GFX_ELEMENT(element);
6545 return element_info[element].graphic[action];
6548 int el_act2crm(int element, int action)
6550 element = GFX_ELEMENT(element);
6552 return element_info[element].crumbled[action];
6555 int el_dir2img(int element, int direction)
6557 element = GFX_ELEMENT(element);
6559 return el_act_dir2img(element, ACTION_DEFAULT, direction);
6562 int el2baseimg(int element)
6564 return element_info[element].graphic[ACTION_DEFAULT];
6567 int el2img(int element)
6569 element = GFX_ELEMENT(element);
6571 return element_info[element].graphic[ACTION_DEFAULT];
6574 int el2edimg(int element)
6576 element = GFX_ELEMENT(element);
6578 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
6581 int el2preimg(int element)
6583 element = GFX_ELEMENT(element);
6585 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
6588 int el2panelimg(int element)
6590 element = GFX_ELEMENT(element);
6592 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL];
6595 int font2baseimg(int font_nr)
6597 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
6600 int getBeltNrFromBeltElement(int element)
6602 return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
6603 element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
6604 element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
6607 int getBeltNrFromBeltActiveElement(int element)
6609 return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
6610 element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
6611 element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
6614 int getBeltNrFromBeltSwitchElement(int element)
6616 return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
6617 element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
6618 element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
6621 int getBeltDirNrFromBeltElement(int element)
6623 static int belt_base_element[4] =
6625 EL_CONVEYOR_BELT_1_LEFT,
6626 EL_CONVEYOR_BELT_2_LEFT,
6627 EL_CONVEYOR_BELT_3_LEFT,
6628 EL_CONVEYOR_BELT_4_LEFT
6631 int belt_nr = getBeltNrFromBeltElement(element);
6632 int belt_dir_nr = element - belt_base_element[belt_nr];
6634 return (belt_dir_nr % 3);
6637 int getBeltDirNrFromBeltSwitchElement(int element)
6639 static int belt_base_element[4] =
6641 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
6642 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
6643 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
6644 EL_CONVEYOR_BELT_4_SWITCH_LEFT
6647 int belt_nr = getBeltNrFromBeltSwitchElement(element);
6648 int belt_dir_nr = element - belt_base_element[belt_nr];
6650 return (belt_dir_nr % 3);
6653 int getBeltDirFromBeltElement(int element)
6655 static int belt_move_dir[3] =
6662 int belt_dir_nr = getBeltDirNrFromBeltElement(element);
6664 return belt_move_dir[belt_dir_nr];
6667 int getBeltDirFromBeltSwitchElement(int element)
6669 static int belt_move_dir[3] =
6676 int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
6678 return belt_move_dir[belt_dir_nr];
6681 int getBeltElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
6683 static int belt_base_element[4] =
6685 EL_CONVEYOR_BELT_1_LEFT,
6686 EL_CONVEYOR_BELT_2_LEFT,
6687 EL_CONVEYOR_BELT_3_LEFT,
6688 EL_CONVEYOR_BELT_4_LEFT
6691 return belt_base_element[belt_nr] + belt_dir_nr;
6694 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
6696 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
6698 return getBeltElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
6701 int getBeltSwitchElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
6703 static int belt_base_element[4] =
6705 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
6706 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
6707 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
6708 EL_CONVEYOR_BELT_4_SWITCH_LEFT
6711 return belt_base_element[belt_nr] + belt_dir_nr;
6714 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
6716 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
6718 return getBeltSwitchElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
6721 boolean getTeamMode_EM()
6723 return game.team_mode;
6726 int getGameFrameDelay_EM(int native_em_game_frame_delay)
6728 int game_frame_delay_value;
6730 game_frame_delay_value =
6731 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
6732 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
6735 if (tape.playing && tape.warp_forward && !tape.pausing)
6736 game_frame_delay_value = 0;
6738 return game_frame_delay_value;
6741 unsigned int InitRND(int seed)
6743 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
6744 return InitEngineRandom_EM(seed);
6745 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
6746 return InitEngineRandom_SP(seed);
6748 return InitEngineRandom_RND(seed);
6751 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
6752 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
6754 inline static int get_effective_element_EM(int tile, int frame_em)
6756 int element = object_mapping[tile].element_rnd;
6757 int action = object_mapping[tile].action;
6758 boolean is_backside = object_mapping[tile].is_backside;
6759 boolean action_removing = (action == ACTION_DIGGING ||
6760 action == ACTION_SNAPPING ||
6761 action == ACTION_COLLECTING);
6767 case Yacid_splash_eB:
6768 case Yacid_splash_wB:
6769 return (frame_em > 5 ? EL_EMPTY : element);
6775 else /* frame_em == 7 */
6779 case Yacid_splash_eB:
6780 case Yacid_splash_wB:
6783 case Yemerald_stone:
6786 case Ydiamond_stone:
6790 case Xdrip_stretchB:
6809 case Xsand_stonein_1:
6810 case Xsand_stonein_2:
6811 case Xsand_stonein_3:
6812 case Xsand_stonein_4:
6816 return (is_backside || action_removing ? EL_EMPTY : element);
6821 inline static boolean check_linear_animation_EM(int tile)
6825 case Xsand_stonesand_1:
6826 case Xsand_stonesand_quickout_1:
6827 case Xsand_sandstone_1:
6828 case Xsand_stonein_1:
6829 case Xsand_stoneout_1:
6848 case Yacid_splash_eB:
6849 case Yacid_splash_wB:
6850 case Yemerald_stone:
6857 inline static void set_crumbled_graphics_EM(struct GraphicInfo_EM *g_em,
6858 boolean has_crumbled_graphics,
6859 int crumbled, int sync_frame)
6861 /* if element can be crumbled, but certain action graphics are just empty
6862 space (like instantly snapping sand to empty space in 1 frame), do not
6863 treat these empty space graphics as crumbled graphics in EMC engine */
6864 if (crumbled == IMG_EMPTY_SPACE)
6865 has_crumbled_graphics = FALSE;
6867 if (has_crumbled_graphics)
6869 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
6870 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
6871 g_crumbled->anim_delay,
6872 g_crumbled->anim_mode,
6873 g_crumbled->anim_start_frame,
6876 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
6877 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
6879 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
6881 g_em->has_crumbled_graphics = TRUE;
6885 g_em->crumbled_bitmap = NULL;
6886 g_em->crumbled_src_x = 0;
6887 g_em->crumbled_src_y = 0;
6888 g_em->crumbled_border_size = 0;
6890 g_em->has_crumbled_graphics = FALSE;
6894 void ResetGfxAnimation_EM(int x, int y, int tile)
6899 void SetGfxAnimation_EM(struct GraphicInfo_EM *g_em,
6900 int tile, int frame_em, int x, int y)
6902 int action = object_mapping[tile].action;
6903 int direction = object_mapping[tile].direction;
6904 int effective_element = get_effective_element_EM(tile, frame_em);
6905 int graphic = (direction == MV_NONE ?
6906 el_act2img(effective_element, action) :
6907 el_act_dir2img(effective_element, action, direction));
6908 struct GraphicInfo *g = &graphic_info[graphic];
6910 boolean action_removing = (action == ACTION_DIGGING ||
6911 action == ACTION_SNAPPING ||
6912 action == ACTION_COLLECTING);
6913 boolean action_moving = (action == ACTION_FALLING ||
6914 action == ACTION_MOVING ||
6915 action == ACTION_PUSHING ||
6916 action == ACTION_EATING ||
6917 action == ACTION_FILLING ||
6918 action == ACTION_EMPTYING);
6919 boolean action_falling = (action == ACTION_FALLING ||
6920 action == ACTION_FILLING ||
6921 action == ACTION_EMPTYING);
6923 /* special case: graphic uses "2nd movement tile" and has defined
6924 7 frames for movement animation (or less) => use default graphic
6925 for last (8th) frame which ends the movement animation */
6926 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
6928 action = ACTION_DEFAULT; /* (keep action_* unchanged for now) */
6929 graphic = (direction == MV_NONE ?
6930 el_act2img(effective_element, action) :
6931 el_act_dir2img(effective_element, action, direction));
6933 g = &graphic_info[graphic];
6936 if ((action_removing || check_linear_animation_EM(tile)) && frame_em == 0)
6940 else if (action_moving)
6942 boolean is_backside = object_mapping[tile].is_backside;
6946 int direction = object_mapping[tile].direction;
6947 int move_dir = (action_falling ? MV_DOWN : direction);
6952 /* !!! TEST !!! NEW !!! DOES NOT WORK RIGHT YET !!! */
6953 if (g->double_movement && frame_em == 0)
6957 if (move_dir == MV_LEFT)
6958 GfxFrame[x - 1][y] = GfxFrame[x][y];
6959 else if (move_dir == MV_RIGHT)
6960 GfxFrame[x + 1][y] = GfxFrame[x][y];
6961 else if (move_dir == MV_UP)
6962 GfxFrame[x][y - 1] = GfxFrame[x][y];
6963 else if (move_dir == MV_DOWN)
6964 GfxFrame[x][y + 1] = GfxFrame[x][y];
6971 /* special case: animation for Xsand_stonesand_quickout_1/2 twice as fast */
6972 if (tile == Xsand_stonesand_quickout_1 ||
6973 tile == Xsand_stonesand_quickout_2)
6977 if (graphic_info[graphic].anim_global_sync)
6978 sync_frame = FrameCounter;
6979 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
6980 sync_frame = GfxFrame[x][y];
6982 sync_frame = 0; /* playfield border (pseudo steel) */
6984 SetRandomAnimationValue(x, y);
6986 int frame = getAnimationFrame(g->anim_frames,
6989 g->anim_start_frame,
6992 g_em->unique_identifier =
6993 (graphic << 16) | ((frame % 8) << 12) | (g_em->width << 6) | g_em->height;
6996 void getGraphicSourceObjectExt_EM(struct GraphicInfo_EM *g_em,
6997 int tile, int frame_em, int x, int y)
6999 int action = object_mapping[tile].action;
7000 int direction = object_mapping[tile].direction;
7001 boolean is_backside = object_mapping[tile].is_backside;
7002 int effective_element = get_effective_element_EM(tile, frame_em);
7003 int effective_action = action;
7004 int graphic = (direction == MV_NONE ?
7005 el_act2img(effective_element, effective_action) :
7006 el_act_dir2img(effective_element, effective_action,
7008 int crumbled = (direction == MV_NONE ?
7009 el_act2crm(effective_element, effective_action) :
7010 el_act_dir2crm(effective_element, effective_action,
7012 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7013 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7014 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7015 struct GraphicInfo *g = &graphic_info[graphic];
7018 /* special case: graphic uses "2nd movement tile" and has defined
7019 7 frames for movement animation (or less) => use default graphic
7020 for last (8th) frame which ends the movement animation */
7021 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
7023 effective_action = ACTION_DEFAULT;
7024 graphic = (direction == MV_NONE ?
7025 el_act2img(effective_element, effective_action) :
7026 el_act_dir2img(effective_element, effective_action,
7028 crumbled = (direction == MV_NONE ?
7029 el_act2crm(effective_element, effective_action) :
7030 el_act_dir2crm(effective_element, effective_action,
7033 g = &graphic_info[graphic];
7036 if (graphic_info[graphic].anim_global_sync)
7037 sync_frame = FrameCounter;
7038 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
7039 sync_frame = GfxFrame[x][y];
7041 sync_frame = 0; /* playfield border (pseudo steel) */
7043 SetRandomAnimationValue(x, y);
7045 int frame = getAnimationFrame(g->anim_frames,
7048 g->anim_start_frame,
7051 getGraphicSourceExt(graphic, frame, &g_em->bitmap, &g_em->src_x, &g_em->src_y,
7052 g->double_movement && is_backside);
7054 /* (updating the "crumbled" graphic definitions is probably not really needed,
7055 as animations for crumbled graphics can't be longer than one EMC cycle) */
7056 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
7060 void getGraphicSourcePlayerExt_EM(struct GraphicInfo_EM *g_em,
7061 int player_nr, int anim, int frame_em)
7063 int element = player_mapping[player_nr][anim].element_rnd;
7064 int action = player_mapping[player_nr][anim].action;
7065 int direction = player_mapping[player_nr][anim].direction;
7066 int graphic = (direction == MV_NONE ?
7067 el_act2img(element, action) :
7068 el_act_dir2img(element, action, direction));
7069 struct GraphicInfo *g = &graphic_info[graphic];
7072 InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
7074 stored_player[player_nr].StepFrame = frame_em;
7076 sync_frame = stored_player[player_nr].Frame;
7078 int frame = getAnimationFrame(g->anim_frames,
7081 g->anim_start_frame,
7084 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
7085 &g_em->src_x, &g_em->src_y, FALSE);
7088 void InitGraphicInfo_EM(void)
7093 int num_em_gfx_errors = 0;
7095 if (graphic_info_em_object[0][0].bitmap == NULL)
7097 /* EM graphics not yet initialized in em_open_all() */
7102 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
7105 /* always start with reliable default values */
7106 for (i = 0; i < TILE_MAX; i++)
7108 object_mapping[i].element_rnd = EL_UNKNOWN;
7109 object_mapping[i].is_backside = FALSE;
7110 object_mapping[i].action = ACTION_DEFAULT;
7111 object_mapping[i].direction = MV_NONE;
7114 /* always start with reliable default values */
7115 for (p = 0; p < MAX_PLAYERS; p++)
7117 for (i = 0; i < SPR_MAX; i++)
7119 player_mapping[p][i].element_rnd = EL_UNKNOWN;
7120 player_mapping[p][i].action = ACTION_DEFAULT;
7121 player_mapping[p][i].direction = MV_NONE;
7125 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
7127 int e = em_object_mapping_list[i].element_em;
7129 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
7130 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
7132 if (em_object_mapping_list[i].action != -1)
7133 object_mapping[e].action = em_object_mapping_list[i].action;
7135 if (em_object_mapping_list[i].direction != -1)
7136 object_mapping[e].direction =
7137 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
7140 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
7142 int a = em_player_mapping_list[i].action_em;
7143 int p = em_player_mapping_list[i].player_nr;
7145 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
7147 if (em_player_mapping_list[i].action != -1)
7148 player_mapping[p][a].action = em_player_mapping_list[i].action;
7150 if (em_player_mapping_list[i].direction != -1)
7151 player_mapping[p][a].direction =
7152 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
7155 for (i = 0; i < TILE_MAX; i++)
7157 int element = object_mapping[i].element_rnd;
7158 int action = object_mapping[i].action;
7159 int direction = object_mapping[i].direction;
7160 boolean is_backside = object_mapping[i].is_backside;
7161 boolean action_exploding = ((action == ACTION_EXPLODING ||
7162 action == ACTION_SMASHED_BY_ROCK ||
7163 action == ACTION_SMASHED_BY_SPRING) &&
7164 element != EL_DIAMOND);
7165 boolean action_active = (action == ACTION_ACTIVE);
7166 boolean action_other = (action == ACTION_OTHER);
7168 for (j = 0; j < 8; j++)
7170 int effective_element = get_effective_element_EM(i, j);
7171 int effective_action = (j < 7 ? action :
7172 i == Xdrip_stretch ? action :
7173 i == Xdrip_stretchB ? action :
7174 i == Ydrip_s1 ? action :
7175 i == Ydrip_s1B ? action :
7176 i == Xball_1B ? action :
7177 i == Xball_2 ? action :
7178 i == Xball_2B ? action :
7179 i == Yball_eat ? action :
7180 i == Ykey_1_eat ? action :
7181 i == Ykey_2_eat ? action :
7182 i == Ykey_3_eat ? action :
7183 i == Ykey_4_eat ? action :
7184 i == Ykey_5_eat ? action :
7185 i == Ykey_6_eat ? action :
7186 i == Ykey_7_eat ? action :
7187 i == Ykey_8_eat ? action :
7188 i == Ylenses_eat ? action :
7189 i == Ymagnify_eat ? action :
7190 i == Ygrass_eat ? action :
7191 i == Ydirt_eat ? action :
7192 i == Xsand_stonein_1 ? action :
7193 i == Xsand_stonein_2 ? action :
7194 i == Xsand_stonein_3 ? action :
7195 i == Xsand_stonein_4 ? action :
7196 i == Xsand_stoneout_1 ? action :
7197 i == Xsand_stoneout_2 ? action :
7198 i == Xboom_android ? ACTION_EXPLODING :
7199 action_exploding ? ACTION_EXPLODING :
7200 action_active ? action :
7201 action_other ? action :
7203 int graphic = (el_act_dir2img(effective_element, effective_action,
7205 int crumbled = (el_act_dir2crm(effective_element, effective_action,
7207 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7208 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7209 boolean has_action_graphics = (graphic != base_graphic);
7210 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7211 struct GraphicInfo *g = &graphic_info[graphic];
7212 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7215 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
7216 boolean special_animation = (action != ACTION_DEFAULT &&
7217 g->anim_frames == 3 &&
7218 g->anim_delay == 2 &&
7219 g->anim_mode & ANIM_LINEAR);
7220 int sync_frame = (i == Xdrip_stretch ? 7 :
7221 i == Xdrip_stretchB ? 7 :
7222 i == Ydrip_s2 ? j + 8 :
7223 i == Ydrip_s2B ? j + 8 :
7232 i == Xfake_acid_1 ? 0 :
7233 i == Xfake_acid_2 ? 10 :
7234 i == Xfake_acid_3 ? 20 :
7235 i == Xfake_acid_4 ? 30 :
7236 i == Xfake_acid_5 ? 40 :
7237 i == Xfake_acid_6 ? 50 :
7238 i == Xfake_acid_7 ? 60 :
7239 i == Xfake_acid_8 ? 70 :
7241 i == Xball_2B ? j + 8 :
7242 i == Yball_eat ? j + 1 :
7243 i == Ykey_1_eat ? j + 1 :
7244 i == Ykey_2_eat ? j + 1 :
7245 i == Ykey_3_eat ? j + 1 :
7246 i == Ykey_4_eat ? j + 1 :
7247 i == Ykey_5_eat ? j + 1 :
7248 i == Ykey_6_eat ? j + 1 :
7249 i == Ykey_7_eat ? j + 1 :
7250 i == Ykey_8_eat ? j + 1 :
7251 i == Ylenses_eat ? j + 1 :
7252 i == Ymagnify_eat ? j + 1 :
7253 i == Ygrass_eat ? j + 1 :
7254 i == Ydirt_eat ? j + 1 :
7255 i == Xamoeba_1 ? 0 :
7256 i == Xamoeba_2 ? 1 :
7257 i == Xamoeba_3 ? 2 :
7258 i == Xamoeba_4 ? 3 :
7259 i == Xamoeba_5 ? 0 :
7260 i == Xamoeba_6 ? 1 :
7261 i == Xamoeba_7 ? 2 :
7262 i == Xamoeba_8 ? 3 :
7263 i == Xexit_2 ? j + 8 :
7264 i == Xexit_3 ? j + 16 :
7265 i == Xdynamite_1 ? 0 :
7266 i == Xdynamite_2 ? 8 :
7267 i == Xdynamite_3 ? 16 :
7268 i == Xdynamite_4 ? 24 :
7269 i == Xsand_stonein_1 ? j + 1 :
7270 i == Xsand_stonein_2 ? j + 9 :
7271 i == Xsand_stonein_3 ? j + 17 :
7272 i == Xsand_stonein_4 ? j + 25 :
7273 i == Xsand_stoneout_1 && j == 0 ? 0 :
7274 i == Xsand_stoneout_1 && j == 1 ? 0 :
7275 i == Xsand_stoneout_1 && j == 2 ? 1 :
7276 i == Xsand_stoneout_1 && j == 3 ? 2 :
7277 i == Xsand_stoneout_1 && j == 4 ? 2 :
7278 i == Xsand_stoneout_1 && j == 5 ? 3 :
7279 i == Xsand_stoneout_1 && j == 6 ? 4 :
7280 i == Xsand_stoneout_1 && j == 7 ? 4 :
7281 i == Xsand_stoneout_2 && j == 0 ? 5 :
7282 i == Xsand_stoneout_2 && j == 1 ? 6 :
7283 i == Xsand_stoneout_2 && j == 2 ? 7 :
7284 i == Xsand_stoneout_2 && j == 3 ? 8 :
7285 i == Xsand_stoneout_2 && j == 4 ? 9 :
7286 i == Xsand_stoneout_2 && j == 5 ? 11 :
7287 i == Xsand_stoneout_2 && j == 6 ? 13 :
7288 i == Xsand_stoneout_2 && j == 7 ? 15 :
7289 i == Xboom_bug && j == 1 ? 2 :
7290 i == Xboom_bug && j == 2 ? 2 :
7291 i == Xboom_bug && j == 3 ? 4 :
7292 i == Xboom_bug && j == 4 ? 4 :
7293 i == Xboom_bug && j == 5 ? 2 :
7294 i == Xboom_bug && j == 6 ? 2 :
7295 i == Xboom_bug && j == 7 ? 0 :
7296 i == Xboom_bomb && j == 1 ? 2 :
7297 i == Xboom_bomb && j == 2 ? 2 :
7298 i == Xboom_bomb && j == 3 ? 4 :
7299 i == Xboom_bomb && j == 4 ? 4 :
7300 i == Xboom_bomb && j == 5 ? 2 :
7301 i == Xboom_bomb && j == 6 ? 2 :
7302 i == Xboom_bomb && j == 7 ? 0 :
7303 i == Xboom_android && j == 7 ? 6 :
7304 i == Xboom_1 && j == 1 ? 2 :
7305 i == Xboom_1 && j == 2 ? 2 :
7306 i == Xboom_1 && j == 3 ? 4 :
7307 i == Xboom_1 && j == 4 ? 4 :
7308 i == Xboom_1 && j == 5 ? 6 :
7309 i == Xboom_1 && j == 6 ? 6 :
7310 i == Xboom_1 && j == 7 ? 8 :
7311 i == Xboom_2 && j == 0 ? 8 :
7312 i == Xboom_2 && j == 1 ? 8 :
7313 i == Xboom_2 && j == 2 ? 10 :
7314 i == Xboom_2 && j == 3 ? 10 :
7315 i == Xboom_2 && j == 4 ? 10 :
7316 i == Xboom_2 && j == 5 ? 12 :
7317 i == Xboom_2 && j == 6 ? 12 :
7318 i == Xboom_2 && j == 7 ? 12 :
7319 special_animation && j == 4 ? 3 :
7320 effective_action != action ? 0 :
7324 Bitmap *debug_bitmap = g_em->bitmap;
7325 int debug_src_x = g_em->src_x;
7326 int debug_src_y = g_em->src_y;
7329 int frame = getAnimationFrame(g->anim_frames,
7332 g->anim_start_frame,
7335 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
7336 g->double_movement && is_backside);
7338 g_em->bitmap = src_bitmap;
7339 g_em->src_x = src_x;
7340 g_em->src_y = src_y;
7341 g_em->src_offset_x = 0;
7342 g_em->src_offset_y = 0;
7343 g_em->dst_offset_x = 0;
7344 g_em->dst_offset_y = 0;
7345 g_em->width = TILEX;
7346 g_em->height = TILEY;
7348 g_em->preserve_background = FALSE;
7350 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
7353 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
7354 effective_action == ACTION_MOVING ||
7355 effective_action == ACTION_PUSHING ||
7356 effective_action == ACTION_EATING)) ||
7357 (!has_action_graphics && (effective_action == ACTION_FILLING ||
7358 effective_action == ACTION_EMPTYING)))
7361 (effective_action == ACTION_FALLING ||
7362 effective_action == ACTION_FILLING ||
7363 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
7364 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
7365 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
7366 int num_steps = (i == Ydrip_s1 ? 16 :
7367 i == Ydrip_s1B ? 16 :
7368 i == Ydrip_s2 ? 16 :
7369 i == Ydrip_s2B ? 16 :
7370 i == Xsand_stonein_1 ? 32 :
7371 i == Xsand_stonein_2 ? 32 :
7372 i == Xsand_stonein_3 ? 32 :
7373 i == Xsand_stonein_4 ? 32 :
7374 i == Xsand_stoneout_1 ? 16 :
7375 i == Xsand_stoneout_2 ? 16 : 8);
7376 int cx = ABS(dx) * (TILEX / num_steps);
7377 int cy = ABS(dy) * (TILEY / num_steps);
7378 int step_frame = (i == Ydrip_s2 ? j + 8 :
7379 i == Ydrip_s2B ? j + 8 :
7380 i == Xsand_stonein_2 ? j + 8 :
7381 i == Xsand_stonein_3 ? j + 16 :
7382 i == Xsand_stonein_4 ? j + 24 :
7383 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
7384 int step = (is_backside ? step_frame : num_steps - step_frame);
7386 if (is_backside) /* tile where movement starts */
7388 if (dx < 0 || dy < 0)
7390 g_em->src_offset_x = cx * step;
7391 g_em->src_offset_y = cy * step;
7395 g_em->dst_offset_x = cx * step;
7396 g_em->dst_offset_y = cy * step;
7399 else /* tile where movement ends */
7401 if (dx < 0 || dy < 0)
7403 g_em->dst_offset_x = cx * step;
7404 g_em->dst_offset_y = cy * step;
7408 g_em->src_offset_x = cx * step;
7409 g_em->src_offset_y = cy * step;
7413 g_em->width = TILEX - cx * step;
7414 g_em->height = TILEY - cy * step;
7417 /* create unique graphic identifier to decide if tile must be redrawn */
7418 /* bit 31 - 16 (16 bit): EM style graphic
7419 bit 15 - 12 ( 4 bit): EM style frame
7420 bit 11 - 6 ( 6 bit): graphic width
7421 bit 5 - 0 ( 6 bit): graphic height */
7422 g_em->unique_identifier =
7423 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
7427 /* skip check for EMC elements not contained in original EMC artwork */
7428 if (element == EL_EMC_FAKE_ACID)
7431 if (g_em->bitmap != debug_bitmap ||
7432 g_em->src_x != debug_src_x ||
7433 g_em->src_y != debug_src_y ||
7434 g_em->src_offset_x != 0 ||
7435 g_em->src_offset_y != 0 ||
7436 g_em->dst_offset_x != 0 ||
7437 g_em->dst_offset_y != 0 ||
7438 g_em->width != TILEX ||
7439 g_em->height != TILEY)
7441 static int last_i = -1;
7449 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
7450 i, element, element_info[element].token_name,
7451 element_action_info[effective_action].suffix, direction);
7453 if (element != effective_element)
7454 printf(" [%d ('%s')]",
7456 element_info[effective_element].token_name);
7460 if (g_em->bitmap != debug_bitmap)
7461 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
7462 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
7464 if (g_em->src_x != debug_src_x ||
7465 g_em->src_y != debug_src_y)
7466 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
7467 j, (is_backside ? 'B' : 'F'),
7468 g_em->src_x, g_em->src_y,
7469 g_em->src_x / 32, g_em->src_y / 32,
7470 debug_src_x, debug_src_y,
7471 debug_src_x / 32, debug_src_y / 32);
7473 if (g_em->src_offset_x != 0 ||
7474 g_em->src_offset_y != 0 ||
7475 g_em->dst_offset_x != 0 ||
7476 g_em->dst_offset_y != 0)
7477 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
7479 g_em->src_offset_x, g_em->src_offset_y,
7480 g_em->dst_offset_x, g_em->dst_offset_y);
7482 if (g_em->width != TILEX ||
7483 g_em->height != TILEY)
7484 printf(" %d (%d): size %d,%d should be %d,%d\n",
7486 g_em->width, g_em->height, TILEX, TILEY);
7488 num_em_gfx_errors++;
7495 for (i = 0; i < TILE_MAX; i++)
7497 for (j = 0; j < 8; j++)
7499 int element = object_mapping[i].element_rnd;
7500 int action = object_mapping[i].action;
7501 int direction = object_mapping[i].direction;
7502 boolean is_backside = object_mapping[i].is_backside;
7503 int graphic_action = el_act_dir2img(element, action, direction);
7504 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
7506 if ((action == ACTION_SMASHED_BY_ROCK ||
7507 action == ACTION_SMASHED_BY_SPRING ||
7508 action == ACTION_EATING) &&
7509 graphic_action == graphic_default)
7511 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
7512 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
7513 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
7514 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
7517 /* no separate animation for "smashed by rock" -- use rock instead */
7518 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7519 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
7521 g_em->bitmap = g_xx->bitmap;
7522 g_em->src_x = g_xx->src_x;
7523 g_em->src_y = g_xx->src_y;
7524 g_em->src_offset_x = g_xx->src_offset_x;
7525 g_em->src_offset_y = g_xx->src_offset_y;
7526 g_em->dst_offset_x = g_xx->dst_offset_x;
7527 g_em->dst_offset_y = g_xx->dst_offset_y;
7528 g_em->width = g_xx->width;
7529 g_em->height = g_xx->height;
7530 g_em->unique_identifier = g_xx->unique_identifier;
7533 g_em->preserve_background = TRUE;
7538 for (p = 0; p < MAX_PLAYERS; p++)
7540 for (i = 0; i < SPR_MAX; i++)
7542 int element = player_mapping[p][i].element_rnd;
7543 int action = player_mapping[p][i].action;
7544 int direction = player_mapping[p][i].direction;
7546 for (j = 0; j < 8; j++)
7548 int effective_element = element;
7549 int effective_action = action;
7550 int graphic = (direction == MV_NONE ?
7551 el_act2img(effective_element, effective_action) :
7552 el_act_dir2img(effective_element, effective_action,
7554 struct GraphicInfo *g = &graphic_info[graphic];
7555 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
7561 Bitmap *debug_bitmap = g_em->bitmap;
7562 int debug_src_x = g_em->src_x;
7563 int debug_src_y = g_em->src_y;
7566 int frame = getAnimationFrame(g->anim_frames,
7569 g->anim_start_frame,
7572 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
7574 g_em->bitmap = src_bitmap;
7575 g_em->src_x = src_x;
7576 g_em->src_y = src_y;
7577 g_em->src_offset_x = 0;
7578 g_em->src_offset_y = 0;
7579 g_em->dst_offset_x = 0;
7580 g_em->dst_offset_y = 0;
7581 g_em->width = TILEX;
7582 g_em->height = TILEY;
7586 /* skip check for EMC elements not contained in original EMC artwork */
7587 if (element == EL_PLAYER_3 ||
7588 element == EL_PLAYER_4)
7591 if (g_em->bitmap != debug_bitmap ||
7592 g_em->src_x != debug_src_x ||
7593 g_em->src_y != debug_src_y)
7595 static int last_i = -1;
7603 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
7604 p, i, element, element_info[element].token_name,
7605 element_action_info[effective_action].suffix, direction);
7607 if (element != effective_element)
7608 printf(" [%d ('%s')]",
7610 element_info[effective_element].token_name);
7614 if (g_em->bitmap != debug_bitmap)
7615 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
7616 j, (int)(g_em->bitmap), (int)(debug_bitmap));
7618 if (g_em->src_x != debug_src_x ||
7619 g_em->src_y != debug_src_y)
7620 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
7622 g_em->src_x, g_em->src_y,
7623 g_em->src_x / 32, g_em->src_y / 32,
7624 debug_src_x, debug_src_y,
7625 debug_src_x / 32, debug_src_y / 32);
7627 num_em_gfx_errors++;
7637 printf("::: [%d errors found]\n", num_em_gfx_errors);
7643 void CheckSaveEngineSnapshot_EM(byte action[MAX_PLAYERS], int frame,
7644 boolean any_player_moving,
7645 boolean any_player_snapping,
7646 boolean any_player_dropping)
7648 static boolean player_was_waiting = TRUE;
7650 if (frame == 0 && !any_player_dropping)
7652 if (!player_was_waiting)
7654 if (!SaveEngineSnapshotToList())
7657 player_was_waiting = TRUE;
7660 else if (any_player_moving || any_player_snapping || any_player_dropping)
7662 player_was_waiting = FALSE;
7666 void CheckSaveEngineSnapshot_SP(boolean murphy_is_waiting,
7667 boolean murphy_is_dropping)
7669 static boolean player_was_waiting = TRUE;
7671 if (murphy_is_waiting)
7673 if (!player_was_waiting)
7675 if (!SaveEngineSnapshotToList())
7678 player_was_waiting = TRUE;
7683 player_was_waiting = FALSE;
7687 void CheckSingleStepMode_EM(byte action[MAX_PLAYERS], int frame,
7688 boolean any_player_moving,
7689 boolean any_player_snapping,
7690 boolean any_player_dropping)
7692 if (tape.single_step && tape.recording && !tape.pausing)
7693 if (frame == 0 && !any_player_dropping)
7694 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
7696 CheckSaveEngineSnapshot_EM(action, frame, any_player_moving,
7697 any_player_snapping, any_player_dropping);
7700 void CheckSingleStepMode_SP(boolean murphy_is_waiting,
7701 boolean murphy_is_dropping)
7703 if (tape.single_step && tape.recording && !tape.pausing)
7704 if (murphy_is_waiting)
7705 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
7707 CheckSaveEngineSnapshot_SP(murphy_is_waiting, murphy_is_dropping);
7710 void getGraphicSource_SP(struct GraphicInfo_SP *g_sp,
7711 int graphic, int sync_frame, int x, int y)
7713 int frame = getGraphicAnimationFrame(graphic, sync_frame);
7715 getGraphicSource(graphic, frame, &g_sp->bitmap, &g_sp->src_x, &g_sp->src_y);
7718 boolean isNextAnimationFrame_SP(int graphic, int sync_frame)
7720 return (IS_NEXT_FRAME(sync_frame, graphic));
7723 int getGraphicInfo_Delay(int graphic)
7725 return graphic_info[graphic].anim_delay;
7728 void PlayMenuSoundExt(int sound)
7730 if (sound == SND_UNDEFINED)
7733 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
7734 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
7737 if (IS_LOOP_SOUND(sound))
7738 PlaySoundLoop(sound);
7743 void PlayMenuSound()
7745 PlayMenuSoundExt(menu.sound[game_status]);
7748 void PlayMenuSoundStereo(int sound, int stereo_position)
7750 if (sound == SND_UNDEFINED)
7753 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
7754 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
7757 if (IS_LOOP_SOUND(sound))
7758 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
7760 PlaySoundStereo(sound, stereo_position);
7763 void PlayMenuSoundIfLoopExt(int sound)
7765 if (sound == SND_UNDEFINED)
7768 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
7769 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
7772 if (IS_LOOP_SOUND(sound))
7773 PlaySoundLoop(sound);
7776 void PlayMenuSoundIfLoop()
7778 PlayMenuSoundIfLoopExt(menu.sound[game_status]);
7781 void PlayMenuMusicExt(int music)
7783 if (music == MUS_UNDEFINED)
7786 if (!setup.sound_music)
7792 void PlayMenuMusic()
7794 PlayMenuMusicExt(menu.music[game_status]);
7797 void PlaySoundActivating()
7800 PlaySound(SND_MENU_ITEM_ACTIVATING);
7804 void PlaySoundSelecting()
7807 PlaySound(SND_MENU_ITEM_SELECTING);
7811 void ToggleFullscreenOrChangeWindowScalingIfNeeded()
7813 boolean change_fullscreen = (setup.fullscreen !=
7814 video.fullscreen_enabled);
7815 boolean change_fullscreen_mode = (video.fullscreen_enabled &&
7816 !strEqual(setup.fullscreen_mode,
7817 video.fullscreen_mode_current));
7818 boolean change_window_scaling_percent = (!video.fullscreen_enabled &&
7819 setup.window_scaling_percent !=
7820 video.window_scaling_percent);
7822 if (change_window_scaling_percent && video.fullscreen_enabled)
7825 if (!change_window_scaling_percent && !video.fullscreen_available)
7828 #if defined(TARGET_SDL2)
7829 if (change_window_scaling_percent)
7831 SDLSetWindowScaling(setup.window_scaling_percent);
7835 else if (change_fullscreen)
7837 SDLSetWindowFullscreen(setup.fullscreen);
7839 /* set setup value according to successfully changed fullscreen mode */
7840 setup.fullscreen = video.fullscreen_enabled;
7846 if (change_fullscreen ||
7847 change_fullscreen_mode ||
7848 change_window_scaling_percent)
7850 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
7852 /* save backbuffer content which gets lost when toggling fullscreen mode */
7853 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
7855 if (change_fullscreen_mode)
7857 /* keep fullscreen, but change fullscreen mode (screen resolution) */
7858 video.fullscreen_enabled = FALSE; /* force new fullscreen mode */
7861 if (change_window_scaling_percent)
7863 /* keep window mode, but change window scaling */
7864 video.fullscreen_enabled = TRUE; /* force new window scaling */
7867 /* toggle fullscreen */
7868 ChangeVideoModeIfNeeded(setup.fullscreen);
7870 /* set setup value according to successfully changed fullscreen mode */
7871 setup.fullscreen = video.fullscreen_enabled;
7873 /* restore backbuffer content from temporary backbuffer backup bitmap */
7874 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
7876 FreeBitmap(tmp_backbuffer);
7878 /* update visible window/screen */
7879 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
7883 void ChangeViewportPropertiesIfNeeded()
7885 int gfx_game_mode = game_status;
7886 int gfx_game_mode2 = (game_status == GAME_MODE_EDITOR ? GAME_MODE_DEFAULT :
7888 struct RectWithBorder *vp_playfield = &viewport.playfield[gfx_game_mode];
7889 struct RectWithBorder *vp_door_1 = &viewport.door_1[gfx_game_mode];
7890 struct RectWithBorder *vp_door_2 = &viewport.door_2[gfx_game_mode2];
7891 struct RectWithBorder *vp_door_3 = &viewport.door_2[GAME_MODE_EDITOR];
7892 int border_size = vp_playfield->border_size;
7893 int new_sx = vp_playfield->x + border_size;
7894 int new_sy = vp_playfield->y + border_size;
7895 int new_sxsize = vp_playfield->width - 2 * border_size;
7896 int new_sysize = vp_playfield->height - 2 * border_size;
7897 int new_real_sx = vp_playfield->x;
7898 int new_real_sy = vp_playfield->y;
7899 int new_full_sxsize = vp_playfield->width;
7900 int new_full_sysize = vp_playfield->height;
7901 int new_dx = vp_door_1->x;
7902 int new_dy = vp_door_1->y;
7903 int new_dxsize = vp_door_1->width;
7904 int new_dysize = vp_door_1->height;
7905 int new_vx = vp_door_2->x;
7906 int new_vy = vp_door_2->y;
7907 int new_vxsize = vp_door_2->width;
7908 int new_vysize = vp_door_2->height;
7909 int new_ex = vp_door_3->x;
7910 int new_ey = vp_door_3->y;
7911 int new_exsize = vp_door_3->width;
7912 int new_eysize = vp_door_3->height;
7913 int new_tilesize_var =
7914 (setup.small_game_graphics ? MINI_TILESIZE : game.tile_size);
7916 int tilesize = (gfx_game_mode == GAME_MODE_PLAYING ? new_tilesize_var :
7917 gfx_game_mode == GAME_MODE_EDITOR ? MINI_TILESIZE : TILESIZE);
7918 int new_scr_fieldx = new_sxsize / tilesize;
7919 int new_scr_fieldy = new_sysize / tilesize;
7920 int new_scr_fieldx_buffers = new_sxsize / new_tilesize_var;
7921 int new_scr_fieldy_buffers = new_sysize / new_tilesize_var;
7922 boolean init_gfx_buffers = FALSE;
7923 boolean init_video_buffer = FALSE;
7924 boolean init_gadgets_and_toons = FALSE;
7925 boolean init_em_graphics = FALSE;
7926 boolean drawing_area_changed = FALSE;
7928 if (viewport.window.width != WIN_XSIZE ||
7929 viewport.window.height != WIN_YSIZE)
7931 WIN_XSIZE = viewport.window.width;
7932 WIN_YSIZE = viewport.window.height;
7934 init_video_buffer = TRUE;
7935 init_gfx_buffers = TRUE;
7937 // printf("::: video: init_video_buffer, init_gfx_buffers\n");
7940 if (new_scr_fieldx != SCR_FIELDX ||
7941 new_scr_fieldy != SCR_FIELDY)
7943 /* this always toggles between MAIN and GAME when using small tile size */
7945 SCR_FIELDX = new_scr_fieldx;
7946 SCR_FIELDY = new_scr_fieldy;
7948 // printf("::: new_scr_fieldx != SCR_FIELDX ...\n");
7959 new_sxsize != SXSIZE ||
7960 new_sysize != SYSIZE ||
7961 new_dxsize != DXSIZE ||
7962 new_dysize != DYSIZE ||
7963 new_vxsize != VXSIZE ||
7964 new_vysize != VYSIZE ||
7965 new_exsize != EXSIZE ||
7966 new_eysize != EYSIZE ||
7967 new_real_sx != REAL_SX ||
7968 new_real_sy != REAL_SY ||
7969 new_full_sxsize != FULL_SXSIZE ||
7970 new_full_sysize != FULL_SYSIZE ||
7971 new_tilesize_var != TILESIZE_VAR
7974 if (new_tilesize_var != TILESIZE_VAR)
7976 // printf("::: new_tilesize_var != TILESIZE_VAR\n");
7978 // changing tile size invalidates scroll values of engine snapshots
7979 FreeEngineSnapshotSingle();
7981 // changing tile size requires update of graphic mapping for EM engine
7982 init_em_graphics = TRUE;
7987 new_sxsize != SXSIZE ||
7988 new_sysize != SYSIZE ||
7989 new_real_sx != REAL_SX ||
7990 new_real_sy != REAL_SY ||
7991 new_full_sxsize != FULL_SXSIZE ||
7992 new_full_sysize != FULL_SYSIZE)
7994 if (!init_video_buffer)
7995 drawing_area_changed = TRUE;
8006 SXSIZE = new_sxsize;
8007 SYSIZE = new_sysize;
8008 DXSIZE = new_dxsize;
8009 DYSIZE = new_dysize;
8010 VXSIZE = new_vxsize;
8011 VYSIZE = new_vysize;
8012 EXSIZE = new_exsize;
8013 EYSIZE = new_eysize;
8014 REAL_SX = new_real_sx;
8015 REAL_SY = new_real_sy;
8016 FULL_SXSIZE = new_full_sxsize;
8017 FULL_SYSIZE = new_full_sysize;
8018 TILESIZE_VAR = new_tilesize_var;
8020 init_gfx_buffers = TRUE;
8021 init_gadgets_and_toons = TRUE;
8023 // printf("::: viewports: init_gfx_buffers\n");
8024 // printf("::: viewports: init_gadgets_and_toons\n");
8027 if (init_gfx_buffers)
8029 // printf("::: init_gfx_buffers\n");
8031 SCR_FIELDX = new_scr_fieldx_buffers;
8032 SCR_FIELDY = new_scr_fieldy_buffers;
8036 SCR_FIELDX = new_scr_fieldx;
8037 SCR_FIELDY = new_scr_fieldy;
8039 gfx.drawing_area_changed = drawing_area_changed;
8041 SetDrawDeactivationMask(REDRAW_NONE);
8042 SetDrawBackgroundMask(REDRAW_FIELD);
8045 if (init_video_buffer)
8047 // printf("::: init_video_buffer\n");
8049 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
8052 if (init_gadgets_and_toons)
8054 // printf("::: init_gadgets_and_toons\n");
8060 if (init_em_graphics)
8062 InitGraphicInfo_EM();