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 // redraw playfield if anything inside main playfield area needs redraw
440 if (redraw_mask & REDRAW_MAIN)
441 redraw_mask |= REDRAW_FIELD;
443 // draw masked border to all viewports, if defined
444 DrawMaskedBorder(redraw_mask);
446 // draw frames per second (only if debug mode is enabled)
447 if (redraw_mask & REDRAW_FPS)
448 DrawFramesPerSecond();
450 // redraw complete window if both playfield and (some) doors need redraw
451 if (redraw_mask & REDRAW_FIELD && redraw_mask & REDRAW_DOORS)
452 redraw_mask = REDRAW_ALL;
454 /* although redrawing the whole window would be fine for normal gameplay,
455 being able to only redraw the playfield is required for deactivating
456 certain drawing areas (mainly playfield) to work, which is needed for
457 warp-forward to be fast enough (by skipping redraw of most frames) */
459 if (redraw_mask & REDRAW_ALL)
461 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
463 else if (redraw_mask & REDRAW_FIELD)
465 BlitBitmap(backbuffer, window,
466 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
468 else if (redraw_mask & REDRAW_DOORS)
470 if (redraw_mask & REDRAW_DOOR_1)
471 BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
473 if (redraw_mask & REDRAW_DOOR_2)
474 BlitBitmap(backbuffer, window, VX, VY, VXSIZE, VYSIZE, VX, VY);
476 if (redraw_mask & REDRAW_DOOR_3)
477 BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
480 redraw_mask = REDRAW_NONE;
483 static void FadeCrossSaveBackbuffer()
485 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
488 static void FadeExt(int fade_mask, int fade_mode, int fade_type)
490 static int fade_type_skip = FADE_TYPE_NONE;
491 void (*draw_border_function)(void) = NULL;
492 Bitmap *bitmap = (fade_mode & FADE_TYPE_TRANSFORM ? bitmap_db_cross : NULL);
493 int x, y, width, height;
494 int fade_delay, post_delay;
496 if (fade_type == FADE_TYPE_FADE_OUT)
498 if (fade_type_skip != FADE_TYPE_NONE)
500 /* skip all fade operations until specified fade operation */
501 if (fade_type & fade_type_skip)
502 fade_type_skip = FADE_TYPE_NONE;
507 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
509 FadeCrossSaveBackbuffer();
515 redraw_mask |= fade_mask;
517 if (fade_type == FADE_TYPE_SKIP)
519 fade_type_skip = fade_mode;
524 fade_delay = fading.fade_delay;
525 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
527 if (fade_type_skip != FADE_TYPE_NONE)
529 /* skip all fade operations until specified fade operation */
530 if (fade_type & fade_type_skip)
531 fade_type_skip = FADE_TYPE_NONE;
536 if (global.autoplay_leveldir)
541 if (fade_mask == REDRAW_FIELD)
546 height = FULL_SYSIZE;
548 if (border.draw_masked_when_fading)
549 draw_border_function = DrawMaskedBorder_FIELD; /* update when fading */
551 DrawMaskedBorder_FIELD(); /* draw once */
553 else /* REDRAW_ALL */
561 if (!setup.fade_screens ||
563 fading.fade_mode == FADE_MODE_NONE)
565 if (fade_mode == FADE_MODE_FADE_OUT)
568 BlitBitmap(backbuffer, window, x, y, width, height, x, y);
570 redraw_mask &= ~fade_mask;
575 FadeRectangle(bitmap, x, y, width, height, fade_mode, fade_delay, post_delay,
576 draw_border_function);
578 redraw_mask &= ~fade_mask;
581 void FadeIn(int fade_mask)
583 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
584 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_IN);
586 FadeExt(fade_mask, FADE_MODE_FADE_IN, FADE_TYPE_FADE_IN);
589 void FadeOut(int fade_mask)
591 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
592 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_OUT);
594 FadeExt(fade_mask, FADE_MODE_FADE_OUT, FADE_TYPE_FADE_OUT);
596 global.border_status = game_status;
599 static void FadeSetLeaveNext(struct TitleFadingInfo fading_leave, boolean set)
601 static struct TitleFadingInfo fading_leave_stored;
604 fading_leave_stored = fading_leave;
606 fading = fading_leave_stored;
609 void FadeSetEnterMenu()
611 fading = menu.enter_menu;
613 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
616 void FadeSetLeaveMenu()
618 fading = menu.leave_menu;
620 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
623 void FadeSetEnterScreen()
625 fading = menu.enter_screen[game_status];
627 FadeSetLeaveNext(menu.leave_screen[game_status], TRUE); /* store */
630 void FadeSetNextScreen()
632 fading = menu.next_screen;
634 // (do not overwrite fade mode set by FadeSetEnterScreen)
635 // FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
638 void FadeSetLeaveScreen()
640 FadeSetLeaveNext(menu.leave_screen[game_status], FALSE); /* recall */
643 void FadeSetFromType(int type)
645 if (type & TYPE_ENTER_SCREEN)
646 FadeSetEnterScreen();
647 else if (type & TYPE_ENTER)
649 else if (type & TYPE_LEAVE)
653 void FadeSetDisabled()
655 static struct TitleFadingInfo fading_none = { FADE_MODE_NONE, -1, -1, -1 };
657 fading = fading_none;
660 void FadeSkipNextFadeIn()
662 FadeExt(0, FADE_MODE_SKIP_FADE_IN, FADE_TYPE_SKIP);
665 void FadeSkipNextFadeOut()
667 FadeExt(0, FADE_MODE_SKIP_FADE_OUT, FADE_TYPE_SKIP);
670 void SetWindowBackgroundImageIfDefined(int graphic)
672 if (graphic_info[graphic].bitmap)
673 SetWindowBackgroundBitmap(graphic_info[graphic].bitmap);
676 void SetMainBackgroundImageIfDefined(int graphic)
678 if (graphic_info[graphic].bitmap)
679 SetMainBackgroundBitmap(graphic_info[graphic].bitmap);
682 void SetDoorBackgroundImageIfDefined(int graphic)
684 if (graphic_info[graphic].bitmap)
685 SetDoorBackgroundBitmap(graphic_info[graphic].bitmap);
688 void SetWindowBackgroundImage(int graphic)
690 SetWindowBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
691 graphic_info[graphic].bitmap ?
692 graphic_info[graphic].bitmap :
693 graphic_info[IMG_BACKGROUND].bitmap);
696 void SetMainBackgroundImage(int graphic)
698 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
699 graphic_info[graphic].bitmap ?
700 graphic_info[graphic].bitmap :
701 graphic_info[IMG_BACKGROUND].bitmap);
704 void SetDoorBackgroundImage(int graphic)
706 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
707 graphic_info[graphic].bitmap ?
708 graphic_info[graphic].bitmap :
709 graphic_info[IMG_BACKGROUND].bitmap);
712 void SetPanelBackground()
714 struct GraphicInfo *gfx = &graphic_info[IMG_BACKGROUND_PANEL];
716 BlitBitmapTiled(gfx->bitmap, bitmap_db_panel, gfx->src_x, gfx->src_y,
717 gfx->width, gfx->height, 0, 0, DXSIZE, DYSIZE);
719 SetDoorBackgroundBitmap(bitmap_db_panel);
722 void DrawBackground(int x, int y, int width, int height)
724 /* "drawto" might still point to playfield buffer here (hall of fame) */
725 ClearRectangleOnBackground(backbuffer, x, y, width, height);
727 if (IN_GFX_FIELD_FULL(x, y))
728 redraw_mask |= REDRAW_FIELD;
729 else if (IN_GFX_DOOR_1(x, y))
730 redraw_mask |= REDRAW_DOOR_1;
731 else if (IN_GFX_DOOR_2(x, y))
732 redraw_mask |= REDRAW_DOOR_2;
733 else if (IN_GFX_DOOR_3(x, y))
734 redraw_mask |= REDRAW_DOOR_3;
737 void DrawBackgroundForFont(int x, int y, int width, int height, int font_nr)
739 struct FontBitmapInfo *font = getFontBitmapInfo(font_nr);
741 if (font->bitmap == NULL)
744 DrawBackground(x, y, width, height);
747 void DrawBackgroundForGraphic(int x, int y, int width, int height, int graphic)
749 struct GraphicInfo *g = &graphic_info[graphic];
751 if (g->bitmap == NULL)
754 DrawBackground(x, y, width, height);
759 /* !!! "drawto" might still point to playfield buffer here (see above) !!! */
760 /* (when entering hall of fame after playing) */
761 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
763 /* !!! maybe this should be done before clearing the background !!! */
764 if (game_status == GAME_MODE_PLAYING)
766 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
767 SetDrawtoField(DRAW_FIELDBUFFER);
771 SetDrawtoField(DRAW_BACKBUFFER);
775 void MarkTileDirty(int x, int y)
777 redraw_mask |= REDRAW_FIELD;
780 void SetBorderElement()
784 BorderElement = EL_EMPTY;
786 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
788 for (x = 0; x < lev_fieldx; x++)
790 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
791 BorderElement = EL_STEELWALL;
793 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
799 void FloodFillLevel(int from_x, int from_y, int fill_element,
800 short field[MAX_LEV_FIELDX][MAX_LEV_FIELDY],
801 int max_fieldx, int max_fieldy)
805 static int check[4][2] = { { -1, 0 }, { 0, -1 }, { 1, 0 }, { 0, 1 } };
806 static int safety = 0;
808 /* check if starting field still has the desired content */
809 if (field[from_x][from_y] == fill_element)
814 if (safety > max_fieldx * max_fieldy)
815 Error(ERR_EXIT, "Something went wrong in 'FloodFill()'. Please debug.");
817 old_element = field[from_x][from_y];
818 field[from_x][from_y] = fill_element;
820 for (i = 0; i < 4; i++)
822 x = from_x + check[i][0];
823 y = from_y + check[i][1];
825 if (IN_FIELD(x, y, max_fieldx, max_fieldy) && field[x][y] == old_element)
826 FloodFillLevel(x, y, fill_element, field, max_fieldx, max_fieldy);
832 void SetRandomAnimationValue(int x, int y)
834 gfx.anim_random_frame = GfxRandom[x][y];
837 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
839 /* animation synchronized with global frame counter, not move position */
840 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
841 sync_frame = FrameCounter;
843 return getAnimationFrame(graphic_info[graphic].anim_frames,
844 graphic_info[graphic].anim_delay,
845 graphic_info[graphic].anim_mode,
846 graphic_info[graphic].anim_start_frame,
850 void getSizedGraphicSourceExt(int graphic, int frame, int tilesize,
851 Bitmap **bitmap, int *x, int *y,
852 boolean get_backside)
854 struct GraphicInfo *g = &graphic_info[graphic];
855 Bitmap *src_bitmap = g->bitmap;
856 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
857 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
858 int tilesize_capped = MIN(MAX(1, tilesize), TILESIZE);
860 // if no in-game graphics defined, always use standard graphic size
861 if (g->bitmaps[IMG_BITMAP_GAME] == NULL)
864 if (tilesize == gfx.standard_tile_size)
865 src_bitmap = g->bitmaps[IMG_BITMAP_STANDARD];
866 else if (tilesize == game.tile_size)
867 src_bitmap = g->bitmaps[IMG_BITMAP_GAME];
869 src_bitmap = g->bitmaps[IMG_BITMAP_1x1 - log_2(tilesize_capped)];
871 if (g->offset_y == 0) /* frames are ordered horizontally */
873 int max_width = g->anim_frames_per_line * g->width;
874 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
876 src_x = pos % max_width;
877 src_y = src_y % g->height + pos / max_width * g->height;
879 else if (g->offset_x == 0) /* frames are ordered vertically */
881 int max_height = g->anim_frames_per_line * g->height;
882 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
884 src_x = src_x % g->width + pos / max_height * g->width;
885 src_y = pos % max_height;
887 else /* frames are ordered diagonally */
889 src_x = src_x + frame * g->offset_x;
890 src_y = src_y + frame * g->offset_y;
893 *bitmap = src_bitmap;
894 *x = src_x * tilesize / TILESIZE;
895 *y = src_y * tilesize / TILESIZE;
898 void getFixedGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
899 int *x, int *y, boolean get_backside)
901 getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y,
905 void getSizedGraphicSource(int graphic, int frame, int tilesize,
906 Bitmap **bitmap, int *x, int *y)
908 getSizedGraphicSourceExt(graphic, frame, tilesize, bitmap, x, y, FALSE);
911 void getFixedGraphicSource(int graphic, int frame,
912 Bitmap **bitmap, int *x, int *y)
914 getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y, FALSE);
917 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
919 getSizedGraphicSource(graphic, 0, MINI_TILESIZE, bitmap, x, y);
922 inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
923 int *x, int *y, boolean get_backside)
925 struct GraphicInfo *g = &graphic_info[graphic];
926 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
927 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
929 if (TILESIZE_VAR != TILESIZE)
930 return getSizedGraphicSourceExt(graphic, frame, TILESIZE_VAR, bitmap, x, y,
935 if (g->offset_y == 0) /* frames are ordered horizontally */
937 int max_width = g->anim_frames_per_line * g->width;
938 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
940 *x = pos % max_width;
941 *y = src_y % g->height + pos / max_width * g->height;
943 else if (g->offset_x == 0) /* frames are ordered vertically */
945 int max_height = g->anim_frames_per_line * g->height;
946 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
948 *x = src_x % g->width + pos / max_height * g->width;
949 *y = pos % max_height;
951 else /* frames are ordered diagonally */
953 *x = src_x + frame * g->offset_x;
954 *y = src_y + frame * g->offset_y;
958 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
960 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
963 void DrawGraphic(int x, int y, int graphic, int frame)
966 if (!IN_SCR_FIELD(x, y))
968 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
969 printf("DrawGraphic(): This should never happen!\n");
974 DrawGraphicExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR, graphic,
980 void DrawFixedGraphic(int x, int y, int graphic, int frame)
983 if (!IN_SCR_FIELD(x, y))
985 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
986 printf("DrawGraphic(): This should never happen!\n");
991 DrawFixedGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic,
996 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1002 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1004 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX_VAR, TILEY_VAR, x, y);
1007 void DrawFixedGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1013 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1014 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
1017 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
1020 if (!IN_SCR_FIELD(x, y))
1022 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1023 printf("DrawGraphicThruMask(): This should never happen!\n");
1028 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
1031 MarkTileDirty(x, y);
1034 void DrawFixedGraphicThruMask(int x, int y, int graphic, int frame)
1037 if (!IN_SCR_FIELD(x, y))
1039 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1040 printf("DrawGraphicThruMask(): This should never happen!\n");
1045 DrawFixedGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
1047 MarkTileDirty(x, y);
1050 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
1056 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1058 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX_VAR, TILEY_VAR,
1062 void DrawFixedGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y,
1063 int graphic, int frame)
1065 struct GraphicInfo *g = &graphic_info[graphic];
1069 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1071 BlitBitmapMasked(src_bitmap, d, src_x, src_y, g->width, g->height,
1075 void DrawSizedGraphic(int x, int y, int graphic, int frame, int tilesize)
1077 DrawSizedGraphicExt(drawto, SX + x * tilesize, SY + y * tilesize, graphic,
1079 MarkTileDirty(x / tilesize, y / tilesize);
1082 void DrawSizedGraphicExt(DrawBuffer *d, int x, int y, int graphic, int frame,
1088 getSizedGraphicSource(graphic, frame, tilesize, &src_bitmap, &src_x, &src_y);
1089 BlitBitmap(src_bitmap, d, src_x, src_y, tilesize, tilesize, x, y);
1092 void DrawMiniGraphic(int x, int y, int graphic)
1094 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
1095 MarkTileDirty(x / 2, y / 2);
1098 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
1103 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1104 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
1107 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
1108 int graphic, int frame,
1109 int cut_mode, int mask_mode)
1114 int width = TILEX, height = TILEY;
1117 if (dx || dy) /* shifted graphic */
1119 if (x < BX1) /* object enters playfield from the left */
1126 else if (x > BX2) /* object enters playfield from the right */
1132 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
1138 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
1140 else if (dx) /* general horizontal movement */
1141 MarkTileDirty(x + SIGN(dx), y);
1143 if (y < BY1) /* object enters playfield from the top */
1145 if (cut_mode==CUT_BELOW) /* object completely above top border */
1153 else if (y > BY2) /* object enters playfield from the bottom */
1159 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
1165 else if (dy > 0 && cut_mode == CUT_ABOVE)
1167 if (y == BY2) /* object completely above bottom border */
1173 MarkTileDirty(x, y + 1);
1174 } /* object leaves playfield to the bottom */
1175 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1177 else if (dy) /* general vertical movement */
1178 MarkTileDirty(x, y + SIGN(dy));
1182 if (!IN_SCR_FIELD(x, y))
1184 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1185 printf("DrawGraphicShifted(): This should never happen!\n");
1190 width = width * TILESIZE_VAR / TILESIZE;
1191 height = height * TILESIZE_VAR / TILESIZE;
1192 cx = cx * TILESIZE_VAR / TILESIZE;
1193 cy = cy * TILESIZE_VAR / TILESIZE;
1194 dx = dx * TILESIZE_VAR / TILESIZE;
1195 dy = dy * TILESIZE_VAR / TILESIZE;
1197 if (width > 0 && height > 0)
1199 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1204 dst_x = FX + x * TILEX_VAR + dx;
1205 dst_y = FY + y * TILEY_VAR + dy;
1207 if (mask_mode == USE_MASKING)
1208 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1211 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1214 MarkTileDirty(x, y);
1218 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
1219 int graphic, int frame,
1220 int cut_mode, int mask_mode)
1225 int width = TILEX_VAR, height = TILEY_VAR;
1228 int x2 = x + SIGN(dx);
1229 int y2 = y + SIGN(dy);
1231 /* movement with two-tile animations must be sync'ed with movement position,
1232 not with current GfxFrame (which can be higher when using slow movement) */
1233 int anim_pos = (dx ? ABS(dx) : ABS(dy));
1234 int anim_frames = graphic_info[graphic].anim_frames;
1236 /* (we also need anim_delay here for movement animations with less frames) */
1237 int anim_delay = graphic_info[graphic].anim_delay;
1238 int sync_frame = anim_pos * anim_frames * anim_delay / TILESIZE;
1240 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
1241 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
1243 /* re-calculate animation frame for two-tile movement animation */
1244 frame = getGraphicAnimationFrame(graphic, sync_frame);
1246 /* check if movement start graphic inside screen area and should be drawn */
1247 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
1249 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
1251 dst_x = FX + x1 * TILEX_VAR;
1252 dst_y = FY + y1 * TILEY_VAR;
1254 if (mask_mode == USE_MASKING)
1255 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1258 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1261 MarkTileDirty(x1, y1);
1264 /* check if movement end graphic inside screen area and should be drawn */
1265 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
1267 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
1269 dst_x = FX + x2 * TILEX_VAR;
1270 dst_y = FY + y2 * TILEY_VAR;
1272 if (mask_mode == USE_MASKING)
1273 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1276 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1279 MarkTileDirty(x2, y2);
1283 static void DrawGraphicShifted(int x, int y, int dx, int dy,
1284 int graphic, int frame,
1285 int cut_mode, int mask_mode)
1289 DrawGraphic(x, y, graphic, frame);
1294 if (graphic_info[graphic].double_movement) /* EM style movement images */
1295 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1297 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1300 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1301 int frame, int cut_mode)
1303 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
1306 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1307 int cut_mode, int mask_mode)
1309 int lx = LEVELX(x), ly = LEVELY(y);
1313 if (IN_LEV_FIELD(lx, ly))
1315 SetRandomAnimationValue(lx, ly);
1317 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
1318 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1320 /* do not use double (EM style) movement graphic when not moving */
1321 if (graphic_info[graphic].double_movement && !dx && !dy)
1323 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
1324 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1327 else /* border element */
1329 graphic = el2img(element);
1330 frame = getGraphicAnimationFrame(graphic, -1);
1333 if (element == EL_EXPANDABLE_WALL)
1335 boolean left_stopped = FALSE, right_stopped = FALSE;
1337 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1338 left_stopped = TRUE;
1339 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1340 right_stopped = TRUE;
1342 if (left_stopped && right_stopped)
1344 else if (left_stopped)
1346 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1347 frame = graphic_info[graphic].anim_frames - 1;
1349 else if (right_stopped)
1351 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1352 frame = graphic_info[graphic].anim_frames - 1;
1357 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1358 else if (mask_mode == USE_MASKING)
1359 DrawGraphicThruMask(x, y, graphic, frame);
1361 DrawGraphic(x, y, graphic, frame);
1364 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1365 int cut_mode, int mask_mode)
1367 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1368 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1369 cut_mode, mask_mode);
1372 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1375 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1378 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1381 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1384 void DrawLevelElementThruMask(int x, int y, int element)
1386 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1389 void DrawLevelFieldThruMask(int x, int y)
1391 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1394 /* !!! implementation of quicksand is totally broken !!! */
1395 #define IS_CRUMBLED_TILE(x, y, e) \
1396 (GFX_CRUMBLED(e) && (!IN_LEV_FIELD(x, y) || \
1397 !IS_MOVING(x, y) || \
1398 (e) == EL_QUICKSAND_EMPTYING || \
1399 (e) == EL_QUICKSAND_FAST_EMPTYING))
1401 static void DrawLevelFieldCrumbledInnerCorners(int x, int y, int dx, int dy,
1406 int width, height, cx, cy;
1407 int sx = SCREENX(x), sy = SCREENY(y);
1408 int crumbled_border_size = graphic_info[graphic].border_size;
1411 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1413 for (i = 1; i < 4; i++)
1415 int dxx = (i & 1 ? dx : 0);
1416 int dyy = (i & 2 ? dy : 0);
1419 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1422 /* check if neighbour field is of same crumble type */
1423 boolean same = (IS_CRUMBLED_TILE(xx, yy, element) &&
1424 graphic_info[graphic].class ==
1425 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class);
1427 /* return if check prevents inner corner */
1428 if (same == (dxx == dx && dyy == dy))
1432 /* if we reach this point, we have an inner corner */
1434 getGraphicSource(graphic, 1, &src_bitmap, &src_x, &src_y);
1436 width = crumbled_border_size * TILESIZE_VAR / TILESIZE;
1437 height = crumbled_border_size * TILESIZE_VAR / TILESIZE;
1438 cx = (dx > 0 ? TILESIZE_VAR - width : 0);
1439 cy = (dy > 0 ? TILESIZE_VAR - height : 0);
1441 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1442 width, height, FX + sx * TILEX_VAR + cx, FY + sy * TILEY_VAR + cy);
1445 static void DrawLevelFieldCrumbledBorders(int x, int y, int graphic, int frame,
1450 int width, height, bx, by, cx, cy;
1451 int sx = SCREENX(x), sy = SCREENY(y);
1452 int crumbled_border_size = graphic_info[graphic].border_size;
1453 int crumbled_border_size_var = crumbled_border_size * TILESIZE_VAR / TILESIZE;
1454 int crumbled_border_pos_var = TILESIZE_VAR - crumbled_border_size_var;
1457 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1459 /* draw simple, sloppy, non-corner-accurate crumbled border */
1461 width = (dir == 1 || dir == 2 ? crumbled_border_size_var : TILESIZE_VAR);
1462 height = (dir == 0 || dir == 3 ? crumbled_border_size_var : TILESIZE_VAR);
1463 cx = (dir == 2 ? crumbled_border_pos_var : 0);
1464 cy = (dir == 3 ? crumbled_border_pos_var : 0);
1466 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy, width, height,
1467 FX + sx * TILEX_VAR + cx,
1468 FY + sy * TILEY_VAR + cy);
1470 /* (remaining middle border part must be at least as big as corner part) */
1471 if (!(graphic_info[graphic].style & STYLE_ACCURATE_BORDERS) ||
1472 crumbled_border_size >= TILESIZE / 3)
1475 /* correct corners of crumbled border, if needed */
1477 for (i = -1; i <= 1; i += 2)
1479 int xx = x + (dir == 0 || dir == 3 ? i : 0);
1480 int yy = y + (dir == 1 || dir == 2 ? i : 0);
1481 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1484 /* check if neighbour field is of same crumble type */
1485 if (IS_CRUMBLED_TILE(xx, yy, element) &&
1486 graphic_info[graphic].class ==
1487 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1489 /* no crumbled corner, but continued crumbled border */
1491 int c1 = (dir == 2 || dir == 3 ? crumbled_border_pos_var : 0);
1492 int c2 = (i == 1 ? crumbled_border_pos_var : 0);
1493 int b1 = (i == 1 ? crumbled_border_size_var :
1494 TILESIZE_VAR - 2 * crumbled_border_size_var);
1496 width = crumbled_border_size_var;
1497 height = crumbled_border_size_var;
1499 if (dir == 1 || dir == 2)
1514 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
1516 FX + sx * TILEX_VAR + cx,
1517 FY + sy * TILEY_VAR + cy);
1522 static void DrawLevelFieldCrumbledExt(int x, int y, int graphic, int frame)
1524 int sx = SCREENX(x), sy = SCREENY(y);
1527 static int xy[4][2] =
1535 if (!IN_LEV_FIELD(x, y))
1538 element = TILE_GFX_ELEMENT(x, y);
1540 /* crumble field itself */
1541 if (IS_CRUMBLED_TILE(x, y, element))
1543 if (!IN_SCR_FIELD(sx, sy))
1546 for (i = 0; i < 4; i++)
1548 int xx = x + xy[i][0];
1549 int yy = y + xy[i][1];
1551 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1554 /* check if neighbour field is of same crumble type */
1555 if (IS_CRUMBLED_TILE(xx, yy, element) &&
1556 graphic_info[graphic].class ==
1557 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1560 DrawLevelFieldCrumbledBorders(x, y, graphic, frame, i);
1563 if ((graphic_info[graphic].style & STYLE_INNER_CORNERS) &&
1564 graphic_info[graphic].anim_frames == 2)
1566 for (i = 0; i < 4; i++)
1568 int dx = (i & 1 ? +1 : -1);
1569 int dy = (i & 2 ? +1 : -1);
1571 DrawLevelFieldCrumbledInnerCorners(x, y, dx, dy, graphic);
1575 MarkTileDirty(sx, sy);
1577 else /* center field not crumbled -- crumble neighbour fields */
1579 for (i = 0; i < 4; i++)
1581 int xx = x + xy[i][0];
1582 int yy = y + xy[i][1];
1583 int sxx = sx + xy[i][0];
1584 int syy = sy + xy[i][1];
1586 if (!IN_LEV_FIELD(xx, yy) ||
1587 !IN_SCR_FIELD(sxx, syy))
1590 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
1593 element = TILE_GFX_ELEMENT(xx, yy);
1595 if (!IS_CRUMBLED_TILE(xx, yy, element))
1598 graphic = el_act2crm(element, ACTION_DEFAULT);
1600 DrawLevelFieldCrumbledBorders(xx, yy, graphic, 0, 3 - i);
1602 MarkTileDirty(sxx, syy);
1607 void DrawLevelFieldCrumbled(int x, int y)
1611 if (!IN_LEV_FIELD(x, y))
1614 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1615 GfxElement[x][y] != EL_UNDEFINED &&
1616 GFX_CRUMBLED(GfxElement[x][y]))
1618 DrawLevelFieldCrumbledDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
1623 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
1625 DrawLevelFieldCrumbledExt(x, y, graphic, 0);
1628 void DrawLevelFieldCrumbledDigging(int x, int y, int direction,
1631 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1632 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1633 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1634 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1635 int sx = SCREENX(x), sy = SCREENY(y);
1637 DrawGraphic(sx, sy, graphic1, frame1);
1638 DrawLevelFieldCrumbledExt(x, y, graphic2, frame2);
1641 void DrawLevelFieldCrumbledNeighbours(int x, int y)
1643 int sx = SCREENX(x), sy = SCREENY(y);
1644 static int xy[4][2] =
1653 for (i = 0; i < 4; i++)
1655 int xx = x + xy[i][0];
1656 int yy = y + xy[i][1];
1657 int sxx = sx + xy[i][0];
1658 int syy = sy + xy[i][1];
1660 if (!IN_LEV_FIELD(xx, yy) ||
1661 !IN_SCR_FIELD(sxx, syy) ||
1662 !GFX_CRUMBLED(Feld[xx][yy]) ||
1666 DrawLevelField(xx, yy);
1670 static int getBorderElement(int x, int y)
1674 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1675 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1676 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1677 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1678 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1679 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1680 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1682 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1683 int steel_position = (x == -1 && y == -1 ? 0 :
1684 x == lev_fieldx && y == -1 ? 1 :
1685 x == -1 && y == lev_fieldy ? 2 :
1686 x == lev_fieldx && y == lev_fieldy ? 3 :
1687 x == -1 || x == lev_fieldx ? 4 :
1688 y == -1 || y == lev_fieldy ? 5 : 6);
1690 return border[steel_position][steel_type];
1693 void DrawScreenElement(int x, int y, int element)
1695 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1696 DrawLevelFieldCrumbled(LEVELX(x), LEVELY(y));
1699 void DrawLevelElement(int x, int y, int element)
1701 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1702 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1705 void DrawScreenField(int x, int y)
1707 int lx = LEVELX(x), ly = LEVELY(y);
1708 int element, content;
1710 if (!IN_LEV_FIELD(lx, ly))
1712 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1715 element = getBorderElement(lx, ly);
1717 DrawScreenElement(x, y, element);
1722 element = Feld[lx][ly];
1723 content = Store[lx][ly];
1725 if (IS_MOVING(lx, ly))
1727 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1728 boolean cut_mode = NO_CUTTING;
1730 if (element == EL_QUICKSAND_EMPTYING ||
1731 element == EL_QUICKSAND_FAST_EMPTYING ||
1732 element == EL_MAGIC_WALL_EMPTYING ||
1733 element == EL_BD_MAGIC_WALL_EMPTYING ||
1734 element == EL_DC_MAGIC_WALL_EMPTYING ||
1735 element == EL_AMOEBA_DROPPING)
1736 cut_mode = CUT_ABOVE;
1737 else if (element == EL_QUICKSAND_FILLING ||
1738 element == EL_QUICKSAND_FAST_FILLING ||
1739 element == EL_MAGIC_WALL_FILLING ||
1740 element == EL_BD_MAGIC_WALL_FILLING ||
1741 element == EL_DC_MAGIC_WALL_FILLING)
1742 cut_mode = CUT_BELOW;
1744 if (cut_mode == CUT_ABOVE)
1745 DrawScreenElement(x, y, element);
1747 DrawScreenElement(x, y, EL_EMPTY);
1750 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1751 else if (cut_mode == NO_CUTTING)
1752 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1755 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1757 if (cut_mode == CUT_BELOW &&
1758 IN_LEV_FIELD(lx, ly + 1) && IN_SCR_FIELD(x, y + 1))
1759 DrawLevelElement(lx, ly + 1, element);
1762 if (content == EL_ACID)
1764 int dir = MovDir[lx][ly];
1765 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
1766 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
1768 DrawLevelElementThruMask(newlx, newly, EL_ACID);
1771 else if (IS_BLOCKED(lx, ly))
1776 boolean cut_mode = NO_CUTTING;
1777 int element_old, content_old;
1779 Blocked2Moving(lx, ly, &oldx, &oldy);
1782 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1783 MovDir[oldx][oldy] == MV_RIGHT);
1785 element_old = Feld[oldx][oldy];
1786 content_old = Store[oldx][oldy];
1788 if (element_old == EL_QUICKSAND_EMPTYING ||
1789 element_old == EL_QUICKSAND_FAST_EMPTYING ||
1790 element_old == EL_MAGIC_WALL_EMPTYING ||
1791 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1792 element_old == EL_DC_MAGIC_WALL_EMPTYING ||
1793 element_old == EL_AMOEBA_DROPPING)
1794 cut_mode = CUT_ABOVE;
1796 DrawScreenElement(x, y, EL_EMPTY);
1799 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1801 else if (cut_mode == NO_CUTTING)
1802 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1805 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1808 else if (IS_DRAWABLE(element))
1809 DrawScreenElement(x, y, element);
1811 DrawScreenElement(x, y, EL_EMPTY);
1814 void DrawLevelField(int x, int y)
1816 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1817 DrawScreenField(SCREENX(x), SCREENY(y));
1818 else if (IS_MOVING(x, y))
1822 Moving2Blocked(x, y, &newx, &newy);
1823 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1824 DrawScreenField(SCREENX(newx), SCREENY(newy));
1826 else if (IS_BLOCKED(x, y))
1830 Blocked2Moving(x, y, &oldx, &oldy);
1831 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1832 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1836 void DrawSizedElement(int x, int y, int element, int tilesize)
1840 graphic = el2edimg(element);
1841 DrawSizedGraphic(x, y, graphic, 0, tilesize);
1844 void DrawMiniElement(int x, int y, int element)
1848 graphic = el2edimg(element);
1849 DrawMiniGraphic(x, y, graphic);
1852 void DrawSizedElementOrWall(int sx, int sy, int scroll_x, int scroll_y,
1855 int x = sx + scroll_x, y = sy + scroll_y;
1857 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1858 DrawSizedElement(sx, sy, EL_EMPTY, tilesize);
1859 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1860 DrawSizedElement(sx, sy, Feld[x][y], tilesize);
1862 DrawSizedGraphic(sx, sy, el2edimg(getBorderElement(x, y)), 0, tilesize);
1865 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1867 int x = sx + scroll_x, y = sy + scroll_y;
1869 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1870 DrawMiniElement(sx, sy, EL_EMPTY);
1871 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1872 DrawMiniElement(sx, sy, Feld[x][y]);
1874 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1877 void DrawEnvelopeBackgroundTiles(int graphic, int startx, int starty,
1878 int x, int y, int xsize, int ysize,
1879 int tile_width, int tile_height)
1883 int dst_x = startx + x * tile_width;
1884 int dst_y = starty + y * tile_height;
1885 int width = graphic_info[graphic].width;
1886 int height = graphic_info[graphic].height;
1887 int inner_width_raw = MAX(width - 2 * tile_width, tile_width);
1888 int inner_height_raw = MAX(height - 2 * tile_height, tile_height);
1889 int inner_width = inner_width_raw - (inner_width_raw % tile_width);
1890 int inner_height = inner_height_raw - (inner_height_raw % tile_height);
1891 int inner_sx = (width >= 3 * tile_width ? tile_width : 0);
1892 int inner_sy = (height >= 3 * tile_height ? tile_height : 0);
1893 boolean draw_masked = graphic_info[graphic].draw_masked;
1895 getFixedGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1897 if (src_bitmap == NULL || width < tile_width || height < tile_height)
1899 ClearRectangle(drawto, dst_x, dst_y, tile_width, tile_height);
1903 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - tile_width :
1904 inner_sx + (x - 1) * tile_width % inner_width);
1905 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - tile_height :
1906 inner_sy + (y - 1) * tile_height % inner_height);
1909 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
1912 BlitBitmap(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
1916 void DrawEnvelopeBackground(int graphic, int startx, int starty,
1917 int x, int y, int xsize, int ysize, int font_nr)
1919 int font_width = getFontWidth(font_nr);
1920 int font_height = getFontHeight(font_nr);
1922 DrawEnvelopeBackgroundTiles(graphic, startx, starty, x, y, xsize, ysize,
1923 font_width, font_height);
1926 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
1928 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1929 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1930 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
1931 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1932 boolean no_delay = (tape.warp_forward);
1933 unsigned int anim_delay = 0;
1934 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
1935 int anim_delay_value = (no_delay ? 0 : frame_delay_value) / 2;
1936 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
1937 int font_width = getFontWidth(font_nr);
1938 int font_height = getFontHeight(font_nr);
1939 int max_xsize = level.envelope[envelope_nr].xsize;
1940 int max_ysize = level.envelope[envelope_nr].ysize;
1941 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
1942 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
1943 int xend = max_xsize;
1944 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
1945 int xstep = (xstart < xend ? 1 : 0);
1946 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
1948 int end = MAX(xend - xstart, yend - ystart);
1951 for (i = start; i <= end; i++)
1953 int last_frame = end; // last frame of this "for" loop
1954 int x = xstart + i * xstep;
1955 int y = ystart + i * ystep;
1956 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
1957 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
1958 int sx = SX + (SXSIZE - xsize * font_width) / 2;
1959 int sy = SY + (SYSIZE - ysize * font_height) / 2;
1962 SetDrawtoField(DRAW_FIELDBUFFER);
1964 BlitScreenToBitmap(backbuffer);
1966 SetDrawtoField(DRAW_BACKBUFFER);
1968 for (yy = 0; yy < ysize; yy++)
1969 for (xx = 0; xx < xsize; xx++)
1970 DrawEnvelopeBackground(graphic, sx, sy, xx, yy, xsize, ysize, font_nr);
1972 DrawTextBuffer(sx + font_width, sy + font_height,
1973 level.envelope[envelope_nr].text, font_nr, max_xsize,
1974 xsize - 2, ysize - 2, 0, mask_mode,
1975 level.envelope[envelope_nr].autowrap,
1976 level.envelope[envelope_nr].centered, FALSE);
1978 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
1981 SkipUntilDelayReached(&anim_delay, anim_delay_value, &i, last_frame);
1985 void ShowEnvelope(int envelope_nr)
1987 int element = EL_ENVELOPE_1 + envelope_nr;
1988 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1989 int sound_opening = element_info[element].sound[ACTION_OPENING];
1990 int sound_closing = element_info[element].sound[ACTION_CLOSING];
1991 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1992 boolean no_delay = (tape.warp_forward);
1993 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
1994 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
1995 int anim_mode = graphic_info[graphic].anim_mode;
1996 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
1997 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
1999 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
2001 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2003 if (anim_mode == ANIM_DEFAULT)
2004 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
2006 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
2009 Delay(wait_delay_value);
2011 WaitForEventToContinue();
2013 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2015 if (anim_mode != ANIM_NONE)
2016 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
2018 if (anim_mode == ANIM_DEFAULT)
2019 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
2021 game.envelope_active = FALSE;
2023 SetDrawtoField(DRAW_FIELDBUFFER);
2025 redraw_mask |= REDRAW_FIELD;
2029 static void setRequestCenterPosition(int *x, int *y)
2031 int sx_center = (request.x != -1 ? request.x : SX + SXSIZE / 2);
2032 int sy_center = (request.y != -1 ? request.y : SY + SYSIZE / 2);
2038 static void setRequestPosition(int *x, int *y, boolean add_border_size)
2040 int border_size = request.border_size;
2041 int sx_center, sy_center;
2044 setRequestCenterPosition(&sx_center, &sy_center);
2046 sx = sx_center - request.width / 2;
2047 sy = sy_center - request.height / 2;
2049 if (add_border_size)
2059 void DrawEnvelopeRequest(char *text)
2061 char *text_final = text;
2062 char *text_door_style = NULL;
2063 int graphic = IMG_BACKGROUND_REQUEST;
2064 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2065 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2066 int font_nr = FONT_REQUEST;
2067 int font_width = getFontWidth(font_nr);
2068 int font_height = getFontHeight(font_nr);
2069 int border_size = request.border_size;
2070 int line_spacing = request.line_spacing;
2071 int line_height = font_height + line_spacing;
2072 int text_width = request.width - 2 * border_size;
2073 int text_height = request.height - 2 * border_size;
2074 int line_length = text_width / font_width;
2075 int max_lines = text_height / line_height;
2076 int width = request.width;
2077 int height = request.height;
2078 int tile_size = request.step_offset;
2079 int x_steps = width / tile_size;
2080 int y_steps = height / tile_size;
2084 if (request.wrap_single_words)
2086 char *src_text_ptr, *dst_text_ptr;
2088 text_door_style = checked_malloc(2 * strlen(text) + 1);
2090 src_text_ptr = text;
2091 dst_text_ptr = text_door_style;
2093 while (*src_text_ptr)
2095 if (*src_text_ptr == ' ' ||
2096 *src_text_ptr == '?' ||
2097 *src_text_ptr == '!')
2098 *dst_text_ptr++ = '\n';
2100 if (*src_text_ptr != ' ')
2101 *dst_text_ptr++ = *src_text_ptr;
2106 *dst_text_ptr = '\0';
2108 text_final = text_door_style;
2111 setRequestPosition(&sx, &sy, FALSE);
2113 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
2115 for (y = 0; y < y_steps; y++)
2116 for (x = 0; x < x_steps; x++)
2117 DrawEnvelopeBackgroundTiles(graphic, sx, sy,
2118 x, y, x_steps, y_steps,
2119 tile_size, tile_size);
2121 DrawTextBuffer(sx + border_size, sy + border_size, text_final, font_nr,
2122 line_length, -1, max_lines, line_spacing, mask_mode,
2123 request.autowrap, request.centered, FALSE);
2125 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2126 RedrawGadget(tool_gadget[i]);
2128 // store readily prepared envelope request for later use when animating
2129 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2131 if (text_door_style)
2132 free(text_door_style);
2135 void AnimateEnvelopeRequest(int anim_mode, int action)
2137 int graphic = IMG_BACKGROUND_REQUEST;
2138 boolean draw_masked = graphic_info[graphic].draw_masked;
2139 int delay_value_normal = request.step_delay;
2140 int delay_value_fast = delay_value_normal / 2;
2141 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2142 boolean no_delay = (tape.warp_forward);
2143 int delay_value = (ffwd_delay ? delay_value_fast : delay_value_normal);
2144 int anim_delay_value = (no_delay ? 0 : delay_value + 500 * 0) / 2;
2145 unsigned int anim_delay = 0;
2147 int width = request.width;
2148 int height = request.height;
2149 int tile_size = request.step_offset;
2150 int max_xsize = width / tile_size;
2151 int max_ysize = height / tile_size;
2152 int max_xsize_inner = max_xsize - 2;
2153 int max_ysize_inner = max_ysize - 2;
2155 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize_inner : 0);
2156 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize_inner : 0);
2157 int xend = max_xsize_inner;
2158 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize_inner : 0);
2159 int xstep = (xstart < xend ? 1 : 0);
2160 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2162 int end = MAX(xend - xstart, yend - ystart);
2165 if (setup.quick_doors)
2173 if (action == ACTION_OPENING)
2174 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2175 else if (action == ACTION_CLOSING)
2176 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2179 for (i = start; i <= end; i++)
2181 int last_frame = end; // last frame of this "for" loop
2182 int x = xstart + i * xstep;
2183 int y = ystart + i * ystep;
2184 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2185 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2186 int xsize_size_left = (xsize - 1) * tile_size;
2187 int ysize_size_top = (ysize - 1) * tile_size;
2188 int max_xsize_pos = (max_xsize - 1) * tile_size;
2189 int max_ysize_pos = (max_ysize - 1) * tile_size;
2190 int sx_center, sy_center;
2195 setRequestCenterPosition(&sx_center, &sy_center);
2197 src_x = sx_center - width / 2;
2198 src_y = sy_center - height / 2;
2199 dst_x = sx_center - xsize * tile_size / 2;
2200 dst_y = sy_center - ysize * tile_size / 2;
2202 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2204 for (yy = 0; yy < 2; yy++)
2206 for (xx = 0; xx < 2; xx++)
2208 int src_xx = src_x + xx * max_xsize_pos;
2209 int src_yy = src_y + yy * max_ysize_pos;
2210 int dst_xx = dst_x + xx * xsize_size_left;
2211 int dst_yy = dst_y + yy * ysize_size_top;
2212 int xx_size = (xx ? tile_size : xsize_size_left);
2213 int yy_size = (yy ? tile_size : ysize_size_top);
2216 BlitBitmapMasked(bitmap_db_cross, backbuffer,
2217 src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
2219 BlitBitmap(bitmap_db_cross, backbuffer,
2220 src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
2224 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2229 SkipUntilDelayReached(&anim_delay, anim_delay_value, &i, last_frame);
2233 void ShowEnvelopeRequest(char *text, unsigned int req_state, int action)
2235 int last_game_status = game_status; /* save current game status */
2236 int graphic = IMG_BACKGROUND_REQUEST;
2237 int sound_opening = SND_REQUEST_OPENING;
2238 int sound_closing = SND_REQUEST_CLOSING;
2239 int anim_mode = graphic_info[graphic].anim_mode;
2240 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2241 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2243 if (game_status == GAME_MODE_PLAYING)
2244 BlitScreenToBitmap(backbuffer);
2246 SetDrawtoField(DRAW_BACKBUFFER);
2248 // SetDrawBackgroundMask(REDRAW_NONE);
2250 if (action == ACTION_OPENING)
2252 BlitBitmap(backbuffer, bitmap_db_store, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2254 if (req_state & REQ_ASK)
2256 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2257 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2259 else if (req_state & REQ_CONFIRM)
2261 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2263 else if (req_state & REQ_PLAYER)
2265 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2266 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2267 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2268 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2271 DrawEnvelopeRequest(text);
2273 if (game_status != GAME_MODE_MAIN)
2277 /* force DOOR font inside door area */
2278 game_status = GAME_MODE_PSEUDO_DOOR;
2280 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
2282 if (action == ACTION_OPENING)
2284 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2286 if (anim_mode == ANIM_DEFAULT)
2287 AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_OPENING);
2289 AnimateEnvelopeRequest(main_anim_mode, ACTION_OPENING);
2293 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2295 if (anim_mode != ANIM_NONE)
2296 AnimateEnvelopeRequest(main_anim_mode, ACTION_CLOSING);
2298 if (anim_mode == ANIM_DEFAULT)
2299 AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_CLOSING);
2302 game.envelope_active = FALSE;
2304 game_status = last_game_status; /* restore current game status */
2306 if (action == ACTION_CLOSING)
2308 if (game_status != GAME_MODE_MAIN)
2311 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2314 // SetDrawBackgroundMask(last_draw_background_mask);
2316 redraw_mask |= REDRAW_FIELD;
2318 if (game_status == GAME_MODE_MAIN)
2323 if (action == ACTION_CLOSING &&
2324 game_status == GAME_MODE_PLAYING &&
2325 level.game_engine_type == GAME_ENGINE_TYPE_RND)
2326 SetDrawtoField(DRAW_FIELDBUFFER);
2329 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
2333 int graphic = el2preimg(element);
2335 getSizedGraphicSource(graphic, 0, tilesize, &src_bitmap, &src_x, &src_y);
2336 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
2339 void DrawLevel(int draw_background_mask)
2343 SetMainBackgroundImage(IMG_BACKGROUND_PLAYING);
2344 SetDrawBackgroundMask(draw_background_mask);
2348 for (x = BX1; x <= BX2; x++)
2349 for (y = BY1; y <= BY2; y++)
2350 DrawScreenField(x, y);
2352 redraw_mask |= REDRAW_FIELD;
2355 void DrawSizedLevel(int size_x, int size_y, int scroll_x, int scroll_y,
2360 for (x = 0; x < size_x; x++)
2361 for (y = 0; y < size_y; y++)
2362 DrawSizedElementOrWall(x, y, scroll_x, scroll_y, tilesize);
2364 redraw_mask |= REDRAW_FIELD;
2367 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
2371 for (x = 0; x < size_x; x++)
2372 for (y = 0; y < size_y; y++)
2373 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
2375 redraw_mask |= REDRAW_FIELD;
2378 static void DrawPreviewLevelPlayfieldExt(int from_x, int from_y)
2380 boolean show_level_border = (BorderElement != EL_EMPTY);
2381 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2382 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2383 int tile_size = preview.tile_size;
2384 int preview_width = preview.xsize * tile_size;
2385 int preview_height = preview.ysize * tile_size;
2386 int real_preview_xsize = MIN(level_xsize, preview.xsize);
2387 int real_preview_ysize = MIN(level_ysize, preview.ysize);
2388 int real_preview_width = real_preview_xsize * tile_size;
2389 int real_preview_height = real_preview_ysize * tile_size;
2390 int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
2391 int dst_y = SY + ALIGNED_YPOS(preview.y, preview_height, preview.valign);
2394 if (!IN_GFX_FIELD_FULL(dst_x, dst_y + preview_height - 1))
2397 DrawBackground(dst_x, dst_y, preview_width, preview_height);
2399 dst_x += (preview_width - real_preview_width) / 2;
2400 dst_y += (preview_height - real_preview_height) / 2;
2402 for (x = 0; x < real_preview_xsize; x++)
2404 for (y = 0; y < real_preview_ysize; y++)
2406 int lx = from_x + x + (show_level_border ? -1 : 0);
2407 int ly = from_y + y + (show_level_border ? -1 : 0);
2408 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
2409 getBorderElement(lx, ly));
2411 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
2412 element, tile_size);
2416 redraw_mask |= REDRAW_MICROLEVEL;
2419 #define MICROLABEL_EMPTY 0
2420 #define MICROLABEL_LEVEL_NAME 1
2421 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
2422 #define MICROLABEL_LEVEL_AUTHOR 3
2423 #define MICROLABEL_IMPORTED_FROM_HEAD 4
2424 #define MICROLABEL_IMPORTED_FROM 5
2425 #define MICROLABEL_IMPORTED_BY_HEAD 6
2426 #define MICROLABEL_IMPORTED_BY 7
2428 static int getMaxTextLength(struct TextPosInfo *pos, int font_nr)
2430 int max_text_width = SXSIZE;
2431 int font_width = getFontWidth(font_nr);
2433 if (pos->align == ALIGN_CENTER)
2434 max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
2435 else if (pos->align == ALIGN_RIGHT)
2436 max_text_width = pos->x;
2438 max_text_width = SXSIZE - pos->x;
2440 return max_text_width / font_width;
2443 static void DrawPreviewLevelLabelExt(int mode)
2445 struct TextPosInfo *pos = &menu.main.text.level_info_2;
2446 char label_text[MAX_OUTPUT_LINESIZE + 1];
2447 int max_len_label_text;
2448 int font_nr = pos->font;
2451 if (!IN_GFX_FIELD_FULL(pos->x, pos->y + getFontHeight(pos->font)))
2454 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
2455 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
2456 mode == MICROLABEL_IMPORTED_BY_HEAD)
2457 font_nr = pos->font_alt;
2459 max_len_label_text = getMaxTextLength(pos, font_nr);
2461 if (pos->size != -1)
2462 max_len_label_text = pos->size;
2464 for (i = 0; i < max_len_label_text; i++)
2465 label_text[i] = ' ';
2466 label_text[max_len_label_text] = '\0';
2468 if (strlen(label_text) > 0)
2469 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2472 (mode == MICROLABEL_LEVEL_NAME ? level.name :
2473 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
2474 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
2475 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
2476 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
2477 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
2478 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
2479 max_len_label_text);
2480 label_text[max_len_label_text] = '\0';
2482 if (strlen(label_text) > 0)
2483 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2485 redraw_mask |= REDRAW_MICROLEVEL;
2488 static void DrawPreviewLevelExt(boolean restart)
2490 static unsigned int scroll_delay = 0;
2491 static unsigned int label_delay = 0;
2492 static int from_x, from_y, scroll_direction;
2493 static int label_state, label_counter;
2494 unsigned int scroll_delay_value = preview.step_delay;
2495 boolean show_level_border = (BorderElement != EL_EMPTY);
2496 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2497 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2498 int last_game_status = game_status; /* save current game status */
2505 if (preview.anim_mode == ANIM_CENTERED)
2507 if (level_xsize > preview.xsize)
2508 from_x = (level_xsize - preview.xsize) / 2;
2509 if (level_ysize > preview.ysize)
2510 from_y = (level_ysize - preview.ysize) / 2;
2513 from_x += preview.xoffset;
2514 from_y += preview.yoffset;
2516 scroll_direction = MV_RIGHT;
2520 DrawPreviewLevelPlayfieldExt(from_x, from_y);
2521 DrawPreviewLevelLabelExt(label_state);
2523 /* initialize delay counters */
2524 DelayReached(&scroll_delay, 0);
2525 DelayReached(&label_delay, 0);
2527 if (leveldir_current->name)
2529 struct TextPosInfo *pos = &menu.main.text.level_info_1;
2530 char label_text[MAX_OUTPUT_LINESIZE + 1];
2531 int font_nr = pos->font;
2532 int max_len_label_text = getMaxTextLength(pos, font_nr);
2534 if (pos->size != -1)
2535 max_len_label_text = pos->size;
2537 strncpy(label_text, leveldir_current->name, max_len_label_text);
2538 label_text[max_len_label_text] = '\0';
2540 if (IN_GFX_FIELD_FULL(pos->x, pos->y + getFontHeight(pos->font)))
2541 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2544 game_status = last_game_status; /* restore current game status */
2549 /* scroll preview level, if needed */
2550 if (preview.anim_mode != ANIM_NONE &&
2551 (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
2552 DelayReached(&scroll_delay, scroll_delay_value))
2554 switch (scroll_direction)
2559 from_x -= preview.step_offset;
2560 from_x = (from_x < 0 ? 0 : from_x);
2563 scroll_direction = MV_UP;
2567 if (from_x < level_xsize - preview.xsize)
2569 from_x += preview.step_offset;
2570 from_x = (from_x > level_xsize - preview.xsize ?
2571 level_xsize - preview.xsize : from_x);
2574 scroll_direction = MV_DOWN;
2580 from_y -= preview.step_offset;
2581 from_y = (from_y < 0 ? 0 : from_y);
2584 scroll_direction = MV_RIGHT;
2588 if (from_y < level_ysize - preview.ysize)
2590 from_y += preview.step_offset;
2591 from_y = (from_y > level_ysize - preview.ysize ?
2592 level_ysize - preview.ysize : from_y);
2595 scroll_direction = MV_LEFT;
2602 DrawPreviewLevelPlayfieldExt(from_x, from_y);
2605 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
2606 /* redraw micro level label, if needed */
2607 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
2608 !strEqual(level.author, ANONYMOUS_NAME) &&
2609 !strEqual(level.author, leveldir_current->name) &&
2610 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
2612 int max_label_counter = 23;
2614 if (leveldir_current->imported_from != NULL &&
2615 strlen(leveldir_current->imported_from) > 0)
2616 max_label_counter += 14;
2617 if (leveldir_current->imported_by != NULL &&
2618 strlen(leveldir_current->imported_by) > 0)
2619 max_label_counter += 14;
2621 label_counter = (label_counter + 1) % max_label_counter;
2622 label_state = (label_counter >= 0 && label_counter <= 7 ?
2623 MICROLABEL_LEVEL_NAME :
2624 label_counter >= 9 && label_counter <= 12 ?
2625 MICROLABEL_LEVEL_AUTHOR_HEAD :
2626 label_counter >= 14 && label_counter <= 21 ?
2627 MICROLABEL_LEVEL_AUTHOR :
2628 label_counter >= 23 && label_counter <= 26 ?
2629 MICROLABEL_IMPORTED_FROM_HEAD :
2630 label_counter >= 28 && label_counter <= 35 ?
2631 MICROLABEL_IMPORTED_FROM :
2632 label_counter >= 37 && label_counter <= 40 ?
2633 MICROLABEL_IMPORTED_BY_HEAD :
2634 label_counter >= 42 && label_counter <= 49 ?
2635 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
2637 if (leveldir_current->imported_from == NULL &&
2638 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
2639 label_state == MICROLABEL_IMPORTED_FROM))
2640 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
2641 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
2643 DrawPreviewLevelLabelExt(label_state);
2646 game_status = last_game_status; /* restore current game status */
2649 void DrawPreviewLevelInitial()
2651 DrawPreviewLevelExt(TRUE);
2654 void DrawPreviewLevelAnimation()
2656 DrawPreviewLevelExt(FALSE);
2659 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
2660 int graphic, int sync_frame, int mask_mode)
2662 int frame = getGraphicAnimationFrame(graphic, sync_frame);
2664 if (mask_mode == USE_MASKING)
2665 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
2667 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
2670 inline void DrawFixedGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
2671 int graphic, int sync_frame,
2674 int frame = getGraphicAnimationFrame(graphic, sync_frame);
2676 if (mask_mode == USE_MASKING)
2677 DrawFixedGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
2679 DrawFixedGraphicExt(dst_bitmap, x, y, graphic, frame);
2682 inline void DrawGraphicAnimation(int x, int y, int graphic)
2684 int lx = LEVELX(x), ly = LEVELY(y);
2686 if (!IN_SCR_FIELD(x, y))
2689 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
2690 graphic, GfxFrame[lx][ly], NO_MASKING);
2692 MarkTileDirty(x, y);
2695 inline void DrawFixedGraphicAnimation(int x, int y, int graphic)
2697 int lx = LEVELX(x), ly = LEVELY(y);
2699 if (!IN_SCR_FIELD(x, y))
2702 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
2703 graphic, GfxFrame[lx][ly], NO_MASKING);
2704 MarkTileDirty(x, y);
2707 void DrawLevelGraphicAnimation(int x, int y, int graphic)
2709 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2712 void DrawLevelElementAnimation(int x, int y, int element)
2714 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2716 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2719 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
2721 int sx = SCREENX(x), sy = SCREENY(y);
2723 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2726 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2729 DrawGraphicAnimation(sx, sy, graphic);
2732 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
2733 DrawLevelFieldCrumbled(x, y);
2735 if (GFX_CRUMBLED(Feld[x][y]))
2736 DrawLevelFieldCrumbled(x, y);
2740 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
2742 int sx = SCREENX(x), sy = SCREENY(y);
2745 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2748 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2750 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2753 DrawGraphicAnimation(sx, sy, graphic);
2755 if (GFX_CRUMBLED(element))
2756 DrawLevelFieldCrumbled(x, y);
2759 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
2761 if (player->use_murphy)
2763 /* this works only because currently only one player can be "murphy" ... */
2764 static int last_horizontal_dir = MV_LEFT;
2765 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
2767 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2768 last_horizontal_dir = move_dir;
2770 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
2772 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
2774 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
2780 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
2783 static boolean equalGraphics(int graphic1, int graphic2)
2785 struct GraphicInfo *g1 = &graphic_info[graphic1];
2786 struct GraphicInfo *g2 = &graphic_info[graphic2];
2788 return (g1->bitmap == g2->bitmap &&
2789 g1->src_x == g2->src_x &&
2790 g1->src_y == g2->src_y &&
2791 g1->anim_frames == g2->anim_frames &&
2792 g1->anim_delay == g2->anim_delay &&
2793 g1->anim_mode == g2->anim_mode);
2796 void DrawAllPlayers()
2800 for (i = 0; i < MAX_PLAYERS; i++)
2801 if (stored_player[i].active)
2802 DrawPlayer(&stored_player[i]);
2805 void DrawPlayerField(int x, int y)
2807 if (!IS_PLAYER(x, y))
2810 DrawPlayer(PLAYERINFO(x, y));
2813 #define DRAW_PLAYER_OVER_PUSHED_ELEMENT 1
2815 void DrawPlayer(struct PlayerInfo *player)
2817 int jx = player->jx;
2818 int jy = player->jy;
2819 int move_dir = player->MovDir;
2820 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
2821 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
2822 int last_jx = (player->is_moving ? jx - dx : jx);
2823 int last_jy = (player->is_moving ? jy - dy : jy);
2824 int next_jx = jx + dx;
2825 int next_jy = jy + dy;
2826 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
2827 boolean player_is_opaque = FALSE;
2828 int sx = SCREENX(jx), sy = SCREENY(jy);
2829 int sxx = 0, syy = 0;
2830 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
2832 int action = ACTION_DEFAULT;
2833 int last_player_graphic = getPlayerGraphic(player, move_dir);
2834 int last_player_frame = player->Frame;
2837 /* GfxElement[][] is set to the element the player is digging or collecting;
2838 remove also for off-screen player if the player is not moving anymore */
2839 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
2840 GfxElement[jx][jy] = EL_UNDEFINED;
2842 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
2846 if (!IN_LEV_FIELD(jx, jy))
2848 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
2849 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
2850 printf("DrawPlayerField(): This should never happen!\n");
2855 if (element == EL_EXPLOSION)
2858 action = (player->is_pushing ? ACTION_PUSHING :
2859 player->is_digging ? ACTION_DIGGING :
2860 player->is_collecting ? ACTION_COLLECTING :
2861 player->is_moving ? ACTION_MOVING :
2862 player->is_snapping ? ACTION_SNAPPING :
2863 player->is_dropping ? ACTION_DROPPING :
2864 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
2866 if (player->is_waiting)
2867 move_dir = player->dir_waiting;
2869 InitPlayerGfxAnimation(player, action, move_dir);
2871 /* ----------------------------------------------------------------------- */
2872 /* draw things in the field the player is leaving, if needed */
2873 /* ----------------------------------------------------------------------- */
2875 if (player->is_moving)
2877 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
2879 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
2881 if (last_element == EL_DYNAMITE_ACTIVE ||
2882 last_element == EL_EM_DYNAMITE_ACTIVE ||
2883 last_element == EL_SP_DISK_RED_ACTIVE)
2884 DrawDynamite(last_jx, last_jy);
2886 DrawLevelFieldThruMask(last_jx, last_jy);
2888 else if (last_element == EL_DYNAMITE_ACTIVE ||
2889 last_element == EL_EM_DYNAMITE_ACTIVE ||
2890 last_element == EL_SP_DISK_RED_ACTIVE)
2891 DrawDynamite(last_jx, last_jy);
2893 /* !!! this is not enough to prevent flickering of players which are
2894 moving next to each others without a free tile between them -- this
2895 can only be solved by drawing all players layer by layer (first the
2896 background, then the foreground etc.) !!! => TODO */
2897 else if (!IS_PLAYER(last_jx, last_jy))
2898 DrawLevelField(last_jx, last_jy);
2901 DrawLevelField(last_jx, last_jy);
2904 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
2905 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
2908 if (!IN_SCR_FIELD(sx, sy))
2911 /* ----------------------------------------------------------------------- */
2912 /* draw things behind the player, if needed */
2913 /* ----------------------------------------------------------------------- */
2916 DrawLevelElement(jx, jy, Back[jx][jy]);
2917 else if (IS_ACTIVE_BOMB(element))
2918 DrawLevelElement(jx, jy, EL_EMPTY);
2921 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
2923 int old_element = GfxElement[jx][jy];
2924 int old_graphic = el_act_dir2img(old_element, action, move_dir);
2925 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
2927 if (GFX_CRUMBLED(old_element))
2928 DrawLevelFieldCrumbledDigging(jx, jy, move_dir, player->StepFrame);
2930 DrawGraphic(sx, sy, old_graphic, frame);
2932 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
2933 player_is_opaque = TRUE;
2937 GfxElement[jx][jy] = EL_UNDEFINED;
2939 /* make sure that pushed elements are drawn with correct frame rate */
2940 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2942 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
2943 GfxFrame[jx][jy] = player->StepFrame;
2945 DrawLevelField(jx, jy);
2949 #if !DRAW_PLAYER_OVER_PUSHED_ELEMENT
2950 /* ----------------------------------------------------------------------- */
2951 /* draw player himself */
2952 /* ----------------------------------------------------------------------- */
2954 graphic = getPlayerGraphic(player, move_dir);
2956 /* in the case of changed player action or direction, prevent the current
2957 animation frame from being restarted for identical animations */
2958 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
2959 player->Frame = last_player_frame;
2961 frame = getGraphicAnimationFrame(graphic, player->Frame);
2965 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2966 sxx = player->GfxPos;
2968 syy = player->GfxPos;
2971 if (player_is_opaque)
2972 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
2974 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2976 if (SHIELD_ON(player))
2978 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
2979 IMG_SHIELD_NORMAL_ACTIVE);
2980 int frame = getGraphicAnimationFrame(graphic, -1);
2982 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2986 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
2989 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2990 sxx = player->GfxPos;
2992 syy = player->GfxPos;
2996 /* ----------------------------------------------------------------------- */
2997 /* draw things the player is pushing, if needed */
2998 /* ----------------------------------------------------------------------- */
3000 if (player->is_pushing && player->is_moving)
3002 int px = SCREENX(jx), py = SCREENY(jy);
3003 int pxx = (TILEX - ABS(sxx)) * dx;
3004 int pyy = (TILEY - ABS(syy)) * dy;
3005 int gfx_frame = GfxFrame[jx][jy];
3011 if (!IS_MOVING(jx, jy)) /* push movement already finished */
3013 element = Feld[next_jx][next_jy];
3014 gfx_frame = GfxFrame[next_jx][next_jy];
3017 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
3019 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
3020 frame = getGraphicAnimationFrame(graphic, sync_frame);
3022 /* draw background element under pushed element (like the Sokoban field) */
3023 if (game.use_masked_pushing && IS_MOVING(jx, jy))
3025 /* this allows transparent pushing animation over non-black background */
3028 DrawLevelElement(jx, jy, Back[jx][jy]);
3030 DrawLevelElement(jx, jy, EL_EMPTY);
3032 if (Back[next_jx][next_jy])
3033 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3035 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
3037 else if (Back[next_jx][next_jy])
3038 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3041 /* do not draw (EM style) pushing animation when pushing is finished */
3042 /* (two-tile animations usually do not contain start and end frame) */
3043 if (graphic_info[graphic].double_movement && !IS_MOVING(jx, jy))
3044 DrawLevelElement(next_jx, next_jy, Feld[next_jx][next_jy]);
3046 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3048 /* masked drawing is needed for EMC style (double) movement graphics */
3049 /* !!! (ONLY WHEN DRAWING PUSHED ELEMENT OVER THE PLAYER) !!! */
3050 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3054 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
3055 /* ----------------------------------------------------------------------- */
3056 /* draw player himself */
3057 /* ----------------------------------------------------------------------- */
3059 graphic = getPlayerGraphic(player, move_dir);
3061 /* in the case of changed player action or direction, prevent the current
3062 animation frame from being restarted for identical animations */
3063 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
3064 player->Frame = last_player_frame;
3066 frame = getGraphicAnimationFrame(graphic, player->Frame);
3070 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3071 sxx = player->GfxPos;
3073 syy = player->GfxPos;
3076 if (player_is_opaque)
3077 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
3079 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3081 if (SHIELD_ON(player))
3083 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
3084 IMG_SHIELD_NORMAL_ACTIVE);
3085 int frame = getGraphicAnimationFrame(graphic, -1);
3087 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3091 /* ----------------------------------------------------------------------- */
3092 /* draw things in front of player (active dynamite or dynabombs) */
3093 /* ----------------------------------------------------------------------- */
3095 if (IS_ACTIVE_BOMB(element))
3097 graphic = el2img(element);
3098 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
3100 if (game.emulation == EMU_SUPAPLEX)
3101 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
3103 DrawGraphicThruMask(sx, sy, graphic, frame);
3106 if (player_is_moving && last_element == EL_EXPLOSION)
3108 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
3109 GfxElement[last_jx][last_jy] : EL_EMPTY);
3110 int graphic = el_act2img(element, ACTION_EXPLODING);
3111 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
3112 int phase = ExplodePhase[last_jx][last_jy] - 1;
3113 int frame = getGraphicAnimationFrame(graphic, phase - delay);
3116 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
3119 /* ----------------------------------------------------------------------- */
3120 /* draw elements the player is just walking/passing through/under */
3121 /* ----------------------------------------------------------------------- */
3123 if (player_is_moving)
3125 /* handle the field the player is leaving ... */
3126 if (IS_ACCESSIBLE_INSIDE(last_element))
3127 DrawLevelField(last_jx, last_jy);
3128 else if (IS_ACCESSIBLE_UNDER(last_element))
3129 DrawLevelFieldThruMask(last_jx, last_jy);
3132 /* do not redraw accessible elements if the player is just pushing them */
3133 if (!player_is_moving || !player->is_pushing)
3135 /* ... and the field the player is entering */
3136 if (IS_ACCESSIBLE_INSIDE(element))
3137 DrawLevelField(jx, jy);
3138 else if (IS_ACCESSIBLE_UNDER(element))
3139 DrawLevelFieldThruMask(jx, jy);
3142 MarkTileDirty(sx, sy);
3145 /* ------------------------------------------------------------------------- */
3147 void WaitForEventToContinue()
3149 boolean still_wait = TRUE;
3151 /* simulate releasing mouse button over last gadget, if still pressed */
3153 HandleGadgets(-1, -1, 0);
3155 button_status = MB_RELEASED;
3169 case EVENT_BUTTONPRESS:
3170 case EVENT_KEYPRESS:
3174 case EVENT_KEYRELEASE:
3175 ClearPlayerAction();
3179 HandleOtherEvents(&event);
3183 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3190 /* don't eat all CPU time */
3195 #define MAX_REQUEST_LINES 13
3196 #define MAX_REQUEST_LINE_FONT1_LEN 7
3197 #define MAX_REQUEST_LINE_FONT2_LEN 10
3199 static int RequestHandleEvents(unsigned int req_state)
3201 boolean level_solved = (game_status == GAME_MODE_PLAYING &&
3202 local_player->LevelSolved_GameEnd);
3203 int last_game_status = game_status; /* save current game status */
3204 int width = request.width;
3205 int height = request.height;
3209 setRequestPosition(&sx, &sy, FALSE);
3211 button_status = MB_RELEASED;
3213 request_gadget_id = -1;
3220 SetDrawtoField(DRAW_FIELDBUFFER);
3222 HandleGameActions();
3224 SetDrawtoField(DRAW_BACKBUFFER);
3226 if (global.use_envelope_request)
3228 /* copy current state of request area to middle of playfield area */
3229 BlitBitmap(bitmap_db_cross, drawto, sx, sy, width, height, sx, sy);
3237 while (NextValidEvent(&event))
3241 case EVENT_BUTTONPRESS:
3242 case EVENT_BUTTONRELEASE:
3243 case EVENT_MOTIONNOTIFY:
3247 if (event.type == EVENT_MOTIONNOTIFY)
3252 motion_status = TRUE;
3253 mx = ((MotionEvent *) &event)->x;
3254 my = ((MotionEvent *) &event)->y;
3258 motion_status = FALSE;
3259 mx = ((ButtonEvent *) &event)->x;
3260 my = ((ButtonEvent *) &event)->y;
3261 if (event.type == EVENT_BUTTONPRESS)
3262 button_status = ((ButtonEvent *) &event)->button;
3264 button_status = MB_RELEASED;
3267 /* this sets 'request_gadget_id' */
3268 HandleGadgets(mx, my, button_status);
3270 switch (request_gadget_id)
3272 case TOOL_CTRL_ID_YES:
3275 case TOOL_CTRL_ID_NO:
3278 case TOOL_CTRL_ID_CONFIRM:
3279 result = TRUE | FALSE;
3282 case TOOL_CTRL_ID_PLAYER_1:
3285 case TOOL_CTRL_ID_PLAYER_2:
3288 case TOOL_CTRL_ID_PLAYER_3:
3291 case TOOL_CTRL_ID_PLAYER_4:
3302 case EVENT_KEYPRESS:
3303 switch (GetEventKey((KeyEvent *)&event, TRUE))
3306 if (req_state & REQ_CONFIRM)
3311 #if defined(TARGET_SDL2)
3318 #if defined(TARGET_SDL2)
3328 if (req_state & REQ_PLAYER)
3332 case EVENT_KEYRELEASE:
3333 ClearPlayerAction();
3337 HandleOtherEvents(&event);
3342 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3344 int joy = AnyJoystick();
3346 if (joy & JOY_BUTTON_1)
3348 else if (joy & JOY_BUTTON_2)
3354 if (global.use_envelope_request)
3356 /* copy back current state of pressed buttons inside request area */
3357 BlitBitmap(drawto, bitmap_db_cross, sx, sy, width, height, sx, sy);
3364 if (!PendingEvent()) /* delay only if no pending events */
3368 game_status = GAME_MODE_PSEUDO_DOOR;
3372 game_status = last_game_status; /* restore current game status */
3378 static boolean RequestDoor(char *text, unsigned int req_state)
3380 unsigned int old_door_state;
3381 int last_game_status = game_status; /* save current game status */
3382 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
3383 int font_nr = FONT_TEXT_2;
3388 if (maxWordLengthInString(text) > MAX_REQUEST_LINE_FONT1_LEN)
3390 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
3391 font_nr = FONT_TEXT_1;
3394 if (game_status == GAME_MODE_PLAYING)
3395 BlitScreenToBitmap(backbuffer);
3397 /* disable deactivated drawing when quick-loading level tape recording */
3398 if (tape.playing && tape.deactivate_display)
3399 TapeDeactivateDisplayOff(TRUE);
3401 SetMouseCursor(CURSOR_DEFAULT);
3403 #if defined(NETWORK_AVALIABLE)
3404 /* pause network game while waiting for request to answer */
3405 if (options.network &&
3406 game_status == GAME_MODE_PLAYING &&
3407 req_state & REQUEST_WAIT_FOR_INPUT)
3408 SendToServer_PausePlaying();
3411 old_door_state = GetDoorState();
3413 /* simulate releasing mouse button over last gadget, if still pressed */
3415 HandleGadgets(-1, -1, 0);
3419 /* draw released gadget before proceeding */
3422 if (old_door_state & DOOR_OPEN_1)
3424 CloseDoor(DOOR_CLOSE_1);
3426 /* save old door content */
3427 BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
3428 0 * DXSIZE, 0, DXSIZE, DYSIZE, 1 * DXSIZE, 0);
3431 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
3432 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3434 /* clear door drawing field */
3435 DrawBackground(DX, DY, DXSIZE, DYSIZE);
3437 /* force DOOR font inside door area */
3438 game_status = GAME_MODE_PSEUDO_DOOR;
3440 /* write text for request */
3441 for (text_ptr = text, ty = 0; ty < MAX_REQUEST_LINES; ty++)
3443 char text_line[max_request_line_len + 1];
3449 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
3451 tc = *(text_ptr + tx);
3452 // if (!tc || tc == ' ')
3453 if (!tc || tc == ' ' || tc == '?' || tc == '!')
3457 if ((tc == '?' || tc == '!') && tl == 0)
3467 strncpy(text_line, text_ptr, tl);
3470 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
3471 DY + 8 + ty * (getFontHeight(font_nr) + 2),
3472 text_line, font_nr);
3474 text_ptr += tl + (tc == ' ' ? 1 : 0);
3475 // text_ptr += tl + (tc == ' ' || tc == '?' || tc == '!' ? 1 : 0);
3478 game_status = last_game_status; /* restore current game status */
3480 if (req_state & REQ_ASK)
3482 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
3483 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
3485 else if (req_state & REQ_CONFIRM)
3487 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
3489 else if (req_state & REQ_PLAYER)
3491 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
3492 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
3493 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
3494 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
3497 /* copy request gadgets to door backbuffer */
3498 BlitBitmap(drawto, bitmap_db_door_1, DX, DY, DXSIZE, DYSIZE, 0, 0);
3500 OpenDoor(DOOR_OPEN_1);
3502 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
3504 if (game_status == GAME_MODE_PLAYING)
3506 SetPanelBackground();
3507 SetDrawBackgroundMask(REDRAW_DOOR_1);
3511 SetDrawBackgroundMask(REDRAW_FIELD);
3517 if (game_status != GAME_MODE_MAIN)
3520 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3522 // ---------- handle request buttons ----------
3523 result = RequestHandleEvents(req_state);
3525 if (game_status != GAME_MODE_MAIN)
3530 if (!(req_state & REQ_STAY_OPEN))
3532 CloseDoor(DOOR_CLOSE_1);
3534 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
3535 (req_state & REQ_REOPEN))
3536 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
3541 if (game_status == GAME_MODE_PLAYING)
3543 SetPanelBackground();
3544 SetDrawBackgroundMask(REDRAW_DOOR_1);
3548 SetDrawBackgroundMask(REDRAW_FIELD);
3551 #if defined(NETWORK_AVALIABLE)
3552 /* continue network game after request */
3553 if (options.network &&
3554 game_status == GAME_MODE_PLAYING &&
3555 req_state & REQUEST_WAIT_FOR_INPUT)
3556 SendToServer_ContinuePlaying();
3559 /* restore deactivated drawing when quick-loading level tape recording */
3560 if (tape.playing && tape.deactivate_display)
3561 TapeDeactivateDisplayOn();
3566 static boolean RequestEnvelope(char *text, unsigned int req_state)
3570 if (game_status == GAME_MODE_PLAYING)
3571 BlitScreenToBitmap(backbuffer);
3573 /* disable deactivated drawing when quick-loading level tape recording */
3574 if (tape.playing && tape.deactivate_display)
3575 TapeDeactivateDisplayOff(TRUE);
3577 SetMouseCursor(CURSOR_DEFAULT);
3579 #if defined(NETWORK_AVALIABLE)
3580 /* pause network game while waiting for request to answer */
3581 if (options.network &&
3582 game_status == GAME_MODE_PLAYING &&
3583 req_state & REQUEST_WAIT_FOR_INPUT)
3584 SendToServer_PausePlaying();
3587 /* simulate releasing mouse button over last gadget, if still pressed */
3589 HandleGadgets(-1, -1, 0);
3593 // (replace with setting corresponding request background)
3594 // SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
3595 // SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3597 /* clear door drawing field */
3598 // DrawBackground(DX, DY, DXSIZE, DYSIZE);
3600 ShowEnvelopeRequest(text, req_state, ACTION_OPENING);
3602 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
3604 if (game_status == GAME_MODE_PLAYING)
3606 SetPanelBackground();
3607 SetDrawBackgroundMask(REDRAW_DOOR_1);
3611 SetDrawBackgroundMask(REDRAW_FIELD);
3617 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3619 // ---------- handle request buttons ----------
3620 result = RequestHandleEvents(req_state);
3622 if (game_status != GAME_MODE_MAIN)
3627 ShowEnvelopeRequest(text, req_state, ACTION_CLOSING);
3631 if (game_status == GAME_MODE_PLAYING)
3633 SetPanelBackground();
3634 SetDrawBackgroundMask(REDRAW_DOOR_1);
3638 SetDrawBackgroundMask(REDRAW_FIELD);
3641 #if defined(NETWORK_AVALIABLE)
3642 /* continue network game after request */
3643 if (options.network &&
3644 game_status == GAME_MODE_PLAYING &&
3645 req_state & REQUEST_WAIT_FOR_INPUT)
3646 SendToServer_ContinuePlaying();
3649 /* restore deactivated drawing when quick-loading level tape recording */
3650 if (tape.playing && tape.deactivate_display)
3651 TapeDeactivateDisplayOn();
3656 boolean Request(char *text, unsigned int req_state)
3658 if (global.use_envelope_request)
3659 return RequestEnvelope(text, req_state);
3661 return RequestDoor(text, req_state);
3664 static int compareDoorPartOrderInfo(const void *object1, const void *object2)
3666 const struct DoorPartOrderInfo *dpo1 = (struct DoorPartOrderInfo *)object1;
3667 const struct DoorPartOrderInfo *dpo2 = (struct DoorPartOrderInfo *)object2;
3670 if (dpo1->sort_priority != dpo2->sort_priority)
3671 compare_result = dpo1->sort_priority - dpo2->sort_priority;
3673 compare_result = dpo1->nr - dpo2->nr;
3675 return compare_result;
3678 void InitGraphicCompatibilityInfo_Doors()
3684 struct DoorInfo *door;
3688 { DOOR_1, IMG_DOOR_1_GFX_PART_1, IMG_DOOR_1_GFX_PART_8, &door_1 },
3689 { DOOR_2, IMG_DOOR_2_GFX_PART_1, IMG_DOOR_2_GFX_PART_8, &door_2 },
3691 { -1, -1, -1, NULL }
3693 struct Rect door_rect_list[] =
3695 { DX, DY, DXSIZE, DYSIZE },
3696 { VX, VY, VXSIZE, VYSIZE }
3700 for (i = 0; doors[i].door_token != -1; i++)
3702 int door_token = doors[i].door_token;
3703 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
3704 int part_1 = doors[i].part_1;
3705 int part_8 = doors[i].part_8;
3706 int part_2 = part_1 + 1;
3707 int part_3 = part_1 + 2;
3708 struct DoorInfo *door = doors[i].door;
3709 struct Rect *door_rect = &door_rect_list[door_index];
3710 boolean door_gfx_redefined = FALSE;
3712 /* check if any door part graphic definitions have been redefined */
3714 for (j = 0; door_part_controls[j].door_token != -1; j++)
3716 struct DoorPartControlInfo *dpc = &door_part_controls[j];
3717 struct FileInfo *fi = getImageListEntryFromImageID(dpc->graphic);
3719 if (dpc->door_token == door_token && fi->redefined)
3720 door_gfx_redefined = TRUE;
3723 /* check for old-style door graphic/animation modifications */
3725 if (!door_gfx_redefined)
3727 if (door->anim_mode & ANIM_STATIC_PANEL)
3729 door->panel.step_xoffset = 0;
3730 door->panel.step_yoffset = 0;
3733 if (door->anim_mode & (ANIM_HORIZONTAL | ANIM_VERTICAL))
3735 struct GraphicInfo *g_part_1 = &graphic_info[part_1];
3736 struct GraphicInfo *g_part_2 = &graphic_info[part_2];
3737 int num_door_steps, num_panel_steps;
3739 /* remove door part graphics other than the two default wings */
3741 for (j = 0; door_part_controls[j].door_token != -1; j++)
3743 struct DoorPartControlInfo *dpc = &door_part_controls[j];
3744 struct GraphicInfo *g = &graphic_info[dpc->graphic];
3746 if (dpc->graphic >= part_3 &&
3747 dpc->graphic <= part_8)
3751 /* set graphics and screen positions of the default wings */
3753 g_part_1->width = door_rect->width;
3754 g_part_1->height = door_rect->height;
3755 g_part_2->width = door_rect->width;
3756 g_part_2->height = door_rect->height;
3757 g_part_2->src_x = door_rect->width;
3758 g_part_2->src_y = g_part_1->src_y;
3760 door->part_2.x = door->part_1.x;
3761 door->part_2.y = door->part_1.y;
3763 if (door->width != -1)
3765 g_part_1->width = door->width;
3766 g_part_2->width = door->width;
3768 // special treatment for graphics and screen position of right wing
3769 g_part_2->src_x += door_rect->width - door->width;
3770 door->part_2.x += door_rect->width - door->width;
3773 if (door->height != -1)
3775 g_part_1->height = door->height;
3776 g_part_2->height = door->height;
3778 // special treatment for graphics and screen position of bottom wing
3779 g_part_2->src_y += door_rect->height - door->height;
3780 door->part_2.y += door_rect->height - door->height;
3783 /* set animation delays for the default wings and panels */
3785 door->part_1.step_delay = door->step_delay;
3786 door->part_2.step_delay = door->step_delay;
3787 door->panel.step_delay = door->step_delay;
3789 /* set animation draw order for the default wings */
3791 door->part_1.sort_priority = 2; /* draw left wing over ... */
3792 door->part_2.sort_priority = 1; /* ... right wing */
3794 /* set animation draw offset for the default wings */
3796 if (door->anim_mode & ANIM_HORIZONTAL)
3798 door->part_1.step_xoffset = door->step_offset;
3799 door->part_1.step_yoffset = 0;
3800 door->part_2.step_xoffset = door->step_offset * -1;
3801 door->part_2.step_yoffset = 0;
3803 num_door_steps = g_part_1->width / door->step_offset;
3805 else // ANIM_VERTICAL
3807 door->part_1.step_xoffset = 0;
3808 door->part_1.step_yoffset = door->step_offset;
3809 door->part_2.step_xoffset = 0;
3810 door->part_2.step_yoffset = door->step_offset * -1;
3812 num_door_steps = g_part_1->height / door->step_offset;
3815 /* set animation draw offset for the default panels */
3817 if (door->step_offset > 1)
3819 num_panel_steps = 2 * door_rect->height / door->step_offset;
3820 door->panel.start_step = num_panel_steps - num_door_steps;
3821 door->panel.start_step_closing = door->panel.start_step;
3825 num_panel_steps = door_rect->height / door->step_offset;
3826 door->panel.start_step = num_panel_steps - num_door_steps / 2;
3827 door->panel.start_step_closing = door->panel.start_step;
3828 door->panel.step_delay *= 2;
3839 for (i = 0; door_part_controls[i].door_token != -1; i++)
3841 struct DoorPartControlInfo *dpc = &door_part_controls[i];
3842 struct DoorPartOrderInfo *dpo = &door_part_order[i];
3844 /* initialize "start_step_opening" and "start_step_closing", if needed */
3845 if (dpc->pos->start_step_opening == 0 &&
3846 dpc->pos->start_step_closing == 0)
3848 // dpc->pos->start_step_opening = dpc->pos->start_step;
3849 dpc->pos->start_step_closing = dpc->pos->start_step;
3852 /* fill structure for door part draw order (sorted below) */
3854 dpo->sort_priority = dpc->pos->sort_priority;
3857 /* sort door part controls according to sort_priority and graphic number */
3858 qsort(door_part_order, MAX_DOOR_PARTS,
3859 sizeof(struct DoorPartOrderInfo), compareDoorPartOrderInfo);
3862 unsigned int OpenDoor(unsigned int door_state)
3864 if (door_state & DOOR_COPY_BACK)
3866 if (door_state & DOOR_OPEN_1)
3867 BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
3868 1 * DXSIZE, 0, DXSIZE, DYSIZE, 0 * DXSIZE, 0);
3870 if (door_state & DOOR_OPEN_2)
3871 BlitBitmap(bitmap_db_door_2, bitmap_db_door_2,
3872 1 * VXSIZE, 0, VXSIZE, VYSIZE, 0 * VXSIZE, 0);
3874 door_state &= ~DOOR_COPY_BACK;
3877 return MoveDoor(door_state);
3880 unsigned int CloseDoor(unsigned int door_state)
3882 unsigned int old_door_state = GetDoorState();
3884 if (!(door_state & DOOR_NO_COPY_BACK))
3886 if (old_door_state & DOOR_OPEN_1)
3887 BlitBitmap(backbuffer, bitmap_db_door_1,
3888 DX, DY, DXSIZE, DYSIZE, 0, 0);
3890 if (old_door_state & DOOR_OPEN_2)
3891 BlitBitmap(backbuffer, bitmap_db_door_2,
3892 VX, VY, VXSIZE, VYSIZE, 0, 0);
3894 door_state &= ~DOOR_NO_COPY_BACK;
3897 return MoveDoor(door_state);
3900 unsigned int GetDoorState()
3902 return MoveDoor(DOOR_GET_STATE);
3905 unsigned int SetDoorState(unsigned int door_state)
3907 return MoveDoor(door_state | DOOR_SET_STATE);
3910 int euclid(int a, int b)
3912 return (b ? euclid(b, a % b) : a);
3915 unsigned int MoveDoor(unsigned int door_state)
3917 struct Rect door_rect_list[] =
3919 { DX, DY, DXSIZE, DYSIZE },
3920 { VX, VY, VXSIZE, VYSIZE }
3922 static int door1 = DOOR_OPEN_1;
3923 static int door2 = DOOR_CLOSE_2;
3924 unsigned int door_delay = 0;
3925 unsigned int door_delay_value;
3928 if (door_state == DOOR_GET_STATE)
3929 return (door1 | door2);
3931 if (door_state & DOOR_SET_STATE)
3933 if (door_state & DOOR_ACTION_1)
3934 door1 = door_state & DOOR_ACTION_1;
3935 if (door_state & DOOR_ACTION_2)
3936 door2 = door_state & DOOR_ACTION_2;
3938 return (door1 | door2);
3941 if (!(door_state & DOOR_FORCE_REDRAW))
3943 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
3944 door_state &= ~DOOR_OPEN_1;
3945 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
3946 door_state &= ~DOOR_CLOSE_1;
3947 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
3948 door_state &= ~DOOR_OPEN_2;
3949 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
3950 door_state &= ~DOOR_CLOSE_2;
3953 if (global.autoplay_leveldir)
3955 door_state |= DOOR_NO_DELAY;
3956 door_state &= ~DOOR_CLOSE_ALL;
3959 if (game_status == GAME_MODE_EDITOR)
3960 door_state |= DOOR_NO_DELAY;
3962 if (door_state & DOOR_ACTION)
3964 boolean door_panel_drawn[NUM_DOORS];
3965 boolean panel_has_doors[NUM_DOORS];
3966 boolean door_part_skip[MAX_DOOR_PARTS];
3967 boolean door_part_done[MAX_DOOR_PARTS];
3968 boolean door_part_done_all;
3969 int num_steps[MAX_DOOR_PARTS];
3970 int max_move_delay = 0; // delay for complete animations of all doors
3971 int max_step_delay = 0; // delay (ms) between two animation frames
3972 int num_move_steps = 0; // number of animation steps for all doors
3973 int max_move_delay_doors_only = 0; // delay for doors only (no panel)
3974 int num_move_steps_doors_only = 0; // steps for doors only (no panel)
3975 int current_move_delay = 0;
3979 for (i = 0; i < NUM_DOORS; i++)
3980 panel_has_doors[i] = FALSE;
3982 for (i = 0; i < MAX_DOOR_PARTS; i++)
3984 struct DoorPartControlInfo *dpc = &door_part_controls[i];
3985 struct GraphicInfo *g = &graphic_info[dpc->graphic];
3986 int door_token = dpc->door_token;
3988 door_part_done[i] = FALSE;
3989 door_part_skip[i] = (!(door_state & door_token) ||
3993 for (i = 0; i < MAX_DOOR_PARTS; i++)
3995 int nr = door_part_order[i].nr;
3996 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
3997 struct DoorPartPosInfo *pos = dpc->pos;
3998 struct GraphicInfo *g = &graphic_info[dpc->graphic];
3999 int door_token = dpc->door_token;
4000 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
4001 boolean is_panel = DOOR_PART_IS_PANEL(nr);
4002 int step_xoffset = ABS(pos->step_xoffset);
4003 int step_yoffset = ABS(pos->step_yoffset);
4004 int step_delay = pos->step_delay;
4005 int current_door_state = door_state & door_token;
4006 boolean door_opening = ((current_door_state & DOOR_OPEN) != 0);
4007 boolean door_closing = ((current_door_state & DOOR_CLOSE) != 0);
4008 boolean part_opening = (is_panel ? door_closing : door_opening);
4009 int start_step = (part_opening ? pos->start_step_opening :
4010 pos->start_step_closing);
4011 float move_xsize = (step_xoffset ? g->width : 0);
4012 float move_ysize = (step_yoffset ? g->height : 0);
4013 int move_xsteps = (step_xoffset ? ceil(move_xsize / step_xoffset) : 0);
4014 int move_ysteps = (step_yoffset ? ceil(move_ysize / step_yoffset) : 0);
4015 int move_steps = (move_xsteps && move_ysteps ?
4016 MIN(move_xsteps, move_ysteps) :
4017 move_xsteps ? move_xsteps : move_ysteps) - start_step;
4018 int move_delay = move_steps * step_delay;
4020 if (door_part_skip[nr])
4023 max_move_delay = MAX(max_move_delay, move_delay);
4024 max_step_delay = (max_step_delay == 0 ? step_delay :
4025 euclid(max_step_delay, step_delay));
4026 num_steps[nr] = move_steps;
4030 max_move_delay_doors_only = MAX(max_move_delay_doors_only, move_delay);
4032 panel_has_doors[door_index] = TRUE;
4036 max_step_delay = MAX(1, max_step_delay); // prevent division by zero
4038 num_move_steps = max_move_delay / max_step_delay;
4039 num_move_steps_doors_only = max_move_delay_doors_only / max_step_delay;
4041 door_delay_value = max_step_delay;
4043 if ((door_state & DOOR_NO_DELAY) || setup.quick_doors)
4045 start = num_move_steps - 1;
4049 /* opening door sound has priority over simultaneously closing door */
4050 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
4051 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
4052 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
4053 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
4056 for (k = start; k < num_move_steps; k++)
4058 int last_frame = num_move_steps - 1; // last frame of this "for" loop
4060 door_part_done_all = TRUE;
4062 for (i = 0; i < NUM_DOORS; i++)
4063 door_panel_drawn[i] = FALSE;
4065 for (i = 0; i < MAX_DOOR_PARTS; i++)
4067 int nr = door_part_order[i].nr;
4068 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
4069 struct DoorPartPosInfo *pos = dpc->pos;
4070 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4071 int door_token = dpc->door_token;
4072 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
4073 boolean is_panel = DOOR_PART_IS_PANEL(nr);
4074 boolean is_panel_and_door_has_closed = FALSE;
4075 struct Rect *door_rect = &door_rect_list[door_index];
4076 Bitmap *bitmap_db_door = (door_token == DOOR_1 ? bitmap_db_door_1 :
4078 Bitmap *bitmap = (is_panel ? bitmap_db_door : g->bitmap);
4079 int current_door_state = door_state & door_token;
4080 boolean door_opening = ((current_door_state & DOOR_OPEN) != 0);
4081 boolean door_closing = !door_opening;
4082 boolean part_opening = (is_panel ? door_closing : door_opening);
4083 boolean part_closing = !part_opening;
4084 int start_step = (part_opening ? pos->start_step_opening :
4085 pos->start_step_closing);
4086 int step_delay = pos->step_delay;
4087 int step_factor = step_delay / max_step_delay;
4088 int k1 = (step_factor ? k / step_factor + 1 : k);
4089 int k2 = (part_opening ? k1 + start_step : num_steps[nr] - k1);
4090 int kk = MAX(0, k2);
4093 int src_x, src_y, src_xx, src_yy;
4094 int dst_x, dst_y, dst_xx, dst_yy;
4097 if (door_part_skip[nr])
4100 if (!(door_state & door_token))
4108 int k2_door = (door_opening ? k : num_move_steps_doors_only - k - 1);
4109 int kk_door = MAX(0, k2_door);
4110 int sync_frame = kk_door * door_delay_value;
4111 int frame = getGraphicAnimationFrame(dpc->graphic, sync_frame);
4113 getGraphicSource(dpc->graphic, frame, &bitmap, &g_src_x, &g_src_y);
4118 if (!door_panel_drawn[door_index])
4120 ClearRectangle(drawto, door_rect->x, door_rect->y,
4121 door_rect->width, door_rect->height);
4123 door_panel_drawn[door_index] = TRUE;
4126 // draw opening or closing door parts
4128 if (pos->step_xoffset < 0) // door part on right side
4131 dst_xx = pos->x + ABS(kk * pos->step_xoffset);
4134 if (dst_xx + width > door_rect->width)
4135 width = door_rect->width - dst_xx;
4137 else // door part on left side
4140 dst_xx = pos->x - kk * pos->step_xoffset;
4144 src_xx = ABS(dst_xx);
4148 width = g->width - src_xx;
4150 // printf("::: k == %d [%d] \n", k, start_step);
4153 if (pos->step_yoffset < 0) // door part on bottom side
4156 dst_yy = pos->y + ABS(kk * pos->step_yoffset);
4159 if (dst_yy + height > door_rect->height)
4160 height = door_rect->height - dst_yy;
4162 else // door part on top side
4165 dst_yy = pos->y - kk * pos->step_yoffset;
4169 src_yy = ABS(dst_yy);
4173 height = g->height - src_yy;
4176 src_x = g_src_x + src_xx;
4177 src_y = g_src_y + src_yy;
4179 dst_x = door_rect->x + dst_xx;
4180 dst_y = door_rect->y + dst_yy;
4182 is_panel_and_door_has_closed =
4185 panel_has_doors[door_index] &&
4186 k >= num_move_steps_doors_only - 1);
4188 if (width >= 0 && width <= g->width &&
4189 height >= 0 && height <= g->height &&
4190 !is_panel_and_door_has_closed)
4192 if (is_panel || !pos->draw_masked)
4193 BlitBitmap(bitmap, drawto, src_x, src_y, width, height,
4196 BlitBitmapMasked(bitmap, drawto, src_x, src_y, width, height,
4200 redraw_mask |= REDRAW_DOOR_FROM_TOKEN(door_token);
4202 if ((part_opening && (width < 0 || height < 0)) ||
4203 (part_closing && (width >= g->width && height >= g->height)))
4204 door_part_done[nr] = TRUE;
4206 // continue door part animations, but not panel after door has closed
4207 if (!door_part_done[nr] && !is_panel_and_door_has_closed)
4208 door_part_done_all = FALSE;
4211 if (!(door_state & DOOR_NO_DELAY))
4215 if (game_status == GAME_MODE_MAIN)
4218 SkipUntilDelayReached(&door_delay, door_delay_value, &k, last_frame);
4220 current_move_delay += max_step_delay;
4223 if (door_part_done_all)
4228 if (door_state & DOOR_ACTION_1)
4229 door1 = door_state & DOOR_ACTION_1;
4230 if (door_state & DOOR_ACTION_2)
4231 door2 = door_state & DOOR_ACTION_2;
4233 return (door1 | door2);
4236 void DrawSpecialEditorDoor()
4238 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
4239 int top_border_width = gfx1->width;
4240 int top_border_height = gfx1->height;
4241 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
4242 int ex = EX - outer_border;
4243 int ey = EY - outer_border;
4244 int vy = VY - outer_border;
4245 int exsize = EXSIZE + 2 * outer_border;
4247 /* draw bigger level editor toolbox window */
4248 BlitBitmap(gfx1->bitmap, drawto, gfx1->src_x, gfx1->src_y,
4249 top_border_width, top_border_height, ex, ey - top_border_height);
4250 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto, ex, vy,
4251 exsize, EYSIZE - VYSIZE + outer_border, ex, ey);
4253 redraw_mask |= REDRAW_ALL;
4256 void UndrawSpecialEditorDoor()
4258 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
4259 int top_border_width = gfx1->width;
4260 int top_border_height = gfx1->height;
4261 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
4262 int ex = EX - outer_border;
4263 int ey = EY - outer_border;
4264 int ey_top = ey - top_border_height;
4265 int exsize = EXSIZE + 2 * outer_border;
4266 int eysize = EYSIZE + 2 * outer_border;
4268 /* draw normal tape recorder window */
4269 if (graphic_info[IMG_GLOBAL_BORDER].bitmap)
4271 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
4272 ex, ey_top, top_border_width, top_border_height,
4274 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
4275 ex, ey, exsize, eysize, ex, ey);
4279 // if screen background is set to "[NONE]", clear editor toolbox window
4280 ClearRectangle(drawto, ex, ey_top, top_border_width, top_border_height);
4281 ClearRectangle(drawto, ex, ey, exsize, eysize);
4284 redraw_mask |= REDRAW_ALL;
4288 /* ---------- new tool button stuff ---------------------------------------- */
4293 struct TextPosInfo *pos;
4296 } toolbutton_info[NUM_TOOL_BUTTONS] =
4299 IMG_REQUEST_BUTTON_GFX_YES, &request.button.yes,
4300 TOOL_CTRL_ID_YES, "yes"
4303 IMG_REQUEST_BUTTON_GFX_NO, &request.button.no,
4304 TOOL_CTRL_ID_NO, "no"
4307 IMG_REQUEST_BUTTON_GFX_CONFIRM, &request.button.confirm,
4308 TOOL_CTRL_ID_CONFIRM, "confirm"
4311 IMG_REQUEST_BUTTON_GFX_PLAYER_1, &request.button.player_1,
4312 TOOL_CTRL_ID_PLAYER_1, "player 1"
4315 IMG_REQUEST_BUTTON_GFX_PLAYER_2, &request.button.player_2,
4316 TOOL_CTRL_ID_PLAYER_2, "player 2"
4319 IMG_REQUEST_BUTTON_GFX_PLAYER_3, &request.button.player_3,
4320 TOOL_CTRL_ID_PLAYER_3, "player 3"
4323 IMG_REQUEST_BUTTON_GFX_PLAYER_4, &request.button.player_4,
4324 TOOL_CTRL_ID_PLAYER_4, "player 4"
4328 void CreateToolButtons()
4332 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4334 struct GraphicInfo *gfx = &graphic_info[toolbutton_info[i].graphic];
4335 struct TextPosInfo *pos = toolbutton_info[i].pos;
4336 struct GadgetInfo *gi;
4337 Bitmap *deco_bitmap = None;
4338 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
4339 unsigned int event_mask = GD_EVENT_RELEASED;
4342 int gd_x = gfx->src_x;
4343 int gd_y = gfx->src_y;
4344 int gd_xp = gfx->src_x + gfx->pressed_xoffset;
4345 int gd_yp = gfx->src_y + gfx->pressed_yoffset;
4348 if (global.use_envelope_request)
4349 setRequestPosition(&dx, &dy, TRUE);
4351 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
4353 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
4355 getSizedGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr), 0,
4356 pos->size, &deco_bitmap, &deco_x, &deco_y);
4357 deco_xpos = (gfx->width - pos->size) / 2;
4358 deco_ypos = (gfx->height - pos->size) / 2;
4361 gi = CreateGadget(GDI_CUSTOM_ID, id,
4362 GDI_INFO_TEXT, toolbutton_info[i].infotext,
4363 GDI_X, dx + GDI_ACTIVE_POS(pos->x),
4364 GDI_Y, dy + GDI_ACTIVE_POS(pos->y),
4365 GDI_WIDTH, gfx->width,
4366 GDI_HEIGHT, gfx->height,
4367 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
4368 GDI_STATE, GD_BUTTON_UNPRESSED,
4369 GDI_DESIGN_UNPRESSED, gfx->bitmap, gd_x, gd_y,
4370 GDI_DESIGN_PRESSED, gfx->bitmap, gd_xp, gd_yp,
4371 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
4372 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
4373 GDI_DECORATION_SIZE, pos->size, pos->size,
4374 GDI_DECORATION_SHIFTING, 1, 1,
4375 GDI_DIRECT_DRAW, FALSE,
4376 GDI_EVENT_MASK, event_mask,
4377 GDI_CALLBACK_ACTION, HandleToolButtons,
4381 Error(ERR_EXIT, "cannot create gadget");
4383 tool_gadget[id] = gi;
4387 void FreeToolButtons()
4391 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4392 FreeGadget(tool_gadget[i]);
4395 static void UnmapToolButtons()
4399 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4400 UnmapGadget(tool_gadget[i]);
4403 static void HandleToolButtons(struct GadgetInfo *gi)
4405 request_gadget_id = gi->custom_id;
4408 static struct Mapping_EM_to_RND_object
4411 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
4412 boolean is_backside; /* backside of moving element */
4418 em_object_mapping_list[] =
4421 Xblank, TRUE, FALSE,
4425 Yacid_splash_eB, FALSE, FALSE,
4426 EL_ACID_SPLASH_RIGHT, -1, -1
4429 Yacid_splash_wB, FALSE, FALSE,
4430 EL_ACID_SPLASH_LEFT, -1, -1
4433 #ifdef EM_ENGINE_BAD_ROLL
4435 Xstone_force_e, FALSE, FALSE,
4436 EL_ROCK, -1, MV_BIT_RIGHT
4439 Xstone_force_w, FALSE, FALSE,
4440 EL_ROCK, -1, MV_BIT_LEFT
4443 Xnut_force_e, FALSE, FALSE,
4444 EL_NUT, -1, MV_BIT_RIGHT
4447 Xnut_force_w, FALSE, FALSE,
4448 EL_NUT, -1, MV_BIT_LEFT
4451 Xspring_force_e, FALSE, FALSE,
4452 EL_SPRING, -1, MV_BIT_RIGHT
4455 Xspring_force_w, FALSE, FALSE,
4456 EL_SPRING, -1, MV_BIT_LEFT
4459 Xemerald_force_e, FALSE, FALSE,
4460 EL_EMERALD, -1, MV_BIT_RIGHT
4463 Xemerald_force_w, FALSE, FALSE,
4464 EL_EMERALD, -1, MV_BIT_LEFT
4467 Xdiamond_force_e, FALSE, FALSE,
4468 EL_DIAMOND, -1, MV_BIT_RIGHT
4471 Xdiamond_force_w, FALSE, FALSE,
4472 EL_DIAMOND, -1, MV_BIT_LEFT
4475 Xbomb_force_e, FALSE, FALSE,
4476 EL_BOMB, -1, MV_BIT_RIGHT
4479 Xbomb_force_w, FALSE, FALSE,
4480 EL_BOMB, -1, MV_BIT_LEFT
4482 #endif /* EM_ENGINE_BAD_ROLL */
4485 Xstone, TRUE, FALSE,
4489 Xstone_pause, FALSE, FALSE,
4493 Xstone_fall, FALSE, FALSE,
4497 Ystone_s, FALSE, FALSE,
4498 EL_ROCK, ACTION_FALLING, -1
4501 Ystone_sB, FALSE, TRUE,
4502 EL_ROCK, ACTION_FALLING, -1
4505 Ystone_e, FALSE, FALSE,
4506 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
4509 Ystone_eB, FALSE, TRUE,
4510 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
4513 Ystone_w, FALSE, FALSE,
4514 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
4517 Ystone_wB, FALSE, TRUE,
4518 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
4525 Xnut_pause, FALSE, FALSE,
4529 Xnut_fall, FALSE, FALSE,
4533 Ynut_s, FALSE, FALSE,
4534 EL_NUT, ACTION_FALLING, -1
4537 Ynut_sB, FALSE, TRUE,
4538 EL_NUT, ACTION_FALLING, -1
4541 Ynut_e, FALSE, FALSE,
4542 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
4545 Ynut_eB, FALSE, TRUE,
4546 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
4549 Ynut_w, FALSE, FALSE,
4550 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
4553 Ynut_wB, FALSE, TRUE,
4554 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
4557 Xbug_n, TRUE, FALSE,
4561 Xbug_e, TRUE, FALSE,
4562 EL_BUG_RIGHT, -1, -1
4565 Xbug_s, TRUE, FALSE,
4569 Xbug_w, TRUE, FALSE,
4573 Xbug_gon, FALSE, FALSE,
4577 Xbug_goe, FALSE, FALSE,
4578 EL_BUG_RIGHT, -1, -1
4581 Xbug_gos, FALSE, FALSE,
4585 Xbug_gow, FALSE, FALSE,
4589 Ybug_n, FALSE, FALSE,
4590 EL_BUG, ACTION_MOVING, MV_BIT_UP
4593 Ybug_nB, FALSE, TRUE,
4594 EL_BUG, ACTION_MOVING, MV_BIT_UP
4597 Ybug_e, FALSE, FALSE,
4598 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
4601 Ybug_eB, FALSE, TRUE,
4602 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
4605 Ybug_s, FALSE, FALSE,
4606 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
4609 Ybug_sB, FALSE, TRUE,
4610 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
4613 Ybug_w, FALSE, FALSE,
4614 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
4617 Ybug_wB, FALSE, TRUE,
4618 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
4621 Ybug_w_n, FALSE, FALSE,
4622 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
4625 Ybug_n_e, FALSE, FALSE,
4626 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
4629 Ybug_e_s, FALSE, FALSE,
4630 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
4633 Ybug_s_w, FALSE, FALSE,
4634 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
4637 Ybug_e_n, FALSE, FALSE,
4638 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
4641 Ybug_s_e, FALSE, FALSE,
4642 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
4645 Ybug_w_s, FALSE, FALSE,
4646 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
4649 Ybug_n_w, FALSE, FALSE,
4650 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
4653 Ybug_stone, FALSE, FALSE,
4654 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
4657 Ybug_spring, FALSE, FALSE,
4658 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
4661 Xtank_n, TRUE, FALSE,
4662 EL_SPACESHIP_UP, -1, -1
4665 Xtank_e, TRUE, FALSE,
4666 EL_SPACESHIP_RIGHT, -1, -1
4669 Xtank_s, TRUE, FALSE,
4670 EL_SPACESHIP_DOWN, -1, -1
4673 Xtank_w, TRUE, FALSE,
4674 EL_SPACESHIP_LEFT, -1, -1
4677 Xtank_gon, FALSE, FALSE,
4678 EL_SPACESHIP_UP, -1, -1
4681 Xtank_goe, FALSE, FALSE,
4682 EL_SPACESHIP_RIGHT, -1, -1
4685 Xtank_gos, FALSE, FALSE,
4686 EL_SPACESHIP_DOWN, -1, -1
4689 Xtank_gow, FALSE, FALSE,
4690 EL_SPACESHIP_LEFT, -1, -1
4693 Ytank_n, FALSE, FALSE,
4694 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
4697 Ytank_nB, FALSE, TRUE,
4698 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
4701 Ytank_e, FALSE, FALSE,
4702 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
4705 Ytank_eB, FALSE, TRUE,
4706 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
4709 Ytank_s, FALSE, FALSE,
4710 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
4713 Ytank_sB, FALSE, TRUE,
4714 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
4717 Ytank_w, FALSE, FALSE,
4718 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
4721 Ytank_wB, FALSE, TRUE,
4722 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
4725 Ytank_w_n, FALSE, FALSE,
4726 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
4729 Ytank_n_e, FALSE, FALSE,
4730 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
4733 Ytank_e_s, FALSE, FALSE,
4734 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
4737 Ytank_s_w, FALSE, FALSE,
4738 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
4741 Ytank_e_n, FALSE, FALSE,
4742 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
4745 Ytank_s_e, FALSE, FALSE,
4746 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
4749 Ytank_w_s, FALSE, FALSE,
4750 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
4753 Ytank_n_w, FALSE, FALSE,
4754 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
4757 Ytank_stone, FALSE, FALSE,
4758 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
4761 Ytank_spring, FALSE, FALSE,
4762 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
4765 Xandroid, TRUE, FALSE,
4766 EL_EMC_ANDROID, ACTION_ACTIVE, -1
4769 Xandroid_1_n, FALSE, FALSE,
4770 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
4773 Xandroid_2_n, FALSE, FALSE,
4774 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
4777 Xandroid_1_e, FALSE, FALSE,
4778 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
4781 Xandroid_2_e, FALSE, FALSE,
4782 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
4785 Xandroid_1_w, FALSE, FALSE,
4786 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
4789 Xandroid_2_w, FALSE, FALSE,
4790 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
4793 Xandroid_1_s, FALSE, FALSE,
4794 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
4797 Xandroid_2_s, FALSE, FALSE,
4798 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
4801 Yandroid_n, FALSE, FALSE,
4802 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
4805 Yandroid_nB, FALSE, TRUE,
4806 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
4809 Yandroid_ne, FALSE, FALSE,
4810 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
4813 Yandroid_neB, FALSE, TRUE,
4814 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
4817 Yandroid_e, FALSE, FALSE,
4818 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
4821 Yandroid_eB, FALSE, TRUE,
4822 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
4825 Yandroid_se, FALSE, FALSE,
4826 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
4829 Yandroid_seB, FALSE, TRUE,
4830 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
4833 Yandroid_s, FALSE, FALSE,
4834 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
4837 Yandroid_sB, FALSE, TRUE,
4838 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
4841 Yandroid_sw, FALSE, FALSE,
4842 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
4845 Yandroid_swB, FALSE, TRUE,
4846 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
4849 Yandroid_w, FALSE, FALSE,
4850 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
4853 Yandroid_wB, FALSE, TRUE,
4854 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
4857 Yandroid_nw, FALSE, FALSE,
4858 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
4861 Yandroid_nwB, FALSE, TRUE,
4862 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
4865 Xspring, TRUE, FALSE,
4869 Xspring_pause, FALSE, FALSE,
4873 Xspring_e, FALSE, FALSE,
4877 Xspring_w, FALSE, FALSE,
4881 Xspring_fall, FALSE, FALSE,
4885 Yspring_s, FALSE, FALSE,
4886 EL_SPRING, ACTION_FALLING, -1
4889 Yspring_sB, FALSE, TRUE,
4890 EL_SPRING, ACTION_FALLING, -1
4893 Yspring_e, FALSE, FALSE,
4894 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
4897 Yspring_eB, FALSE, TRUE,
4898 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
4901 Yspring_w, FALSE, FALSE,
4902 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
4905 Yspring_wB, FALSE, TRUE,
4906 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
4909 Yspring_kill_e, FALSE, FALSE,
4910 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
4913 Yspring_kill_eB, FALSE, TRUE,
4914 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
4917 Yspring_kill_w, FALSE, FALSE,
4918 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
4921 Yspring_kill_wB, FALSE, TRUE,
4922 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
4925 Xeater_n, TRUE, FALSE,
4926 EL_YAMYAM_UP, -1, -1
4929 Xeater_e, TRUE, FALSE,
4930 EL_YAMYAM_RIGHT, -1, -1
4933 Xeater_w, TRUE, FALSE,
4934 EL_YAMYAM_LEFT, -1, -1
4937 Xeater_s, TRUE, FALSE,
4938 EL_YAMYAM_DOWN, -1, -1
4941 Yeater_n, FALSE, FALSE,
4942 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
4945 Yeater_nB, FALSE, TRUE,
4946 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
4949 Yeater_e, FALSE, FALSE,
4950 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
4953 Yeater_eB, FALSE, TRUE,
4954 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
4957 Yeater_s, FALSE, FALSE,
4958 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
4961 Yeater_sB, FALSE, TRUE,
4962 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
4965 Yeater_w, FALSE, FALSE,
4966 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
4969 Yeater_wB, FALSE, TRUE,
4970 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
4973 Yeater_stone, FALSE, FALSE,
4974 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
4977 Yeater_spring, FALSE, FALSE,
4978 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
4981 Xalien, TRUE, FALSE,
4985 Xalien_pause, FALSE, FALSE,
4989 Yalien_n, FALSE, FALSE,
4990 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
4993 Yalien_nB, FALSE, TRUE,
4994 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
4997 Yalien_e, FALSE, FALSE,
4998 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
5001 Yalien_eB, FALSE, TRUE,
5002 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
5005 Yalien_s, FALSE, FALSE,
5006 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
5009 Yalien_sB, FALSE, TRUE,
5010 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
5013 Yalien_w, FALSE, FALSE,
5014 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
5017 Yalien_wB, FALSE, TRUE,
5018 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
5021 Yalien_stone, FALSE, FALSE,
5022 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
5025 Yalien_spring, FALSE, FALSE,
5026 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
5029 Xemerald, TRUE, FALSE,
5033 Xemerald_pause, FALSE, FALSE,
5037 Xemerald_fall, FALSE, FALSE,
5041 Xemerald_shine, FALSE, FALSE,
5042 EL_EMERALD, ACTION_TWINKLING, -1
5045 Yemerald_s, FALSE, FALSE,
5046 EL_EMERALD, ACTION_FALLING, -1
5049 Yemerald_sB, FALSE, TRUE,
5050 EL_EMERALD, ACTION_FALLING, -1
5053 Yemerald_e, FALSE, FALSE,
5054 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
5057 Yemerald_eB, FALSE, TRUE,
5058 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
5061 Yemerald_w, FALSE, FALSE,
5062 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
5065 Yemerald_wB, FALSE, TRUE,
5066 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
5069 Yemerald_eat, FALSE, FALSE,
5070 EL_EMERALD, ACTION_COLLECTING, -1
5073 Yemerald_stone, FALSE, FALSE,
5074 EL_NUT, ACTION_BREAKING, -1
5077 Xdiamond, TRUE, FALSE,
5081 Xdiamond_pause, FALSE, FALSE,
5085 Xdiamond_fall, FALSE, FALSE,
5089 Xdiamond_shine, FALSE, FALSE,
5090 EL_DIAMOND, ACTION_TWINKLING, -1
5093 Ydiamond_s, FALSE, FALSE,
5094 EL_DIAMOND, ACTION_FALLING, -1
5097 Ydiamond_sB, FALSE, TRUE,
5098 EL_DIAMOND, ACTION_FALLING, -1
5101 Ydiamond_e, FALSE, FALSE,
5102 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
5105 Ydiamond_eB, FALSE, TRUE,
5106 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
5109 Ydiamond_w, FALSE, FALSE,
5110 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
5113 Ydiamond_wB, FALSE, TRUE,
5114 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
5117 Ydiamond_eat, FALSE, FALSE,
5118 EL_DIAMOND, ACTION_COLLECTING, -1
5121 Ydiamond_stone, FALSE, FALSE,
5122 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
5125 Xdrip_fall, TRUE, FALSE,
5126 EL_AMOEBA_DROP, -1, -1
5129 Xdrip_stretch, FALSE, FALSE,
5130 EL_AMOEBA_DROP, ACTION_FALLING, -1
5133 Xdrip_stretchB, FALSE, TRUE,
5134 EL_AMOEBA_DROP, ACTION_FALLING, -1
5137 Xdrip_eat, FALSE, FALSE,
5138 EL_AMOEBA_DROP, ACTION_GROWING, -1
5141 Ydrip_s1, FALSE, FALSE,
5142 EL_AMOEBA_DROP, ACTION_FALLING, -1
5145 Ydrip_s1B, FALSE, TRUE,
5146 EL_AMOEBA_DROP, ACTION_FALLING, -1
5149 Ydrip_s2, FALSE, FALSE,
5150 EL_AMOEBA_DROP, ACTION_FALLING, -1
5153 Ydrip_s2B, FALSE, TRUE,
5154 EL_AMOEBA_DROP, ACTION_FALLING, -1
5161 Xbomb_pause, FALSE, FALSE,
5165 Xbomb_fall, FALSE, FALSE,
5169 Ybomb_s, FALSE, FALSE,
5170 EL_BOMB, ACTION_FALLING, -1
5173 Ybomb_sB, FALSE, TRUE,
5174 EL_BOMB, ACTION_FALLING, -1
5177 Ybomb_e, FALSE, FALSE,
5178 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
5181 Ybomb_eB, FALSE, TRUE,
5182 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
5185 Ybomb_w, FALSE, FALSE,
5186 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
5189 Ybomb_wB, FALSE, TRUE,
5190 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
5193 Ybomb_eat, FALSE, FALSE,
5194 EL_BOMB, ACTION_ACTIVATING, -1
5197 Xballoon, TRUE, FALSE,
5201 Yballoon_n, FALSE, FALSE,
5202 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
5205 Yballoon_nB, FALSE, TRUE,
5206 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
5209 Yballoon_e, FALSE, FALSE,
5210 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
5213 Yballoon_eB, FALSE, TRUE,
5214 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
5217 Yballoon_s, FALSE, FALSE,
5218 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
5221 Yballoon_sB, FALSE, TRUE,
5222 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
5225 Yballoon_w, FALSE, FALSE,
5226 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
5229 Yballoon_wB, FALSE, TRUE,
5230 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
5233 Xgrass, TRUE, FALSE,
5234 EL_EMC_GRASS, -1, -1
5237 Ygrass_nB, FALSE, FALSE,
5238 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
5241 Ygrass_eB, FALSE, FALSE,
5242 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
5245 Ygrass_sB, FALSE, FALSE,
5246 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
5249 Ygrass_wB, FALSE, FALSE,
5250 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
5257 Ydirt_nB, FALSE, FALSE,
5258 EL_SAND, ACTION_DIGGING, MV_BIT_UP
5261 Ydirt_eB, FALSE, FALSE,
5262 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
5265 Ydirt_sB, FALSE, FALSE,
5266 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
5269 Ydirt_wB, FALSE, FALSE,
5270 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
5273 Xacid_ne, TRUE, FALSE,
5274 EL_ACID_POOL_TOPRIGHT, -1, -1
5277 Xacid_se, TRUE, FALSE,
5278 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
5281 Xacid_s, TRUE, FALSE,
5282 EL_ACID_POOL_BOTTOM, -1, -1
5285 Xacid_sw, TRUE, FALSE,
5286 EL_ACID_POOL_BOTTOMLEFT, -1, -1
5289 Xacid_nw, TRUE, FALSE,
5290 EL_ACID_POOL_TOPLEFT, -1, -1
5293 Xacid_1, TRUE, FALSE,
5297 Xacid_2, FALSE, FALSE,
5301 Xacid_3, FALSE, FALSE,
5305 Xacid_4, FALSE, FALSE,
5309 Xacid_5, FALSE, FALSE,
5313 Xacid_6, FALSE, FALSE,
5317 Xacid_7, FALSE, FALSE,
5321 Xacid_8, FALSE, FALSE,
5325 Xball_1, TRUE, FALSE,
5326 EL_EMC_MAGIC_BALL, -1, -1
5329 Xball_1B, FALSE, FALSE,
5330 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5333 Xball_2, FALSE, FALSE,
5334 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5337 Xball_2B, FALSE, FALSE,
5338 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5341 Yball_eat, FALSE, FALSE,
5342 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
5345 Ykey_1_eat, FALSE, FALSE,
5346 EL_EM_KEY_1, ACTION_COLLECTING, -1
5349 Ykey_2_eat, FALSE, FALSE,
5350 EL_EM_KEY_2, ACTION_COLLECTING, -1
5353 Ykey_3_eat, FALSE, FALSE,
5354 EL_EM_KEY_3, ACTION_COLLECTING, -1
5357 Ykey_4_eat, FALSE, FALSE,
5358 EL_EM_KEY_4, ACTION_COLLECTING, -1
5361 Ykey_5_eat, FALSE, FALSE,
5362 EL_EMC_KEY_5, ACTION_COLLECTING, -1
5365 Ykey_6_eat, FALSE, FALSE,
5366 EL_EMC_KEY_6, ACTION_COLLECTING, -1
5369 Ykey_7_eat, FALSE, FALSE,
5370 EL_EMC_KEY_7, ACTION_COLLECTING, -1
5373 Ykey_8_eat, FALSE, FALSE,
5374 EL_EMC_KEY_8, ACTION_COLLECTING, -1
5377 Ylenses_eat, FALSE, FALSE,
5378 EL_EMC_LENSES, ACTION_COLLECTING, -1
5381 Ymagnify_eat, FALSE, FALSE,
5382 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
5385 Ygrass_eat, FALSE, FALSE,
5386 EL_EMC_GRASS, ACTION_SNAPPING, -1
5389 Ydirt_eat, FALSE, FALSE,
5390 EL_SAND, ACTION_SNAPPING, -1
5393 Xgrow_ns, TRUE, FALSE,
5394 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
5397 Ygrow_ns_eat, FALSE, FALSE,
5398 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
5401 Xgrow_ew, TRUE, FALSE,
5402 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
5405 Ygrow_ew_eat, FALSE, FALSE,
5406 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
5409 Xwonderwall, TRUE, FALSE,
5410 EL_MAGIC_WALL, -1, -1
5413 XwonderwallB, FALSE, FALSE,
5414 EL_MAGIC_WALL, ACTION_ACTIVE, -1
5417 Xamoeba_1, TRUE, FALSE,
5418 EL_AMOEBA_DRY, ACTION_OTHER, -1
5421 Xamoeba_2, FALSE, FALSE,
5422 EL_AMOEBA_DRY, ACTION_OTHER, -1
5425 Xamoeba_3, FALSE, FALSE,
5426 EL_AMOEBA_DRY, ACTION_OTHER, -1
5429 Xamoeba_4, FALSE, FALSE,
5430 EL_AMOEBA_DRY, ACTION_OTHER, -1
5433 Xamoeba_5, TRUE, FALSE,
5434 EL_AMOEBA_WET, ACTION_OTHER, -1
5437 Xamoeba_6, FALSE, FALSE,
5438 EL_AMOEBA_WET, ACTION_OTHER, -1
5441 Xamoeba_7, FALSE, FALSE,
5442 EL_AMOEBA_WET, ACTION_OTHER, -1
5445 Xamoeba_8, FALSE, FALSE,
5446 EL_AMOEBA_WET, ACTION_OTHER, -1
5449 Xdoor_1, TRUE, FALSE,
5450 EL_EM_GATE_1, -1, -1
5453 Xdoor_2, TRUE, FALSE,
5454 EL_EM_GATE_2, -1, -1
5457 Xdoor_3, TRUE, FALSE,
5458 EL_EM_GATE_3, -1, -1
5461 Xdoor_4, TRUE, FALSE,
5462 EL_EM_GATE_4, -1, -1
5465 Xdoor_5, TRUE, FALSE,
5466 EL_EMC_GATE_5, -1, -1
5469 Xdoor_6, TRUE, FALSE,
5470 EL_EMC_GATE_6, -1, -1
5473 Xdoor_7, TRUE, FALSE,
5474 EL_EMC_GATE_7, -1, -1
5477 Xdoor_8, TRUE, FALSE,
5478 EL_EMC_GATE_8, -1, -1
5481 Xkey_1, TRUE, FALSE,
5485 Xkey_2, TRUE, FALSE,
5489 Xkey_3, TRUE, FALSE,
5493 Xkey_4, TRUE, FALSE,
5497 Xkey_5, TRUE, FALSE,
5498 EL_EMC_KEY_5, -1, -1
5501 Xkey_6, TRUE, FALSE,
5502 EL_EMC_KEY_6, -1, -1
5505 Xkey_7, TRUE, FALSE,
5506 EL_EMC_KEY_7, -1, -1
5509 Xkey_8, TRUE, FALSE,
5510 EL_EMC_KEY_8, -1, -1
5513 Xwind_n, TRUE, FALSE,
5514 EL_BALLOON_SWITCH_UP, -1, -1
5517 Xwind_e, TRUE, FALSE,
5518 EL_BALLOON_SWITCH_RIGHT, -1, -1
5521 Xwind_s, TRUE, FALSE,
5522 EL_BALLOON_SWITCH_DOWN, -1, -1
5525 Xwind_w, TRUE, FALSE,
5526 EL_BALLOON_SWITCH_LEFT, -1, -1
5529 Xwind_nesw, TRUE, FALSE,
5530 EL_BALLOON_SWITCH_ANY, -1, -1
5533 Xwind_stop, TRUE, FALSE,
5534 EL_BALLOON_SWITCH_NONE, -1, -1
5538 EL_EM_EXIT_CLOSED, -1, -1
5541 Xexit_1, TRUE, FALSE,
5542 EL_EM_EXIT_OPEN, -1, -1
5545 Xexit_2, FALSE, FALSE,
5546 EL_EM_EXIT_OPEN, -1, -1
5549 Xexit_3, FALSE, FALSE,
5550 EL_EM_EXIT_OPEN, -1, -1
5553 Xdynamite, TRUE, FALSE,
5554 EL_EM_DYNAMITE, -1, -1
5557 Ydynamite_eat, FALSE, FALSE,
5558 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
5561 Xdynamite_1, TRUE, FALSE,
5562 EL_EM_DYNAMITE_ACTIVE, -1, -1
5565 Xdynamite_2, FALSE, FALSE,
5566 EL_EM_DYNAMITE_ACTIVE, -1, -1
5569 Xdynamite_3, FALSE, FALSE,
5570 EL_EM_DYNAMITE_ACTIVE, -1, -1
5573 Xdynamite_4, FALSE, FALSE,
5574 EL_EM_DYNAMITE_ACTIVE, -1, -1
5577 Xbumper, TRUE, FALSE,
5578 EL_EMC_SPRING_BUMPER, -1, -1
5581 XbumperB, FALSE, FALSE,
5582 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
5585 Xwheel, TRUE, FALSE,
5586 EL_ROBOT_WHEEL, -1, -1
5589 XwheelB, FALSE, FALSE,
5590 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
5593 Xswitch, TRUE, FALSE,
5594 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
5597 XswitchB, FALSE, FALSE,
5598 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
5602 EL_QUICKSAND_EMPTY, -1, -1
5605 Xsand_stone, TRUE, FALSE,
5606 EL_QUICKSAND_FULL, -1, -1
5609 Xsand_stonein_1, FALSE, TRUE,
5610 EL_ROCK, ACTION_FILLING, -1
5613 Xsand_stonein_2, FALSE, TRUE,
5614 EL_ROCK, ACTION_FILLING, -1
5617 Xsand_stonein_3, FALSE, TRUE,
5618 EL_ROCK, ACTION_FILLING, -1
5621 Xsand_stonein_4, FALSE, TRUE,
5622 EL_ROCK, ACTION_FILLING, -1
5625 Xsand_stonesand_1, FALSE, FALSE,
5626 EL_QUICKSAND_EMPTYING, -1, -1
5629 Xsand_stonesand_2, FALSE, FALSE,
5630 EL_QUICKSAND_EMPTYING, -1, -1
5633 Xsand_stonesand_3, FALSE, FALSE,
5634 EL_QUICKSAND_EMPTYING, -1, -1
5637 Xsand_stonesand_4, FALSE, FALSE,
5638 EL_QUICKSAND_EMPTYING, -1, -1
5641 Xsand_stonesand_quickout_1, FALSE, FALSE,
5642 EL_QUICKSAND_EMPTYING, -1, -1
5645 Xsand_stonesand_quickout_2, FALSE, FALSE,
5646 EL_QUICKSAND_EMPTYING, -1, -1
5649 Xsand_stoneout_1, FALSE, FALSE,
5650 EL_ROCK, ACTION_EMPTYING, -1
5653 Xsand_stoneout_2, FALSE, FALSE,
5654 EL_ROCK, ACTION_EMPTYING, -1
5657 Xsand_sandstone_1, FALSE, FALSE,
5658 EL_QUICKSAND_FILLING, -1, -1
5661 Xsand_sandstone_2, FALSE, FALSE,
5662 EL_QUICKSAND_FILLING, -1, -1
5665 Xsand_sandstone_3, FALSE, FALSE,
5666 EL_QUICKSAND_FILLING, -1, -1
5669 Xsand_sandstone_4, FALSE, FALSE,
5670 EL_QUICKSAND_FILLING, -1, -1
5673 Xplant, TRUE, FALSE,
5674 EL_EMC_PLANT, -1, -1
5677 Yplant, FALSE, FALSE,
5678 EL_EMC_PLANT, -1, -1
5681 Xlenses, TRUE, FALSE,
5682 EL_EMC_LENSES, -1, -1
5685 Xmagnify, TRUE, FALSE,
5686 EL_EMC_MAGNIFIER, -1, -1
5689 Xdripper, TRUE, FALSE,
5690 EL_EMC_DRIPPER, -1, -1
5693 XdripperB, FALSE, FALSE,
5694 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
5697 Xfake_blank, TRUE, FALSE,
5698 EL_INVISIBLE_WALL, -1, -1
5701 Xfake_blankB, FALSE, FALSE,
5702 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
5705 Xfake_grass, TRUE, FALSE,
5706 EL_EMC_FAKE_GRASS, -1, -1
5709 Xfake_grassB, FALSE, FALSE,
5710 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
5713 Xfake_door_1, TRUE, FALSE,
5714 EL_EM_GATE_1_GRAY, -1, -1
5717 Xfake_door_2, TRUE, FALSE,
5718 EL_EM_GATE_2_GRAY, -1, -1
5721 Xfake_door_3, TRUE, FALSE,
5722 EL_EM_GATE_3_GRAY, -1, -1
5725 Xfake_door_4, TRUE, FALSE,
5726 EL_EM_GATE_4_GRAY, -1, -1
5729 Xfake_door_5, TRUE, FALSE,
5730 EL_EMC_GATE_5_GRAY, -1, -1
5733 Xfake_door_6, TRUE, FALSE,
5734 EL_EMC_GATE_6_GRAY, -1, -1
5737 Xfake_door_7, TRUE, FALSE,
5738 EL_EMC_GATE_7_GRAY, -1, -1
5741 Xfake_door_8, TRUE, FALSE,
5742 EL_EMC_GATE_8_GRAY, -1, -1
5745 Xfake_acid_1, TRUE, FALSE,
5746 EL_EMC_FAKE_ACID, -1, -1
5749 Xfake_acid_2, FALSE, FALSE,
5750 EL_EMC_FAKE_ACID, -1, -1
5753 Xfake_acid_3, FALSE, FALSE,
5754 EL_EMC_FAKE_ACID, -1, -1
5757 Xfake_acid_4, FALSE, FALSE,
5758 EL_EMC_FAKE_ACID, -1, -1
5761 Xfake_acid_5, FALSE, FALSE,
5762 EL_EMC_FAKE_ACID, -1, -1
5765 Xfake_acid_6, FALSE, FALSE,
5766 EL_EMC_FAKE_ACID, -1, -1
5769 Xfake_acid_7, FALSE, FALSE,
5770 EL_EMC_FAKE_ACID, -1, -1
5773 Xfake_acid_8, FALSE, FALSE,
5774 EL_EMC_FAKE_ACID, -1, -1
5777 Xsteel_1, TRUE, FALSE,
5778 EL_STEELWALL, -1, -1
5781 Xsteel_2, TRUE, FALSE,
5782 EL_EMC_STEELWALL_2, -1, -1
5785 Xsteel_3, TRUE, FALSE,
5786 EL_EMC_STEELWALL_3, -1, -1
5789 Xsteel_4, TRUE, FALSE,
5790 EL_EMC_STEELWALL_4, -1, -1
5793 Xwall_1, TRUE, FALSE,
5797 Xwall_2, TRUE, FALSE,
5798 EL_EMC_WALL_14, -1, -1
5801 Xwall_3, TRUE, FALSE,
5802 EL_EMC_WALL_15, -1, -1
5805 Xwall_4, TRUE, FALSE,
5806 EL_EMC_WALL_16, -1, -1
5809 Xround_wall_1, TRUE, FALSE,
5810 EL_WALL_SLIPPERY, -1, -1
5813 Xround_wall_2, TRUE, FALSE,
5814 EL_EMC_WALL_SLIPPERY_2, -1, -1
5817 Xround_wall_3, TRUE, FALSE,
5818 EL_EMC_WALL_SLIPPERY_3, -1, -1
5821 Xround_wall_4, TRUE, FALSE,
5822 EL_EMC_WALL_SLIPPERY_4, -1, -1
5825 Xdecor_1, TRUE, FALSE,
5826 EL_EMC_WALL_8, -1, -1
5829 Xdecor_2, TRUE, FALSE,
5830 EL_EMC_WALL_6, -1, -1
5833 Xdecor_3, TRUE, FALSE,
5834 EL_EMC_WALL_4, -1, -1
5837 Xdecor_4, TRUE, FALSE,
5838 EL_EMC_WALL_7, -1, -1
5841 Xdecor_5, TRUE, FALSE,
5842 EL_EMC_WALL_5, -1, -1
5845 Xdecor_6, TRUE, FALSE,
5846 EL_EMC_WALL_9, -1, -1
5849 Xdecor_7, TRUE, FALSE,
5850 EL_EMC_WALL_10, -1, -1
5853 Xdecor_8, TRUE, FALSE,
5854 EL_EMC_WALL_1, -1, -1
5857 Xdecor_9, TRUE, FALSE,
5858 EL_EMC_WALL_2, -1, -1
5861 Xdecor_10, TRUE, FALSE,
5862 EL_EMC_WALL_3, -1, -1
5865 Xdecor_11, TRUE, FALSE,
5866 EL_EMC_WALL_11, -1, -1
5869 Xdecor_12, TRUE, FALSE,
5870 EL_EMC_WALL_12, -1, -1
5873 Xalpha_0, TRUE, FALSE,
5874 EL_CHAR('0'), -1, -1
5877 Xalpha_1, TRUE, FALSE,
5878 EL_CHAR('1'), -1, -1
5881 Xalpha_2, TRUE, FALSE,
5882 EL_CHAR('2'), -1, -1
5885 Xalpha_3, TRUE, FALSE,
5886 EL_CHAR('3'), -1, -1
5889 Xalpha_4, TRUE, FALSE,
5890 EL_CHAR('4'), -1, -1
5893 Xalpha_5, TRUE, FALSE,
5894 EL_CHAR('5'), -1, -1
5897 Xalpha_6, TRUE, FALSE,
5898 EL_CHAR('6'), -1, -1
5901 Xalpha_7, TRUE, FALSE,
5902 EL_CHAR('7'), -1, -1
5905 Xalpha_8, TRUE, FALSE,
5906 EL_CHAR('8'), -1, -1
5909 Xalpha_9, TRUE, FALSE,
5910 EL_CHAR('9'), -1, -1
5913 Xalpha_excla, TRUE, FALSE,
5914 EL_CHAR('!'), -1, -1
5917 Xalpha_quote, TRUE, FALSE,
5918 EL_CHAR('"'), -1, -1
5921 Xalpha_comma, TRUE, FALSE,
5922 EL_CHAR(','), -1, -1
5925 Xalpha_minus, TRUE, FALSE,
5926 EL_CHAR('-'), -1, -1
5929 Xalpha_perio, TRUE, FALSE,
5930 EL_CHAR('.'), -1, -1
5933 Xalpha_colon, TRUE, FALSE,
5934 EL_CHAR(':'), -1, -1
5937 Xalpha_quest, TRUE, FALSE,
5938 EL_CHAR('?'), -1, -1
5941 Xalpha_a, TRUE, FALSE,
5942 EL_CHAR('A'), -1, -1
5945 Xalpha_b, TRUE, FALSE,
5946 EL_CHAR('B'), -1, -1
5949 Xalpha_c, TRUE, FALSE,
5950 EL_CHAR('C'), -1, -1
5953 Xalpha_d, TRUE, FALSE,
5954 EL_CHAR('D'), -1, -1
5957 Xalpha_e, TRUE, FALSE,
5958 EL_CHAR('E'), -1, -1
5961 Xalpha_f, TRUE, FALSE,
5962 EL_CHAR('F'), -1, -1
5965 Xalpha_g, TRUE, FALSE,
5966 EL_CHAR('G'), -1, -1
5969 Xalpha_h, TRUE, FALSE,
5970 EL_CHAR('H'), -1, -1
5973 Xalpha_i, TRUE, FALSE,
5974 EL_CHAR('I'), -1, -1
5977 Xalpha_j, TRUE, FALSE,
5978 EL_CHAR('J'), -1, -1
5981 Xalpha_k, TRUE, FALSE,
5982 EL_CHAR('K'), -1, -1
5985 Xalpha_l, TRUE, FALSE,
5986 EL_CHAR('L'), -1, -1
5989 Xalpha_m, TRUE, FALSE,
5990 EL_CHAR('M'), -1, -1
5993 Xalpha_n, TRUE, FALSE,
5994 EL_CHAR('N'), -1, -1
5997 Xalpha_o, TRUE, FALSE,
5998 EL_CHAR('O'), -1, -1
6001 Xalpha_p, TRUE, FALSE,
6002 EL_CHAR('P'), -1, -1
6005 Xalpha_q, TRUE, FALSE,
6006 EL_CHAR('Q'), -1, -1
6009 Xalpha_r, TRUE, FALSE,
6010 EL_CHAR('R'), -1, -1
6013 Xalpha_s, TRUE, FALSE,
6014 EL_CHAR('S'), -1, -1
6017 Xalpha_t, TRUE, FALSE,
6018 EL_CHAR('T'), -1, -1
6021 Xalpha_u, TRUE, FALSE,
6022 EL_CHAR('U'), -1, -1
6025 Xalpha_v, TRUE, FALSE,
6026 EL_CHAR('V'), -1, -1
6029 Xalpha_w, TRUE, FALSE,
6030 EL_CHAR('W'), -1, -1
6033 Xalpha_x, TRUE, FALSE,
6034 EL_CHAR('X'), -1, -1
6037 Xalpha_y, TRUE, FALSE,
6038 EL_CHAR('Y'), -1, -1
6041 Xalpha_z, TRUE, FALSE,
6042 EL_CHAR('Z'), -1, -1
6045 Xalpha_arrow_e, TRUE, FALSE,
6046 EL_CHAR('>'), -1, -1
6049 Xalpha_arrow_w, TRUE, FALSE,
6050 EL_CHAR('<'), -1, -1
6053 Xalpha_copyr, TRUE, FALSE,
6054 EL_CHAR(CHAR_BYTE_COPYRIGHT), -1, -1
6058 Xboom_bug, FALSE, FALSE,
6059 EL_BUG, ACTION_EXPLODING, -1
6062 Xboom_bomb, FALSE, FALSE,
6063 EL_BOMB, ACTION_EXPLODING, -1
6066 Xboom_android, FALSE, FALSE,
6067 EL_EMC_ANDROID, ACTION_OTHER, -1
6070 Xboom_1, FALSE, FALSE,
6071 EL_DEFAULT, ACTION_EXPLODING, -1
6074 Xboom_2, FALSE, FALSE,
6075 EL_DEFAULT, ACTION_EXPLODING, -1
6078 Znormal, FALSE, FALSE,
6082 Zdynamite, FALSE, FALSE,
6086 Zplayer, FALSE, FALSE,
6090 ZBORDER, FALSE, FALSE,
6100 static struct Mapping_EM_to_RND_player
6109 em_player_mapping_list[] =
6113 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
6117 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
6121 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
6125 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
6129 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
6133 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
6137 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
6141 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
6145 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
6149 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
6153 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
6157 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
6161 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
6165 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
6169 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
6173 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
6177 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
6181 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
6185 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
6189 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
6193 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
6197 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
6201 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
6205 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
6209 EL_PLAYER_1, ACTION_DEFAULT, -1,
6213 EL_PLAYER_2, ACTION_DEFAULT, -1,
6217 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
6221 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
6225 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
6229 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
6233 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
6237 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
6241 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
6245 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
6249 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
6253 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
6257 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
6261 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
6265 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
6269 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
6273 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
6277 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
6281 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
6285 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
6289 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
6293 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
6297 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
6301 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
6305 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
6309 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
6313 EL_PLAYER_3, ACTION_DEFAULT, -1,
6317 EL_PLAYER_4, ACTION_DEFAULT, -1,
6326 int map_element_RND_to_EM(int element_rnd)
6328 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
6329 static boolean mapping_initialized = FALSE;
6331 if (!mapping_initialized)
6335 /* return "Xalpha_quest" for all undefined elements in mapping array */
6336 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
6337 mapping_RND_to_EM[i] = Xalpha_quest;
6339 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6340 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
6341 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
6342 em_object_mapping_list[i].element_em;
6344 mapping_initialized = TRUE;
6347 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
6348 return mapping_RND_to_EM[element_rnd];
6350 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
6355 int map_element_EM_to_RND(int element_em)
6357 static unsigned short mapping_EM_to_RND[TILE_MAX];
6358 static boolean mapping_initialized = FALSE;
6360 if (!mapping_initialized)
6364 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
6365 for (i = 0; i < TILE_MAX; i++)
6366 mapping_EM_to_RND[i] = EL_UNKNOWN;
6368 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6369 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
6370 em_object_mapping_list[i].element_rnd;
6372 mapping_initialized = TRUE;
6375 if (element_em >= 0 && element_em < TILE_MAX)
6376 return mapping_EM_to_RND[element_em];
6378 Error(ERR_WARN, "invalid EM level element %d", element_em);
6383 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
6385 struct LevelInfo_EM *level_em = level->native_em_level;
6386 struct LEVEL *lev = level_em->lev;
6389 for (i = 0; i < TILE_MAX; i++)
6390 lev->android_array[i] = Xblank;
6392 for (i = 0; i < level->num_android_clone_elements; i++)
6394 int element_rnd = level->android_clone_element[i];
6395 int element_em = map_element_RND_to_EM(element_rnd);
6397 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
6398 if (em_object_mapping_list[j].element_rnd == element_rnd)
6399 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
6403 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
6405 struct LevelInfo_EM *level_em = level->native_em_level;
6406 struct LEVEL *lev = level_em->lev;
6409 level->num_android_clone_elements = 0;
6411 for (i = 0; i < TILE_MAX; i++)
6413 int element_em = lev->android_array[i];
6415 boolean element_found = FALSE;
6417 if (element_em == Xblank)
6420 element_rnd = map_element_EM_to_RND(element_em);
6422 for (j = 0; j < level->num_android_clone_elements; j++)
6423 if (level->android_clone_element[j] == element_rnd)
6424 element_found = TRUE;
6428 level->android_clone_element[level->num_android_clone_elements++] =
6431 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
6436 if (level->num_android_clone_elements == 0)
6438 level->num_android_clone_elements = 1;
6439 level->android_clone_element[0] = EL_EMPTY;
6443 int map_direction_RND_to_EM(int direction)
6445 return (direction == MV_UP ? 0 :
6446 direction == MV_RIGHT ? 1 :
6447 direction == MV_DOWN ? 2 :
6448 direction == MV_LEFT ? 3 :
6452 int map_direction_EM_to_RND(int direction)
6454 return (direction == 0 ? MV_UP :
6455 direction == 1 ? MV_RIGHT :
6456 direction == 2 ? MV_DOWN :
6457 direction == 3 ? MV_LEFT :
6461 int map_element_RND_to_SP(int element_rnd)
6463 int element_sp = 0x20; /* map unknown elements to yellow "hardware" */
6465 if (element_rnd >= EL_SP_START &&
6466 element_rnd <= EL_SP_END)
6467 element_sp = element_rnd - EL_SP_START;
6468 else if (element_rnd == EL_EMPTY_SPACE)
6470 else if (element_rnd == EL_INVISIBLE_WALL)
6476 int map_element_SP_to_RND(int element_sp)
6478 int element_rnd = EL_UNKNOWN;
6480 if (element_sp >= 0x00 &&
6482 element_rnd = EL_SP_START + element_sp;
6483 else if (element_sp == 0x28)
6484 element_rnd = EL_INVISIBLE_WALL;
6489 int map_action_SP_to_RND(int action_sp)
6493 case actActive: return ACTION_ACTIVE;
6494 case actImpact: return ACTION_IMPACT;
6495 case actExploding: return ACTION_EXPLODING;
6496 case actDigging: return ACTION_DIGGING;
6497 case actSnapping: return ACTION_SNAPPING;
6498 case actCollecting: return ACTION_COLLECTING;
6499 case actPassing: return ACTION_PASSING;
6500 case actPushing: return ACTION_PUSHING;
6501 case actDropping: return ACTION_DROPPING;
6503 default: return ACTION_DEFAULT;
6507 int get_next_element(int element)
6511 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
6512 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
6513 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
6514 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
6515 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
6516 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
6517 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
6518 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
6519 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
6520 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
6521 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
6523 default: return element;
6527 int el_act_dir2img(int element, int action, int direction)
6529 element = GFX_ELEMENT(element);
6530 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
6532 /* direction_graphic[][] == graphic[] for undefined direction graphics */
6533 return element_info[element].direction_graphic[action][direction];
6536 static int el_act_dir2crm(int element, int action, int direction)
6538 element = GFX_ELEMENT(element);
6539 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
6541 /* direction_graphic[][] == graphic[] for undefined direction graphics */
6542 return element_info[element].direction_crumbled[action][direction];
6545 int el_act2img(int element, int action)
6547 element = GFX_ELEMENT(element);
6549 return element_info[element].graphic[action];
6552 int el_act2crm(int element, int action)
6554 element = GFX_ELEMENT(element);
6556 return element_info[element].crumbled[action];
6559 int el_dir2img(int element, int direction)
6561 element = GFX_ELEMENT(element);
6563 return el_act_dir2img(element, ACTION_DEFAULT, direction);
6566 int el2baseimg(int element)
6568 return element_info[element].graphic[ACTION_DEFAULT];
6571 int el2img(int element)
6573 element = GFX_ELEMENT(element);
6575 return element_info[element].graphic[ACTION_DEFAULT];
6578 int el2edimg(int element)
6580 element = GFX_ELEMENT(element);
6582 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
6585 int el2preimg(int element)
6587 element = GFX_ELEMENT(element);
6589 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
6592 int el2panelimg(int element)
6594 element = GFX_ELEMENT(element);
6596 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL];
6599 int font2baseimg(int font_nr)
6601 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
6604 int getBeltNrFromBeltElement(int element)
6606 return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
6607 element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
6608 element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
6611 int getBeltNrFromBeltActiveElement(int element)
6613 return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
6614 element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
6615 element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
6618 int getBeltNrFromBeltSwitchElement(int element)
6620 return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
6621 element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
6622 element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
6625 int getBeltDirNrFromBeltElement(int element)
6627 static int belt_base_element[4] =
6629 EL_CONVEYOR_BELT_1_LEFT,
6630 EL_CONVEYOR_BELT_2_LEFT,
6631 EL_CONVEYOR_BELT_3_LEFT,
6632 EL_CONVEYOR_BELT_4_LEFT
6635 int belt_nr = getBeltNrFromBeltElement(element);
6636 int belt_dir_nr = element - belt_base_element[belt_nr];
6638 return (belt_dir_nr % 3);
6641 int getBeltDirNrFromBeltSwitchElement(int element)
6643 static int belt_base_element[4] =
6645 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
6646 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
6647 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
6648 EL_CONVEYOR_BELT_4_SWITCH_LEFT
6651 int belt_nr = getBeltNrFromBeltSwitchElement(element);
6652 int belt_dir_nr = element - belt_base_element[belt_nr];
6654 return (belt_dir_nr % 3);
6657 int getBeltDirFromBeltElement(int element)
6659 static int belt_move_dir[3] =
6666 int belt_dir_nr = getBeltDirNrFromBeltElement(element);
6668 return belt_move_dir[belt_dir_nr];
6671 int getBeltDirFromBeltSwitchElement(int element)
6673 static int belt_move_dir[3] =
6680 int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
6682 return belt_move_dir[belt_dir_nr];
6685 int getBeltElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
6687 static int belt_base_element[4] =
6689 EL_CONVEYOR_BELT_1_LEFT,
6690 EL_CONVEYOR_BELT_2_LEFT,
6691 EL_CONVEYOR_BELT_3_LEFT,
6692 EL_CONVEYOR_BELT_4_LEFT
6695 return belt_base_element[belt_nr] + belt_dir_nr;
6698 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
6700 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
6702 return getBeltElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
6705 int getBeltSwitchElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
6707 static int belt_base_element[4] =
6709 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
6710 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
6711 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
6712 EL_CONVEYOR_BELT_4_SWITCH_LEFT
6715 return belt_base_element[belt_nr] + belt_dir_nr;
6718 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
6720 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
6722 return getBeltSwitchElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
6725 boolean getTeamMode_EM()
6727 return game.team_mode;
6730 int getGameFrameDelay_EM(int native_em_game_frame_delay)
6732 int game_frame_delay_value;
6734 game_frame_delay_value =
6735 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
6736 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
6739 if (tape.playing && tape.warp_forward && !tape.pausing)
6740 game_frame_delay_value = 0;
6742 return game_frame_delay_value;
6745 unsigned int InitRND(int seed)
6747 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
6748 return InitEngineRandom_EM(seed);
6749 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
6750 return InitEngineRandom_SP(seed);
6752 return InitEngineRandom_RND(seed);
6755 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
6756 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
6758 inline static int get_effective_element_EM(int tile, int frame_em)
6760 int element = object_mapping[tile].element_rnd;
6761 int action = object_mapping[tile].action;
6762 boolean is_backside = object_mapping[tile].is_backside;
6763 boolean action_removing = (action == ACTION_DIGGING ||
6764 action == ACTION_SNAPPING ||
6765 action == ACTION_COLLECTING);
6771 case Yacid_splash_eB:
6772 case Yacid_splash_wB:
6773 return (frame_em > 5 ? EL_EMPTY : element);
6779 else /* frame_em == 7 */
6783 case Yacid_splash_eB:
6784 case Yacid_splash_wB:
6787 case Yemerald_stone:
6790 case Ydiamond_stone:
6794 case Xdrip_stretchB:
6813 case Xsand_stonein_1:
6814 case Xsand_stonein_2:
6815 case Xsand_stonein_3:
6816 case Xsand_stonein_4:
6820 return (is_backside || action_removing ? EL_EMPTY : element);
6825 inline static boolean check_linear_animation_EM(int tile)
6829 case Xsand_stonesand_1:
6830 case Xsand_stonesand_quickout_1:
6831 case Xsand_sandstone_1:
6832 case Xsand_stonein_1:
6833 case Xsand_stoneout_1:
6852 case Yacid_splash_eB:
6853 case Yacid_splash_wB:
6854 case Yemerald_stone:
6861 inline static void set_crumbled_graphics_EM(struct GraphicInfo_EM *g_em,
6862 boolean has_crumbled_graphics,
6863 int crumbled, int sync_frame)
6865 /* if element can be crumbled, but certain action graphics are just empty
6866 space (like instantly snapping sand to empty space in 1 frame), do not
6867 treat these empty space graphics as crumbled graphics in EMC engine */
6868 if (crumbled == IMG_EMPTY_SPACE)
6869 has_crumbled_graphics = FALSE;
6871 if (has_crumbled_graphics)
6873 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
6874 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
6875 g_crumbled->anim_delay,
6876 g_crumbled->anim_mode,
6877 g_crumbled->anim_start_frame,
6880 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
6881 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
6883 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
6885 g_em->has_crumbled_graphics = TRUE;
6889 g_em->crumbled_bitmap = NULL;
6890 g_em->crumbled_src_x = 0;
6891 g_em->crumbled_src_y = 0;
6892 g_em->crumbled_border_size = 0;
6894 g_em->has_crumbled_graphics = FALSE;
6898 void ResetGfxAnimation_EM(int x, int y, int tile)
6903 void SetGfxAnimation_EM(struct GraphicInfo_EM *g_em,
6904 int tile, int frame_em, int x, int y)
6906 int action = object_mapping[tile].action;
6907 int direction = object_mapping[tile].direction;
6908 int effective_element = get_effective_element_EM(tile, frame_em);
6909 int graphic = (direction == MV_NONE ?
6910 el_act2img(effective_element, action) :
6911 el_act_dir2img(effective_element, action, direction));
6912 struct GraphicInfo *g = &graphic_info[graphic];
6914 boolean action_removing = (action == ACTION_DIGGING ||
6915 action == ACTION_SNAPPING ||
6916 action == ACTION_COLLECTING);
6917 boolean action_moving = (action == ACTION_FALLING ||
6918 action == ACTION_MOVING ||
6919 action == ACTION_PUSHING ||
6920 action == ACTION_EATING ||
6921 action == ACTION_FILLING ||
6922 action == ACTION_EMPTYING);
6923 boolean action_falling = (action == ACTION_FALLING ||
6924 action == ACTION_FILLING ||
6925 action == ACTION_EMPTYING);
6927 /* special case: graphic uses "2nd movement tile" and has defined
6928 7 frames for movement animation (or less) => use default graphic
6929 for last (8th) frame which ends the movement animation */
6930 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
6932 action = ACTION_DEFAULT; /* (keep action_* unchanged for now) */
6933 graphic = (direction == MV_NONE ?
6934 el_act2img(effective_element, action) :
6935 el_act_dir2img(effective_element, action, direction));
6937 g = &graphic_info[graphic];
6940 if ((action_removing || check_linear_animation_EM(tile)) && frame_em == 0)
6944 else if (action_moving)
6946 boolean is_backside = object_mapping[tile].is_backside;
6950 int direction = object_mapping[tile].direction;
6951 int move_dir = (action_falling ? MV_DOWN : direction);
6956 /* !!! TEST !!! NEW !!! DOES NOT WORK RIGHT YET !!! */
6957 if (g->double_movement && frame_em == 0)
6961 if (move_dir == MV_LEFT)
6962 GfxFrame[x - 1][y] = GfxFrame[x][y];
6963 else if (move_dir == MV_RIGHT)
6964 GfxFrame[x + 1][y] = GfxFrame[x][y];
6965 else if (move_dir == MV_UP)
6966 GfxFrame[x][y - 1] = GfxFrame[x][y];
6967 else if (move_dir == MV_DOWN)
6968 GfxFrame[x][y + 1] = GfxFrame[x][y];
6975 /* special case: animation for Xsand_stonesand_quickout_1/2 twice as fast */
6976 if (tile == Xsand_stonesand_quickout_1 ||
6977 tile == Xsand_stonesand_quickout_2)
6981 if (graphic_info[graphic].anim_global_sync)
6982 sync_frame = FrameCounter;
6983 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
6984 sync_frame = GfxFrame[x][y];
6986 sync_frame = 0; /* playfield border (pseudo steel) */
6988 SetRandomAnimationValue(x, y);
6990 int frame = getAnimationFrame(g->anim_frames,
6993 g->anim_start_frame,
6996 g_em->unique_identifier =
6997 (graphic << 16) | ((frame % 8) << 12) | (g_em->width << 6) | g_em->height;
7000 void getGraphicSourceObjectExt_EM(struct GraphicInfo_EM *g_em,
7001 int tile, int frame_em, int x, int y)
7003 int action = object_mapping[tile].action;
7004 int direction = object_mapping[tile].direction;
7005 boolean is_backside = object_mapping[tile].is_backside;
7006 int effective_element = get_effective_element_EM(tile, frame_em);
7007 int effective_action = action;
7008 int graphic = (direction == MV_NONE ?
7009 el_act2img(effective_element, effective_action) :
7010 el_act_dir2img(effective_element, effective_action,
7012 int crumbled = (direction == MV_NONE ?
7013 el_act2crm(effective_element, effective_action) :
7014 el_act_dir2crm(effective_element, effective_action,
7016 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7017 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7018 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7019 struct GraphicInfo *g = &graphic_info[graphic];
7022 /* special case: graphic uses "2nd movement tile" and has defined
7023 7 frames for movement animation (or less) => use default graphic
7024 for last (8th) frame which ends the movement animation */
7025 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
7027 effective_action = ACTION_DEFAULT;
7028 graphic = (direction == MV_NONE ?
7029 el_act2img(effective_element, effective_action) :
7030 el_act_dir2img(effective_element, effective_action,
7032 crumbled = (direction == MV_NONE ?
7033 el_act2crm(effective_element, effective_action) :
7034 el_act_dir2crm(effective_element, effective_action,
7037 g = &graphic_info[graphic];
7040 if (graphic_info[graphic].anim_global_sync)
7041 sync_frame = FrameCounter;
7042 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
7043 sync_frame = GfxFrame[x][y];
7045 sync_frame = 0; /* playfield border (pseudo steel) */
7047 SetRandomAnimationValue(x, y);
7049 int frame = getAnimationFrame(g->anim_frames,
7052 g->anim_start_frame,
7055 getGraphicSourceExt(graphic, frame, &g_em->bitmap, &g_em->src_x, &g_em->src_y,
7056 g->double_movement && is_backside);
7058 /* (updating the "crumbled" graphic definitions is probably not really needed,
7059 as animations for crumbled graphics can't be longer than one EMC cycle) */
7060 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
7064 void getGraphicSourcePlayerExt_EM(struct GraphicInfo_EM *g_em,
7065 int player_nr, int anim, int frame_em)
7067 int element = player_mapping[player_nr][anim].element_rnd;
7068 int action = player_mapping[player_nr][anim].action;
7069 int direction = player_mapping[player_nr][anim].direction;
7070 int graphic = (direction == MV_NONE ?
7071 el_act2img(element, action) :
7072 el_act_dir2img(element, action, direction));
7073 struct GraphicInfo *g = &graphic_info[graphic];
7076 InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
7078 stored_player[player_nr].StepFrame = frame_em;
7080 sync_frame = stored_player[player_nr].Frame;
7082 int frame = getAnimationFrame(g->anim_frames,
7085 g->anim_start_frame,
7088 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
7089 &g_em->src_x, &g_em->src_y, FALSE);
7092 void InitGraphicInfo_EM(void)
7097 int num_em_gfx_errors = 0;
7099 if (graphic_info_em_object[0][0].bitmap == NULL)
7101 /* EM graphics not yet initialized in em_open_all() */
7106 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
7109 /* always start with reliable default values */
7110 for (i = 0; i < TILE_MAX; i++)
7112 object_mapping[i].element_rnd = EL_UNKNOWN;
7113 object_mapping[i].is_backside = FALSE;
7114 object_mapping[i].action = ACTION_DEFAULT;
7115 object_mapping[i].direction = MV_NONE;
7118 /* always start with reliable default values */
7119 for (p = 0; p < MAX_PLAYERS; p++)
7121 for (i = 0; i < SPR_MAX; i++)
7123 player_mapping[p][i].element_rnd = EL_UNKNOWN;
7124 player_mapping[p][i].action = ACTION_DEFAULT;
7125 player_mapping[p][i].direction = MV_NONE;
7129 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
7131 int e = em_object_mapping_list[i].element_em;
7133 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
7134 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
7136 if (em_object_mapping_list[i].action != -1)
7137 object_mapping[e].action = em_object_mapping_list[i].action;
7139 if (em_object_mapping_list[i].direction != -1)
7140 object_mapping[e].direction =
7141 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
7144 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
7146 int a = em_player_mapping_list[i].action_em;
7147 int p = em_player_mapping_list[i].player_nr;
7149 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
7151 if (em_player_mapping_list[i].action != -1)
7152 player_mapping[p][a].action = em_player_mapping_list[i].action;
7154 if (em_player_mapping_list[i].direction != -1)
7155 player_mapping[p][a].direction =
7156 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
7159 for (i = 0; i < TILE_MAX; i++)
7161 int element = object_mapping[i].element_rnd;
7162 int action = object_mapping[i].action;
7163 int direction = object_mapping[i].direction;
7164 boolean is_backside = object_mapping[i].is_backside;
7165 boolean action_exploding = ((action == ACTION_EXPLODING ||
7166 action == ACTION_SMASHED_BY_ROCK ||
7167 action == ACTION_SMASHED_BY_SPRING) &&
7168 element != EL_DIAMOND);
7169 boolean action_active = (action == ACTION_ACTIVE);
7170 boolean action_other = (action == ACTION_OTHER);
7172 for (j = 0; j < 8; j++)
7174 int effective_element = get_effective_element_EM(i, j);
7175 int effective_action = (j < 7 ? action :
7176 i == Xdrip_stretch ? action :
7177 i == Xdrip_stretchB ? action :
7178 i == Ydrip_s1 ? action :
7179 i == Ydrip_s1B ? action :
7180 i == Xball_1B ? action :
7181 i == Xball_2 ? action :
7182 i == Xball_2B ? action :
7183 i == Yball_eat ? action :
7184 i == Ykey_1_eat ? action :
7185 i == Ykey_2_eat ? action :
7186 i == Ykey_3_eat ? action :
7187 i == Ykey_4_eat ? action :
7188 i == Ykey_5_eat ? action :
7189 i == Ykey_6_eat ? action :
7190 i == Ykey_7_eat ? action :
7191 i == Ykey_8_eat ? action :
7192 i == Ylenses_eat ? action :
7193 i == Ymagnify_eat ? action :
7194 i == Ygrass_eat ? action :
7195 i == Ydirt_eat ? action :
7196 i == Xsand_stonein_1 ? action :
7197 i == Xsand_stonein_2 ? action :
7198 i == Xsand_stonein_3 ? action :
7199 i == Xsand_stonein_4 ? action :
7200 i == Xsand_stoneout_1 ? action :
7201 i == Xsand_stoneout_2 ? action :
7202 i == Xboom_android ? ACTION_EXPLODING :
7203 action_exploding ? ACTION_EXPLODING :
7204 action_active ? action :
7205 action_other ? action :
7207 int graphic = (el_act_dir2img(effective_element, effective_action,
7209 int crumbled = (el_act_dir2crm(effective_element, effective_action,
7211 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7212 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7213 boolean has_action_graphics = (graphic != base_graphic);
7214 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7215 struct GraphicInfo *g = &graphic_info[graphic];
7216 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7219 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
7220 boolean special_animation = (action != ACTION_DEFAULT &&
7221 g->anim_frames == 3 &&
7222 g->anim_delay == 2 &&
7223 g->anim_mode & ANIM_LINEAR);
7224 int sync_frame = (i == Xdrip_stretch ? 7 :
7225 i == Xdrip_stretchB ? 7 :
7226 i == Ydrip_s2 ? j + 8 :
7227 i == Ydrip_s2B ? j + 8 :
7236 i == Xfake_acid_1 ? 0 :
7237 i == Xfake_acid_2 ? 10 :
7238 i == Xfake_acid_3 ? 20 :
7239 i == Xfake_acid_4 ? 30 :
7240 i == Xfake_acid_5 ? 40 :
7241 i == Xfake_acid_6 ? 50 :
7242 i == Xfake_acid_7 ? 60 :
7243 i == Xfake_acid_8 ? 70 :
7245 i == Xball_2B ? j + 8 :
7246 i == Yball_eat ? j + 1 :
7247 i == Ykey_1_eat ? j + 1 :
7248 i == Ykey_2_eat ? j + 1 :
7249 i == Ykey_3_eat ? j + 1 :
7250 i == Ykey_4_eat ? j + 1 :
7251 i == Ykey_5_eat ? j + 1 :
7252 i == Ykey_6_eat ? j + 1 :
7253 i == Ykey_7_eat ? j + 1 :
7254 i == Ykey_8_eat ? j + 1 :
7255 i == Ylenses_eat ? j + 1 :
7256 i == Ymagnify_eat ? j + 1 :
7257 i == Ygrass_eat ? j + 1 :
7258 i == Ydirt_eat ? j + 1 :
7259 i == Xamoeba_1 ? 0 :
7260 i == Xamoeba_2 ? 1 :
7261 i == Xamoeba_3 ? 2 :
7262 i == Xamoeba_4 ? 3 :
7263 i == Xamoeba_5 ? 0 :
7264 i == Xamoeba_6 ? 1 :
7265 i == Xamoeba_7 ? 2 :
7266 i == Xamoeba_8 ? 3 :
7267 i == Xexit_2 ? j + 8 :
7268 i == Xexit_3 ? j + 16 :
7269 i == Xdynamite_1 ? 0 :
7270 i == Xdynamite_2 ? 8 :
7271 i == Xdynamite_3 ? 16 :
7272 i == Xdynamite_4 ? 24 :
7273 i == Xsand_stonein_1 ? j + 1 :
7274 i == Xsand_stonein_2 ? j + 9 :
7275 i == Xsand_stonein_3 ? j + 17 :
7276 i == Xsand_stonein_4 ? j + 25 :
7277 i == Xsand_stoneout_1 && j == 0 ? 0 :
7278 i == Xsand_stoneout_1 && j == 1 ? 0 :
7279 i == Xsand_stoneout_1 && j == 2 ? 1 :
7280 i == Xsand_stoneout_1 && j == 3 ? 2 :
7281 i == Xsand_stoneout_1 && j == 4 ? 2 :
7282 i == Xsand_stoneout_1 && j == 5 ? 3 :
7283 i == Xsand_stoneout_1 && j == 6 ? 4 :
7284 i == Xsand_stoneout_1 && j == 7 ? 4 :
7285 i == Xsand_stoneout_2 && j == 0 ? 5 :
7286 i == Xsand_stoneout_2 && j == 1 ? 6 :
7287 i == Xsand_stoneout_2 && j == 2 ? 7 :
7288 i == Xsand_stoneout_2 && j == 3 ? 8 :
7289 i == Xsand_stoneout_2 && j == 4 ? 9 :
7290 i == Xsand_stoneout_2 && j == 5 ? 11 :
7291 i == Xsand_stoneout_2 && j == 6 ? 13 :
7292 i == Xsand_stoneout_2 && j == 7 ? 15 :
7293 i == Xboom_bug && j == 1 ? 2 :
7294 i == Xboom_bug && j == 2 ? 2 :
7295 i == Xboom_bug && j == 3 ? 4 :
7296 i == Xboom_bug && j == 4 ? 4 :
7297 i == Xboom_bug && j == 5 ? 2 :
7298 i == Xboom_bug && j == 6 ? 2 :
7299 i == Xboom_bug && j == 7 ? 0 :
7300 i == Xboom_bomb && j == 1 ? 2 :
7301 i == Xboom_bomb && j == 2 ? 2 :
7302 i == Xboom_bomb && j == 3 ? 4 :
7303 i == Xboom_bomb && j == 4 ? 4 :
7304 i == Xboom_bomb && j == 5 ? 2 :
7305 i == Xboom_bomb && j == 6 ? 2 :
7306 i == Xboom_bomb && j == 7 ? 0 :
7307 i == Xboom_android && j == 7 ? 6 :
7308 i == Xboom_1 && j == 1 ? 2 :
7309 i == Xboom_1 && j == 2 ? 2 :
7310 i == Xboom_1 && j == 3 ? 4 :
7311 i == Xboom_1 && j == 4 ? 4 :
7312 i == Xboom_1 && j == 5 ? 6 :
7313 i == Xboom_1 && j == 6 ? 6 :
7314 i == Xboom_1 && j == 7 ? 8 :
7315 i == Xboom_2 && j == 0 ? 8 :
7316 i == Xboom_2 && j == 1 ? 8 :
7317 i == Xboom_2 && j == 2 ? 10 :
7318 i == Xboom_2 && j == 3 ? 10 :
7319 i == Xboom_2 && j == 4 ? 10 :
7320 i == Xboom_2 && j == 5 ? 12 :
7321 i == Xboom_2 && j == 6 ? 12 :
7322 i == Xboom_2 && j == 7 ? 12 :
7323 special_animation && j == 4 ? 3 :
7324 effective_action != action ? 0 :
7328 Bitmap *debug_bitmap = g_em->bitmap;
7329 int debug_src_x = g_em->src_x;
7330 int debug_src_y = g_em->src_y;
7333 int frame = getAnimationFrame(g->anim_frames,
7336 g->anim_start_frame,
7339 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
7340 g->double_movement && is_backside);
7342 g_em->bitmap = src_bitmap;
7343 g_em->src_x = src_x;
7344 g_em->src_y = src_y;
7345 g_em->src_offset_x = 0;
7346 g_em->src_offset_y = 0;
7347 g_em->dst_offset_x = 0;
7348 g_em->dst_offset_y = 0;
7349 g_em->width = TILEX;
7350 g_em->height = TILEY;
7352 g_em->preserve_background = FALSE;
7354 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
7357 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
7358 effective_action == ACTION_MOVING ||
7359 effective_action == ACTION_PUSHING ||
7360 effective_action == ACTION_EATING)) ||
7361 (!has_action_graphics && (effective_action == ACTION_FILLING ||
7362 effective_action == ACTION_EMPTYING)))
7365 (effective_action == ACTION_FALLING ||
7366 effective_action == ACTION_FILLING ||
7367 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
7368 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
7369 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
7370 int num_steps = (i == Ydrip_s1 ? 16 :
7371 i == Ydrip_s1B ? 16 :
7372 i == Ydrip_s2 ? 16 :
7373 i == Ydrip_s2B ? 16 :
7374 i == Xsand_stonein_1 ? 32 :
7375 i == Xsand_stonein_2 ? 32 :
7376 i == Xsand_stonein_3 ? 32 :
7377 i == Xsand_stonein_4 ? 32 :
7378 i == Xsand_stoneout_1 ? 16 :
7379 i == Xsand_stoneout_2 ? 16 : 8);
7380 int cx = ABS(dx) * (TILEX / num_steps);
7381 int cy = ABS(dy) * (TILEY / num_steps);
7382 int step_frame = (i == Ydrip_s2 ? j + 8 :
7383 i == Ydrip_s2B ? j + 8 :
7384 i == Xsand_stonein_2 ? j + 8 :
7385 i == Xsand_stonein_3 ? j + 16 :
7386 i == Xsand_stonein_4 ? j + 24 :
7387 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
7388 int step = (is_backside ? step_frame : num_steps - step_frame);
7390 if (is_backside) /* tile where movement starts */
7392 if (dx < 0 || dy < 0)
7394 g_em->src_offset_x = cx * step;
7395 g_em->src_offset_y = cy * step;
7399 g_em->dst_offset_x = cx * step;
7400 g_em->dst_offset_y = cy * step;
7403 else /* tile where movement ends */
7405 if (dx < 0 || dy < 0)
7407 g_em->dst_offset_x = cx * step;
7408 g_em->dst_offset_y = cy * step;
7412 g_em->src_offset_x = cx * step;
7413 g_em->src_offset_y = cy * step;
7417 g_em->width = TILEX - cx * step;
7418 g_em->height = TILEY - cy * step;
7421 /* create unique graphic identifier to decide if tile must be redrawn */
7422 /* bit 31 - 16 (16 bit): EM style graphic
7423 bit 15 - 12 ( 4 bit): EM style frame
7424 bit 11 - 6 ( 6 bit): graphic width
7425 bit 5 - 0 ( 6 bit): graphic height */
7426 g_em->unique_identifier =
7427 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
7431 /* skip check for EMC elements not contained in original EMC artwork */
7432 if (element == EL_EMC_FAKE_ACID)
7435 if (g_em->bitmap != debug_bitmap ||
7436 g_em->src_x != debug_src_x ||
7437 g_em->src_y != debug_src_y ||
7438 g_em->src_offset_x != 0 ||
7439 g_em->src_offset_y != 0 ||
7440 g_em->dst_offset_x != 0 ||
7441 g_em->dst_offset_y != 0 ||
7442 g_em->width != TILEX ||
7443 g_em->height != TILEY)
7445 static int last_i = -1;
7453 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
7454 i, element, element_info[element].token_name,
7455 element_action_info[effective_action].suffix, direction);
7457 if (element != effective_element)
7458 printf(" [%d ('%s')]",
7460 element_info[effective_element].token_name);
7464 if (g_em->bitmap != debug_bitmap)
7465 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
7466 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
7468 if (g_em->src_x != debug_src_x ||
7469 g_em->src_y != debug_src_y)
7470 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
7471 j, (is_backside ? 'B' : 'F'),
7472 g_em->src_x, g_em->src_y,
7473 g_em->src_x / 32, g_em->src_y / 32,
7474 debug_src_x, debug_src_y,
7475 debug_src_x / 32, debug_src_y / 32);
7477 if (g_em->src_offset_x != 0 ||
7478 g_em->src_offset_y != 0 ||
7479 g_em->dst_offset_x != 0 ||
7480 g_em->dst_offset_y != 0)
7481 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
7483 g_em->src_offset_x, g_em->src_offset_y,
7484 g_em->dst_offset_x, g_em->dst_offset_y);
7486 if (g_em->width != TILEX ||
7487 g_em->height != TILEY)
7488 printf(" %d (%d): size %d,%d should be %d,%d\n",
7490 g_em->width, g_em->height, TILEX, TILEY);
7492 num_em_gfx_errors++;
7499 for (i = 0; i < TILE_MAX; i++)
7501 for (j = 0; j < 8; j++)
7503 int element = object_mapping[i].element_rnd;
7504 int action = object_mapping[i].action;
7505 int direction = object_mapping[i].direction;
7506 boolean is_backside = object_mapping[i].is_backside;
7507 int graphic_action = el_act_dir2img(element, action, direction);
7508 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
7510 if ((action == ACTION_SMASHED_BY_ROCK ||
7511 action == ACTION_SMASHED_BY_SPRING ||
7512 action == ACTION_EATING) &&
7513 graphic_action == graphic_default)
7515 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
7516 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
7517 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
7518 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
7521 /* no separate animation for "smashed by rock" -- use rock instead */
7522 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7523 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
7525 g_em->bitmap = g_xx->bitmap;
7526 g_em->src_x = g_xx->src_x;
7527 g_em->src_y = g_xx->src_y;
7528 g_em->src_offset_x = g_xx->src_offset_x;
7529 g_em->src_offset_y = g_xx->src_offset_y;
7530 g_em->dst_offset_x = g_xx->dst_offset_x;
7531 g_em->dst_offset_y = g_xx->dst_offset_y;
7532 g_em->width = g_xx->width;
7533 g_em->height = g_xx->height;
7534 g_em->unique_identifier = g_xx->unique_identifier;
7537 g_em->preserve_background = TRUE;
7542 for (p = 0; p < MAX_PLAYERS; p++)
7544 for (i = 0; i < SPR_MAX; i++)
7546 int element = player_mapping[p][i].element_rnd;
7547 int action = player_mapping[p][i].action;
7548 int direction = player_mapping[p][i].direction;
7550 for (j = 0; j < 8; j++)
7552 int effective_element = element;
7553 int effective_action = action;
7554 int graphic = (direction == MV_NONE ?
7555 el_act2img(effective_element, effective_action) :
7556 el_act_dir2img(effective_element, effective_action,
7558 struct GraphicInfo *g = &graphic_info[graphic];
7559 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
7565 Bitmap *debug_bitmap = g_em->bitmap;
7566 int debug_src_x = g_em->src_x;
7567 int debug_src_y = g_em->src_y;
7570 int frame = getAnimationFrame(g->anim_frames,
7573 g->anim_start_frame,
7576 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
7578 g_em->bitmap = src_bitmap;
7579 g_em->src_x = src_x;
7580 g_em->src_y = src_y;
7581 g_em->src_offset_x = 0;
7582 g_em->src_offset_y = 0;
7583 g_em->dst_offset_x = 0;
7584 g_em->dst_offset_y = 0;
7585 g_em->width = TILEX;
7586 g_em->height = TILEY;
7590 /* skip check for EMC elements not contained in original EMC artwork */
7591 if (element == EL_PLAYER_3 ||
7592 element == EL_PLAYER_4)
7595 if (g_em->bitmap != debug_bitmap ||
7596 g_em->src_x != debug_src_x ||
7597 g_em->src_y != debug_src_y)
7599 static int last_i = -1;
7607 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
7608 p, i, element, element_info[element].token_name,
7609 element_action_info[effective_action].suffix, direction);
7611 if (element != effective_element)
7612 printf(" [%d ('%s')]",
7614 element_info[effective_element].token_name);
7618 if (g_em->bitmap != debug_bitmap)
7619 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
7620 j, (int)(g_em->bitmap), (int)(debug_bitmap));
7622 if (g_em->src_x != debug_src_x ||
7623 g_em->src_y != debug_src_y)
7624 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
7626 g_em->src_x, g_em->src_y,
7627 g_em->src_x / 32, g_em->src_y / 32,
7628 debug_src_x, debug_src_y,
7629 debug_src_x / 32, debug_src_y / 32);
7631 num_em_gfx_errors++;
7641 printf("::: [%d errors found]\n", num_em_gfx_errors);
7647 void CheckSaveEngineSnapshot_EM(byte action[MAX_PLAYERS], int frame,
7648 boolean any_player_moving,
7649 boolean any_player_snapping,
7650 boolean any_player_dropping)
7652 static boolean player_was_waiting = TRUE;
7654 if (frame == 0 && !any_player_dropping)
7656 if (!player_was_waiting)
7658 if (!SaveEngineSnapshotToList())
7661 player_was_waiting = TRUE;
7664 else if (any_player_moving || any_player_snapping || any_player_dropping)
7666 player_was_waiting = FALSE;
7670 void CheckSaveEngineSnapshot_SP(boolean murphy_is_waiting,
7671 boolean murphy_is_dropping)
7673 static boolean player_was_waiting = TRUE;
7675 if (murphy_is_waiting)
7677 if (!player_was_waiting)
7679 if (!SaveEngineSnapshotToList())
7682 player_was_waiting = TRUE;
7687 player_was_waiting = FALSE;
7691 void CheckSingleStepMode_EM(byte action[MAX_PLAYERS], int frame,
7692 boolean any_player_moving,
7693 boolean any_player_snapping,
7694 boolean any_player_dropping)
7696 if (tape.single_step && tape.recording && !tape.pausing)
7697 if (frame == 0 && !any_player_dropping)
7698 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
7700 CheckSaveEngineSnapshot_EM(action, frame, any_player_moving,
7701 any_player_snapping, any_player_dropping);
7704 void CheckSingleStepMode_SP(boolean murphy_is_waiting,
7705 boolean murphy_is_dropping)
7707 if (tape.single_step && tape.recording && !tape.pausing)
7708 if (murphy_is_waiting)
7709 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
7711 CheckSaveEngineSnapshot_SP(murphy_is_waiting, murphy_is_dropping);
7714 void getGraphicSource_SP(struct GraphicInfo_SP *g_sp,
7715 int graphic, int sync_frame, int x, int y)
7717 int frame = getGraphicAnimationFrame(graphic, sync_frame);
7719 getGraphicSource(graphic, frame, &g_sp->bitmap, &g_sp->src_x, &g_sp->src_y);
7722 boolean isNextAnimationFrame_SP(int graphic, int sync_frame)
7724 return (IS_NEXT_FRAME(sync_frame, graphic));
7727 int getGraphicInfo_Delay(int graphic)
7729 return graphic_info[graphic].anim_delay;
7732 void PlayMenuSoundExt(int sound)
7734 if (sound == SND_UNDEFINED)
7737 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
7738 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
7741 if (IS_LOOP_SOUND(sound))
7742 PlaySoundLoop(sound);
7747 void PlayMenuSound()
7749 PlayMenuSoundExt(menu.sound[game_status]);
7752 void PlayMenuSoundStereo(int sound, int stereo_position)
7754 if (sound == SND_UNDEFINED)
7757 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
7758 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
7761 if (IS_LOOP_SOUND(sound))
7762 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
7764 PlaySoundStereo(sound, stereo_position);
7767 void PlayMenuSoundIfLoopExt(int sound)
7769 if (sound == SND_UNDEFINED)
7772 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
7773 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
7776 if (IS_LOOP_SOUND(sound))
7777 PlaySoundLoop(sound);
7780 void PlayMenuSoundIfLoop()
7782 PlayMenuSoundIfLoopExt(menu.sound[game_status]);
7785 void PlayMenuMusicExt(int music)
7787 if (music == MUS_UNDEFINED)
7790 if (!setup.sound_music)
7796 void PlayMenuMusic()
7798 PlayMenuMusicExt(menu.music[game_status]);
7801 void PlaySoundActivating()
7804 PlaySound(SND_MENU_ITEM_ACTIVATING);
7808 void PlaySoundSelecting()
7811 PlaySound(SND_MENU_ITEM_SELECTING);
7815 void ToggleFullscreenOrChangeWindowScalingIfNeeded()
7817 boolean change_fullscreen = (setup.fullscreen !=
7818 video.fullscreen_enabled);
7819 boolean change_fullscreen_mode = (video.fullscreen_enabled &&
7820 !strEqual(setup.fullscreen_mode,
7821 video.fullscreen_mode_current));
7822 boolean change_window_scaling_percent = (!video.fullscreen_enabled &&
7823 setup.window_scaling_percent !=
7824 video.window_scaling_percent);
7826 if (change_window_scaling_percent && video.fullscreen_enabled)
7829 if (!change_window_scaling_percent && !video.fullscreen_available)
7832 #if defined(TARGET_SDL2)
7833 if (change_window_scaling_percent)
7835 SDLSetWindowScaling(setup.window_scaling_percent);
7839 else if (change_fullscreen)
7841 SDLSetWindowFullscreen(setup.fullscreen);
7843 /* set setup value according to successfully changed fullscreen mode */
7844 setup.fullscreen = video.fullscreen_enabled;
7850 if (change_fullscreen ||
7851 change_fullscreen_mode ||
7852 change_window_scaling_percent)
7854 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
7856 /* save backbuffer content which gets lost when toggling fullscreen mode */
7857 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
7859 if (change_fullscreen_mode)
7861 /* keep fullscreen, but change fullscreen mode (screen resolution) */
7862 video.fullscreen_enabled = FALSE; /* force new fullscreen mode */
7865 if (change_window_scaling_percent)
7867 /* keep window mode, but change window scaling */
7868 video.fullscreen_enabled = TRUE; /* force new window scaling */
7871 /* toggle fullscreen */
7872 ChangeVideoModeIfNeeded(setup.fullscreen);
7874 /* set setup value according to successfully changed fullscreen mode */
7875 setup.fullscreen = video.fullscreen_enabled;
7877 /* restore backbuffer content from temporary backbuffer backup bitmap */
7878 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
7880 FreeBitmap(tmp_backbuffer);
7882 /* update visible window/screen */
7883 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
7887 void ChangeViewportPropertiesIfNeeded()
7889 int gfx_game_mode = game_status;
7890 int gfx_game_mode2 = (game_status == GAME_MODE_EDITOR ? GAME_MODE_DEFAULT :
7892 struct RectWithBorder *vp_playfield = &viewport.playfield[gfx_game_mode];
7893 struct RectWithBorder *vp_door_1 = &viewport.door_1[gfx_game_mode];
7894 struct RectWithBorder *vp_door_2 = &viewport.door_2[gfx_game_mode2];
7895 struct RectWithBorder *vp_door_3 = &viewport.door_2[GAME_MODE_EDITOR];
7896 int border_size = vp_playfield->border_size;
7897 int new_sx = vp_playfield->x + border_size;
7898 int new_sy = vp_playfield->y + border_size;
7899 int new_sxsize = vp_playfield->width - 2 * border_size;
7900 int new_sysize = vp_playfield->height - 2 * border_size;
7901 int new_real_sx = vp_playfield->x;
7902 int new_real_sy = vp_playfield->y;
7903 int new_full_sxsize = vp_playfield->width;
7904 int new_full_sysize = vp_playfield->height;
7905 int new_dx = vp_door_1->x;
7906 int new_dy = vp_door_1->y;
7907 int new_dxsize = vp_door_1->width;
7908 int new_dysize = vp_door_1->height;
7909 int new_vx = vp_door_2->x;
7910 int new_vy = vp_door_2->y;
7911 int new_vxsize = vp_door_2->width;
7912 int new_vysize = vp_door_2->height;
7913 int new_ex = vp_door_3->x;
7914 int new_ey = vp_door_3->y;
7915 int new_exsize = vp_door_3->width;
7916 int new_eysize = vp_door_3->height;
7917 int new_tilesize_var =
7918 (setup.small_game_graphics ? MINI_TILESIZE : game.tile_size);
7920 int tilesize = (gfx_game_mode == GAME_MODE_PLAYING ? new_tilesize_var :
7921 gfx_game_mode == GAME_MODE_EDITOR ? MINI_TILESIZE : TILESIZE);
7922 int new_scr_fieldx = new_sxsize / tilesize;
7923 int new_scr_fieldy = new_sysize / tilesize;
7924 int new_scr_fieldx_buffers = new_sxsize / new_tilesize_var;
7925 int new_scr_fieldy_buffers = new_sysize / new_tilesize_var;
7926 boolean init_gfx_buffers = FALSE;
7927 boolean init_video_buffer = FALSE;
7928 boolean init_gadgets_and_toons = FALSE;
7929 boolean init_em_graphics = FALSE;
7930 boolean drawing_area_changed = FALSE;
7932 if (viewport.window.width != WIN_XSIZE ||
7933 viewport.window.height != WIN_YSIZE)
7935 WIN_XSIZE = viewport.window.width;
7936 WIN_YSIZE = viewport.window.height;
7938 init_video_buffer = TRUE;
7939 init_gfx_buffers = TRUE;
7941 // printf("::: video: init_video_buffer, init_gfx_buffers\n");
7944 if (new_scr_fieldx != SCR_FIELDX ||
7945 new_scr_fieldy != SCR_FIELDY)
7947 /* this always toggles between MAIN and GAME when using small tile size */
7949 SCR_FIELDX = new_scr_fieldx;
7950 SCR_FIELDY = new_scr_fieldy;
7952 // printf("::: new_scr_fieldx != SCR_FIELDX ...\n");
7963 new_sxsize != SXSIZE ||
7964 new_sysize != SYSIZE ||
7965 new_dxsize != DXSIZE ||
7966 new_dysize != DYSIZE ||
7967 new_vxsize != VXSIZE ||
7968 new_vysize != VYSIZE ||
7969 new_exsize != EXSIZE ||
7970 new_eysize != EYSIZE ||
7971 new_real_sx != REAL_SX ||
7972 new_real_sy != REAL_SY ||
7973 new_full_sxsize != FULL_SXSIZE ||
7974 new_full_sysize != FULL_SYSIZE ||
7975 new_tilesize_var != TILESIZE_VAR
7978 if (new_tilesize_var != TILESIZE_VAR)
7980 // printf("::: new_tilesize_var != TILESIZE_VAR\n");
7982 // changing tile size invalidates scroll values of engine snapshots
7983 FreeEngineSnapshotSingle();
7985 // changing tile size requires update of graphic mapping for EM engine
7986 init_em_graphics = TRUE;
7991 new_sxsize != SXSIZE ||
7992 new_sysize != SYSIZE ||
7993 new_real_sx != REAL_SX ||
7994 new_real_sy != REAL_SY ||
7995 new_full_sxsize != FULL_SXSIZE ||
7996 new_full_sysize != FULL_SYSIZE)
7998 if (!init_video_buffer)
7999 drawing_area_changed = TRUE;
8010 SXSIZE = new_sxsize;
8011 SYSIZE = new_sysize;
8012 DXSIZE = new_dxsize;
8013 DYSIZE = new_dysize;
8014 VXSIZE = new_vxsize;
8015 VYSIZE = new_vysize;
8016 EXSIZE = new_exsize;
8017 EYSIZE = new_eysize;
8018 REAL_SX = new_real_sx;
8019 REAL_SY = new_real_sy;
8020 FULL_SXSIZE = new_full_sxsize;
8021 FULL_SYSIZE = new_full_sysize;
8022 TILESIZE_VAR = new_tilesize_var;
8024 init_gfx_buffers = TRUE;
8025 init_gadgets_and_toons = TRUE;
8027 // printf("::: viewports: init_gfx_buffers\n");
8028 // printf("::: viewports: init_gadgets_and_toons\n");
8031 if (init_gfx_buffers)
8033 // printf("::: init_gfx_buffers\n");
8035 SCR_FIELDX = new_scr_fieldx_buffers;
8036 SCR_FIELDY = new_scr_fieldy_buffers;
8040 SCR_FIELDX = new_scr_fieldx;
8041 SCR_FIELDY = new_scr_fieldy;
8043 gfx.drawing_area_changed = drawing_area_changed;
8045 SetDrawDeactivationMask(REDRAW_NONE);
8046 SetDrawBackgroundMask(REDRAW_FIELD);
8049 if (init_video_buffer)
8051 // printf("::: init_video_buffer\n");
8053 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
8056 if (init_gadgets_and_toons)
8058 // printf("::: init_gadgets_and_toons\n");
8064 if (init_em_graphics)
8066 InitGraphicInfo_EM();