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 BackToFront_OLD()
424 DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
427 /* !!! TEST ONLY !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
428 /* (force full redraw) */
429 if (game_status == GAME_MODE_PLAYING)
430 redraw_mask |= REDRAW_FIELD;
433 if (redraw_mask == REDRAW_NONE)
438 if (redraw_mask & REDRAW_ALL)
439 printf("[REDRAW_ALL]");
440 if (redraw_mask & REDRAW_FIELD)
441 printf("[REDRAW_FIELD]");
442 if (redraw_mask & REDRAW_DOOR_1)
443 printf("[REDRAW_DOOR_1]");
444 if (redraw_mask & REDRAW_DOOR_2)
445 printf("[REDRAW_DOOR_2]");
446 if (redraw_mask & REDRAW_FROM_BACKBUFFER)
447 printf("[REDRAW_FROM_BACKBUFFER]");
448 printf(" [%d]\n", FrameCounter);
451 if (global.fps_slowdown && game_status == GAME_MODE_PLAYING)
453 static boolean last_frame_skipped = FALSE;
454 boolean skip_even_when_not_scrolling = TRUE;
455 boolean just_scrolling = (ScreenMovDir != 0);
456 boolean verbose = FALSE;
458 if (global.fps_slowdown_factor > 1 &&
459 (FrameCounter % global.fps_slowdown_factor) &&
460 (just_scrolling || skip_even_when_not_scrolling))
462 redraw_mask &= ~REDRAW_MAIN;
464 last_frame_skipped = TRUE;
467 printf("FRAME SKIPPED\n");
471 if (last_frame_skipped)
472 redraw_mask |= REDRAW_FIELD;
474 last_frame_skipped = FALSE;
477 printf("frame not skipped\n");
481 /* synchronize X11 graphics at this point; if we would synchronize the
482 display immediately after the buffer switching (after the XFlush),
483 this could mean that we have to wait for the graphics to complete,
484 although we could go on doing calculations for the next frame */
488 /* never draw masked border to backbuffer when using playfield buffer */
489 if (game_status != GAME_MODE_PLAYING ||
490 redraw_mask & REDRAW_FROM_BACKBUFFER ||
491 buffer == backbuffer)
492 DrawMaskedBorder(redraw_mask);
494 DrawMaskedBorder(redraw_mask & REDRAW_DOORS);
496 if (redraw_mask & REDRAW_ALL)
498 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
500 redraw_mask = REDRAW_NONE;
503 if (redraw_mask & REDRAW_FIELD)
505 if (game_status != GAME_MODE_PLAYING ||
506 redraw_mask & REDRAW_FROM_BACKBUFFER)
508 BlitBitmap(backbuffer, window,
509 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
513 BlitScreenToBitmap_RND(window);
516 redraw_mask &= ~REDRAW_MAIN;
519 if (redraw_mask & REDRAW_DOORS)
521 if (redraw_mask & REDRAW_DOOR_1)
522 BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
524 if (redraw_mask & REDRAW_DOOR_2)
525 BlitBitmap(backbuffer, window, VX, VY, VXSIZE, VYSIZE, VX, VY);
527 if (redraw_mask & REDRAW_DOOR_3)
528 BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
530 redraw_mask &= ~REDRAW_DOORS;
533 if (redraw_mask & REDRAW_MICROLEVEL)
535 BlitBitmap(backbuffer, window, SX, SY + 10 * TILEY, SXSIZE, 7 * TILEY,
536 SX, SY + 10 * TILEY);
538 redraw_mask &= ~REDRAW_MICROLEVEL;
541 if (redraw_mask & REDRAW_FPS) /* display frames per second */
546 sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
547 if (!global.fps_slowdown)
550 sprintf(text, "%04.1f fps%s", global.frames_per_second, info1);
552 DrawTextExt(window, SX + SXSIZE + SX, 0, text, FONT_TEXT_2, BLIT_OPAQUE);
555 redraw_mask = REDRAW_NONE;
560 if (redraw_mask == REDRAW_NONE)
563 // redraw playfield if anything inside main playfield area needs redraw
564 if (redraw_mask & REDRAW_MAIN)
565 redraw_mask |= REDRAW_FIELD;
567 // draw masked border to all viewports, if defined
568 DrawMaskedBorder(redraw_mask);
570 // redraw complete window if both playfield and (some) doors need redraw
571 if (redraw_mask & REDRAW_FIELD && redraw_mask & REDRAW_DOORS)
572 redraw_mask = REDRAW_ALL;
574 /* although redrawing the whole window would be fine for normal gameplay,
575 being able to only redraw the playfield is required for deactivating
576 certain drawing areas (mainly playfield) to work, which is needed for
577 warp-forward to be fast enough (by skipping redraw of most frames) */
579 if (redraw_mask & REDRAW_ALL)
581 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
583 else if (redraw_mask & REDRAW_FIELD)
585 BlitBitmap(backbuffer, window,
586 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
588 else if (redraw_mask & REDRAW_DOORS)
590 if (redraw_mask & REDRAW_DOOR_1)
591 BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
593 if (redraw_mask & REDRAW_DOOR_2)
594 BlitBitmap(backbuffer, window, VX, VY, VXSIZE, VYSIZE, VX, VY);
596 if (redraw_mask & REDRAW_DOOR_3)
597 BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
600 redraw_mask = REDRAW_NONE;
603 static void FadeCrossSaveBackbuffer()
605 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
608 static void FadeExt(int fade_mask, int fade_mode, int fade_type)
610 static int fade_type_skip = FADE_TYPE_NONE;
611 void (*draw_border_function)(void) = NULL;
612 Bitmap *bitmap = (fade_mode & FADE_TYPE_TRANSFORM ? bitmap_db_cross : NULL);
613 int x, y, width, height;
614 int fade_delay, post_delay;
616 if (fade_type == FADE_TYPE_FADE_OUT)
618 if (fade_type_skip != FADE_TYPE_NONE)
620 /* skip all fade operations until specified fade operation */
621 if (fade_type & fade_type_skip)
622 fade_type_skip = FADE_TYPE_NONE;
627 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
629 FadeCrossSaveBackbuffer();
635 redraw_mask |= fade_mask;
637 if (fade_type == FADE_TYPE_SKIP)
639 fade_type_skip = fade_mode;
644 fade_delay = fading.fade_delay;
645 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
647 if (fade_type_skip != FADE_TYPE_NONE)
649 /* skip all fade operations until specified fade operation */
650 if (fade_type & fade_type_skip)
651 fade_type_skip = FADE_TYPE_NONE;
656 if (global.autoplay_leveldir)
661 if (fade_mask == REDRAW_FIELD)
666 height = FULL_SYSIZE;
668 if (border.draw_masked_when_fading)
669 draw_border_function = DrawMaskedBorder_FIELD; /* update when fading */
671 DrawMaskedBorder_FIELD(); /* draw once */
673 else /* REDRAW_ALL */
681 if (!setup.fade_screens ||
683 fading.fade_mode == FADE_MODE_NONE)
685 if (fade_mode == FADE_MODE_FADE_OUT)
688 BlitBitmap(backbuffer, window, x, y, width, height, x, y);
690 redraw_mask &= ~fade_mask;
695 FadeRectangle(bitmap, x, y, width, height, fade_mode, fade_delay, post_delay,
696 draw_border_function);
698 redraw_mask &= ~fade_mask;
701 void FadeIn(int fade_mask)
703 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
704 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_IN);
706 FadeExt(fade_mask, FADE_MODE_FADE_IN, FADE_TYPE_FADE_IN);
709 void FadeOut(int fade_mask)
711 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
712 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_OUT);
714 FadeExt(fade_mask, FADE_MODE_FADE_OUT, FADE_TYPE_FADE_OUT);
716 global.border_status = game_status;
719 static void FadeSetLeaveNext(struct TitleFadingInfo fading_leave, boolean set)
721 static struct TitleFadingInfo fading_leave_stored;
724 fading_leave_stored = fading_leave;
726 fading = fading_leave_stored;
729 void FadeSetEnterMenu()
731 fading = menu.enter_menu;
733 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
736 void FadeSetLeaveMenu()
738 fading = menu.leave_menu;
740 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
743 void FadeSetEnterScreen()
745 fading = menu.enter_screen[game_status];
747 FadeSetLeaveNext(menu.leave_screen[game_status], TRUE); /* store */
750 void FadeSetNextScreen()
752 fading = menu.next_screen;
754 // (do not overwrite fade mode set by FadeSetEnterScreen)
755 // FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
758 void FadeSetLeaveScreen()
760 FadeSetLeaveNext(menu.leave_screen[game_status], FALSE); /* recall */
763 void FadeSetFromType(int type)
765 if (type & TYPE_ENTER_SCREEN)
766 FadeSetEnterScreen();
767 else if (type & TYPE_ENTER)
769 else if (type & TYPE_LEAVE)
773 void FadeSetDisabled()
775 static struct TitleFadingInfo fading_none = { FADE_MODE_NONE, -1, -1, -1 };
777 fading = fading_none;
780 void FadeSkipNextFadeIn()
782 FadeExt(0, FADE_MODE_SKIP_FADE_IN, FADE_TYPE_SKIP);
785 void FadeSkipNextFadeOut()
787 FadeExt(0, FADE_MODE_SKIP_FADE_OUT, FADE_TYPE_SKIP);
790 void SetWindowBackgroundImageIfDefined(int graphic)
792 if (graphic_info[graphic].bitmap)
793 SetWindowBackgroundBitmap(graphic_info[graphic].bitmap);
796 void SetMainBackgroundImageIfDefined(int graphic)
798 if (graphic_info[graphic].bitmap)
799 SetMainBackgroundBitmap(graphic_info[graphic].bitmap);
802 void SetDoorBackgroundImageIfDefined(int graphic)
804 if (graphic_info[graphic].bitmap)
805 SetDoorBackgroundBitmap(graphic_info[graphic].bitmap);
808 void SetWindowBackgroundImage(int graphic)
810 SetWindowBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
811 graphic_info[graphic].bitmap ?
812 graphic_info[graphic].bitmap :
813 graphic_info[IMG_BACKGROUND].bitmap);
816 void SetMainBackgroundImage(int graphic)
818 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
819 graphic_info[graphic].bitmap ?
820 graphic_info[graphic].bitmap :
821 graphic_info[IMG_BACKGROUND].bitmap);
824 void SetDoorBackgroundImage(int graphic)
826 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
827 graphic_info[graphic].bitmap ?
828 graphic_info[graphic].bitmap :
829 graphic_info[IMG_BACKGROUND].bitmap);
832 void SetPanelBackground()
834 struct GraphicInfo *gfx = &graphic_info[IMG_BACKGROUND_PANEL];
836 BlitBitmapTiled(gfx->bitmap, bitmap_db_panel, gfx->src_x, gfx->src_y,
837 gfx->width, gfx->height, 0, 0, DXSIZE, DYSIZE);
839 SetDoorBackgroundBitmap(bitmap_db_panel);
842 void DrawBackground(int x, int y, int width, int height)
844 /* "drawto" might still point to playfield buffer here (hall of fame) */
845 ClearRectangleOnBackground(backbuffer, x, y, width, height);
847 if (IN_GFX_FIELD_FULL(x, y))
848 redraw_mask |= REDRAW_FIELD;
849 else if (IN_GFX_DOOR_1(x, y))
850 redraw_mask |= REDRAW_DOOR_1;
851 else if (IN_GFX_DOOR_2(x, y))
852 redraw_mask |= REDRAW_DOOR_2;
853 else if (IN_GFX_DOOR_3(x, y))
854 redraw_mask |= REDRAW_DOOR_3;
857 void DrawBackgroundForFont(int x, int y, int width, int height, int font_nr)
859 struct FontBitmapInfo *font = getFontBitmapInfo(font_nr);
861 if (font->bitmap == NULL)
864 DrawBackground(x, y, width, height);
867 void DrawBackgroundForGraphic(int x, int y, int width, int height, int graphic)
869 struct GraphicInfo *g = &graphic_info[graphic];
871 if (g->bitmap == NULL)
874 DrawBackground(x, y, width, height);
879 /* !!! "drawto" might still point to playfield buffer here (see above) !!! */
880 /* (when entering hall of fame after playing) */
881 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
883 /* !!! maybe this should be done before clearing the background !!! */
884 if (game_status == GAME_MODE_PLAYING)
886 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
887 SetDrawtoField(DRAW_FIELDBUFFER);
891 SetDrawtoField(DRAW_BACKBUFFER);
895 void MarkTileDirty(int x, int y)
897 redraw_mask |= REDRAW_FIELD;
900 void SetBorderElement()
904 BorderElement = EL_EMPTY;
906 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
908 for (x = 0; x < lev_fieldx; x++)
910 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
911 BorderElement = EL_STEELWALL;
913 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
919 void FloodFillLevel(int from_x, int from_y, int fill_element,
920 short field[MAX_LEV_FIELDX][MAX_LEV_FIELDY],
921 int max_fieldx, int max_fieldy)
925 static int check[4][2] = { { -1, 0 }, { 0, -1 }, { 1, 0 }, { 0, 1 } };
926 static int safety = 0;
928 /* check if starting field still has the desired content */
929 if (field[from_x][from_y] == fill_element)
934 if (safety > max_fieldx * max_fieldy)
935 Error(ERR_EXIT, "Something went wrong in 'FloodFill()'. Please debug.");
937 old_element = field[from_x][from_y];
938 field[from_x][from_y] = fill_element;
940 for (i = 0; i < 4; i++)
942 x = from_x + check[i][0];
943 y = from_y + check[i][1];
945 if (IN_FIELD(x, y, max_fieldx, max_fieldy) && field[x][y] == old_element)
946 FloodFillLevel(x, y, fill_element, field, max_fieldx, max_fieldy);
952 void SetRandomAnimationValue(int x, int y)
954 gfx.anim_random_frame = GfxRandom[x][y];
957 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
959 /* animation synchronized with global frame counter, not move position */
960 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
961 sync_frame = FrameCounter;
963 return getAnimationFrame(graphic_info[graphic].anim_frames,
964 graphic_info[graphic].anim_delay,
965 graphic_info[graphic].anim_mode,
966 graphic_info[graphic].anim_start_frame,
970 void getSizedGraphicSourceExt(int graphic, int frame, int tilesize,
971 Bitmap **bitmap, int *x, int *y,
972 boolean get_backside)
974 struct GraphicInfo *g = &graphic_info[graphic];
975 Bitmap *src_bitmap = g->bitmap;
976 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
977 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
978 int tilesize_capped = MIN(MAX(1, tilesize), TILESIZE);
980 // if no in-game graphics defined, always use standard graphic size
981 if (g->bitmaps[IMG_BITMAP_GAME] == NULL)
984 if (tilesize == gfx.standard_tile_size)
985 src_bitmap = g->bitmaps[IMG_BITMAP_STANDARD];
986 else if (tilesize == game.tile_size)
987 src_bitmap = g->bitmaps[IMG_BITMAP_GAME];
989 src_bitmap = g->bitmaps[IMG_BITMAP_1x1 - log_2(tilesize_capped)];
991 if (g->offset_y == 0) /* frames are ordered horizontally */
993 int max_width = g->anim_frames_per_line * g->width;
994 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
996 src_x = pos % max_width;
997 src_y = src_y % g->height + pos / max_width * g->height;
999 else if (g->offset_x == 0) /* frames are ordered vertically */
1001 int max_height = g->anim_frames_per_line * g->height;
1002 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
1004 src_x = src_x % g->width + pos / max_height * g->width;
1005 src_y = pos % max_height;
1007 else /* frames are ordered diagonally */
1009 src_x = src_x + frame * g->offset_x;
1010 src_y = src_y + frame * g->offset_y;
1013 *bitmap = src_bitmap;
1014 *x = src_x * tilesize / TILESIZE;
1015 *y = src_y * tilesize / TILESIZE;
1018 void getFixedGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1019 int *x, int *y, boolean get_backside)
1021 getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y,
1025 void getSizedGraphicSource(int graphic, int frame, int tilesize,
1026 Bitmap **bitmap, int *x, int *y)
1028 getSizedGraphicSourceExt(graphic, frame, tilesize, bitmap, x, y, FALSE);
1031 void getFixedGraphicSource(int graphic, int frame,
1032 Bitmap **bitmap, int *x, int *y)
1034 getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y, FALSE);
1037 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1039 getSizedGraphicSource(graphic, 0, MINI_TILESIZE, bitmap, x, y);
1042 inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1043 int *x, int *y, boolean get_backside)
1045 struct GraphicInfo *g = &graphic_info[graphic];
1046 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
1047 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
1049 if (TILESIZE_VAR != TILESIZE)
1050 return getSizedGraphicSourceExt(graphic, frame, TILESIZE_VAR, bitmap, x, y,
1053 *bitmap = g->bitmap;
1055 if (g->offset_y == 0) /* frames are ordered horizontally */
1057 int max_width = g->anim_frames_per_line * g->width;
1058 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
1060 *x = pos % max_width;
1061 *y = src_y % g->height + pos / max_width * g->height;
1063 else if (g->offset_x == 0) /* frames are ordered vertically */
1065 int max_height = g->anim_frames_per_line * g->height;
1066 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
1068 *x = src_x % g->width + pos / max_height * g->width;
1069 *y = pos % max_height;
1071 else /* frames are ordered diagonally */
1073 *x = src_x + frame * g->offset_x;
1074 *y = src_y + frame * g->offset_y;
1078 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
1080 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
1083 void DrawGraphic(int x, int y, int graphic, int frame)
1086 if (!IN_SCR_FIELD(x, y))
1088 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1089 printf("DrawGraphic(): This should never happen!\n");
1094 DrawGraphicExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR, graphic,
1097 MarkTileDirty(x, y);
1100 void DrawFixedGraphic(int x, int y, int graphic, int frame)
1103 if (!IN_SCR_FIELD(x, y))
1105 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1106 printf("DrawGraphic(): This should never happen!\n");
1111 DrawFixedGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic,
1113 MarkTileDirty(x, y);
1116 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1122 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1124 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX_VAR, TILEY_VAR, x, y);
1127 void DrawFixedGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1133 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1134 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
1137 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
1140 if (!IN_SCR_FIELD(x, y))
1142 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1143 printf("DrawGraphicThruMask(): This should never happen!\n");
1148 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
1151 MarkTileDirty(x, y);
1154 void DrawFixedGraphicThruMask(int x, int y, int graphic, int frame)
1157 if (!IN_SCR_FIELD(x, y))
1159 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1160 printf("DrawGraphicThruMask(): This should never happen!\n");
1165 DrawFixedGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
1167 MarkTileDirty(x, y);
1170 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
1176 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1178 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX_VAR, TILEY_VAR,
1182 void DrawFixedGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y,
1183 int graphic, int frame)
1185 struct GraphicInfo *g = &graphic_info[graphic];
1189 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1191 BlitBitmapMasked(src_bitmap, d, src_x, src_y, g->width, g->height,
1195 void DrawSizedGraphic(int x, int y, int graphic, int frame, int tilesize)
1197 DrawSizedGraphicExt(drawto, SX + x * tilesize, SY + y * tilesize, graphic,
1199 MarkTileDirty(x / tilesize, y / tilesize);
1202 void DrawSizedGraphicExt(DrawBuffer *d, int x, int y, int graphic, int frame,
1208 getSizedGraphicSource(graphic, frame, tilesize, &src_bitmap, &src_x, &src_y);
1209 BlitBitmap(src_bitmap, d, src_x, src_y, tilesize, tilesize, x, y);
1212 void DrawMiniGraphic(int x, int y, int graphic)
1214 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
1215 MarkTileDirty(x / 2, y / 2);
1218 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
1223 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1224 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
1227 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
1228 int graphic, int frame,
1229 int cut_mode, int mask_mode)
1234 int width = TILEX, height = TILEY;
1237 if (dx || dy) /* shifted graphic */
1239 if (x < BX1) /* object enters playfield from the left */
1246 else if (x > BX2) /* object enters playfield from the right */
1252 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
1258 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
1260 else if (dx) /* general horizontal movement */
1261 MarkTileDirty(x + SIGN(dx), y);
1263 if (y < BY1) /* object enters playfield from the top */
1265 if (cut_mode==CUT_BELOW) /* object completely above top border */
1273 else if (y > BY2) /* object enters playfield from the bottom */
1279 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
1285 else if (dy > 0 && cut_mode == CUT_ABOVE)
1287 if (y == BY2) /* object completely above bottom border */
1293 MarkTileDirty(x, y + 1);
1294 } /* object leaves playfield to the bottom */
1295 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1297 else if (dy) /* general vertical movement */
1298 MarkTileDirty(x, y + SIGN(dy));
1302 if (!IN_SCR_FIELD(x, y))
1304 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1305 printf("DrawGraphicShifted(): This should never happen!\n");
1310 width = width * TILESIZE_VAR / TILESIZE;
1311 height = height * TILESIZE_VAR / TILESIZE;
1312 cx = cx * TILESIZE_VAR / TILESIZE;
1313 cy = cy * TILESIZE_VAR / TILESIZE;
1314 dx = dx * TILESIZE_VAR / TILESIZE;
1315 dy = dy * TILESIZE_VAR / TILESIZE;
1317 if (width > 0 && height > 0)
1319 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1324 dst_x = FX + x * TILEX_VAR + dx;
1325 dst_y = FY + y * TILEY_VAR + dy;
1327 if (mask_mode == USE_MASKING)
1328 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1331 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1334 MarkTileDirty(x, y);
1338 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
1339 int graphic, int frame,
1340 int cut_mode, int mask_mode)
1345 int width = TILEX_VAR, height = TILEY_VAR;
1348 int x2 = x + SIGN(dx);
1349 int y2 = y + SIGN(dy);
1351 /* movement with two-tile animations must be sync'ed with movement position,
1352 not with current GfxFrame (which can be higher when using slow movement) */
1353 int anim_pos = (dx ? ABS(dx) : ABS(dy));
1354 int anim_frames = graphic_info[graphic].anim_frames;
1356 /* (we also need anim_delay here for movement animations with less frames) */
1357 int anim_delay = graphic_info[graphic].anim_delay;
1358 int sync_frame = anim_pos * anim_frames * anim_delay / TILESIZE;
1360 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
1361 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
1363 /* re-calculate animation frame for two-tile movement animation */
1364 frame = getGraphicAnimationFrame(graphic, sync_frame);
1366 /* check if movement start graphic inside screen area and should be drawn */
1367 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
1369 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
1371 dst_x = FX + x1 * TILEX_VAR;
1372 dst_y = FY + y1 * TILEY_VAR;
1374 if (mask_mode == USE_MASKING)
1375 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1378 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1381 MarkTileDirty(x1, y1);
1384 /* check if movement end graphic inside screen area and should be drawn */
1385 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
1387 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
1389 dst_x = FX + x2 * TILEX_VAR;
1390 dst_y = FY + y2 * TILEY_VAR;
1392 if (mask_mode == USE_MASKING)
1393 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1396 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1399 MarkTileDirty(x2, y2);
1403 static void DrawGraphicShifted(int x, int y, int dx, int dy,
1404 int graphic, int frame,
1405 int cut_mode, int mask_mode)
1409 DrawGraphic(x, y, graphic, frame);
1414 if (graphic_info[graphic].double_movement) /* EM style movement images */
1415 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1417 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1420 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1421 int frame, int cut_mode)
1423 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
1426 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1427 int cut_mode, int mask_mode)
1429 int lx = LEVELX(x), ly = LEVELY(y);
1433 if (IN_LEV_FIELD(lx, ly))
1435 SetRandomAnimationValue(lx, ly);
1437 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
1438 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1440 /* do not use double (EM style) movement graphic when not moving */
1441 if (graphic_info[graphic].double_movement && !dx && !dy)
1443 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
1444 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1447 else /* border element */
1449 graphic = el2img(element);
1450 frame = getGraphicAnimationFrame(graphic, -1);
1453 if (element == EL_EXPANDABLE_WALL)
1455 boolean left_stopped = FALSE, right_stopped = FALSE;
1457 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1458 left_stopped = TRUE;
1459 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1460 right_stopped = TRUE;
1462 if (left_stopped && right_stopped)
1464 else if (left_stopped)
1466 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1467 frame = graphic_info[graphic].anim_frames - 1;
1469 else if (right_stopped)
1471 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1472 frame = graphic_info[graphic].anim_frames - 1;
1477 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1478 else if (mask_mode == USE_MASKING)
1479 DrawGraphicThruMask(x, y, graphic, frame);
1481 DrawGraphic(x, y, graphic, frame);
1484 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1485 int cut_mode, int mask_mode)
1487 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1488 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1489 cut_mode, mask_mode);
1492 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1495 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1498 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1501 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1504 void DrawLevelElementThruMask(int x, int y, int element)
1506 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1509 void DrawLevelFieldThruMask(int x, int y)
1511 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1514 /* !!! implementation of quicksand is totally broken !!! */
1515 #define IS_CRUMBLED_TILE(x, y, e) \
1516 (GFX_CRUMBLED(e) && (!IN_LEV_FIELD(x, y) || \
1517 !IS_MOVING(x, y) || \
1518 (e) == EL_QUICKSAND_EMPTYING || \
1519 (e) == EL_QUICKSAND_FAST_EMPTYING))
1521 static void DrawLevelFieldCrumbledInnerCorners(int x, int y, int dx, int dy,
1526 int width, height, cx, cy;
1527 int sx = SCREENX(x), sy = SCREENY(y);
1528 int crumbled_border_size = graphic_info[graphic].border_size;
1531 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1533 for (i = 1; i < 4; i++)
1535 int dxx = (i & 1 ? dx : 0);
1536 int dyy = (i & 2 ? dy : 0);
1539 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1542 /* check if neighbour field is of same crumble type */
1543 boolean same = (IS_CRUMBLED_TILE(xx, yy, element) &&
1544 graphic_info[graphic].class ==
1545 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class);
1547 /* return if check prevents inner corner */
1548 if (same == (dxx == dx && dyy == dy))
1552 /* if we reach this point, we have an inner corner */
1554 getGraphicSource(graphic, 1, &src_bitmap, &src_x, &src_y);
1556 width = crumbled_border_size * TILESIZE_VAR / TILESIZE;
1557 height = crumbled_border_size * TILESIZE_VAR / TILESIZE;
1558 cx = (dx > 0 ? TILESIZE_VAR - width : 0);
1559 cy = (dy > 0 ? TILESIZE_VAR - height : 0);
1561 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1562 width, height, FX + sx * TILEX_VAR + cx, FY + sy * TILEY_VAR + cy);
1565 static void DrawLevelFieldCrumbledBorders(int x, int y, int graphic, int frame,
1570 int width, height, bx, by, cx, cy;
1571 int sx = SCREENX(x), sy = SCREENY(y);
1572 int crumbled_border_size = graphic_info[graphic].border_size;
1573 int crumbled_border_size_var = crumbled_border_size * TILESIZE_VAR / TILESIZE;
1574 int crumbled_border_pos_var = TILESIZE_VAR - crumbled_border_size_var;
1577 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1579 /* draw simple, sloppy, non-corner-accurate crumbled border */
1581 width = (dir == 1 || dir == 2 ? crumbled_border_size_var : TILESIZE_VAR);
1582 height = (dir == 0 || dir == 3 ? crumbled_border_size_var : TILESIZE_VAR);
1583 cx = (dir == 2 ? crumbled_border_pos_var : 0);
1584 cy = (dir == 3 ? crumbled_border_pos_var : 0);
1586 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy, width, height,
1587 FX + sx * TILEX_VAR + cx,
1588 FY + sy * TILEY_VAR + cy);
1590 /* (remaining middle border part must be at least as big as corner part) */
1591 if (!(graphic_info[graphic].style & STYLE_ACCURATE_BORDERS) ||
1592 crumbled_border_size >= TILESIZE / 3)
1595 /* correct corners of crumbled border, if needed */
1597 for (i = -1; i <= 1; i += 2)
1599 int xx = x + (dir == 0 || dir == 3 ? i : 0);
1600 int yy = y + (dir == 1 || dir == 2 ? i : 0);
1601 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1604 /* check if neighbour field is of same crumble type */
1605 if (IS_CRUMBLED_TILE(xx, yy, element) &&
1606 graphic_info[graphic].class ==
1607 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1609 /* no crumbled corner, but continued crumbled border */
1611 int c1 = (dir == 2 || dir == 3 ? crumbled_border_pos_var : 0);
1612 int c2 = (i == 1 ? crumbled_border_pos_var : 0);
1613 int b1 = (i == 1 ? crumbled_border_size_var :
1614 TILESIZE_VAR - 2 * crumbled_border_size_var);
1616 width = crumbled_border_size_var;
1617 height = crumbled_border_size_var;
1619 if (dir == 1 || dir == 2)
1634 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
1636 FX + sx * TILEX_VAR + cx,
1637 FY + sy * TILEY_VAR + cy);
1642 static void DrawLevelFieldCrumbledExt(int x, int y, int graphic, int frame)
1644 int sx = SCREENX(x), sy = SCREENY(y);
1647 static int xy[4][2] =
1655 if (!IN_LEV_FIELD(x, y))
1658 element = TILE_GFX_ELEMENT(x, y);
1660 /* crumble field itself */
1661 if (IS_CRUMBLED_TILE(x, y, element))
1663 if (!IN_SCR_FIELD(sx, sy))
1666 for (i = 0; i < 4; i++)
1668 int xx = x + xy[i][0];
1669 int yy = y + xy[i][1];
1671 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1674 /* check if neighbour field is of same crumble type */
1675 if (IS_CRUMBLED_TILE(xx, yy, element) &&
1676 graphic_info[graphic].class ==
1677 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1680 DrawLevelFieldCrumbledBorders(x, y, graphic, frame, i);
1683 if ((graphic_info[graphic].style & STYLE_INNER_CORNERS) &&
1684 graphic_info[graphic].anim_frames == 2)
1686 for (i = 0; i < 4; i++)
1688 int dx = (i & 1 ? +1 : -1);
1689 int dy = (i & 2 ? +1 : -1);
1691 DrawLevelFieldCrumbledInnerCorners(x, y, dx, dy, graphic);
1695 MarkTileDirty(sx, sy);
1697 else /* center field not crumbled -- crumble neighbour fields */
1699 for (i = 0; i < 4; i++)
1701 int xx = x + xy[i][0];
1702 int yy = y + xy[i][1];
1703 int sxx = sx + xy[i][0];
1704 int syy = sy + xy[i][1];
1706 if (!IN_LEV_FIELD(xx, yy) ||
1707 !IN_SCR_FIELD(sxx, syy))
1710 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
1713 element = TILE_GFX_ELEMENT(xx, yy);
1715 if (!IS_CRUMBLED_TILE(xx, yy, element))
1718 graphic = el_act2crm(element, ACTION_DEFAULT);
1720 DrawLevelFieldCrumbledBorders(xx, yy, graphic, 0, 3 - i);
1722 MarkTileDirty(sxx, syy);
1727 void DrawLevelFieldCrumbled(int x, int y)
1731 if (!IN_LEV_FIELD(x, y))
1734 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1735 GfxElement[x][y] != EL_UNDEFINED &&
1736 GFX_CRUMBLED(GfxElement[x][y]))
1738 DrawLevelFieldCrumbledDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
1743 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
1745 DrawLevelFieldCrumbledExt(x, y, graphic, 0);
1748 void DrawLevelFieldCrumbledDigging(int x, int y, int direction,
1751 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1752 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1753 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1754 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1755 int sx = SCREENX(x), sy = SCREENY(y);
1757 DrawGraphic(sx, sy, graphic1, frame1);
1758 DrawLevelFieldCrumbledExt(x, y, graphic2, frame2);
1761 void DrawLevelFieldCrumbledNeighbours(int x, int y)
1763 int sx = SCREENX(x), sy = SCREENY(y);
1764 static int xy[4][2] =
1773 for (i = 0; i < 4; i++)
1775 int xx = x + xy[i][0];
1776 int yy = y + xy[i][1];
1777 int sxx = sx + xy[i][0];
1778 int syy = sy + xy[i][1];
1780 if (!IN_LEV_FIELD(xx, yy) ||
1781 !IN_SCR_FIELD(sxx, syy) ||
1782 !GFX_CRUMBLED(Feld[xx][yy]) ||
1786 DrawLevelField(xx, yy);
1790 static int getBorderElement(int x, int y)
1794 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1795 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1796 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1797 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1798 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1799 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1800 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1802 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1803 int steel_position = (x == -1 && y == -1 ? 0 :
1804 x == lev_fieldx && y == -1 ? 1 :
1805 x == -1 && y == lev_fieldy ? 2 :
1806 x == lev_fieldx && y == lev_fieldy ? 3 :
1807 x == -1 || x == lev_fieldx ? 4 :
1808 y == -1 || y == lev_fieldy ? 5 : 6);
1810 return border[steel_position][steel_type];
1813 void DrawScreenElement(int x, int y, int element)
1815 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1816 DrawLevelFieldCrumbled(LEVELX(x), LEVELY(y));
1819 void DrawLevelElement(int x, int y, int element)
1821 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1822 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1825 void DrawScreenField(int x, int y)
1827 int lx = LEVELX(x), ly = LEVELY(y);
1828 int element, content;
1830 if (!IN_LEV_FIELD(lx, ly))
1832 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1835 element = getBorderElement(lx, ly);
1837 DrawScreenElement(x, y, element);
1842 element = Feld[lx][ly];
1843 content = Store[lx][ly];
1845 if (IS_MOVING(lx, ly))
1847 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1848 boolean cut_mode = NO_CUTTING;
1850 if (element == EL_QUICKSAND_EMPTYING ||
1851 element == EL_QUICKSAND_FAST_EMPTYING ||
1852 element == EL_MAGIC_WALL_EMPTYING ||
1853 element == EL_BD_MAGIC_WALL_EMPTYING ||
1854 element == EL_DC_MAGIC_WALL_EMPTYING ||
1855 element == EL_AMOEBA_DROPPING)
1856 cut_mode = CUT_ABOVE;
1857 else if (element == EL_QUICKSAND_FILLING ||
1858 element == EL_QUICKSAND_FAST_FILLING ||
1859 element == EL_MAGIC_WALL_FILLING ||
1860 element == EL_BD_MAGIC_WALL_FILLING ||
1861 element == EL_DC_MAGIC_WALL_FILLING)
1862 cut_mode = CUT_BELOW;
1864 if (cut_mode == CUT_ABOVE)
1865 DrawScreenElement(x, y, element);
1867 DrawScreenElement(x, y, EL_EMPTY);
1870 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1871 else if (cut_mode == NO_CUTTING)
1872 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1875 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1877 if (cut_mode == CUT_BELOW &&
1878 IN_LEV_FIELD(lx, ly + 1) && IN_SCR_FIELD(x, y + 1))
1879 DrawLevelElement(lx, ly + 1, element);
1882 if (content == EL_ACID)
1884 int dir = MovDir[lx][ly];
1885 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
1886 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
1888 DrawLevelElementThruMask(newlx, newly, EL_ACID);
1891 else if (IS_BLOCKED(lx, ly))
1896 boolean cut_mode = NO_CUTTING;
1897 int element_old, content_old;
1899 Blocked2Moving(lx, ly, &oldx, &oldy);
1902 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1903 MovDir[oldx][oldy] == MV_RIGHT);
1905 element_old = Feld[oldx][oldy];
1906 content_old = Store[oldx][oldy];
1908 if (element_old == EL_QUICKSAND_EMPTYING ||
1909 element_old == EL_QUICKSAND_FAST_EMPTYING ||
1910 element_old == EL_MAGIC_WALL_EMPTYING ||
1911 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1912 element_old == EL_DC_MAGIC_WALL_EMPTYING ||
1913 element_old == EL_AMOEBA_DROPPING)
1914 cut_mode = CUT_ABOVE;
1916 DrawScreenElement(x, y, EL_EMPTY);
1919 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1921 else if (cut_mode == NO_CUTTING)
1922 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1925 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1928 else if (IS_DRAWABLE(element))
1929 DrawScreenElement(x, y, element);
1931 DrawScreenElement(x, y, EL_EMPTY);
1934 void DrawLevelField(int x, int y)
1936 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1937 DrawScreenField(SCREENX(x), SCREENY(y));
1938 else if (IS_MOVING(x, y))
1942 Moving2Blocked(x, y, &newx, &newy);
1943 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1944 DrawScreenField(SCREENX(newx), SCREENY(newy));
1946 else if (IS_BLOCKED(x, y))
1950 Blocked2Moving(x, y, &oldx, &oldy);
1951 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1952 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1956 void DrawSizedElement(int x, int y, int element, int tilesize)
1960 graphic = el2edimg(element);
1961 DrawSizedGraphic(x, y, graphic, 0, tilesize);
1964 void DrawMiniElement(int x, int y, int element)
1968 graphic = el2edimg(element);
1969 DrawMiniGraphic(x, y, graphic);
1972 void DrawSizedElementOrWall(int sx, int sy, int scroll_x, int scroll_y,
1975 int x = sx + scroll_x, y = sy + scroll_y;
1977 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1978 DrawSizedElement(sx, sy, EL_EMPTY, tilesize);
1979 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1980 DrawSizedElement(sx, sy, Feld[x][y], tilesize);
1982 DrawSizedGraphic(sx, sy, el2edimg(getBorderElement(x, y)), 0, tilesize);
1985 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1987 int x = sx + scroll_x, y = sy + scroll_y;
1989 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1990 DrawMiniElement(sx, sy, EL_EMPTY);
1991 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1992 DrawMiniElement(sx, sy, Feld[x][y]);
1994 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1997 void DrawEnvelopeBackgroundTiles(int graphic, int startx, int starty,
1998 int x, int y, int xsize, int ysize,
1999 int tile_width, int tile_height)
2003 int dst_x = startx + x * tile_width;
2004 int dst_y = starty + y * tile_height;
2005 int width = graphic_info[graphic].width;
2006 int height = graphic_info[graphic].height;
2007 int inner_width_raw = MAX(width - 2 * tile_width, tile_width);
2008 int inner_height_raw = MAX(height - 2 * tile_height, tile_height);
2009 int inner_width = inner_width_raw - (inner_width_raw % tile_width);
2010 int inner_height = inner_height_raw - (inner_height_raw % tile_height);
2011 int inner_sx = (width >= 3 * tile_width ? tile_width : 0);
2012 int inner_sy = (height >= 3 * tile_height ? tile_height : 0);
2013 boolean draw_masked = graphic_info[graphic].draw_masked;
2015 getFixedGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
2017 if (src_bitmap == NULL || width < tile_width || height < tile_height)
2019 ClearRectangle(drawto, dst_x, dst_y, tile_width, tile_height);
2023 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - tile_width :
2024 inner_sx + (x - 1) * tile_width % inner_width);
2025 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - tile_height :
2026 inner_sy + (y - 1) * tile_height % inner_height);
2029 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
2032 BlitBitmap(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
2036 void DrawEnvelopeBackground(int graphic, int startx, int starty,
2037 int x, int y, int xsize, int ysize, int font_nr)
2039 int font_width = getFontWidth(font_nr);
2040 int font_height = getFontHeight(font_nr);
2042 DrawEnvelopeBackgroundTiles(graphic, startx, starty, x, y, xsize, ysize,
2043 font_width, font_height);
2046 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
2048 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2049 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2050 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2051 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2052 boolean no_delay = (tape.warp_forward);
2053 unsigned int anim_delay = 0;
2054 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
2055 int anim_delay_value = (no_delay ? 0 : frame_delay_value) / 2;
2056 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
2057 int font_width = getFontWidth(font_nr);
2058 int font_height = getFontHeight(font_nr);
2059 int max_xsize = level.envelope[envelope_nr].xsize;
2060 int max_ysize = level.envelope[envelope_nr].ysize;
2061 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
2062 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
2063 int xend = max_xsize;
2064 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
2065 int xstep = (xstart < xend ? 1 : 0);
2066 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2068 int end = MAX(xend - xstart, yend - ystart);
2071 for (i = start; i <= end; i++)
2073 int last_frame = end; // last frame of this "for" loop
2074 int x = xstart + i * xstep;
2075 int y = ystart + i * ystep;
2076 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2077 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2078 int sx = SX + (SXSIZE - xsize * font_width) / 2;
2079 int sy = SY + (SYSIZE - ysize * font_height) / 2;
2082 SetDrawtoField(DRAW_FIELDBUFFER);
2084 BlitScreenToBitmap(backbuffer);
2086 SetDrawtoField(DRAW_BACKBUFFER);
2088 for (yy = 0; yy < ysize; yy++)
2089 for (xx = 0; xx < xsize; xx++)
2090 DrawEnvelopeBackground(graphic, sx, sy, xx, yy, xsize, ysize, font_nr);
2092 DrawTextBuffer(sx + font_width, sy + font_height,
2093 level.envelope[envelope_nr].text, font_nr, max_xsize,
2094 xsize - 2, ysize - 2, 0, mask_mode,
2095 level.envelope[envelope_nr].autowrap,
2096 level.envelope[envelope_nr].centered, FALSE);
2098 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2101 SkipUntilDelayReached(&anim_delay, anim_delay_value, &i, last_frame);
2105 void ShowEnvelope(int envelope_nr)
2107 int element = EL_ENVELOPE_1 + envelope_nr;
2108 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2109 int sound_opening = element_info[element].sound[ACTION_OPENING];
2110 int sound_closing = element_info[element].sound[ACTION_CLOSING];
2111 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2112 boolean no_delay = (tape.warp_forward);
2113 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
2114 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
2115 int anim_mode = graphic_info[graphic].anim_mode;
2116 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2117 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2119 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
2121 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2123 if (anim_mode == ANIM_DEFAULT)
2124 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
2126 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
2129 Delay(wait_delay_value);
2131 WaitForEventToContinue();
2133 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2135 if (anim_mode != ANIM_NONE)
2136 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
2138 if (anim_mode == ANIM_DEFAULT)
2139 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
2141 game.envelope_active = FALSE;
2143 SetDrawtoField(DRAW_FIELDBUFFER);
2145 redraw_mask |= REDRAW_FIELD;
2149 static void setRequestCenterPosition(int *x, int *y)
2151 int sx_center = (request.x != -1 ? request.x : SX + SXSIZE / 2);
2152 int sy_center = (request.y != -1 ? request.y : SY + SYSIZE / 2);
2158 static void setRequestPosition(int *x, int *y, boolean add_border_size)
2160 int border_size = request.border_size;
2161 int sx_center, sy_center;
2164 setRequestCenterPosition(&sx_center, &sy_center);
2166 sx = sx_center - request.width / 2;
2167 sy = sy_center - request.height / 2;
2169 if (add_border_size)
2179 void DrawEnvelopeRequest(char *text)
2181 char *text_final = text;
2182 char *text_door_style = NULL;
2183 int graphic = IMG_BACKGROUND_REQUEST;
2184 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2185 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2186 int font_nr = FONT_REQUEST;
2187 int font_width = getFontWidth(font_nr);
2188 int font_height = getFontHeight(font_nr);
2189 int border_size = request.border_size;
2190 int line_spacing = request.line_spacing;
2191 int line_height = font_height + line_spacing;
2192 int text_width = request.width - 2 * border_size;
2193 int text_height = request.height - 2 * border_size;
2194 int line_length = text_width / font_width;
2195 int max_lines = text_height / line_height;
2196 int width = request.width;
2197 int height = request.height;
2198 int tile_size = request.step_offset;
2199 int x_steps = width / tile_size;
2200 int y_steps = height / tile_size;
2204 if (request.wrap_single_words)
2206 char *src_text_ptr, *dst_text_ptr;
2208 text_door_style = checked_malloc(2 * strlen(text) + 1);
2210 src_text_ptr = text;
2211 dst_text_ptr = text_door_style;
2213 while (*src_text_ptr)
2215 if (*src_text_ptr == ' ' ||
2216 *src_text_ptr == '?' ||
2217 *src_text_ptr == '!')
2218 *dst_text_ptr++ = '\n';
2220 if (*src_text_ptr != ' ')
2221 *dst_text_ptr++ = *src_text_ptr;
2226 *dst_text_ptr = '\0';
2228 text_final = text_door_style;
2231 setRequestPosition(&sx, &sy, FALSE);
2233 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
2235 for (y = 0; y < y_steps; y++)
2236 for (x = 0; x < x_steps; x++)
2237 DrawEnvelopeBackgroundTiles(graphic, sx, sy,
2238 x, y, x_steps, y_steps,
2239 tile_size, tile_size);
2241 DrawTextBuffer(sx + border_size, sy + border_size, text_final, font_nr,
2242 line_length, -1, max_lines, line_spacing, mask_mode,
2243 request.autowrap, request.centered, FALSE);
2245 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2246 RedrawGadget(tool_gadget[i]);
2248 // store readily prepared envelope request for later use when animating
2249 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2251 if (text_door_style)
2252 free(text_door_style);
2255 void AnimateEnvelopeRequest(int anim_mode, int action)
2257 int graphic = IMG_BACKGROUND_REQUEST;
2258 boolean draw_masked = graphic_info[graphic].draw_masked;
2259 int delay_value_normal = request.step_delay;
2260 int delay_value_fast = delay_value_normal / 2;
2261 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2262 boolean no_delay = (tape.warp_forward);
2263 int delay_value = (ffwd_delay ? delay_value_fast : delay_value_normal);
2264 int anim_delay_value = (no_delay ? 0 : delay_value + 500 * 0) / 2;
2265 unsigned int anim_delay = 0;
2267 int width = request.width;
2268 int height = request.height;
2269 int tile_size = request.step_offset;
2270 int max_xsize = width / tile_size;
2271 int max_ysize = height / tile_size;
2272 int max_xsize_inner = max_xsize - 2;
2273 int max_ysize_inner = max_ysize - 2;
2275 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize_inner : 0);
2276 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize_inner : 0);
2277 int xend = max_xsize_inner;
2278 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize_inner : 0);
2279 int xstep = (xstart < xend ? 1 : 0);
2280 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2282 int end = MAX(xend - xstart, yend - ystart);
2285 if (setup.quick_doors)
2293 if (action == ACTION_OPENING)
2294 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2295 else if (action == ACTION_CLOSING)
2296 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2299 for (i = start; i <= end; i++)
2301 int last_frame = end; // last frame of this "for" loop
2302 int x = xstart + i * xstep;
2303 int y = ystart + i * ystep;
2304 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2305 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2306 int xsize_size_left = (xsize - 1) * tile_size;
2307 int ysize_size_top = (ysize - 1) * tile_size;
2308 int max_xsize_pos = (max_xsize - 1) * tile_size;
2309 int max_ysize_pos = (max_ysize - 1) * tile_size;
2310 int sx_center, sy_center;
2315 setRequestCenterPosition(&sx_center, &sy_center);
2317 src_x = sx_center - width / 2;
2318 src_y = sy_center - height / 2;
2319 dst_x = sx_center - xsize * tile_size / 2;
2320 dst_y = sy_center - ysize * tile_size / 2;
2322 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2324 for (yy = 0; yy < 2; yy++)
2326 for (xx = 0; xx < 2; xx++)
2328 int src_xx = src_x + xx * max_xsize_pos;
2329 int src_yy = src_y + yy * max_ysize_pos;
2330 int dst_xx = dst_x + xx * xsize_size_left;
2331 int dst_yy = dst_y + yy * ysize_size_top;
2332 int xx_size = (xx ? tile_size : xsize_size_left);
2333 int yy_size = (yy ? tile_size : ysize_size_top);
2336 BlitBitmapMasked(bitmap_db_cross, backbuffer,
2337 src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
2339 BlitBitmap(bitmap_db_cross, backbuffer,
2340 src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
2344 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2349 SkipUntilDelayReached(&anim_delay, anim_delay_value, &i, last_frame);
2353 void ShowEnvelopeRequest(char *text, unsigned int req_state, int action)
2355 int last_game_status = game_status; /* save current game status */
2356 int graphic = IMG_BACKGROUND_REQUEST;
2357 int sound_opening = SND_REQUEST_OPENING;
2358 int sound_closing = SND_REQUEST_CLOSING;
2359 int anim_mode = graphic_info[graphic].anim_mode;
2360 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2361 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2363 if (game_status == GAME_MODE_PLAYING)
2364 BlitScreenToBitmap(backbuffer);
2366 SetDrawtoField(DRAW_BACKBUFFER);
2368 // SetDrawBackgroundMask(REDRAW_NONE);
2370 if (action == ACTION_OPENING)
2372 BlitBitmap(backbuffer, bitmap_db_store, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2374 if (req_state & REQ_ASK)
2376 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2377 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2379 else if (req_state & REQ_CONFIRM)
2381 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2383 else if (req_state & REQ_PLAYER)
2385 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2386 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2387 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2388 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2391 DrawEnvelopeRequest(text);
2393 if (game_status != GAME_MODE_MAIN)
2397 /* force DOOR font inside door area */
2398 game_status = GAME_MODE_PSEUDO_DOOR;
2400 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
2402 if (action == ACTION_OPENING)
2404 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2406 if (anim_mode == ANIM_DEFAULT)
2407 AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_OPENING);
2409 AnimateEnvelopeRequest(main_anim_mode, ACTION_OPENING);
2413 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2415 if (anim_mode != ANIM_NONE)
2416 AnimateEnvelopeRequest(main_anim_mode, ACTION_CLOSING);
2418 if (anim_mode == ANIM_DEFAULT)
2419 AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_CLOSING);
2422 game.envelope_active = FALSE;
2424 game_status = last_game_status; /* restore current game status */
2426 if (action == ACTION_CLOSING)
2428 if (game_status != GAME_MODE_MAIN)
2431 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2434 // SetDrawBackgroundMask(last_draw_background_mask);
2436 redraw_mask |= REDRAW_FIELD;
2438 if (game_status == GAME_MODE_MAIN)
2443 if (action == ACTION_CLOSING &&
2444 game_status == GAME_MODE_PLAYING &&
2445 level.game_engine_type == GAME_ENGINE_TYPE_RND)
2446 SetDrawtoField(DRAW_FIELDBUFFER);
2449 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
2453 int graphic = el2preimg(element);
2455 getSizedGraphicSource(graphic, 0, tilesize, &src_bitmap, &src_x, &src_y);
2456 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
2459 void DrawLevel(int draw_background_mask)
2463 SetMainBackgroundImage(IMG_BACKGROUND_PLAYING);
2464 SetDrawBackgroundMask(draw_background_mask);
2468 for (x = BX1; x <= BX2; x++)
2469 for (y = BY1; y <= BY2; y++)
2470 DrawScreenField(x, y);
2472 redraw_mask |= REDRAW_FIELD;
2475 void DrawSizedLevel(int size_x, int size_y, int scroll_x, int scroll_y,
2480 for (x = 0; x < size_x; x++)
2481 for (y = 0; y < size_y; y++)
2482 DrawSizedElementOrWall(x, y, scroll_x, scroll_y, tilesize);
2484 redraw_mask |= REDRAW_FIELD;
2487 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
2491 for (x = 0; x < size_x; x++)
2492 for (y = 0; y < size_y; y++)
2493 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
2495 redraw_mask |= REDRAW_FIELD;
2498 static void DrawPreviewLevelPlayfieldExt(int from_x, int from_y)
2500 boolean show_level_border = (BorderElement != EL_EMPTY);
2501 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2502 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2503 int tile_size = preview.tile_size;
2504 int preview_width = preview.xsize * tile_size;
2505 int preview_height = preview.ysize * tile_size;
2506 int real_preview_xsize = MIN(level_xsize, preview.xsize);
2507 int real_preview_ysize = MIN(level_ysize, preview.ysize);
2508 int real_preview_width = real_preview_xsize * tile_size;
2509 int real_preview_height = real_preview_ysize * tile_size;
2510 int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
2511 int dst_y = SY + ALIGNED_YPOS(preview.y, preview_height, preview.valign);
2514 if (!IN_GFX_FIELD_FULL(dst_x, dst_y + preview_height - 1))
2517 DrawBackground(dst_x, dst_y, preview_width, preview_height);
2519 dst_x += (preview_width - real_preview_width) / 2;
2520 dst_y += (preview_height - real_preview_height) / 2;
2522 for (x = 0; x < real_preview_xsize; x++)
2524 for (y = 0; y < real_preview_ysize; y++)
2526 int lx = from_x + x + (show_level_border ? -1 : 0);
2527 int ly = from_y + y + (show_level_border ? -1 : 0);
2528 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
2529 getBorderElement(lx, ly));
2531 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
2532 element, tile_size);
2536 redraw_mask |= REDRAW_MICROLEVEL;
2539 #define MICROLABEL_EMPTY 0
2540 #define MICROLABEL_LEVEL_NAME 1
2541 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
2542 #define MICROLABEL_LEVEL_AUTHOR 3
2543 #define MICROLABEL_IMPORTED_FROM_HEAD 4
2544 #define MICROLABEL_IMPORTED_FROM 5
2545 #define MICROLABEL_IMPORTED_BY_HEAD 6
2546 #define MICROLABEL_IMPORTED_BY 7
2548 static int getMaxTextLength(struct TextPosInfo *pos, int font_nr)
2550 int max_text_width = SXSIZE;
2551 int font_width = getFontWidth(font_nr);
2553 if (pos->align == ALIGN_CENTER)
2554 max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
2555 else if (pos->align == ALIGN_RIGHT)
2556 max_text_width = pos->x;
2558 max_text_width = SXSIZE - pos->x;
2560 return max_text_width / font_width;
2563 static void DrawPreviewLevelLabelExt(int mode)
2565 struct TextPosInfo *pos = &menu.main.text.level_info_2;
2566 char label_text[MAX_OUTPUT_LINESIZE + 1];
2567 int max_len_label_text;
2568 int font_nr = pos->font;
2571 if (!IN_GFX_FIELD_FULL(pos->x, pos->y + getFontHeight(pos->font)))
2574 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
2575 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
2576 mode == MICROLABEL_IMPORTED_BY_HEAD)
2577 font_nr = pos->font_alt;
2579 max_len_label_text = getMaxTextLength(pos, font_nr);
2581 if (pos->size != -1)
2582 max_len_label_text = pos->size;
2584 for (i = 0; i < max_len_label_text; i++)
2585 label_text[i] = ' ';
2586 label_text[max_len_label_text] = '\0';
2588 if (strlen(label_text) > 0)
2589 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2592 (mode == MICROLABEL_LEVEL_NAME ? level.name :
2593 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
2594 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
2595 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
2596 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
2597 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
2598 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
2599 max_len_label_text);
2600 label_text[max_len_label_text] = '\0';
2602 if (strlen(label_text) > 0)
2603 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2605 redraw_mask |= REDRAW_MICROLEVEL;
2608 static void DrawPreviewLevelExt(boolean restart)
2610 static unsigned int scroll_delay = 0;
2611 static unsigned int label_delay = 0;
2612 static int from_x, from_y, scroll_direction;
2613 static int label_state, label_counter;
2614 unsigned int scroll_delay_value = preview.step_delay;
2615 boolean show_level_border = (BorderElement != EL_EMPTY);
2616 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2617 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2618 int last_game_status = game_status; /* save current game status */
2625 if (preview.anim_mode == ANIM_CENTERED)
2627 if (level_xsize > preview.xsize)
2628 from_x = (level_xsize - preview.xsize) / 2;
2629 if (level_ysize > preview.ysize)
2630 from_y = (level_ysize - preview.ysize) / 2;
2633 from_x += preview.xoffset;
2634 from_y += preview.yoffset;
2636 scroll_direction = MV_RIGHT;
2640 DrawPreviewLevelPlayfieldExt(from_x, from_y);
2641 DrawPreviewLevelLabelExt(label_state);
2643 /* initialize delay counters */
2644 DelayReached(&scroll_delay, 0);
2645 DelayReached(&label_delay, 0);
2647 if (leveldir_current->name)
2649 struct TextPosInfo *pos = &menu.main.text.level_info_1;
2650 char label_text[MAX_OUTPUT_LINESIZE + 1];
2651 int font_nr = pos->font;
2652 int max_len_label_text = getMaxTextLength(pos, font_nr);
2654 if (pos->size != -1)
2655 max_len_label_text = pos->size;
2657 strncpy(label_text, leveldir_current->name, max_len_label_text);
2658 label_text[max_len_label_text] = '\0';
2660 if (IN_GFX_FIELD_FULL(pos->x, pos->y + getFontHeight(pos->font)))
2661 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2664 game_status = last_game_status; /* restore current game status */
2669 /* scroll preview level, if needed */
2670 if (preview.anim_mode != ANIM_NONE &&
2671 (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
2672 DelayReached(&scroll_delay, scroll_delay_value))
2674 switch (scroll_direction)
2679 from_x -= preview.step_offset;
2680 from_x = (from_x < 0 ? 0 : from_x);
2683 scroll_direction = MV_UP;
2687 if (from_x < level_xsize - preview.xsize)
2689 from_x += preview.step_offset;
2690 from_x = (from_x > level_xsize - preview.xsize ?
2691 level_xsize - preview.xsize : from_x);
2694 scroll_direction = MV_DOWN;
2700 from_y -= preview.step_offset;
2701 from_y = (from_y < 0 ? 0 : from_y);
2704 scroll_direction = MV_RIGHT;
2708 if (from_y < level_ysize - preview.ysize)
2710 from_y += preview.step_offset;
2711 from_y = (from_y > level_ysize - preview.ysize ?
2712 level_ysize - preview.ysize : from_y);
2715 scroll_direction = MV_LEFT;
2722 DrawPreviewLevelPlayfieldExt(from_x, from_y);
2725 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
2726 /* redraw micro level label, if needed */
2727 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
2728 !strEqual(level.author, ANONYMOUS_NAME) &&
2729 !strEqual(level.author, leveldir_current->name) &&
2730 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
2732 int max_label_counter = 23;
2734 if (leveldir_current->imported_from != NULL &&
2735 strlen(leveldir_current->imported_from) > 0)
2736 max_label_counter += 14;
2737 if (leveldir_current->imported_by != NULL &&
2738 strlen(leveldir_current->imported_by) > 0)
2739 max_label_counter += 14;
2741 label_counter = (label_counter + 1) % max_label_counter;
2742 label_state = (label_counter >= 0 && label_counter <= 7 ?
2743 MICROLABEL_LEVEL_NAME :
2744 label_counter >= 9 && label_counter <= 12 ?
2745 MICROLABEL_LEVEL_AUTHOR_HEAD :
2746 label_counter >= 14 && label_counter <= 21 ?
2747 MICROLABEL_LEVEL_AUTHOR :
2748 label_counter >= 23 && label_counter <= 26 ?
2749 MICROLABEL_IMPORTED_FROM_HEAD :
2750 label_counter >= 28 && label_counter <= 35 ?
2751 MICROLABEL_IMPORTED_FROM :
2752 label_counter >= 37 && label_counter <= 40 ?
2753 MICROLABEL_IMPORTED_BY_HEAD :
2754 label_counter >= 42 && label_counter <= 49 ?
2755 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
2757 if (leveldir_current->imported_from == NULL &&
2758 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
2759 label_state == MICROLABEL_IMPORTED_FROM))
2760 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
2761 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
2763 DrawPreviewLevelLabelExt(label_state);
2766 game_status = last_game_status; /* restore current game status */
2769 void DrawPreviewLevelInitial()
2771 DrawPreviewLevelExt(TRUE);
2774 void DrawPreviewLevelAnimation()
2776 DrawPreviewLevelExt(FALSE);
2779 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
2780 int graphic, int sync_frame, int mask_mode)
2782 int frame = getGraphicAnimationFrame(graphic, sync_frame);
2784 if (mask_mode == USE_MASKING)
2785 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
2787 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
2790 inline void DrawFixedGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
2791 int graphic, int sync_frame,
2794 int frame = getGraphicAnimationFrame(graphic, sync_frame);
2796 if (mask_mode == USE_MASKING)
2797 DrawFixedGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
2799 DrawFixedGraphicExt(dst_bitmap, x, y, graphic, frame);
2802 inline void DrawGraphicAnimation(int x, int y, int graphic)
2804 int lx = LEVELX(x), ly = LEVELY(y);
2806 if (!IN_SCR_FIELD(x, y))
2809 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
2810 graphic, GfxFrame[lx][ly], NO_MASKING);
2812 MarkTileDirty(x, y);
2815 inline void DrawFixedGraphicAnimation(int x, int y, int graphic)
2817 int lx = LEVELX(x), ly = LEVELY(y);
2819 if (!IN_SCR_FIELD(x, y))
2822 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
2823 graphic, GfxFrame[lx][ly], NO_MASKING);
2824 MarkTileDirty(x, y);
2827 void DrawLevelGraphicAnimation(int x, int y, int graphic)
2829 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2832 void DrawLevelElementAnimation(int x, int y, int element)
2834 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2836 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2839 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
2841 int sx = SCREENX(x), sy = SCREENY(y);
2843 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2846 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2849 DrawGraphicAnimation(sx, sy, graphic);
2852 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
2853 DrawLevelFieldCrumbled(x, y);
2855 if (GFX_CRUMBLED(Feld[x][y]))
2856 DrawLevelFieldCrumbled(x, y);
2860 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
2862 int sx = SCREENX(x), sy = SCREENY(y);
2865 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2868 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2870 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2873 DrawGraphicAnimation(sx, sy, graphic);
2875 if (GFX_CRUMBLED(element))
2876 DrawLevelFieldCrumbled(x, y);
2879 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
2881 if (player->use_murphy)
2883 /* this works only because currently only one player can be "murphy" ... */
2884 static int last_horizontal_dir = MV_LEFT;
2885 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
2887 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2888 last_horizontal_dir = move_dir;
2890 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
2892 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
2894 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
2900 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
2903 static boolean equalGraphics(int graphic1, int graphic2)
2905 struct GraphicInfo *g1 = &graphic_info[graphic1];
2906 struct GraphicInfo *g2 = &graphic_info[graphic2];
2908 return (g1->bitmap == g2->bitmap &&
2909 g1->src_x == g2->src_x &&
2910 g1->src_y == g2->src_y &&
2911 g1->anim_frames == g2->anim_frames &&
2912 g1->anim_delay == g2->anim_delay &&
2913 g1->anim_mode == g2->anim_mode);
2916 void DrawAllPlayers()
2920 for (i = 0; i < MAX_PLAYERS; i++)
2921 if (stored_player[i].active)
2922 DrawPlayer(&stored_player[i]);
2925 void DrawPlayerField(int x, int y)
2927 if (!IS_PLAYER(x, y))
2930 DrawPlayer(PLAYERINFO(x, y));
2933 #define DRAW_PLAYER_OVER_PUSHED_ELEMENT 1
2935 void DrawPlayer(struct PlayerInfo *player)
2937 int jx = player->jx;
2938 int jy = player->jy;
2939 int move_dir = player->MovDir;
2940 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
2941 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
2942 int last_jx = (player->is_moving ? jx - dx : jx);
2943 int last_jy = (player->is_moving ? jy - dy : jy);
2944 int next_jx = jx + dx;
2945 int next_jy = jy + dy;
2946 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
2947 boolean player_is_opaque = FALSE;
2948 int sx = SCREENX(jx), sy = SCREENY(jy);
2949 int sxx = 0, syy = 0;
2950 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
2952 int action = ACTION_DEFAULT;
2953 int last_player_graphic = getPlayerGraphic(player, move_dir);
2954 int last_player_frame = player->Frame;
2957 /* GfxElement[][] is set to the element the player is digging or collecting;
2958 remove also for off-screen player if the player is not moving anymore */
2959 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
2960 GfxElement[jx][jy] = EL_UNDEFINED;
2962 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
2966 if (!IN_LEV_FIELD(jx, jy))
2968 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
2969 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
2970 printf("DrawPlayerField(): This should never happen!\n");
2975 if (element == EL_EXPLOSION)
2978 action = (player->is_pushing ? ACTION_PUSHING :
2979 player->is_digging ? ACTION_DIGGING :
2980 player->is_collecting ? ACTION_COLLECTING :
2981 player->is_moving ? ACTION_MOVING :
2982 player->is_snapping ? ACTION_SNAPPING :
2983 player->is_dropping ? ACTION_DROPPING :
2984 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
2986 if (player->is_waiting)
2987 move_dir = player->dir_waiting;
2989 InitPlayerGfxAnimation(player, action, move_dir);
2991 /* ----------------------------------------------------------------------- */
2992 /* draw things in the field the player is leaving, if needed */
2993 /* ----------------------------------------------------------------------- */
2995 if (player->is_moving)
2997 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
2999 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
3001 if (last_element == EL_DYNAMITE_ACTIVE ||
3002 last_element == EL_EM_DYNAMITE_ACTIVE ||
3003 last_element == EL_SP_DISK_RED_ACTIVE)
3004 DrawDynamite(last_jx, last_jy);
3006 DrawLevelFieldThruMask(last_jx, last_jy);
3008 else if (last_element == EL_DYNAMITE_ACTIVE ||
3009 last_element == EL_EM_DYNAMITE_ACTIVE ||
3010 last_element == EL_SP_DISK_RED_ACTIVE)
3011 DrawDynamite(last_jx, last_jy);
3013 /* !!! this is not enough to prevent flickering of players which are
3014 moving next to each others without a free tile between them -- this
3015 can only be solved by drawing all players layer by layer (first the
3016 background, then the foreground etc.) !!! => TODO */
3017 else if (!IS_PLAYER(last_jx, last_jy))
3018 DrawLevelField(last_jx, last_jy);
3021 DrawLevelField(last_jx, last_jy);
3024 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
3025 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
3028 if (!IN_SCR_FIELD(sx, sy))
3031 /* ----------------------------------------------------------------------- */
3032 /* draw things behind the player, if needed */
3033 /* ----------------------------------------------------------------------- */
3036 DrawLevelElement(jx, jy, Back[jx][jy]);
3037 else if (IS_ACTIVE_BOMB(element))
3038 DrawLevelElement(jx, jy, EL_EMPTY);
3041 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
3043 int old_element = GfxElement[jx][jy];
3044 int old_graphic = el_act_dir2img(old_element, action, move_dir);
3045 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
3047 if (GFX_CRUMBLED(old_element))
3048 DrawLevelFieldCrumbledDigging(jx, jy, move_dir, player->StepFrame);
3050 DrawGraphic(sx, sy, old_graphic, frame);
3052 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
3053 player_is_opaque = TRUE;
3057 GfxElement[jx][jy] = EL_UNDEFINED;
3059 /* make sure that pushed elements are drawn with correct frame rate */
3060 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
3062 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
3063 GfxFrame[jx][jy] = player->StepFrame;
3065 DrawLevelField(jx, jy);
3069 #if !DRAW_PLAYER_OVER_PUSHED_ELEMENT
3070 /* ----------------------------------------------------------------------- */
3071 /* draw player himself */
3072 /* ----------------------------------------------------------------------- */
3074 graphic = getPlayerGraphic(player, move_dir);
3076 /* in the case of changed player action or direction, prevent the current
3077 animation frame from being restarted for identical animations */
3078 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
3079 player->Frame = last_player_frame;
3081 frame = getGraphicAnimationFrame(graphic, player->Frame);
3085 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3086 sxx = player->GfxPos;
3088 syy = player->GfxPos;
3091 if (player_is_opaque)
3092 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
3094 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3096 if (SHIELD_ON(player))
3098 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
3099 IMG_SHIELD_NORMAL_ACTIVE);
3100 int frame = getGraphicAnimationFrame(graphic, -1);
3102 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3106 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
3109 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3110 sxx = player->GfxPos;
3112 syy = player->GfxPos;
3116 /* ----------------------------------------------------------------------- */
3117 /* draw things the player is pushing, if needed */
3118 /* ----------------------------------------------------------------------- */
3120 if (player->is_pushing && player->is_moving)
3122 int px = SCREENX(jx), py = SCREENY(jy);
3123 int pxx = (TILEX - ABS(sxx)) * dx;
3124 int pyy = (TILEY - ABS(syy)) * dy;
3125 int gfx_frame = GfxFrame[jx][jy];
3131 if (!IS_MOVING(jx, jy)) /* push movement already finished */
3133 element = Feld[next_jx][next_jy];
3134 gfx_frame = GfxFrame[next_jx][next_jy];
3137 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
3139 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
3140 frame = getGraphicAnimationFrame(graphic, sync_frame);
3142 /* draw background element under pushed element (like the Sokoban field) */
3143 if (game.use_masked_pushing && IS_MOVING(jx, jy))
3145 /* this allows transparent pushing animation over non-black background */
3148 DrawLevelElement(jx, jy, Back[jx][jy]);
3150 DrawLevelElement(jx, jy, EL_EMPTY);
3152 if (Back[next_jx][next_jy])
3153 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3155 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
3157 else if (Back[next_jx][next_jy])
3158 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3161 /* do not draw (EM style) pushing animation when pushing is finished */
3162 /* (two-tile animations usually do not contain start and end frame) */
3163 if (graphic_info[graphic].double_movement && !IS_MOVING(jx, jy))
3164 DrawLevelElement(next_jx, next_jy, Feld[next_jx][next_jy]);
3166 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3168 /* masked drawing is needed for EMC style (double) movement graphics */
3169 /* !!! (ONLY WHEN DRAWING PUSHED ELEMENT OVER THE PLAYER) !!! */
3170 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3174 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
3175 /* ----------------------------------------------------------------------- */
3176 /* draw player himself */
3177 /* ----------------------------------------------------------------------- */
3179 graphic = getPlayerGraphic(player, move_dir);
3181 /* in the case of changed player action or direction, prevent the current
3182 animation frame from being restarted for identical animations */
3183 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
3184 player->Frame = last_player_frame;
3186 frame = getGraphicAnimationFrame(graphic, player->Frame);
3190 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3191 sxx = player->GfxPos;
3193 syy = player->GfxPos;
3196 if (player_is_opaque)
3197 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
3199 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3201 if (SHIELD_ON(player))
3203 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
3204 IMG_SHIELD_NORMAL_ACTIVE);
3205 int frame = getGraphicAnimationFrame(graphic, -1);
3207 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3211 /* ----------------------------------------------------------------------- */
3212 /* draw things in front of player (active dynamite or dynabombs) */
3213 /* ----------------------------------------------------------------------- */
3215 if (IS_ACTIVE_BOMB(element))
3217 graphic = el2img(element);
3218 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
3220 if (game.emulation == EMU_SUPAPLEX)
3221 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
3223 DrawGraphicThruMask(sx, sy, graphic, frame);
3226 if (player_is_moving && last_element == EL_EXPLOSION)
3228 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
3229 GfxElement[last_jx][last_jy] : EL_EMPTY);
3230 int graphic = el_act2img(element, ACTION_EXPLODING);
3231 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
3232 int phase = ExplodePhase[last_jx][last_jy] - 1;
3233 int frame = getGraphicAnimationFrame(graphic, phase - delay);
3236 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
3239 /* ----------------------------------------------------------------------- */
3240 /* draw elements the player is just walking/passing through/under */
3241 /* ----------------------------------------------------------------------- */
3243 if (player_is_moving)
3245 /* handle the field the player is leaving ... */
3246 if (IS_ACCESSIBLE_INSIDE(last_element))
3247 DrawLevelField(last_jx, last_jy);
3248 else if (IS_ACCESSIBLE_UNDER(last_element))
3249 DrawLevelFieldThruMask(last_jx, last_jy);
3252 /* do not redraw accessible elements if the player is just pushing them */
3253 if (!player_is_moving || !player->is_pushing)
3255 /* ... and the field the player is entering */
3256 if (IS_ACCESSIBLE_INSIDE(element))
3257 DrawLevelField(jx, jy);
3258 else if (IS_ACCESSIBLE_UNDER(element))
3259 DrawLevelFieldThruMask(jx, jy);
3262 MarkTileDirty(sx, sy);
3265 /* ------------------------------------------------------------------------- */
3267 void WaitForEventToContinue()
3269 boolean still_wait = TRUE;
3271 /* simulate releasing mouse button over last gadget, if still pressed */
3273 HandleGadgets(-1, -1, 0);
3275 button_status = MB_RELEASED;
3289 case EVENT_BUTTONPRESS:
3290 case EVENT_KEYPRESS:
3294 case EVENT_KEYRELEASE:
3295 ClearPlayerAction();
3299 HandleOtherEvents(&event);
3303 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3310 /* don't eat all CPU time */
3315 #define MAX_REQUEST_LINES 13
3316 #define MAX_REQUEST_LINE_FONT1_LEN 7
3317 #define MAX_REQUEST_LINE_FONT2_LEN 10
3319 static int RequestHandleEvents(unsigned int req_state)
3321 boolean level_solved = (game_status == GAME_MODE_PLAYING &&
3322 local_player->LevelSolved_GameEnd);
3323 int last_game_status = game_status; /* save current game status */
3324 int width = request.width;
3325 int height = request.height;
3329 setRequestPosition(&sx, &sy, FALSE);
3331 button_status = MB_RELEASED;
3333 request_gadget_id = -1;
3340 SetDrawtoField(DRAW_FIELDBUFFER);
3342 HandleGameActions();
3344 SetDrawtoField(DRAW_BACKBUFFER);
3346 if (global.use_envelope_request)
3348 /* copy current state of request area to middle of playfield area */
3349 BlitBitmap(bitmap_db_cross, drawto, sx, sy, width, height, sx, sy);
3357 while (NextValidEvent(&event))
3361 case EVENT_BUTTONPRESS:
3362 case EVENT_BUTTONRELEASE:
3363 case EVENT_MOTIONNOTIFY:
3367 if (event.type == EVENT_MOTIONNOTIFY)
3372 motion_status = TRUE;
3373 mx = ((MotionEvent *) &event)->x;
3374 my = ((MotionEvent *) &event)->y;
3378 motion_status = FALSE;
3379 mx = ((ButtonEvent *) &event)->x;
3380 my = ((ButtonEvent *) &event)->y;
3381 if (event.type == EVENT_BUTTONPRESS)
3382 button_status = ((ButtonEvent *) &event)->button;
3384 button_status = MB_RELEASED;
3387 /* this sets 'request_gadget_id' */
3388 HandleGadgets(mx, my, button_status);
3390 switch (request_gadget_id)
3392 case TOOL_CTRL_ID_YES:
3395 case TOOL_CTRL_ID_NO:
3398 case TOOL_CTRL_ID_CONFIRM:
3399 result = TRUE | FALSE;
3402 case TOOL_CTRL_ID_PLAYER_1:
3405 case TOOL_CTRL_ID_PLAYER_2:
3408 case TOOL_CTRL_ID_PLAYER_3:
3411 case TOOL_CTRL_ID_PLAYER_4:
3422 case EVENT_KEYPRESS:
3423 switch (GetEventKey((KeyEvent *)&event, TRUE))
3426 if (req_state & REQ_CONFIRM)
3431 #if defined(TARGET_SDL2)
3438 #if defined(TARGET_SDL2)
3448 if (req_state & REQ_PLAYER)
3452 case EVENT_KEYRELEASE:
3453 ClearPlayerAction();
3457 HandleOtherEvents(&event);
3462 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3464 int joy = AnyJoystick();
3466 if (joy & JOY_BUTTON_1)
3468 else if (joy & JOY_BUTTON_2)
3474 if (global.use_envelope_request)
3476 /* copy back current state of pressed buttons inside request area */
3477 BlitBitmap(drawto, bitmap_db_cross, sx, sy, width, height, sx, sy);
3484 if (!PendingEvent()) /* delay only if no pending events */
3488 game_status = GAME_MODE_PSEUDO_DOOR;
3492 game_status = last_game_status; /* restore current game status */
3498 static boolean RequestDoor(char *text, unsigned int req_state)
3500 unsigned int old_door_state;
3501 int last_game_status = game_status; /* save current game status */
3502 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
3503 int font_nr = FONT_TEXT_2;
3508 if (maxWordLengthInString(text) > MAX_REQUEST_LINE_FONT1_LEN)
3510 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
3511 font_nr = FONT_TEXT_1;
3514 if (game_status == GAME_MODE_PLAYING)
3515 BlitScreenToBitmap(backbuffer);
3517 /* disable deactivated drawing when quick-loading level tape recording */
3518 if (tape.playing && tape.deactivate_display)
3519 TapeDeactivateDisplayOff(TRUE);
3521 SetMouseCursor(CURSOR_DEFAULT);
3523 #if defined(NETWORK_AVALIABLE)
3524 /* pause network game while waiting for request to answer */
3525 if (options.network &&
3526 game_status == GAME_MODE_PLAYING &&
3527 req_state & REQUEST_WAIT_FOR_INPUT)
3528 SendToServer_PausePlaying();
3531 old_door_state = GetDoorState();
3533 /* simulate releasing mouse button over last gadget, if still pressed */
3535 HandleGadgets(-1, -1, 0);
3539 /* draw released gadget before proceeding */
3542 if (old_door_state & DOOR_OPEN_1)
3544 CloseDoor(DOOR_CLOSE_1);
3546 /* save old door content */
3547 BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
3548 0 * DXSIZE, 0, DXSIZE, DYSIZE, 1 * DXSIZE, 0);
3551 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
3552 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3554 /* clear door drawing field */
3555 DrawBackground(DX, DY, DXSIZE, DYSIZE);
3557 /* force DOOR font inside door area */
3558 game_status = GAME_MODE_PSEUDO_DOOR;
3560 /* write text for request */
3561 for (text_ptr = text, ty = 0; ty < MAX_REQUEST_LINES; ty++)
3563 char text_line[max_request_line_len + 1];
3569 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
3571 tc = *(text_ptr + tx);
3572 // if (!tc || tc == ' ')
3573 if (!tc || tc == ' ' || tc == '?' || tc == '!')
3577 if ((tc == '?' || tc == '!') && tl == 0)
3587 strncpy(text_line, text_ptr, tl);
3590 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
3591 DY + 8 + ty * (getFontHeight(font_nr) + 2),
3592 text_line, font_nr);
3594 text_ptr += tl + (tc == ' ' ? 1 : 0);
3595 // text_ptr += tl + (tc == ' ' || tc == '?' || tc == '!' ? 1 : 0);
3598 game_status = last_game_status; /* restore current game status */
3600 if (req_state & REQ_ASK)
3602 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
3603 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
3605 else if (req_state & REQ_CONFIRM)
3607 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
3609 else if (req_state & REQ_PLAYER)
3611 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
3612 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
3613 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
3614 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
3617 /* copy request gadgets to door backbuffer */
3618 BlitBitmap(drawto, bitmap_db_door_1, DX, DY, DXSIZE, DYSIZE, 0, 0);
3620 OpenDoor(DOOR_OPEN_1);
3622 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
3624 if (game_status == GAME_MODE_PLAYING)
3626 SetPanelBackground();
3627 SetDrawBackgroundMask(REDRAW_DOOR_1);
3631 SetDrawBackgroundMask(REDRAW_FIELD);
3637 if (game_status != GAME_MODE_MAIN)
3640 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3642 // ---------- handle request buttons ----------
3643 result = RequestHandleEvents(req_state);
3645 if (game_status != GAME_MODE_MAIN)
3650 if (!(req_state & REQ_STAY_OPEN))
3652 CloseDoor(DOOR_CLOSE_1);
3654 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
3655 (req_state & REQ_REOPEN))
3656 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
3661 if (game_status == GAME_MODE_PLAYING)
3663 SetPanelBackground();
3664 SetDrawBackgroundMask(REDRAW_DOOR_1);
3668 SetDrawBackgroundMask(REDRAW_FIELD);
3671 #if defined(NETWORK_AVALIABLE)
3672 /* continue network game after request */
3673 if (options.network &&
3674 game_status == GAME_MODE_PLAYING &&
3675 req_state & REQUEST_WAIT_FOR_INPUT)
3676 SendToServer_ContinuePlaying();
3679 /* restore deactivated drawing when quick-loading level tape recording */
3680 if (tape.playing && tape.deactivate_display)
3681 TapeDeactivateDisplayOn();
3686 static boolean RequestEnvelope(char *text, unsigned int req_state)
3690 if (game_status == GAME_MODE_PLAYING)
3691 BlitScreenToBitmap(backbuffer);
3693 /* disable deactivated drawing when quick-loading level tape recording */
3694 if (tape.playing && tape.deactivate_display)
3695 TapeDeactivateDisplayOff(TRUE);
3697 SetMouseCursor(CURSOR_DEFAULT);
3699 #if defined(NETWORK_AVALIABLE)
3700 /* pause network game while waiting for request to answer */
3701 if (options.network &&
3702 game_status == GAME_MODE_PLAYING &&
3703 req_state & REQUEST_WAIT_FOR_INPUT)
3704 SendToServer_PausePlaying();
3707 /* simulate releasing mouse button over last gadget, if still pressed */
3709 HandleGadgets(-1, -1, 0);
3713 // (replace with setting corresponding request background)
3714 // SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
3715 // SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3717 /* clear door drawing field */
3718 // DrawBackground(DX, DY, DXSIZE, DYSIZE);
3720 ShowEnvelopeRequest(text, req_state, ACTION_OPENING);
3722 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
3724 if (game_status == GAME_MODE_PLAYING)
3726 SetPanelBackground();
3727 SetDrawBackgroundMask(REDRAW_DOOR_1);
3731 SetDrawBackgroundMask(REDRAW_FIELD);
3737 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3739 // ---------- handle request buttons ----------
3740 result = RequestHandleEvents(req_state);
3742 if (game_status != GAME_MODE_MAIN)
3747 ShowEnvelopeRequest(text, req_state, ACTION_CLOSING);
3751 if (game_status == GAME_MODE_PLAYING)
3753 SetPanelBackground();
3754 SetDrawBackgroundMask(REDRAW_DOOR_1);
3758 SetDrawBackgroundMask(REDRAW_FIELD);
3761 #if defined(NETWORK_AVALIABLE)
3762 /* continue network game after request */
3763 if (options.network &&
3764 game_status == GAME_MODE_PLAYING &&
3765 req_state & REQUEST_WAIT_FOR_INPUT)
3766 SendToServer_ContinuePlaying();
3769 /* restore deactivated drawing when quick-loading level tape recording */
3770 if (tape.playing && tape.deactivate_display)
3771 TapeDeactivateDisplayOn();
3776 boolean Request(char *text, unsigned int req_state)
3778 if (global.use_envelope_request)
3779 return RequestEnvelope(text, req_state);
3781 return RequestDoor(text, req_state);
3784 static int compareDoorPartOrderInfo(const void *object1, const void *object2)
3786 const struct DoorPartOrderInfo *dpo1 = (struct DoorPartOrderInfo *)object1;
3787 const struct DoorPartOrderInfo *dpo2 = (struct DoorPartOrderInfo *)object2;
3790 if (dpo1->sort_priority != dpo2->sort_priority)
3791 compare_result = dpo1->sort_priority - dpo2->sort_priority;
3793 compare_result = dpo1->nr - dpo2->nr;
3795 return compare_result;
3798 void InitGraphicCompatibilityInfo_Doors()
3804 struct DoorInfo *door;
3808 { DOOR_1, IMG_DOOR_1_GFX_PART_1, IMG_DOOR_1_GFX_PART_8, &door_1 },
3809 { DOOR_2, IMG_DOOR_2_GFX_PART_1, IMG_DOOR_2_GFX_PART_8, &door_2 },
3811 { -1, -1, -1, NULL }
3813 struct Rect door_rect_list[] =
3815 { DX, DY, DXSIZE, DYSIZE },
3816 { VX, VY, VXSIZE, VYSIZE }
3820 for (i = 0; doors[i].door_token != -1; i++)
3822 int door_token = doors[i].door_token;
3823 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
3824 int part_1 = doors[i].part_1;
3825 int part_8 = doors[i].part_8;
3826 int part_2 = part_1 + 1;
3827 int part_3 = part_1 + 2;
3828 struct DoorInfo *door = doors[i].door;
3829 struct Rect *door_rect = &door_rect_list[door_index];
3830 boolean door_gfx_redefined = FALSE;
3832 /* check if any door part graphic definitions have been redefined */
3834 for (j = 0; door_part_controls[j].door_token != -1; j++)
3836 struct DoorPartControlInfo *dpc = &door_part_controls[j];
3837 struct FileInfo *fi = getImageListEntryFromImageID(dpc->graphic);
3839 if (dpc->door_token == door_token && fi->redefined)
3840 door_gfx_redefined = TRUE;
3843 /* check for old-style door graphic/animation modifications */
3845 if (!door_gfx_redefined)
3847 if (door->anim_mode & ANIM_STATIC_PANEL)
3849 door->panel.step_xoffset = 0;
3850 door->panel.step_yoffset = 0;
3853 if (door->anim_mode & (ANIM_HORIZONTAL | ANIM_VERTICAL))
3855 struct GraphicInfo *g_part_1 = &graphic_info[part_1];
3856 struct GraphicInfo *g_part_2 = &graphic_info[part_2];
3857 int num_door_steps, num_panel_steps;
3859 /* remove door part graphics other than the two default wings */
3861 for (j = 0; door_part_controls[j].door_token != -1; j++)
3863 struct DoorPartControlInfo *dpc = &door_part_controls[j];
3864 struct GraphicInfo *g = &graphic_info[dpc->graphic];
3866 if (dpc->graphic >= part_3 &&
3867 dpc->graphic <= part_8)
3871 /* set graphics and screen positions of the default wings */
3873 g_part_1->width = door_rect->width;
3874 g_part_1->height = door_rect->height;
3875 g_part_2->width = door_rect->width;
3876 g_part_2->height = door_rect->height;
3877 g_part_2->src_x = door_rect->width;
3878 g_part_2->src_y = g_part_1->src_y;
3880 door->part_2.x = door->part_1.x;
3881 door->part_2.y = door->part_1.y;
3883 if (door->width != -1)
3885 g_part_1->width = door->width;
3886 g_part_2->width = door->width;
3888 // special treatment for graphics and screen position of right wing
3889 g_part_2->src_x += door_rect->width - door->width;
3890 door->part_2.x += door_rect->width - door->width;
3893 if (door->height != -1)
3895 g_part_1->height = door->height;
3896 g_part_2->height = door->height;
3898 // special treatment for graphics and screen position of bottom wing
3899 g_part_2->src_y += door_rect->height - door->height;
3900 door->part_2.y += door_rect->height - door->height;
3903 /* set animation delays for the default wings and panels */
3905 door->part_1.step_delay = door->step_delay;
3906 door->part_2.step_delay = door->step_delay;
3907 door->panel.step_delay = door->step_delay;
3909 /* set animation draw order for the default wings */
3911 door->part_1.sort_priority = 2; /* draw left wing over ... */
3912 door->part_2.sort_priority = 1; /* ... right wing */
3914 /* set animation draw offset for the default wings */
3916 if (door->anim_mode & ANIM_HORIZONTAL)
3918 door->part_1.step_xoffset = door->step_offset;
3919 door->part_1.step_yoffset = 0;
3920 door->part_2.step_xoffset = door->step_offset * -1;
3921 door->part_2.step_yoffset = 0;
3923 num_door_steps = g_part_1->width / door->step_offset;
3925 else // ANIM_VERTICAL
3927 door->part_1.step_xoffset = 0;
3928 door->part_1.step_yoffset = door->step_offset;
3929 door->part_2.step_xoffset = 0;
3930 door->part_2.step_yoffset = door->step_offset * -1;
3932 num_door_steps = g_part_1->height / door->step_offset;
3935 /* set animation draw offset for the default panels */
3937 if (door->step_offset > 1)
3939 num_panel_steps = 2 * door_rect->height / door->step_offset;
3940 door->panel.start_step = num_panel_steps - num_door_steps;
3941 door->panel.start_step_closing = door->panel.start_step;
3945 num_panel_steps = door_rect->height / door->step_offset;
3946 door->panel.start_step = num_panel_steps - num_door_steps / 2;
3947 door->panel.start_step_closing = door->panel.start_step;
3948 door->panel.step_delay *= 2;
3959 for (i = 0; door_part_controls[i].door_token != -1; i++)
3961 struct DoorPartControlInfo *dpc = &door_part_controls[i];
3962 struct DoorPartOrderInfo *dpo = &door_part_order[i];
3964 /* initialize "start_step_opening" and "start_step_closing", if needed */
3965 if (dpc->pos->start_step_opening == 0 &&
3966 dpc->pos->start_step_closing == 0)
3968 // dpc->pos->start_step_opening = dpc->pos->start_step;
3969 dpc->pos->start_step_closing = dpc->pos->start_step;
3972 /* fill structure for door part draw order (sorted below) */
3974 dpo->sort_priority = dpc->pos->sort_priority;
3977 /* sort door part controls according to sort_priority and graphic number */
3978 qsort(door_part_order, MAX_DOOR_PARTS,
3979 sizeof(struct DoorPartOrderInfo), compareDoorPartOrderInfo);
3982 unsigned int OpenDoor(unsigned int door_state)
3984 if (door_state & DOOR_COPY_BACK)
3986 if (door_state & DOOR_OPEN_1)
3987 BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
3988 1 * DXSIZE, 0, DXSIZE, DYSIZE, 0 * DXSIZE, 0);
3990 if (door_state & DOOR_OPEN_2)
3991 BlitBitmap(bitmap_db_door_2, bitmap_db_door_2,
3992 1 * VXSIZE, 0, VXSIZE, VYSIZE, 0 * VXSIZE, 0);
3994 door_state &= ~DOOR_COPY_BACK;
3997 return MoveDoor(door_state);
4000 unsigned int CloseDoor(unsigned int door_state)
4002 unsigned int old_door_state = GetDoorState();
4004 if (!(door_state & DOOR_NO_COPY_BACK))
4006 if (old_door_state & DOOR_OPEN_1)
4007 BlitBitmap(backbuffer, bitmap_db_door_1,
4008 DX, DY, DXSIZE, DYSIZE, 0, 0);
4010 if (old_door_state & DOOR_OPEN_2)
4011 BlitBitmap(backbuffer, bitmap_db_door_2,
4012 VX, VY, VXSIZE, VYSIZE, 0, 0);
4014 door_state &= ~DOOR_NO_COPY_BACK;
4017 return MoveDoor(door_state);
4020 unsigned int GetDoorState()
4022 return MoveDoor(DOOR_GET_STATE);
4025 unsigned int SetDoorState(unsigned int door_state)
4027 return MoveDoor(door_state | DOOR_SET_STATE);
4030 int euclid(int a, int b)
4032 return (b ? euclid(b, a % b) : a);
4035 unsigned int MoveDoor(unsigned int door_state)
4037 struct Rect door_rect_list[] =
4039 { DX, DY, DXSIZE, DYSIZE },
4040 { VX, VY, VXSIZE, VYSIZE }
4042 static int door1 = DOOR_OPEN_1;
4043 static int door2 = DOOR_CLOSE_2;
4044 unsigned int door_delay = 0;
4045 unsigned int door_delay_value;
4048 if (door_state == DOOR_GET_STATE)
4049 return (door1 | door2);
4051 if (door_state & DOOR_SET_STATE)
4053 if (door_state & DOOR_ACTION_1)
4054 door1 = door_state & DOOR_ACTION_1;
4055 if (door_state & DOOR_ACTION_2)
4056 door2 = door_state & DOOR_ACTION_2;
4058 return (door1 | door2);
4061 if (!(door_state & DOOR_FORCE_REDRAW))
4063 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
4064 door_state &= ~DOOR_OPEN_1;
4065 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
4066 door_state &= ~DOOR_CLOSE_1;
4067 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
4068 door_state &= ~DOOR_OPEN_2;
4069 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
4070 door_state &= ~DOOR_CLOSE_2;
4073 if (global.autoplay_leveldir)
4075 door_state |= DOOR_NO_DELAY;
4076 door_state &= ~DOOR_CLOSE_ALL;
4079 if (game_status == GAME_MODE_EDITOR)
4080 door_state |= DOOR_NO_DELAY;
4082 if (door_state & DOOR_ACTION)
4084 boolean door_panel_drawn[NUM_DOORS];
4085 boolean panel_has_doors[NUM_DOORS];
4086 boolean door_part_skip[MAX_DOOR_PARTS];
4087 boolean door_part_done[MAX_DOOR_PARTS];
4088 boolean door_part_done_all;
4089 int num_steps[MAX_DOOR_PARTS];
4090 int max_move_delay = 0; // delay for complete animations of all doors
4091 int max_step_delay = 0; // delay (ms) between two animation frames
4092 int num_move_steps = 0; // number of animation steps for all doors
4093 int max_move_delay_doors_only = 0; // delay for doors only (no panel)
4094 int num_move_steps_doors_only = 0; // steps for doors only (no panel)
4095 int current_move_delay = 0;
4099 for (i = 0; i < NUM_DOORS; i++)
4100 panel_has_doors[i] = FALSE;
4102 for (i = 0; i < MAX_DOOR_PARTS; i++)
4104 struct DoorPartControlInfo *dpc = &door_part_controls[i];
4105 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4106 int door_token = dpc->door_token;
4108 door_part_done[i] = FALSE;
4109 door_part_skip[i] = (!(door_state & door_token) ||
4113 for (i = 0; i < MAX_DOOR_PARTS; i++)
4115 int nr = door_part_order[i].nr;
4116 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
4117 struct DoorPartPosInfo *pos = dpc->pos;
4118 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4119 int door_token = dpc->door_token;
4120 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
4121 boolean is_panel = DOOR_PART_IS_PANEL(nr);
4122 int step_xoffset = ABS(pos->step_xoffset);
4123 int step_yoffset = ABS(pos->step_yoffset);
4124 int step_delay = pos->step_delay;
4125 int current_door_state = door_state & door_token;
4126 boolean door_opening = ((current_door_state & DOOR_OPEN) != 0);
4127 boolean door_closing = ((current_door_state & DOOR_CLOSE) != 0);
4128 boolean part_opening = (is_panel ? door_closing : door_opening);
4129 int start_step = (part_opening ? pos->start_step_opening :
4130 pos->start_step_closing);
4131 float move_xsize = (step_xoffset ? g->width : 0);
4132 float move_ysize = (step_yoffset ? g->height : 0);
4133 int move_xsteps = (step_xoffset ? ceil(move_xsize / step_xoffset) : 0);
4134 int move_ysteps = (step_yoffset ? ceil(move_ysize / step_yoffset) : 0);
4135 int move_steps = (move_xsteps && move_ysteps ?
4136 MIN(move_xsteps, move_ysteps) :
4137 move_xsteps ? move_xsteps : move_ysteps) - start_step;
4138 int move_delay = move_steps * step_delay;
4140 if (door_part_skip[nr])
4143 max_move_delay = MAX(max_move_delay, move_delay);
4144 max_step_delay = (max_step_delay == 0 ? step_delay :
4145 euclid(max_step_delay, step_delay));
4146 num_steps[nr] = move_steps;
4150 max_move_delay_doors_only = MAX(max_move_delay_doors_only, move_delay);
4152 panel_has_doors[door_index] = TRUE;
4156 max_step_delay = MAX(1, max_step_delay); // prevent division by zero
4158 num_move_steps = max_move_delay / max_step_delay;
4159 num_move_steps_doors_only = max_move_delay_doors_only / max_step_delay;
4161 door_delay_value = max_step_delay;
4163 if ((door_state & DOOR_NO_DELAY) || setup.quick_doors)
4165 start = num_move_steps - 1;
4169 /* opening door sound has priority over simultaneously closing door */
4170 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
4171 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
4172 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
4173 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
4176 for (k = start; k < num_move_steps; k++)
4178 int last_frame = num_move_steps - 1; // last frame of this "for" loop
4180 door_part_done_all = TRUE;
4182 for (i = 0; i < NUM_DOORS; i++)
4183 door_panel_drawn[i] = FALSE;
4185 for (i = 0; i < MAX_DOOR_PARTS; i++)
4187 int nr = door_part_order[i].nr;
4188 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
4189 struct DoorPartPosInfo *pos = dpc->pos;
4190 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4191 int door_token = dpc->door_token;
4192 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
4193 boolean is_panel = DOOR_PART_IS_PANEL(nr);
4194 boolean is_panel_and_door_has_closed = FALSE;
4195 struct Rect *door_rect = &door_rect_list[door_index];
4196 Bitmap *bitmap_db_door = (door_token == DOOR_1 ? bitmap_db_door_1 :
4198 Bitmap *bitmap = (is_panel ? bitmap_db_door : g->bitmap);
4199 int current_door_state = door_state & door_token;
4200 boolean door_opening = ((current_door_state & DOOR_OPEN) != 0);
4201 boolean door_closing = !door_opening;
4202 boolean part_opening = (is_panel ? door_closing : door_opening);
4203 boolean part_closing = !part_opening;
4204 int start_step = (part_opening ? pos->start_step_opening :
4205 pos->start_step_closing);
4206 int step_delay = pos->step_delay;
4207 int step_factor = step_delay / max_step_delay;
4208 int k1 = (step_factor ? k / step_factor + 1 : k);
4209 int k2 = (part_opening ? k1 + start_step : num_steps[nr] - k1);
4210 int kk = MAX(0, k2);
4213 int src_x, src_y, src_xx, src_yy;
4214 int dst_x, dst_y, dst_xx, dst_yy;
4217 if (door_part_skip[nr])
4220 if (!(door_state & door_token))
4228 int k2_door = (door_opening ? k : num_move_steps_doors_only - k - 1);
4229 int kk_door = MAX(0, k2_door);
4230 int sync_frame = kk_door * door_delay_value;
4231 int frame = getGraphicAnimationFrame(dpc->graphic, sync_frame);
4233 getGraphicSource(dpc->graphic, frame, &bitmap, &g_src_x, &g_src_y);
4238 if (!door_panel_drawn[door_index])
4240 ClearRectangle(drawto, door_rect->x, door_rect->y,
4241 door_rect->width, door_rect->height);
4243 door_panel_drawn[door_index] = TRUE;
4246 // draw opening or closing door parts
4248 if (pos->step_xoffset < 0) // door part on right side
4251 dst_xx = pos->x + ABS(kk * pos->step_xoffset);
4254 if (dst_xx + width > door_rect->width)
4255 width = door_rect->width - dst_xx;
4257 else // door part on left side
4260 dst_xx = pos->x - kk * pos->step_xoffset;
4264 src_xx = ABS(dst_xx);
4268 width = g->width - src_xx;
4270 // printf("::: k == %d [%d] \n", k, start_step);
4273 if (pos->step_yoffset < 0) // door part on bottom side
4276 dst_yy = pos->y + ABS(kk * pos->step_yoffset);
4279 if (dst_yy + height > door_rect->height)
4280 height = door_rect->height - dst_yy;
4282 else // door part on top side
4285 dst_yy = pos->y - kk * pos->step_yoffset;
4289 src_yy = ABS(dst_yy);
4293 height = g->height - src_yy;
4296 src_x = g_src_x + src_xx;
4297 src_y = g_src_y + src_yy;
4299 dst_x = door_rect->x + dst_xx;
4300 dst_y = door_rect->y + dst_yy;
4302 is_panel_and_door_has_closed =
4305 panel_has_doors[door_index] &&
4306 k >= num_move_steps_doors_only - 1);
4308 if (width >= 0 && width <= g->width &&
4309 height >= 0 && height <= g->height &&
4310 !is_panel_and_door_has_closed)
4312 if (is_panel || !pos->draw_masked)
4313 BlitBitmap(bitmap, drawto, src_x, src_y, width, height,
4316 BlitBitmapMasked(bitmap, drawto, src_x, src_y, width, height,
4320 redraw_mask |= REDRAW_DOOR_FROM_TOKEN(door_token);
4322 if ((part_opening && (width < 0 || height < 0)) ||
4323 (part_closing && (width >= g->width && height >= g->height)))
4324 door_part_done[nr] = TRUE;
4326 // continue door part animations, but not panel after door has closed
4327 if (!door_part_done[nr] && !is_panel_and_door_has_closed)
4328 door_part_done_all = FALSE;
4331 if (!(door_state & DOOR_NO_DELAY))
4335 if (game_status == GAME_MODE_MAIN)
4338 SkipUntilDelayReached(&door_delay, door_delay_value, &k, last_frame);
4340 current_move_delay += max_step_delay;
4343 if (door_part_done_all)
4348 if (door_state & DOOR_ACTION_1)
4349 door1 = door_state & DOOR_ACTION_1;
4350 if (door_state & DOOR_ACTION_2)
4351 door2 = door_state & DOOR_ACTION_2;
4353 return (door1 | door2);
4356 void DrawSpecialEditorDoor()
4358 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
4359 int top_border_width = gfx1->width;
4360 int top_border_height = gfx1->height;
4361 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
4362 int ex = EX - outer_border;
4363 int ey = EY - outer_border;
4364 int vy = VY - outer_border;
4365 int exsize = EXSIZE + 2 * outer_border;
4367 /* draw bigger level editor toolbox window */
4368 BlitBitmap(gfx1->bitmap, drawto, gfx1->src_x, gfx1->src_y,
4369 top_border_width, top_border_height, ex, ey - top_border_height);
4370 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto, ex, vy,
4371 exsize, EYSIZE - VYSIZE + outer_border, ex, ey);
4373 redraw_mask |= REDRAW_ALL;
4376 void UndrawSpecialEditorDoor()
4378 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
4379 int top_border_width = gfx1->width;
4380 int top_border_height = gfx1->height;
4381 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
4382 int ex = EX - outer_border;
4383 int ey = EY - outer_border;
4384 int ey_top = ey - top_border_height;
4385 int exsize = EXSIZE + 2 * outer_border;
4386 int eysize = EYSIZE + 2 * outer_border;
4388 /* draw normal tape recorder window */
4389 if (graphic_info[IMG_GLOBAL_BORDER].bitmap)
4391 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
4392 ex, ey_top, top_border_width, top_border_height,
4394 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
4395 ex, ey, exsize, eysize, ex, ey);
4399 // if screen background is set to "[NONE]", clear editor toolbox window
4400 ClearRectangle(drawto, ex, ey_top, top_border_width, top_border_height);
4401 ClearRectangle(drawto, ex, ey, exsize, eysize);
4404 redraw_mask |= REDRAW_ALL;
4408 /* ---------- new tool button stuff ---------------------------------------- */
4413 struct TextPosInfo *pos;
4416 } toolbutton_info[NUM_TOOL_BUTTONS] =
4419 IMG_REQUEST_BUTTON_GFX_YES, &request.button.yes,
4420 TOOL_CTRL_ID_YES, "yes"
4423 IMG_REQUEST_BUTTON_GFX_NO, &request.button.no,
4424 TOOL_CTRL_ID_NO, "no"
4427 IMG_REQUEST_BUTTON_GFX_CONFIRM, &request.button.confirm,
4428 TOOL_CTRL_ID_CONFIRM, "confirm"
4431 IMG_REQUEST_BUTTON_GFX_PLAYER_1, &request.button.player_1,
4432 TOOL_CTRL_ID_PLAYER_1, "player 1"
4435 IMG_REQUEST_BUTTON_GFX_PLAYER_2, &request.button.player_2,
4436 TOOL_CTRL_ID_PLAYER_2, "player 2"
4439 IMG_REQUEST_BUTTON_GFX_PLAYER_3, &request.button.player_3,
4440 TOOL_CTRL_ID_PLAYER_3, "player 3"
4443 IMG_REQUEST_BUTTON_GFX_PLAYER_4, &request.button.player_4,
4444 TOOL_CTRL_ID_PLAYER_4, "player 4"
4448 void CreateToolButtons()
4452 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4454 struct GraphicInfo *gfx = &graphic_info[toolbutton_info[i].graphic];
4455 struct TextPosInfo *pos = toolbutton_info[i].pos;
4456 struct GadgetInfo *gi;
4457 Bitmap *deco_bitmap = None;
4458 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
4459 unsigned int event_mask = GD_EVENT_RELEASED;
4462 int gd_x = gfx->src_x;
4463 int gd_y = gfx->src_y;
4464 int gd_xp = gfx->src_x + gfx->pressed_xoffset;
4465 int gd_yp = gfx->src_y + gfx->pressed_yoffset;
4468 if (global.use_envelope_request)
4469 setRequestPosition(&dx, &dy, TRUE);
4471 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
4473 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
4475 getSizedGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr), 0,
4476 pos->size, &deco_bitmap, &deco_x, &deco_y);
4477 deco_xpos = (gfx->width - pos->size) / 2;
4478 deco_ypos = (gfx->height - pos->size) / 2;
4481 gi = CreateGadget(GDI_CUSTOM_ID, id,
4482 GDI_INFO_TEXT, toolbutton_info[i].infotext,
4483 GDI_X, dx + GDI_ACTIVE_POS(pos->x),
4484 GDI_Y, dy + GDI_ACTIVE_POS(pos->y),
4485 GDI_WIDTH, gfx->width,
4486 GDI_HEIGHT, gfx->height,
4487 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
4488 GDI_STATE, GD_BUTTON_UNPRESSED,
4489 GDI_DESIGN_UNPRESSED, gfx->bitmap, gd_x, gd_y,
4490 GDI_DESIGN_PRESSED, gfx->bitmap, gd_xp, gd_yp,
4491 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
4492 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
4493 GDI_DECORATION_SIZE, pos->size, pos->size,
4494 GDI_DECORATION_SHIFTING, 1, 1,
4495 GDI_DIRECT_DRAW, FALSE,
4496 GDI_EVENT_MASK, event_mask,
4497 GDI_CALLBACK_ACTION, HandleToolButtons,
4501 Error(ERR_EXIT, "cannot create gadget");
4503 tool_gadget[id] = gi;
4507 void FreeToolButtons()
4511 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4512 FreeGadget(tool_gadget[i]);
4515 static void UnmapToolButtons()
4519 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4520 UnmapGadget(tool_gadget[i]);
4523 static void HandleToolButtons(struct GadgetInfo *gi)
4525 request_gadget_id = gi->custom_id;
4528 static struct Mapping_EM_to_RND_object
4531 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
4532 boolean is_backside; /* backside of moving element */
4538 em_object_mapping_list[] =
4541 Xblank, TRUE, FALSE,
4545 Yacid_splash_eB, FALSE, FALSE,
4546 EL_ACID_SPLASH_RIGHT, -1, -1
4549 Yacid_splash_wB, FALSE, FALSE,
4550 EL_ACID_SPLASH_LEFT, -1, -1
4553 #ifdef EM_ENGINE_BAD_ROLL
4555 Xstone_force_e, FALSE, FALSE,
4556 EL_ROCK, -1, MV_BIT_RIGHT
4559 Xstone_force_w, FALSE, FALSE,
4560 EL_ROCK, -1, MV_BIT_LEFT
4563 Xnut_force_e, FALSE, FALSE,
4564 EL_NUT, -1, MV_BIT_RIGHT
4567 Xnut_force_w, FALSE, FALSE,
4568 EL_NUT, -1, MV_BIT_LEFT
4571 Xspring_force_e, FALSE, FALSE,
4572 EL_SPRING, -1, MV_BIT_RIGHT
4575 Xspring_force_w, FALSE, FALSE,
4576 EL_SPRING, -1, MV_BIT_LEFT
4579 Xemerald_force_e, FALSE, FALSE,
4580 EL_EMERALD, -1, MV_BIT_RIGHT
4583 Xemerald_force_w, FALSE, FALSE,
4584 EL_EMERALD, -1, MV_BIT_LEFT
4587 Xdiamond_force_e, FALSE, FALSE,
4588 EL_DIAMOND, -1, MV_BIT_RIGHT
4591 Xdiamond_force_w, FALSE, FALSE,
4592 EL_DIAMOND, -1, MV_BIT_LEFT
4595 Xbomb_force_e, FALSE, FALSE,
4596 EL_BOMB, -1, MV_BIT_RIGHT
4599 Xbomb_force_w, FALSE, FALSE,
4600 EL_BOMB, -1, MV_BIT_LEFT
4602 #endif /* EM_ENGINE_BAD_ROLL */
4605 Xstone, TRUE, FALSE,
4609 Xstone_pause, FALSE, FALSE,
4613 Xstone_fall, FALSE, FALSE,
4617 Ystone_s, FALSE, FALSE,
4618 EL_ROCK, ACTION_FALLING, -1
4621 Ystone_sB, FALSE, TRUE,
4622 EL_ROCK, ACTION_FALLING, -1
4625 Ystone_e, FALSE, FALSE,
4626 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
4629 Ystone_eB, FALSE, TRUE,
4630 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
4633 Ystone_w, FALSE, FALSE,
4634 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
4637 Ystone_wB, FALSE, TRUE,
4638 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
4645 Xnut_pause, FALSE, FALSE,
4649 Xnut_fall, FALSE, FALSE,
4653 Ynut_s, FALSE, FALSE,
4654 EL_NUT, ACTION_FALLING, -1
4657 Ynut_sB, FALSE, TRUE,
4658 EL_NUT, ACTION_FALLING, -1
4661 Ynut_e, FALSE, FALSE,
4662 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
4665 Ynut_eB, FALSE, TRUE,
4666 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
4669 Ynut_w, FALSE, FALSE,
4670 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
4673 Ynut_wB, FALSE, TRUE,
4674 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
4677 Xbug_n, TRUE, FALSE,
4681 Xbug_e, TRUE, FALSE,
4682 EL_BUG_RIGHT, -1, -1
4685 Xbug_s, TRUE, FALSE,
4689 Xbug_w, TRUE, FALSE,
4693 Xbug_gon, FALSE, FALSE,
4697 Xbug_goe, FALSE, FALSE,
4698 EL_BUG_RIGHT, -1, -1
4701 Xbug_gos, FALSE, FALSE,
4705 Xbug_gow, FALSE, FALSE,
4709 Ybug_n, FALSE, FALSE,
4710 EL_BUG, ACTION_MOVING, MV_BIT_UP
4713 Ybug_nB, FALSE, TRUE,
4714 EL_BUG, ACTION_MOVING, MV_BIT_UP
4717 Ybug_e, FALSE, FALSE,
4718 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
4721 Ybug_eB, FALSE, TRUE,
4722 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
4725 Ybug_s, FALSE, FALSE,
4726 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
4729 Ybug_sB, FALSE, TRUE,
4730 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
4733 Ybug_w, FALSE, FALSE,
4734 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
4737 Ybug_wB, FALSE, TRUE,
4738 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
4741 Ybug_w_n, FALSE, FALSE,
4742 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
4745 Ybug_n_e, FALSE, FALSE,
4746 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
4749 Ybug_e_s, FALSE, FALSE,
4750 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
4753 Ybug_s_w, FALSE, FALSE,
4754 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
4757 Ybug_e_n, FALSE, FALSE,
4758 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
4761 Ybug_s_e, FALSE, FALSE,
4762 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
4765 Ybug_w_s, FALSE, FALSE,
4766 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
4769 Ybug_n_w, FALSE, FALSE,
4770 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
4773 Ybug_stone, FALSE, FALSE,
4774 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
4777 Ybug_spring, FALSE, FALSE,
4778 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
4781 Xtank_n, TRUE, FALSE,
4782 EL_SPACESHIP_UP, -1, -1
4785 Xtank_e, TRUE, FALSE,
4786 EL_SPACESHIP_RIGHT, -1, -1
4789 Xtank_s, TRUE, FALSE,
4790 EL_SPACESHIP_DOWN, -1, -1
4793 Xtank_w, TRUE, FALSE,
4794 EL_SPACESHIP_LEFT, -1, -1
4797 Xtank_gon, FALSE, FALSE,
4798 EL_SPACESHIP_UP, -1, -1
4801 Xtank_goe, FALSE, FALSE,
4802 EL_SPACESHIP_RIGHT, -1, -1
4805 Xtank_gos, FALSE, FALSE,
4806 EL_SPACESHIP_DOWN, -1, -1
4809 Xtank_gow, FALSE, FALSE,
4810 EL_SPACESHIP_LEFT, -1, -1
4813 Ytank_n, FALSE, FALSE,
4814 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
4817 Ytank_nB, FALSE, TRUE,
4818 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
4821 Ytank_e, FALSE, FALSE,
4822 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
4825 Ytank_eB, FALSE, TRUE,
4826 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
4829 Ytank_s, FALSE, FALSE,
4830 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
4833 Ytank_sB, FALSE, TRUE,
4834 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
4837 Ytank_w, FALSE, FALSE,
4838 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
4841 Ytank_wB, FALSE, TRUE,
4842 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
4845 Ytank_w_n, FALSE, FALSE,
4846 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
4849 Ytank_n_e, FALSE, FALSE,
4850 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
4853 Ytank_e_s, FALSE, FALSE,
4854 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
4857 Ytank_s_w, FALSE, FALSE,
4858 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
4861 Ytank_e_n, FALSE, FALSE,
4862 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
4865 Ytank_s_e, FALSE, FALSE,
4866 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
4869 Ytank_w_s, FALSE, FALSE,
4870 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
4873 Ytank_n_w, FALSE, FALSE,
4874 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
4877 Ytank_stone, FALSE, FALSE,
4878 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
4881 Ytank_spring, FALSE, FALSE,
4882 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
4885 Xandroid, TRUE, FALSE,
4886 EL_EMC_ANDROID, ACTION_ACTIVE, -1
4889 Xandroid_1_n, FALSE, FALSE,
4890 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
4893 Xandroid_2_n, FALSE, FALSE,
4894 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
4897 Xandroid_1_e, FALSE, FALSE,
4898 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
4901 Xandroid_2_e, FALSE, FALSE,
4902 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
4905 Xandroid_1_w, FALSE, FALSE,
4906 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
4909 Xandroid_2_w, FALSE, FALSE,
4910 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
4913 Xandroid_1_s, FALSE, FALSE,
4914 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
4917 Xandroid_2_s, FALSE, FALSE,
4918 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
4921 Yandroid_n, FALSE, FALSE,
4922 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
4925 Yandroid_nB, FALSE, TRUE,
4926 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
4929 Yandroid_ne, FALSE, FALSE,
4930 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
4933 Yandroid_neB, FALSE, TRUE,
4934 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
4937 Yandroid_e, FALSE, FALSE,
4938 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
4941 Yandroid_eB, FALSE, TRUE,
4942 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
4945 Yandroid_se, FALSE, FALSE,
4946 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
4949 Yandroid_seB, FALSE, TRUE,
4950 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
4953 Yandroid_s, FALSE, FALSE,
4954 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
4957 Yandroid_sB, FALSE, TRUE,
4958 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
4961 Yandroid_sw, FALSE, FALSE,
4962 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
4965 Yandroid_swB, FALSE, TRUE,
4966 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
4969 Yandroid_w, FALSE, FALSE,
4970 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
4973 Yandroid_wB, FALSE, TRUE,
4974 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
4977 Yandroid_nw, FALSE, FALSE,
4978 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
4981 Yandroid_nwB, FALSE, TRUE,
4982 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
4985 Xspring, TRUE, FALSE,
4989 Xspring_pause, FALSE, FALSE,
4993 Xspring_e, FALSE, FALSE,
4997 Xspring_w, FALSE, FALSE,
5001 Xspring_fall, FALSE, FALSE,
5005 Yspring_s, FALSE, FALSE,
5006 EL_SPRING, ACTION_FALLING, -1
5009 Yspring_sB, FALSE, TRUE,
5010 EL_SPRING, ACTION_FALLING, -1
5013 Yspring_e, FALSE, FALSE,
5014 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
5017 Yspring_eB, FALSE, TRUE,
5018 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
5021 Yspring_w, FALSE, FALSE,
5022 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
5025 Yspring_wB, FALSE, TRUE,
5026 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
5029 Yspring_kill_e, FALSE, FALSE,
5030 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
5033 Yspring_kill_eB, FALSE, TRUE,
5034 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
5037 Yspring_kill_w, FALSE, FALSE,
5038 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
5041 Yspring_kill_wB, FALSE, TRUE,
5042 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
5045 Xeater_n, TRUE, FALSE,
5046 EL_YAMYAM_UP, -1, -1
5049 Xeater_e, TRUE, FALSE,
5050 EL_YAMYAM_RIGHT, -1, -1
5053 Xeater_w, TRUE, FALSE,
5054 EL_YAMYAM_LEFT, -1, -1
5057 Xeater_s, TRUE, FALSE,
5058 EL_YAMYAM_DOWN, -1, -1
5061 Yeater_n, FALSE, FALSE,
5062 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
5065 Yeater_nB, FALSE, TRUE,
5066 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
5069 Yeater_e, FALSE, FALSE,
5070 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
5073 Yeater_eB, FALSE, TRUE,
5074 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
5077 Yeater_s, FALSE, FALSE,
5078 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
5081 Yeater_sB, FALSE, TRUE,
5082 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
5085 Yeater_w, FALSE, FALSE,
5086 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
5089 Yeater_wB, FALSE, TRUE,
5090 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
5093 Yeater_stone, FALSE, FALSE,
5094 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
5097 Yeater_spring, FALSE, FALSE,
5098 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
5101 Xalien, TRUE, FALSE,
5105 Xalien_pause, FALSE, FALSE,
5109 Yalien_n, FALSE, FALSE,
5110 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
5113 Yalien_nB, FALSE, TRUE,
5114 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
5117 Yalien_e, FALSE, FALSE,
5118 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
5121 Yalien_eB, FALSE, TRUE,
5122 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
5125 Yalien_s, FALSE, FALSE,
5126 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
5129 Yalien_sB, FALSE, TRUE,
5130 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
5133 Yalien_w, FALSE, FALSE,
5134 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
5137 Yalien_wB, FALSE, TRUE,
5138 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
5141 Yalien_stone, FALSE, FALSE,
5142 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
5145 Yalien_spring, FALSE, FALSE,
5146 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
5149 Xemerald, TRUE, FALSE,
5153 Xemerald_pause, FALSE, FALSE,
5157 Xemerald_fall, FALSE, FALSE,
5161 Xemerald_shine, FALSE, FALSE,
5162 EL_EMERALD, ACTION_TWINKLING, -1
5165 Yemerald_s, FALSE, FALSE,
5166 EL_EMERALD, ACTION_FALLING, -1
5169 Yemerald_sB, FALSE, TRUE,
5170 EL_EMERALD, ACTION_FALLING, -1
5173 Yemerald_e, FALSE, FALSE,
5174 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
5177 Yemerald_eB, FALSE, TRUE,
5178 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
5181 Yemerald_w, FALSE, FALSE,
5182 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
5185 Yemerald_wB, FALSE, TRUE,
5186 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
5189 Yemerald_eat, FALSE, FALSE,
5190 EL_EMERALD, ACTION_COLLECTING, -1
5193 Yemerald_stone, FALSE, FALSE,
5194 EL_NUT, ACTION_BREAKING, -1
5197 Xdiamond, TRUE, FALSE,
5201 Xdiamond_pause, FALSE, FALSE,
5205 Xdiamond_fall, FALSE, FALSE,
5209 Xdiamond_shine, FALSE, FALSE,
5210 EL_DIAMOND, ACTION_TWINKLING, -1
5213 Ydiamond_s, FALSE, FALSE,
5214 EL_DIAMOND, ACTION_FALLING, -1
5217 Ydiamond_sB, FALSE, TRUE,
5218 EL_DIAMOND, ACTION_FALLING, -1
5221 Ydiamond_e, FALSE, FALSE,
5222 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
5225 Ydiamond_eB, FALSE, TRUE,
5226 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
5229 Ydiamond_w, FALSE, FALSE,
5230 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
5233 Ydiamond_wB, FALSE, TRUE,
5234 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
5237 Ydiamond_eat, FALSE, FALSE,
5238 EL_DIAMOND, ACTION_COLLECTING, -1
5241 Ydiamond_stone, FALSE, FALSE,
5242 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
5245 Xdrip_fall, TRUE, FALSE,
5246 EL_AMOEBA_DROP, -1, -1
5249 Xdrip_stretch, FALSE, FALSE,
5250 EL_AMOEBA_DROP, ACTION_FALLING, -1
5253 Xdrip_stretchB, FALSE, TRUE,
5254 EL_AMOEBA_DROP, ACTION_FALLING, -1
5257 Xdrip_eat, FALSE, FALSE,
5258 EL_AMOEBA_DROP, ACTION_GROWING, -1
5261 Ydrip_s1, FALSE, FALSE,
5262 EL_AMOEBA_DROP, ACTION_FALLING, -1
5265 Ydrip_s1B, FALSE, TRUE,
5266 EL_AMOEBA_DROP, ACTION_FALLING, -1
5269 Ydrip_s2, FALSE, FALSE,
5270 EL_AMOEBA_DROP, ACTION_FALLING, -1
5273 Ydrip_s2B, FALSE, TRUE,
5274 EL_AMOEBA_DROP, ACTION_FALLING, -1
5281 Xbomb_pause, FALSE, FALSE,
5285 Xbomb_fall, FALSE, FALSE,
5289 Ybomb_s, FALSE, FALSE,
5290 EL_BOMB, ACTION_FALLING, -1
5293 Ybomb_sB, FALSE, TRUE,
5294 EL_BOMB, ACTION_FALLING, -1
5297 Ybomb_e, FALSE, FALSE,
5298 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
5301 Ybomb_eB, FALSE, TRUE,
5302 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
5305 Ybomb_w, FALSE, FALSE,
5306 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
5309 Ybomb_wB, FALSE, TRUE,
5310 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
5313 Ybomb_eat, FALSE, FALSE,
5314 EL_BOMB, ACTION_ACTIVATING, -1
5317 Xballoon, TRUE, FALSE,
5321 Yballoon_n, FALSE, FALSE,
5322 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
5325 Yballoon_nB, FALSE, TRUE,
5326 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
5329 Yballoon_e, FALSE, FALSE,
5330 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
5333 Yballoon_eB, FALSE, TRUE,
5334 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
5337 Yballoon_s, FALSE, FALSE,
5338 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
5341 Yballoon_sB, FALSE, TRUE,
5342 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
5345 Yballoon_w, FALSE, FALSE,
5346 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
5349 Yballoon_wB, FALSE, TRUE,
5350 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
5353 Xgrass, TRUE, FALSE,
5354 EL_EMC_GRASS, -1, -1
5357 Ygrass_nB, FALSE, FALSE,
5358 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
5361 Ygrass_eB, FALSE, FALSE,
5362 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
5365 Ygrass_sB, FALSE, FALSE,
5366 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
5369 Ygrass_wB, FALSE, FALSE,
5370 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
5377 Ydirt_nB, FALSE, FALSE,
5378 EL_SAND, ACTION_DIGGING, MV_BIT_UP
5381 Ydirt_eB, FALSE, FALSE,
5382 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
5385 Ydirt_sB, FALSE, FALSE,
5386 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
5389 Ydirt_wB, FALSE, FALSE,
5390 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
5393 Xacid_ne, TRUE, FALSE,
5394 EL_ACID_POOL_TOPRIGHT, -1, -1
5397 Xacid_se, TRUE, FALSE,
5398 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
5401 Xacid_s, TRUE, FALSE,
5402 EL_ACID_POOL_BOTTOM, -1, -1
5405 Xacid_sw, TRUE, FALSE,
5406 EL_ACID_POOL_BOTTOMLEFT, -1, -1
5409 Xacid_nw, TRUE, FALSE,
5410 EL_ACID_POOL_TOPLEFT, -1, -1
5413 Xacid_1, TRUE, FALSE,
5417 Xacid_2, FALSE, FALSE,
5421 Xacid_3, FALSE, FALSE,
5425 Xacid_4, FALSE, FALSE,
5429 Xacid_5, FALSE, FALSE,
5433 Xacid_6, FALSE, FALSE,
5437 Xacid_7, FALSE, FALSE,
5441 Xacid_8, FALSE, FALSE,
5445 Xball_1, TRUE, FALSE,
5446 EL_EMC_MAGIC_BALL, -1, -1
5449 Xball_1B, FALSE, FALSE,
5450 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5453 Xball_2, FALSE, FALSE,
5454 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5457 Xball_2B, FALSE, FALSE,
5458 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5461 Yball_eat, FALSE, FALSE,
5462 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
5465 Ykey_1_eat, FALSE, FALSE,
5466 EL_EM_KEY_1, ACTION_COLLECTING, -1
5469 Ykey_2_eat, FALSE, FALSE,
5470 EL_EM_KEY_2, ACTION_COLLECTING, -1
5473 Ykey_3_eat, FALSE, FALSE,
5474 EL_EM_KEY_3, ACTION_COLLECTING, -1
5477 Ykey_4_eat, FALSE, FALSE,
5478 EL_EM_KEY_4, ACTION_COLLECTING, -1
5481 Ykey_5_eat, FALSE, FALSE,
5482 EL_EMC_KEY_5, ACTION_COLLECTING, -1
5485 Ykey_6_eat, FALSE, FALSE,
5486 EL_EMC_KEY_6, ACTION_COLLECTING, -1
5489 Ykey_7_eat, FALSE, FALSE,
5490 EL_EMC_KEY_7, ACTION_COLLECTING, -1
5493 Ykey_8_eat, FALSE, FALSE,
5494 EL_EMC_KEY_8, ACTION_COLLECTING, -1
5497 Ylenses_eat, FALSE, FALSE,
5498 EL_EMC_LENSES, ACTION_COLLECTING, -1
5501 Ymagnify_eat, FALSE, FALSE,
5502 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
5505 Ygrass_eat, FALSE, FALSE,
5506 EL_EMC_GRASS, ACTION_SNAPPING, -1
5509 Ydirt_eat, FALSE, FALSE,
5510 EL_SAND, ACTION_SNAPPING, -1
5513 Xgrow_ns, TRUE, FALSE,
5514 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
5517 Ygrow_ns_eat, FALSE, FALSE,
5518 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
5521 Xgrow_ew, TRUE, FALSE,
5522 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
5525 Ygrow_ew_eat, FALSE, FALSE,
5526 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
5529 Xwonderwall, TRUE, FALSE,
5530 EL_MAGIC_WALL, -1, -1
5533 XwonderwallB, FALSE, FALSE,
5534 EL_MAGIC_WALL, ACTION_ACTIVE, -1
5537 Xamoeba_1, TRUE, FALSE,
5538 EL_AMOEBA_DRY, ACTION_OTHER, -1
5541 Xamoeba_2, FALSE, FALSE,
5542 EL_AMOEBA_DRY, ACTION_OTHER, -1
5545 Xamoeba_3, FALSE, FALSE,
5546 EL_AMOEBA_DRY, ACTION_OTHER, -1
5549 Xamoeba_4, FALSE, FALSE,
5550 EL_AMOEBA_DRY, ACTION_OTHER, -1
5553 Xamoeba_5, TRUE, FALSE,
5554 EL_AMOEBA_WET, ACTION_OTHER, -1
5557 Xamoeba_6, FALSE, FALSE,
5558 EL_AMOEBA_WET, ACTION_OTHER, -1
5561 Xamoeba_7, FALSE, FALSE,
5562 EL_AMOEBA_WET, ACTION_OTHER, -1
5565 Xamoeba_8, FALSE, FALSE,
5566 EL_AMOEBA_WET, ACTION_OTHER, -1
5569 Xdoor_1, TRUE, FALSE,
5570 EL_EM_GATE_1, -1, -1
5573 Xdoor_2, TRUE, FALSE,
5574 EL_EM_GATE_2, -1, -1
5577 Xdoor_3, TRUE, FALSE,
5578 EL_EM_GATE_3, -1, -1
5581 Xdoor_4, TRUE, FALSE,
5582 EL_EM_GATE_4, -1, -1
5585 Xdoor_5, TRUE, FALSE,
5586 EL_EMC_GATE_5, -1, -1
5589 Xdoor_6, TRUE, FALSE,
5590 EL_EMC_GATE_6, -1, -1
5593 Xdoor_7, TRUE, FALSE,
5594 EL_EMC_GATE_7, -1, -1
5597 Xdoor_8, TRUE, FALSE,
5598 EL_EMC_GATE_8, -1, -1
5601 Xkey_1, TRUE, FALSE,
5605 Xkey_2, TRUE, FALSE,
5609 Xkey_3, TRUE, FALSE,
5613 Xkey_4, TRUE, FALSE,
5617 Xkey_5, TRUE, FALSE,
5618 EL_EMC_KEY_5, -1, -1
5621 Xkey_6, TRUE, FALSE,
5622 EL_EMC_KEY_6, -1, -1
5625 Xkey_7, TRUE, FALSE,
5626 EL_EMC_KEY_7, -1, -1
5629 Xkey_8, TRUE, FALSE,
5630 EL_EMC_KEY_8, -1, -1
5633 Xwind_n, TRUE, FALSE,
5634 EL_BALLOON_SWITCH_UP, -1, -1
5637 Xwind_e, TRUE, FALSE,
5638 EL_BALLOON_SWITCH_RIGHT, -1, -1
5641 Xwind_s, TRUE, FALSE,
5642 EL_BALLOON_SWITCH_DOWN, -1, -1
5645 Xwind_w, TRUE, FALSE,
5646 EL_BALLOON_SWITCH_LEFT, -1, -1
5649 Xwind_nesw, TRUE, FALSE,
5650 EL_BALLOON_SWITCH_ANY, -1, -1
5653 Xwind_stop, TRUE, FALSE,
5654 EL_BALLOON_SWITCH_NONE, -1, -1
5658 EL_EM_EXIT_CLOSED, -1, -1
5661 Xexit_1, TRUE, FALSE,
5662 EL_EM_EXIT_OPEN, -1, -1
5665 Xexit_2, FALSE, FALSE,
5666 EL_EM_EXIT_OPEN, -1, -1
5669 Xexit_3, FALSE, FALSE,
5670 EL_EM_EXIT_OPEN, -1, -1
5673 Xdynamite, TRUE, FALSE,
5674 EL_EM_DYNAMITE, -1, -1
5677 Ydynamite_eat, FALSE, FALSE,
5678 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
5681 Xdynamite_1, TRUE, FALSE,
5682 EL_EM_DYNAMITE_ACTIVE, -1, -1
5685 Xdynamite_2, FALSE, FALSE,
5686 EL_EM_DYNAMITE_ACTIVE, -1, -1
5689 Xdynamite_3, FALSE, FALSE,
5690 EL_EM_DYNAMITE_ACTIVE, -1, -1
5693 Xdynamite_4, FALSE, FALSE,
5694 EL_EM_DYNAMITE_ACTIVE, -1, -1
5697 Xbumper, TRUE, FALSE,
5698 EL_EMC_SPRING_BUMPER, -1, -1
5701 XbumperB, FALSE, FALSE,
5702 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
5705 Xwheel, TRUE, FALSE,
5706 EL_ROBOT_WHEEL, -1, -1
5709 XwheelB, FALSE, FALSE,
5710 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
5713 Xswitch, TRUE, FALSE,
5714 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
5717 XswitchB, FALSE, FALSE,
5718 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
5722 EL_QUICKSAND_EMPTY, -1, -1
5725 Xsand_stone, TRUE, FALSE,
5726 EL_QUICKSAND_FULL, -1, -1
5729 Xsand_stonein_1, FALSE, TRUE,
5730 EL_ROCK, ACTION_FILLING, -1
5733 Xsand_stonein_2, FALSE, TRUE,
5734 EL_ROCK, ACTION_FILLING, -1
5737 Xsand_stonein_3, FALSE, TRUE,
5738 EL_ROCK, ACTION_FILLING, -1
5741 Xsand_stonein_4, FALSE, TRUE,
5742 EL_ROCK, ACTION_FILLING, -1
5745 Xsand_stonesand_1, FALSE, FALSE,
5746 EL_QUICKSAND_EMPTYING, -1, -1
5749 Xsand_stonesand_2, FALSE, FALSE,
5750 EL_QUICKSAND_EMPTYING, -1, -1
5753 Xsand_stonesand_3, FALSE, FALSE,
5754 EL_QUICKSAND_EMPTYING, -1, -1
5757 Xsand_stonesand_4, FALSE, FALSE,
5758 EL_QUICKSAND_EMPTYING, -1, -1
5761 Xsand_stonesand_quickout_1, FALSE, FALSE,
5762 EL_QUICKSAND_EMPTYING, -1, -1
5765 Xsand_stonesand_quickout_2, FALSE, FALSE,
5766 EL_QUICKSAND_EMPTYING, -1, -1
5769 Xsand_stoneout_1, FALSE, FALSE,
5770 EL_ROCK, ACTION_EMPTYING, -1
5773 Xsand_stoneout_2, FALSE, FALSE,
5774 EL_ROCK, ACTION_EMPTYING, -1
5777 Xsand_sandstone_1, FALSE, FALSE,
5778 EL_QUICKSAND_FILLING, -1, -1
5781 Xsand_sandstone_2, FALSE, FALSE,
5782 EL_QUICKSAND_FILLING, -1, -1
5785 Xsand_sandstone_3, FALSE, FALSE,
5786 EL_QUICKSAND_FILLING, -1, -1
5789 Xsand_sandstone_4, FALSE, FALSE,
5790 EL_QUICKSAND_FILLING, -1, -1
5793 Xplant, TRUE, FALSE,
5794 EL_EMC_PLANT, -1, -1
5797 Yplant, FALSE, FALSE,
5798 EL_EMC_PLANT, -1, -1
5801 Xlenses, TRUE, FALSE,
5802 EL_EMC_LENSES, -1, -1
5805 Xmagnify, TRUE, FALSE,
5806 EL_EMC_MAGNIFIER, -1, -1
5809 Xdripper, TRUE, FALSE,
5810 EL_EMC_DRIPPER, -1, -1
5813 XdripperB, FALSE, FALSE,
5814 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
5817 Xfake_blank, TRUE, FALSE,
5818 EL_INVISIBLE_WALL, -1, -1
5821 Xfake_blankB, FALSE, FALSE,
5822 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
5825 Xfake_grass, TRUE, FALSE,
5826 EL_EMC_FAKE_GRASS, -1, -1
5829 Xfake_grassB, FALSE, FALSE,
5830 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
5833 Xfake_door_1, TRUE, FALSE,
5834 EL_EM_GATE_1_GRAY, -1, -1
5837 Xfake_door_2, TRUE, FALSE,
5838 EL_EM_GATE_2_GRAY, -1, -1
5841 Xfake_door_3, TRUE, FALSE,
5842 EL_EM_GATE_3_GRAY, -1, -1
5845 Xfake_door_4, TRUE, FALSE,
5846 EL_EM_GATE_4_GRAY, -1, -1
5849 Xfake_door_5, TRUE, FALSE,
5850 EL_EMC_GATE_5_GRAY, -1, -1
5853 Xfake_door_6, TRUE, FALSE,
5854 EL_EMC_GATE_6_GRAY, -1, -1
5857 Xfake_door_7, TRUE, FALSE,
5858 EL_EMC_GATE_7_GRAY, -1, -1
5861 Xfake_door_8, TRUE, FALSE,
5862 EL_EMC_GATE_8_GRAY, -1, -1
5865 Xfake_acid_1, TRUE, FALSE,
5866 EL_EMC_FAKE_ACID, -1, -1
5869 Xfake_acid_2, FALSE, FALSE,
5870 EL_EMC_FAKE_ACID, -1, -1
5873 Xfake_acid_3, FALSE, FALSE,
5874 EL_EMC_FAKE_ACID, -1, -1
5877 Xfake_acid_4, FALSE, FALSE,
5878 EL_EMC_FAKE_ACID, -1, -1
5881 Xfake_acid_5, FALSE, FALSE,
5882 EL_EMC_FAKE_ACID, -1, -1
5885 Xfake_acid_6, FALSE, FALSE,
5886 EL_EMC_FAKE_ACID, -1, -1
5889 Xfake_acid_7, FALSE, FALSE,
5890 EL_EMC_FAKE_ACID, -1, -1
5893 Xfake_acid_8, FALSE, FALSE,
5894 EL_EMC_FAKE_ACID, -1, -1
5897 Xsteel_1, TRUE, FALSE,
5898 EL_STEELWALL, -1, -1
5901 Xsteel_2, TRUE, FALSE,
5902 EL_EMC_STEELWALL_2, -1, -1
5905 Xsteel_3, TRUE, FALSE,
5906 EL_EMC_STEELWALL_3, -1, -1
5909 Xsteel_4, TRUE, FALSE,
5910 EL_EMC_STEELWALL_4, -1, -1
5913 Xwall_1, TRUE, FALSE,
5917 Xwall_2, TRUE, FALSE,
5918 EL_EMC_WALL_14, -1, -1
5921 Xwall_3, TRUE, FALSE,
5922 EL_EMC_WALL_15, -1, -1
5925 Xwall_4, TRUE, FALSE,
5926 EL_EMC_WALL_16, -1, -1
5929 Xround_wall_1, TRUE, FALSE,
5930 EL_WALL_SLIPPERY, -1, -1
5933 Xround_wall_2, TRUE, FALSE,
5934 EL_EMC_WALL_SLIPPERY_2, -1, -1
5937 Xround_wall_3, TRUE, FALSE,
5938 EL_EMC_WALL_SLIPPERY_3, -1, -1
5941 Xround_wall_4, TRUE, FALSE,
5942 EL_EMC_WALL_SLIPPERY_4, -1, -1
5945 Xdecor_1, TRUE, FALSE,
5946 EL_EMC_WALL_8, -1, -1
5949 Xdecor_2, TRUE, FALSE,
5950 EL_EMC_WALL_6, -1, -1
5953 Xdecor_3, TRUE, FALSE,
5954 EL_EMC_WALL_4, -1, -1
5957 Xdecor_4, TRUE, FALSE,
5958 EL_EMC_WALL_7, -1, -1
5961 Xdecor_5, TRUE, FALSE,
5962 EL_EMC_WALL_5, -1, -1
5965 Xdecor_6, TRUE, FALSE,
5966 EL_EMC_WALL_9, -1, -1
5969 Xdecor_7, TRUE, FALSE,
5970 EL_EMC_WALL_10, -1, -1
5973 Xdecor_8, TRUE, FALSE,
5974 EL_EMC_WALL_1, -1, -1
5977 Xdecor_9, TRUE, FALSE,
5978 EL_EMC_WALL_2, -1, -1
5981 Xdecor_10, TRUE, FALSE,
5982 EL_EMC_WALL_3, -1, -1
5985 Xdecor_11, TRUE, FALSE,
5986 EL_EMC_WALL_11, -1, -1
5989 Xdecor_12, TRUE, FALSE,
5990 EL_EMC_WALL_12, -1, -1
5993 Xalpha_0, TRUE, FALSE,
5994 EL_CHAR('0'), -1, -1
5997 Xalpha_1, TRUE, FALSE,
5998 EL_CHAR('1'), -1, -1
6001 Xalpha_2, TRUE, FALSE,
6002 EL_CHAR('2'), -1, -1
6005 Xalpha_3, TRUE, FALSE,
6006 EL_CHAR('3'), -1, -1
6009 Xalpha_4, TRUE, FALSE,
6010 EL_CHAR('4'), -1, -1
6013 Xalpha_5, TRUE, FALSE,
6014 EL_CHAR('5'), -1, -1
6017 Xalpha_6, TRUE, FALSE,
6018 EL_CHAR('6'), -1, -1
6021 Xalpha_7, TRUE, FALSE,
6022 EL_CHAR('7'), -1, -1
6025 Xalpha_8, TRUE, FALSE,
6026 EL_CHAR('8'), -1, -1
6029 Xalpha_9, TRUE, FALSE,
6030 EL_CHAR('9'), -1, -1
6033 Xalpha_excla, TRUE, FALSE,
6034 EL_CHAR('!'), -1, -1
6037 Xalpha_quote, TRUE, FALSE,
6038 EL_CHAR('"'), -1, -1
6041 Xalpha_comma, TRUE, FALSE,
6042 EL_CHAR(','), -1, -1
6045 Xalpha_minus, TRUE, FALSE,
6046 EL_CHAR('-'), -1, -1
6049 Xalpha_perio, TRUE, FALSE,
6050 EL_CHAR('.'), -1, -1
6053 Xalpha_colon, TRUE, FALSE,
6054 EL_CHAR(':'), -1, -1
6057 Xalpha_quest, TRUE, FALSE,
6058 EL_CHAR('?'), -1, -1
6061 Xalpha_a, TRUE, FALSE,
6062 EL_CHAR('A'), -1, -1
6065 Xalpha_b, TRUE, FALSE,
6066 EL_CHAR('B'), -1, -1
6069 Xalpha_c, TRUE, FALSE,
6070 EL_CHAR('C'), -1, -1
6073 Xalpha_d, TRUE, FALSE,
6074 EL_CHAR('D'), -1, -1
6077 Xalpha_e, TRUE, FALSE,
6078 EL_CHAR('E'), -1, -1
6081 Xalpha_f, TRUE, FALSE,
6082 EL_CHAR('F'), -1, -1
6085 Xalpha_g, TRUE, FALSE,
6086 EL_CHAR('G'), -1, -1
6089 Xalpha_h, TRUE, FALSE,
6090 EL_CHAR('H'), -1, -1
6093 Xalpha_i, TRUE, FALSE,
6094 EL_CHAR('I'), -1, -1
6097 Xalpha_j, TRUE, FALSE,
6098 EL_CHAR('J'), -1, -1
6101 Xalpha_k, TRUE, FALSE,
6102 EL_CHAR('K'), -1, -1
6105 Xalpha_l, TRUE, FALSE,
6106 EL_CHAR('L'), -1, -1
6109 Xalpha_m, TRUE, FALSE,
6110 EL_CHAR('M'), -1, -1
6113 Xalpha_n, TRUE, FALSE,
6114 EL_CHAR('N'), -1, -1
6117 Xalpha_o, TRUE, FALSE,
6118 EL_CHAR('O'), -1, -1
6121 Xalpha_p, TRUE, FALSE,
6122 EL_CHAR('P'), -1, -1
6125 Xalpha_q, TRUE, FALSE,
6126 EL_CHAR('Q'), -1, -1
6129 Xalpha_r, TRUE, FALSE,
6130 EL_CHAR('R'), -1, -1
6133 Xalpha_s, TRUE, FALSE,
6134 EL_CHAR('S'), -1, -1
6137 Xalpha_t, TRUE, FALSE,
6138 EL_CHAR('T'), -1, -1
6141 Xalpha_u, TRUE, FALSE,
6142 EL_CHAR('U'), -1, -1
6145 Xalpha_v, TRUE, FALSE,
6146 EL_CHAR('V'), -1, -1
6149 Xalpha_w, TRUE, FALSE,
6150 EL_CHAR('W'), -1, -1
6153 Xalpha_x, TRUE, FALSE,
6154 EL_CHAR('X'), -1, -1
6157 Xalpha_y, TRUE, FALSE,
6158 EL_CHAR('Y'), -1, -1
6161 Xalpha_z, TRUE, FALSE,
6162 EL_CHAR('Z'), -1, -1
6165 Xalpha_arrow_e, TRUE, FALSE,
6166 EL_CHAR('>'), -1, -1
6169 Xalpha_arrow_w, TRUE, FALSE,
6170 EL_CHAR('<'), -1, -1
6173 Xalpha_copyr, TRUE, FALSE,
6174 EL_CHAR(CHAR_BYTE_COPYRIGHT), -1, -1
6178 Xboom_bug, FALSE, FALSE,
6179 EL_BUG, ACTION_EXPLODING, -1
6182 Xboom_bomb, FALSE, FALSE,
6183 EL_BOMB, ACTION_EXPLODING, -1
6186 Xboom_android, FALSE, FALSE,
6187 EL_EMC_ANDROID, ACTION_OTHER, -1
6190 Xboom_1, FALSE, FALSE,
6191 EL_DEFAULT, ACTION_EXPLODING, -1
6194 Xboom_2, FALSE, FALSE,
6195 EL_DEFAULT, ACTION_EXPLODING, -1
6198 Znormal, FALSE, FALSE,
6202 Zdynamite, FALSE, FALSE,
6206 Zplayer, FALSE, FALSE,
6210 ZBORDER, FALSE, FALSE,
6220 static struct Mapping_EM_to_RND_player
6229 em_player_mapping_list[] =
6233 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
6237 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
6241 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
6245 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
6249 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
6253 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
6257 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
6261 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
6265 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
6269 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
6273 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
6277 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
6281 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
6285 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
6289 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
6293 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
6297 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
6301 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
6305 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
6309 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
6313 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
6317 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
6321 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
6325 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
6329 EL_PLAYER_1, ACTION_DEFAULT, -1,
6333 EL_PLAYER_2, ACTION_DEFAULT, -1,
6337 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
6341 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
6345 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
6349 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
6353 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
6357 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
6361 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
6365 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
6369 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
6373 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
6377 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
6381 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
6385 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
6389 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
6393 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
6397 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
6401 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
6405 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
6409 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
6413 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
6417 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
6421 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
6425 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
6429 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
6433 EL_PLAYER_3, ACTION_DEFAULT, -1,
6437 EL_PLAYER_4, ACTION_DEFAULT, -1,
6446 int map_element_RND_to_EM(int element_rnd)
6448 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
6449 static boolean mapping_initialized = FALSE;
6451 if (!mapping_initialized)
6455 /* return "Xalpha_quest" for all undefined elements in mapping array */
6456 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
6457 mapping_RND_to_EM[i] = Xalpha_quest;
6459 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6460 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
6461 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
6462 em_object_mapping_list[i].element_em;
6464 mapping_initialized = TRUE;
6467 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
6468 return mapping_RND_to_EM[element_rnd];
6470 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
6475 int map_element_EM_to_RND(int element_em)
6477 static unsigned short mapping_EM_to_RND[TILE_MAX];
6478 static boolean mapping_initialized = FALSE;
6480 if (!mapping_initialized)
6484 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
6485 for (i = 0; i < TILE_MAX; i++)
6486 mapping_EM_to_RND[i] = EL_UNKNOWN;
6488 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6489 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
6490 em_object_mapping_list[i].element_rnd;
6492 mapping_initialized = TRUE;
6495 if (element_em >= 0 && element_em < TILE_MAX)
6496 return mapping_EM_to_RND[element_em];
6498 Error(ERR_WARN, "invalid EM level element %d", element_em);
6503 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
6505 struct LevelInfo_EM *level_em = level->native_em_level;
6506 struct LEVEL *lev = level_em->lev;
6509 for (i = 0; i < TILE_MAX; i++)
6510 lev->android_array[i] = Xblank;
6512 for (i = 0; i < level->num_android_clone_elements; i++)
6514 int element_rnd = level->android_clone_element[i];
6515 int element_em = map_element_RND_to_EM(element_rnd);
6517 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
6518 if (em_object_mapping_list[j].element_rnd == element_rnd)
6519 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
6523 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
6525 struct LevelInfo_EM *level_em = level->native_em_level;
6526 struct LEVEL *lev = level_em->lev;
6529 level->num_android_clone_elements = 0;
6531 for (i = 0; i < TILE_MAX; i++)
6533 int element_em = lev->android_array[i];
6535 boolean element_found = FALSE;
6537 if (element_em == Xblank)
6540 element_rnd = map_element_EM_to_RND(element_em);
6542 for (j = 0; j < level->num_android_clone_elements; j++)
6543 if (level->android_clone_element[j] == element_rnd)
6544 element_found = TRUE;
6548 level->android_clone_element[level->num_android_clone_elements++] =
6551 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
6556 if (level->num_android_clone_elements == 0)
6558 level->num_android_clone_elements = 1;
6559 level->android_clone_element[0] = EL_EMPTY;
6563 int map_direction_RND_to_EM(int direction)
6565 return (direction == MV_UP ? 0 :
6566 direction == MV_RIGHT ? 1 :
6567 direction == MV_DOWN ? 2 :
6568 direction == MV_LEFT ? 3 :
6572 int map_direction_EM_to_RND(int direction)
6574 return (direction == 0 ? MV_UP :
6575 direction == 1 ? MV_RIGHT :
6576 direction == 2 ? MV_DOWN :
6577 direction == 3 ? MV_LEFT :
6581 int map_element_RND_to_SP(int element_rnd)
6583 int element_sp = 0x20; /* map unknown elements to yellow "hardware" */
6585 if (element_rnd >= EL_SP_START &&
6586 element_rnd <= EL_SP_END)
6587 element_sp = element_rnd - EL_SP_START;
6588 else if (element_rnd == EL_EMPTY_SPACE)
6590 else if (element_rnd == EL_INVISIBLE_WALL)
6596 int map_element_SP_to_RND(int element_sp)
6598 int element_rnd = EL_UNKNOWN;
6600 if (element_sp >= 0x00 &&
6602 element_rnd = EL_SP_START + element_sp;
6603 else if (element_sp == 0x28)
6604 element_rnd = EL_INVISIBLE_WALL;
6609 int map_action_SP_to_RND(int action_sp)
6613 case actActive: return ACTION_ACTIVE;
6614 case actImpact: return ACTION_IMPACT;
6615 case actExploding: return ACTION_EXPLODING;
6616 case actDigging: return ACTION_DIGGING;
6617 case actSnapping: return ACTION_SNAPPING;
6618 case actCollecting: return ACTION_COLLECTING;
6619 case actPassing: return ACTION_PASSING;
6620 case actPushing: return ACTION_PUSHING;
6621 case actDropping: return ACTION_DROPPING;
6623 default: return ACTION_DEFAULT;
6627 int get_next_element(int element)
6631 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
6632 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
6633 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
6634 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
6635 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
6636 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
6637 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
6638 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
6639 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
6640 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
6641 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
6643 default: return element;
6647 int el_act_dir2img(int element, int action, int direction)
6649 element = GFX_ELEMENT(element);
6650 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
6652 /* direction_graphic[][] == graphic[] for undefined direction graphics */
6653 return element_info[element].direction_graphic[action][direction];
6656 static int el_act_dir2crm(int element, int action, int direction)
6658 element = GFX_ELEMENT(element);
6659 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
6661 /* direction_graphic[][] == graphic[] for undefined direction graphics */
6662 return element_info[element].direction_crumbled[action][direction];
6665 int el_act2img(int element, int action)
6667 element = GFX_ELEMENT(element);
6669 return element_info[element].graphic[action];
6672 int el_act2crm(int element, int action)
6674 element = GFX_ELEMENT(element);
6676 return element_info[element].crumbled[action];
6679 int el_dir2img(int element, int direction)
6681 element = GFX_ELEMENT(element);
6683 return el_act_dir2img(element, ACTION_DEFAULT, direction);
6686 int el2baseimg(int element)
6688 return element_info[element].graphic[ACTION_DEFAULT];
6691 int el2img(int element)
6693 element = GFX_ELEMENT(element);
6695 return element_info[element].graphic[ACTION_DEFAULT];
6698 int el2edimg(int element)
6700 element = GFX_ELEMENT(element);
6702 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
6705 int el2preimg(int element)
6707 element = GFX_ELEMENT(element);
6709 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
6712 int el2panelimg(int element)
6714 element = GFX_ELEMENT(element);
6716 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL];
6719 int font2baseimg(int font_nr)
6721 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
6724 int getBeltNrFromBeltElement(int element)
6726 return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
6727 element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
6728 element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
6731 int getBeltNrFromBeltActiveElement(int element)
6733 return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
6734 element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
6735 element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
6738 int getBeltNrFromBeltSwitchElement(int element)
6740 return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
6741 element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
6742 element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
6745 int getBeltDirNrFromBeltElement(int element)
6747 static int belt_base_element[4] =
6749 EL_CONVEYOR_BELT_1_LEFT,
6750 EL_CONVEYOR_BELT_2_LEFT,
6751 EL_CONVEYOR_BELT_3_LEFT,
6752 EL_CONVEYOR_BELT_4_LEFT
6755 int belt_nr = getBeltNrFromBeltElement(element);
6756 int belt_dir_nr = element - belt_base_element[belt_nr];
6758 return (belt_dir_nr % 3);
6761 int getBeltDirNrFromBeltSwitchElement(int element)
6763 static int belt_base_element[4] =
6765 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
6766 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
6767 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
6768 EL_CONVEYOR_BELT_4_SWITCH_LEFT
6771 int belt_nr = getBeltNrFromBeltSwitchElement(element);
6772 int belt_dir_nr = element - belt_base_element[belt_nr];
6774 return (belt_dir_nr % 3);
6777 int getBeltDirFromBeltElement(int element)
6779 static int belt_move_dir[3] =
6786 int belt_dir_nr = getBeltDirNrFromBeltElement(element);
6788 return belt_move_dir[belt_dir_nr];
6791 int getBeltDirFromBeltSwitchElement(int element)
6793 static int belt_move_dir[3] =
6800 int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
6802 return belt_move_dir[belt_dir_nr];
6805 int getBeltElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
6807 static int belt_base_element[4] =
6809 EL_CONVEYOR_BELT_1_LEFT,
6810 EL_CONVEYOR_BELT_2_LEFT,
6811 EL_CONVEYOR_BELT_3_LEFT,
6812 EL_CONVEYOR_BELT_4_LEFT
6815 return belt_base_element[belt_nr] + belt_dir_nr;
6818 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
6820 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
6822 return getBeltElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
6825 int getBeltSwitchElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
6827 static int belt_base_element[4] =
6829 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
6830 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
6831 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
6832 EL_CONVEYOR_BELT_4_SWITCH_LEFT
6835 return belt_base_element[belt_nr] + belt_dir_nr;
6838 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
6840 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
6842 return getBeltSwitchElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
6845 boolean getTeamMode_EM()
6847 return game.team_mode;
6850 int getGameFrameDelay_EM(int native_em_game_frame_delay)
6852 int game_frame_delay_value;
6854 game_frame_delay_value =
6855 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
6856 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
6859 if (tape.playing && tape.warp_forward && !tape.pausing)
6860 game_frame_delay_value = 0;
6862 return game_frame_delay_value;
6865 unsigned int InitRND(int seed)
6867 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
6868 return InitEngineRandom_EM(seed);
6869 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
6870 return InitEngineRandom_SP(seed);
6872 return InitEngineRandom_RND(seed);
6875 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
6876 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
6878 inline static int get_effective_element_EM(int tile, int frame_em)
6880 int element = object_mapping[tile].element_rnd;
6881 int action = object_mapping[tile].action;
6882 boolean is_backside = object_mapping[tile].is_backside;
6883 boolean action_removing = (action == ACTION_DIGGING ||
6884 action == ACTION_SNAPPING ||
6885 action == ACTION_COLLECTING);
6891 case Yacid_splash_eB:
6892 case Yacid_splash_wB:
6893 return (frame_em > 5 ? EL_EMPTY : element);
6899 else /* frame_em == 7 */
6903 case Yacid_splash_eB:
6904 case Yacid_splash_wB:
6907 case Yemerald_stone:
6910 case Ydiamond_stone:
6914 case Xdrip_stretchB:
6933 case Xsand_stonein_1:
6934 case Xsand_stonein_2:
6935 case Xsand_stonein_3:
6936 case Xsand_stonein_4:
6940 return (is_backside || action_removing ? EL_EMPTY : element);
6945 inline static boolean check_linear_animation_EM(int tile)
6949 case Xsand_stonesand_1:
6950 case Xsand_stonesand_quickout_1:
6951 case Xsand_sandstone_1:
6952 case Xsand_stonein_1:
6953 case Xsand_stoneout_1:
6972 case Yacid_splash_eB:
6973 case Yacid_splash_wB:
6974 case Yemerald_stone:
6981 inline static void set_crumbled_graphics_EM(struct GraphicInfo_EM *g_em,
6982 boolean has_crumbled_graphics,
6983 int crumbled, int sync_frame)
6985 /* if element can be crumbled, but certain action graphics are just empty
6986 space (like instantly snapping sand to empty space in 1 frame), do not
6987 treat these empty space graphics as crumbled graphics in EMC engine */
6988 if (crumbled == IMG_EMPTY_SPACE)
6989 has_crumbled_graphics = FALSE;
6991 if (has_crumbled_graphics)
6993 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
6994 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
6995 g_crumbled->anim_delay,
6996 g_crumbled->anim_mode,
6997 g_crumbled->anim_start_frame,
7000 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
7001 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
7003 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
7005 g_em->has_crumbled_graphics = TRUE;
7009 g_em->crumbled_bitmap = NULL;
7010 g_em->crumbled_src_x = 0;
7011 g_em->crumbled_src_y = 0;
7012 g_em->crumbled_border_size = 0;
7014 g_em->has_crumbled_graphics = FALSE;
7018 void ResetGfxAnimation_EM(int x, int y, int tile)
7023 void SetGfxAnimation_EM(struct GraphicInfo_EM *g_em,
7024 int tile, int frame_em, int x, int y)
7026 int action = object_mapping[tile].action;
7027 int direction = object_mapping[tile].direction;
7028 int effective_element = get_effective_element_EM(tile, frame_em);
7029 int graphic = (direction == MV_NONE ?
7030 el_act2img(effective_element, action) :
7031 el_act_dir2img(effective_element, action, direction));
7032 struct GraphicInfo *g = &graphic_info[graphic];
7034 boolean action_removing = (action == ACTION_DIGGING ||
7035 action == ACTION_SNAPPING ||
7036 action == ACTION_COLLECTING);
7037 boolean action_moving = (action == ACTION_FALLING ||
7038 action == ACTION_MOVING ||
7039 action == ACTION_PUSHING ||
7040 action == ACTION_EATING ||
7041 action == ACTION_FILLING ||
7042 action == ACTION_EMPTYING);
7043 boolean action_falling = (action == ACTION_FALLING ||
7044 action == ACTION_FILLING ||
7045 action == ACTION_EMPTYING);
7047 /* special case: graphic uses "2nd movement tile" and has defined
7048 7 frames for movement animation (or less) => use default graphic
7049 for last (8th) frame which ends the movement animation */
7050 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
7052 action = ACTION_DEFAULT; /* (keep action_* unchanged for now) */
7053 graphic = (direction == MV_NONE ?
7054 el_act2img(effective_element, action) :
7055 el_act_dir2img(effective_element, action, direction));
7057 g = &graphic_info[graphic];
7060 if ((action_removing || check_linear_animation_EM(tile)) && frame_em == 0)
7064 else if (action_moving)
7066 boolean is_backside = object_mapping[tile].is_backside;
7070 int direction = object_mapping[tile].direction;
7071 int move_dir = (action_falling ? MV_DOWN : direction);
7076 /* !!! TEST !!! NEW !!! DOES NOT WORK RIGHT YET !!! */
7077 if (g->double_movement && frame_em == 0)
7081 if (move_dir == MV_LEFT)
7082 GfxFrame[x - 1][y] = GfxFrame[x][y];
7083 else if (move_dir == MV_RIGHT)
7084 GfxFrame[x + 1][y] = GfxFrame[x][y];
7085 else if (move_dir == MV_UP)
7086 GfxFrame[x][y - 1] = GfxFrame[x][y];
7087 else if (move_dir == MV_DOWN)
7088 GfxFrame[x][y + 1] = GfxFrame[x][y];
7095 /* special case: animation for Xsand_stonesand_quickout_1/2 twice as fast */
7096 if (tile == Xsand_stonesand_quickout_1 ||
7097 tile == Xsand_stonesand_quickout_2)
7101 if (graphic_info[graphic].anim_global_sync)
7102 sync_frame = FrameCounter;
7103 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
7104 sync_frame = GfxFrame[x][y];
7106 sync_frame = 0; /* playfield border (pseudo steel) */
7108 SetRandomAnimationValue(x, y);
7110 int frame = getAnimationFrame(g->anim_frames,
7113 g->anim_start_frame,
7116 g_em->unique_identifier =
7117 (graphic << 16) | ((frame % 8) << 12) | (g_em->width << 6) | g_em->height;
7120 void getGraphicSourceObjectExt_EM(struct GraphicInfo_EM *g_em,
7121 int tile, int frame_em, int x, int y)
7123 int action = object_mapping[tile].action;
7124 int direction = object_mapping[tile].direction;
7125 boolean is_backside = object_mapping[tile].is_backside;
7126 int effective_element = get_effective_element_EM(tile, frame_em);
7127 int effective_action = action;
7128 int graphic = (direction == MV_NONE ?
7129 el_act2img(effective_element, effective_action) :
7130 el_act_dir2img(effective_element, effective_action,
7132 int crumbled = (direction == MV_NONE ?
7133 el_act2crm(effective_element, effective_action) :
7134 el_act_dir2crm(effective_element, effective_action,
7136 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7137 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7138 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7139 struct GraphicInfo *g = &graphic_info[graphic];
7142 /* special case: graphic uses "2nd movement tile" and has defined
7143 7 frames for movement animation (or less) => use default graphic
7144 for last (8th) frame which ends the movement animation */
7145 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
7147 effective_action = ACTION_DEFAULT;
7148 graphic = (direction == MV_NONE ?
7149 el_act2img(effective_element, effective_action) :
7150 el_act_dir2img(effective_element, effective_action,
7152 crumbled = (direction == MV_NONE ?
7153 el_act2crm(effective_element, effective_action) :
7154 el_act_dir2crm(effective_element, effective_action,
7157 g = &graphic_info[graphic];
7160 if (graphic_info[graphic].anim_global_sync)
7161 sync_frame = FrameCounter;
7162 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
7163 sync_frame = GfxFrame[x][y];
7165 sync_frame = 0; /* playfield border (pseudo steel) */
7167 SetRandomAnimationValue(x, y);
7169 int frame = getAnimationFrame(g->anim_frames,
7172 g->anim_start_frame,
7175 getGraphicSourceExt(graphic, frame, &g_em->bitmap, &g_em->src_x, &g_em->src_y,
7176 g->double_movement && is_backside);
7178 /* (updating the "crumbled" graphic definitions is probably not really needed,
7179 as animations for crumbled graphics can't be longer than one EMC cycle) */
7180 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
7184 void getGraphicSourcePlayerExt_EM(struct GraphicInfo_EM *g_em,
7185 int player_nr, int anim, int frame_em)
7187 int element = player_mapping[player_nr][anim].element_rnd;
7188 int action = player_mapping[player_nr][anim].action;
7189 int direction = player_mapping[player_nr][anim].direction;
7190 int graphic = (direction == MV_NONE ?
7191 el_act2img(element, action) :
7192 el_act_dir2img(element, action, direction));
7193 struct GraphicInfo *g = &graphic_info[graphic];
7196 InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
7198 stored_player[player_nr].StepFrame = frame_em;
7200 sync_frame = stored_player[player_nr].Frame;
7202 int frame = getAnimationFrame(g->anim_frames,
7205 g->anim_start_frame,
7208 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
7209 &g_em->src_x, &g_em->src_y, FALSE);
7212 void InitGraphicInfo_EM(void)
7217 int num_em_gfx_errors = 0;
7219 if (graphic_info_em_object[0][0].bitmap == NULL)
7221 /* EM graphics not yet initialized in em_open_all() */
7226 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
7229 /* always start with reliable default values */
7230 for (i = 0; i < TILE_MAX; i++)
7232 object_mapping[i].element_rnd = EL_UNKNOWN;
7233 object_mapping[i].is_backside = FALSE;
7234 object_mapping[i].action = ACTION_DEFAULT;
7235 object_mapping[i].direction = MV_NONE;
7238 /* always start with reliable default values */
7239 for (p = 0; p < MAX_PLAYERS; p++)
7241 for (i = 0; i < SPR_MAX; i++)
7243 player_mapping[p][i].element_rnd = EL_UNKNOWN;
7244 player_mapping[p][i].action = ACTION_DEFAULT;
7245 player_mapping[p][i].direction = MV_NONE;
7249 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
7251 int e = em_object_mapping_list[i].element_em;
7253 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
7254 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
7256 if (em_object_mapping_list[i].action != -1)
7257 object_mapping[e].action = em_object_mapping_list[i].action;
7259 if (em_object_mapping_list[i].direction != -1)
7260 object_mapping[e].direction =
7261 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
7264 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
7266 int a = em_player_mapping_list[i].action_em;
7267 int p = em_player_mapping_list[i].player_nr;
7269 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
7271 if (em_player_mapping_list[i].action != -1)
7272 player_mapping[p][a].action = em_player_mapping_list[i].action;
7274 if (em_player_mapping_list[i].direction != -1)
7275 player_mapping[p][a].direction =
7276 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
7279 for (i = 0; i < TILE_MAX; i++)
7281 int element = object_mapping[i].element_rnd;
7282 int action = object_mapping[i].action;
7283 int direction = object_mapping[i].direction;
7284 boolean is_backside = object_mapping[i].is_backside;
7285 boolean action_exploding = ((action == ACTION_EXPLODING ||
7286 action == ACTION_SMASHED_BY_ROCK ||
7287 action == ACTION_SMASHED_BY_SPRING) &&
7288 element != EL_DIAMOND);
7289 boolean action_active = (action == ACTION_ACTIVE);
7290 boolean action_other = (action == ACTION_OTHER);
7292 for (j = 0; j < 8; j++)
7294 int effective_element = get_effective_element_EM(i, j);
7295 int effective_action = (j < 7 ? action :
7296 i == Xdrip_stretch ? action :
7297 i == Xdrip_stretchB ? action :
7298 i == Ydrip_s1 ? action :
7299 i == Ydrip_s1B ? action :
7300 i == Xball_1B ? action :
7301 i == Xball_2 ? action :
7302 i == Xball_2B ? action :
7303 i == Yball_eat ? action :
7304 i == Ykey_1_eat ? action :
7305 i == Ykey_2_eat ? action :
7306 i == Ykey_3_eat ? action :
7307 i == Ykey_4_eat ? action :
7308 i == Ykey_5_eat ? action :
7309 i == Ykey_6_eat ? action :
7310 i == Ykey_7_eat ? action :
7311 i == Ykey_8_eat ? action :
7312 i == Ylenses_eat ? action :
7313 i == Ymagnify_eat ? action :
7314 i == Ygrass_eat ? action :
7315 i == Ydirt_eat ? action :
7316 i == Xsand_stonein_1 ? action :
7317 i == Xsand_stonein_2 ? action :
7318 i == Xsand_stonein_3 ? action :
7319 i == Xsand_stonein_4 ? action :
7320 i == Xsand_stoneout_1 ? action :
7321 i == Xsand_stoneout_2 ? action :
7322 i == Xboom_android ? ACTION_EXPLODING :
7323 action_exploding ? ACTION_EXPLODING :
7324 action_active ? action :
7325 action_other ? action :
7327 int graphic = (el_act_dir2img(effective_element, effective_action,
7329 int crumbled = (el_act_dir2crm(effective_element, effective_action,
7331 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7332 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7333 boolean has_action_graphics = (graphic != base_graphic);
7334 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7335 struct GraphicInfo *g = &graphic_info[graphic];
7336 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7339 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
7340 boolean special_animation = (action != ACTION_DEFAULT &&
7341 g->anim_frames == 3 &&
7342 g->anim_delay == 2 &&
7343 g->anim_mode & ANIM_LINEAR);
7344 int sync_frame = (i == Xdrip_stretch ? 7 :
7345 i == Xdrip_stretchB ? 7 :
7346 i == Ydrip_s2 ? j + 8 :
7347 i == Ydrip_s2B ? j + 8 :
7356 i == Xfake_acid_1 ? 0 :
7357 i == Xfake_acid_2 ? 10 :
7358 i == Xfake_acid_3 ? 20 :
7359 i == Xfake_acid_4 ? 30 :
7360 i == Xfake_acid_5 ? 40 :
7361 i == Xfake_acid_6 ? 50 :
7362 i == Xfake_acid_7 ? 60 :
7363 i == Xfake_acid_8 ? 70 :
7365 i == Xball_2B ? j + 8 :
7366 i == Yball_eat ? j + 1 :
7367 i == Ykey_1_eat ? j + 1 :
7368 i == Ykey_2_eat ? j + 1 :
7369 i == Ykey_3_eat ? j + 1 :
7370 i == Ykey_4_eat ? j + 1 :
7371 i == Ykey_5_eat ? j + 1 :
7372 i == Ykey_6_eat ? j + 1 :
7373 i == Ykey_7_eat ? j + 1 :
7374 i == Ykey_8_eat ? j + 1 :
7375 i == Ylenses_eat ? j + 1 :
7376 i == Ymagnify_eat ? j + 1 :
7377 i == Ygrass_eat ? j + 1 :
7378 i == Ydirt_eat ? j + 1 :
7379 i == Xamoeba_1 ? 0 :
7380 i == Xamoeba_2 ? 1 :
7381 i == Xamoeba_3 ? 2 :
7382 i == Xamoeba_4 ? 3 :
7383 i == Xamoeba_5 ? 0 :
7384 i == Xamoeba_6 ? 1 :
7385 i == Xamoeba_7 ? 2 :
7386 i == Xamoeba_8 ? 3 :
7387 i == Xexit_2 ? j + 8 :
7388 i == Xexit_3 ? j + 16 :
7389 i == Xdynamite_1 ? 0 :
7390 i == Xdynamite_2 ? 8 :
7391 i == Xdynamite_3 ? 16 :
7392 i == Xdynamite_4 ? 24 :
7393 i == Xsand_stonein_1 ? j + 1 :
7394 i == Xsand_stonein_2 ? j + 9 :
7395 i == Xsand_stonein_3 ? j + 17 :
7396 i == Xsand_stonein_4 ? j + 25 :
7397 i == Xsand_stoneout_1 && j == 0 ? 0 :
7398 i == Xsand_stoneout_1 && j == 1 ? 0 :
7399 i == Xsand_stoneout_1 && j == 2 ? 1 :
7400 i == Xsand_stoneout_1 && j == 3 ? 2 :
7401 i == Xsand_stoneout_1 && j == 4 ? 2 :
7402 i == Xsand_stoneout_1 && j == 5 ? 3 :
7403 i == Xsand_stoneout_1 && j == 6 ? 4 :
7404 i == Xsand_stoneout_1 && j == 7 ? 4 :
7405 i == Xsand_stoneout_2 && j == 0 ? 5 :
7406 i == Xsand_stoneout_2 && j == 1 ? 6 :
7407 i == Xsand_stoneout_2 && j == 2 ? 7 :
7408 i == Xsand_stoneout_2 && j == 3 ? 8 :
7409 i == Xsand_stoneout_2 && j == 4 ? 9 :
7410 i == Xsand_stoneout_2 && j == 5 ? 11 :
7411 i == Xsand_stoneout_2 && j == 6 ? 13 :
7412 i == Xsand_stoneout_2 && j == 7 ? 15 :
7413 i == Xboom_bug && j == 1 ? 2 :
7414 i == Xboom_bug && j == 2 ? 2 :
7415 i == Xboom_bug && j == 3 ? 4 :
7416 i == Xboom_bug && j == 4 ? 4 :
7417 i == Xboom_bug && j == 5 ? 2 :
7418 i == Xboom_bug && j == 6 ? 2 :
7419 i == Xboom_bug && j == 7 ? 0 :
7420 i == Xboom_bomb && j == 1 ? 2 :
7421 i == Xboom_bomb && j == 2 ? 2 :
7422 i == Xboom_bomb && j == 3 ? 4 :
7423 i == Xboom_bomb && j == 4 ? 4 :
7424 i == Xboom_bomb && j == 5 ? 2 :
7425 i == Xboom_bomb && j == 6 ? 2 :
7426 i == Xboom_bomb && j == 7 ? 0 :
7427 i == Xboom_android && j == 7 ? 6 :
7428 i == Xboom_1 && j == 1 ? 2 :
7429 i == Xboom_1 && j == 2 ? 2 :
7430 i == Xboom_1 && j == 3 ? 4 :
7431 i == Xboom_1 && j == 4 ? 4 :
7432 i == Xboom_1 && j == 5 ? 6 :
7433 i == Xboom_1 && j == 6 ? 6 :
7434 i == Xboom_1 && j == 7 ? 8 :
7435 i == Xboom_2 && j == 0 ? 8 :
7436 i == Xboom_2 && j == 1 ? 8 :
7437 i == Xboom_2 && j == 2 ? 10 :
7438 i == Xboom_2 && j == 3 ? 10 :
7439 i == Xboom_2 && j == 4 ? 10 :
7440 i == Xboom_2 && j == 5 ? 12 :
7441 i == Xboom_2 && j == 6 ? 12 :
7442 i == Xboom_2 && j == 7 ? 12 :
7443 special_animation && j == 4 ? 3 :
7444 effective_action != action ? 0 :
7448 Bitmap *debug_bitmap = g_em->bitmap;
7449 int debug_src_x = g_em->src_x;
7450 int debug_src_y = g_em->src_y;
7453 int frame = getAnimationFrame(g->anim_frames,
7456 g->anim_start_frame,
7459 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
7460 g->double_movement && is_backside);
7462 g_em->bitmap = src_bitmap;
7463 g_em->src_x = src_x;
7464 g_em->src_y = src_y;
7465 g_em->src_offset_x = 0;
7466 g_em->src_offset_y = 0;
7467 g_em->dst_offset_x = 0;
7468 g_em->dst_offset_y = 0;
7469 g_em->width = TILEX;
7470 g_em->height = TILEY;
7472 g_em->preserve_background = FALSE;
7474 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
7477 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
7478 effective_action == ACTION_MOVING ||
7479 effective_action == ACTION_PUSHING ||
7480 effective_action == ACTION_EATING)) ||
7481 (!has_action_graphics && (effective_action == ACTION_FILLING ||
7482 effective_action == ACTION_EMPTYING)))
7485 (effective_action == ACTION_FALLING ||
7486 effective_action == ACTION_FILLING ||
7487 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
7488 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
7489 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
7490 int num_steps = (i == Ydrip_s1 ? 16 :
7491 i == Ydrip_s1B ? 16 :
7492 i == Ydrip_s2 ? 16 :
7493 i == Ydrip_s2B ? 16 :
7494 i == Xsand_stonein_1 ? 32 :
7495 i == Xsand_stonein_2 ? 32 :
7496 i == Xsand_stonein_3 ? 32 :
7497 i == Xsand_stonein_4 ? 32 :
7498 i == Xsand_stoneout_1 ? 16 :
7499 i == Xsand_stoneout_2 ? 16 : 8);
7500 int cx = ABS(dx) * (TILEX / num_steps);
7501 int cy = ABS(dy) * (TILEY / num_steps);
7502 int step_frame = (i == Ydrip_s2 ? j + 8 :
7503 i == Ydrip_s2B ? j + 8 :
7504 i == Xsand_stonein_2 ? j + 8 :
7505 i == Xsand_stonein_3 ? j + 16 :
7506 i == Xsand_stonein_4 ? j + 24 :
7507 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
7508 int step = (is_backside ? step_frame : num_steps - step_frame);
7510 if (is_backside) /* tile where movement starts */
7512 if (dx < 0 || dy < 0)
7514 g_em->src_offset_x = cx * step;
7515 g_em->src_offset_y = cy * step;
7519 g_em->dst_offset_x = cx * step;
7520 g_em->dst_offset_y = cy * step;
7523 else /* tile where movement ends */
7525 if (dx < 0 || dy < 0)
7527 g_em->dst_offset_x = cx * step;
7528 g_em->dst_offset_y = cy * step;
7532 g_em->src_offset_x = cx * step;
7533 g_em->src_offset_y = cy * step;
7537 g_em->width = TILEX - cx * step;
7538 g_em->height = TILEY - cy * step;
7541 /* create unique graphic identifier to decide if tile must be redrawn */
7542 /* bit 31 - 16 (16 bit): EM style graphic
7543 bit 15 - 12 ( 4 bit): EM style frame
7544 bit 11 - 6 ( 6 bit): graphic width
7545 bit 5 - 0 ( 6 bit): graphic height */
7546 g_em->unique_identifier =
7547 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
7551 /* skip check for EMC elements not contained in original EMC artwork */
7552 if (element == EL_EMC_FAKE_ACID)
7555 if (g_em->bitmap != debug_bitmap ||
7556 g_em->src_x != debug_src_x ||
7557 g_em->src_y != debug_src_y ||
7558 g_em->src_offset_x != 0 ||
7559 g_em->src_offset_y != 0 ||
7560 g_em->dst_offset_x != 0 ||
7561 g_em->dst_offset_y != 0 ||
7562 g_em->width != TILEX ||
7563 g_em->height != TILEY)
7565 static int last_i = -1;
7573 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
7574 i, element, element_info[element].token_name,
7575 element_action_info[effective_action].suffix, direction);
7577 if (element != effective_element)
7578 printf(" [%d ('%s')]",
7580 element_info[effective_element].token_name);
7584 if (g_em->bitmap != debug_bitmap)
7585 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
7586 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
7588 if (g_em->src_x != debug_src_x ||
7589 g_em->src_y != debug_src_y)
7590 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
7591 j, (is_backside ? 'B' : 'F'),
7592 g_em->src_x, g_em->src_y,
7593 g_em->src_x / 32, g_em->src_y / 32,
7594 debug_src_x, debug_src_y,
7595 debug_src_x / 32, debug_src_y / 32);
7597 if (g_em->src_offset_x != 0 ||
7598 g_em->src_offset_y != 0 ||
7599 g_em->dst_offset_x != 0 ||
7600 g_em->dst_offset_y != 0)
7601 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
7603 g_em->src_offset_x, g_em->src_offset_y,
7604 g_em->dst_offset_x, g_em->dst_offset_y);
7606 if (g_em->width != TILEX ||
7607 g_em->height != TILEY)
7608 printf(" %d (%d): size %d,%d should be %d,%d\n",
7610 g_em->width, g_em->height, TILEX, TILEY);
7612 num_em_gfx_errors++;
7619 for (i = 0; i < TILE_MAX; i++)
7621 for (j = 0; j < 8; j++)
7623 int element = object_mapping[i].element_rnd;
7624 int action = object_mapping[i].action;
7625 int direction = object_mapping[i].direction;
7626 boolean is_backside = object_mapping[i].is_backside;
7627 int graphic_action = el_act_dir2img(element, action, direction);
7628 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
7630 if ((action == ACTION_SMASHED_BY_ROCK ||
7631 action == ACTION_SMASHED_BY_SPRING ||
7632 action == ACTION_EATING) &&
7633 graphic_action == graphic_default)
7635 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
7636 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
7637 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
7638 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
7641 /* no separate animation for "smashed by rock" -- use rock instead */
7642 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7643 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
7645 g_em->bitmap = g_xx->bitmap;
7646 g_em->src_x = g_xx->src_x;
7647 g_em->src_y = g_xx->src_y;
7648 g_em->src_offset_x = g_xx->src_offset_x;
7649 g_em->src_offset_y = g_xx->src_offset_y;
7650 g_em->dst_offset_x = g_xx->dst_offset_x;
7651 g_em->dst_offset_y = g_xx->dst_offset_y;
7652 g_em->width = g_xx->width;
7653 g_em->height = g_xx->height;
7654 g_em->unique_identifier = g_xx->unique_identifier;
7657 g_em->preserve_background = TRUE;
7662 for (p = 0; p < MAX_PLAYERS; p++)
7664 for (i = 0; i < SPR_MAX; i++)
7666 int element = player_mapping[p][i].element_rnd;
7667 int action = player_mapping[p][i].action;
7668 int direction = player_mapping[p][i].direction;
7670 for (j = 0; j < 8; j++)
7672 int effective_element = element;
7673 int effective_action = action;
7674 int graphic = (direction == MV_NONE ?
7675 el_act2img(effective_element, effective_action) :
7676 el_act_dir2img(effective_element, effective_action,
7678 struct GraphicInfo *g = &graphic_info[graphic];
7679 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
7685 Bitmap *debug_bitmap = g_em->bitmap;
7686 int debug_src_x = g_em->src_x;
7687 int debug_src_y = g_em->src_y;
7690 int frame = getAnimationFrame(g->anim_frames,
7693 g->anim_start_frame,
7696 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
7698 g_em->bitmap = src_bitmap;
7699 g_em->src_x = src_x;
7700 g_em->src_y = src_y;
7701 g_em->src_offset_x = 0;
7702 g_em->src_offset_y = 0;
7703 g_em->dst_offset_x = 0;
7704 g_em->dst_offset_y = 0;
7705 g_em->width = TILEX;
7706 g_em->height = TILEY;
7710 /* skip check for EMC elements not contained in original EMC artwork */
7711 if (element == EL_PLAYER_3 ||
7712 element == EL_PLAYER_4)
7715 if (g_em->bitmap != debug_bitmap ||
7716 g_em->src_x != debug_src_x ||
7717 g_em->src_y != debug_src_y)
7719 static int last_i = -1;
7727 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
7728 p, i, element, element_info[element].token_name,
7729 element_action_info[effective_action].suffix, direction);
7731 if (element != effective_element)
7732 printf(" [%d ('%s')]",
7734 element_info[effective_element].token_name);
7738 if (g_em->bitmap != debug_bitmap)
7739 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
7740 j, (int)(g_em->bitmap), (int)(debug_bitmap));
7742 if (g_em->src_x != debug_src_x ||
7743 g_em->src_y != debug_src_y)
7744 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
7746 g_em->src_x, g_em->src_y,
7747 g_em->src_x / 32, g_em->src_y / 32,
7748 debug_src_x, debug_src_y,
7749 debug_src_x / 32, debug_src_y / 32);
7751 num_em_gfx_errors++;
7761 printf("::: [%d errors found]\n", num_em_gfx_errors);
7767 void CheckSaveEngineSnapshot_EM(byte action[MAX_PLAYERS], int frame,
7768 boolean any_player_moving,
7769 boolean any_player_snapping,
7770 boolean any_player_dropping)
7772 static boolean player_was_waiting = TRUE;
7774 if (frame == 0 && !any_player_dropping)
7776 if (!player_was_waiting)
7778 if (!SaveEngineSnapshotToList())
7781 player_was_waiting = TRUE;
7784 else if (any_player_moving || any_player_snapping || any_player_dropping)
7786 player_was_waiting = FALSE;
7790 void CheckSaveEngineSnapshot_SP(boolean murphy_is_waiting,
7791 boolean murphy_is_dropping)
7793 static boolean player_was_waiting = TRUE;
7795 if (murphy_is_waiting)
7797 if (!player_was_waiting)
7799 if (!SaveEngineSnapshotToList())
7802 player_was_waiting = TRUE;
7807 player_was_waiting = FALSE;
7811 void CheckSingleStepMode_EM(byte action[MAX_PLAYERS], int frame,
7812 boolean any_player_moving,
7813 boolean any_player_snapping,
7814 boolean any_player_dropping)
7816 if (tape.single_step && tape.recording && !tape.pausing)
7817 if (frame == 0 && !any_player_dropping)
7818 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
7820 CheckSaveEngineSnapshot_EM(action, frame, any_player_moving,
7821 any_player_snapping, any_player_dropping);
7824 void CheckSingleStepMode_SP(boolean murphy_is_waiting,
7825 boolean murphy_is_dropping)
7827 if (tape.single_step && tape.recording && !tape.pausing)
7828 if (murphy_is_waiting)
7829 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
7831 CheckSaveEngineSnapshot_SP(murphy_is_waiting, murphy_is_dropping);
7834 void getGraphicSource_SP(struct GraphicInfo_SP *g_sp,
7835 int graphic, int sync_frame, int x, int y)
7837 int frame = getGraphicAnimationFrame(graphic, sync_frame);
7839 getGraphicSource(graphic, frame, &g_sp->bitmap, &g_sp->src_x, &g_sp->src_y);
7842 boolean isNextAnimationFrame_SP(int graphic, int sync_frame)
7844 return (IS_NEXT_FRAME(sync_frame, graphic));
7847 int getGraphicInfo_Delay(int graphic)
7849 return graphic_info[graphic].anim_delay;
7852 void PlayMenuSoundExt(int sound)
7854 if (sound == SND_UNDEFINED)
7857 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
7858 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
7861 if (IS_LOOP_SOUND(sound))
7862 PlaySoundLoop(sound);
7867 void PlayMenuSound()
7869 PlayMenuSoundExt(menu.sound[game_status]);
7872 void PlayMenuSoundStereo(int sound, int stereo_position)
7874 if (sound == SND_UNDEFINED)
7877 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
7878 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
7881 if (IS_LOOP_SOUND(sound))
7882 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
7884 PlaySoundStereo(sound, stereo_position);
7887 void PlayMenuSoundIfLoopExt(int sound)
7889 if (sound == SND_UNDEFINED)
7892 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
7893 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
7896 if (IS_LOOP_SOUND(sound))
7897 PlaySoundLoop(sound);
7900 void PlayMenuSoundIfLoop()
7902 PlayMenuSoundIfLoopExt(menu.sound[game_status]);
7905 void PlayMenuMusicExt(int music)
7907 if (music == MUS_UNDEFINED)
7910 if (!setup.sound_music)
7916 void PlayMenuMusic()
7918 PlayMenuMusicExt(menu.music[game_status]);
7921 void PlaySoundActivating()
7924 PlaySound(SND_MENU_ITEM_ACTIVATING);
7928 void PlaySoundSelecting()
7931 PlaySound(SND_MENU_ITEM_SELECTING);
7935 void ToggleFullscreenOrChangeWindowScalingIfNeeded()
7937 boolean change_fullscreen = (setup.fullscreen !=
7938 video.fullscreen_enabled);
7939 boolean change_fullscreen_mode = (video.fullscreen_enabled &&
7940 !strEqual(setup.fullscreen_mode,
7941 video.fullscreen_mode_current));
7942 boolean change_window_scaling_percent = (!video.fullscreen_enabled &&
7943 setup.window_scaling_percent !=
7944 video.window_scaling_percent);
7946 if (change_window_scaling_percent && video.fullscreen_enabled)
7949 if (!change_window_scaling_percent && !video.fullscreen_available)
7952 #if defined(TARGET_SDL2)
7953 if (change_window_scaling_percent)
7955 SDLSetWindowScaling(setup.window_scaling_percent);
7959 else if (change_fullscreen)
7961 SDLSetWindowFullscreen(setup.fullscreen);
7963 /* set setup value according to successfully changed fullscreen mode */
7964 setup.fullscreen = video.fullscreen_enabled;
7970 if (change_fullscreen ||
7971 change_fullscreen_mode ||
7972 change_window_scaling_percent)
7974 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
7976 /* save backbuffer content which gets lost when toggling fullscreen mode */
7977 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
7979 if (change_fullscreen_mode)
7981 /* keep fullscreen, but change fullscreen mode (screen resolution) */
7982 video.fullscreen_enabled = FALSE; /* force new fullscreen mode */
7985 if (change_window_scaling_percent)
7987 /* keep window mode, but change window scaling */
7988 video.fullscreen_enabled = TRUE; /* force new window scaling */
7991 /* toggle fullscreen */
7992 ChangeVideoModeIfNeeded(setup.fullscreen);
7994 /* set setup value according to successfully changed fullscreen mode */
7995 setup.fullscreen = video.fullscreen_enabled;
7997 /* restore backbuffer content from temporary backbuffer backup bitmap */
7998 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8000 FreeBitmap(tmp_backbuffer);
8002 /* update visible window/screen */
8003 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8007 void ChangeViewportPropertiesIfNeeded()
8009 int gfx_game_mode = game_status;
8010 int gfx_game_mode2 = (game_status == GAME_MODE_EDITOR ? GAME_MODE_DEFAULT :
8012 struct RectWithBorder *vp_playfield = &viewport.playfield[gfx_game_mode];
8013 struct RectWithBorder *vp_door_1 = &viewport.door_1[gfx_game_mode];
8014 struct RectWithBorder *vp_door_2 = &viewport.door_2[gfx_game_mode2];
8015 struct RectWithBorder *vp_door_3 = &viewport.door_2[GAME_MODE_EDITOR];
8016 int border_size = vp_playfield->border_size;
8017 int new_sx = vp_playfield->x + border_size;
8018 int new_sy = vp_playfield->y + border_size;
8019 int new_sxsize = vp_playfield->width - 2 * border_size;
8020 int new_sysize = vp_playfield->height - 2 * border_size;
8021 int new_real_sx = vp_playfield->x;
8022 int new_real_sy = vp_playfield->y;
8023 int new_full_sxsize = vp_playfield->width;
8024 int new_full_sysize = vp_playfield->height;
8025 int new_dx = vp_door_1->x;
8026 int new_dy = vp_door_1->y;
8027 int new_dxsize = vp_door_1->width;
8028 int new_dysize = vp_door_1->height;
8029 int new_vx = vp_door_2->x;
8030 int new_vy = vp_door_2->y;
8031 int new_vxsize = vp_door_2->width;
8032 int new_vysize = vp_door_2->height;
8033 int new_ex = vp_door_3->x;
8034 int new_ey = vp_door_3->y;
8035 int new_exsize = vp_door_3->width;
8036 int new_eysize = vp_door_3->height;
8037 int new_tilesize_var =
8038 (setup.small_game_graphics ? MINI_TILESIZE : game.tile_size);
8040 int tilesize = (gfx_game_mode == GAME_MODE_PLAYING ? new_tilesize_var :
8041 gfx_game_mode == GAME_MODE_EDITOR ? MINI_TILESIZE : TILESIZE);
8042 int new_scr_fieldx = new_sxsize / tilesize;
8043 int new_scr_fieldy = new_sysize / tilesize;
8044 int new_scr_fieldx_buffers = new_sxsize / new_tilesize_var;
8045 int new_scr_fieldy_buffers = new_sysize / new_tilesize_var;
8046 boolean init_gfx_buffers = FALSE;
8047 boolean init_video_buffer = FALSE;
8048 boolean init_gadgets_and_toons = FALSE;
8049 boolean init_em_graphics = FALSE;
8050 boolean drawing_area_changed = FALSE;
8052 if (viewport.window.width != WIN_XSIZE ||
8053 viewport.window.height != WIN_YSIZE)
8055 WIN_XSIZE = viewport.window.width;
8056 WIN_YSIZE = viewport.window.height;
8058 init_video_buffer = TRUE;
8059 init_gfx_buffers = TRUE;
8061 // printf("::: video: init_video_buffer, init_gfx_buffers\n");
8064 if (new_scr_fieldx != SCR_FIELDX ||
8065 new_scr_fieldy != SCR_FIELDY)
8067 /* this always toggles between MAIN and GAME when using small tile size */
8069 SCR_FIELDX = new_scr_fieldx;
8070 SCR_FIELDY = new_scr_fieldy;
8072 // printf("::: new_scr_fieldx != SCR_FIELDX ...\n");
8083 new_sxsize != SXSIZE ||
8084 new_sysize != SYSIZE ||
8085 new_dxsize != DXSIZE ||
8086 new_dysize != DYSIZE ||
8087 new_vxsize != VXSIZE ||
8088 new_vysize != VYSIZE ||
8089 new_exsize != EXSIZE ||
8090 new_eysize != EYSIZE ||
8091 new_real_sx != REAL_SX ||
8092 new_real_sy != REAL_SY ||
8093 new_full_sxsize != FULL_SXSIZE ||
8094 new_full_sysize != FULL_SYSIZE ||
8095 new_tilesize_var != TILESIZE_VAR
8098 if (new_tilesize_var != TILESIZE_VAR)
8100 // printf("::: new_tilesize_var != TILESIZE_VAR\n");
8102 // changing tile size invalidates scroll values of engine snapshots
8103 FreeEngineSnapshotSingle();
8105 // changing tile size requires update of graphic mapping for EM engine
8106 init_em_graphics = TRUE;
8111 new_sxsize != SXSIZE ||
8112 new_sysize != SYSIZE ||
8113 new_real_sx != REAL_SX ||
8114 new_real_sy != REAL_SY ||
8115 new_full_sxsize != FULL_SXSIZE ||
8116 new_full_sysize != FULL_SYSIZE)
8118 if (!init_video_buffer)
8119 drawing_area_changed = TRUE;
8130 SXSIZE = new_sxsize;
8131 SYSIZE = new_sysize;
8132 DXSIZE = new_dxsize;
8133 DYSIZE = new_dysize;
8134 VXSIZE = new_vxsize;
8135 VYSIZE = new_vysize;
8136 EXSIZE = new_exsize;
8137 EYSIZE = new_eysize;
8138 REAL_SX = new_real_sx;
8139 REAL_SY = new_real_sy;
8140 FULL_SXSIZE = new_full_sxsize;
8141 FULL_SYSIZE = new_full_sysize;
8142 TILESIZE_VAR = new_tilesize_var;
8144 init_gfx_buffers = TRUE;
8145 init_gadgets_and_toons = TRUE;
8147 // printf("::: viewports: init_gfx_buffers\n");
8148 // printf("::: viewports: init_gadgets_and_toons\n");
8151 if (init_gfx_buffers)
8153 // printf("::: init_gfx_buffers\n");
8155 SCR_FIELDX = new_scr_fieldx_buffers;
8156 SCR_FIELDY = new_scr_fieldy_buffers;
8160 SCR_FIELDX = new_scr_fieldx;
8161 SCR_FIELDY = new_scr_fieldy;
8163 gfx.drawing_area_changed = drawing_area_changed;
8165 SetDrawDeactivationMask(REDRAW_NONE);
8166 SetDrawBackgroundMask(REDRAW_FIELD);
8169 if (init_video_buffer)
8171 // printf("::: init_video_buffer\n");
8173 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
8176 if (init_gadgets_and_toons)
8178 // printf("::: init_gadgets_and_toons\n");
8184 if (init_em_graphics)
8186 InitGraphicInfo_EM();